agentengine-sdk-python 0.6.4__py3-none-any.whl → 0.7.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.7.0.dist-info/METADATA +181 -0
- agentengine_sdk_python-0.7.0.dist-info/RECORD +482 -0
- {agentengine_sdk_python-0.6.4.dist-info → agentengine_sdk_python-0.7.0.dist-info}/WHEEL +1 -1
- agentengine_sdk_python-0.7.0.dist-info/entry_points.txt +3 -0
- agentengine_sdk_python-0.7.0.dist-info/licenses/LICENSE +175 -0
- agentengine_sdk_python-0.7.0.dist-info/top_level.txt +2 -0
- ksadk/__init__.py +13 -0
- ksadk/__main__.py +4 -0
- ksadk/a2a/__init__.py +15 -0
- ksadk/a2a/card_builder.py +64 -0
- ksadk/a2a/client.py +309 -0
- ksadk/a2a/executor.py +201 -0
- ksadk/a2a/server.py +79 -0
- ksadk/agents/__init__.py +20 -0
- ksadk/agents/base.py +370 -0
- ksadk/agents/context.py +38 -0
- ksadk/agents/event.py +35 -0
- ksadk/agents/loop_agent.py +71 -0
- ksadk/agents/parallel_agent.py +109 -0
- ksadk/agents/runner_adapter.py +24 -0
- ksadk/agents/sequential_agent.py +34 -0
- ksadk/api/__init__.py +3 -0
- ksadk/api/client.py +2246 -0
- ksadk/builders/__init__.py +20 -0
- ksadk/builders/base.py +66 -0
- ksadk/builders/code_builder.py +1990 -0
- ksadk/builders/container_builder.py +786 -0
- ksadk/builders/framework_requirements.py +59 -0
- ksadk/builders/ks3_uploader.py +389 -0
- ksadk/builders/mcp_builder.py +476 -0
- ksadk/builders/requirements_utils.py +75 -0
- ksadk/cli/__init__.py +531 -0
- ksadk/cli/__main__.py +4 -0
- ksadk/cli/agent_ref.py +204 -0
- ksadk/cli/cmd_a2a.py +167 -0
- ksadk/cli/cmd_agent.py +201 -0
- ksadk/cli/cmd_build.py +270 -0
- ksadk/cli/cmd_completion.py +304 -0
- ksadk/cli/cmd_config.py +758 -0
- ksadk/cli/cmd_create.py +2304 -0
- ksadk/cli/cmd_dashboard.py +900 -0
- ksadk/cli/cmd_deploy.py +704 -0
- ksadk/cli/cmd_destroy.py +345 -0
- ksadk/cli/cmd_files.py +1227 -0
- ksadk/cli/cmd_hermes.py +1263 -0
- ksadk/cli/cmd_invoke.py +1503 -0
- ksadk/cli/cmd_launch.py +564 -0
- ksadk/cli/cmd_mcp.py +1179 -0
- ksadk/cli/cmd_model.py +302 -0
- ksadk/cli/cmd_openclaw.py +3922 -0
- ksadk/cli/cmd_run.py +239 -0
- ksadk/cli/cmd_status.py +588 -0
- ksadk/cli/cmd_version.py +522 -0
- ksadk/cli/cmd_web.py +288 -0
- ksadk/cli/deploy_utils.py +87 -0
- ksadk/cli/dry_run.py +214 -0
- ksadk/cli/env_options.py +82 -0
- ksadk/cli/error_utils.py +525 -0
- ksadk/cli/global_options.py +31 -0
- ksadk/cli/local_runtime.py +97 -0
- ksadk/cli/model_catalog.py +136 -0
- ksadk/cli/network_options.py +412 -0
- ksadk/cli/resource_common.py +621 -0
- ksadk/cli/storage.py +84 -0
- ksadk/cli/ui.py +431 -0
- ksadk/cli/workflow_common.py +552 -0
- ksadk/common/__init__.py +14 -0
- ksadk/common/aicp_env.py +128 -0
- ksadk/common/auth.py +190 -0
- ksadk/common/constants.py +84 -0
- ksadk/common/llm_utils.py +61 -0
- ksadk/configs/__init__.py +61 -0
- ksadk/configs/env_registry.py +343 -0
- ksadk/configs/global_config.py +200 -0
- ksadk/configs/settings.py +706 -0
- ksadk/conversations/__init__.py +95 -0
- ksadk/conversations/attachment_storage.py +379 -0
- ksadk/conversations/attachments.py +774 -0
- ksadk/conversations/compaction_pipeline.py +387 -0
- ksadk/conversations/compaction_prompt.py +128 -0
- ksadk/conversations/context.py +303 -0
- ksadk/conversations/message_projection.py +269 -0
- ksadk/conversations/model_context.py +370 -0
- ksadk/conversations/model_options.py +136 -0
- ksadk/conversations/normalize.py +446 -0
- ksadk/conversations/reasoning_markup.py +91 -0
- ksadk/conversations/run_kinds.py +61 -0
- ksadk/conversations/run_status.py +53 -0
- ksadk/conversations/runtime.py +5276 -0
- ksadk/conversations/semantic_summary.py +359 -0
- ksadk/conversations/session_title.py +254 -0
- ksadk/deployment/__init__.py +83 -0
- ksadk/deployment/agent_access.py +226 -0
- ksadk/deployment/base.py +229 -0
- ksadk/deployment/manager.py +332 -0
- ksadk/deployment/providers/__init__.py +10 -0
- ksadk/deployment/providers/serverless.py +1115 -0
- ksadk/deployment/registry.py +120 -0
- ksadk/deployment/state.py +78 -0
- ksadk/deployment/ui_config.py +21 -0
- ksadk/detection/__init__.py +7 -0
- ksadk/detection/detector.py +431 -0
- ksadk/detection/mcp_detector.py +250 -0
- ksadk/hermes_terminal.py +467 -0
- ksadk/identity/__init__.py +17 -0
- ksadk/identity/resolver.py +385 -0
- ksadk/knowledge_base/__init__.py +62 -0
- ksadk/knowledge_base/adk_tool.py +47 -0
- ksadk/knowledge_base/client.py +297 -0
- ksadk/knowledge_base/langchain_tool.py +55 -0
- ksadk/knowledge_base/service.py +66 -0
- ksadk/knowledge_base/tool.py +50 -0
- ksadk/markdown.py +169 -0
- ksadk/mcp_runtime/__init__.py +231 -0
- ksadk/memory/__init__.py +57 -0
- ksadk/memory/adk/__init__.py +51 -0
- ksadk/memory/adk/backends/__init__.py +5 -0
- ksadk/memory/adk/backends/base_ltm_backend.py +52 -0
- ksadk/memory/adk/backends/http_ltm_backend.py +183 -0
- ksadk/memory/adk/backends/inmemory_ltm_backend.py +96 -0
- ksadk/memory/adk/backends/sdk_ltm_backend.py +456 -0
- ksadk/memory/adk/long_term_memory.py +273 -0
- ksadk/memory/adk/resilient_session_service.py +268 -0
- ksadk/memory/adk/short_term_memory.py +304 -0
- ksadk/memory/adk_tool.py +31 -0
- ksadk/memory/backends/__init__.py +6 -0
- ksadk/memory/backends/base.py +103 -0
- ksadk/memory/backends/memory.py +112 -0
- ksadk/memory/backends/redis.py +146 -0
- ksadk/memory/langchain_tool.py +39 -0
- ksadk/memory/ltm_backend_factory.py +24 -0
- ksadk/memory/manager.py +215 -0
- ksadk/memory/service.py +172 -0
- ksadk/memory/tool.py +96 -0
- ksadk/model_policy.py +223 -0
- ksadk/openclaw_gateway.py +378 -0
- ksadk/runners/__init__.py +8 -0
- ksadk/runners/adk_runner.py +1994 -0
- ksadk/runners/base_runner.py +305 -0
- ksadk/runners/deepagents_runner.py +13 -0
- ksadk/runners/factory.py +73 -0
- ksadk/runners/langchain_runner.py +751 -0
- ksadk/runners/langgraph_runner.py +985 -0
- ksadk/runners/patch_langchain.py +187 -0
- ksadk/runners/remote_runner.py +792 -0
- ksadk/runners/usage_accumulator.py +38 -0
- ksadk/runners/utils/__init__.py +19 -0
- ksadk/runners/utils/langfuse.py +230 -0
- ksadk/runners/utils/loader.py +62 -0
- ksadk/runtime_context.py +166 -0
- ksadk/runtime_state.py +25 -0
- ksadk/sandbox/__init__.py +28 -0
- ksadk/sandbox/backends/__init__.py +9 -0
- ksadk/sandbox/backends/e2b.py +154 -0
- ksadk/sandbox/backends/local_process.py +131 -0
- ksadk/sandbox/base.py +101 -0
- ksadk/sandbox/factory.py +53 -0
- ksadk/sandbox/registry.py +187 -0
- ksadk/server/__init__.py +7 -0
- ksadk/server/api_models.py +73 -0
- ksadk/server/app.py +3931 -0
- ksadk/server/static/assets/ArtifactsPanel-D-SSn2ee.js +1 -0
- ksadk/server/static/assets/CodeBlock-P16VOLYi.js +9 -0
- ksadk/server/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- ksadk/server/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- ksadk/server/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- ksadk/server/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- ksadk/server/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- ksadk/server/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- ksadk/server/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- ksadk/server/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- ksadk/server/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- ksadk/server/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- ksadk/server/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- ksadk/server/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- ksadk/server/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- ksadk/server/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- ksadk/server/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- ksadk/server/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- ksadk/server/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- ksadk/server/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- ksadk/server/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- ksadk/server/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- ksadk/server/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +8 -0
- ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +1 -0
- ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +303 -0
- ksadk/server/static/assets/NativeTerminalPanel-CHOd7Rch.css +1 -0
- ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +1 -0
- ksadk/server/static/assets/addon-fit-DthTIhi3.js +1 -0
- ksadk/server/static/assets/apl-CnwPGSsG.js +1 -0
- ksadk/server/static/assets/arc-BA13sHc9.js +1 -0
- ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +1 -0
- ksadk/server/static/assets/architectureDiagram-3BPJPVTR-DzJzgVoL.js +36 -0
- ksadk/server/static/assets/asciiarmor-qTkVPQu6.js +1 -0
- ksadk/server/static/assets/asn1-Dr8qZg38.js +1 -0
- ksadk/server/static/assets/asterisk-Bja0s6e1.js +1 -0
- ksadk/server/static/assets/blockDiagram-GPEHLZMM-UTdVcZhn.js +132 -0
- ksadk/server/static/assets/brainfuck-D5EjA2JK.js +1 -0
- ksadk/server/static/assets/c4Diagram-AAUBKEIU-Dix0GD4m.js +10 -0
- ksadk/server/static/assets/channel-CTuydARX.js +1 -0
- ksadk/server/static/assets/chunk-2J33WTMH-C2JxuZ42.js +1 -0
- ksadk/server/static/assets/chunk-4BX2VUAB-Be57QPgD.js +1 -0
- ksadk/server/static/assets/chunk-55IACEB6-WjSuy4nv.js +1 -0
- ksadk/server/static/assets/chunk-727SXJPM-BOovP-b5.js +206 -0
- ksadk/server/static/assets/chunk-AQP2D5EJ-DOmZNmWj.js +231 -0
- ksadk/server/static/assets/chunk-FMBD7UC4-DzwlodkU.js +15 -0
- ksadk/server/static/assets/chunk-ND2GUHAM-DMqAikEU.js +1 -0
- ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +1 -0
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +1 -0
- ksadk/server/static/assets/clike-DHH8Ad3s.js +1 -0
- ksadk/server/static/assets/clojure-BflJGmDX.js +1 -0
- ksadk/server/static/assets/cmake-CyVbuzPu.js +1 -0
- ksadk/server/static/assets/cobol-B_OZ4V-R.js +1 -0
- ksadk/server/static/assets/coffeescript-B2pKbFk8.js +1 -0
- ksadk/server/static/assets/commonlisp-CcllspGY.js +1 -0
- ksadk/server/static/assets/cose-bilkent-S5V4N54A-Zhy2GBnP.js +1 -0
- ksadk/server/static/assets/crystal-M5-qzICs.js +1 -0
- ksadk/server/static/assets/css-CYpP4FRV.js +1 -0
- ksadk/server/static/assets/cypher-p9eYesGn.js +1 -0
- ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +321 -0
- ksadk/server/static/assets/d-BhMjBjQP.js +1 -0
- ksadk/server/static/assets/dagre-BM42HDAG-CbKrtIUz.js +4 -0
- ksadk/server/static/assets/dagre-Bx709z4p.js +1 -0
- ksadk/server/static/assets/defaultLocale-C8Fc0cco.js +1 -0
- ksadk/server/static/assets/diagram-2AECGRRQ-BRApgQRK.js +43 -0
- ksadk/server/static/assets/diagram-5GNKFQAL-D0xbnDiK.js +10 -0
- ksadk/server/static/assets/diagram-KO2AKTUF-CVugVI9L.js +3 -0
- ksadk/server/static/assets/diagram-LMA3HP47-DozUGgee.js +24 -0
- ksadk/server/static/assets/diagram-OG6HWLK6-ZOYsKlru.js +24 -0
- ksadk/server/static/assets/diff-ChtP43wD.js +1 -0
- ksadk/server/static/assets/dist-2hInLS_J.js +9 -0
- ksadk/server/static/assets/dist-8EEyGgDx.js +1 -0
- ksadk/server/static/assets/dist-8_SfK1IP.js +1 -0
- ksadk/server/static/assets/dist-B0NP_Z0z.js +23 -0
- ksadk/server/static/assets/dist-BIJVDMuB.js +1 -0
- ksadk/server/static/assets/dist-BmlMPsCc.js +2 -0
- ksadk/server/static/assets/dist-BrCcQ47T.js +1 -0
- ksadk/server/static/assets/dist-BssVmjIo.js +6 -0
- ksadk/server/static/assets/dist-C3HIIaN5.js +1 -0
- ksadk/server/static/assets/dist-CPBtqRTW.js +1 -0
- ksadk/server/static/assets/dist-CkEKJFtk.js +1 -0
- ksadk/server/static/assets/dist-D-JMdWPQ.js +1 -0
- ksadk/server/static/assets/dist-D-xOD048.js +1 -0
- ksadk/server/static/assets/dist-D57wnGWd.js +1 -0
- ksadk/server/static/assets/dist-DL_NKc_z.js +1 -0
- ksadk/server/static/assets/dist-DMezvBGJ.js +1 -0
- ksadk/server/static/assets/dist-DmFaq_Iy.js +1 -0
- ksadk/server/static/assets/dist-Dp0k7bWI.js +1 -0
- ksadk/server/static/assets/dist-DpKtt4Bo.js +1 -0
- ksadk/server/static/assets/dist-DyOkZmze.js +11 -0
- ksadk/server/static/assets/dist-DyWsb78Q.js +1 -0
- ksadk/server/static/assets/dist-gX6GOLKq.js +1 -0
- ksadk/server/static/assets/dockerfile-BLkNEvjs.js +1 -0
- ksadk/server/static/assets/dtd-DTF72YNO.js +1 -0
- ksadk/server/static/assets/dylan-C6jEEEk-.js +1 -0
- ksadk/server/static/assets/ebnf-D4c0_ac3.js +1 -0
- ksadk/server/static/assets/ecl-BSZaIHnp.js +1 -0
- ksadk/server/static/assets/eiffel-BEjRio4Q.js +1 -0
- ksadk/server/static/assets/elm-Cshzl8qu.js +1 -0
- ksadk/server/static/assets/erDiagram-TEJ5UH35-Bk-9bgE5.js +85 -0
- ksadk/server/static/assets/erlang-DaB2Rkuy.js +1 -0
- ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +1 -0
- ksadk/server/static/assets/factor-D7LVTn2l.js +1 -0
- ksadk/server/static/assets/fcl-ClOhbFR7.js +1 -0
- ksadk/server/static/assets/flowDiagram-I6XJVG4X-Dn9kZVuZ.js +162 -0
- ksadk/server/static/assets/forth-Cezjo90N.js +1 -0
- ksadk/server/static/assets/fortran-Bt6PBEDR.js +1 -0
- ksadk/server/static/assets/ganttDiagram-6RSMTGT7-BGxXlJqm.js +292 -0
- ksadk/server/static/assets/gas-BHEdbvp9.js +1 -0
- ksadk/server/static/assets/gherkin-oBAE_ms0.js +1 -0
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +1 -0
- ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-C7Q0X-wi.js +106 -0
- ksadk/server/static/assets/graphlib-B8gBHxth.js +1 -0
- ksadk/server/static/assets/groovy-BC3IOsC8.js +1 -0
- ksadk/server/static/assets/haskell-BRsoo5mP.js +1 -0
- ksadk/server/static/assets/haxe-DIz0ZZqd.js +1 -0
- ksadk/server/static/assets/http-CLVgA2GD.js +1 -0
- ksadk/server/static/assets/idl-BUZw3wgd.js +1 -0
- ksadk/server/static/assets/index-C00Lwg3L.js +165 -0
- ksadk/server/static/assets/index-DAURbCsP.css +1 -0
- ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +1 -0
- ksadk/server/static/assets/infoDiagram-5YYISTIA-BO_CSqq5.js +2 -0
- ksadk/server/static/assets/init-D6jRqBbL.js +1 -0
- ksadk/server/static/assets/ishikawaDiagram-YF4QCWOH-eYLPLd46.js +70 -0
- ksadk/server/static/assets/javascript-9Tg8ixDm.js +1 -0
- ksadk/server/static/assets/journeyDiagram-JHISSGLW-De9geSb0.js +139 -0
- ksadk/server/static/assets/julia-CQfgDRfP.js +1 -0
- ksadk/server/static/assets/kanban-definition-UN3LZRKU-Cs80kQto.js +89 -0
- ksadk/server/static/assets/katex-DSrCFD8n.js +265 -0
- ksadk/server/static/assets/linear-CN9sbKTF.js +1 -0
- ksadk/server/static/assets/livescript-BXxG0Yva.js +1 -0
- ksadk/server/static/assets/lua-CiA1ziua.js +1 -0
- ksadk/server/static/assets/mathematica-u8YMmbU0.js +1 -0
- ksadk/server/static/assets/mbox-BEMVcqjs.js +1 -0
- ksadk/server/static/assets/mermaid-parser.core-DlgSBU8l.js +161 -0
- ksadk/server/static/assets/mindmap-definition-RKZ34NQL-9afz7Oug.js +96 -0
- ksadk/server/static/assets/mirc-C9zpzAZU.js +1 -0
- ksadk/server/static/assets/mllike-B45xgp2S.js +1 -0
- ksadk/server/static/assets/modelica-CqHI_q-D.js +1 -0
- ksadk/server/static/assets/mscgen-qgSLujhx.js +1 -0
- ksadk/server/static/assets/mumps-CW_TBmxz.js +1 -0
- ksadk/server/static/assets/nginx-BMaDbqW3.js +1 -0
- ksadk/server/static/assets/nsis-AQ_alPln.js +1 -0
- ksadk/server/static/assets/ntriples-d28e9m0E.js +1 -0
- ksadk/server/static/assets/octave-D2Q8cUp1.js +1 -0
- ksadk/server/static/assets/ordinal-hYBb2elL.js +1 -0
- ksadk/server/static/assets/oz-BwTct_5T.js +1 -0
- ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +1 -0
- ksadk/server/static/assets/pascal-Dp_KdFgX.js +1 -0
- ksadk/server/static/assets/perl-CdEHsPfU.js +1 -0
- ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +1 -0
- ksadk/server/static/assets/pieDiagram-4H26LBE5-DPv_VstN.js +30 -0
- ksadk/server/static/assets/pig-AF4Hwhju.js +1 -0
- ksadk/server/static/assets/powershell-CzG71I4L.js +1 -0
- ksadk/server/static/assets/properties-C357ku5U.js +1 -0
- ksadk/server/static/assets/protobuf-D1ij_kNL.js +1 -0
- ksadk/server/static/assets/pug-Bugr-47h.js +1 -0
- ksadk/server/static/assets/puppet-B4hC2X4m.js +1 -0
- ksadk/server/static/assets/python-BqYw9LYJ.js +1 -0
- ksadk/server/static/assets/q-B9NhS7L_.js +1 -0
- ksadk/server/static/assets/quadrantDiagram-W4KKPZXB-o77wZ1XK.js +7 -0
- ksadk/server/static/assets/r-DADKenSm.js +1 -0
- ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +1 -0
- ksadk/server/static/assets/requirementDiagram-4Y6WPE33-BYVw81VC.js +84 -0
- ksadk/server/static/assets/rpm-gpDK5sbt.js +1 -0
- ksadk/server/static/assets/ruby-DsYpTuWg.js +1 -0
- ksadk/server/static/assets/sankeyDiagram-5OEKKPKP-B7nZFMKT.js +40 -0
- ksadk/server/static/assets/sas-C2OyD2Y6.js +1 -0
- ksadk/server/static/assets/scheme-CyDdOh7e.js +1 -0
- ksadk/server/static/assets/sequenceDiagram-3UESZ5HK-BGRRrFw5.js +162 -0
- ksadk/server/static/assets/shell-Du5Qg9im.js +1 -0
- ksadk/server/static/assets/sieve-BAxa3IjF.js +1 -0
- ksadk/server/static/assets/simple-mode-DRpGK0lJ.js +1 -0
- ksadk/server/static/assets/smalltalk-BLp5-jwC.js +1 -0
- ksadk/server/static/assets/solr-BBopId9w.js +1 -0
- ksadk/server/static/assets/sparql-Dz-mlCAC.js +1 -0
- ksadk/server/static/assets/spreadsheet-CTIncYxj.js +1 -0
- ksadk/server/static/assets/sql-DcCJ9jop.js +1 -0
- ksadk/server/static/assets/stateDiagram-AJRCARHV-BUfHCoPs.js +1 -0
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +1 -0
- ksadk/server/static/assets/stex-sDrdk2BW.js +1 -0
- ksadk/server/static/assets/stylus-DLLZ8dgm.js +1 -0
- ksadk/server/static/assets/swift-DKB6_1j6.js +1 -0
- ksadk/server/static/assets/tcl-BGfruO1u.js +1 -0
- ksadk/server/static/assets/textile-DWBqthVk.js +1 -0
- ksadk/server/static/assets/tiddlywiki-VlUiK86J.js +1 -0
- ksadk/server/static/assets/tiki-CxVlf5KZ.js +1 -0
- ksadk/server/static/assets/timeline-definition-PNZ67QCA-FbCTGrf9.js +120 -0
- ksadk/server/static/assets/toml-LvoKBwCs.js +1 -0
- ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +1 -0
- ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +1 -0
- ksadk/server/static/assets/troff-C2dAgh7P.js +1 -0
- ksadk/server/static/assets/ttcn-BePYh-hG.js +1 -0
- ksadk/server/static/assets/ttcn-cfg-CY0aot7Q.js +1 -0
- ksadk/server/static/assets/turtle-BDLWE2cD.js +1 -0
- ksadk/server/static/assets/vb-BthdM_4N.js +1 -0
- ksadk/server/static/assets/vbscript-D9f6rSsU.js +1 -0
- ksadk/server/static/assets/velocity-CqftRsjg.js +1 -0
- ksadk/server/static/assets/vennDiagram-CIIHVFJN-DWgwtPsJ.js +34 -0
- ksadk/server/static/assets/verilog-D-x6ne0Z.js +1 -0
- ksadk/server/static/assets/vhdl-CMrOq2q1.js +1 -0
- ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +1 -0
- ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-2x8G-tTM.js +78 -0
- ksadk/server/static/assets/webidl-D5jiJvOU.js +1 -0
- ksadk/server/static/assets/xquery-fj_R-kMw.js +1 -0
- ksadk/server/static/assets/xterm-DooSxjI5.js +36 -0
- ksadk/server/static/assets/xychartDiagram-2RQKCTM6-Drma3AYl.js +7 -0
- ksadk/server/static/assets/yacas-CXXgtw0p.js +1 -0
- ksadk/server/static/assets/z80-CL1naaMV.js +1 -0
- ksadk/server/static/favicon.svg +1 -0
- ksadk/server/static/icons.svg +24 -0
- ksadk/server/static/index.html +14 -0
- ksadk/server/terminal_sessions.py +551 -0
- ksadk/sessions/__init__.py +279 -0
- ksadk/sessions/base.py +354 -0
- ksadk/sessions/continuity.py +337 -0
- ksadk/sessions/errors.py +7 -0
- ksadk/sessions/in_memory.py +273 -0
- ksadk/sessions/local_service.py +949 -0
- ksadk/sessions/postgres_service.py +901 -0
- ksadk/sessions/resilience.py +52 -0
- ksadk/sessions/resilient.py +360 -0
- ksadk/sessions/sqlite_service.py +13 -0
- ksadk/skills/__init__.py +9 -0
- ksadk/skills/loader.py +46 -0
- ksadk/skills/models.py +120 -0
- ksadk/skills/package_store.py +104 -0
- ksadk/skills/runtime/__init__.py +17 -0
- ksadk/skills/runtime/agent.py +183 -0
- ksadk/skills/runtime/artifacts.py +39 -0
- ksadk/skills/runtime/backends/__init__.py +1 -0
- ksadk/skills/runtime/backends/disabled.py +8 -0
- ksadk/skills/runtime/backends/e2b.py +168 -0
- ksadk/skills/runtime/backends/local.py +95 -0
- ksadk/skills/runtime/base.py +103 -0
- ksadk/skills/runtime/executor.py +219 -0
- ksadk/skills/runtime/factory.py +37 -0
- ksadk/skills/runtime/loader.py +131 -0
- ksadk/skills/runtime/registry.py +150 -0
- ksadk/skills/runtime/request.py +67 -0
- ksadk/skills/service_client.py +239 -0
- ksadk/skills/service_env.py +58 -0
- ksadk/skills/tool_defs.py +221 -0
- ksadk/terminal_client.py +69 -0
- ksadk/terminal_exec_policy.py +229 -0
- ksadk/tools/__init__.py +17 -0
- ksadk/tools/gateway.py +230 -0
- ksadk/tools/result_budget.py +154 -0
- ksadk/toolsets/__init__.py +854 -0
- ksadk/toolsets/_langchain.py +11 -0
- ksadk/toolsets/platform.py +93 -0
- ksadk/toolsets/sandbox.py +310 -0
- ksadk/toolsets/skills.py +217 -0
- ksadk/toolsets/web.py +266 -0
- ksadk/toolsets/workspace.py +917 -0
- ksadk/toolsets/workspace_state.py +44 -0
- ksadk/tracing/__init__.py +37 -0
- ksadk/tracing/exporters/__init__.py +1 -0
- ksadk/tracing/exporters/inmemory_exporter.py +116 -0
- ksadk/tracing/exporters/langfuse_exporter.py +445 -0
- ksadk/tracing/setup.py +892 -0
- ksadk/tracing/span_utils.py +114 -0
- ksadk/tui/__init__.py +27 -0
- ksadk/tui/loop.py +1877 -0
- ksadk/tui/stream_render.py +68 -0
- ksadk/ui_config.py +168 -0
- ksadk/version.py +4 -0
- ksadk_runtime_common/__init__.py +20 -0
- ksadk_runtime_common/memory_backend/__init__.py +29 -0
- ksadk_runtime_common/memory_backend/manifest.py +79 -0
- ksadk_runtime_common/memory_backend/providers/__init__.py +6 -0
- ksadk_runtime_common/memory_backend/providers/lancedb.py +151 -0
- ksadk_runtime_common/memory_backend/providers/mem0.py +74 -0
- ksadk_runtime_common/memory_backend/registry.py +56 -0
- ksadk_runtime_common/memory_backend/render.py +71 -0
- ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -0
- ksadk_runtime_common/workspace_files/__init__.py +29 -0
- ksadk_runtime_common/workspace_files/bootstrap.py +56 -0
- ksadk_runtime_common/workspace_files/constants.py +9 -0
- ksadk_runtime_common/workspace_files/path_utils.py +71 -0
- ksadk_runtime_common/workspace_files/preview.py +96 -0
- ksadk_runtime_common/workspace_files/router.py +254 -0
- agentengine_sdk_python/__init__.py +0 -3
- agentengine_sdk_python-0.6.4.dist-info/METADATA +0 -48
- agentengine_sdk_python-0.6.4.dist-info/RECORD +0 -5
- agentengine_sdk_python-0.6.4.dist-info/top_level.txt +0 -1
|
@@ -0,0 +1,786 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Container Builder - Docker 镜像构建
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import subprocess
|
|
7
|
+
import shutil
|
|
8
|
+
import time
|
|
9
|
+
import platform
|
|
10
|
+
import asyncio
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Optional
|
|
13
|
+
|
|
14
|
+
import click
|
|
15
|
+
|
|
16
|
+
from ksadk.builders.base import BaseBuilder, BuildResult
|
|
17
|
+
from ksadk.builders.code_builder import CodeBuilder
|
|
18
|
+
from ksadk.builders.framework_requirements import (
|
|
19
|
+
FASTAPI_REQUIREMENT,
|
|
20
|
+
requirements_for_framework,
|
|
21
|
+
)
|
|
22
|
+
from ksadk.builders.requirements_utils import (
|
|
23
|
+
exclude_requirement_names,
|
|
24
|
+
merge_requirement_lists,
|
|
25
|
+
parse_requirements_text,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _registry_host(registry: str | None) -> str:
|
|
30
|
+
value = str(registry or "").strip()
|
|
31
|
+
for prefix in ("http://", "https://"):
|
|
32
|
+
if value.startswith(prefix):
|
|
33
|
+
value = value[len(prefix):]
|
|
34
|
+
break
|
|
35
|
+
return value.split("/", 1)[0].strip()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _registry_kind(registry: str | None) -> str:
|
|
39
|
+
host = _registry_host(registry)
|
|
40
|
+
if host.endswith(".ksyunkcr.com"):
|
|
41
|
+
return "enterprise_kcr"
|
|
42
|
+
if host.endswith(".kce.ksyun.com"):
|
|
43
|
+
return "personal_kcr"
|
|
44
|
+
return "third_party"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def registry_kind_label(kind: str) -> str:
|
|
48
|
+
if kind == "personal_kcr":
|
|
49
|
+
return "个人版 KCR"
|
|
50
|
+
if kind == "enterprise_kcr":
|
|
51
|
+
return "企业版 KCR"
|
|
52
|
+
return "第三方镜像仓库"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def resolve_registry_credentials(
|
|
56
|
+
registry: str | None,
|
|
57
|
+
*,
|
|
58
|
+
environ: Optional[dict[str, str]] = None,
|
|
59
|
+
) -> tuple[str, str, str]:
|
|
60
|
+
"""Resolve registry credentials.
|
|
61
|
+
|
|
62
|
+
Returns (username, password, kind). Personal KCR keeps the historical
|
|
63
|
+
KSYUN_ACCOUNT_ID fallback; enterprise KCR and third-party registries require
|
|
64
|
+
explicit registry credentials.
|
|
65
|
+
"""
|
|
66
|
+
env = environ if environ is not None else os.environ
|
|
67
|
+
kind = _registry_kind(registry)
|
|
68
|
+
password = str(env.get("KCR_PASSWORD") or "")
|
|
69
|
+
username = str(env.get("KCR_USERNAME") or "")
|
|
70
|
+
if kind == "personal_kcr" and not username:
|
|
71
|
+
username = str(env.get("KSYUN_ACCOUNT_ID") or "")
|
|
72
|
+
return username, password, kind
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def print_registry_credentials_help(registry: str | None, *, kind: str | None = None) -> None:
|
|
76
|
+
kind = kind or _registry_kind(registry)
|
|
77
|
+
click.echo("")
|
|
78
|
+
if kind == "personal_kcr":
|
|
79
|
+
click.secho("❌ 缺少个人版 KCR 镜像仓库凭证。", fg="red")
|
|
80
|
+
click.echo("个人版 KCR 可使用 KSYUN_ACCOUNT_ID 作为用户名兜底,并配置 KCR_PASSWORD。")
|
|
81
|
+
click.echo("")
|
|
82
|
+
click.echo("请设置:")
|
|
83
|
+
click.echo(" KSYUN_ACCOUNT_ID=<金山云账号ID>")
|
|
84
|
+
click.echo(" KCR_PASSWORD=<个人版 KCR 访问凭证密码或 Token>")
|
|
85
|
+
else:
|
|
86
|
+
click.secho("❌ 缺少企业版或第三方镜像仓库凭证。", fg="red")
|
|
87
|
+
click.echo("企业版或第三方镜像仓库必须配置 KCR_USERNAME 和 KCR_PASSWORD。")
|
|
88
|
+
click.echo("KSYUN_ACCOUNT_ID 只会作为个人版 KCR 的用户名兜底。")
|
|
89
|
+
click.echo("")
|
|
90
|
+
click.echo("请设置:")
|
|
91
|
+
click.echo(" KCR_USERNAME=<镜像仓库访问凭证用户名>")
|
|
92
|
+
click.echo(" KCR_PASSWORD=<镜像仓库访问凭证密码或 Token>")
|
|
93
|
+
click.echo("")
|
|
94
|
+
click.echo("可选设置默认构建仓库:")
|
|
95
|
+
click.echo(" KCR_REGISTRY=<registry>/<namespace>")
|
|
96
|
+
if registry:
|
|
97
|
+
click.echo("")
|
|
98
|
+
click.echo(f"当前目标 registry: {_registry_host(registry)}")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def ensure_docker_running() -> bool:
|
|
102
|
+
"""确保 Docker 正在运行"""
|
|
103
|
+
if not shutil.which('docker'):
|
|
104
|
+
click.secho("❌ 未找到 docker 命令", fg='red')
|
|
105
|
+
click.echo("")
|
|
106
|
+
click.echo("请先安装 Docker:")
|
|
107
|
+
if platform.system() == "Darwin":
|
|
108
|
+
click.echo(" • 下载 Docker Desktop: https://www.docker.com/products/docker-desktop/")
|
|
109
|
+
click.echo(" • 或使用 Homebrew: brew install --cask docker")
|
|
110
|
+
elif platform.system() == "Linux":
|
|
111
|
+
click.echo(" • Ubuntu/Debian: sudo apt-get install docker.io")
|
|
112
|
+
click.echo(" • CentOS/RHEL: sudo yum install docker")
|
|
113
|
+
else:
|
|
114
|
+
click.echo(" • 下载 Docker Desktop: https://www.docker.com/products/docker-desktop/")
|
|
115
|
+
return False
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
result = subprocess.run(['docker', 'info'], capture_output=True, timeout=10)
|
|
119
|
+
if result.returncode == 0:
|
|
120
|
+
return True
|
|
121
|
+
except:
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
click.secho("⚠️ Docker daemon 未运行", fg='yellow')
|
|
125
|
+
|
|
126
|
+
system_name = platform.system()
|
|
127
|
+
if system_name == "Darwin":
|
|
128
|
+
click.echo("🚀 正在启动 Docker Desktop...")
|
|
129
|
+
try:
|
|
130
|
+
subprocess.run(['open', '-a', 'Docker'], check=True)
|
|
131
|
+
for i in range(60):
|
|
132
|
+
time.sleep(1)
|
|
133
|
+
try:
|
|
134
|
+
result = subprocess.run(['docker', 'info'], capture_output=True, timeout=5)
|
|
135
|
+
if result.returncode == 0:
|
|
136
|
+
click.secho("✅ Docker Desktop 已启动", fg='green')
|
|
137
|
+
return True
|
|
138
|
+
except:
|
|
139
|
+
pass
|
|
140
|
+
if i % 5 == 0 and i > 0:
|
|
141
|
+
click.echo(f" 等待 Docker 启动中... ({i}秒)")
|
|
142
|
+
click.secho("❌ Docker Desktop 启动超时", fg='red')
|
|
143
|
+
return False
|
|
144
|
+
except:
|
|
145
|
+
click.secho("❌ 无法启动 Docker Desktop", fg='red')
|
|
146
|
+
return False
|
|
147
|
+
elif system_name == "Windows":
|
|
148
|
+
click.echo("请启动 Docker Desktop,然后重试当前命令。")
|
|
149
|
+
return False
|
|
150
|
+
else:
|
|
151
|
+
click.echo("请启动 Docker daemon: sudo systemctl start docker")
|
|
152
|
+
return False
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class ContainerBuilder(BaseBuilder):
|
|
156
|
+
"""Docker 镜像构建器"""
|
|
157
|
+
|
|
158
|
+
def __init__(self, project_dir: Path, config: dict = None,
|
|
159
|
+
tag: str = None, registry: str = None, no_cache: bool = False):
|
|
160
|
+
super().__init__(project_dir, config)
|
|
161
|
+
self.tag = tag
|
|
162
|
+
self.registry = registry
|
|
163
|
+
self.no_cache = no_cache
|
|
164
|
+
|
|
165
|
+
def _get_smart_kcr_endpoint(self, region: str) -> str:
|
|
166
|
+
"""智能选择 KCR endpoint
|
|
167
|
+
|
|
168
|
+
使用企业版 KCR (hub.kce.ksyun.com/agentengine/)。
|
|
169
|
+
优先使用内网 VPC endpoint,如果内网不可达则使用公网。
|
|
170
|
+
"""
|
|
171
|
+
from ksadk.configs.settings import check_endpoint_reachable
|
|
172
|
+
|
|
173
|
+
# 企业版 KCR 地址 (带 agentengine 命名空间)
|
|
174
|
+
vpc_endpoint = "hub-vpc.kce.ksyun.com/agentengine"
|
|
175
|
+
public_endpoint = "hub.kce.ksyun.com/agentengine"
|
|
176
|
+
|
|
177
|
+
click.echo(f"🔍 检测 KCR 内网连通性...")
|
|
178
|
+
|
|
179
|
+
# 检测 VPC 内网是否可达 (端口 443 for HTTPS registry)
|
|
180
|
+
if check_endpoint_reachable("hub-vpc.kce.ksyun.com", port=443, timeout=2.0):
|
|
181
|
+
click.secho(f" ✅ 使用内网: {vpc_endpoint}", fg='green')
|
|
182
|
+
return vpc_endpoint
|
|
183
|
+
else:
|
|
184
|
+
click.echo(f" ℹ️ 使用公网: {public_endpoint}")
|
|
185
|
+
return public_endpoint
|
|
186
|
+
|
|
187
|
+
def _optimize_kcr_endpoint(self, registry: str) -> str:
|
|
188
|
+
"""优化 KCR endpoint
|
|
189
|
+
|
|
190
|
+
如果是金山云 KCR 公网地址,且内网可达,则替换为内网地址。
|
|
191
|
+
"""
|
|
192
|
+
from ksadk.configs.settings import check_endpoint_reachable
|
|
193
|
+
|
|
194
|
+
# 已经是内网地址
|
|
195
|
+
if 'hub-vpc' in registry:
|
|
196
|
+
return registry
|
|
197
|
+
|
|
198
|
+
# 匹配企业版 KCR: hub.kce.ksyun.com
|
|
199
|
+
if 'hub.kce.ksyun.com' in registry:
|
|
200
|
+
click.echo(f"🔍 检测 KCR 内网连通性...")
|
|
201
|
+
if check_endpoint_reachable("hub-vpc.kce.ksyun.com", port=443, timeout=2.0):
|
|
202
|
+
optimized = registry.replace("hub.kce.ksyun.com", "hub-vpc.kce.ksyun.com")
|
|
203
|
+
click.secho(f" ✅ 优化为内网: {optimized}", fg='green')
|
|
204
|
+
return optimized
|
|
205
|
+
else:
|
|
206
|
+
click.echo(f" ℹ️ 使用公网: {registry}")
|
|
207
|
+
|
|
208
|
+
return registry
|
|
209
|
+
|
|
210
|
+
def _package(self, detection_result) -> 'PackageInfo':
|
|
211
|
+
"""打包项目 - 复制文件并生成 Dockerfile/requirements/entrypoint"""
|
|
212
|
+
from ksadk.deployment.base import PackageInfo
|
|
213
|
+
|
|
214
|
+
project_path = self.project_dir
|
|
215
|
+
output_dir = project_path / ".agentengine" / "build"
|
|
216
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
217
|
+
|
|
218
|
+
package_name = Path(detection_result.package_path).name
|
|
219
|
+
is_container_first_template = (
|
|
220
|
+
getattr(getattr(detection_result, "type", None), "value", "") == "hermes"
|
|
221
|
+
and (project_path / "Dockerfile").exists()
|
|
222
|
+
and (project_path / "entrypoint.sh").exists()
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
# 复制项目文件。真实 .env 只通过 deploy payload 注入,不进入镜像上下文。
|
|
226
|
+
for item in project_path.iterdir():
|
|
227
|
+
if CodeBuilder._is_real_dotenv_file(item.name):
|
|
228
|
+
continue
|
|
229
|
+
if (
|
|
230
|
+
(item.name.startswith('.') and item.name != '.env.example')
|
|
231
|
+
or item.name in ('__pycache__', '.git', 'node_modules')
|
|
232
|
+
):
|
|
233
|
+
continue
|
|
234
|
+
dest = output_dir / item.name
|
|
235
|
+
if item.is_dir():
|
|
236
|
+
if dest.exists():
|
|
237
|
+
shutil.rmtree(dest)
|
|
238
|
+
shutil.copytree(
|
|
239
|
+
item,
|
|
240
|
+
dest,
|
|
241
|
+
ignore=shutil.ignore_patterns(
|
|
242
|
+
"__pycache__",
|
|
243
|
+
"*.pyc",
|
|
244
|
+
"node_modules",
|
|
245
|
+
".pytest_cache",
|
|
246
|
+
".mypy_cache",
|
|
247
|
+
".ruff_cache",
|
|
248
|
+
),
|
|
249
|
+
)
|
|
250
|
+
else:
|
|
251
|
+
shutil.copy2(item, dest)
|
|
252
|
+
|
|
253
|
+
# 复制 ksadk 源码 (确保容器内可用)
|
|
254
|
+
import ksadk
|
|
255
|
+
ksadk_src = Path(ksadk.__file__).parent
|
|
256
|
+
ksadk_dest = output_dir / "ksadk"
|
|
257
|
+
if ksadk_dest.exists():
|
|
258
|
+
shutil.rmtree(ksadk_dest)
|
|
259
|
+
|
|
260
|
+
def _ignore_ksadk_source(current_dir: str, names: list[str]):
|
|
261
|
+
ignored = set(
|
|
262
|
+
shutil.ignore_patterns(
|
|
263
|
+
"__pycache__",
|
|
264
|
+
"*.pyc",
|
|
265
|
+
"*.pyd",
|
|
266
|
+
"*.so",
|
|
267
|
+
"*.dylib",
|
|
268
|
+
"*.bin",
|
|
269
|
+
)(current_dir, names)
|
|
270
|
+
)
|
|
271
|
+
relative_dir = Path(current_dir).resolve().relative_to(ksadk_src.resolve())
|
|
272
|
+
if relative_dir == Path("server") and "web-ui" in names:
|
|
273
|
+
ignored.add("web-ui")
|
|
274
|
+
return ignored
|
|
275
|
+
|
|
276
|
+
shutil.copytree(
|
|
277
|
+
ksadk_src,
|
|
278
|
+
ksadk_dest,
|
|
279
|
+
ignore=_ignore_ksadk_source,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
# 复制 ksadk_runtime_common (如果存在)
|
|
283
|
+
try:
|
|
284
|
+
import ksadk_runtime_common
|
|
285
|
+
runtime_common_src = Path(ksadk_runtime_common.__file__).parent
|
|
286
|
+
runtime_common_dest = output_dir / "ksadk_runtime_common"
|
|
287
|
+
if runtime_common_dest.exists():
|
|
288
|
+
shutil.rmtree(runtime_common_dest)
|
|
289
|
+
shutil.copytree(
|
|
290
|
+
runtime_common_src,
|
|
291
|
+
runtime_common_dest,
|
|
292
|
+
ignore=shutil.ignore_patterns("__pycache__", "*.pyc"),
|
|
293
|
+
)
|
|
294
|
+
except ImportError:
|
|
295
|
+
# 旧版本 ksadk 没有 ksadk_runtime_common,从源码目录复制
|
|
296
|
+
# 这个分支处理从 master 迁移到 main 后,环境中安装的是旧版本的情况
|
|
297
|
+
source_runtime_common = Path(ksadk_src).parent / "ksadk_runtime_common"
|
|
298
|
+
if source_runtime_common.exists():
|
|
299
|
+
runtime_common_dest = output_dir / "ksadk_runtime_common"
|
|
300
|
+
if runtime_common_dest.exists():
|
|
301
|
+
shutil.rmtree(runtime_common_dest)
|
|
302
|
+
shutil.copytree(
|
|
303
|
+
source_runtime_common,
|
|
304
|
+
runtime_common_dest,
|
|
305
|
+
ignore=shutil.ignore_patterns("__pycache__", "*.pyc"),
|
|
306
|
+
)
|
|
307
|
+
else:
|
|
308
|
+
click.echo(click.style(
|
|
309
|
+
"⚠️ 警告: 未找到 ksadk_runtime_common,镜像可能无法正常运行",
|
|
310
|
+
fg="yellow"
|
|
311
|
+
))
|
|
312
|
+
|
|
313
|
+
dockerfile_path = output_dir / "Dockerfile"
|
|
314
|
+
if not is_container_first_template:
|
|
315
|
+
dockerfile = self._generate_dockerfile(detection_result)
|
|
316
|
+
dockerfile_path.write_text(dockerfile)
|
|
317
|
+
|
|
318
|
+
# 生成 requirements.txt (合并用户依赖)
|
|
319
|
+
requirements = self._generate_requirements(detection_result, project_path)
|
|
320
|
+
requirements_path = output_dir / "requirements.txt"
|
|
321
|
+
requirements_path.write_text(requirements)
|
|
322
|
+
|
|
323
|
+
# 生成启动脚本
|
|
324
|
+
if is_container_first_template:
|
|
325
|
+
entrypoint_path = output_dir / "entrypoint.sh"
|
|
326
|
+
else:
|
|
327
|
+
entrypoint = self._generate_entrypoint(detection_result, package_name)
|
|
328
|
+
entrypoint_path = output_dir / "entrypoint.py"
|
|
329
|
+
entrypoint_path.write_text(entrypoint)
|
|
330
|
+
|
|
331
|
+
return PackageInfo(
|
|
332
|
+
name=detection_result.name or project_path.name,
|
|
333
|
+
framework=detection_result.type.value,
|
|
334
|
+
build_dir=str(output_dir),
|
|
335
|
+
project_dir=str(project_path),
|
|
336
|
+
dockerfile=str(dockerfile_path),
|
|
337
|
+
entry_point=detection_result.entry_point,
|
|
338
|
+
metadata={
|
|
339
|
+
"package_name": package_name,
|
|
340
|
+
"requirements": str(requirements_path),
|
|
341
|
+
"entrypoint": str(entrypoint_path),
|
|
342
|
+
}
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
def _generate_dockerfile(self, detection_result) -> str:
|
|
346
|
+
"""生成优化的 Dockerfile"""
|
|
347
|
+
base_image = "python:3.12-slim"
|
|
348
|
+
|
|
349
|
+
return f'''FROM {base_image}
|
|
350
|
+
|
|
351
|
+
# 设置环境变量
|
|
352
|
+
ENV PYTHONUNBUFFERED=1 \\
|
|
353
|
+
PYTHONDONTWRITEBYTECODE=1 \\
|
|
354
|
+
PIP_NO_CACHE_DIR=1 \\
|
|
355
|
+
PIP_DISABLE_PIP_VERSION_CHECK=1
|
|
356
|
+
|
|
357
|
+
WORKDIR /app
|
|
358
|
+
|
|
359
|
+
# 先复制依赖文件 (利用 Docker Layer 缓存)
|
|
360
|
+
COPY requirements.txt .
|
|
361
|
+
|
|
362
|
+
# 使用清华镜像源加速安装
|
|
363
|
+
RUN pip install -r requirements.txt -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
|
|
364
|
+
|
|
365
|
+
# 复制应用代码
|
|
366
|
+
COPY . .
|
|
367
|
+
|
|
368
|
+
# 创建非 root 用户 (安全最佳实践)
|
|
369
|
+
RUN useradd -m -u 1000 agent && chown -R agent:agent /app
|
|
370
|
+
USER agent
|
|
371
|
+
|
|
372
|
+
EXPOSE 8080
|
|
373
|
+
|
|
374
|
+
# 使用 exec 形式确保信号正确传递
|
|
375
|
+
CMD ["python", "entrypoint.py"]
|
|
376
|
+
'''
|
|
377
|
+
|
|
378
|
+
def _generate_requirements(self, detection_result, project_path: Path = None) -> str:
|
|
379
|
+
"""生成 requirements.txt"""
|
|
380
|
+
base_deps = [
|
|
381
|
+
# Core
|
|
382
|
+
FASTAPI_REQUIREMENT,
|
|
383
|
+
"uvicorn>=0.23.0",
|
|
384
|
+
"python-dotenv>=1.0.0",
|
|
385
|
+
"pydantic>=2.0.0",
|
|
386
|
+
"pyyaml>=6.0.0",
|
|
387
|
+
"httpx>=0.24.0",
|
|
388
|
+
# Tracing
|
|
389
|
+
"opentelemetry-api>=1.37.0",
|
|
390
|
+
"opentelemetry-sdk>=1.37.0",
|
|
391
|
+
"opentelemetry-exporter-otlp>=1.37.0",
|
|
392
|
+
"openinference-instrumentation-langchain>=0.1.0",
|
|
393
|
+
"langfuse>=2.0.0",
|
|
394
|
+
]
|
|
395
|
+
|
|
396
|
+
framework = detection_result.type.value
|
|
397
|
+
base_deps += requirements_for_framework(framework)
|
|
398
|
+
|
|
399
|
+
base_deps = merge_requirement_lists(
|
|
400
|
+
base_deps,
|
|
401
|
+
CodeBuilder(project_path or self.project_dir)._bundled_runtime_requirements(),
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
# 合并用户 requirements.txt (如果存在)
|
|
405
|
+
if project_path:
|
|
406
|
+
user_requirements = project_path / "requirements.txt"
|
|
407
|
+
if user_requirements.exists():
|
|
408
|
+
user_content = user_requirements.read_text()
|
|
409
|
+
user_deps = exclude_requirement_names(
|
|
410
|
+
parse_requirements_text(user_content),
|
|
411
|
+
excluded_names={"ksadk"},
|
|
412
|
+
)
|
|
413
|
+
base_deps = merge_requirement_lists(base_deps, user_deps)
|
|
414
|
+
|
|
415
|
+
return "\n".join(base_deps)
|
|
416
|
+
|
|
417
|
+
def _generate_entrypoint(self, detection_result, package_name: str) -> str:
|
|
418
|
+
"""生成 entrypoint.py"""
|
|
419
|
+
return f'''"""
|
|
420
|
+
AgentEngine Container 模式入口
|
|
421
|
+
"""
|
|
422
|
+
|
|
423
|
+
import sys
|
|
424
|
+
import os
|
|
425
|
+
import logging
|
|
426
|
+
from pathlib import Path
|
|
427
|
+
|
|
428
|
+
# ========== 日志配置 ==========
|
|
429
|
+
LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO").upper()
|
|
430
|
+
|
|
431
|
+
logging.basicConfig(
|
|
432
|
+
level=getattr(logging, LOG_LEVEL, logging.INFO),
|
|
433
|
+
format="%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
|
|
434
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
435
|
+
stream=sys.stdout,
|
|
436
|
+
force=True,
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
logger = logging.getLogger("entrypoint")
|
|
440
|
+
logger.info(f"日志级别: {{LOG_LEVEL}}")
|
|
441
|
+
|
|
442
|
+
# 配置第三方库日志级别
|
|
443
|
+
if LOG_LEVEL != "DEBUG":
|
|
444
|
+
logging.getLogger("httpx").setLevel(logging.WARNING)
|
|
445
|
+
logging.getLogger("httpcore").setLevel(logging.WARNING)
|
|
446
|
+
|
|
447
|
+
# ========== 路径设置 ==========
|
|
448
|
+
sys.path.insert(0, "/app")
|
|
449
|
+
os.chdir("/app")
|
|
450
|
+
|
|
451
|
+
logger.info("=" * 60)
|
|
452
|
+
logger.info("AgentEngine 启动 (Container 模式)")
|
|
453
|
+
logger.info("=" * 60)
|
|
454
|
+
logger.info(f"Python: {{sys.version}}")
|
|
455
|
+
|
|
456
|
+
# 加载环境变量
|
|
457
|
+
try:
|
|
458
|
+
from dotenv import load_dotenv
|
|
459
|
+
if os.path.exists("/app/.env"):
|
|
460
|
+
load_dotenv("/app/.env")
|
|
461
|
+
logger.info("加载 .env 文件")
|
|
462
|
+
except ImportError:
|
|
463
|
+
pass
|
|
464
|
+
|
|
465
|
+
env_keys = [
|
|
466
|
+
"AGENT_RUNTIME_NAME", "AGENT_RUNTIME_ID", "ACCOUNT_ID", "PORT",
|
|
467
|
+
"LANGFUSE_BASE_URL", "LANGFUSE_HOST", "LANGFUSE_PUBLIC_KEY",
|
|
468
|
+
"LANGFUSE_SECRET_KEY", "LANGFUSE_USE_CALLBACK",
|
|
469
|
+
"OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
|
|
470
|
+
"OTEL_EXPORTER_OTLP_HEADERS", "OTEL_EXPORTER_OTLP_TRACES_HEADERS",
|
|
471
|
+
"OTEL_SERVICE_NAME", "CLOUD_MONITOR_APP_KEY",
|
|
472
|
+
"CLOUD_MONITOR_OTLP_ENABLED", "CLOUD_MONITOR_OTLP_ENDPOINT",
|
|
473
|
+
"CLOUD_MONITOR_OTLP_TRACES_ENDPOINT", "CLOUD_MONITOR_OTLP_HEADERS",
|
|
474
|
+
"CLOUD_MONITOR_LANGFUSE_HOST", "CLOUD_MONITOR_LANGFUSE_PUBLIC_KEY",
|
|
475
|
+
"CLOUD_MONITOR_LANGFUSE_SECRET_KEY", "CLOUD_MONITOR_LANGFUSE_ENABLED",
|
|
476
|
+
"LANGCHAIN_TRACING_V2", "MODEL_NAME",
|
|
477
|
+
]
|
|
478
|
+
for key in env_keys:
|
|
479
|
+
value = os.environ.get(key)
|
|
480
|
+
if value:
|
|
481
|
+
if "KEY" in key or "SECRET" in key or "HEADERS" in key:
|
|
482
|
+
value = value[:8] + "****" if len(value) > 8 else "****"
|
|
483
|
+
logger.info(f" {{key}}: {{value}}")
|
|
484
|
+
|
|
485
|
+
# ========== 加载 Agent ==========
|
|
486
|
+
from ksadk.configs import setup_environment
|
|
487
|
+
setup_environment(Path("/app"))
|
|
488
|
+
|
|
489
|
+
try:
|
|
490
|
+
from ksadk.runners.patch_langchain import apply_patch as apply_langchain_patch
|
|
491
|
+
apply_langchain_patch()
|
|
492
|
+
except ImportError:
|
|
493
|
+
pass
|
|
494
|
+
|
|
495
|
+
from ksadk.runners import create_runner
|
|
496
|
+
from ksadk.detection import DetectionResult, FrameworkType
|
|
497
|
+
from ksadk.server import app, set_runner
|
|
498
|
+
import uvicorn
|
|
499
|
+
|
|
500
|
+
# 检测结果 (构建时固化)
|
|
501
|
+
detection_result = DetectionResult(
|
|
502
|
+
type=FrameworkType.{detection_result.type.name},
|
|
503
|
+
name="{detection_result.name}",
|
|
504
|
+
entry_point="{detection_result.entry_point}",
|
|
505
|
+
package_path="/app/{package_name}",
|
|
506
|
+
agent_variable="{detection_result.agent_variable}",
|
|
507
|
+
runner_class="{getattr(detection_result, 'runner_class', '')}"
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
logger.info(f"框架: {{detection_result.name}}")
|
|
511
|
+
logger.info(f"入口: {{detection_result.entry_point}}")
|
|
512
|
+
|
|
513
|
+
# 初始化 Tracing (如果配置了 Langfuse、标准 OTLP HTTP 或 CloudMonitor OTLP)
|
|
514
|
+
has_otlp = bool(os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT") or os.environ.get("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"))
|
|
515
|
+
has_cloud_monitor_otlp = bool(
|
|
516
|
+
os.environ.get("CLOUD_MONITOR_APP_KEY")
|
|
517
|
+
or os.environ.get("CLOUD_MONITOR_OTLP_ENDPOINT")
|
|
518
|
+
or os.environ.get("CLOUD_MONITOR_OTLP_TRACES_ENDPOINT")
|
|
519
|
+
)
|
|
520
|
+
has_cloud_monitor_langfuse = bool(
|
|
521
|
+
os.environ.get("CLOUD_MONITOR_LANGFUSE_PUBLIC_KEY")
|
|
522
|
+
or os.environ.get("CLOUD_MONITOR_LANGFUSE_SECRET_KEY")
|
|
523
|
+
or os.environ.get("CLOUD_MONITOR_LANGFUSE_HOST")
|
|
524
|
+
)
|
|
525
|
+
if os.environ.get("LANGFUSE_PUBLIC_KEY") or has_otlp or has_cloud_monitor_otlp or has_cloud_monitor_langfuse:
|
|
526
|
+
try:
|
|
527
|
+
from ksadk.tracing import setup_tracing
|
|
528
|
+
use_callback_only = os.environ.get("LANGFUSE_USE_CALLBACK", "").strip().lower() in ("1", "true", "yes", "on")
|
|
529
|
+
setup_tracing(use_callback_only=use_callback_only)
|
|
530
|
+
logger.info(
|
|
531
|
+
f"Tracing 已启用 (OTLP={{has_otlp}}, "
|
|
532
|
+
f"CloudMonitorOTLP={{has_cloud_monitor_otlp}}, "
|
|
533
|
+
f"CloudMonitorLangfuse={{has_cloud_monitor_langfuse}}, "
|
|
534
|
+
f"CallbackOnly={{use_callback_only}})"
|
|
535
|
+
)
|
|
536
|
+
except Exception as e:
|
|
537
|
+
logger.warning(f"Tracing 初始化失败: {{e}}")
|
|
538
|
+
|
|
539
|
+
# 创建 Runner 并加载 Agent
|
|
540
|
+
logger.info("正在加载 Agent...")
|
|
541
|
+
runner = create_runner(detection_result, "/app")
|
|
542
|
+
runner.load_agent()
|
|
543
|
+
set_runner(runner)
|
|
544
|
+
logger.info("Agent 加载成功!")
|
|
545
|
+
|
|
546
|
+
if __name__ == "__main__":
|
|
547
|
+
port = int(os.environ.get("PORT", 8080))
|
|
548
|
+
logger.info(f"启动 HTTP Server: 0.0.0.0:{{port}}")
|
|
549
|
+
uvicorn.run(app, host="0.0.0.0", port=port, log_level=LOG_LEVEL.lower())
|
|
550
|
+
'''
|
|
551
|
+
|
|
552
|
+
def build(self) -> BuildResult:
|
|
553
|
+
"""构建 Docker 镜像"""
|
|
554
|
+
from ksadk.detection import FrameworkDetector
|
|
555
|
+
|
|
556
|
+
self._load_dotenv()
|
|
557
|
+
config = self._load_config()
|
|
558
|
+
|
|
559
|
+
# 检测框架
|
|
560
|
+
detector = FrameworkDetector(str(self.project_dir))
|
|
561
|
+
result = detector.detect()
|
|
562
|
+
|
|
563
|
+
if result.type.value == "unknown":
|
|
564
|
+
return BuildResult(
|
|
565
|
+
success=False,
|
|
566
|
+
error_message="未检测到支持的框架"
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
click.echo(f"📦 框架: {click.style(result.name, fg='green')}")
|
|
570
|
+
|
|
571
|
+
# 确定镜像名称
|
|
572
|
+
image_name = config.get('name', self.project_dir.name).replace('-', '_').replace('.', '_')
|
|
573
|
+
|
|
574
|
+
# Tag 优先级: 命令行 > agentengine.yaml version > config image.tag > latest
|
|
575
|
+
image_tag = self.tag
|
|
576
|
+
if not image_tag:
|
|
577
|
+
image_tag = config.get('version', '') # 使用项目版本作为 tag
|
|
578
|
+
if not image_tag:
|
|
579
|
+
image_tag = config.get('image', {}).get('tag', 'latest')
|
|
580
|
+
|
|
581
|
+
# Registry 优先级: 命令行 > .env KCR_REGISTRY > agentengine.yaml > 默认企业版 KCR
|
|
582
|
+
import os
|
|
583
|
+
image_registry = self.registry
|
|
584
|
+
if not image_registry:
|
|
585
|
+
image_registry = os.getenv('KCR_REGISTRY', '')
|
|
586
|
+
if not image_registry:
|
|
587
|
+
image_registry = config.get('image', {}).get('registry', '')
|
|
588
|
+
if not image_registry:
|
|
589
|
+
# 默认使用企业版 KCR,智能选择内网/公网
|
|
590
|
+
image_registry = self._get_smart_kcr_endpoint(os.getenv('KSYUN_REGION', 'cn-beijing-6'))
|
|
591
|
+
else:
|
|
592
|
+
# 即使设置了 registry,如果是金山云公网地址,也尝试优化为内网
|
|
593
|
+
image_registry = self._optimize_kcr_endpoint(image_registry)
|
|
594
|
+
|
|
595
|
+
full_image = f"{image_registry}/{image_name}:{image_tag}"
|
|
596
|
+
|
|
597
|
+
click.echo(f"🏷️ 镜像名称: {full_image}")
|
|
598
|
+
|
|
599
|
+
# 打包 (内置打包逻辑,不再依赖 DockerProvider)
|
|
600
|
+
click.echo("\n📦 打包中...")
|
|
601
|
+
try:
|
|
602
|
+
package_info = self._package(result)
|
|
603
|
+
click.echo("✅ 打包完成")
|
|
604
|
+
except Exception as e:
|
|
605
|
+
return BuildResult(
|
|
606
|
+
success=False,
|
|
607
|
+
error_message=f"打包失败: {e}"
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
# Docker 构建
|
|
611
|
+
if not ensure_docker_running():
|
|
612
|
+
return BuildResult(
|
|
613
|
+
success=False,
|
|
614
|
+
error_message="Docker 未运行"
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
click.echo("\n🔨 构建 Docker 镜像 (目标平台: linux/amd64)...")
|
|
618
|
+
try:
|
|
619
|
+
cmd = ['docker', 'build', '--platform', 'linux/amd64', '-t', full_image]
|
|
620
|
+
if self.no_cache:
|
|
621
|
+
cmd.append('--no-cache')
|
|
622
|
+
cmd.append(package_info.build_dir)
|
|
623
|
+
|
|
624
|
+
quiet_mode = os.getenv("AGENTENGINE_OUTPUT_MODE", "").strip().lower() == "json"
|
|
625
|
+
subprocess.run(
|
|
626
|
+
cmd,
|
|
627
|
+
check=True,
|
|
628
|
+
capture_output=quiet_mode,
|
|
629
|
+
text=quiet_mode,
|
|
630
|
+
)
|
|
631
|
+
click.secho(f"\n✅ 镜像构建成功: {full_image}", fg='green')
|
|
632
|
+
|
|
633
|
+
return BuildResult(
|
|
634
|
+
success=True,
|
|
635
|
+
artifact_path=None, # Docker 镜像没有本地文件路径
|
|
636
|
+
metadata={
|
|
637
|
+
"image": full_image,
|
|
638
|
+
"framework": result.type.value,
|
|
639
|
+
"build_dir": package_info.build_dir
|
|
640
|
+
}
|
|
641
|
+
)
|
|
642
|
+
except subprocess.CalledProcessError as e:
|
|
643
|
+
error_message = f"镜像构建失败: {e}"
|
|
644
|
+
if quiet_mode:
|
|
645
|
+
stderr = (e.stderr or "").strip()
|
|
646
|
+
stdout = (e.stdout or "").strip()
|
|
647
|
+
detail = stderr or stdout
|
|
648
|
+
if detail:
|
|
649
|
+
error_message = f"{error_message}: {detail}"
|
|
650
|
+
return BuildResult(
|
|
651
|
+
success=False,
|
|
652
|
+
error_message=error_message
|
|
653
|
+
)
|
|
654
|
+
|
|
655
|
+
def push(self, image_name: str) -> bool:
|
|
656
|
+
"""推送镜像到仓库"""
|
|
657
|
+
# 检查镜像仓库认证
|
|
658
|
+
registry = self._extract_registry(image_name)
|
|
659
|
+
|
|
660
|
+
# 尝试使用 .env 中的认证信息自动登录
|
|
661
|
+
if registry:
|
|
662
|
+
if not self._auto_login_from_env(registry):
|
|
663
|
+
# 自动登录失败,检查是否已有认证
|
|
664
|
+
if not self._check_registry_auth(registry):
|
|
665
|
+
return False
|
|
666
|
+
|
|
667
|
+
click.echo(f"\n📤 推送镜像...")
|
|
668
|
+
try:
|
|
669
|
+
result = subprocess.run(
|
|
670
|
+
['docker', 'push', image_name],
|
|
671
|
+
capture_output=True,
|
|
672
|
+
text=True
|
|
673
|
+
)
|
|
674
|
+
if result.returncode != 0:
|
|
675
|
+
# 检查是否是认证问题
|
|
676
|
+
if 'denied' in result.stderr.lower() or 'unauthorized' in result.stderr.lower():
|
|
677
|
+
self._print_auth_help(registry or 'docker.io')
|
|
678
|
+
return False
|
|
679
|
+
click.secho(f"❌ 镜像推送失败: {result.stderr}", fg='red')
|
|
680
|
+
return False
|
|
681
|
+
|
|
682
|
+
click.secho(f"✅ 镜像推送成功", fg='green')
|
|
683
|
+
return True
|
|
684
|
+
except subprocess.CalledProcessError as e:
|
|
685
|
+
click.secho(f"❌ 镜像推送失败: {e}", fg='red')
|
|
686
|
+
return False
|
|
687
|
+
|
|
688
|
+
def _auto_login_from_env(self, registry: str) -> bool:
|
|
689
|
+
"""尝试使用 .env 中的凭证自动登录"""
|
|
690
|
+
import os
|
|
691
|
+
from dotenv import load_dotenv
|
|
692
|
+
|
|
693
|
+
# 加载 .env
|
|
694
|
+
load_dotenv()
|
|
695
|
+
|
|
696
|
+
# KCR_REGISTRY is a generic registry/namespace target used for KCR and third-party registries.
|
|
697
|
+
kcr_registry = os.getenv('KCR_REGISTRY', '')
|
|
698
|
+
if not kcr_registry:
|
|
699
|
+
kcr_registry = "hub.kce.ksyun.com/agentengine"
|
|
700
|
+
|
|
701
|
+
kcr_username, kcr_password, registry_kind = resolve_registry_credentials(registry)
|
|
702
|
+
|
|
703
|
+
# 检查是否匹配当前 registry (支持部分匹配)
|
|
704
|
+
if registry not in kcr_registry and kcr_registry not in registry:
|
|
705
|
+
return False
|
|
706
|
+
|
|
707
|
+
if not kcr_username or not kcr_password:
|
|
708
|
+
print_registry_credentials_help(registry, kind=registry_kind)
|
|
709
|
+
return False
|
|
710
|
+
|
|
711
|
+
click.echo(f"🔐 使用 .env 中的凭证登录 {registry}...")
|
|
712
|
+
try:
|
|
713
|
+
result = subprocess.run(
|
|
714
|
+
['docker', 'login', registry, '-u', kcr_username, '--password-stdin'],
|
|
715
|
+
input=kcr_password,
|
|
716
|
+
capture_output=True,
|
|
717
|
+
text=True,
|
|
718
|
+
timeout=30
|
|
719
|
+
)
|
|
720
|
+
if result.returncode == 0:
|
|
721
|
+
click.secho(f"✅ 登录成功", fg='green')
|
|
722
|
+
return True
|
|
723
|
+
else:
|
|
724
|
+
click.secho(f"⚠️ 自动登录失败: {result.stderr.strip()}", fg='yellow')
|
|
725
|
+
return False
|
|
726
|
+
except Exception as e:
|
|
727
|
+
click.secho(f"⚠️ 自动登录异常: {e}", fg='yellow')
|
|
728
|
+
return False
|
|
729
|
+
|
|
730
|
+
def get_registry_credentials(self, registry: str | None = None) -> dict:
|
|
731
|
+
"""获取镜像仓库凭证 (用于传给 Serverless)
|
|
732
|
+
|
|
733
|
+
返回扁平化结构: {"username": "...", "password": "..."}
|
|
734
|
+
"""
|
|
735
|
+
import os
|
|
736
|
+
from dotenv import load_dotenv
|
|
737
|
+
|
|
738
|
+
load_dotenv()
|
|
739
|
+
|
|
740
|
+
registry = registry or os.getenv("KCR_REGISTRY", "")
|
|
741
|
+
username, password, _ = resolve_registry_credentials(registry)
|
|
742
|
+
|
|
743
|
+
if username and password:
|
|
744
|
+
return {
|
|
745
|
+
'username': username,
|
|
746
|
+
'password': password
|
|
747
|
+
}
|
|
748
|
+
return {}
|
|
749
|
+
|
|
750
|
+
def _extract_registry(self, image_name: str) -> Optional[str]:
|
|
751
|
+
"""从镜像名称提取仓库地址"""
|
|
752
|
+
# 格式: registry/namespace/image:tag 或 namespace/image:tag (默认 docker.io)
|
|
753
|
+
parts = image_name.split('/')
|
|
754
|
+
if len(parts) >= 2 and ('.' in parts[0] or ':' in parts[0]):
|
|
755
|
+
return parts[0]
|
|
756
|
+
return None # 使用默认 docker.io
|
|
757
|
+
|
|
758
|
+
def _check_registry_auth(self, registry: str) -> bool:
|
|
759
|
+
"""检查是否已登录镜像仓库"""
|
|
760
|
+
try:
|
|
761
|
+
# 尝试获取 docker 配置
|
|
762
|
+
import json
|
|
763
|
+
from pathlib import Path
|
|
764
|
+
|
|
765
|
+
docker_config = Path.home() / '.docker' / 'config.json'
|
|
766
|
+
if docker_config.exists():
|
|
767
|
+
with open(docker_config) as f:
|
|
768
|
+
config = json.load(f)
|
|
769
|
+
auths = config.get('auths', {})
|
|
770
|
+
# 检查是否有该仓库的认证信息
|
|
771
|
+
if registry in auths or f'https://{registry}' in auths:
|
|
772
|
+
return True
|
|
773
|
+
|
|
774
|
+
# 没有找到认证信息,提示用户
|
|
775
|
+
click.secho(f"\n⚠️ 未检测到 {registry} 的登录凭证", fg='yellow')
|
|
776
|
+
self._print_auth_help(registry)
|
|
777
|
+
return False
|
|
778
|
+
except Exception:
|
|
779
|
+
# 无法检查,继续尝试推送
|
|
780
|
+
return True
|
|
781
|
+
|
|
782
|
+
def _print_auth_help(self, registry: str):
|
|
783
|
+
"""打印认证帮助信息"""
|
|
784
|
+
print_registry_credentials_help(registry)
|
|
785
|
+
click.echo("也可以先手动登录:")
|
|
786
|
+
click.echo(f" docker login {registry or 'docker.io'}")
|