@mcoda/mswarm 0.1.90 → 0.1.94

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 (113) hide show
  1. package/dist/codali-executor.d.ts +107 -6
  2. package/dist/codali-executor.d.ts.map +1 -1
  3. package/dist/codali-executor.js +500 -26
  4. package/dist/codali-executor.js.map +1 -1
  5. package/dist/runtime.d.ts +4 -2
  6. package/dist/runtime.d.ts.map +1 -1
  7. package/dist/runtime.js +18 -5
  8. package/dist/runtime.js.map +1 -1
  9. package/dist/vendor/codali/cli/DatasetCommand.d.ts +38 -0
  10. package/dist/vendor/codali/cli/DatasetCommand.d.ts.map +1 -0
  11. package/dist/vendor/codali/cli/DatasetCommand.js +959 -0
  12. package/dist/vendor/codali/cli/EvalCommand.d.ts +3 -0
  13. package/dist/vendor/codali/cli/EvalCommand.d.ts.map +1 -1
  14. package/dist/vendor/codali/cli/EvalCommand.js +55 -1
  15. package/dist/vendor/codali/cli/ImprovementCommand.d.ts +97 -0
  16. package/dist/vendor/codali/cli/ImprovementCommand.d.ts.map +1 -0
  17. package/dist/vendor/codali/cli/ImprovementCommand.js +1879 -0
  18. package/dist/vendor/codali/cli.d.ts.map +1 -1
  19. package/dist/vendor/codali/cli.js +15 -0
  20. package/dist/vendor/codali/dataset-cli.d.ts +3 -0
  21. package/dist/vendor/codali/dataset-cli.d.ts.map +1 -0
  22. package/dist/vendor/codali/dataset-cli.js +30 -0
  23. package/dist/vendor/codali/eval/CodaliGatewayLiveHarness.d.ts +90 -1
  24. package/dist/vendor/codali/eval/CodaliGatewayLiveHarness.d.ts.map +1 -1
  25. package/dist/vendor/codali/eval/CodaliGatewayLiveHarness.js +443 -9
  26. package/dist/vendor/codali/eval/GatewayDatasetEval.d.ts +70 -0
  27. package/dist/vendor/codali/eval/GatewayDatasetEval.d.ts.map +1 -0
  28. package/dist/vendor/codali/eval/GatewayDatasetEval.js +477 -0
  29. package/dist/vendor/codali/eval/GatewayEvalSuite.d.ts +52 -0
  30. package/dist/vendor/codali/eval/GatewayEvalSuite.d.ts.map +1 -1
  31. package/dist/vendor/codali/eval/GatewayEvalSuite.js +135 -1
  32. package/dist/vendor/codali/gateway/CodaliGateway.d.ts +4 -0
  33. package/dist/vendor/codali/gateway/CodaliGateway.d.ts.map +1 -1
  34. package/dist/vendor/codali/gateway/CodaliGateway.js +37 -1
  35. package/dist/vendor/codali/gateway/CodaliGatewaySchemas.d.ts.map +1 -1
  36. package/dist/vendor/codali/gateway/CodaliGatewaySchemas.js +0 -4
  37. package/dist/vendor/codali/gateway/CodaliGatewayStore.d.ts.map +1 -1
  38. package/dist/vendor/codali/gateway/CodaliGatewayStore.js +1 -0
  39. package/dist/vendor/codali/gateway/GatewayPlanner.d.ts.map +1 -1
  40. package/dist/vendor/codali/gateway/GatewayPlanner.js +355 -41
  41. package/dist/vendor/codali/gateway/GatewayStateMachine.d.ts +1 -0
  42. package/dist/vendor/codali/gateway/GatewayStateMachine.d.ts.map +1 -1
  43. package/dist/vendor/codali/gateway/GatewayStateMachine.js +221 -5
  44. package/dist/vendor/codali/improvement/CandidateReleaseBuilder.d.ts +201 -0
  45. package/dist/vendor/codali/improvement/CandidateReleaseBuilder.d.ts.map +1 -0
  46. package/dist/vendor/codali/improvement/CandidateReleaseBuilder.js +1175 -0
  47. package/dist/vendor/codali/improvement/DatasetEligibilityGate.d.ts +75 -0
  48. package/dist/vendor/codali/improvement/DatasetEligibilityGate.d.ts.map +1 -0
  49. package/dist/vendor/codali/improvement/DatasetEligibilityGate.js +497 -0
  50. package/dist/vendor/codali/improvement/DatasetExportManifestReader.d.ts +88 -0
  51. package/dist/vendor/codali/improvement/DatasetExportManifestReader.d.ts.map +1 -0
  52. package/dist/vendor/codali/improvement/DatasetExportManifestReader.js +333 -0
  53. package/dist/vendor/codali/improvement/DocdexRetrievalCandidateBuilder.d.ts +192 -0
  54. package/dist/vendor/codali/improvement/DocdexRetrievalCandidateBuilder.d.ts.map +1 -0
  55. package/dist/vendor/codali/improvement/DocdexRetrievalCandidateBuilder.js +625 -0
  56. package/dist/vendor/codali/improvement/EvalReplayCandidateBuilder.d.ts +173 -0
  57. package/dist/vendor/codali/improvement/EvalReplayCandidateBuilder.d.ts.map +1 -0
  58. package/dist/vendor/codali/improvement/EvalReplayCandidateBuilder.js +363 -0
  59. package/dist/vendor/codali/improvement/FineTuneJobPlanner.d.ts +281 -0
  60. package/dist/vendor/codali/improvement/FineTuneJobPlanner.d.ts.map +1 -0
  61. package/dist/vendor/codali/improvement/FineTuneJobPlanner.js +823 -0
  62. package/dist/vendor/codali/improvement/ImprovementEvalRunner.d.ts +50 -0
  63. package/dist/vendor/codali/improvement/ImprovementEvalRunner.d.ts.map +1 -0
  64. package/dist/vendor/codali/improvement/ImprovementEvalRunner.js +648 -0
  65. package/dist/vendor/codali/improvement/ImprovementPolicy.d.ts +272 -0
  66. package/dist/vendor/codali/improvement/ImprovementPolicy.d.ts.map +1 -0
  67. package/dist/vendor/codali/improvement/ImprovementPolicy.js +1450 -0
  68. package/dist/vendor/codali/improvement/ModelRouterCandidateBuilder.d.ts +186 -0
  69. package/dist/vendor/codali/improvement/ModelRouterCandidateBuilder.d.ts.map +1 -0
  70. package/dist/vendor/codali/improvement/ModelRouterCandidateBuilder.js +880 -0
  71. package/dist/vendor/codali/improvement/OperatorInspector.d.ts +182 -0
  72. package/dist/vendor/codali/improvement/OperatorInspector.d.ts.map +1 -0
  73. package/dist/vendor/codali/improvement/OperatorInspector.js +604 -0
  74. package/dist/vendor/codali/improvement/ProductionGovernance.d.ts +91 -0
  75. package/dist/vendor/codali/improvement/ProductionGovernance.d.ts.map +1 -0
  76. package/dist/vendor/codali/improvement/ProductionGovernance.js +329 -0
  77. package/dist/vendor/codali/improvement/PromptSchemaToolMetadataCandidateBuilder.d.ts +152 -0
  78. package/dist/vendor/codali/improvement/PromptSchemaToolMetadataCandidateBuilder.d.ts.map +1 -0
  79. package/dist/vendor/codali/improvement/PromptSchemaToolMetadataCandidateBuilder.js +480 -0
  80. package/dist/vendor/codali/improvement/PublishOrchestrator.d.ts +113 -0
  81. package/dist/vendor/codali/improvement/PublishOrchestrator.d.ts.map +1 -0
  82. package/dist/vendor/codali/improvement/PublishOrchestrator.js +590 -0
  83. package/dist/vendor/codali/improvement/ReleaseOutcomeReporter.d.ts +133 -0
  84. package/dist/vendor/codali/improvement/ReleaseOutcomeReporter.d.ts.map +1 -0
  85. package/dist/vendor/codali/improvement/ReleaseOutcomeReporter.js +501 -0
  86. package/dist/vendor/codali/improvement/StorageServiceImprovementClient.d.ts +71 -0
  87. package/dist/vendor/codali/improvement/StorageServiceImprovementClient.d.ts.map +1 -0
  88. package/dist/vendor/codali/improvement/StorageServiceImprovementClient.js +245 -0
  89. package/dist/vendor/codali/index.d.ts +43 -0
  90. package/dist/vendor/codali/index.d.ts.map +1 -1
  91. package/dist/vendor/codali/index.js +21 -0
  92. package/dist/vendor/codali/runtime/CodaliRuntime.d.ts +0 -2
  93. package/dist/vendor/codali/runtime/CodaliRuntime.d.ts.map +1 -1
  94. package/dist/vendor/codali/runtime/CodaliRuntime.js +0 -5
  95. package/dist/vendor/codali/storage/CodaliDatasetPrivacyEngine.d.ts +138 -0
  96. package/dist/vendor/codali/storage/CodaliDatasetPrivacyEngine.d.ts.map +1 -0
  97. package/dist/vendor/codali/storage/CodaliDatasetPrivacyEngine.js +417 -0
  98. package/dist/vendor/codali/storage/CodaliFeedbackReviewIngestion.d.ts +50 -0
  99. package/dist/vendor/codali/storage/CodaliFeedbackReviewIngestion.d.ts.map +1 -0
  100. package/dist/vendor/codali/storage/CodaliFeedbackReviewIngestion.js +141 -0
  101. package/dist/vendor/codali/storage/CodaliStorageContracts.d.ts +337 -0
  102. package/dist/vendor/codali/storage/CodaliStorageContracts.d.ts.map +1 -0
  103. package/dist/vendor/codali/storage/CodaliStorageContracts.js +1555 -0
  104. package/dist/vendor/codali/storage/DatasetExportJob.d.ts +51 -0
  105. package/dist/vendor/codali/storage/DatasetExportJob.d.ts.map +1 -0
  106. package/dist/vendor/codali/storage/DatasetExportJob.js +358 -0
  107. package/dist/vendor/codali/storage/DatasetReviewQueue.d.ts +98 -0
  108. package/dist/vendor/codali/storage/DatasetReviewQueue.d.ts.map +1 -0
  109. package/dist/vendor/codali/storage/DatasetReviewQueue.js +426 -0
  110. package/dist/vendor/codali/storage/GatewayDatasetStore.d.ts +233 -0
  111. package/dist/vendor/codali/storage/GatewayDatasetStore.d.ts.map +1 -0
  112. package/dist/vendor/codali/storage/GatewayDatasetStore.js +2070 -0
  113. package/package.json +3 -3
