agentengine-sdk-python 0.8.0__py3-none-any.whl → 0.8.2__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 (494) hide show
  1. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/METADATA +43 -7
  2. agentengine_sdk_python-0.8.2.dist-info/RECORD +778 -0
  3. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/WHEEL +1 -1
  4. ksadk/a2a/__init__.py +2 -0
  5. ksadk/a2a/_space_client_events.py +381 -0
  6. ksadk/a2a/bootstrap.py +0 -2
  7. ksadk/a2a/card.py +6 -111
  8. ksadk/a2a/control_plane.py +239 -1
  9. ksadk/a2a/event_adapter.py +156 -64
  10. ksadk/a2a/executor.py +195 -172
  11. ksadk/a2a/routes.py +12 -5
  12. ksadk/a2a/server.py +1 -8
  13. ksadk/a2a/service_env.py +33 -0
  14. ksadk/a2a/space_client.py +43 -349
  15. ksadk/a2a_card.py +101 -0
  16. ksadk/a2ui/core.py +222 -53
  17. ksadk/agui/_agent_helpers.py +243 -0
  18. ksadk/agui/a2ui_projection.py +12 -5
  19. ksadk/agui/agent.py +474 -275
  20. ksadk/agui/config.py +11 -5
  21. ksadk/agui/routes.py +7 -15
  22. ksadk/api/client.py +530 -40
  23. ksadk/api/environment.py +27 -0
  24. ksadk/builders/code_builder.py +352 -53
  25. ksadk/builders/container_builder.py +71 -44
  26. ksadk/builders/framework_requirements.py +2 -1
  27. ksadk/builders/ks3_uploader.py +2 -2
  28. ksadk/builders/managed_runtime_builder.py +60 -28
  29. ksadk/cli/__init__.py +25 -0
  30. ksadk/cli/cmd_a2a.py +18 -31
  31. ksadk/cli/cmd_create.py +13 -26
  32. ksadk/cli/cmd_dashboard.py +15 -1
  33. ksadk/cli/cmd_deploy.py +28 -3
  34. ksadk/cli/cmd_eval.py +443 -0
  35. ksadk/cli/cmd_evalset.py +284 -0
  36. ksadk/cli/cmd_files.py +5 -1
  37. ksadk/cli/cmd_hermes.py +137 -163
  38. ksadk/cli/cmd_invoke.py +28 -38
  39. ksadk/cli/cmd_launch.py +12 -0
  40. ksadk/cli/cmd_managed_runtime.py +95 -0
  41. ksadk/cli/cmd_observe.py +85 -0
  42. ksadk/cli/cmd_openclaw.py +85 -479
  43. ksadk/cli/cmd_replay.py +28 -4
  44. ksadk/cli/cmd_run.py +29 -67
  45. ksadk/cli/cmd_studio.py +201 -0
  46. ksadk/cli/cmd_web.py +15 -6
  47. ksadk/cli/dry_run.py +2 -1
  48. ksadk/cli/env_options.py +83 -0
  49. ksadk/cli/global_options.py +3 -1
  50. ksadk/cli/hermes_env.py +151 -0
  51. ksadk/cli/invoke_payload.py +49 -0
  52. ksadk/cli/network_options.py +7 -5
  53. ksadk/cli/openclaw_env.py +458 -0
  54. ksadk/cli/runtime_bootstrap.py +51 -0
  55. ksadk/cli/ui.py +6 -0
  56. ksadk/cli/workflow_common.py +5 -5
  57. ksadk/codex/__init__.py +3 -3
  58. ksadk/codex/client.py +833 -49
  59. ksadk/codex/phase.py +1 -1
  60. ksadk/codex/runtime.py +720 -127
  61. ksadk/common/kop_client.py +232 -0
  62. ksadk/configs/__init__.py +1 -3
  63. ksadk/configs/env_registry.py +244 -45
  64. ksadk/configs/env_registry_pcm.py +181 -0
  65. ksadk/configs/env_var_spec.py +18 -0
  66. ksadk/configs/global_config.py +6 -1
  67. ksadk/configs/settings.py +5 -108
  68. ksadk/context_engine/__init__.py +98 -0
  69. ksadk/context_engine/assembler.py +176 -0
  70. ksadk/context_engine/baseline.py +419 -0
  71. ksadk/context_engine/cache_observability.py +228 -0
  72. ksadk/context_engine/capabilities.py +443 -0
  73. ksadk/context_engine/contributors.py +344 -0
  74. ksadk/context_engine/hosted_pipeline.py +417 -0
  75. ksadk/context_engine/models.py +117 -0
  76. ksadk/context_engine/planner.py +698 -0
  77. ksadk/context_engine/policies.py +319 -0
  78. ksadk/context_engine/projection.py +31 -0
  79. ksadk/context_engine/shadow_plan.py +266 -0
  80. ksadk/context_engine/tokenizer.py +164 -0
  81. ksadk/conversations/__init__.py +85 -94
  82. ksadk/conversations/context.py +126 -6
  83. ksadk/conversations/message_projection.py +292 -28
  84. ksadk/conversations/model_context.py +49 -3
  85. ksadk/conversations/runtime_compaction.py +207 -5
  86. ksadk/conversations/runtime_input.py +193 -3
  87. ksadk/conversations/runtime_invocation.py +81 -3
  88. ksadk/conversations/runtime_observability.py +157 -4
  89. ksadk/conversations/runtime_payloads.py +42 -0
  90. ksadk/conversations/runtime_preparation.py +280 -2
  91. ksadk/conversations/runtime_resume.py +71 -32
  92. ksadk/conversations/runtime_stream_events.py +94 -9
  93. ksadk/conversations/runtime_streaming.py +175 -22
  94. ksadk/conversations/semantic_summary.py +311 -1
  95. ksadk/conversations/session_lock.py +51 -0
  96. ksadk/deployment/env_forward.py +72 -0
  97. ksadk/deployment/managed_runtime.py +38 -0
  98. ksadk/deployment/manager.py +24 -8
  99. ksadk/deployment/providers/serverless.py +228 -92
  100. ksadk/evaluation/__init__.py +116 -0
  101. ksadk/evaluation/a2a_adapter.py +452 -0
  102. ksadk/evaluation/adapters.py +67 -0
  103. ksadk/evaluation/agent_eval_client.py +395 -0
  104. ksadk/evaluation/cloud_binding.py +80 -0
  105. ksadk/evaluation/cloud_converter.py +194 -0
  106. ksadk/evaluation/cloud_service.py +199 -0
  107. ksadk/evaluation/contracts.py +478 -0
  108. ksadk/evaluation/evalset.py +351 -0
  109. ksadk/evaluation/evaluators.py +627 -0
  110. ksadk/evaluation/evidence.py +258 -0
  111. ksadk/evaluation/executor.py +143 -0
  112. ksadk/evaluation/local_adapter.py +550 -0
  113. ksadk/evaluation/service_env.py +27 -0
  114. ksadk/evaluation/storage.py +68 -0
  115. ksadk/evaluation/studio_build_adapter.py +253 -0
  116. ksadk/evaluation/target.py +82 -0
  117. ksadk/events/__init__.py +13 -13
  118. ksadk/events/_v1_compat/__init__.py +1 -0
  119. ksadk/events/_v1_compat/models.py +299 -0
  120. ksadk/events/_v1_compat/parser.py +247 -0
  121. ksadk/events/_v1_compat/projection.py +753 -0
  122. ksadk/events/adapters/__init__.py +34 -0
  123. ksadk/events/adapters/_a2a_snapshot.py +622 -0
  124. ksadk/events/adapters/_a2a_support.py +275 -0
  125. ksadk/events/adapters/_codex_interactions.py +375 -0
  126. ksadk/events/adapters/_codex_items.py +801 -0
  127. ksadk/events/adapters/_codex_validators.py +311 -0
  128. ksadk/events/adapters/_langgraph_support.py +785 -0
  129. ksadk/events/adapters/a2a.py +841 -0
  130. ksadk/events/adapters/adk.py +503 -0
  131. ksadk/events/adapters/codex.py +717 -0
  132. ksadk/events/adapters/langgraph.py +745 -0
  133. ksadk/events/canonical.py +440 -0
  134. ksadk/events/canonical_replay.py +497 -0
  135. ksadk/events/canonical_store.py +468 -0
  136. ksadk/events/cold_recovery.py +257 -0
  137. ksadk/events/content.py +89 -0
  138. ksadk/events/identity.py +86 -0
  139. ksadk/events/pipeline.py +455 -0
  140. ksadk/events/projections.py +66 -0
  141. ksadk/events/reducer.py +661 -0
  142. ksadk/events/replay.py +3 -36
  143. ksadk/events/runtime_event.py +20 -256
  144. ksadk/events/session_event.py +324 -0
  145. ksadk/events/store.py +3 -316
  146. ksadk/events/v1_compat.py +41 -0
  147. ksadk/harness/__init__.py +3 -2
  148. ksadk/harness/app.py +114 -123
  149. ksadk/harness/config.py +1 -1
  150. ksadk/harness/runtime.py +467 -0
  151. ksadk/hermes_terminal.py +5 -0
  152. ksadk/identity/resolver.py +4 -3
  153. ksadk/interaction/__init__.py +28 -0
  154. ksadk/interaction/contracts.py +136 -0
  155. ksadk/interaction/ledger.py +189 -0
  156. ksadk/interaction/provider.py +122 -0
  157. ksadk/interaction/providers/__init__.py +52 -0
  158. ksadk/interaction/providers/adk.py +40 -0
  159. ksadk/interaction/providers/codex.py +94 -0
  160. ksadk/interaction/providers/langgraph.py +58 -0
  161. ksadk/kernel/__init__.py +117 -0
  162. ksadk/kernel/authorization.py +258 -0
  163. ksadk/kernel/bootstrap.py +1074 -0
  164. ksadk/kernel/contract_fingerprints.py +61 -0
  165. ksadk/kernel/contracts.py +362 -0
  166. ksadk/kernel/control.py +219 -0
  167. ksadk/kernel/errors.py +79 -0
  168. ksadk/kernel/ingress.py +1102 -0
  169. ksadk/kernel/mapping.py +111 -0
  170. ksadk/kernel/memory_store.py +1133 -0
  171. ksadk/kernel/postgres_store.py +1756 -0
  172. ksadk/kernel/recovery.py +452 -0
  173. ksadk/kernel/runtime_identity.py +103 -0
  174. ksadk/kernel/sql/001_agent_kernel.sql +120 -0
  175. ksadk/kernel/sqlite_store.py +1410 -0
  176. ksadk/kernel/state.py +145 -0
  177. ksadk/kernel/store.py +232 -0
  178. ksadk/kernel/worker.py +953 -0
  179. ksadk/knowledge_base/client.py +22 -4
  180. ksadk/knowledge_base/service.py +32 -5
  181. ksadk/managed_a2a_card.py +160 -0
  182. ksadk/managed_runtime.py +16 -9
  183. ksadk/memory/__init__.py +61 -0
  184. ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
  185. ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
  186. ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
  187. ksadk/memory/adk/backends/sdk_ltm_backend.py +394 -5
  188. ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
  189. ksadk/memory/adk/long_term_memory.py +3 -2
  190. ksadk/memory/coordinator.py +461 -0
  191. ksadk/memory/events.py +202 -0
  192. ksadk/memory/extraction.py +228 -0
  193. ksadk/memory/ltm_backend_factory.py +16 -3
  194. ksadk/memory/models.py +316 -0
  195. ksadk/memory/policy.py +215 -0
  196. ksadk/memory/provider.py +47 -0
  197. ksadk/memory/provider_adapter.py +159 -0
  198. ksadk/memory/provider_resolver.py +71 -0
  199. ksadk/memory/providers/__init__.py +5 -0
  200. ksadk/memory/providers/local_sqlite.py +490 -0
  201. ksadk/memory/resolved_policy.py +145 -0
  202. ksadk/memory/service.py +198 -8
  203. ksadk/memory/tool.py +4 -0
  204. ksadk/model_proxy/bootstrap.py +16 -9
  205. ksadk/model_proxy/config.py +22 -1
  206. ksadk/model_proxy/detect.py +202 -9
  207. ksadk/model_proxy/namespace.py +67 -15
  208. ksadk/model_proxy/server.py +168 -6
  209. ksadk/model_proxy/transform.py +105 -3
  210. ksadk/observability/__init__.py +25 -0
  211. ksadk/observability/session_log.py +420 -0
  212. ksadk/observability/trajectory.py +105 -0
  213. ksadk/prompts/__init__.py +71 -0
  214. ksadk/prompts/compiler.py +215 -0
  215. ksadk/prompts/models.py +82 -0
  216. ksadk/prompts/projection.py +89 -0
  217. ksadk/prompts/resolved.py +137 -0
  218. ksadk/prompts/sources.py +233 -0
  219. ksadk/runners/_langgraph_runner_streams.py +822 -0
  220. ksadk/runners/adk_runner.py +14 -31
  221. ksadk/runners/base_runner.py +44 -3
  222. ksadk/runners/factory.py +3 -3
  223. ksadk/runners/langgraph_runner.py +252 -433
  224. ksadk/runners/utils/__init__.py +0 -10
  225. ksadk/runners/utils/loader.py +16 -0
  226. ksadk/runtime/__init__.py +67 -41
  227. ksadk/runtime/_runner_adapter/__init__.py +1 -0
  228. ksadk/runtime/_runner_adapter/stream_mapping.py +788 -0
  229. ksadk/runtime/adapter.py +199 -16
  230. ksadk/runtime/conversation_execution.py +687 -0
  231. ksadk/runtime/executor.py +392 -0
  232. ksadk/runtime/factory.py +342 -0
  233. ksadk/runtime/framework_adapters.py +6 -12
  234. ksadk/runtime/hosted_finalizer.py +268 -0
  235. ksadk/runtime/launch.py +61 -0
  236. ksadk/runtime/preprocessing.py +49 -14
  237. ksadk/runtime/runner_adapter.py +330 -391
  238. ksadk/runtime/runner_loading.py +36 -0
  239. ksadk/runtime/usage.py +33 -0
  240. ksadk/sandbox/backends/e2b.py +36 -3
  241. ksadk/server/__init__.py +39 -4
  242. ksadk/server/app.py +18 -492
  243. ksadk/server/composition.py +36 -2
  244. ksadk/server/factory.py +210 -149
  245. ksadk/server/routes/common.py +15 -46
  246. ksadk/server/routes/control.py +13 -9
  247. ksadk/server/routes/kernel_ingress.py +258 -0
  248. ksadk/server/routes/misc.py +10 -33
  249. ksadk/server/routes/models.py +14 -6
  250. ksadk/server/routes/openai_compat.py +129 -27
  251. ksadk/server/routes/projection.py +84 -16
  252. ksadk/server/routes/run.py +347 -460
  253. ksadk/server/routes/sessions.py +37 -40
  254. ksadk/server/routes/streaming.py +52 -7
  255. ksadk/server/routes/workspace.py +54 -21
  256. ksadk/server/static/assets/{ArtifactsPanel-Cjnqt-8W.js → ArtifactsPanel-DSU1sWD_.js} +1 -1
  257. ksadk/server/static/assets/{CodeBlock-BqyqZfuB.js → CodeBlock-DOH6MVcn.js} +4 -4
  258. ksadk/server/static/assets/{MathMessageMarkdown-BpH7jiFM.js → MathMessageMarkdown-BL8my1R2.js} +4 -4
  259. ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
  260. ksadk/server/static/assets/MermaidBlock-Dz4IP-Tx.js +312 -0
  261. ksadk/server/static/assets/NativeTerminalPanel-DUrK0JpZ.js +1 -0
  262. ksadk/server/static/assets/abnfDiagram-VCTEODGH-g20pFzNV.js +1 -0
  263. ksadk/server/static/assets/arc-C4FzinUA.js +1 -0
  264. ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +1 -0
  265. ksadk/server/static/assets/architectureDiagram-5GKGNRK7-DpIqL5h4.js +36 -0
  266. ksadk/server/static/assets/blockDiagram-NRAW4CY4-BjkljTNz.js +129 -0
  267. ksadk/server/static/assets/c4Diagram-UCG6FXSJ-Dk_ieq2X.js +38 -0
  268. ksadk/server/static/assets/channel-4cQHKtx1.js +1 -0
  269. ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +1 -0
  270. ksadk/server/static/assets/{chunk-FMBD7UC4-BGhvzDYt.js → chunk-5VM5RSS4-BVHAchFb.js} +1 -1
  271. ksadk/server/static/assets/{chunk-ND2GUHAM-D98vPd-E.js → chunk-F27PBJKO-C-ipQzuS.js} +1 -1
  272. ksadk/server/static/assets/chunk-G27WJ6UU-C2EyJbIK.js +231 -0
  273. ksadk/server/static/assets/{chunk-4BX2VUAB-CsWIQRhc.js → chunk-JWPE2WC7-vYvVJb_M.js} +1 -1
  274. ksadk/server/static/assets/chunk-LCL6LL3I-BcI6ysPT.js +206 -0
  275. ksadk/server/static/assets/chunk-POPQ4Y6H-C030x_Z1.js +1 -0
  276. ksadk/server/static/assets/chunk-RHFEMEQ7-yyGpsz4n.js +168 -0
  277. ksadk/server/static/assets/chunk-SVP7TREG-BLTlmMU7.js +88 -0
  278. ksadk/server/static/assets/chunk-XXDRQBXY-C_32ArgP.js +1 -0
  279. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +1 -0
  280. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +1 -0
  281. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-CX3yotHq.js → cose-bilkent-JH36ORCC-9YQYwdl0.js} +1 -1
  282. ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +1 -0
  283. ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-ErLF5N13.js +62 -0
  284. ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
  285. ksadk/server/static/assets/dagre-3AP2YEHR-DFiQF-6f.js +4 -0
  286. ksadk/server/static/assets/dagre-BuhGnRI1.js +1 -0
  287. ksadk/server/static/assets/diagram-S7CK7UJ4-Bt1v8-GC.js +30 -0
  288. ksadk/server/static/assets/diagram-UQ7AKVKN-DSCxJdBK.js +41 -0
  289. ksadk/server/static/assets/diagram-VSXAHHWV-DHfYwp_9.js +3 -0
  290. ksadk/server/static/assets/diagram-VX7I27RA-DdzD-4Le.js +24 -0
  291. ksadk/server/static/assets/diagram-Z3DM3KII-Du-nAJ9F.js +24 -0
  292. ksadk/server/static/assets/{dist-D82mtD2s.js → dist-8hqcx0sU.js} +1 -1
  293. ksadk/server/static/assets/dist-B7seoj3d.js +1 -0
  294. ksadk/server/static/assets/{dist-DHn6nBzr.js → dist-BE7bu-DL.js} +1 -1
  295. ksadk/server/static/assets/{dist-eoW6tZXA.js → dist-BVDffZ0U.js} +1 -1
  296. ksadk/server/static/assets/{dist-C2xjE7cO.js → dist-BX8z72IC.js} +1 -1
  297. ksadk/server/static/assets/{dist-CgF3fj15.js → dist-Bf2M8m3N.js} +1 -1
  298. ksadk/server/static/assets/{dist-Bs-jQcRX.js → dist-BjU6y-A2.js} +1 -1
  299. ksadk/server/static/assets/{dist-Djgl2wVZ.js → dist-BytlxIDT.js} +1 -1
  300. ksadk/server/static/assets/{dist-CVQRZjPu.js → dist-CSh_DE14.js} +1 -1
  301. ksadk/server/static/assets/{dist-6CVKuTAe.js → dist-CXYYBw3_.js} +1 -1
  302. ksadk/server/static/assets/{dist-DlzCRy0S.js → dist-C_wsv-Qd.js} +1 -1
  303. ksadk/server/static/assets/{dist-DF06ORQo.js → dist-ClxGviKw.js} +1 -1
  304. ksadk/server/static/assets/{dist-Cf23NY4L.js → dist-CttYUqzS.js} +1 -1
  305. ksadk/server/static/assets/{dist-ivOya1LD.js → dist-DNp6rLRA.js} +1 -1
  306. ksadk/server/static/assets/{dist-BibcG1V9.js → dist-DUX-id_F.js} +1 -1
  307. ksadk/server/static/assets/{dist-BUHRxvDG.js → dist-DmldrHd_.js} +1 -1
  308. ksadk/server/static/assets/{dist-BZ9n9AjO.js → dist-DnfXs8Vn.js} +2 -2
  309. ksadk/server/static/assets/{dist-DqNnNFrw.js → dist-Dq9gLD7L.js} +1 -1
  310. ksadk/server/static/assets/{dist-CGcp2ex8.js → dist-W-TIVntx.js} +1 -1
  311. ksadk/server/static/assets/{dist-Cwt7koer.js → dist-dDdADKFA.js} +1 -1
  312. ksadk/server/static/assets/{dist-C7-3jInC.js → dist-dydu68Fl.js} +1 -1
  313. ksadk/server/static/assets/{dist-C99THtIA.js → dist-ngtN0DJB.js} +1 -1
  314. ksadk/server/static/assets/ebnfDiagram-PWID7BFC-Da9C9NO1.js +1 -0
  315. ksadk/server/static/assets/erDiagram-SSCWMZ5O-EAGqqR79.js +99 -0
  316. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +1 -0
  317. ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +1 -0
  318. ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-DqJsKb59.js +292 -0
  319. ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +1 -0
  320. ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-B6g4dtDi.js +106 -0
  321. ksadk/server/static/assets/index-8ipRcQ-M.js +240 -0
  322. ksadk/server/static/assets/index-ByFCqjlh.css +2 -0
  323. ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +1 -0
  324. ksadk/server/static/assets/infoDiagram-RXCK75RN-Djm_nbd5.js +2 -0
  325. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-DLOHGvWw.js → ishikawaDiagram-5VMMS53U-DWya9SG2.js} +6 -6
  326. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-BIzKeejT.js → journeyDiagram-EYS64GPL-DutxhSNI.js} +6 -6
  327. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-BWHoFSw2.js → kanban-definition-3QL26DDD-DJdOF8Fm.js} +10 -10
  328. ksadk/server/static/assets/katex-vFWytM5c.js +257 -0
  329. ksadk/server/static/assets/{linear-CvMBw9cA.js → linear-BHjG8b-J.js} +1 -1
  330. ksadk/server/static/assets/mermaid-parser.core-KGSy4jWT.js +166 -0
  331. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-CSAQxEAe.js → mindmap-definition-FBJOCRG2-9-HC88D4.js} +29 -29
  332. ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +1 -0
  333. ksadk/server/static/assets/pegDiagram-XKGWAZYB-DrEZd4fD.js +1 -0
  334. ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +1 -0
  335. ksadk/server/static/assets/pieDiagram-E7YTZNPT-DpjqOFFp.js +39 -0
  336. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-CxIR4JXI.js → quadrantDiagram-AXDQQJYC-BiNhgOXX.js} +6 -6
  337. ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +1 -0
  338. ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +1 -0
  339. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +1 -0
  340. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +1 -0
  341. ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +1 -0
  342. ksadk/server/static/assets/railroadDiagram-O6MQD6OU-_Y3Ojg6G.js +1 -0
  343. ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-DeCFdg9K.js +84 -0
  344. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-DpGa6EAV.js → sankeyDiagram-P5KCCOFB-CPH75rhw.js} +7 -7
  345. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-NTKNGGe5.js → sequenceDiagram-WJ2MYXX4-OEpQQdr4.js} +10 -10
  346. ksadk/server/static/assets/sizeCapture-X5ZJPWSS-heUErzhI.js +1 -0
  347. ksadk/server/static/assets/stateDiagram-HBIQ2CUA-DvA3jSMB.js +1 -0
  348. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +1 -0
  349. ksadk/server/static/assets/swimlanes-XN3QIQJK-CR-dfN_t.js +1 -0
  350. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +8 -0
  351. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-jqoYs3jQ.js → timeline-definition-24CTP7MA-DAVJf1TX.js} +7 -7
  352. ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +1 -0
  353. ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +1 -0
  354. ksadk/server/static/assets/vennDiagram-4TSXK5OY-DwM8eDkh.js +34 -0
  355. ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +1 -0
  356. ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DZL-Zz2t.js +78 -0
  357. ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js +7 -0
  358. ksadk/server/static/index.html +2 -2
  359. ksadk/sessions/__init__.py +26 -9
  360. ksadk/sessions/_local_service_sync.py +688 -0
  361. ksadk/sessions/_local_tables.py +21 -0
  362. ksadk/sessions/_postgres_schema.py +305 -0
  363. ksadk/sessions/_postgres_tables.py +15 -0
  364. ksadk/sessions/base.py +80 -1
  365. ksadk/sessions/in_memory.py +53 -2
  366. ksadk/sessions/local_service.py +63 -604
  367. ksadk/sessions/postgres_service.py +58 -148
  368. ksadk/sessions/resilient.py +35 -1
  369. ksadk/skills/runtime/backends/e2b.py +1 -1
  370. ksadk/skills/service_client.py +13 -3
  371. ksadk/studio/__init__.py +5 -0
  372. ksadk/studio/agent_avatar_assets.py +120 -0
  373. ksadk/studio/agent_lifecycle.py +51 -0
  374. ksadk/studio/api.py +1598 -0
  375. ksadk/studio/api_catalog_routes.py +324 -0
  376. ksadk/studio/api_contracts.py +286 -0
  377. ksadk/studio/api_helpers.py +132 -0
  378. ksadk/studio/api_memory_routes.py +82 -0
  379. ksadk/studio/authoring.py +749 -0
  380. ksadk/studio/authoring_coordinator.py +1017 -0
  381. ksadk/studio/builder.py +397 -0
  382. ksadk/studio/capabilities.py +368 -0
  383. ksadk/studio/cloud.py +2099 -0
  384. ksadk/studio/codex_agent_service.py +694 -0
  385. ksadk/studio/codex_authoring.py +469 -0
  386. ksadk/studio/codex_builder.py +437 -0
  387. ksadk/studio/codex_manifest.py +307 -0
  388. ksadk/studio/codex_run.py +395 -0
  389. ksadk/studio/compiler.py +190 -0
  390. ksadk/studio/contracts.py +755 -0
  391. ksadk/studio/errors.py +47 -0
  392. ksadk/studio/event_store.py +214 -0
  393. ksadk/studio/framework_run.py +342 -0
  394. ksadk/studio/hosted_kernel.py +317 -0
  395. ksadk/studio/identifiers.py +33 -0
  396. ksadk/studio/manifest_resolver.py +131 -0
  397. ksadk/studio/mcp_runtime.py +229 -0
  398. ksadk/studio/model_client.py +629 -0
  399. ksadk/studio/model_profile_service.py +214 -0
  400. ksadk/studio/operations.py +275 -0
  401. ksadk/studio/otel_trace.py +1060 -0
  402. ksadk/studio/pagination.py +182 -0
  403. ksadk/studio/pcm_memory.py +85 -0
  404. ksadk/studio/python_tool_inspection.py +183 -0
  405. ksadk/studio/repository.py +327 -0
  406. ksadk/studio/resource_catalog.py +1260 -0
  407. ksadk/studio/run_service.py +1133 -0
  408. ksadk/studio/runtime_catalog.py +74 -0
  409. ksadk/studio/runtime_source.py +365 -0
  410. ksadk/studio/service.py +2249 -0
  411. ksadk/studio/shared_web.py +1004 -0
  412. ksadk/studio/skill_discovery.py +628 -0
  413. ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
  414. ksadk/studio/static/assets/index-BLpcdrgW.css +1 -0
  415. ksadk/studio/static/assets/index-CYekR2Xv.js +260 -0
  416. ksadk/studio/static/assets/react-vendor-BNmTiJ-I.js +9 -0
  417. ksadk/studio/static/assets/rolldown-runtime-hePW80VL.js +1 -0
  418. ksadk/studio/static/index.html +15 -0
  419. ksadk/studio/templates.py +722 -0
  420. ksadk/studio/validator.py +265 -0
  421. ksadk/studio/workspace.py +135 -0
  422. ksadk/tools/gateway.py +9 -0
  423. ksadk/toolsets/__init__.py +27 -1
  424. ksadk/toolsets/a2a.py +426 -0
  425. ksadk/tracing/__init__.py +19 -21
  426. ksadk/tracing/setup.py +317 -403
  427. ksadk/tracing/span_utils.py +0 -44
  428. ksadk/version.py +1 -1
  429. ksadk_runtime_common/memory_backend/registry.py +56 -56
  430. ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
  431. ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
  432. ksadk_runtime_common/workspace_files/router.py +8 -2
  433. agentengine_sdk_python-0.8.0.dist-info/RECORD +0 -578
  434. ksadk/a2a/card_builder.py +0 -64
  435. ksadk/a2a/client.py +0 -309
  436. ksadk/events/parser.py +0 -191
  437. ksadk/harness/runner.py +0 -211
  438. ksadk/runners/codex_runner.py +0 -132
  439. ksadk/runners/utils/langfuse.py +0 -230
  440. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
  441. ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +0 -303
  442. ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +0 -1
  443. ksadk/server/static/assets/arc-CFKwSk_B.js +0 -1
  444. ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +0 -1
  445. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-Dej8jX8c.js +0 -36
  446. ksadk/server/static/assets/blockDiagram-GPEHLZMM-1F64jqvy.js +0 -132
  447. ksadk/server/static/assets/c4Diagram-AAUBKEIU-9q7AUAKb.js +0 -10
  448. ksadk/server/static/assets/channel-iUGv2N24.js +0 -1
  449. ksadk/server/static/assets/chunk-2J33WTMH-6qgwJm7Q.js +0 -1
  450. ksadk/server/static/assets/chunk-55IACEB6-BK8paA20.js +0 -1
  451. ksadk/server/static/assets/chunk-727SXJPM-B-JEhy7h.js +0 -206
  452. ksadk/server/static/assets/chunk-AQP2D5EJ-DYBvMHAa.js +0 -231
  453. ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +0 -1
  454. ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +0 -1
  455. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +0 -1
  456. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
  457. ksadk/server/static/assets/dagre-BM42HDAG-C7TguAWo.js +0 -4
  458. ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
  459. ksadk/server/static/assets/diagram-2AECGRRQ-Dd17_kws.js +0 -43
  460. ksadk/server/static/assets/diagram-5GNKFQAL-DVIClIil.js +0 -10
  461. ksadk/server/static/assets/diagram-KO2AKTUF-Df_3gYQa.js +0 -3
  462. ksadk/server/static/assets/diagram-LMA3HP47-BhLk6ZtA.js +0 -24
  463. ksadk/server/static/assets/diagram-OG6HWLK6-D4GNGvuu.js +0 -24
  464. ksadk/server/static/assets/dist-DyvYLMW9.js +0 -1
  465. ksadk/server/static/assets/erDiagram-TEJ5UH35-CnfRcY2M.js +0 -85
  466. ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +0 -1
  467. ksadk/server/static/assets/flowDiagram-I6XJVG4X-DGaJjGNJ.js +0 -162
  468. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-DpCoB2g9.js +0 -292
  469. ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +0 -1
  470. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-9IKVFBVT.js +0 -106
  471. ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
  472. ksadk/server/static/assets/index-QSwCHuB8.js +0 -177
  473. ksadk/server/static/assets/index-jOPmTOZH.css +0 -2
  474. ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +0 -1
  475. ksadk/server/static/assets/infoDiagram-5YYISTIA-CYIIsb8y.js +0 -2
  476. ksadk/server/static/assets/katex-DATssjp1.js +0 -265
  477. ksadk/server/static/assets/mermaid-parser.core-mGAcEwcq.js +0 -161
  478. ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +0 -1
  479. ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +0 -1
  480. ksadk/server/static/assets/pieDiagram-4H26LBE5-By-ra07M.js +0 -30
  481. ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +0 -1
  482. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DpW90iu3.js +0 -84
  483. ksadk/server/static/assets/stateDiagram-AJRCARHV-DGpd9yFG.js +0 -1
  484. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +0 -1
  485. ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +0 -1
  486. ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +0 -1
  487. ksadk/server/static/assets/vennDiagram-CIIHVFJN-l3Z7-wbP.js +0 -34
  488. ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +0 -1
  489. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-BR54GPmr.js +0 -78
  490. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-SkiH8GsK.js +0 -7
  491. ksadk/tracing/exporters/langfuse_exporter.py +0 -460
  492. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/entry_points.txt +0 -0
  493. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/licenses/LICENSE +0 -0
  494. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/top_level.txt +0 -0
