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,223 @@
|
|
|
1
|
+
"""Detached streaming and per-app resource lifecycle."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import logging
|
|
7
|
+
from collections.abc import AsyncIterator, Mapping
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from fastapi import HTTPException
|
|
11
|
+
|
|
12
|
+
from ksadk.server.factory import get_state
|
|
13
|
+
|
|
14
|
+
from . import dependencies as deps
|
|
15
|
+
from .models import _RUN_TERMINAL_STATUSES
|
|
16
|
+
from .projection import _latest_invocation_status
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
_RESERVED_UI_PATHS = {"/", "/chat", "/build", "/deploy"}
|
|
21
|
+
_CUSTOM_API_PROXY_ENV_KEYS = ("KSADK_USER_BACKEND_URL", "LUOLUO_USER_BACKEND_URL")
|
|
22
|
+
_HOP_BY_HOP_HEADERS = {
|
|
23
|
+
"connection",
|
|
24
|
+
"keep-alive",
|
|
25
|
+
"proxy-authenticate",
|
|
26
|
+
"proxy-authorization",
|
|
27
|
+
"te",
|
|
28
|
+
"trailer",
|
|
29
|
+
"transfer-encoding",
|
|
30
|
+
"upgrade",
|
|
31
|
+
"host",
|
|
32
|
+
"content-length",
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class _DetachedSSEStream:
|
|
37
|
+
_MAX_BACKLOG_CHUNKS = 256
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
source: AsyncIterator[str],
|
|
42
|
+
*,
|
|
43
|
+
invocation_id: str | None = None,
|
|
44
|
+
session_id: str | None = None,
|
|
45
|
+
run_mode: str = "unknown",
|
|
46
|
+
run_trigger: str = "unknown",
|
|
47
|
+
):
|
|
48
|
+
self._source = source
|
|
49
|
+
self.invocation_id = invocation_id
|
|
50
|
+
self.session_id = session_id
|
|
51
|
+
self._run_mode = run_mode
|
|
52
|
+
self._run_trigger = run_trigger
|
|
53
|
+
self._subscribers: set[asyncio.Queue[str | None]] = set()
|
|
54
|
+
self._backlog: list[str] = []
|
|
55
|
+
self._done = False
|
|
56
|
+
# 后台 task 脱离请求上下文,创建时捕获 per-app registry(goal-01)。
|
|
57
|
+
self._registry = get_state().stream_registry
|
|
58
|
+
self._task = asyncio.create_task(self._consume())
|
|
59
|
+
self._registry.streams.add(self._task)
|
|
60
|
+
self._task.add_done_callback(self._registry.streams.discard)
|
|
61
|
+
if self.invocation_id:
|
|
62
|
+
self._registry.streams_by_invocation[self.invocation_id] = self
|
|
63
|
+
self._task.add_done_callback(
|
|
64
|
+
lambda _task: self._registry.streams_by_invocation.pop(
|
|
65
|
+
self.invocation_id or "", None
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
async def _has_terminal_run_status(self) -> bool:
|
|
70
|
+
if not self.session_id or not self.invocation_id:
|
|
71
|
+
return False
|
|
72
|
+
status = await _latest_invocation_status(
|
|
73
|
+
deps.resolve_session_service(),
|
|
74
|
+
self.session_id,
|
|
75
|
+
self.invocation_id,
|
|
76
|
+
)
|
|
77
|
+
return status in _RUN_TERMINAL_STATUSES
|
|
78
|
+
|
|
79
|
+
async def _consume(self) -> None:
|
|
80
|
+
terminal_fallback_status: str | None = None
|
|
81
|
+
try:
|
|
82
|
+
async for chunk in self._source:
|
|
83
|
+
self._backlog.append(chunk)
|
|
84
|
+
if len(self._backlog) > self._MAX_BACKLOG_CHUNKS:
|
|
85
|
+
self._backlog = self._backlog[-self._MAX_BACKLOG_CHUNKS :]
|
|
86
|
+
subscribers = list(self._subscribers)
|
|
87
|
+
if not subscribers:
|
|
88
|
+
continue
|
|
89
|
+
await asyncio.gather(
|
|
90
|
+
*(subscriber.put(chunk) for subscriber in subscribers),
|
|
91
|
+
return_exceptions=True,
|
|
92
|
+
)
|
|
93
|
+
except asyncio.CancelledError:
|
|
94
|
+
terminal_fallback_status = "cancelled"
|
|
95
|
+
raise
|
|
96
|
+
except Exception:
|
|
97
|
+
terminal_fallback_status = "failed"
|
|
98
|
+
logger.exception("Detached SSE stream failed")
|
|
99
|
+
raise
|
|
100
|
+
finally:
|
|
101
|
+
self._done = True
|
|
102
|
+
subscribers = list(self._subscribers)
|
|
103
|
+
if subscribers:
|
|
104
|
+
await asyncio.gather(
|
|
105
|
+
*(subscriber.put(None) for subscriber in subscribers),
|
|
106
|
+
return_exceptions=True,
|
|
107
|
+
)
|
|
108
|
+
if terminal_fallback_status and self.session_id:
|
|
109
|
+
try:
|
|
110
|
+
if not await self._has_terminal_run_status():
|
|
111
|
+
await deps.conversation().append_run_status_event(
|
|
112
|
+
session_id=self.session_id,
|
|
113
|
+
author="system",
|
|
114
|
+
status=terminal_fallback_status,
|
|
115
|
+
invocation_id=self.invocation_id or "",
|
|
116
|
+
detail=(
|
|
117
|
+
f"background_{terminal_fallback_status}:{self.invocation_id or ''}"
|
|
118
|
+
),
|
|
119
|
+
session_service_provider=deps.resolve_session_service,
|
|
120
|
+
run_mode=self._run_mode,
|
|
121
|
+
run_trigger=self._run_trigger,
|
|
122
|
+
)
|
|
123
|
+
except Exception:
|
|
124
|
+
logger.exception("failed to write background terminal status fallback")
|
|
125
|
+
|
|
126
|
+
def subscribe(self) -> asyncio.Queue[str | None]:
|
|
127
|
+
queue: asyncio.Queue[str | None] = asyncio.Queue()
|
|
128
|
+
for chunk in self._backlog:
|
|
129
|
+
queue.put_nowait(chunk)
|
|
130
|
+
if self._done:
|
|
131
|
+
queue.put_nowait(None)
|
|
132
|
+
else:
|
|
133
|
+
self._subscribers.add(queue)
|
|
134
|
+
return queue
|
|
135
|
+
|
|
136
|
+
def unsubscribe(self, queue: asyncio.Queue[str | None]) -> None:
|
|
137
|
+
self._subscribers.discard(queue)
|
|
138
|
+
|
|
139
|
+
def cancel(self) -> bool:
|
|
140
|
+
if self._task.done():
|
|
141
|
+
return False
|
|
142
|
+
return self._task.cancel()
|
|
143
|
+
|
|
144
|
+
async def iter_for_client(self) -> AsyncIterator[str]:
|
|
145
|
+
queue = self.subscribe()
|
|
146
|
+
try:
|
|
147
|
+
while True:
|
|
148
|
+
# 对 queue.get() 计时而不取消上游:cancel queue.get() 只影响本订阅者的等待,
|
|
149
|
+
# 不影响 _consume 后台 task;心跳直接发给当前客户端,不进 _backlog,
|
|
150
|
+
# 因此断线重连(SubscribeRunEvents)不会回放心跳帧。
|
|
151
|
+
try:
|
|
152
|
+
chunk = await asyncio.wait_for(
|
|
153
|
+
queue.get(),
|
|
154
|
+
timeout=deps.heartbeat_interval(),
|
|
155
|
+
)
|
|
156
|
+
except asyncio.TimeoutError:
|
|
157
|
+
yield ": ping\n\n"
|
|
158
|
+
continue
|
|
159
|
+
if chunk is None:
|
|
160
|
+
break
|
|
161
|
+
yield chunk
|
|
162
|
+
finally:
|
|
163
|
+
self.unsubscribe(queue)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
async def _cancel_detached_streams_for_session(session_id: str) -> None:
|
|
167
|
+
target_session_id = str(session_id or "").strip()
|
|
168
|
+
if not target_session_id:
|
|
169
|
+
return
|
|
170
|
+
registry = get_state().stream_registry
|
|
171
|
+
detached_streams = [
|
|
172
|
+
detached
|
|
173
|
+
for detached in list(registry.streams_by_invocation.values())
|
|
174
|
+
if detached.session_id == target_session_id
|
|
175
|
+
]
|
|
176
|
+
for detached in detached_streams:
|
|
177
|
+
detached.cancel()
|
|
178
|
+
if detached_streams:
|
|
179
|
+
await asyncio.gather(
|
|
180
|
+
*(detached._task for detached in detached_streams),
|
|
181
|
+
return_exceptions=True,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _clear_detached_resume_key(registry, invocation_id: str, resume_key: tuple[str, str]) -> None:
|
|
186
|
+
registry.resume_keys_by_invocation.pop(invocation_id, None)
|
|
187
|
+
if registry.active_resume_invocation_by_key.get(resume_key) == invocation_id:
|
|
188
|
+
registry.active_resume_invocation_by_key.pop(resume_key, None)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _detached_resume_key_from_input(
|
|
192
|
+
session_id: str | None,
|
|
193
|
+
resume_input: Mapping[str, Any] | None,
|
|
194
|
+
) -> tuple[str, str] | None:
|
|
195
|
+
if not isinstance(resume_input, Mapping):
|
|
196
|
+
return None
|
|
197
|
+
if str(resume_input.get("type") or "").strip() != "agentengine.resume_checkpoint":
|
|
198
|
+
return None
|
|
199
|
+
normalized_session_id = str(session_id or "").strip()
|
|
200
|
+
run_id = str(resume_input.get("run_id") or "").strip()
|
|
201
|
+
if not normalized_session_id or not run_id:
|
|
202
|
+
return None
|
|
203
|
+
return normalized_session_id, run_id
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _reject_if_detached_resume_active(resume_key: tuple[str, str] | None) -> None:
|
|
207
|
+
if resume_key is None:
|
|
208
|
+
return
|
|
209
|
+
active_resume_invocation_id = get_state().stream_registry.active_resume_invocation_by_key.get(
|
|
210
|
+
resume_key
|
|
211
|
+
)
|
|
212
|
+
if not active_resume_invocation_id:
|
|
213
|
+
return
|
|
214
|
+
raise HTTPException(
|
|
215
|
+
status_code=409,
|
|
216
|
+
detail={
|
|
217
|
+
"code": "resume_already_running",
|
|
218
|
+
"message": "A checkpoint resume is already running for this session and run.",
|
|
219
|
+
"invocation_id": active_resume_invocation_id,
|
|
220
|
+
"session_id": resume_key[0],
|
|
221
|
+
"run_id": resume_key[1],
|
|
222
|
+
},
|
|
223
|
+
)
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
"""Workspace, attachment upload, model catalog, and cancel routes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import io
|
|
6
|
+
import logging
|
|
7
|
+
import uuid
|
|
8
|
+
import zipfile
|
|
9
|
+
from pathlib import PurePosixPath
|
|
10
|
+
from typing import Any, Optional
|
|
11
|
+
from urllib.parse import quote
|
|
12
|
+
|
|
13
|
+
from fastapi import File, Form, HTTPException, Query, Request, UploadFile
|
|
14
|
+
from fastapi.responses import Response, StreamingResponse
|
|
15
|
+
from pydantic import BaseModel
|
|
16
|
+
|
|
17
|
+
from ksadk.conversations.attachment_storage import AttachmentStorageService
|
|
18
|
+
from ksadk.conversations.model_context import normalize_model_metadata
|
|
19
|
+
from ksadk.server.factory import get_state
|
|
20
|
+
from ksadk_runtime_common.workspace_files.preview import (
|
|
21
|
+
build_workspace_file_base_href,
|
|
22
|
+
build_workspace_preview_csp,
|
|
23
|
+
inject_workspace_html_preview,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
from . import dependencies as deps
|
|
27
|
+
from .common import (
|
|
28
|
+
_action_response,
|
|
29
|
+
_resolve_active_runner,
|
|
30
|
+
_resolve_current_model,
|
|
31
|
+
_workspace_root_dir,
|
|
32
|
+
_workspace_runtime_request,
|
|
33
|
+
)
|
|
34
|
+
from .models import (
|
|
35
|
+
CancelRunActionRequest,
|
|
36
|
+
WorkspaceDeleteActionRequest,
|
|
37
|
+
WorkspaceListActionRequest,
|
|
38
|
+
)
|
|
39
|
+
from .projection import (
|
|
40
|
+
_agent_contains_invocation,
|
|
41
|
+
_require_action_session,
|
|
42
|
+
_session_contains_invocation,
|
|
43
|
+
)
|
|
44
|
+
from .routers import control_router, workspace_router
|
|
45
|
+
|
|
46
|
+
logger = logging.getLogger(__name__)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@workspace_router.post("/agentengine/api/v1/UploadFile")
|
|
50
|
+
async def upload_file_action(file: UploadFile = File(...)):
|
|
51
|
+
file_id = uuid.uuid4().hex
|
|
52
|
+
data = await file.read()
|
|
53
|
+
file_uri, _local_path = await AttachmentStorageService().store(
|
|
54
|
+
data=data,
|
|
55
|
+
file_id=file_id,
|
|
56
|
+
display_name=file.filename,
|
|
57
|
+
mime_type=file.content_type,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
return _action_response(
|
|
61
|
+
"UploadFile",
|
|
62
|
+
{
|
|
63
|
+
"FileData": {
|
|
64
|
+
"fileUri": file_uri,
|
|
65
|
+
"displayName": file.filename or "uploaded_file",
|
|
66
|
+
"mimeType": file.content_type or "application/octet-stream",
|
|
67
|
+
"sizeBytes": len(data),
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@workspace_router.get("/agentengine/api/v1/AttachmentContent", include_in_schema=False)
|
|
74
|
+
async def attachment_content_action(FileUri: str = Query(...)):
|
|
75
|
+
loaded = AttachmentStorageService().read(FileUri)
|
|
76
|
+
if loaded is None:
|
|
77
|
+
raise HTTPException(status_code=404, detail="Attachment not found")
|
|
78
|
+
|
|
79
|
+
return Response(
|
|
80
|
+
content=loaded.data,
|
|
81
|
+
media_type=loaded.mime_type or "application/octet-stream",
|
|
82
|
+
headers={"Content-Disposition": f'inline; filename="{loaded.display_name}"'},
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@workspace_router.post("/agentengine/api/v1/ListWorkspaceFiles")
|
|
87
|
+
async def list_workspace_files_action(request: WorkspaceListActionRequest):
|
|
88
|
+
response = await _workspace_runtime_request(
|
|
89
|
+
"GET",
|
|
90
|
+
"/_ksadk/workspace/v1/entries",
|
|
91
|
+
params={
|
|
92
|
+
"path": request.Path,
|
|
93
|
+
"recursive": "true" if request.Recursive else "false",
|
|
94
|
+
},
|
|
95
|
+
)
|
|
96
|
+
return _action_response("ListWorkspaceFiles", response.json())
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@workspace_router.post("/agentengine/api/v1/AddWorkspaceFile")
|
|
100
|
+
async def upload_workspace_file_action(
|
|
101
|
+
file: UploadFile = File(...),
|
|
102
|
+
AgentId: Optional[str] = Form(None),
|
|
103
|
+
Path: str = Form(...),
|
|
104
|
+
):
|
|
105
|
+
del AgentId
|
|
106
|
+
try:
|
|
107
|
+
payload = await file.read()
|
|
108
|
+
finally:
|
|
109
|
+
await file.close()
|
|
110
|
+
|
|
111
|
+
file_name = file.filename or Path.rsplit("/", 1)[-1]
|
|
112
|
+
response = await _workspace_runtime_request(
|
|
113
|
+
"POST",
|
|
114
|
+
f"/_ksadk/workspace/v1/files/{quote(Path, safe='/')}",
|
|
115
|
+
files={
|
|
116
|
+
"file": (
|
|
117
|
+
file_name,
|
|
118
|
+
payload,
|
|
119
|
+
file.content_type or "application/octet-stream",
|
|
120
|
+
)
|
|
121
|
+
},
|
|
122
|
+
)
|
|
123
|
+
return _action_response("AddWorkspaceFile", response.json())
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@workspace_router.post("/agentengine/api/v1/DeleteWorkspaceFile")
|
|
127
|
+
async def delete_workspace_file_action(request: WorkspaceDeleteActionRequest):
|
|
128
|
+
response = await _workspace_runtime_request(
|
|
129
|
+
"DELETE",
|
|
130
|
+
f"/_ksadk/workspace/v1/files/{quote(request.Path, safe='/')}",
|
|
131
|
+
)
|
|
132
|
+
return _action_response("DeleteWorkspaceFile", response.json())
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@control_router.post("/agentengine/api/v1/CancelRun")
|
|
136
|
+
async def cancel_run_action(request: CancelRunActionRequest):
|
|
137
|
+
detached = get_state().stream_registry.streams_by_invocation.get(request.InvocationId)
|
|
138
|
+
service = deps.resolve_session_service()
|
|
139
|
+
scoped_session_id = str(request.SessionId or "").strip()
|
|
140
|
+
detached_session_id = str(detached.session_id or "").strip() if detached is not None else ""
|
|
141
|
+
if scoped_session_id and detached_session_id and scoped_session_id != detached_session_id:
|
|
142
|
+
raise HTTPException(
|
|
143
|
+
status_code=409,
|
|
144
|
+
detail="InvocationId does not belong to SessionId",
|
|
145
|
+
)
|
|
146
|
+
if not scoped_session_id and detached is not None:
|
|
147
|
+
scoped_session_id = detached_session_id
|
|
148
|
+
if scoped_session_id:
|
|
149
|
+
await _require_action_session(
|
|
150
|
+
service,
|
|
151
|
+
session_id=scoped_session_id,
|
|
152
|
+
agent_id=request.AgentId,
|
|
153
|
+
user_id=request.UserId,
|
|
154
|
+
)
|
|
155
|
+
if detached is None and not await _session_contains_invocation(
|
|
156
|
+
service,
|
|
157
|
+
scoped_session_id,
|
|
158
|
+
request.InvocationId,
|
|
159
|
+
):
|
|
160
|
+
raise HTTPException(
|
|
161
|
+
status_code=409,
|
|
162
|
+
detail="InvocationId does not belong to SessionId",
|
|
163
|
+
)
|
|
164
|
+
elif request.UserId:
|
|
165
|
+
if not request.AgentId:
|
|
166
|
+
raise HTTPException(status_code=400, detail="AgentId is required with UserId")
|
|
167
|
+
if not await _agent_contains_invocation(
|
|
168
|
+
service,
|
|
169
|
+
request.AgentId,
|
|
170
|
+
request.InvocationId,
|
|
171
|
+
user_id=request.UserId,
|
|
172
|
+
):
|
|
173
|
+
raise HTTPException(status_code=404, detail="Invocation not found")
|
|
174
|
+
found = detached is not None
|
|
175
|
+
cancel_requested = False
|
|
176
|
+
if detached is not None:
|
|
177
|
+
cancel_requested = detached.cancel()
|
|
178
|
+
runner_cancel_status = "not_found" if found else "unsupported"
|
|
179
|
+
active_runner = _resolve_active_runner()
|
|
180
|
+
if active_runner is not None:
|
|
181
|
+
try:
|
|
182
|
+
runner_result = active_runner.request_cancel(request.InvocationId)
|
|
183
|
+
if isinstance(runner_result, str) and runner_result:
|
|
184
|
+
runner_cancel_status = runner_result
|
|
185
|
+
elif runner_result is True:
|
|
186
|
+
runner_cancel_status = "accepted"
|
|
187
|
+
elif runner_result is False and not found:
|
|
188
|
+
runner_cancel_status = "not_found"
|
|
189
|
+
except Exception as exc:
|
|
190
|
+
runner_cancel_status = "error"
|
|
191
|
+
logger.warning("CancelRun failed: %s", exc)
|
|
192
|
+
runner_accepted = runner_cancel_status in {"accepted", "cancelling", "cancelled"}
|
|
193
|
+
status = "cancelling" if found or runner_accepted else runner_cancel_status
|
|
194
|
+
return _action_response(
|
|
195
|
+
"CancelRun",
|
|
196
|
+
{
|
|
197
|
+
"Cancelled": bool(cancel_requested or runner_accepted),
|
|
198
|
+
"Found": found,
|
|
199
|
+
"Status": status,
|
|
200
|
+
"RunnerCancelStatus": runner_cancel_status,
|
|
201
|
+
},
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@workspace_router.get("/agentengine/api/v1/GetWorkspaceFileContent", include_in_schema=False)
|
|
206
|
+
async def get_workspace_file_content_action(
|
|
207
|
+
FilePath: str = Query(...),
|
|
208
|
+
AgentId: Optional[str] = Query(None),
|
|
209
|
+
):
|
|
210
|
+
del AgentId
|
|
211
|
+
response = await _workspace_runtime_request(
|
|
212
|
+
"GET",
|
|
213
|
+
f"/_ksadk/workspace/v1/files/{quote(FilePath, safe='/')}",
|
|
214
|
+
)
|
|
215
|
+
headers = {}
|
|
216
|
+
for key in ("content-disposition", "last-modified"):
|
|
217
|
+
value = response.headers.get(key)
|
|
218
|
+
if value:
|
|
219
|
+
headers[key] = value
|
|
220
|
+
return Response(
|
|
221
|
+
content=response.content,
|
|
222
|
+
status_code=response.status_code,
|
|
223
|
+
headers=headers,
|
|
224
|
+
media_type=response.headers.get("content-type"),
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
@workspace_router.get("/agentengine/api/v1/ws/{agent_id}/{file_path:path}", include_in_schema=False)
|
|
229
|
+
async def workspace_file_path_route(request: Request, agent_id: str, file_path: str):
|
|
230
|
+
response = await _workspace_runtime_request(
|
|
231
|
+
"GET",
|
|
232
|
+
f"/_ksadk/workspace/v1/files/{quote(file_path, safe='/')}",
|
|
233
|
+
)
|
|
234
|
+
headers = {}
|
|
235
|
+
for key in ("content-disposition", "last-modified"):
|
|
236
|
+
value = response.headers.get(key)
|
|
237
|
+
if value:
|
|
238
|
+
headers[key] = value
|
|
239
|
+
|
|
240
|
+
content_type = response.headers.get("content-type", "")
|
|
241
|
+
is_html = "text/html" in content_type or file_path.lower().endswith((".html", ".htm"))
|
|
242
|
+
|
|
243
|
+
if is_html and response.status_code == 200:
|
|
244
|
+
del agent_id
|
|
245
|
+
base_href = build_workspace_file_base_href(file_path)
|
|
246
|
+
asset_source = f"{request.url.scheme}://{request.url.netloc}{base_href}"
|
|
247
|
+
html_doc = response.content.decode("utf-8", errors="replace")
|
|
248
|
+
html_doc = inject_workspace_html_preview(html_doc, file_path)
|
|
249
|
+
headers.pop("content-disposition", None)
|
|
250
|
+
headers["Content-Security-Policy"] = build_workspace_preview_csp(asset_source)
|
|
251
|
+
return Response(
|
|
252
|
+
content=html_doc.encode("utf-8"),
|
|
253
|
+
status_code=response.status_code,
|
|
254
|
+
headers=headers,
|
|
255
|
+
media_type="text/html; charset=utf-8",
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
return Response(
|
|
259
|
+
content=response.content,
|
|
260
|
+
status_code=response.status_code,
|
|
261
|
+
headers=headers,
|
|
262
|
+
media_type=content_type,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@workspace_router.get("/agentengine/api/v1/ExportWorkspaceZip", include_in_schema=False)
|
|
267
|
+
async def export_workspace_zip(
|
|
268
|
+
AgentId: Optional[str] = Query(None),
|
|
269
|
+
Path: str = Query("."),
|
|
270
|
+
):
|
|
271
|
+
del AgentId
|
|
272
|
+
dir_path = Path.strip() or "."
|
|
273
|
+
response = await _workspace_runtime_request(
|
|
274
|
+
"GET",
|
|
275
|
+
"/_ksadk/workspace/v1/entries",
|
|
276
|
+
params={"path": dir_path, "recursive": "true"},
|
|
277
|
+
)
|
|
278
|
+
data = response.json() if response.status_code == 200 else {}
|
|
279
|
+
entries = data.get("Entries", []) if isinstance(data, dict) else []
|
|
280
|
+
root = _workspace_root_dir()
|
|
281
|
+
root_resolved = root.resolve()
|
|
282
|
+
buf = io.BytesIO()
|
|
283
|
+
with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf:
|
|
284
|
+
for entry in entries:
|
|
285
|
+
if entry.get("Type") != "file":
|
|
286
|
+
continue
|
|
287
|
+
rel = entry.get("Path", "")
|
|
288
|
+
if not rel:
|
|
289
|
+
continue
|
|
290
|
+
rel_path = PurePosixPath(rel)
|
|
291
|
+
if rel_path.is_absolute() or ".." in rel_path.parts:
|
|
292
|
+
continue
|
|
293
|
+
target = root.joinpath(*rel_path.parts)
|
|
294
|
+
if target.is_symlink():
|
|
295
|
+
continue
|
|
296
|
+
try:
|
|
297
|
+
resolved_target = target.resolve(strict=True)
|
|
298
|
+
except OSError:
|
|
299
|
+
continue
|
|
300
|
+
if not resolved_target.is_relative_to(root_resolved):
|
|
301
|
+
continue
|
|
302
|
+
if resolved_target.is_file():
|
|
303
|
+
zf.writestr(rel_path.as_posix(), resolved_target.read_bytes())
|
|
304
|
+
buf.seek(0)
|
|
305
|
+
zip_name = f"workspace-{dir_path.replace('/', '-')}.zip" if dir_path != "." else "workspace.zip"
|
|
306
|
+
return StreamingResponse(
|
|
307
|
+
buf,
|
|
308
|
+
media_type="application/zip",
|
|
309
|
+
headers={"Content-Disposition": f'attachment; filename="{zip_name}"'},
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def _normalize_model_catalog_items(raw_models: list[Any]) -> list[dict[str, Any]]:
|
|
314
|
+
"""统一模型目录 shape,并按 id 去重。
|
|
315
|
+
|
|
316
|
+
这里刻意保留上游原始 dict 字段,再补 canonical metadata。
|
|
317
|
+
这样两周后模型服务扩展字段时,这一层不会再次把信息裁掉。
|
|
318
|
+
"""
|
|
319
|
+
|
|
320
|
+
normalized_by_id: dict[str, dict[str, Any]] = {}
|
|
321
|
+
for raw_model in raw_models:
|
|
322
|
+
item = normalize_model_metadata(raw_model)
|
|
323
|
+
normalized_by_id[item["id"]] = item
|
|
324
|
+
return sorted(normalized_by_id.values(), key=lambda item: item["id"])
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
async def _build_models_payload() -> dict[str, Any]:
|
|
328
|
+
import os
|
|
329
|
+
|
|
330
|
+
import httpx
|
|
331
|
+
|
|
332
|
+
api_base = os.getenv("OPENAI_BASE_URL") or os.getenv("OPENAI_API_BASE")
|
|
333
|
+
api_key = os.getenv("OPENAI_API_KEY")
|
|
334
|
+
current_model, source = _resolve_current_model()
|
|
335
|
+
|
|
336
|
+
def _fallback_catalog() -> dict[str, Any]:
|
|
337
|
+
models = _normalize_model_catalog_items([current_model]) if current_model else []
|
|
338
|
+
return {
|
|
339
|
+
"data": models,
|
|
340
|
+
"current": current_model,
|
|
341
|
+
"source": source,
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if not api_base:
|
|
345
|
+
return _fallback_catalog()
|
|
346
|
+
|
|
347
|
+
try:
|
|
348
|
+
base_url = api_base.rstrip("/")
|
|
349
|
+
if base_url.endswith("/v1"):
|
|
350
|
+
url = f"{base_url}/models"
|
|
351
|
+
else:
|
|
352
|
+
url = f"{base_url}/v1/models"
|
|
353
|
+
|
|
354
|
+
headers = {}
|
|
355
|
+
if api_key:
|
|
356
|
+
headers["Authorization"] = f"Bearer {api_key}"
|
|
357
|
+
|
|
358
|
+
async with httpx.AsyncClient(verify=False, timeout=10) as client:
|
|
359
|
+
resp = await client.get(url, headers=headers)
|
|
360
|
+
resp.raise_for_status()
|
|
361
|
+
data = resp.json()
|
|
362
|
+
|
|
363
|
+
if isinstance(data, list):
|
|
364
|
+
models = _normalize_model_catalog_items(list(data))
|
|
365
|
+
else:
|
|
366
|
+
models = _normalize_model_catalog_items(list(data.get("data", [])))
|
|
367
|
+
if current_model and all(
|
|
368
|
+
str(item.get("id") or "").strip() != current_model for item in models
|
|
369
|
+
):
|
|
370
|
+
models = _normalize_model_catalog_items([*models, current_model])
|
|
371
|
+
return {"data": models, "current": current_model, "source": source}
|
|
372
|
+
except Exception as e:
|
|
373
|
+
logger.error(f"Failed to fetch models: {e}")
|
|
374
|
+
fallback = _fallback_catalog()
|
|
375
|
+
fallback["error"] = str(e)
|
|
376
|
+
return fallback
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
class ListAgentModelsRequest(BaseModel):
|
|
380
|
+
AgentId: Optional[str] = None
|
|
381
|
+
Name: Optional[str] = None
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{bt as e,
|
|
1
|
+
import{bt as e,ht as t,lt as n,n as r,t as i,ut as a,wt as o,xt as s,yt as c}from"./index-QSwCHuB8.js";var l=o(s(),1),u=c();function d(){let o=e(e=>e.visible),s=e(e=>e.content),c=e(e=>e.type),d=e(e=>e.hide),f=(0,l.useRef)(null);if(r(f),!o||!s)return null;let p=i(s);return(0,u.jsxs)(`aside`,{className:n(`flex h-full flex-shrink-0 flex-col border-l border-slate-200/30 bg-white dark:border-slate-800/40 dark:bg-slate-950`,`w-[min(42rem,50vw)]`),children:[(0,u.jsxs)(`div`,{className:`flex h-14 flex-shrink-0 items-center justify-between border-b border-slate-200/30 px-4 dark:border-slate-800/40`,children:[(0,u.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,u.jsx)(`span`,{className:`text-sm font-semibold text-slate-900 dark:text-slate-100`,children:`Artifact`}),(0,u.jsx)(`span`,{className:`rounded-md bg-slate-100 px-1.5 py-0.5 font-mono text-[11px] text-slate-500 dark:bg-slate-900 dark:text-slate-400`,children:c})]}),(0,u.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,u.jsxs)(`button`,{type:`button`,onClick:()=>{let e=new Blob([s],{type:`text/html;charset=utf-8`}),t=URL.createObjectURL(e),n=document.createElement(`a`);n.href=t,n.download=`artifact.${c===`svg`?`svg`:`html`}`,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(t)},className:`inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium text-slate-600 transition hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-900`,title:`Download`,children:[(0,u.jsx)(t,{className:`h-3.5 w-3.5`}),`Download`]}),(0,u.jsx)(`button`,{type:`button`,onClick:d,className:`rounded-lg p-1.5 text-slate-500 transition hover:bg-slate-100 hover:text-slate-900 dark:text-slate-400 dark:hover:bg-slate-900 dark:hover:text-slate-100`,"aria-label":`Close Artifact`,title:`Close`,children:(0,u.jsx)(a,{className:`h-4 w-4`})})]})]}),(0,u.jsx)(`div`,{className:`min-h-0 flex-1`,children:(0,u.jsx)(`iframe`,{ref:f,srcDoc:p,sandbox:`allow-scripts allow-downloads`,title:`Artifact Preview`,className:`h-full w-full border-0 bg-white`})})]})}export{d as ArtifactsPanel};
|