@@ -0,0 +1,823 @@
1
+ import { createHash } from "node:crypto";
2
+ import { resolveCodaliGatewayAgentTiers, } from "../gateway/AgentTierResolver.js";
3
+ export const CODALI_FINE_TUNE_JOB_PLANNER_SCHEMA_VERSION = "codali.improvement.fine_tune_job_planner.v1";
4
+ export const CODALI_FINE_TUNE_PROPOSAL_ARTIFACT = "fine-tune";
5
+ export const CODALI_FINE_TUNE_WORKER_ROLES = [
6
+ "extractor",
7
+ "tool_router",
8
+ "planner",
9
+ "verifier",
10
+ "query_expander",
11
+ "repair",
12
+ "context_refiner",
13
+ ];
14
+ export const CODALI_FINE_TUNE_FINAL_SYNTHESIZER_ROLE = "final_synthesizer";
15
+ const DEFAULT_INVENTORY_COMMAND = {
16
+ command: "mcoda",
17
+ args: ["agent", "list", "--json", "--refresh-health"],
18
+ };
19
+ const ROLE_SPECS = {
20
+ extractor: {
21
+ resolverRole: "extractor",
22
+ sourceArtifactTypes: ["extractor", "extractor_sft"],
23
+ supportedExportKinds: ["extractor-sft"],
24
+ },
25
+ tool_router: {
26
+ resolverRole: "router",
27
+ sourceArtifactTypes: [
28
+ "router",
29
+ "tool_router",
30
+ "tool_router_sft",
31
+ "model_router",
32
+ "model-router",
33
+ ],
34
+ supportedExportKinds: ["tool-router-sft", "model-router"],
35
+ },
36
+ planner: {
37
+ resolverRole: "planner",
38
+ sourceArtifactTypes: ["planner", "planner_sft"],
39
+ supportedExportKinds: ["planner-sft"],
40
+ },
41
+ verifier: {
42
+ resolverRole: "verifier",
43
+ sourceArtifactTypes: ["verifier", "verifier_sft"],
44
+ supportedExportKinds: ["verifier-sft"],
45
+ },
46
+ query_expander: {
47
+ resolverRole: "query_expander",
48
+ sourceArtifactTypes: [
49
+ "query_expander",
50
+ "query_expander_sft",
51
+ "rag_reranker",
52
+ "rag-reranker",
53
+ ],
54
+ supportedExportKinds: ["query-expander-sft", "rag-reranker"],
55
+ },
56
+ repair: {
57
+ resolverRole: "repair",
58
+ sourceArtifactTypes: ["repair", "repair_sft"],
59
+ supportedExportKinds: ["repair-sft"],
60
+ },
61
+ context_refiner: {
62
+ resolverRole: "context_refiner",
63
+ sourceArtifactTypes: ["context_refiner", "context_refiner_sft"],
64
+ supportedExportKinds: ["context-refiner-sft"],
65
+ },
66
+ final_synthesizer: {
67
+ resolverRole: "final_synthesizer",
68
+ sourceArtifactTypes: ["final_synthesizer", "final_synthesizer_sft"],
69
+ supportedExportKinds: [],
70
+ },
71
+ };
72
+ const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
73
+ const stableJson = (value) => {
74
+ if (Array.isArray(value))
75
+ return `[${value.map(stableJson).join(",")}]`;
76
+ if (!isRecord(value))
77
+ return JSON.stringify(value);
78
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`;
79
+ };
80
+ const sha256Hex = (value) => createHash("sha256").update(stableJson(value)).digest("hex");
81
+ const stableId = (prefix, value) => `${prefix}-${sha256Hex(value).slice(0, 16)}`;
82
+ const normalizeToken = (value) => value.trim().toLowerCase().replace(/[\s-]+/g, "_");
83
+ const uniqueSorted = (values) => Array.from(new Set(values
84
+ .map((value) => value?.trim())
85
+ .filter((value) => Boolean(value))))
86
+ .sort();
87
+ const normalizedUniqueSorted = (values) => uniqueSorted(values.map((value) => value ? normalizeToken(value) : undefined));
88
+ const readString = (record, keys) => {
89
+ for (const key of keys) {
90
+ const value = record?.[key];
91
+ if (typeof value === "string" && value.trim())
92
+ return value.trim();
93
+ }
94
+ return undefined;
95
+ };
96
+ const readNumber = (record, keys) => {
97
+ for (const key of keys) {
98
+ const value = record?.[key];
99
+ if (typeof value === "number" && Number.isFinite(value))
100
+ return value;
101
+ if (typeof value === "string" && value.trim() && Number.isFinite(Number(value))) {
102
+ return Number(value);
103
+ }
104
+ }
105
+ return undefined;
106
+ };
107
+ const objectRefFromValue = (value) => isRecord(value) &&
108
+ typeof value.refId === "string" &&
109
+ typeof value.contentHash === "string" &&
110
+ typeof value.byteSize === "number" &&
111
+ typeof value.mimeType === "string" &&
112
+ typeof value.deletionGroupId === "string" &&
113
+ isRecord(value.privacyFlags)
114
+ ? value
115
+ : undefined;
116
+ const refsForRow = (row) => {
117
+ const evidenceRefs = Array.isArray(row?.evidenceRefs)
118
+ ? row.evidenceRefs.map(objectRefFromValue)
119
+ .filter((ref) => Boolean(ref))
120
+ : [];
121
+ return {
122
+ inputRef: objectRefFromValue(row?.inputRef),
123
+ outputRef: objectRefFromValue(row?.outputRef),
124
+ evidenceRefs,
125
+ };
126
+ };
127
+ const allRefsForRow = (row) => {
128
+ const refs = refsForRow(row);
129
+ return [refs.inputRef, refs.outputRef, ...refs.evidenceRefs]
130
+ .filter((ref) => Boolean(ref));
131
+ };
132
+ const summarizeObjectRef = (ref) => ({
133
+ refId: ref.refId,
134
+ kind: ref.kind,
135
+ contentHash: ref.contentHash,
136
+ byteSize: ref.byteSize,
137
+ mimeType: ref.mimeType,
138
+ deletionGroupId: ref.deletionGroupId,
139
+ privacyFlags: ref.privacyFlags,
140
+ ...(ref.uri ? { uri: ref.uri } : {}),
141
+ ...(ref.mediaType ? { mediaType: ref.mediaType } : {}),
142
+ metadataKeys: isRecord(ref.metadata) ? Object.keys(ref.metadata).sort() : [],
143
+ });
144
+ const recordIdForRow = (row) => isRecord(row) ? readString(row, ["recordId", "record_id"]) : undefined;
145
+ const rowsByRecordId = (rows) => {
146
+ const output = new Map();
147
+ for (const row of rows) {
148
+ if (!isRecord(row))
149
+ continue;
150
+ const recordId = recordIdForRow(row);
151
+ if (recordId)
152
+ output.set(recordId, row);
153
+ }
154
+ return output;
155
+ };
156
+ const metadataForRow = (row) => isRecord(row?.metadata) ? row.metadata : {};
157
+ const privacyForRow = (row) => isRecord(row?.privacy)
158
+ ? row.privacy
159
+ : undefined;
160
+ const nestedRecord = (record, keys) => {
161
+ for (const key of keys) {
162
+ const value = record[key];
163
+ if (isRecord(value))
164
+ return value;
165
+ }
166
+ return {};
167
+ };
168
+ const scorecardMetadataForRow = (row) => {
169
+ const metadata = metadataForRow(row);
170
+ return nestedRecord(metadata, [
171
+ "scorecard",
172
+ "evalScorecard",
173
+ "eval_scorecard",
174
+ "qualityScorecard",
175
+ "quality_scorecard",
176
+ ]);
177
+ };
178
+ const roleSpecFor = (role) => ROLE_SPECS[role];
179
+ export const normalizeCodaliFineTuneWorkerRole = (value) => {
180
+ const normalized = normalizeToken(value);
181
+ if (normalized === "final" || normalized === "synthesizer") {
182
+ return CODALI_FINE_TUNE_FINAL_SYNTHESIZER_ROLE;
183
+ }
184
+ if (normalized === CODALI_FINE_TUNE_FINAL_SYNTHESIZER_ROLE) {
185
+ return CODALI_FINE_TUNE_FINAL_SYNTHESIZER_ROLE;
186
+ }
187
+ return CODALI_FINE_TUNE_WORKER_ROLES.includes(normalized)
188
+ ? normalized
189
+ : undefined;
190
+ };
191
+ export const fineTuneArtifactTypesForRole = (role) => [...roleSpecFor(role).sourceArtifactTypes];
192
+ const jobKindForExportKind = (exportKind) => exportKind === "rag-reranker" || exportKind === "model-router"
193
+ ? "preference"
194
+ : "sft";
195
+ const supportedExportForRole = (role, exportKind) => roleSpecFor(role).supportedExportKinds.includes(exportKind);
196
+ const policyHashFor = (role, exportKind) => `sha256:${sha256Hex({
197
+ role,
198
+ exportKind,
199
+ trainingAllowedRequired: true,
200
+ scorecardRequired: true,
201
+ scorecardBypassAllowed: false,
202
+ finalSynthesizerAllowed: false,
203
+ providerAutoSubmitAllowed: false,
204
+ }).slice(0, 24)}`;
205
+ const hasTrainingPermission = (row, refs) => {
206
+ const privacy = privacyForRow(row);
207
+ return privacy?.trainingAllowed === true &&
208
+ refs.length > 0 &&
209
+ refs.every((ref) => ref.privacyFlags.trainingAllowed === true);
210
+ };
211
+ const privacySummaryForRow = (row, refs) => {
212
+ const privacy = privacyForRow(row);
213
+ return {
214
+ trainingAllowed: true,
215
+ policyTags: uniqueSorted(privacy?.policyTags ?? []),
216
+ containsPersonalData: privacy?.containsPersonalData === true ||
217
+ refs.some((ref) => ref.privacyFlags.containsPersonalData),
218
+ containsTenantPrivateData: refs.some((ref) => ref.privacyFlags.containsTenantPrivateData),
219
+ containsCustomerData: refs.some((ref) => ref.privacyFlags.containsCustomerData),
220
+ containsSourceCode: refs.some((ref) => ref.privacyFlags.containsSourceCode),
221
+ };
222
+ };
223
+ const scorecardMetricDeltas = (scorecard) => {
224
+ const metricNames = new Set();
225
+ for (const key of Object.keys(scorecard)) {
226
+ const normalized = key.replace(/[_-]/g, "");
227
+ const match = normalized.match(/^(.*?)(Before|After|Baseline|Candidate|Delta)$/i);
228
+ if (match?.[1]) {
229
+ metricNames.add(normalizeToken(match[1]));
230
+ }
231
+ }
232
+ const deltas = [];
233
+ for (const metric of [...metricNames].sort()) {
234
+ const before = readNumber(scorecard, [
235
+ `${metric}Before`,
236
+ `${metric}_before`,
237
+ `${metric}Baseline`,
238
+ `${metric}_baseline`,
239
+ ]);
240
+ const after = readNumber(scorecard, [
241
+ `${metric}After`,
242
+ `${metric}_after`,
243
+ `${metric}Candidate`,
244
+ `${metric}_candidate`,
245
+ ]);
246
+ const explicitDelta = readNumber(scorecard, [`${metric}Delta`, `${metric}_delta`]);
247
+ const delta = explicitDelta ?? (before !== undefined && after !== undefined ? after - before : undefined);
248
+ if (before !== undefined || after !== undefined || delta !== undefined) {
249
+ deltas.push({
250
+ metric,
251
+ ...(before !== undefined ? { before } : {}),
252
+ ...(after !== undefined ? { after } : {}),
253
+ ...(delta !== undefined ? { delta: Number(delta.toFixed(6)) } : {}),
254
+ });
255
+ }
256
+ }
257
+ return deltas;
258
+ };
259
+ const scorecardForRow = (accepted, row) => {
260
+ const scorecard = scorecardMetadataForRow(row);
261
+ const metricKeys = Object.keys(scorecard).sort();
262
+ return {
263
+ scorecardId: stableId("fine-tune-scorecard", {
264
+ recordId: accepted.recordId,
265
+ metricKeys,
266
+ lineageKey: accepted.lineageKey,
267
+ }),
268
+ present: metricKeys.length > 0,
269
+ metricKeys,
270
+ metricDeltas: scorecardMetricDeltas(scorecard),
271
+ };
272
+ };
273
+ const tokenEstimateForRefs = (refs) => Math.max(1, Math.ceil(refs.reduce((sum, ref) => sum + ref.byteSize, 0) / 4));
274
+ const sourceExampleForAccepted = (accepted, row) => {
275
+ const refs = refsForRow(row);
276
+ const allRefs = [refs.inputRef, refs.outputRef, ...refs.evidenceRefs]
277
+ .filter((ref) => Boolean(ref));
278
+ if (!hasTrainingPermission(row, allRefs)) {
279
+ return undefined;
280
+ }
281
+ const metadata = metadataForRow(row);
282
+ const scorecard = scorecardForRow(accepted, row);
283
+ return {
284
+ recordId: accepted.recordId,
285
+ ...(accepted.sourceGatewayRecordId ? {
286
+ sourceGatewayRecordId: accepted.sourceGatewayRecordId,
287
+ } : {}),
288
+ artifactTypes: accepted.artifactTypes,
289
+ preferenceSignals: accepted.preferenceSignals.map(String).sort(),
290
+ priorityScore: accepted.priorityScore,
291
+ lineageKey: accepted.lineageKey,
292
+ privacy: privacySummaryForRow(row, allRefs),
293
+ scorecard,
294
+ objectRefs: {
295
+ ...(refs.inputRef ? { inputRef: summarizeObjectRef(refs.inputRef) } : {}),
296
+ ...(refs.outputRef ? { outputRef: summarizeObjectRef(refs.outputRef) } : {}),
297
+ evidenceRefs: refs.evidenceRefs.map(summarizeObjectRef),
298
+ },
299
+ tokenEstimate: tokenEstimateForRefs(allRefs),
300
+ metadataShape: {
301
+ keys: Object.keys(metadata).sort(),
302
+ scorecardKeys: scorecard.metricKeys,
303
+ },
304
+ };
305
+ };
306
+ const buildSourceExampleSet = (inspection) => {
307
+ const rowMap = rowsByRecordId(inspection.primaryArtifactRows);
308
+ const sourceExamples = [];
309
+ const excludedTrainingBlockedRecordIds = [];
310
+ for (const accepted of inspection.curationReport.accepted) {
311
+ const row = rowMap.get(accepted.recordId);
312
+ const refs = allRefsForRow(row);
313
+ if (!hasTrainingPermission(row, refs)) {
314
+ excludedTrainingBlockedRecordIds.push(accepted.recordId);
315
+ continue;
316
+ }
317
+ const sourceExample = sourceExampleForAccepted(accepted, row);
318
+ if (sourceExample)
319
+ sourceExamples.push(sourceExample);
320
+ }
321
+ return {
322
+ sourceExamples: sourceExamples.sort((left, right) => right.priorityScore - left.priorityScore || left.recordId.localeCompare(right.recordId)),
323
+ excludedTrainingBlockedRecordIds: excludedTrainingBlockedRecordIds.sort(),
324
+ };
325
+ };
326
+ const buildTrainingManifest = (inspection, role, jobKind, sourceExamples, excludedTrainingBlockedRecordIds) => {
327
+ const policyHash = policyHashFor(role, inspection.manifest.exportKind);
328
+ const manifestId = stableId("fine-tune-manifest", {
329
+ exportId: inspection.exportId,
330
+ sourceManifestId: inspection.manifest.manifestId,
331
+ checksum: inspection.manifest.checksum,
332
+ role,
333
+ jobKind,
334
+ policyHash,
335
+ recordIds: sourceExamples.map((example) => example.recordId),
336
+ });
337
+ const records = sourceExamples.map((example) => {
338
+ const objectRefHashes = uniqueSorted([
339
+ example.objectRefs.inputRef?.contentHash,
340
+ example.objectRefs.outputRef?.contentHash,
341
+ ...example.objectRefs.evidenceRefs.map((ref) => ref.contentHash),
342
+ ]).map((hash) => `sha256:${hash.replace(/^sha256:/, "")}`);
343
+ return {
344
+ recordId: example.recordId,
345
+ ...(example.sourceGatewayRecordId ? {
346
+ sourceGatewayRecordId: example.sourceGatewayRecordId,
347
+ } : {}),
348
+ lineageKey: example.lineageKey,
349
+ scorecardId: example.scorecard.scorecardId,
350
+ objectRefHashes,
351
+ tokenEstimate: example.tokenEstimate,
352
+ preferenceSignals: example.preferenceSignals,
353
+ priorityScore: example.priorityScore,
354
+ };
355
+ });
356
+ return {
357
+ manifestId,
358
+ jobKind,
359
+ role,
360
+ exportId: inspection.exportId,
361
+ sourceManifestId: inspection.manifest.manifestId,
362
+ sourceChecksum: inspection.manifest.checksum,
363
+ reproducibleFrom: {
364
+ exportId: inspection.exportId,
365
+ sourceManifestId: inspection.manifest.manifestId,
366
+ sourceChecksum: inspection.manifest.checksum,
367
+ policyHash,
368
+ role,
369
+ },
370
+ records,
371
+ rowCount: records.length,
372
+ totalTokenEstimate: records.reduce((sum, record) => sum + record.tokenEstimate, 0),
373
+ excludedTrainingBlockedRecordIds: [...excludedTrainingBlockedRecordIds],
374
+ };
375
+ };
376
+ const averageMetricDeltas = (sourceExamples) => {
377
+ const byMetric = new Map();
378
+ for (const example of sourceExamples) {
379
+ for (const delta of example.scorecard.metricDeltas) {
380
+ if (delta.delta === undefined)
381
+ continue;
382
+ const values = byMetric.get(delta.metric) ?? [];
383
+ values.push(delta.delta);
384
+ byMetric.set(delta.metric, values);
385
+ }
386
+ }
387
+ return [...byMetric.entries()].sort(([left], [right]) => left.localeCompare(right))
388
+ .map(([metric, values]) => ({
389
+ metric,
390
+ delta: Number((values.reduce((sum, value) => sum + value, 0) / values.length).toFixed(6)),
391
+ }));
392
+ };
393
+ const buildScorecardSummary = (sourceExamples) => {
394
+ const missingRecordIds = sourceExamples
395
+ .filter((example) => !example.scorecard.present)
396
+ .map((example) => example.recordId)
397
+ .sort();
398
+ const scorecardIds = sourceExamples
399
+ .filter((example) => example.scorecard.present)
400
+ .map((example) => example.scorecard.scorecardId)
401
+ .sort();
402
+ return {
403
+ required: true,
404
+ bypassAllowed: false,
405
+ examplesWithScorecards: scorecardIds.length,
406
+ missingRecordIds,
407
+ scorecardIds,
408
+ averageMetricDeltas: averageMetricDeltas(sourceExamples),
409
+ };
410
+ };
411
+ const inventorySourceFor = (input) => {
412
+ if (input.inventorySource)
413
+ return input.inventorySource;
414
+ if (input.inventory) {
415
+ return {
416
+ source: "provided",
417
+ status: "succeeded",
418
+ inventoryCount: input.inventory.length,
419
+ };
420
+ }
421
+ return {
422
+ source: "not_provided",
423
+ command: DEFAULT_INVENTORY_COMMAND.command,
424
+ args: [...DEFAULT_INVENTORY_COMMAND.args],
425
+ status: "not_run",
426
+ inventoryCount: 0,
427
+ };
428
+ };
429
+ const summarizeAssignment = (resolverRole, assignment) => ({
430
+ resolverRole,
431
+ agentSlug: assignment.candidate.slug,
432
+ adapter: assignment.candidate.adapter,
433
+ ...(assignment.candidate.provider ? { provider: assignment.candidate.provider } : {}),
434
+ model: assignment.candidate.model,
435
+ source: assignment.candidate.source,
436
+ tier: assignment.candidate.tier,
437
+ runtimeHealth: {
438
+ status: assignment.candidate.healthStatus,
439
+ ...(assignment.candidate.latencyMs !== undefined ? {
440
+ latencyMs: assignment.candidate.latencyMs,
441
+ } : {}),
442
+ },
443
+ capabilities: assignment.candidate.capabilities,
444
+ ...(assignment.candidate.contextWindow !== undefined ? {
445
+ contextWindow: assignment.candidate.contextWindow,
446
+ } : {}),
447
+ ...(assignment.candidate.costPerMillion !== undefined ? {
448
+ costPerMillion: assignment.candidate.costPerMillion,
449
+ } : {}),
450
+ score: Number(assignment.score.toFixed(6)),
451
+ reasons: [...assignment.reasons],
452
+ });
453
+ const resolveTarget = (input, role) => {
454
+ const spec = roleSpecFor(role);
455
+ const inventory = input.inventory ?? [];
456
+ const inventorySource = inventorySourceFor(input);
457
+ const refreshWarnings = input.inventoryWarnings ?? [];
458
+ let resolution;
459
+ if (inventory.length > 0) {
460
+ resolution = resolveCodaliGatewayAgentTiers({
461
+ inventory,
462
+ roles: [spec.resolverRole],
463
+ allowImageWorker: false,
464
+ });
465
+ }
466
+ const assignment = resolution?.assignments[spec.resolverRole];
467
+ return {
468
+ source: {
469
+ ...inventorySource,
470
+ inventoryCount: inventorySource.inventoryCount ?? inventory.length,
471
+ },
472
+ status: assignment ? "resolved" : "unresolved",
473
+ resolverRole: spec.resolverRole,
474
+ ...(inventory.length > 0 ? {
475
+ inventorySnapshotHash: `sha256:${sha256Hex(inventory).slice(0, 24)}`,
476
+ } : {}),
477
+ inventoryCount: inventory.length,
478
+ ...(assignment ? { assignment: summarizeAssignment(spec.resolverRole, assignment) } : {}),
479
+ diagnostics: resolution?.diagnostics ?? [],
480
+ warnings: resolution?.warnings ?? [],
481
+ errors: resolution?.errors ?? (inventory.length === 0
482
+ ? [{
483
+ code: "GATEWAY_AGENT_INVENTORY_EMPTY",
484
+ message: "No mcoda agent candidates were available to resolve fine-tune target.",
485
+ role: spec.resolverRole,
486
+ }]
487
+ : []),
488
+ refreshWarnings,
489
+ };
490
+ };
491
+ const buildEvalCommands = (role, trainingManifest, scorecardSummary) => [
492
+ {
493
+ commandId: stableId("fine-tune-eval-command", {
494
+ kind: "phase-27-run-tests",
495
+ role,
496
+ manifestId: trainingManifest.manifestId,
497
+ }),
498
+ command: "docdexd",
499
+ args: [
500
+ "run-tests",
501
+ "--repo",
502
+ "<repo>",
503
+ "--target",
504
+ "packages/codali/src/improvement/__tests__/FineTuneJobPlanner.test.ts",
505
+ ],
506
+ dryRunSafe: true,
507
+ expectedScorecards: scorecardSummary.scorecardIds,
508
+ scorecardBypassAllowed: false,
509
+ },
510
+ {
511
+ commandId: stableId("fine-tune-eval-command", {
512
+ kind: "phase-27-pre-commit",
513
+ role,
514
+ manifestId: trainingManifest.manifestId,
515
+ }),
516
+ command: "docdexd",
517
+ args: [
518
+ "hook",
519
+ "pre-commit",
520
+ "--repo",
521
+ "<repo>",
522
+ ],
523
+ dryRunSafe: true,
524
+ expectedScorecards: [],
525
+ scorecardBypassAllowed: false,
526
+ },
527
+ ];
528
+ const buildEvalPlan = (role, trainingManifest, scorecardSummary, targetResolution, blockedReasons) => ({
529
+ planId: stableId("fine-tune-eval-plan", {
530
+ role,
531
+ manifestId: trainingManifest.manifestId,
532
+ scorecardIds: scorecardSummary.scorecardIds,
533
+ }),
534
+ scorecardRequired: true,
535
+ bypassAllowed: false,
536
+ scorecardIds: scorecardSummary.scorecardIds,
537
+ gates: [
538
+ {
539
+ gateId: stableId("fine-tune-gate", {
540
+ role,
541
+ manifestId: trainingManifest.manifestId,
542
+ type: "privacy",
543
+ }),
544
+ type: "privacy",
545
+ required: true,
546
+ passed: trainingManifest.rowCount > 0 &&
547
+ trainingManifest.excludedTrainingBlockedRecordIds.length === 0,
548
+ reasons: trainingManifest.excludedTrainingBlockedRecordIds.length
549
+ ? ["training_allowed_required"]
550
+ : [],
551
+ },
552
+ {
553
+ gateId: stableId("fine-tune-gate", {
554
+ role,
555
+ manifestId: trainingManifest.manifestId,
556
+ type: "scorecard",
557
+ }),
558
+ type: "scorecard",
559
+ required: true,
560
+ passed: scorecardSummary.missingRecordIds.length === 0 &&
561
+ scorecardSummary.examplesWithScorecards === trainingManifest.rowCount &&
562
+ trainingManifest.rowCount > 0,
563
+ reasons: scorecardSummary.missingRecordIds.length
564
+ ? ["scorecard_required"]
565
+ : [],
566
+ },
567
+ {
568
+ gateId: stableId("fine-tune-gate", {
569
+ role,
570
+ manifestId: trainingManifest.manifestId,
571
+ type: "target_health",
572
+ }),
573
+ type: "target_health",
574
+ required: true,
575
+ passed: targetResolution.status === "resolved",
576
+ reasons: targetResolution.status === "resolved" ? [] : ["target_resolution_required"],
577
+ },
578
+ {
579
+ gateId: stableId("fine-tune-gate", {
580
+ role,
581
+ manifestId: trainingManifest.manifestId,
582
+ type: "offline_eval",
583
+ }),
584
+ type: "offline_eval",
585
+ required: true,
586
+ passed: !blockedReasons.includes("scorecard_required") && trainingManifest.rowCount > 0,
587
+ reasons: blockedReasons.includes("scorecard_required")
588
+ ? ["scorecard_required"]
589
+ : [],
590
+ },
591
+ ],
592
+ commands: buildEvalCommands(role, trainingManifest, scorecardSummary),
593
+ });
594
+ const buildCostEstimate = (trainingManifest, targetResolution) => {
595
+ const costPerMillionTokens = targetResolution.assignment?.costPerMillion;
596
+ const estimatedProviderCostUsd = costPerMillionTokens === undefined
597
+ ? undefined
598
+ : Number(((trainingManifest.totalTokenEstimate / 1000000) * costPerMillionTokens)
599
+ .toFixed(6));
600
+ return {
601
+ source: costPerMillionTokens === undefined ? "not_available" : "mcoda_inventory",
602
+ currency: "USD",
603
+ estimatedTrainingTokens: trainingManifest.totalTokenEstimate,
604
+ ...(costPerMillionTokens !== undefined ? { costPerMillionTokens } : {}),
605
+ ...(estimatedProviderCostUsd !== undefined ? { estimatedProviderCostUsd } : {}),
606
+ notes: costPerMillionTokens === undefined
607
+ ? ["target cost data was not present in the mcoda inventory snapshot"]
608
+ : ["estimate uses mcoda inventory cost_per_million and manifest token estimate"],
609
+ };
610
+ };
611
+ const providerSubmissionPolicy = () => ({
612
+ automaticSubmission: false,
613
+ approvalRequired: true,
614
+ status: "not_submitted",
615
+ runnerStatus: "not_approved",
616
+ blocker: "provider_specific_runners_not_approved",
617
+ });
618
+ const buildRollbackPlan = (role, trainingManifest) => ({
619
+ planId: stableId("fine-tune-rollback-plan", {
620
+ role,
621
+ manifestId: trainingManifest.manifestId,
622
+ }),
623
+ automaticProviderJobSubmitted: false,
624
+ triggers: [
625
+ "scorecard_regression",
626
+ "target_health_regression",
627
+ "privacy_policy_revocation",
628
+ ],
629
+ steps: [
630
+ "do_not_submit_provider_job_without_runner_approval",
631
+ "remove_candidate_manifest_from improvement queue",
632
+ "restore previous worker target assignment",
633
+ "rerun scorecards before any later provider submission",
634
+ ],
635
+ });
636
+ const blockedReasonsFor = (input) => normalizedUniqueSorted([
637
+ input.role === CODALI_FINE_TUNE_FINAL_SYNTHESIZER_ROLE
638
+ ? "final_synthesizer_fine_tune_disabled_by_default"
639
+ : undefined,
640
+ supportedExportForRole(input.role, input.exportKind)
641
+ ? undefined
642
+ : "export_kind_not_supported_for_role",
643
+ input.trainingManifest.rowCount === 0 ? "no_training_allowed_examples" : undefined,
644
+ input.trainingManifest.excludedTrainingBlockedRecordIds.length > 0
645
+ ? "training_allowed_required"
646
+ : undefined,
647
+ input.scorecardSummary.examplesWithScorecards === input.trainingManifest.rowCount &&
648
+ input.trainingManifest.rowCount > 0 &&
649
+ input.scorecardSummary.missingRecordIds.length === 0
650
+ ? undefined
651
+ : "scorecard_required",
652
+ input.targetResolution.status === "resolved" ? undefined : "target_resolution_required",
653
+ ]);
654
+ const buildJobSpec = (input) => {
655
+ const jobPlanId = stableId("fine-tune-job-plan", {
656
+ role: input.role,
657
+ sourceManifestId: input.inspection.manifest.manifestId,
658
+ trainingManifestId: input.trainingManifest.manifestId,
659
+ policyHash: input.trainingManifest.reproducibleFrom.policyHash,
660
+ });
661
+ return {
662
+ jobSpecId: stableId("fine-tune-job-spec", {
663
+ jobPlanId,
664
+ targetSnapshot: input.targetResolution.inventorySnapshotHash,
665
+ targetSlug: input.targetResolution.assignment?.agentSlug,
666
+ }),
667
+ jobPlanId,
668
+ status: input.blockedReasons.length ? "blocked" : "draft",
669
+ jobKind: input.jobKind,
670
+ role: input.role,
671
+ targetResolution: input.targetResolution,
672
+ trainingManifest: input.trainingManifest,
673
+ datasetLineage: input.inspection.manifest.lineage,
674
+ privacySummary: input.inspection.manifest.privacySummary,
675
+ scorecardSummary: input.scorecardSummary,
676
+ evalPlan: input.evalPlan,
677
+ costEstimate: input.costEstimate,
678
+ rollbackPlan: input.rollbackPlan,
679
+ providerSubmission: input.providerSubmission,
680
+ };
681
+ };
682
+ const buildCandidateSummary = (input) => ({
683
+ candidateId: stableId("fine-tune-candidate", {
684
+ role: input.role,
685
+ sourceManifestId: input.inspection.manifest.manifestId,
686
+ sourceRecordIds: input.sourceExamples.map((example) => example.recordId),
687
+ jobSpecIds: input.jobSpecs.map((spec) => spec.jobSpecId),
688
+ blockedReasons: input.blockedReasons,
689
+ }),
690
+ candidateKind: "fine_tune_job_spec",
691
+ status: input.blockedReasons.length ? "blocked" : "proposed",
692
+ role: input.role,
693
+ jobKind: input.jobKind,
694
+ sourceExportIds: [input.inspection.manifest.manifestId],
695
+ sourceRecordIds: input.sourceExamples.map((example) => example.recordId),
696
+ artifactIds: input.inspection.manifest.artifactRefs.map((ref) => ref.refId),
697
+ exampleCount: input.sourceExamples.length,
698
+ objectBytes: input.inspection.manifest.artifactRefs
699
+ .reduce((total, ref) => total + ref.byteSize, 0),
700
+ jobSpecIds: input.jobSpecs.map((spec) => spec.jobSpecId),
701
+ blockedReasons: [...input.blockedReasons],
702
+ scorecardRequired: true,
703
+ providerSubmissionEnabled: false,
704
+ });
705
+ export const buildCodaliFineTuneJobPlannerBundle = ({ inspection, role = "extractor", artifact = CODALI_FINE_TUNE_PROPOSAL_ARTIFACT, ...input }) => {
706
+ const jobKind = jobKindForExportKind(inspection.manifest.exportKind);
707
+ const { sourceExamples, excludedTrainingBlockedRecordIds } = buildSourceExampleSet(inspection);
708
+ const trainingManifest = buildTrainingManifest(inspection, role, jobKind, sourceExamples, excludedTrainingBlockedRecordIds);
709
+ const targetResolution = resolveTarget({ inspection, role, artifact, ...input }, role);
710
+ const scorecardSummary = buildScorecardSummary(sourceExamples);
711
+ const providerSubmission = providerSubmissionPolicy();
712
+ const initialBlockedReasons = blockedReasonsFor({
713
+ role,
714
+ exportKind: inspection.manifest.exportKind,
715
+ trainingManifest,
716
+ scorecardSummary,
717
+ targetResolution,
718
+ });
719
+ const evalPlan = buildEvalPlan(role, trainingManifest, scorecardSummary, targetResolution, initialBlockedReasons);
720
+ const costEstimate = buildCostEstimate(trainingManifest, targetResolution);
721
+ const rollbackPlan = buildRollbackPlan(role, trainingManifest);
722
+ const blockedReasons = blockedReasonsFor({
723
+ role,
724
+ exportKind: inspection.manifest.exportKind,
725
+ trainingManifest,
726
+ scorecardSummary,
727
+ targetResolution,
728
+ });
729
+ const jobSpecs = role === CODALI_FINE_TUNE_FINAL_SYNTHESIZER_ROLE
730
+ ? []
731
+ : [
732
+ buildJobSpec({
733
+ inspection,
734
+ role,
735
+ jobKind,
736
+ trainingManifest,
737
+ targetResolution,
738
+ scorecardSummary,
739
+ evalPlan,
740
+ costEstimate,
741
+ rollbackPlan,
742
+ providerSubmission,
743
+ blockedReasons,
744
+ }),
745
+ ];
746
+ return {
747
+ schemaVersion: CODALI_FINE_TUNE_JOB_PLANNER_SCHEMA_VERSION,
748
+ artifact,
749
+ source: {
750
+ exportId: inspection.exportId,
751
+ manifestId: inspection.manifest.manifestId,
752
+ manifestPath: inspection.manifestPath,
753
+ exportKind: inspection.manifest.exportKind,
754
+ checksum: inspection.manifest.checksum,
755
+ recordCount: inspection.manifest.recordCount,
756
+ primaryArtifactRef: summarizeObjectRef(inspection.primaryArtifact?.ref ?? inspection.manifest.artifactRefs[0]),
757
+ },
758
+ generationPolicy: {
759
+ deterministic: true,
760
+ modifiesRuntimePrompts: false,
761
+ modifiesRuntimeCode: false,
762
+ bodyPolicy: "object_refs_and_hashes_only",
763
+ uploadEnabled: false,
764
+ providerSubmissionEnabled: false,
765
+ scorecardRequired: true,
766
+ scorecardBypassAllowed: false,
767
+ finalSynthesizerFineTuning: false,
768
+ },
769
+ expectedShape: {
770
+ schemaVersion: CODALI_FINE_TUNE_JOB_PLANNER_SCHEMA_VERSION,
771
+ artifact,
772
+ requiredFields: [
773
+ "sourceExamples",
774
+ "trainingManifest",
775
+ "targetResolution",
776
+ "scorecardSummary",
777
+ "evalPlan",
778
+ "costEstimate",
779
+ "rollbackPlan",
780
+ "providerSubmission",
781
+ "jobSpecs",
782
+ ],
783
+ jobSpecRequiredFields: [
784
+ "targetResolution",
785
+ "trainingManifest",
786
+ "datasetLineage",
787
+ "privacySummary",
788
+ "evalPlan",
789
+ "costEstimate",
790
+ "rollbackPlan",
791
+ "providerSubmission",
792
+ ],
793
+ },
794
+ rolePolicy: {
795
+ role,
796
+ resolverRole: roleSpecFor(role).resolverRole,
797
+ allowedWorkerRole: role !== CODALI_FINE_TUNE_FINAL_SYNTHESIZER_ROLE,
798
+ supportedExportKinds: [...roleSpecFor(role).supportedExportKinds],
799
+ finalSynthesizerAllowed: false,
800
+ providerAutoSubmitAllowed: false,
801
+ },
802
+ sourceExamples,
803
+ trainingManifest,
804
+ targetResolution,
805
+ scorecardSummary,
806
+ evalPlan,
807
+ costEstimate,
808
+ rollbackPlan,
809
+ providerSubmission,
810
+ jobSpecs,
811
+ rejectedEvidence: inspection.curationReport.rejected,
812
+ candidates: [
813
+ buildCandidateSummary({
814
+ inspection,
815
+ role,
816
+ jobKind,
817
+ sourceExamples,
818
+ jobSpecs,
819
+ blockedReasons,
820
+ }),
821
+ ],
822
+ };
823
+ };