@uns-kit/assistant-workflow 2.0.72

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 (295) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -0
  3. package/dist/clarification-policy.d.ts +64 -0
  4. package/dist/clarification-policy.d.ts.map +1 -0
  5. package/dist/clarification-policy.js +174 -0
  6. package/dist/clarification-policy.js.map +1 -0
  7. package/dist/decision.d.ts +37 -0
  8. package/dist/decision.d.ts.map +1 -0
  9. package/dist/decision.js +100 -0
  10. package/dist/decision.js.map +1 -0
  11. package/dist/definition-catalog-replay.d.ts +25 -0
  12. package/dist/definition-catalog-replay.d.ts.map +1 -0
  13. package/dist/definition-catalog-replay.js +54 -0
  14. package/dist/definition-catalog-replay.js.map +1 -0
  15. package/dist/definition-catalog.d.ts +45 -0
  16. package/dist/definition-catalog.d.ts.map +1 -0
  17. package/dist/definition-catalog.js +97 -0
  18. package/dist/definition-catalog.js.map +1 -0
  19. package/dist/definition-diagnostics.d.ts +17 -0
  20. package/dist/definition-diagnostics.d.ts.map +1 -0
  21. package/dist/definition-diagnostics.js +353 -0
  22. package/dist/definition-diagnostics.js.map +1 -0
  23. package/dist/definition-diff.d.ts +51 -0
  24. package/dist/definition-diff.d.ts.map +1 -0
  25. package/dist/definition-diff.js +172 -0
  26. package/dist/definition-diff.js.map +1 -0
  27. package/dist/definition-json.d.ts +53 -0
  28. package/dist/definition-json.d.ts.map +1 -0
  29. package/dist/definition-json.js +186 -0
  30. package/dist/definition-json.js.map +1 -0
  31. package/dist/definition-manifest.d.ts +41 -0
  32. package/dist/definition-manifest.d.ts.map +1 -0
  33. package/dist/definition-manifest.js +119 -0
  34. package/dist/definition-manifest.js.map +1 -0
  35. package/dist/definition-package-execution-json.d.ts +64 -0
  36. package/dist/definition-package-execution-json.d.ts.map +1 -0
  37. package/dist/definition-package-execution-json.js +245 -0
  38. package/dist/definition-package-execution-json.js.map +1 -0
  39. package/dist/definition-package-execution-replay.d.ts +14 -0
  40. package/dist/definition-package-execution-replay.d.ts.map +1 -0
  41. package/dist/definition-package-execution-replay.js +47 -0
  42. package/dist/definition-package-execution-replay.js.map +1 -0
  43. package/dist/definition-package-executor.d.ts +52 -0
  44. package/dist/definition-package-executor.d.ts.map +1 -0
  45. package/dist/definition-package-executor.js +70 -0
  46. package/dist/definition-package-executor.js.map +1 -0
  47. package/dist/definition-package-loader.d.ts +36 -0
  48. package/dist/definition-package-loader.d.ts.map +1 -0
  49. package/dist/definition-package-loader.js +56 -0
  50. package/dist/definition-package-loader.js.map +1 -0
  51. package/dist/definition-package-replay.d.ts +28 -0
  52. package/dist/definition-package-replay.d.ts.map +1 -0
  53. package/dist/definition-package-replay.js +74 -0
  54. package/dist/definition-package-replay.js.map +1 -0
  55. package/dist/definition-package-resolver.d.ts +31 -0
  56. package/dist/definition-package-resolver.d.ts.map +1 -0
  57. package/dist/definition-package-resolver.js +60 -0
  58. package/dist/definition-package-resolver.js.map +1 -0
  59. package/dist/definition-package-review.d.ts +29 -0
  60. package/dist/definition-package-review.d.ts.map +1 -0
  61. package/dist/definition-package-review.js +74 -0
  62. package/dist/definition-package-review.js.map +1 -0
  63. package/dist/definition-package-run-report.d.ts +25 -0
  64. package/dist/definition-package-run-report.d.ts.map +1 -0
  65. package/dist/definition-package-run-report.js +37 -0
  66. package/dist/definition-package-run-report.js.map +1 -0
  67. package/dist/definition-package-run.d.ts +20 -0
  68. package/dist/definition-package-run.d.ts.map +1 -0
  69. package/dist/definition-package-run.js +41 -0
  70. package/dist/definition-package-run.js.map +1 -0
  71. package/dist/definition-package-selection.d.ts +29 -0
  72. package/dist/definition-package-selection.d.ts.map +1 -0
  73. package/dist/definition-package-selection.js +68 -0
  74. package/dist/definition-package-selection.js.map +1 -0
  75. package/dist/definition-package-smoke.d.ts +74 -0
  76. package/dist/definition-package-smoke.d.ts.map +1 -0
  77. package/dist/definition-package-smoke.js +184 -0
  78. package/dist/definition-package-smoke.js.map +1 -0
  79. package/dist/definition-package.d.ts +36 -0
  80. package/dist/definition-package.d.ts.map +1 -0
  81. package/dist/definition-package.js +114 -0
  82. package/dist/definition-package.js.map +1 -0
  83. package/dist/definition-tuning-approval.d.ts +39 -0
  84. package/dist/definition-tuning-approval.d.ts.map +1 -0
  85. package/dist/definition-tuning-approval.js +207 -0
  86. package/dist/definition-tuning-approval.js.map +1 -0
  87. package/dist/definition-tuning-json.d.ts +58 -0
  88. package/dist/definition-tuning-json.d.ts.map +1 -0
  89. package/dist/definition-tuning-json.js +276 -0
  90. package/dist/definition-tuning-json.js.map +1 -0
  91. package/dist/definition-tuning-promotion.d.ts +120 -0
  92. package/dist/definition-tuning-promotion.d.ts.map +1 -0
  93. package/dist/definition-tuning-promotion.js +460 -0
  94. package/dist/definition-tuning-promotion.js.map +1 -0
  95. package/dist/definition-tuning-replay.d.ts +14 -0
  96. package/dist/definition-tuning-replay.d.ts.map +1 -0
  97. package/dist/definition-tuning-replay.js +50 -0
  98. package/dist/definition-tuning-replay.js.map +1 -0
  99. package/dist/definition-tuning-review-artifact.d.ts +56 -0
  100. package/dist/definition-tuning-review-artifact.d.ts.map +1 -0
  101. package/dist/definition-tuning-review-artifact.js +302 -0
  102. package/dist/definition-tuning-review-artifact.js.map +1 -0
  103. package/dist/definition-tuning-review.d.ts +59 -0
  104. package/dist/definition-tuning-review.d.ts.map +1 -0
  105. package/dist/definition-tuning-review.js +213 -0
  106. package/dist/definition-tuning-review.js.map +1 -0
  107. package/dist/definition-tuning-source-patch.d.ts +43 -0
  108. package/dist/definition-tuning-source-patch.d.ts.map +1 -0
  109. package/dist/definition-tuning-source-patch.js +214 -0
  110. package/dist/definition-tuning-source-patch.js.map +1 -0
  111. package/dist/definition-tuning.d.ts +73 -0
  112. package/dist/definition-tuning.d.ts.map +1 -0
  113. package/dist/definition-tuning.js +426 -0
  114. package/dist/definition-tuning.js.map +1 -0
  115. package/dist/definition.d.ts +189 -0
  116. package/dist/definition.d.ts.map +1 -0
  117. package/dist/definition.js +494 -0
  118. package/dist/definition.js.map +1 -0
  119. package/dist/direct-route-invocation.d.ts +132 -0
  120. package/dist/direct-route-invocation.d.ts.map +1 -0
  121. package/dist/direct-route-invocation.js +325 -0
  122. package/dist/direct-route-invocation.js.map +1 -0
  123. package/dist/direct-route-policy.d.ts +25 -0
  124. package/dist/direct-route-policy.d.ts.map +1 -0
  125. package/dist/direct-route-policy.js +106 -0
  126. package/dist/direct-route-policy.js.map +1 -0
  127. package/dist/eval-case.d.ts +85 -0
  128. package/dist/eval-case.d.ts.map +1 -0
  129. package/dist/eval-case.js +366 -0
  130. package/dist/eval-case.js.map +1 -0
  131. package/dist/eval-replay.d.ts +18 -0
  132. package/dist/eval-replay.d.ts.map +1 -0
  133. package/dist/eval-replay.js +41 -0
  134. package/dist/eval-replay.js.map +1 -0
  135. package/dist/eval-result.d.ts +46 -0
  136. package/dist/eval-result.d.ts.map +1 -0
  137. package/dist/eval-result.js +183 -0
  138. package/dist/eval-result.js.map +1 -0
  139. package/dist/eval-runner.d.ts +30 -0
  140. package/dist/eval-runner.d.ts.map +1 -0
  141. package/dist/eval-runner.js +57 -0
  142. package/dist/eval-runner.js.map +1 -0
  143. package/dist/eval-suite.d.ts +43 -0
  144. package/dist/eval-suite.d.ts.map +1 -0
  145. package/dist/eval-suite.js +101 -0
  146. package/dist/eval-suite.js.map +1 -0
  147. package/dist/execution-plan.d.ts +43 -0
  148. package/dist/execution-plan.d.ts.map +1 -0
  149. package/dist/execution-plan.js +187 -0
  150. package/dist/execution-plan.js.map +1 -0
  151. package/dist/hosted-tool-policy.d.ts +70 -0
  152. package/dist/hosted-tool-policy.d.ts.map +1 -0
  153. package/dist/hosted-tool-policy.js +228 -0
  154. package/dist/hosted-tool-policy.js.map +1 -0
  155. package/dist/index.d.ts +73 -0
  156. package/dist/index.d.ts.map +1 -0
  157. package/dist/index.js +73 -0
  158. package/dist/index.js.map +1 -0
  159. package/dist/memory-policy.d.ts +55 -0
  160. package/dist/memory-policy.d.ts.map +1 -0
  161. package/dist/memory-policy.js +187 -0
  162. package/dist/memory-policy.js.map +1 -0
  163. package/dist/memory-updates.d.ts +39 -0
  164. package/dist/memory-updates.d.ts.map +1 -0
  165. package/dist/memory-updates.js +110 -0
  166. package/dist/memory-updates.js.map +1 -0
  167. package/dist/outcome-trace.d.ts +79 -0
  168. package/dist/outcome-trace.d.ts.map +1 -0
  169. package/dist/outcome-trace.js +117 -0
  170. package/dist/outcome-trace.js.map +1 -0
  171. package/dist/outcome.d.ts +97 -0
  172. package/dist/outcome.d.ts.map +1 -0
  173. package/dist/outcome.js +160 -0
  174. package/dist/outcome.js.map +1 -0
  175. package/dist/planner-compiler.d.ts +14 -0
  176. package/dist/planner-compiler.d.ts.map +1 -0
  177. package/dist/planner-compiler.js +26 -0
  178. package/dist/planner-compiler.js.map +1 -0
  179. package/dist/planning.d.ts +36 -0
  180. package/dist/planning.d.ts.map +1 -0
  181. package/dist/planning.js +141 -0
  182. package/dist/planning.js.map +1 -0
  183. package/dist/policy-resolution.d.ts +10 -0
  184. package/dist/policy-resolution.d.ts.map +1 -0
  185. package/dist/policy-resolution.js +30 -0
  186. package/dist/policy-resolution.js.map +1 -0
  187. package/dist/run-evaluation.d.ts +29 -0
  188. package/dist/run-evaluation.d.ts.map +1 -0
  189. package/dist/run-evaluation.js +128 -0
  190. package/dist/run-evaluation.js.map +1 -0
  191. package/dist/run-parity.d.ts +24 -0
  192. package/dist/run-parity.d.ts.map +1 -0
  193. package/dist/run-parity.js +36 -0
  194. package/dist/run-parity.js.map +1 -0
  195. package/dist/run-report-batch.d.ts +150 -0
  196. package/dist/run-report-batch.d.ts.map +1 -0
  197. package/dist/run-report-batch.js +391 -0
  198. package/dist/run-report-batch.js.map +1 -0
  199. package/dist/run-report-json.d.ts +76 -0
  200. package/dist/run-report-json.d.ts.map +1 -0
  201. package/dist/run-report-json.js +451 -0
  202. package/dist/run-report-json.js.map +1 -0
  203. package/dist/run-report.d.ts +22 -0
  204. package/dist/run-report.d.ts.map +1 -0
  205. package/dist/run-report.js +46 -0
  206. package/dist/run-report.js.map +1 -0
  207. package/dist/run.d.ts +20 -0
  208. package/dist/run.d.ts.map +1 -0
  209. package/dist/run.js +36 -0
  210. package/dist/run.js.map +1 -0
  211. package/dist/tool-bindings.d.ts +42 -0
  212. package/dist/tool-bindings.d.ts.map +1 -0
  213. package/dist/tool-bindings.js +124 -0
  214. package/dist/tool-bindings.js.map +1 -0
  215. package/dist/tool-capabilities.d.ts +37 -0
  216. package/dist/tool-capabilities.d.ts.map +1 -0
  217. package/dist/tool-capabilities.js +91 -0
  218. package/dist/tool-capabilities.js.map +1 -0
  219. package/dist/tool-executor.d.ts +63 -0
  220. package/dist/tool-executor.d.ts.map +1 -0
  221. package/dist/tool-executor.js +176 -0
  222. package/dist/tool-executor.js.map +1 -0
  223. package/dist/tool-fixtures.d.ts +18 -0
  224. package/dist/tool-fixtures.d.ts.map +1 -0
  225. package/dist/tool-fixtures.js +52 -0
  226. package/dist/tool-fixtures.js.map +1 -0
  227. package/dist/tool-invocations.d.ts +31 -0
  228. package/dist/tool-invocations.d.ts.map +1 -0
  229. package/dist/tool-invocations.js +79 -0
  230. package/dist/tool-invocations.js.map +1 -0
  231. package/dist/tool-provider-executors.d.ts +43 -0
  232. package/dist/tool-provider-executors.d.ts.map +1 -0
  233. package/dist/tool-provider-executors.js +59 -0
  234. package/dist/tool-provider-executors.js.map +1 -0
  235. package/dist/tool-result-cache.d.ts +37 -0
  236. package/dist/tool-result-cache.d.ts.map +1 -0
  237. package/dist/tool-result-cache.js +173 -0
  238. package/dist/tool-result-cache.js.map +1 -0
  239. package/dist/tool-results.d.ts +41 -0
  240. package/dist/tool-results.d.ts.map +1 -0
  241. package/dist/tool-results.js +137 -0
  242. package/dist/tool-results.js.map +1 -0
  243. package/dist/tool-runtime.d.ts +46 -0
  244. package/dist/tool-runtime.d.ts.map +1 -0
  245. package/dist/tool-runtime.js +163 -0
  246. package/dist/tool-runtime.js.map +1 -0
  247. package/dist/tool-selection-evaluation.d.ts +214 -0
  248. package/dist/tool-selection-evaluation.d.ts.map +1 -0
  249. package/dist/tool-selection-evaluation.js +773 -0
  250. package/dist/tool-selection-evaluation.js.map +1 -0
  251. package/dist/tool-selection-json.d.ts +71 -0
  252. package/dist/tool-selection-json.d.ts.map +1 -0
  253. package/dist/tool-selection-json.js +284 -0
  254. package/dist/tool-selection-json.js.map +1 -0
  255. package/dist/tool-selection-policy.d.ts +81 -0
  256. package/dist/tool-selection-policy.d.ts.map +1 -0
  257. package/dist/tool-selection-policy.js +376 -0
  258. package/dist/tool-selection-policy.js.map +1 -0
  259. package/dist/tool-selection-replay.d.ts +26 -0
  260. package/dist/tool-selection-replay.d.ts.map +1 -0
  261. package/dist/tool-selection-replay.js +88 -0
  262. package/dist/tool-selection-replay.js.map +1 -0
  263. package/dist/tool-selection-rules.d.ts +46 -0
  264. package/dist/tool-selection-rules.d.ts.map +1 -0
  265. package/dist/tool-selection-rules.js +183 -0
  266. package/dist/tool-selection-rules.js.map +1 -0
  267. package/dist/tool-selection-trace-export.d.ts +37 -0
  268. package/dist/tool-selection-trace-export.d.ts.map +1 -0
  269. package/dist/tool-selection-trace-export.js +324 -0
  270. package/dist/tool-selection-trace-export.js.map +1 -0
  271. package/dist/trace-events.d.ts +14 -0
  272. package/dist/trace-events.d.ts.map +1 -0
  273. package/dist/trace-events.js +65 -0
  274. package/dist/trace-events.js.map +1 -0
  275. package/dist/trace-payload.d.ts +24 -0
  276. package/dist/trace-payload.d.ts.map +1 -0
  277. package/dist/trace-payload.js +113 -0
  278. package/dist/trace-payload.js.map +1 -0
  279. package/dist/trace-replay.d.ts +276 -0
  280. package/dist/trace-replay.d.ts.map +1 -0
  281. package/dist/trace-replay.js +685 -0
  282. package/dist/trace-replay.js.map +1 -0
  283. package/dist/trace-report.d.ts +320 -0
  284. package/dist/trace-report.d.ts.map +1 -0
  285. package/dist/trace-report.js +1394 -0
  286. package/dist/trace-report.js.map +1 -0
  287. package/dist/trace-stages.d.ts +70 -0
  288. package/dist/trace-stages.d.ts.map +1 -0
  289. package/dist/trace-stages.js +103 -0
  290. package/dist/trace-stages.js.map +1 -0
  291. package/dist/value-readers.d.ts +20 -0
  292. package/dist/value-readers.d.ts.map +1 -0
  293. package/dist/value-readers.js +82 -0
  294. package/dist/value-readers.js.map +1 -0
  295. package/package.json +341 -0
