agentengine-sdk-python 0.7.0__py3-none-any.whl → 0.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +36 -20
- agentengine_sdk_python-0.8.0.dist-info/RECORD +578 -0
- ksadk/a2a/__init__.py +178 -11
- ksadk/a2a/bootstrap.py +334 -0
- ksadk/a2a/card.py +120 -0
- ksadk/a2a/context_store.py +203 -0
- ksadk/a2a/control_plane.py +818 -0
- ksadk/a2a/credential.py +99 -0
- ksadk/a2a/event_adapter.py +149 -0
- ksadk/a2a/executor.py +406 -89
- ksadk/a2a/external_transport.py +516 -0
- ksadk/a2a/identity.py +304 -0
- ksadk/a2a/ids.py +22 -0
- ksadk/a2a/langgraph.py +285 -0
- ksadk/a2a/resume_store.py +201 -0
- ksadk/a2a/routes.py +105 -0
- ksadk/a2a/server.py +107 -60
- ksadk/a2a/space_client.py +1101 -0
- ksadk/a2a/task_adapter.py +423 -0
- ksadk/a2a/task_event_dispatcher.py +167 -0
- ksadk/a2a/task_event_outbox.py +326 -0
- ksadk/a2a/task_store.py +206 -0
- ksadk/a2ui/__init__.py +27 -0
- ksadk/a2ui/core.py +186 -0
- ksadk/a2ui/models.py +166 -0
- ksadk/a2ui/renderer.py +198 -0
- ksadk/agui/__init__.py +9 -0
- ksadk/agui/a2ui_projection.py +92 -0
- ksadk/agui/agent.py +857 -0
- ksadk/agui/config.py +86 -0
- ksadk/agui/routes.py +55 -0
- ksadk/api/client.py +233 -191
- ksadk/builders/__init__.py +2 -0
- ksadk/builders/base.py +16 -14
- ksadk/builders/code_builder.py +318 -236
- ksadk/builders/container_builder.py +187 -167
- ksadk/builders/framework_requirements.py +29 -11
- ksadk/builders/ks3_uploader.py +58 -27
- ksadk/builders/managed_runtime_builder.py +145 -0
- ksadk/builders/mcp_builder.py +91 -92
- ksadk/builders/requirements_utils.py +1 -5
- ksadk/cli/__init__.py +89 -171
- ksadk/cli/cmd_a2a.py +254 -70
- ksadk/cli/cmd_agent.py +19 -5
- ksadk/cli/cmd_build.py +158 -29
- ksadk/cli/cmd_completion.py +47 -35
- ksadk/cli/cmd_config.py +267 -198
- ksadk/cli/cmd_create.py +500 -720
- ksadk/cli/cmd_dashboard.py +120 -45
- ksadk/cli/cmd_deploy.py +117 -58
- ksadk/cli/cmd_destroy.py +44 -14
- ksadk/cli/cmd_files.py +63 -24
- ksadk/cli/cmd_hermes.py +168 -89
- ksadk/cli/cmd_invoke.py +184 -122
- ksadk/cli/cmd_launch.py +64 -28
- ksadk/cli/cmd_mcp.py +98 -64
- ksadk/cli/cmd_model.py +14 -5
- ksadk/cli/cmd_openclaw.py +483 -227
- ksadk/cli/cmd_replay.py +71 -0
- ksadk/cli/cmd_run.py +33 -10
- ksadk/cli/cmd_status.py +80 -31
- ksadk/cli/cmd_version.py +20 -13
- ksadk/cli/cmd_web.py +89 -13
- ksadk/cli/deploy_utils.py +20 -20
- ksadk/cli/dry_run.py +5 -3
- ksadk/cli/error_utils.py +37 -12
- ksadk/cli/global_options.py +1 -2
- ksadk/cli/local_runtime.py +1 -2
- ksadk/cli/model_catalog.py +6 -2
- ksadk/cli/network_options.py +34 -14
- ksadk/cli/resource_common.py +6 -2
- ksadk/cli/storage.py +0 -1
- ksadk/cli/ui.py +5 -3
- ksadk/cli/workflow_common.py +51 -17
- ksadk/codex/__init__.py +12 -0
- ksadk/codex/client.py +408 -0
- ksadk/codex/phase.py +143 -0
- ksadk/codex/runtime.py +449 -0
- ksadk/common/aicp_env.py +0 -1
- ksadk/common/auth.py +2 -2
- ksadk/common/constants.py +1 -3
- ksadk/common/llm_utils.py +17 -13
- ksadk/compat/__init__.py +5 -0
- ksadk/compat/adk_compat.py +200 -0
- ksadk/compat/copilotkit_a2ui.py +330 -0
- ksadk/configs/__init__.py +12 -12
- ksadk/configs/env_registry.py +500 -100
- ksadk/configs/global_config.py +2 -1
- ksadk/configs/settings.py +151 -124
- ksadk/conversations/__init__.py +7 -5
- ksadk/conversations/attachment_storage.py +16 -11
- ksadk/conversations/attachments.py +44 -36
- ksadk/conversations/compaction_pipeline.py +12 -12
- ksadk/conversations/compaction_prompt.py +9 -5
- ksadk/conversations/context.py +221 -6
- ksadk/conversations/message_projection.py +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 +652 -0
- ksadk/conversations/runtime_invocation.py +395 -0
- ksadk/conversations/runtime_metadata.py +475 -0
- ksadk/conversations/runtime_observability.py +355 -0
- ksadk/conversations/runtime_payloads.py +272 -0
- ksadk/conversations/runtime_persistence.py +440 -0
- ksadk/conversations/runtime_preparation.py +418 -0
- ksadk/conversations/runtime_resume.py +816 -0
- ksadk/conversations/runtime_stream_events.py +902 -0
- ksadk/conversations/runtime_streaming.py +547 -0
- ksadk/conversations/semantic_summary.py +17 -5
- ksadk/conversations/session_title.py +6 -3
- ksadk/deployment/__init__.py +15 -16
- ksadk/deployment/agent_access.py +12 -23
- ksadk/deployment/base.py +51 -38
- ksadk/deployment/manager.py +63 -65
- ksadk/deployment/providers/serverless.py +309 -202
- ksadk/deployment/registry.py +38 -32
- ksadk/deployment/state.py +11 -11
- ksadk/deployment/ui_config.py +1 -1
- ksadk/detection/__init__.py +1 -1
- ksadk/detection/detector.py +146 -83
- ksadk/detection/mcp_detector.py +9 -6
- ksadk/events/__init__.py +25 -0
- ksadk/events/parser.py +191 -0
- ksadk/events/replay.py +37 -0
- ksadk/events/runtime_event.py +264 -0
- ksadk/events/store.py +317 -0
- ksadk/harness/__init__.py +34 -0
- ksadk/harness/app.py +278 -0
- ksadk/harness/config.py +181 -0
- ksadk/harness/reasoner.py +105 -0
- ksadk/harness/runner.py +211 -0
- ksadk/harness/sandbox.py +141 -0
- ksadk/harness/tools.py +222 -0
- ksadk/hermes_terminal.py +23 -12
- ksadk/identity/resolver.py +15 -9
- ksadk/ids.py +32 -0
- ksadk/knowledge_base/adk_tool.py +1 -1
- ksadk/knowledge_base/client.py +23 -29
- ksadk/managed_runtime.py +188 -0
- ksadk/markdown.py +5 -2
- ksadk/mcp_runtime/__init__.py +9 -6
- ksadk/memory/__init__.py +1 -1
- ksadk/memory/adk/__init__.py +2 -0
- ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
- ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
- ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
- ksadk/memory/adk/backends/sdk_ltm_backend.py +26 -33
- ksadk/memory/adk/long_term_memory.py +31 -35
- ksadk/memory/adk/resilient_session_service.py +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 +10 -8
- ksadk/model_policy.py +15 -7
- ksadk/model_proxy/__init__.py +51 -0
- ksadk/model_proxy/bootstrap.py +80 -0
- ksadk/model_proxy/cache.py +165 -0
- ksadk/model_proxy/config.py +45 -0
- ksadk/model_proxy/demo_webui.py +115 -0
- ksadk/model_proxy/detect.py +145 -0
- ksadk/model_proxy/gate.py +68 -0
- ksadk/model_proxy/namespace.py +173 -0
- ksadk/model_proxy/protocol_proxy.py +22 -0
- ksadk/model_proxy/server.py +300 -0
- ksadk/model_proxy/transform.py +691 -0
- ksadk/openclaw_gateway.py +29 -14
- ksadk/runners/adk_runner.py +345 -120
- ksadk/runners/base_runner.py +46 -29
- ksadk/runners/codex_runner.py +132 -0
- ksadk/runners/deepagents_runner.py +0 -1
- ksadk/runners/factory.py +17 -5
- ksadk/runners/langchain_runner.py +29 -742
- ksadk/runners/langgraph_runner.py +352 -90
- ksadk/runners/patch_langchain.py +16 -16
- ksadk/runners/remote_runner.py +134 -33
- ksadk/runners/usage_accumulator.py +1 -0
- ksadk/runners/utils/langfuse.py +3 -3
- ksadk/runners/utils/loader.py +7 -7
- ksadk/runtime/__init__.py +41 -0
- ksadk/runtime/adapter.py +345 -0
- ksadk/runtime/framework_adapters.py +124 -0
- ksadk/runtime/preprocessing.py +118 -0
- ksadk/runtime/runner_adapter.py +873 -0
- ksadk/runtime_context.py +18 -3
- ksadk/runtime_state.py +0 -1
- ksadk/sandbox/__init__.py +4 -1
- ksadk/sandbox/backends/__init__.py +4 -1
- ksadk/sandbox/backends/e2b.py +13 -5
- ksadk/sandbox/backends/local_process.py +11 -3
- ksadk/sandbox/base.py +10 -15
- ksadk/sandbox/factory.py +14 -4
- ksadk/sandbox/registry.py +57 -6
- ksadk/server/api_models.py +15 -5
- ksadk/server/app.py +455 -3885
- ksadk/server/composition.py +21 -0
- ksadk/server/factory.py +624 -0
- ksadk/server/routes/__init__.py +1 -0
- ksadk/server/routes/checkpoint_resolution.py +116 -0
- ksadk/server/routes/common.py +713 -0
- ksadk/server/routes/control.py +327 -0
- ksadk/server/routes/dependencies.py +98 -0
- ksadk/server/routes/misc.py +448 -0
- ksadk/server/routes/models.py +443 -0
- ksadk/server/routes/openai_compat.py +207 -0
- ksadk/server/routes/projection.py +795 -0
- ksadk/server/routes/routers.py +52 -0
- ksadk/server/routes/run.py +726 -0
- ksadk/server/routes/sessions.py +649 -0
- ksadk/server/routes/streaming.py +223 -0
- ksadk/server/routes/workspace.py +381 -0
- ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-Cjnqt-8W.js} +1 -1
- ksadk/server/static/assets/CodeBlock-BqyqZfuB.js +9 -0
- ksadk/server/static/assets/MathMessageMarkdown-BpH7jiFM.js +8 -0
- ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +303 -0
- ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +1 -0
- ksadk/server/static/assets/{arc-BA13sHc9.js → arc-CFKwSk_B.js} +1 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +1 -0
- ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
- ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
- ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
- ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
- ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
- ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
- ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-BK8paA20.js} +1 -1
- ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
- ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
- ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
- ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D98vPd-E.js} +1 -1
- ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +1 -0
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
- ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
- ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
- ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
- ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
- ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
- ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
- ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-6CVKuTAe.js} +1 -1
- ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-BUHRxvDG.js} +1 -1
- ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-BZ9n9AjO.js} +1 -1
- ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BibcG1V9.js} +1 -1
- ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-Bs-jQcRX.js} +1 -1
- ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-C2xjE7cO.js} +1 -1
- ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-C7-3jInC.js} +1 -1
- ksadk/server/static/assets/{dist-D-xOD048.js → dist-C99THtIA.js} +1 -1
- ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-CGcp2ex8.js} +1 -1
- ksadk/server/static/assets/{dist-DyOkZmze.js → dist-CVQRZjPu.js} +1 -1
- ksadk/server/static/assets/{dist-BssVmjIo.js → dist-Cf23NY4L.js} +1 -1
- ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-CgF3fj15.js} +1 -1
- ksadk/server/static/assets/{dist-2hInLS_J.js → dist-Cwt7koer.js} +1 -1
- ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-D82mtD2s.js} +1 -1
- ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-DF06ORQo.js} +1 -1
- ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-DHn6nBzr.js} +1 -1
- ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-Djgl2wVZ.js} +1 -1
- ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-DlzCRy0S.js} +1 -1
- ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-DqNnNFrw.js} +1 -1
- ksadk/server/static/assets/{dist-D57wnGWd.js → dist-DyvYLMW9.js} +1 -1
- ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-eoW6tZXA.js} +1 -1
- ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-ivOya1LD.js} +1 -1
- ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-CnfRcY2M.js} +1 -1
- ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +1 -0
- ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
- ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-DpCoB2g9.js} +1 -1
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +1 -0
- ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-9IKVFBVT.js} +1 -1
- ksadk/server/static/assets/index-QSwCHuB8.js +177 -0
- ksadk/server/static/assets/index-jOPmTOZH.css +2 -0
- ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +1 -0
- ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
- ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
- ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
- ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
- ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-DATssjp1.js} +1 -1
- ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-CvMBw9cA.js} +1 -1
- ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
- ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-CSAQxEAe.js} +1 -1
- ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +1 -0
- ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +1 -0
- ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
- ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-CxIR4JXI.js} +1 -1
- ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +1 -0
- ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
- ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
- ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
- ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-DGpd9yFG.js} +1 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +1 -0
- ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-jqoYs3jQ.js} +1 -1
- ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +1 -0
- ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +1 -0
- ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-l3Z7-wbP.js} +1 -1
- ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +1 -0
- ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
- ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-SkiH8GsK.js} +1 -1
- ksadk/server/static/index.html +2 -2
- ksadk/server/terminal_sessions.py +111 -58
- ksadk/sessions/__init__.py +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 +38 -17
- ksadk/skills/tool_defs.py +15 -10
- ksadk/terminal_exec_policy.py +3 -4
- ksadk/tools/gateway.py +92 -15
- ksadk/tools/result_budget.py +12 -4
- ksadk/toolsets/__init__.py +134 -36
- ksadk/toolsets/platform.py +21 -5
- ksadk/toolsets/sandbox.py +82 -16
- ksadk/toolsets/skills.py +200 -39
- ksadk/toolsets/web.py +123 -26
- ksadk/toolsets/workspace.py +212 -101
- ksadk/tracing/exporters/inmemory_exporter.py +62 -51
- ksadk/tracing/exporters/langfuse_exporter.py +91 -76
- ksadk/tracing/setup.py +69 -53
- ksadk/tracing/span_utils.py +5 -2
- 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/schemas/runtime_event_v1.json +95 -0
- agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
- 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
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
ksadk/common/llm_utils.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""LLM Utilities"""
|
|
2
2
|
|
|
3
|
-
import os
|
|
4
3
|
import logging
|
|
4
|
+
import os
|
|
5
5
|
|
|
6
6
|
logger = logging.getLogger(__name__)
|
|
7
7
|
|
|
@@ -10,28 +10,32 @@ PUBLIC_ENDPOINT = "https://kspmas.ksyun.com/v1/"
|
|
|
10
10
|
|
|
11
11
|
# Internal Endpoint (Auto-injected by Platform)
|
|
12
12
|
# Note: In most cases, we don't need to hardcode this because the platform injects it.
|
|
13
|
-
# But for
|
|
13
|
+
# But for "smart switching based on public URL", we might need to know
|
|
14
|
+
# what to switch TO,
|
|
14
15
|
# or simply rely on leaving it empty so the platform default takes over?
|
|
15
|
-
#
|
|
16
|
+
#
|
|
16
17
|
# According to user: "OPENAI_BASE_URL 不填会自动选择的" (If empty, it auto-selects).
|
|
17
|
-
#
|
|
18
|
+
# Strategy: If Public URL + Internal Env -> Unset OPENAI_BASE_URL,
|
|
19
|
+
# letting it fall back to the platform default.
|
|
20
|
+
|
|
18
21
|
|
|
19
22
|
def get_smart_openai_env() -> None:
|
|
20
23
|
"""Smartly configure OpenAI Environment Variables.
|
|
21
|
-
|
|
24
|
+
|
|
22
25
|
If it detects that the code is running in a Ksyun Internal Environment (Serverless/KCE)
|
|
23
26
|
AND the OPENAI_BASE_URL is set to the Public Endpoint, it will unset OPENAI_BASE_URL
|
|
24
27
|
to allow the platform's automatic internal endpoint injection to take effect.
|
|
25
|
-
|
|
26
|
-
This prevents network hangs caused by accessing public endpoints from
|
|
28
|
+
|
|
29
|
+
This prevents network hangs caused by accessing public endpoints from
|
|
30
|
+
internal-only environments.
|
|
27
31
|
"""
|
|
28
32
|
base_url = os.environ.get("OPENAI_BASE_URL", "").strip()
|
|
29
|
-
|
|
33
|
+
|
|
30
34
|
# logic 1: Check if it is the Public Endpoint
|
|
31
35
|
# Normalize by removing trailing slash for comparison
|
|
32
36
|
normalized_url = base_url.rstrip("/")
|
|
33
37
|
normalized_public = PUBLIC_ENDPOINT.rstrip("/")
|
|
34
|
-
|
|
38
|
+
|
|
35
39
|
if normalized_url != normalized_public:
|
|
36
40
|
return
|
|
37
41
|
|
|
@@ -41,11 +45,11 @@ def get_smart_openai_env() -> None:
|
|
|
41
45
|
# - K_SERVICE (Injected by Knative/Serverless)
|
|
42
46
|
# - KUBERNETES_SERVICE_HOST (Injected by K8s)
|
|
43
47
|
is_internal = (
|
|
44
|
-
"KSYUN_REGION" in os.environ
|
|
48
|
+
"KSYUN_REGION" in os.environ
|
|
45
49
|
or "K_SERVICE" in os.environ
|
|
46
50
|
or "KUBERNETES_SERVICE_HOST" in os.environ
|
|
47
51
|
)
|
|
48
|
-
|
|
52
|
+
|
|
49
53
|
if is_internal:
|
|
50
54
|
logger.warning(
|
|
51
55
|
f"Detected Public OPENAI_BASE_URL ({base_url}) in Internal Environment. "
|
|
@@ -55,7 +59,7 @@ def get_smart_openai_env() -> None:
|
|
|
55
59
|
# Or explicitly set it to internal generic address if known?
|
|
56
60
|
# User said: "OPENAI_BASE_URL 不填会自动选择". So we unset it.
|
|
57
61
|
del os.environ["OPENAI_BASE_URL"]
|
|
58
|
-
|
|
62
|
+
|
|
59
63
|
# Verify if successful removal
|
|
60
64
|
if "OPENAI_BASE_URL" not in os.environ:
|
|
61
|
-
|
|
65
|
+
logger.info("Successfully switched to Internal Endpoint mode.")
|
ksadk/compat/__init__.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""Google ADK 多版本兼容层 (goal-00)。
|
|
2
|
+
|
|
3
|
+
ksadk 业务代码**不直接** ``import google.adk``;统一从本模块取符号。
|
|
4
|
+
``google-adk`` 的版本差异只在兼容层内消化,业务代码对版本无感知。
|
|
5
|
+
|
|
6
|
+
版本窗口
|
|
7
|
+
--------
|
|
8
|
+
依赖约束 ``google-adk>=1.34.0,<3.0.0``:
|
|
9
|
+
|
|
10
|
+
- **1.34.x** 是最低支持锚点(不承诺 1.x 全系;1.0 缺 ``google.adk.apps`` 等,代价过大)。
|
|
11
|
+
- **2.x**(当前 2.5.x)是上界内最新主线。
|
|
12
|
+
|
|
13
|
+
实测(2026-07-21, goal-00 探测,解包对比 1.34.3 vs 2.5.0):ksadk 用到的
|
|
14
|
+
全部符号在两个版本**都存在**,差异仅为 2.x 的**向后兼容可选新增**:
|
|
15
|
+
|
|
16
|
+
- ``Runner.run_async`` 2.x 新增可选 ``yield_user_message``(默认 False)。
|
|
17
|
+
- ``RunConfig`` 2.x 新增若干可选字段(``http_options`` / ``telemetry`` /
|
|
18
|
+
``model_input_context`` 等),均为可选,不传不影响。
|
|
19
|
+
- ``App.root_agent`` 2.x 变为可选(1.34 必填);ksadk 始终显式传,两版皆可。
|
|
20
|
+
- ``DatabaseSessionService`` 2.x 新增可选 ``db_engine``(``db_url`` 变可选);
|
|
21
|
+
ksadk 始终传 ``db_url``,两版皆可。
|
|
22
|
+
- ``McpToolset.header_provider`` 2.x 支持 awaitable;ksadk 未用该参数。
|
|
23
|
+
|
|
24
|
+
ksadk 现有调用**不依赖任何 2.x-only 参数**,因此 1.34 与 2.x 对 ksadk 能力对等,
|
|
25
|
+
无需降级 shim。能力降级矩阵的完整文字版见
|
|
26
|
+
``docs/adk-multi-version-compat.md``。
|
|
27
|
+
|
|
28
|
+
使用 2.x-only 新能力的纪律
|
|
29
|
+
--------------------------
|
|
30
|
+
若未来要用某个 2.x 才有的可选参数/符号,**必须**在本层用
|
|
31
|
+
:func:`adk_version_at_least` 判断后再下发,并对 1.34 做显式降级;不允许业务
|
|
32
|
+
代码自行 ``import google.adk`` 探测。
|
|
33
|
+
|
|
34
|
+
加载语义
|
|
35
|
+
--------
|
|
36
|
+
本模块 import 自身**不触发** ``google.adk`` 导入(惰性,PEP 562
|
|
37
|
+
``__getattr__``)。只有真正访问某个符号时才导入对应 ``google.adk`` 子模块;
|
|
38
|
+
未安装 ``google-adk`` 时抛出带安装提示的 :class:`ImportError`,便于
|
|
39
|
+
``memory/adk_tool`` 等调用方捕获并降级为原函数。
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
from __future__ import annotations
|
|
43
|
+
|
|
44
|
+
from importlib import import_module
|
|
45
|
+
from importlib.metadata import PackageNotFoundError
|
|
46
|
+
from importlib.metadata import version as _dist_version
|
|
47
|
+
from typing import TYPE_CHECKING, Any
|
|
48
|
+
|
|
49
|
+
if TYPE_CHECKING: # pragma: no cover - 仅供 mypy 静态检查,运行时不执行
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
#: 导出符号名 -> 提供该符号的 google.adk 子模块路径。
|
|
53
|
+
#: 这是 ksadk 全部 google.adk 依赖的唯一登记表;新增依赖先在这里登记。
|
|
54
|
+
_LAZY_SYMBOLS: dict[str, str] = {
|
|
55
|
+
# agents
|
|
56
|
+
"Agent": "google.adk.agents",
|
|
57
|
+
"RunConfig": "google.adk.agents.run_config",
|
|
58
|
+
"StreamingMode": "google.adk.agents.run_config",
|
|
59
|
+
# apps
|
|
60
|
+
"App": "google.adk.apps",
|
|
61
|
+
"ResumabilityConfig": "google.adk.apps",
|
|
62
|
+
# events
|
|
63
|
+
"Event": "google.adk.events.event",
|
|
64
|
+
# memory
|
|
65
|
+
"BaseMemoryService": "google.adk.memory.base_memory_service",
|
|
66
|
+
"SearchMemoryResponse": "google.adk.memory.base_memory_service",
|
|
67
|
+
"MemoryEntry": "google.adk.memory.memory_entry",
|
|
68
|
+
# models
|
|
69
|
+
"LlmResponse": "google.adk.models",
|
|
70
|
+
"LiteLlm": "google.adk.models.lite_llm",
|
|
71
|
+
# runners
|
|
72
|
+
"Runner": "google.adk.runners",
|
|
73
|
+
# sessions
|
|
74
|
+
"BaseSessionService": "google.adk.sessions",
|
|
75
|
+
"InMemorySessionService": "google.adk.sessions",
|
|
76
|
+
"Session": "google.adk.sessions",
|
|
77
|
+
"DatabaseSessionService": "google.adk.sessions",
|
|
78
|
+
"InvocationContext": "google.adk.agents",
|
|
79
|
+
"ToolContext": "google.adk.tools",
|
|
80
|
+
"GetSessionConfig": "google.adk.sessions.base_session_service",
|
|
81
|
+
"ListSessionsResponse": "google.adk.sessions.base_session_service",
|
|
82
|
+
# tools
|
|
83
|
+
"FunctionTool": "google.adk.tools",
|
|
84
|
+
"load_memory": "google.adk.tools",
|
|
85
|
+
"McpTool": "google.adk.tools.mcp_tool.mcp_tool",
|
|
86
|
+
"McpToolset": "google.adk.tools.mcp_tool.mcp_toolset",
|
|
87
|
+
"CheckableMcpHttpClientFactory": "google.adk.tools.mcp_tool.mcp_session_manager",
|
|
88
|
+
"StreamableHTTPConnectionParams": "google.adk.tools.mcp_tool.mcp_session_manager",
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
#: 以模块形式导出的名字 -> 模块路径(如 genai types、需要 monkeypatch 的 lite_llm)。
|
|
92
|
+
_LAZY_MODULES: dict[str, str] = {
|
|
93
|
+
"genai_types": "google.genai.types",
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
_INSTALL_HINT = (
|
|
97
|
+
"google-adk 未安装或版本不在支持窗口 (>=1.34.0,<3.0.0)。" "安装: pip install 'ksadk[adk]'"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
_ADK_NOT_FOUND = "google-adk 未安装"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _raise_missing(name: str, exc: BaseException) -> None:
|
|
104
|
+
raise ImportError(f"无法导入 google.adk 符号 {name!r}。{_INSTALL_HINT}") from exc
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def __getattr__(name: str) -> Any:
|
|
108
|
+
"""PEP 562 惰性解析:首次访问符号时才导入对应 google.adk 子模块。"""
|
|
109
|
+
if name in _LAZY_SYMBOLS:
|
|
110
|
+
module_path = _LAZY_SYMBOLS[name]
|
|
111
|
+
try:
|
|
112
|
+
module = import_module(module_path)
|
|
113
|
+
except ImportError as exc:
|
|
114
|
+
_raise_missing(name, exc)
|
|
115
|
+
try:
|
|
116
|
+
value = getattr(module, name)
|
|
117
|
+
except AttributeError as exc:
|
|
118
|
+
raise ImportError(
|
|
119
|
+
f"google.adk 已安装但 {module_path} 缺少 {name!r};"
|
|
120
|
+
f"当前版本 {adk_version() or '未知'} 可能不在支持窗口 (>=1.34.0,<3.0.0)。"
|
|
121
|
+
) from exc
|
|
122
|
+
# 注意: 刻意不缓存到 globals()。测试常 monkeypatch ``google.adk.*``
|
|
123
|
+
# 子模块符号(如把 Runner 换成 FakeRunner);若在此缓存,会把某次 patch
|
|
124
|
+
# 后的值泄漏给后续解析,造成跨测试污染。每次经 getattr 重新解析,
|
|
125
|
+
# 让既有 ``google.adk.*`` patch 点继续生效。开销可忽略(import_module
|
|
126
|
+
# 命中 sys.modules 缓存)。
|
|
127
|
+
return value
|
|
128
|
+
if name in _LAZY_MODULES:
|
|
129
|
+
module_path = _LAZY_MODULES[name]
|
|
130
|
+
try:
|
|
131
|
+
value = import_module(module_path)
|
|
132
|
+
except ImportError as exc:
|
|
133
|
+
_raise_missing(name, exc)
|
|
134
|
+
return value
|
|
135
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def __dir__() -> list[str]:
|
|
139
|
+
return sorted(set(globals()) | set(_LAZY_SYMBOLS) | set(_LAZY_MODULES))
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def is_adk_available() -> bool:
|
|
143
|
+
"""google-adk 是否可导入(不关心版本)。"""
|
|
144
|
+
try:
|
|
145
|
+
import_module("google.adk")
|
|
146
|
+
except ImportError:
|
|
147
|
+
return False
|
|
148
|
+
return True
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def adk_version() -> str | None:
|
|
152
|
+
"""返回已安装的 google-adk 版本;未安装返回 None。"""
|
|
153
|
+
try:
|
|
154
|
+
return _dist_version("google-adk")
|
|
155
|
+
except PackageNotFoundError:
|
|
156
|
+
return None
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def adk_version_at_least(min_version: str) -> bool:
|
|
160
|
+
"""已安装 google-adk 版本是否 >= ``min_version``;未安装或无法解析返回 False。
|
|
161
|
+
|
|
162
|
+
用于下发 2.x-only 能力前的版本门禁,例如::
|
|
163
|
+
|
|
164
|
+
if adk_version_at_least("2.0.0"):
|
|
165
|
+
kwargs["yield_user_message"] = True
|
|
166
|
+
"""
|
|
167
|
+
ver = adk_version()
|
|
168
|
+
if ver is None:
|
|
169
|
+
return False
|
|
170
|
+
try:
|
|
171
|
+
from packaging.version import Version
|
|
172
|
+
|
|
173
|
+
return bool(Version(ver) >= Version(min_version))
|
|
174
|
+
except Exception:
|
|
175
|
+
return False
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def lite_llm_module() -> Any:
|
|
179
|
+
"""返回 ``google.adk.models.lite_llm`` 模块对象。
|
|
180
|
+
|
|
181
|
+
adk_runner 的 JSON 容错 patch 需要 MonkeyPatch 该模块内的
|
|
182
|
+
``_message_to_generate_content_response``(私有函数),因此需要模块本身
|
|
183
|
+
而非单个符号。未安装 litellm/google-adk 时抛 :class:`ImportError`。
|
|
184
|
+
"""
|
|
185
|
+
try:
|
|
186
|
+
return import_module("google.adk.models.lite_llm")
|
|
187
|
+
except ImportError as exc:
|
|
188
|
+
_raise_missing("google.adk.models.lite_llm", exc)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
__all__ = [
|
|
192
|
+
# 版本/能力探测
|
|
193
|
+
"is_adk_available",
|
|
194
|
+
"adk_version",
|
|
195
|
+
"adk_version_at_least",
|
|
196
|
+
"lite_llm_module",
|
|
197
|
+
# 惰性符号
|
|
198
|
+
*_LAZY_SYMBOLS.keys(),
|
|
199
|
+
*_LAZY_MODULES.keys(),
|
|
200
|
+
]
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"""Compatibility bridge for the pinned CopilotKit and AG-UI A2UI packages.
|
|
2
|
+
|
|
3
|
+
The currently pinned public packages disagree on the A2UI factory signature.
|
|
4
|
+
More importantly, the released LangGraph adapter moves an async model invocation
|
|
5
|
+
to a worker thread and calls it with ``asyncio.run``. Async providers such as
|
|
6
|
+
``ChatOpenAI`` retain event-loop-bound clients, so that path can wait forever.
|
|
7
|
+
|
|
8
|
+
This module keeps CopilotKit's middleware lifecycle and dynamic-tool dispatch,
|
|
9
|
+
but owns the small framework glue that invokes the A2UI sub-agent on the active
|
|
10
|
+
event loop. The A2UI wire format, prompt construction, and validation are still
|
|
11
|
+
provided by the official AG-UI toolkit.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import asyncio
|
|
17
|
+
import inspect
|
|
18
|
+
import logging
|
|
19
|
+
import os
|
|
20
|
+
from importlib import import_module
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
from copilotkit import CopilotKitMiddleware, copilotkit_lg_middleware
|
|
25
|
+
from langchain.tools import ToolRuntime, tool
|
|
26
|
+
from langchain_core.messages import SystemMessage
|
|
27
|
+
except ImportError as exc: # The module itself belongs to the optional AG-UI feature.
|
|
28
|
+
raise ImportError(
|
|
29
|
+
"CopilotKit A2UI requires ksadk[agui] with copilotkit and ag-ui-langgraph installed."
|
|
30
|
+
) from exc
|
|
31
|
+
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
_DEFAULT_GENERATION_TIMEOUT_SECONDS = 20.0
|
|
35
|
+
|
|
36
|
+
# The upstream toolkit's generic default prompt is intentionally exhaustive.
|
|
37
|
+
# It is also large enough to exceed the Hosted UI model gateway's reliable tool
|
|
38
|
+
# latency. This compact contract covers the v0.9 basic catalog used by ksadk-web
|
|
39
|
+
# while leaving applications free to pass their own guidelines explicitly.
|
|
40
|
+
_KSADK_HOSTED_UI_GUIDELINES = {
|
|
41
|
+
"generation_guidelines": """\
|
|
42
|
+
Return exactly one render_a2ui tool call. Use A2UI v0.9 flat components: every
|
|
43
|
+
component has an id and a component field. The root id is root. Use only Text,
|
|
44
|
+
Column, Row, Card, List, Button, ChoicePicker, Divider, TextField, CheckBox,
|
|
45
|
+
or Slider. Put properties directly on each component, never under type or
|
|
46
|
+
properties. Use child for one component id and children for an array of ids.
|
|
47
|
+
For example: [{\"id\":\"root\",\"component\":\"Card\",\"child\":\"content\"},
|
|
48
|
+
{\"id\":\"content\",\"component\":\"Column\",\"children\":[\"title\"]},
|
|
49
|
+
{\"id\":\"title\",\"component\":\"Text\",\"variant\":\"h2\",\"text\":\"Status\"}].
|
|
50
|
+
Use only facts present in the conversation and tool results. Do not return
|
|
51
|
+
Markdown or prose instead of the tool call.""",
|
|
52
|
+
"design_guidelines": """\
|
|
53
|
+
Create one compact, readable surface. Use hierarchy and spacing through Card,
|
|
54
|
+
Column, Row, Text, Divider, and ChoicePicker instead of decorative elements.
|
|
55
|
+
For status, summarize real values; for risks, show severity and owner; for
|
|
56
|
+
choices, use ChoicePicker with a bound data value.""",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _a2ui_toolkit_dependencies() -> tuple[Any, ...]:
|
|
61
|
+
"""Resolve the optional toolkit, which currently publishes no type metadata."""
|
|
62
|
+
try:
|
|
63
|
+
toolkit = import_module("ag_ui_a2ui_toolkit")
|
|
64
|
+
except ImportError as exc:
|
|
65
|
+
raise ImportError(
|
|
66
|
+
"CopilotKit A2UI requires ksadk[agui] with ag-ui-a2ui-toolkit installed."
|
|
67
|
+
) from exc
|
|
68
|
+
names = (
|
|
69
|
+
"RENDER_A2UI_TOOL_DEF",
|
|
70
|
+
"resolve_a2ui_tool_params",
|
|
71
|
+
"prepare_a2ui_request",
|
|
72
|
+
"build_a2ui_envelope",
|
|
73
|
+
"validate_a2ui_components",
|
|
74
|
+
"augment_prompt_with_validation_errors",
|
|
75
|
+
"wrap_error_envelope",
|
|
76
|
+
"MAX_A2UI_ATTEMPTS",
|
|
77
|
+
)
|
|
78
|
+
values = tuple(getattr(toolkit, name, None) for name in names)
|
|
79
|
+
if any(value is None for value in values):
|
|
80
|
+
raise RuntimeError("ag-ui-a2ui-toolkit is missing a required A2UI integration symbol")
|
|
81
|
+
return values
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
(
|
|
85
|
+
_RENDER_A2UI_TOOL_DEF,
|
|
86
|
+
_resolve_a2ui_tool_params,
|
|
87
|
+
_prepare_a2ui_request,
|
|
88
|
+
_build_a2ui_envelope,
|
|
89
|
+
_validate_a2ui_components,
|
|
90
|
+
_augment_prompt_with_validation_errors,
|
|
91
|
+
_wrap_error_envelope,
|
|
92
|
+
_MAX_A2UI_ATTEMPTS,
|
|
93
|
+
) = _a2ui_toolkit_dependencies()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _generation_timeout_seconds() -> float:
|
|
97
|
+
"""Read the operator-owned A2UI deadline, with a conservative default."""
|
|
98
|
+
raw = os.getenv("KSADK_A2UI_GENERATION_TIMEOUT_SECONDS", "").strip()
|
|
99
|
+
if not raw:
|
|
100
|
+
return _DEFAULT_GENERATION_TIMEOUT_SECONDS
|
|
101
|
+
try:
|
|
102
|
+
return max(1.0, min(float(raw), 120.0))
|
|
103
|
+
except ValueError:
|
|
104
|
+
return _DEFAULT_GENERATION_TIMEOUT_SECONDS
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _tool_call_args(response: Any) -> dict[str, Any] | None:
|
|
108
|
+
for call in getattr(response, "tool_calls", None) or []:
|
|
109
|
+
if not isinstance(call, dict):
|
|
110
|
+
continue
|
|
111
|
+
if call.get("name") != _RENDER_A2UI_TOOL_DEF["function"]["name"]:
|
|
112
|
+
continue
|
|
113
|
+
args = call.get("args")
|
|
114
|
+
return args if isinstance(args, dict) else {}
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
async def _invoke_a2ui_subagent(
|
|
119
|
+
model_with_tool: Any,
|
|
120
|
+
*,
|
|
121
|
+
prompt: str,
|
|
122
|
+
messages: list[Any],
|
|
123
|
+
timeout_seconds: float,
|
|
124
|
+
) -> dict[str, Any] | None:
|
|
125
|
+
"""Ask the structured-output model on the same loop as the parent run."""
|
|
126
|
+
|
|
127
|
+
async def invoke() -> Any:
|
|
128
|
+
ainvoke = getattr(model_with_tool, "ainvoke", None)
|
|
129
|
+
if callable(ainvoke):
|
|
130
|
+
result = ainvoke([SystemMessage(content=prompt), *messages])
|
|
131
|
+
return await result if inspect.isawaitable(result) else result
|
|
132
|
+
invoke_sync = getattr(model_with_tool, "invoke", None)
|
|
133
|
+
if not callable(invoke_sync):
|
|
134
|
+
raise TypeError("A2UI model must expose ainvoke() or invoke()")
|
|
135
|
+
return await asyncio.to_thread(invoke_sync, [SystemMessage(content=prompt), *messages])
|
|
136
|
+
|
|
137
|
+
response = await asyncio.wait_for(invoke(), timeout=timeout_seconds)
|
|
138
|
+
return _tool_call_args(response)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _attempt_callback(callback: Any, record: dict[str, Any]) -> None:
|
|
142
|
+
if not callable(callback):
|
|
143
|
+
return
|
|
144
|
+
try:
|
|
145
|
+
callback(record)
|
|
146
|
+
except Exception:
|
|
147
|
+
# Diagnostics must not prevent a usable UI surface from being returned.
|
|
148
|
+
logger.debug("A2UI attempt callback failed", exc_info=True)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
async def _generate_a2ui_envelope(
|
|
152
|
+
*,
|
|
153
|
+
config: dict[str, Any],
|
|
154
|
+
state: dict[str, Any],
|
|
155
|
+
messages: list[Any],
|
|
156
|
+
intent: str,
|
|
157
|
+
target_surface_id: str | None,
|
|
158
|
+
changes: str | None,
|
|
159
|
+
) -> str:
|
|
160
|
+
"""Run the official validate/retry contract without crossing event loops."""
|
|
161
|
+
|
|
162
|
+
prep = _prepare_a2ui_request(
|
|
163
|
+
intent=intent,
|
|
164
|
+
target_surface_id=target_surface_id,
|
|
165
|
+
changes=changes,
|
|
166
|
+
messages=messages,
|
|
167
|
+
state=state,
|
|
168
|
+
guidelines=config["guidelines"],
|
|
169
|
+
)
|
|
170
|
+
if prep.get("error"):
|
|
171
|
+
return str(_wrap_error_envelope(prep["error"]))
|
|
172
|
+
|
|
173
|
+
model = config["model"]
|
|
174
|
+
model_with_tool = model.bind_tools(
|
|
175
|
+
[_RENDER_A2UI_TOOL_DEF],
|
|
176
|
+
tool_choice=_RENDER_A2UI_TOOL_DEF["function"]["name"],
|
|
177
|
+
)
|
|
178
|
+
recovery = config.get("recovery") or {}
|
|
179
|
+
max_attempts = recovery.get("maxAttempts", _MAX_A2UI_ATTEMPTS)
|
|
180
|
+
try:
|
|
181
|
+
max_attempts = max(1, min(int(max_attempts), 5))
|
|
182
|
+
except (TypeError, ValueError):
|
|
183
|
+
max_attempts = _MAX_A2UI_ATTEMPTS
|
|
184
|
+
|
|
185
|
+
timeout_seconds = _generation_timeout_seconds()
|
|
186
|
+
last_errors: list[dict[str, str]] = []
|
|
187
|
+
attempts: list[dict[str, Any]] = []
|
|
188
|
+
for attempt in range(1, max_attempts + 1):
|
|
189
|
+
prompt = _augment_prompt_with_validation_errors(prep["prompt"], last_errors)
|
|
190
|
+
try:
|
|
191
|
+
args = await _invoke_a2ui_subagent(
|
|
192
|
+
model_with_tool,
|
|
193
|
+
prompt=prompt,
|
|
194
|
+
messages=messages,
|
|
195
|
+
timeout_seconds=timeout_seconds,
|
|
196
|
+
)
|
|
197
|
+
except asyncio.TimeoutError:
|
|
198
|
+
record: dict[str, Any] = {
|
|
199
|
+
"attempt": attempt,
|
|
200
|
+
"ok": False,
|
|
201
|
+
"errors": [
|
|
202
|
+
{
|
|
203
|
+
"code": "a2ui_generation_timeout",
|
|
204
|
+
"path": "model",
|
|
205
|
+
"message": f"A2UI generation exceeded {timeout_seconds:g} seconds",
|
|
206
|
+
}
|
|
207
|
+
],
|
|
208
|
+
}
|
|
209
|
+
attempts.append(record)
|
|
210
|
+
_attempt_callback(config.get("on_a2ui_attempt"), record)
|
|
211
|
+
# Retrying an already-cancelled request usually piles up more work;
|
|
212
|
+
# return a visible error instead of leaving the chat in limbo.
|
|
213
|
+
return str(_wrap_error_envelope(record["errors"][0]["message"]))
|
|
214
|
+
except Exception as exc:
|
|
215
|
+
record = {
|
|
216
|
+
"attempt": attempt,
|
|
217
|
+
"ok": False,
|
|
218
|
+
"errors": [
|
|
219
|
+
{
|
|
220
|
+
"code": "a2ui_generation_error",
|
|
221
|
+
"path": "model",
|
|
222
|
+
"message": str(exc) or type(exc).__name__,
|
|
223
|
+
}
|
|
224
|
+
],
|
|
225
|
+
}
|
|
226
|
+
attempts.append(record)
|
|
227
|
+
_attempt_callback(config.get("on_a2ui_attempt"), record)
|
|
228
|
+
return str(_wrap_error_envelope(record["errors"][0]["message"]))
|
|
229
|
+
|
|
230
|
+
if not args:
|
|
231
|
+
record = {
|
|
232
|
+
"attempt": attempt,
|
|
233
|
+
"ok": False,
|
|
234
|
+
"errors": [
|
|
235
|
+
{
|
|
236
|
+
"code": "empty_components",
|
|
237
|
+
"path": "components",
|
|
238
|
+
"message": "Sub-agent did not call render_a2ui",
|
|
239
|
+
}
|
|
240
|
+
],
|
|
241
|
+
}
|
|
242
|
+
else:
|
|
243
|
+
components = args.get("components")
|
|
244
|
+
data = args.get("data")
|
|
245
|
+
validation = _validate_a2ui_components(
|
|
246
|
+
components=components if isinstance(components, list) else [],
|
|
247
|
+
data=data if isinstance(data, dict) else {},
|
|
248
|
+
catalog=config.get("catalog"),
|
|
249
|
+
)
|
|
250
|
+
record = {
|
|
251
|
+
"attempt": attempt,
|
|
252
|
+
"ok": bool(validation["valid"]),
|
|
253
|
+
"errors": list(validation["errors"]),
|
|
254
|
+
}
|
|
255
|
+
attempts.append(record)
|
|
256
|
+
_attempt_callback(config.get("on_a2ui_attempt"), record)
|
|
257
|
+
if record["ok"]:
|
|
258
|
+
return str(
|
|
259
|
+
_build_a2ui_envelope(
|
|
260
|
+
args=args,
|
|
261
|
+
is_update=prep["is_update"],
|
|
262
|
+
target_surface_id=target_surface_id,
|
|
263
|
+
prior=prep["prior"],
|
|
264
|
+
default_surface_id=config["default_surface_id"],
|
|
265
|
+
default_catalog_id=config["default_catalog_id"],
|
|
266
|
+
)
|
|
267
|
+
)
|
|
268
|
+
last_errors = record["errors"]
|
|
269
|
+
|
|
270
|
+
return str(
|
|
271
|
+
_wrap_error_envelope(f"Failed to generate valid A2UI after {max_attempts} attempt(s)")
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def build_ksadk_a2ui_tool(params: dict[str, Any]) -> Any:
|
|
276
|
+
"""Build the dynamic LangChain A2UI tool used by the CopilotKit shim."""
|
|
277
|
+
|
|
278
|
+
resolved_params = dict(params)
|
|
279
|
+
resolved_params.setdefault("guidelines", _KSADK_HOSTED_UI_GUIDELINES)
|
|
280
|
+
config = _resolve_a2ui_tool_params(resolved_params)
|
|
281
|
+
|
|
282
|
+
@tool(config["tool_name"], description=config["tool_description"])
|
|
283
|
+
async def generate_a2ui(
|
|
284
|
+
runtime: ToolRuntime[Any],
|
|
285
|
+
intent: str = "create",
|
|
286
|
+
target_surface_id: str | None = None,
|
|
287
|
+
changes: str | None = None,
|
|
288
|
+
) -> str:
|
|
289
|
+
state = runtime.state if isinstance(runtime.state, dict) else {}
|
|
290
|
+
messages = list(state.get("messages") or [])[:-1]
|
|
291
|
+
return await _generate_a2ui_envelope(
|
|
292
|
+
config=config,
|
|
293
|
+
state=state,
|
|
294
|
+
messages=messages,
|
|
295
|
+
intent=intent,
|
|
296
|
+
target_surface_id=target_surface_id,
|
|
297
|
+
changes=changes,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
return generate_a2ui
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class KsadkCopilotKitMiddleware(CopilotKitMiddleware):
|
|
304
|
+
"""Official lifecycle middleware with KSADK's safe A2UI tool executor."""
|
|
305
|
+
|
|
306
|
+
def _maybe_build_a2ui_tool(self, request: Any) -> Any | None:
|
|
307
|
+
state = request.state or {}
|
|
308
|
+
if not self._a2ui_inject_decision(state):
|
|
309
|
+
return None
|
|
310
|
+
|
|
311
|
+
resolved = self._resolve_a2ui_catalog(state)
|
|
312
|
+
_component_schema, catalog_id = resolved if resolved else (None, None)
|
|
313
|
+
params: dict[str, Any] = {"model": request.model}
|
|
314
|
+
if catalog_id:
|
|
315
|
+
params["default_catalog_id"] = catalog_id
|
|
316
|
+
|
|
317
|
+
tool = build_ksadk_a2ui_tool(params)
|
|
318
|
+
existing_names = {getattr(item, "name", None) for item in (request.tools or [])}
|
|
319
|
+
if tool.name in existing_names:
|
|
320
|
+
return None
|
|
321
|
+
|
|
322
|
+
thread_key = (
|
|
323
|
+
copilotkit_lg_middleware._current_thread_id()
|
|
324
|
+
or copilotkit_lg_middleware._DEFAULT_THREAD_KEY
|
|
325
|
+
)
|
|
326
|
+
copilotkit_lg_middleware._a2ui_tools_by_thread[thread_key] = tool
|
|
327
|
+
return tool
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
__all__ = ["KsadkCopilotKitMiddleware", "build_ksadk_a2ui_tool"]
|
ksadk/configs/__init__.py
CHANGED
|
@@ -5,7 +5,7 @@ AgentEngine 统一配置管理
|
|
|
5
5
|
|
|
6
6
|
使用方式:
|
|
7
7
|
from ksadk.configs import settings
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
环境变量优先级 (举例):
|
|
10
10
|
Model: OPENAI_API_KEY > LLM_API_KEY > MODEL_API_KEY
|
|
11
11
|
Langfuse: LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, LANGFUSE_HOST
|
|
@@ -17,24 +17,24 @@ AgentEngine 统一配置管理
|
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
19
|
from ksadk.configs.settings import (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
ModelConfig,
|
|
25
|
-
LangfuseConfig,
|
|
20
|
+
DEFAULT_MODEL_NAME,
|
|
21
|
+
KSPMAS_INTERNAL_HOST,
|
|
22
|
+
KSPMAS_INTERNAL_URL,
|
|
23
|
+
KSPMAS_PUBLIC_URL,
|
|
26
24
|
AgentConfig,
|
|
27
|
-
KingsoftCloudConfig,
|
|
28
25
|
CodeModeConfig,
|
|
26
|
+
KingsoftCloudConfig,
|
|
27
|
+
LangfuseConfig,
|
|
28
|
+
# 各配置类
|
|
29
|
+
ModelConfig,
|
|
29
30
|
OTelConfig,
|
|
31
|
+
Settings,
|
|
30
32
|
# 通用网络检测工具
|
|
31
33
|
check_endpoint_reachable,
|
|
32
34
|
# KSPMAS 服务
|
|
33
35
|
get_kspmas_api_base,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
KSPMAS_PUBLIC_URL,
|
|
37
|
-
DEFAULT_MODEL_NAME,
|
|
36
|
+
# 全局配置入口
|
|
37
|
+
settings,
|
|
38
38
|
setup_environment,
|
|
39
39
|
)
|
|
40
40
|
|