agentengine-sdk-python 0.6.9__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.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +41 -23
- 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 +252 -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 +533 -726
- 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 +173 -90
- ksadk/cli/cmd_invoke.py +388 -159
- ksadk/cli/cmd_launch.py +64 -28
- ksadk/cli/cmd_mcp.py +103 -64
- ksadk/cli/cmd_model.py +14 -5
- ksadk/cli/cmd_openclaw.py +488 -228
- ksadk/cli/cmd_replay.py +71 -0
- ksadk/cli/cmd_run.py +44 -14
- 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 +38 -16
- 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 +501 -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 +656 -0
- ksadk/conversations/model_context.py +22 -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 -5187
- 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 +52 -39
- ksadk/deployment/manager.py +63 -65
- ksadk/deployment/providers/serverless.py +326 -209
- 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 +267 -0
- ksadk/memory/adk/short_term_memory.py +33 -27
- 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 +1248 -164
- 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 -530
- ksadk/runners/langgraph_runner.py +490 -95
- ksadk/runners/patch_langchain.py +16 -16
- ksadk/runners/remote_runner.py +264 -38
- 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 -3743
- 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-C0meuOdi.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-bj2rZnP5.js → arc-CFKwSk_B.js} +1 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +1 -0
- ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-2u1ltDIj.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
- ksadk/server/static/assets/{blockDiagram-GPEHLZMM-D6fvdK20.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
- ksadk/server/static/assets/{c4Diagram-AAUBKEIU-BK82L5n5.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
- ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
- ksadk/server/static/assets/{chunk-2J33WTMH-DLVdkeyQ.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
- ksadk/server/static/assets/{chunk-4BX2VUAB-BbwsYcbW.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
- ksadk/server/static/assets/{chunk-55IACEB6-DOairxzw.js → chunk-55IACEB6-BK8paA20.js} +1 -1
- ksadk/server/static/assets/{chunk-727SXJPM-hCO487gs.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
- ksadk/server/static/assets/{chunk-AQP2D5EJ-XU8vDOuG.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
- ksadk/server/static/assets/{chunk-FMBD7UC4-PrapyfMu.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
- ksadk/server/static/assets/{chunk-ND2GUHAM-CboKhTZ3.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-_N8bJ-EU.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
- ksadk/server/static/assets/{dagre-BM42HDAG-FoDlo5J2.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
- ksadk/server/static/assets/{diagram-2AECGRRQ-BBp6ebBw.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
- ksadk/server/static/assets/{diagram-5GNKFQAL-CqOvG1PR.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
- ksadk/server/static/assets/{diagram-KO2AKTUF-O9T3t6ba.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
- ksadk/server/static/assets/{diagram-LMA3HP47-CGG8ekBO.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
- ksadk/server/static/assets/{diagram-OG6HWLK6-4BmH1EEg.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
- ksadk/server/static/assets/{dist-CiZHB6ZW.js → dist-6CVKuTAe.js} +1 -1
- ksadk/server/static/assets/{dist-BMKM66B4.js → dist-BUHRxvDG.js} +1 -1
- ksadk/server/static/assets/{dist-CZ6C3x8B.js → dist-BZ9n9AjO.js} +1 -1
- ksadk/server/static/assets/{dist-DbaH3p5h.js → dist-BibcG1V9.js} +1 -1
- ksadk/server/static/assets/{dist-BVzcWa6D.js → dist-Bs-jQcRX.js} +1 -1
- ksadk/server/static/assets/{dist-D99wf6_X.js → dist-C2xjE7cO.js} +1 -1
- ksadk/server/static/assets/{dist-DLMjL01k.js → dist-C7-3jInC.js} +1 -1
- ksadk/server/static/assets/{dist-DI-oVAXw.js → dist-C99THtIA.js} +1 -1
- ksadk/server/static/assets/{dist-BkJjNih3.js → dist-CGcp2ex8.js} +1 -1
- ksadk/server/static/assets/{dist-D5JGcxBx.js → dist-CVQRZjPu.js} +1 -1
- ksadk/server/static/assets/{dist-CWiTDN_V.js → dist-Cf23NY4L.js} +1 -1
- ksadk/server/static/assets/{dist-DLeM1OCK.js → dist-CgF3fj15.js} +1 -1
- ksadk/server/static/assets/{dist-BmuTWcm7.js → dist-Cwt7koer.js} +1 -1
- ksadk/server/static/assets/{dist-C2DKRFVK.js → dist-D82mtD2s.js} +1 -1
- ksadk/server/static/assets/{dist-B67uF2uK.js → dist-DF06ORQo.js} +1 -1
- ksadk/server/static/assets/{dist-Cwhk4lwI.js → dist-DHn6nBzr.js} +1 -1
- ksadk/server/static/assets/{dist-S4klkK5W.js → dist-Djgl2wVZ.js} +1 -1
- ksadk/server/static/assets/{dist-DCpZrjaK.js → dist-DlzCRy0S.js} +1 -1
- ksadk/server/static/assets/{dist-Cp1_jKwf.js → dist-DqNnNFrw.js} +1 -1
- ksadk/server/static/assets/{dist-6kSZvCZh.js → dist-DyvYLMW9.js} +1 -1
- ksadk/server/static/assets/{dist-DM0rEQPk.js → dist-eoW6tZXA.js} +1 -1
- ksadk/server/static/assets/{dist-Bk1l05Ni.js → dist-ivOya1LD.js} +1 -1
- ksadk/server/static/assets/{erDiagram-TEJ5UH35-oJhaci7S.js → erDiagram-TEJ5UH35-CnfRcY2M.js} +1 -1
- ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +1 -0
- ksadk/server/static/assets/{flowDiagram-I6XJVG4X-DtTmUan-.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
- ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BSsb_eij.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-BR5s6Pws.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-DYPc5cvh.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
- ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-MoBdALDg.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
- ksadk/server/static/assets/{journeyDiagram-JHISSGLW-DgLiQT8l.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
- ksadk/server/static/assets/{kanban-definition-UN3LZRKU-CsFx112F.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
- ksadk/server/static/assets/{katex-DRsiwpM2.js → katex-DATssjp1.js} +1 -1
- ksadk/server/static/assets/{linear-TNRQ5Orv.js → linear-CvMBw9cA.js} +1 -1
- ksadk/server/static/assets/{mermaid-parser.core-D2eMVOgo.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
- ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-BtByYFhL.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-DPnuCB8c.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
- ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-miFpCPv4.js → quadrantDiagram-W4KKPZXB-CxIR4JXI.js} +1 -1
- ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +1 -0
- ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-mjB_yYkW.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
- ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-D7hSlZZZ.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
- ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-D9Cx6hC3.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
- ksadk/server/static/assets/{stateDiagram-AJRCARHV-D_zrg47o.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-CwSec0Wa.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-agCVobiF.js → vennDiagram-CIIHVFJN-l3Z7-wbP.js} +1 -1
- ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +1 -0
- ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-TmrlhWNt.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
- ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-DV71V-ah.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 +86 -40
- ksadk/sessions/base.py +31 -11
- ksadk/sessions/continuity.py +28 -5
- ksadk/sessions/in_memory.py +46 -2
- ksadk/sessions/local_service.py +148 -17
- ksadk/sessions/postgres_service.py +216 -35
- ksadk/sessions/resilience.py +52 -0
- ksadk/sessions/resilient.py +388 -0
- 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 +136 -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 +264 -114
- ksadk/tracing/exporters/inmemory_exporter.py +62 -51
- ksadk/tracing/exporters/langfuse_exporter.py +91 -76
- ksadk/tracing/setup.py +132 -53
- ksadk/tracing/span_utils.py +5 -2
- ksadk/tui/__init__.py +22 -7
- ksadk/tui/loop.py +1925 -0
- ksadk/tui/stream_render.py +69 -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.6.9.dist-info/RECORD +0 -487
- ksadk/server/static/assets/CodeBlock-BbI4HPtJ.js +0 -9
- ksadk/server/static/assets/MathMessageMarkdown-DMLQYoLp.js +0 -8
- ksadk/server/static/assets/MermaidBlock-DCR8WZ17.js +0 -303
- ksadk/server/static/assets/NativeTerminalPanel-CKUvWhUz.js +0 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-Cr6Xz1_c.js +0 -1
- ksadk/server/static/assets/channel-BSSOwFIb.js +0 -1
- ksadk/server/static/assets/chunk-QZHKN3VN-XXpdiwUL.js +0 -1
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-C5HvGiyK.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-C5HvGiyK.js +0 -1
- ksadk/server/static/assets/eventmodeling-FCH6USID-CIgwHJLL.js +0 -1
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BVAJ7uo0.js +0 -1
- ksadk/server/static/assets/index-BH7-pC0B.js +0 -165
- ksadk/server/static/assets/index-DAURbCsP.css +0 -1
- ksadk/server/static/assets/info-J43DQDTF-MT80V4ge.js +0 -1
- ksadk/server/static/assets/packet-YPE3B663-BLKhbXZB.js +0 -1
- ksadk/server/static/assets/pie-LRSECV5Y-DFOikjSY.js +0 -1
- ksadk/server/static/assets/radar-GUYGQ44K-095b1Ikw.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-J9kCb0nC.js +0 -1
- ksadk/server/static/assets/treeView-BLDUP644-yinfJEY6.js +0 -1
- ksadk/server/static/assets/treemap-LRROVOQU-DosUqN1Q.js +0 -1
- ksadk/server/static/assets/wardley-L42UT6IY-Bvp7-5uH.js +0 -1
- ksadk/tui/app.py +0 -400
- ksadk/tui/clipboard.py +0 -100
- ksadk/tui/widgets/__init__.py +0 -22
- ksadk/tui/widgets/assistant.py +0 -89
- ksadk/tui/widgets/base.py +0 -54
- ksadk/tui/widgets/chat_input.py +0 -246
- ksadk/tui/widgets/history.py +0 -156
- ksadk/tui/widgets/system.py +0 -87
- ksadk/tui/widgets/thinking.py +0 -110
- ksadk/tui/widgets/tool_call.py +0 -161
- ksadk/tui/widgets/user.py +0 -37
- {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
- {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
"""Durable local outbox for AgentEngine A2A task event batches."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import hashlib
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
import sqlite3
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
ENV_A2A_EVENT_OUTBOX_PATH = "KSADK_A2A_EVENT_OUTBOX_PATH"
|
|
16
|
+
DEFAULT_A2A_EVENT_OUTBOX_PATH = ".agentengine/a2a_event_outbox.sqlite3"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class A2ATaskEventBatch:
|
|
21
|
+
sequence: int
|
|
22
|
+
batch_id: str
|
|
23
|
+
platform_task_id: str
|
|
24
|
+
events: list[dict[str, Any]]
|
|
25
|
+
attempt_count: int = 0
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class A2ATaskEventOutbox(ABC):
|
|
29
|
+
"""Persists task-sink batches until AgentEngine acknowledges them."""
|
|
30
|
+
|
|
31
|
+
@abstractmethod
|
|
32
|
+
async def initialize(self) -> None:
|
|
33
|
+
raise NotImplementedError
|
|
34
|
+
|
|
35
|
+
@abstractmethod
|
|
36
|
+
async def ensure_writable(self) -> None:
|
|
37
|
+
raise NotImplementedError
|
|
38
|
+
|
|
39
|
+
@abstractmethod
|
|
40
|
+
async def enqueue(
|
|
41
|
+
self,
|
|
42
|
+
*,
|
|
43
|
+
platform_task_id: str,
|
|
44
|
+
events: list[dict[str, Any]],
|
|
45
|
+
) -> str:
|
|
46
|
+
raise NotImplementedError
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
async def pending(self, *, limit: int = 100) -> list[A2ATaskEventBatch]:
|
|
50
|
+
raise NotImplementedError
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
async def acknowledge(self, batch_id: str) -> None:
|
|
54
|
+
raise NotImplementedError
|
|
55
|
+
|
|
56
|
+
@abstractmethod
|
|
57
|
+
async def record_failure(self, batch_id: str, error: str) -> None:
|
|
58
|
+
raise NotImplementedError
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _serialize_events(events: list[dict[str, Any]]) -> str:
|
|
62
|
+
return json.dumps(events, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _batch_id(platform_task_id: str, events_json: str) -> str:
|
|
66
|
+
digest = hashlib.sha256(f"{platform_task_id}:{events_json}".encode("utf-8")).hexdigest()
|
|
67
|
+
return f"a2a-event-batch-{digest}"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class InMemoryA2ATaskEventOutbox(A2ATaskEventOutbox):
|
|
71
|
+
"""Test/local adapter; production Runtime deployments should use SQLite."""
|
|
72
|
+
|
|
73
|
+
def __init__(self) -> None:
|
|
74
|
+
self._batches: dict[str, A2ATaskEventBatch] = {}
|
|
75
|
+
self._lock = asyncio.Lock()
|
|
76
|
+
self._next_sequence = 0
|
|
77
|
+
|
|
78
|
+
async def initialize(self) -> None:
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
async def ensure_writable(self) -> None:
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
async def enqueue(
|
|
85
|
+
self,
|
|
86
|
+
*,
|
|
87
|
+
platform_task_id: str,
|
|
88
|
+
events: list[dict[str, Any]],
|
|
89
|
+
) -> str:
|
|
90
|
+
events_json = _serialize_events(events)
|
|
91
|
+
batch_id = _batch_id(platform_task_id, events_json)
|
|
92
|
+
async with self._lock:
|
|
93
|
+
if batch_id not in self._batches:
|
|
94
|
+
self._next_sequence += 1
|
|
95
|
+
self._batches[batch_id] = A2ATaskEventBatch(
|
|
96
|
+
sequence=self._next_sequence,
|
|
97
|
+
batch_id=batch_id,
|
|
98
|
+
platform_task_id=platform_task_id,
|
|
99
|
+
events=json.loads(events_json),
|
|
100
|
+
)
|
|
101
|
+
return batch_id
|
|
102
|
+
|
|
103
|
+
async def pending(self, *, limit: int = 100) -> list[A2ATaskEventBatch]:
|
|
104
|
+
async with self._lock:
|
|
105
|
+
return sorted(self._batches.values(), key=lambda batch: batch.sequence)[:limit]
|
|
106
|
+
|
|
107
|
+
async def acknowledge(self, batch_id: str) -> None:
|
|
108
|
+
async with self._lock:
|
|
109
|
+
self._batches.pop(batch_id, None)
|
|
110
|
+
|
|
111
|
+
async def record_failure(self, batch_id: str, error: str) -> None:
|
|
112
|
+
async with self._lock:
|
|
113
|
+
batch = self._batches.get(batch_id)
|
|
114
|
+
if batch is not None:
|
|
115
|
+
self._batches[batch_id] = A2ATaskEventBatch(
|
|
116
|
+
sequence=batch.sequence,
|
|
117
|
+
batch_id=batch.batch_id,
|
|
118
|
+
platform_task_id=batch.platform_task_id,
|
|
119
|
+
events=batch.events,
|
|
120
|
+
attempt_count=batch.attempt_count + 1,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class SQLiteA2ATaskEventOutbox(A2ATaskEventOutbox):
|
|
125
|
+
"""SQLite adapter with stable batch IDs and crash-safe acknowledgement."""
|
|
126
|
+
|
|
127
|
+
def __init__(self, path: str | os.PathLike[str] | None = None) -> None:
|
|
128
|
+
configured = path or os.getenv(ENV_A2A_EVENT_OUTBOX_PATH) or DEFAULT_A2A_EVENT_OUTBOX_PATH
|
|
129
|
+
self._path = Path(configured).expanduser()
|
|
130
|
+
self._initialized = False
|
|
131
|
+
self._init_lock = asyncio.Lock()
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def path(self) -> Path:
|
|
135
|
+
return self._path
|
|
136
|
+
|
|
137
|
+
async def initialize(self) -> None:
|
|
138
|
+
if self._initialized:
|
|
139
|
+
return
|
|
140
|
+
async with self._init_lock:
|
|
141
|
+
if self._initialized:
|
|
142
|
+
return
|
|
143
|
+
await asyncio.to_thread(self._initialize_sync)
|
|
144
|
+
self._initialized = True
|
|
145
|
+
|
|
146
|
+
def _initialize_sync(self) -> None:
|
|
147
|
+
self._path.parent.mkdir(parents=True, exist_ok=True)
|
|
148
|
+
connection = sqlite3.connect(self._path, timeout=5)
|
|
149
|
+
try:
|
|
150
|
+
connection.execute("PRAGMA journal_mode=WAL")
|
|
151
|
+
connection.execute("PRAGMA synchronous=FULL")
|
|
152
|
+
connection.execute(
|
|
153
|
+
"""
|
|
154
|
+
CREATE TABLE IF NOT EXISTS a2a_task_event_outbox (
|
|
155
|
+
sequence INTEGER NOT NULL,
|
|
156
|
+
batch_id TEXT PRIMARY KEY,
|
|
157
|
+
platform_task_id TEXT NOT NULL,
|
|
158
|
+
events_json TEXT NOT NULL,
|
|
159
|
+
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
160
|
+
attempt_count INTEGER NOT NULL DEFAULT 0,
|
|
161
|
+
last_error TEXT
|
|
162
|
+
)
|
|
163
|
+
"""
|
|
164
|
+
)
|
|
165
|
+
columns = {
|
|
166
|
+
str(row[1])
|
|
167
|
+
for row in connection.execute("PRAGMA table_info(a2a_task_event_outbox)").fetchall()
|
|
168
|
+
}
|
|
169
|
+
if "sequence" not in columns:
|
|
170
|
+
connection.execute("ALTER TABLE a2a_task_event_outbox ADD COLUMN sequence INTEGER")
|
|
171
|
+
connection.execute(
|
|
172
|
+
"UPDATE a2a_task_event_outbox SET sequence = rowid WHERE sequence IS NULL"
|
|
173
|
+
)
|
|
174
|
+
connection.execute(
|
|
175
|
+
"""
|
|
176
|
+
CREATE TABLE IF NOT EXISTS a2a_task_event_outbox_sequence (
|
|
177
|
+
sequence INTEGER PRIMARY KEY AUTOINCREMENT
|
|
178
|
+
)
|
|
179
|
+
"""
|
|
180
|
+
)
|
|
181
|
+
connection.execute(
|
|
182
|
+
"""
|
|
183
|
+
INSERT OR IGNORE INTO a2a_task_event_outbox_sequence(sequence)
|
|
184
|
+
SELECT sequence FROM a2a_task_event_outbox
|
|
185
|
+
"""
|
|
186
|
+
)
|
|
187
|
+
connection.execute(
|
|
188
|
+
"""
|
|
189
|
+
CREATE INDEX IF NOT EXISTS ix_a2a_task_event_outbox_created
|
|
190
|
+
ON a2a_task_event_outbox(sequence)
|
|
191
|
+
"""
|
|
192
|
+
)
|
|
193
|
+
connection.commit()
|
|
194
|
+
finally:
|
|
195
|
+
connection.close()
|
|
196
|
+
os.chmod(self._path, 0o600)
|
|
197
|
+
|
|
198
|
+
async def enqueue(
|
|
199
|
+
self,
|
|
200
|
+
*,
|
|
201
|
+
platform_task_id: str,
|
|
202
|
+
events: list[dict[str, Any]],
|
|
203
|
+
) -> str:
|
|
204
|
+
await self.initialize()
|
|
205
|
+
events_json = _serialize_events(events)
|
|
206
|
+
batch_id = _batch_id(platform_task_id, events_json)
|
|
207
|
+
await asyncio.to_thread(
|
|
208
|
+
self._enqueue_sync,
|
|
209
|
+
batch_id,
|
|
210
|
+
platform_task_id,
|
|
211
|
+
events_json,
|
|
212
|
+
)
|
|
213
|
+
return batch_id
|
|
214
|
+
|
|
215
|
+
async def ensure_writable(self) -> None:
|
|
216
|
+
await self.initialize()
|
|
217
|
+
await asyncio.to_thread(self._ensure_writable_sync)
|
|
218
|
+
|
|
219
|
+
async def pending(self, *, limit: int = 100) -> list[A2ATaskEventBatch]:
|
|
220
|
+
await self.initialize()
|
|
221
|
+
rows = await asyncio.to_thread(self._pending_sync, limit)
|
|
222
|
+
return [
|
|
223
|
+
A2ATaskEventBatch(
|
|
224
|
+
sequence=int(row[0]),
|
|
225
|
+
batch_id=str(row[1]),
|
|
226
|
+
platform_task_id=str(row[2]),
|
|
227
|
+
events=list(json.loads(str(row[3]))),
|
|
228
|
+
attempt_count=int(row[4]),
|
|
229
|
+
)
|
|
230
|
+
for row in rows
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
async def acknowledge(self, batch_id: str) -> None:
|
|
234
|
+
await self.initialize()
|
|
235
|
+
await asyncio.to_thread(
|
|
236
|
+
self._execute,
|
|
237
|
+
"DELETE FROM a2a_task_event_outbox WHERE batch_id = ?",
|
|
238
|
+
(batch_id,),
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
async def record_failure(self, batch_id: str, error: str) -> None:
|
|
242
|
+
await self.initialize()
|
|
243
|
+
await asyncio.to_thread(
|
|
244
|
+
self._execute,
|
|
245
|
+
"""
|
|
246
|
+
UPDATE a2a_task_event_outbox
|
|
247
|
+
SET attempt_count = attempt_count + 1, last_error = ?
|
|
248
|
+
WHERE batch_id = ?
|
|
249
|
+
""",
|
|
250
|
+
(error[:512], batch_id),
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
def _execute(self, statement: str, params: tuple[Any, ...]) -> None:
|
|
254
|
+
connection = sqlite3.connect(self._path, timeout=5)
|
|
255
|
+
try:
|
|
256
|
+
connection.execute("PRAGMA synchronous=FULL")
|
|
257
|
+
connection.execute(statement, params)
|
|
258
|
+
connection.commit()
|
|
259
|
+
finally:
|
|
260
|
+
connection.close()
|
|
261
|
+
|
|
262
|
+
def _enqueue_sync(self, batch_id: str, platform_task_id: str, events_json: str) -> None:
|
|
263
|
+
connection = sqlite3.connect(self._path, timeout=5, isolation_level=None)
|
|
264
|
+
try:
|
|
265
|
+
connection.execute("PRAGMA synchronous=FULL")
|
|
266
|
+
connection.execute("BEGIN IMMEDIATE")
|
|
267
|
+
existing = connection.execute(
|
|
268
|
+
"SELECT 1 FROM a2a_task_event_outbox WHERE batch_id = ?",
|
|
269
|
+
(batch_id,),
|
|
270
|
+
).fetchone()
|
|
271
|
+
if existing is None:
|
|
272
|
+
cursor = connection.execute(
|
|
273
|
+
"INSERT INTO a2a_task_event_outbox_sequence DEFAULT VALUES"
|
|
274
|
+
)
|
|
275
|
+
if cursor.lastrowid is None:
|
|
276
|
+
raise RuntimeError("SQLite did not return an outbox sequence")
|
|
277
|
+
sequence = int(cursor.lastrowid)
|
|
278
|
+
connection.execute(
|
|
279
|
+
"""
|
|
280
|
+
INSERT INTO a2a_task_event_outbox(
|
|
281
|
+
sequence, batch_id, platform_task_id, events_json
|
|
282
|
+
) VALUES (?, ?, ?, ?)
|
|
283
|
+
""",
|
|
284
|
+
(sequence, batch_id, platform_task_id, events_json),
|
|
285
|
+
)
|
|
286
|
+
connection.execute("COMMIT")
|
|
287
|
+
except BaseException:
|
|
288
|
+
connection.rollback()
|
|
289
|
+
raise
|
|
290
|
+
finally:
|
|
291
|
+
connection.close()
|
|
292
|
+
|
|
293
|
+
def _ensure_writable_sync(self) -> None:
|
|
294
|
+
connection = sqlite3.connect(self._path, timeout=5, isolation_level=None)
|
|
295
|
+
try:
|
|
296
|
+
connection.execute("BEGIN IMMEDIATE")
|
|
297
|
+
connection.execute("ROLLBACK")
|
|
298
|
+
finally:
|
|
299
|
+
connection.close()
|
|
300
|
+
|
|
301
|
+
def _pending_sync(self, limit: int) -> list[tuple[Any, ...]]:
|
|
302
|
+
connection = sqlite3.connect(self._path, timeout=5)
|
|
303
|
+
try:
|
|
304
|
+
return list(
|
|
305
|
+
connection.execute(
|
|
306
|
+
"""
|
|
307
|
+
SELECT sequence, batch_id, platform_task_id, events_json, attempt_count
|
|
308
|
+
FROM a2a_task_event_outbox
|
|
309
|
+
ORDER BY sequence
|
|
310
|
+
LIMIT ?
|
|
311
|
+
""",
|
|
312
|
+
(limit,),
|
|
313
|
+
).fetchall()
|
|
314
|
+
)
|
|
315
|
+
finally:
|
|
316
|
+
connection.close()
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
__all__ = [
|
|
320
|
+
"A2ATaskEventBatch",
|
|
321
|
+
"A2ATaskEventOutbox",
|
|
322
|
+
"DEFAULT_A2A_EVENT_OUTBOX_PATH",
|
|
323
|
+
"ENV_A2A_EVENT_OUTBOX_PATH",
|
|
324
|
+
"InMemoryA2ATaskEventOutbox",
|
|
325
|
+
"SQLiteA2ATaskEventOutbox",
|
|
326
|
+
]
|
ksadk/a2a/task_store.py
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"""A2A durable TaskStore (goal-05)。
|
|
2
|
+
|
|
3
|
+
契约(§4.6):托管被调 task 使用 SDK ``DatabaseTaskStore``,表名隔离为
|
|
4
|
+
``ksadk_a2a_tasks``,owner resolver 必须包含 account/runtime identity。
|
|
5
|
+
**不用 InMemoryTaskStore**——7/31 重启恢复发布门禁依赖 durable store。
|
|
6
|
+
|
|
7
|
+
注意:TaskStore 只持久化**协议 Task**,不等于 runner checkpoint;两者必须共同成功
|
|
8
|
+
才能声明 durable async(§7.2)。SQLite 只用于快速单测;进程崩溃恢复门禁必须使用
|
|
9
|
+
真实 PostgreSQL 和独立 OS 进程。
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import warnings
|
|
15
|
+
from threading import Lock
|
|
16
|
+
from typing import Any, Callable, Mapping, Optional, Sequence
|
|
17
|
+
|
|
18
|
+
from a2a.server import models as _sdk_models
|
|
19
|
+
from a2a.server.context import ServerCallContext
|
|
20
|
+
from a2a.server.routes.common import DefaultServerCallContextBuilder
|
|
21
|
+
from a2a.server.tasks import DatabaseTaskStore
|
|
22
|
+
from sqlalchemy.exc import SAWarning
|
|
23
|
+
from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine
|
|
24
|
+
from starlette.requests import Request
|
|
25
|
+
|
|
26
|
+
from ksadk.a2a.identity import A2AIngressIdentity, A2ATrustedIdentityResolver
|
|
27
|
+
|
|
28
|
+
#: 契约 §4.6 规定的隔离表名。
|
|
29
|
+
A2A_TASK_TABLE = "ksadk_a2a_tasks"
|
|
30
|
+
|
|
31
|
+
DEFAULT_ACCOUNT_HEADERS = ("x-ksc-account-id", "x-account-id")
|
|
32
|
+
DEFAULT_RUNTIME_HEADERS = ("x-auth-agent-id", "x-ksc-agent-id", "x-runtime-id")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# a2a-sdk 1.1.0 dynamically declares a new ORM model for every custom-table
|
|
36
|
+
# store. Repeating the same table in one process raises an SQLAlchemy duplicate
|
|
37
|
+
# table error. Cache only KsADK's model instead of monkeypatching the SDK module.
|
|
38
|
+
_task_model_cache: dict[str, type[Any]] = {}
|
|
39
|
+
_task_model_lock = Lock()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _task_model(table_name: str) -> type[Any]:
|
|
43
|
+
with _task_model_lock:
|
|
44
|
+
model = _task_model_cache.get(table_name)
|
|
45
|
+
if model is None:
|
|
46
|
+
with warnings.catch_warnings():
|
|
47
|
+
warnings.filterwarnings(
|
|
48
|
+
"ignore",
|
|
49
|
+
message=(
|
|
50
|
+
"This declarative base already contains a class with the same class name"
|
|
51
|
+
),
|
|
52
|
+
category=SAWarning,
|
|
53
|
+
)
|
|
54
|
+
model = _sdk_models.create_task_model(table_name)
|
|
55
|
+
_task_model_cache[table_name] = model
|
|
56
|
+
return model
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class _KsADKDatabaseTaskStore(DatabaseTaskStore):
|
|
60
|
+
"""DatabaseTaskStore with a process-local, non-global custom-table model."""
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
*,
|
|
65
|
+
engine: AsyncEngine,
|
|
66
|
+
create_table: bool,
|
|
67
|
+
table_name: str,
|
|
68
|
+
owner_resolver: Callable[[ServerCallContext], str],
|
|
69
|
+
) -> None:
|
|
70
|
+
super().__init__(
|
|
71
|
+
engine=engine,
|
|
72
|
+
create_table=create_table,
|
|
73
|
+
owner_resolver=owner_resolver,
|
|
74
|
+
)
|
|
75
|
+
self.task_model = _task_model(table_name)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _first(state: dict[str, Any], *keys: str) -> Optional[str]:
|
|
79
|
+
for key in keys:
|
|
80
|
+
value = state.get(key)
|
|
81
|
+
if value:
|
|
82
|
+
return str(value)
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def default_owner_resolver(context: ServerCallContext) -> str:
|
|
87
|
+
"""默认 owner resolver:组合 account + runtime identity(契约 §4.6 要求两者)。
|
|
88
|
+
|
|
89
|
+
owner 形如 ``"{account}/{runtime}"``:account 取 ``account_id``/``tenant_id``,
|
|
90
|
+
runtime 取 ``runtime_id``/``agent_id``。**同一 account 下不同 runtime 形成独立任务
|
|
91
|
+
权限域**(不会共用);只凑齐一侧时用一侧;两侧都缺时退回 ``user``/``anonymous``。
|
|
92
|
+
生产环境应由鉴权/STS 在 context.state 注入这些键;本地无鉴权时退回匿名。
|
|
93
|
+
"""
|
|
94
|
+
state = getattr(context, "state", None) or {}
|
|
95
|
+
verified_identity = state.get(A2ATrustedIdentityResolver.state_key)
|
|
96
|
+
if isinstance(verified_identity, A2AIngressIdentity):
|
|
97
|
+
return verified_identity.owner_key()
|
|
98
|
+
account = _first(state, "account_id", "tenant_id")
|
|
99
|
+
runtime = _first(state, "runtime_id", "agent_id")
|
|
100
|
+
parts = [part for part in (account, runtime) if part]
|
|
101
|
+
if parts:
|
|
102
|
+
return "/".join(parts)
|
|
103
|
+
return _first(state, "user") or "anonymous"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class A2AOwnerContextBuilder(DefaultServerCallContextBuilder):
|
|
107
|
+
"""Build A2A call contexts from platform-authenticated HTTP identity.
|
|
108
|
+
|
|
109
|
+
The SDK default stores headers only under ``state['headers']`` while the
|
|
110
|
+
task store intentionally reads normalized top-level identity fields. This
|
|
111
|
+
builder is shared by JSON-RPC and REST so both transports enforce the same
|
|
112
|
+
account/runtime owner boundary. Deployments must strip/replace these
|
|
113
|
+
platform headers at the public edge; message metadata is never trusted.
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
def __init__(
|
|
117
|
+
self,
|
|
118
|
+
*,
|
|
119
|
+
account_headers: Sequence[str] = DEFAULT_ACCOUNT_HEADERS,
|
|
120
|
+
runtime_headers: Sequence[str] = DEFAULT_RUNTIME_HEADERS,
|
|
121
|
+
identity_resolver: A2ATrustedIdentityResolver | None = None,
|
|
122
|
+
allow_unverified_identity: bool = True,
|
|
123
|
+
) -> None:
|
|
124
|
+
self._account_headers = tuple(header.lower() for header in account_headers)
|
|
125
|
+
self._runtime_headers = tuple(header.lower() for header in runtime_headers)
|
|
126
|
+
self._identity_resolver = identity_resolver
|
|
127
|
+
self._allow_unverified_identity = allow_unverified_identity
|
|
128
|
+
|
|
129
|
+
@staticmethod
|
|
130
|
+
def _header(headers: Mapping[str, Any], names: Sequence[str]) -> str | None:
|
|
131
|
+
for name in names:
|
|
132
|
+
value = str(headers.get(name) or "").strip()
|
|
133
|
+
if value:
|
|
134
|
+
return value
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
def build(self, request: Request) -> ServerCallContext:
|
|
138
|
+
context = super().build(request)
|
|
139
|
+
state = dict(context.state or {})
|
|
140
|
+
headers = {str(key).lower(): value for key, value in request.headers.items()}
|
|
141
|
+
scope_state = request.scope.get("state")
|
|
142
|
+
trusted_state = dict(scope_state) if isinstance(scope_state, Mapping) else {}
|
|
143
|
+
if self._identity_resolver is not None:
|
|
144
|
+
identity = self._identity_resolver.resolve(request)
|
|
145
|
+
state[A2ATrustedIdentityResolver.state_key] = identity
|
|
146
|
+
state["account_id"] = identity.account_id
|
|
147
|
+
state["tenant_id"] = identity.tenant_id
|
|
148
|
+
state["caller_principal_type"] = identity.caller_principal_type
|
|
149
|
+
state["caller_principal_id"] = identity.caller_principal_id
|
|
150
|
+
elif not self._allow_unverified_identity:
|
|
151
|
+
raise PermissionError("verified Gateway identity is required for inbound A2A")
|
|
152
|
+
else:
|
|
153
|
+
account = _first(trusted_state, "account_id", "tenant_id") or self._header(
|
|
154
|
+
headers, self._account_headers
|
|
155
|
+
)
|
|
156
|
+
runtime = _first(trusted_state, "runtime_id", "agent_id") or self._header(
|
|
157
|
+
headers, self._runtime_headers
|
|
158
|
+
)
|
|
159
|
+
if account:
|
|
160
|
+
state["account_id"] = account
|
|
161
|
+
if runtime:
|
|
162
|
+
state["runtime_id"] = runtime
|
|
163
|
+
context.state = state
|
|
164
|
+
context.tenant = default_owner_resolver(context)
|
|
165
|
+
return context
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def build_a2a_task_store(
|
|
169
|
+
dsn: str | None = None,
|
|
170
|
+
*,
|
|
171
|
+
engine: Optional[AsyncEngine] = None,
|
|
172
|
+
table_name: str = A2A_TASK_TABLE,
|
|
173
|
+
owner_resolver: Optional[Callable[[ServerCallContext], str]] = None,
|
|
174
|
+
create_table: bool = True,
|
|
175
|
+
) -> DatabaseTaskStore:
|
|
176
|
+
"""构建 durable ``DatabaseTaskStore``。
|
|
177
|
+
|
|
178
|
+
参数:
|
|
179
|
+
dsn: 数据库 DSN(如 ``sqlite+aiosqlite:///path.db`` 或
|
|
180
|
+
``postgresql+asyncpg://...``)。与 ``engine`` 二选一。
|
|
181
|
+
engine: 已存在的 SQLAlchemy AsyncEngine(优先于 dsn)。
|
|
182
|
+
table_name: 隔离表名,默认 ``ksadk_a2a_tasks``。
|
|
183
|
+
owner_resolver: owner 解析器,默认 :func:`default_owner_resolver`。
|
|
184
|
+
create_table: 是否在 initialize 时建表(测试/本地默认 True;生产可 False
|
|
185
|
+
由迁移管理)。
|
|
186
|
+
"""
|
|
187
|
+
if engine is None:
|
|
188
|
+
if not dsn:
|
|
189
|
+
raise ValueError("build_a2a_task_store 需要 dsn 或 engine 之一")
|
|
190
|
+
engine = create_async_engine(dsn)
|
|
191
|
+
return _KsADKDatabaseTaskStore(
|
|
192
|
+
engine=engine,
|
|
193
|
+
create_table=create_table,
|
|
194
|
+
table_name=table_name,
|
|
195
|
+
owner_resolver=owner_resolver or default_owner_resolver,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
__all__ = [
|
|
200
|
+
"A2A_TASK_TABLE",
|
|
201
|
+
"A2AOwnerContextBuilder",
|
|
202
|
+
"DEFAULT_ACCOUNT_HEADERS",
|
|
203
|
+
"DEFAULT_RUNTIME_HEADERS",
|
|
204
|
+
"build_a2a_task_store",
|
|
205
|
+
"default_owner_resolver",
|
|
206
|
+
]
|
ksadk/a2ui/__init__.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""A2UI(Agent 驱动 UI)— canonical:docs/A2UI-agent驱动UI技术方案.md。"""
|
|
2
|
+
|
|
3
|
+
from ksadk.a2ui.core import A2UICore
|
|
4
|
+
from ksadk.a2ui.models import (
|
|
5
|
+
BASIC_CATALOG,
|
|
6
|
+
BASIC_CATALOG_ID,
|
|
7
|
+
A2UIValidationError,
|
|
8
|
+
ActionReceipt,
|
|
9
|
+
Component,
|
|
10
|
+
PendingInteraction,
|
|
11
|
+
Surface,
|
|
12
|
+
)
|
|
13
|
+
from ksadk.a2ui.renderer import A2UIRenderer, RenderedNode, submit_a2ui_action
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"A2UICore",
|
|
17
|
+
"A2UIRenderer",
|
|
18
|
+
"RenderedNode",
|
|
19
|
+
"submit_a2ui_action",
|
|
20
|
+
"A2UIValidationError",
|
|
21
|
+
"ActionReceipt",
|
|
22
|
+
"BASIC_CATALOG",
|
|
23
|
+
"BASIC_CATALOG_ID",
|
|
24
|
+
"Component",
|
|
25
|
+
"PendingInteraction",
|
|
26
|
+
"Surface",
|
|
27
|
+
]
|