agentengine-sdk-python 0.8.0__py3-none-any.whl → 0.8.2__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.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/METADATA +43 -7
- agentengine_sdk_python-0.8.2.dist-info/RECORD +778 -0
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/WHEEL +1 -1
- ksadk/a2a/__init__.py +2 -0
- ksadk/a2a/_space_client_events.py +381 -0
- ksadk/a2a/bootstrap.py +0 -2
- ksadk/a2a/card.py +6 -111
- ksadk/a2a/control_plane.py +239 -1
- ksadk/a2a/event_adapter.py +156 -64
- ksadk/a2a/executor.py +195 -172
- ksadk/a2a/routes.py +12 -5
- ksadk/a2a/server.py +1 -8
- ksadk/a2a/service_env.py +33 -0
- ksadk/a2a/space_client.py +43 -349
- ksadk/a2a_card.py +101 -0
- ksadk/a2ui/core.py +222 -53
- ksadk/agui/_agent_helpers.py +243 -0
- ksadk/agui/a2ui_projection.py +12 -5
- ksadk/agui/agent.py +474 -275
- ksadk/agui/config.py +11 -5
- ksadk/agui/routes.py +7 -15
- ksadk/api/client.py +530 -40
- ksadk/api/environment.py +27 -0
- ksadk/builders/code_builder.py +352 -53
- ksadk/builders/container_builder.py +71 -44
- ksadk/builders/framework_requirements.py +2 -1
- ksadk/builders/ks3_uploader.py +2 -2
- ksadk/builders/managed_runtime_builder.py +60 -28
- ksadk/cli/__init__.py +25 -0
- ksadk/cli/cmd_a2a.py +18 -31
- ksadk/cli/cmd_create.py +13 -26
- ksadk/cli/cmd_dashboard.py +15 -1
- ksadk/cli/cmd_deploy.py +28 -3
- ksadk/cli/cmd_eval.py +443 -0
- ksadk/cli/cmd_evalset.py +284 -0
- ksadk/cli/cmd_files.py +5 -1
- ksadk/cli/cmd_hermes.py +137 -163
- ksadk/cli/cmd_invoke.py +28 -38
- ksadk/cli/cmd_launch.py +12 -0
- ksadk/cli/cmd_managed_runtime.py +95 -0
- ksadk/cli/cmd_observe.py +85 -0
- ksadk/cli/cmd_openclaw.py +85 -479
- ksadk/cli/cmd_replay.py +28 -4
- ksadk/cli/cmd_run.py +29 -67
- ksadk/cli/cmd_studio.py +201 -0
- ksadk/cli/cmd_web.py +15 -6
- ksadk/cli/dry_run.py +2 -1
- ksadk/cli/env_options.py +83 -0
- ksadk/cli/global_options.py +3 -1
- ksadk/cli/hermes_env.py +151 -0
- ksadk/cli/invoke_payload.py +49 -0
- ksadk/cli/network_options.py +7 -5
- ksadk/cli/openclaw_env.py +458 -0
- ksadk/cli/runtime_bootstrap.py +51 -0
- ksadk/cli/ui.py +6 -0
- ksadk/cli/workflow_common.py +5 -5
- ksadk/codex/__init__.py +3 -3
- ksadk/codex/client.py +833 -49
- ksadk/codex/phase.py +1 -1
- ksadk/codex/runtime.py +720 -127
- ksadk/common/kop_client.py +232 -0
- ksadk/configs/__init__.py +1 -3
- ksadk/configs/env_registry.py +244 -45
- ksadk/configs/env_registry_pcm.py +181 -0
- ksadk/configs/env_var_spec.py +18 -0
- ksadk/configs/global_config.py +6 -1
- ksadk/configs/settings.py +5 -108
- ksadk/context_engine/__init__.py +98 -0
- ksadk/context_engine/assembler.py +176 -0
- ksadk/context_engine/baseline.py +419 -0
- ksadk/context_engine/cache_observability.py +228 -0
- ksadk/context_engine/capabilities.py +443 -0
- ksadk/context_engine/contributors.py +344 -0
- ksadk/context_engine/hosted_pipeline.py +417 -0
- ksadk/context_engine/models.py +117 -0
- ksadk/context_engine/planner.py +698 -0
- ksadk/context_engine/policies.py +319 -0
- ksadk/context_engine/projection.py +31 -0
- ksadk/context_engine/shadow_plan.py +266 -0
- ksadk/context_engine/tokenizer.py +164 -0
- ksadk/conversations/__init__.py +85 -94
- ksadk/conversations/context.py +126 -6
- ksadk/conversations/message_projection.py +292 -28
- ksadk/conversations/model_context.py +49 -3
- ksadk/conversations/runtime_compaction.py +207 -5
- ksadk/conversations/runtime_input.py +193 -3
- ksadk/conversations/runtime_invocation.py +81 -3
- ksadk/conversations/runtime_observability.py +157 -4
- ksadk/conversations/runtime_payloads.py +42 -0
- ksadk/conversations/runtime_preparation.py +280 -2
- ksadk/conversations/runtime_resume.py +71 -32
- ksadk/conversations/runtime_stream_events.py +94 -9
- ksadk/conversations/runtime_streaming.py +175 -22
- ksadk/conversations/semantic_summary.py +311 -1
- ksadk/conversations/session_lock.py +51 -0
- ksadk/deployment/env_forward.py +72 -0
- ksadk/deployment/managed_runtime.py +38 -0
- ksadk/deployment/manager.py +24 -8
- ksadk/deployment/providers/serverless.py +228 -92
- ksadk/evaluation/__init__.py +116 -0
- ksadk/evaluation/a2a_adapter.py +452 -0
- ksadk/evaluation/adapters.py +67 -0
- ksadk/evaluation/agent_eval_client.py +395 -0
- ksadk/evaluation/cloud_binding.py +80 -0
- ksadk/evaluation/cloud_converter.py +194 -0
- ksadk/evaluation/cloud_service.py +199 -0
- ksadk/evaluation/contracts.py +478 -0
- ksadk/evaluation/evalset.py +351 -0
- ksadk/evaluation/evaluators.py +627 -0
- ksadk/evaluation/evidence.py +258 -0
- ksadk/evaluation/executor.py +143 -0
- ksadk/evaluation/local_adapter.py +550 -0
- ksadk/evaluation/service_env.py +27 -0
- ksadk/evaluation/storage.py +68 -0
- ksadk/evaluation/studio_build_adapter.py +253 -0
- ksadk/evaluation/target.py +82 -0
- ksadk/events/__init__.py +13 -13
- ksadk/events/_v1_compat/__init__.py +1 -0
- ksadk/events/_v1_compat/models.py +299 -0
- ksadk/events/_v1_compat/parser.py +247 -0
- ksadk/events/_v1_compat/projection.py +753 -0
- ksadk/events/adapters/__init__.py +34 -0
- ksadk/events/adapters/_a2a_snapshot.py +622 -0
- ksadk/events/adapters/_a2a_support.py +275 -0
- ksadk/events/adapters/_codex_interactions.py +375 -0
- ksadk/events/adapters/_codex_items.py +801 -0
- ksadk/events/adapters/_codex_validators.py +311 -0
- ksadk/events/adapters/_langgraph_support.py +785 -0
- ksadk/events/adapters/a2a.py +841 -0
- ksadk/events/adapters/adk.py +503 -0
- ksadk/events/adapters/codex.py +717 -0
- ksadk/events/adapters/langgraph.py +745 -0
- ksadk/events/canonical.py +440 -0
- ksadk/events/canonical_replay.py +497 -0
- ksadk/events/canonical_store.py +468 -0
- ksadk/events/cold_recovery.py +257 -0
- ksadk/events/content.py +89 -0
- ksadk/events/identity.py +86 -0
- ksadk/events/pipeline.py +455 -0
- ksadk/events/projections.py +66 -0
- ksadk/events/reducer.py +661 -0
- ksadk/events/replay.py +3 -36
- ksadk/events/runtime_event.py +20 -256
- ksadk/events/session_event.py +324 -0
- ksadk/events/store.py +3 -316
- ksadk/events/v1_compat.py +41 -0
- ksadk/harness/__init__.py +3 -2
- ksadk/harness/app.py +114 -123
- ksadk/harness/config.py +1 -1
- ksadk/harness/runtime.py +467 -0
- ksadk/hermes_terminal.py +5 -0
- ksadk/identity/resolver.py +4 -3
- ksadk/interaction/__init__.py +28 -0
- ksadk/interaction/contracts.py +136 -0
- ksadk/interaction/ledger.py +189 -0
- ksadk/interaction/provider.py +122 -0
- ksadk/interaction/providers/__init__.py +52 -0
- ksadk/interaction/providers/adk.py +40 -0
- ksadk/interaction/providers/codex.py +94 -0
- ksadk/interaction/providers/langgraph.py +58 -0
- ksadk/kernel/__init__.py +117 -0
- ksadk/kernel/authorization.py +258 -0
- ksadk/kernel/bootstrap.py +1074 -0
- ksadk/kernel/contract_fingerprints.py +61 -0
- ksadk/kernel/contracts.py +362 -0
- ksadk/kernel/control.py +219 -0
- ksadk/kernel/errors.py +79 -0
- ksadk/kernel/ingress.py +1102 -0
- ksadk/kernel/mapping.py +111 -0
- ksadk/kernel/memory_store.py +1133 -0
- ksadk/kernel/postgres_store.py +1756 -0
- ksadk/kernel/recovery.py +452 -0
- ksadk/kernel/runtime_identity.py +103 -0
- ksadk/kernel/sql/001_agent_kernel.sql +120 -0
- ksadk/kernel/sqlite_store.py +1410 -0
- ksadk/kernel/state.py +145 -0
- ksadk/kernel/store.py +232 -0
- ksadk/kernel/worker.py +953 -0
- ksadk/knowledge_base/client.py +22 -4
- ksadk/knowledge_base/service.py +32 -5
- ksadk/managed_a2a_card.py +160 -0
- ksadk/managed_runtime.py +16 -9
- ksadk/memory/__init__.py +61 -0
- ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
- ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
- ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
- ksadk/memory/adk/backends/sdk_ltm_backend.py +394 -5
- ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
- ksadk/memory/adk/long_term_memory.py +3 -2
- ksadk/memory/coordinator.py +461 -0
- ksadk/memory/events.py +202 -0
- ksadk/memory/extraction.py +228 -0
- ksadk/memory/ltm_backend_factory.py +16 -3
- ksadk/memory/models.py +316 -0
- ksadk/memory/policy.py +215 -0
- ksadk/memory/provider.py +47 -0
- ksadk/memory/provider_adapter.py +159 -0
- ksadk/memory/provider_resolver.py +71 -0
- ksadk/memory/providers/__init__.py +5 -0
- ksadk/memory/providers/local_sqlite.py +490 -0
- ksadk/memory/resolved_policy.py +145 -0
- ksadk/memory/service.py +198 -8
- ksadk/memory/tool.py +4 -0
- ksadk/model_proxy/bootstrap.py +16 -9
- ksadk/model_proxy/config.py +22 -1
- ksadk/model_proxy/detect.py +202 -9
- ksadk/model_proxy/namespace.py +67 -15
- ksadk/model_proxy/server.py +168 -6
- ksadk/model_proxy/transform.py +105 -3
- ksadk/observability/__init__.py +25 -0
- ksadk/observability/session_log.py +420 -0
- ksadk/observability/trajectory.py +105 -0
- ksadk/prompts/__init__.py +71 -0
- ksadk/prompts/compiler.py +215 -0
- ksadk/prompts/models.py +82 -0
- ksadk/prompts/projection.py +89 -0
- ksadk/prompts/resolved.py +137 -0
- ksadk/prompts/sources.py +233 -0
- ksadk/runners/_langgraph_runner_streams.py +822 -0
- ksadk/runners/adk_runner.py +14 -31
- ksadk/runners/base_runner.py +44 -3
- ksadk/runners/factory.py +3 -3
- ksadk/runners/langgraph_runner.py +252 -433
- ksadk/runners/utils/__init__.py +0 -10
- ksadk/runners/utils/loader.py +16 -0
- ksadk/runtime/__init__.py +67 -41
- ksadk/runtime/_runner_adapter/__init__.py +1 -0
- ksadk/runtime/_runner_adapter/stream_mapping.py +788 -0
- ksadk/runtime/adapter.py +199 -16
- ksadk/runtime/conversation_execution.py +687 -0
- ksadk/runtime/executor.py +392 -0
- ksadk/runtime/factory.py +342 -0
- ksadk/runtime/framework_adapters.py +6 -12
- ksadk/runtime/hosted_finalizer.py +268 -0
- ksadk/runtime/launch.py +61 -0
- ksadk/runtime/preprocessing.py +49 -14
- ksadk/runtime/runner_adapter.py +330 -391
- ksadk/runtime/runner_loading.py +36 -0
- ksadk/runtime/usage.py +33 -0
- ksadk/sandbox/backends/e2b.py +36 -3
- ksadk/server/__init__.py +39 -4
- ksadk/server/app.py +18 -492
- ksadk/server/composition.py +36 -2
- ksadk/server/factory.py +210 -149
- ksadk/server/routes/common.py +15 -46
- ksadk/server/routes/control.py +13 -9
- ksadk/server/routes/kernel_ingress.py +258 -0
- ksadk/server/routes/misc.py +10 -33
- ksadk/server/routes/models.py +14 -6
- ksadk/server/routes/openai_compat.py +129 -27
- ksadk/server/routes/projection.py +84 -16
- ksadk/server/routes/run.py +347 -460
- ksadk/server/routes/sessions.py +37 -40
- ksadk/server/routes/streaming.py +52 -7
- ksadk/server/routes/workspace.py +54 -21
- ksadk/server/static/assets/{ArtifactsPanel-Cjnqt-8W.js → ArtifactsPanel-DSU1sWD_.js} +1 -1
- ksadk/server/static/assets/{CodeBlock-BqyqZfuB.js → CodeBlock-DOH6MVcn.js} +4 -4
- ksadk/server/static/assets/{MathMessageMarkdown-BpH7jiFM.js → MathMessageMarkdown-BL8my1R2.js} +4 -4
- ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
- ksadk/server/static/assets/MermaidBlock-Dz4IP-Tx.js +312 -0
- ksadk/server/static/assets/NativeTerminalPanel-DUrK0JpZ.js +1 -0
- ksadk/server/static/assets/abnfDiagram-VCTEODGH-g20pFzNV.js +1 -0
- ksadk/server/static/assets/arc-C4FzinUA.js +1 -0
- ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +1 -0
- ksadk/server/static/assets/architectureDiagram-5GKGNRK7-DpIqL5h4.js +36 -0
- ksadk/server/static/assets/blockDiagram-NRAW4CY4-BjkljTNz.js +129 -0
- ksadk/server/static/assets/c4Diagram-UCG6FXSJ-Dk_ieq2X.js +38 -0
- ksadk/server/static/assets/channel-4cQHKtx1.js +1 -0
- ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +1 -0
- ksadk/server/static/assets/{chunk-FMBD7UC4-BGhvzDYt.js → chunk-5VM5RSS4-BVHAchFb.js} +1 -1
- ksadk/server/static/assets/{chunk-ND2GUHAM-D98vPd-E.js → chunk-F27PBJKO-C-ipQzuS.js} +1 -1
- ksadk/server/static/assets/chunk-G27WJ6UU-C2EyJbIK.js +231 -0
- ksadk/server/static/assets/{chunk-4BX2VUAB-CsWIQRhc.js → chunk-JWPE2WC7-vYvVJb_M.js} +1 -1
- ksadk/server/static/assets/chunk-LCL6LL3I-BcI6ysPT.js +206 -0
- ksadk/server/static/assets/chunk-POPQ4Y6H-C030x_Z1.js +1 -0
- ksadk/server/static/assets/chunk-RHFEMEQ7-yyGpsz4n.js +168 -0
- ksadk/server/static/assets/chunk-SVP7TREG-BLTlmMU7.js +88 -0
- ksadk/server/static/assets/chunk-XXDRQBXY-C_32ArgP.js +1 -0
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-S5V4N54A-CX3yotHq.js → cose-bilkent-JH36ORCC-9YQYwdl0.js} +1 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +1 -0
- ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-ErLF5N13.js +62 -0
- ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
- ksadk/server/static/assets/dagre-3AP2YEHR-DFiQF-6f.js +4 -0
- ksadk/server/static/assets/dagre-BuhGnRI1.js +1 -0
- ksadk/server/static/assets/diagram-S7CK7UJ4-Bt1v8-GC.js +30 -0
- ksadk/server/static/assets/diagram-UQ7AKVKN-DSCxJdBK.js +41 -0
- ksadk/server/static/assets/diagram-VSXAHHWV-DHfYwp_9.js +3 -0
- ksadk/server/static/assets/diagram-VX7I27RA-DdzD-4Le.js +24 -0
- ksadk/server/static/assets/diagram-Z3DM3KII-Du-nAJ9F.js +24 -0
- ksadk/server/static/assets/{dist-D82mtD2s.js → dist-8hqcx0sU.js} +1 -1
- ksadk/server/static/assets/dist-B7seoj3d.js +1 -0
- ksadk/server/static/assets/{dist-DHn6nBzr.js → dist-BE7bu-DL.js} +1 -1
- ksadk/server/static/assets/{dist-eoW6tZXA.js → dist-BVDffZ0U.js} +1 -1
- ksadk/server/static/assets/{dist-C2xjE7cO.js → dist-BX8z72IC.js} +1 -1
- ksadk/server/static/assets/{dist-CgF3fj15.js → dist-Bf2M8m3N.js} +1 -1
- ksadk/server/static/assets/{dist-Bs-jQcRX.js → dist-BjU6y-A2.js} +1 -1
- ksadk/server/static/assets/{dist-Djgl2wVZ.js → dist-BytlxIDT.js} +1 -1
- ksadk/server/static/assets/{dist-CVQRZjPu.js → dist-CSh_DE14.js} +1 -1
- ksadk/server/static/assets/{dist-6CVKuTAe.js → dist-CXYYBw3_.js} +1 -1
- ksadk/server/static/assets/{dist-DlzCRy0S.js → dist-C_wsv-Qd.js} +1 -1
- ksadk/server/static/assets/{dist-DF06ORQo.js → dist-ClxGviKw.js} +1 -1
- ksadk/server/static/assets/{dist-Cf23NY4L.js → dist-CttYUqzS.js} +1 -1
- ksadk/server/static/assets/{dist-ivOya1LD.js → dist-DNp6rLRA.js} +1 -1
- ksadk/server/static/assets/{dist-BibcG1V9.js → dist-DUX-id_F.js} +1 -1
- ksadk/server/static/assets/{dist-BUHRxvDG.js → dist-DmldrHd_.js} +1 -1
- ksadk/server/static/assets/{dist-BZ9n9AjO.js → dist-DnfXs8Vn.js} +2 -2
- ksadk/server/static/assets/{dist-DqNnNFrw.js → dist-Dq9gLD7L.js} +1 -1
- ksadk/server/static/assets/{dist-CGcp2ex8.js → dist-W-TIVntx.js} +1 -1
- ksadk/server/static/assets/{dist-Cwt7koer.js → dist-dDdADKFA.js} +1 -1
- ksadk/server/static/assets/{dist-C7-3jInC.js → dist-dydu68Fl.js} +1 -1
- ksadk/server/static/assets/{dist-C99THtIA.js → dist-ngtN0DJB.js} +1 -1
- ksadk/server/static/assets/ebnfDiagram-PWID7BFC-Da9C9NO1.js +1 -0
- ksadk/server/static/assets/erDiagram-SSCWMZ5O-EAGqqR79.js +99 -0
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +1 -0
- ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +1 -0
- ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-DqJsKb59.js +292 -0
- ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +1 -0
- ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-B6g4dtDi.js +106 -0
- ksadk/server/static/assets/index-8ipRcQ-M.js +240 -0
- ksadk/server/static/assets/index-ByFCqjlh.css +2 -0
- ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +1 -0
- ksadk/server/static/assets/infoDiagram-RXCK75RN-Djm_nbd5.js +2 -0
- ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-DLOHGvWw.js → ishikawaDiagram-5VMMS53U-DWya9SG2.js} +6 -6
- ksadk/server/static/assets/{journeyDiagram-JHISSGLW-BIzKeejT.js → journeyDiagram-EYS64GPL-DutxhSNI.js} +6 -6
- ksadk/server/static/assets/{kanban-definition-UN3LZRKU-BWHoFSw2.js → kanban-definition-3QL26DDD-DJdOF8Fm.js} +10 -10
- ksadk/server/static/assets/katex-vFWytM5c.js +257 -0
- ksadk/server/static/assets/{linear-CvMBw9cA.js → linear-BHjG8b-J.js} +1 -1
- ksadk/server/static/assets/mermaid-parser.core-KGSy4jWT.js +166 -0
- ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-CSAQxEAe.js → mindmap-definition-FBJOCRG2-9-HC88D4.js} +29 -29
- ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +1 -0
- ksadk/server/static/assets/pegDiagram-XKGWAZYB-DrEZd4fD.js +1 -0
- ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +1 -0
- ksadk/server/static/assets/pieDiagram-E7YTZNPT-DpjqOFFp.js +39 -0
- ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-CxIR4JXI.js → quadrantDiagram-AXDQQJYC-BiNhgOXX.js} +6 -6
- ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +1 -0
- ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +1 -0
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +1 -0
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +1 -0
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +1 -0
- ksadk/server/static/assets/railroadDiagram-O6MQD6OU-_Y3Ojg6G.js +1 -0
- ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-DeCFdg9K.js +84 -0
- ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-DpGa6EAV.js → sankeyDiagram-P5KCCOFB-CPH75rhw.js} +7 -7
- ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-NTKNGGe5.js → sequenceDiagram-WJ2MYXX4-OEpQQdr4.js} +10 -10
- ksadk/server/static/assets/sizeCapture-X5ZJPWSS-heUErzhI.js +1 -0
- ksadk/server/static/assets/stateDiagram-HBIQ2CUA-DvA3jSMB.js +1 -0
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +1 -0
- ksadk/server/static/assets/swimlanes-XN3QIQJK-CR-dfN_t.js +1 -0
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +8 -0
- ksadk/server/static/assets/{timeline-definition-PNZ67QCA-jqoYs3jQ.js → timeline-definition-24CTP7MA-DAVJf1TX.js} +7 -7
- ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +1 -0
- ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +1 -0
- ksadk/server/static/assets/vennDiagram-4TSXK5OY-DwM8eDkh.js +34 -0
- ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +1 -0
- ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DZL-Zz2t.js +78 -0
- ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js +7 -0
- ksadk/server/static/index.html +2 -2
- ksadk/sessions/__init__.py +26 -9
- ksadk/sessions/_local_service_sync.py +688 -0
- ksadk/sessions/_local_tables.py +21 -0
- ksadk/sessions/_postgres_schema.py +305 -0
- ksadk/sessions/_postgres_tables.py +15 -0
- ksadk/sessions/base.py +80 -1
- ksadk/sessions/in_memory.py +53 -2
- ksadk/sessions/local_service.py +63 -604
- ksadk/sessions/postgres_service.py +58 -148
- ksadk/sessions/resilient.py +35 -1
- ksadk/skills/runtime/backends/e2b.py +1 -1
- ksadk/skills/service_client.py +13 -3
- 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 +1598 -0
- ksadk/studio/api_catalog_routes.py +324 -0
- ksadk/studio/api_contracts.py +286 -0
- ksadk/studio/api_helpers.py +132 -0
- ksadk/studio/api_memory_routes.py +82 -0
- ksadk/studio/authoring.py +749 -0
- ksadk/studio/authoring_coordinator.py +1017 -0
- ksadk/studio/builder.py +397 -0
- ksadk/studio/capabilities.py +368 -0
- ksadk/studio/cloud.py +2099 -0
- ksadk/studio/codex_agent_service.py +694 -0
- ksadk/studio/codex_authoring.py +469 -0
- ksadk/studio/codex_builder.py +437 -0
- ksadk/studio/codex_manifest.py +307 -0
- ksadk/studio/codex_run.py +395 -0
- ksadk/studio/compiler.py +190 -0
- ksadk/studio/contracts.py +755 -0
- ksadk/studio/errors.py +47 -0
- ksadk/studio/event_store.py +214 -0
- ksadk/studio/framework_run.py +342 -0
- ksadk/studio/hosted_kernel.py +317 -0
- ksadk/studio/identifiers.py +33 -0
- ksadk/studio/manifest_resolver.py +131 -0
- ksadk/studio/mcp_runtime.py +229 -0
- ksadk/studio/model_client.py +629 -0
- ksadk/studio/model_profile_service.py +214 -0
- ksadk/studio/operations.py +275 -0
- ksadk/studio/otel_trace.py +1060 -0
- ksadk/studio/pagination.py +182 -0
- ksadk/studio/pcm_memory.py +85 -0
- ksadk/studio/python_tool_inspection.py +183 -0
- ksadk/studio/repository.py +327 -0
- ksadk/studio/resource_catalog.py +1260 -0
- ksadk/studio/run_service.py +1133 -0
- ksadk/studio/runtime_catalog.py +74 -0
- ksadk/studio/runtime_source.py +365 -0
- ksadk/studio/service.py +2249 -0
- ksadk/studio/shared_web.py +1004 -0
- ksadk/studio/skill_discovery.py +628 -0
- ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
- ksadk/studio/static/assets/index-BLpcdrgW.css +1 -0
- ksadk/studio/static/assets/index-CYekR2Xv.js +260 -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 +722 -0
- ksadk/studio/validator.py +265 -0
- ksadk/studio/workspace.py +135 -0
- ksadk/tools/gateway.py +9 -0
- ksadk/toolsets/__init__.py +27 -1
- ksadk/toolsets/a2a.py +426 -0
- ksadk/tracing/__init__.py +19 -21
- ksadk/tracing/setup.py +317 -403
- ksadk/tracing/span_utils.py +0 -44
- ksadk/version.py +1 -1
- ksadk_runtime_common/memory_backend/registry.py +56 -56
- ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
- ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
- ksadk_runtime_common/workspace_files/router.py +8 -2
- agentengine_sdk_python-0.8.0.dist-info/RECORD +0 -578
- ksadk/a2a/card_builder.py +0 -64
- ksadk/a2a/client.py +0 -309
- ksadk/events/parser.py +0 -191
- ksadk/harness/runner.py +0 -211
- ksadk/runners/codex_runner.py +0 -132
- ksadk/runners/utils/langfuse.py +0 -230
- ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
- ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +0 -303
- ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +0 -1
- ksadk/server/static/assets/arc-CFKwSk_B.js +0 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +0 -1
- ksadk/server/static/assets/architectureDiagram-3BPJPVTR-Dej8jX8c.js +0 -36
- ksadk/server/static/assets/blockDiagram-GPEHLZMM-1F64jqvy.js +0 -132
- ksadk/server/static/assets/c4Diagram-AAUBKEIU-9q7AUAKb.js +0 -10
- ksadk/server/static/assets/channel-iUGv2N24.js +0 -1
- ksadk/server/static/assets/chunk-2J33WTMH-6qgwJm7Q.js +0 -1
- ksadk/server/static/assets/chunk-55IACEB6-BK8paA20.js +0 -1
- ksadk/server/static/assets/chunk-727SXJPM-B-JEhy7h.js +0 -206
- ksadk/server/static/assets/chunk-AQP2D5EJ-DYBvMHAa.js +0 -231
- ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +0 -1
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +0 -1
- ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
- ksadk/server/static/assets/dagre-BM42HDAG-C7TguAWo.js +0 -4
- ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
- ksadk/server/static/assets/diagram-2AECGRRQ-Dd17_kws.js +0 -43
- ksadk/server/static/assets/diagram-5GNKFQAL-DVIClIil.js +0 -10
- ksadk/server/static/assets/diagram-KO2AKTUF-Df_3gYQa.js +0 -3
- ksadk/server/static/assets/diagram-LMA3HP47-BhLk6ZtA.js +0 -24
- ksadk/server/static/assets/diagram-OG6HWLK6-D4GNGvuu.js +0 -24
- ksadk/server/static/assets/dist-DyvYLMW9.js +0 -1
- ksadk/server/static/assets/erDiagram-TEJ5UH35-CnfRcY2M.js +0 -85
- ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +0 -1
- ksadk/server/static/assets/flowDiagram-I6XJVG4X-DGaJjGNJ.js +0 -162
- ksadk/server/static/assets/ganttDiagram-6RSMTGT7-DpCoB2g9.js +0 -292
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +0 -1
- ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-9IKVFBVT.js +0 -106
- ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
- ksadk/server/static/assets/index-QSwCHuB8.js +0 -177
- ksadk/server/static/assets/index-jOPmTOZH.css +0 -2
- ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +0 -1
- ksadk/server/static/assets/infoDiagram-5YYISTIA-CYIIsb8y.js +0 -2
- ksadk/server/static/assets/katex-DATssjp1.js +0 -265
- ksadk/server/static/assets/mermaid-parser.core-mGAcEwcq.js +0 -161
- ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +0 -1
- ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +0 -1
- ksadk/server/static/assets/pieDiagram-4H26LBE5-By-ra07M.js +0 -30
- ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +0 -1
- ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DpW90iu3.js +0 -84
- ksadk/server/static/assets/stateDiagram-AJRCARHV-DGpd9yFG.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +0 -1
- ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +0 -1
- ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +0 -1
- ksadk/server/static/assets/vennDiagram-CIIHVFJN-l3Z7-wbP.js +0 -34
- ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +0 -1
- ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-BR54GPmr.js +0 -78
- ksadk/server/static/assets/xychartDiagram-2RQKCTM6-SkiH8GsK.js +0 -7
- ksadk/tracing/exporters/langfuse_exporter.py +0 -460
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,627 @@
|
|
|
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
|
+
BUSINESS_STANDARD_EVALUATOR = "business_standard@v1"
|
|
53
|
+
LEGACY_ASSERTION_EVALUATORS = (
|
|
54
|
+
"response_contract@v1",
|
|
55
|
+
"runtime_budget@v1",
|
|
56
|
+
"tool_trajectory@v1",
|
|
57
|
+
)
|
|
58
|
+
# Kept for external imports only. Empty evaluator selection uses the
|
|
59
|
+
# data-derived automatic plan in _automatic_evaluator_names instead.
|
|
60
|
+
DEFAULT_EVALUATORS = LEGACY_ASSERTION_EVALUATORS
|
|
61
|
+
_RESPONSE_MATCH_THRESHOLD = 0.8
|
|
62
|
+
_TOKEN_PATTERN = re.compile(r"[A-Za-z0-9_]+|[\u4e00-\u9fff]")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def evaluate_case(
|
|
66
|
+
case: EvalCase,
|
|
67
|
+
target_run: TargetRun,
|
|
68
|
+
evaluator_names: list[str],
|
|
69
|
+
config: EvaluationConfig | None = None,
|
|
70
|
+
) -> list[MetricResult]:
|
|
71
|
+
"""Run selected evaluators in request order."""
|
|
72
|
+
|
|
73
|
+
context = _EvaluationContext(case, target_run, config or EvaluationConfig())
|
|
74
|
+
evaluators = _resolve_evaluators(evaluator_names, context)
|
|
75
|
+
return _run_evaluators(context, evaluators)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
async def evaluate_case_async(
|
|
79
|
+
case: EvalCase,
|
|
80
|
+
target_run: TargetRun,
|
|
81
|
+
evaluator_names: list[str],
|
|
82
|
+
config: EvaluationConfig,
|
|
83
|
+
) -> list[MetricResult]:
|
|
84
|
+
"""Run evaluators without blocking the target invocation event loop."""
|
|
85
|
+
|
|
86
|
+
return await asyncio.to_thread(evaluate_case, case, target_run, evaluator_names, config)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _resolve_evaluators(
|
|
90
|
+
evaluator_names: list[str], context: _EvaluationContext
|
|
91
|
+
) -> list[_EvaluatorDefinition]:
|
|
92
|
+
selected_names = evaluator_names or _automatic_evaluator_names(context.case, context.config)
|
|
93
|
+
unsupported_names = [name for name in selected_names if name not in _EVALUATOR_REGISTRY]
|
|
94
|
+
if unsupported_names:
|
|
95
|
+
raise ValueError(f"不支持的评估器: {', '.join(unsupported_names)}")
|
|
96
|
+
return [_EVALUATOR_REGISTRY[name] for name in selected_names]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def resolve_evaluator_plan(
|
|
100
|
+
cases: list[EvalCase],
|
|
101
|
+
evaluator_names: list[str],
|
|
102
|
+
config: EvaluationConfig,
|
|
103
|
+
) -> list[str]:
|
|
104
|
+
"""Return the explicit or data-derived evaluator plan for an EvalSet."""
|
|
105
|
+
|
|
106
|
+
if evaluator_names:
|
|
107
|
+
unsupported_names = [name for name in evaluator_names if name not in _EVALUATOR_REGISTRY]
|
|
108
|
+
if unsupported_names:
|
|
109
|
+
raise ValueError(f"不支持的评估器: {', '.join(unsupported_names)}")
|
|
110
|
+
return list(evaluator_names)
|
|
111
|
+
|
|
112
|
+
plan: list[str] = []
|
|
113
|
+
for case in cases:
|
|
114
|
+
for evaluator_name in _automatic_evaluator_names(case, config):
|
|
115
|
+
if evaluator_name not in plan:
|
|
116
|
+
plan.append(evaluator_name)
|
|
117
|
+
return plan
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _automatic_evaluator_names(case: EvalCase, config: EvaluationConfig) -> list[str]:
|
|
121
|
+
"""Select only the evaluators whose business standard is present in a Case."""
|
|
122
|
+
|
|
123
|
+
names: list[str] = []
|
|
124
|
+
if _response_assertions(case):
|
|
125
|
+
names.append("response_contract@v1")
|
|
126
|
+
if _runtime_assertions(case):
|
|
127
|
+
names.append("runtime_budget@v1")
|
|
128
|
+
if _tool_requirements(case):
|
|
129
|
+
names.append("tool_trajectory@v1")
|
|
130
|
+
|
|
131
|
+
if _final_expected_output(case):
|
|
132
|
+
if _judge_unavailable_reason(config) is None:
|
|
133
|
+
names.insert(0, LLM_JUDGE_EVALUATOR)
|
|
134
|
+
else:
|
|
135
|
+
names.insert(0, REFERENCE_MATCH_EVALUATOR)
|
|
136
|
+
elif not _response_assertions(case):
|
|
137
|
+
names.insert(0, BUSINESS_STANDARD_EVALUATOR)
|
|
138
|
+
return names
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _run_evaluators(
|
|
142
|
+
context: _EvaluationContext,
|
|
143
|
+
evaluators: list[_EvaluatorDefinition],
|
|
144
|
+
) -> list[MetricResult]:
|
|
145
|
+
metrics: list[MetricResult] = []
|
|
146
|
+
for evaluator in evaluators:
|
|
147
|
+
metrics.extend(_run_evaluator(evaluator, context))
|
|
148
|
+
return metrics
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _run_evaluator(
|
|
152
|
+
evaluator: _EvaluatorDefinition,
|
|
153
|
+
context: _EvaluationContext,
|
|
154
|
+
) -> list[MetricResult]:
|
|
155
|
+
try:
|
|
156
|
+
return evaluator.strategy(context)
|
|
157
|
+
except Exception as exc:
|
|
158
|
+
return [_evaluator_error_metric(evaluator, exc)]
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _evaluate_reference_match(context: _EvaluationContext) -> list[MetricResult]:
|
|
162
|
+
"""Score the final response against the case's reference output."""
|
|
163
|
+
|
|
164
|
+
expected_output = _final_expected_output(context.case)
|
|
165
|
+
if not expected_output:
|
|
166
|
+
return []
|
|
167
|
+
|
|
168
|
+
score = _rouge_1_f1(context.target_run.output, expected_output)
|
|
169
|
+
return [
|
|
170
|
+
_score_metric(
|
|
171
|
+
name="response_match",
|
|
172
|
+
score=score,
|
|
173
|
+
evidence={
|
|
174
|
+
"evaluator": REFERENCE_MATCH_EVALUATOR,
|
|
175
|
+
"method": "rouge_1_f1",
|
|
176
|
+
"threshold": _RESPONSE_MATCH_THRESHOLD,
|
|
177
|
+
},
|
|
178
|
+
)
|
|
179
|
+
]
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _evaluate_llm_judge(
|
|
183
|
+
context: _EvaluationContext,
|
|
184
|
+
) -> list[MetricResult]:
|
|
185
|
+
"""Use the configured LLM Judge to score a final response."""
|
|
186
|
+
|
|
187
|
+
expected_output = _final_expected_output(context.case)
|
|
188
|
+
if not expected_output:
|
|
189
|
+
return []
|
|
190
|
+
|
|
191
|
+
unavailable_reason = _judge_unavailable_reason(context.config)
|
|
192
|
+
if unavailable_reason:
|
|
193
|
+
return [_judge_unavailable_metric(unavailable_reason)]
|
|
194
|
+
|
|
195
|
+
try:
|
|
196
|
+
score = _judge_score(
|
|
197
|
+
input_text=context.case.input,
|
|
198
|
+
actual_output=context.target_run.output,
|
|
199
|
+
expected_output=expected_output,
|
|
200
|
+
config=context.config,
|
|
201
|
+
)
|
|
202
|
+
except ImportError:
|
|
203
|
+
return [_judge_unavailable_metric("未安装 ksadk[judge]")]
|
|
204
|
+
except Exception as exc:
|
|
205
|
+
return [_judge_error_metric(exc)]
|
|
206
|
+
|
|
207
|
+
return [_judge_score_metric(score, context.config.judge_model)]
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _evaluate_business_standard(context: _EvaluationContext) -> list[MetricResult]:
|
|
211
|
+
"""Prevent execution-only Cases from being reported as business-quality passes."""
|
|
212
|
+
|
|
213
|
+
return [
|
|
214
|
+
MetricResult(
|
|
215
|
+
name="response_quality",
|
|
216
|
+
status=MetricStatus.UNAVAILABLE,
|
|
217
|
+
evidence={
|
|
218
|
+
"evaluator": BUSINESS_STANDARD_EVALUATOR,
|
|
219
|
+
"reason": "Case 未提供响应业务标准",
|
|
220
|
+
},
|
|
221
|
+
)
|
|
222
|
+
]
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _evaluate_response_contract(
|
|
226
|
+
context: _EvaluationContext,
|
|
227
|
+
) -> list[MetricResult]:
|
|
228
|
+
"""Evaluate response assertions against the normalized target output."""
|
|
229
|
+
|
|
230
|
+
return [
|
|
231
|
+
_response_metric(assertion, context.target_run.output)
|
|
232
|
+
for assertion in _response_assertions(context.case)
|
|
233
|
+
]
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _evaluate_runtime_budget(
|
|
237
|
+
context: _EvaluationContext,
|
|
238
|
+
) -> list[MetricResult]:
|
|
239
|
+
"""Evaluate runtime assertions against adapter-reported measurements."""
|
|
240
|
+
|
|
241
|
+
return [
|
|
242
|
+
_runtime_metric(assertion, context.target_run)
|
|
243
|
+
for assertion in _runtime_assertions(context.case)
|
|
244
|
+
]
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _evaluate_tool_trajectory(
|
|
248
|
+
context: _EvaluationContext,
|
|
249
|
+
) -> list[MetricResult]:
|
|
250
|
+
"""Evaluate tool requirements against normalized RuntimeEvent evidence."""
|
|
251
|
+
|
|
252
|
+
requirements = _tool_requirements(context.case)
|
|
253
|
+
if not requirements:
|
|
254
|
+
return []
|
|
255
|
+
|
|
256
|
+
if context.target_run.trace_ref is None:
|
|
257
|
+
return [
|
|
258
|
+
MetricResult(
|
|
259
|
+
name="tool_trajectory",
|
|
260
|
+
status=MetricStatus.UNAVAILABLE,
|
|
261
|
+
required=required,
|
|
262
|
+
evidence={
|
|
263
|
+
"assertion": assertion_type,
|
|
264
|
+
"tool": expected,
|
|
265
|
+
"reason": "Target 未提供可查询的标准化工具轨迹",
|
|
266
|
+
},
|
|
267
|
+
)
|
|
268
|
+
for assertion_type, expected, required in requirements
|
|
269
|
+
]
|
|
270
|
+
|
|
271
|
+
results: list[MetricResult] = []
|
|
272
|
+
for assertion_type, expected, required in requirements:
|
|
273
|
+
results.append(
|
|
274
|
+
_tool_metric(
|
|
275
|
+
assertion_type,
|
|
276
|
+
expected,
|
|
277
|
+
required,
|
|
278
|
+
context.target_run.tool_calls,
|
|
279
|
+
)
|
|
280
|
+
)
|
|
281
|
+
return results
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _tool_metric(
|
|
285
|
+
assertion_type: str,
|
|
286
|
+
expected: str | list[str],
|
|
287
|
+
required: bool,
|
|
288
|
+
tool_calls: list[Any],
|
|
289
|
+
) -> MetricResult:
|
|
290
|
+
if assertion_type == AssertionType.TOOL_SEQUENCE.value:
|
|
291
|
+
expected_sequence = list(expected) if isinstance(expected, list) else []
|
|
292
|
+
ordered_calls = sorted(
|
|
293
|
+
(call for call in tool_calls if call.status == "SUCCEEDED"),
|
|
294
|
+
key=lambda call: call.seq_start if call.seq_start is not None else float("inf"),
|
|
295
|
+
)
|
|
296
|
+
actual_sequence = [call.name for call in ordered_calls]
|
|
297
|
+
matched_calls = _ordered_tool_subsequence(ordered_calls, expected_sequence)
|
|
298
|
+
passed = len(matched_calls) == len(expected_sequence)
|
|
299
|
+
return MetricResult(
|
|
300
|
+
name="tool_trajectory",
|
|
301
|
+
status=MetricStatus.PASS if passed else MetricStatus.FAIL,
|
|
302
|
+
score=1.0 if passed else 0.0,
|
|
303
|
+
required=required,
|
|
304
|
+
evidence={
|
|
305
|
+
"assertion": assertion_type,
|
|
306
|
+
"expectedSequence": expected_sequence,
|
|
307
|
+
"actualSequence": actual_sequence,
|
|
308
|
+
"matchedCallIds": matched_calls,
|
|
309
|
+
},
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
tool_name = str(expected)
|
|
313
|
+
matched = [call for call in tool_calls if call.name == tool_name]
|
|
314
|
+
if assertion_type == AssertionType.TOOL_NOT_CALLED.value:
|
|
315
|
+
passed = not matched
|
|
316
|
+
matched_ids = [call.call_id for call in matched]
|
|
317
|
+
elif assertion_type == AssertionType.TOOL_SUCCEEDED.value:
|
|
318
|
+
matched_ids = [call.call_id for call in matched if call.status == "SUCCEEDED"]
|
|
319
|
+
passed = bool(matched_ids)
|
|
320
|
+
else:
|
|
321
|
+
matched_ids = [call.call_id for call in matched]
|
|
322
|
+
passed = bool(matched_ids)
|
|
323
|
+
return MetricResult(
|
|
324
|
+
name="tool_trajectory",
|
|
325
|
+
status=MetricStatus.PASS if passed else MetricStatus.FAIL,
|
|
326
|
+
score=1.0 if passed else 0.0,
|
|
327
|
+
required=required,
|
|
328
|
+
evidence={
|
|
329
|
+
"assertion": assertion_type,
|
|
330
|
+
"tool": tool_name,
|
|
331
|
+
"matchedCallIds": matched_ids,
|
|
332
|
+
},
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def _ordered_tool_subsequence(tool_calls: list[Any], expected_sequence: list[str]) -> list[str]:
|
|
337
|
+
matched_call_ids: list[str] = []
|
|
338
|
+
expected_index = 0
|
|
339
|
+
for call in tool_calls:
|
|
340
|
+
if expected_index == len(expected_sequence):
|
|
341
|
+
break
|
|
342
|
+
if call.name == expected_sequence[expected_index]:
|
|
343
|
+
matched_call_ids.append(call.call_id)
|
|
344
|
+
expected_index += 1
|
|
345
|
+
return matched_call_ids
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def _response_assertions(case: EvalCase) -> list[AssertionSpec]:
|
|
349
|
+
response_types = {
|
|
350
|
+
AssertionType.RESPONSE_EQUALS,
|
|
351
|
+
AssertionType.RESPONSE_CONTAINS,
|
|
352
|
+
AssertionType.RESPONSE_NOT_CONTAINS,
|
|
353
|
+
AssertionType.RESPONSE_JSON_SCHEMA,
|
|
354
|
+
}
|
|
355
|
+
return [assertion for assertion in case.assertions if assertion.type in response_types]
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def _runtime_assertions(case: EvalCase) -> list[AssertionSpec]:
|
|
359
|
+
return [
|
|
360
|
+
assertion for assertion in case.assertions if assertion.type.value.startswith("runtime.")
|
|
361
|
+
]
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def _tool_requirements(case: EvalCase) -> list[tuple[str, str | list[str], bool]]:
|
|
365
|
+
requirements = [
|
|
366
|
+
(
|
|
367
|
+
assertion.type.value,
|
|
368
|
+
assertion.value,
|
|
369
|
+
assertion.required,
|
|
370
|
+
)
|
|
371
|
+
for assertion in case.assertions
|
|
372
|
+
if assertion.type
|
|
373
|
+
in {
|
|
374
|
+
AssertionType.TOOL_CALLED,
|
|
375
|
+
AssertionType.TOOL_NOT_CALLED,
|
|
376
|
+
AssertionType.TOOL_SUCCEEDED,
|
|
377
|
+
AssertionType.TOOL_SEQUENCE,
|
|
378
|
+
}
|
|
379
|
+
]
|
|
380
|
+
requirements.extend(
|
|
381
|
+
("tool.expected", str(tool.get("name") or ""), True)
|
|
382
|
+
for turn in case.turns
|
|
383
|
+
for tool in turn.expected_tools
|
|
384
|
+
if str(tool.get("name") or "").strip()
|
|
385
|
+
)
|
|
386
|
+
return requirements
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def evaluate_tool_trajectory(case: EvalCase, target_run: TargetRun) -> list[MetricResult]:
|
|
390
|
+
"""Compatibility entry point for direct deterministic tool evaluation."""
|
|
391
|
+
|
|
392
|
+
return _evaluate_tool_trajectory(_EvaluationContext(case, target_run, EvaluationConfig()))
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def _response_metric(assertion: AssertionSpec, output: str) -> MetricResult:
|
|
396
|
+
reason = ""
|
|
397
|
+
if assertion.type is AssertionType.RESPONSE_EQUALS:
|
|
398
|
+
passed = output == assertion.value
|
|
399
|
+
elif assertion.type is AssertionType.RESPONSE_CONTAINS:
|
|
400
|
+
passed = assertion.value in output
|
|
401
|
+
elif assertion.type is AssertionType.RESPONSE_NOT_CONTAINS:
|
|
402
|
+
passed = assertion.value not in output
|
|
403
|
+
else:
|
|
404
|
+
try:
|
|
405
|
+
validate_json(json.loads(output), assertion.value)
|
|
406
|
+
passed = True
|
|
407
|
+
except (json.JSONDecodeError, JSONSchemaValidationError) as exc:
|
|
408
|
+
passed = False
|
|
409
|
+
reason = str(exc)
|
|
410
|
+
|
|
411
|
+
return _metric(
|
|
412
|
+
"response_contract",
|
|
413
|
+
assertion,
|
|
414
|
+
passed=passed,
|
|
415
|
+
reason=reason,
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
def _runtime_metric(assertion: AssertionSpec, target_run: TargetRun) -> MetricResult:
|
|
420
|
+
actual: int | None
|
|
421
|
+
if assertion.type is AssertionType.RUNTIME_MAX_LATENCY_MS:
|
|
422
|
+
actual = target_run.duration_ms
|
|
423
|
+
elif not target_run.usage.reported:
|
|
424
|
+
actual = None
|
|
425
|
+
elif assertion.type is AssertionType.RUNTIME_MAX_INPUT_TOKENS:
|
|
426
|
+
actual = target_run.usage.input_tokens
|
|
427
|
+
elif assertion.type is AssertionType.RUNTIME_MAX_TOTAL_TOKENS:
|
|
428
|
+
actual = target_run.usage.total_tokens
|
|
429
|
+
else:
|
|
430
|
+
actual = target_run.usage.output_tokens
|
|
431
|
+
|
|
432
|
+
if actual is None:
|
|
433
|
+
return MetricResult(
|
|
434
|
+
name="runtime_budget",
|
|
435
|
+
status=MetricStatus.UNAVAILABLE,
|
|
436
|
+
required=assertion.required,
|
|
437
|
+
evidence={
|
|
438
|
+
"assertion": assertion.type.value,
|
|
439
|
+
"reason": "Target 未提供该运行指标",
|
|
440
|
+
},
|
|
441
|
+
)
|
|
442
|
+
return _metric(
|
|
443
|
+
"runtime_budget",
|
|
444
|
+
assertion,
|
|
445
|
+
passed=actual <= assertion.value,
|
|
446
|
+
evidence={"actual": actual},
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def _metric(
|
|
451
|
+
name: str,
|
|
452
|
+
assertion: AssertionSpec,
|
|
453
|
+
*,
|
|
454
|
+
passed: bool,
|
|
455
|
+
reason: str = "",
|
|
456
|
+
evidence: dict[str, Any] | None = None,
|
|
457
|
+
) -> MetricResult:
|
|
458
|
+
details = {"assertion": assertion.type.value, **(evidence or {})}
|
|
459
|
+
if reason:
|
|
460
|
+
details["reason"] = reason
|
|
461
|
+
return MetricResult(
|
|
462
|
+
name=name,
|
|
463
|
+
status=MetricStatus.PASS if passed else MetricStatus.FAIL,
|
|
464
|
+
score=1.0 if passed else 0.0,
|
|
465
|
+
required=assertion.required,
|
|
466
|
+
evidence=details,
|
|
467
|
+
)
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
def _evaluator_error_metric(
|
|
471
|
+
evaluator: _EvaluatorDefinition,
|
|
472
|
+
error: Exception,
|
|
473
|
+
) -> MetricResult:
|
|
474
|
+
return MetricResult(
|
|
475
|
+
name=evaluator.metric_name,
|
|
476
|
+
status=MetricStatus.ERROR,
|
|
477
|
+
evidence={
|
|
478
|
+
"evaluator": evaluator.evaluator_id,
|
|
479
|
+
"reason": "评估器执行失败",
|
|
480
|
+
"errorType": type(error).__name__,
|
|
481
|
+
},
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def _score_metric(
|
|
486
|
+
*,
|
|
487
|
+
name: str,
|
|
488
|
+
score: float,
|
|
489
|
+
evidence: dict[str, Any],
|
|
490
|
+
) -> MetricResult:
|
|
491
|
+
return MetricResult(
|
|
492
|
+
name=name,
|
|
493
|
+
status=MetricStatus.PASS if score >= _RESPONSE_MATCH_THRESHOLD else MetricStatus.FAIL,
|
|
494
|
+
score=score,
|
|
495
|
+
evidence=evidence,
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def _final_expected_output(case: EvalCase) -> str | None:
|
|
500
|
+
return case.turns[-1].expected_output
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
def _judge_unavailable_reason(config: EvaluationConfig) -> str | None:
|
|
504
|
+
if config.data_policy is not DataPolicy.FULL_TRACE:
|
|
505
|
+
return "Judge 需要 dataPolicy=full_trace"
|
|
506
|
+
if not config.judge_model:
|
|
507
|
+
return "未配置 judgeModel"
|
|
508
|
+
if not config.judge_api_base:
|
|
509
|
+
return "未配置 judgeApiBase"
|
|
510
|
+
if not os.getenv(config.judge_api_key_env):
|
|
511
|
+
return f"未设置 Judge 密钥环境变量: {config.judge_api_key_env}"
|
|
512
|
+
return None
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
def _judge_score(
|
|
516
|
+
*,
|
|
517
|
+
input_text: str,
|
|
518
|
+
actual_output: str,
|
|
519
|
+
expected_output: str,
|
|
520
|
+
config: EvaluationConfig,
|
|
521
|
+
) -> float:
|
|
522
|
+
return _run_llm_judge(
|
|
523
|
+
input_text=input_text,
|
|
524
|
+
actual_output=actual_output,
|
|
525
|
+
expected_output=expected_output,
|
|
526
|
+
model=config.judge_model or "",
|
|
527
|
+
api_base=config.judge_api_base or "",
|
|
528
|
+
api_key=os.environ[config.judge_api_key_env],
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def _judge_unavailable_metric(reason: str) -> MetricResult:
|
|
533
|
+
return MetricResult(
|
|
534
|
+
name="response_quality",
|
|
535
|
+
status=MetricStatus.UNAVAILABLE,
|
|
536
|
+
evidence={"evaluator": LLM_JUDGE_EVALUATOR, "reason": reason},
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
def _judge_error_metric(error: Exception) -> MetricResult:
|
|
541
|
+
return MetricResult(
|
|
542
|
+
name="response_quality",
|
|
543
|
+
status=MetricStatus.ERROR,
|
|
544
|
+
evidence={
|
|
545
|
+
"evaluator": LLM_JUDGE_EVALUATOR,
|
|
546
|
+
"reason": "Judge 执行失败",
|
|
547
|
+
"errorType": type(error).__name__,
|
|
548
|
+
},
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
def _judge_score_metric(score: float, judge_model: str | None) -> MetricResult:
|
|
553
|
+
return _score_metric(
|
|
554
|
+
name="response_quality",
|
|
555
|
+
score=score,
|
|
556
|
+
evidence={
|
|
557
|
+
"evaluator": LLM_JUDGE_EVALUATOR,
|
|
558
|
+
"threshold": _RESPONSE_MATCH_THRESHOLD,
|
|
559
|
+
"judgeModel": judge_model,
|
|
560
|
+
},
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def _rouge_1_f1(actual: str, expected: str) -> float:
|
|
565
|
+
actual_tokens = Counter(_TOKEN_PATTERN.findall(actual.lower()))
|
|
566
|
+
expected_tokens = Counter(_TOKEN_PATTERN.findall(expected.lower()))
|
|
567
|
+
if not actual_tokens or not expected_tokens:
|
|
568
|
+
return float(actual.strip() == expected.strip())
|
|
569
|
+
|
|
570
|
+
overlap = sum((actual_tokens & expected_tokens).values())
|
|
571
|
+
precision = overlap / sum(actual_tokens.values())
|
|
572
|
+
recall = overlap / sum(expected_tokens.values())
|
|
573
|
+
return 2 * precision * recall / (precision + recall) if precision + recall else 0.0
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
def _run_llm_judge(
|
|
577
|
+
*,
|
|
578
|
+
input_text: str,
|
|
579
|
+
actual_output: str,
|
|
580
|
+
expected_output: str,
|
|
581
|
+
model: str,
|
|
582
|
+
api_base: str,
|
|
583
|
+
api_key: str,
|
|
584
|
+
) -> float:
|
|
585
|
+
"""Run the minimal external Judge configuration."""
|
|
586
|
+
|
|
587
|
+
os.environ.setdefault("DEEPEVAL_TELEMETRY_OPT_OUT", "YES")
|
|
588
|
+
from deepeval.metrics import GEval
|
|
589
|
+
from deepeval.models import LocalModel
|
|
590
|
+
from deepeval.test_case import LLMTestCase, LLMTestCaseParams
|
|
591
|
+
|
|
592
|
+
judge = LocalModel(model=model, base_url=api_base, api_key=api_key)
|
|
593
|
+
metric = GEval(
|
|
594
|
+
name="Response quality",
|
|
595
|
+
criteria=(
|
|
596
|
+
"Determine whether the actual output is factually correct based on the expected output."
|
|
597
|
+
),
|
|
598
|
+
evaluation_params=[
|
|
599
|
+
LLMTestCaseParams.INPUT,
|
|
600
|
+
LLMTestCaseParams.ACTUAL_OUTPUT,
|
|
601
|
+
LLMTestCaseParams.EXPECTED_OUTPUT,
|
|
602
|
+
],
|
|
603
|
+
threshold=_RESPONSE_MATCH_THRESHOLD,
|
|
604
|
+
model=judge,
|
|
605
|
+
)
|
|
606
|
+
metric.measure(
|
|
607
|
+
LLMTestCase(
|
|
608
|
+
input=input_text,
|
|
609
|
+
actual_output=actual_output,
|
|
610
|
+
expected_output=expected_output,
|
|
611
|
+
)
|
|
612
|
+
)
|
|
613
|
+
return float(metric.score)
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
_EVALUATORS = (
|
|
617
|
+
_EvaluatorDefinition(
|
|
618
|
+
BUSINESS_STANDARD_EVALUATOR, "response_quality", _evaluate_business_standard
|
|
619
|
+
),
|
|
620
|
+
_EvaluatorDefinition("response_contract@v1", "response_contract", _evaluate_response_contract),
|
|
621
|
+
_EvaluatorDefinition("runtime_budget@v1", "runtime_budget", _evaluate_runtime_budget),
|
|
622
|
+
_EvaluatorDefinition("tool_trajectory@v1", "tool_trajectory", _evaluate_tool_trajectory),
|
|
623
|
+
_EvaluatorDefinition(REFERENCE_MATCH_EVALUATOR, "response_match", _evaluate_reference_match),
|
|
624
|
+
_EvaluatorDefinition(LLM_JUDGE_EVALUATOR, "response_quality", _evaluate_llm_judge),
|
|
625
|
+
)
|
|
626
|
+
_EVALUATOR_REGISTRY = {evaluator.evaluator_id: evaluator for evaluator in _EVALUATORS}
|
|
627
|
+
SUPPORTED_EVALUATORS = tuple(evaluator.evaluator_id for evaluator in _EVALUATORS)
|