@mcoda/codali 0.1.90 → 0.1.91
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.
- package/dist/cli/DatasetCommand.d.ts +38 -0
- package/dist/cli/DatasetCommand.d.ts.map +1 -0
- package/dist/cli/DatasetCommand.js +959 -0
- package/dist/cli/EvalCommand.d.ts +3 -0
- package/dist/cli/EvalCommand.d.ts.map +1 -1
- package/dist/cli/EvalCommand.js +55 -1
- package/dist/cli/ImprovementCommand.d.ts +97 -0
- package/dist/cli/ImprovementCommand.d.ts.map +1 -0
- package/dist/cli/ImprovementCommand.js +1879 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +15 -0
- package/dist/dataset-cli.d.ts +3 -0
- package/dist/dataset-cli.d.ts.map +1 -0
- package/dist/dataset-cli.js +30 -0
- package/dist/eval/CodaliGatewayLiveHarness.d.ts +90 -1
- package/dist/eval/CodaliGatewayLiveHarness.d.ts.map +1 -1
- package/dist/eval/CodaliGatewayLiveHarness.js +443 -9
- package/dist/eval/GatewayDatasetEval.d.ts +70 -0
- package/dist/eval/GatewayDatasetEval.d.ts.map +1 -0
- package/dist/eval/GatewayDatasetEval.js +477 -0
- package/dist/eval/GatewayEvalSuite.d.ts +52 -0
- package/dist/eval/GatewayEvalSuite.d.ts.map +1 -1
- package/dist/eval/GatewayEvalSuite.js +135 -1
- package/dist/gateway/CodaliGateway.d.ts +4 -0
- package/dist/gateway/CodaliGateway.d.ts.map +1 -1
- package/dist/gateway/CodaliGateway.js +37 -1
- package/dist/gateway/CodaliGatewaySchemas.d.ts.map +1 -1
- package/dist/gateway/CodaliGatewaySchemas.js +0 -4
- package/dist/gateway/CodaliGatewayStore.d.ts.map +1 -1
- package/dist/gateway/CodaliGatewayStore.js +1 -0
- package/dist/gateway/GatewayPlanner.d.ts.map +1 -1
- package/dist/gateway/GatewayPlanner.js +355 -41
- package/dist/gateway/GatewayStateMachine.d.ts +1 -0
- package/dist/gateway/GatewayStateMachine.d.ts.map +1 -1
- package/dist/gateway/GatewayStateMachine.js +221 -5
- package/dist/improvement/CandidateReleaseBuilder.d.ts +201 -0
- package/dist/improvement/CandidateReleaseBuilder.d.ts.map +1 -0
- package/dist/improvement/CandidateReleaseBuilder.js +1175 -0
- package/dist/improvement/DatasetEligibilityGate.d.ts +75 -0
- package/dist/improvement/DatasetEligibilityGate.d.ts.map +1 -0
- package/dist/improvement/DatasetEligibilityGate.js +497 -0
- package/dist/improvement/DatasetExportManifestReader.d.ts +88 -0
- package/dist/improvement/DatasetExportManifestReader.d.ts.map +1 -0
- package/dist/improvement/DatasetExportManifestReader.js +333 -0
- package/dist/improvement/DocdexRetrievalCandidateBuilder.d.ts +192 -0
- package/dist/improvement/DocdexRetrievalCandidateBuilder.d.ts.map +1 -0
- package/dist/improvement/DocdexRetrievalCandidateBuilder.js +625 -0
- package/dist/improvement/EvalReplayCandidateBuilder.d.ts +173 -0
- package/dist/improvement/EvalReplayCandidateBuilder.d.ts.map +1 -0
- package/dist/improvement/EvalReplayCandidateBuilder.js +363 -0
- package/dist/improvement/FineTuneJobPlanner.d.ts +281 -0
- package/dist/improvement/FineTuneJobPlanner.d.ts.map +1 -0
- package/dist/improvement/FineTuneJobPlanner.js +823 -0
- package/dist/improvement/ImprovementEvalRunner.d.ts +50 -0
- package/dist/improvement/ImprovementEvalRunner.d.ts.map +1 -0
- package/dist/improvement/ImprovementEvalRunner.js +648 -0
- package/dist/improvement/ImprovementPolicy.d.ts +272 -0
- package/dist/improvement/ImprovementPolicy.d.ts.map +1 -0
- package/dist/improvement/ImprovementPolicy.js +1450 -0
- package/dist/improvement/ModelRouterCandidateBuilder.d.ts +186 -0
- package/dist/improvement/ModelRouterCandidateBuilder.d.ts.map +1 -0
- package/dist/improvement/ModelRouterCandidateBuilder.js +880 -0
- package/dist/improvement/OperatorInspector.d.ts +182 -0
- package/dist/improvement/OperatorInspector.d.ts.map +1 -0
- package/dist/improvement/OperatorInspector.js +604 -0
- package/dist/improvement/ProductionGovernance.d.ts +91 -0
- package/dist/improvement/ProductionGovernance.d.ts.map +1 -0
- package/dist/improvement/ProductionGovernance.js +329 -0
- package/dist/improvement/PromptSchemaToolMetadataCandidateBuilder.d.ts +152 -0
- package/dist/improvement/PromptSchemaToolMetadataCandidateBuilder.d.ts.map +1 -0
- package/dist/improvement/PromptSchemaToolMetadataCandidateBuilder.js +480 -0
- package/dist/improvement/PublishOrchestrator.d.ts +113 -0
- package/dist/improvement/PublishOrchestrator.d.ts.map +1 -0
- package/dist/improvement/PublishOrchestrator.js +590 -0
- package/dist/improvement/ReleaseOutcomeReporter.d.ts +133 -0
- package/dist/improvement/ReleaseOutcomeReporter.d.ts.map +1 -0
- package/dist/improvement/ReleaseOutcomeReporter.js +501 -0
- package/dist/improvement/StorageServiceImprovementClient.d.ts +71 -0
- package/dist/improvement/StorageServiceImprovementClient.d.ts.map +1 -0
- package/dist/improvement/StorageServiceImprovementClient.js +245 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -0
- package/dist/runtime/CodaliRuntime.d.ts +0 -2
- package/dist/runtime/CodaliRuntime.d.ts.map +1 -1
- package/dist/runtime/CodaliRuntime.js +0 -5
- package/dist/storage/CodaliDatasetPrivacyEngine.d.ts +138 -0
- package/dist/storage/CodaliDatasetPrivacyEngine.d.ts.map +1 -0
- package/dist/storage/CodaliDatasetPrivacyEngine.js +417 -0
- package/dist/storage/CodaliFeedbackReviewIngestion.d.ts +50 -0
- package/dist/storage/CodaliFeedbackReviewIngestion.d.ts.map +1 -0
- package/dist/storage/CodaliFeedbackReviewIngestion.js +141 -0
- package/dist/storage/CodaliStorageContracts.d.ts +337 -0
- package/dist/storage/CodaliStorageContracts.d.ts.map +1 -0
- package/dist/storage/CodaliStorageContracts.js +1555 -0
- package/dist/storage/DatasetExportJob.d.ts +51 -0
- package/dist/storage/DatasetExportJob.d.ts.map +1 -0
- package/dist/storage/DatasetExportJob.js +358 -0
- package/dist/storage/DatasetReviewQueue.d.ts +98 -0
- package/dist/storage/DatasetReviewQueue.d.ts.map +1 -0
- package/dist/storage/DatasetReviewQueue.js +426 -0
- package/dist/storage/GatewayDatasetStore.d.ts +233 -0
- package/dist/storage/GatewayDatasetStore.d.ts.map +1 -0
- package/dist/storage/GatewayDatasetStore.js +2070 -0
- package/package.json +5 -4
|
@@ -0,0 +1,880 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
export const CODALI_MODEL_ROUTER_CANDIDATE_SCHEMA_VERSION = "codali.improvement.model_router_candidate.v1";
|
|
3
|
+
export const CODALI_MODEL_ROUTER_PROPOSAL_ARTIFACT = "model-router";
|
|
4
|
+
export const CODALI_MODEL_ROUTER_SOURCE_ARTIFACT_TYPES = [
|
|
5
|
+
"model_router",
|
|
6
|
+
"model-router",
|
|
7
|
+
"router",
|
|
8
|
+
"tool_router",
|
|
9
|
+
"tool-router",
|
|
10
|
+
];
|
|
11
|
+
export const CODALI_MODEL_ROUTER_SUPPORTED_EXPORT_KINDS = [
|
|
12
|
+
"model-router",
|
|
13
|
+
];
|
|
14
|
+
const SCORE_DELTA_THRESHOLD = 0.05;
|
|
15
|
+
const LOCAL_PREFERENCE_SCORE_DELTA_THRESHOLD = 0.03;
|
|
16
|
+
const MIN_SHADOW_CONFIDENCE = 0.7;
|
|
17
|
+
const MIN_SHADOW_SCHEMA_SUCCESS = 0.85;
|
|
18
|
+
const MIN_SHADOW_AVAILABILITY = 0.7;
|
|
19
|
+
const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
20
|
+
const stableJson = (value) => {
|
|
21
|
+
if (Array.isArray(value))
|
|
22
|
+
return `[${value.map(stableJson).join(",")}]`;
|
|
23
|
+
if (!isRecord(value))
|
|
24
|
+
return JSON.stringify(value);
|
|
25
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`;
|
|
26
|
+
};
|
|
27
|
+
const sha256Hex = (value) => createHash("sha256").update(stableJson(value)).digest("hex");
|
|
28
|
+
const stableId = (prefix, value) => `${prefix}-${sha256Hex(value).slice(0, 16)}`;
|
|
29
|
+
const normalizeToken = (value) => value.trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
30
|
+
const uniqueSorted = (values) => Array.from(new Set(values
|
|
31
|
+
.map((value) => value?.trim())
|
|
32
|
+
.filter((value) => Boolean(value))))
|
|
33
|
+
.sort();
|
|
34
|
+
const clamp01 = (value, fallback = 0) => {
|
|
35
|
+
if (value === undefined || !Number.isFinite(value))
|
|
36
|
+
return fallback;
|
|
37
|
+
return Math.max(0, Math.min(1, value));
|
|
38
|
+
};
|
|
39
|
+
const readString = (record, keys) => {
|
|
40
|
+
for (const key of keys) {
|
|
41
|
+
const value = record?.[key];
|
|
42
|
+
if (typeof value === "string" && value.trim())
|
|
43
|
+
return value.trim();
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
};
|
|
47
|
+
const readBoolean = (record, keys) => {
|
|
48
|
+
for (const key of keys) {
|
|
49
|
+
const value = record?.[key];
|
|
50
|
+
if (typeof value === "boolean")
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
};
|
|
55
|
+
const readNumber = (record, keys) => {
|
|
56
|
+
for (const key of keys) {
|
|
57
|
+
const value = record?.[key];
|
|
58
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
59
|
+
return value;
|
|
60
|
+
if (typeof value === "string" && value.trim() && Number.isFinite(Number(value))) {
|
|
61
|
+
return Number(value);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return undefined;
|
|
65
|
+
};
|
|
66
|
+
const stringList = (value) => {
|
|
67
|
+
if (Array.isArray(value)) {
|
|
68
|
+
return uniqueSorted(value.map((entry) => typeof entry === "string" ? entry : undefined));
|
|
69
|
+
}
|
|
70
|
+
if (typeof value === "string" && value.trim())
|
|
71
|
+
return [value.trim()];
|
|
72
|
+
return [];
|
|
73
|
+
};
|
|
74
|
+
const recordList = (value) => Array.isArray(value) ? value.filter(isRecord) : [];
|
|
75
|
+
const numberObject = (entries) => {
|
|
76
|
+
const result = {};
|
|
77
|
+
for (const [key, value] of entries) {
|
|
78
|
+
if (value !== undefined && Number.isFinite(value))
|
|
79
|
+
result[key] = value;
|
|
80
|
+
}
|
|
81
|
+
return Object.keys(result).length ? result : undefined;
|
|
82
|
+
};
|
|
83
|
+
const nestedRecord = (record, keys) => {
|
|
84
|
+
for (const key of keys) {
|
|
85
|
+
const value = record?.[key];
|
|
86
|
+
if (isRecord(value))
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
};
|
|
91
|
+
const nestedRecords = (record, keys) => {
|
|
92
|
+
for (const key of keys) {
|
|
93
|
+
const value = record?.[key];
|
|
94
|
+
if (Array.isArray(value))
|
|
95
|
+
return value.filter(isRecord);
|
|
96
|
+
}
|
|
97
|
+
return [];
|
|
98
|
+
};
|
|
99
|
+
const objectRefSummary = (ref) => {
|
|
100
|
+
if (!ref)
|
|
101
|
+
return undefined;
|
|
102
|
+
return {
|
|
103
|
+
refId: ref.refId,
|
|
104
|
+
kind: ref.kind,
|
|
105
|
+
contentHash: ref.contentHash,
|
|
106
|
+
byteSize: ref.byteSize,
|
|
107
|
+
mimeType: ref.mimeType,
|
|
108
|
+
deletionGroupId: ref.deletionGroupId,
|
|
109
|
+
privacyFlags: ref.privacyFlags,
|
|
110
|
+
...(ref.uri ? { uri: ref.uri } : {}),
|
|
111
|
+
...(ref.mediaType ? { mediaType: ref.mediaType } : {}),
|
|
112
|
+
metadataKeys: isRecord(ref.metadata) ? Object.keys(ref.metadata).sort() : [],
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
const metadataForRow = (row) => isRecord(row.metadata) ? row.metadata : {};
|
|
116
|
+
const comparisonRecordLooksValid = (value) => isRecord(value.metrics) &&
|
|
117
|
+
Boolean(readString(value, ["role"]) || readString(value, ["resolverRole", "resolver_role"]));
|
|
118
|
+
const normalizeComparisonRole = (value, primary) => {
|
|
119
|
+
const normalized = normalizeToken(value ?? "");
|
|
120
|
+
if (normalized === "shadow")
|
|
121
|
+
return "shadow";
|
|
122
|
+
if (normalized === "primary")
|
|
123
|
+
return "primary";
|
|
124
|
+
return primary === false ? "shadow" : "primary";
|
|
125
|
+
};
|
|
126
|
+
const normalizeScenarioStatus = (value) => {
|
|
127
|
+
const normalized = normalizeToken(value ?? "");
|
|
128
|
+
if (normalized === "passed" ||
|
|
129
|
+
normalized === "failed" ||
|
|
130
|
+
normalized === "degraded" ||
|
|
131
|
+
normalized === "skipped") {
|
|
132
|
+
return normalized;
|
|
133
|
+
}
|
|
134
|
+
return "skipped";
|
|
135
|
+
};
|
|
136
|
+
const normalizeComparisonRecord = (raw) => {
|
|
137
|
+
const rawMetrics = isRecord(raw.metrics) ? raw.metrics : {};
|
|
138
|
+
const rawQuality = isRecord(rawMetrics.quality) ? rawMetrics.quality : {};
|
|
139
|
+
const rawFailure = isRecord(rawMetrics.failure) ? rawMetrics.failure : {};
|
|
140
|
+
const rawTokenUse = nestedRecord(rawMetrics, ["tokenUse", "token_use"]);
|
|
141
|
+
const rawQueue = nestedRecord(rawMetrics, ["queue"]);
|
|
142
|
+
const rawThroughput = nestedRecord(rawMetrics, ["throughput"]);
|
|
143
|
+
const queueStatus = rawQueue ? readString(rawQueue, ["status"]) : undefined;
|
|
144
|
+
const tokenUse = rawTokenUse
|
|
145
|
+
? numberObject([
|
|
146
|
+
["inputTokens", readNumber(rawTokenUse, ["inputTokens", "input_tokens"])],
|
|
147
|
+
["outputTokens", readNumber(rawTokenUse, ["outputTokens", "output_tokens"])],
|
|
148
|
+
["totalTokens", readNumber(rawTokenUse, ["totalTokens", "total_tokens"])],
|
|
149
|
+
])
|
|
150
|
+
: undefined;
|
|
151
|
+
const queue = rawQueue
|
|
152
|
+
? {
|
|
153
|
+
...numberObject([
|
|
154
|
+
["waitMs", readNumber(rawQueue, ["waitMs", "wait_ms"])],
|
|
155
|
+
["depth", readNumber(rawQueue, ["depth"])],
|
|
156
|
+
]),
|
|
157
|
+
...(queueStatus ? { status: queueStatus } : {}),
|
|
158
|
+
}
|
|
159
|
+
: undefined;
|
|
160
|
+
const throughput = rawThroughput
|
|
161
|
+
? numberObject([
|
|
162
|
+
[
|
|
163
|
+
"tokensPerSecond",
|
|
164
|
+
readNumber(rawThroughput, ["tokensPerSecond", "tokens_per_second"]),
|
|
165
|
+
],
|
|
166
|
+
[
|
|
167
|
+
"requestsPerMinute",
|
|
168
|
+
readNumber(rawThroughput, ["requestsPerMinute", "requests_per_minute"]),
|
|
169
|
+
],
|
|
170
|
+
])
|
|
171
|
+
: undefined;
|
|
172
|
+
const comparisonRole = normalizeComparisonRole(readString(raw, ["comparisonRole", "comparison_role"]), readBoolean(raw, ["primary"]));
|
|
173
|
+
const role = readString(raw, ["role"]) ?? "small_json";
|
|
174
|
+
const resolverRole = readString(raw, ["resolverRole", "resolver_role"]) ?? role;
|
|
175
|
+
const qualityStatus = normalizeScenarioStatus(readString(rawQuality, ["status"]) ?? readString(raw, ["resultStatus", "result_status"]));
|
|
176
|
+
return {
|
|
177
|
+
id: readString(raw, ["id"]) ?? stableId("comparison", raw),
|
|
178
|
+
scenarioId: (readString(raw, ["scenarioId", "scenario_id"]) ?? "generic_question"),
|
|
179
|
+
role: role,
|
|
180
|
+
resolverRole,
|
|
181
|
+
comparisonRole,
|
|
182
|
+
primary: readBoolean(raw, ["primary"]) ?? comparisonRole === "primary",
|
|
183
|
+
...(readNumber(raw, ["candidateRank", "candidate_rank"]) !== undefined
|
|
184
|
+
? { candidateRank: readNumber(raw, ["candidateRank", "candidate_rank"]) }
|
|
185
|
+
: {}),
|
|
186
|
+
...(readString(raw, ["agentSlug", "agent_slug", "slug"])
|
|
187
|
+
? { agentSlug: readString(raw, ["agentSlug", "agent_slug", "slug"]) }
|
|
188
|
+
: {}),
|
|
189
|
+
...(readString(raw, ["tier"])
|
|
190
|
+
? { tier: readString(raw, ["tier"]) }
|
|
191
|
+
: {}),
|
|
192
|
+
...(readString(raw, ["model"]) ? { model: readString(raw, ["model"]) } : {}),
|
|
193
|
+
...(readString(raw, ["adapter"]) ? { adapter: readString(raw, ["adapter"]) } : {}),
|
|
194
|
+
...(readString(raw, ["source"])
|
|
195
|
+
? { source: readString(raw, ["source"]) }
|
|
196
|
+
: {}),
|
|
197
|
+
...(readString(raw, ["healthStatus", "health_status", "health"])
|
|
198
|
+
? {
|
|
199
|
+
healthStatus: readString(raw, [
|
|
200
|
+
"healthStatus",
|
|
201
|
+
"health_status",
|
|
202
|
+
"health",
|
|
203
|
+
]),
|
|
204
|
+
}
|
|
205
|
+
: {}),
|
|
206
|
+
capabilities: stringList(raw.capabilities),
|
|
207
|
+
resultStatus: normalizeScenarioStatus(readString(raw, ["resultStatus", "result_status"])),
|
|
208
|
+
selectedByPolicy: readBoolean(raw, ["selectedByPolicy", "selected_by_policy"]) ??
|
|
209
|
+
comparisonRole === "primary",
|
|
210
|
+
metrics: {
|
|
211
|
+
quality: {
|
|
212
|
+
status: qualityStatus,
|
|
213
|
+
score: clamp01(readNumber(rawQuality, ["score"]), 0),
|
|
214
|
+
...(readBoolean(rawQuality, ["jsonValid", "json_valid"]) !== undefined
|
|
215
|
+
? { jsonValid: readBoolean(rawQuality, ["jsonValid", "json_valid"]) }
|
|
216
|
+
: {}),
|
|
217
|
+
...(readNumber(rawQuality, ["toolCallCount", "tool_call_count"]) !== undefined
|
|
218
|
+
? { toolCallCount: readNumber(rawQuality, ["toolCallCount", "tool_call_count"]) }
|
|
219
|
+
: {}),
|
|
220
|
+
...(readBoolean(rawQuality, ["artifactPresent", "artifact_present"]) !== undefined
|
|
221
|
+
? {
|
|
222
|
+
artifactPresent: readBoolean(rawQuality, [
|
|
223
|
+
"artifactPresent",
|
|
224
|
+
"artifact_present",
|
|
225
|
+
]),
|
|
226
|
+
}
|
|
227
|
+
: {}),
|
|
228
|
+
...(readBoolean(rawQuality, [
|
|
229
|
+
"finalAnswerSucceeded",
|
|
230
|
+
"final_answer_succeeded",
|
|
231
|
+
]) !== undefined
|
|
232
|
+
? {
|
|
233
|
+
finalAnswerSucceeded: readBoolean(rawQuality, [
|
|
234
|
+
"finalAnswerSucceeded",
|
|
235
|
+
"final_answer_succeeded",
|
|
236
|
+
]),
|
|
237
|
+
}
|
|
238
|
+
: {}),
|
|
239
|
+
},
|
|
240
|
+
...(readNumber(rawMetrics, ["latencyMs", "latency_ms"]) !== undefined
|
|
241
|
+
? { latencyMs: readNumber(rawMetrics, ["latencyMs", "latency_ms"]) }
|
|
242
|
+
: {}),
|
|
243
|
+
...(readNumber(rawMetrics, ["costUsd", "cost_usd"]) !== undefined
|
|
244
|
+
? { costUsd: readNumber(rawMetrics, ["costUsd", "cost_usd"]) }
|
|
245
|
+
: {}),
|
|
246
|
+
...(tokenUse ? { tokenUse } : {}),
|
|
247
|
+
...(queue && Object.keys(queue).length > 0 ? { queue } : {}),
|
|
248
|
+
...(throughput ? { throughput } : {}),
|
|
249
|
+
failure: {
|
|
250
|
+
status: (readString(rawFailure, ["status"]) === "failed" ||
|
|
251
|
+
readString(rawFailure, ["status"]) === "degraded" ||
|
|
252
|
+
readString(rawFailure, ["status"]) === "skipped")
|
|
253
|
+
? readString(rawFailure, ["status"])
|
|
254
|
+
: "none",
|
|
255
|
+
reasons: stringList(rawFailure.reasons),
|
|
256
|
+
},
|
|
257
|
+
...(isRecord(rawMetrics.localInference)
|
|
258
|
+
? { localInference: rawMetrics.localInference }
|
|
259
|
+
: {}),
|
|
260
|
+
},
|
|
261
|
+
warnings: stringList(raw.warnings),
|
|
262
|
+
errors: stringList(raw.errors),
|
|
263
|
+
...(isRecord(raw.metadata) ? { metadata: raw.metadata } : {}),
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
const extractComparisonRecordsFromRecord = (record) => {
|
|
267
|
+
if (!record)
|
|
268
|
+
return [];
|
|
269
|
+
const shadowComparison = nestedRecord(record, ["shadowComparison", "shadow_comparison"]);
|
|
270
|
+
const modelComparison = nestedRecord(record, ["modelComparison", "model_comparison"]);
|
|
271
|
+
return [
|
|
272
|
+
...nestedRecords(record, ["modelComparisonRecords", "model_comparison_records"]),
|
|
273
|
+
...nestedRecords(record, ["comparisonRecords", "comparison_records"]),
|
|
274
|
+
...nestedRecords(record, ["records"]),
|
|
275
|
+
...nestedRecords(shadowComparison, ["records"]),
|
|
276
|
+
...nestedRecords(modelComparison, ["records"]),
|
|
277
|
+
...(comparisonRecordLooksValid(record) ? [record] : []),
|
|
278
|
+
...(modelComparison && comparisonRecordLooksValid(modelComparison) ? [modelComparison] : []),
|
|
279
|
+
];
|
|
280
|
+
};
|
|
281
|
+
const comparisonRecordsForRow = (row) => {
|
|
282
|
+
const metadata = metadataForRow(row);
|
|
283
|
+
const records = [
|
|
284
|
+
...extractComparisonRecordsFromRecord(row),
|
|
285
|
+
...extractComparisonRecordsFromRecord(metadata),
|
|
286
|
+
];
|
|
287
|
+
const byId = new Map();
|
|
288
|
+
for (const record of records) {
|
|
289
|
+
if (!comparisonRecordLooksValid(record))
|
|
290
|
+
continue;
|
|
291
|
+
const normalized = normalizeComparisonRecord(record);
|
|
292
|
+
byId.set(normalized.id, normalized);
|
|
293
|
+
}
|
|
294
|
+
return [...byId.values()].sort((left, right) => left.id.localeCompare(right.id));
|
|
295
|
+
};
|
|
296
|
+
const recordIdForRow = (row) => readString(row, ["recordId", "record_id"]);
|
|
297
|
+
const acceptedRows = (inspection) => {
|
|
298
|
+
const acceptedByRecordId = new Map(inspection.curationReport.accepted.map((accepted) => [accepted.recordId, accepted]));
|
|
299
|
+
return inspection.primaryArtifactRows
|
|
300
|
+
.filter(isRecord)
|
|
301
|
+
.flatMap((row) => {
|
|
302
|
+
const recordId = recordIdForRow(row);
|
|
303
|
+
const accepted = recordId ? acceptedByRecordId.get(recordId) : undefined;
|
|
304
|
+
return accepted ? [{ row, accepted }] : [];
|
|
305
|
+
});
|
|
306
|
+
};
|
|
307
|
+
const sourceExampleForRow = (input) => {
|
|
308
|
+
const metadata = metadataForRow(input.row);
|
|
309
|
+
const comparisonRecords = comparisonRecordsForRow(input.row);
|
|
310
|
+
const comparisonKeys = Object.keys(metadata).filter((key) => normalizeToken(key).includes("comparison") ||
|
|
311
|
+
normalizeToken(key).includes("model_router") ||
|
|
312
|
+
normalizeToken(key).includes("router"));
|
|
313
|
+
const inputRef = objectRefSummary(input.row.inputRef);
|
|
314
|
+
const outputRef = objectRefSummary(input.row.outputRef);
|
|
315
|
+
const evidenceRefs = recordList(input.row.evidenceRefs)
|
|
316
|
+
.map((ref) => objectRefSummary(ref))
|
|
317
|
+
.filter((ref) => Boolean(ref));
|
|
318
|
+
return {
|
|
319
|
+
recordId: input.accepted.recordId,
|
|
320
|
+
...(input.accepted.sourceGatewayRecordId
|
|
321
|
+
? { sourceGatewayRecordId: input.accepted.sourceGatewayRecordId }
|
|
322
|
+
: {}),
|
|
323
|
+
artifactTypes: input.accepted.artifactTypes,
|
|
324
|
+
preferenceSignals: input.accepted.preferenceSignals,
|
|
325
|
+
priorityScore: input.accepted.priorityScore,
|
|
326
|
+
comparisonRecordCount: comparisonRecords.length,
|
|
327
|
+
shadowRecordCount: comparisonRecords.filter((record) => record.comparisonRole === "shadow").length,
|
|
328
|
+
objectRefs: {
|
|
329
|
+
...(inputRef ? { inputRef } : {}),
|
|
330
|
+
...(outputRef ? { outputRef } : {}),
|
|
331
|
+
evidenceRefs,
|
|
332
|
+
},
|
|
333
|
+
metadataShape: {
|
|
334
|
+
keys: Object.keys(metadata).sort(),
|
|
335
|
+
comparisonKeys: comparisonKeys.sort(),
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
};
|
|
339
|
+
const routeKeyForRecord = (record) => `${normalizeToken(record.role)}::${normalizeToken(record.resolverRole)}`;
|
|
340
|
+
const identityForRecord = (record) => {
|
|
341
|
+
const identityInput = {
|
|
342
|
+
agentSlug: record.agentSlug,
|
|
343
|
+
tier: record.tier,
|
|
344
|
+
model: record.model,
|
|
345
|
+
adapter: record.adapter,
|
|
346
|
+
source: record.source,
|
|
347
|
+
healthStatus: record.healthStatus,
|
|
348
|
+
capabilities: record.capabilities ?? [],
|
|
349
|
+
};
|
|
350
|
+
return {
|
|
351
|
+
identityKey: stableId("identity", identityInput),
|
|
352
|
+
comparisonRole: record.comparisonRole,
|
|
353
|
+
...(record.agentSlug ? { agentSlug: record.agentSlug } : {}),
|
|
354
|
+
...(record.tier ? { tier: record.tier } : {}),
|
|
355
|
+
...(record.model ? { model: record.model } : {}),
|
|
356
|
+
...(record.adapter ? { adapter: record.adapter } : {}),
|
|
357
|
+
...(record.source ? { source: record.source } : {}),
|
|
358
|
+
...(record.healthStatus ? { healthStatus: record.healthStatus } : {}),
|
|
359
|
+
capabilities: [...(record.capabilities ?? [])].sort(),
|
|
360
|
+
};
|
|
361
|
+
};
|
|
362
|
+
const aggregateKeyForRecord = (record) => `${routeKeyForRecord(record)}::${identityForRecord(record).identityKey}`;
|
|
363
|
+
const average = (values) => values.length ? values.reduce((sum, value) => sum + value, 0) / values.length : undefined;
|
|
364
|
+
const failurePenalty = (record) => {
|
|
365
|
+
if (record.metrics.failure.status === "failed")
|
|
366
|
+
return 1;
|
|
367
|
+
if (record.metrics.failure.status === "skipped")
|
|
368
|
+
return 0.8;
|
|
369
|
+
if (record.metrics.failure.status === "degraded")
|
|
370
|
+
return 0.5;
|
|
371
|
+
if (record.resultStatus === "failed")
|
|
372
|
+
return 1;
|
|
373
|
+
if (record.resultStatus === "degraded")
|
|
374
|
+
return 0.5;
|
|
375
|
+
return 0;
|
|
376
|
+
};
|
|
377
|
+
const explicitScore = (record, keys) => {
|
|
378
|
+
const metadata = isRecord(record.metadata) ? record.metadata : {};
|
|
379
|
+
const scorecard = nestedRecord(metadata, ["scorecard", "scores", "metrics"]);
|
|
380
|
+
const rawMetrics = record.metrics;
|
|
381
|
+
return readNumber(scorecard, keys) ?? readNumber(metadata, keys) ?? readNumber(rawMetrics, keys);
|
|
382
|
+
};
|
|
383
|
+
const toolAccuracyForRecord = (record) => {
|
|
384
|
+
const explicit = explicitScore(record, [
|
|
385
|
+
"toolAccuracy",
|
|
386
|
+
"tool_accuracy",
|
|
387
|
+
"toolSuccess",
|
|
388
|
+
"tool_success",
|
|
389
|
+
"toolSuccessRate",
|
|
390
|
+
"tool_success_rate",
|
|
391
|
+
]);
|
|
392
|
+
if (explicit !== undefined)
|
|
393
|
+
return clamp01(explicit);
|
|
394
|
+
const toolCallCount = record.metrics.quality.toolCallCount;
|
|
395
|
+
if (toolCallCount === undefined)
|
|
396
|
+
return 1;
|
|
397
|
+
if (toolCallCount > 0 && failurePenalty(record) === 0)
|
|
398
|
+
return 1;
|
|
399
|
+
if (toolCallCount > 0)
|
|
400
|
+
return 0.5;
|
|
401
|
+
return 0;
|
|
402
|
+
};
|
|
403
|
+
const schemaSuccessForRecord = (record) => {
|
|
404
|
+
const explicit = explicitScore(record, [
|
|
405
|
+
"schemaSuccess",
|
|
406
|
+
"schema_success",
|
|
407
|
+
"jsonSuccess",
|
|
408
|
+
"json_success",
|
|
409
|
+
"schemaSuccessRate",
|
|
410
|
+
"schema_success_rate",
|
|
411
|
+
]);
|
|
412
|
+
if (explicit !== undefined)
|
|
413
|
+
return clamp01(explicit);
|
|
414
|
+
if (record.metrics.quality.jsonValid === true)
|
|
415
|
+
return 1;
|
|
416
|
+
if (record.metrics.quality.jsonValid === false)
|
|
417
|
+
return 0;
|
|
418
|
+
return (record.capabilities ?? []).some((capability) => normalizeToken(capability).includes("json") ||
|
|
419
|
+
normalizeToken(capability).includes("schema"))
|
|
420
|
+
? 0.85
|
|
421
|
+
: 0.75;
|
|
422
|
+
};
|
|
423
|
+
const availabilityForRecord = (record) => {
|
|
424
|
+
const health = normalizeToken(record.healthStatus ?? "");
|
|
425
|
+
if (health === "healthy")
|
|
426
|
+
return 1;
|
|
427
|
+
if (health === "degraded")
|
|
428
|
+
return 0.65;
|
|
429
|
+
if (health === "limited")
|
|
430
|
+
return 0.55;
|
|
431
|
+
if (health === "unreachable")
|
|
432
|
+
return 0;
|
|
433
|
+
return record.resultStatus === "passed" ? 0.8 : 0.4;
|
|
434
|
+
};
|
|
435
|
+
const confidenceForRecord = (record) => {
|
|
436
|
+
const explicit = explicitScore(record, [
|
|
437
|
+
"confidence",
|
|
438
|
+
"confidenceScore",
|
|
439
|
+
"confidence_score",
|
|
440
|
+
]);
|
|
441
|
+
if (explicit !== undefined)
|
|
442
|
+
return clamp01(explicit);
|
|
443
|
+
return clamp01(record.metrics.quality.score, 0);
|
|
444
|
+
};
|
|
445
|
+
const fallbackUsedForRecord = (record) => {
|
|
446
|
+
const metadata = isRecord(record.metadata) ? record.metadata : {};
|
|
447
|
+
const rawMetrics = record.metrics;
|
|
448
|
+
return readBoolean(metadata, ["fallbackUsed", "fallback_used"]) ??
|
|
449
|
+
readBoolean(rawMetrics, ["fallbackUsed", "fallback_used"]) ??
|
|
450
|
+
record.metrics.failure.reasons.some((reason) => normalizeToken(reason).includes("fallback"));
|
|
451
|
+
};
|
|
452
|
+
const fallbackRateForRecord = (record) => {
|
|
453
|
+
const explicit = explicitScore(record, [
|
|
454
|
+
"fallbackRate",
|
|
455
|
+
"fallback_rate",
|
|
456
|
+
"fallbackUseRate",
|
|
457
|
+
"fallback_use_rate",
|
|
458
|
+
]);
|
|
459
|
+
if (explicit !== undefined)
|
|
460
|
+
return clamp01(explicit);
|
|
461
|
+
return fallbackUsedForRecord(record) ? 1 : 0;
|
|
462
|
+
};
|
|
463
|
+
const inferenceSummaryForRecords = (records) => {
|
|
464
|
+
const averageNumber = (values) => average(values.filter((value) => typeof value === "number" && Number.isFinite(value)));
|
|
465
|
+
const averageInputTokens = averageNumber(records.map((record) => record.metrics.tokenUse?.inputTokens));
|
|
466
|
+
const averageOutputTokens = averageNumber(records.map((record) => record.metrics.tokenUse?.outputTokens));
|
|
467
|
+
const averageTotalTokens = averageNumber(records.map((record) => record.metrics.tokenUse?.totalTokens));
|
|
468
|
+
const averageQueueWaitMs = averageNumber(records.map((record) => record.metrics.queue?.waitMs));
|
|
469
|
+
const averageQueueDepth = averageNumber(records.map((record) => record.metrics.queue?.depth));
|
|
470
|
+
const averageThroughputTokensPerSecond = averageNumber(records.map((record) => record.metrics.throughput?.tokensPerSecond));
|
|
471
|
+
const averageRequestsPerMinute = averageNumber(records.map((record) => record.metrics.throughput?.requestsPerMinute));
|
|
472
|
+
return {
|
|
473
|
+
...(averageInputTokens !== undefined
|
|
474
|
+
? { averageInputTokens }
|
|
475
|
+
: {}),
|
|
476
|
+
...(averageOutputTokens !== undefined
|
|
477
|
+
? { averageOutputTokens }
|
|
478
|
+
: {}),
|
|
479
|
+
...(averageTotalTokens !== undefined
|
|
480
|
+
? { averageTotalTokens }
|
|
481
|
+
: {}),
|
|
482
|
+
...(averageQueueWaitMs !== undefined
|
|
483
|
+
? { averageQueueWaitMs }
|
|
484
|
+
: {}),
|
|
485
|
+
...(averageQueueDepth !== undefined
|
|
486
|
+
? { averageQueueDepth }
|
|
487
|
+
: {}),
|
|
488
|
+
...(averageThroughputTokensPerSecond !== undefined
|
|
489
|
+
? { averageThroughputTokensPerSecond }
|
|
490
|
+
: {}),
|
|
491
|
+
...(averageRequestsPerMinute !== undefined
|
|
492
|
+
? { averageRequestsPerMinute }
|
|
493
|
+
: {}),
|
|
494
|
+
localInferenceSampleCount: records.filter((record) => isRecord(record.metrics.localInference) &&
|
|
495
|
+
Object.keys(record.metrics.localInference).length > 0).length,
|
|
496
|
+
};
|
|
497
|
+
};
|
|
498
|
+
const metricScorecardForRecords = (records) => {
|
|
499
|
+
const rawRecords = records.map((entry) => entry.record);
|
|
500
|
+
const sampleCount = rawRecords.length;
|
|
501
|
+
const quality = average(rawRecords.map((record) => record.metrics.quality.score)) ?? 0;
|
|
502
|
+
const toolAccuracy = average(rawRecords.map(toolAccuracyForRecord)) ?? 0;
|
|
503
|
+
const schemaSuccess = average(rawRecords.map(schemaSuccessForRecord)) ?? 0;
|
|
504
|
+
const latencyMs = average(rawRecords
|
|
505
|
+
.map((record) => record.metrics.latencyMs)
|
|
506
|
+
.filter((value) => typeof value === "number" && Number.isFinite(value)));
|
|
507
|
+
const costUsd = average(rawRecords
|
|
508
|
+
.map((record) => record.metrics.costUsd)
|
|
509
|
+
.filter((value) => typeof value === "number" && Number.isFinite(value)));
|
|
510
|
+
const inference = inferenceSummaryForRecords(rawRecords);
|
|
511
|
+
const effectiveLatencyMs = latencyMs !== undefined && inference.averageQueueWaitMs !== undefined
|
|
512
|
+
? latencyMs + inference.averageQueueWaitMs
|
|
513
|
+
: latencyMs ?? inference.averageQueueWaitMs;
|
|
514
|
+
const latency = effectiveLatencyMs === undefined ? 0.75 : 1 / (1 + effectiveLatencyMs / 3000);
|
|
515
|
+
const cost = costUsd !== undefined
|
|
516
|
+
? 1 / (1 + costUsd * 100)
|
|
517
|
+
: inference.averageTotalTokens !== undefined
|
|
518
|
+
? 1 / (1 + inference.averageTotalTokens / 10000)
|
|
519
|
+
: 0.75;
|
|
520
|
+
const availability = average(rawRecords.map(availabilityForRecord)) ?? 0;
|
|
521
|
+
const confidence = average(rawRecords.map(confidenceForRecord)) ?? 0;
|
|
522
|
+
const failureRate = average(rawRecords.map(failurePenalty)) ?? 0;
|
|
523
|
+
const fallbackRate = average(rawRecords.map(fallbackRateForRecord)) ?? 0;
|
|
524
|
+
const fallbackReliability = 1 - fallbackRate;
|
|
525
|
+
const finalScore = quality * 0.24 +
|
|
526
|
+
toolAccuracy * 0.16 +
|
|
527
|
+
schemaSuccess * 0.16 +
|
|
528
|
+
latency * 0.12 +
|
|
529
|
+
cost * 0.10 +
|
|
530
|
+
availability * 0.12 +
|
|
531
|
+
confidence * 0.08 +
|
|
532
|
+
fallbackReliability * 0.02;
|
|
533
|
+
return {
|
|
534
|
+
quality: clamp01(quality),
|
|
535
|
+
toolAccuracy: clamp01(toolAccuracy),
|
|
536
|
+
schemaSuccess: clamp01(schemaSuccess),
|
|
537
|
+
latency: clamp01(latency),
|
|
538
|
+
cost: clamp01(cost),
|
|
539
|
+
availability: clamp01(availability),
|
|
540
|
+
confidence: clamp01(confidence),
|
|
541
|
+
fallbackReliability: clamp01(fallbackReliability),
|
|
542
|
+
finalScore: clamp01(finalScore),
|
|
543
|
+
sampleCount,
|
|
544
|
+
shadowSampleCount: rawRecords.filter((record) => record.comparisonRole === "shadow").length,
|
|
545
|
+
selectedByPolicyCount: rawRecords.filter((record) => record.selectedByPolicy).length,
|
|
546
|
+
...(latencyMs !== undefined ? { averageLatencyMs: latencyMs } : {}),
|
|
547
|
+
...(costUsd !== undefined ? { averageCostUsd: costUsd } : {}),
|
|
548
|
+
inference,
|
|
549
|
+
failureRate: clamp01(failureRate),
|
|
550
|
+
fallbackRate: clamp01(fallbackRate),
|
|
551
|
+
};
|
|
552
|
+
};
|
|
553
|
+
const aggregateEvidence = (records) => {
|
|
554
|
+
const groups = new Map();
|
|
555
|
+
for (const entry of records) {
|
|
556
|
+
const key = aggregateKeyForRecord(entry.record);
|
|
557
|
+
groups.set(key, [...(groups.get(key) ?? []), entry]);
|
|
558
|
+
}
|
|
559
|
+
return [...groups.entries()].map(([key, group]) => {
|
|
560
|
+
const first = group[0]?.record;
|
|
561
|
+
if (!first) {
|
|
562
|
+
throw new Error(`Empty model-router aggregate ${key}.`);
|
|
563
|
+
}
|
|
564
|
+
const comparisonRole = group.every((entry) => entry.record.comparisonRole === "primary")
|
|
565
|
+
? "primary"
|
|
566
|
+
: group.every((entry) => entry.record.comparisonRole === "shadow")
|
|
567
|
+
? "shadow"
|
|
568
|
+
: "mixed";
|
|
569
|
+
return {
|
|
570
|
+
routeKey: routeKeyForRecord(first),
|
|
571
|
+
role: first.role,
|
|
572
|
+
resolverRole: first.resolverRole,
|
|
573
|
+
identity: {
|
|
574
|
+
...identityForRecord(first),
|
|
575
|
+
comparisonRole,
|
|
576
|
+
},
|
|
577
|
+
records: group,
|
|
578
|
+
scorecard: metricScorecardForRecords(group),
|
|
579
|
+
};
|
|
580
|
+
}).sort((left, right) => left.routeKey.localeCompare(right.routeKey) ||
|
|
581
|
+
right.scorecard.finalScore - left.scorecard.finalScore);
|
|
582
|
+
};
|
|
583
|
+
const sourceRecordIdsForAggregate = (aggregate) => uniqueSorted(aggregate?.records.map((entry) => entry.rowRecordId) ?? []);
|
|
584
|
+
const gatewayRecordIdsForAggregate = (aggregate) => uniqueSorted(aggregate?.records.map((entry) => entry.sourceGatewayRecordId) ?? []);
|
|
585
|
+
const comparisonRecordIdsForAggregate = (aggregate) => uniqueSorted(aggregate?.records.map((entry) => entry.record.id) ?? []);
|
|
586
|
+
const finalSynthesisRouteSignal = (value) => value.includes("large_final") ||
|
|
587
|
+
value.includes("final_synth") ||
|
|
588
|
+
value.includes("final_answer_large_model") ||
|
|
589
|
+
value === "final";
|
|
590
|
+
const isFinalSynthesisRoute = (route) => route.some((aggregate) => {
|
|
591
|
+
const routeSignals = [
|
|
592
|
+
aggregate.role,
|
|
593
|
+
aggregate.resolverRole,
|
|
594
|
+
...aggregate.records.map((entry) => entry.record.scenarioId),
|
|
595
|
+
]
|
|
596
|
+
.filter((value) => typeof value === "string")
|
|
597
|
+
.map(normalizeToken);
|
|
598
|
+
const tier = normalizeToken(aggregate.identity.tier ?? "");
|
|
599
|
+
return routeSignals.some(finalSynthesisRouteSignal) ||
|
|
600
|
+
(tier === "large" && routeSignals.some((value) => value.includes("final")));
|
|
601
|
+
});
|
|
602
|
+
const isConstrainedWorkerRoute = (route) => route.some((aggregate) => [aggregate.role, aggregate.resolverRole]
|
|
603
|
+
.map(normalizeToken)
|
|
604
|
+
.some((value) => value.includes("small_json") ||
|
|
605
|
+
value.includes("extract") ||
|
|
606
|
+
value.includes("repair") ||
|
|
607
|
+
value.includes("router") ||
|
|
608
|
+
value.includes("tool") ||
|
|
609
|
+
value.includes("schema") ||
|
|
610
|
+
value.includes("json") ||
|
|
611
|
+
value.includes("constrained") ||
|
|
612
|
+
value.includes("verifier")));
|
|
613
|
+
const isLocalOrSelfHosted = (aggregate) => {
|
|
614
|
+
const source = normalizeToken(aggregate.identity.source ?? "");
|
|
615
|
+
const adapter = normalizeToken(aggregate.identity.adapter ?? "");
|
|
616
|
+
return source === "local" ||
|
|
617
|
+
source === "self_hosted" ||
|
|
618
|
+
adapter.includes("ollama") ||
|
|
619
|
+
adapter.includes("llama_cpp") ||
|
|
620
|
+
adapter.includes("local");
|
|
621
|
+
};
|
|
622
|
+
const choosePrimaryAggregate = (aggregates) => aggregates
|
|
623
|
+
.filter((aggregate) => aggregate.records.some((entry) => entry.record.comparisonRole === "primary" ||
|
|
624
|
+
entry.record.primary ||
|
|
625
|
+
entry.record.selectedByPolicy))
|
|
626
|
+
.sort((left, right) => right.scorecard.selectedByPolicyCount - left.scorecard.selectedByPolicyCount ||
|
|
627
|
+
right.scorecard.sampleCount - left.scorecard.sampleCount ||
|
|
628
|
+
right.scorecard.finalScore - left.scorecard.finalScore)[0];
|
|
629
|
+
const chooseShadowAggregate = (aggregates, primary, constrainedWorker) => {
|
|
630
|
+
const shadows = aggregates
|
|
631
|
+
.filter((aggregate) => aggregate.scorecard.shadowSampleCount > 0)
|
|
632
|
+
.sort((left, right) => right.scorecard.finalScore - left.scorecard.finalScore);
|
|
633
|
+
if (!constrainedWorker || !primary)
|
|
634
|
+
return shadows[0];
|
|
635
|
+
const local = shadows
|
|
636
|
+
.filter(isLocalOrSelfHosted)
|
|
637
|
+
.filter((aggregate) => aggregate.scorecard.finalScore >=
|
|
638
|
+
primary.scorecard.finalScore + LOCAL_PREFERENCE_SCORE_DELTA_THRESHOLD)
|
|
639
|
+
.sort((left, right) => right.scorecard.finalScore - left.scorecard.finalScore)[0];
|
|
640
|
+
return local ?? shadows[0];
|
|
641
|
+
};
|
|
642
|
+
const routeCandidateForAggregates = (routeKey, aggregates) => {
|
|
643
|
+
const primary = choosePrimaryAggregate(aggregates);
|
|
644
|
+
const constrainedWorker = isConstrainedWorkerRoute(aggregates);
|
|
645
|
+
const shadow = chooseShadowAggregate(aggregates, primary, constrainedWorker);
|
|
646
|
+
const finalRoute = isFinalSynthesisRoute(aggregates);
|
|
647
|
+
const blockedReasons = [];
|
|
648
|
+
if (!primary)
|
|
649
|
+
blockedReasons.push("primary_evidence_missing");
|
|
650
|
+
if (!shadow)
|
|
651
|
+
blockedReasons.push("shadow_evidence_required");
|
|
652
|
+
if (finalRoute)
|
|
653
|
+
blockedReasons.push("final_synthesis_large_model_preserved");
|
|
654
|
+
if (shadow && shadow.scorecard.confidence < MIN_SHADOW_CONFIDENCE) {
|
|
655
|
+
blockedReasons.push("shadow_confidence_below_threshold");
|
|
656
|
+
}
|
|
657
|
+
if (shadow && shadow.scorecard.schemaSuccess < MIN_SHADOW_SCHEMA_SUCCESS) {
|
|
658
|
+
blockedReasons.push("shadow_schema_success_below_threshold");
|
|
659
|
+
}
|
|
660
|
+
if (shadow && shadow.scorecard.availability < MIN_SHADOW_AVAILABILITY) {
|
|
661
|
+
blockedReasons.push("shadow_availability_below_threshold");
|
|
662
|
+
}
|
|
663
|
+
const scoreDelta = primary && shadow
|
|
664
|
+
? shadow.scorecard.finalScore - primary.scorecard.finalScore
|
|
665
|
+
: undefined;
|
|
666
|
+
if (scoreDelta !== undefined && scoreDelta < SCORE_DELTA_THRESHOLD && !finalRoute) {
|
|
667
|
+
blockedReasons.push("shadow_score_delta_insufficient");
|
|
668
|
+
}
|
|
669
|
+
const canPropose = Boolean(primary && shadow && !finalRoute && blockedReasons.length === 0);
|
|
670
|
+
const action = canPropose
|
|
671
|
+
? "propose_shadow_route"
|
|
672
|
+
: finalRoute
|
|
673
|
+
? "preserve_current"
|
|
674
|
+
: "no_change";
|
|
675
|
+
const status = canPropose ? "proposed" : finalRoute ? "no_change" : "blocked";
|
|
676
|
+
const evidenceAggregates = [primary, shadow].filter((value) => Boolean(value));
|
|
677
|
+
return {
|
|
678
|
+
routeId: stableId("router-route", {
|
|
679
|
+
routeKey,
|
|
680
|
+
primary: primary?.identity.identityKey,
|
|
681
|
+
shadow: shadow?.identity.identityKey,
|
|
682
|
+
}),
|
|
683
|
+
role: primary?.role ?? shadow?.role ?? aggregates[0]?.role ?? routeKey.split("::")[0] ?? "unknown",
|
|
684
|
+
resolverRole: primary?.resolverRole ??
|
|
685
|
+
shadow?.resolverRole ??
|
|
686
|
+
aggregates[0]?.resolverRole ??
|
|
687
|
+
routeKey.split("::")[1] ??
|
|
688
|
+
"unknown",
|
|
689
|
+
action,
|
|
690
|
+
status,
|
|
691
|
+
...(primary ? { current: primary.identity } : {}),
|
|
692
|
+
...(canPropose && shadow ? { proposed: shadow.identity } : {}),
|
|
693
|
+
...(scoreDelta !== undefined ? { scoreDelta } : {}),
|
|
694
|
+
...(primary ? { primaryScorecard: primary.scorecard } : {}),
|
|
695
|
+
...(shadow ? { proposedScorecard: shadow.scorecard } : {}),
|
|
696
|
+
blockedReasons: uniqueSorted(blockedReasons),
|
|
697
|
+
evidence: {
|
|
698
|
+
sourceRecordIds: uniqueSorted(evidenceAggregates.flatMap(sourceRecordIdsForAggregate)),
|
|
699
|
+
sourceGatewayRecordIds: uniqueSorted(evidenceAggregates.flatMap(gatewayRecordIdsForAggregate)),
|
|
700
|
+
comparisonRecordIds: uniqueSorted(evidenceAggregates.flatMap(comparisonRecordIdsForAggregate)),
|
|
701
|
+
primarySampleCount: primary?.scorecard.sampleCount ?? 0,
|
|
702
|
+
shadowSampleCount: shadow?.scorecard.shadowSampleCount ?? 0,
|
|
703
|
+
scorecardSampleCount: evidenceAggregates.reduce((total, aggregate) => total + aggregate.scorecard.sampleCount, 0),
|
|
704
|
+
shadowEvidenceRequired: true,
|
|
705
|
+
shadowEvidencePresent: Boolean(shadow),
|
|
706
|
+
},
|
|
707
|
+
rollbackPlan: {
|
|
708
|
+
reversible: true,
|
|
709
|
+
...(primary ? { restoreIdentity: primary.identity } : {}),
|
|
710
|
+
...(canPropose && shadow ? { removeCandidateIdentity: shadow.identity } : {}),
|
|
711
|
+
steps: canPropose
|
|
712
|
+
? [
|
|
713
|
+
"Apply candidate behind an explicit router policy flag.",
|
|
714
|
+
"Restore the captured current identity if scorecards regress.",
|
|
715
|
+
"Remove the candidate identity from the router policy to roll back.",
|
|
716
|
+
]
|
|
717
|
+
: [
|
|
718
|
+
"No runtime router mutation was produced.",
|
|
719
|
+
"Keep current router policy unchanged.",
|
|
720
|
+
],
|
|
721
|
+
},
|
|
722
|
+
};
|
|
723
|
+
};
|
|
724
|
+
const buildEvidenceRecords = (rows) => rows.flatMap((input) => comparisonRecordsForRow(input.row).map((record) => ({
|
|
725
|
+
rowRecordId: input.accepted.recordId,
|
|
726
|
+
...(input.accepted.sourceGatewayRecordId
|
|
727
|
+
? { sourceGatewayRecordId: input.accepted.sourceGatewayRecordId }
|
|
728
|
+
: {}),
|
|
729
|
+
record,
|
|
730
|
+
})));
|
|
731
|
+
const buildRouteCandidates = (records) => {
|
|
732
|
+
const aggregates = aggregateEvidence(records);
|
|
733
|
+
const byRoute = new Map();
|
|
734
|
+
for (const aggregate of aggregates) {
|
|
735
|
+
byRoute.set(aggregate.routeKey, [...(byRoute.get(aggregate.routeKey) ?? []), aggregate]);
|
|
736
|
+
}
|
|
737
|
+
return [...byRoute.entries()]
|
|
738
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
739
|
+
.map(([routeKey, routeAggregates]) => routeCandidateForAggregates(routeKey, routeAggregates));
|
|
740
|
+
};
|
|
741
|
+
const planForRoutes = (inspection, routeCandidates, comparisonRecordCount) => {
|
|
742
|
+
const proposedRouteCount = routeCandidates.filter((route) => route.status === "proposed").length;
|
|
743
|
+
const preservedRouteCount = routeCandidates.filter((route) => route.action === "preserve_current").length;
|
|
744
|
+
const reasons = uniqueSorted([
|
|
745
|
+
...(comparisonRecordCount === 0 ? ["comparison_evidence_missing"] : []),
|
|
746
|
+
...(inspection.curationReport.acceptedCount === 0 ? ["accepted_examples_missing"] : []),
|
|
747
|
+
...routeCandidates.flatMap((route) => route.blockedReasons),
|
|
748
|
+
]);
|
|
749
|
+
return {
|
|
750
|
+
planId: stableId("model-router-plan", {
|
|
751
|
+
exportId: inspection.exportId,
|
|
752
|
+
checksum: inspection.provenance.checksum,
|
|
753
|
+
routeIds: routeCandidates.map((route) => route.routeId),
|
|
754
|
+
}),
|
|
755
|
+
action: proposedRouteCount > 0 ? "propose_shadow_route" : "no_change",
|
|
756
|
+
status: proposedRouteCount > 0 ? "proposed" : "blocked",
|
|
757
|
+
reasons,
|
|
758
|
+
routeCount: routeCandidates.length,
|
|
759
|
+
proposedRouteCount,
|
|
760
|
+
preservedRouteCount,
|
|
761
|
+
noChangeRouteCount: routeCandidates.filter((route) => route.status !== "proposed").length,
|
|
762
|
+
reversible: true,
|
|
763
|
+
requiresShadowEvidence: true,
|
|
764
|
+
productionRouterChangeAllowed: false,
|
|
765
|
+
};
|
|
766
|
+
};
|
|
767
|
+
const candidateSummary = (inspection, routerPlan, sourceExamples) => {
|
|
768
|
+
const status = routerPlan.action === "propose_shadow_route"
|
|
769
|
+
? "proposed"
|
|
770
|
+
: "no_change";
|
|
771
|
+
return {
|
|
772
|
+
candidateId: stableId("model-router-candidate", {
|
|
773
|
+
planId: routerPlan.planId,
|
|
774
|
+
exportId: inspection.exportId,
|
|
775
|
+
checksum: inspection.provenance.checksum,
|
|
776
|
+
}),
|
|
777
|
+
candidateKind: "model_router",
|
|
778
|
+
status,
|
|
779
|
+
sourceExportIds: [inspection.exportId],
|
|
780
|
+
sourceRecordIds: inspection.provenance.sourceRecordIds,
|
|
781
|
+
artifactIds: inspection.provenance.artifactRefs.map((ref) => ref.refId),
|
|
782
|
+
exampleCount: sourceExamples.length,
|
|
783
|
+
objectBytes: inspection.provenance.artifactRefs.reduce((total, ref) => total + ref.byteSize, 0),
|
|
784
|
+
routeCount: routerPlan.routeCount,
|
|
785
|
+
proposedRouteCount: routerPlan.proposedRouteCount,
|
|
786
|
+
blockedReasons: routerPlan.action === "no_change" ? routerPlan.reasons : [],
|
|
787
|
+
};
|
|
788
|
+
};
|
|
789
|
+
export const buildCodaliModelRouterCandidateBundle = (input) => {
|
|
790
|
+
const artifact = input.artifact ?? CODALI_MODEL_ROUTER_PROPOSAL_ARTIFACT;
|
|
791
|
+
const rows = acceptedRows(input.inspection);
|
|
792
|
+
const sourceExamples = rows.map(sourceExampleForRow);
|
|
793
|
+
const evidenceRecords = buildEvidenceRecords(rows);
|
|
794
|
+
const routeCandidates = buildRouteCandidates(evidenceRecords);
|
|
795
|
+
const routerPlan = planForRoutes(input.inspection, routeCandidates, evidenceRecords.length);
|
|
796
|
+
const roles = uniqueSorted(evidenceRecords.map((entry) => entry.record.resolverRole));
|
|
797
|
+
return {
|
|
798
|
+
schemaVersion: CODALI_MODEL_ROUTER_CANDIDATE_SCHEMA_VERSION,
|
|
799
|
+
artifact,
|
|
800
|
+
source: {
|
|
801
|
+
exportId: input.inspection.exportId,
|
|
802
|
+
manifestId: input.inspection.provenance.manifestId,
|
|
803
|
+
manifestPath: input.inspection.manifestPath,
|
|
804
|
+
exportKind: input.inspection.provenance.exportKind,
|
|
805
|
+
checksum: input.inspection.provenance.checksum,
|
|
806
|
+
recordCount: input.inspection.provenance.recordCount,
|
|
807
|
+
...(input.inspection.primaryArtifact
|
|
808
|
+
? { primaryArtifactRef: objectRefSummary(input.inspection.primaryArtifact.ref) }
|
|
809
|
+
: {}),
|
|
810
|
+
},
|
|
811
|
+
generationPolicy: {
|
|
812
|
+
deterministic: true,
|
|
813
|
+
dryRunOnly: true,
|
|
814
|
+
modifiesRuntimePrompts: false,
|
|
815
|
+
modifiesRuntimeCode: false,
|
|
816
|
+
modifiesRuntimeRouter: false,
|
|
817
|
+
productionRouterChangeAllowed: false,
|
|
818
|
+
requiresShadowEvidence: true,
|
|
819
|
+
reversible: true,
|
|
820
|
+
uploadEnabled: false,
|
|
821
|
+
preservesFinalSynthesisRoute: true,
|
|
822
|
+
finalSynthesizerFineTuning: false,
|
|
823
|
+
},
|
|
824
|
+
expectedShape: {
|
|
825
|
+
schemaVersion: CODALI_MODEL_ROUTER_CANDIDATE_SCHEMA_VERSION,
|
|
826
|
+
artifact,
|
|
827
|
+
requiredFields: [
|
|
828
|
+
"schemaVersion",
|
|
829
|
+
"artifact",
|
|
830
|
+
"generationPolicy",
|
|
831
|
+
"evidenceSummary",
|
|
832
|
+
"routerPlan",
|
|
833
|
+
"routeCandidates",
|
|
834
|
+
"candidates",
|
|
835
|
+
],
|
|
836
|
+
routeCandidateRequiredFields: [
|
|
837
|
+
"routeId",
|
|
838
|
+
"role",
|
|
839
|
+
"resolverRole",
|
|
840
|
+
"action",
|
|
841
|
+
"evidence",
|
|
842
|
+
"rollbackPlan",
|
|
843
|
+
],
|
|
844
|
+
scorecardFields: [
|
|
845
|
+
"quality",
|
|
846
|
+
"toolAccuracy",
|
|
847
|
+
"schemaSuccess",
|
|
848
|
+
"latency",
|
|
849
|
+
"cost",
|
|
850
|
+
"availability",
|
|
851
|
+
"confidence",
|
|
852
|
+
"fallbackReliability",
|
|
853
|
+
"fallbackRate",
|
|
854
|
+
"inference",
|
|
855
|
+
"finalScore",
|
|
856
|
+
],
|
|
857
|
+
},
|
|
858
|
+
sourceExamples,
|
|
859
|
+
evidenceSummary: {
|
|
860
|
+
comparisonRecordCount: evidenceRecords.length,
|
|
861
|
+
primaryRecordCount: evidenceRecords.filter((entry) => entry.record.comparisonRole === "primary").length,
|
|
862
|
+
shadowRecordCount: evidenceRecords.filter((entry) => entry.record.comparisonRole === "shadow").length,
|
|
863
|
+
roleCount: roles.length,
|
|
864
|
+
roles,
|
|
865
|
+
metricInputs: [
|
|
866
|
+
"quality",
|
|
867
|
+
"tool_accuracy",
|
|
868
|
+
"schema_success",
|
|
869
|
+
"latency",
|
|
870
|
+
"cost",
|
|
871
|
+
"availability",
|
|
872
|
+
"confidence",
|
|
873
|
+
"fallback_rate",
|
|
874
|
+
],
|
|
875
|
+
},
|
|
876
|
+
routerPlan,
|
|
877
|
+
routeCandidates,
|
|
878
|
+
candidates: [candidateSummary(input.inspection, routerPlan, sourceExamples)],
|
|
879
|
+
};
|
|
880
|
+
};
|