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,461 @@
|
|
|
1
|
+
"""Deterministic evaluators for normalized target results."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
from collections import Counter
|
|
10
|
+
from collections.abc import Callable
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from jsonschema import ValidationError as JSONSchemaValidationError
|
|
15
|
+
from jsonschema import validate as validate_json
|
|
16
|
+
|
|
17
|
+
from .contracts import (
|
|
18
|
+
AssertionSpec,
|
|
19
|
+
AssertionType,
|
|
20
|
+
DataPolicy,
|
|
21
|
+
EvalCase,
|
|
22
|
+
EvaluationConfig,
|
|
23
|
+
MetricResult,
|
|
24
|
+
MetricStatus,
|
|
25
|
+
TargetRun,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True)
|
|
30
|
+
class _EvaluationContext:
|
|
31
|
+
"""Inputs shared by every evaluator for one target invocation."""
|
|
32
|
+
|
|
33
|
+
case: EvalCase
|
|
34
|
+
target_run: TargetRun
|
|
35
|
+
config: EvaluationConfig
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
EvaluatorStrategy = Callable[[_EvaluationContext], list[MetricResult]]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass(frozen=True)
|
|
42
|
+
class _EvaluatorDefinition:
|
|
43
|
+
"""Stable evaluator metadata and its stateless scoring strategy."""
|
|
44
|
+
|
|
45
|
+
evaluator_id: str
|
|
46
|
+
metric_name: str
|
|
47
|
+
strategy: EvaluatorStrategy
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
REFERENCE_MATCH_EVALUATOR = "reference_match@v1"
|
|
51
|
+
LLM_JUDGE_EVALUATOR = "llm_judge@v1"
|
|
52
|
+
DEFAULT_EVALUATORS = (
|
|
53
|
+
"response_contract@v1",
|
|
54
|
+
"runtime_budget@v1",
|
|
55
|
+
"tool_trajectory@v1",
|
|
56
|
+
)
|
|
57
|
+
_RESPONSE_MATCH_THRESHOLD = 0.8
|
|
58
|
+
_TOKEN_PATTERN = re.compile(r"[A-Za-z0-9_]+|[\u4e00-\u9fff]")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def evaluate_case(
|
|
62
|
+
case: EvalCase,
|
|
63
|
+
target_run: TargetRun,
|
|
64
|
+
evaluator_names: list[str],
|
|
65
|
+
config: EvaluationConfig | None = None,
|
|
66
|
+
) -> list[MetricResult]:
|
|
67
|
+
"""Run selected evaluators in request order."""
|
|
68
|
+
|
|
69
|
+
context = _EvaluationContext(case, target_run, config or EvaluationConfig())
|
|
70
|
+
evaluators = _resolve_evaluators(evaluator_names)
|
|
71
|
+
return _run_evaluators(context, evaluators)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
async def evaluate_case_async(
|
|
75
|
+
case: EvalCase,
|
|
76
|
+
target_run: TargetRun,
|
|
77
|
+
evaluator_names: list[str],
|
|
78
|
+
config: EvaluationConfig,
|
|
79
|
+
) -> list[MetricResult]:
|
|
80
|
+
"""Run evaluators without blocking the target invocation event loop."""
|
|
81
|
+
|
|
82
|
+
return await asyncio.to_thread(evaluate_case, case, target_run, evaluator_names, config)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _resolve_evaluators(evaluator_names: list[str]) -> list[_EvaluatorDefinition]:
|
|
86
|
+
selected_names = evaluator_names or DEFAULT_EVALUATORS
|
|
87
|
+
unsupported_names = [name for name in selected_names if name not in _EVALUATOR_REGISTRY]
|
|
88
|
+
if unsupported_names:
|
|
89
|
+
raise ValueError(f"不支持的评估器: {', '.join(unsupported_names)}")
|
|
90
|
+
return [_EVALUATOR_REGISTRY[name] for name in selected_names]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _run_evaluators(
|
|
94
|
+
context: _EvaluationContext,
|
|
95
|
+
evaluators: list[_EvaluatorDefinition],
|
|
96
|
+
) -> list[MetricResult]:
|
|
97
|
+
metrics: list[MetricResult] = []
|
|
98
|
+
for evaluator in evaluators:
|
|
99
|
+
metrics.extend(_run_evaluator(evaluator, context))
|
|
100
|
+
return metrics
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _run_evaluator(
|
|
104
|
+
evaluator: _EvaluatorDefinition,
|
|
105
|
+
context: _EvaluationContext,
|
|
106
|
+
) -> list[MetricResult]:
|
|
107
|
+
try:
|
|
108
|
+
return evaluator.strategy(context)
|
|
109
|
+
except Exception as exc:
|
|
110
|
+
return [_evaluator_error_metric(evaluator, exc)]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _evaluate_reference_match(context: _EvaluationContext) -> list[MetricResult]:
|
|
114
|
+
"""Score the final response against the case's reference output."""
|
|
115
|
+
|
|
116
|
+
expected_output = _final_expected_output(context.case)
|
|
117
|
+
if not expected_output:
|
|
118
|
+
return []
|
|
119
|
+
|
|
120
|
+
score = _rouge_1_f1(context.target_run.output, expected_output)
|
|
121
|
+
return [
|
|
122
|
+
_score_metric(
|
|
123
|
+
name="response_match",
|
|
124
|
+
score=score,
|
|
125
|
+
evidence={
|
|
126
|
+
"evaluator": REFERENCE_MATCH_EVALUATOR,
|
|
127
|
+
"method": "rouge_1_f1",
|
|
128
|
+
"threshold": _RESPONSE_MATCH_THRESHOLD,
|
|
129
|
+
},
|
|
130
|
+
)
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _evaluate_llm_judge(
|
|
135
|
+
context: _EvaluationContext,
|
|
136
|
+
) -> list[MetricResult]:
|
|
137
|
+
"""Use the configured LLM Judge to score a final response."""
|
|
138
|
+
|
|
139
|
+
expected_output = _final_expected_output(context.case)
|
|
140
|
+
if not expected_output:
|
|
141
|
+
return []
|
|
142
|
+
|
|
143
|
+
unavailable_reason = _judge_unavailable_reason(context.config)
|
|
144
|
+
if unavailable_reason:
|
|
145
|
+
return [_judge_unavailable_metric(unavailable_reason)]
|
|
146
|
+
|
|
147
|
+
try:
|
|
148
|
+
score = _judge_score(
|
|
149
|
+
input_text=context.case.input,
|
|
150
|
+
actual_output=context.target_run.output,
|
|
151
|
+
expected_output=expected_output,
|
|
152
|
+
config=context.config,
|
|
153
|
+
)
|
|
154
|
+
except ImportError:
|
|
155
|
+
return [_judge_unavailable_metric("未安装 ksadk[judge]")]
|
|
156
|
+
except Exception as exc:
|
|
157
|
+
return [_judge_error_metric(exc)]
|
|
158
|
+
|
|
159
|
+
return [_judge_score_metric(score, context.config.judge_model)]
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _evaluate_response_contract(
|
|
163
|
+
context: _EvaluationContext,
|
|
164
|
+
) -> list[MetricResult]:
|
|
165
|
+
"""Evaluate response assertions against the normalized target output."""
|
|
166
|
+
|
|
167
|
+
return [
|
|
168
|
+
_response_metric(assertion, context.target_run.output)
|
|
169
|
+
for assertion in _response_assertions(context.case)
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _evaluate_runtime_budget(
|
|
174
|
+
context: _EvaluationContext,
|
|
175
|
+
) -> list[MetricResult]:
|
|
176
|
+
"""Evaluate runtime assertions against adapter-reported measurements."""
|
|
177
|
+
|
|
178
|
+
return [
|
|
179
|
+
_runtime_metric(assertion, context.target_run)
|
|
180
|
+
for assertion in _runtime_assertions(context.case)
|
|
181
|
+
]
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _evaluate_tool_trajectory(
|
|
185
|
+
context: _EvaluationContext,
|
|
186
|
+
) -> list[MetricResult]:
|
|
187
|
+
"""Report unavailable until A2A exposes normalized tool trajectories."""
|
|
188
|
+
|
|
189
|
+
requirements = _tool_requirements(context.case)
|
|
190
|
+
if not requirements:
|
|
191
|
+
return []
|
|
192
|
+
|
|
193
|
+
return [
|
|
194
|
+
MetricResult(
|
|
195
|
+
name="tool_trajectory",
|
|
196
|
+
status=MetricStatus.UNAVAILABLE,
|
|
197
|
+
required=required,
|
|
198
|
+
evidence={
|
|
199
|
+
"assertion": assertion_type,
|
|
200
|
+
"reason": "A2A target 未提供标准化工具轨迹",
|
|
201
|
+
},
|
|
202
|
+
)
|
|
203
|
+
for assertion_type, required in requirements
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _response_assertions(case: EvalCase) -> list[AssertionSpec]:
|
|
208
|
+
response_types = {
|
|
209
|
+
AssertionType.RESPONSE_EQUALS,
|
|
210
|
+
AssertionType.RESPONSE_CONTAINS,
|
|
211
|
+
AssertionType.RESPONSE_NOT_CONTAINS,
|
|
212
|
+
AssertionType.RESPONSE_JSON_SCHEMA,
|
|
213
|
+
}
|
|
214
|
+
return [assertion for assertion in case.assertions if assertion.type in response_types]
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _runtime_assertions(case: EvalCase) -> list[AssertionSpec]:
|
|
218
|
+
return [
|
|
219
|
+
assertion for assertion in case.assertions if assertion.type.value.startswith("runtime.")
|
|
220
|
+
]
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _tool_requirements(case: EvalCase) -> list[tuple[str, bool]]:
|
|
224
|
+
requirements = [
|
|
225
|
+
(assertion.type.value, assertion.required)
|
|
226
|
+
for assertion in case.assertions
|
|
227
|
+
if assertion.type in {AssertionType.TOOL_CALLED, AssertionType.TOOL_NOT_CALLED}
|
|
228
|
+
]
|
|
229
|
+
requirements.extend(("tool.expected", True) for turn in case.turns for _ in turn.expected_tools)
|
|
230
|
+
return requirements
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _response_metric(assertion: AssertionSpec, output: str) -> MetricResult:
|
|
234
|
+
reason = ""
|
|
235
|
+
if assertion.type is AssertionType.RESPONSE_EQUALS:
|
|
236
|
+
passed = output == assertion.value
|
|
237
|
+
elif assertion.type is AssertionType.RESPONSE_CONTAINS:
|
|
238
|
+
passed = assertion.value in output
|
|
239
|
+
elif assertion.type is AssertionType.RESPONSE_NOT_CONTAINS:
|
|
240
|
+
passed = assertion.value not in output
|
|
241
|
+
else:
|
|
242
|
+
try:
|
|
243
|
+
validate_json(json.loads(output), assertion.value)
|
|
244
|
+
passed = True
|
|
245
|
+
except (json.JSONDecodeError, JSONSchemaValidationError) as exc:
|
|
246
|
+
passed = False
|
|
247
|
+
reason = str(exc)
|
|
248
|
+
|
|
249
|
+
return _metric(
|
|
250
|
+
"response_contract",
|
|
251
|
+
assertion,
|
|
252
|
+
passed=passed,
|
|
253
|
+
reason=reason,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _runtime_metric(assertion: AssertionSpec, target_run: TargetRun) -> MetricResult:
|
|
258
|
+
actual: int | None
|
|
259
|
+
if assertion.type is AssertionType.RUNTIME_MAX_LATENCY_MS:
|
|
260
|
+
actual = target_run.duration_ms
|
|
261
|
+
elif not target_run.usage.reported:
|
|
262
|
+
actual = None
|
|
263
|
+
elif assertion.type is AssertionType.RUNTIME_MAX_INPUT_TOKENS:
|
|
264
|
+
actual = target_run.usage.input_tokens
|
|
265
|
+
else:
|
|
266
|
+
actual = target_run.usage.output_tokens
|
|
267
|
+
|
|
268
|
+
if actual is None:
|
|
269
|
+
return MetricResult(
|
|
270
|
+
name="runtime_budget",
|
|
271
|
+
status=MetricStatus.UNAVAILABLE,
|
|
272
|
+
required=assertion.required,
|
|
273
|
+
evidence={
|
|
274
|
+
"assertion": assertion.type.value,
|
|
275
|
+
"reason": "Target 未提供该运行指标",
|
|
276
|
+
},
|
|
277
|
+
)
|
|
278
|
+
return _metric(
|
|
279
|
+
"runtime_budget",
|
|
280
|
+
assertion,
|
|
281
|
+
passed=actual <= assertion.value,
|
|
282
|
+
evidence={"actual": actual},
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def _metric(
|
|
287
|
+
name: str,
|
|
288
|
+
assertion: AssertionSpec,
|
|
289
|
+
*,
|
|
290
|
+
passed: bool,
|
|
291
|
+
reason: str = "",
|
|
292
|
+
evidence: dict[str, Any] | None = None,
|
|
293
|
+
) -> MetricResult:
|
|
294
|
+
details = {"assertion": assertion.type.value, **(evidence or {})}
|
|
295
|
+
if reason:
|
|
296
|
+
details["reason"] = reason
|
|
297
|
+
return MetricResult(
|
|
298
|
+
name=name,
|
|
299
|
+
status=MetricStatus.PASS if passed else MetricStatus.FAIL,
|
|
300
|
+
score=1.0 if passed else 0.0,
|
|
301
|
+
required=assertion.required,
|
|
302
|
+
evidence=details,
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def _evaluator_error_metric(
|
|
307
|
+
evaluator: _EvaluatorDefinition,
|
|
308
|
+
error: Exception,
|
|
309
|
+
) -> MetricResult:
|
|
310
|
+
return MetricResult(
|
|
311
|
+
name=evaluator.metric_name,
|
|
312
|
+
status=MetricStatus.ERROR,
|
|
313
|
+
evidence={
|
|
314
|
+
"evaluator": evaluator.evaluator_id,
|
|
315
|
+
"reason": "评估器执行失败",
|
|
316
|
+
"errorType": type(error).__name__,
|
|
317
|
+
},
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _score_metric(
|
|
322
|
+
*,
|
|
323
|
+
name: str,
|
|
324
|
+
score: float,
|
|
325
|
+
evidence: dict[str, Any],
|
|
326
|
+
) -> MetricResult:
|
|
327
|
+
return MetricResult(
|
|
328
|
+
name=name,
|
|
329
|
+
status=MetricStatus.PASS if score >= _RESPONSE_MATCH_THRESHOLD else MetricStatus.FAIL,
|
|
330
|
+
score=score,
|
|
331
|
+
evidence=evidence,
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def _final_expected_output(case: EvalCase) -> str | None:
|
|
336
|
+
return case.turns[-1].expected_output
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def _judge_unavailable_reason(config: EvaluationConfig) -> str | None:
|
|
340
|
+
if config.data_policy is not DataPolicy.FULL_TRACE:
|
|
341
|
+
return "Judge 需要 dataPolicy=full_trace"
|
|
342
|
+
if not config.judge_model:
|
|
343
|
+
return "未配置 judgeModel"
|
|
344
|
+
if not config.judge_api_base:
|
|
345
|
+
return "未配置 judgeApiBase"
|
|
346
|
+
if not os.getenv(config.judge_api_key_env):
|
|
347
|
+
return f"未设置 Judge 密钥环境变量: {config.judge_api_key_env}"
|
|
348
|
+
return None
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def _judge_score(
|
|
352
|
+
*,
|
|
353
|
+
input_text: str,
|
|
354
|
+
actual_output: str,
|
|
355
|
+
expected_output: str,
|
|
356
|
+
config: EvaluationConfig,
|
|
357
|
+
) -> float:
|
|
358
|
+
return _run_llm_judge(
|
|
359
|
+
input_text=input_text,
|
|
360
|
+
actual_output=actual_output,
|
|
361
|
+
expected_output=expected_output,
|
|
362
|
+
model=config.judge_model or "",
|
|
363
|
+
api_base=config.judge_api_base or "",
|
|
364
|
+
api_key=os.environ[config.judge_api_key_env],
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def _judge_unavailable_metric(reason: str) -> MetricResult:
|
|
369
|
+
return MetricResult(
|
|
370
|
+
name="response_quality",
|
|
371
|
+
status=MetricStatus.UNAVAILABLE,
|
|
372
|
+
evidence={"evaluator": LLM_JUDGE_EVALUATOR, "reason": reason},
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def _judge_error_metric(error: Exception) -> MetricResult:
|
|
377
|
+
return MetricResult(
|
|
378
|
+
name="response_quality",
|
|
379
|
+
status=MetricStatus.ERROR,
|
|
380
|
+
evidence={
|
|
381
|
+
"evaluator": LLM_JUDGE_EVALUATOR,
|
|
382
|
+
"reason": "Judge 执行失败",
|
|
383
|
+
"errorType": type(error).__name__,
|
|
384
|
+
},
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def _judge_score_metric(score: float, judge_model: str | None) -> MetricResult:
|
|
389
|
+
return _score_metric(
|
|
390
|
+
name="response_quality",
|
|
391
|
+
score=score,
|
|
392
|
+
evidence={
|
|
393
|
+
"evaluator": LLM_JUDGE_EVALUATOR,
|
|
394
|
+
"threshold": _RESPONSE_MATCH_THRESHOLD,
|
|
395
|
+
"judgeModel": judge_model,
|
|
396
|
+
},
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def _rouge_1_f1(actual: str, expected: str) -> float:
|
|
401
|
+
actual_tokens = Counter(_TOKEN_PATTERN.findall(actual.lower()))
|
|
402
|
+
expected_tokens = Counter(_TOKEN_PATTERN.findall(expected.lower()))
|
|
403
|
+
if not actual_tokens or not expected_tokens:
|
|
404
|
+
return float(actual.strip() == expected.strip())
|
|
405
|
+
|
|
406
|
+
overlap = sum((actual_tokens & expected_tokens).values())
|
|
407
|
+
precision = overlap / sum(actual_tokens.values())
|
|
408
|
+
recall = overlap / sum(expected_tokens.values())
|
|
409
|
+
return 2 * precision * recall / (precision + recall) if precision + recall else 0.0
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def _run_llm_judge(
|
|
413
|
+
*,
|
|
414
|
+
input_text: str,
|
|
415
|
+
actual_output: str,
|
|
416
|
+
expected_output: str,
|
|
417
|
+
model: str,
|
|
418
|
+
api_base: str,
|
|
419
|
+
api_key: str,
|
|
420
|
+
) -> float:
|
|
421
|
+
"""Run the minimal external Judge configuration."""
|
|
422
|
+
|
|
423
|
+
os.environ.setdefault("DEEPEVAL_TELEMETRY_OPT_OUT", "YES")
|
|
424
|
+
from deepeval.metrics import GEval
|
|
425
|
+
from deepeval.models import LocalModel
|
|
426
|
+
from deepeval.test_case import LLMTestCase, LLMTestCaseParams
|
|
427
|
+
|
|
428
|
+
judge = LocalModel(model=model, base_url=api_base, api_key=api_key)
|
|
429
|
+
metric = GEval(
|
|
430
|
+
name="Response quality",
|
|
431
|
+
criteria=(
|
|
432
|
+
"Determine whether the actual output is factually correct "
|
|
433
|
+
"based on the expected output."
|
|
434
|
+
),
|
|
435
|
+
evaluation_params=[
|
|
436
|
+
LLMTestCaseParams.INPUT,
|
|
437
|
+
LLMTestCaseParams.ACTUAL_OUTPUT,
|
|
438
|
+
LLMTestCaseParams.EXPECTED_OUTPUT,
|
|
439
|
+
],
|
|
440
|
+
threshold=_RESPONSE_MATCH_THRESHOLD,
|
|
441
|
+
model=judge,
|
|
442
|
+
)
|
|
443
|
+
metric.measure(
|
|
444
|
+
LLMTestCase(
|
|
445
|
+
input=input_text,
|
|
446
|
+
actual_output=actual_output,
|
|
447
|
+
expected_output=expected_output,
|
|
448
|
+
)
|
|
449
|
+
)
|
|
450
|
+
return float(metric.score)
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
_EVALUATORS = (
|
|
454
|
+
_EvaluatorDefinition("response_contract@v1", "response_contract", _evaluate_response_contract),
|
|
455
|
+
_EvaluatorDefinition("runtime_budget@v1", "runtime_budget", _evaluate_runtime_budget),
|
|
456
|
+
_EvaluatorDefinition("tool_trajectory@v1", "tool_trajectory", _evaluate_tool_trajectory),
|
|
457
|
+
_EvaluatorDefinition(REFERENCE_MATCH_EVALUATOR, "response_match", _evaluate_reference_match),
|
|
458
|
+
_EvaluatorDefinition(LLM_JUDGE_EVALUATOR, "response_quality", _evaluate_llm_judge),
|
|
459
|
+
)
|
|
460
|
+
_EVALUATOR_REGISTRY = {evaluator.evaluator_id: evaluator for evaluator in _EVALUATORS}
|
|
461
|
+
SUPPORTED_EVALUATORS = tuple(evaluator.evaluator_id for evaluator in _EVALUATORS)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Single public evaluation handoff shared by CLI and Studio."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from uuid import uuid4
|
|
7
|
+
|
|
8
|
+
from .adapters import EvaluationNotImplementedError, TargetAdapter
|
|
9
|
+
from .contracts import (
|
|
10
|
+
CaseRun,
|
|
11
|
+
EvalRunReport,
|
|
12
|
+
EvalRunSpec,
|
|
13
|
+
EvalRunStatus,
|
|
14
|
+
EvaluationRequest,
|
|
15
|
+
MetricStatus,
|
|
16
|
+
TargetRunStatus,
|
|
17
|
+
)
|
|
18
|
+
from .evaluators import evaluate_case_async
|
|
19
|
+
from .storage import EvaluationStorage, EvaluationStorageError
|
|
20
|
+
from .target import EvaluationExecutionError, EvaluationTarget
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"EvaluationExecutionError",
|
|
24
|
+
"EvaluationNotImplementedError",
|
|
25
|
+
"TargetAdapter",
|
|
26
|
+
"execute_evaluation",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
async def execute_evaluation(
|
|
31
|
+
request: EvaluationRequest,
|
|
32
|
+
*,
|
|
33
|
+
on_case_started: Callable[[str, int, int], None] | None = None,
|
|
34
|
+
) -> EvalRunReport:
|
|
35
|
+
"""Execute and persist one evaluation request."""
|
|
36
|
+
|
|
37
|
+
target = EvaluationTarget(request.target, request.config)
|
|
38
|
+
snapshot = await target.snapshot()
|
|
39
|
+
spec = EvalRunSpec(
|
|
40
|
+
id=f"eval_{uuid4().hex}",
|
|
41
|
+
evalset=request.evalset,
|
|
42
|
+
target=snapshot,
|
|
43
|
+
config=request.config,
|
|
44
|
+
)
|
|
45
|
+
case_runs = await _run_cases(target, spec, on_case_started=on_case_started)
|
|
46
|
+
report = EvalRunReport(
|
|
47
|
+
spec=spec,
|
|
48
|
+
status=_report_status(case_runs),
|
|
49
|
+
case_runs=case_runs,
|
|
50
|
+
)
|
|
51
|
+
_persist_report(request, report)
|
|
52
|
+
return report
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
async def _run_cases(
|
|
56
|
+
target: EvaluationTarget,
|
|
57
|
+
spec: EvalRunSpec,
|
|
58
|
+
*,
|
|
59
|
+
on_case_started: Callable[[str, int, int], None] | None,
|
|
60
|
+
) -> list[CaseRun]:
|
|
61
|
+
case_runs: list[CaseRun] = []
|
|
62
|
+
total_cases = len(spec.evalset.cases)
|
|
63
|
+
for index, case in enumerate(spec.evalset.cases, start=1):
|
|
64
|
+
_notify_case_started(on_case_started, case.id, index, total_cases)
|
|
65
|
+
target_run = await target.run_case(spec, case)
|
|
66
|
+
try:
|
|
67
|
+
metrics = await evaluate_case_async(
|
|
68
|
+
case, target_run, spec.config.evaluators, spec.config
|
|
69
|
+
)
|
|
70
|
+
except ValueError as exc:
|
|
71
|
+
raise EvaluationExecutionError(str(exc)) from exc
|
|
72
|
+
case_run = CaseRun(
|
|
73
|
+
case_id=case.id,
|
|
74
|
+
attempt=spec.attempt,
|
|
75
|
+
target_run=target_run,
|
|
76
|
+
metrics=metrics,
|
|
77
|
+
)
|
|
78
|
+
case_runs.append(case_run)
|
|
79
|
+
if spec.config.fail_fast and not case_run.passed:
|
|
80
|
+
break
|
|
81
|
+
return case_runs
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _notify_case_started(
|
|
85
|
+
callback: Callable[[str, int, int], None] | None,
|
|
86
|
+
case_id: str,
|
|
87
|
+
index: int,
|
|
88
|
+
total_cases: int,
|
|
89
|
+
) -> None:
|
|
90
|
+
if callback is None:
|
|
91
|
+
return
|
|
92
|
+
try:
|
|
93
|
+
callback(case_id, index, total_cases)
|
|
94
|
+
except Exception:
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _report_status(case_runs: list[CaseRun]) -> EvalRunStatus:
|
|
99
|
+
if any(
|
|
100
|
+
case.target_run.status is TargetRunStatus.ERROR
|
|
101
|
+
or any(metric.required and metric.status is MetricStatus.ERROR for metric in case.metrics)
|
|
102
|
+
for case in case_runs
|
|
103
|
+
):
|
|
104
|
+
return EvalRunStatus.ERROR
|
|
105
|
+
if any(case.target_run.status is TargetRunStatus.CANCELLED for case in case_runs):
|
|
106
|
+
return EvalRunStatus.CANCELLED
|
|
107
|
+
if any(not case.passed for case in case_runs):
|
|
108
|
+
return EvalRunStatus.FAILED
|
|
109
|
+
return EvalRunStatus.PASSED
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _persist_report(request: EvaluationRequest, report: EvalRunReport) -> None:
|
|
113
|
+
if not request.report_dir:
|
|
114
|
+
return
|
|
115
|
+
try:
|
|
116
|
+
EvaluationStorage(request.report_dir).write_report(report)
|
|
117
|
+
except EvaluationStorageError as exc:
|
|
118
|
+
raise EvaluationExecutionError("评测报告写入失败") from exc
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Local, atomic storage for the shared evaluation report contract."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from .contracts import EvalRunReport
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class EvaluationStorageError(RuntimeError):
|
|
12
|
+
"""Raised when a report cannot be read or safely persisted."""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class EvaluationStorage:
|
|
16
|
+
"""Persist reports below one workspace-owned evaluation directory."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, root: str | Path):
|
|
19
|
+
self.root = Path(root).expanduser().resolve()
|
|
20
|
+
|
|
21
|
+
def report_path(self, run_id: str) -> Path:
|
|
22
|
+
"""Return the only report location allowed for a run identifier."""
|
|
23
|
+
|
|
24
|
+
if not run_id or Path(run_id).name != run_id:
|
|
25
|
+
raise EvaluationStorageError("run_id 只能包含文件名,不允许路径穿越")
|
|
26
|
+
return self.root / run_id / "report.json"
|
|
27
|
+
|
|
28
|
+
def write_report(self, report: EvalRunReport) -> Path:
|
|
29
|
+
"""Write the completed report atomically after its artifact directory exists."""
|
|
30
|
+
|
|
31
|
+
path = self.report_path(report.spec.id)
|
|
32
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
33
|
+
temporary = path.with_name(f".{path.name}.{report.report_digest}.tmp")
|
|
34
|
+
payload = json.dumps(
|
|
35
|
+
report.model_dump(mode="json", by_alias=True, exclude_none=True),
|
|
36
|
+
ensure_ascii=False,
|
|
37
|
+
sort_keys=True,
|
|
38
|
+
indent=2,
|
|
39
|
+
) + "\n"
|
|
40
|
+
try:
|
|
41
|
+
temporary.write_text(payload, encoding="utf-8")
|
|
42
|
+
temporary.replace(path)
|
|
43
|
+
except OSError as exc:
|
|
44
|
+
temporary.unlink(missing_ok=True)
|
|
45
|
+
raise EvaluationStorageError("评测报告写入失败") from exc
|
|
46
|
+
return path
|
|
47
|
+
|
|
48
|
+
def read_report(self, run_id: str) -> EvalRunReport:
|
|
49
|
+
path = self.report_path(run_id)
|
|
50
|
+
try:
|
|
51
|
+
return EvalRunReport.model_validate_json(path.read_text(encoding="utf-8"))
|
|
52
|
+
except FileNotFoundError as exc:
|
|
53
|
+
raise EvaluationStorageError("评测报告不存在") from exc
|
|
54
|
+
except (OSError, ValueError) as exc:
|
|
55
|
+
raise EvaluationStorageError("评测报告损坏或不可读") from exc
|
|
56
|
+
|
|
57
|
+
def list_reports(self) -> list[EvalRunReport]:
|
|
58
|
+
if not self.root.is_dir():
|
|
59
|
+
return []
|
|
60
|
+
reports: list[EvalRunReport] = []
|
|
61
|
+
for path in sorted(self.root.glob("*/report.json")):
|
|
62
|
+
try:
|
|
63
|
+
reports.append(
|
|
64
|
+
EvalRunReport.model_validate_json(path.read_text(encoding="utf-8"))
|
|
65
|
+
)
|
|
66
|
+
except (OSError, ValueError):
|
|
67
|
+
continue
|
|
68
|
+
return reports
|