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
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Runtime app route composition independent from the default app facade."""
|
|
2
|
+
|
|
3
|
+
from fastapi import FastAPI
|
|
4
|
+
|
|
5
|
+
from ksadk.server.factory import RuntimeAppState
|
|
6
|
+
from ksadk.server.routes.common import _register_integrated_routers
|
|
7
|
+
from ksadk.server.routes.routers import GROUP_ROUTERS, load_route_modules
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def configure_runtime_app(app: FastAPI, state: RuntimeAppState, groups: set[str]) -> None:
|
|
11
|
+
"""Attach integrated resources and the selected route groups to one app."""
|
|
12
|
+
load_route_modules()
|
|
13
|
+
_register_integrated_routers(app, state)
|
|
14
|
+
|
|
15
|
+
ordered = sorted(group for group in groups if group != "health_meta")
|
|
16
|
+
if "health_meta" in groups:
|
|
17
|
+
ordered.append("health_meta")
|
|
18
|
+
for group in ordered:
|
|
19
|
+
router = GROUP_ROUTERS.get(group)
|
|
20
|
+
if router is not None:
|
|
21
|
+
app.include_router(router)
|
ksadk/server/factory.py
ADDED
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
"""create_runtime_app — 普通 runtime 与 HarnessApp 共用的 app factory (goal-01)。
|
|
2
|
+
|
|
3
|
+
H2 §4.2:这是三线公共装配入口,替代 `ksadk/server/app.py` 的模块级单例 +
|
|
4
|
+
`set_runner` 全局态。纯结构性重构,不动业务逻辑。
|
|
5
|
+
|
|
6
|
+
设计要点:
|
|
7
|
+
|
|
8
|
+
- **per-app state**:runner / runner_loaded / detached-stream registry 全部挂在
|
|
9
|
+
`app.state.runtime`(:class:`RuntimeAppState`)上,每个 app 实例一份,普通 app 与
|
|
10
|
+
HarnessApp 互不共享。不再有模块级 ``runner`` / ``_DETACHED_*`` 全局可变态。
|
|
11
|
+
- **请求级桥接**:中间件把当前 app 的 state 写入 :data:`current_state` 的
|
|
12
|
+
contextvar,handler 内既有辅助函数经 :func:`get_state` 取 state,从而**不必逐个
|
|
13
|
+
改写约 30 个 handler 的签名**。后台 detached task 脱离请求上下文,在创建时
|
|
14
|
+
从 state 捕获 registry(见 ``_detached_streaming_response``)。
|
|
15
|
+
- **route group 化**:路由按域拆成 APIRouter,factory 按 ``config.route_groups``
|
|
16
|
+
可插拔装配;数据面 group 进 HarnessApp,控制面(cancel/resume/builder/debug)
|
|
17
|
+
不进。
|
|
18
|
+
- **薄兼容壳**:`ksadk/server/app.py` 仍以 ``app`` / ``set_runner`` 暴露,内部
|
|
19
|
+
改为调用本 factory,老调用方(TestClient / run_server / builders / deploy
|
|
20
|
+
manager)零改动。
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import asyncio
|
|
26
|
+
import contextvars
|
|
27
|
+
import logging
|
|
28
|
+
from contextlib import contextmanager
|
|
29
|
+
from typing import TYPE_CHECKING, Any, Callable, Iterator, Optional, cast
|
|
30
|
+
|
|
31
|
+
from fastapi import FastAPI
|
|
32
|
+
|
|
33
|
+
from ksadk.runners.base_runner import BaseRunner
|
|
34
|
+
from ksadk.sandbox.registry import (
|
|
35
|
+
SandboxRegistry,
|
|
36
|
+
bind_sandbox_registry,
|
|
37
|
+
set_fallback_sandbox_registry,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
if TYPE_CHECKING:
|
|
43
|
+
from ksadk.server.terminal_sessions import TerminalSessionManager
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
# route group 注册表(冻结稿 G0.1):数据面 vs 控制面
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
#: 数据面 route group —— 可插拔装配进 HarnessApp。
|
|
51
|
+
DATA_PLANE_GROUPS: frozenset[str] = frozenset(
|
|
52
|
+
{
|
|
53
|
+
"health_meta",
|
|
54
|
+
"sessions",
|
|
55
|
+
"sessions_adk_compat",
|
|
56
|
+
"run",
|
|
57
|
+
"openai_compat",
|
|
58
|
+
"workspace",
|
|
59
|
+
"models",
|
|
60
|
+
"feedback",
|
|
61
|
+
"tools",
|
|
62
|
+
"ui_bootstrap",
|
|
63
|
+
"agui",
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
#: 控制面 route group —— 不进入 HarnessApp(H2 §4.2:控制面 action 不进入)。
|
|
68
|
+
CONTROL_PLANE_GROUPS: frozenset[str] = frozenset(
|
|
69
|
+
{
|
|
70
|
+
"control", # cancel / resume / checkpoint-resume-preview
|
|
71
|
+
"builder",
|
|
72
|
+
"debug",
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
#: 全部 group(普通 runtime app 默认装配)。
|
|
77
|
+
ALL_GROUPS: frozenset[str] = DATA_PLANE_GROUPS | CONTROL_PLANE_GROUPS
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class StreamRegistry:
|
|
81
|
+
"""per-app detached SSE stream + resume-key 状态。
|
|
82
|
+
|
|
83
|
+
替代 `app.py` 曾经的模块级 ``_DETACHED_STREAMS`` / ``_DETACHED_STREAMS_BY_INVOCATION``
|
|
84
|
+
/ ``_DETACHED_RESUME_KEYS_BY_INVOCATION`` / ``_ACTIVE_DETACHED_RESUME_INVOCATION_BY_KEY``。
|
|
85
|
+
生命周期绑定所属 app(lifespan 清理)。SSE/cancel 行为与旧模块级实现逐点一致。
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def __init__(self) -> None:
|
|
89
|
+
self.streams: set[asyncio.Task[Any]] = set()
|
|
90
|
+
self.streams_by_invocation: dict[str, Any] = {}
|
|
91
|
+
self.resume_keys_by_invocation: dict[str, tuple[str, str]] = {}
|
|
92
|
+
self.active_resume_invocation_by_key: dict[tuple[str, str], str] = {}
|
|
93
|
+
|
|
94
|
+
def clear(self) -> None:
|
|
95
|
+
self.streams.clear()
|
|
96
|
+
self.streams_by_invocation.clear()
|
|
97
|
+
self.resume_keys_by_invocation.clear()
|
|
98
|
+
self.active_resume_invocation_by_key.clear()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class RuntimeAppState:
|
|
102
|
+
"""per-app 运行时状态及其拥有的可清理资源。"""
|
|
103
|
+
|
|
104
|
+
def __init__(
|
|
105
|
+
self,
|
|
106
|
+
runner: Optional[BaseRunner] = None,
|
|
107
|
+
*,
|
|
108
|
+
session_service_provider: Callable[[], Any] | None = None,
|
|
109
|
+
session_backend_provider: Callable[[], dict[str, Any]] | None = None,
|
|
110
|
+
) -> None:
|
|
111
|
+
self.app: Optional[FastAPI] = None
|
|
112
|
+
self.runner: Optional[BaseRunner] = runner
|
|
113
|
+
self.runner_loaded: bool = False
|
|
114
|
+
self.stream_registry = StreamRegistry()
|
|
115
|
+
self.sandbox_registry = SandboxRegistry()
|
|
116
|
+
self.session_service: Any = None
|
|
117
|
+
self._session_services_by_loop: dict[asyncio.AbstractEventLoop, Any] = {}
|
|
118
|
+
self._sync_session_service: Any = None
|
|
119
|
+
# The legacy ``server.app`` facade exposes monkeypatchable providers.
|
|
120
|
+
# New factory callers leave these unset and get per-app owned services.
|
|
121
|
+
self._session_service_provider = session_service_provider
|
|
122
|
+
self._session_backend_provider = session_backend_provider
|
|
123
|
+
# app.py 在装配 terminal routes 时创建,避免 factory 反向依赖 server。
|
|
124
|
+
self.terminal_manager: Optional[TerminalSessionManager] = None
|
|
125
|
+
# A2A 装配产物(config.a2a.enabled 时由 _wire_a2a_if_enabled 写入)。
|
|
126
|
+
self.a2a_server: Any = None
|
|
127
|
+
self.a2a_bootstrap: Any = None
|
|
128
|
+
# AG-UI endpoint 及其 app-owned RuntimeAdapter handle registry。
|
|
129
|
+
self.agui_agent: Any = None
|
|
130
|
+
self.agui_config: Any = None
|
|
131
|
+
|
|
132
|
+
def resolve_session_service(self) -> Any:
|
|
133
|
+
"""Return this app's session service for the current execution loop."""
|
|
134
|
+
if self.session_service is not None:
|
|
135
|
+
return self.session_service
|
|
136
|
+
if self._session_service_provider is not None:
|
|
137
|
+
return self._session_service_provider()
|
|
138
|
+
|
|
139
|
+
from ksadk.sessions import create_session_service
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
loop = asyncio.get_running_loop()
|
|
143
|
+
except RuntimeError:
|
|
144
|
+
if self._sync_session_service is None:
|
|
145
|
+
self._sync_session_service = create_session_service()
|
|
146
|
+
return self._sync_session_service
|
|
147
|
+
|
|
148
|
+
service = self._session_services_by_loop.get(loop)
|
|
149
|
+
if service is None:
|
|
150
|
+
service = create_session_service()
|
|
151
|
+
self._session_services_by_loop[loop] = service
|
|
152
|
+
return service
|
|
153
|
+
|
|
154
|
+
def session_services(self) -> list[Any]:
|
|
155
|
+
"""Return all unique services owned by this app for shutdown."""
|
|
156
|
+
candidates = [
|
|
157
|
+
self.session_service,
|
|
158
|
+
self._sync_session_service,
|
|
159
|
+
*self._session_services_by_loop.values(),
|
|
160
|
+
]
|
|
161
|
+
services: list[Any] = []
|
|
162
|
+
for service in candidates:
|
|
163
|
+
if service is not None and all(service is not item for item in services):
|
|
164
|
+
services.append(service)
|
|
165
|
+
return services
|
|
166
|
+
|
|
167
|
+
def describe_session_backend(self) -> dict[str, Any]:
|
|
168
|
+
if self._session_backend_provider is not None:
|
|
169
|
+
return dict(self._session_backend_provider())
|
|
170
|
+
from ksadk.sessions import describe_session_backend
|
|
171
|
+
|
|
172
|
+
return dict(describe_session_backend())
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class RuntimeAppConfig:
|
|
176
|
+
"""create_runtime_app 的装配配置。
|
|
177
|
+
|
|
178
|
+
- ``runner``:依赖注入的 runner(替代 set_runner 全局态);可在装配后由
|
|
179
|
+
兼容壳 ``set_runner`` 再写入 ``app.state.runtime.runner``。
|
|
180
|
+
- ``runtime_type``:runtime 类型标识(普通 / harness / codex ...)。
|
|
181
|
+
- ``route_groups``:要装配的 route group 集合;默认 :data:`ALL_GROUPS`,
|
|
182
|
+
HarnessApp 传 :data:`DATA_PLANE_GROUPS`。
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
def __init__(
|
|
186
|
+
self,
|
|
187
|
+
runner: Optional[BaseRunner] = None,
|
|
188
|
+
*,
|
|
189
|
+
runtime_type: str = "local",
|
|
190
|
+
route_groups: Optional[set[str]] = None,
|
|
191
|
+
a2a: Optional[Any] = None,
|
|
192
|
+
runtime_adapter: Any = None,
|
|
193
|
+
agui: Optional[Any] = None,
|
|
194
|
+
session_service_provider: Callable[[], Any] | None = None,
|
|
195
|
+
session_backend_provider: Callable[[], dict[str, Any]] | None = None,
|
|
196
|
+
) -> None:
|
|
197
|
+
self.runner = runner
|
|
198
|
+
self.runtime_type = runtime_type
|
|
199
|
+
self.route_groups: set[str] = (
|
|
200
|
+
set(route_groups) if route_groups is not None else set(ALL_GROUPS)
|
|
201
|
+
)
|
|
202
|
+
# A2A 协议装配配置(``ksadk.a2a.routes.A2AConfig``);enabled 时 factory 装配
|
|
203
|
+
# A2A 数据面端点(契约 §8)。用 Any 避免本模块硬依赖可选的 a2a-sdk。
|
|
204
|
+
self.a2a = a2a
|
|
205
|
+
self.runtime_adapter = runtime_adapter
|
|
206
|
+
self.agui = agui
|
|
207
|
+
self.session_service_provider = session_service_provider
|
|
208
|
+
self.session_backend_provider = session_backend_provider
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# ---------------------------------------------------------------------------
|
|
212
|
+
# 请求级 state 桥接
|
|
213
|
+
# ---------------------------------------------------------------------------
|
|
214
|
+
|
|
215
|
+
_current_state: contextvars.ContextVar[Optional[RuntimeAppState]] = contextvars.ContextVar(
|
|
216
|
+
"ksadk_runtime_app_state", default=None
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
# 非请求上下文(直接调用内部 helper 的测试 / run_server 启动前)的兜底 state。
|
|
220
|
+
# 由 app.py 在 factory 建 app 后指向 ``app.state.runtime``。
|
|
221
|
+
_fallback_state: RuntimeAppState = RuntimeAppState()
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def set_fallback_state(state: RuntimeAppState) -> None:
|
|
225
|
+
"""把兜底 state 指向某个 app 的 state(兼容壳用)。"""
|
|
226
|
+
global _fallback_state
|
|
227
|
+
_fallback_state = state
|
|
228
|
+
set_fallback_sandbox_registry(state.sandbox_registry)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def get_state() -> RuntimeAppState:
|
|
232
|
+
"""取当前请求对应的 app state;非请求上下文退回兜底 state。"""
|
|
233
|
+
state = _current_state.get()
|
|
234
|
+
return state if state is not None else _fallback_state
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
@contextmanager
|
|
238
|
+
def bind_runtime_state(state: RuntimeAppState) -> Iterator[None]:
|
|
239
|
+
"""Bind one app state for non-HTTP scopes such as WebSockets."""
|
|
240
|
+
token = _current_state.set(state)
|
|
241
|
+
try:
|
|
242
|
+
with bind_sandbox_registry(state.sandbox_registry):
|
|
243
|
+
yield
|
|
244
|
+
finally:
|
|
245
|
+
_current_state.reset(token)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def get_runner() -> BaseRunner:
|
|
249
|
+
"""取当前 app 的 runner(懒加载 agent)。等价旧的 ``_resolve_active_runner``。"""
|
|
250
|
+
from fastapi import HTTPException
|
|
251
|
+
|
|
252
|
+
state = get_state()
|
|
253
|
+
runner = state.runner
|
|
254
|
+
if runner is None:
|
|
255
|
+
raise HTTPException(status_code=500, detail="Runner 未初始化")
|
|
256
|
+
if not state.runner_loaded:
|
|
257
|
+
try:
|
|
258
|
+
runner.load_agent()
|
|
259
|
+
except HTTPException:
|
|
260
|
+
raise
|
|
261
|
+
except Exception as exc: # noqa: BLE001
|
|
262
|
+
logger.warning("Runner 加载失败: %s", exc)
|
|
263
|
+
raise HTTPException(status_code=500, detail=str(exc) or "Runner 加载失败") from exc
|
|
264
|
+
state.runner_loaded = True
|
|
265
|
+
return runner
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
# ---------------------------------------------------------------------------
|
|
269
|
+
# factory
|
|
270
|
+
# ---------------------------------------------------------------------------
|
|
271
|
+
|
|
272
|
+
# configure 回调签名:由 app.py 提供,负责把各 domain router 挂到 app 上。
|
|
273
|
+
ConfigureApp = Callable[[FastAPI, RuntimeAppState, set[str]], None]
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
async def shutdown_runtime_resources(state: RuntimeAppState) -> None:
|
|
277
|
+
"""Close only resources owned by one runtime app."""
|
|
278
|
+
manager = state.terminal_manager
|
|
279
|
+
if manager is not None:
|
|
280
|
+
try:
|
|
281
|
+
await manager.close()
|
|
282
|
+
except Exception:
|
|
283
|
+
logger.exception("failed to close terminal sessions on shutdown")
|
|
284
|
+
|
|
285
|
+
registry = state.stream_registry
|
|
286
|
+
pending_streams = list(registry.streams)
|
|
287
|
+
for task in pending_streams:
|
|
288
|
+
task.cancel()
|
|
289
|
+
if pending_streams:
|
|
290
|
+
await asyncio.gather(*pending_streams, return_exceptions=True)
|
|
291
|
+
registry.clear()
|
|
292
|
+
|
|
293
|
+
active_runner = state.runner
|
|
294
|
+
if active_runner is not None:
|
|
295
|
+
close = getattr(active_runner, "close", None)
|
|
296
|
+
if callable(close):
|
|
297
|
+
try:
|
|
298
|
+
await close()
|
|
299
|
+
except Exception:
|
|
300
|
+
logger.exception("failed to close runner on shutdown")
|
|
301
|
+
|
|
302
|
+
for service in state.session_services():
|
|
303
|
+
close = getattr(service, "aclose", None)
|
|
304
|
+
if callable(close):
|
|
305
|
+
try:
|
|
306
|
+
await close()
|
|
307
|
+
except Exception:
|
|
308
|
+
logger.exception("failed to close app session service on shutdown")
|
|
309
|
+
|
|
310
|
+
try:
|
|
311
|
+
state.sandbox_registry.close()
|
|
312
|
+
except Exception:
|
|
313
|
+
logger.exception("failed to clear sandbox registry on shutdown")
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def create_runtime_app(
|
|
317
|
+
config: RuntimeAppConfig,
|
|
318
|
+
configure: Optional[ConfigureApp] = None,
|
|
319
|
+
) -> FastAPI:
|
|
320
|
+
"""装配一个 runtime app。
|
|
321
|
+
|
|
322
|
+
参数:
|
|
323
|
+
config: :class:`RuntimeAppConfig`(runner / runtime_type / route_groups)。
|
|
324
|
+
configure: 路由装配回调 ``configure(app, state, route_groups)``;由
|
|
325
|
+
``ksadk/server/app.py`` 提供,负责按 group 把 domain router include 进 app。
|
|
326
|
+
factory 自身只负责 FastAPI 实例、state、中间件、lifespan、异常处理器,
|
|
327
|
+
不 import 全局 ``base_app`` 再过滤复制路由(H2 禁止)。
|
|
328
|
+
"""
|
|
329
|
+
from contextlib import asynccontextmanager
|
|
330
|
+
from typing import AsyncIterator
|
|
331
|
+
|
|
332
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
333
|
+
from fastapi.responses import Response
|
|
334
|
+
|
|
335
|
+
state = RuntimeAppState(
|
|
336
|
+
runner=config.runner,
|
|
337
|
+
session_service_provider=config.session_service_provider,
|
|
338
|
+
session_backend_provider=config.session_backend_provider,
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
@asynccontextmanager
|
|
342
|
+
async def _lifespan(app: FastAPI) -> AsyncIterator[None]:
|
|
343
|
+
try:
|
|
344
|
+
if state.a2a_bootstrap is not None:
|
|
345
|
+
await state.a2a_bootstrap.start()
|
|
346
|
+
yield
|
|
347
|
+
finally:
|
|
348
|
+
if state.a2a_bootstrap is not None:
|
|
349
|
+
await state.a2a_bootstrap.stop()
|
|
350
|
+
await shutdown_runtime_resources(state)
|
|
351
|
+
|
|
352
|
+
app = FastAPI(
|
|
353
|
+
title="ADK Core API",
|
|
354
|
+
description="Agent Development Kit HTTP API",
|
|
355
|
+
version="1.0.0",
|
|
356
|
+
lifespan=_lifespan,
|
|
357
|
+
)
|
|
358
|
+
state.app = app
|
|
359
|
+
app.state.runtime = state
|
|
360
|
+
|
|
361
|
+
# 中间件:把当前 app 的 state 写入请求级 contextvar(handler 经 get_state() 取)。
|
|
362
|
+
@app.middleware("http")
|
|
363
|
+
async def _runtime_state_bridge(request, call_next):
|
|
364
|
+
from ksadk.server.routes.dependencies import bind_session_service
|
|
365
|
+
|
|
366
|
+
with (
|
|
367
|
+
bind_runtime_state(state),
|
|
368
|
+
bind_session_service(
|
|
369
|
+
state.resolve_session_service(),
|
|
370
|
+
backend=state.describe_session_backend(),
|
|
371
|
+
),
|
|
372
|
+
):
|
|
373
|
+
# 保持旧行为:前端入口禁缓存。
|
|
374
|
+
response = await call_next(request)
|
|
375
|
+
path = request.url.path
|
|
376
|
+
if path == "/" or path.endswith(".html"):
|
|
377
|
+
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
|
|
378
|
+
response.headers["Pragma"] = "no-cache"
|
|
379
|
+
response.headers["Expires"] = "0"
|
|
380
|
+
return response
|
|
381
|
+
|
|
382
|
+
# CORS(与旧 app 一致,默认对 ADK 工具放开)。
|
|
383
|
+
app.add_middleware(
|
|
384
|
+
CORSMiddleware,
|
|
385
|
+
allow_origins=["*"],
|
|
386
|
+
allow_credentials=True,
|
|
387
|
+
allow_methods=["*"],
|
|
388
|
+
allow_headers=["*"],
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
# 异常处理器(与旧 app 一致)。
|
|
392
|
+
import json as _json
|
|
393
|
+
|
|
394
|
+
from ksadk.sessions.errors import SessionBackendUnavailable
|
|
395
|
+
|
|
396
|
+
@app.exception_handler(SessionBackendUnavailable)
|
|
397
|
+
async def session_backend_unavailable_handler(_request, exc: SessionBackendUnavailable):
|
|
398
|
+
return Response(
|
|
399
|
+
content=_json.dumps(
|
|
400
|
+
{"detail": {"code": "session_backend_unavailable", "message": str(exc)}},
|
|
401
|
+
ensure_ascii=False,
|
|
402
|
+
),
|
|
403
|
+
status_code=503,
|
|
404
|
+
media_type="application/json",
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
# A2A 端点须在 configure 之前装配:health_meta 含 GET catch-all ``/{requested_path:path}``,
|
|
408
|
+
# 若 A2A 后挂,A2A 的 GET 路由(agent-card / tasks/{id})会被 catch-all 遮蔽成 404。
|
|
409
|
+
_wire_a2a_if_enabled(app, state, config)
|
|
410
|
+
_wire_agui_if_enabled(app, state, config)
|
|
411
|
+
|
|
412
|
+
if configure is not None:
|
|
413
|
+
configure(app, state, set(config.route_groups))
|
|
414
|
+
|
|
415
|
+
return app
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
class _LazyRunnerProxy:
|
|
419
|
+
"""把 app.state 的 runner 以惰性方式暴露给 A2A executor/adapter。
|
|
420
|
+
|
|
421
|
+
兼容壳常在 factory 建 app 后才 ``set_runner`` 写入真实 runner,因此不能在装配期
|
|
422
|
+
固化 runner 引用。代理在每次调用时从 ``state`` 解析真实 runner 并懒加载,
|
|
423
|
+
接口与 ``BaseRunner`` 对齐(load_agent / stream / invoke,其余属性经 __getattr__
|
|
424
|
+
转发)。
|
|
425
|
+
"""
|
|
426
|
+
|
|
427
|
+
def __init__(self, state: RuntimeAppState) -> None:
|
|
428
|
+
self.__dict__["_state"] = state
|
|
429
|
+
|
|
430
|
+
def _real(self) -> BaseRunner:
|
|
431
|
+
state: RuntimeAppState = self.__dict__["_state"]
|
|
432
|
+
runner = state.runner
|
|
433
|
+
if runner is None:
|
|
434
|
+
raise RuntimeError("A2A: runner 尚未装配(set_runner 未调用)")
|
|
435
|
+
if not state.runner_loaded:
|
|
436
|
+
runner.load_agent()
|
|
437
|
+
state.runner_loaded = True
|
|
438
|
+
return runner
|
|
439
|
+
|
|
440
|
+
def load_agent(self) -> BaseRunner:
|
|
441
|
+
return self._real()
|
|
442
|
+
|
|
443
|
+
def stream(self, input_data: Any) -> Any:
|
|
444
|
+
# 与普通方法(非 async def)返回真实 runner.stream 的结果(async gen 或 coroutine),
|
|
445
|
+
# 由 RunnerRuntimeAdapter/executor 按既有分支处理。
|
|
446
|
+
return self._real().stream(input_data)
|
|
447
|
+
|
|
448
|
+
async def invoke(self, input_data: Any) -> Any:
|
|
449
|
+
return await self._real().invoke(input_data)
|
|
450
|
+
|
|
451
|
+
def __getattr__(self, name: str) -> Any:
|
|
452
|
+
return getattr(self._real(), name)
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def _wire_a2a_if_enabled(app: FastAPI, state: RuntimeAppState, config: RuntimeAppConfig) -> None:
|
|
456
|
+
"""契约 §8:``config.a2a.enabled`` 时把 A2A 协议端点装配进 app(数据面)。
|
|
457
|
+
|
|
458
|
+
runner 经 :class:`_LazyRunnerProxy` 惰性解析;RuntimeAdapter 用通用
|
|
459
|
+
``RunnerRuntimeAdapter``(经 P0-2 后 cancel 走真实 asyncio 任务中断)。
|
|
460
|
+
"""
|
|
461
|
+
a2a_cfg = config.a2a
|
|
462
|
+
if a2a_cfg is None:
|
|
463
|
+
return
|
|
464
|
+
from ksadk.a2a.bootstrap import AgentEngineA2ABootstrap
|
|
465
|
+
|
|
466
|
+
if isinstance(a2a_cfg, AgentEngineA2ABootstrap):
|
|
467
|
+
from ksadk.runtime.runner_adapter import RunnerRuntimeAdapter
|
|
468
|
+
|
|
469
|
+
proxy = _LazyRunnerProxy(state)
|
|
470
|
+
runtime_adapter = config.runtime_adapter or RunnerRuntimeAdapter(
|
|
471
|
+
cast("BaseRunner", proxy),
|
|
472
|
+
runtime_type=config.runtime_type,
|
|
473
|
+
)
|
|
474
|
+
server = a2a_cfg.mount(
|
|
475
|
+
app,
|
|
476
|
+
runner=proxy,
|
|
477
|
+
runtime_adapter=runtime_adapter,
|
|
478
|
+
runtime_type=config.runtime_type,
|
|
479
|
+
)
|
|
480
|
+
state.a2a_bootstrap = a2a_cfg
|
|
481
|
+
state.a2a_server = server
|
|
482
|
+
logger.info(
|
|
483
|
+
"managed A2A Runtime mounted(agent=%s inbound_enabled=%s)",
|
|
484
|
+
a2a_cfg.runtime_metadata.agent_id,
|
|
485
|
+
a2a_cfg.inbound_enabled,
|
|
486
|
+
)
|
|
487
|
+
return
|
|
488
|
+
if not getattr(a2a_cfg, "enabled", False):
|
|
489
|
+
return
|
|
490
|
+
from ksadk.a2a.routes import add_a2a_protocol_routes
|
|
491
|
+
from ksadk.a2a.task_adapter import A2ARuntimeTaskAdapter
|
|
492
|
+
from ksadk.runtime.runner_adapter import RunnerRuntimeAdapter
|
|
493
|
+
|
|
494
|
+
proxy = _LazyRunnerProxy(state)
|
|
495
|
+
adapter = RunnerRuntimeAdapter(cast("BaseRunner", proxy), runtime_type=config.runtime_type)
|
|
496
|
+
task_adapter = A2ARuntimeTaskAdapter(adapter, runtime_type=config.runtime_type)
|
|
497
|
+
server = add_a2a_protocol_routes(app, proxy, a2a_cfg, task_adapter=task_adapter)
|
|
498
|
+
state.a2a_server = server
|
|
499
|
+
logger.info("A2A 协议端点已装配进 runtime app(agent=%s)", a2a_cfg.agent_name)
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def _wire_agui_if_enabled(app: FastAPI, state: RuntimeAppState, config: RuntimeAppConfig) -> None:
|
|
503
|
+
"""Mount the optional official AG-UI endpoint before the static catch-all."""
|
|
504
|
+
agui_cfg = config.agui
|
|
505
|
+
if (
|
|
506
|
+
agui_cfg is None
|
|
507
|
+
or not getattr(agui_cfg, "enabled", False)
|
|
508
|
+
or "agui" not in config.route_groups
|
|
509
|
+
):
|
|
510
|
+
return
|
|
511
|
+
|
|
512
|
+
from ksadk.agui.config import require_agui_dependencies
|
|
513
|
+
|
|
514
|
+
require_agui_dependencies()
|
|
515
|
+
|
|
516
|
+
from ksadk.agui.routes import add_ksadk_agui_endpoint
|
|
517
|
+
from ksadk.events.store import RuntimeEventStore
|
|
518
|
+
from ksadk.server.routes import dependencies as route_dependencies
|
|
519
|
+
|
|
520
|
+
proxy = _LazyRunnerProxy(state)
|
|
521
|
+
|
|
522
|
+
class _AutoSessionRuntimeEventStore:
|
|
523
|
+
"""Create a session on first AG-UI event when HttpAgent starts fresh."""
|
|
524
|
+
|
|
525
|
+
def __init__(self, service: Any) -> None:
|
|
526
|
+
self._service = service
|
|
527
|
+
self._store = RuntimeEventStore(service)
|
|
528
|
+
|
|
529
|
+
async def append_one(self, event: Any) -> Any:
|
|
530
|
+
existing = await self._service.get_session(event.session_id)
|
|
531
|
+
if existing is None:
|
|
532
|
+
await self._service.create_session(
|
|
533
|
+
event.agent_id,
|
|
534
|
+
event.user_id,
|
|
535
|
+
event.session_id,
|
|
536
|
+
)
|
|
537
|
+
return await self._store.append_one(event)
|
|
538
|
+
|
|
539
|
+
async def reserve_once(self, event: Any) -> Any:
|
|
540
|
+
existing = await self._service.get_session(event.session_id)
|
|
541
|
+
if existing is None:
|
|
542
|
+
await self._service.create_session(
|
|
543
|
+
event.agent_id,
|
|
544
|
+
event.user_id,
|
|
545
|
+
event.session_id,
|
|
546
|
+
)
|
|
547
|
+
return await self._store.reserve_once(event)
|
|
548
|
+
|
|
549
|
+
async def list(self, session_id: str, **kwargs: Any) -> Any:
|
|
550
|
+
return await self._store.list(session_id, **kwargs)
|
|
551
|
+
|
|
552
|
+
agent = add_ksadk_agui_endpoint(
|
|
553
|
+
app,
|
|
554
|
+
cast("BaseRunner", proxy),
|
|
555
|
+
agui_cfg,
|
|
556
|
+
event_store_factory=lambda: _AutoSessionRuntimeEventStore(
|
|
557
|
+
route_dependencies.resolve_session_service()
|
|
558
|
+
),
|
|
559
|
+
session_service_factory=route_dependencies.resolve_session_service,
|
|
560
|
+
)
|
|
561
|
+
state.agui_agent = agent
|
|
562
|
+
state.agui_config = agui_cfg
|
|
563
|
+
logger.info("AG-UI endpoint mounted at %s", agui_cfg.path)
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
def wire_default_agui_for_runner(state: RuntimeAppState, runner: BaseRunner) -> None:
|
|
567
|
+
"""Mount AG-UI for legacy ``app`` + ``set_runner`` production entrypoints.
|
|
568
|
+
|
|
569
|
+
Those entrypoints create the FastAPI app before the framework runner exists.
|
|
570
|
+
Mounting immediately after ``set_runner`` is still startup-time wiring. New
|
|
571
|
+
protocol routes are moved ahead of the static catch-all to preserve routing
|
|
572
|
+
order exactly as the normal factory path does.
|
|
573
|
+
"""
|
|
574
|
+
if state.app is None or state.agui_agent is not None:
|
|
575
|
+
return
|
|
576
|
+
|
|
577
|
+
from ksadk.agui.config import default_agui_config
|
|
578
|
+
|
|
579
|
+
agui_config = default_agui_config(runner)
|
|
580
|
+
if not agui_config.enabled:
|
|
581
|
+
return
|
|
582
|
+
|
|
583
|
+
app = state.app
|
|
584
|
+
routes = app.router.routes
|
|
585
|
+
previous_count = len(routes)
|
|
586
|
+
_wire_agui_if_enabled(
|
|
587
|
+
app,
|
|
588
|
+
state,
|
|
589
|
+
RuntimeAppConfig(
|
|
590
|
+
runner=runner,
|
|
591
|
+
runtime_type=agui_config.runtime_type,
|
|
592
|
+
route_groups={"agui"},
|
|
593
|
+
agui=agui_config,
|
|
594
|
+
),
|
|
595
|
+
)
|
|
596
|
+
new_routes = routes[previous_count:]
|
|
597
|
+
if not new_routes:
|
|
598
|
+
return
|
|
599
|
+
del routes[previous_count:]
|
|
600
|
+
catch_all_index = next(
|
|
601
|
+
(
|
|
602
|
+
index
|
|
603
|
+
for index, route in enumerate(routes)
|
|
604
|
+
if getattr(route, "path", None) == "/{requested_path:path}"
|
|
605
|
+
),
|
|
606
|
+
len(routes),
|
|
607
|
+
)
|
|
608
|
+
routes[catch_all_index:catch_all_index] = new_routes
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
__all__ = [
|
|
612
|
+
"ALL_GROUPS",
|
|
613
|
+
"CONTROL_PLANE_GROUPS",
|
|
614
|
+
"DATA_PLANE_GROUPS",
|
|
615
|
+
"RuntimeAppConfig",
|
|
616
|
+
"RuntimeAppState",
|
|
617
|
+
"bind_runtime_state",
|
|
618
|
+
"StreamRegistry",
|
|
619
|
+
"create_runtime_app",
|
|
620
|
+
"get_runner",
|
|
621
|
+
"get_state",
|
|
622
|
+
"set_fallback_state",
|
|
623
|
+
"wire_default_agui_for_runner",
|
|
624
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Domain routers used by the runtime app composition root."""
|