agentengine-sdk-python 0.7.0__py3-none-any.whl → 0.8.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/METADATA +52 -20
- agentengine_sdk_python-0.8.1.dist-info/RECORD +644 -0
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/WHEEL +1 -1
- ksadk/a2a/__init__.py +180 -11
- ksadk/a2a/bootstrap.py +332 -0
- ksadk/a2a/card.py +15 -0
- ksadk/a2a/context_store.py +203 -0
- ksadk/a2a/control_plane.py +1056 -0
- ksadk/a2a/credential.py +99 -0
- ksadk/a2a/event_adapter.py +149 -0
- ksadk/a2a/executor.py +361 -137
- ksadk/a2a/external_transport.py +516 -0
- ksadk/a2a/identity.py +304 -0
- ksadk/a2a/ids.py +22 -0
- ksadk/a2a/langgraph.py +285 -0
- ksadk/a2a/resume_store.py +201 -0
- ksadk/a2a/routes.py +112 -0
- ksadk/a2a/server.py +102 -62
- ksadk/a2a/service_env.py +33 -0
- ksadk/a2a/space_client.py +1122 -0
- ksadk/a2a/task_adapter.py +423 -0
- ksadk/a2a/task_event_dispatcher.py +167 -0
- ksadk/a2a/task_event_outbox.py +326 -0
- ksadk/a2a/task_store.py +206 -0
- ksadk/a2a_card.py +101 -0
- ksadk/a2ui/__init__.py +27 -0
- ksadk/a2ui/core.py +186 -0
- ksadk/a2ui/models.py +166 -0
- ksadk/a2ui/renderer.py +198 -0
- ksadk/agui/__init__.py +9 -0
- ksadk/agui/a2ui_projection.py +92 -0
- ksadk/agui/agent.py +872 -0
- ksadk/agui/config.py +92 -0
- ksadk/agui/routes.py +47 -0
- ksadk/api/client.py +238 -204
- ksadk/api/environment.py +27 -0
- ksadk/builders/__init__.py +2 -0
- ksadk/builders/base.py +16 -14
- ksadk/builders/code_builder.py +375 -270
- ksadk/builders/container_builder.py +240 -200
- ksadk/builders/framework_requirements.py +31 -12
- ksadk/builders/ks3_uploader.py +60 -29
- ksadk/builders/managed_runtime_builder.py +173 -0
- ksadk/builders/mcp_builder.py +91 -92
- ksadk/builders/requirements_utils.py +1 -5
- ksadk/cli/__init__.py +97 -171
- ksadk/cli/cmd_a2a.py +255 -84
- ksadk/cli/cmd_agent.py +19 -5
- ksadk/cli/cmd_build.py +158 -29
- ksadk/cli/cmd_completion.py +47 -35
- ksadk/cli/cmd_config.py +267 -198
- ksadk/cli/cmd_create.py +507 -740
- ksadk/cli/cmd_dashboard.py +120 -45
- ksadk/cli/cmd_deploy.py +135 -59
- ksadk/cli/cmd_destroy.py +44 -14
- ksadk/cli/cmd_eval.py +386 -0
- ksadk/cli/cmd_files.py +63 -24
- ksadk/cli/cmd_hermes.py +313 -135
- ksadk/cli/cmd_invoke.py +184 -122
- ksadk/cli/cmd_launch.py +76 -28
- ksadk/cli/cmd_mcp.py +98 -64
- ksadk/cli/cmd_model.py +14 -5
- ksadk/cli/cmd_openclaw.py +564 -268
- ksadk/cli/cmd_replay.py +71 -0
- ksadk/cli/cmd_run.py +58 -73
- ksadk/cli/cmd_status.py +80 -31
- ksadk/cli/cmd_studio.py +110 -0
- ksadk/cli/cmd_version.py +20 -13
- ksadk/cli/cmd_web.py +95 -18
- ksadk/cli/deploy_utils.py +20 -20
- ksadk/cli/dry_run.py +7 -4
- ksadk/cli/env_options.py +83 -0
- ksadk/cli/error_utils.py +37 -12
- ksadk/cli/global_options.py +4 -3
- ksadk/cli/local_runtime.py +1 -2
- ksadk/cli/model_catalog.py +6 -2
- ksadk/cli/network_options.py +41 -19
- ksadk/cli/resource_common.py +6 -2
- ksadk/cli/runtime_bootstrap.py +51 -0
- ksadk/cli/storage.py +0 -1
- ksadk/cli/ui.py +11 -3
- ksadk/cli/workflow_common.py +52 -18
- ksadk/codex/__init__.py +12 -0
- ksadk/codex/client.py +1042 -0
- ksadk/codex/phase.py +143 -0
- ksadk/codex/runtime.py +940 -0
- ksadk/common/aicp_env.py +0 -1
- ksadk/common/auth.py +2 -2
- ksadk/common/constants.py +1 -3
- ksadk/common/kop_client.py +232 -0
- ksadk/common/llm_utils.py +17 -13
- ksadk/compat/__init__.py +5 -0
- ksadk/compat/adk_compat.py +200 -0
- ksadk/compat/copilotkit_a2ui.py +330 -0
- ksadk/configs/__init__.py +12 -14
- ksadk/configs/env_registry.py +661 -116
- ksadk/configs/global_config.py +3 -2
- ksadk/configs/settings.py +133 -209
- ksadk/conversations/__init__.py +85 -92
- ksadk/conversations/attachment_storage.py +16 -11
- ksadk/conversations/attachments.py +44 -36
- ksadk/conversations/compaction_pipeline.py +12 -12
- ksadk/conversations/compaction_prompt.py +9 -5
- ksadk/conversations/context.py +221 -6
- ksadk/conversations/message_projection.py +438 -51
- ksadk/conversations/model_context.py +12 -6
- ksadk/conversations/model_options.py +0 -1
- ksadk/conversations/normalize.py +20 -16
- ksadk/conversations/reasoning_markup.py +1 -1
- ksadk/conversations/runtime.py +339 -5255
- ksadk/conversations/runtime_compaction.py +333 -0
- ksadk/conversations/runtime_constants.py +27 -0
- ksadk/conversations/runtime_governance.py +185 -0
- ksadk/conversations/runtime_input.py +660 -0
- ksadk/conversations/runtime_invocation.py +395 -0
- ksadk/conversations/runtime_metadata.py +475 -0
- ksadk/conversations/runtime_observability.py +367 -0
- ksadk/conversations/runtime_payloads.py +272 -0
- ksadk/conversations/runtime_persistence.py +440 -0
- ksadk/conversations/runtime_preparation.py +426 -0
- ksadk/conversations/runtime_resume.py +836 -0
- ksadk/conversations/runtime_stream_events.py +902 -0
- ksadk/conversations/runtime_streaming.py +700 -0
- ksadk/conversations/semantic_summary.py +17 -5
- ksadk/conversations/session_title.py +6 -3
- ksadk/deployment/__init__.py +15 -16
- ksadk/deployment/agent_access.py +12 -23
- ksadk/deployment/base.py +51 -38
- ksadk/deployment/managed_runtime.py +33 -0
- ksadk/deployment/manager.py +85 -71
- ksadk/deployment/providers/serverless.py +379 -210
- ksadk/deployment/registry.py +38 -32
- ksadk/deployment/state.py +11 -11
- ksadk/deployment/ui_config.py +1 -1
- ksadk/detection/__init__.py +1 -1
- ksadk/detection/detector.py +146 -83
- ksadk/detection/mcp_detector.py +9 -6
- ksadk/evaluation/__init__.py +84 -0
- ksadk/evaluation/a2a_adapter.py +444 -0
- ksadk/evaluation/adapters.py +54 -0
- ksadk/evaluation/contracts.py +409 -0
- ksadk/evaluation/evalset.py +351 -0
- ksadk/evaluation/evaluators.py +461 -0
- ksadk/evaluation/executor.py +118 -0
- ksadk/evaluation/storage.py +68 -0
- ksadk/evaluation/target.py +73 -0
- ksadk/events/__init__.py +25 -0
- ksadk/events/parser.py +191 -0
- ksadk/events/replay.py +37 -0
- ksadk/events/runtime_event.py +273 -0
- ksadk/events/store.py +317 -0
- ksadk/harness/__init__.py +35 -0
- ksadk/harness/app.py +269 -0
- ksadk/harness/config.py +181 -0
- ksadk/harness/reasoner.py +105 -0
- ksadk/harness/runtime.py +364 -0
- ksadk/harness/sandbox.py +141 -0
- ksadk/harness/tools.py +222 -0
- ksadk/hermes_terminal.py +28 -12
- ksadk/identity/resolver.py +15 -9
- ksadk/ids.py +32 -0
- ksadk/knowledge_base/adk_tool.py +1 -1
- ksadk/knowledge_base/client.py +38 -33
- ksadk/managed_a2a_card.py +160 -0
- ksadk/managed_runtime.py +195 -0
- ksadk/markdown.py +5 -2
- ksadk/mcp_runtime/__init__.py +9 -6
- ksadk/memory/__init__.py +1 -1
- ksadk/memory/adk/__init__.py +2 -0
- ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
- ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
- ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
- ksadk/memory/adk/backends/sdk_ltm_backend.py +36 -36
- ksadk/memory/adk/long_term_memory.py +34 -37
- ksadk/memory/adk/resilient_session_service.py +4 -5
- ksadk/memory/adk/short_term_memory.py +12 -21
- ksadk/memory/adk_tool.py +3 -2
- ksadk/memory/backends/base.py +19 -19
- ksadk/memory/backends/memory.py +24 -25
- ksadk/memory/backends/redis.py +31 -30
- ksadk/memory/langchain_tool.py +2 -1
- ksadk/memory/manager.py +52 -47
- ksadk/memory/service.py +16 -6
- ksadk/memory/tool.py +4 -0
- ksadk/model_policy.py +15 -7
- ksadk/model_proxy/__init__.py +51 -0
- ksadk/model_proxy/bootstrap.py +80 -0
- ksadk/model_proxy/cache.py +165 -0
- ksadk/model_proxy/config.py +66 -0
- ksadk/model_proxy/demo_webui.py +115 -0
- ksadk/model_proxy/detect.py +145 -0
- ksadk/model_proxy/gate.py +68 -0
- ksadk/model_proxy/namespace.py +201 -0
- ksadk/model_proxy/protocol_proxy.py +22 -0
- ksadk/model_proxy/server.py +443 -0
- ksadk/model_proxy/transform.py +735 -0
- ksadk/openclaw_gateway.py +29 -14
- ksadk/runners/adk_runner.py +354 -146
- ksadk/runners/base_runner.py +71 -29
- ksadk/runners/deepagents_runner.py +0 -1
- ksadk/runners/factory.py +18 -5
- ksadk/runners/langchain_runner.py +29 -742
- ksadk/runners/langgraph_runner.py +417 -97
- ksadk/runners/patch_langchain.py +16 -16
- ksadk/runners/remote_runner.py +134 -33
- ksadk/runners/usage_accumulator.py +1 -0
- ksadk/runners/utils/__init__.py +0 -10
- ksadk/runners/utils/loader.py +23 -7
- ksadk/runtime/__init__.py +67 -0
- ksadk/runtime/adapter.py +412 -0
- ksadk/runtime/conversation_execution.py +553 -0
- ksadk/runtime/executor.py +251 -0
- ksadk/runtime/factory.py +156 -0
- ksadk/runtime/framework_adapters.py +118 -0
- ksadk/runtime/launch.py +48 -0
- ksadk/runtime/preprocessing.py +131 -0
- ksadk/runtime/runner_adapter.py +1032 -0
- ksadk/runtime/runner_loading.py +36 -0
- ksadk/runtime_context.py +18 -3
- ksadk/runtime_state.py +0 -1
- ksadk/sandbox/__init__.py +4 -1
- ksadk/sandbox/backends/__init__.py +4 -1
- ksadk/sandbox/backends/e2b.py +13 -5
- ksadk/sandbox/backends/local_process.py +11 -3
- ksadk/sandbox/base.py +10 -15
- ksadk/sandbox/factory.py +14 -4
- ksadk/sandbox/registry.py +57 -6
- ksadk/server/__init__.py +39 -4
- ksadk/server/api_models.py +15 -5
- ksadk/server/app.py +24 -3928
- ksadk/server/composition.py +47 -0
- ksadk/server/factory.py +622 -0
- ksadk/server/routes/__init__.py +1 -0
- ksadk/server/routes/checkpoint_resolution.py +116 -0
- ksadk/server/routes/common.py +682 -0
- ksadk/server/routes/control.py +331 -0
- ksadk/server/routes/dependencies.py +98 -0
- ksadk/server/routes/misc.py +425 -0
- ksadk/server/routes/models.py +451 -0
- ksadk/server/routes/openai_compat.py +229 -0
- ksadk/server/routes/projection.py +848 -0
- ksadk/server/routes/routers.py +52 -0
- ksadk/server/routes/run.py +519 -0
- ksadk/server/routes/sessions.py +644 -0
- ksadk/server/routes/streaming.py +265 -0
- ksadk/server/routes/workspace.py +414 -0
- ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-CakCqxEN.js} +1 -1
- ksadk/server/static/assets/CodeBlock-CynLknyO.js +9 -0
- ksadk/server/static/assets/MathMessageMarkdown-3sQdOysS.js +8 -0
- ksadk/server/static/assets/MermaidBlock-NERD_ef7.js +303 -0
- ksadk/server/static/assets/NativeTerminalPanel-CiHWf82q.js +1 -0
- ksadk/server/static/assets/{arc-BA13sHc9.js → arc-DrgjcKhl.js} +1 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-CpZLRCcY.js +1 -0
- ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-BXoVRbQ6.js} +1 -1
- ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-BnaB3Ywv.js} +1 -1
- ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-Dw4weZcp.js} +1 -1
- ksadk/server/static/assets/channel-Dt3rQTFI.js +1 -0
- ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-ChjpLK7j.js} +1 -1
- ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-B9drTgOW.js} +1 -1
- ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-CK4ROATy.js} +1 -1
- ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B9KtTTgw.js} +1 -1
- ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-1O1mki3m.js} +1 -1
- ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-B_fH2YuH.js} +1 -1
- ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D6rFLaVV.js} +1 -1
- ksadk/server/static/assets/chunk-QZHKN3VN-iXEZtKQc.js +1 -0
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-DIveV17Q.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-DIveV17Q.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-ChNs_Mdk.js} +1 -1
- ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-D0QXg_MQ.js} +1 -1
- ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-DBDDKwBQ.js} +1 -1
- ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-BkwDOxmO.js} +1 -1
- ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Bv8waYvY.js} +1 -1
- ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-e1VECDdu.js} +1 -1
- ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-Ds9adfRl.js} +1 -1
- ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-4N2NMVYg.js} +1 -1
- ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-B-jNR6Vn.js} +1 -1
- ksadk/server/static/assets/{dist-D57wnGWd.js → dist-B5J2uhNk.js} +1 -1
- ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-B5oS1zcj.js} +1 -1
- ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BB3-OwTQ.js} +1 -1
- ksadk/server/static/assets/{dist-2hInLS_J.js → dist-BIlKoW0k.js} +1 -1
- ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-BjOdlDjj.js} +1 -1
- ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-C1sz5Eo3.js} +1 -1
- ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-CWV4lDr1.js} +1 -1
- ksadk/server/static/assets/{dist-D-xOD048.js → dist-CmZHzlwZ.js} +1 -1
- ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-D6MpCZtz.js} +1 -1
- ksadk/server/static/assets/{dist-DyOkZmze.js → dist-DJN_6Y39.js} +1 -1
- ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-DQU9EWw-.js} +1 -1
- ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-DWKByxWV.js} +1 -1
- ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-Dli7qW-B.js} +1 -1
- ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-DsHPdk3W.js} +1 -1
- ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-X4TnqwOK.js} +1 -1
- ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-_pHPTyZ-.js} +1 -1
- ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-fhOuWds5.js} +1 -1
- ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-gLnrGsoU.js} +1 -1
- ksadk/server/static/assets/{dist-BssVmjIo.js → dist-j6Dxmf_j.js} +1 -1
- ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-o2OVmKvt.js} +1 -1
- ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-BPItFKH6.js} +1 -1
- ksadk/server/static/assets/eventmodeling-FCH6USID-DYFSxbqr.js +1 -0
- ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-BbYB9w5Y.js} +1 -1
- ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-TQXa0KXv.js} +1 -1
- ksadk/server/static/assets/gitGraph-WXDBUCRP-DyNYp6BN.js +1 -0
- ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-bKblCnpa.js} +1 -1
- ksadk/server/static/assets/index-R52pJJvg.js +177 -0
- ksadk/server/static/assets/index-jJr3_955.css +2 -0
- ksadk/server/static/assets/info-J43DQDTF-WUx7qTde.js +1 -0
- ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-BGVT7J_i.js} +1 -1
- ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-K0OOfVna.js} +1 -1
- ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-8LeOJaZp.js} +1 -1
- ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-C6uCgZrW.js} +1 -1
- ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-CYWseY5E.js} +1 -1
- ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-hdBcYzM8.js} +1 -1
- ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-BWrDjSZM.js} +2 -2
- ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-Bjy_2v4_.js} +1 -1
- ksadk/server/static/assets/packet-YPE3B663-BN13y_xl.js +1 -0
- ksadk/server/static/assets/pie-LRSECV5Y-ftSLXhhc.js +1 -0
- ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-GmmqNiVH.js} +1 -1
- ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-BmkRbwCg.js} +1 -1
- ksadk/server/static/assets/radar-GUYGQ44K-jaICkIeO.js +1 -0
- ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DSWFqL7c.js} +1 -1
- ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-l6iXmU65.js} +1 -1
- ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-Cq6UBeQB.js} +1 -1
- ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-qzTQpg3Y.js} +1 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-BYCoYGAN.js +1 -0
- ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-DEz24vV0.js} +1 -1
- ksadk/server/static/assets/treeView-BLDUP644-Cpib_vlz.js +1 -0
- ksadk/server/static/assets/treemap-LRROVOQU-DQxfmVHK.js +1 -0
- ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-CMCixki2.js} +1 -1
- ksadk/server/static/assets/wardley-L42UT6IY-BQYHnnkU.js +1 -0
- ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-CVzB8F9K.js} +1 -1
- ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-BFBqBLc1.js} +1 -1
- ksadk/server/static/index.html +2 -2
- ksadk/server/terminal_sessions.py +111 -58
- ksadk/sessions/__init__.py +69 -19
- ksadk/sessions/base.py +31 -11
- ksadk/sessions/continuity.py +2 -3
- ksadk/sessions/in_memory.py +46 -2
- ksadk/sessions/local_service.py +148 -17
- ksadk/sessions/postgres_service.py +143 -25
- ksadk/sessions/resilient.py +36 -8
- ksadk/skills/models.py +17 -5
- ksadk/skills/package_store.py +5 -2
- ksadk/skills/runtime/agent.py +20 -5
- ksadk/skills/runtime/artifacts.py +1 -5
- ksadk/skills/runtime/backends/e2b.py +10 -4
- ksadk/skills/runtime/backends/local.py +15 -3
- ksadk/skills/runtime/base.py +1 -2
- ksadk/skills/runtime/executor.py +10 -3
- ksadk/skills/runtime/factory.py +4 -2
- ksadk/skills/runtime/loader.py +1 -2
- ksadk/skills/runtime/registry.py +15 -10
- ksadk/skills/runtime/request.py +3 -1
- ksadk/skills/service_client.py +47 -16
- ksadk/skills/tool_defs.py +15 -10
- ksadk/studio/__init__.py +5 -0
- ksadk/studio/agent_avatar_assets.py +120 -0
- ksadk/studio/agent_lifecycle.py +51 -0
- ksadk/studio/api.py +1046 -0
- ksadk/studio/api_catalog_routes.py +324 -0
- ksadk/studio/api_contracts.py +177 -0
- ksadk/studio/api_helpers.py +132 -0
- ksadk/studio/authoring.py +524 -0
- ksadk/studio/authoring_coordinator.py +285 -0
- ksadk/studio/builder.py +320 -0
- ksadk/studio/capabilities.py +351 -0
- ksadk/studio/cloud.py +278 -0
- ksadk/studio/codex_agent_service.py +583 -0
- ksadk/studio/codex_builder.py +324 -0
- ksadk/studio/codex_manifest.py +278 -0
- ksadk/studio/codex_run.py +352 -0
- ksadk/studio/compiler.py +189 -0
- ksadk/studio/contracts.py +644 -0
- ksadk/studio/errors.py +47 -0
- ksadk/studio/evaluation.py +192 -0
- ksadk/studio/event_store.py +284 -0
- ksadk/studio/framework_run.py +114 -0
- ksadk/studio/identifiers.py +33 -0
- ksadk/studio/mcp_runtime.py +229 -0
- ksadk/studio/model_client.py +543 -0
- ksadk/studio/model_profile_service.py +214 -0
- ksadk/studio/operations.py +243 -0
- ksadk/studio/otel_trace.py +754 -0
- ksadk/studio/pagination.py +182 -0
- ksadk/studio/python_tool_inspection.py +183 -0
- ksadk/studio/repository.py +306 -0
- ksadk/studio/resource_catalog.py +1217 -0
- ksadk/studio/run_service.py +707 -0
- ksadk/studio/runtime_catalog.py +74 -0
- ksadk/studio/runtime_source.py +339 -0
- ksadk/studio/service.py +1141 -0
- ksadk/studio/shared_web.py +994 -0
- ksadk/studio/skill_discovery.py +628 -0
- ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
- ksadk/studio/static/assets/index-CaEN0eTR.css +1 -0
- ksadk/studio/static/assets/index-DI2eY_NH.js +252 -0
- ksadk/studio/static/assets/react-vendor-BNmTiJ-I.js +9 -0
- ksadk/studio/static/assets/rolldown-runtime-hePW80VL.js +1 -0
- ksadk/studio/static/index.html +15 -0
- ksadk/studio/templates.py +630 -0
- ksadk/studio/validator.py +246 -0
- ksadk/studio/workspace.py +137 -0
- ksadk/terminal_exec_policy.py +3 -4
- ksadk/tools/gateway.py +101 -15
- ksadk/tools/result_budget.py +12 -4
- ksadk/toolsets/__init__.py +161 -37
- ksadk/toolsets/a2a.py +426 -0
- ksadk/toolsets/platform.py +21 -5
- ksadk/toolsets/sandbox.py +82 -16
- ksadk/toolsets/skills.py +200 -39
- ksadk/toolsets/web.py +123 -26
- ksadk/toolsets/workspace.py +212 -101
- ksadk/tracing/__init__.py +19 -21
- ksadk/tracing/exporters/inmemory_exporter.py +62 -51
- ksadk/tracing/setup.py +135 -506
- ksadk/tracing/span_utils.py +0 -41
- ksadk/tui/loop.py +78 -30
- ksadk/tui/stream_render.py +1 -0
- ksadk/ui_config.py +5 -3
- ksadk/version.py +1 -1
- ksadk_runtime_common/memory_backend/registry.py +56 -56
- ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
- ksadk_runtime_common/workspace_files/router.py +8 -2
- agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
- ksadk/a2a/card_builder.py +0 -64
- ksadk/a2a/client.py +0 -309
- ksadk/runners/utils/langfuse.py +0 -230
- ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
- ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
- ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
- ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
- ksadk/server/static/assets/channel-CTuydARX.js +0 -1
- ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
- ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
- ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
- ksadk/server/static/assets/index-DAURbCsP.css +0 -1
- ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
- ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
- ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
- ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
- ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
- ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
- ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
- ksadk/tracing/exporters/langfuse_exporter.py +0 -445
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""Local evaluation suites and deterministic assertions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from collections.abc import Awaitable, Callable
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import cast
|
|
9
|
+
from uuid import uuid4
|
|
10
|
+
|
|
11
|
+
from jsonschema import ( # type: ignore[import-untyped]
|
|
12
|
+
ValidationError as JSONSchemaValidationError,
|
|
13
|
+
)
|
|
14
|
+
from jsonschema import validate as validate_json # type: ignore[import-untyped]
|
|
15
|
+
|
|
16
|
+
from ksadk.studio.contracts import (
|
|
17
|
+
AssertionResult,
|
|
18
|
+
AssertionSpec,
|
|
19
|
+
EvaluationCaseResult,
|
|
20
|
+
EvaluationRun,
|
|
21
|
+
EvaluationSuite,
|
|
22
|
+
RunRecord,
|
|
23
|
+
RunStatus,
|
|
24
|
+
)
|
|
25
|
+
from ksadk.studio.errors import StudioError
|
|
26
|
+
from ksadk.studio.event_store import RunEventStore
|
|
27
|
+
from ksadk.studio.repository import BuildRepository, load_yaml_file
|
|
28
|
+
from ksadk.studio.workspace import Workspace
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class EvaluationRunner:
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
workspace: Workspace,
|
|
35
|
+
*,
|
|
36
|
+
run_agent: Callable[[str, str, str | None], Awaitable[RunRecord]],
|
|
37
|
+
event_store: RunEventStore,
|
|
38
|
+
build_repository: BuildRepository | None = None,
|
|
39
|
+
) -> None:
|
|
40
|
+
self.workspace = workspace
|
|
41
|
+
self.run_agent = run_agent
|
|
42
|
+
self.event_store = event_store
|
|
43
|
+
self.build_repository = build_repository or BuildRepository(workspace)
|
|
44
|
+
|
|
45
|
+
async def run(
|
|
46
|
+
self,
|
|
47
|
+
build_id: str,
|
|
48
|
+
suite_refs: list[str],
|
|
49
|
+
*,
|
|
50
|
+
fail_fast: bool = False,
|
|
51
|
+
) -> EvaluationRun:
|
|
52
|
+
build = self.build_repository.get(build_id)
|
|
53
|
+
suites = [
|
|
54
|
+
self._load_suite(build.agent_id, reference) for reference in suite_refs
|
|
55
|
+
]
|
|
56
|
+
evaluation = EvaluationRun(
|
|
57
|
+
id=f"eval_{uuid4().hex}",
|
|
58
|
+
build_id=build_id,
|
|
59
|
+
status=RunStatus.RUNNING,
|
|
60
|
+
)
|
|
61
|
+
for suite in suites:
|
|
62
|
+
for case in suite.cases:
|
|
63
|
+
run = await self.run_agent(
|
|
64
|
+
build_id,
|
|
65
|
+
case.input,
|
|
66
|
+
f"eval_{evaluation.id}_{case.id}",
|
|
67
|
+
)
|
|
68
|
+
assertion_results = [
|
|
69
|
+
self._assert(assertion, run) for assertion in case.assertions
|
|
70
|
+
]
|
|
71
|
+
passed = run.status == RunStatus.COMPLETED and all(
|
|
72
|
+
result.passed for result in assertion_results
|
|
73
|
+
)
|
|
74
|
+
evaluation.results.append(
|
|
75
|
+
EvaluationCaseResult(
|
|
76
|
+
case_id=case.id,
|
|
77
|
+
run_id=run.id,
|
|
78
|
+
passed=passed,
|
|
79
|
+
assertions=assertion_results,
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
if fail_fast and not passed:
|
|
83
|
+
break
|
|
84
|
+
if fail_fast and evaluation.results and not evaluation.results[-1].passed:
|
|
85
|
+
break
|
|
86
|
+
evaluation.total = len(evaluation.results)
|
|
87
|
+
evaluation.passed = sum(1 for result in evaluation.results if result.passed)
|
|
88
|
+
evaluation.failed = evaluation.total - evaluation.passed
|
|
89
|
+
evaluation.pass_rate = (
|
|
90
|
+
evaluation.passed / evaluation.total if evaluation.total else 0
|
|
91
|
+
)
|
|
92
|
+
evaluation.status = (
|
|
93
|
+
RunStatus.COMPLETED if evaluation.failed == 0 else RunStatus.FAILED
|
|
94
|
+
)
|
|
95
|
+
self._save(evaluation)
|
|
96
|
+
return evaluation
|
|
97
|
+
|
|
98
|
+
def get(self, evaluation_id: str) -> EvaluationRun:
|
|
99
|
+
path = self.workspace.resolve(
|
|
100
|
+
Path(".agentkit/evaluations") / f"{evaluation_id}.json"
|
|
101
|
+
)
|
|
102
|
+
if not path.is_file():
|
|
103
|
+
raise StudioError(
|
|
104
|
+
"EVALUATION_NOT_FOUND",
|
|
105
|
+
"Evaluation 不存在",
|
|
106
|
+
status_code=404,
|
|
107
|
+
details={"id": evaluation_id},
|
|
108
|
+
)
|
|
109
|
+
return cast(
|
|
110
|
+
EvaluationRun,
|
|
111
|
+
EvaluationRun.model_validate_json(path.read_text(encoding="utf-8")),
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
def _load_suite(self, agent_id: str, reference: str) -> EvaluationSuite:
|
|
115
|
+
candidates = [
|
|
116
|
+
Path("agents") / agent_id / reference,
|
|
117
|
+
Path(reference),
|
|
118
|
+
]
|
|
119
|
+
for candidate in candidates:
|
|
120
|
+
path = self.workspace.resolve(candidate)
|
|
121
|
+
if path.is_file():
|
|
122
|
+
try:
|
|
123
|
+
return cast(
|
|
124
|
+
EvaluationSuite,
|
|
125
|
+
EvaluationSuite.model_validate(load_yaml_file(path)),
|
|
126
|
+
)
|
|
127
|
+
except ValueError as exc:
|
|
128
|
+
raise StudioError(
|
|
129
|
+
"EVALUATION_SUITE_INVALID",
|
|
130
|
+
"评测集格式无效",
|
|
131
|
+
status_code=422,
|
|
132
|
+
details={"reference": reference, "reason": str(exc)},
|
|
133
|
+
) from exc
|
|
134
|
+
raise StudioError(
|
|
135
|
+
"EVALUATION_SUITE_NOT_FOUND",
|
|
136
|
+
"评测集不存在",
|
|
137
|
+
status_code=404,
|
|
138
|
+
details={"reference": reference},
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
def _assert(self, assertion: AssertionSpec, run: RunRecord) -> AssertionResult:
|
|
142
|
+
value = assertion.value
|
|
143
|
+
passed = False
|
|
144
|
+
message = ""
|
|
145
|
+
if assertion.type == "contains":
|
|
146
|
+
passed = str(value) in run.output
|
|
147
|
+
elif assertion.type == "equals":
|
|
148
|
+
passed = run.output == str(value)
|
|
149
|
+
elif assertion.type == "notContains":
|
|
150
|
+
passed = str(value) not in run.output
|
|
151
|
+
elif assertion.type == "maxLatencyMs":
|
|
152
|
+
passed = (run.duration_ms or 0) <= int(value)
|
|
153
|
+
elif assertion.type == "maxInputTokens":
|
|
154
|
+
passed = run.usage.input_tokens <= int(value)
|
|
155
|
+
elif assertion.type == "maxOutputTokens":
|
|
156
|
+
passed = run.usage.output_tokens <= int(value)
|
|
157
|
+
elif assertion.type == "jsonSchema":
|
|
158
|
+
try:
|
|
159
|
+
validate_json(json.loads(run.output), value)
|
|
160
|
+
passed = True
|
|
161
|
+
except (ValueError, JSONSchemaValidationError) as exc:
|
|
162
|
+
message = str(exc)
|
|
163
|
+
elif assertion.type in {"toolCalled", "toolNotCalled"}:
|
|
164
|
+
called = {
|
|
165
|
+
event.data.get("tool")
|
|
166
|
+
for event in self.event_store.events(run.id)
|
|
167
|
+
if event.type == "tool.requested"
|
|
168
|
+
}
|
|
169
|
+
passed = (
|
|
170
|
+
str(value) in called
|
|
171
|
+
if assertion.type == "toolCalled"
|
|
172
|
+
else str(value) not in called
|
|
173
|
+
)
|
|
174
|
+
if not message and not passed:
|
|
175
|
+
message = f"断言 {assertion.type} 未通过"
|
|
176
|
+
return AssertionResult(assertion=assertion, passed=passed, message=message)
|
|
177
|
+
|
|
178
|
+
def _save(self, evaluation: EvaluationRun) -> None:
|
|
179
|
+
directory = self.workspace.resolve(".agentkit/evaluations")
|
|
180
|
+
directory.mkdir(parents=True, exist_ok=True)
|
|
181
|
+
self.workspace.atomic_write_text(
|
|
182
|
+
directory / f"{evaluation.id}.json",
|
|
183
|
+
json.dumps(
|
|
184
|
+
evaluation.model_dump(
|
|
185
|
+
by_alias=True, exclude_none=True, mode="json"
|
|
186
|
+
),
|
|
187
|
+
ensure_ascii=False,
|
|
188
|
+
sort_keys=True,
|
|
189
|
+
indent=2,
|
|
190
|
+
)
|
|
191
|
+
+ "\n",
|
|
192
|
+
)
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"""Persistent local Run and Event store."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import shutil
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import List
|
|
10
|
+
|
|
11
|
+
from pydantic import ValidationError
|
|
12
|
+
|
|
13
|
+
from ksadk.studio.contracts import RunEvent, RunRecord, RunStatus
|
|
14
|
+
from ksadk.studio.errors import StudioError, not_found
|
|
15
|
+
from ksadk.studio.otel_trace import OtlpTraceStore
|
|
16
|
+
from ksadk.studio.workspace import Workspace
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class RunEventStore:
|
|
20
|
+
def __init__(self, workspace: Workspace) -> None:
|
|
21
|
+
self.workspace = workspace
|
|
22
|
+
self.trace_store = OtlpTraceStore(workspace)
|
|
23
|
+
|
|
24
|
+
def _path(self, run_id: str) -> Path:
|
|
25
|
+
return self.workspace.resolve(Path(".agentkit/runs") / f"{run_id}.json")
|
|
26
|
+
|
|
27
|
+
def create(self, record: RunRecord) -> RunRecord:
|
|
28
|
+
path = self._path(record.id)
|
|
29
|
+
if path.exists():
|
|
30
|
+
raise StudioError("RUN_ALREADY_EXISTS", "Run 已存在", status_code=409)
|
|
31
|
+
self._write(record, [])
|
|
32
|
+
return record
|
|
33
|
+
|
|
34
|
+
def save(self, record: RunRecord) -> RunRecord:
|
|
35
|
+
_, events = self._read(record.id)
|
|
36
|
+
self._write(record, events)
|
|
37
|
+
return record
|
|
38
|
+
|
|
39
|
+
def append(self, run_id: str, event_type: str, data: dict) -> RunEvent:
|
|
40
|
+
record, events = self._read(run_id)
|
|
41
|
+
event = RunEvent(
|
|
42
|
+
id=len(events) + 1,
|
|
43
|
+
run_id=run_id,
|
|
44
|
+
type=event_type,
|
|
45
|
+
data=data,
|
|
46
|
+
)
|
|
47
|
+
events.append(event)
|
|
48
|
+
self._write(record, events)
|
|
49
|
+
return event
|
|
50
|
+
|
|
51
|
+
def get(self, run_id: str) -> RunRecord:
|
|
52
|
+
record, _ = self._read(run_id)
|
|
53
|
+
return record
|
|
54
|
+
|
|
55
|
+
def events(self, run_id: str, *, after: int = 0) -> list[RunEvent]:
|
|
56
|
+
_, events = self._read(run_id)
|
|
57
|
+
return [event for event in events if event.id > after]
|
|
58
|
+
|
|
59
|
+
def list_runs(
|
|
60
|
+
self,
|
|
61
|
+
*,
|
|
62
|
+
session_id: str | None = None,
|
|
63
|
+
agent_id: str | None = None,
|
|
64
|
+
) -> List[RunRecord]:
|
|
65
|
+
records: list[RunRecord] = []
|
|
66
|
+
directory = self.workspace.resolve(".agentkit/runs")
|
|
67
|
+
for path in sorted(directory.glob("run_*.json")):
|
|
68
|
+
try:
|
|
69
|
+
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
70
|
+
record = RunRecord.model_validate(payload["record"])
|
|
71
|
+
except (OSError, ValueError, KeyError, ValidationError):
|
|
72
|
+
continue
|
|
73
|
+
if session_id and record.session_id != session_id:
|
|
74
|
+
continue
|
|
75
|
+
if agent_id and record.agent_id != agent_id:
|
|
76
|
+
continue
|
|
77
|
+
records.append(record)
|
|
78
|
+
records.sort(
|
|
79
|
+
key=lambda item: (
|
|
80
|
+
item.started_at or item.completed_at or datetime.min.replace(tzinfo=timezone.utc)
|
|
81
|
+
),
|
|
82
|
+
reverse=False,
|
|
83
|
+
)
|
|
84
|
+
return records
|
|
85
|
+
|
|
86
|
+
def delete_session(self, session_id: str) -> int:
|
|
87
|
+
"""Delete every persisted run that belongs to one local chat session."""
|
|
88
|
+
|
|
89
|
+
deleted = 0
|
|
90
|
+
for record in self.list_runs(session_id=session_id):
|
|
91
|
+
path = self._path(record.id)
|
|
92
|
+
if path.is_file():
|
|
93
|
+
self.trace_store.delete(record.trace_id, purge=True)
|
|
94
|
+
path.unlink()
|
|
95
|
+
deleted += 1
|
|
96
|
+
return deleted
|
|
97
|
+
|
|
98
|
+
def delete_agent(
|
|
99
|
+
self,
|
|
100
|
+
agent_id: str,
|
|
101
|
+
*,
|
|
102
|
+
purge: bool,
|
|
103
|
+
trash_directory: Path | None = None,
|
|
104
|
+
) -> int:
|
|
105
|
+
"""Remove the persisted Runs and Trace events owned by one Agent."""
|
|
106
|
+
|
|
107
|
+
deleted = 0
|
|
108
|
+
for record in self.list_runs(agent_id=agent_id):
|
|
109
|
+
path = self._path(record.id)
|
|
110
|
+
if not path.is_file():
|
|
111
|
+
continue
|
|
112
|
+
if purge:
|
|
113
|
+
self.trace_store.delete(record.trace_id, purge=True)
|
|
114
|
+
path.unlink()
|
|
115
|
+
else:
|
|
116
|
+
if trash_directory is None:
|
|
117
|
+
raise ValueError("recoverable deletion requires a trash directory")
|
|
118
|
+
destination = self.workspace.resolve(trash_directory / "runs" / path.name)
|
|
119
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
120
|
+
self.trace_store.delete(
|
|
121
|
+
record.trace_id,
|
|
122
|
+
purge=False,
|
|
123
|
+
trash_directory=trash_directory,
|
|
124
|
+
)
|
|
125
|
+
shutil.move(str(path), str(destination))
|
|
126
|
+
deleted += 1
|
|
127
|
+
return deleted
|
|
128
|
+
|
|
129
|
+
def recover_interrupted(self) -> int:
|
|
130
|
+
"""Reconcile non-terminal records left behind by a stopped Studio.
|
|
131
|
+
|
|
132
|
+
Events are persisted before the final RunRecord update. A browser
|
|
133
|
+
disconnect or process stop can therefore leave a terminal event next
|
|
134
|
+
to a stale ``RUNNING`` record. On startup the event log wins; a run
|
|
135
|
+
without any terminal event is explicitly marked interrupted because
|
|
136
|
+
its in-memory runtime task cannot survive a Studio restart.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
recovered = 0
|
|
140
|
+
for record in self.list_runs():
|
|
141
|
+
if record.status not in {
|
|
142
|
+
RunStatus.CREATED,
|
|
143
|
+
RunStatus.RUNNING,
|
|
144
|
+
RunStatus.PAUSED,
|
|
145
|
+
RunStatus.WAITING_INPUT,
|
|
146
|
+
}:
|
|
147
|
+
continue
|
|
148
|
+
events = self.events(record.id)
|
|
149
|
+
terminal = next(
|
|
150
|
+
(
|
|
151
|
+
event
|
|
152
|
+
for event in reversed(events)
|
|
153
|
+
if event.type
|
|
154
|
+
in {
|
|
155
|
+
"run.completed",
|
|
156
|
+
"run.failed",
|
|
157
|
+
"run.cancelled",
|
|
158
|
+
"run.interrupted",
|
|
159
|
+
}
|
|
160
|
+
),
|
|
161
|
+
None,
|
|
162
|
+
)
|
|
163
|
+
if terminal is None:
|
|
164
|
+
terminal = self.append(
|
|
165
|
+
record.id,
|
|
166
|
+
"run.interrupted",
|
|
167
|
+
{
|
|
168
|
+
"status": "interrupted",
|
|
169
|
+
"reason": "studio_restarted",
|
|
170
|
+
},
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
if terminal.type == "run.completed":
|
|
174
|
+
record.status = RunStatus.COMPLETED
|
|
175
|
+
record.error = None
|
|
176
|
+
elif terminal.type == "run.failed":
|
|
177
|
+
record.status = RunStatus.FAILED
|
|
178
|
+
record.error = {
|
|
179
|
+
"code": "RUNTIME_RUN_FAILED",
|
|
180
|
+
"message": str(
|
|
181
|
+
terminal.data.get("error")
|
|
182
|
+
or terminal.data.get("message")
|
|
183
|
+
or "Agent 运行失败"
|
|
184
|
+
),
|
|
185
|
+
}
|
|
186
|
+
elif terminal.type == "run.cancelled":
|
|
187
|
+
record.status = RunStatus.CANCELLED
|
|
188
|
+
record.error = {"code": "RUN_CANCELLED", "message": "运行已取消"}
|
|
189
|
+
else:
|
|
190
|
+
record.status = RunStatus.INTERRUPTED
|
|
191
|
+
record.error = {
|
|
192
|
+
"code": "RUN_INTERRUPTED",
|
|
193
|
+
"message": "Studio 重启后无法重新 attach 上一次本地运行",
|
|
194
|
+
}
|
|
195
|
+
record.completed_at = terminal.created_at
|
|
196
|
+
if record.started_at is not None:
|
|
197
|
+
record.duration_ms = max(
|
|
198
|
+
0,
|
|
199
|
+
int((record.completed_at - record.started_at).total_seconds() * 1000),
|
|
200
|
+
)
|
|
201
|
+
self.save(record)
|
|
202
|
+
recovered += 1
|
|
203
|
+
return recovered
|
|
204
|
+
|
|
205
|
+
def trace(self, trace_id: str) -> dict:
|
|
206
|
+
return self.trace_store.get_trace_view(trace_id)
|
|
207
|
+
|
|
208
|
+
def trace_otlp(self, trace_id: str) -> dict:
|
|
209
|
+
return self.trace_store.get_otlp(trace_id)
|
|
210
|
+
|
|
211
|
+
def list_traces(
|
|
212
|
+
self,
|
|
213
|
+
*,
|
|
214
|
+
agent_id: str | None = None,
|
|
215
|
+
status: str | None = None,
|
|
216
|
+
limit: int = 200,
|
|
217
|
+
) -> list[dict]:
|
|
218
|
+
return self.trace_store.list_trace_summaries(
|
|
219
|
+
agent_id=agent_id,
|
|
220
|
+
status=status,
|
|
221
|
+
limit=limit,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
def list_traces_page(
|
|
225
|
+
self,
|
|
226
|
+
*,
|
|
227
|
+
agent_id: str | None = None,
|
|
228
|
+
status: str | None = None,
|
|
229
|
+
query: str = "",
|
|
230
|
+
limit: int = 50,
|
|
231
|
+
cursor: str | None = None,
|
|
232
|
+
sort: str = "startedAt:desc",
|
|
233
|
+
) -> dict:
|
|
234
|
+
return self.trace_store.paginate_trace_summaries(
|
|
235
|
+
agent_id=agent_id,
|
|
236
|
+
status=status,
|
|
237
|
+
query=query,
|
|
238
|
+
limit=limit,
|
|
239
|
+
cursor=cursor,
|
|
240
|
+
sort=sort,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
def trace_overview(
|
|
244
|
+
self,
|
|
245
|
+
*,
|
|
246
|
+
range_name: str = "24h",
|
|
247
|
+
agent_id: str | None = None,
|
|
248
|
+
status: str | None = None,
|
|
249
|
+
) -> dict:
|
|
250
|
+
return self.trace_store.trace_overview(
|
|
251
|
+
range_name=range_name,
|
|
252
|
+
agent_id=agent_id,
|
|
253
|
+
status=status,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
def _read(self, run_id: str) -> tuple[RunRecord, List[RunEvent]]:
|
|
257
|
+
path = self._path(run_id)
|
|
258
|
+
if not path.is_file():
|
|
259
|
+
raise not_found("run", run_id)
|
|
260
|
+
try:
|
|
261
|
+
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
262
|
+
record = RunRecord.model_validate(payload["record"])
|
|
263
|
+
events = [RunEvent.model_validate(item) for item in payload["events"]]
|
|
264
|
+
return record, events
|
|
265
|
+
except (OSError, ValueError, KeyError, ValidationError) as exc:
|
|
266
|
+
raise StudioError(
|
|
267
|
+
"RUN_RECORD_INVALID",
|
|
268
|
+
"Run 记录损坏",
|
|
269
|
+
status_code=500,
|
|
270
|
+
details={"id": run_id},
|
|
271
|
+
) from exc
|
|
272
|
+
|
|
273
|
+
def _write(self, record: RunRecord, events: List[RunEvent]) -> None:
|
|
274
|
+
payload = {
|
|
275
|
+
"record": record.model_dump(by_alias=True, exclude_none=True, mode="json"),
|
|
276
|
+
"events": [
|
|
277
|
+
event.model_dump(by_alias=True, exclude_none=True, mode="json") for event in events
|
|
278
|
+
],
|
|
279
|
+
}
|
|
280
|
+
self.workspace.atomic_write_text(
|
|
281
|
+
self._path(record.id),
|
|
282
|
+
json.dumps(payload, ensure_ascii=False, sort_keys=True, indent=2) + "\n",
|
|
283
|
+
)
|
|
284
|
+
self.trace_store.sync(record, events)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""Resolve immutable ADK/LangGraph Studio builds into RuntimeLaunchContext."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
from ksadk.detection.detector import FrameworkDetector
|
|
8
|
+
from ksadk.runtime import RuntimeLaunchContext
|
|
9
|
+
from ksadk.studio.errors import StudioError
|
|
10
|
+
from ksadk.studio.repository import BuildRepository
|
|
11
|
+
from ksadk.studio.run_service import StudioRunSpec
|
|
12
|
+
from ksadk.studio.workspace import Workspace
|
|
13
|
+
from ksadk.tools.gateway import normalize_tool_approval_mode
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class FrameworkRunSpecResolver:
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
workspace: Workspace,
|
|
20
|
+
*,
|
|
21
|
+
build_repository: BuildRepository | None = None,
|
|
22
|
+
) -> None:
|
|
23
|
+
self.workspace = workspace
|
|
24
|
+
self.builds = build_repository or BuildRepository(workspace)
|
|
25
|
+
|
|
26
|
+
def resolve(
|
|
27
|
+
self,
|
|
28
|
+
build_id: str,
|
|
29
|
+
*,
|
|
30
|
+
model: str | None = None,
|
|
31
|
+
approval_mode: str | None = None,
|
|
32
|
+
) -> StudioRunSpec:
|
|
33
|
+
build = self.builds.get(build_id)
|
|
34
|
+
runtime_type = build.runtime_type.strip().lower()
|
|
35
|
+
if runtime_type not in {"adk", "langgraph"}:
|
|
36
|
+
raise StudioError(
|
|
37
|
+
"BUILD_RUNTIME_UNSUPPORTED",
|
|
38
|
+
"Build 没有可由 RuntimeAdapter 启动的 ADK/LangGraph Runtime",
|
|
39
|
+
status_code=422,
|
|
40
|
+
details={"buildId": build_id, "runtimeType": runtime_type},
|
|
41
|
+
)
|
|
42
|
+
if not build.artifact_path:
|
|
43
|
+
raise StudioError("BUILD_NOT_READY", "Build 尚未生成制品", status_code=409)
|
|
44
|
+
artifact_root = self.workspace.resolve(build.artifact_path, must_exist=True).parent
|
|
45
|
+
bundle_root = artifact_root / "agent-bundle"
|
|
46
|
+
project_dir = bundle_root / "runtime"
|
|
47
|
+
if not project_dir.is_dir():
|
|
48
|
+
raise StudioError(
|
|
49
|
+
"BUILD_RUNTIME_SOURCE_MISSING",
|
|
50
|
+
"Build 缺少不可变 Runtime 源码快照",
|
|
51
|
+
status_code=500,
|
|
52
|
+
)
|
|
53
|
+
detection = FrameworkDetector(str(project_dir)).detect()
|
|
54
|
+
if not detection.is_valid or detection.type.value != runtime_type:
|
|
55
|
+
raise StudioError(
|
|
56
|
+
"BUILD_RUNTIME_DETECTION_MISMATCH",
|
|
57
|
+
"Build 中的 Runtime 源码与 Runtime Lock 不一致",
|
|
58
|
+
status_code=422,
|
|
59
|
+
details={
|
|
60
|
+
"expected": runtime_type,
|
|
61
|
+
"detected": detection.type.value,
|
|
62
|
+
},
|
|
63
|
+
)
|
|
64
|
+
selected_model = self._select_model(build.runtime_lock, model)
|
|
65
|
+
resolved_path = bundle_root / "resolved-agent-spec.json"
|
|
66
|
+
resolved = json.loads(resolved_path.read_text(encoding="utf-8"))
|
|
67
|
+
instructions = resolved.get("instructions") if isinstance(resolved, dict) else {}
|
|
68
|
+
request_config = {
|
|
69
|
+
"base_instructions": str((instructions or {}).get("system") or ""),
|
|
70
|
+
"entry_point": detection.entry_point,
|
|
71
|
+
"agent_variable": detection.agent_variable,
|
|
72
|
+
}
|
|
73
|
+
if approval_mode:
|
|
74
|
+
request_config["tool_approval_mode"] = normalize_tool_approval_mode(
|
|
75
|
+
approval_mode
|
|
76
|
+
)
|
|
77
|
+
return StudioRunSpec(
|
|
78
|
+
launch_context=RuntimeLaunchContext(
|
|
79
|
+
runtime_type=runtime_type,
|
|
80
|
+
project_dir=project_dir,
|
|
81
|
+
detection=detection,
|
|
82
|
+
config=dict(detection.raw_config or {}),
|
|
83
|
+
),
|
|
84
|
+
build_id=build.id,
|
|
85
|
+
agent_id=build.agent_id,
|
|
86
|
+
model=selected_model,
|
|
87
|
+
request_config=request_config,
|
|
88
|
+
manifest_sha256=build.resolved_digest,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def _select_model(runtime_lock: dict, requested: str | None) -> str:
|
|
93
|
+
allowed = [str(value) for value in runtime_lock.get("models") or [] if str(value)]
|
|
94
|
+
default = str(runtime_lock.get("model") or "").strip()
|
|
95
|
+
if default and default not in allowed:
|
|
96
|
+
allowed.insert(0, default)
|
|
97
|
+
selected = str(requested or default).strip()
|
|
98
|
+
if not selected:
|
|
99
|
+
raise StudioError(
|
|
100
|
+
"AGENT_MODEL_REQUIRED",
|
|
101
|
+
"Build 没有绑定可运行模型",
|
|
102
|
+
status_code=422,
|
|
103
|
+
)
|
|
104
|
+
if allowed and selected not in allowed:
|
|
105
|
+
raise StudioError(
|
|
106
|
+
"MODEL_NOT_BOUND",
|
|
107
|
+
"请求模型未绑定到当前 Agent Build",
|
|
108
|
+
status_code=422,
|
|
109
|
+
details={"model": selected, "allowedModels": allowed},
|
|
110
|
+
)
|
|
111
|
+
return selected
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
__all__ = ["FrameworkRunSpecResolver"]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Server-owned local identifiers for Studio resources."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
import secrets
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
|
|
9
|
+
from ksadk.studio.errors import StudioError
|
|
10
|
+
|
|
11
|
+
_GENERATED_AGENT_SLUG = re.compile(r"^agentkit-[0-9a-f]{8}$")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def generate_agent_slug(exists: Callable[[str], bool]) -> str:
|
|
15
|
+
"""Allocate a short opaque Agent ID without trusting a client-side default."""
|
|
16
|
+
|
|
17
|
+
for _attempt in range(32):
|
|
18
|
+
candidate = f"agentkit-{secrets.token_hex(4)}"
|
|
19
|
+
if not exists(candidate):
|
|
20
|
+
return candidate
|
|
21
|
+
raise StudioError(
|
|
22
|
+
"AGENT_ID_EXHAUSTED",
|
|
23
|
+
"无法分配唯一的本地标识",
|
|
24
|
+
status_code=503,
|
|
25
|
+
field="slug",
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def is_generated_agent_slug(value: str) -> bool:
|
|
30
|
+
return bool(_GENERATED_AGENT_SLUG.fullmatch(str(value or "").strip()))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
__all__ = ["generate_agent_slug", "is_generated_agent_slug"]
|