agentengine-sdk-python 0.7.0__py3-none-any.whl → 0.8.1__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 → agentengine_sdk_python-0.8.1.dist-info}/METADATA +52 -20
- agentengine_sdk_python-0.8.1.dist-info/RECORD +644 -0
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/WHEEL +1 -1
- ksadk/a2a/__init__.py +180 -11
- ksadk/a2a/bootstrap.py +332 -0
- ksadk/a2a/card.py +15 -0
- ksadk/a2a/context_store.py +203 -0
- ksadk/a2a/control_plane.py +1056 -0
- ksadk/a2a/credential.py +99 -0
- ksadk/a2a/event_adapter.py +149 -0
- ksadk/a2a/executor.py +361 -137
- 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 +112 -0
- ksadk/a2a/server.py +102 -62
- ksadk/a2a/service_env.py +33 -0
- ksadk/a2a/space_client.py +1122 -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/a2a_card.py +101 -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 +872 -0
- ksadk/agui/config.py +92 -0
- ksadk/agui/routes.py +47 -0
- ksadk/api/client.py +238 -204
- ksadk/api/environment.py +27 -0
- ksadk/builders/__init__.py +2 -0
- ksadk/builders/base.py +16 -14
- ksadk/builders/code_builder.py +375 -270
- ksadk/builders/container_builder.py +240 -200
- ksadk/builders/framework_requirements.py +31 -12
- ksadk/builders/ks3_uploader.py +60 -29
- ksadk/builders/managed_runtime_builder.py +173 -0
- ksadk/builders/mcp_builder.py +91 -92
- ksadk/builders/requirements_utils.py +1 -5
- ksadk/cli/__init__.py +97 -171
- ksadk/cli/cmd_a2a.py +255 -84
- 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 +507 -740
- ksadk/cli/cmd_dashboard.py +120 -45
- ksadk/cli/cmd_deploy.py +135 -59
- ksadk/cli/cmd_destroy.py +44 -14
- ksadk/cli/cmd_eval.py +386 -0
- ksadk/cli/cmd_files.py +63 -24
- ksadk/cli/cmd_hermes.py +313 -135
- ksadk/cli/cmd_invoke.py +184 -122
- ksadk/cli/cmd_launch.py +76 -28
- ksadk/cli/cmd_mcp.py +98 -64
- ksadk/cli/cmd_model.py +14 -5
- ksadk/cli/cmd_openclaw.py +564 -268
- ksadk/cli/cmd_replay.py +71 -0
- ksadk/cli/cmd_run.py +58 -73
- ksadk/cli/cmd_status.py +80 -31
- ksadk/cli/cmd_studio.py +110 -0
- ksadk/cli/cmd_version.py +20 -13
- ksadk/cli/cmd_web.py +95 -18
- ksadk/cli/deploy_utils.py +20 -20
- ksadk/cli/dry_run.py +7 -4
- ksadk/cli/env_options.py +83 -0
- ksadk/cli/error_utils.py +37 -12
- ksadk/cli/global_options.py +4 -3
- ksadk/cli/local_runtime.py +1 -2
- ksadk/cli/model_catalog.py +6 -2
- ksadk/cli/network_options.py +41 -19
- ksadk/cli/resource_common.py +6 -2
- ksadk/cli/runtime_bootstrap.py +51 -0
- ksadk/cli/storage.py +0 -1
- ksadk/cli/ui.py +11 -3
- ksadk/cli/workflow_common.py +52 -18
- ksadk/codex/__init__.py +12 -0
- ksadk/codex/client.py +1042 -0
- ksadk/codex/phase.py +143 -0
- ksadk/codex/runtime.py +940 -0
- ksadk/common/aicp_env.py +0 -1
- ksadk/common/auth.py +2 -2
- ksadk/common/constants.py +1 -3
- ksadk/common/kop_client.py +232 -0
- 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 -14
- ksadk/configs/env_registry.py +661 -116
- ksadk/configs/global_config.py +3 -2
- ksadk/configs/settings.py +133 -209
- ksadk/conversations/__init__.py +85 -92
- 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 +438 -51
- ksadk/conversations/model_context.py +12 -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 -5255
- 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 +660 -0
- ksadk/conversations/runtime_invocation.py +395 -0
- ksadk/conversations/runtime_metadata.py +475 -0
- ksadk/conversations/runtime_observability.py +367 -0
- ksadk/conversations/runtime_payloads.py +272 -0
- ksadk/conversations/runtime_persistence.py +440 -0
- ksadk/conversations/runtime_preparation.py +426 -0
- ksadk/conversations/runtime_resume.py +836 -0
- ksadk/conversations/runtime_stream_events.py +902 -0
- ksadk/conversations/runtime_streaming.py +700 -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 +51 -38
- ksadk/deployment/managed_runtime.py +33 -0
- ksadk/deployment/manager.py +85 -71
- ksadk/deployment/providers/serverless.py +379 -210
- 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/evaluation/__init__.py +84 -0
- ksadk/evaluation/a2a_adapter.py +444 -0
- ksadk/evaluation/adapters.py +54 -0
- ksadk/evaluation/contracts.py +409 -0
- ksadk/evaluation/evalset.py +351 -0
- ksadk/evaluation/evaluators.py +461 -0
- ksadk/evaluation/executor.py +118 -0
- ksadk/evaluation/storage.py +68 -0
- ksadk/evaluation/target.py +73 -0
- ksadk/events/__init__.py +25 -0
- ksadk/events/parser.py +191 -0
- ksadk/events/replay.py +37 -0
- ksadk/events/runtime_event.py +273 -0
- ksadk/events/store.py +317 -0
- ksadk/harness/__init__.py +35 -0
- ksadk/harness/app.py +269 -0
- ksadk/harness/config.py +181 -0
- ksadk/harness/reasoner.py +105 -0
- ksadk/harness/runtime.py +364 -0
- ksadk/harness/sandbox.py +141 -0
- ksadk/harness/tools.py +222 -0
- ksadk/hermes_terminal.py +28 -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 +38 -33
- ksadk/managed_a2a_card.py +160 -0
- ksadk/managed_runtime.py +195 -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 +36 -36
- ksadk/memory/adk/long_term_memory.py +34 -37
- ksadk/memory/adk/resilient_session_service.py +4 -5
- ksadk/memory/adk/short_term_memory.py +12 -21
- 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 +16 -6
- ksadk/memory/tool.py +4 -0
- 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 +66 -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 +201 -0
- ksadk/model_proxy/protocol_proxy.py +22 -0
- ksadk/model_proxy/server.py +443 -0
- ksadk/model_proxy/transform.py +735 -0
- ksadk/openclaw_gateway.py +29 -14
- ksadk/runners/adk_runner.py +354 -146
- ksadk/runners/base_runner.py +71 -29
- ksadk/runners/deepagents_runner.py +0 -1
- ksadk/runners/factory.py +18 -5
- ksadk/runners/langchain_runner.py +29 -742
- ksadk/runners/langgraph_runner.py +417 -97
- ksadk/runners/patch_langchain.py +16 -16
- ksadk/runners/remote_runner.py +134 -33
- ksadk/runners/usage_accumulator.py +1 -0
- ksadk/runners/utils/__init__.py +0 -10
- ksadk/runners/utils/loader.py +23 -7
- ksadk/runtime/__init__.py +67 -0
- ksadk/runtime/adapter.py +412 -0
- ksadk/runtime/conversation_execution.py +553 -0
- ksadk/runtime/executor.py +251 -0
- ksadk/runtime/factory.py +156 -0
- ksadk/runtime/framework_adapters.py +118 -0
- ksadk/runtime/launch.py +48 -0
- ksadk/runtime/preprocessing.py +131 -0
- ksadk/runtime/runner_adapter.py +1032 -0
- ksadk/runtime/runner_loading.py +36 -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/__init__.py +39 -4
- ksadk/server/api_models.py +15 -5
- ksadk/server/app.py +24 -3928
- ksadk/server/composition.py +47 -0
- ksadk/server/factory.py +622 -0
- ksadk/server/routes/__init__.py +1 -0
- ksadk/server/routes/checkpoint_resolution.py +116 -0
- ksadk/server/routes/common.py +682 -0
- ksadk/server/routes/control.py +331 -0
- ksadk/server/routes/dependencies.py +98 -0
- ksadk/server/routes/misc.py +425 -0
- ksadk/server/routes/models.py +451 -0
- ksadk/server/routes/openai_compat.py +229 -0
- ksadk/server/routes/projection.py +848 -0
- ksadk/server/routes/routers.py +52 -0
- ksadk/server/routes/run.py +519 -0
- ksadk/server/routes/sessions.py +644 -0
- ksadk/server/routes/streaming.py +265 -0
- ksadk/server/routes/workspace.py +414 -0
- ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-CakCqxEN.js} +1 -1
- ksadk/server/static/assets/CodeBlock-CynLknyO.js +9 -0
- ksadk/server/static/assets/MathMessageMarkdown-3sQdOysS.js +8 -0
- ksadk/server/static/assets/MermaidBlock-NERD_ef7.js +303 -0
- ksadk/server/static/assets/NativeTerminalPanel-CiHWf82q.js +1 -0
- ksadk/server/static/assets/{arc-BA13sHc9.js → arc-DrgjcKhl.js} +1 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-CpZLRCcY.js +1 -0
- ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-BXoVRbQ6.js} +1 -1
- ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-BnaB3Ywv.js} +1 -1
- ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-Dw4weZcp.js} +1 -1
- ksadk/server/static/assets/channel-Dt3rQTFI.js +1 -0
- ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-ChjpLK7j.js} +1 -1
- ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-B9drTgOW.js} +1 -1
- ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-CK4ROATy.js} +1 -1
- ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B9KtTTgw.js} +1 -1
- ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-1O1mki3m.js} +1 -1
- ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-B_fH2YuH.js} +1 -1
- ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D6rFLaVV.js} +1 -1
- ksadk/server/static/assets/chunk-QZHKN3VN-iXEZtKQc.js +1 -0
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-DIveV17Q.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-DIveV17Q.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-ChNs_Mdk.js} +1 -1
- ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-D0QXg_MQ.js} +1 -1
- ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-DBDDKwBQ.js} +1 -1
- ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-BkwDOxmO.js} +1 -1
- ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Bv8waYvY.js} +1 -1
- ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-e1VECDdu.js} +1 -1
- ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-Ds9adfRl.js} +1 -1
- ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-4N2NMVYg.js} +1 -1
- ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-B-jNR6Vn.js} +1 -1
- ksadk/server/static/assets/{dist-D57wnGWd.js → dist-B5J2uhNk.js} +1 -1
- ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-B5oS1zcj.js} +1 -1
- ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BB3-OwTQ.js} +1 -1
- ksadk/server/static/assets/{dist-2hInLS_J.js → dist-BIlKoW0k.js} +1 -1
- ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-BjOdlDjj.js} +1 -1
- ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-C1sz5Eo3.js} +1 -1
- ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-CWV4lDr1.js} +1 -1
- ksadk/server/static/assets/{dist-D-xOD048.js → dist-CmZHzlwZ.js} +1 -1
- ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-D6MpCZtz.js} +1 -1
- ksadk/server/static/assets/{dist-DyOkZmze.js → dist-DJN_6Y39.js} +1 -1
- ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-DQU9EWw-.js} +1 -1
- ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-DWKByxWV.js} +1 -1
- ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-Dli7qW-B.js} +1 -1
- ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-DsHPdk3W.js} +1 -1
- ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-X4TnqwOK.js} +1 -1
- ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-_pHPTyZ-.js} +1 -1
- ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-fhOuWds5.js} +1 -1
- ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-gLnrGsoU.js} +1 -1
- ksadk/server/static/assets/{dist-BssVmjIo.js → dist-j6Dxmf_j.js} +1 -1
- ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-o2OVmKvt.js} +1 -1
- ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-BPItFKH6.js} +1 -1
- ksadk/server/static/assets/eventmodeling-FCH6USID-DYFSxbqr.js +1 -0
- ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-BbYB9w5Y.js} +1 -1
- ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-TQXa0KXv.js} +1 -1
- ksadk/server/static/assets/gitGraph-WXDBUCRP-DyNYp6BN.js +1 -0
- ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-bKblCnpa.js} +1 -1
- ksadk/server/static/assets/index-R52pJJvg.js +177 -0
- ksadk/server/static/assets/index-jJr3_955.css +2 -0
- ksadk/server/static/assets/info-J43DQDTF-WUx7qTde.js +1 -0
- ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-BGVT7J_i.js} +1 -1
- ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-K0OOfVna.js} +1 -1
- ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-8LeOJaZp.js} +1 -1
- ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-C6uCgZrW.js} +1 -1
- ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-CYWseY5E.js} +1 -1
- ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-hdBcYzM8.js} +1 -1
- ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-BWrDjSZM.js} +2 -2
- ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-Bjy_2v4_.js} +1 -1
- ksadk/server/static/assets/packet-YPE3B663-BN13y_xl.js +1 -0
- ksadk/server/static/assets/pie-LRSECV5Y-ftSLXhhc.js +1 -0
- ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-GmmqNiVH.js} +1 -1
- ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-BmkRbwCg.js} +1 -1
- ksadk/server/static/assets/radar-GUYGQ44K-jaICkIeO.js +1 -0
- ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DSWFqL7c.js} +1 -1
- ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-l6iXmU65.js} +1 -1
- ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-Cq6UBeQB.js} +1 -1
- ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-qzTQpg3Y.js} +1 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-BYCoYGAN.js +1 -0
- ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-DEz24vV0.js} +1 -1
- ksadk/server/static/assets/treeView-BLDUP644-Cpib_vlz.js +1 -0
- ksadk/server/static/assets/treemap-LRROVOQU-DQxfmVHK.js +1 -0
- ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-CMCixki2.js} +1 -1
- ksadk/server/static/assets/wardley-L42UT6IY-BQYHnnkU.js +1 -0
- ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-CVzB8F9K.js} +1 -1
- ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-BFBqBLc1.js} +1 -1
- ksadk/server/static/index.html +2 -2
- ksadk/server/terminal_sessions.py +111 -58
- ksadk/sessions/__init__.py +69 -19
- ksadk/sessions/base.py +31 -11
- ksadk/sessions/continuity.py +2 -3
- ksadk/sessions/in_memory.py +46 -2
- ksadk/sessions/local_service.py +148 -17
- ksadk/sessions/postgres_service.py +143 -25
- ksadk/sessions/resilient.py +36 -8
- 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 +47 -16
- ksadk/skills/tool_defs.py +15 -10
- ksadk/studio/__init__.py +5 -0
- ksadk/studio/agent_avatar_assets.py +120 -0
- ksadk/studio/agent_lifecycle.py +51 -0
- ksadk/studio/api.py +1046 -0
- ksadk/studio/api_catalog_routes.py +324 -0
- ksadk/studio/api_contracts.py +177 -0
- ksadk/studio/api_helpers.py +132 -0
- ksadk/studio/authoring.py +524 -0
- ksadk/studio/authoring_coordinator.py +285 -0
- ksadk/studio/builder.py +320 -0
- ksadk/studio/capabilities.py +351 -0
- ksadk/studio/cloud.py +278 -0
- ksadk/studio/codex_agent_service.py +583 -0
- ksadk/studio/codex_builder.py +324 -0
- ksadk/studio/codex_manifest.py +278 -0
- ksadk/studio/codex_run.py +352 -0
- ksadk/studio/compiler.py +189 -0
- ksadk/studio/contracts.py +644 -0
- ksadk/studio/errors.py +47 -0
- ksadk/studio/evaluation.py +192 -0
- ksadk/studio/event_store.py +284 -0
- ksadk/studio/framework_run.py +114 -0
- ksadk/studio/identifiers.py +33 -0
- ksadk/studio/mcp_runtime.py +229 -0
- ksadk/studio/model_client.py +543 -0
- ksadk/studio/model_profile_service.py +214 -0
- ksadk/studio/operations.py +243 -0
- ksadk/studio/otel_trace.py +754 -0
- ksadk/studio/pagination.py +182 -0
- ksadk/studio/python_tool_inspection.py +183 -0
- ksadk/studio/repository.py +306 -0
- ksadk/studio/resource_catalog.py +1217 -0
- ksadk/studio/run_service.py +707 -0
- ksadk/studio/runtime_catalog.py +74 -0
- ksadk/studio/runtime_source.py +339 -0
- ksadk/studio/service.py +1141 -0
- ksadk/studio/shared_web.py +994 -0
- ksadk/studio/skill_discovery.py +628 -0
- ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
- ksadk/studio/static/assets/index-CaEN0eTR.css +1 -0
- ksadk/studio/static/assets/index-DI2eY_NH.js +252 -0
- ksadk/studio/static/assets/react-vendor-BNmTiJ-I.js +9 -0
- ksadk/studio/static/assets/rolldown-runtime-hePW80VL.js +1 -0
- ksadk/studio/static/index.html +15 -0
- ksadk/studio/templates.py +630 -0
- ksadk/studio/validator.py +246 -0
- ksadk/studio/workspace.py +137 -0
- ksadk/terminal_exec_policy.py +3 -4
- ksadk/tools/gateway.py +101 -15
- ksadk/tools/result_budget.py +12 -4
- ksadk/toolsets/__init__.py +161 -37
- ksadk/toolsets/a2a.py +426 -0
- 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 +212 -101
- ksadk/tracing/__init__.py +19 -21
- ksadk/tracing/exporters/inmemory_exporter.py +62 -51
- ksadk/tracing/setup.py +135 -506
- ksadk/tracing/span_utils.py +0 -41
- ksadk/tui/loop.py +78 -30
- ksadk/tui/stream_render.py +1 -0
- ksadk/ui_config.py +5 -3
- ksadk/version.py +1 -1
- ksadk_runtime_common/memory_backend/registry.py +56 -56
- ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
- ksadk_runtime_common/workspace_files/router.py +8 -2
- agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
- ksadk/a2a/card_builder.py +0 -64
- ksadk/a2a/client.py +0 -309
- ksadk/runners/utils/langfuse.py +0 -230
- ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
- ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
- ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
- ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
- ksadk/server/static/assets/channel-CTuydARX.js +0 -1
- ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
- ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
- ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
- ksadk/server/static/assets/index-DAURbCsP.css +0 -1
- ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
- ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
- ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
- ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
- ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
- ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
- ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
- ksadk/tracing/exporters/langfuse_exporter.py +0 -445
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/top_level.txt +0 -0
ksadk/builders/code_builder.py
CHANGED
|
@@ -7,17 +7,17 @@ Code Builder - zip 打包模式构建
|
|
|
7
7
|
3. 打包 zip (用户代码 + 依赖 + ksadk 源码 + entrypoint)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
+
import ast
|
|
11
|
+
import hashlib
|
|
12
|
+
import json
|
|
10
13
|
import os
|
|
11
|
-
import
|
|
14
|
+
import re
|
|
12
15
|
import shutil
|
|
13
16
|
import subprocess
|
|
17
|
+
import sys
|
|
14
18
|
import threading
|
|
15
19
|
import time
|
|
16
20
|
import zipfile
|
|
17
|
-
import re
|
|
18
|
-
import json
|
|
19
|
-
import hashlib
|
|
20
|
-
import ast
|
|
21
21
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
22
22
|
from pathlib import Path
|
|
23
23
|
from typing import List, Optional, Set
|
|
@@ -25,11 +25,13 @@ from urllib.parse import urlparse
|
|
|
25
25
|
from urllib.request import Request, urlopen
|
|
26
26
|
|
|
27
27
|
import click
|
|
28
|
+
from packaging.requirements import InvalidRequirement, Requirement
|
|
28
29
|
|
|
29
30
|
from ksadk.builders.base import BaseBuilder, BuildResult
|
|
30
31
|
from ksadk.builders.framework_requirements import (
|
|
31
32
|
FASTAPI_REQUIREMENT,
|
|
32
|
-
|
|
33
|
+
STARLETTE_REQUIREMENT,
|
|
34
|
+
code_requirements_for_framework,
|
|
33
35
|
)
|
|
34
36
|
from ksadk.builders.requirements_utils import (
|
|
35
37
|
exclude_requirement_names,
|
|
@@ -85,35 +87,39 @@ class CodeBuilder(BaseBuilder):
|
|
|
85
87
|
}
|
|
86
88
|
IGNORED_FILE_NAMES = {".DS_Store"}
|
|
87
89
|
KSADK_ALLOWED_SUFFIXES = {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
90
|
+
".py",
|
|
91
|
+
".yaml",
|
|
92
|
+
".yml",
|
|
93
|
+
".json",
|
|
94
|
+
".jinja2",
|
|
95
|
+
".j2",
|
|
96
|
+
".txt",
|
|
97
|
+
".md",
|
|
98
|
+
".html",
|
|
99
|
+
".js",
|
|
100
|
+
".css",
|
|
101
|
+
".svg",
|
|
102
|
+
".ico",
|
|
103
|
+
".png",
|
|
104
|
+
".jpg",
|
|
105
|
+
".jpeg",
|
|
106
|
+
".gif",
|
|
107
|
+
".webp",
|
|
108
|
+
".woff",
|
|
109
|
+
".woff2",
|
|
110
|
+
".ttf",
|
|
111
|
+
".map",
|
|
110
112
|
}
|
|
111
113
|
BUNDLED_KSADK_CORE_RUNTIME_REQUIREMENTS = (
|
|
112
114
|
"a2a-sdk>=0.3.22",
|
|
115
|
+
"culsans>=0.11.0",
|
|
113
116
|
"httpx-sse>=0.4.0",
|
|
114
117
|
"sse-starlette>=2.1.0",
|
|
115
118
|
"python-multipart>=0.0.9,<1.0.0",
|
|
116
119
|
"requests>=2.28.0",
|
|
120
|
+
"sqlalchemy>=2.0.0",
|
|
121
|
+
"aiosqlite>=0.19.0",
|
|
122
|
+
"greenlet>=3.0.0",
|
|
117
123
|
"requests-aws4auth>=1.2.0",
|
|
118
124
|
"kingsoftcloud-sdk-python>=1.5.8.94",
|
|
119
125
|
"cryptography>=44.0.0",
|
|
@@ -124,15 +130,16 @@ class CodeBuilder(BaseBuilder):
|
|
|
124
130
|
"mcp>=1.1.0",
|
|
125
131
|
"langchain-mcp-adapters>=0.0.1",
|
|
126
132
|
)
|
|
127
|
-
BUNDLED_KSADK_POSTGRES_SESSION_REQUIREMENTS = (
|
|
128
|
-
"asyncpg>=0.30.0,<1.0.0",
|
|
129
|
-
)
|
|
133
|
+
BUNDLED_KSADK_POSTGRES_SESSION_REQUIREMENTS = ("asyncpg>=0.30.0,<1.0.0",)
|
|
130
134
|
BUNDLED_KSADK_ATTACHMENT_RUNTIME_REQUIREMENTS = (
|
|
131
135
|
"pypdf>=6.0.0",
|
|
132
136
|
"beautifulsoup4>=4.12.0",
|
|
133
137
|
)
|
|
134
|
-
BUNDLED_KSADK_ATTACHMENT_OCR_RUNTIME_REQUIREMENTS = (
|
|
135
|
-
|
|
138
|
+
BUNDLED_KSADK_ATTACHMENT_OCR_RUNTIME_REQUIREMENTS = ("rapidocr-onnxruntime>=1.2.0",)
|
|
139
|
+
BUNDLED_AGUI_RUNTIME_REQUIREMENTS = (
|
|
140
|
+
"ag-ui-protocol==0.1.19",
|
|
141
|
+
"ag-ui-langgraph[fastapi]==0.0.42",
|
|
142
|
+
"copilotkit==0.1.94",
|
|
136
143
|
)
|
|
137
144
|
BUNDLED_KSADK_RUNTIME_REQUIREMENTS = (
|
|
138
145
|
*BUNDLED_KSADK_CORE_RUNTIME_REQUIREMENTS,
|
|
@@ -149,8 +156,8 @@ class CodeBuilder(BaseBuilder):
|
|
|
149
156
|
PIP_INSTALL_TIMEOUT_SECONDS = 45 * 60
|
|
150
157
|
CONTAINER_SUGGESTION_RAW_THRESHOLD_BYTES = 500 * 1024 * 1024
|
|
151
158
|
CONTAINER_SUGGESTION_ZIP_THRESHOLD_BYTES = 300 * 1024 * 1024
|
|
152
|
-
|
|
153
|
-
def __init__(self, project_dir: Path, config: dict = None):
|
|
159
|
+
|
|
160
|
+
def __init__(self, project_dir: Path, config: Optional[dict] = None):
|
|
154
161
|
super().__init__(project_dir, config)
|
|
155
162
|
self.build_dir = self.project_dir / ".agentengine" / "code_build"
|
|
156
163
|
self.deps_dir = self.build_dir / "linux_deps"
|
|
@@ -168,33 +175,38 @@ class CodeBuilder(BaseBuilder):
|
|
|
168
175
|
self._package_progress_logged_milestone_by_label: dict[str, int] = {}
|
|
169
176
|
self._pip_index_candidates_cache: Optional[list[Optional[str]]] = None
|
|
170
177
|
self._pip_index_selection_summary = ""
|
|
171
|
-
|
|
178
|
+
|
|
172
179
|
def build(self) -> BuildResult:
|
|
173
180
|
"""执行 Code 模式构建"""
|
|
174
181
|
from ksadk.detection import FrameworkDetector
|
|
175
|
-
|
|
182
|
+
|
|
176
183
|
self._load_dotenv()
|
|
177
184
|
config = self._load_config()
|
|
178
|
-
|
|
185
|
+
|
|
179
186
|
# 检测框架
|
|
180
187
|
detector = FrameworkDetector(str(self.project_dir))
|
|
181
188
|
detection_result = detector.detect()
|
|
182
|
-
|
|
189
|
+
|
|
183
190
|
if detection_result.type.value == "unknown":
|
|
191
|
+
return BuildResult(success=False, error_message="未检测到支持的框架")
|
|
192
|
+
if detection_result.type.value == "codex":
|
|
184
193
|
return BuildResult(
|
|
185
194
|
success=False,
|
|
186
|
-
error_message=
|
|
195
|
+
error_message=(
|
|
196
|
+
"Codex 是 ManagedRuntime,不能构建宿主机 Code zip;"
|
|
197
|
+
"请使用 `ksadk build .` 的 managed 模式,或显式构建 Container"
|
|
198
|
+
),
|
|
187
199
|
)
|
|
188
|
-
|
|
200
|
+
|
|
189
201
|
click.echo(f"📦 框架: {click.style(detection_result.type.value, fg='green')}")
|
|
190
202
|
click.echo(f"🤖 Agent: {click.style(detection_result.name, fg='blue')}")
|
|
191
|
-
|
|
192
|
-
agent_name = config.get(
|
|
193
|
-
|
|
203
|
+
|
|
204
|
+
agent_name = config.get("name", self.project_dir.name).replace("-", "_").replace(".", "_")
|
|
205
|
+
|
|
194
206
|
# 创建构建目录
|
|
195
207
|
self.build_dir.mkdir(parents=True, exist_ok=True)
|
|
196
208
|
zip_path = self.build_dir / f"{agent_name}.zip"
|
|
197
|
-
|
|
209
|
+
|
|
198
210
|
# 检查是否需要重新构建
|
|
199
211
|
no_cache = self.config.get("no_cache", False) if self.config else False
|
|
200
212
|
repackage = self.config.get("repackage", False) if self.config else False
|
|
@@ -207,31 +219,33 @@ class CodeBuilder(BaseBuilder):
|
|
|
207
219
|
if zip_path.exists() and not rebuild_needed:
|
|
208
220
|
incompatibles = self._scan_incompatible_binaries_in_zip(zip_path)
|
|
209
221
|
if incompatibles:
|
|
210
|
-
click.secho(
|
|
222
|
+
click.secho(
|
|
223
|
+
"\n⚠️ 检测到缓存构建包含非 Linux 兼容关键二进制,自动重建...", fg="yellow"
|
|
224
|
+
)
|
|
211
225
|
for item in incompatibles[:5]:
|
|
212
226
|
click.echo(f" - {item}")
|
|
213
227
|
rebuild_reason = "缓存 zip 存在 Linux 兼容性问题"
|
|
214
228
|
else:
|
|
215
229
|
self._save_input_fingerprint(zip_path, detection_result)
|
|
216
230
|
zip_size = zip_path.stat().st_size / (1024 * 1024)
|
|
217
|
-
click.secho(f"\n✅ 使用已有构建: {zip_path.name} ({zip_size:.2f} MB)", fg=
|
|
218
|
-
click.echo(
|
|
231
|
+
click.secho(f"\n✅ 使用已有构建: {zip_path.name} ({zip_size:.2f} MB)", fg="green")
|
|
232
|
+
click.echo(
|
|
233
|
+
" (如需只重新打包当前代码/runtime,请使用 --repackage;"
|
|
234
|
+
"如需重装依赖,请使用 --no-cache)"
|
|
235
|
+
)
|
|
219
236
|
return BuildResult(
|
|
220
237
|
success=True,
|
|
221
238
|
artifact_path=zip_path,
|
|
222
239
|
artifact_size=zip_path.stat().st_size,
|
|
223
|
-
metadata={
|
|
224
|
-
"agent_name": agent_name,
|
|
225
|
-
"framework": detection_result.type.value
|
|
226
|
-
}
|
|
240
|
+
metadata={"agent_name": agent_name, "framework": detection_result.type.value},
|
|
227
241
|
)
|
|
228
242
|
elif rebuild_reason:
|
|
229
243
|
click.echo(f" 重新打包原因: {rebuild_reason}")
|
|
230
|
-
|
|
244
|
+
|
|
231
245
|
# Step 1: 准备依赖
|
|
232
246
|
click.echo("\n📋 Step 1/3: 准备依赖清单...")
|
|
233
247
|
requirements_path = self._prepare_requirements(detection_result)
|
|
234
|
-
|
|
248
|
+
|
|
235
249
|
# Step 2: 安装依赖
|
|
236
250
|
click.echo("\n📦 Step 2/3: 安装依赖...")
|
|
237
251
|
reuse_dependencies, reuse_reason = self._can_reuse_dependency_cache(
|
|
@@ -241,7 +255,8 @@ class CodeBuilder(BaseBuilder):
|
|
|
241
255
|
if reuse_dependencies:
|
|
242
256
|
stats = self._current_dependency_stats()
|
|
243
257
|
click.secho(
|
|
244
|
-
f" ✓ 复用 Linux 依赖缓存: {stats['file_count']} 个文件,
|
|
258
|
+
f" ✓ 复用 Linux 依赖缓存: {stats['file_count']} 个文件, "
|
|
259
|
+
f"{stats['size_mb']:.1f} MB",
|
|
245
260
|
fg="green",
|
|
246
261
|
)
|
|
247
262
|
click.echo(f" {reuse_reason}")
|
|
@@ -250,25 +265,22 @@ class CodeBuilder(BaseBuilder):
|
|
|
250
265
|
click.echo(f" {reuse_reason}")
|
|
251
266
|
self._clear_dependency_cache()
|
|
252
267
|
self.deps_dir.mkdir(parents=True, exist_ok=True)
|
|
253
|
-
|
|
268
|
+
|
|
254
269
|
if not self._install_dependencies(requirements_path):
|
|
255
|
-
return BuildResult(
|
|
256
|
-
success=False,
|
|
257
|
-
error_message="依赖安装失败"
|
|
258
|
-
)
|
|
270
|
+
return BuildResult(success=False, error_message="依赖安装失败")
|
|
259
271
|
self._save_dependency_fingerprint(requirements_path)
|
|
260
|
-
|
|
272
|
+
|
|
261
273
|
# Step 3: 打包 zip
|
|
262
274
|
click.echo("\n📦 Step 3/3: 打包 zip...")
|
|
263
275
|
package_started_at = time.monotonic()
|
|
264
276
|
self._package_zip(zip_path, detection_result)
|
|
265
277
|
click.echo(f" ✓ 打包耗时: {self._format_elapsed(package_started_at)}")
|
|
266
278
|
self._save_input_fingerprint(zip_path, detection_result)
|
|
267
|
-
|
|
279
|
+
|
|
268
280
|
zip_size = zip_path.stat().st_size
|
|
269
281
|
click.echo(f" zip 文件: {zip_path}")
|
|
270
282
|
click.echo(f" 大小: {zip_size / (1024 * 1024):.2f} MB")
|
|
271
|
-
|
|
283
|
+
|
|
272
284
|
return BuildResult(
|
|
273
285
|
success=True,
|
|
274
286
|
artifact_path=zip_path,
|
|
@@ -276,8 +288,8 @@ class CodeBuilder(BaseBuilder):
|
|
|
276
288
|
metadata={
|
|
277
289
|
"agent_name": agent_name,
|
|
278
290
|
"framework": detection_result.type.value,
|
|
279
|
-
"deps_dir": str(self.deps_dir)
|
|
280
|
-
}
|
|
291
|
+
"deps_dir": str(self.deps_dir),
|
|
292
|
+
},
|
|
281
293
|
)
|
|
282
294
|
|
|
283
295
|
def _rebuild_decision(
|
|
@@ -321,26 +333,32 @@ class CodeBuilder(BaseBuilder):
|
|
|
321
333
|
if changed:
|
|
322
334
|
return "业务代码或项目文件变更"
|
|
323
335
|
return "构建输入指纹变化"
|
|
324
|
-
|
|
336
|
+
|
|
325
337
|
def _need_rebuild(self, zip_path: Path, detection_result) -> bool:
|
|
326
338
|
"""检查是否需要重新构建。优先使用输入内容指纹,缺失时回退到 mtime。"""
|
|
327
339
|
manifest = self._load_input_fingerprint(zip_path)
|
|
328
340
|
if manifest:
|
|
329
341
|
current_fingerprint = self._build_input_fingerprint(detection_result)
|
|
330
|
-
return manifest.get("fingerprint") != current_fingerprint["fingerprint"]
|
|
342
|
+
return bool(manifest.get("fingerprint") != current_fingerprint["fingerprint"])
|
|
331
343
|
return self._need_rebuild_from_mtime(zip_path)
|
|
332
344
|
|
|
333
345
|
def _need_rebuild_from_mtime(self, zip_path: Path) -> bool:
|
|
334
346
|
"""兼容旧缓存:当没有指纹文件时,回退到 mtime 判断。"""
|
|
335
347
|
zip_mtime = zip_path.stat().st_mtime
|
|
336
|
-
|
|
348
|
+
|
|
337
349
|
for item in self.project_dir.iterdir():
|
|
338
|
-
if item.name.startswith(
|
|
350
|
+
if item.name.startswith(".") or item.name in (
|
|
351
|
+
"__pycache__",
|
|
352
|
+
"node_modules",
|
|
353
|
+
".git",
|
|
354
|
+
".venv",
|
|
355
|
+
"venv",
|
|
356
|
+
):
|
|
339
357
|
continue
|
|
340
358
|
if item.is_file() and item.stat().st_mtime > zip_mtime:
|
|
341
359
|
return True
|
|
342
360
|
if item.is_dir():
|
|
343
|
-
for file_path in item.rglob(
|
|
361
|
+
for file_path in item.rglob("*.py"):
|
|
344
362
|
if file_path.stat().st_mtime > zip_mtime:
|
|
345
363
|
return True
|
|
346
364
|
return False
|
|
@@ -360,7 +378,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
360
378
|
data = json.load(f)
|
|
361
379
|
if data.get("version") != self.INPUT_FINGERPRINT_VERSION:
|
|
362
380
|
return None
|
|
363
|
-
return data
|
|
381
|
+
return data if isinstance(data, dict) else None
|
|
364
382
|
except Exception:
|
|
365
383
|
return None
|
|
366
384
|
|
|
@@ -380,7 +398,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
380
398
|
data = json.load(f)
|
|
381
399
|
if data.get("version") != self.DEPENDENCY_FINGERPRINT_VERSION:
|
|
382
400
|
return None
|
|
383
|
-
return data
|
|
401
|
+
return data if isinstance(data, dict) else None
|
|
384
402
|
except Exception:
|
|
385
403
|
return None
|
|
386
404
|
|
|
@@ -429,7 +447,12 @@ class CodeBuilder(BaseBuilder):
|
|
|
429
447
|
return True
|
|
430
448
|
if self._project_env_has_configured_value("KSADK_MCP_SERVERS"):
|
|
431
449
|
return True
|
|
432
|
-
if self._project_env_value("KSADK_ENABLE_MCP_TOOLS").strip().lower() in {
|
|
450
|
+
if self._project_env_value("KSADK_ENABLE_MCP_TOOLS").strip().lower() in {
|
|
451
|
+
"1",
|
|
452
|
+
"true",
|
|
453
|
+
"yes",
|
|
454
|
+
"on",
|
|
455
|
+
}:
|
|
433
456
|
return True
|
|
434
457
|
return self._project_imports_any({"mcp", "langchain_mcp_adapters"})
|
|
435
458
|
|
|
@@ -515,13 +538,17 @@ class CodeBuilder(BaseBuilder):
|
|
|
515
538
|
digest = hashlib.sha256()
|
|
516
539
|
requirements_text = requirements_path.read_text(encoding="utf-8")
|
|
517
540
|
|
|
518
|
-
digest.update(
|
|
541
|
+
digest.update(
|
|
542
|
+
f"deps-fingerprint-version:{self.DEPENDENCY_FINGERPRINT_VERSION}\n".encode("utf-8")
|
|
543
|
+
)
|
|
519
544
|
digest.update(f"builder-platform:{sys.platform}\n".encode("utf-8"))
|
|
520
545
|
digest.update(
|
|
521
546
|
f"builder-python:{sys.version_info.major}.{sys.version_info.minor}\n".encode("utf-8")
|
|
522
547
|
)
|
|
523
548
|
digest.update(f"target-python:{self.TARGET_PYTHON_VERSION}\n".encode("utf-8"))
|
|
524
|
-
digest.update(
|
|
549
|
+
digest.update(
|
|
550
|
+
f"target-platforms:{','.join(self.TARGET_INSTALL_PLATFORMS)}\n".encode("utf-8")
|
|
551
|
+
)
|
|
525
552
|
digest.update(requirements_text.encode("utf-8"))
|
|
526
553
|
|
|
527
554
|
requirements = [line for line in requirements_text.splitlines() if line.strip()]
|
|
@@ -641,13 +668,13 @@ class CodeBuilder(BaseBuilder):
|
|
|
641
668
|
)
|
|
642
669
|
|
|
643
670
|
def _iter_bundled_source_package(self, package_name: str, package_root: Path):
|
|
644
|
-
for file_path in sorted(package_root.rglob(
|
|
671
|
+
for file_path in sorted(package_root.rglob("*")):
|
|
645
672
|
if not file_path.is_file():
|
|
646
673
|
continue
|
|
647
674
|
relative_path = file_path.relative_to(package_root)
|
|
648
675
|
if package_name == "ksadk" and self._should_skip_ksadk_relative_path(relative_path):
|
|
649
676
|
continue
|
|
650
|
-
if
|
|
677
|
+
if "__pycache__" in file_path.parts:
|
|
651
678
|
continue
|
|
652
679
|
suffix = file_path.suffix.lower()
|
|
653
680
|
if suffix not in self.KSADK_ALLOWED_SUFFIXES:
|
|
@@ -709,26 +736,26 @@ class CodeBuilder(BaseBuilder):
|
|
|
709
736
|
file_name.startswith(".env.")
|
|
710
737
|
and file_name not in {".env.example", ".env.sample", ".env.template"}
|
|
711
738
|
)
|
|
712
|
-
|
|
739
|
+
|
|
713
740
|
def _prepare_requirements(self, detection_result) -> Path:
|
|
714
741
|
"""准备 requirements.txt"""
|
|
715
742
|
final_deps = self._build_requirements_list(detection_result)
|
|
716
743
|
|
|
717
744
|
if (self.project_dir / "requirements.txt").exists():
|
|
718
|
-
click.echo(
|
|
745
|
+
click.echo(" 发现 requirements.txt,正在合并...")
|
|
719
746
|
else:
|
|
720
|
-
click.echo(
|
|
721
|
-
|
|
747
|
+
click.echo(" 自动生成依赖清单")
|
|
748
|
+
|
|
722
749
|
# 写入构建目录
|
|
723
750
|
requirements_path = self.build_dir / "requirements.txt"
|
|
724
751
|
requirements_path.write_text("\n".join(final_deps))
|
|
725
|
-
|
|
752
|
+
|
|
726
753
|
click.echo(f" 共 {len(final_deps)} 个依赖包:")
|
|
727
754
|
for dep in final_deps[:5]:
|
|
728
755
|
click.echo(f" • {dep}")
|
|
729
756
|
if len(final_deps) > 5:
|
|
730
757
|
click.echo(f" ... 及其他 {len(final_deps) - 5} 个")
|
|
731
|
-
|
|
758
|
+
|
|
732
759
|
return requirements_path
|
|
733
760
|
|
|
734
761
|
def _build_requirements_list(self, detection_result) -> List[str]:
|
|
@@ -740,37 +767,59 @@ class CodeBuilder(BaseBuilder):
|
|
|
740
767
|
user_requirements = self.project_dir / "requirements.txt"
|
|
741
768
|
if user_requirements.exists():
|
|
742
769
|
user_content = user_requirements.read_text(encoding="utf-8")
|
|
770
|
+
parsed_user_requirements = parse_requirements_text(user_content)
|
|
771
|
+
final_deps = merge_requirement_lists(
|
|
772
|
+
final_deps,
|
|
773
|
+
self._bundled_ksadk_extra_requirements(parsed_user_requirements),
|
|
774
|
+
)
|
|
743
775
|
user_deps = exclude_requirement_names(
|
|
744
|
-
|
|
776
|
+
parsed_user_requirements,
|
|
745
777
|
excluded_names={"ksadk"},
|
|
746
778
|
)
|
|
747
779
|
final_deps = merge_requirement_lists(final_deps, user_deps)
|
|
748
780
|
|
|
749
781
|
return final_deps
|
|
750
|
-
|
|
782
|
+
|
|
783
|
+
def _bundled_ksadk_extra_requirements(self, requirements: List[str]) -> tuple[str, ...]:
|
|
784
|
+
extras: set[str] = set()
|
|
785
|
+
for raw_requirement in requirements:
|
|
786
|
+
try:
|
|
787
|
+
parsed = Requirement(raw_requirement)
|
|
788
|
+
except InvalidRequirement:
|
|
789
|
+
continue
|
|
790
|
+
if parsed.name.lower().replace("_", "-") != "ksadk":
|
|
791
|
+
continue
|
|
792
|
+
extras.update(extra.lower() for extra in parsed.extras)
|
|
793
|
+
|
|
794
|
+
bundled: list[str] = []
|
|
795
|
+
if "agui" in extras:
|
|
796
|
+
bundled.extend(self.BUNDLED_AGUI_RUNTIME_REQUIREMENTS)
|
|
797
|
+
return tuple(bundled)
|
|
798
|
+
|
|
751
799
|
def _get_base_requirements(self, detection_result) -> List[str]:
|
|
752
800
|
"""获取基础依赖列表"""
|
|
753
801
|
deps = [
|
|
754
802
|
# Core
|
|
755
803
|
FASTAPI_REQUIREMENT,
|
|
804
|
+
STARLETTE_REQUIREMENT,
|
|
756
805
|
"uvicorn>=0.23.0",
|
|
757
806
|
"python-dotenv>=1.0.0",
|
|
758
807
|
"pydantic>=2.0.0",
|
|
759
808
|
"pyyaml>=6.0.0",
|
|
760
809
|
"httpx>=0.24.0",
|
|
761
|
-
# Tracing
|
|
810
|
+
# Tracing — OTLP 双写收敛:只用 OTel + openinference 自动插桩,
|
|
811
|
+
# 不再安装 Langfuse SDK(callback 路径已删除,Langfuse 通过标准 OTLP 接收)。
|
|
762
812
|
"opentelemetry-api>=1.37.0",
|
|
763
813
|
"opentelemetry-sdk>=1.37.0",
|
|
764
814
|
"opentelemetry-exporter-otlp>=1.37.0",
|
|
765
815
|
"openinference-instrumentation-langchain>=0.1.0",
|
|
766
|
-
"langfuse>=2.0.0",
|
|
767
816
|
]
|
|
768
|
-
|
|
817
|
+
|
|
769
818
|
framework = detection_result.type.value
|
|
770
|
-
deps +=
|
|
771
|
-
|
|
819
|
+
deps += code_requirements_for_framework(framework)
|
|
820
|
+
|
|
772
821
|
return deps
|
|
773
|
-
|
|
822
|
+
|
|
774
823
|
# 目标 Python 版本 (必须与容器运行时一致)
|
|
775
824
|
TARGET_PYTHON_VERSION = "312" # 容器中为 Python 3.12
|
|
776
825
|
|
|
@@ -875,9 +924,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
875
924
|
def _result_error_summary(self, result: subprocess.CompletedProcess[str] | None) -> str:
|
|
876
925
|
if result is None:
|
|
877
926
|
return "unknown"
|
|
878
|
-
combined = "\n".join(
|
|
879
|
-
part for part in (result.stderr or "", result.stdout or "") if part
|
|
880
|
-
)
|
|
927
|
+
combined = "\n".join(part for part in (result.stderr or "", result.stdout or "") if part)
|
|
881
928
|
for line in reversed(combined.splitlines()):
|
|
882
929
|
normalized = line.strip()
|
|
883
930
|
if normalized:
|
|
@@ -887,9 +934,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
887
934
|
def _pip_missing_from_result(self, result: subprocess.CompletedProcess[str] | None) -> bool:
|
|
888
935
|
if result is None:
|
|
889
936
|
return False
|
|
890
|
-
combined = "\n".join(
|
|
891
|
-
part for part in (result.stderr or "", result.stdout or "") if part
|
|
892
|
-
)
|
|
937
|
+
combined = "\n".join(part for part in (result.stderr or "", result.stdout or "") if part)
|
|
893
938
|
return "No module named pip" in combined
|
|
894
939
|
|
|
895
940
|
def _bootstrap_pip_if_missing(self, result: subprocess.CompletedProcess[str] | None) -> bool:
|
|
@@ -952,7 +997,9 @@ class CodeBuilder(BaseBuilder):
|
|
|
952
997
|
if not normalized:
|
|
953
998
|
return None
|
|
954
999
|
|
|
955
|
-
force_emit =
|
|
1000
|
+
force_emit = (
|
|
1001
|
+
percent > self._install_progress_percent or stage != self._install_progress_stage_name
|
|
1002
|
+
)
|
|
956
1003
|
count = self._install_progress_event_counts.get(stage, 0) + 1
|
|
957
1004
|
self._install_progress_event_counts[stage] = count
|
|
958
1005
|
|
|
@@ -960,7 +1007,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
960
1007
|
return self._truncate_progress_summary(normalized)
|
|
961
1008
|
|
|
962
1009
|
if stage == "解析依赖":
|
|
963
|
-
detail = normalized[len("Collecting "):].split(" (from ", 1)[0]
|
|
1010
|
+
detail = normalized[len("Collecting ") :].split(" (from ", 1)[0]
|
|
964
1011
|
summary = f"已解析 {count} 个依赖,最近: {detail}"
|
|
965
1012
|
if force_emit or count in self.INSTALL_PROGRESS_EVENT_MILESTONES or count % 10 == 0:
|
|
966
1013
|
return summary
|
|
@@ -973,35 +1020,36 @@ class CodeBuilder(BaseBuilder):
|
|
|
973
1020
|
|
|
974
1021
|
if stage == "下载依赖":
|
|
975
1022
|
if normalized.startswith("Using cached "):
|
|
976
|
-
payload = normalized[len("Using cached "):]
|
|
1023
|
+
payload = normalized[len("Using cached ") :]
|
|
977
1024
|
elif normalized.startswith("Downloading "):
|
|
978
|
-
payload = normalized[len("Downloading "):]
|
|
1025
|
+
payload = normalized[len("Downloading ") :]
|
|
979
1026
|
else:
|
|
980
1027
|
payload = normalized
|
|
981
1028
|
target = self._extract_pip_artifact_name(payload)
|
|
982
|
-
|
|
1029
|
+
elapsed = self._format_elapsed(self._install_progress_started_at)
|
|
1030
|
+
summary = f"已处理 {count} 个 wheel,耗时 {elapsed},最近: {target}"
|
|
983
1031
|
if force_emit or count in self.INSTALL_PROGRESS_EVENT_MILESTONES or count % 5 == 0:
|
|
984
1032
|
return summary
|
|
985
1033
|
return None
|
|
986
1034
|
|
|
987
1035
|
if stage == "构建 wheel":
|
|
988
|
-
detail = normalized[len("Building wheel for "):].split(" ", 1)[0]
|
|
1036
|
+
detail = normalized[len("Building wheel for ") :].split(" ", 1)[0]
|
|
989
1037
|
if force_emit or count == 1 or count % 5 == 0:
|
|
990
1038
|
return f"构建 wheel: {detail}"
|
|
991
1039
|
return None
|
|
992
1040
|
|
|
993
1041
|
if stage == "安装依赖":
|
|
994
|
-
detail = normalized[len("Installing collected packages:"):].strip()
|
|
1042
|
+
detail = normalized[len("Installing collected packages:") :].strip()
|
|
995
1043
|
return f"安装包: {self._truncate_progress_summary(detail, max_length=60)}"
|
|
996
1044
|
|
|
997
1045
|
if stage == "复用已安装依赖":
|
|
998
|
-
detail = normalized[len("Requirement already satisfied:"):].split(" in ", 1)[0].strip()
|
|
1046
|
+
detail = normalized[len("Requirement already satisfied:") :].split(" in ", 1)[0].strip()
|
|
999
1047
|
if force_emit or count in self.INSTALL_PROGRESS_EVENT_MILESTONES or count % 10 == 0:
|
|
1000
1048
|
return f"复用依赖: {detail}"
|
|
1001
1049
|
return None
|
|
1002
1050
|
|
|
1003
1051
|
if stage == "安装完成":
|
|
1004
|
-
detail = normalized[len("Successfully installed "):].strip()
|
|
1052
|
+
detail = normalized[len("Successfully installed ") :].strip()
|
|
1005
1053
|
return f"最近结果: {self._truncate_progress_summary(detail, max_length=60)}"
|
|
1006
1054
|
|
|
1007
1055
|
return self._truncate_progress_summary(normalized)
|
|
@@ -1094,8 +1142,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
1094
1142
|
timings: dict[str, Optional[float]] = {}
|
|
1095
1143
|
with ThreadPoolExecutor(max_workers=min(4, len(urls))) as executor:
|
|
1096
1144
|
future_to_url = {
|
|
1097
|
-
executor.submit(self._probe_pip_index_latency, url): url
|
|
1098
|
-
for url in urls
|
|
1145
|
+
executor.submit(self._probe_pip_index_latency, url): url for url in urls
|
|
1099
1146
|
}
|
|
1100
1147
|
for future in as_completed(future_to_url):
|
|
1101
1148
|
url = future_to_url[future]
|
|
@@ -1116,7 +1163,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
1116
1163
|
best = ordered[0]
|
|
1117
1164
|
best_ms = round((timings[best] or 0.0) * 1000)
|
|
1118
1165
|
return ordered, f"测速优先 {self._short_pip_index_label(best)} ({best_ms} ms)"
|
|
1119
|
-
|
|
1166
|
+
|
|
1120
1167
|
def _install_dependencies(self, requirements_path: Path) -> bool:
|
|
1121
1168
|
"""安装依赖到 deps_dir"""
|
|
1122
1169
|
current_python = f"{sys.version_info.major}.{sys.version_info.minor}"
|
|
@@ -1128,9 +1175,8 @@ class CodeBuilder(BaseBuilder):
|
|
|
1128
1175
|
)
|
|
1129
1176
|
|
|
1130
1177
|
try:
|
|
1131
|
-
need_binary_replacement = (
|
|
1132
|
-
sys.platform
|
|
1133
|
-
or (sys.platform.startswith("linux") and current_python != target_python)
|
|
1178
|
+
need_binary_replacement = sys.platform in ("darwin", "win32") or (
|
|
1179
|
+
sys.platform.startswith("linux") and current_python != target_python
|
|
1134
1180
|
)
|
|
1135
1181
|
used_target_runtime_wheels = False
|
|
1136
1182
|
result = None
|
|
@@ -1167,16 +1213,18 @@ class CodeBuilder(BaseBuilder):
|
|
|
1167
1213
|
requirements_path,
|
|
1168
1214
|
target_runtime_wheels=False,
|
|
1169
1215
|
)
|
|
1170
|
-
|
|
1216
|
+
|
|
1171
1217
|
if result.returncode != 0:
|
|
1172
1218
|
self._finish_install_progress()
|
|
1173
|
-
click.secho(" ✗ 安装失败", fg=
|
|
1219
|
+
click.secho(" ✗ 安装失败", fg="red")
|
|
1174
1220
|
if result.stderr:
|
|
1175
|
-
error_lines = [
|
|
1221
|
+
error_lines = [
|
|
1222
|
+
line for line in result.stderr.split("\n") if "ERROR" in line.upper()
|
|
1223
|
+
][:3]
|
|
1176
1224
|
for line in error_lines:
|
|
1177
1225
|
click.echo(f" {line}")
|
|
1178
1226
|
return False
|
|
1179
|
-
|
|
1227
|
+
|
|
1180
1228
|
# 替换非 Linux 平台二进制,或 Linux 下非目标 Python ABI 的二进制
|
|
1181
1229
|
if need_binary_replacement and not used_target_runtime_wheels:
|
|
1182
1230
|
self._emit_install_progress(
|
|
@@ -1185,7 +1233,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
1185
1233
|
"检测并替换平台相关二进制",
|
|
1186
1234
|
)
|
|
1187
1235
|
self._replace_platform_binaries()
|
|
1188
|
-
|
|
1236
|
+
|
|
1189
1237
|
# 二进制兼容性校验(避免把不可运行的包部署到 Linux Runtime)
|
|
1190
1238
|
self._emit_install_progress(
|
|
1191
1239
|
96,
|
|
@@ -1195,7 +1243,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
1195
1243
|
incompatibles = self._scan_incompatible_binaries_in_deps()
|
|
1196
1244
|
if incompatibles:
|
|
1197
1245
|
self._finish_install_progress()
|
|
1198
|
-
click.secho(" ✗ 检测到与 Linux Runtime 不兼容的关键二进制,构建终止", fg=
|
|
1246
|
+
click.secho(" ✗ 检测到与 Linux Runtime 不兼容的关键二进制,构建终止", fg="red")
|
|
1199
1247
|
for item in incompatibles[:10]:
|
|
1200
1248
|
click.echo(f" - {item}")
|
|
1201
1249
|
if any(i.startswith("python-abi-mismatch:") for i in incompatibles):
|
|
@@ -1204,213 +1252,243 @@ class CodeBuilder(BaseBuilder):
|
|
|
1204
1252
|
f"请使用 Python {target_python} 构建,或改用 Container 模式部署"
|
|
1205
1253
|
)
|
|
1206
1254
|
if any("tiktoken" in i for i in incompatibles):
|
|
1207
|
-
click.echo(
|
|
1255
|
+
click.echo(
|
|
1256
|
+
" 提示: tiktoken 为 langchain-openai 必需;"
|
|
1257
|
+
"若替换失败可重试或检查网络/镜像"
|
|
1258
|
+
)
|
|
1208
1259
|
click.echo(" 建议: 删除 .agentengine/*_build 后重新构建,或在 Linux 环境重新打包")
|
|
1209
1260
|
return False
|
|
1210
|
-
|
|
1211
|
-
deps_count = sum(1 for _ in self.deps_dir.rglob(
|
|
1212
|
-
deps_size = sum(f.stat().st_size for f in self.deps_dir.rglob(
|
|
1261
|
+
|
|
1262
|
+
deps_count = sum(1 for _ in self.deps_dir.rglob("*") if _.is_file())
|
|
1263
|
+
deps_size = sum(f.stat().st_size for f in self.deps_dir.rglob("*") if f.is_file()) / (
|
|
1264
|
+
1024 * 1024
|
|
1265
|
+
)
|
|
1213
1266
|
self._emit_install_progress(
|
|
1214
1267
|
100,
|
|
1215
1268
|
"依赖安装完成",
|
|
1216
1269
|
f"{deps_count} 个文件, {deps_size:.1f} MB",
|
|
1217
1270
|
)
|
|
1218
1271
|
self._finish_install_progress()
|
|
1219
|
-
|
|
1272
|
+
|
|
1220
1273
|
return True
|
|
1221
|
-
|
|
1274
|
+
|
|
1222
1275
|
except subprocess.TimeoutExpired:
|
|
1223
1276
|
self._finish_install_progress()
|
|
1224
1277
|
timeout_minutes = max(1, round(self._pip_install_timeout_seconds() / 60))
|
|
1225
|
-
click.secho(f" ✗ 安装超时 ({timeout_minutes}分钟)", fg=
|
|
1278
|
+
click.secho(f" ✗ 安装超时 ({timeout_minutes}分钟)", fg="red")
|
|
1226
1279
|
return False
|
|
1227
1280
|
except Exception as e:
|
|
1228
1281
|
self._finish_install_progress()
|
|
1229
|
-
click.secho(f" ✗ 依赖安装失败: {e}", fg=
|
|
1282
|
+
click.secho(f" ✗ 依赖安装失败: {e}", fg="red")
|
|
1230
1283
|
return False
|
|
1231
|
-
|
|
1284
|
+
|
|
1232
1285
|
def _replace_platform_binaries(self) -> None:
|
|
1233
1286
|
"""替换非目标运行时平台/ABI 的 C 扩展为 Linux 目标版本。"""
|
|
1234
1287
|
# 模块名到 pip 包名的映射
|
|
1235
1288
|
MODULE_TO_PACKAGE = {
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1289
|
+
"_cffi_backend": "cffi",
|
|
1290
|
+
"yaml": "pyyaml",
|
|
1291
|
+
"_yaml": "pyyaml",
|
|
1292
|
+
"rpds": "rpds-py",
|
|
1293
|
+
"PIL": "pillow",
|
|
1294
|
+
"cv2": "opencv-python",
|
|
1295
|
+
"sklearn": "scikit-learn",
|
|
1296
|
+
"_watchdog_fsevents": "watchdog",
|
|
1297
|
+
"google": None, # 跳过命名空间包
|
|
1298
|
+
"grpc": "grpcio",
|
|
1299
|
+
"_grpc": "grpcio",
|
|
1300
|
+
"uuid_utils": "uuid-utils",
|
|
1301
|
+
"pydantic_core": "pydantic-core",
|
|
1302
|
+
"_pydantic_core": "pydantic-core",
|
|
1250
1303
|
# tiktoken: langchain-openai 核心依赖, Rust 编译的 C 扩展
|
|
1251
|
-
|
|
1252
|
-
|
|
1304
|
+
"tiktoken": "tiktoken",
|
|
1305
|
+
"_tiktoken": "tiktoken",
|
|
1253
1306
|
# 其他常见原生扩展
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1307
|
+
"regex": "regex",
|
|
1308
|
+
"_regex": "regex",
|
|
1309
|
+
"multidict": "multidict",
|
|
1310
|
+
"yarl": "yarl",
|
|
1311
|
+
"aiohttp": "aiohttp",
|
|
1312
|
+
"frozenlist": "frozenlist",
|
|
1313
|
+
"charset_normalizer": "charset-normalizer",
|
|
1314
|
+
"msgpack": "msgpack",
|
|
1262
1315
|
# Windows 特有
|
|
1263
|
-
|
|
1264
|
-
|
|
1316
|
+
"win32": "pywin32",
|
|
1317
|
+
"win32com": "pywin32",
|
|
1265
1318
|
}
|
|
1266
|
-
|
|
1319
|
+
|
|
1267
1320
|
# 找到所有二进制文件
|
|
1268
1321
|
binary_files = []
|
|
1269
|
-
if sys.platform ==
|
|
1270
|
-
binary_files = list(self.deps_dir.rglob(
|
|
1271
|
-
elif sys.platform ==
|
|
1272
|
-
binary_files = list(self.deps_dir.rglob(
|
|
1273
|
-
elif sys.platform.startswith(
|
|
1274
|
-
binary_files = list(self.deps_dir.rglob(
|
|
1275
|
-
|
|
1322
|
+
if sys.platform == "darwin":
|
|
1323
|
+
binary_files = list(self.deps_dir.rglob("*.so")) + list(self.deps_dir.rglob("*.dylib"))
|
|
1324
|
+
elif sys.platform == "win32":
|
|
1325
|
+
binary_files = list(self.deps_dir.rglob("*.pyd")) + list(self.deps_dir.rglob("*.dll"))
|
|
1326
|
+
elif sys.platform.startswith("linux"):
|
|
1327
|
+
binary_files = list(self.deps_dir.rglob("*.so"))
|
|
1328
|
+
|
|
1276
1329
|
if not binary_files:
|
|
1277
1330
|
return
|
|
1278
|
-
|
|
1331
|
+
|
|
1279
1332
|
# 提取需要替换的包名
|
|
1280
1333
|
packages_to_replace: Set[str] = set()
|
|
1281
1334
|
for bin_file in binary_files:
|
|
1282
1335
|
rel_path = bin_file.relative_to(self.deps_dir)
|
|
1283
1336
|
parts = rel_path.parts
|
|
1284
|
-
|
|
1337
|
+
|
|
1285
1338
|
# 忽略 bin 目录下的 dll (通常是 runtime)
|
|
1286
|
-
if
|
|
1339
|
+
if "bin" in parts:
|
|
1287
1340
|
continue
|
|
1288
|
-
|
|
1341
|
+
|
|
1289
1342
|
if len(parts) > 1:
|
|
1290
1343
|
detected_name = parts[0]
|
|
1291
1344
|
else:
|
|
1292
|
-
detected_name = bin_file.name.split(
|
|
1293
|
-
|
|
1345
|
+
detected_name = bin_file.name.split(".")[0]
|
|
1346
|
+
|
|
1294
1347
|
# 跳过特定文件夹
|
|
1295
|
-
if detected_name in (
|
|
1348
|
+
if detected_name in ("__pycache__", "bin", "include", "lib", "Scripts"):
|
|
1296
1349
|
continue
|
|
1297
|
-
|
|
1350
|
+
|
|
1298
1351
|
if detected_name in MODULE_TO_PACKAGE:
|
|
1299
1352
|
pkg_name = MODULE_TO_PACKAGE[detected_name]
|
|
1300
1353
|
if pkg_name:
|
|
1301
1354
|
packages_to_replace.add(pkg_name)
|
|
1302
1355
|
else:
|
|
1303
1356
|
packages_to_replace.add(detected_name)
|
|
1304
|
-
|
|
1357
|
+
|
|
1305
1358
|
if not packages_to_replace:
|
|
1306
1359
|
return
|
|
1307
|
-
|
|
1308
|
-
click.echo(
|
|
1309
|
-
|
|
1360
|
+
|
|
1361
|
+
click.echo(
|
|
1362
|
+
f"\r 检测到 {len(binary_files)} 个二进制文件 ({sys.platform}), "
|
|
1363
|
+
f"替换 {len(packages_to_replace)} 个包为 Linux 版本"
|
|
1364
|
+
)
|
|
1365
|
+
|
|
1310
1366
|
# 下载 Linux wheels
|
|
1311
1367
|
wheels_dir = self.build_dir / "linux_wheels"
|
|
1312
1368
|
if wheels_dir.exists():
|
|
1313
1369
|
shutil.rmtree(wheels_dir)
|
|
1314
1370
|
wheels_dir.mkdir(parents=True)
|
|
1315
|
-
|
|
1371
|
+
|
|
1316
1372
|
replaced_count = 0
|
|
1317
1373
|
total_packages = len(packages_to_replace)
|
|
1318
1374
|
for index, pkg_name in enumerate(sorted(packages_to_replace), start=1):
|
|
1319
1375
|
# 提取确切的版本号以避免不兼容问题 (如 pydantic-core)
|
|
1320
1376
|
target_version = ""
|
|
1321
|
-
search_name = pkg_name.replace(
|
|
1377
|
+
search_name = pkg_name.replace("-", "_").lower()
|
|
1322
1378
|
for info_dir in self.deps_dir.glob(f"{search_name}-*.dist-info"):
|
|
1323
|
-
version_str = info_dir.name[
|
|
1379
|
+
version_str = info_dir.name[
|
|
1380
|
+
len(search_name) + 1 : -10
|
|
1381
|
+
] # remove search_name + '-' and '.dist-info'
|
|
1324
1382
|
target_version = f"=={version_str}"
|
|
1325
1383
|
break
|
|
1326
|
-
|
|
1384
|
+
|
|
1327
1385
|
pkg_with_version = f"{pkg_name}{target_version}"
|
|
1328
1386
|
self._emit_install_progress(
|
|
1329
1387
|
88 + min(6, round((index / max(total_packages, 1)) * 6)),
|
|
1330
1388
|
"替换 Linux wheels",
|
|
1331
1389
|
f"{index}/{total_packages} {pkg_with_version}",
|
|
1332
1390
|
)
|
|
1333
|
-
|
|
1391
|
+
|
|
1334
1392
|
try:
|
|
1335
1393
|
downloaded = False
|
|
1336
1394
|
for index_url in self._pip_index_candidates():
|
|
1337
1395
|
download_cmd = [
|
|
1338
|
-
sys.executable,
|
|
1396
|
+
sys.executable,
|
|
1397
|
+
"-m",
|
|
1398
|
+
"pip",
|
|
1399
|
+
"download",
|
|
1339
1400
|
pkg_with_version,
|
|
1340
|
-
"-d",
|
|
1341
|
-
|
|
1342
|
-
"--platform",
|
|
1343
|
-
"
|
|
1344
|
-
"--platform",
|
|
1345
|
-
"
|
|
1346
|
-
"--
|
|
1401
|
+
"-d",
|
|
1402
|
+
str(wheels_dir),
|
|
1403
|
+
"--platform",
|
|
1404
|
+
"manylinux2014_x86_64",
|
|
1405
|
+
"--platform",
|
|
1406
|
+
"manylinux_2_17_x86_64",
|
|
1407
|
+
"--platform",
|
|
1408
|
+
"manylinux_2_28_x86_64",
|
|
1409
|
+
"--platform",
|
|
1410
|
+
"musllinux_1_2_x86_64",
|
|
1411
|
+
"--platform",
|
|
1412
|
+
"linux_x86_64",
|
|
1413
|
+
"--python-version",
|
|
1414
|
+
self.TARGET_PYTHON_VERSION,
|
|
1347
1415
|
"--only-binary=:all:",
|
|
1348
|
-
"--implementation",
|
|
1416
|
+
"--implementation",
|
|
1417
|
+
"cp",
|
|
1349
1418
|
"--no-deps",
|
|
1350
1419
|
"--quiet",
|
|
1351
1420
|
"--disable-pip-version-check",
|
|
1352
|
-
"--retries",
|
|
1353
|
-
"
|
|
1354
|
-
"--
|
|
1421
|
+
"--retries",
|
|
1422
|
+
"2",
|
|
1423
|
+
"--timeout",
|
|
1424
|
+
"30",
|
|
1425
|
+
"--cache-dir",
|
|
1426
|
+
str(self.pip_cache_dir),
|
|
1355
1427
|
]
|
|
1356
1428
|
if index_url:
|
|
1357
1429
|
download_cmd += ["-i", index_url]
|
|
1358
|
-
result = subprocess.run(
|
|
1430
|
+
result = subprocess.run(
|
|
1431
|
+
download_cmd, capture_output=True, text=True, timeout=90
|
|
1432
|
+
)
|
|
1359
1433
|
if result.returncode == 0:
|
|
1360
1434
|
downloaded = True
|
|
1361
1435
|
break
|
|
1362
1436
|
if downloaded:
|
|
1363
1437
|
replaced_count += 1
|
|
1364
1438
|
else:
|
|
1365
|
-
failed_msg =
|
|
1366
|
-
|
|
1439
|
+
failed_msg = (
|
|
1440
|
+
result.stderr.strip().split("\n")[-1]
|
|
1441
|
+
if result and result.stderr
|
|
1442
|
+
else "unknown"
|
|
1443
|
+
)
|
|
1444
|
+
click.secho(f" ⚠ 替换失败: {pkg_with_version} ({failed_msg})", fg="yellow")
|
|
1367
1445
|
except Exception as e:
|
|
1368
|
-
click.secho(f" ⚠ 替换异常: {pkg_name} ({e})", fg=
|
|
1369
|
-
|
|
1446
|
+
click.secho(f" ⚠ 替换异常: {pkg_name} ({e})", fg="yellow")
|
|
1447
|
+
|
|
1370
1448
|
# 解压 wheel 覆盖到 deps_dir
|
|
1371
1449
|
for wheel_file in wheels_dir.glob("*.whl"):
|
|
1372
1450
|
try:
|
|
1373
|
-
wheel_name = wheel_file.name.split(
|
|
1374
|
-
|
|
1451
|
+
wheel_name = wheel_file.name.split("-")[0].lower().replace("_", "-")
|
|
1452
|
+
|
|
1375
1453
|
# 删除旧的包目录
|
|
1376
1454
|
for old_dir in self.deps_dir.iterdir():
|
|
1377
|
-
if old_dir.is_dir() and old_dir.name.lower().replace(
|
|
1455
|
+
if old_dir.is_dir() and old_dir.name.lower().replace("_", "-") == wheel_name:
|
|
1378
1456
|
shutil.rmtree(old_dir)
|
|
1379
|
-
# 不要 break
|
|
1380
|
-
|
|
1457
|
+
# 不要 break:一个包可能有多个目录,例如 dist-info。
|
|
1458
|
+
|
|
1381
1459
|
# 删除根目录下的二进制文件
|
|
1382
|
-
for ext in (
|
|
1460
|
+
for ext in ("*.so", "*.dylib", "*.pyd", "*.dll"):
|
|
1383
1461
|
for bin_file in self.deps_dir.glob(f"{wheel_name}*{ext[1:]}"):
|
|
1384
1462
|
try:
|
|
1385
1463
|
bin_file.unlink()
|
|
1386
|
-
except:
|
|
1464
|
+
except OSError:
|
|
1387
1465
|
pass
|
|
1388
1466
|
for bin_file in self.deps_dir.glob(f"{wheel_name.replace('-', '_')}*{ext[1:]}"):
|
|
1389
1467
|
try:
|
|
1390
1468
|
bin_file.unlink()
|
|
1391
|
-
except:
|
|
1469
|
+
except OSError:
|
|
1392
1470
|
pass
|
|
1393
|
-
|
|
1471
|
+
|
|
1394
1472
|
# 解压新的 wheel
|
|
1395
|
-
with zipfile.ZipFile(wheel_file,
|
|
1473
|
+
with zipfile.ZipFile(wheel_file, "r") as zf:
|
|
1396
1474
|
zf.extractall(self.deps_dir)
|
|
1397
1475
|
except Exception:
|
|
1398
1476
|
pass
|
|
1399
|
-
|
|
1477
|
+
|
|
1400
1478
|
shutil.rmtree(wheels_dir, ignore_errors=True)
|
|
1401
|
-
|
|
1479
|
+
|
|
1402
1480
|
# 清理所有残留的非 Linux 平台二进制文件
|
|
1403
1481
|
# (wheel 解压后可能有旧的 darwin/win .so 文件未被覆盖)
|
|
1404
1482
|
cleaned_count = 0
|
|
1405
|
-
for so_file in list(self.deps_dir.rglob(
|
|
1483
|
+
for so_file in list(self.deps_dir.rglob("*.so")):
|
|
1406
1484
|
name = so_file.name.lower()
|
|
1407
|
-
if
|
|
1485
|
+
if "darwin" in name or "win" in name:
|
|
1408
1486
|
try:
|
|
1409
1487
|
so_file.unlink()
|
|
1410
1488
|
cleaned_count += 1
|
|
1411
1489
|
except Exception:
|
|
1412
1490
|
pass
|
|
1413
|
-
for dylib_file in list(self.deps_dir.rglob(
|
|
1491
|
+
for dylib_file in list(self.deps_dir.rglob("*.dylib")):
|
|
1414
1492
|
try:
|
|
1415
1493
|
dylib_file.unlink()
|
|
1416
1494
|
cleaned_count += 1
|
|
@@ -1418,7 +1496,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
1418
1496
|
pass
|
|
1419
1497
|
if cleaned_count > 0:
|
|
1420
1498
|
click.echo(f" ✓ 清理 {cleaned_count} 个残留平台二进制文件")
|
|
1421
|
-
|
|
1499
|
+
|
|
1422
1500
|
click.echo(f" ✓ 成功替换 {replaced_count}/{len(packages_to_replace)} 个包")
|
|
1423
1501
|
|
|
1424
1502
|
def _is_linux_so(self, name: str) -> bool:
|
|
@@ -1463,7 +1541,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
1463
1541
|
|
|
1464
1542
|
def _detect_critical_binary_issues(self, names: List[str]) -> List[str]:
|
|
1465
1543
|
issues: List[str] = []
|
|
1466
|
-
|
|
1544
|
+
|
|
1467
1545
|
# 定义需要检查的关键原生扩展模块
|
|
1468
1546
|
# 格式: (描述, 正则模式)
|
|
1469
1547
|
critical_modules = [
|
|
@@ -1474,7 +1552,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
1474
1552
|
# tiktoken/_tiktoken: langchain-openai 核心依赖 (Rust 编译)
|
|
1475
1553
|
("tiktoken/_tiktoken", r"tiktoken/_tiktoken.*\.(so|pyd)$"),
|
|
1476
1554
|
]
|
|
1477
|
-
|
|
1555
|
+
|
|
1478
1556
|
for module_name, pattern in critical_modules:
|
|
1479
1557
|
matched_bins = [n for n in names if re.search(pattern, n)]
|
|
1480
1558
|
if matched_bins:
|
|
@@ -1487,19 +1565,21 @@ class CodeBuilder(BaseBuilder):
|
|
|
1487
1565
|
f"python-abi-mismatch:{module_name}:"
|
|
1488
1566
|
f"expected-cpython-{self.TARGET_PYTHON_VERSION}-or-abi3"
|
|
1489
1567
|
)
|
|
1490
|
-
|
|
1568
|
+
|
|
1491
1569
|
# 通用检查: 所有 .so 文件中不应包含 darwin/win 平台标识
|
|
1492
|
-
all_so_files = [n for n in names if n.endswith(
|
|
1493
|
-
darwin_so_count = sum(1 for n in all_so_files if
|
|
1570
|
+
all_so_files = [n for n in names if n.endswith(".so")]
|
|
1571
|
+
darwin_so_count = sum(1 for n in all_so_files if "darwin" in n.lower())
|
|
1494
1572
|
if darwin_so_count > 0:
|
|
1495
1573
|
issues.append(f"warning:found-{darwin_so_count}-darwin-so-files")
|
|
1496
|
-
|
|
1574
|
+
|
|
1497
1575
|
return issues
|
|
1498
|
-
|
|
1576
|
+
|
|
1499
1577
|
def _package_zip(self, zip_path: Path, detection_result) -> None:
|
|
1500
1578
|
"""打包 zip 文件"""
|
|
1501
1579
|
project_files = list(self._iter_project_files())
|
|
1502
|
-
dependency_files = [
|
|
1580
|
+
dependency_files = [
|
|
1581
|
+
file_path for file_path in self.deps_dir.rglob("*") if file_path.is_file()
|
|
1582
|
+
]
|
|
1503
1583
|
bundled_source_files = list(self._iter_bundled_source_files())
|
|
1504
1584
|
dependency_size = sum(file_path.stat().st_size for file_path in dependency_files)
|
|
1505
1585
|
if dependency_files:
|
|
@@ -1509,12 +1589,12 @@ class CodeBuilder(BaseBuilder):
|
|
|
1509
1589
|
f"{len(bundled_source_files)} 个 runtime 文件"
|
|
1510
1590
|
)
|
|
1511
1591
|
|
|
1512
|
-
with zipfile.ZipFile(zip_path,
|
|
1592
|
+
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
|
1513
1593
|
# 添加项目文件
|
|
1514
1594
|
for file_path in project_files:
|
|
1515
1595
|
arcname = file_path.relative_to(self.project_dir).as_posix()
|
|
1516
1596
|
zf.write(file_path, arcname)
|
|
1517
|
-
|
|
1597
|
+
|
|
1518
1598
|
# 添加依赖
|
|
1519
1599
|
deps_count = 0
|
|
1520
1600
|
for file_path in dependency_files:
|
|
@@ -1523,7 +1603,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
1523
1603
|
deps_count += 1
|
|
1524
1604
|
self._emit_package_progress("打包依赖", deps_count, len(dependency_files))
|
|
1525
1605
|
self._finish_package_progress()
|
|
1526
|
-
|
|
1606
|
+
|
|
1527
1607
|
# 添加随运行时下发的 ksadk 源码
|
|
1528
1608
|
bundled_source_count = 0
|
|
1529
1609
|
for package_name, relative, file_path in bundled_source_files:
|
|
@@ -1536,13 +1616,13 @@ class CodeBuilder(BaseBuilder):
|
|
|
1536
1616
|
len(bundled_source_files),
|
|
1537
1617
|
)
|
|
1538
1618
|
self._finish_package_progress()
|
|
1539
|
-
|
|
1619
|
+
|
|
1540
1620
|
click.echo(f" ✓ 打包运行时源码: {bundled_source_count} 个文件")
|
|
1541
|
-
|
|
1621
|
+
|
|
1542
1622
|
# 添加 entrypoint
|
|
1543
1623
|
entrypoint_content = self._generate_entrypoint(detection_result)
|
|
1544
1624
|
zf.writestr("entrypoint.py", entrypoint_content)
|
|
1545
|
-
|
|
1625
|
+
|
|
1546
1626
|
click.echo(f" ✓ 打包完成: {len(project_files)} 个项目文件 + {deps_count} 个依赖文件")
|
|
1547
1627
|
self._emit_package_size_report(zip_path)
|
|
1548
1628
|
|
|
@@ -1586,10 +1666,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
1586
1666
|
)
|
|
1587
1667
|
if by_top_level:
|
|
1588
1668
|
top_items = sorted(by_top_level.items(), key=lambda item: item[1], reverse=True)[:limit]
|
|
1589
|
-
summary = ", ".join(
|
|
1590
|
-
f"{name} {size / (1024 * 1024):.1f} MB"
|
|
1591
|
-
for name, size in top_items
|
|
1592
|
-
)
|
|
1669
|
+
summary = ", ".join(f"{name} {size / (1024 * 1024):.1f} MB" for name, size in top_items)
|
|
1593
1670
|
click.echo(f" 体积 Top{len(top_items)}: {summary}")
|
|
1594
1671
|
if (
|
|
1595
1672
|
raw_total > self.CONTAINER_SUGGESTION_RAW_THRESHOLD_BYTES
|
|
@@ -1660,7 +1737,7 @@ class CodeBuilder(BaseBuilder):
|
|
|
1660
1737
|
self._package_progress_last_line = ""
|
|
1661
1738
|
self._package_progress_last_percent_by_label = {}
|
|
1662
1739
|
self._package_progress_logged_milestone_by_label = {}
|
|
1663
|
-
|
|
1740
|
+
|
|
1664
1741
|
def _generate_entrypoint(self, detection_result) -> str:
|
|
1665
1742
|
"""生成 entrypoint.py"""
|
|
1666
1743
|
package_name = Path(detection_result.package_path).name
|
|
@@ -1737,15 +1814,11 @@ logger.info(f"PYTHONPATH: {{os.environ.get('PYTHONPATH', 'N/A')}}")
|
|
|
1737
1814
|
# 打印关键环境变量 (隐藏敏感信息)
|
|
1738
1815
|
env_keys = [
|
|
1739
1816
|
"AGENT_RUNTIME_NAME", "AGENT_RUNTIME_ID", "ACCOUNT_ID", "PORT",
|
|
1740
|
-
"LANGFUSE_BASE_URL", "LANGFUSE_HOST", "LANGFUSE_PUBLIC_KEY",
|
|
1741
|
-
"LANGFUSE_SECRET_KEY", "LANGFUSE_USE_CALLBACK",
|
|
1742
1817
|
"OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
|
|
1743
1818
|
"OTEL_EXPORTER_OTLP_HEADERS", "OTEL_EXPORTER_OTLP_TRACES_HEADERS",
|
|
1744
|
-
"OTEL_SERVICE_NAME",
|
|
1745
|
-
"
|
|
1746
|
-
"
|
|
1747
|
-
"CLOUD_MONITOR_LANGFUSE_HOST", "CLOUD_MONITOR_LANGFUSE_PUBLIC_KEY",
|
|
1748
|
-
"CLOUD_MONITOR_LANGFUSE_SECRET_KEY", "CLOUD_MONITOR_LANGFUSE_ENABLED",
|
|
1819
|
+
"OTEL_SERVICE_NAME",
|
|
1820
|
+
"CLOUD_MONITOR_OTLP_ENDPOINT", "CLOUD_MONITOR_OTLP_TRACES_ENDPOINT",
|
|
1821
|
+
"CLOUD_MONITOR_OTLP_HEADERS", "CLOUD_MONITOR_OTLP_TRACES_HEADERS",
|
|
1749
1822
|
"LANGCHAIN_TRACING_V2", "MODEL_NAME",
|
|
1750
1823
|
]
|
|
1751
1824
|
for key in env_keys:
|
|
@@ -1762,15 +1835,9 @@ logger.info("=" * 60)
|
|
|
1762
1835
|
from ksadk.configs import setup_environment
|
|
1763
1836
|
setup_environment(Path(CODE_ROOT))
|
|
1764
1837
|
|
|
1765
|
-
try:
|
|
1766
|
-
from ksadk.runners.patch_langchain import apply_patch as apply_langchain_patch
|
|
1767
|
-
apply_langchain_patch()
|
|
1768
|
-
except ImportError:
|
|
1769
|
-
pass
|
|
1770
|
-
|
|
1771
|
-
from ksadk.runners import create_runner
|
|
1772
1838
|
from ksadk.detection import DetectionResult, FrameworkType
|
|
1773
|
-
from ksadk.
|
|
1839
|
+
from ksadk.runtime import RuntimeExecutor, RuntimeLaunchContext, build_default_runtime_registry
|
|
1840
|
+
from ksadk.server import RuntimeAppConfig, configure_runtime_app, create_runtime_app
|
|
1774
1841
|
import uvicorn
|
|
1775
1842
|
|
|
1776
1843
|
# 检测结果 (构建时固化)
|
|
@@ -1780,46 +1847,84 @@ detection_result = DetectionResult(
|
|
|
1780
1847
|
entry_point="{detection_result.entry_point}",
|
|
1781
1848
|
package_path=os.path.join(CODE_ROOT, "{package_name}"),
|
|
1782
1849
|
agent_variable="{detection_result.agent_variable}",
|
|
1783
|
-
runner_class="{getattr(detection_result,
|
|
1850
|
+
runner_class="{getattr(detection_result, "runner_class", "")}"
|
|
1784
1851
|
)
|
|
1785
1852
|
|
|
1786
1853
|
logger.info(f"框架: {{detection_result.name}}")
|
|
1787
1854
|
logger.info(f"入口: {{detection_result.entry_point}}")
|
|
1788
1855
|
|
|
1789
|
-
# 初始化 Tracing (
|
|
1790
|
-
has_otlp = bool(
|
|
1856
|
+
# 初始化 Tracing (如果配置了标准 OTLP HTTP 或 CloudMonitor OTLP)
|
|
1857
|
+
has_otlp = bool(
|
|
1858
|
+
os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT")
|
|
1859
|
+
or os.environ.get("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT")
|
|
1860
|
+
)
|
|
1791
1861
|
has_cloud_monitor_otlp = bool(
|
|
1792
|
-
os.environ.get("
|
|
1862
|
+
os.environ.get("CLOUD_MONITOR_OTLP_TRACES_HEADERS")
|
|
1863
|
+
or os.environ.get("CLOUD_MONITOR_OTLP_HEADERS")
|
|
1793
1864
|
or os.environ.get("CLOUD_MONITOR_OTLP_ENDPOINT")
|
|
1794
1865
|
or os.environ.get("CLOUD_MONITOR_OTLP_TRACES_ENDPOINT")
|
|
1866
|
+
or os.environ.get("CLOUD_MONITOR_APP_KEY")
|
|
1795
1867
|
)
|
|
1796
|
-
|
|
1797
|
-
os.environ.get("CLOUD_MONITOR_LANGFUSE_PUBLIC_KEY")
|
|
1798
|
-
or os.environ.get("CLOUD_MONITOR_LANGFUSE_SECRET_KEY")
|
|
1799
|
-
or os.environ.get("CLOUD_MONITOR_LANGFUSE_HOST")
|
|
1800
|
-
)
|
|
1801
|
-
if os.environ.get("LANGFUSE_PUBLIC_KEY") or has_otlp or has_cloud_monitor_otlp or has_cloud_monitor_langfuse:
|
|
1868
|
+
if has_otlp or has_cloud_monitor_otlp:
|
|
1802
1869
|
try:
|
|
1803
1870
|
from ksadk.tracing import setup_tracing
|
|
1804
|
-
|
|
1805
|
-
use_callback_only = os.environ.get("LANGFUSE_USE_CALLBACK", "").strip().lower() in ("1", "true", "yes", "on")
|
|
1806
1871
|
|
|
1807
|
-
setup_tracing(
|
|
1872
|
+
setup_tracing()
|
|
1808
1873
|
logger.info(
|
|
1809
1874
|
f"Tracing 已启用 (OTLP={{has_otlp}}, "
|
|
1810
|
-
f"CloudMonitorOTLP={{has_cloud_monitor_otlp}}
|
|
1811
|
-
f"CloudMonitorLangfuse={{has_cloud_monitor_langfuse}}, "
|
|
1812
|
-
f"CallbackOnly={{use_callback_only}})"
|
|
1875
|
+
f"CloudMonitorOTLP={{has_cloud_monitor_otlp}})"
|
|
1813
1876
|
)
|
|
1814
1877
|
except Exception as e:
|
|
1815
1878
|
logger.warning(f"Tracing 初始化失败: {{e}}")
|
|
1816
1879
|
|
|
1817
|
-
#
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1880
|
+
# 只装配统一 RuntimeAdapter 执行链;具体 Adapter 在请求开始时由 Registry 创建。
|
|
1881
|
+
runtime_context = RuntimeLaunchContext(
|
|
1882
|
+
runtime_type=detection_result.type.value,
|
|
1883
|
+
project_dir=Path(CODE_ROOT),
|
|
1884
|
+
detection=detection_result,
|
|
1885
|
+
config=dict(getattr(detection_result, "raw_config", None) or {{}}),
|
|
1886
|
+
)
|
|
1887
|
+
# managed A2A:KSADK_A2A_RUNTIME_ID 非空时挂 discovery card + 完整数据面 route。
|
|
1888
|
+
_a2a_config = None
|
|
1889
|
+
_a2a_adapter = None
|
|
1890
|
+
if os.environ.get("KSADK_A2A_RUNTIME_ID", "").strip():
|
|
1891
|
+
from ksadk.managed_a2a_card import build_managed_a2a_card_if_configured
|
|
1892
|
+
|
|
1893
|
+
_managed_a2a_card = build_managed_a2a_card_if_configured()
|
|
1894
|
+
try:
|
|
1895
|
+
from ksadk.a2a.routes import A2AConfig
|
|
1896
|
+
from ksadk.runtime.factory import create_runtime_adapter
|
|
1897
|
+
|
|
1898
|
+
_a2a_adapter = create_runtime_adapter(runtime_context)
|
|
1899
|
+
_base = (
|
|
1900
|
+
os.environ.get("KSADK_A2A_INTERNAL_BASE_URL", "").strip()
|
|
1901
|
+
or "http://localhost:8080"
|
|
1902
|
+
)
|
|
1903
|
+
_a2a_config = A2AConfig(
|
|
1904
|
+
enabled=True,
|
|
1905
|
+
base_url=_base,
|
|
1906
|
+
agent_name=(
|
|
1907
|
+
os.environ.get("KSADK_A2A_AGENT_NAME", "").strip()
|
|
1908
|
+
or os.environ.get("KSADK_A2A_RUNTIME_ID", "").strip()
|
|
1909
|
+
),
|
|
1910
|
+
streaming=True,
|
|
1911
|
+
task_store_dsn="sqlite+aiosqlite:///.agentengine/a2a_tasks.db",
|
|
1912
|
+
)
|
|
1913
|
+
except Exception as _e:
|
|
1914
|
+
logger.warning(f"managed A2A 数据面装配失败,回退 discovery-only: {{_e}}")
|
|
1915
|
+
_a2a_config = None
|
|
1916
|
+
_a2a_adapter = None
|
|
1917
|
+
app = create_runtime_app(
|
|
1918
|
+
RuntimeAppConfig(
|
|
1919
|
+
runtime_type=detection_result.type.value,
|
|
1920
|
+
runtime_executor=RuntimeExecutor(build_default_runtime_registry()),
|
|
1921
|
+
launch_context=runtime_context,
|
|
1922
|
+
a2a=_a2a_config or _managed_a2a_card,
|
|
1923
|
+
a2a_runtime_adapter=_a2a_adapter,
|
|
1924
|
+
),
|
|
1925
|
+
configure_runtime_app,
|
|
1926
|
+
)
|
|
1927
|
+
logger.info("RuntimeAdapter 执行链装配成功!")
|
|
1823
1928
|
|
|
1824
1929
|
if __name__ == "__main__":
|
|
1825
1930
|
port = int(os.environ.get("PORT", 8080))
|
|
@@ -1848,13 +1953,13 @@ if __name__ == "__main__":
|
|
|
1848
1953
|
self._pip_index_candidates_cache = candidates
|
|
1849
1954
|
return list(candidates)
|
|
1850
1955
|
|
|
1851
|
-
|
|
1956
|
+
fallback_seen: Set[str] = set()
|
|
1852
1957
|
urls: list[str] = []
|
|
1853
1958
|
for candidate in self.PIP_INDEX_FALLBACKS:
|
|
1854
1959
|
normalized = self._normalize_pip_index_url(candidate)
|
|
1855
|
-
if normalized in
|
|
1960
|
+
if normalized in fallback_seen:
|
|
1856
1961
|
continue
|
|
1857
|
-
|
|
1962
|
+
fallback_seen.add(normalized)
|
|
1858
1963
|
urls.append(normalized)
|
|
1859
1964
|
|
|
1860
1965
|
ordered, summary = self._rank_pip_index_urls(urls)
|