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
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""模型能力矩阵探测(v2.3):替代简单 responses/chat 二分。
|
|
2
|
+
|
|
3
|
+
"支持 responses" 不等于 "该直通"——glm-5.1 原生 responses 丢增量 delta + 拒 namespace 工具,
|
|
4
|
+
经转换层反而更好。本模块用能力矩阵描述一个 (model, base_url, credential) 的真实能力,
|
|
5
|
+
供路由决策(直通 responses / 走转换层 chat / …)。
|
|
6
|
+
|
|
7
|
+
探测铁律(review v1):
|
|
8
|
+
- **功能性 probe 而非状态码 probe**:发最小真请求打 /v1/responses,校验返回是否为
|
|
9
|
+
合法 responses 结构(有 ``output``/``status``),不只看 HTTP 200——网关对不支持的
|
|
10
|
+
端点有时也返回 200 但内容是错误页。
|
|
11
|
+
- **只在 "确凿协议否定" 时翻案**:`404/405/400 unknown endpoint` 才判 "不支持 responses";
|
|
12
|
+
超时/5xx/429/401/403 一律 "unknown",不改变判定(故障 ≠ 能力缺失)。
|
|
13
|
+
- ``stream_delta_ok`` 需真发流式请求才能判定,成本高,本模块默认 None(不探),
|
|
14
|
+
由调用方按需触发或默认走转换层(转换层自己生成完整 delta)。
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import time
|
|
20
|
+
from dataclasses import dataclass, field
|
|
21
|
+
from typing import Any, Literal
|
|
22
|
+
|
|
23
|
+
import httpx
|
|
24
|
+
|
|
25
|
+
Verdict = Literal["supported", "unsupported", "unknown"]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class ModelCapabilities:
|
|
30
|
+
"""一个 (model, base_url, credential_scope) 的协议能力矩阵。"""
|
|
31
|
+
|
|
32
|
+
responses_supported: bool | None = None # None = 未知(未探/不确定)
|
|
33
|
+
stream_delta_ok: bool | None = None # 流式增量 delta;None = 未探
|
|
34
|
+
tool_types: set[str] = field(default_factory=set) # 支持的工具 namespace
|
|
35
|
+
preferred_protocol: str = "chat" # "responses" | "chat":路由该走哪条
|
|
36
|
+
checked_at: float = 0.0
|
|
37
|
+
verdict: Verdict = "unknown" # 最近一次探测结论
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _classify_responses_error(status: int, body: str) -> Verdict:
|
|
41
|
+
"""把非 200 响应分类成 supported/unsupported/unknown。
|
|
42
|
+
|
|
43
|
+
只有 "确凿协议否定" 才判 unsupported;故障类一律 unknown(不误固化)。
|
|
44
|
+
"""
|
|
45
|
+
if status in (404, 405):
|
|
46
|
+
return "unsupported"
|
|
47
|
+
if status == 400:
|
|
48
|
+
low = (body or "").lower()
|
|
49
|
+
# 400 且 body 含 "unknown/not supported/endpoint" -> endpoint 不支持
|
|
50
|
+
if any(k in low for k in ("unknown", "not supported", "endpoint", "unrecognized")):
|
|
51
|
+
return "unsupported"
|
|
52
|
+
return "unknown" # 400 但不像协议级否定(可能是请求字段问题)
|
|
53
|
+
# 401/403:鉴权/权限问题,不代表 endpoint 不存在(同 key 不同能力,见 glm-5.1 403)
|
|
54
|
+
if status in (401, 403):
|
|
55
|
+
return "unknown"
|
|
56
|
+
return "unknown" # 5xx/429/其他:故障类
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def probe_responses_capability(
|
|
60
|
+
client: httpx.Client | httpx.AsyncClient,
|
|
61
|
+
base: str,
|
|
62
|
+
key: str,
|
|
63
|
+
model: str,
|
|
64
|
+
timeout: float = 30.0,
|
|
65
|
+
):
|
|
66
|
+
"""功能性 probe /v1/responses,返回能力矩阵(sync) 或 coroutine(async)。
|
|
67
|
+
|
|
68
|
+
- 200 且结构合法(output+status)→ supported,preferred_protocol=responses
|
|
69
|
+
- 200 但非 responses 结构(网关伪 200)→ unsupported,preferred_protocol=chat
|
|
70
|
+
- 404/405/400 unknown → unsupported,preferred_protocol=chat
|
|
71
|
+
- 超时/5xx/429/401/403 → unknown,preferred_protocol 保持默认 chat(保守走转换层)
|
|
72
|
+
|
|
73
|
+
按 client 类型分发:``httpx.Client`` 同步返回 ``ModelCapabilities``;
|
|
74
|
+
``httpx.AsyncClient`` 返回 coroutine(调用方 await)。
|
|
75
|
+
"""
|
|
76
|
+
if isinstance(client, httpx.AsyncClient):
|
|
77
|
+
return _probe_async(client, base, key, model, timeout)
|
|
78
|
+
if isinstance(client, httpx.Client):
|
|
79
|
+
return _probe_sync(client, base, key, model, timeout)
|
|
80
|
+
raise TypeError(f"client 必须是 httpx.Client/AsyncClient,不是 {type(client).__name__}")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _probe_sync(
|
|
84
|
+
client: httpx.Client, base: str, key: str, model: str, timeout: float
|
|
85
|
+
) -> ModelCapabilities:
|
|
86
|
+
caps = ModelCapabilities(checked_at=time.time(), verdict="unknown")
|
|
87
|
+
url = f"{base.rstrip('/')}/responses"
|
|
88
|
+
headers = {"Authorization": f"Bearer {key}", "Content-Type": "application/json"}
|
|
89
|
+
payload = {"model": model, "input": "hi", "max_output_tokens": 1, "stream": False}
|
|
90
|
+
try:
|
|
91
|
+
r = client.post(url, json=payload, headers=headers, timeout=timeout)
|
|
92
|
+
except (httpx.TimeoutException, httpx.ConnectError, httpx.HTTPError):
|
|
93
|
+
return _finalize(caps)
|
|
94
|
+
try:
|
|
95
|
+
data = r.json()
|
|
96
|
+
except ValueError:
|
|
97
|
+
data = None
|
|
98
|
+
return _apply_response(caps, r.status_code, r.text, data)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
async def _probe_async(
|
|
102
|
+
client: httpx.AsyncClient, base: str, key: str, model: str, timeout: float
|
|
103
|
+
) -> ModelCapabilities:
|
|
104
|
+
caps = ModelCapabilities(checked_at=time.time(), verdict="unknown")
|
|
105
|
+
url = f"{base.rstrip('/')}/responses"
|
|
106
|
+
headers = {"Authorization": f"Bearer {key}", "Content-Type": "application/json"}
|
|
107
|
+
payload = {"model": model, "input": "hi", "max_output_tokens": 1, "stream": False}
|
|
108
|
+
try:
|
|
109
|
+
r = await client.post(url, json=payload, headers=headers, timeout=timeout)
|
|
110
|
+
except (httpx.TimeoutException, httpx.ConnectError, httpx.HTTPError):
|
|
111
|
+
return _finalize(caps)
|
|
112
|
+
try:
|
|
113
|
+
data = r.json()
|
|
114
|
+
except ValueError:
|
|
115
|
+
data = None
|
|
116
|
+
return _apply_response(caps, r.status_code, r.text, data)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _apply_response(
|
|
120
|
+
caps: ModelCapabilities, status: int, text: str, data: Any
|
|
121
|
+
) -> ModelCapabilities:
|
|
122
|
+
if status == 200:
|
|
123
|
+
# 功能性校验:合法 responses 结构有 output + status(不只看 200)
|
|
124
|
+
if isinstance(data, dict) and "output" in data and "status" in data:
|
|
125
|
+
caps.responses_supported = True
|
|
126
|
+
caps.verdict = "supported"
|
|
127
|
+
else:
|
|
128
|
+
# 200 但不是 responses 结构(网关伪 200 / 错误页)
|
|
129
|
+
caps.responses_supported = False
|
|
130
|
+
caps.verdict = "unsupported"
|
|
131
|
+
return _finalize(caps)
|
|
132
|
+
caps.verdict = _classify_responses_error(status, text)
|
|
133
|
+
caps.responses_supported = False if caps.verdict == "unsupported" else None
|
|
134
|
+
return _finalize(caps)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _finalize(caps: ModelCapabilities) -> ModelCapabilities:
|
|
138
|
+
"""根据 verdict 定 preferred_protocol(保守:不确定也走转换层 chat)。"""
|
|
139
|
+
if caps.verdict == "supported" and caps.responses_supported:
|
|
140
|
+
caps.preferred_protocol = "responses"
|
|
141
|
+
else:
|
|
142
|
+
# unsupported 或 unknown 都默认 chat(走转换层):unknown 时走转换层更安全,
|
|
143
|
+
# 因为转换层对 chat 模型是确定可用的,而直连 responses 在 unknown 下有风险
|
|
144
|
+
caps.preferred_protocol = "chat"
|
|
145
|
+
return caps
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""开关与灰度配置(v2.5):默认关闭,按需启用,一键回退直连。
|
|
2
|
+
|
|
3
|
+
review v1 要求:全局默认关,支持按 agent/按模型白名单开启,故障一键回退。
|
|
4
|
+
设计为纯配置判定(env/agentengine.yaml 解析后传入),不含网络/proxy 生命周期——
|
|
5
|
+
后者由 v2.1(codex)/v2.2(env 框架)各自接线时调用。
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class ProxyGate:
|
|
16
|
+
"""协议转换层的开关/灰度判定(纯函数,不持有运行时状态)。
|
|
17
|
+
|
|
18
|
+
- ``enabled``:全局开关,默认 False。
|
|
19
|
+
- ``agent_allowlist``/``model_allowlist``:细粒度白名单;空=不按此维度放行。
|
|
20
|
+
- ``denylist``:显式拒绝(优先级最高),用于故障一键回退某 agent/模型。
|
|
21
|
+
|
|
22
|
+
判定优先级:denylist > 全局 enabled > 白名单。
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
enabled: bool = False
|
|
26
|
+
agent_allowlist: set[str] = field(default_factory=set)
|
|
27
|
+
model_allowlist: set[str] = field(default_factory=set)
|
|
28
|
+
denylist: set[str] = field(default_factory=set)
|
|
29
|
+
|
|
30
|
+
def is_on(self, agent: str | None = None, model: str | None = None) -> bool:
|
|
31
|
+
"""是否对该 (agent, model) 启用转换层。
|
|
32
|
+
|
|
33
|
+
- denylist 命中(agent 或 model)→ False(一键回退)
|
|
34
|
+
- 全局 enabled=False → False(默认关)
|
|
35
|
+
- 全局 enabled=True → True(除非 denylist)
|
|
36
|
+
- 全局关但白名单命中(agent 或 model)→ True(灰度放行)
|
|
37
|
+
"""
|
|
38
|
+
if agent and agent in self.denylist:
|
|
39
|
+
return False
|
|
40
|
+
if model and model in self.denylist:
|
|
41
|
+
return False
|
|
42
|
+
if self.enabled:
|
|
43
|
+
return True
|
|
44
|
+
if agent and agent in self.agent_allowlist:
|
|
45
|
+
return True
|
|
46
|
+
if model and model in self.model_allowlist:
|
|
47
|
+
return True
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def from_env(cls) -> "ProxyGate":
|
|
52
|
+
"""从 env 读开关与白名单(逗号分隔)。
|
|
53
|
+
|
|
54
|
+
- ``KSADK_MODEL_PROXY_ENABLED=1`` 全局开
|
|
55
|
+
- ``KSADK_MODEL_PROXY_AGENTS=a,b`` agent 白名单
|
|
56
|
+
- ``KSADK_MODEL_PROXY_MODELS=glm-5.2`` model 白名单
|
|
57
|
+
- ``KSADK_MODEL_PROXY_DENY=c`` 一键回退
|
|
58
|
+
"""
|
|
59
|
+
def _split(name: str) -> set[str]:
|
|
60
|
+
v = os.environ.get(name, "").strip()
|
|
61
|
+
return {x.strip() for x in v.split(",") if x.strip()} if v else set()
|
|
62
|
+
|
|
63
|
+
return cls(
|
|
64
|
+
enabled=os.environ.get("KSADK_MODEL_PROXY_ENABLED") == "1",
|
|
65
|
+
agent_allowlist=_split("KSADK_MODEL_PROXY_AGENTS"),
|
|
66
|
+
model_allowlist=_split("KSADK_MODEL_PROXY_MODELS"),
|
|
67
|
+
denylist=_split("KSADK_MODEL_PROXY_DENY"),
|
|
68
|
+
)
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""codex namespace 工具拍平 + 还原(responses↔chat 路径)。
|
|
2
|
+
|
|
3
|
+
codex 0.142+ 用 namespace 工具声明插件/MCP 工具:
|
|
4
|
+
|
|
5
|
+
{"type":"namespace","name":"mcp__x__","tools":[{"type":"function","name":"foo",...}]}
|
|
6
|
+
|
|
7
|
+
并在 input 历史里发 namespace-qualified function_call:
|
|
8
|
+
|
|
9
|
+
{"type":"function_call","name":"foo","namespace":"mcp__x__",...}
|
|
10
|
+
|
|
11
|
+
chat completions 只认顶层 ``function`` 工具(chat 嵌套)和 ``function.name``,
|
|
12
|
+
不认 ``namespace`` 字段。本模块把 namespace 工具**拍平**成顶层 function,
|
|
13
|
+
名字用确定性的 ``<namespace>__<child>``(超长 sha256 截断,与 cc-switch 一致),
|
|
14
|
+
响应侧再把 flat 名字**还原**回 ``{name, namespace}``,让 codex client 能匹配
|
|
15
|
+
自己的 namespace 工具注册表。
|
|
16
|
+
|
|
17
|
+
请求侧拍平 + 响应侧还原都从**同一份 request tools** 经
|
|
18
|
+
:func:`flatten_namespace_tool_name` 派生名字映射,前后一致,无需跨请求状态。
|
|
19
|
+
|
|
20
|
+
参照 cc-switch ``transform_codex_responses_namespace.rs``(用 Python 重写)。
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import hashlib
|
|
26
|
+
import json
|
|
27
|
+
from typing import Any
|
|
28
|
+
|
|
29
|
+
CHAT_TOOL_NAME_MAX_LEN = 64
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def flatten_namespace_tool_name(namespace: str, name: str) -> str:
|
|
33
|
+
"""``<namespace>__<name>``;超长则尾部接 sha256 截断,保持在 64 字符内。
|
|
34
|
+
|
|
35
|
+
截断按字符边界,保证返回值是合法 UTF-8(不会从多字节字符中间切断)。
|
|
36
|
+
"""
|
|
37
|
+
full = f"{namespace}__{name}"
|
|
38
|
+
if len(full) <= CHAT_TOOL_NAME_MAX_LEN:
|
|
39
|
+
return full
|
|
40
|
+
suffix = "__" + hashlib.sha256(full.encode("utf-8")).hexdigest()[:8]
|
|
41
|
+
prefix_len = CHAT_TOOL_NAME_MAX_LEN - len(suffix)
|
|
42
|
+
prefix = ""
|
|
43
|
+
for ch in full:
|
|
44
|
+
if len(prefix.encode("utf-8")) + len(ch.encode("utf-8")) > prefix_len:
|
|
45
|
+
break
|
|
46
|
+
prefix += ch
|
|
47
|
+
return prefix + suffix
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _namespace_children(tool: dict) -> list[dict]:
|
|
51
|
+
for key in ("tools", "children"):
|
|
52
|
+
kids = tool.get(key)
|
|
53
|
+
if isinstance(kids, list):
|
|
54
|
+
return kids
|
|
55
|
+
return []
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def build_restore_map(tools: list[Any] | None) -> dict[str, dict[str, str]]:
|
|
59
|
+
"""从 request 的 namespace 工具声明建 ``flat -> {namespace, name}`` 映射。
|
|
60
|
+
|
|
61
|
+
两个不同 child 拍平后撞名时,后者覆盖前者(与 cc-switch ``or_insert`` 不同,
|
|
62
|
+
cc-switch 用 first-wins 并对撞名报错;这里取 first-wins + 调用方撞名检测)。
|
|
63
|
+
"""
|
|
64
|
+
restore: dict[str, dict[str, str]] = {}
|
|
65
|
+
if not tools:
|
|
66
|
+
return restore
|
|
67
|
+
for tool in tools:
|
|
68
|
+
if not isinstance(tool, dict):
|
|
69
|
+
continue
|
|
70
|
+
if tool.get("type") == "custom":
|
|
71
|
+
# custom 工具(如 apply_patch freeform)拍平为普通 function 转发,
|
|
72
|
+
# 响应侧据此把 function_call 还原成 custom_tool_call
|
|
73
|
+
custom_name = (tool.get("name") or "").strip()
|
|
74
|
+
if custom_name:
|
|
75
|
+
restore.setdefault(
|
|
76
|
+
custom_name,
|
|
77
|
+
{"custom": "true", "namespace": "", "name": custom_name},
|
|
78
|
+
)
|
|
79
|
+
continue
|
|
80
|
+
if tool.get("type") != "namespace":
|
|
81
|
+
continue
|
|
82
|
+
namespace = (tool.get("name") or "").strip()
|
|
83
|
+
if not namespace:
|
|
84
|
+
continue
|
|
85
|
+
for child in _namespace_children(tool):
|
|
86
|
+
if not isinstance(child, dict) or child.get("type") != "function":
|
|
87
|
+
continue
|
|
88
|
+
name = (child.get("name") or "").strip()
|
|
89
|
+
if not name:
|
|
90
|
+
continue
|
|
91
|
+
flat = flatten_namespace_tool_name(namespace, name)
|
|
92
|
+
restore.setdefault(flat, {"namespace": namespace, "name": name})
|
|
93
|
+
return restore
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _rewrite_qualified_calls(value: Any, owners: dict[str, dict[str, str]]) -> bool:
|
|
97
|
+
"""递归把 input 里的 namespace-qualified function_call 重写成 flat name。
|
|
98
|
+
|
|
99
|
+
``{type:function_call, name:child, namespace:ns}`` -> ``{type:function_call, name:flat}``
|
|
100
|
+
(去掉 namespace 字段);只在 (ns, name) 与 owners 条目匹配时重写。
|
|
101
|
+
"""
|
|
102
|
+
changed = False
|
|
103
|
+
if isinstance(value, list):
|
|
104
|
+
for item in value:
|
|
105
|
+
changed |= _rewrite_qualified_calls(item, owners)
|
|
106
|
+
elif isinstance(value, dict):
|
|
107
|
+
if value.get("type") == "function_call":
|
|
108
|
+
namespace = (value.get("namespace") or "").strip()
|
|
109
|
+
name = (value.get("name") or "").strip()
|
|
110
|
+
if namespace and name:
|
|
111
|
+
flat = flatten_namespace_tool_name(namespace, name)
|
|
112
|
+
entry = owners.get(flat)
|
|
113
|
+
if entry and entry["namespace"] == namespace and entry["name"] == name:
|
|
114
|
+
value["name"] = flat
|
|
115
|
+
value.pop("namespace", None)
|
|
116
|
+
changed = True
|
|
117
|
+
for child in value.values():
|
|
118
|
+
changed |= _rewrite_qualified_calls(child, owners)
|
|
119
|
+
return changed
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def flatten_request_namespaces(body: dict) -> dict[str, dict[str, str]]:
|
|
123
|
+
"""原地拍平 body 的 namespace 工具,返回 restore_map(供响应侧还原)。
|
|
124
|
+
|
|
125
|
+
- tools:namespace children 提升为顶层 responses function 工具(flat name),
|
|
126
|
+
原 namespace 工具移除;检测撞名(两个 child 拍平后同名)则 raise。
|
|
127
|
+
- input:namespace-qualified function_call 重写为 flat name。
|
|
128
|
+
- tool_choice:namespace-typed 丢弃(chat 不认)。
|
|
129
|
+
|
|
130
|
+
返回 ``flat -> {namespace, name}`` 映射;无 namespace 工具时返回空 dict,
|
|
131
|
+
调用方可据此跳过响应侧还原。
|
|
132
|
+
"""
|
|
133
|
+
tools = body.get("tools")
|
|
134
|
+
if not isinstance(tools, list):
|
|
135
|
+
return {}
|
|
136
|
+
restore = build_restore_map(tools)
|
|
137
|
+
flat_tools: list[dict] = []
|
|
138
|
+
seen_flat: set[str] = set()
|
|
139
|
+
for tool in tools:
|
|
140
|
+
if not isinstance(tool, dict):
|
|
141
|
+
continue
|
|
142
|
+
if tool.get("type") == "namespace":
|
|
143
|
+
namespace = (tool.get("name") or "").strip()
|
|
144
|
+
for child in _namespace_children(tool):
|
|
145
|
+
if not isinstance(child, dict) or child.get("type") != "function":
|
|
146
|
+
continue
|
|
147
|
+
name = (child.get("name") or "").strip()
|
|
148
|
+
if not name or not namespace:
|
|
149
|
+
continue
|
|
150
|
+
flat = flatten_namespace_tool_name(namespace, name)
|
|
151
|
+
if flat in seen_flat:
|
|
152
|
+
raise ValueError(
|
|
153
|
+
f"namespace 拍平撞名:{flat} 来自不同 child,上游无法消歧"
|
|
154
|
+
)
|
|
155
|
+
seen_flat.add(flat)
|
|
156
|
+
flat_tools.append({
|
|
157
|
+
"type": "function",
|
|
158
|
+
"name": flat,
|
|
159
|
+
"description": child.get("description", ""),
|
|
160
|
+
"parameters": child.get("parameters", {"type": "object", "properties": {}}),
|
|
161
|
+
**({"strict": child["strict"]} if "strict" in child else {}),
|
|
162
|
+
})
|
|
163
|
+
else:
|
|
164
|
+
flat_tools.append(tool)
|
|
165
|
+
body["tools"] = flat_tools
|
|
166
|
+
if restore and isinstance(body.get("input"), list):
|
|
167
|
+
_rewrite_qualified_calls(body["input"], restore)
|
|
168
|
+
tc = body.get("tool_choice")
|
|
169
|
+
if isinstance(tc, dict) and tc.get("type") == "namespace":
|
|
170
|
+
body.pop("tool_choice", None)
|
|
171
|
+
return restore
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def restore_function_call(item: dict, restore_map: dict[str, dict[str, str]]) -> dict:
|
|
175
|
+
"""把响应里 function_call 的 flat name 还原成 ``{name, namespace}``(原地改)。
|
|
176
|
+
|
|
177
|
+
无映射或 name 不在映射中时原样返回(普通 function 工具的 call 不受影响)。
|
|
178
|
+
"""
|
|
179
|
+
if not restore_map or item.get("type") != "function_call":
|
|
180
|
+
return item
|
|
181
|
+
flat = item.get("name")
|
|
182
|
+
entry = restore_map.get(flat) if isinstance(flat, str) else None
|
|
183
|
+
if entry:
|
|
184
|
+
if entry.get("custom") == "true":
|
|
185
|
+
# function_call(JSON arguments) -> custom_tool_call(原始文本 input)
|
|
186
|
+
raw_args = item.pop("arguments", "") or ""
|
|
187
|
+
try:
|
|
188
|
+
payload = json.loads(raw_args)
|
|
189
|
+
text_input = (
|
|
190
|
+
payload.get("input", raw_args) if isinstance(payload, dict) else raw_args
|
|
191
|
+
)
|
|
192
|
+
except Exception:
|
|
193
|
+
text_input = raw_args
|
|
194
|
+
item["type"] = "custom_tool_call"
|
|
195
|
+
item["name"] = entry["name"]
|
|
196
|
+
item["input"] = text_input
|
|
197
|
+
item.pop("namespace", None)
|
|
198
|
+
return item
|
|
199
|
+
item["name"] = entry["name"]
|
|
200
|
+
item["namespace"] = entry["namespace"]
|
|
201
|
+
return item
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""可独立运行的转换 proxy 入口:读 env → ProxyConfig → uvicorn。
|
|
2
|
+
|
|
3
|
+
用法:
|
|
4
|
+
KSPMAS_API_KEY=xxx python -m ksadk.model_proxy.protocol_proxy # 默认 127.0.0.1:8899
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
import uvicorn
|
|
10
|
+
|
|
11
|
+
from .config import ProxyConfig
|
|
12
|
+
from .server import create_app
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main():
|
|
16
|
+
config = ProxyConfig.from_env()
|
|
17
|
+
port = int(os.environ.get("PORT", "8899"))
|
|
18
|
+
uvicorn.run(create_app(config), host="127.0.0.1", port=port, log_level="warning")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
if __name__ == "__main__":
|
|
22
|
+
main()
|