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.
- {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +41 -23
- agentengine_sdk_python-0.8.0.dist-info/RECORD +578 -0
- ksadk/a2a/__init__.py +178 -11
- ksadk/a2a/bootstrap.py +334 -0
- ksadk/a2a/card.py +120 -0
- ksadk/a2a/context_store.py +203 -0
- ksadk/a2a/control_plane.py +818 -0
- ksadk/a2a/credential.py +99 -0
- ksadk/a2a/event_adapter.py +149 -0
- ksadk/a2a/executor.py +406 -89
- ksadk/a2a/external_transport.py +516 -0
- ksadk/a2a/identity.py +304 -0
- ksadk/a2a/ids.py +22 -0
- ksadk/a2a/langgraph.py +285 -0
- ksadk/a2a/resume_store.py +201 -0
- ksadk/a2a/routes.py +105 -0
- ksadk/a2a/server.py +107 -60
- ksadk/a2a/space_client.py +1101 -0
- ksadk/a2a/task_adapter.py +423 -0
- ksadk/a2a/task_event_dispatcher.py +167 -0
- ksadk/a2a/task_event_outbox.py +326 -0
- ksadk/a2a/task_store.py +206 -0
- ksadk/a2ui/__init__.py +27 -0
- ksadk/a2ui/core.py +186 -0
- ksadk/a2ui/models.py +166 -0
- ksadk/a2ui/renderer.py +198 -0
- ksadk/agui/__init__.py +9 -0
- ksadk/agui/a2ui_projection.py +92 -0
- ksadk/agui/agent.py +857 -0
- ksadk/agui/config.py +86 -0
- ksadk/agui/routes.py +55 -0
- ksadk/api/client.py +252 -191
- ksadk/builders/__init__.py +2 -0
- ksadk/builders/base.py +16 -14
- ksadk/builders/code_builder.py +318 -236
- ksadk/builders/container_builder.py +187 -167
- ksadk/builders/framework_requirements.py +29 -11
- ksadk/builders/ks3_uploader.py +58 -27
- ksadk/builders/managed_runtime_builder.py +145 -0
- ksadk/builders/mcp_builder.py +91 -92
- ksadk/builders/requirements_utils.py +1 -5
- ksadk/cli/__init__.py +89 -171
- ksadk/cli/cmd_a2a.py +254 -70
- ksadk/cli/cmd_agent.py +19 -5
- ksadk/cli/cmd_build.py +158 -29
- ksadk/cli/cmd_completion.py +47 -35
- ksadk/cli/cmd_config.py +267 -198
- ksadk/cli/cmd_create.py +533 -726
- ksadk/cli/cmd_dashboard.py +120 -45
- ksadk/cli/cmd_deploy.py +117 -58
- ksadk/cli/cmd_destroy.py +44 -14
- ksadk/cli/cmd_files.py +63 -24
- ksadk/cli/cmd_hermes.py +173 -90
- ksadk/cli/cmd_invoke.py +388 -159
- ksadk/cli/cmd_launch.py +64 -28
- ksadk/cli/cmd_mcp.py +103 -64
- ksadk/cli/cmd_model.py +14 -5
- ksadk/cli/cmd_openclaw.py +488 -228
- ksadk/cli/cmd_replay.py +71 -0
- ksadk/cli/cmd_run.py +44 -14
- ksadk/cli/cmd_status.py +80 -31
- ksadk/cli/cmd_version.py +20 -13
- ksadk/cli/cmd_web.py +89 -13
- ksadk/cli/deploy_utils.py +20 -20
- ksadk/cli/dry_run.py +5 -3
- ksadk/cli/error_utils.py +37 -12
- ksadk/cli/global_options.py +1 -2
- ksadk/cli/local_runtime.py +1 -2
- ksadk/cli/model_catalog.py +6 -2
- ksadk/cli/network_options.py +38 -16
- ksadk/cli/resource_common.py +6 -2
- ksadk/cli/storage.py +0 -1
- ksadk/cli/ui.py +5 -3
- ksadk/cli/workflow_common.py +51 -17
- ksadk/codex/__init__.py +12 -0
- ksadk/codex/client.py +408 -0
- ksadk/codex/phase.py +143 -0
- ksadk/codex/runtime.py +449 -0
- ksadk/common/aicp_env.py +0 -1
- ksadk/common/auth.py +2 -2
- ksadk/common/constants.py +1 -3
- ksadk/common/llm_utils.py +17 -13
- ksadk/compat/__init__.py +5 -0
- ksadk/compat/adk_compat.py +200 -0
- ksadk/compat/copilotkit_a2ui.py +330 -0
- ksadk/configs/__init__.py +12 -12
- ksadk/configs/env_registry.py +501 -100
- ksadk/configs/global_config.py +2 -1
- ksadk/configs/settings.py +151 -124
- ksadk/conversations/__init__.py +7 -5
- ksadk/conversations/attachment_storage.py +16 -11
- ksadk/conversations/attachments.py +44 -36
- ksadk/conversations/compaction_pipeline.py +12 -12
- ksadk/conversations/compaction_prompt.py +9 -5
- ksadk/conversations/context.py +221 -6
- ksadk/conversations/message_projection.py +656 -0
- ksadk/conversations/model_context.py +22 -6
- ksadk/conversations/model_options.py +0 -1
- ksadk/conversations/normalize.py +20 -16
- ksadk/conversations/reasoning_markup.py +1 -1
- ksadk/conversations/runtime.py +339 -5187
- ksadk/conversations/runtime_compaction.py +333 -0
- ksadk/conversations/runtime_constants.py +27 -0
- ksadk/conversations/runtime_governance.py +185 -0
- ksadk/conversations/runtime_input.py +652 -0
- ksadk/conversations/runtime_invocation.py +395 -0
- ksadk/conversations/runtime_metadata.py +475 -0
- ksadk/conversations/runtime_observability.py +355 -0
- ksadk/conversations/runtime_payloads.py +272 -0
- ksadk/conversations/runtime_persistence.py +440 -0
- ksadk/conversations/runtime_preparation.py +418 -0
- ksadk/conversations/runtime_resume.py +816 -0
- ksadk/conversations/runtime_stream_events.py +902 -0
- ksadk/conversations/runtime_streaming.py +547 -0
- ksadk/conversations/semantic_summary.py +17 -5
- ksadk/conversations/session_title.py +6 -3
- ksadk/deployment/__init__.py +15 -16
- ksadk/deployment/agent_access.py +12 -23
- ksadk/deployment/base.py +52 -39
- ksadk/deployment/manager.py +63 -65
- ksadk/deployment/providers/serverless.py +326 -209
- ksadk/deployment/registry.py +38 -32
- ksadk/deployment/state.py +11 -11
- ksadk/deployment/ui_config.py +1 -1
- ksadk/detection/__init__.py +1 -1
- ksadk/detection/detector.py +146 -83
- ksadk/detection/mcp_detector.py +9 -6
- ksadk/events/__init__.py +25 -0
- ksadk/events/parser.py +191 -0
- ksadk/events/replay.py +37 -0
- ksadk/events/runtime_event.py +264 -0
- ksadk/events/store.py +317 -0
- ksadk/harness/__init__.py +34 -0
- ksadk/harness/app.py +278 -0
- ksadk/harness/config.py +181 -0
- ksadk/harness/reasoner.py +105 -0
- ksadk/harness/runner.py +211 -0
- ksadk/harness/sandbox.py +141 -0
- ksadk/harness/tools.py +222 -0
- ksadk/hermes_terminal.py +23 -12
- ksadk/identity/resolver.py +15 -9
- ksadk/ids.py +32 -0
- ksadk/knowledge_base/adk_tool.py +1 -1
- ksadk/knowledge_base/client.py +23 -29
- ksadk/managed_runtime.py +188 -0
- ksadk/markdown.py +5 -2
- ksadk/mcp_runtime/__init__.py +9 -6
- ksadk/memory/__init__.py +1 -1
- ksadk/memory/adk/__init__.py +2 -0
- ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
- ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
- ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
- ksadk/memory/adk/backends/sdk_ltm_backend.py +26 -33
- ksadk/memory/adk/long_term_memory.py +31 -35
- ksadk/memory/adk/resilient_session_service.py +267 -0
- ksadk/memory/adk/short_term_memory.py +33 -27
- ksadk/memory/adk_tool.py +3 -2
- ksadk/memory/backends/base.py +19 -19
- ksadk/memory/backends/memory.py +24 -25
- ksadk/memory/backends/redis.py +31 -30
- ksadk/memory/langchain_tool.py +2 -1
- ksadk/memory/manager.py +52 -47
- ksadk/memory/service.py +10 -8
- ksadk/model_policy.py +15 -7
- ksadk/model_proxy/__init__.py +51 -0
- ksadk/model_proxy/bootstrap.py +80 -0
- ksadk/model_proxy/cache.py +165 -0
- ksadk/model_proxy/config.py +45 -0
- ksadk/model_proxy/demo_webui.py +115 -0
- ksadk/model_proxy/detect.py +145 -0
- ksadk/model_proxy/gate.py +68 -0
- ksadk/model_proxy/namespace.py +173 -0
- ksadk/model_proxy/protocol_proxy.py +22 -0
- ksadk/model_proxy/server.py +300 -0
- ksadk/model_proxy/transform.py +691 -0
- ksadk/openclaw_gateway.py +29 -14
- ksadk/runners/adk_runner.py +1248 -164
- ksadk/runners/base_runner.py +46 -29
- ksadk/runners/codex_runner.py +132 -0
- ksadk/runners/deepagents_runner.py +0 -1
- ksadk/runners/factory.py +17 -5
- ksadk/runners/langchain_runner.py +29 -530
- ksadk/runners/langgraph_runner.py +490 -95
- ksadk/runners/patch_langchain.py +16 -16
- ksadk/runners/remote_runner.py +264 -38
- ksadk/runners/usage_accumulator.py +1 -0
- ksadk/runners/utils/langfuse.py +3 -3
- ksadk/runners/utils/loader.py +7 -7
- ksadk/runtime/__init__.py +41 -0
- ksadk/runtime/adapter.py +345 -0
- ksadk/runtime/framework_adapters.py +124 -0
- ksadk/runtime/preprocessing.py +118 -0
- ksadk/runtime/runner_adapter.py +873 -0
- ksadk/runtime_context.py +18 -3
- ksadk/runtime_state.py +0 -1
- ksadk/sandbox/__init__.py +4 -1
- ksadk/sandbox/backends/__init__.py +4 -1
- ksadk/sandbox/backends/e2b.py +13 -5
- ksadk/sandbox/backends/local_process.py +11 -3
- ksadk/sandbox/base.py +10 -15
- ksadk/sandbox/factory.py +14 -4
- ksadk/sandbox/registry.py +57 -6
- ksadk/server/api_models.py +15 -5
- ksadk/server/app.py +455 -3743
- ksadk/server/composition.py +21 -0
- ksadk/server/factory.py +624 -0
- ksadk/server/routes/__init__.py +1 -0
- ksadk/server/routes/checkpoint_resolution.py +116 -0
- ksadk/server/routes/common.py +713 -0
- ksadk/server/routes/control.py +327 -0
- ksadk/server/routes/dependencies.py +98 -0
- ksadk/server/routes/misc.py +448 -0
- ksadk/server/routes/models.py +443 -0
- ksadk/server/routes/openai_compat.py +207 -0
- ksadk/server/routes/projection.py +795 -0
- ksadk/server/routes/routers.py +52 -0
- ksadk/server/routes/run.py +726 -0
- ksadk/server/routes/sessions.py +649 -0
- ksadk/server/routes/streaming.py +223 -0
- ksadk/server/routes/workspace.py +381 -0
- ksadk/server/static/assets/{ArtifactsPanel-C0meuOdi.js → ArtifactsPanel-Cjnqt-8W.js} +1 -1
- ksadk/server/static/assets/CodeBlock-BqyqZfuB.js +9 -0
- ksadk/server/static/assets/MathMessageMarkdown-BpH7jiFM.js +8 -0
- ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +303 -0
- ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +1 -0
- ksadk/server/static/assets/{arc-bj2rZnP5.js → arc-CFKwSk_B.js} +1 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +1 -0
- ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-2u1ltDIj.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
- ksadk/server/static/assets/{blockDiagram-GPEHLZMM-D6fvdK20.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
- ksadk/server/static/assets/{c4Diagram-AAUBKEIU-BK82L5n5.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
- ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
- ksadk/server/static/assets/{chunk-2J33WTMH-DLVdkeyQ.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
- ksadk/server/static/assets/{chunk-4BX2VUAB-BbwsYcbW.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
- ksadk/server/static/assets/{chunk-55IACEB6-DOairxzw.js → chunk-55IACEB6-BK8paA20.js} +1 -1
- ksadk/server/static/assets/{chunk-727SXJPM-hCO487gs.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
- ksadk/server/static/assets/{chunk-AQP2D5EJ-XU8vDOuG.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
- ksadk/server/static/assets/{chunk-FMBD7UC4-PrapyfMu.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
- ksadk/server/static/assets/{chunk-ND2GUHAM-CboKhTZ3.js → chunk-ND2GUHAM-D98vPd-E.js} +1 -1
- ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +1 -0
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-S5V4N54A-_N8bJ-EU.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
- ksadk/server/static/assets/{dagre-BM42HDAG-FoDlo5J2.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
- ksadk/server/static/assets/{diagram-2AECGRRQ-BBp6ebBw.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
- ksadk/server/static/assets/{diagram-5GNKFQAL-CqOvG1PR.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
- ksadk/server/static/assets/{diagram-KO2AKTUF-O9T3t6ba.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
- ksadk/server/static/assets/{diagram-LMA3HP47-CGG8ekBO.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
- ksadk/server/static/assets/{diagram-OG6HWLK6-4BmH1EEg.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
- ksadk/server/static/assets/{dist-CiZHB6ZW.js → dist-6CVKuTAe.js} +1 -1
- ksadk/server/static/assets/{dist-BMKM66B4.js → dist-BUHRxvDG.js} +1 -1
- ksadk/server/static/assets/{dist-CZ6C3x8B.js → dist-BZ9n9AjO.js} +1 -1
- ksadk/server/static/assets/{dist-DbaH3p5h.js → dist-BibcG1V9.js} +1 -1
- ksadk/server/static/assets/{dist-BVzcWa6D.js → dist-Bs-jQcRX.js} +1 -1
- ksadk/server/static/assets/{dist-D99wf6_X.js → dist-C2xjE7cO.js} +1 -1
- ksadk/server/static/assets/{dist-DLMjL01k.js → dist-C7-3jInC.js} +1 -1
- ksadk/server/static/assets/{dist-DI-oVAXw.js → dist-C99THtIA.js} +1 -1
- ksadk/server/static/assets/{dist-BkJjNih3.js → dist-CGcp2ex8.js} +1 -1
- ksadk/server/static/assets/{dist-D5JGcxBx.js → dist-CVQRZjPu.js} +1 -1
- ksadk/server/static/assets/{dist-CWiTDN_V.js → dist-Cf23NY4L.js} +1 -1
- ksadk/server/static/assets/{dist-DLeM1OCK.js → dist-CgF3fj15.js} +1 -1
- ksadk/server/static/assets/{dist-BmuTWcm7.js → dist-Cwt7koer.js} +1 -1
- ksadk/server/static/assets/{dist-C2DKRFVK.js → dist-D82mtD2s.js} +1 -1
- ksadk/server/static/assets/{dist-B67uF2uK.js → dist-DF06ORQo.js} +1 -1
- ksadk/server/static/assets/{dist-Cwhk4lwI.js → dist-DHn6nBzr.js} +1 -1
- ksadk/server/static/assets/{dist-S4klkK5W.js → dist-Djgl2wVZ.js} +1 -1
- ksadk/server/static/assets/{dist-DCpZrjaK.js → dist-DlzCRy0S.js} +1 -1
- ksadk/server/static/assets/{dist-Cp1_jKwf.js → dist-DqNnNFrw.js} +1 -1
- ksadk/server/static/assets/{dist-6kSZvCZh.js → dist-DyvYLMW9.js} +1 -1
- ksadk/server/static/assets/{dist-DM0rEQPk.js → dist-eoW6tZXA.js} +1 -1
- ksadk/server/static/assets/{dist-Bk1l05Ni.js → dist-ivOya1LD.js} +1 -1
- ksadk/server/static/assets/{erDiagram-TEJ5UH35-oJhaci7S.js → erDiagram-TEJ5UH35-CnfRcY2M.js} +1 -1
- ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +1 -0
- ksadk/server/static/assets/{flowDiagram-I6XJVG4X-DtTmUan-.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
- ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BSsb_eij.js → ganttDiagram-6RSMTGT7-DpCoB2g9.js} +1 -1
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +1 -0
- ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-BR5s6Pws.js → gitGraphDiagram-PVQCEYII-9IKVFBVT.js} +1 -1
- ksadk/server/static/assets/index-QSwCHuB8.js +177 -0
- ksadk/server/static/assets/index-jOPmTOZH.css +2 -0
- ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +1 -0
- ksadk/server/static/assets/{infoDiagram-5YYISTIA-DYPc5cvh.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
- ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-MoBdALDg.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
- ksadk/server/static/assets/{journeyDiagram-JHISSGLW-DgLiQT8l.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
- ksadk/server/static/assets/{kanban-definition-UN3LZRKU-CsFx112F.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
- ksadk/server/static/assets/{katex-DRsiwpM2.js → katex-DATssjp1.js} +1 -1
- ksadk/server/static/assets/{linear-TNRQ5Orv.js → linear-CvMBw9cA.js} +1 -1
- ksadk/server/static/assets/{mermaid-parser.core-D2eMVOgo.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
- ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-BtByYFhL.js → mindmap-definition-RKZ34NQL-CSAQxEAe.js} +1 -1
- ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +1 -0
- ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +1 -0
- ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPnuCB8c.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
- ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-miFpCPv4.js → quadrantDiagram-W4KKPZXB-CxIR4JXI.js} +1 -1
- ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +1 -0
- ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-mjB_yYkW.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
- ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-D7hSlZZZ.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
- ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-D9Cx6hC3.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
- ksadk/server/static/assets/{stateDiagram-AJRCARHV-D_zrg47o.js → stateDiagram-AJRCARHV-DGpd9yFG.js} +1 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +1 -0
- ksadk/server/static/assets/{timeline-definition-PNZ67QCA-CwSec0Wa.js → timeline-definition-PNZ67QCA-jqoYs3jQ.js} +1 -1
- ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +1 -0
- ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +1 -0
- ksadk/server/static/assets/{vennDiagram-CIIHVFJN-agCVobiF.js → vennDiagram-CIIHVFJN-l3Z7-wbP.js} +1 -1
- ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +1 -0
- ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-TmrlhWNt.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
- ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-DV71V-ah.js → xychartDiagram-2RQKCTM6-SkiH8GsK.js} +1 -1
- ksadk/server/static/index.html +2 -2
- ksadk/server/terminal_sessions.py +111 -58
- ksadk/sessions/__init__.py +86 -40
- ksadk/sessions/base.py +31 -11
- ksadk/sessions/continuity.py +28 -5
- ksadk/sessions/in_memory.py +46 -2
- ksadk/sessions/local_service.py +148 -17
- ksadk/sessions/postgres_service.py +216 -35
- ksadk/sessions/resilience.py +52 -0
- ksadk/sessions/resilient.py +388 -0
- ksadk/skills/models.py +17 -5
- ksadk/skills/package_store.py +5 -2
- ksadk/skills/runtime/agent.py +20 -5
- ksadk/skills/runtime/artifacts.py +1 -5
- ksadk/skills/runtime/backends/e2b.py +10 -4
- ksadk/skills/runtime/backends/local.py +15 -3
- ksadk/skills/runtime/base.py +1 -2
- ksadk/skills/runtime/executor.py +10 -3
- ksadk/skills/runtime/factory.py +4 -2
- ksadk/skills/runtime/loader.py +1 -2
- ksadk/skills/runtime/registry.py +15 -10
- ksadk/skills/runtime/request.py +3 -1
- ksadk/skills/service_client.py +38 -17
- ksadk/skills/tool_defs.py +15 -10
- ksadk/terminal_exec_policy.py +3 -4
- ksadk/tools/gateway.py +92 -15
- ksadk/tools/result_budget.py +12 -4
- ksadk/toolsets/__init__.py +136 -36
- ksadk/toolsets/platform.py +21 -5
- ksadk/toolsets/sandbox.py +82 -16
- ksadk/toolsets/skills.py +200 -39
- ksadk/toolsets/web.py +123 -26
- ksadk/toolsets/workspace.py +264 -114
- ksadk/tracing/exporters/inmemory_exporter.py +62 -51
- ksadk/tracing/exporters/langfuse_exporter.py +91 -76
- ksadk/tracing/setup.py +132 -53
- ksadk/tracing/span_utils.py +5 -2
- ksadk/tui/__init__.py +22 -7
- ksadk/tui/loop.py +1925 -0
- ksadk/tui/stream_render.py +69 -0
- ksadk/ui_config.py +5 -3
- ksadk/version.py +1 -1
- ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
- agentengine_sdk_python-0.6.9.dist-info/RECORD +0 -487
- ksadk/server/static/assets/CodeBlock-BbI4HPtJ.js +0 -9
- ksadk/server/static/assets/MathMessageMarkdown-DMLQYoLp.js +0 -8
- ksadk/server/static/assets/MermaidBlock-DCR8WZ17.js +0 -303
- ksadk/server/static/assets/NativeTerminalPanel-CKUvWhUz.js +0 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-Cr6Xz1_c.js +0 -1
- ksadk/server/static/assets/channel-BSSOwFIb.js +0 -1
- ksadk/server/static/assets/chunk-QZHKN3VN-XXpdiwUL.js +0 -1
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-C5HvGiyK.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-C5HvGiyK.js +0 -1
- ksadk/server/static/assets/eventmodeling-FCH6USID-CIgwHJLL.js +0 -1
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BVAJ7uo0.js +0 -1
- ksadk/server/static/assets/index-BH7-pC0B.js +0 -165
- ksadk/server/static/assets/index-DAURbCsP.css +0 -1
- ksadk/server/static/assets/info-J43DQDTF-MT80V4ge.js +0 -1
- ksadk/server/static/assets/packet-YPE3B663-BLKhbXZB.js +0 -1
- ksadk/server/static/assets/pie-LRSECV5Y-DFOikjSY.js +0 -1
- ksadk/server/static/assets/radar-GUYGQ44K-095b1Ikw.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-J9kCb0nC.js +0 -1
- ksadk/server/static/assets/treeView-BLDUP644-yinfJEY6.js +0 -1
- ksadk/server/static/assets/treemap-LRROVOQU-DosUqN1Q.js +0 -1
- ksadk/server/static/assets/wardley-L42UT6IY-Bvp7-5uH.js +0 -1
- ksadk/tui/app.py +0 -400
- ksadk/tui/clipboard.py +0 -100
- ksadk/tui/widgets/__init__.py +0 -22
- ksadk/tui/widgets/assistant.py +0 -89
- ksadk/tui/widgets/base.py +0 -54
- ksadk/tui/widgets/chat_input.py +0 -246
- ksadk/tui/widgets/history.py +0 -156
- ksadk/tui/widgets/system.py +0 -87
- ksadk/tui/widgets/thinking.py +0 -110
- ksadk/tui/widgets/tool_call.py +0 -161
- ksadk/tui/widgets/user.py +0 -37
- {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
- {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
ksadk/cli/cmd_openclaw.py
CHANGED
|
@@ -10,11 +10,11 @@ agentengine openclaw - OpenClaw 资源管理
|
|
|
10
10
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
|
+
import asyncio
|
|
13
14
|
import copy
|
|
14
15
|
import io
|
|
15
|
-
import os
|
|
16
|
-
import asyncio
|
|
17
16
|
import json
|
|
17
|
+
import os
|
|
18
18
|
import re
|
|
19
19
|
import secrets
|
|
20
20
|
import shutil
|
|
@@ -26,23 +26,27 @@ import time
|
|
|
26
26
|
import webbrowser
|
|
27
27
|
from datetime import datetime, timedelta, timezone
|
|
28
28
|
from pathlib import Path
|
|
29
|
-
from typing import
|
|
29
|
+
from typing import Any, Dict, Optional, cast
|
|
30
30
|
|
|
31
31
|
import click
|
|
32
32
|
from click.core import ParameterSource
|
|
33
|
+
from rich.console import Console
|
|
33
34
|
from rich.measure import Measurement
|
|
34
35
|
from rich.table import Table as RichTable
|
|
35
36
|
|
|
36
37
|
from ksadk.api.client import DryRunExit
|
|
38
|
+
from ksadk.builders.container_builder import (
|
|
39
|
+
registry_kind_label,
|
|
40
|
+
resolve_registry_credentials,
|
|
41
|
+
)
|
|
37
42
|
from ksadk.cli.agent_ref import resolve_openclaw_ref
|
|
38
|
-
from ksadk.cli.dry_run import dry_run_option,
|
|
43
|
+
from ksadk.cli.dry_run import dry_run_option, effective_dry_run, run_async_with_dry_run
|
|
39
44
|
from ksadk.cli.error_utils import abort_with_cli_error, remote_error, resolution_error
|
|
45
|
+
from ksadk.cli.model_catalog import fetch_provider_model_catalog, find_model_in_catalog
|
|
40
46
|
from ksadk.cli.network_options import build_network_payload, network_cli_kwargs, network_options
|
|
41
|
-
from ksadk.cli.storage import build_storage_config
|
|
42
|
-
from ksadk.cli.resource_common import ResourceActionDescriptor
|
|
43
47
|
from ksadk.cli.resource_common import (
|
|
44
48
|
CONTEXT_SETTINGS,
|
|
45
|
-
|
|
49
|
+
ResourceActionDescriptor,
|
|
46
50
|
ResourceDescriptor,
|
|
47
51
|
ResourceListSchema,
|
|
48
52
|
ResourceStatusSchema,
|
|
@@ -51,18 +55,17 @@ from ksadk.cli.resource_common import (
|
|
|
51
55
|
confirm_destructive,
|
|
52
56
|
confirm_options,
|
|
53
57
|
pagination_options,
|
|
54
|
-
|
|
58
|
+
region_option,
|
|
55
59
|
render_descriptor_list,
|
|
56
60
|
render_descriptor_status,
|
|
57
|
-
region_option,
|
|
58
61
|
)
|
|
62
|
+
from ksadk.cli.storage import build_storage_config
|
|
59
63
|
from ksadk.cli.ui import (
|
|
60
64
|
emit_json,
|
|
61
65
|
get_console,
|
|
62
66
|
is_json_output,
|
|
63
67
|
is_stdout_tty,
|
|
64
68
|
json_dumps,
|
|
65
|
-
output_option as cli_output_option,
|
|
66
69
|
print_info,
|
|
67
70
|
print_kv,
|
|
68
71
|
print_rule,
|
|
@@ -71,17 +74,19 @@ from ksadk.cli.ui import (
|
|
|
71
74
|
print_warn,
|
|
72
75
|
status_rich_style,
|
|
73
76
|
)
|
|
74
|
-
from ksadk.
|
|
75
|
-
|
|
77
|
+
from ksadk.cli.ui import (
|
|
78
|
+
output_option as cli_output_option,
|
|
79
|
+
)
|
|
76
80
|
from ksadk.conversations.model_context import normalize_model_metadata
|
|
81
|
+
from ksadk.deployment.agent_access import get_latest_agent_access
|
|
77
82
|
from ksadk.model_policy import build_runtime_model_policy_env
|
|
78
|
-
from ksadk.
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
from ksadk.openclaw_gateway import (
|
|
84
|
+
OpenClawGatewayClient,
|
|
85
|
+
OpenClawGatewayError,
|
|
86
|
+
OpenClawGatewayRequestError,
|
|
81
87
|
)
|
|
82
|
-
from ksadk.openclaw_gateway import OpenClawGatewayClient, OpenClawGatewayError, OpenClawGatewayRequestError
|
|
83
|
-
from ksadk.terminal_exec_policy import OPENCLAW_TERMINAL_EXEC_POLICY
|
|
84
88
|
from ksadk.terminal_client import run_terminal_session
|
|
89
|
+
from ksadk.terminal_exec_policy import OPENCLAW_TERMINAL_EXEC_POLICY
|
|
85
90
|
|
|
86
91
|
console = get_console()
|
|
87
92
|
# 默认 OpenClaw 镜像。
|
|
@@ -136,7 +141,8 @@ OPENCLAW_CHANNEL_CONNECT_HELP = """连接指定 channel。
|
|
|
136
141
|
飞书:启动官方 onboarding 流程。
|
|
137
142
|
agentengine openclaw channel connect <id> --channel feishu
|
|
138
143
|
WPS 协作:写入开放平台 appId/appSecret 并启动长连接。
|
|
139
|
-
agentengine openclaw channel connect <id> --channel wps-xiezuo
|
|
144
|
+
agentengine openclaw channel connect <id> --channel wps-xiezuo \
|
|
145
|
+
--app-id <appId> --app-secret <appSecret>
|
|
140
146
|
|
|
141
147
|
\b
|
|
142
148
|
WPS 协作说明:
|
|
@@ -347,6 +353,7 @@ def _get_global_env() -> Dict[str, str]:
|
|
|
347
353
|
|
|
348
354
|
try:
|
|
349
355
|
from ksadk.configs.global_config import get_env_from_global_config
|
|
356
|
+
|
|
350
357
|
_GLOBAL_ENV_CACHE = {
|
|
351
358
|
str(k): str(v).strip()
|
|
352
359
|
for k, v in get_env_from_global_config().items()
|
|
@@ -395,6 +402,7 @@ def _resolve_model_base_url(cli_value: Optional[str]) -> Optional[str]:
|
|
|
395
402
|
|
|
396
403
|
try:
|
|
397
404
|
from ksadk.configs.settings import settings
|
|
405
|
+
|
|
398
406
|
api_base = settings.model.api_base
|
|
399
407
|
if api_base and str(api_base).strip():
|
|
400
408
|
return str(api_base).strip()
|
|
@@ -434,8 +442,9 @@ def _summarize_openclaw_region(agents: list[Dict[str, Any]], fallback_region: Op
|
|
|
434
442
|
|
|
435
443
|
def _print_openclaw_list_summary(table: RichTable, summary_text: str) -> None:
|
|
436
444
|
"""将摘要贴在表格下方;宽度不足时退化成普通单行。"""
|
|
437
|
-
|
|
438
|
-
|
|
445
|
+
rich_console = cast(Console, console)
|
|
446
|
+
table_width = Measurement.get(rich_console, rich_console.options, table).maximum
|
|
447
|
+
summary_width = Measurement.get(rich_console, rich_console.options, summary_text).maximum
|
|
439
448
|
if table_width >= summary_width:
|
|
440
449
|
summary_grid = RichTable.grid(expand=False)
|
|
441
450
|
summary_grid.add_column(justify="right", width=table_width)
|
|
@@ -456,7 +465,12 @@ def _normalize_ui_locale(raw: Optional[str]) -> str:
|
|
|
456
465
|
|
|
457
466
|
if low in {"c", "c-utf-8", "c.utf-8", "posix"}:
|
|
458
467
|
return "zh-CN"
|
|
459
|
-
if
|
|
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
|
+
):
|
|
460
474
|
return "zh-TW"
|
|
461
475
|
if low.startswith("zh"):
|
|
462
476
|
return "zh-CN"
|
|
@@ -531,7 +545,9 @@ def _strip_provider_prefix(provider_id: str, model_id: str) -> str:
|
|
|
531
545
|
|
|
532
546
|
|
|
533
547
|
def _default_openclaw_model_inputs(provider_id: str, model_id: str) -> list[str]:
|
|
534
|
-
if str(provider_id or "").strip().lower() == "ksyun" and str(
|
|
548
|
+
if str(provider_id or "").strip().lower() == "ksyun" and str(
|
|
549
|
+
model_id or ""
|
|
550
|
+
).strip().lower() in {"glm-5.1", "glm-5.2"}:
|
|
535
551
|
return ["text"]
|
|
536
552
|
return ["text", "image"]
|
|
537
553
|
|
|
@@ -597,9 +613,11 @@ def _openclaw_catalog_item_from_metadata(
|
|
|
597
613
|
"api": str(raw_model.get("api") or provider_api or "openai-completions"),
|
|
598
614
|
"reasoning": bool(raw_model.get("reasoning", True)),
|
|
599
615
|
"input": inputs or _default_openclaw_model_inputs(provider_id, model_id),
|
|
600
|
-
"cost":
|
|
601
|
-
|
|
602
|
-
|
|
616
|
+
"cost": (
|
|
617
|
+
raw_model.get("cost")
|
|
618
|
+
if isinstance(raw_model.get("cost"), dict)
|
|
619
|
+
else {"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0}
|
|
620
|
+
),
|
|
603
621
|
"contextWindow": int(metadata.get("context_window_tokens") or 200_000),
|
|
604
622
|
"maxTokens": int(metadata.get("max_output_tokens") or 20_000),
|
|
605
623
|
}
|
|
@@ -613,7 +631,9 @@ def _apply_openclaw_provider_model_catalog(
|
|
|
613
631
|
return False
|
|
614
632
|
|
|
615
633
|
provider_id = str(env.get("OPENCLAW_MODEL_PROVIDER_ID") or "ksyun").strip() or "ksyun"
|
|
616
|
-
provider_api =
|
|
634
|
+
provider_api = (
|
|
635
|
+
str(env.get("OPENCLAW_MODEL_API") or "openai-completions").strip() or "openai-completions"
|
|
636
|
+
)
|
|
617
637
|
raw_catalog = str(env.get("OPENCLAW_MODEL_CATALOG_JSON") or "").strip()
|
|
618
638
|
catalog: list[Dict[str, Any]] = []
|
|
619
639
|
if raw_catalog:
|
|
@@ -632,16 +652,17 @@ def _apply_openclaw_provider_model_catalog(
|
|
|
632
652
|
|
|
633
653
|
changed = False
|
|
634
654
|
for raw_model in raw_models:
|
|
635
|
-
|
|
636
|
-
raw_model
|
|
637
|
-
|
|
638
|
-
|
|
655
|
+
raw_model_dict: Dict[str, Any] = (
|
|
656
|
+
dict(raw_model) if isinstance(raw_model, dict) else {"id": str(raw_model or "").strip()}
|
|
657
|
+
)
|
|
658
|
+
catalog_item = _openclaw_catalog_item_from_metadata(
|
|
659
|
+
raw_model_dict,
|
|
639
660
|
provider_id=provider_id,
|
|
640
661
|
provider_api=provider_api,
|
|
641
662
|
)
|
|
642
|
-
if not
|
|
663
|
+
if not catalog_item:
|
|
643
664
|
continue
|
|
644
|
-
model_key = str(
|
|
665
|
+
model_key = str(catalog_item["id"])
|
|
645
666
|
existing_index = next(
|
|
646
667
|
(
|
|
647
668
|
index
|
|
@@ -651,13 +672,13 @@ def _apply_openclaw_provider_model_catalog(
|
|
|
651
672
|
None,
|
|
652
673
|
)
|
|
653
674
|
if existing_index is not None:
|
|
654
|
-
merged = {**catalog[existing_index], **
|
|
675
|
+
merged = {**catalog[existing_index], **catalog_item}
|
|
655
676
|
if merged != catalog[existing_index]:
|
|
656
677
|
catalog[existing_index] = merged
|
|
657
678
|
changed = True
|
|
658
679
|
continue
|
|
659
680
|
seen.add(model_key)
|
|
660
|
-
catalog.append(
|
|
681
|
+
catalog.append(catalog_item)
|
|
661
682
|
changed = True
|
|
662
683
|
|
|
663
684
|
if not catalog or not changed:
|
|
@@ -679,20 +700,12 @@ def _apply_openclaw_provider_model_metadata(
|
|
|
679
700
|
|
|
680
701
|
def _openclaw_requested_model_ids(env: Dict[str, str]) -> list[str]:
|
|
681
702
|
raw_allowlist = str(
|
|
682
|
-
env.get("OPENCLAW_MODEL_ALLOWLIST")
|
|
683
|
-
or env.get("AGENTENGINE_MODEL_ALLOWLIST")
|
|
684
|
-
or ""
|
|
703
|
+
env.get("OPENCLAW_MODEL_ALLOWLIST") or env.get("AGENTENGINE_MODEL_ALLOWLIST") or ""
|
|
685
704
|
).strip()
|
|
686
705
|
if raw_allowlist:
|
|
687
|
-
return [
|
|
688
|
-
item.strip()
|
|
689
|
-
for item in raw_allowlist.replace(";", ",").split(",")
|
|
690
|
-
if item.strip()
|
|
691
|
-
]
|
|
706
|
+
return [item.strip() for item in raw_allowlist.replace(";", ",").split(",") if item.strip()]
|
|
692
707
|
primary_model = str(
|
|
693
|
-
env.get("OPENCLAW_DEFAULT_MODEL")
|
|
694
|
-
or env.get("OPENAI_MODEL_NAME")
|
|
695
|
-
or ""
|
|
708
|
+
env.get("OPENCLAW_DEFAULT_MODEL") or env.get("OPENAI_MODEL_NAME") or ""
|
|
696
709
|
).strip()
|
|
697
710
|
return [primary_model] if primary_model else []
|
|
698
711
|
|
|
@@ -705,9 +718,7 @@ def _filter_openclaw_provider_catalog(
|
|
|
705
718
|
if not requested_models:
|
|
706
719
|
return []
|
|
707
720
|
raw_models = [
|
|
708
|
-
item.get("_provider_raw_model") or item
|
|
709
|
-
if isinstance(item, dict)
|
|
710
|
-
else item
|
|
721
|
+
item.get("_provider_raw_model") or item if isinstance(item, dict) else item
|
|
711
722
|
for item in provider_catalog
|
|
712
723
|
]
|
|
713
724
|
selected: list[Any] = []
|
|
@@ -716,7 +727,9 @@ def _filter_openclaw_provider_catalog(
|
|
|
716
727
|
match = find_model_in_catalog(raw_models, model_id)
|
|
717
728
|
if match is None:
|
|
718
729
|
continue
|
|
719
|
-
identities = sorted(
|
|
730
|
+
identities = sorted(
|
|
731
|
+
str(value).strip().lower() for value in (model_id, str(match)) if str(value).strip()
|
|
732
|
+
)
|
|
720
733
|
dedupe_key = identities[0] if identities else str(model_id).lower()
|
|
721
734
|
if dedupe_key in seen:
|
|
722
735
|
continue
|
|
@@ -747,14 +760,12 @@ def _build_openclaw_env_vars(
|
|
|
747
760
|
openclaw_explicit_model = default_model or _resolve_env("OPENCLAW_DEFAULT_MODEL")
|
|
748
761
|
generic_model_preference = _resolve_env("OPENAI_MODEL_NAME", "MODEL_NAME", "LLM_MODEL")
|
|
749
762
|
model_preference = openclaw_explicit_model or generic_model_preference
|
|
750
|
-
explicit_base_url = (
|
|
751
|
-
|
|
752
|
-
or _resolve_env("OPENCLAW_MODEL_BASE_URL", "OPENAI_BASE_URL", "OPENAI_API_BASE")
|
|
763
|
+
explicit_base_url = model_base_url or _resolve_env(
|
|
764
|
+
"OPENCLAW_MODEL_BASE_URL", "OPENAI_BASE_URL", "OPENAI_API_BASE"
|
|
753
765
|
)
|
|
754
766
|
base_url = _resolve_model_base_url(explicit_base_url)
|
|
755
|
-
api_key = (
|
|
756
|
-
|
|
757
|
-
or _resolve_env("OPENCLAW_MODEL_API_KEY", "OPENAI_API_KEY", "LLM_API_KEY", "MODEL_API_KEY")
|
|
767
|
+
api_key = model_api_key or _resolve_env(
|
|
768
|
+
"OPENCLAW_MODEL_API_KEY", "OPENAI_API_KEY", "LLM_API_KEY", "MODEL_API_KEY"
|
|
758
769
|
)
|
|
759
770
|
model = model_preference or "glm-5.2"
|
|
760
771
|
explicit_provider_id = model_provider_id or _resolve_env("OPENCLAW_MODEL_PROVIDER_ID")
|
|
@@ -762,34 +773,33 @@ def _build_openclaw_env_vars(
|
|
|
762
773
|
if not inferred_provider_id and model and "/" in model:
|
|
763
774
|
inferred_provider_id = model.split("/", 1)[0].strip()
|
|
764
775
|
provider_id = inferred_provider_id or default_provider_id
|
|
765
|
-
resolved_gateway_port = (
|
|
766
|
-
|
|
767
|
-
or _resolve_env("OPENCLAW_GATEWAY_PORT", "PORT")
|
|
768
|
-
or "8080"
|
|
769
|
-
)
|
|
770
|
-
resolved_public_port = (
|
|
771
|
-
public_port
|
|
772
|
-
or _resolve_env("OPENCLAW_PUBLIC_PORT")
|
|
773
|
-
or "80"
|
|
774
|
-
)
|
|
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"
|
|
775
778
|
explicit_model_api = _resolve_env("OPENCLAW_MODEL_API")
|
|
776
779
|
model_api = explicit_model_api or default_model_api
|
|
777
780
|
trusted_proxy_user_header = (
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
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
|
|
781
787
|
)
|
|
782
|
-
|
|
783
|
-
|
|
788
|
+
.strip()
|
|
789
|
+
.lower()
|
|
790
|
+
)
|
|
784
791
|
internal_trusted_proxy_user = (
|
|
785
|
-
_resolve_env("OPENCLAW_INTERNAL_TRUSTED_PROXY_USER")
|
|
786
|
-
or "openclaw-backend"
|
|
792
|
+
_resolve_env("OPENCLAW_INTERNAL_TRUSTED_PROXY_USER") or "openclaw-backend"
|
|
787
793
|
)
|
|
788
794
|
internal_trusted_proxy_user_header = (
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
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
|
+
)
|
|
793
803
|
trusted_proxies = _normalize_csv_list(
|
|
794
804
|
_resolve_env("OPENCLAW_TRUSTED_PROXIES") or "",
|
|
795
805
|
default_items=DEFAULT_TRUSTED_PROXY_CIDRS,
|
|
@@ -797,7 +807,9 @@ def _build_openclaw_env_vars(
|
|
|
797
807
|
browser_enabled = _resolve_env("OPENCLAW_BROWSER_ENABLED")
|
|
798
808
|
browser_no_sandbox = _resolve_env("OPENCLAW_BROWSER_NO_SANDBOX") or "true"
|
|
799
809
|
browser_headless = _resolve_env("OPENCLAW_BROWSER_HEADLESS") or "true"
|
|
800
|
-
browser_executable = _resolve_env(
|
|
810
|
+
browser_executable = _resolve_env(
|
|
811
|
+
"OPENCLAW_BROWSER_EXECUTABLE_PATH", "OPENCLAW_BROWSER_EXECUTABLE"
|
|
812
|
+
)
|
|
801
813
|
ui_locale = _normalize_ui_locale(_resolve_env("OPENCLAW_UI_LOCALE", "LANG", "LC_ALL"))
|
|
802
814
|
exec_strict_mode_raw = (
|
|
803
815
|
exec_profile_overrides.get("OPENCLAW_EXEC_STRICT_MODE")
|
|
@@ -806,13 +818,21 @@ def _build_openclaw_env_vars(
|
|
|
806
818
|
)
|
|
807
819
|
exec_strict_mode = _is_truthy(exec_strict_mode_raw)
|
|
808
820
|
|
|
809
|
-
exec_host =
|
|
821
|
+
exec_host = (
|
|
822
|
+
exec_profile_overrides.get("OPENCLAW_EXEC_HOST")
|
|
823
|
+
or _resolve_env("OPENCLAW_EXEC_HOST")
|
|
824
|
+
or "gateway"
|
|
825
|
+
)
|
|
810
826
|
exec_security = (
|
|
811
827
|
exec_profile_overrides.get("OPENCLAW_EXEC_SECURITY")
|
|
812
828
|
or _resolve_env("OPENCLAW_EXEC_SECURITY")
|
|
813
829
|
or ("allowlist" if exec_strict_mode else "full")
|
|
814
830
|
)
|
|
815
|
-
exec_ask =
|
|
831
|
+
exec_ask = (
|
|
832
|
+
exec_profile_overrides.get("OPENCLAW_EXEC_ASK")
|
|
833
|
+
or _resolve_env("OPENCLAW_EXEC_ASK")
|
|
834
|
+
or "off"
|
|
835
|
+
)
|
|
816
836
|
exec_ask_fallback = (
|
|
817
837
|
exec_profile_overrides.get("OPENCLAW_EXEC_ASK_FALLBACK")
|
|
818
838
|
or _resolve_env("OPENCLAW_EXEC_ASK_FALLBACK")
|
|
@@ -831,9 +851,7 @@ def _build_openclaw_env_vars(
|
|
|
831
851
|
exec_default_allowlist_enabled = (
|
|
832
852
|
exec_profile_overrides.get("OPENCLAW_EXEC_DEFAULT_ALLOWLIST_ENABLED")
|
|
833
853
|
or _resolve_env("OPENCLAW_EXEC_DEFAULT_ALLOWLIST_ENABLED")
|
|
834
|
-
or (
|
|
835
|
-
"true" if exec_strict_mode else "false"
|
|
836
|
-
)
|
|
854
|
+
or ("true" if exec_strict_mode else "false")
|
|
837
855
|
)
|
|
838
856
|
exec_allowlist = _resolve_env("OPENCLAW_EXEC_ALLOWLIST")
|
|
839
857
|
fs_workspace_only = (
|
|
@@ -850,10 +868,14 @@ def _build_openclaw_env_vars(
|
|
|
850
868
|
env["OPENCLAW_GATEWAY_BIND"] = "lan"
|
|
851
869
|
if gateway_auth_mode:
|
|
852
870
|
env["OPENCLAW_GATEWAY_AUTH_MODE"] = gateway_auth_mode
|
|
853
|
-
env["OPENCLAW_TRUSTED_PROXY_USER_HEADER"] =
|
|
871
|
+
env["OPENCLAW_TRUSTED_PROXY_USER_HEADER"] = (
|
|
872
|
+
trusted_proxy_user_header or DEFAULT_TRUSTED_PROXY_USER_HEADER
|
|
873
|
+
)
|
|
854
874
|
env["OPENCLAW_INTERNAL_TRUSTED_PROXY_USER"] = internal_trusted_proxy_user
|
|
855
875
|
env["OPENCLAW_INTERNAL_TRUSTED_PROXY_USER_HEADER"] = (
|
|
856
|
-
internal_trusted_proxy_user_header
|
|
876
|
+
internal_trusted_proxy_user_header
|
|
877
|
+
or trusted_proxy_user_header
|
|
878
|
+
or DEFAULT_TRUSTED_PROXY_USER_HEADER
|
|
857
879
|
)
|
|
858
880
|
env["OPENCLAW_TRUSTED_PROXIES"] = trusted_proxies
|
|
859
881
|
env["OPENCLAW_GATEWAY_PORT"] = str(resolved_gateway_port)
|
|
@@ -899,8 +921,9 @@ def _build_openclaw_env_vars(
|
|
|
899
921
|
_, catalog_model_id = normalized_model.split("/", 1)
|
|
900
922
|
resolved_model = normalized_model
|
|
901
923
|
else:
|
|
902
|
-
|
|
903
|
-
|
|
924
|
+
resolved_model = (
|
|
925
|
+
f"{provider_id}/{normalized_model}" if provider_id else normalized_model
|
|
926
|
+
)
|
|
904
927
|
if openclaw_explicit_model:
|
|
905
928
|
env["OPENCLAW_DEFAULT_MODEL"] = resolved_model
|
|
906
929
|
elif generic_model_preference:
|
|
@@ -1005,11 +1028,14 @@ def _normalize_openclaw_gateway_auth_env(env: dict[str, str]) -> dict[str, str]:
|
|
|
1005
1028
|
auth_mode = raw_mode or ("token" if raw_token or raw_password else "trusted-proxy")
|
|
1006
1029
|
if auth_mode == "token":
|
|
1007
1030
|
if raw_token and raw_password and raw_token != raw_password:
|
|
1008
|
-
raise ValueError(
|
|
1031
|
+
raise ValueError(
|
|
1032
|
+
"OPENCLAW_GATEWAY_TOKEN 与 OPENCLAW_GATEWAY_PASSWORD 同时提供时必须一致"
|
|
1033
|
+
)
|
|
1009
1034
|
shared_secret = raw_token or raw_password
|
|
1010
1035
|
if not shared_secret:
|
|
1011
1036
|
raise ValueError(
|
|
1012
|
-
"OPENCLAW_GATEWAY_AUTH_MODE=token 时必须提供
|
|
1037
|
+
"OPENCLAW_GATEWAY_AUTH_MODE=token 时必须提供 "
|
|
1038
|
+
"OPENCLAW_GATEWAY_TOKEN 或 OPENCLAW_GATEWAY_PASSWORD"
|
|
1013
1039
|
)
|
|
1014
1040
|
normalized_env["OPENCLAW_GATEWAY_AUTH_MODE"] = "token"
|
|
1015
1041
|
normalized_env["OPENCLAW_GATEWAY_TOKEN"] = shared_secret
|
|
@@ -1018,7 +1044,8 @@ def _normalize_openclaw_gateway_auth_env(env: dict[str, str]) -> dict[str, str]:
|
|
|
1018
1044
|
|
|
1019
1045
|
if raw_token or raw_password:
|
|
1020
1046
|
raise ValueError(
|
|
1021
|
-
"仅在 OPENCLAW_GATEWAY_AUTH_MODE=token 时支持
|
|
1047
|
+
"仅在 OPENCLAW_GATEWAY_AUTH_MODE=token 时支持 "
|
|
1048
|
+
"OPENCLAW_GATEWAY_TOKEN 或 OPENCLAW_GATEWAY_PASSWORD"
|
|
1022
1049
|
)
|
|
1023
1050
|
|
|
1024
1051
|
normalized_env["OPENCLAW_GATEWAY_AUTH_MODE"] = auth_mode
|
|
@@ -1174,7 +1201,7 @@ async def _fetch_bootstrap_config(region: str) -> Optional[Dict[str, Any]]:
|
|
|
1174
1201
|
|
|
1175
1202
|
try:
|
|
1176
1203
|
async with AgentEngineClient(region=region) as client:
|
|
1177
|
-
|
|
1204
|
+
result = await client.get_client_bootstrap_config(
|
|
1178
1205
|
product="openclaw",
|
|
1179
1206
|
framework="openclaw",
|
|
1180
1207
|
region=region,
|
|
@@ -1183,6 +1210,7 @@ async def _fetch_bootstrap_config(region: str) -> Optional[Dict[str, Any]]:
|
|
|
1183
1210
|
locale=_resolve_env("OPENCLAW_UI_LOCALE", "LANG", "LC_ALL"),
|
|
1184
1211
|
ignore_dry_run=True,
|
|
1185
1212
|
)
|
|
1213
|
+
return dict(result) if isinstance(result, dict) else None
|
|
1186
1214
|
except Exception as e:
|
|
1187
1215
|
print_warn(f"拉取服务端默认配置失败,回退本地默认镜像: {e}")
|
|
1188
1216
|
return None
|
|
@@ -1253,14 +1281,22 @@ def _flatten_agent_detail(agent: dict) -> dict:
|
|
|
1253
1281
|
"agent_id": basic.get("agent_id") or agent.get("agent_id") or "",
|
|
1254
1282
|
"name": basic.get("name") or agent.get("name") or "",
|
|
1255
1283
|
"status": (basic.get("status") or agent.get("status") or "UNKNOWN").upper(),
|
|
1256
|
-
"framework": basic.get("framework")
|
|
1284
|
+
"framework": basic.get("framework")
|
|
1285
|
+
or deploy.get("framework")
|
|
1286
|
+
or agent.get("framework")
|
|
1287
|
+
or "",
|
|
1257
1288
|
"region": basic.get("region") or deploy.get("region") or agent.get("region") or "",
|
|
1258
|
-
"endpoint": quick.get("public_endpoint")
|
|
1289
|
+
"endpoint": quick.get("public_endpoint")
|
|
1290
|
+
or quick.get("private_endpoint")
|
|
1291
|
+
or agent.get("endpoint")
|
|
1292
|
+
or "",
|
|
1259
1293
|
"artifact_path": deploy.get("artifact_path") or agent.get("artifact_path") or "",
|
|
1260
1294
|
"created_at": basic.get("created_at") or agent.get("created_at") or "",
|
|
1261
1295
|
"updated_at": basic.get("updated_at") or agent.get("updated_at") or "",
|
|
1262
1296
|
"api_key": quick.get("api_key") or agent.get("api_key"),
|
|
1263
|
-
"langfuse_url": (agent.get("advanced") or {}).get("observability_url")
|
|
1297
|
+
"langfuse_url": (agent.get("advanced") or {}).get("observability_url")
|
|
1298
|
+
or agent.get("langfuse_trace_url")
|
|
1299
|
+
or "",
|
|
1264
1300
|
}
|
|
1265
1301
|
|
|
1266
1302
|
|
|
@@ -1277,7 +1313,9 @@ async def _get_openclaw_detail_with_client(
|
|
|
1277
1313
|
detail = _flatten_agent_detail(agent)
|
|
1278
1314
|
framework = str(detail.get("framework") or "").strip().lower()
|
|
1279
1315
|
if framework and framework != "openclaw":
|
|
1280
|
-
raise resolution_error(
|
|
1316
|
+
raise resolution_error(
|
|
1317
|
+
f"目标 Agent 不是 OpenClaw: {agent_ref}", hints=["agentengine openclaw list"]
|
|
1318
|
+
)
|
|
1281
1319
|
return detail
|
|
1282
1320
|
|
|
1283
1321
|
|
|
@@ -1303,10 +1341,7 @@ def _resolve_region(
|
|
|
1303
1341
|
) -> str:
|
|
1304
1342
|
"""解析 region: 显式参数 > state > 环境变量 > 默认值。"""
|
|
1305
1343
|
return (
|
|
1306
|
-
cli_region
|
|
1307
|
-
or (state or {}).get("region")
|
|
1308
|
-
or _resolve_env("KSYUN_REGION")
|
|
1309
|
-
or "cn-beijing-6"
|
|
1344
|
+
cli_region or (state or {}).get("region") or _resolve_env("KSYUN_REGION") or "cn-beijing-6"
|
|
1310
1345
|
)
|
|
1311
1346
|
|
|
1312
1347
|
|
|
@@ -1331,7 +1366,9 @@ async def _resolve_openclaw_detail_or_raise(
|
|
|
1331
1366
|
detail = await _get_openclaw_detail_with_client(client, resolved.value)
|
|
1332
1367
|
|
|
1333
1368
|
if not detail:
|
|
1334
|
-
raise resolution_error(
|
|
1369
|
+
raise resolution_error(
|
|
1370
|
+
f"未找到 OpenClaw: {resolved.value}", hints=["agentengine openclaw list"]
|
|
1371
|
+
)
|
|
1335
1372
|
return resolved_region, detail
|
|
1336
1373
|
|
|
1337
1374
|
|
|
@@ -1378,7 +1415,9 @@ async def _ensure_openclaw_gateway_available(
|
|
|
1378
1415
|
await _wait_for_gateway_ready(region, detail, timeout_seconds=timeout_seconds)
|
|
1379
1416
|
|
|
1380
1417
|
|
|
1381
|
-
def _emit_data_payload(
|
|
1418
|
+
def _emit_data_payload(
|
|
1419
|
+
title: str, payload: dict[str, Any], *, subtitle: Optional[str] = None
|
|
1420
|
+
) -> None:
|
|
1382
1421
|
if is_json_output():
|
|
1383
1422
|
emit_json(payload)
|
|
1384
1423
|
return
|
|
@@ -1386,7 +1425,9 @@ def _emit_data_payload(title: str, payload: dict[str, Any], *, subtitle: Optiona
|
|
|
1386
1425
|
console.print(json_dumps(payload), markup=False)
|
|
1387
1426
|
|
|
1388
1427
|
|
|
1389
|
-
def _render_openclaw_dry_run(
|
|
1428
|
+
def _render_openclaw_dry_run(
|
|
1429
|
+
action: str, request: dict[str, Any], hints: tuple[str, ...] = ()
|
|
1430
|
+
) -> None:
|
|
1390
1431
|
if is_json_output():
|
|
1391
1432
|
emit_json(
|
|
1392
1433
|
build_dry_run_envelope(
|
|
@@ -1456,7 +1497,9 @@ def _select_openclaw_gateway_secret(
|
|
|
1456
1497
|
or ""
|
|
1457
1498
|
).strip()
|
|
1458
1499
|
if token and password and token != password:
|
|
1459
|
-
raise click.ClickException(
|
|
1500
|
+
raise click.ClickException(
|
|
1501
|
+
"OPENCLAW_GATEWAY_TOKEN 与 OPENCLAW_GATEWAY_PASSWORD 同时提供时必须一致"
|
|
1502
|
+
)
|
|
1460
1503
|
if token:
|
|
1461
1504
|
return "token", token
|
|
1462
1505
|
if password:
|
|
@@ -1473,14 +1516,20 @@ def _mask_openclaw_secret(secret: str | None) -> str:
|
|
|
1473
1516
|
return f"{text[:4]}****"
|
|
1474
1517
|
|
|
1475
1518
|
|
|
1476
|
-
def _openclaw_auth_mode_from_sources(
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1519
|
+
def _openclaw_auth_mode_from_sources(
|
|
1520
|
+
detail: dict[str, Any], state: dict[str, Any] | None = None
|
|
1521
|
+
) -> str:
|
|
1522
|
+
return (
|
|
1523
|
+
str(
|
|
1524
|
+
detail.get("openclaw_auth_mode")
|
|
1525
|
+
or detail.get("gateway_auth_mode")
|
|
1526
|
+
or (state or {}).get("openclaw_auth_mode")
|
|
1527
|
+
or (state or {}).get("gateway_auth_mode")
|
|
1528
|
+
or ""
|
|
1529
|
+
)
|
|
1530
|
+
.strip()
|
|
1531
|
+
.lower()
|
|
1532
|
+
)
|
|
1484
1533
|
|
|
1485
1534
|
|
|
1486
1535
|
def _openclaw_state_gateway_token(env_vars: dict[str, str]) -> str | None:
|
|
@@ -1488,9 +1537,7 @@ def _openclaw_state_gateway_token(env_vars: dict[str, str]) -> str | None:
|
|
|
1488
1537
|
if str(env_vars.get("OPENCLAW_GATEWAY_AUTH_MODE") or "").strip().lower() != "token":
|
|
1489
1538
|
return None
|
|
1490
1539
|
token = str(
|
|
1491
|
-
env_vars.get("OPENCLAW_GATEWAY_TOKEN")
|
|
1492
|
-
or env_vars.get("OPENCLAW_GATEWAY_PASSWORD")
|
|
1493
|
-
or ""
|
|
1540
|
+
env_vars.get("OPENCLAW_GATEWAY_TOKEN") or env_vars.get("OPENCLAW_GATEWAY_PASSWORD") or ""
|
|
1494
1541
|
).strip()
|
|
1495
1542
|
return token or None
|
|
1496
1543
|
|
|
@@ -1523,7 +1570,9 @@ async def _run_weixin_remote_cli_login(
|
|
|
1523
1570
|
if not endpoint:
|
|
1524
1571
|
raise OpenClawGatewayError("OpenClaw runtime endpoint 为空,无法通过远端 CLI 执行微信登录")
|
|
1525
1572
|
|
|
1526
|
-
print_info(
|
|
1573
|
+
print_info(
|
|
1574
|
+
f"当前 OpenClaw 未暴露微信 web login RPC,改用远端 OpenClaw CLI 登录流程({reason})"
|
|
1575
|
+
)
|
|
1527
1576
|
exit_code = await run_terminal_session(
|
|
1528
1577
|
endpoint=endpoint,
|
|
1529
1578
|
api_key=_openclaw_terminal_api_key(detail),
|
|
@@ -1592,9 +1641,8 @@ async def _wait_for_gateway_reload_after_config_apply(
|
|
|
1592
1641
|
|
|
1593
1642
|
def _is_gateway_reload_disconnect_error(exc: Exception) -> bool:
|
|
1594
1643
|
message = str(exc).lower()
|
|
1595
|
-
return (
|
|
1596
|
-
"
|
|
1597
|
-
and ("1011" in message or "bad gateway" in message or "going away" in message)
|
|
1644
|
+
return "websocket receive failed" in message and (
|
|
1645
|
+
"1011" in message or "bad gateway" in message or "going away" in message
|
|
1598
1646
|
)
|
|
1599
1647
|
|
|
1600
1648
|
|
|
@@ -1684,9 +1732,15 @@ def _is_channel_configured(
|
|
|
1684
1732
|
accounts = channel_cfg.get("accounts")
|
|
1685
1733
|
return isinstance(accounts, dict) and any(str(key).strip() for key in accounts.keys())
|
|
1686
1734
|
if channel == "feishu":
|
|
1687
|
-
return bool(
|
|
1735
|
+
return bool(
|
|
1736
|
+
str(channel_cfg.get("appId") or "").strip()
|
|
1737
|
+
and str(channel_cfg.get("appSecret") or "").strip()
|
|
1738
|
+
)
|
|
1688
1739
|
if channel == "wps-xiezuo":
|
|
1689
|
-
return bool(
|
|
1740
|
+
return bool(
|
|
1741
|
+
str(channel_cfg.get("appId") or "").strip()
|
|
1742
|
+
and str(channel_cfg.get("appSecret") or "").strip()
|
|
1743
|
+
)
|
|
1690
1744
|
return bool(channel_cfg)
|
|
1691
1745
|
|
|
1692
1746
|
|
|
@@ -1791,7 +1845,9 @@ def _ensure_local_node_tools() -> dict[str, str]:
|
|
|
1791
1845
|
if not node_path or not npx_path:
|
|
1792
1846
|
raise resolution_error(
|
|
1793
1847
|
"本地缺少 `node` 或 `npx`,飞书接入依赖官方 onboarding 工具",
|
|
1794
|
-
hints=[
|
|
1848
|
+
hints=[
|
|
1849
|
+
"先安装 Node.js,然后重试 `agentengine openclaw channel connect --channel feishu`"
|
|
1850
|
+
],
|
|
1795
1851
|
)
|
|
1796
1852
|
return {"node": node_path, "npx": npx_path}
|
|
1797
1853
|
|
|
@@ -1822,14 +1878,11 @@ async def _resolve_npx_cached_package_file(package_spec: str, relative_path: str
|
|
|
1822
1878
|
text=True,
|
|
1823
1879
|
)
|
|
1824
1880
|
if completed.returncode != 0:
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
)
|
|
1881
|
+
npm_error = completed.stderr.strip() or completed.stdout.strip() or package_spec
|
|
1882
|
+
raise OpenClawGatewayError(f"无法准备官方 npm 包缓存: {npm_error}")
|
|
1828
1883
|
|
|
1829
1884
|
npm_cache_root = Path(
|
|
1830
|
-
os.getenv("NPM_CONFIG_CACHE")
|
|
1831
|
-
or os.getenv("npm_config_cache")
|
|
1832
|
-
or str(Path.home() / ".npm")
|
|
1885
|
+
os.getenv("NPM_CONFIG_CACHE") or os.getenv("npm_config_cache") or str(Path.home() / ".npm")
|
|
1833
1886
|
)
|
|
1834
1887
|
pattern = f"_npx/**/node_modules/{package_name}/{relative_path}"
|
|
1835
1888
|
matches = list(npm_cache_root.glob(pattern))
|
|
@@ -1847,8 +1900,7 @@ async def _run_feishu_onboarding(existing_app_id: Optional[str]) -> dict[str, An
|
|
|
1847
1900
|
"@larksuite/openclaw-lark-tools@latest",
|
|
1848
1901
|
"dist/utils/install-prompts.js",
|
|
1849
1902
|
)
|
|
1850
|
-
script_body = textwrap.dedent(
|
|
1851
|
-
"""
|
|
1903
|
+
script_body = textwrap.dedent("""
|
|
1852
1904
|
const fs = require("fs");
|
|
1853
1905
|
const { runInstallAuthFlow } = require(__INSTALL_PROMPTS_PATH__);
|
|
1854
1906
|
|
|
@@ -1860,19 +1912,26 @@ async def _run_feishu_onboarding(existing_app_id: Optional[str]) -> dict[str, An
|
|
|
1860
1912
|
{},
|
|
1861
1913
|
false,
|
|
1862
1914
|
);
|
|
1863
|
-
fs.writeFileSync(
|
|
1915
|
+
fs.writeFileSync(
|
|
1916
|
+
process.env.KSADK_FEISHU_RESULT_PATH,
|
|
1917
|
+
JSON.stringify(result),
|
|
1918
|
+
"utf8",
|
|
1919
|
+
);
|
|
1864
1920
|
} catch (error) {
|
|
1865
1921
|
console.error(error);
|
|
1866
1922
|
process.exit(1);
|
|
1867
1923
|
}
|
|
1868
1924
|
})();
|
|
1869
|
-
"""
|
|
1870
|
-
|
|
1871
|
-
|
|
1925
|
+
""").replace("__INSTALL_PROMPTS_PATH__", json.dumps(str(install_prompts_path)))
|
|
1926
|
+
with tempfile.NamedTemporaryFile(
|
|
1927
|
+
"w", suffix=".cjs", delete=False, encoding="utf-8"
|
|
1928
|
+
) as script_file:
|
|
1872
1929
|
script_file.write(script_body.strip())
|
|
1873
1930
|
script_path = script_file.name
|
|
1874
1931
|
|
|
1875
|
-
with tempfile.NamedTemporaryFile(
|
|
1932
|
+
with tempfile.NamedTemporaryFile(
|
|
1933
|
+
"w", suffix=".json", delete=False, encoding="utf-8"
|
|
1934
|
+
) as result_file:
|
|
1876
1935
|
result_path = result_file.name
|
|
1877
1936
|
|
|
1878
1937
|
env = os.environ.copy()
|
|
@@ -1945,7 +2004,9 @@ def _resolve_weixin_account_id(
|
|
|
1945
2004
|
raise click.ClickException("检测到多个微信账号,请显式传入 --account-id")
|
|
1946
2005
|
if create_if_missing:
|
|
1947
2006
|
return "default"
|
|
1948
|
-
raise click.ClickException(
|
|
2007
|
+
raise click.ClickException(
|
|
2008
|
+
"尚未检测到微信账号,请先执行 `agentengine openclaw channel connect --channel weixin`"
|
|
2009
|
+
)
|
|
1949
2010
|
|
|
1950
2011
|
|
|
1951
2012
|
def _mutate_weixin_account_enabled(
|
|
@@ -2011,7 +2072,8 @@ def _mutate_feishu_connect_config(config: dict[str, Any], onboarding: dict[str,
|
|
|
2011
2072
|
feishu_cfg[key] = value
|
|
2012
2073
|
changed = True
|
|
2013
2074
|
|
|
2014
|
-
|
|
2075
|
+
user_info_value = onboarding.get("userInfo")
|
|
2076
|
+
user_info: dict[str, Any] = dict(user_info_value) if isinstance(user_info_value, dict) else {}
|
|
2015
2077
|
open_id = str(user_info.get("openId") or "").strip()
|
|
2016
2078
|
if open_id:
|
|
2017
2079
|
if feishu_cfg.get("dmPolicy") != "allowlist":
|
|
@@ -2105,8 +2167,12 @@ def _mutate_wps_xiezuo_connect_config(
|
|
|
2105
2167
|
bindings = config.setdefault("bindings", [])
|
|
2106
2168
|
if isinstance(bindings, list):
|
|
2107
2169
|
next_bindings = [
|
|
2108
|
-
item
|
|
2109
|
-
|
|
2170
|
+
item
|
|
2171
|
+
for item in bindings
|
|
2172
|
+
if not (
|
|
2173
|
+
isinstance(item, dict)
|
|
2174
|
+
and item.get("match", {}).get("channel") == WPS_XIEZUO_CHANNEL_KEY
|
|
2175
|
+
)
|
|
2110
2176
|
]
|
|
2111
2177
|
desired_binding = {
|
|
2112
2178
|
"type": "route",
|
|
@@ -2130,7 +2196,9 @@ def _mutate_wps_xiezuo_enabled(
|
|
|
2130
2196
|
) -> bool:
|
|
2131
2197
|
normalized_account = str(account_id or WPS_XIEZUO_DEFAULT_ACCOUNT_ID).strip()
|
|
2132
2198
|
if normalized_account and normalized_account != WPS_XIEZUO_DEFAULT_ACCOUNT_ID:
|
|
2133
|
-
raise click.ClickException(
|
|
2199
|
+
raise click.ClickException(
|
|
2200
|
+
"WPS 协作插件使用扁平 channel 配置,`--account-id` 仅支持 default"
|
|
2201
|
+
)
|
|
2134
2202
|
changed = _ensure_plugin_enabled(config, WPS_XIEZUO_PLUGIN_ID) if enabled else False
|
|
2135
2203
|
channels = config.setdefault("channels", {})
|
|
2136
2204
|
channel_cfg = channels.setdefault(WPS_XIEZUO_CHANNEL_KEY, {})
|
|
@@ -2152,7 +2220,9 @@ def _check_wps_xiezuo_local_deps() -> dict[str, Any]:
|
|
|
2152
2220
|
}
|
|
2153
2221
|
|
|
2154
2222
|
|
|
2155
|
-
@click.group(
|
|
2223
|
+
@click.group(
|
|
2224
|
+
"openclaw", context_settings=CONTEXT_SETTINGS, help=build_resource_group_help(OPENCLAW_RESOURCE)
|
|
2225
|
+
)
|
|
2156
2226
|
def openclaw():
|
|
2157
2227
|
pass
|
|
2158
2228
|
|
|
@@ -2211,8 +2281,15 @@ async def _run_openclaw_repair_action(
|
|
|
2211
2281
|
@click.option("--session", "-s", default=None, help="OpenClaw Session key")
|
|
2212
2282
|
@click.option("--message", "-m", default=None, help="连接后发送的初始消息")
|
|
2213
2283
|
@click.option("--thinking", default=None, help="Thinking level override")
|
|
2214
|
-
@click.option(
|
|
2215
|
-
|
|
2284
|
+
@click.option(
|
|
2285
|
+
"--history-limit",
|
|
2286
|
+
type=click.IntRange(1, 10000),
|
|
2287
|
+
default=None,
|
|
2288
|
+
help="历史条数 (默认使用 OpenClaw 默认值)",
|
|
2289
|
+
)
|
|
2290
|
+
@click.option(
|
|
2291
|
+
"--timeout-ms", type=click.IntRange(1, 86400000), default=None, help="Agent timeout ms"
|
|
2292
|
+
)
|
|
2216
2293
|
@click.option("--deliver", is_flag=True, help="Deliver assistant replies")
|
|
2217
2294
|
@click.option("--insecure", "-k", is_flag=True, help="跳过 SSL 证书验证")
|
|
2218
2295
|
@dry_run_option()
|
|
@@ -2279,10 +2356,14 @@ def tui_openclaw(
|
|
|
2279
2356
|
elif not agent_ref and str(state.get("endpoint") or "").strip():
|
|
2280
2357
|
resolved_endpoint = str(state.get("endpoint") or "").strip()
|
|
2281
2358
|
else:
|
|
2282
|
-
resolved_region, detail = asyncio.run(
|
|
2359
|
+
resolved_region, detail = asyncio.run(
|
|
2360
|
+
_resolve_openclaw_detail_or_raise(agent_ref, region=region)
|
|
2361
|
+
)
|
|
2283
2362
|
resolved_endpoint = str(detail.get("endpoint") or "").strip()
|
|
2284
2363
|
if not resolved_endpoint:
|
|
2285
|
-
raise click.ClickException(
|
|
2364
|
+
raise click.ClickException(
|
|
2365
|
+
"未解析到 OpenClaw Endpoint,请传入 --endpoint 或指定 OpenClaw ID/名称"
|
|
2366
|
+
)
|
|
2286
2367
|
|
|
2287
2368
|
secret_kind, gateway_secret = _select_openclaw_gateway_secret(
|
|
2288
2369
|
gateway_token=gateway_token,
|
|
@@ -2293,18 +2374,26 @@ def tui_openclaw(
|
|
|
2293
2374
|
auth_mode = _openclaw_auth_mode_from_sources(detail, state)
|
|
2294
2375
|
if auth_mode in {"token", "password"} and not gateway_secret:
|
|
2295
2376
|
raise click.ClickException(
|
|
2296
|
-
"当前 OpenClaw Gateway 为 token/password 模式,
|
|
2377
|
+
"当前 OpenClaw Gateway 为 token/password 模式,"
|
|
2378
|
+
"agentengine openclaw tui 需要 OpenClaw Gateway token/password。\n"
|
|
2297
2379
|
"请使用: agentengine openclaw tui --gateway-token <token>\n"
|
|
2298
2380
|
"或设置: OPENCLAW_GATEWAY_TOKEN=<token> agentengine openclaw tui\n"
|
|
2299
|
-
"如果部署时传过 OPENCLAW_GATEWAY_TOKEN,请重新运行部署让本地
|
|
2381
|
+
"如果部署时传过 OPENCLAW_GATEWAY_TOKEN,请重新运行部署让本地 "
|
|
2382
|
+
".agentengine.state 记录该 token。\n"
|
|
2300
2383
|
"注意:这里不是 AgentEngine API Key(ak-*)。"
|
|
2301
2384
|
)
|
|
2302
2385
|
|
|
2303
|
-
terminal_api_key =
|
|
2386
|
+
terminal_api_key = (
|
|
2387
|
+
gateway_secret
|
|
2388
|
+
or api_key
|
|
2389
|
+
or str(detail.get("api_key") or state.get("api_key") or "").strip()
|
|
2390
|
+
or None
|
|
2391
|
+
)
|
|
2304
2392
|
click.secho("🖥️ OpenClaw Native Remote TUI", fg="blue", bold=True)
|
|
2305
2393
|
click.echo(f" Endpoint: {resolved_endpoint}")
|
|
2306
2394
|
if gateway_secret:
|
|
2307
|
-
|
|
2395
|
+
masked_gateway_secret = _mask_openclaw_secret(gateway_secret)
|
|
2396
|
+
click.echo(f" Runtime Auth: OpenClaw Gateway {secret_kind} {masked_gateway_secret}")
|
|
2308
2397
|
elif terminal_api_key:
|
|
2309
2398
|
click.echo(f" Runtime Auth: Bearer {_mask_openclaw_secret(terminal_api_key)}")
|
|
2310
2399
|
else:
|
|
@@ -2337,7 +2426,9 @@ def tui_openclaw(
|
|
|
2337
2426
|
@region_option(default=None, envvar=None, help_text="区域 (默认优先读取 .agentengine.state)")
|
|
2338
2427
|
@click.option("--no-open", is_flag=True, help="仅打印 URL,不自动打开浏览器")
|
|
2339
2428
|
@cli_output_option()
|
|
2340
|
-
def gateway_open(
|
|
2429
|
+
def gateway_open(
|
|
2430
|
+
agent_ref: Optional[str], region: Optional[str], no_open: bool, output_mode: str | None
|
|
2431
|
+
):
|
|
2341
2432
|
"""打开 OpenClaw gateway Dashboard。"""
|
|
2342
2433
|
_ = output_mode
|
|
2343
2434
|
no_open = no_open or is_json_output()
|
|
@@ -2408,19 +2499,29 @@ def gateway_ws_url(agent_ref: Optional[str], region: Optional[str], output_mode:
|
|
|
2408
2499
|
"auth_mode": "cookie-session",
|
|
2409
2500
|
"note": "该 ws-url 依赖短链 cookie session,不承诺长期复用。",
|
|
2410
2501
|
}
|
|
2411
|
-
_emit_data_payload(
|
|
2502
|
+
_emit_data_payload(
|
|
2503
|
+
"OpenClaw Gateway 连接信息", payload, subtitle=str(detail.get("name") or "-")
|
|
2504
|
+
)
|
|
2412
2505
|
|
|
2413
2506
|
try:
|
|
2414
2507
|
asyncio.run(_run())
|
|
2415
2508
|
except Exception as e:
|
|
2416
|
-
_abort_openclaw_error(
|
|
2509
|
+
_abort_openclaw_error(
|
|
2510
|
+
e, context="获取 gateway ws-url 失败", argv=["openclaw", "gateway", "ws-url"]
|
|
2511
|
+
)
|
|
2417
2512
|
|
|
2418
2513
|
|
|
2419
2514
|
@openclaw_gateway.command("logs", context_settings=CONTEXT_SETTINGS)
|
|
2420
2515
|
@click.argument("agent_ref", required=False)
|
|
2421
2516
|
@region_option(default=None, envvar=None, help_text="区域 (默认优先读取 .agentengine.state)")
|
|
2422
2517
|
@click.option("--instance", default=None, help="实例名;不填则查询全部实例")
|
|
2423
|
-
@click.option(
|
|
2518
|
+
@click.option(
|
|
2519
|
+
"--log-type",
|
|
2520
|
+
type=click.Choice(["stdout", "log"], case_sensitive=False),
|
|
2521
|
+
default="stdout",
|
|
2522
|
+
show_default=True,
|
|
2523
|
+
help="日志类型",
|
|
2524
|
+
)
|
|
2424
2525
|
@click.option("--start-time", default=None, help="开始时间,支持 Unix 毫秒或 ISO-8601")
|
|
2425
2526
|
@click.option("--end-time", default=None, help="结束时间,支持 Unix 毫秒或 ISO-8601")
|
|
2426
2527
|
@cli_output_option()
|
|
@@ -2465,7 +2566,9 @@ def gateway_logs(
|
|
|
2465
2566
|
emit_json(payload)
|
|
2466
2567
|
return
|
|
2467
2568
|
|
|
2468
|
-
print_title(
|
|
2569
|
+
print_title(
|
|
2570
|
+
"OpenClaw Gateway 日志", str(detail.get("name") or detail.get("agent_id") or "-")
|
|
2571
|
+
)
|
|
2469
2572
|
print_kv("实例", str(resp.get("instance") or "all"))
|
|
2470
2573
|
print_kv("日志类型", str(resp.get("log_type") or log_type))
|
|
2471
2574
|
print_kv("日志条数", str(resp.get("total") or 0))
|
|
@@ -2479,13 +2582,20 @@ def gateway_logs(
|
|
|
2479
2582
|
try:
|
|
2480
2583
|
asyncio.run(_run())
|
|
2481
2584
|
except Exception as e:
|
|
2482
|
-
_abort_openclaw_error(
|
|
2585
|
+
_abort_openclaw_error(
|
|
2586
|
+
e, context="获取 gateway 日志失败", argv=["openclaw", "gateway", "logs"]
|
|
2587
|
+
)
|
|
2483
2588
|
|
|
2484
2589
|
|
|
2485
2590
|
@openclaw_gateway.command("doctor", context_settings=CONTEXT_SETTINGS)
|
|
2486
2591
|
@click.argument("agent_ref", required=False)
|
|
2487
2592
|
@region_option(default=None, envvar=None, help_text="区域 (默认优先读取 .agentengine.state)")
|
|
2488
|
-
@click.option(
|
|
2593
|
+
@click.option(
|
|
2594
|
+
"--fix",
|
|
2595
|
+
"do_fix",
|
|
2596
|
+
is_flag=True,
|
|
2597
|
+
help="不走 gateway 内诊断,改为通过控制面执行 openclaw doctor --fix",
|
|
2598
|
+
)
|
|
2489
2599
|
@cli_output_option()
|
|
2490
2600
|
def gateway_doctor(
|
|
2491
2601
|
agent_ref: Optional[str],
|
|
@@ -2519,7 +2629,7 @@ def gateway_doctor(
|
|
|
2519
2629
|
"ws_url": info.ws_url,
|
|
2520
2630
|
}
|
|
2521
2631
|
)
|
|
2522
|
-
|
|
2632
|
+
await gateway.connect()
|
|
2523
2633
|
checks.append(
|
|
2524
2634
|
{
|
|
2525
2635
|
"name": "cookie_ws_handshake",
|
|
@@ -2606,7 +2716,12 @@ def openclaw_channel():
|
|
|
2606
2716
|
@openclaw_channel.command("status", context_settings=CONTEXT_SETTINGS)
|
|
2607
2717
|
@click.argument("agent_ref", required=False)
|
|
2608
2718
|
@region_option(default=None, envvar=None, help_text="区域 (默认优先读取 .agentengine.state)")
|
|
2609
|
-
@click.option(
|
|
2719
|
+
@click.option(
|
|
2720
|
+
"--channel",
|
|
2721
|
+
type=click.Choice(OPENCLAW_CHANNELS, case_sensitive=False),
|
|
2722
|
+
default=None,
|
|
2723
|
+
help="指定 channel",
|
|
2724
|
+
)
|
|
2610
2725
|
@click.option("--probe", is_flag=True, help="触发远端 probe 刷新 channel 快照")
|
|
2611
2726
|
@cli_output_option()
|
|
2612
2727
|
def channel_status(
|
|
@@ -2626,7 +2741,9 @@ def channel_status(
|
|
|
2626
2741
|
gateway = _build_gateway_client(resolved_region, detail)
|
|
2627
2742
|
try:
|
|
2628
2743
|
await gateway.connect()
|
|
2629
|
-
snapshot = await gateway.channels_status(
|
|
2744
|
+
snapshot = await gateway.channels_status(
|
|
2745
|
+
probe=probe, timeout_ms=8_000 if probe else None
|
|
2746
|
+
)
|
|
2630
2747
|
finally:
|
|
2631
2748
|
await gateway.close()
|
|
2632
2749
|
|
|
@@ -2640,26 +2757,67 @@ def channel_status(
|
|
|
2640
2757
|
"snapshot": snapshot,
|
|
2641
2758
|
"selected": _extract_channel_snapshot(snapshot, normalized_channel),
|
|
2642
2759
|
}
|
|
2643
|
-
_emit_data_payload(
|
|
2760
|
+
_emit_data_payload(
|
|
2761
|
+
"OpenClaw Channel 状态", payload, subtitle=str(detail.get("name") or "-")
|
|
2762
|
+
)
|
|
2644
2763
|
|
|
2645
2764
|
try:
|
|
2646
2765
|
asyncio.run(_run())
|
|
2647
2766
|
except Exception as e:
|
|
2648
|
-
_abort_openclaw_error(
|
|
2767
|
+
_abort_openclaw_error(
|
|
2768
|
+
e, context="获取 channel 状态失败", argv=["openclaw", "channel", "status"]
|
|
2769
|
+
)
|
|
2649
2770
|
|
|
2650
2771
|
|
|
2651
|
-
@openclaw_channel.command(
|
|
2772
|
+
@openclaw_channel.command(
|
|
2773
|
+
"connect", context_settings=CONTEXT_SETTINGS, help=OPENCLAW_CHANNEL_CONNECT_HELP
|
|
2774
|
+
)
|
|
2652
2775
|
@click.argument("agent_ref", required=False)
|
|
2653
2776
|
@region_option(default=None, envvar=None, help_text="区域 (默认优先读取 .agentengine.state)")
|
|
2654
|
-
@click.option(
|
|
2777
|
+
@click.option(
|
|
2778
|
+
"--channel",
|
|
2779
|
+
"channel_name",
|
|
2780
|
+
type=click.Choice(OPENCLAW_CHANNELS, case_sensitive=False),
|
|
2781
|
+
required=True,
|
|
2782
|
+
help="目标 channel",
|
|
2783
|
+
)
|
|
2655
2784
|
@click.option("--open-qr", is_flag=True, help="仅微信:在本地浏览器额外打开二维码链接")
|
|
2656
2785
|
@click.option("--app-id", "wps_xiezuo_app_id", default=None, help="仅 WPS 协作:开放平台应用 ID")
|
|
2657
|
-
@click.option(
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
@click.option(
|
|
2661
|
-
|
|
2662
|
-
|
|
2786
|
+
@click.option(
|
|
2787
|
+
"--app-secret", "wps_xiezuo_app_secret", default=None, help="仅 WPS 协作:开放平台应用密钥"
|
|
2788
|
+
)
|
|
2789
|
+
@click.option(
|
|
2790
|
+
"--account-id",
|
|
2791
|
+
"wps_xiezuo_account_id",
|
|
2792
|
+
default="default",
|
|
2793
|
+
help="仅 WPS 协作:账号 ID;当前只支持 default",
|
|
2794
|
+
)
|
|
2795
|
+
@click.option(
|
|
2796
|
+
"--agent-id",
|
|
2797
|
+
"wps_xiezuo_agent_id",
|
|
2798
|
+
default="main",
|
|
2799
|
+
help="仅 WPS 协作:消息路由到的 OpenClaw agentId",
|
|
2800
|
+
)
|
|
2801
|
+
@click.option(
|
|
2802
|
+
"--dm-policy",
|
|
2803
|
+
"wps_xiezuo_dm_policy",
|
|
2804
|
+
type=click.Choice(("disabled", "open", "pairing", "allowlist")),
|
|
2805
|
+
default="pairing",
|
|
2806
|
+
help="仅 WPS 协作:私聊策略,默认 pairing",
|
|
2807
|
+
)
|
|
2808
|
+
@click.option(
|
|
2809
|
+
"--group-policy",
|
|
2810
|
+
"wps_xiezuo_group_policy",
|
|
2811
|
+
type=click.Choice(("open", "allowlist")),
|
|
2812
|
+
default="open",
|
|
2813
|
+
help="仅 WPS 协作:群聊策略,默认 open",
|
|
2814
|
+
)
|
|
2815
|
+
@click.option(
|
|
2816
|
+
"--base-url",
|
|
2817
|
+
"wps_xiezuo_base_url",
|
|
2818
|
+
default="https://openapi.wps.cn",
|
|
2819
|
+
help="仅 WPS 协作:WPS OpenAPI 基础地址",
|
|
2820
|
+
)
|
|
2663
2821
|
def channel_connect(
|
|
2664
2822
|
agent_ref: Optional[str],
|
|
2665
2823
|
region: Optional[str],
|
|
@@ -2779,13 +2937,18 @@ def channel_connect(
|
|
|
2779
2937
|
if normalized_channel == "wps-xiezuo":
|
|
2780
2938
|
app_id = str(wps_xiezuo_app_id or "").strip()
|
|
2781
2939
|
app_secret = str(wps_xiezuo_app_secret or "").strip()
|
|
2782
|
-
account_id =
|
|
2940
|
+
account_id = (
|
|
2941
|
+
str(wps_xiezuo_account_id or WPS_XIEZUO_DEFAULT_ACCOUNT_ID).strip()
|
|
2942
|
+
or WPS_XIEZUO_DEFAULT_ACCOUNT_ID
|
|
2943
|
+
)
|
|
2783
2944
|
if not app_id:
|
|
2784
2945
|
raise click.ClickException("连接 WPS 协作 channel 必须提供 --app-id")
|
|
2785
2946
|
if not app_secret:
|
|
2786
2947
|
raise click.ClickException("连接 WPS 协作 channel 必须提供 --app-secret")
|
|
2787
2948
|
if account_id != WPS_XIEZUO_DEFAULT_ACCOUNT_ID:
|
|
2788
|
-
raise click.ClickException(
|
|
2949
|
+
raise click.ClickException(
|
|
2950
|
+
"WPS 协作插件使用扁平 channel 配置,`--account-id` 仅支持 default"
|
|
2951
|
+
)
|
|
2789
2952
|
apply_gateway = _build_gateway_client(resolved_region, detail)
|
|
2790
2953
|
changed = False
|
|
2791
2954
|
try:
|
|
@@ -2800,7 +2963,8 @@ def channel_connect(
|
|
|
2800
2963
|
agent_id=str(wps_xiezuo_agent_id or "main").strip() or "main",
|
|
2801
2964
|
dm_policy=wps_xiezuo_dm_policy,
|
|
2802
2965
|
group_policy=wps_xiezuo_group_policy,
|
|
2803
|
-
base_url=str(wps_xiezuo_base_url or "https://openapi.wps.cn").strip()
|
|
2966
|
+
base_url=str(wps_xiezuo_base_url or "https://openapi.wps.cn").strip()
|
|
2967
|
+
or "https://openapi.wps.cn",
|
|
2804
2968
|
)
|
|
2805
2969
|
if changed:
|
|
2806
2970
|
await _config_apply_and_wait_for_reload(
|
|
@@ -2842,9 +3006,12 @@ def channel_connect(
|
|
|
2842
3006
|
await bootstrap_gateway.close()
|
|
2843
3007
|
|
|
2844
3008
|
config, _ = _extract_config_state(cfg_snapshot)
|
|
2845
|
-
existing_app_id =
|
|
2846
|
-
(
|
|
2847
|
-
|
|
3009
|
+
existing_app_id = (
|
|
3010
|
+
str(
|
|
3011
|
+
((config.get("channels") or {}).get(FEISHU_CHANNEL_KEY) or {}).get("appId") or ""
|
|
3012
|
+
).strip()
|
|
3013
|
+
or None
|
|
3014
|
+
)
|
|
2848
3015
|
onboarding = await _run_feishu_onboarding(existing_app_id)
|
|
2849
3016
|
changed_config = copy.deepcopy(config)
|
|
2850
3017
|
changed = _mutate_feishu_connect_config(changed_config, onboarding)
|
|
@@ -2885,7 +3052,9 @@ def channel_connect(
|
|
|
2885
3052
|
try:
|
|
2886
3053
|
asyncio.run(_run())
|
|
2887
3054
|
except Exception as e:
|
|
2888
|
-
_abort_openclaw_error(
|
|
3055
|
+
_abort_openclaw_error(
|
|
3056
|
+
e, context="channel connect 失败", argv=["openclaw", "channel", "connect"]
|
|
3057
|
+
)
|
|
2889
3058
|
|
|
2890
3059
|
|
|
2891
3060
|
def _run_channel_toggle_command(
|
|
@@ -2954,18 +3123,28 @@ def _run_channel_toggle_command(
|
|
|
2954
3123
|
"enabled": enabled,
|
|
2955
3124
|
"status": _extract_channel_snapshot(snapshot, normalized_channel),
|
|
2956
3125
|
}
|
|
2957
|
-
_emit_data_payload(
|
|
3126
|
+
_emit_data_payload(
|
|
3127
|
+
f"OpenClaw Channel {action.title()}", payload, subtitle=normalized_channel
|
|
3128
|
+
)
|
|
2958
3129
|
|
|
2959
3130
|
try:
|
|
2960
3131
|
asyncio.run(_run())
|
|
2961
3132
|
except Exception as e:
|
|
2962
|
-
_abort_openclaw_error(
|
|
3133
|
+
_abort_openclaw_error(
|
|
3134
|
+
e, context=f"channel {action} 失败", argv=["openclaw", "channel", action]
|
|
3135
|
+
)
|
|
2963
3136
|
|
|
2964
3137
|
|
|
2965
3138
|
@openclaw_channel.command("enable", context_settings=CONTEXT_SETTINGS)
|
|
2966
3139
|
@click.argument("agent_ref", required=False)
|
|
2967
3140
|
@region_option(default=None, envvar=None, help_text="区域 (默认优先读取 .agentengine.state)")
|
|
2968
|
-
@click.option(
|
|
3141
|
+
@click.option(
|
|
3142
|
+
"--channel",
|
|
3143
|
+
"channel_name",
|
|
3144
|
+
type=click.Choice(OPENCLAW_CHANNELS, case_sensitive=False),
|
|
3145
|
+
required=True,
|
|
3146
|
+
help="目标 channel",
|
|
3147
|
+
)
|
|
2969
3148
|
@click.option("--account-id", default=None, help="账号 ID;飞书 V1 仅支持 default")
|
|
2970
3149
|
def channel_enable(
|
|
2971
3150
|
agent_ref: Optional[str],
|
|
@@ -2987,7 +3166,13 @@ def channel_enable(
|
|
|
2987
3166
|
@openclaw_channel.command("disable", context_settings=CONTEXT_SETTINGS)
|
|
2988
3167
|
@click.argument("agent_ref", required=False)
|
|
2989
3168
|
@region_option(default=None, envvar=None, help_text="区域 (默认优先读取 .agentengine.state)")
|
|
2990
|
-
@click.option(
|
|
3169
|
+
@click.option(
|
|
3170
|
+
"--channel",
|
|
3171
|
+
"channel_name",
|
|
3172
|
+
type=click.Choice(OPENCLAW_CHANNELS, case_sensitive=False),
|
|
3173
|
+
required=True,
|
|
3174
|
+
help="目标 channel",
|
|
3175
|
+
)
|
|
2991
3176
|
@click.option("--account-id", default=None, help="账号 ID;飞书 V1 仅支持 default")
|
|
2992
3177
|
def channel_disable(
|
|
2993
3178
|
agent_ref: Optional[str],
|
|
@@ -3009,9 +3194,16 @@ def channel_disable(
|
|
|
3009
3194
|
@openclaw_channel.command("doctor", context_settings=CONTEXT_SETTINGS)
|
|
3010
3195
|
@click.argument("agent_ref", required=False)
|
|
3011
3196
|
@region_option(default=None, envvar=None, help_text="区域 (默认优先读取 .agentengine.state)")
|
|
3012
|
-
@click.option(
|
|
3197
|
+
@click.option(
|
|
3198
|
+
"--channel",
|
|
3199
|
+
type=click.Choice(OPENCLAW_CHANNELS, case_sensitive=False),
|
|
3200
|
+
default=None,
|
|
3201
|
+
help="指定 channel",
|
|
3202
|
+
)
|
|
3013
3203
|
@cli_output_option()
|
|
3014
|
-
def channel_doctor(
|
|
3204
|
+
def channel_doctor(
|
|
3205
|
+
agent_ref: Optional[str], region: Optional[str], channel: Optional[str], output_mode: str | None
|
|
3206
|
+
):
|
|
3015
3207
|
"""检查 channel 接入前置条件。"""
|
|
3016
3208
|
_ = output_mode
|
|
3017
3209
|
normalized_channel = str(channel).lower() if channel else None
|
|
@@ -3028,20 +3220,28 @@ def channel_doctor(agent_ref: Optional[str], region: Optional[str], channel: Opt
|
|
|
3028
3220
|
gateway = _build_gateway_client(resolved_region, detail)
|
|
3029
3221
|
try:
|
|
3030
3222
|
info = await gateway.build_access_info()
|
|
3031
|
-
checks.append(
|
|
3223
|
+
checks.append(
|
|
3224
|
+
{"name": "dashboard_short_link", "ok": True, "dashboard_url": info.access_url}
|
|
3225
|
+
)
|
|
3032
3226
|
await gateway.connect()
|
|
3033
3227
|
methods = gateway.methods
|
|
3034
3228
|
checks.append({"name": "cookie_ws_handshake", "ok": True, "methods": len(methods)})
|
|
3035
3229
|
snapshot = await gateway.channels_status(probe=False)
|
|
3036
3230
|
config_snapshot = await gateway.config_get()
|
|
3037
|
-
config =
|
|
3231
|
+
config = (
|
|
3232
|
+
config_snapshot.get("config")
|
|
3233
|
+
if isinstance(config_snapshot.get("config"), dict)
|
|
3234
|
+
else {}
|
|
3235
|
+
)
|
|
3038
3236
|
except Exception as exc:
|
|
3039
3237
|
checks.append({"name": "gateway_connectivity", "ok": False, "error": str(exc)})
|
|
3040
3238
|
finally:
|
|
3041
3239
|
await gateway.close()
|
|
3042
3240
|
|
|
3043
3241
|
channels_to_check = [normalized_channel] if normalized_channel else list(OPENCLAW_CHANNELS)
|
|
3044
|
-
plugin_entries = (
|
|
3242
|
+
plugin_entries = (
|
|
3243
|
+
((config.get("plugins") or {}).get("entries") or {}) if isinstance(config, dict) else {}
|
|
3244
|
+
)
|
|
3045
3245
|
for item in channels_to_check:
|
|
3046
3246
|
selected_snapshot = _extract_channel_snapshot(snapshot, item)
|
|
3047
3247
|
configured = _is_channel_configured(item, config=config, snapshot=selected_snapshot)
|
|
@@ -3059,7 +3259,9 @@ def channel_doctor(agent_ref: Optional[str], region: Optional[str], channel: Opt
|
|
|
3059
3259
|
name="weixin_status_snapshot",
|
|
3060
3260
|
available=selected_snapshot is not None,
|
|
3061
3261
|
configured=configured,
|
|
3062
|
-
connect_required_message=
|
|
3262
|
+
connect_required_message=(
|
|
3263
|
+
"首次连接前微信状态快照可能为空," "执行 channel connect 后会自动补齐"
|
|
3264
|
+
),
|
|
3063
3265
|
)
|
|
3064
3266
|
)
|
|
3065
3267
|
checks.append(
|
|
@@ -3067,7 +3269,9 @@ def channel_doctor(agent_ref: Optional[str], region: Optional[str], channel: Opt
|
|
|
3067
3269
|
name="weixin_qr_rpc",
|
|
3068
3270
|
available="web.login.start" in methods and "web.login.wait" in methods,
|
|
3069
3271
|
configured=configured,
|
|
3070
|
-
connect_required_message=
|
|
3272
|
+
connect_required_message=(
|
|
3273
|
+
"首次连接会先自动启用 bundled weixin plugin," "然后再暴露扫码 RPC"
|
|
3274
|
+
),
|
|
3071
3275
|
connect_required_ok=False,
|
|
3072
3276
|
required_methods=["web.login.start", "web.login.wait"],
|
|
3073
3277
|
)
|
|
@@ -3085,7 +3289,10 @@ def channel_doctor(agent_ref: Optional[str], region: Optional[str], channel: Opt
|
|
|
3085
3289
|
name="feishu_status_snapshot",
|
|
3086
3290
|
available=selected_snapshot is not None,
|
|
3087
3291
|
configured=configured,
|
|
3088
|
-
connect_required_message=
|
|
3292
|
+
connect_required_message=(
|
|
3293
|
+
"飞书尚未完成 connect/onboarding,"
|
|
3294
|
+
"首次接入前不会出现在 channel snapshot 中"
|
|
3295
|
+
),
|
|
3089
3296
|
)
|
|
3090
3297
|
)
|
|
3091
3298
|
node_path = shutil.which("node")
|
|
@@ -3111,7 +3318,9 @@ def channel_doctor(agent_ref: Optional[str], region: Optional[str], channel: Opt
|
|
|
3111
3318
|
name="wps_xiezuo_status_snapshot",
|
|
3112
3319
|
available=selected_snapshot is not None,
|
|
3113
3320
|
configured=configured,
|
|
3114
|
-
connect_required_message=
|
|
3321
|
+
connect_required_message=(
|
|
3322
|
+
"WPS 协作尚未完成配置," "首次 connect 前不会出现在 channel snapshot 中"
|
|
3323
|
+
),
|
|
3115
3324
|
)
|
|
3116
3325
|
)
|
|
3117
3326
|
dep_check = _check_wps_xiezuo_local_deps()
|
|
@@ -3134,15 +3343,20 @@ def channel_doctor(agent_ref: Optional[str], region: Optional[str], channel: Opt
|
|
|
3134
3343
|
|
|
3135
3344
|
try:
|
|
3136
3345
|
payload = asyncio.run(_run())
|
|
3137
|
-
_emit_data_payload(
|
|
3346
|
+
_emit_data_payload(
|
|
3347
|
+
"OpenClaw Channel Doctor", payload, subtitle=str(payload.get("name") or "-")
|
|
3348
|
+
)
|
|
3138
3349
|
except Exception as e:
|
|
3139
|
-
_abort_openclaw_error(
|
|
3350
|
+
_abort_openclaw_error(
|
|
3351
|
+
e, context="channel doctor 执行失败", argv=["openclaw", "channel", "doctor"]
|
|
3352
|
+
)
|
|
3140
3353
|
|
|
3141
3354
|
|
|
3142
3355
|
@openclaw.command("deploy", context_settings=CONTEXT_SETTINGS)
|
|
3143
3356
|
@click.option("--name", "-n", default=None, help="OpenClaw 名称 (默认: openclaw-gateway)")
|
|
3144
3357
|
@click.option(
|
|
3145
|
-
"--region",
|
|
3358
|
+
"--region",
|
|
3359
|
+
"-r",
|
|
3146
3360
|
default="cn-beijing-6",
|
|
3147
3361
|
envvar="KSYUN_REGION",
|
|
3148
3362
|
help="部署区域 (默认: cn-beijing-6)",
|
|
@@ -3154,7 +3368,9 @@ def channel_doctor(agent_ref: Optional[str], region: Optional[str], channel: Opt
|
|
|
3154
3368
|
help="安全预设: relaxed | strict | strictest (安全测试建议 strictest)",
|
|
3155
3369
|
)
|
|
3156
3370
|
@click.option("--strict-mode", "security_profile", flag_value="strict", help="快捷开启严格模式")
|
|
3157
|
-
@click.option(
|
|
3371
|
+
@click.option(
|
|
3372
|
+
"--strictest", "security_profile", flag_value="strictest", help="快捷开启最严格安全模式"
|
|
3373
|
+
)
|
|
3158
3374
|
@click.option(
|
|
3159
3375
|
"--image",
|
|
3160
3376
|
default=None,
|
|
@@ -3179,7 +3395,9 @@ def channel_doctor(agent_ref: Optional[str], region: Optional[str], channel: Opt
|
|
|
3179
3395
|
help="额外透传自定义环境变量,格式 KEY=VALUE,可重复传入",
|
|
3180
3396
|
)
|
|
3181
3397
|
@click.option("--storage-size-gi", type=int, default=20, show_default=True, help="PVC 容量(Gi)")
|
|
3182
|
-
@click.option(
|
|
3398
|
+
@click.option(
|
|
3399
|
+
"--storage-mount-path", default=None, help="PVC 挂载目录(默认: /home/node/.openclaw)"
|
|
3400
|
+
)
|
|
3183
3401
|
@click.option("--no-storage", is_flag=True, help="禁用默认 PVC 挂载")
|
|
3184
3402
|
@network_options
|
|
3185
3403
|
@dry_run_option("仅显示请求,不实际部署")
|
|
@@ -3222,7 +3440,8 @@ def deploy(
|
|
|
3222
3440
|
# 一键创建最严格实例(适合安全测试)
|
|
3223
3441
|
agentengine openclaw deploy --security-profile strictest
|
|
3224
3442
|
# 显式指定模型
|
|
3225
|
-
agentengine openclaw deploy --model-base-url https://api.example.com/v1
|
|
3443
|
+
agentengine openclaw deploy --model-base-url https://api.example.com/v1 \
|
|
3444
|
+
--model-api-key sk-xxx
|
|
3226
3445
|
# 使用自定义镜像
|
|
3227
3446
|
agentengine openclaw deploy --image ghcr.io/my-org/openclaw:v2
|
|
3228
3447
|
# 透传业务自定义环境变量
|
|
@@ -3316,10 +3535,11 @@ async def _deploy_openclaw(
|
|
|
3316
3535
|
dry_run: bool,
|
|
3317
3536
|
):
|
|
3318
3537
|
"""异步部署 OpenClaw"""
|
|
3319
|
-
from ksadk.api import AgentEngineClient
|
|
3320
|
-
from ksadk.deployment.state import load_state, save_state, clear_state
|
|
3321
3538
|
from dotenv import dotenv_values
|
|
3322
3539
|
|
|
3540
|
+
from ksadk.api import AgentEngineClient
|
|
3541
|
+
from ksadk.deployment.state import clear_state, load_state, save_state
|
|
3542
|
+
|
|
3323
3543
|
# 自动加载当前目录 .env(仅补充未导出的变量,不覆盖已导出的 shell 环境)
|
|
3324
3544
|
project_dir = Path(".").resolve()
|
|
3325
3545
|
env_file = project_dir / ".env"
|
|
@@ -3377,13 +3597,15 @@ async def _deploy_openclaw(
|
|
|
3377
3597
|
env_vars.update(custom_env_vars)
|
|
3378
3598
|
env_vars = _normalize_openclaw_gateway_auth_env(env_vars)
|
|
3379
3599
|
if not str(env_vars.get("OPENCLAW_MODEL_CATALOG_JSON") or "").strip():
|
|
3380
|
-
catalog_api_base = (
|
|
3381
|
-
|
|
3382
|
-
|
|
3600
|
+
catalog_api_base = model_base_url or _resolve_env(
|
|
3601
|
+
"OPENCLAW_MODEL_BASE_URL",
|
|
3602
|
+
"OPENAI_BASE_URL",
|
|
3603
|
+
"OPENAI_API_BASE",
|
|
3604
|
+
"LLM_API_BASE",
|
|
3605
|
+
"MODEL_API_BASE",
|
|
3383
3606
|
)
|
|
3384
|
-
catalog_api_key = (
|
|
3385
|
-
|
|
3386
|
-
or _resolve_env("OPENCLAW_MODEL_API_KEY", "OPENAI_API_KEY", "LLM_API_KEY", "MODEL_API_KEY")
|
|
3607
|
+
catalog_api_key = model_api_key or _resolve_env(
|
|
3608
|
+
"OPENCLAW_MODEL_API_KEY", "OPENAI_API_KEY", "LLM_API_KEY", "MODEL_API_KEY"
|
|
3387
3609
|
)
|
|
3388
3610
|
provider_catalog = await fetch_provider_model_catalog(
|
|
3389
3611
|
api_base=catalog_api_base,
|
|
@@ -3391,7 +3613,9 @@ async def _deploy_openclaw(
|
|
|
3391
3613
|
)
|
|
3392
3614
|
selected_catalog = _filter_openclaw_provider_catalog(env_vars, provider_catalog)
|
|
3393
3615
|
if _apply_openclaw_provider_model_catalog(env_vars, selected_catalog):
|
|
3394
|
-
print_info(
|
|
3616
|
+
print_info(
|
|
3617
|
+
f"已从模型服务 /v1/models 同步 OpenClaw 模型元数据: {len(selected_catalog)} 个"
|
|
3618
|
+
)
|
|
3395
3619
|
memory_config = _build_openclaw_memory_config(
|
|
3396
3620
|
memory_system=memory_system,
|
|
3397
3621
|
mem0_instance_id=mem0_instance_id,
|
|
@@ -3445,7 +3669,9 @@ async def _deploy_openclaw(
|
|
|
3445
3669
|
if storage_config:
|
|
3446
3670
|
request_data["storage"] = storage_config
|
|
3447
3671
|
if existing_agent_id and include_storage_on_update and no_storage:
|
|
3448
|
-
print_warn(
|
|
3672
|
+
print_warn(
|
|
3673
|
+
"更新已有 OpenClaw 时 `--no-storage` 不会删除服务端既有挂盘配置;默认保留已有配置。"
|
|
3674
|
+
)
|
|
3449
3675
|
network_payload = build_network_payload(
|
|
3450
3676
|
enable_public_access=enable_public_access,
|
|
3451
3677
|
enable_vpc_access=enable_vpc_access,
|
|
@@ -3456,8 +3682,12 @@ async def _deploy_openclaw(
|
|
|
3456
3682
|
region=region,
|
|
3457
3683
|
dry_run=dry_run,
|
|
3458
3684
|
)
|
|
3459
|
-
|
|
3460
|
-
|
|
3685
|
+
# Create 默认开公网;update 使用原始 payload,None 表示保留现有配置。
|
|
3686
|
+
create_network_payload = dict(network_payload) if network_payload is not None else {}
|
|
3687
|
+
if "enable_public_access" not in create_network_payload:
|
|
3688
|
+
create_network_payload["enable_public_access"] = True
|
|
3689
|
+
if create_network_payload:
|
|
3690
|
+
request_data["network"] = create_network_payload
|
|
3461
3691
|
|
|
3462
3692
|
# 镜像凭证:按目标镜像地址判断仓库类型,避免企业版/第三方误用 KSYUN_ACCOUNT_ID。
|
|
3463
3693
|
image_credential = None
|
|
@@ -3473,12 +3703,15 @@ async def _deploy_openclaw(
|
|
|
3473
3703
|
request_data["image_credential"] = image_credential
|
|
3474
3704
|
elif kcr_password and not kcr_username and registry_kind != "personal_kcr":
|
|
3475
3705
|
print_warn(
|
|
3476
|
-
|
|
3706
|
+
"检测到 KCR_PASSWORD 但缺少 KCR_USERNAME,已忽略"
|
|
3707
|
+
f"{registry_kind_label(registry_kind)}镜像凭证;"
|
|
3477
3708
|
"企业版 KCR 和第三方镜像仓库必须配置 KCR_USERNAME + KCR_PASSWORD"
|
|
3478
3709
|
)
|
|
3479
3710
|
elif "/agentengine-public/" not in image_ref:
|
|
3480
3711
|
if registry_kind == "personal_kcr":
|
|
3481
|
-
print_warn(
|
|
3712
|
+
print_warn(
|
|
3713
|
+
"未配置个人版 KCR 镜像凭证 (KSYUN_ACCOUNT_ID/KCR_PASSWORD),私有镜像可能无法拉取"
|
|
3714
|
+
)
|
|
3482
3715
|
else:
|
|
3483
3716
|
print_warn(
|
|
3484
3717
|
f"未配置{registry_kind_label(registry_kind)}镜像凭证 "
|
|
@@ -3534,12 +3767,13 @@ async def _deploy_openclaw(
|
|
|
3534
3767
|
except Exception as update_err:
|
|
3535
3768
|
err_msg = str(update_err)
|
|
3536
3769
|
not_found = (
|
|
3537
|
-
"code: 404" in err_msg.lower()
|
|
3538
|
-
or "agent not found" in err_msg.lower()
|
|
3770
|
+
"code: 404" in err_msg.lower() or "agent not found" in err_msg.lower()
|
|
3539
3771
|
)
|
|
3540
3772
|
if not not_found:
|
|
3541
3773
|
raise
|
|
3542
|
-
print_warn(
|
|
3774
|
+
print_warn(
|
|
3775
|
+
f"本地状态失效 ({existing_agent_id}),将自动回退为新建: {update_err}"
|
|
3776
|
+
)
|
|
3543
3777
|
cleared = clear_state(project_dir, key=existing_agent_id)
|
|
3544
3778
|
if cleared:
|
|
3545
3779
|
print_info("已清理失效的 .agentengine.state")
|
|
@@ -3564,10 +3798,12 @@ async def _deploy_openclaw(
|
|
|
3564
3798
|
attempts=12,
|
|
3565
3799
|
interval_seconds=5,
|
|
3566
3800
|
include_api_key=True,
|
|
3567
|
-
detail_fetcher=lambda agent_ref, include_api_key:
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3801
|
+
detail_fetcher=lambda agent_ref, include_api_key: (
|
|
3802
|
+
_get_openclaw_detail_with_client(
|
|
3803
|
+
client,
|
|
3804
|
+
agent_ref,
|
|
3805
|
+
include_api_key=include_api_key,
|
|
3806
|
+
)
|
|
3571
3807
|
),
|
|
3572
3808
|
suppress_transient_not_found_log=True,
|
|
3573
3809
|
)
|
|
@@ -3579,8 +3815,7 @@ async def _deploy_openclaw(
|
|
|
3579
3815
|
else:
|
|
3580
3816
|
print_warn("实例创建中,稍后使用 'agentengine openclaw list' 查看")
|
|
3581
3817
|
elif agent_id and (
|
|
3582
|
-
not str(endpoint or "").strip()
|
|
3583
|
-
or not str(api_key or "").strip()
|
|
3818
|
+
not str(endpoint or "").strip() or not str(api_key or "").strip()
|
|
3584
3819
|
):
|
|
3585
3820
|
latest = await get_latest_agent_access(
|
|
3586
3821
|
client,
|
|
@@ -3590,10 +3825,12 @@ async def _deploy_openclaw(
|
|
|
3590
3825
|
initial_delay_seconds=2,
|
|
3591
3826
|
require_complete_access=True,
|
|
3592
3827
|
include_api_key=True,
|
|
3593
|
-
detail_fetcher=lambda agent_ref, include_api_key:
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3828
|
+
detail_fetcher=lambda agent_ref, include_api_key: (
|
|
3829
|
+
_get_openclaw_detail_with_client(
|
|
3830
|
+
client,
|
|
3831
|
+
agent_ref,
|
|
3832
|
+
include_api_key=include_api_key,
|
|
3833
|
+
)
|
|
3597
3834
|
),
|
|
3598
3835
|
suppress_transient_not_found_log=True,
|
|
3599
3836
|
)
|
|
@@ -3623,11 +3860,13 @@ async def _deploy_openclaw(
|
|
|
3623
3860
|
state_payload["openclaw_gateway_token"] = state_gateway_token
|
|
3624
3861
|
save_state(project_dir, state_payload)
|
|
3625
3862
|
|
|
3626
|
-
#
|
|
3863
|
+
# 更新已有实例才回读;新建后立即查询可能早于底层落库。
|
|
3627
3864
|
if updated_existing_agent and agent_id:
|
|
3628
3865
|
try:
|
|
3629
3866
|
latest = await client.get_agent(agent_id=agent_id, include_api_key=False)
|
|
3630
|
-
latest_status =
|
|
3867
|
+
latest_status = (
|
|
3868
|
+
str(((latest.get("basic") or {}).get("status") or "")).upper() or None
|
|
3869
|
+
)
|
|
3631
3870
|
except Exception:
|
|
3632
3871
|
latest_status = None
|
|
3633
3872
|
|
|
@@ -3668,7 +3907,9 @@ def list_openclaws(region: str, page: int, size: int, dry_run: bool, output_mode
|
|
|
3668
3907
|
|
|
3669
3908
|
async def _list():
|
|
3670
3909
|
async with AgentEngineClient(region=region, dry_run=dry_run) as client:
|
|
3671
|
-
resp = await client.list_agents(
|
|
3910
|
+
resp = await client.list_agents(
|
|
3911
|
+
region=region, framework="openclaw", page=page, page_size=size
|
|
3912
|
+
)
|
|
3672
3913
|
agents = resp.get("agents", []) or []
|
|
3673
3914
|
total = int(resp.get("total") or len(agents))
|
|
3674
3915
|
rows = []
|
|
@@ -3761,7 +4002,9 @@ def status(agent_ref: Optional[str], region: Optional[str], dry_run: bool, outpu
|
|
|
3761
4002
|
agent = await client.get_agent(name=agent_ref)
|
|
3762
4003
|
|
|
3763
4004
|
if not agent:
|
|
3764
|
-
raise resolution_error(
|
|
4005
|
+
raise resolution_error(
|
|
4006
|
+
f"未找到 OpenClaw: {agent_ref}", hints=["agentengine openclaw list"]
|
|
4007
|
+
)
|
|
3765
4008
|
|
|
3766
4009
|
detail = _flatten_agent_detail(agent)
|
|
3767
4010
|
status_val = detail.get("status", "UNKNOWN")
|
|
@@ -3777,7 +4020,11 @@ def status(agent_ref: Optional[str], region: Optional[str], dry_run: bool, outpu
|
|
|
3777
4020
|
("框架", str(detail.get("framework") or "-"), None),
|
|
3778
4021
|
("区域", str(detail.get("region") or region), None),
|
|
3779
4022
|
("Endpoint", str(detail.get("endpoint") or "N/A"), "#58a6ff"),
|
|
3780
|
-
(
|
|
4023
|
+
(
|
|
4024
|
+
"Langfuse",
|
|
4025
|
+
str(detail.get("langfuse_url") or "-"),
|
|
4026
|
+
"#58a6ff" if detail.get("langfuse_url") else None,
|
|
4027
|
+
),
|
|
3781
4028
|
("镜像", str(detail.get("artifact_path") or "-"), None),
|
|
3782
4029
|
("创建时间", created_at_display, None),
|
|
3783
4030
|
("更新时间", updated_at_display, None),
|
|
@@ -3840,6 +4087,7 @@ def _delete_impl(agent_refs: tuple[str, ...], region: str, assume_yes: bool, dry
|
|
|
3840
4087
|
|
|
3841
4088
|
# 清理本地状态
|
|
3842
4089
|
from ksadk.deployment.state import clear_state
|
|
4090
|
+
|
|
3843
4091
|
try:
|
|
3844
4092
|
removed = clear_state(Path("."), key=agent_ref)
|
|
3845
4093
|
if removed:
|
|
@@ -3862,7 +4110,7 @@ def _delete_impl(agent_refs: tuple[str, ...], region: str, assume_yes: bool, dry
|
|
|
3862
4110
|
"failed": failed_refs,
|
|
3863
4111
|
}
|
|
3864
4112
|
|
|
3865
|
-
dry_run_kwargs = {"dry_run": dry_run}
|
|
4113
|
+
dry_run_kwargs: dict[str, Any] = {"dry_run": dry_run}
|
|
3866
4114
|
if is_json_output():
|
|
3867
4115
|
dry_run_kwargs.update(
|
|
3868
4116
|
dry_run_resource="openclaw",
|
|
@@ -3900,7 +4148,13 @@ def _delete_impl(agent_refs: tuple[str, ...], region: str, assume_yes: bool, dry
|
|
|
3900
4148
|
@confirm_options()
|
|
3901
4149
|
@dry_run_option()
|
|
3902
4150
|
@cli_output_option()
|
|
3903
|
-
def delete(
|
|
4151
|
+
def delete(
|
|
4152
|
+
agent_refs: tuple[str, ...],
|
|
4153
|
+
region: str,
|
|
4154
|
+
assume_yes: bool,
|
|
4155
|
+
dry_run: bool,
|
|
4156
|
+
output_mode: str | None,
|
|
4157
|
+
):
|
|
3904
4158
|
"""删除 OpenClaw 实例。"""
|
|
3905
4159
|
_ = output_mode
|
|
3906
4160
|
_delete_impl(agent_refs=agent_refs, region=region, assume_yes=assume_yes, dry_run=dry_run)
|
|
@@ -3912,7 +4166,13 @@ def delete(agent_refs: tuple[str, ...], region: str, assume_yes: bool, dry_run:
|
|
|
3912
4166
|
@confirm_options()
|
|
3913
4167
|
@dry_run_option()
|
|
3914
4168
|
@cli_output_option()
|
|
3915
|
-
def destroy(
|
|
4169
|
+
def destroy(
|
|
4170
|
+
agent_refs: tuple[str, ...],
|
|
4171
|
+
region: str,
|
|
4172
|
+
assume_yes: bool,
|
|
4173
|
+
dry_run: bool,
|
|
4174
|
+
output_mode: str | None,
|
|
4175
|
+
):
|
|
3916
4176
|
"""删除 OpenClaw 实例。"""
|
|
3917
4177
|
_ = output_mode
|
|
3918
4178
|
_delete_impl(agent_refs=agent_refs, region=region, assume_yes=assume_yes, dry_run=dry_run)
|