ksadk/cli/cmd_openclaw.py CHANGED
@@ -41,6 +41,7 @@ from ksadk.builders.container_builder import (
41
41
  )
42
42
  from ksadk.cli.agent_ref import resolve_openclaw_ref
43
43
  from ksadk.cli.dry_run import dry_run_option, effective_dry_run, run_async_with_dry_run
44
+ from ksadk.cli.env_options import env_options, parse_env_pairs
44
45
  from ksadk.cli.error_utils import abort_with_cli_error, remote_error, resolution_error
45
46
  from ksadk.cli.model_catalog import fetch_provider_model_catalog, find_model_in_catalog
46
47
  from ksadk.cli.network_options import build_network_payload, network_cli_kwargs, network_options
@@ -77,9 +78,10 @@ from ksadk.cli.ui import (
77
78
  from ksadk.cli.ui import (
78
79
  output_option as cli_output_option,
79
80
  )
81
+ from ksadk.configs.env_registry import is_sensitive_env_var
80
82
  from ksadk.conversations.model_context import normalize_model_metadata
81
83
  from ksadk.deployment.agent_access import get_latest_agent_access
82
- from ksadk.model_policy import build_runtime_model_policy_env
84
+ from ksadk.cli.openclaw_env import _build_openclaw_env_vars, _normalize_openclaw_gateway_auth_env
83
85
  from ksadk.openclaw_gateway import (
84
86
  OpenClawGatewayClient,
85
87
  OpenClawGatewayError,
@@ -95,19 +97,9 @@ DEFAULT_OPENCLAW_REPO = "openclaw"
95
97
  DEFAULT_OPENCLAW_VERSION = "2026.6.1"
96
98
  DEFAULT_OPENCLAW_REGISTRY = "ghcr.io/kingsoftcloud"
97
99
  DEFAULT_OPENCLAW_NAME = "openclaw-gateway"
98
- DEFAULT_TRUSTED_PROXY_USER_HEADER = "x-forwarded-user"
99
- DEFAULT_TRUSTED_PROXY_CIDRS = [
100
- "127.0.0.1",
101
- "::1",
102
- "10.0.0.0/8",
103
- "172.16.0.0/12",
104
- "192.168.0.0/16",
105
- "35.0.0.0/8",
106
- ]
107
100
  _GLOBAL_ENV_CACHE: Optional[Dict[str, str]] = None
108
101
  OPENCLAW_SECURITY_PROFILES = ("relaxed", "strict", "strictest")
109
102
  OPENCLAW_CHANNELS = ("weixin", "feishu", "wps-xiezuo")
110
- OPENCLAW_ENV_KEY_PATTERN = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
111
103
  WEIXIN_PLUGIN_ID = "openclaw-weixin"
112
104
  FEISHU_PLUGIN_ID = "openclaw-lark"
113
105
  FEISHU_CHANNEL_KEY = "feishu"
@@ -385,33 +377,6 @@ def _openclaw_registry_env() -> dict[str, str]:
385
377
  return env
386
378
 
387
379
 
388
- def _resolve_model_base_url(cli_value: Optional[str]) -> Optional[str]:
389
- """解析模型 Base URL,缺失时回退到 settings.model.api_base(KSPMAS 自动探测)。"""
390
- if cli_value and str(cli_value).strip():
391
- return str(cli_value).strip()
392
-
393
- from_env = _resolve_env(
394
- "OPENCLAW_MODEL_BASE_URL",
395
- "OPENAI_BASE_URL",
396
- "OPENAI_API_BASE",
397
- "LLM_API_BASE",
398
- "MODEL_API_BASE",
399
- )
400
- if from_env:
401
- return from_env
402
-
403
- try:
404
- from ksadk.configs.settings import settings
405
-
406
- api_base = settings.model.api_base
407
- if api_base and str(api_base).strip():
408
- return str(api_base).strip()
409
- except Exception:
410
- pass
411
-
412
- return None
413
-
414
-
415
380
  def _summarize_openclaw_account(agents: list[Dict[str, Any]]) -> str:
416
381
  """汇总列表所属账号,优先使用响应字段,缺失时回退当前 CLI 上下文。"""
417
382
  accounts = sorted(
@@ -454,88 +419,6 @@ def _print_openclaw_list_summary(table: RichTable, summary_text: str) -> None:
454
419
  console.print(f"[muted]{summary_text}[/]")
455
420
 
456
421
 
457
- def _normalize_ui_locale(raw: Optional[str]) -> str:
458
- """标准化 UI 语言代码,默认 zh-CN。"""
459
- text = str(raw or "").strip()
460
- if not text:
461
- return "zh-CN"
462
-
463
- base = text.split(".", 1)[0].replace("_", "-").strip()
464
- low = base.lower()
465
-
466
- if low in {"c", "c-utf-8", "c.utf-8", "posix"}:
467
- return "zh-CN"
468
- if (
469
- low.startswith("zh-tw")
470
- or low.startswith("zh-hk")
471
- or low.startswith("zh-mo")
472
- or low.startswith("zh-hant")
473
- ):
474
- return "zh-TW"
475
- if low.startswith("zh"):
476
- return "zh-CN"
477
- if low.startswith("pt"):
478
- return "pt-BR"
479
- if low.startswith("de"):
480
- return "de"
481
- if low.startswith("en"):
482
- return "en"
483
-
484
- return "zh-CN"
485
-
486
-
487
- def _is_truthy(raw: Optional[str]) -> bool:
488
- text = str(raw or "").strip().lower()
489
- return text in {"1", "true", "yes", "on"}
490
-
491
-
492
- def _resolve_exec_profile_overrides(security_profile: Optional[str]) -> Dict[str, str]:
493
- """根据 CLI 安全预设返回 OpenClaw 运行时环境变量覆盖项。"""
494
- profile = str(security_profile or "").strip().lower()
495
- if not profile:
496
- return {}
497
-
498
- common = {
499
- "OPENCLAW_EXEC_HOST": "gateway",
500
- "OPENCLAW_EXEC_AUTO_ALLOW_SKILLS": "false",
501
- "OPENCLAW_ELEVATED_ENABLED": "false",
502
- }
503
- if profile == "relaxed":
504
- return {
505
- **common,
506
- "OPENCLAW_EXEC_STRICT_MODE": "false",
507
- "OPENCLAW_EXEC_UNSAFE_MODE": "true",
508
- "OPENCLAW_EXEC_SECURITY": "full",
509
- "OPENCLAW_EXEC_ASK": "off",
510
- "OPENCLAW_EXEC_ASK_FALLBACK": "full",
511
- "OPENCLAW_EXEC_DEFAULT_ALLOWLIST_ENABLED": "false",
512
- "OPENCLAW_FS_WORKSPACE_ONLY": "false",
513
- }
514
- if profile == "strict":
515
- return {
516
- **common,
517
- "OPENCLAW_EXEC_STRICT_MODE": "true",
518
- "OPENCLAW_EXEC_UNSAFE_MODE": "false",
519
- "OPENCLAW_EXEC_SECURITY": "allowlist",
520
- "OPENCLAW_EXEC_ASK": "off",
521
- "OPENCLAW_EXEC_ASK_FALLBACK": "allowlist",
522
- "OPENCLAW_EXEC_DEFAULT_ALLOWLIST_ENABLED": "true",
523
- "OPENCLAW_FS_WORKSPACE_ONLY": "false",
524
- }
525
- if profile == "strictest":
526
- return {
527
- **common,
528
- "OPENCLAW_EXEC_STRICT_MODE": "true",
529
- "OPENCLAW_EXEC_UNSAFE_MODE": "false",
530
- "OPENCLAW_EXEC_SECURITY": "deny",
531
- "OPENCLAW_EXEC_ASK": "off",
532
- "OPENCLAW_EXEC_ASK_FALLBACK": "deny",
533
- "OPENCLAW_EXEC_DEFAULT_ALLOWLIST_ENABLED": "false",
534
- "OPENCLAW_FS_WORKSPACE_ONLY": "true",
535
- }
536
- raise ValueError(f"unsupported OpenClaw security profile: {security_profile}")
537
-
538
-
539
422
  def _strip_provider_prefix(provider_id: str, model_id: str) -> str:
540
423
  provider = str(provider_id or "").strip()
541
424
  model = str(model_id or "").strip()
@@ -738,339 +621,14 @@ def _filter_openclaw_provider_catalog(
738
621
  return selected
739
622
 
740
623
 
741
- def _build_openclaw_env_vars(
742
- *,
743
- model_base_url: Optional[str] = None,
744
- model_api_key: Optional[str] = None,
745
- default_model: Optional[str] = None,
746
- model_provider_id: Optional[str] = None,
747
- gateway_port: Optional[str] = None,
748
- public_port: Optional[str] = None,
749
- security_profile: Optional[str] = None,
750
- ) -> dict:
751
- """构建 OpenClaw 所需的环境变量,自动复用 OPENAI_* 环境变量"""
752
- env = {}
753
- default_provider_id = "ksyun"
754
- default_model_api = "openai-completions"
755
- default_model_base_url = "https://kspmas.ksyun.com/v1"
756
- exec_profile_overrides = _resolve_exec_profile_overrides(security_profile)
757
-
758
- # 模型配置:客户端只透传用户显式配置和可选的 API Key;
759
- # 其余默认值交给镜像 bootstrap 兜底,避免创建请求把服务端默认行为短路掉。
760
- openclaw_explicit_model = default_model or _resolve_env("OPENCLAW_DEFAULT_MODEL")
761
- generic_model_preference = _resolve_env("OPENAI_MODEL_NAME", "MODEL_NAME", "LLM_MODEL")
762
- model_preference = openclaw_explicit_model or generic_model_preference
763
- explicit_base_url = model_base_url or _resolve_env(
764
- "OPENCLAW_MODEL_BASE_URL", "OPENAI_BASE_URL", "OPENAI_API_BASE"
765
- )
766
- base_url = _resolve_model_base_url(explicit_base_url)
767
- api_key = model_api_key or _resolve_env(
768
- "OPENCLAW_MODEL_API_KEY", "OPENAI_API_KEY", "LLM_API_KEY", "MODEL_API_KEY"
769
- )
770
- model = model_preference or "glm-5.2"
771
- explicit_provider_id = model_provider_id or _resolve_env("OPENCLAW_MODEL_PROVIDER_ID")
772
- inferred_provider_id = explicit_provider_id
773
- if not inferred_provider_id and model and "/" in model:
774
- inferred_provider_id = model.split("/", 1)[0].strip()
775
- provider_id = inferred_provider_id or default_provider_id
776
- resolved_gateway_port = gateway_port or _resolve_env("OPENCLAW_GATEWAY_PORT", "PORT") or "8080"
777
- resolved_public_port = public_port or _resolve_env("OPENCLAW_PUBLIC_PORT") or "80"
778
- explicit_model_api = _resolve_env("OPENCLAW_MODEL_API")
779
- model_api = explicit_model_api or default_model_api
780
- trusted_proxy_user_header = (
781
- (
782
- _resolve_env(
783
- "OPENCLAW_TRUSTED_PROXY_USER_HEADER",
784
- "OPENCLAW_GATEWAY_TRUSTED_PROXY_USER_HEADER",
785
- )
786
- or DEFAULT_TRUSTED_PROXY_USER_HEADER
787
- )
788
- .strip()
789
- .lower()
790
- )
791
- internal_trusted_proxy_user = (
792
- _resolve_env("OPENCLAW_INTERNAL_TRUSTED_PROXY_USER") or "openclaw-backend"
793
- )
794
- internal_trusted_proxy_user_header = (
795
- (
796
- _resolve_env("OPENCLAW_INTERNAL_TRUSTED_PROXY_USER_HEADER")
797
- or trusted_proxy_user_header
798
- or DEFAULT_TRUSTED_PROXY_USER_HEADER
799
- )
800
- .strip()
801
- .lower()
802
- )
803
- trusted_proxies = _normalize_csv_list(
804
- _resolve_env("OPENCLAW_TRUSTED_PROXIES") or "",
805
- default_items=DEFAULT_TRUSTED_PROXY_CIDRS,
806
- )
807
- browser_enabled = _resolve_env("OPENCLAW_BROWSER_ENABLED")
808
- browser_no_sandbox = _resolve_env("OPENCLAW_BROWSER_NO_SANDBOX") or "true"
809
- browser_headless = _resolve_env("OPENCLAW_BROWSER_HEADLESS") or "true"
810
- browser_executable = _resolve_env(
811
- "OPENCLAW_BROWSER_EXECUTABLE_PATH", "OPENCLAW_BROWSER_EXECUTABLE"
812
- )
813
- ui_locale = _normalize_ui_locale(_resolve_env("OPENCLAW_UI_LOCALE", "LANG", "LC_ALL"))
814
- exec_strict_mode_raw = (
815
- exec_profile_overrides.get("OPENCLAW_EXEC_STRICT_MODE")
816
- or _resolve_env("OPENCLAW_EXEC_STRICT_MODE", "OPENCLAW_EXEC_SAFE_MODE")
817
- or "false"
818
- )
819
- exec_strict_mode = _is_truthy(exec_strict_mode_raw)
820
-
821
- exec_host = (
822
- exec_profile_overrides.get("OPENCLAW_EXEC_HOST")
823
- or _resolve_env("OPENCLAW_EXEC_HOST")
824
- or "gateway"
825
- )
826
- exec_security = (
827
- exec_profile_overrides.get("OPENCLAW_EXEC_SECURITY")
828
- or _resolve_env("OPENCLAW_EXEC_SECURITY")
829
- or ("allowlist" if exec_strict_mode else "full")
830
- )
831
- exec_ask = (
832
- exec_profile_overrides.get("OPENCLAW_EXEC_ASK")
833
- or _resolve_env("OPENCLAW_EXEC_ASK")
834
- or "off"
835
- )
836
- exec_ask_fallback = (
837
- exec_profile_overrides.get("OPENCLAW_EXEC_ASK_FALLBACK")
838
- or _resolve_env("OPENCLAW_EXEC_ASK_FALLBACK")
839
- or ("allowlist" if exec_strict_mode else "full")
840
- )
841
- exec_auto_allow_skills = (
842
- exec_profile_overrides.get("OPENCLAW_EXEC_AUTO_ALLOW_SKILLS")
843
- or _resolve_env("OPENCLAW_EXEC_AUTO_ALLOW_SKILLS")
844
- or "false"
845
- )
846
- elevated_enabled = (
847
- exec_profile_overrides.get("OPENCLAW_ELEVATED_ENABLED")
848
- or _resolve_env("OPENCLAW_ELEVATED_ENABLED")
849
- or "false"
850
- )
851
- exec_default_allowlist_enabled = (
852
- exec_profile_overrides.get("OPENCLAW_EXEC_DEFAULT_ALLOWLIST_ENABLED")
853
- or _resolve_env("OPENCLAW_EXEC_DEFAULT_ALLOWLIST_ENABLED")
854
- or ("true" if exec_strict_mode else "false")
855
- )
856
- exec_allowlist = _resolve_env("OPENCLAW_EXEC_ALLOWLIST")
857
- fs_workspace_only = (
858
- exec_profile_overrides.get("OPENCLAW_FS_WORKSPACE_ONLY")
859
- or _resolve_env("OPENCLAW_FS_WORKSPACE_ONLY")
860
- or "false"
861
- )
862
- model_api_key_secret_source = _resolve_env("OPENCLAW_MODEL_API_KEY_SECRET_SOURCE") or "file"
863
- model_api_key_secret_file_path = _resolve_env("OPENCLAW_MODEL_API_KEY_SECRET_FILE_PATH")
864
- gateway_auth_mode = _resolve_env("OPENCLAW_GATEWAY_AUTH_MODE")
865
- gateway_token = _resolve_env("OPENCLAW_GATEWAY_TOKEN")
866
- gateway_password = _resolve_env("OPENCLAW_GATEWAY_PASSWORD")
867
-
868
- env["OPENCLAW_GATEWAY_BIND"] = "lan"
869
- if gateway_auth_mode:
870
- env["OPENCLAW_GATEWAY_AUTH_MODE"] = gateway_auth_mode
871
- env["OPENCLAW_TRUSTED_PROXY_USER_HEADER"] = (
872
- trusted_proxy_user_header or DEFAULT_TRUSTED_PROXY_USER_HEADER
873
- )
874
- env["OPENCLAW_INTERNAL_TRUSTED_PROXY_USER"] = internal_trusted_proxy_user
875
- env["OPENCLAW_INTERNAL_TRUSTED_PROXY_USER_HEADER"] = (
876
- internal_trusted_proxy_user_header
877
- or trusted_proxy_user_header
878
- or DEFAULT_TRUSTED_PROXY_USER_HEADER
879
- )
880
- env["OPENCLAW_TRUSTED_PROXIES"] = trusted_proxies
881
- env["OPENCLAW_GATEWAY_PORT"] = str(resolved_gateway_port)
882
- env["OPENCLAW_PUBLIC_PORT"] = str(resolved_public_port)
883
- if browser_enabled:
884
- env["OPENCLAW_BROWSER_ENABLED"] = browser_enabled
885
- env["OPENCLAW_BROWSER_NO_SANDBOX"] = browser_no_sandbox
886
- env["OPENCLAW_BROWSER_HEADLESS"] = browser_headless
887
- if browser_executable:
888
- env["OPENCLAW_BROWSER_EXECUTABLE_PATH"] = browser_executable
889
- env["OPENCLAW_UI_LOCALE"] = ui_locale
890
- env["OPENCLAW_EXEC_HOST"] = exec_host
891
- env["OPENCLAW_EXEC_STRICT_MODE"] = "true" if exec_strict_mode else "false"
892
- env["OPENCLAW_EXEC_UNSAFE_MODE"] = "false" if exec_strict_mode else "true"
893
- env["OPENCLAW_EXEC_SECURITY"] = exec_security
894
- env["OPENCLAW_EXEC_ASK"] = exec_ask
895
- env["OPENCLAW_EXEC_ASK_FALLBACK"] = exec_ask_fallback
896
- env["OPENCLAW_EXEC_AUTO_ALLOW_SKILLS"] = exec_auto_allow_skills
897
- env["OPENCLAW_ELEVATED_ENABLED"] = elevated_enabled
898
- env["OPENCLAW_EXEC_DEFAULT_ALLOWLIST_ENABLED"] = exec_default_allowlist_enabled
899
- env["OPENCLAW_FS_WORKSPACE_ONLY"] = fs_workspace_only
900
- env["OPENCLAW_MODEL_API_KEY_SECRET_SOURCE"] = model_api_key_secret_source
901
- if exec_allowlist:
902
- env["OPENCLAW_EXEC_ALLOWLIST"] = exec_allowlist
903
- if model_api_key_secret_file_path:
904
- env["OPENCLAW_MODEL_API_KEY_SECRET_FILE_PATH"] = model_api_key_secret_file_path
905
-
906
- if explicit_provider_id and provider_id != default_provider_id:
907
- env["OPENCLAW_MODEL_PROVIDER_ID"] = provider_id
908
- elif not explicit_provider_id and provider_id and provider_id != default_provider_id:
909
- env["OPENCLAW_MODEL_PROVIDER_ID"] = provider_id
910
- if explicit_model_api and model_api != default_model_api:
911
- env["OPENCLAW_MODEL_API"] = model_api
912
- if explicit_base_url and base_url and base_url != default_model_base_url:
913
- env["OPENCLAW_MODEL_BASE_URL"] = base_url
914
- if api_key:
915
- env["OPENCLAW_MODEL_API_KEY"] = api_key
916
- normalized_model = model.strip() if model else None
917
- catalog_model_id = None
918
- resolved_model = None
919
- if normalized_model:
920
- if "/" in normalized_model:
921
- _, catalog_model_id = normalized_model.split("/", 1)
922
- resolved_model = normalized_model
923
- else:
924
- resolved_model = (
925
- f"{provider_id}/{normalized_model}" if provider_id else normalized_model
926
- )
927
- if openclaw_explicit_model:
928
- env["OPENCLAW_DEFAULT_MODEL"] = resolved_model
929
- elif generic_model_preference:
930
- env["OPENAI_MODEL_NAME"] = resolved_model
931
-
932
- # 额外的可选配置
933
- catalog = _resolve_env("OPENCLAW_MODEL_CATALOG_JSON")
934
- if catalog:
935
- env["OPENCLAW_MODEL_CATALOG_JSON"] = catalog
936
- openclaw_model_allowlist = _resolve_env("OPENCLAW_MODEL_ALLOWLIST")
937
- agentengine_model_allowlist = _resolve_env("AGENTENGINE_MODEL_ALLOWLIST")
938
- if openclaw_model_allowlist:
939
- env["OPENCLAW_MODEL_ALLOWLIST"] = openclaw_model_allowlist
940
- elif agentengine_model_allowlist:
941
- env["AGENTENGINE_MODEL_ALLOWLIST"] = agentengine_model_allowlist
942
- origins = _resolve_env("OPENCLAW_ALLOWED_ORIGINS")
943
- if origins:
944
- env["OPENCLAW_ALLOWED_ORIGINS"] = _normalize_allowed_origins(origins)
945
- else:
946
- # 统一输出 JSON 数组字符串,兼容旧版 bootstrap(仅支持 JSON.parse)。
947
- env["OPENCLAW_ALLOWED_ORIGINS"] = json.dumps(["*"])
948
- allow_insecure_auth = _resolve_env("OPENCLAW_ALLOW_INSECURE_AUTH")
949
- env["OPENCLAW_ALLOW_INSECURE_AUTH"] = allow_insecure_auth if allow_insecure_auth else "true"
950
- disable_device_auth = _resolve_env("OPENCLAW_DISABLE_DEVICE_AUTH")
951
- env["OPENCLAW_DISABLE_DEVICE_AUTH"] = disable_device_auth if disable_device_auth else "true"
952
- if gateway_token:
953
- env["OPENCLAW_GATEWAY_TOKEN"] = gateway_token
954
- if gateway_password:
955
- env["OPENCLAW_GATEWAY_PASSWORD"] = gateway_password
956
- for passthrough_key in [
957
- "OPENCLAW_CHANNEL_BOOTSTRAP_JSON",
958
- "OPENCLAW_BROWSER_SSRF_POLICY_JSON",
959
- "OPENCLAW_WEB_FETCH_ENABLED",
960
- "OPENCLAW_WEB_SEARCH_PROVIDER",
961
- "OPENCLAW_WEB_SEARCH_BASE_URL",
962
- "OPENCLAW_WEB_SEARCH_MODEL",
963
- "OPENCLAW_WEB_SEARCH_API_KEY",
964
- "OPENCLAW_WEB_SEARCH_API_KEY_SECRET_SOURCE",
965
- "OPENCLAW_WEB_SEARCH_API_KEY_SECRET_PROVIDER",
966
- "OPENCLAW_WEB_SEARCH_API_KEY_SECRET_ID",
967
- ]:
968
- passthrough_value = _resolve_env(passthrough_key)
969
- if passthrough_value:
970
- env[passthrough_key] = passthrough_value
971
-
972
- env = _normalize_openclaw_gateway_auth_env(env)
973
- return build_runtime_model_policy_env(env, runtime="openclaw")
974
-
975
-
976
- def _normalize_allowed_origins(raw: str) -> str:
977
- """标准化 OPENCLAW_ALLOWED_ORIGINS,统一输出 JSON 数组字符串。"""
978
- text = (raw or "").strip()
979
- if not text:
980
- return ""
981
-
982
- origins = []
983
- try:
984
- parsed = json.loads(text)
985
- if isinstance(parsed, list):
986
- origins = [str(x).strip() for x in parsed if str(x).strip()]
987
- except Exception:
988
- # Backward compatible: 支持逗号/分号/空白分隔字符串。
989
- parts = [p.strip() for p in text.replace(";", ",").replace(" ", ",").split(",")]
990
- origins = [p.strip() for p in parts if p.strip()]
991
-
992
- if not origins:
993
- origins = [text]
994
-
995
- deduped = list(dict.fromkeys(origins))
996
- return json.dumps(deduped, ensure_ascii=False)
997
-
998
-
999
- def _normalize_csv_list(raw: str, *, default_items: Optional[list[str]] = None) -> str:
1000
- """标准化字符串列表为逗号分隔格式。"""
1001
- text = (raw or "").strip()
1002
- items: list[str] = []
1003
- if text:
1004
- try:
1005
- parsed = json.loads(text)
1006
- if isinstance(parsed, list):
1007
- items = [str(x).strip() for x in parsed if str(x).strip()]
1008
- except Exception:
1009
- parts = [p.strip() for p in text.replace(";", ",").replace(" ", ",").split(",")]
1010
- items = [p for p in parts if p]
1011
-
1012
- if not items:
1013
- items = [str(x).strip() for x in (default_items or []) if str(x).strip()]
1014
-
1015
- return ",".join(list(dict.fromkeys(items)))
1016
-
1017
-
1018
- def _normalize_openclaw_gateway_auth_env(env: dict[str, str]) -> dict[str, str]:
1019
- """标准化 OpenClaw gateway 鉴权模式与共享密钥配置。"""
1020
- normalized_env = dict(env or {})
1021
- raw_mode = str(normalized_env.get("OPENCLAW_GATEWAY_AUTH_MODE") or "").strip().lower()
1022
- raw_token = str(normalized_env.get("OPENCLAW_GATEWAY_TOKEN") or "").strip()
1023
- raw_password = str(normalized_env.get("OPENCLAW_GATEWAY_PASSWORD") or "").strip()
1024
-
1025
- if raw_mode and raw_mode not in {"trusted-proxy", "token", "none"}:
1026
- raise ValueError("OPENCLAW_GATEWAY_AUTH_MODE 仅支持 trusted-proxy、token 或 none")
1027
-
1028
- auth_mode = raw_mode or ("token" if raw_token or raw_password else "trusted-proxy")
1029
- if auth_mode == "token":
1030
- if raw_token and raw_password and raw_token != raw_password:
1031
- raise ValueError(
1032
- "OPENCLAW_GATEWAY_TOKEN 与 OPENCLAW_GATEWAY_PASSWORD 同时提供时必须一致"
1033
- )
1034
- shared_secret = raw_token or raw_password
1035
- if not shared_secret:
1036
- raise ValueError(
1037
- "OPENCLAW_GATEWAY_AUTH_MODE=token 时必须提供 "
1038
- "OPENCLAW_GATEWAY_TOKEN 或 OPENCLAW_GATEWAY_PASSWORD"
1039
- )
1040
- normalized_env["OPENCLAW_GATEWAY_AUTH_MODE"] = "token"
1041
- normalized_env["OPENCLAW_GATEWAY_TOKEN"] = shared_secret
1042
- normalized_env["OPENCLAW_GATEWAY_PASSWORD"] = shared_secret
1043
- return normalized_env
1044
-
1045
- if raw_token or raw_password:
1046
- raise ValueError(
1047
- "仅在 OPENCLAW_GATEWAY_AUTH_MODE=token 时支持 "
1048
- "OPENCLAW_GATEWAY_TOKEN 或 OPENCLAW_GATEWAY_PASSWORD"
1049
- )
1050
-
1051
- normalized_env["OPENCLAW_GATEWAY_AUTH_MODE"] = auth_mode
1052
- normalized_env.pop("OPENCLAW_GATEWAY_TOKEN", None)
1053
- normalized_env.pop("OPENCLAW_GATEWAY_PASSWORD", None)
1054
- return normalized_env
1055
-
1056
-
1057
624
  def _parse_extra_openclaw_env_pairs(items: tuple[str, ...] | list[str] | None) -> dict[str, str]:
1058
- """解析 deploy --env 传入的自定义环境变量。"""
1059
- parsed: dict[str, str] = {}
1060
- for raw_item in items or ():
1061
- item = str(raw_item or "").strip()
1062
- if not item or "=" not in item:
1063
- raise ValueError(f"自定义环境变量格式错误: {raw_item!r},应为 KEY=VALUE")
1064
- key, value = item.split("=", 1)
1065
- key = key.strip()
1066
- if not OPENCLAW_ENV_KEY_PATTERN.fullmatch(key):
1067
- raise ValueError(f"自定义环境变量名不合法: {key!r},请使用合法的环境变量名")
1068
- if key == "OPENCLAW_GATEWAY_AUTH_MODE":
1069
- normalized = value.strip().lower()
1070
- if normalized not in {"trusted-proxy", "token", "none"}:
1071
- raise ValueError("OPENCLAW_GATEWAY_AUTH_MODE 仅支持 trusted-proxy、token 或 none")
1072
- value = normalized
1073
- parsed[key] = value
625
+ """解析 deploy --env 传入的自定义环境变量,并对 gateway 鉴权模式做早期归一化。"""
626
+ parsed = parse_env_pairs(items)
627
+ if "OPENCLAW_GATEWAY_AUTH_MODE" in parsed:
628
+ normalized = parsed["OPENCLAW_GATEWAY_AUTH_MODE"].strip().lower()
629
+ if normalized not in {"trusted-proxy", "token", "none"}:
630
+ raise ValueError("OPENCLAW_GATEWAY_AUTH_MODE 仅支持 trusted-proxy、token 或 none")
631
+ parsed["OPENCLAW_GATEWAY_AUTH_MODE"] = normalized
1074
632
  return parsed
1075
633
 
1076
634
 
@@ -3388,17 +2946,21 @@ def channel_doctor(
3388
2946
  @click.option("--mem0-instance-id", default=None, help="mem0 实例 ID")
3389
2947
  @click.option("--mem0-instance-name", default=None, help="mem0 实例名称(可选)")
3390
2948
  @click.option("--mem0-region", default=None, help="mem0 实例区域(可选)")
3391
- @click.option(
3392
- "--env",
3393
- "extra_env",
3394
- multiple=True,
3395
- help="额外透传自定义环境变量,格式 KEY=VALUE,可重复传入",
3396
- )
2949
+ @env_options
3397
2950
  @click.option("--storage-size-gi", type=int, default=20, show_default=True, help="PVC 容量(Gi)")
3398
2951
  @click.option(
3399
2952
  "--storage-mount-path", default=None, help="PVC 挂载目录(默认: /home/node/.openclaw)"
3400
2953
  )
3401
2954
  @click.option("--no-storage", is_flag=True, help="禁用默认 PVC 挂载")
2955
+ @click.option(
2956
+ "--agent-id",
2957
+ "agent_id_opt",
2958
+ default=None,
2959
+ help=(
2960
+ "指定要更新的已有 Agent ID;当前凭证有权限时会自动回填 "
2961
+ ".agentengine.state 并走热更新(用于本地状态丢失后重新关联)"
2962
+ ),
2963
+ )
3402
2964
  @network_options
3403
2965
  @dry_run_option("仅显示请求,不实际部署")
3404
2966
  def deploy(
@@ -3414,9 +2976,11 @@ def deploy(
3414
2976
  mem0_instance_name: Optional[str],
3415
2977
  mem0_region: Optional[str],
3416
2978
  extra_env: tuple[str, ...],
2979
+ env_file: Optional[str],
3417
2980
  storage_size_gi: int,
3418
2981
  storage_mount_path: Optional[str],
3419
2982
  no_storage: bool,
2983
+ agent_id_opt: Optional[str],
3420
2984
  enable_public_access: Optional[bool],
3421
2985
  enable_vpc_access: bool,
3422
2986
  vpc_id: Optional[str],
@@ -3456,6 +3020,7 @@ def deploy(
3456
3020
  _option_was_explicit(ctx, "model_api_key"),
3457
3021
  _option_was_explicit(ctx, "default_model"),
3458
3022
  bool(extra_env),
3023
+ _option_was_explicit(ctx, "env_file"),
3459
3024
  )
3460
3025
  )
3461
3026
  include_storage_on_update = any(
@@ -3486,9 +3051,11 @@ def deploy(
3486
3051
  mem0_instance_name=mem0_instance_name,
3487
3052
  mem0_region=mem0_region,
3488
3053
  extra_env=extra_env,
3054
+ env_file=env_file,
3489
3055
  storage_size_gi=storage_size_gi,
3490
3056
  storage_mount_path=storage_mount_path,
3491
3057
  no_storage=no_storage,
3058
+ agent_id_opt=agent_id_opt,
3492
3059
  include_env_on_update=include_env_on_update,
3493
3060
  include_storage_on_update=include_storage_on_update,
3494
3061
  **network_cli_kwargs(
@@ -3521,9 +3088,11 @@ async def _deploy_openclaw(
3521
3088
  mem0_instance_name: Optional[str],
3522
3089
  mem0_region: Optional[str],
3523
3090
  extra_env: tuple[str, ...] = (),
3091
+ env_file: Optional[str] = None,
3524
3092
  storage_size_gi: int = 20,
3525
3093
  storage_mount_path: Optional[str] = None,
3526
3094
  no_storage: bool = False,
3095
+ agent_id_opt: Optional[str] = None,
3527
3096
  include_env_on_update: bool = False,
3528
3097
  include_storage_on_update: bool = False,
3529
3098
  enable_public_access: Optional[bool] = None,
@@ -3535,27 +3104,26 @@ async def _deploy_openclaw(
3535
3104
  dry_run: bool,
3536
3105
  ):
3537
3106
  """异步部署 OpenClaw"""
3538
- from dotenv import dotenv_values
3539
-
3540
3107
  from ksadk.api import AgentEngineClient
3108
+ from ksadk.cli.env_options import (
3109
+ apply_explicit_env_with_shell_priority,
3110
+ inject_env_to_environ,
3111
+ resolve_runtime_env_overrides,
3112
+ )
3541
3113
  from ksadk.deployment.state import clear_state, load_state, save_state
3542
3114
 
3543
- # 自动加载当前目录 .env(仅补充未导出的变量,不覆盖已导出的 shell 环境)
3115
+ # 自动加载当前目录 .env 或 --env-file 指定文件(优先级: --env > --env-file > shell > .env)
3544
3116
  project_dir = Path(".").resolve()
3545
- env_file = project_dir / ".env"
3546
- if env_file.exists():
3547
- try:
3548
- loaded = 0
3549
- for k, v in dotenv_values(env_file).items():
3550
- if not k or v is None:
3551
- continue
3552
- if os.getenv(k) is None:
3553
- os.environ[k] = str(v)
3554
- loaded += 1
3555
- if loaded:
3556
- print_info(f"已从 .env 注入环境变量: {loaded} 项")
3557
- except Exception as e:
3558
- print_warn(f"读取 .env 失败,将继续使用当前 shell 环境: {e}")
3117
+ cli_env, auto_dotenv, shell_keys, env_source = resolve_runtime_env_overrides(
3118
+ env_file=env_file,
3119
+ extra_env=extra_env,
3120
+ base_dir=project_dir,
3121
+ )
3122
+ loaded = inject_env_to_environ(cli_env, auto_dotenv, shell_keys)
3123
+ if loaded:
3124
+ print_info(f"已从 {env_source or '--env'} 注入环境变量: {loaded} 项")
3125
+ if cli_env or auto_dotenv:
3126
+ include_env_on_update = True
3559
3127
 
3560
3128
  # 读取本地状态 (判断创建 vs 更新)
3561
3129
  state = load_state(project_dir)
@@ -3565,6 +3133,14 @@ async def _deploy_openclaw(
3565
3133
  if state_kind == "openclaw":
3566
3134
  existing_agent_id = state.get("agent_id")
3567
3135
  state_name = str(state.get("name") or "").strip() or None
3136
+ explicit_agent_id = (agent_id_opt or "").strip() or None
3137
+ if explicit_agent_id:
3138
+ if existing_agent_id and existing_agent_id != explicit_agent_id:
3139
+ print_info(
3140
+ f"--agent-id ({explicit_agent_id}) 与本地状态 "
3141
+ f"({existing_agent_id}) 不一致,以 --agent-id 为准"
3142
+ )
3143
+ existing_agent_id = explicit_agent_id
3568
3144
 
3569
3145
  if name:
3570
3146
  openclaw_name = name
@@ -3592,9 +3168,8 @@ async def _deploy_openclaw(
3592
3168
  default_model=default_model,
3593
3169
  security_profile=security_profile,
3594
3170
  )
3595
- custom_env_vars = _parse_extra_openclaw_env_pairs(extra_env)
3596
- if custom_env_vars:
3597
- env_vars.update(custom_env_vars)
3171
+ if cli_env or auto_dotenv:
3172
+ apply_explicit_env_with_shell_priority(env_vars, cli_env, auto_dotenv, shell_keys)
3598
3173
  env_vars = _normalize_openclaw_gateway_auth_env(env_vars)
3599
3174
  if not str(env_vars.get("OPENCLAW_MODEL_CATALOG_JSON") or "").strip():
3600
3175
  catalog_api_base = model_base_url or _resolve_env(
@@ -3636,7 +3211,7 @@ async def _deploy_openclaw(
3636
3211
 
3637
3212
  # 构建环境变量列表
3638
3213
  env_list = [
3639
- {"Key": k, "Value": v, "IsSensitive": "KEY" in k or "TOKEN" in k or "SECRET" in k}
3214
+ {"Key": k, "Value": v, "IsSensitive": is_sensitive_env_var(k)}
3640
3215
  for k, v in env_vars.items()
3641
3216
  ]
3642
3217
  # 资源规格(支持通过环境变量覆盖)
@@ -3744,6 +3319,37 @@ async def _deploy_openclaw(
3744
3319
  latest_status = None
3745
3320
  updated_existing_agent = False
3746
3321
  async with AgentEngineClient(region=region) as client:
3322
+ if explicit_agent_id:
3323
+ try:
3324
+ detail = await client.get_agent(
3325
+ explicit_agent_id, include_api_key=True
3326
+ )
3327
+ except Exception as e:
3328
+ raise click.ClickException(
3329
+ f"指定的 Agent ID '{explicit_agent_id}' 不存在,或当前凭证无权限访问。\n"
3330
+ f" 详情: {e}\n"
3331
+ " 👉 请确认 agent_id 正确,且当前 AK/SK / 账号有该 Agent 的权限。"
3332
+ ) from e
3333
+ qa = detail.get("quick_access", {}) or {}
3334
+ basic = detail.get("basic", {}) or {}
3335
+ recovered_state = state.copy()
3336
+ recovered_state.update(
3337
+ {
3338
+ "agent_id": explicit_agent_id,
3339
+ "name": basic.get("name") or openclaw_name,
3340
+ "type": "openclaw",
3341
+ "region": region,
3342
+ "endpoint": qa.get("public_endpoint"),
3343
+ }
3344
+ )
3345
+ if qa.get("api_key"):
3346
+ recovered_state["api_key"] = qa["api_key"]
3347
+ recovered_state = {
3348
+ k: v for k, v in recovered_state.items() if v is not None
3349
+ }
3350
+ save_state(project_dir, recovered_state)
3351
+ state = recovered_state
3352
+ print_info(f"已通过 --agent-id 关联已有 Agent: {explicit_agent_id}")
3747
3353
  if existing_agent_id:
3748
3354
  print_info(f"检测到本地状态: {existing_agent_id},执行更新...")
3749
3355
  try: