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,199 @@
|
|
|
1
|
+
"""Cloud EvalSet publication orchestration shared by CLI and Studio."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Protocol
|
|
8
|
+
|
|
9
|
+
from pydantic import Field
|
|
10
|
+
|
|
11
|
+
from .cloud_binding import CloudBinding, CloudBindingStore
|
|
12
|
+
from .cloud_converter import (
|
|
13
|
+
CloudDatasetSnapshot,
|
|
14
|
+
evalset_from_dataset_snapshot,
|
|
15
|
+
evalset_to_dataset_snapshot,
|
|
16
|
+
)
|
|
17
|
+
from .contracts import CloudDatasetRef, DataPolicy, EvalSetVersion, EvaluationModel
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CloudEvalSetPreviewError(ValueError):
|
|
21
|
+
"""Raised before an EvalSet body is allowed to leave the local process."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class CloudEvalSetPublishResult(EvaluationModel):
|
|
25
|
+
"""Provider acknowledgement for one immutable Dataset snapshot."""
|
|
26
|
+
|
|
27
|
+
dataset_id: str = Field(min_length=1)
|
|
28
|
+
dataset_version: int = Field(ge=1)
|
|
29
|
+
project_id: str | None = None
|
|
30
|
+
schema_hash: str = Field(min_length=64, max_length=64)
|
|
31
|
+
content_digest: str = Field(min_length=64, max_length=64)
|
|
32
|
+
row_count: int = Field(ge=0)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class CloudEvalSetPullResult(EvaluationModel):
|
|
36
|
+
"""One validated immutable cloud snapshot and its normalized local form."""
|
|
37
|
+
|
|
38
|
+
snapshot: CloudDatasetSnapshot
|
|
39
|
+
evalset: EvalSetVersion
|
|
40
|
+
cloud_dataset: CloudDatasetRef
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class CloudEvalSetCatalogItem(EvaluationModel):
|
|
44
|
+
"""One immutable Dataset version exposed by the cloud catalog."""
|
|
45
|
+
|
|
46
|
+
dataset_id: str = Field(min_length=1)
|
|
47
|
+
name: str = Field(min_length=1)
|
|
48
|
+
project_id: str | None = None
|
|
49
|
+
version: int = Field(ge=1)
|
|
50
|
+
schema_hash: str = Field(min_length=64, max_length=64)
|
|
51
|
+
content_digest: str = Field(min_length=64, max_length=64)
|
|
52
|
+
row_count: int = Field(ge=0)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class CloudDatasetClient(Protocol):
|
|
56
|
+
"""Minimal provider contract required before a snapshot can be published."""
|
|
57
|
+
|
|
58
|
+
async def publish_snapshot(
|
|
59
|
+
self,
|
|
60
|
+
snapshot: CloudDatasetSnapshot,
|
|
61
|
+
*,
|
|
62
|
+
dataset_id: str | None,
|
|
63
|
+
base_version: int | None,
|
|
64
|
+
idempotency_key: str,
|
|
65
|
+
) -> CloudEvalSetPublishResult: ...
|
|
66
|
+
|
|
67
|
+
async def read_snapshot(
|
|
68
|
+
self,
|
|
69
|
+
dataset_id: str,
|
|
70
|
+
version: int,
|
|
71
|
+
*,
|
|
72
|
+
project_id: str | None = None,
|
|
73
|
+
) -> CloudDatasetSnapshot: ...
|
|
74
|
+
|
|
75
|
+
async def list_datasets(
|
|
76
|
+
self,
|
|
77
|
+
*,
|
|
78
|
+
project_id: str | None = None,
|
|
79
|
+
) -> list[CloudEvalSetCatalogItem]: ...
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class CloudEvalSetService:
|
|
83
|
+
"""Validate, publish, and bind EvalSets without changing runtime execution."""
|
|
84
|
+
|
|
85
|
+
def __init__(
|
|
86
|
+
self,
|
|
87
|
+
workspace_root: str | Path,
|
|
88
|
+
client: CloudDatasetClient,
|
|
89
|
+
*,
|
|
90
|
+
provider: str = "agent-eval/evalsmith",
|
|
91
|
+
):
|
|
92
|
+
self.bindings = CloudBindingStore(workspace_root)
|
|
93
|
+
self.client = client
|
|
94
|
+
self.provider = provider
|
|
95
|
+
|
|
96
|
+
def preview(self, evalset: EvalSetVersion, *, data_policy: DataPolicy) -> CloudDatasetSnapshot:
|
|
97
|
+
"""Return the exact outgoing snapshot or fail before any network request."""
|
|
98
|
+
|
|
99
|
+
if data_policy is DataPolicy.LOCAL_ONLY:
|
|
100
|
+
raise CloudEvalSetPreviewError("DataPolicy=local_only 禁止上传 EvalSet 正文")
|
|
101
|
+
if data_policy is DataPolicy.METADATA_ONLY:
|
|
102
|
+
raise CloudEvalSetPreviewError(
|
|
103
|
+
"DataPolicy=metadata_only 不能发布包含 Case 正文的 EvalSet"
|
|
104
|
+
)
|
|
105
|
+
if data_policy is not DataPolicy.FULL_TRACE:
|
|
106
|
+
raise CloudEvalSetPreviewError("当前端云评测集发布仅支持显式 DataPolicy=full_trace")
|
|
107
|
+
return evalset_to_dataset_snapshot(evalset)
|
|
108
|
+
|
|
109
|
+
async def publish(
|
|
110
|
+
self,
|
|
111
|
+
evalset: EvalSetVersion,
|
|
112
|
+
*,
|
|
113
|
+
evalset_path: str,
|
|
114
|
+
data_policy: DataPolicy,
|
|
115
|
+
dataset_id: str | None = None,
|
|
116
|
+
idempotency_key: str | None = None,
|
|
117
|
+
) -> CloudEvalSetPublishResult:
|
|
118
|
+
"""Publish a full snapshot to an existing Dataset and advance its binding."""
|
|
119
|
+
|
|
120
|
+
if idempotency_key is not None and not idempotency_key.strip():
|
|
121
|
+
raise ValueError("Idempotency-Key 不能为空")
|
|
122
|
+
snapshot = self.preview(evalset, data_policy=data_policy)
|
|
123
|
+
existing = self.bindings.read(evalset_path)
|
|
124
|
+
requested_dataset_id = str(dataset_id or "").strip() or None
|
|
125
|
+
target_dataset_id = requested_dataset_id or (existing.dataset_id if existing else None)
|
|
126
|
+
if target_dataset_id is None:
|
|
127
|
+
raise ValueError("datasetId is required for the first publish of an EvalSet")
|
|
128
|
+
resolved_idempotency_key = idempotency_key or self._idempotency_key(
|
|
129
|
+
target_dataset_id,
|
|
130
|
+
snapshot.content_digest,
|
|
131
|
+
)
|
|
132
|
+
result = await self.client.publish_snapshot(
|
|
133
|
+
snapshot,
|
|
134
|
+
dataset_id=target_dataset_id,
|
|
135
|
+
base_version=None,
|
|
136
|
+
idempotency_key=resolved_idempotency_key,
|
|
137
|
+
)
|
|
138
|
+
if result.dataset_id != target_dataset_id:
|
|
139
|
+
raise CloudEvalSetPreviewError("云端返回的 datasetId 与目标 Dataset 不一致")
|
|
140
|
+
if result.content_digest != snapshot.content_digest:
|
|
141
|
+
raise CloudEvalSetPreviewError("云端返回的 contentDigest 与本地预检结果不一致")
|
|
142
|
+
if result.schema_hash != snapshot.schema_hash:
|
|
143
|
+
raise CloudEvalSetPreviewError("云端返回的 schemaHash 与本地预检结果不一致")
|
|
144
|
+
if result.row_count != len(snapshot.rows):
|
|
145
|
+
raise CloudEvalSetPreviewError("云端返回的 RowCount 与本地预检结果不一致")
|
|
146
|
+
self.bindings.write(
|
|
147
|
+
CloudBinding(
|
|
148
|
+
evalset_path=evalset_path,
|
|
149
|
+
content_digest=snapshot.content_digest,
|
|
150
|
+
provider=self.provider,
|
|
151
|
+
project_id=result.project_id,
|
|
152
|
+
dataset_id=result.dataset_id,
|
|
153
|
+
dataset_version=result.dataset_version,
|
|
154
|
+
schema_hash=result.schema_hash,
|
|
155
|
+
)
|
|
156
|
+
)
|
|
157
|
+
return result
|
|
158
|
+
|
|
159
|
+
@staticmethod
|
|
160
|
+
def _idempotency_key(dataset_id: str, content_digest: str) -> str:
|
|
161
|
+
identity = f"{dataset_id}:{content_digest}".encode("utf-8")
|
|
162
|
+
return f"ksadk-evalset-{hashlib.sha256(identity).hexdigest()}"
|
|
163
|
+
|
|
164
|
+
async def pull(
|
|
165
|
+
self,
|
|
166
|
+
*,
|
|
167
|
+
dataset_id: str,
|
|
168
|
+
version: int,
|
|
169
|
+
project_id: str | None = None,
|
|
170
|
+
) -> CloudEvalSetPullResult:
|
|
171
|
+
"""Read and validate one immutable Dataset version before execution."""
|
|
172
|
+
|
|
173
|
+
if not dataset_id.strip() or version < 1:
|
|
174
|
+
raise ValueError("datasetId 和 version 必须有效")
|
|
175
|
+
snapshot = await self.client.read_snapshot(
|
|
176
|
+
dataset_id,
|
|
177
|
+
version,
|
|
178
|
+
project_id=project_id,
|
|
179
|
+
)
|
|
180
|
+
evalset = evalset_from_dataset_snapshot(snapshot)
|
|
181
|
+
if evalset.content_digest != snapshot.content_digest:
|
|
182
|
+
raise CloudEvalSetPreviewError("云端 snapshot 的 contentDigest 校验失败")
|
|
183
|
+
reference = CloudDatasetRef(
|
|
184
|
+
provider=self.provider,
|
|
185
|
+
project_id=project_id,
|
|
186
|
+
dataset_id=dataset_id,
|
|
187
|
+
version=version,
|
|
188
|
+
schema_hash=snapshot.schema_hash,
|
|
189
|
+
content_digest=snapshot.content_digest,
|
|
190
|
+
row_count=len(snapshot.rows),
|
|
191
|
+
)
|
|
192
|
+
return CloudEvalSetPullResult(
|
|
193
|
+
snapshot=snapshot,
|
|
194
|
+
evalset=evalset,
|
|
195
|
+
cloud_dataset=reference,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
async def catalog(self, *, project_id: str | None = None) -> list[CloudEvalSetCatalogItem]:
|
|
199
|
+
return await self.client.list_datasets(project_id=project_id)
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
"""Stable, serializable data objects shared by CLI and Studio evaluation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime, timezone
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import Any, Literal
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
10
|
+
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
|
+
# Base model & helpers
|
|
13
|
+
# ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _to_camel_case(value: str) -> str:
|
|
17
|
+
head, *tail = value.split("_")
|
|
18
|
+
return head + "".join(part.capitalize() for part in tail)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _content_digest(payload: dict[str, Any]) -> str:
|
|
22
|
+
import hashlib
|
|
23
|
+
import json
|
|
24
|
+
|
|
25
|
+
encoded = json.dumps(
|
|
26
|
+
payload,
|
|
27
|
+
ensure_ascii=False,
|
|
28
|
+
sort_keys=True,
|
|
29
|
+
separators=(",", ":"),
|
|
30
|
+
).encode("utf-8")
|
|
31
|
+
return hashlib.sha256(encoded).hexdigest()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class EvaluationModel(BaseModel):
|
|
35
|
+
"""Use camelCase on the wire while keeping Python fields snake_case."""
|
|
36
|
+
|
|
37
|
+
model_config = ConfigDict(
|
|
38
|
+
alias_generator=_to_camel_case,
|
|
39
|
+
populate_by_name=True,
|
|
40
|
+
extra="forbid",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# ---------------------------------------------------------------------------
|
|
45
|
+
# Enums
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# Assertion kinds & data egress policy (configure how cases are asserted and
|
|
50
|
+
# what data may leave the local process).
|
|
51
|
+
class AssertionType(str, Enum):
|
|
52
|
+
"""Deterministic assertion kinds supported by the first evaluation phase."""
|
|
53
|
+
|
|
54
|
+
RESPONSE_EQUALS = "response.equals"
|
|
55
|
+
RESPONSE_CONTAINS = "response.contains"
|
|
56
|
+
RESPONSE_NOT_CONTAINS = "response.notContains"
|
|
57
|
+
RESPONSE_JSON_SCHEMA = "response.jsonSchema"
|
|
58
|
+
RUNTIME_MAX_LATENCY_MS = "runtime.maxLatencyMs"
|
|
59
|
+
RUNTIME_MAX_INPUT_TOKENS = "runtime.maxInputTokens"
|
|
60
|
+
RUNTIME_MAX_OUTPUT_TOKENS = "runtime.maxOutputTokens"
|
|
61
|
+
RUNTIME_MAX_TOTAL_TOKENS = "runtime.maxTotalTokens"
|
|
62
|
+
TOOL_CALLED = "tool.called"
|
|
63
|
+
TOOL_NOT_CALLED = "tool.notCalled"
|
|
64
|
+
TOOL_SUCCEEDED = "tool.succeeded"
|
|
65
|
+
TOOL_SEQUENCE = "tool.sequence"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class DataPolicy(str, Enum):
|
|
69
|
+
"""Controls what evaluation data may leave the local process."""
|
|
70
|
+
|
|
71
|
+
LOCAL_ONLY = "local_only"
|
|
72
|
+
METADATA_ONLY = "metadata_only"
|
|
73
|
+
REDACTED_TRACE = "redacted_trace"
|
|
74
|
+
FULL_TRACE = "full_trace"
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# Lifecycle & outcome statuses (run-level, per-case target invocation, and
|
|
78
|
+
# per-metric verdicts).
|
|
79
|
+
class EvalRunStatus(str, Enum):
|
|
80
|
+
"""Lifecycle status for an entire evaluation run."""
|
|
81
|
+
|
|
82
|
+
PENDING = "PENDING"
|
|
83
|
+
RUNNING = "RUNNING"
|
|
84
|
+
PASSED = "PASSED"
|
|
85
|
+
FAILED = "FAILED"
|
|
86
|
+
ERROR = "ERROR"
|
|
87
|
+
CANCELLED = "CANCELLED"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class TargetRunStatus(str, Enum):
|
|
91
|
+
"""Terminal status returned by one target invocation."""
|
|
92
|
+
|
|
93
|
+
PASSED = "PASSED"
|
|
94
|
+
FAILED = "FAILED"
|
|
95
|
+
ERROR = "ERROR"
|
|
96
|
+
CANCELLED = "CANCELLED"
|
|
97
|
+
UNAVAILABLE = "UNAVAILABLE"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class MetricStatus(str, Enum):
|
|
101
|
+
"""Outcome of a single deterministic metric."""
|
|
102
|
+
|
|
103
|
+
PASS = "PASS"
|
|
104
|
+
FAIL = "FAIL"
|
|
105
|
+
UNAVAILABLE = "UNAVAILABLE"
|
|
106
|
+
ERROR = "ERROR"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# ---------------------------------------------------------------------------
|
|
110
|
+
# Evaluation set & input cases
|
|
111
|
+
# ---------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class EvalTurn(EvaluationModel):
|
|
115
|
+
"""A single conversational turn within a multi-turn case."""
|
|
116
|
+
|
|
117
|
+
input: str = Field(min_length=1, max_length=32768)
|
|
118
|
+
expected_output: str | None = Field(default=None, max_length=32768)
|
|
119
|
+
expected_tools: list[dict[str, Any]] = Field(default_factory=list)
|
|
120
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class AssertionSpec(EvaluationModel):
|
|
124
|
+
"""A single deterministic assertion with type-dependent value validation."""
|
|
125
|
+
|
|
126
|
+
type: AssertionType
|
|
127
|
+
value: Any
|
|
128
|
+
required: bool = True
|
|
129
|
+
|
|
130
|
+
@model_validator(mode="after")
|
|
131
|
+
def validate_value(self) -> "AssertionSpec":
|
|
132
|
+
if self.type is AssertionType.RESPONSE_JSON_SCHEMA:
|
|
133
|
+
if not isinstance(self.value, dict):
|
|
134
|
+
raise ValueError("response.jsonSchema 的 value 必须是对象")
|
|
135
|
+
elif self.type.value.startswith("runtime."):
|
|
136
|
+
if isinstance(self.value, bool) or not isinstance(self.value, (int, float)):
|
|
137
|
+
raise ValueError(f"{self.type} 的 value 必须是非负数字")
|
|
138
|
+
if self.value < 0:
|
|
139
|
+
raise ValueError(f"{self.type} 的 value 必须是非负数字")
|
|
140
|
+
elif self.type is AssertionType.TOOL_SEQUENCE:
|
|
141
|
+
if (
|
|
142
|
+
not isinstance(self.value, list)
|
|
143
|
+
or not self.value
|
|
144
|
+
or any(not isinstance(item, str) or not item.strip() for item in self.value)
|
|
145
|
+
):
|
|
146
|
+
raise ValueError("tool.sequence 的 value 必须是非空工具名称数组")
|
|
147
|
+
elif not isinstance(self.value, str):
|
|
148
|
+
raise ValueError(f"{self.type} 的 value 必须是字符串")
|
|
149
|
+
return self
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class EvalCase(EvaluationModel):
|
|
153
|
+
"""One evaluation case: ordered turns plus assertions to check."""
|
|
154
|
+
|
|
155
|
+
id: str = Field(min_length=1, max_length=128)
|
|
156
|
+
turns: list[EvalTurn] = Field(min_length=1)
|
|
157
|
+
assertions: list[AssertionSpec] = Field(default_factory=list)
|
|
158
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
159
|
+
|
|
160
|
+
@model_validator(mode="before")
|
|
161
|
+
@classmethod
|
|
162
|
+
def normalize_single_input(cls, value: Any) -> Any:
|
|
163
|
+
if not isinstance(value, dict):
|
|
164
|
+
return value
|
|
165
|
+
data = dict(value)
|
|
166
|
+
if "input" in data and "turns" not in data:
|
|
167
|
+
turn = {"input": data.pop("input")}
|
|
168
|
+
for field in (
|
|
169
|
+
"expected_output",
|
|
170
|
+
"expectedOutput",
|
|
171
|
+
"reference_output",
|
|
172
|
+
"referenceOutput",
|
|
173
|
+
"expected_tools",
|
|
174
|
+
"expectedTools",
|
|
175
|
+
):
|
|
176
|
+
if field in data:
|
|
177
|
+
normalized_field = (
|
|
178
|
+
"expected_output"
|
|
179
|
+
if field in {"reference_output", "referenceOutput"}
|
|
180
|
+
else field
|
|
181
|
+
)
|
|
182
|
+
turn[normalized_field] = data.pop(field)
|
|
183
|
+
data["turns"] = [turn]
|
|
184
|
+
return data
|
|
185
|
+
|
|
186
|
+
@property
|
|
187
|
+
def input(self) -> str:
|
|
188
|
+
"""Return the final turn for legacy single-input consumers."""
|
|
189
|
+
|
|
190
|
+
return self.turns[-1].input
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class EvalSetVersion(EvaluationModel):
|
|
194
|
+
"""A versioned, content-digested evaluation set of one or more cases."""
|
|
195
|
+
|
|
196
|
+
schema_version: Literal["ksadk.eval/v1"] = "ksadk.eval/v1"
|
|
197
|
+
name: str = Field(min_length=1, max_length=256)
|
|
198
|
+
cases: list[EvalCase] = Field(min_length=1)
|
|
199
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
200
|
+
source_format: str = "native"
|
|
201
|
+
content_digest: str = ""
|
|
202
|
+
|
|
203
|
+
@model_validator(mode="after")
|
|
204
|
+
def validate_and_digest(self) -> "EvalSetVersion":
|
|
205
|
+
ids = [case.id for case in self.cases]
|
|
206
|
+
if len(ids) != len(set(ids)):
|
|
207
|
+
raise ValueError("评测集中的 case id 必须唯一")
|
|
208
|
+
expected = self.compute_digest()
|
|
209
|
+
if self.content_digest and self.content_digest != expected:
|
|
210
|
+
raise ValueError("contentDigest 与规范化评测集内容不一致")
|
|
211
|
+
self.content_digest = expected
|
|
212
|
+
return self
|
|
213
|
+
|
|
214
|
+
def compute_digest(self) -> str:
|
|
215
|
+
"""Hash normalized cases, excluding transport format and the digest itself."""
|
|
216
|
+
|
|
217
|
+
payload = self.model_dump(
|
|
218
|
+
mode="json",
|
|
219
|
+
by_alias=False,
|
|
220
|
+
exclude={"content_digest", "source_format"},
|
|
221
|
+
)
|
|
222
|
+
return _content_digest(payload)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class CloudDatasetRef(EvaluationModel):
|
|
226
|
+
"""Immutable reference to the exact cloud Dataset snapshot used by a run."""
|
|
227
|
+
|
|
228
|
+
provider: str = Field(min_length=1, max_length=256)
|
|
229
|
+
project_id: str | None = Field(default=None, min_length=1, max_length=256)
|
|
230
|
+
dataset_id: str = Field(min_length=1, max_length=256)
|
|
231
|
+
version: int = Field(ge=1)
|
|
232
|
+
schema_hash: str = Field(min_length=64, max_length=64)
|
|
233
|
+
content_digest: str = Field(min_length=64, max_length=64)
|
|
234
|
+
row_count: int = Field(default=0, ge=0)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
# ---------------------------------------------------------------------------
|
|
238
|
+
# Target identity & references
|
|
239
|
+
# ---------------------------------------------------------------------------
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class TargetKind(str, Enum):
|
|
243
|
+
"""Supported target categories; adapters own their implementation details."""
|
|
244
|
+
|
|
245
|
+
LOCAL_SOURCE = "local_source"
|
|
246
|
+
STUDIO_BUILD = "studio_build"
|
|
247
|
+
A2A = "a2a"
|
|
248
|
+
CODEX_WORKTREE = "codex_worktree"
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class TargetSnapshot(EvaluationModel):
|
|
252
|
+
"""Immutable target identity recorded with an evaluation run."""
|
|
253
|
+
|
|
254
|
+
kind: TargetKind
|
|
255
|
+
entrypoint: str = Field(min_length=1, max_length=1024)
|
|
256
|
+
revision_digest: str = Field(min_length=1, max_length=128)
|
|
257
|
+
runtime: str = Field(default="", max_length=128)
|
|
258
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class TargetRef(EvaluationModel):
|
|
262
|
+
"""Unresolved target supplied by CLI/Studio before an adapter snapshots it."""
|
|
263
|
+
|
|
264
|
+
kind: TargetKind
|
|
265
|
+
locator: str = Field(min_length=1, max_length=2048)
|
|
266
|
+
entrypoint: str | None = Field(default=None, min_length=1, max_length=1024)
|
|
267
|
+
credential_ref: str | None = Field(default=None, min_length=1, max_length=512)
|
|
268
|
+
profile: str | None = Field(default=None, min_length=1, max_length=256)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
# ---------------------------------------------------------------------------
|
|
272
|
+
# Execution config & request / spec
|
|
273
|
+
# ---------------------------------------------------------------------------
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
class EvaluationConfig(EvaluationModel):
|
|
277
|
+
"""Execution limits and evaluator selection shared by CLI and Studio."""
|
|
278
|
+
|
|
279
|
+
timeout_seconds: int = Field(default=120, ge=1, le=3600)
|
|
280
|
+
fail_fast: bool = False
|
|
281
|
+
evaluators: list[str] = Field(default_factory=list)
|
|
282
|
+
data_policy: DataPolicy = DataPolicy.LOCAL_ONLY
|
|
283
|
+
judge_model: str | None = Field(default=None, min_length=1, max_length=256)
|
|
284
|
+
judge_api_base: str | None = Field(default=None, min_length=1, max_length=2048)
|
|
285
|
+
judge_api_key_env: str = Field(
|
|
286
|
+
default="KSADK_EVAL_JUDGE_API_KEY",
|
|
287
|
+
pattern=r"^[A-Za-z_][A-Za-z0-9_]*$",
|
|
288
|
+
max_length=128,
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class EvaluationRequest(EvaluationModel):
|
|
293
|
+
"""Validated input passed into the one public evaluation executor."""
|
|
294
|
+
|
|
295
|
+
evalset: EvalSetVersion
|
|
296
|
+
target: TargetRef
|
|
297
|
+
config: EvaluationConfig = Field(default_factory=EvaluationConfig)
|
|
298
|
+
report_dir: str | None = Field(default=None, min_length=1, max_length=2048)
|
|
299
|
+
cloud_dataset: CloudDatasetRef | None = None
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
class EvalRunSpec(EvaluationModel):
|
|
303
|
+
"""Immutable execution plan after the target has been snapshotted."""
|
|
304
|
+
|
|
305
|
+
id: str = Field(min_length=1, max_length=128)
|
|
306
|
+
evalset: EvalSetVersion
|
|
307
|
+
target: TargetSnapshot
|
|
308
|
+
config: EvaluationConfig = Field(default_factory=EvaluationConfig)
|
|
309
|
+
environment_digest: str = Field(default="", max_length=128)
|
|
310
|
+
attempt: int = Field(default=1, ge=1)
|
|
311
|
+
cloud_dataset: CloudDatasetRef | None = None
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
# ---------------------------------------------------------------------------
|
|
315
|
+
# Run results: trace, usage, target run, metric results, case run, report
|
|
316
|
+
# ---------------------------------------------------------------------------
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
# Per-case adapter output: trace linkage, token usage, and the normalized
|
|
320
|
+
# invocation result returned by a target adapter.
|
|
321
|
+
class TraceRef(EvaluationModel):
|
|
322
|
+
"""Queryable linkage to a recorded trace; at least one id required."""
|
|
323
|
+
|
|
324
|
+
run_id: str | None = None
|
|
325
|
+
trace_id: str | None = None
|
|
326
|
+
root_span_id: str | None = None
|
|
327
|
+
session_id: str | None = None
|
|
328
|
+
invocation_id: str | None = None
|
|
329
|
+
seq_start: int | None = Field(default=None, ge=1)
|
|
330
|
+
seq_end: int | None = Field(default=None, ge=1)
|
|
331
|
+
remote_task_id: str | None = None
|
|
332
|
+
seq_id: int | None = Field(default=None, ge=1)
|
|
333
|
+
|
|
334
|
+
@model_validator(mode="after")
|
|
335
|
+
def require_reference(self) -> "TraceRef":
|
|
336
|
+
if not any(
|
|
337
|
+
(
|
|
338
|
+
self.run_id,
|
|
339
|
+
self.trace_id,
|
|
340
|
+
self.session_id,
|
|
341
|
+
self.invocation_id,
|
|
342
|
+
self.remote_task_id,
|
|
343
|
+
self.seq_id,
|
|
344
|
+
)
|
|
345
|
+
):
|
|
346
|
+
raise ValueError("TraceRef 至少需要一个可查询 ID")
|
|
347
|
+
return self
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
class UsageSnapshot(EvaluationModel):
|
|
351
|
+
"""Token usage for one invocation; zero unless the adapter reported it."""
|
|
352
|
+
|
|
353
|
+
input_tokens: int = Field(default=0, ge=0)
|
|
354
|
+
output_tokens: int = Field(default=0, ge=0)
|
|
355
|
+
total_tokens: int = Field(default=0, ge=0)
|
|
356
|
+
reported: bool = False
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
class ToolCallEvidence(EvaluationModel):
|
|
360
|
+
"""Non-sensitive projection of one runtime tool invocation."""
|
|
361
|
+
|
|
362
|
+
call_id: str = Field(min_length=1, max_length=256)
|
|
363
|
+
name: str = Field(min_length=1, max_length=256)
|
|
364
|
+
status: Literal["SUCCEEDED", "ERROR", "INCOMPLETE"]
|
|
365
|
+
seq_start: int | None = Field(default=None, ge=1)
|
|
366
|
+
seq_end: int | None = Field(default=None, ge=1)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
class TargetRun(EvaluationModel):
|
|
370
|
+
"""Normalized result returned by a target adapter for one case."""
|
|
371
|
+
|
|
372
|
+
status: TargetRunStatus
|
|
373
|
+
output: str = ""
|
|
374
|
+
duration_ms: int | None = Field(default=None, ge=0)
|
|
375
|
+
usage: UsageSnapshot = Field(default_factory=UsageSnapshot)
|
|
376
|
+
error_code: str | None = None
|
|
377
|
+
error_message: str | None = None
|
|
378
|
+
trace_ref: TraceRef | None = None
|
|
379
|
+
trace_refs: list[TraceRef] = Field(default_factory=list)
|
|
380
|
+
tool_calls: list[ToolCallEvidence] = Field(default_factory=list)
|
|
381
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
# Evaluator output: per-metric verdicts, per-case aggregation, run-level
|
|
385
|
+
# summary counts, and the canonical persisted report.
|
|
386
|
+
class MetricResult(EvaluationModel):
|
|
387
|
+
"""One deterministic evaluator result and its non-sensitive evidence."""
|
|
388
|
+
|
|
389
|
+
name: str = Field(min_length=1, max_length=128)
|
|
390
|
+
version: str = Field(default="v1", min_length=1, max_length=32)
|
|
391
|
+
status: MetricStatus
|
|
392
|
+
score: float | None = Field(default=None, ge=0, le=1)
|
|
393
|
+
required: bool = True
|
|
394
|
+
evidence: dict[str, Any] = Field(default_factory=dict)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
class CaseRun(EvaluationModel):
|
|
398
|
+
"""Target result and metric results for one case attempt."""
|
|
399
|
+
|
|
400
|
+
case_id: str = Field(min_length=1, max_length=128)
|
|
401
|
+
attempt: int = Field(default=1, ge=1)
|
|
402
|
+
target_run: TargetRun
|
|
403
|
+
metrics: list[MetricResult] = Field(default_factory=list)
|
|
404
|
+
|
|
405
|
+
@property
|
|
406
|
+
def passed(self) -> bool:
|
|
407
|
+
return self.target_run.status is TargetRunStatus.PASSED and all(
|
|
408
|
+
metric.status is MetricStatus.PASS for metric in self.metrics if metric.required
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
class EvalRunSummary(EvaluationModel):
|
|
413
|
+
"""Derived terminal counts; callers must not construct their own summary."""
|
|
414
|
+
|
|
415
|
+
total_cases: int = Field(default=0, ge=0)
|
|
416
|
+
passed_cases: int = Field(default=0, ge=0)
|
|
417
|
+
failed_cases: int = Field(default=0, ge=0)
|
|
418
|
+
unavailable_cases: int = Field(default=0, ge=0)
|
|
419
|
+
error_cases: int = Field(default=0, ge=0)
|
|
420
|
+
cancelled_cases: int = Field(default=0, ge=0)
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
class EvalRunReport(EvaluationModel):
|
|
424
|
+
"""Canonical persisted result consumed by CLI, Studio, and future sync."""
|
|
425
|
+
|
|
426
|
+
schema_version: Literal["ksadk.eval.report/v1"] = "ksadk.eval.report/v1"
|
|
427
|
+
spec: EvalRunSpec
|
|
428
|
+
status: EvalRunStatus
|
|
429
|
+
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
|
430
|
+
case_runs: list[CaseRun] = Field(default_factory=list)
|
|
431
|
+
summary: EvalRunSummary = Field(default_factory=EvalRunSummary)
|
|
432
|
+
report_digest: str = ""
|
|
433
|
+
|
|
434
|
+
@model_validator(mode="after")
|
|
435
|
+
def validate_case_ids(self) -> "EvalRunReport":
|
|
436
|
+
case_ids = [case.case_id for case in self.case_runs]
|
|
437
|
+
if len(case_ids) != len(set(case_ids)):
|
|
438
|
+
raise ValueError("一次评测中 case_id 不能重复")
|
|
439
|
+
self.summary = self._summarize_cases()
|
|
440
|
+
expected = self.compute_digest()
|
|
441
|
+
if self.report_digest and self.report_digest != expected:
|
|
442
|
+
legacy_payload = self.model_dump(
|
|
443
|
+
mode="json", by_alias=False, exclude={"report_digest"}
|
|
444
|
+
)
|
|
445
|
+
legacy_payload["spec"].pop("cloud_dataset", None)
|
|
446
|
+
if self.spec.cloud_dataset is not None or self.report_digest != _content_digest(
|
|
447
|
+
legacy_payload
|
|
448
|
+
):
|
|
449
|
+
raise ValueError("reportDigest 与规范化报告内容不一致")
|
|
450
|
+
self.report_digest = expected
|
|
451
|
+
return self
|
|
452
|
+
|
|
453
|
+
def _summarize_cases(self) -> EvalRunSummary:
|
|
454
|
+
counts = EvalRunSummary(total_cases=len(self.case_runs))
|
|
455
|
+
for case_run in self.case_runs:
|
|
456
|
+
if case_run.target_run.status is TargetRunStatus.ERROR or any(
|
|
457
|
+
metric.required and metric.status is MetricStatus.ERROR
|
|
458
|
+
for metric in case_run.metrics
|
|
459
|
+
):
|
|
460
|
+
counts.error_cases += 1
|
|
461
|
+
elif case_run.target_run.status is TargetRunStatus.CANCELLED:
|
|
462
|
+
counts.cancelled_cases += 1
|
|
463
|
+
elif case_run.target_run.status is TargetRunStatus.UNAVAILABLE or any(
|
|
464
|
+
metric.required and metric.status is MetricStatus.UNAVAILABLE
|
|
465
|
+
for metric in case_run.metrics
|
|
466
|
+
):
|
|
467
|
+
counts.unavailable_cases += 1
|
|
468
|
+
elif case_run.passed:
|
|
469
|
+
counts.passed_cases += 1
|
|
470
|
+
else:
|
|
471
|
+
counts.failed_cases += 1
|
|
472
|
+
return counts
|
|
473
|
+
|
|
474
|
+
def compute_digest(self) -> str:
|
|
475
|
+
"""Return a stable digest excluding the digest field itself."""
|
|
476
|
+
|
|
477
|
+
payload = self.model_dump(mode="json", by_alias=False, exclude={"report_digest"})
|
|
478
|
+
return _content_digest(payload)
|