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.
Files changed (494) hide show
  1. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/METADATA +43 -7
  2. agentengine_sdk_python-0.8.2.dist-info/RECORD +778 -0
  3. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/WHEEL +1 -1
  4. ksadk/a2a/__init__.py +2 -0
  5. ksadk/a2a/_space_client_events.py +381 -0
  6. ksadk/a2a/bootstrap.py +0 -2
  7. ksadk/a2a/card.py +6 -111
  8. ksadk/a2a/control_plane.py +239 -1
  9. ksadk/a2a/event_adapter.py +156 -64
  10. ksadk/a2a/executor.py +195 -172
  11. ksadk/a2a/routes.py +12 -5
  12. ksadk/a2a/server.py +1 -8
  13. ksadk/a2a/service_env.py +33 -0
  14. ksadk/a2a/space_client.py +43 -349
  15. ksadk/a2a_card.py +101 -0
  16. ksadk/a2ui/core.py +222 -53
  17. ksadk/agui/_agent_helpers.py +243 -0
  18. ksadk/agui/a2ui_projection.py +12 -5
  19. ksadk/agui/agent.py +474 -275
  20. ksadk/agui/config.py +11 -5
  21. ksadk/agui/routes.py +7 -15
  22. ksadk/api/client.py +530 -40
  23. ksadk/api/environment.py +27 -0
  24. ksadk/builders/code_builder.py +352 -53
  25. ksadk/builders/container_builder.py +71 -44
  26. ksadk/builders/framework_requirements.py +2 -1
  27. ksadk/builders/ks3_uploader.py +2 -2
  28. ksadk/builders/managed_runtime_builder.py +60 -28
  29. ksadk/cli/__init__.py +25 -0
  30. ksadk/cli/cmd_a2a.py +18 -31
  31. ksadk/cli/cmd_create.py +13 -26
  32. ksadk/cli/cmd_dashboard.py +15 -1
  33. ksadk/cli/cmd_deploy.py +28 -3
  34. ksadk/cli/cmd_eval.py +443 -0
  35. ksadk/cli/cmd_evalset.py +284 -0
  36. ksadk/cli/cmd_files.py +5 -1
  37. ksadk/cli/cmd_hermes.py +137 -163
  38. ksadk/cli/cmd_invoke.py +28 -38
  39. ksadk/cli/cmd_launch.py +12 -0
  40. ksadk/cli/cmd_managed_runtime.py +95 -0
  41. ksadk/cli/cmd_observe.py +85 -0
  42. ksadk/cli/cmd_openclaw.py +85 -479
  43. ksadk/cli/cmd_replay.py +28 -4
  44. ksadk/cli/cmd_run.py +29 -67
  45. ksadk/cli/cmd_studio.py +201 -0
  46. ksadk/cli/cmd_web.py +15 -6
  47. ksadk/cli/dry_run.py +2 -1
  48. ksadk/cli/env_options.py +83 -0
  49. ksadk/cli/global_options.py +3 -1
  50. ksadk/cli/hermes_env.py +151 -0
  51. ksadk/cli/invoke_payload.py +49 -0
  52. ksadk/cli/network_options.py +7 -5
  53. ksadk/cli/openclaw_env.py +458 -0
  54. ksadk/cli/runtime_bootstrap.py +51 -0
  55. ksadk/cli/ui.py +6 -0
  56. ksadk/cli/workflow_common.py +5 -5
  57. ksadk/codex/__init__.py +3 -3
  58. ksadk/codex/client.py +833 -49
  59. ksadk/codex/phase.py +1 -1
  60. ksadk/codex/runtime.py +720 -127
  61. ksadk/common/kop_client.py +232 -0
  62. ksadk/configs/__init__.py +1 -3
  63. ksadk/configs/env_registry.py +244 -45
  64. ksadk/configs/env_registry_pcm.py +181 -0
  65. ksadk/configs/env_var_spec.py +18 -0
  66. ksadk/configs/global_config.py +6 -1
  67. ksadk/configs/settings.py +5 -108
  68. ksadk/context_engine/__init__.py +98 -0
  69. ksadk/context_engine/assembler.py +176 -0
  70. ksadk/context_engine/baseline.py +419 -0
  71. ksadk/context_engine/cache_observability.py +228 -0
  72. ksadk/context_engine/capabilities.py +443 -0
  73. ksadk/context_engine/contributors.py +344 -0
  74. ksadk/context_engine/hosted_pipeline.py +417 -0
  75. ksadk/context_engine/models.py +117 -0
  76. ksadk/context_engine/planner.py +698 -0
  77. ksadk/context_engine/policies.py +319 -0
  78. ksadk/context_engine/projection.py +31 -0
  79. ksadk/context_engine/shadow_plan.py +266 -0
  80. ksadk/context_engine/tokenizer.py +164 -0
  81. ksadk/conversations/__init__.py +85 -94
  82. ksadk/conversations/context.py +126 -6
  83. ksadk/conversations/message_projection.py +292 -28
  84. ksadk/conversations/model_context.py +49 -3
  85. ksadk/conversations/runtime_compaction.py +207 -5
  86. ksadk/conversations/runtime_input.py +193 -3
  87. ksadk/conversations/runtime_invocation.py +81 -3
  88. ksadk/conversations/runtime_observability.py +157 -4
  89. ksadk/conversations/runtime_payloads.py +42 -0
  90. ksadk/conversations/runtime_preparation.py +280 -2
  91. ksadk/conversations/runtime_resume.py +71 -32
  92. ksadk/conversations/runtime_stream_events.py +94 -9
  93. ksadk/conversations/runtime_streaming.py +175 -22
  94. ksadk/conversations/semantic_summary.py +311 -1
  95. ksadk/conversations/session_lock.py +51 -0
  96. ksadk/deployment/env_forward.py +72 -0
  97. ksadk/deployment/managed_runtime.py +38 -0
  98. ksadk/deployment/manager.py +24 -8
  99. ksadk/deployment/providers/serverless.py +228 -92
  100. ksadk/evaluation/__init__.py +116 -0
  101. ksadk/evaluation/a2a_adapter.py +452 -0
  102. ksadk/evaluation/adapters.py +67 -0
  103. ksadk/evaluation/agent_eval_client.py +395 -0
  104. ksadk/evaluation/cloud_binding.py +80 -0
  105. ksadk/evaluation/cloud_converter.py +194 -0
  106. ksadk/evaluation/cloud_service.py +199 -0
  107. ksadk/evaluation/contracts.py +478 -0
  108. ksadk/evaluation/evalset.py +351 -0
  109. ksadk/evaluation/evaluators.py +627 -0
  110. ksadk/evaluation/evidence.py +258 -0
  111. ksadk/evaluation/executor.py +143 -0
  112. ksadk/evaluation/local_adapter.py +550 -0
  113. ksadk/evaluation/service_env.py +27 -0
  114. ksadk/evaluation/storage.py +68 -0
  115. ksadk/evaluation/studio_build_adapter.py +253 -0
  116. ksadk/evaluation/target.py +82 -0
  117. ksadk/events/__init__.py +13 -13
  118. ksadk/events/_v1_compat/__init__.py +1 -0
  119. ksadk/events/_v1_compat/models.py +299 -0
  120. ksadk/events/_v1_compat/parser.py +247 -0
  121. ksadk/events/_v1_compat/projection.py +753 -0
  122. ksadk/events/adapters/__init__.py +34 -0
  123. ksadk/events/adapters/_a2a_snapshot.py +622 -0
  124. ksadk/events/adapters/_a2a_support.py +275 -0
  125. ksadk/events/adapters/_codex_interactions.py +375 -0
  126. ksadk/events/adapters/_codex_items.py +801 -0
  127. ksadk/events/adapters/_codex_validators.py +311 -0
  128. ksadk/events/adapters/_langgraph_support.py +785 -0
  129. ksadk/events/adapters/a2a.py +841 -0
  130. ksadk/events/adapters/adk.py +503 -0
  131. ksadk/events/adapters/codex.py +717 -0
  132. ksadk/events/adapters/langgraph.py +745 -0
  133. ksadk/events/canonical.py +440 -0
  134. ksadk/events/canonical_replay.py +497 -0
  135. ksadk/events/canonical_store.py +468 -0
  136. ksadk/events/cold_recovery.py +257 -0
  137. ksadk/events/content.py +89 -0
  138. ksadk/events/identity.py +86 -0
  139. ksadk/events/pipeline.py +455 -0
  140. ksadk/events/projections.py +66 -0
  141. ksadk/events/reducer.py +661 -0
  142. ksadk/events/replay.py +3 -36
  143. ksadk/events/runtime_event.py +20 -256
  144. ksadk/events/session_event.py +324 -0
  145. ksadk/events/store.py +3 -316
  146. ksadk/events/v1_compat.py +41 -0
  147. ksadk/harness/__init__.py +3 -2
  148. ksadk/harness/app.py +114 -123
  149. ksadk/harness/config.py +1 -1
  150. ksadk/harness/runtime.py +467 -0
  151. ksadk/hermes_terminal.py +5 -0
  152. ksadk/identity/resolver.py +4 -3
  153. ksadk/interaction/__init__.py +28 -0
  154. ksadk/interaction/contracts.py +136 -0
  155. ksadk/interaction/ledger.py +189 -0
  156. ksadk/interaction/provider.py +122 -0
  157. ksadk/interaction/providers/__init__.py +52 -0
  158. ksadk/interaction/providers/adk.py +40 -0
  159. ksadk/interaction/providers/codex.py +94 -0
  160. ksadk/interaction/providers/langgraph.py +58 -0
  161. ksadk/kernel/__init__.py +117 -0
  162. ksadk/kernel/authorization.py +258 -0
  163. ksadk/kernel/bootstrap.py +1074 -0
  164. ksadk/kernel/contract_fingerprints.py +61 -0
  165. ksadk/kernel/contracts.py +362 -0
  166. ksadk/kernel/control.py +219 -0
  167. ksadk/kernel/errors.py +79 -0
  168. ksadk/kernel/ingress.py +1102 -0
  169. ksadk/kernel/mapping.py +111 -0
  170. ksadk/kernel/memory_store.py +1133 -0
  171. ksadk/kernel/postgres_store.py +1756 -0
  172. ksadk/kernel/recovery.py +452 -0
  173. ksadk/kernel/runtime_identity.py +103 -0
  174. ksadk/kernel/sql/001_agent_kernel.sql +120 -0
  175. ksadk/kernel/sqlite_store.py +1410 -0
  176. ksadk/kernel/state.py +145 -0
  177. ksadk/kernel/store.py +232 -0
  178. ksadk/kernel/worker.py +953 -0
  179. ksadk/knowledge_base/client.py +22 -4
  180. ksadk/knowledge_base/service.py +32 -5
  181. ksadk/managed_a2a_card.py +160 -0
  182. ksadk/managed_runtime.py +16 -9
  183. ksadk/memory/__init__.py +61 -0
  184. ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
  185. ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
  186. ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
  187. ksadk/memory/adk/backends/sdk_ltm_backend.py +394 -5
  188. ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
  189. ksadk/memory/adk/long_term_memory.py +3 -2
  190. ksadk/memory/coordinator.py +461 -0
  191. ksadk/memory/events.py +202 -0
  192. ksadk/memory/extraction.py +228 -0
  193. ksadk/memory/ltm_backend_factory.py +16 -3
  194. ksadk/memory/models.py +316 -0
  195. ksadk/memory/policy.py +215 -0
  196. ksadk/memory/provider.py +47 -0
  197. ksadk/memory/provider_adapter.py +159 -0
  198. ksadk/memory/provider_resolver.py +71 -0
  199. ksadk/memory/providers/__init__.py +5 -0
  200. ksadk/memory/providers/local_sqlite.py +490 -0
  201. ksadk/memory/resolved_policy.py +145 -0
  202. ksadk/memory/service.py +198 -8
  203. ksadk/memory/tool.py +4 -0
  204. ksadk/model_proxy/bootstrap.py +16 -9
  205. ksadk/model_proxy/config.py +22 -1
  206. ksadk/model_proxy/detect.py +202 -9
  207. ksadk/model_proxy/namespace.py +67 -15
  208. ksadk/model_proxy/server.py +168 -6
  209. ksadk/model_proxy/transform.py +105 -3
  210. ksadk/observability/__init__.py +25 -0
  211. ksadk/observability/session_log.py +420 -0
  212. ksadk/observability/trajectory.py +105 -0
  213. ksadk/prompts/__init__.py +71 -0
  214. ksadk/prompts/compiler.py +215 -0
  215. ksadk/prompts/models.py +82 -0
  216. ksadk/prompts/projection.py +89 -0
  217. ksadk/prompts/resolved.py +137 -0
  218. ksadk/prompts/sources.py +233 -0
  219. ksadk/runners/_langgraph_runner_streams.py +822 -0
  220. ksadk/runners/adk_runner.py +14 -31
  221. ksadk/runners/base_runner.py +44 -3
  222. ksadk/runners/factory.py +3 -3
  223. ksadk/runners/langgraph_runner.py +252 -433
  224. ksadk/runners/utils/__init__.py +0 -10
  225. ksadk/runners/utils/loader.py +16 -0
  226. ksadk/runtime/__init__.py +67 -41
  227. ksadk/runtime/_runner_adapter/__init__.py +1 -0
  228. ksadk/runtime/_runner_adapter/stream_mapping.py +788 -0
  229. ksadk/runtime/adapter.py +199 -16
  230. ksadk/runtime/conversation_execution.py +687 -0
  231. ksadk/runtime/executor.py +392 -0
  232. ksadk/runtime/factory.py +342 -0
  233. ksadk/runtime/framework_adapters.py +6 -12
  234. ksadk/runtime/hosted_finalizer.py +268 -0
  235. ksadk/runtime/launch.py +61 -0
  236. ksadk/runtime/preprocessing.py +49 -14
  237. ksadk/runtime/runner_adapter.py +330 -391
  238. ksadk/runtime/runner_loading.py +36 -0
  239. ksadk/runtime/usage.py +33 -0
  240. ksadk/sandbox/backends/e2b.py +36 -3
  241. ksadk/server/__init__.py +39 -4
  242. ksadk/server/app.py +18 -492
  243. ksadk/server/composition.py +36 -2
  244. ksadk/server/factory.py +210 -149
  245. ksadk/server/routes/common.py +15 -46
  246. ksadk/server/routes/control.py +13 -9
  247. ksadk/server/routes/kernel_ingress.py +258 -0
  248. ksadk/server/routes/misc.py +10 -33
  249. ksadk/server/routes/models.py +14 -6
  250. ksadk/server/routes/openai_compat.py +129 -27
  251. ksadk/server/routes/projection.py +84 -16
  252. ksadk/server/routes/run.py +347 -460
  253. ksadk/server/routes/sessions.py +37 -40
  254. ksadk/server/routes/streaming.py +52 -7
  255. ksadk/server/routes/workspace.py +54 -21
  256. ksadk/server/static/assets/{ArtifactsPanel-Cjnqt-8W.js → ArtifactsPanel-DSU1sWD_.js} +1 -1
  257. ksadk/server/static/assets/{CodeBlock-BqyqZfuB.js → CodeBlock-DOH6MVcn.js} +4 -4
  258. ksadk/server/static/assets/{MathMessageMarkdown-BpH7jiFM.js → MathMessageMarkdown-BL8my1R2.js} +4 -4
  259. ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
  260. ksadk/server/static/assets/MermaidBlock-Dz4IP-Tx.js +312 -0
  261. ksadk/server/static/assets/NativeTerminalPanel-DUrK0JpZ.js +1 -0
  262. ksadk/server/static/assets/abnfDiagram-VCTEODGH-g20pFzNV.js +1 -0
  263. ksadk/server/static/assets/arc-C4FzinUA.js +1 -0
  264. ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +1 -0
  265. ksadk/server/static/assets/architectureDiagram-5GKGNRK7-DpIqL5h4.js +36 -0
  266. ksadk/server/static/assets/blockDiagram-NRAW4CY4-BjkljTNz.js +129 -0
  267. ksadk/server/static/assets/c4Diagram-UCG6FXSJ-Dk_ieq2X.js +38 -0
  268. ksadk/server/static/assets/channel-4cQHKtx1.js +1 -0
  269. ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +1 -0
  270. ksadk/server/static/assets/{chunk-FMBD7UC4-BGhvzDYt.js → chunk-5VM5RSS4-BVHAchFb.js} +1 -1
  271. ksadk/server/static/assets/{chunk-ND2GUHAM-D98vPd-E.js → chunk-F27PBJKO-C-ipQzuS.js} +1 -1
  272. ksadk/server/static/assets/chunk-G27WJ6UU-C2EyJbIK.js +231 -0
  273. ksadk/server/static/assets/{chunk-4BX2VUAB-CsWIQRhc.js → chunk-JWPE2WC7-vYvVJb_M.js} +1 -1
  274. ksadk/server/static/assets/chunk-LCL6LL3I-BcI6ysPT.js +206 -0
  275. ksadk/server/static/assets/chunk-POPQ4Y6H-C030x_Z1.js +1 -0
  276. ksadk/server/static/assets/chunk-RHFEMEQ7-yyGpsz4n.js +168 -0
  277. ksadk/server/static/assets/chunk-SVP7TREG-BLTlmMU7.js +88 -0
  278. ksadk/server/static/assets/chunk-XXDRQBXY-C_32ArgP.js +1 -0
  279. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +1 -0
  280. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +1 -0
  281. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-CX3yotHq.js → cose-bilkent-JH36ORCC-9YQYwdl0.js} +1 -1
  282. ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +1 -0
  283. ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-ErLF5N13.js +62 -0
  284. ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
  285. ksadk/server/static/assets/dagre-3AP2YEHR-DFiQF-6f.js +4 -0
  286. ksadk/server/static/assets/dagre-BuhGnRI1.js +1 -0
  287. ksadk/server/static/assets/diagram-S7CK7UJ4-Bt1v8-GC.js +30 -0
  288. ksadk/server/static/assets/diagram-UQ7AKVKN-DSCxJdBK.js +41 -0
  289. ksadk/server/static/assets/diagram-VSXAHHWV-DHfYwp_9.js +3 -0
  290. ksadk/server/static/assets/diagram-VX7I27RA-DdzD-4Le.js +24 -0
  291. ksadk/server/static/assets/diagram-Z3DM3KII-Du-nAJ9F.js +24 -0
  292. ksadk/server/static/assets/{dist-D82mtD2s.js → dist-8hqcx0sU.js} +1 -1
  293. ksadk/server/static/assets/dist-B7seoj3d.js +1 -0
  294. ksadk/server/static/assets/{dist-DHn6nBzr.js → dist-BE7bu-DL.js} +1 -1
  295. ksadk/server/static/assets/{dist-eoW6tZXA.js → dist-BVDffZ0U.js} +1 -1
  296. ksadk/server/static/assets/{dist-C2xjE7cO.js → dist-BX8z72IC.js} +1 -1
  297. ksadk/server/static/assets/{dist-CgF3fj15.js → dist-Bf2M8m3N.js} +1 -1
  298. ksadk/server/static/assets/{dist-Bs-jQcRX.js → dist-BjU6y-A2.js} +1 -1
  299. ksadk/server/static/assets/{dist-Djgl2wVZ.js → dist-BytlxIDT.js} +1 -1
  300. ksadk/server/static/assets/{dist-CVQRZjPu.js → dist-CSh_DE14.js} +1 -1
  301. ksadk/server/static/assets/{dist-6CVKuTAe.js → dist-CXYYBw3_.js} +1 -1
  302. ksadk/server/static/assets/{dist-DlzCRy0S.js → dist-C_wsv-Qd.js} +1 -1
  303. ksadk/server/static/assets/{dist-DF06ORQo.js → dist-ClxGviKw.js} +1 -1
  304. ksadk/server/static/assets/{dist-Cf23NY4L.js → dist-CttYUqzS.js} +1 -1
  305. ksadk/server/static/assets/{dist-ivOya1LD.js → dist-DNp6rLRA.js} +1 -1
  306. ksadk/server/static/assets/{dist-BibcG1V9.js → dist-DUX-id_F.js} +1 -1
  307. ksadk/server/static/assets/{dist-BUHRxvDG.js → dist-DmldrHd_.js} +1 -1
  308. ksadk/server/static/assets/{dist-BZ9n9AjO.js → dist-DnfXs8Vn.js} +2 -2
  309. ksadk/server/static/assets/{dist-DqNnNFrw.js → dist-Dq9gLD7L.js} +1 -1
  310. ksadk/server/static/assets/{dist-CGcp2ex8.js → dist-W-TIVntx.js} +1 -1
  311. ksadk/server/static/assets/{dist-Cwt7koer.js → dist-dDdADKFA.js} +1 -1
  312. ksadk/server/static/assets/{dist-C7-3jInC.js → dist-dydu68Fl.js} +1 -1
  313. ksadk/server/static/assets/{dist-C99THtIA.js → dist-ngtN0DJB.js} +1 -1
  314. ksadk/server/static/assets/ebnfDiagram-PWID7BFC-Da9C9NO1.js +1 -0
  315. ksadk/server/static/assets/erDiagram-SSCWMZ5O-EAGqqR79.js +99 -0
  316. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +1 -0
  317. ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +1 -0
  318. ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-DqJsKb59.js +292 -0
  319. ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +1 -0
  320. ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-B6g4dtDi.js +106 -0
  321. ksadk/server/static/assets/index-8ipRcQ-M.js +240 -0
  322. ksadk/server/static/assets/index-ByFCqjlh.css +2 -0
  323. ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +1 -0
  324. ksadk/server/static/assets/infoDiagram-RXCK75RN-Djm_nbd5.js +2 -0
  325. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-DLOHGvWw.js → ishikawaDiagram-5VMMS53U-DWya9SG2.js} +6 -6
  326. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-BIzKeejT.js → journeyDiagram-EYS64GPL-DutxhSNI.js} +6 -6
  327. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-BWHoFSw2.js → kanban-definition-3QL26DDD-DJdOF8Fm.js} +10 -10
  328. ksadk/server/static/assets/katex-vFWytM5c.js +257 -0
  329. ksadk/server/static/assets/{linear-CvMBw9cA.js → linear-BHjG8b-J.js} +1 -1
  330. ksadk/server/static/assets/mermaid-parser.core-KGSy4jWT.js +166 -0
  331. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-CSAQxEAe.js → mindmap-definition-FBJOCRG2-9-HC88D4.js} +29 -29
  332. ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +1 -0
  333. ksadk/server/static/assets/pegDiagram-XKGWAZYB-DrEZd4fD.js +1 -0
  334. ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +1 -0
  335. ksadk/server/static/assets/pieDiagram-E7YTZNPT-DpjqOFFp.js +39 -0
  336. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-CxIR4JXI.js → quadrantDiagram-AXDQQJYC-BiNhgOXX.js} +6 -6
  337. ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +1 -0
  338. ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +1 -0
  339. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +1 -0
  340. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +1 -0
  341. ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +1 -0
  342. ksadk/server/static/assets/railroadDiagram-O6MQD6OU-_Y3Ojg6G.js +1 -0
  343. ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-DeCFdg9K.js +84 -0
  344. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-DpGa6EAV.js → sankeyDiagram-P5KCCOFB-CPH75rhw.js} +7 -7
  345. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-NTKNGGe5.js → sequenceDiagram-WJ2MYXX4-OEpQQdr4.js} +10 -10
  346. ksadk/server/static/assets/sizeCapture-X5ZJPWSS-heUErzhI.js +1 -0
  347. ksadk/server/static/assets/stateDiagram-HBIQ2CUA-DvA3jSMB.js +1 -0
  348. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +1 -0
  349. ksadk/server/static/assets/swimlanes-XN3QIQJK-CR-dfN_t.js +1 -0
  350. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +8 -0
  351. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-jqoYs3jQ.js → timeline-definition-24CTP7MA-DAVJf1TX.js} +7 -7
  352. ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +1 -0
  353. ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +1 -0
  354. ksadk/server/static/assets/vennDiagram-4TSXK5OY-DwM8eDkh.js +34 -0
  355. ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +1 -0
  356. ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DZL-Zz2t.js +78 -0
  357. ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js +7 -0
  358. ksadk/server/static/index.html +2 -2
  359. ksadk/sessions/__init__.py +26 -9
  360. ksadk/sessions/_local_service_sync.py +688 -0
  361. ksadk/sessions/_local_tables.py +21 -0
  362. ksadk/sessions/_postgres_schema.py +305 -0
  363. ksadk/sessions/_postgres_tables.py +15 -0
  364. ksadk/sessions/base.py +80 -1
  365. ksadk/sessions/in_memory.py +53 -2
  366. ksadk/sessions/local_service.py +63 -604
  367. ksadk/sessions/postgres_service.py +58 -148
  368. ksadk/sessions/resilient.py +35 -1
  369. ksadk/skills/runtime/backends/e2b.py +1 -1
  370. ksadk/skills/service_client.py +13 -3
  371. ksadk/studio/__init__.py +5 -0
  372. ksadk/studio/agent_avatar_assets.py +120 -0
  373. ksadk/studio/agent_lifecycle.py +51 -0
  374. ksadk/studio/api.py +1598 -0
  375. ksadk/studio/api_catalog_routes.py +324 -0
  376. ksadk/studio/api_contracts.py +286 -0
  377. ksadk/studio/api_helpers.py +132 -0
  378. ksadk/studio/api_memory_routes.py +82 -0
  379. ksadk/studio/authoring.py +749 -0
  380. ksadk/studio/authoring_coordinator.py +1017 -0
  381. ksadk/studio/builder.py +397 -0
  382. ksadk/studio/capabilities.py +368 -0
  383. ksadk/studio/cloud.py +2099 -0
  384. ksadk/studio/codex_agent_service.py +694 -0
  385. ksadk/studio/codex_authoring.py +469 -0
  386. ksadk/studio/codex_builder.py +437 -0
  387. ksadk/studio/codex_manifest.py +307 -0
  388. ksadk/studio/codex_run.py +395 -0
  389. ksadk/studio/compiler.py +190 -0
  390. ksadk/studio/contracts.py +755 -0
  391. ksadk/studio/errors.py +47 -0
  392. ksadk/studio/event_store.py +214 -0
  393. ksadk/studio/framework_run.py +342 -0
  394. ksadk/studio/hosted_kernel.py +317 -0
  395. ksadk/studio/identifiers.py +33 -0
  396. ksadk/studio/manifest_resolver.py +131 -0
  397. ksadk/studio/mcp_runtime.py +229 -0
  398. ksadk/studio/model_client.py +629 -0
  399. ksadk/studio/model_profile_service.py +214 -0
  400. ksadk/studio/operations.py +275 -0
  401. ksadk/studio/otel_trace.py +1060 -0
  402. ksadk/studio/pagination.py +182 -0
  403. ksadk/studio/pcm_memory.py +85 -0
  404. ksadk/studio/python_tool_inspection.py +183 -0
  405. ksadk/studio/repository.py +327 -0
  406. ksadk/studio/resource_catalog.py +1260 -0
  407. ksadk/studio/run_service.py +1133 -0
  408. ksadk/studio/runtime_catalog.py +74 -0
  409. ksadk/studio/runtime_source.py +365 -0
  410. ksadk/studio/service.py +2249 -0
  411. ksadk/studio/shared_web.py +1004 -0
  412. ksadk/studio/skill_discovery.py +628 -0
  413. ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
  414. ksadk/studio/static/assets/index-BLpcdrgW.css +1 -0
  415. ksadk/studio/static/assets/index-CYekR2Xv.js +260 -0
  416. ksadk/studio/static/assets/react-vendor-BNmTiJ-I.js +9 -0
  417. ksadk/studio/static/assets/rolldown-runtime-hePW80VL.js +1 -0
  418. ksadk/studio/static/index.html +15 -0
  419. ksadk/studio/templates.py +722 -0
  420. ksadk/studio/validator.py +265 -0
  421. ksadk/studio/workspace.py +135 -0
  422. ksadk/tools/gateway.py +9 -0
  423. ksadk/toolsets/__init__.py +27 -1
  424. ksadk/toolsets/a2a.py +426 -0
  425. ksadk/tracing/__init__.py +19 -21
  426. ksadk/tracing/setup.py +317 -403
  427. ksadk/tracing/span_utils.py +0 -44
  428. ksadk/version.py +1 -1
  429. ksadk_runtime_common/memory_backend/registry.py +56 -56
  430. ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
  431. ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
  432. ksadk_runtime_common/workspace_files/router.py +8 -2
  433. agentengine_sdk_python-0.8.0.dist-info/RECORD +0 -578
  434. ksadk/a2a/card_builder.py +0 -64
  435. ksadk/a2a/client.py +0 -309
  436. ksadk/events/parser.py +0 -191
  437. ksadk/harness/runner.py +0 -211
  438. ksadk/runners/codex_runner.py +0 -132
  439. ksadk/runners/utils/langfuse.py +0 -230
  440. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
  441. ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +0 -303
  442. ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +0 -1
  443. ksadk/server/static/assets/arc-CFKwSk_B.js +0 -1
  444. ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +0 -1
  445. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-Dej8jX8c.js +0 -36
  446. ksadk/server/static/assets/blockDiagram-GPEHLZMM-1F64jqvy.js +0 -132
  447. ksadk/server/static/assets/c4Diagram-AAUBKEIU-9q7AUAKb.js +0 -10
  448. ksadk/server/static/assets/channel-iUGv2N24.js +0 -1
  449. ksadk/server/static/assets/chunk-2J33WTMH-6qgwJm7Q.js +0 -1
  450. ksadk/server/static/assets/chunk-55IACEB6-BK8paA20.js +0 -1
  451. ksadk/server/static/assets/chunk-727SXJPM-B-JEhy7h.js +0 -206
  452. ksadk/server/static/assets/chunk-AQP2D5EJ-DYBvMHAa.js +0 -231
  453. ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +0 -1
  454. ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +0 -1
  455. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +0 -1
  456. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
  457. ksadk/server/static/assets/dagre-BM42HDAG-C7TguAWo.js +0 -4
  458. ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
  459. ksadk/server/static/assets/diagram-2AECGRRQ-Dd17_kws.js +0 -43
  460. ksadk/server/static/assets/diagram-5GNKFQAL-DVIClIil.js +0 -10
  461. ksadk/server/static/assets/diagram-KO2AKTUF-Df_3gYQa.js +0 -3
  462. ksadk/server/static/assets/diagram-LMA3HP47-BhLk6ZtA.js +0 -24
  463. ksadk/server/static/assets/diagram-OG6HWLK6-D4GNGvuu.js +0 -24
  464. ksadk/server/static/assets/dist-DyvYLMW9.js +0 -1
  465. ksadk/server/static/assets/erDiagram-TEJ5UH35-CnfRcY2M.js +0 -85
  466. ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +0 -1
  467. ksadk/server/static/assets/flowDiagram-I6XJVG4X-DGaJjGNJ.js +0 -162
  468. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-DpCoB2g9.js +0 -292
  469. ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +0 -1
  470. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-9IKVFBVT.js +0 -106
  471. ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
  472. ksadk/server/static/assets/index-QSwCHuB8.js +0 -177
  473. ksadk/server/static/assets/index-jOPmTOZH.css +0 -2
  474. ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +0 -1
  475. ksadk/server/static/assets/infoDiagram-5YYISTIA-CYIIsb8y.js +0 -2
  476. ksadk/server/static/assets/katex-DATssjp1.js +0 -265
  477. ksadk/server/static/assets/mermaid-parser.core-mGAcEwcq.js +0 -161
  478. ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +0 -1
  479. ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +0 -1
  480. ksadk/server/static/assets/pieDiagram-4H26LBE5-By-ra07M.js +0 -30
  481. ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +0 -1
  482. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DpW90iu3.js +0 -84
  483. ksadk/server/static/assets/stateDiagram-AJRCARHV-DGpd9yFG.js +0 -1
  484. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +0 -1
  485. ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +0 -1
  486. ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +0 -1
  487. ksadk/server/static/assets/vennDiagram-CIIHVFJN-l3Z7-wbP.js +0 -34
  488. ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +0 -1
  489. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-BR54GPmr.js +0 -78
  490. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-SkiH8GsK.js +0 -7
  491. ksadk/tracing/exporters/langfuse_exporter.py +0 -460
  492. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/entry_points.txt +0 -0
  493. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/licenses/LICENSE +0 -0
  494. {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)