@@ -0,0 +1,1394 @@
1
+ import { buildAssistantWorkflowTraceEvalCandidate, buildAssistantWorkflowTraceSummary, collectAssistantWorkflowTraceTuningSignals, getAssistantWorkflowUnmodeledToolCalls, getMissingWorkflowSelectionCandidateTools, hasAssistantWorkflowConstrainedToolSelectionEvidence, } from "./trace-replay.js";
2
+ import { readAssistantWorkflowTraceString as normalizeNullableString, } from "./trace-events.js";
3
+ import { ASSISTANT_WORKFLOW_RUN_REPORT_JSON_SCHEMA_VERSION, } from "./run-report-json.js";
4
+ import { ASSISTANT_WORKFLOW_TRACE_STAGE } from "./trace-stages.js";
5
+ import { buildAssistantWorkflowToolSelectionProfileKey } from "./tool-selection-policy.js";
6
+ export function buildAssistantWorkflowMemoryPatchReadiness(report, options = {}) {
7
+ const workflowIds = normalizeStringScope(options.workflowIds);
8
+ const workflowVersions = normalizeNumberScope(options.workflowVersions);
9
+ const scopedRows = selectWorkflowScopedTraceRows(report.rows, workflowIds, workflowVersions);
10
+ const scopedPatches = scopedRows.flatMap((row) => row.summary.memoryPatches);
11
+ const minEquivalentPatchCount = normalizePositiveInt(options.minEquivalentPatchCount, 1);
12
+ const minGuardedWorkflowWriteCount = normalizeNonNegativeInt(options.minGuardedWorkflowWriteCount, 0);
13
+ const minWorkflowPatchWriteCount = normalizeNonNegativeInt(options.minWorkflowPatchWriteCount, 0);
14
+ const minWorkflowModePatchWriteCount = normalizeNonNegativeInt(options.minWorkflowModePatchWriteCount, 0);
15
+ const requiredPatchDerivationCounts = normalizePatchDerivationRequirements(options.minPatchDerivationCounts);
16
+ const equivalenceCounts = buildStringCounts(scopedPatches.map(buildMemoryPatchEquivalenceKey));
17
+ const derivationCounts = buildStringCounts(scopedPatches.map(buildMemoryPatchDerivationKey));
18
+ const mismatchedProfileFieldCounts = buildStringCounts(scopedPatches.flatMap((patch) => patch.profilePatchMismatchedFields));
19
+ const writeSourceCounts = buildStringCounts(scopedPatches.map(buildMemoryPatchWriteSourceKey));
20
+ const writeReasonCounts = buildStringCounts(scopedPatches.map(buildMemoryPatchWriteReasonKey));
21
+ const equivalentPatchCount = findReportCount(equivalenceCounts, "equivalent");
22
+ const mismatchPatchCount = findReportCount(equivalenceCounts, "mismatch");
23
+ const unknownPatchCount = findReportCount(equivalenceCounts, "unknown");
24
+ const totalPatchCount = equivalenceCounts.reduce((sum, item) => sum + item.count, 0);
25
+ const guardedWorkflowWriteCount = findReportCount(writeSourceCounts, "guarded:workflow_patch");
26
+ const workflowModePatchWriteCount = findReportCount(writeSourceCounts, "workflow:workflow_patch");
27
+ const workflowPatchWriteCount = sumWriteSourceCountsBySource(writeSourceCounts, "workflow_patch");
28
+ const guardedLegacyFallbackCount = findReportCount(writeSourceCounts, "guarded:legacy_fallback");
29
+ const blockingReasons = [];
30
+ if (equivalentPatchCount < minEquivalentPatchCount) {
31
+ blockingReasons.push(`equivalent_patch_count_below_minimum:${equivalentPatchCount}/${minEquivalentPatchCount}`);
32
+ }
33
+ if (mismatchPatchCount > 0) {
34
+ blockingReasons.push(`profile_patch_mismatch:${mismatchPatchCount}`);
35
+ }
36
+ if (unknownPatchCount > 0) {
37
+ blockingReasons.push(`profile_patch_equivalence_unknown:${unknownPatchCount}`);
38
+ }
39
+ if (guardedLegacyFallbackCount > 0) {
40
+ blockingReasons.push(`guarded_legacy_fallback:${guardedLegacyFallbackCount}`);
41
+ }
42
+ if (guardedWorkflowWriteCount < minGuardedWorkflowWriteCount) {
43
+ blockingReasons.push(`guarded_workflow_write_count_below_minimum:${guardedWorkflowWriteCount}/${minGuardedWorkflowWriteCount}`);
44
+ }
45
+ if (workflowPatchWriteCount < minWorkflowPatchWriteCount) {
46
+ blockingReasons.push(`workflow_patch_write_count_below_minimum:${workflowPatchWriteCount}/${minWorkflowPatchWriteCount}`);
47
+ }
48
+ if (workflowModePatchWriteCount < minWorkflowModePatchWriteCount) {
49
+ blockingReasons.push(`workflow_mode_patch_write_count_below_minimum:${workflowModePatchWriteCount}/${minWorkflowModePatchWriteCount}`);
50
+ }
51
+ for (const requirement of requiredPatchDerivationCounts) {
52
+ const observedCount = findReportCount(derivationCounts, requirement.key);
53
+ if (observedCount < requirement.count) {
54
+ blockingReasons.push(`patch_derivation_count_below_minimum:${requirement.key}:${observedCount}/${requirement.count}`);
55
+ }
56
+ }
57
+ const status = mismatchPatchCount > 0 || unknownPatchCount > 0 || guardedLegacyFallbackCount > 0
58
+ ? "blocked"
59
+ : blockingReasons.length > 0
60
+ ? "insufficient_evidence"
61
+ : "ready";
62
+ return {
63
+ status,
64
+ ready: status === "ready",
65
+ workflowIds,
66
+ workflowVersions,
67
+ scopedRowCount: scopedRows.length,
68
+ minEquivalentPatchCount,
69
+ equivalentPatchCount,
70
+ mismatchPatchCount,
71
+ unknownPatchCount,
72
+ totalPatchCount,
73
+ guardedWorkflowWriteCount,
74
+ workflowModePatchWriteCount,
75
+ minWorkflowModePatchWriteCount,
76
+ workflowPatchWriteCount,
77
+ minWorkflowPatchWriteCount,
78
+ guardedLegacyFallbackCount,
79
+ patchDerivationCounts: derivationCounts,
80
+ requiredPatchDerivationCounts,
81
+ mismatchedProfileFieldCounts,
82
+ writeSourceCounts,
83
+ writeReasonCounts,
84
+ blockingReasons,
85
+ };
86
+ }
87
+ export function buildAssistantWorkflowIntentMemoryPolicyReadiness(report, options = {}) {
88
+ const workflowIds = normalizeStringScope(options.workflowIds);
89
+ const workflowVersions = normalizeNumberScope(options.workflowVersions);
90
+ const scopedRows = selectWorkflowScopedTraceRows(report.rows, workflowIds, workflowVersions);
91
+ const scopedIntentPolicies = scopedRows.flatMap((row) => row.summary.memoryPatches.flatMap((patch) => patch.intentWritePolicy ? [patch.intentWritePolicy] : []));
92
+ const minObservedPolicyCount = normalizePositiveInt(options.minObservedPolicyCount, 3);
93
+ const minEquivalentPolicyCount = options.minEquivalentPolicyCount === null || options.minEquivalentPolicyCount === undefined
94
+ ? minObservedPolicyCount
95
+ : normalizeNonNegativeInt(options.minEquivalentPolicyCount, minObservedPolicyCount);
96
+ const maxMismatchPolicyCount = normalizeNonNegativeInt(options.maxMismatchPolicyCount, 0);
97
+ const maxUnknownPolicyCount = normalizeNonNegativeInt(options.maxUnknownPolicyCount, 0);
98
+ const maxWriteNotAllowedCount = normalizeNonNegativeInt(options.maxWriteNotAllowedCount, 0);
99
+ const intentCounts = buildStringCounts(scopedIntentPolicies.flatMap((policy) => policy.intentId ? [policy.intentId] : []));
100
+ const equivalenceCounts = buildStringCounts(scopedIntentPolicies.map(buildMemoryPatchEquivalenceKey));
101
+ const skippedPatchReasonCounts = buildStringCounts(scopedIntentPolicies.flatMap((policy) => policy.skippedPatches.map(buildMemorySkippedPatchReasonKey)));
102
+ const mismatchedProfileFieldCounts = buildStringCounts(scopedIntentPolicies.flatMap((policy) => policy.profilePatchMismatchedFields));
103
+ const equivalentPolicyCount = findReportCount(equivalenceCounts, "equivalent");
104
+ const mismatchPolicyCount = findReportCount(equivalenceCounts, "mismatch");
105
+ const unknownPolicyCount = findReportCount(equivalenceCounts, "unknown");
106
+ const observedPolicyCount = equivalenceCounts
107
+ .reduce((sum, item) => sum + item.count, 0);
108
+ const writeNotAllowedCount = skippedPatchReasonCounts
109
+ .filter((item) => item.key.endsWith(":write-not-allowed"))
110
+ .reduce((sum, item) => sum + item.count, 0);
111
+ const blockingReasons = [];
112
+ if (mismatchPolicyCount > maxMismatchPolicyCount) {
113
+ blockingReasons.push(`intent_write_policy_mismatch:${mismatchPolicyCount}/${maxMismatchPolicyCount}`);
114
+ }
115
+ if (unknownPolicyCount > maxUnknownPolicyCount) {
116
+ blockingReasons.push(`intent_write_policy_equivalence_unknown:${unknownPolicyCount}/${maxUnknownPolicyCount}`);
117
+ }
118
+ if (writeNotAllowedCount > maxWriteNotAllowedCount) {
119
+ blockingReasons.push(`intent_write_policy_write_not_allowed:${writeNotAllowedCount}/${maxWriteNotAllowedCount}`);
120
+ }
121
+ if (observedPolicyCount < minObservedPolicyCount) {
122
+ blockingReasons.push(`intent_write_policy_observed_count_below_minimum:${observedPolicyCount}/${minObservedPolicyCount}`);
123
+ }
124
+ if (equivalentPolicyCount < minEquivalentPolicyCount) {
125
+ blockingReasons.push(`intent_write_policy_equivalent_count_below_minimum:${equivalentPolicyCount}/${minEquivalentPolicyCount}`);
126
+ }
127
+ const hardBlock = mismatchPolicyCount > maxMismatchPolicyCount ||
128
+ unknownPolicyCount > maxUnknownPolicyCount ||
129
+ writeNotAllowedCount > maxWriteNotAllowedCount;
130
+ const status = hardBlock
131
+ ? "blocked"
132
+ : blockingReasons.length > 0
133
+ ? "insufficient_evidence"
134
+ : "ready";
135
+ return {
136
+ status,
137
+ ready: status === "ready",
138
+ workflowIds,
139
+ workflowVersions,
140
+ scopedRowCount: scopedRows.length,
141
+ minObservedPolicyCount,
142
+ minEquivalentPolicyCount,
143
+ maxMismatchPolicyCount,
144
+ maxUnknownPolicyCount,
145
+ maxWriteNotAllowedCount,
146
+ observedPolicyCount,
147
+ equivalentPolicyCount,
148
+ mismatchPolicyCount,
149
+ unknownPolicyCount,
150
+ writeNotAllowedCount,
151
+ intentCounts,
152
+ mismatchedProfileFieldCounts,
153
+ skippedPatchReasonCounts,
154
+ blockingReasons,
155
+ };
156
+ }
157
+ export function buildAssistantWorkflowToolSelectionMetricReadiness(report, options = {}) {
158
+ const workflowIds = normalizeStringScope(options.workflowIds);
159
+ const workflowVersions = normalizeNumberScope(options.workflowVersions);
160
+ const workflowProfileKeys = normalizeStringScope(options.workflowProfileKeys);
161
+ const authoritySources = normalizeStringScope(options.authoritySources);
162
+ const intentIds = normalizeStringScope(options.intentIds);
163
+ const segmentKeys = normalizeStringScope(options.segmentKeys);
164
+ const requiredSchemaCostSource = normalizeOptionalString(options.schemaCostSource);
165
+ const minSelectionCount = normalizePositiveInt(options.minSelectionCount, 3);
166
+ const maxQualityFlaggedSelectionCount = normalizeNonNegativeInt(options.maxQualityFlaggedSelectionCount, 0);
167
+ const maxErrorSelectionCount = normalizeNonNegativeInt(options.maxErrorSelectionCount, 0);
168
+ const maxBadFeedbackSelectionCount = normalizeNonNegativeInt(options.maxBadFeedbackSelectionCount, 0);
169
+ const maxUnavailableOutcomeSelectionCount = normalizeNonNegativeInt(options.maxUnavailableOutcomeSelectionCount, 0);
170
+ const scopedSegments = report.effectiveToolSelectionSegments.filter((segment) => isToolSelectionMetricSegmentInScope(segment, workflowIds, workflowVersions, workflowProfileKeys, authoritySources, intentIds, segmentKeys));
171
+ const ignoredSchemaCostSourceSegments = requiredSchemaCostSource
172
+ ? scopedSegments.filter((segment) => segment.schemaCostSource !== requiredSchemaCostSource)
173
+ : [];
174
+ const evaluatedSegments = requiredSchemaCostSource
175
+ ? scopedSegments.filter((segment) => segment.schemaCostSource === requiredSchemaCostSource)
176
+ : scopedSegments;
177
+ const evidenceCounters = buildToolSelectionMetricEvidenceCounters(report.rows);
178
+ const segments = evaluatedSegments.map((segment) => {
179
+ const counters = evidenceCounters.get(segment.segmentKey) ?? EMPTY_TOOL_SELECTION_METRIC_EVIDENCE_COUNTERS;
180
+ const blockingReasons = [];
181
+ if (counters.qualityFlaggedSelectionCount > maxQualityFlaggedSelectionCount) {
182
+ blockingReasons.push(`quality_flagged_selection_count_exceeds_maximum:${counters.qualityFlaggedSelectionCount}/${maxQualityFlaggedSelectionCount}`);
183
+ }
184
+ if (counters.errorSelectionCount > maxErrorSelectionCount) {
185
+ blockingReasons.push(`error_selection_count_exceeds_maximum:${counters.errorSelectionCount}/${maxErrorSelectionCount}`);
186
+ }
187
+ if (counters.badFeedbackSelectionCount > maxBadFeedbackSelectionCount) {
188
+ blockingReasons.push(`bad_feedback_selection_count_exceeds_maximum:${counters.badFeedbackSelectionCount}/${maxBadFeedbackSelectionCount}`);
189
+ }
190
+ if (counters.unavailableOutcomeSelectionCount > maxUnavailableOutcomeSelectionCount) {
191
+ blockingReasons.push(`unavailable_outcome_selection_count_exceeds_maximum:${counters.unavailableOutcomeSelectionCount}/${maxUnavailableOutcomeSelectionCount}`);
192
+ }
193
+ if (segment.selectionCount < minSelectionCount) {
194
+ blockingReasons.push(`selection_count_below_minimum:${segment.selectionCount}/${minSelectionCount}`);
195
+ }
196
+ const hardBlock = counters.qualityFlaggedSelectionCount > maxQualityFlaggedSelectionCount ||
197
+ counters.errorSelectionCount > maxErrorSelectionCount ||
198
+ counters.badFeedbackSelectionCount > maxBadFeedbackSelectionCount ||
199
+ counters.unavailableOutcomeSelectionCount > maxUnavailableOutcomeSelectionCount;
200
+ const status = hardBlock
201
+ ? "blocked"
202
+ : segment.selectionCount < minSelectionCount
203
+ ? "insufficient_evidence"
204
+ : "ready_for_review";
205
+ return {
206
+ ...segment,
207
+ ...counters,
208
+ status,
209
+ readyForReview: status === "ready_for_review",
210
+ blockingReasons,
211
+ };
212
+ });
213
+ const readySegmentCount = segments.filter((segment) => segment.status === "ready_for_review").length;
214
+ const blockedSegmentCount = segments.filter((segment) => segment.status === "blocked").length;
215
+ const insufficientEvidenceSegmentCount = segments.filter((segment) => segment.status === "insufficient_evidence").length;
216
+ const blockingReasons = [];
217
+ if (!segments.length) {
218
+ blockingReasons.push("no_tool_selection_segments_in_scope");
219
+ }
220
+ if (blockedSegmentCount > 0) {
221
+ blockingReasons.push(`blocked_segments:${blockedSegmentCount}`);
222
+ }
223
+ if (insufficientEvidenceSegmentCount > 0) {
224
+ blockingReasons.push(`insufficient_evidence_segments:${insufficientEvidenceSegmentCount}`);
225
+ }
226
+ const status = blockedSegmentCount > 0
227
+ ? "blocked"
228
+ : !segments.length || insufficientEvidenceSegmentCount > 0
229
+ ? "insufficient_evidence"
230
+ : "ready_for_review";
231
+ return {
232
+ status,
233
+ readyForReview: status === "ready_for_review",
234
+ workflowIds,
235
+ workflowVersions,
236
+ workflowProfileKeys,
237
+ authoritySources,
238
+ intentIds,
239
+ segmentKeys,
240
+ requiredSchemaCostSource,
241
+ minSelectionCount,
242
+ maxQualityFlaggedSelectionCount,
243
+ maxErrorSelectionCount,
244
+ maxBadFeedbackSelectionCount,
245
+ maxUnavailableOutcomeSelectionCount,
246
+ evaluatedSelectionCount: segments.reduce((sum, segment) => sum + segment.selectionCount, 0),
247
+ readySegmentCount,
248
+ blockedSegmentCount,
249
+ insufficientEvidenceSegmentCount,
250
+ ignoredSchemaCostSourceSegmentCount: ignoredSchemaCostSourceSegments.length,
251
+ ignoredSchemaCostSourceSelectionCount: ignoredSchemaCostSourceSegments
252
+ .reduce((sum, segment) => sum + segment.selectionCount, 0),
253
+ ignoredSchemaCostSourceCounts: buildStringCounts(ignoredSchemaCostSourceSegments.map((segment) => segment.schemaCostSource ?? "unknown")),
254
+ segments,
255
+ blockingReasons,
256
+ };
257
+ }
258
+ export function buildAssistantWorkflowTraceReport(sourceRows, options = {}) {
259
+ const directRouteDefinitionLookup = buildDirectRouteDefinitionLookup(options.workflow ?? null);
260
+ const workflowIds = normalizeStringScope(options.workflowIds);
261
+ const workflowVersions = normalizeNumberScope(options.workflowVersions);
262
+ const allRows = sourceRows.map((row) => {
263
+ const summary = buildAssistantWorkflowTraceSummary(row.traceEvents);
264
+ const tuningSignals = collectAssistantWorkflowTraceTuningSignals(summary);
265
+ return {
266
+ debugId: normalizeNullableString(row.debugId),
267
+ requestId: row.requestId,
268
+ threadId: normalizeNullableString(row.threadId),
269
+ userId: normalizeNullableString(row.userId),
270
+ provider: normalizeNullableString(row.provider),
271
+ model: normalizeNullableString(row.model),
272
+ feedback: normalizeNullableString(row.feedback),
273
+ feedbackAt: normalizeNullableString(row.feedbackAt),
274
+ createdAt: normalizeNullableString(row.createdAt),
275
+ summary,
276
+ evalCandidate: buildAssistantWorkflowTraceEvalCandidate(summary),
277
+ tuningSignals,
278
+ directRouteStrategies: buildDirectRouteStrategySummaries(summary, directRouteDefinitionLookup),
279
+ };
280
+ });
281
+ const workflowScopedRows = selectWorkflowScopedTraceRows(allRows, workflowIds, workflowVersions);
282
+ const rows = options.onlyInteresting === true
283
+ ? workflowScopedRows.filter((row) => isInterestingReportRow(row))
284
+ : workflowScopedRows;
285
+ return {
286
+ generatedAt: new Date().toISOString(),
287
+ workflowIds,
288
+ workflowVersions,
289
+ rowCount: rows.length,
290
+ scopedSourceRowCount: workflowScopedRows.length,
291
+ sourceRowCount: sourceRows.length,
292
+ evalCandidateCount: rows.filter((row) => row.evalCandidate !== null).length,
293
+ interestingRowCount: rows.filter(isInterestingReportRow).length,
294
+ qualityFlaggedRowCount: rows.filter((row) => row.summary.quality.flagged).length,
295
+ errorRowCount: rows.filter((row) => row.summary.errorStages.length > 0).length,
296
+ feedbackCounts: buildStringCounts(rows.map((row) => row.feedback ?? "none")),
297
+ intentCounts: buildStringCounts(rows.map((row) => row.summary.classifier?.intent ?? row.summary.workflow?.intent ?? "unknown")),
298
+ authorityCounts: buildStringCounts(rows.map((row) => row.summary.workflow?.authority?.source ?? "none")),
299
+ authorityReasonCounts: buildStringCounts(rows.map((row) => row.summary.workflow?.authority?.reason ?? "none")),
300
+ workflowSelectionOptionalToolModeCounts: buildStringCounts(rows.map((row) => row.summary.workflow?.workflowSelectionOptionalToolMode ?? "none")),
301
+ workflowSelectionExcludedOptionalToolCounts: buildStringCounts(rows.flatMap((row) => row.summary.workflow?.workflowSelectionExcludedOptionalTools ?? [])),
302
+ workflowSelectionActiveProfileCounts: buildStringCounts(rows.flatMap((row) => row.summary.workflow?.workflowSelectionActiveProfileIds ?? [])),
303
+ workflowSelectionProfileToolCounts: buildStringCounts(rows.flatMap((row) => row.summary.workflow?.workflowSelectionProfileTools ?? [])),
304
+ activePlanningStepProfileCounts: buildStringCounts(rows.flatMap((row) => row.summary.workflow?.plan?.activePlanningStepProfileIds ?? [])),
305
+ profileStepCounts: buildStringCounts(rows.flatMap((row) => row.summary.workflow?.plan?.profileStepIds ?? [])),
306
+ outcomeKindCounts: buildStringCounts(rows.flatMap((row) => row.summary.outcomes.map((outcome) => outcome.kind))),
307
+ handledOutcomeKindCounts: buildStringCounts(rows.flatMap((row) => row.summary.outcomes.filter((outcome) => outcome.handled).map((outcome) => outcome.kind))),
308
+ clarificationComparisonMatchedCounts: buildStringCounts(rows.flatMap((row) => row.summary.clarificationComparisons
309
+ .filter((comparison) => comparison.matched === true)
310
+ .map(buildClarificationComparisonMatchedKey))),
311
+ clarificationComparisonMissingRuleCounts: buildStringCounts(rows.flatMap((row) => row.summary.clarificationComparisons.flatMap((comparison) => comparison.missingExpectedRuleIds))),
312
+ clarificationComparisonUnexpectedRuleCounts: buildStringCounts(rows.flatMap((row) => row.summary.clarificationComparisons
313
+ .map((comparison) => comparison.unexpectedObservedRuleId)
314
+ .filter((ruleId) => ruleId !== null))),
315
+ directRoutePolicyEnabledCounts: buildStringCounts(rows.flatMap((row) => row.summary.directRoutePolicies
316
+ .filter((policy) => policy.enabled === true)
317
+ .map((policy) => policy.route ?? "unknown"))),
318
+ directRoutePolicyDisabledReasonCounts: buildStringCounts(rows.flatMap((row) => row.summary.directRoutePolicies
319
+ .filter((policy) => policy.enabled === false)
320
+ .map(buildDirectRoutePolicyDisabledReasonKey))),
321
+ directRouteGapReasonCounts: buildStringCounts(rows.flatMap((row) => row.summary.directRouteGaps.map(buildDirectRouteGapReasonKey))),
322
+ directRouteObservedStrategyCounts: buildStringCounts(rows.flatMap((row) => row.directRouteStrategies.map(buildDirectRouteStrategyKey))),
323
+ directRouteUndeclaredStrategyCounts: buildStringCounts(rows.flatMap((row) => row.directRouteStrategies
324
+ .filter((strategy) => strategy.declared === false)
325
+ .map(buildDirectRouteStrategyKey))),
326
+ directRouteDoneCounts: buildStringCounts(rows.flatMap((row) => row.summary.directRoutes
327
+ .filter((route) => route.outcome === "done")
328
+ .map((route) => route.route))),
329
+ directRouteRecoveredCounts: buildStringCounts(rows.flatMap((row) => row.summary.directRoutes
330
+ .filter((route) => route.outcome === "recovered")
331
+ .map((route) => route.route))),
332
+ directRouteErrorCounts: buildStringCounts(rows.flatMap((row) => row.summary.directRoutes
333
+ .filter((route) => route.outcome === "error")
334
+ .map((route) => route.route))),
335
+ directRouteSkipReasonCounts: buildStringCounts(rows.flatMap((row) => row.summary.directRoutes
336
+ .filter((route) => route.outcome === "skip")
337
+ .map(buildDirectRouteSkipReasonKey)
338
+ .filter((key) => key !== null))),
339
+ memoryChangedSlotCounts: buildStringCounts(rows.flatMap((row) => row.summary.memoryPatches.flatMap((patch) => patch.changedSlots))),
340
+ memoryChangedProfileFieldCounts: buildStringCounts(rows.flatMap((row) => row.summary.memoryPatches.flatMap((patch) => patch.changedProfileFields))),
341
+ memorySkippedPatchReasonCounts: buildStringCounts(rows.flatMap((row) => row.summary.memoryPatches.flatMap((patch) => patch.skippedPatches.map(buildMemorySkippedPatchReasonKey)))),
342
+ memoryPatchEquivalenceCounts: buildStringCounts(rows.flatMap((row) => row.summary.memoryPatches.map(buildMemoryPatchEquivalenceKey))),
343
+ memoryPatchDerivationCounts: buildStringCounts(rows.flatMap((row) => row.summary.memoryPatches.map(buildMemoryPatchDerivationKey))),
344
+ memoryPatchMismatchedProfileFieldCounts: buildStringCounts(rows.flatMap((row) => row.summary.memoryPatches.flatMap((patch) => patch.profilePatchMismatchedFields))),
345
+ memoryPatchWriteSourceCounts: buildStringCounts(rows.flatMap((row) => row.summary.memoryPatches.map(buildMemoryPatchWriteSourceKey))),
346
+ memoryPatchWriteReasonCounts: buildStringCounts(rows.flatMap((row) => row.summary.memoryPatches.map(buildMemoryPatchWriteReasonKey))),
347
+ memoryIntentWritePolicyIntentCounts: buildStringCounts(rows.flatMap((row) => row.summary.memoryPatches.flatMap((patch) => patch.intentWritePolicy?.intentId ? [patch.intentWritePolicy.intentId] : []))),
348
+ memoryIntentWritePolicyEquivalenceCounts: buildStringCounts(rows.flatMap((row) => row.summary.memoryPatches.flatMap((patch) => patch.intentWritePolicy ? [buildMemoryPatchEquivalenceKey(patch.intentWritePolicy)] : []))),
349
+ memoryIntentWritePolicySkippedPatchReasonCounts: buildStringCounts(rows.flatMap((row) => row.summary.memoryPatches.flatMap((patch) => patch.intentWritePolicy?.skippedPatches.map(buildMemorySkippedPatchReasonKey) ?? []))),
350
+ memoryIntentWritePolicyMismatchedProfileFieldCounts: buildStringCounts(rows.flatMap((row) => row.summary.memoryPatches.flatMap((patch) => patch.intentWritePolicy?.profilePatchMismatchedFields ?? []))),
351
+ threadProfileWriteChangedFieldCounts: buildStringCounts(rows.flatMap((row) => row.summary.threadProfileWrites.flatMap((write) => write.changedFields))),
352
+ threadProfileWriteSourceCounts: buildStringCounts(rows.flatMap((row) => row.summary.threadProfileWrites.map(buildThreadProfileWriteSourceKey))),
353
+ threadProfileWriteReasonCounts: buildStringCounts(rows.flatMap((row) => row.summary.threadProfileWrites.map(buildThreadProfileWriteReasonKey))),
354
+ toolRuntimeBindingStatusCounts: buildStringCounts(rows.flatMap((row) => row.summary.toolRuntimeBindings.map((binding) => binding.status ?? "unknown"))),
355
+ toolRuntimeBindingAdapterCounts: buildStringCounts(rows.flatMap((row) => row.summary.toolRuntimeBindings.map((binding) => binding.runtimeAdapterId ?? "unknown"))),
356
+ toolRuntimeBindingPolicyMismatchCounts: buildStringCounts(rows.flatMap((row) => row.summary.toolRuntimeBindings.flatMap((binding) => binding.policyMismatchFields.map((field) => `${binding.toolName ?? "unknown"}:${field}`)))),
357
+ effectiveToolSelectionModeCounts: buildStringCounts(rows.flatMap((row) => row.summary.toolSelections.map((selection) => selection.mode ?? "unknown"))),
358
+ effectiveToolSelectionReasonCounts: buildStringCounts(rows.flatMap((row) => row.summary.toolSelections.map((selection) => selection.reason ?? "unknown"))),
359
+ effectiveToolSelectionToolCounts: buildStringCounts(rows.flatMap((row) => row.summary.toolSelections.flatMap((selection) => selection.toolNames))),
360
+ effectiveToolSelectionSegments: buildEffectiveToolSelectionSegments(rows),
361
+ toolCallCounts: buildStringCounts(rows.flatMap((row) => row.summary.toolCallNames)),
362
+ tuningSignalCounts: buildTuningSignalCounts(rows.flatMap((row) => row.tuningSignals)),
363
+ suggestions: buildReportSuggestions(rows),
364
+ rows,
365
+ };
366
+ }
367
+ export function buildAssistantWorkflowSerializedRunReportFromTraceReportRow(row, options = {}) {
368
+ const signals = buildTraceDerivedRunEvaluationSignals(row);
369
+ const warningCount = signals.filter((signal) => signal.severity === "warning").length;
370
+ const status = buildTraceDerivedRunReportStatus(row, warningCount);
371
+ const intent = row.summary.classifier?.intent ?? row.summary.workflow?.intent ?? null;
372
+ const handledOutcome = row.summary.handledOutcome;
373
+ const outcomeKind = handledOutcome?.kind ?? "trace_summary";
374
+ const outcomeHandled = handledOutcome?.handled ?? status !== "not_handled";
375
+ const outcomeReason = handledOutcome?.reason ?? buildTraceDerivedOutcomeReason(row, status);
376
+ const directRouteDoneRoutes = row.summary.directRoutes
377
+ .filter((route) => route.outcome === "done")
378
+ .map((route) => route.route);
379
+ const directRouteRecoveredRoutes = row.summary.directRoutes
380
+ .filter((route) => route.outcome === "recovered")
381
+ .map((route) => route.route);
382
+ const directRouteErrorRoutes = row.summary.directRoutes
383
+ .filter((route) => route.outcome === "error")
384
+ .map((route) => route.route);
385
+ const directRouteSkipReasons = row.summary.directRoutes
386
+ .filter((route) => route.outcome === "skip")
387
+ .map(buildDirectRouteSkipReasonKey)
388
+ .filter((key) => key !== null);
389
+ const directRoutePolicyEnabledRoutes = row.summary.directRoutePolicies
390
+ .filter((policy) => policy.enabled === true)
391
+ .map((policy) => policy.route ?? "unknown");
392
+ const directRoutePolicyDisabledReasons = row.summary.directRoutePolicies
393
+ .filter((policy) => policy.enabled === false)
394
+ .map(buildDirectRoutePolicyDisabledReasonKey);
395
+ const directRouteGapReasons = row.summary.directRouteGaps.map(buildDirectRouteGapReasonKey);
396
+ const directRouteObservedStrategies = row.directRouteStrategies.map(buildDirectRouteStrategyKey);
397
+ const directRouteUndeclaredStrategies = row.directRouteStrategies
398
+ .filter((strategy) => strategy.declared === false)
399
+ .map(buildDirectRouteStrategyKey);
400
+ const memoryChangedSlots = uniqueStrings(row.summary.memoryPatches.flatMap((patch) => patch.changedSlots));
401
+ const memoryChangedProfileFields = uniqueStrings(row.summary.memoryPatches.flatMap((patch) => patch.changedProfileFields));
402
+ const memorySkippedPatchReasons = row.summary.memoryPatches.flatMap((patch) => patch.skippedPatches.map(buildMemorySkippedPatchReasonKey));
403
+ const memoryPatchEquivalence = uniqueStrings(row.summary.memoryPatches.map(buildMemoryPatchEquivalenceKey));
404
+ const memoryPatchDerivations = uniqueStrings(row.summary.memoryPatches.map(buildMemoryPatchDerivationKey));
405
+ const memoryPatchMismatchedProfileFields = uniqueStrings(row.summary.memoryPatches.flatMap((patch) => patch.profilePatchMismatchedFields));
406
+ const memoryPatchWriteSources = uniqueStrings(row.summary.memoryPatches.map(buildMemoryPatchWriteSourceKey));
407
+ const memoryPatchWriteReasons = uniqueStrings(row.summary.memoryPatches.map(buildMemoryPatchWriteReasonKey));
408
+ const threadProfileWriteSources = uniqueStrings(row.summary.threadProfileWrites.map(buildThreadProfileWriteSourceKey));
409
+ const threadProfileWriteReasons = uniqueStrings(row.summary.threadProfileWrites.map(buildThreadProfileWriteReasonKey));
410
+ const threadProfileWriteChangedFields = uniqueStrings(row.summary.threadProfileWrites.flatMap((write) => write.changedFields));
411
+ const clarificationMatchedRules = row.summary.clarificationComparisons
412
+ .filter((comparison) => comparison.matched === true)
413
+ .map(buildClarificationComparisonMatchedKey);
414
+ const clarificationMissingRules = row.summary.clarificationComparisons.flatMap((comparison) => comparison.missingExpectedRuleIds);
415
+ const clarificationUnexpectedRules = row.summary.clarificationComparisons
416
+ .map((comparison) => comparison.unexpectedObservedRuleId)
417
+ .filter((ruleId) => ruleId !== null);
418
+ const toolResultStatus = row.summary.errorStages.length > 0
419
+ ? "failed"
420
+ : row.summary.toolCalls.length > 0
421
+ ? "complete"
422
+ : null;
423
+ return {
424
+ schemaVersion: ASSISTANT_WORKFLOW_RUN_REPORT_JSON_SCHEMA_VERSION,
425
+ workflowId: normalizeRunReportWorkflowId(options.workflowId),
426
+ workflowVersion: normalizeRunReportWorkflowVersion(options.workflowVersion),
427
+ status,
428
+ run: {
429
+ source: "trace_report",
430
+ requestId: row.requestId,
431
+ debugId: row.debugId,
432
+ threadId: row.threadId,
433
+ createdAt: row.createdAt,
434
+ status: status === "not_handled" ? "blocked" : status === "failed" ? "partial" : "ready",
435
+ decision: {
436
+ intent,
437
+ presentation: row.summary.classifier?.presentation ?? row.summary.workflow?.effectivePresentation ?? null,
438
+ confidence: row.summary.classifier?.confidence ?? null,
439
+ toolsToExpose: row.summary.classifier?.toolsToExpose ?? [],
440
+ plan: row.summary.workflow?.plan ?? null,
441
+ authority: row.summary.workflow?.authority ?? null,
442
+ },
443
+ toolInvocationQueue: {
444
+ invocationCount: row.summary.toolCalls.length,
445
+ toolNames: row.summary.toolCallNames,
446
+ },
447
+ directRoutes: row.summary.directRoutes.map((route) => ({
448
+ route: route.route,
449
+ outcome: route.outcome,
450
+ reason: route.reason ?? null,
451
+ strategy: route.strategy ?? null,
452
+ topic: route.topic ?? null,
453
+ tool: route.tool ?? null,
454
+ mode: route.mode ?? null,
455
+ handled: route.handled ?? null,
456
+ contentChars: route.contentChars ?? null,
457
+ tookMs: route.tookMs ?? null,
458
+ })),
459
+ directRoutePolicies: row.summary.directRoutePolicies.map((policy) => ({
460
+ intent: policy.intent ?? null,
461
+ route: policy.route ?? null,
462
+ enabled: policy.enabled ?? null,
463
+ reason: policy.reason ?? null,
464
+ policyRouteIds: policy.policyRouteIds,
465
+ })),
466
+ directRouteGaps: row.summary.directRouteGaps.map((gap) => ({
467
+ handlerId: gap.handlerId ?? null,
468
+ layer: gap.layer ?? null,
469
+ route: gap.route ?? null,
470
+ reason: gap.reason ?? null,
471
+ })),
472
+ directRouteStrategies: row.directRouteStrategies.map((strategy) => ({
473
+ route: strategy.route,
474
+ strategy: strategy.strategy,
475
+ definitionRouteId: strategy.definitionRouteId,
476
+ declared: strategy.declared,
477
+ status: strategy.status,
478
+ })),
479
+ memoryPatches: row.summary.memoryPatches.map((patch) => ({
480
+ changedSlots: patch.changedSlots,
481
+ changedProfileFields: patch.changedProfileFields,
482
+ appliedPatchCount: patch.appliedPatchCount,
483
+ skippedPatchCount: patch.skippedPatchCount,
484
+ appliedPatches: patch.appliedPatches.map((appliedPatch) => ({ ...appliedPatch })),
485
+ skippedPatches: patch.skippedPatches.map((skippedPatch) => ({ ...skippedPatch })),
486
+ profilePatchEquivalent: patch.profilePatchEquivalent,
487
+ profilePatchComparedFields: patch.profilePatchComparedFields,
488
+ profilePatchMismatchedFields: patch.profilePatchMismatchedFields,
489
+ patchDerivation: patch.patchDerivation,
490
+ profileWriteMode: patch.profileWriteMode,
491
+ profileWriteSource: patch.profileWriteSource,
492
+ profileWriteReason: patch.profileWriteReason,
493
+ intentWritePolicy: patch.intentWritePolicy ? {
494
+ intentId: patch.intentWritePolicy.intentId,
495
+ writeSlots: patch.intentWritePolicy.writeSlots,
496
+ missingMemorySlots: patch.intentWritePolicy.missingMemorySlots,
497
+ changedSlots: patch.intentWritePolicy.changedSlots,
498
+ appliedPatchCount: patch.intentWritePolicy.appliedPatchCount,
499
+ skippedPatchCount: patch.intentWritePolicy.skippedPatchCount,
500
+ skippedPatches: patch.intentWritePolicy.skippedPatches.map((skippedPatch) => ({ ...skippedPatch })),
501
+ profilePatchEquivalent: patch.intentWritePolicy.profilePatchEquivalent,
502
+ profilePatchComparedFields: patch.intentWritePolicy.profilePatchComparedFields,
503
+ profilePatchMismatchedFields: patch.intentWritePolicy.profilePatchMismatchedFields,
504
+ } : null,
505
+ })),
506
+ threadProfileWrites: row.summary.threadProfileWrites.map((write) => ({
507
+ changed: write.changed,
508
+ changedFields: write.changedFields,
509
+ writeMode: write.writeMode,
510
+ writeSource: write.writeSource,
511
+ writeReason: write.writeReason,
512
+ })),
513
+ outcomes: row.summary.outcomes.map((outcome) => ({
514
+ kind: outcome.kind,
515
+ handled: outcome.handled,
516
+ contentChars: outcome.contentChars ?? null,
517
+ reason: outcome.reason ?? null,
518
+ delivery: outcome.delivery ?? null,
519
+ artifactKind: outcome.artifactKind ?? null,
520
+ route: outcome.route ?? null,
521
+ source: outcome.source ?? null,
522
+ layer: outcome.layer ?? null,
523
+ skipEvent: outcome.skipEvent ?? null,
524
+ mode: outcome.mode ?? null,
525
+ submode: outcome.submode ?? null,
526
+ tool: outcome.tool ?? null,
527
+ ruleId: outcome.ruleId ?? null,
528
+ streamed: outcome.streamed ?? null,
529
+ })),
530
+ clarificationComparisons: row.summary.clarificationComparisons.map((comparison) => ({
531
+ intent: comparison.intent ?? null,
532
+ expectedRuleIds: comparison.expectedRuleIds,
533
+ expectedBlockingRuleIds: comparison.expectedBlockingRuleIds,
534
+ expectedSuggestedRuleIds: comparison.expectedSuggestedRuleIds,
535
+ produced: comparison.produced ?? null,
536
+ observedRuleId: comparison.observedRuleId ?? null,
537
+ equivalentRuleIds: comparison.equivalentRuleIds,
538
+ matched: comparison.matched ?? null,
539
+ missingExpectedRuleIds: comparison.missingExpectedRuleIds,
540
+ unexpectedObservedRuleId: comparison.unexpectedObservedRuleId ?? null,
541
+ source: comparison.source ?? null,
542
+ layer: comparison.layer ?? null,
543
+ reason: comparison.reason ?? null,
544
+ })),
545
+ },
546
+ toolExecution: toolResultStatus === null
547
+ ? null
548
+ : {
549
+ status: toolResultStatus,
550
+ totalInvocations: row.summary.toolCalls.length,
551
+ successCount: row.summary.toolCalls.filter((call) => call.success).length,
552
+ errorCount: row.summary.toolCalls.filter((call) => !call.success).length,
553
+ },
554
+ outcome: {
555
+ kind: outcomeKind,
556
+ handled: outcomeHandled,
557
+ reason: outcomeReason,
558
+ delivery: handledOutcome?.delivery ?? null,
559
+ artifactKind: handledOutcome?.artifactKind ?? null,
560
+ route: handledOutcome?.route ?? null,
561
+ contentChars: handledOutcome?.contentChars ?? null,
562
+ source: handledOutcome?.source ?? "trace_summary",
563
+ layer: handledOutcome?.layer ?? null,
564
+ mode: handledOutcome?.mode ?? null,
565
+ submode: handledOutcome?.submode ?? null,
566
+ tool: handledOutcome?.tool ?? null,
567
+ ruleId: handledOutcome?.ruleId ?? null,
568
+ streamed: handledOutcome?.streamed ?? null,
569
+ qualityFlagged: row.summary.quality.flagged,
570
+ feedback: row.feedback,
571
+ },
572
+ evaluation: {
573
+ workflowId: normalizeRunReportWorkflowId(options.workflowId),
574
+ workflowVersion: normalizeRunReportWorkflowVersion(options.workflowVersion),
575
+ status,
576
+ intent,
577
+ outcomeKind,
578
+ handled: outcomeHandled,
579
+ toolResultStatus,
580
+ readyToolCount: row.summary.workflow?.workflowSelectionCandidateTools.length ?? 0,
581
+ invokedToolCount: row.summary.toolCalls.length,
582
+ activePlanningStepProfileIds: row.summary.workflow?.plan?.activePlanningStepProfileIds ?? [],
583
+ profileStepIds: row.summary.workflow?.plan?.profileStepIds ?? [],
584
+ directRouteDoneRoutes,
585
+ directRouteRecoveredRoutes,
586
+ directRouteErrorRoutes,
587
+ directRouteSkipReasons,
588
+ directRoutePolicyEnabledRoutes,
589
+ directRoutePolicyDisabledReasons,
590
+ directRouteGapReasons,
591
+ directRouteObservedStrategies,
592
+ directRouteUndeclaredStrategies,
593
+ memoryChangedSlots,
594
+ memoryChangedProfileFields,
595
+ memorySkippedPatchReasons,
596
+ memoryPatchEquivalence,
597
+ memoryPatchDerivations,
598
+ memoryPatchMismatchedProfileFields,
599
+ memoryPatchWriteSources,
600
+ memoryPatchWriteReasons,
601
+ threadProfileWriteSources,
602
+ threadProfileWriteReasons,
603
+ threadProfileWriteChangedFields,
604
+ clarificationMatchedRules,
605
+ clarificationMissingRules,
606
+ clarificationUnexpectedRules,
607
+ signalCount: signals.length,
608
+ warningCount,
609
+ signals,
610
+ },
611
+ };
612
+ }
613
+ export function buildAssistantWorkflowSerializedRunReportsFromTraceReport(report, options = {}) {
614
+ return report.rows.map((row) => buildAssistantWorkflowSerializedRunReportFromTraceReportRow(row, options));
615
+ }
616
+ function isInterestingReportRow(row) {
617
+ return row.feedback === "bad" ||
618
+ row.summary.quality.flagged ||
619
+ row.summary.errorStages.length > 0 ||
620
+ row.tuningSignals.some((signal) => signal.severity === "warning");
621
+ }
622
+ function buildStringCounts(values) {
623
+ const counts = new Map();
624
+ for (const value of values) {
625
+ if (!value.length)
626
+ continue;
627
+ counts.set(value, (counts.get(value) ?? 0) + 1);
628
+ }
629
+ return [...counts.entries()]
630
+ .map(([key, count]) => ({ key, count }))
631
+ .sort((left, right) => {
632
+ if (right.count !== left.count)
633
+ return right.count - left.count;
634
+ return left.key.localeCompare(right.key);
635
+ });
636
+ }
637
+ function buildEffectiveToolSelectionSegments(rows) {
638
+ const aggregates = new Map();
639
+ for (const row of rows) {
640
+ const workflowId = row.summary.workflow?.workflowId ?? null;
641
+ const workflowVersion = row.summary.workflow?.workflowVersion ?? null;
642
+ const intentId = row.summary.classifier?.intent ?? row.summary.workflow?.intent ?? "unknown";
643
+ const workflowProfileKey = buildAssistantWorkflowToolSelectionProfileKey({
644
+ intentId: row.summary.workflow?.intent ?? intentId,
645
+ profileIds: row.summary.workflow?.workflowSelectionActiveProfileIds ?? [],
646
+ });
647
+ const authoritySource = row.summary.workflow?.authority?.source ?? null;
648
+ const authorityReason = row.summary.workflow?.authority?.reason ?? null;
649
+ for (const selection of row.summary.toolSelections) {
650
+ const toolSet = buildEffectiveToolSelectionToolSet(selection.toolNames);
651
+ const segmentKey = buildEffectiveToolSelectionSegmentKey({
652
+ workflowId,
653
+ workflowVersion,
654
+ workflowProfileKey,
655
+ intentId,
656
+ hop: selection.hop,
657
+ mode: selection.mode,
658
+ selectionReason: selection.reason,
659
+ pruningEnabled: selection.pruningEnabled,
660
+ toolSignature: toolSet.signature,
661
+ schemaCostSource: selection.schemaCostSource,
662
+ authoritySource,
663
+ authorityReason,
664
+ });
665
+ const aggregate = aggregates.get(segmentKey) ?? {
666
+ segmentKey,
667
+ workflowId,
668
+ workflowVersion,
669
+ workflowProfileKey,
670
+ intentId,
671
+ hop: selection.hop,
672
+ mode: selection.mode,
673
+ selectionReason: selection.reason,
674
+ pruningEnabled: selection.pruningEnabled,
675
+ toolSignature: toolSet.signature,
676
+ toolNames: toolSet.toolNames,
677
+ schemaCostSource: selection.schemaCostSource,
678
+ authoritySource,
679
+ authorityReason,
680
+ selectionCount: 0,
681
+ toolCountObservationCount: 0,
682
+ toolCountTotal: 0,
683
+ totalToolCountObservationCount: 0,
684
+ totalToolCountTotal: 0,
685
+ schemaCharsObservationCount: 0,
686
+ schemaCharsTotal: 0,
687
+ savedCharsObservationCount: 0,
688
+ savedCharsTotal: 0,
689
+ };
690
+ aggregate.selectionCount += 1;
691
+ addToolSelectionMetric(aggregate, "toolCount", selection.toolCount);
692
+ addToolSelectionMetric(aggregate, "totalToolCount", selection.totalToolCount);
693
+ addToolSelectionMetric(aggregate, "schemaChars", selection.approxSchemaChars);
694
+ addToolSelectionMetric(aggregate, "savedChars", selection.approxSavedChars);
695
+ aggregates.set(segmentKey, aggregate);
696
+ }
697
+ }
698
+ return [...aggregates.values()]
699
+ .map((aggregate) => ({
700
+ ...aggregate,
701
+ averageToolCount: calculateAverage(aggregate.toolCountTotal, aggregate.toolCountObservationCount),
702
+ averageTotalToolCount: calculateAverage(aggregate.totalToolCountTotal, aggregate.totalToolCountObservationCount),
703
+ averageSchemaChars: calculateAverage(aggregate.schemaCharsTotal, aggregate.schemaCharsObservationCount),
704
+ averageSavedChars: calculateAverage(aggregate.savedCharsTotal, aggregate.savedCharsObservationCount),
705
+ }))
706
+ .sort((left, right) => {
707
+ if (right.selectionCount !== left.selectionCount)
708
+ return right.selectionCount - left.selectionCount;
709
+ return left.segmentKey.localeCompare(right.segmentKey);
710
+ });
711
+ }
712
+ function buildEffectiveToolSelectionSegmentKey(input) {
713
+ return [
714
+ `workflow_id:${input.workflowId ?? "unknown"}`,
715
+ `workflow_version:${input.workflowVersion ?? "unknown"}`,
716
+ `workflow_profile:${input.workflowProfileKey ?? "none"}`,
717
+ `intent:${input.intentId}`,
718
+ `hop:${input.hop ?? "unknown"}`,
719
+ `mode:${input.mode ?? "unknown"}`,
720
+ `reason:${input.selectionReason ?? "unknown"}`,
721
+ `pruning:${input.pruningEnabled === null ? "unknown" : String(input.pruningEnabled)}`,
722
+ `tools:${input.toolSignature}`,
723
+ `schema_cost:${input.schemaCostSource ?? "unknown"}`,
724
+ `authority:${input.authoritySource ?? "unknown"}`,
725
+ `authority_reason:${input.authorityReason ?? "unknown"}`,
726
+ ].join("|");
727
+ }
728
+ function addToolSelectionMetric(aggregate, metric, value) {
729
+ if (value === null || !Number.isFinite(value))
730
+ return;
731
+ const normalized = Math.max(0, value);
732
+ switch (metric) {
733
+ case "toolCount":
734
+ aggregate.toolCountObservationCount += 1;
735
+ aggregate.toolCountTotal += normalized;
736
+ return;
737
+ case "totalToolCount":
738
+ aggregate.totalToolCountObservationCount += 1;
739
+ aggregate.totalToolCountTotal += normalized;
740
+ return;
741
+ case "schemaChars":
742
+ aggregate.schemaCharsObservationCount += 1;
743
+ aggregate.schemaCharsTotal += normalized;
744
+ return;
745
+ case "savedChars":
746
+ aggregate.savedCharsObservationCount += 1;
747
+ aggregate.savedCharsTotal += normalized;
748
+ }
749
+ }
750
+ function calculateAverage(total, count) {
751
+ return count > 0 ? total / count : null;
752
+ }
753
+ const EMPTY_TOOL_SELECTION_METRIC_EVIDENCE_COUNTERS = {
754
+ qualityFlaggedSelectionCount: 0,
755
+ errorSelectionCount: 0,
756
+ badFeedbackSelectionCount: 0,
757
+ unavailableOutcomeSelectionCount: 0,
758
+ };
759
+ function buildToolSelectionMetricEvidenceCounters(rows) {
760
+ const counters = new Map();
761
+ for (const row of rows) {
762
+ const workflowId = row.summary.workflow?.workflowId ?? null;
763
+ const workflowVersion = row.summary.workflow?.workflowVersion ?? null;
764
+ const intentId = row.summary.classifier?.intent ?? row.summary.workflow?.intent ?? "unknown";
765
+ const workflowProfileKey = buildAssistantWorkflowToolSelectionProfileKey({
766
+ intentId: row.summary.workflow?.intent ?? intentId,
767
+ profileIds: row.summary.workflow?.workflowSelectionActiveProfileIds ?? [],
768
+ });
769
+ const authoritySource = row.summary.workflow?.authority?.source ?? null;
770
+ const authorityReason = row.summary.workflow?.authority?.reason ?? null;
771
+ for (const selection of row.summary.toolSelections) {
772
+ const toolSet = buildEffectiveToolSelectionToolSet(selection.toolNames);
773
+ const segmentKey = buildEffectiveToolSelectionSegmentKey({
774
+ workflowId,
775
+ workflowVersion,
776
+ workflowProfileKey,
777
+ intentId,
778
+ hop: selection.hop,
779
+ mode: selection.mode,
780
+ selectionReason: selection.reason,
781
+ pruningEnabled: selection.pruningEnabled,
782
+ toolSignature: toolSet.signature,
783
+ schemaCostSource: selection.schemaCostSource,
784
+ authoritySource,
785
+ authorityReason,
786
+ });
787
+ const current = counters.get(segmentKey) ?? {
788
+ qualityFlaggedSelectionCount: 0,
789
+ errorSelectionCount: 0,
790
+ badFeedbackSelectionCount: 0,
791
+ unavailableOutcomeSelectionCount: 0,
792
+ };
793
+ if (row.summary.quality.flagged)
794
+ current.qualityFlaggedSelectionCount += 1;
795
+ if (row.summary.errorStages.length > 0)
796
+ current.errorSelectionCount += 1;
797
+ if (row.feedback === "bad")
798
+ current.badFeedbackSelectionCount += 1;
799
+ if (row.summary.handledOutcome?.kind === "unavailable") {
800
+ current.unavailableOutcomeSelectionCount += 1;
801
+ }
802
+ counters.set(segmentKey, current);
803
+ }
804
+ }
805
+ return counters;
806
+ }
807
+ function buildEffectiveToolSelectionToolSet(toolNames) {
808
+ const normalized = uniqueStrings(toolNames
809
+ .map((toolName) => toolName.trim())
810
+ .filter((toolName) => toolName.length > 0))
811
+ .sort((left, right) => left.localeCompare(right));
812
+ return {
813
+ signature: normalized.length ? normalized.join(",") : "none",
814
+ toolNames: normalized,
815
+ };
816
+ }
817
+ function isToolSelectionMetricSegmentInScope(segment, workflowIds, workflowVersions, workflowProfileKeys, authoritySources, intentIds, segmentKeys) {
818
+ return (!workflowIds.length || (segment.workflowId !== null && workflowIds.includes(segment.workflowId))) &&
819
+ (!workflowVersions.length || (segment.workflowVersion !== null && workflowVersions.includes(segment.workflowVersion))) &&
820
+ (!workflowProfileKeys.length || (segment.workflowProfileKey !== null && workflowProfileKeys.includes(segment.workflowProfileKey))) &&
821
+ (!authoritySources.length || (segment.authoritySource !== null && authoritySources.includes(segment.authoritySource))) &&
822
+ (!intentIds.length || intentIds.includes(segment.intentId)) &&
823
+ (!segmentKeys.length || segmentKeys.includes(segment.segmentKey));
824
+ }
825
+ function selectWorkflowScopedTraceRows(rows, workflowIds, workflowVersions) {
826
+ if (!workflowIds.length && !workflowVersions.length)
827
+ return [...rows];
828
+ return rows.filter((row) => {
829
+ const workflow = row.summary.workflow;
830
+ if (!workflow)
831
+ return false;
832
+ return (!workflowIds.length || (workflow.workflowId !== null && workflowIds.includes(workflow.workflowId))) && (!workflowVersions.length || (workflow.workflowVersion !== null && workflowVersions.includes(workflow.workflowVersion)));
833
+ });
834
+ }
835
+ function normalizeStringScope(values) {
836
+ const normalized = new Set();
837
+ for (const value of values ?? []) {
838
+ const trimmed = value.trim();
839
+ if (trimmed.length)
840
+ normalized.add(trimmed);
841
+ }
842
+ return [...normalized].sort();
843
+ }
844
+ function normalizeNumberScope(values) {
845
+ const normalized = new Set();
846
+ for (const value of values ?? []) {
847
+ if (Number.isInteger(value) && value > 0)
848
+ normalized.add(value);
849
+ }
850
+ return [...normalized].sort((left, right) => left - right);
851
+ }
852
+ function normalizeOptionalString(value) {
853
+ const trimmed = value?.trim();
854
+ return trimmed?.length ? trimmed : null;
855
+ }
856
+ function findReportCount(counts, key) {
857
+ return counts.find((item) => item.key === key)?.count ?? 0;
858
+ }
859
+ function sumWriteSourceCountsBySource(counts, source) {
860
+ const suffix = `:${source}`;
861
+ return counts.reduce((sum, item) => item.key.endsWith(suffix) ? sum + item.count : sum, 0);
862
+ }
863
+ function normalizePositiveInt(value, fallback) {
864
+ if (typeof value !== "number" || !Number.isFinite(value))
865
+ return fallback;
866
+ const normalized = Math.floor(value);
867
+ return normalized > 0 ? normalized : fallback;
868
+ }
869
+ function normalizeNonNegativeInt(value, fallback) {
870
+ if (typeof value !== "number" || !Number.isFinite(value))
871
+ return fallback;
872
+ const normalized = Math.floor(value);
873
+ return normalized >= 0 ? normalized : fallback;
874
+ }
875
+ function normalizePatchDerivationRequirements(requirements) {
876
+ if (!requirements?.length)
877
+ return [];
878
+ const out = new Map();
879
+ for (const requirement of requirements) {
880
+ const key = requirement.key.trim();
881
+ if (!key.length)
882
+ continue;
883
+ const minCount = normalizePositiveInt(requirement.minCount, 1);
884
+ out.set(key, Math.max(out.get(key) ?? 0, minCount));
885
+ }
886
+ return [...out.entries()]
887
+ .map(([key, count]) => ({ key, count }))
888
+ .sort((left, right) => left.key.localeCompare(right.key));
889
+ }
890
+ function buildTuningSignalCounts(values) {
891
+ const counts = new Map();
892
+ for (const signal of values) {
893
+ const current = counts.get(signal.name);
894
+ if (current) {
895
+ current.count += 1;
896
+ if (signal.severity === "warning")
897
+ current.severity = "warning";
898
+ continue;
899
+ }
900
+ counts.set(signal.name, {
901
+ name: signal.name,
902
+ severity: signal.severity,
903
+ count: 1,
904
+ });
905
+ }
906
+ return [...counts.values()].sort((left, right) => {
907
+ if (right.count !== left.count)
908
+ return right.count - left.count;
909
+ if (left.severity !== right.severity)
910
+ return left.severity === "warning" ? -1 : 1;
911
+ return left.name.localeCompare(right.name);
912
+ });
913
+ }
914
+ function buildDirectRouteSkipReasonKey(input) {
915
+ if (input.reason === "runtime_policy_disabled" || input.reason === "runtime_disabled")
916
+ return null;
917
+ return input.reason ? `${input.route}:${input.reason}` : `${input.route}:unknown`;
918
+ }
919
+ function buildDirectRoutePolicyDisabledReasonKey(input) {
920
+ return `${input.route ?? "unknown"}:${input.reason ?? "unknown"}`;
921
+ }
922
+ function buildDirectRouteGapReasonKey(input) {
923
+ return `${input.route ?? "unknown"}:${input.reason ?? "unknown"}`;
924
+ }
925
+ function buildMemorySkippedPatchReasonKey(input) {
926
+ return `${input.slotId ?? "unknown"}:${input.operation ?? "unknown"}:${input.reason}`;
927
+ }
928
+ function buildMemoryPatchEquivalenceKey(input) {
929
+ if (input.profilePatchEquivalent === true)
930
+ return "equivalent";
931
+ if (input.profilePatchEquivalent === false)
932
+ return "mismatch";
933
+ return "unknown";
934
+ }
935
+ function buildMemoryPatchDerivationKey(input) {
936
+ return input.patchDerivation ?? "unknown";
937
+ }
938
+ function buildMemoryPatchWriteSourceKey(input) {
939
+ const mode = input.profileWriteMode ?? "unknown";
940
+ const source = input.profileWriteSource ?? "unknown";
941
+ return `${mode}:${source}`;
942
+ }
943
+ function buildMemoryPatchWriteReasonKey(input) {
944
+ return input.profileWriteReason ?? "unknown";
945
+ }
946
+ function buildThreadProfileWriteSourceKey(input) {
947
+ const mode = input.writeMode ?? "unknown";
948
+ const source = input.writeSource ?? "unknown";
949
+ return `${mode}:${source}`;
950
+ }
951
+ function buildThreadProfileWriteReasonKey(input) {
952
+ return input.writeReason ?? "unknown";
953
+ }
954
+ function buildDirectRouteDefinitionLookup(workflow) {
955
+ if (!workflow)
956
+ return null;
957
+ const lookup = new Map();
958
+ for (const directRoute of workflow.directRoutes ?? []) {
959
+ addDirectRouteLookupEntry(lookup, directRoute.id, directRoute);
960
+ if (directRoute.outcomeRoute) {
961
+ addDirectRouteLookupEntry(lookup, directRoute.outcomeRoute, directRoute);
962
+ }
963
+ }
964
+ return lookup;
965
+ }
966
+ function addDirectRouteLookupEntry(lookup, routeId, definition) {
967
+ const normalized = routeId.trim();
968
+ if (!normalized.length || lookup.has(normalized))
969
+ return;
970
+ lookup.set(normalized, definition);
971
+ }
972
+ function buildDirectRouteStrategySummaries(summary, directRouteDefinitionLookup) {
973
+ return summary.directRoutes.flatMap((route) => {
974
+ const strategy = route.strategy?.trim();
975
+ if (!strategy)
976
+ return [];
977
+ if (directRouteDefinitionLookup === null) {
978
+ return [{
979
+ route: route.route,
980
+ strategy,
981
+ definitionRouteId: null,
982
+ declared: null,
983
+ status: "workflow_not_provided",
984
+ }];
985
+ }
986
+ const definition = directRouteDefinitionLookup.get(route.route);
987
+ if (!definition) {
988
+ return [{
989
+ route: route.route,
990
+ strategy,
991
+ definitionRouteId: null,
992
+ declared: false,
993
+ status: "route_not_declared",
994
+ }];
995
+ }
996
+ const declaredStrategyIds = new Set((definition.strategies ?? []).map((item) => item.id));
997
+ const declared = declaredStrategyIds.has(strategy);
998
+ return [{
999
+ route: route.route,
1000
+ strategy,
1001
+ definitionRouteId: definition.id,
1002
+ declared,
1003
+ status: declared ? "declared" : "strategy_not_declared",
1004
+ }];
1005
+ });
1006
+ }
1007
+ function buildDirectRouteStrategyKey(input) {
1008
+ return `${input.route}:${input.strategy}`;
1009
+ }
1010
+ function uniqueStrings(values) {
1011
+ const out = [];
1012
+ const seen = new Set();
1013
+ for (const value of values) {
1014
+ if (!value.length || seen.has(value))
1015
+ continue;
1016
+ seen.add(value);
1017
+ out.push(value);
1018
+ }
1019
+ return out;
1020
+ }
1021
+ function buildClarificationComparisonMatchedKey(input) {
1022
+ return input.observedRuleId ?? "none";
1023
+ }
1024
+ function isClarificationBlockingRuleSatisfiedByRuntime(row, ruleId) {
1025
+ return row.summary.clarificationComparisons.some((comparison) => comparison.matched === true &&
1026
+ comparison.produced === true &&
1027
+ (comparison.expectedBlockingRuleIds.includes(ruleId) ||
1028
+ comparison.expectedRuleIds.includes(ruleId)));
1029
+ }
1030
+ function buildReportSuggestions(rows) {
1031
+ const builder = new SuggestionBuilder();
1032
+ for (const row of rows) {
1033
+ const intent = row.summary.classifier?.intent ?? row.summary.workflow?.intent ?? null;
1034
+ const workflow = row.summary.workflow;
1035
+ for (const tool of workflow?.missingRequiredToolHints ?? []) {
1036
+ builder.add({
1037
+ kind: "review_missing_required_tool",
1038
+ severity: "warning",
1039
+ intent,
1040
+ tool,
1041
+ signal: null,
1042
+ requestId: row.requestId,
1043
+ });
1044
+ }
1045
+ if (workflow && hasAssistantWorkflowConstrainedToolSelectionEvidence(workflow)) {
1046
+ for (const tool of getMissingWorkflowSelectionCandidateTools(workflow)) {
1047
+ builder.add({
1048
+ kind: "review_workflow_tool_selection_gap",
1049
+ severity: "info",
1050
+ intent,
1051
+ tool,
1052
+ signal: null,
1053
+ requestId: row.requestId,
1054
+ });
1055
+ }
1056
+ for (const tool of getAssistantWorkflowUnmodeledToolCalls(workflow, row.summary.toolCallNames)) {
1057
+ builder.add({
1058
+ kind: "review_unmodeled_selected_tool",
1059
+ severity: "info",
1060
+ intent,
1061
+ tool,
1062
+ signal: null,
1063
+ requestId: row.requestId,
1064
+ });
1065
+ }
1066
+ }
1067
+ for (const tool of workflow?.extraClassifierTools ?? []) {
1068
+ builder.add({
1069
+ kind: "review_classifier_extra_tool",
1070
+ severity: "info",
1071
+ intent,
1072
+ tool,
1073
+ signal: null,
1074
+ requestId: row.requestId,
1075
+ });
1076
+ }
1077
+ for (const ruleId of workflow?.clarification?.blockingRuleIds ?? []) {
1078
+ if (isClarificationBlockingRuleSatisfiedByRuntime(row, ruleId))
1079
+ continue;
1080
+ builder.add({
1081
+ kind: "review_clarification_policy",
1082
+ severity: "warning",
1083
+ intent,
1084
+ tool: null,
1085
+ signal: ruleId,
1086
+ requestId: row.requestId,
1087
+ });
1088
+ }
1089
+ for (const comparison of row.summary.clarificationComparisons) {
1090
+ for (const ruleId of comparison.missingExpectedRuleIds) {
1091
+ builder.add({
1092
+ kind: "review_clarification_policy",
1093
+ severity: "warning",
1094
+ intent: comparison.intent ?? intent,
1095
+ tool: null,
1096
+ signal: ruleId,
1097
+ requestId: row.requestId,
1098
+ });
1099
+ }
1100
+ if (comparison.unexpectedObservedRuleId) {
1101
+ builder.add({
1102
+ kind: "review_clarification_policy",
1103
+ severity: "warning",
1104
+ intent: comparison.intent ?? intent,
1105
+ tool: null,
1106
+ signal: comparison.unexpectedObservedRuleId,
1107
+ requestId: row.requestId,
1108
+ });
1109
+ }
1110
+ }
1111
+ for (const patch of row.summary.memoryPatches) {
1112
+ if (patch.profilePatchEquivalent !== false)
1113
+ continue;
1114
+ builder.add({
1115
+ kind: "review_memory_patch_equivalence",
1116
+ severity: "warning",
1117
+ intent,
1118
+ tool: null,
1119
+ signal: patch.profilePatchMismatchedFields.join(", ") || "profile_patch_mismatch",
1120
+ requestId: row.requestId,
1121
+ });
1122
+ }
1123
+ for (const strategy of row.directRouteStrategies) {
1124
+ if (strategy.declared !== false)
1125
+ continue;
1126
+ builder.add({
1127
+ kind: "review_direct_route_strategy",
1128
+ severity: "info",
1129
+ intent: strategy.definitionRouteId ?? strategy.route,
1130
+ tool: null,
1131
+ signal: buildDirectRouteStrategyKey(strategy),
1132
+ requestId: row.requestId,
1133
+ });
1134
+ }
1135
+ for (const stage of row.summary.errorStages) {
1136
+ builder.add({
1137
+ kind: "review_trace_error",
1138
+ severity: "warning",
1139
+ intent,
1140
+ tool: null,
1141
+ signal: stage,
1142
+ requestId: row.requestId,
1143
+ });
1144
+ }
1145
+ for (const signal of row.summary.quality.signalNames) {
1146
+ builder.add({
1147
+ kind: "review_quality_signal",
1148
+ severity: "warning",
1149
+ intent,
1150
+ tool: null,
1151
+ signal,
1152
+ requestId: row.requestId,
1153
+ });
1154
+ }
1155
+ if (row.feedback === "bad" && row.evalCandidate) {
1156
+ builder.add({
1157
+ kind: "promote_bad_feedback_eval",
1158
+ severity: "warning",
1159
+ intent,
1160
+ tool: null,
1161
+ signal: "bad_feedback",
1162
+ requestId: row.requestId,
1163
+ });
1164
+ }
1165
+ }
1166
+ return builder.toSuggestions();
1167
+ }
1168
+ function buildTraceDerivedRunReportStatus(row, warningCount) {
1169
+ if (row.summary.handledOutcome?.kind === "clarification")
1170
+ return "clarification";
1171
+ if (row.summary.handledOutcome?.kind === "degraded")
1172
+ return "degraded";
1173
+ if (row.summary.errorStages.length > 0)
1174
+ return "failed";
1175
+ if (warningCount > 0 || row.feedback === "bad" || row.summary.quality.flagged)
1176
+ return "degraded";
1177
+ if (row.summary.handledOutcome)
1178
+ return "completed";
1179
+ if (!row.summary.workflow)
1180
+ return "not_handled";
1181
+ return "completed";
1182
+ }
1183
+ function buildTraceDerivedRunEvaluationSignals(row) {
1184
+ const signals = [];
1185
+ const workflow = row.summary.workflow;
1186
+ if (!workflow && !row.summary.handledOutcome) {
1187
+ signals.push({
1188
+ name: "run_not_handled",
1189
+ severity: "warning",
1190
+ detail: "trace did not include a workflow decision",
1191
+ });
1192
+ }
1193
+ if (row.summary.errorStages.length > 0) {
1194
+ signals.push({
1195
+ name: "run_failed",
1196
+ severity: "warning",
1197
+ detail: row.summary.errorStages.join(", "),
1198
+ });
1199
+ }
1200
+ if (workflow?.missingRequiredToolHints.length) {
1201
+ signals.push({
1202
+ name: "missing_required_tools",
1203
+ severity: "warning",
1204
+ detail: workflow.missingRequiredToolHints.join(", "),
1205
+ });
1206
+ }
1207
+ if (workflow?.plan?.missingRequiredToolHints.length) {
1208
+ signals.push({
1209
+ name: "missing_required_tools",
1210
+ severity: "warning",
1211
+ detail: workflow.plan.missingRequiredToolHints.join(", "),
1212
+ });
1213
+ }
1214
+ if (row.summary.errorStages.some((stage) => stage === ASSISTANT_WORKFLOW_TRACE_STAGE.toolCallError)) {
1215
+ signals.push({
1216
+ name: "tool_execution_failed",
1217
+ severity: "warning",
1218
+ detail: row.summary.errorStages.join(", "),
1219
+ });
1220
+ }
1221
+ if (row.feedback === "bad" || row.summary.quality.flagged) {
1222
+ signals.push({
1223
+ name: "run_degraded",
1224
+ severity: "warning",
1225
+ detail: row.summary.quality.flagged
1226
+ ? row.summary.quality.signalNames.join(", ") || "quality flagged"
1227
+ : "bad feedback",
1228
+ });
1229
+ }
1230
+ for (const comparison of row.summary.clarificationComparisons) {
1231
+ if (comparison.matched !== false)
1232
+ continue;
1233
+ signals.push({
1234
+ name: "clarification_policy_mismatch",
1235
+ severity: "warning",
1236
+ detail: buildClarificationPolicyMismatchDetail(comparison),
1237
+ });
1238
+ }
1239
+ return dedupeRunEvaluationSignals(signals);
1240
+ }
1241
+ function buildClarificationPolicyMismatchDetail(input) {
1242
+ if (input.missingExpectedRuleIds.length)
1243
+ return `missing ${input.missingExpectedRuleIds.join(", ")}`;
1244
+ if (input.unexpectedObservedRuleId)
1245
+ return `unexpected ${input.unexpectedObservedRuleId}`;
1246
+ if (input.observedRuleId)
1247
+ return `unmatched ${input.observedRuleId}`;
1248
+ return "clarification policy mismatch";
1249
+ }
1250
+ function dedupeRunEvaluationSignals(signals) {
1251
+ const out = [];
1252
+ const seen = new Set();
1253
+ for (const signal of signals) {
1254
+ const key = `${signal.name}:${signal.detail ?? ""}`;
1255
+ if (seen.has(key))
1256
+ continue;
1257
+ seen.add(key);
1258
+ out.push(signal);
1259
+ }
1260
+ return out;
1261
+ }
1262
+ function buildTraceDerivedOutcomeReason(row, status) {
1263
+ if (status === "completed")
1264
+ return null;
1265
+ if (!row.summary.workflow)
1266
+ return "trace did not include a workflow decision";
1267
+ if (row.summary.errorStages.length > 0)
1268
+ return row.summary.errorStages.join(", ");
1269
+ if (row.summary.quality.flagged)
1270
+ return row.summary.quality.signalNames.join(", ") || "quality flagged";
1271
+ if (row.feedback === "bad")
1272
+ return "bad feedback";
1273
+ return "trace-derived warning";
1274
+ }
1275
+ function normalizeRunReportWorkflowId(value) {
1276
+ const normalized = value?.trim();
1277
+ return normalized?.length ? normalized : "trace-derived-assistant-workflow";
1278
+ }
1279
+ function normalizeRunReportWorkflowVersion(value) {
1280
+ if (typeof value !== "number" || !Number.isFinite(value))
1281
+ return 1;
1282
+ return Math.max(1, Math.floor(value));
1283
+ }
1284
+ class SuggestionBuilder {
1285
+ suggestions = new Map();
1286
+ add(input) {
1287
+ const id = buildSuggestionId(input);
1288
+ const existing = this.suggestions.get(id);
1289
+ if (existing) {
1290
+ existing.count += 1;
1291
+ if (!existing.requestIds.includes(input.requestId) && existing.requestIds.length < 5) {
1292
+ existing.requestIds.push(input.requestId);
1293
+ }
1294
+ if (input.severity === "warning")
1295
+ existing.severity = "warning";
1296
+ return;
1297
+ }
1298
+ this.suggestions.set(id, {
1299
+ kind: input.kind,
1300
+ severity: input.severity,
1301
+ intent: input.intent,
1302
+ tool: input.tool,
1303
+ signal: input.signal,
1304
+ count: 1,
1305
+ requestIds: [input.requestId],
1306
+ });
1307
+ }
1308
+ toSuggestions() {
1309
+ return [...this.suggestions.entries()]
1310
+ .map(([id, item]) => ({
1311
+ id,
1312
+ kind: item.kind,
1313
+ severity: item.severity,
1314
+ intent: item.intent,
1315
+ tool: item.tool,
1316
+ signal: item.signal,
1317
+ count: item.count,
1318
+ requestIds: item.requestIds,
1319
+ ...describeSuggestion(item),
1320
+ }))
1321
+ .sort((left, right) => {
1322
+ if (left.severity !== right.severity)
1323
+ return left.severity === "warning" ? -1 : 1;
1324
+ if (right.count !== left.count)
1325
+ return right.count - left.count;
1326
+ return left.id.localeCompare(right.id);
1327
+ });
1328
+ }
1329
+ }
1330
+ function buildSuggestionId(input) {
1331
+ return [
1332
+ input.kind,
1333
+ input.intent ?? "unknown",
1334
+ input.tool ?? input.signal ?? "all",
1335
+ ].map((part) => part.replace(/[^a-zA-Z0-9_.-]+/g, "_").toLowerCase()).join(":");
1336
+ }
1337
+ function describeSuggestion(item) {
1338
+ const intent = item.intent ?? "unknown intent";
1339
+ const tool = item.tool ?? "unknown tool";
1340
+ const signal = item.signal ?? "unknown signal";
1341
+ switch (item.kind) {
1342
+ case "review_missing_required_tool":
1343
+ return {
1344
+ rationale: `Workflow required ${tool} for ${intent}, but the tool was not available in these traces.`,
1345
+ suggestedAction: "Check tool registration/policy or relax the requiredToolHint/planning-step requirement if it is no longer valid.",
1346
+ };
1347
+ case "review_workflow_tool_selection_gap":
1348
+ return {
1349
+ rationale: `Workflow suggested ${tool} for ${intent}, but existing tool pruning did not select it.`,
1350
+ suggestedAction: "Compare pruning rules against workflow hints before migrating this route to workflow-owned selection.",
1351
+ };
1352
+ case "review_unmodeled_selected_tool":
1353
+ return {
1354
+ rationale: `Existing runtime selected ${tool} for ${intent}, but the workflow did not suggest it.`,
1355
+ suggestedAction: "If this is intentional, add a tool hint or conditional planning step; otherwise tighten the runtime pruning path.",
1356
+ };
1357
+ case "review_classifier_extra_tool":
1358
+ return {
1359
+ rationale: `Classifier exposed ${tool} for ${intent} outside the workflow hint set.`,
1360
+ suggestedAction: "Add an explicit workflow hint/condition or update classifier prompt facts so the contract stays consistent.",
1361
+ };
1362
+ case "review_clarification_policy":
1363
+ return {
1364
+ rationale: `Clarification rule ${signal} blocked confident execution for ${intent}.`,
1365
+ suggestedAction: "Check whether the runtime already clarified correctly; if repeated, promote examples into evals before changing the clarification rule.",
1366
+ };
1367
+ case "review_memory_patch_equivalence":
1368
+ return {
1369
+ rationale: `Workflow memory patches did not reproduce legacy profile fields (${signal}) for ${intent}.`,
1370
+ suggestedAction: "Keep memory writes in shadow mode; inspect the slot mapping/coercion before cutting over profile persistence.",
1371
+ };
1372
+ case "review_direct_route_strategy":
1373
+ return {
1374
+ rationale: `Runtime direct-route strategy ${signal} was observed for ${intent}, but it is not declared in the workflow route catalog.`,
1375
+ suggestedAction: "Review whether this branch should be added to route strategy metadata or split into a narrower direct-route definition.",
1376
+ };
1377
+ case "review_trace_error":
1378
+ return {
1379
+ rationale: `Trace stage ${signal} occurred for ${intent}.`,
1380
+ suggestedAction: "Debug the request path first; tune workflow only after the implementation error is understood.",
1381
+ };
1382
+ case "review_quality_signal":
1383
+ return {
1384
+ rationale: `Quality signal ${signal} fired for ${intent}.`,
1385
+ suggestedAction: "Promote representative prompts to eval cases, then adjust intent, tool, artifact, or clarification policy if repeated.",
1386
+ };
1387
+ case "promote_bad_feedback_eval":
1388
+ return {
1389
+ rationale: `Bad user feedback was recorded for ${intent}.`,
1390
+ suggestedAction: "Review the trace and promote the prompt into an eval case before changing workflow definitions.",
1391
+ };
1392
+ }
1393
+ }
1394
+ //# sourceMappingURL=trace-report.js.map