@mcoda/codali 0.1.88 → 0.1.89
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/EvalCommand.d.ts +8 -0
- package/dist/cli/EvalCommand.d.ts.map +1 -1
- package/dist/cli/EvalCommand.js +93 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -0
- package/dist/docdex/DocdexClient.d.ts +8 -1
- package/dist/docdex/DocdexClient.d.ts.map +1 -1
- package/dist/docdex/DocdexClient.js +126 -33
- package/dist/eval/CodaliGatewayLiveHarness.d.ts +169 -0
- package/dist/eval/CodaliGatewayLiveHarness.d.ts.map +1 -0
- package/dist/eval/CodaliGatewayLiveHarness.js +824 -0
- package/dist/eval/GatewayEvalSuite.d.ts +202 -0
- package/dist/eval/GatewayEvalSuite.d.ts.map +1 -0
- package/dist/eval/GatewayEvalSuite.js +673 -0
- package/dist/gateway/AgentTierResolver.d.ts +74 -0
- package/dist/gateway/AgentTierResolver.d.ts.map +1 -0
- package/dist/gateway/AgentTierResolver.js +576 -0
- package/dist/gateway/AppToolGatewayDispatcher.d.ts +88 -0
- package/dist/gateway/AppToolGatewayDispatcher.d.ts.map +1 -0
- package/dist/gateway/AppToolGatewayDispatcher.js +381 -0
- package/dist/gateway/CodaliGateway.d.ts +73 -0
- package/dist/gateway/CodaliGateway.d.ts.map +1 -0
- package/dist/gateway/CodaliGateway.js +824 -0
- package/dist/gateway/CodaliGatewaySchemas.d.ts +21 -0
- package/dist/gateway/CodaliGatewaySchemas.d.ts.map +1 -0
- package/dist/gateway/CodaliGatewaySchemas.js +874 -0
- package/dist/gateway/CodaliGatewayStore.d.ts +157 -0
- package/dist/gateway/CodaliGatewayStore.d.ts.map +1 -0
- package/dist/gateway/CodaliGatewayStore.js +206 -0
- package/dist/gateway/CodaliGatewayTypes.d.ts +336 -0
- package/dist/gateway/CodaliGatewayTypes.d.ts.map +1 -0
- package/dist/gateway/CodaliGatewayTypes.js +1 -0
- package/dist/gateway/ContextPackBuilder.d.ts +43 -0
- package/dist/gateway/ContextPackBuilder.d.ts.map +1 -0
- package/dist/gateway/ContextPackBuilder.js +317 -0
- package/dist/gateway/EvidenceNormalizer.d.ts +42 -0
- package/dist/gateway/EvidenceNormalizer.d.ts.map +1 -0
- package/dist/gateway/EvidenceNormalizer.js +488 -0
- package/dist/gateway/GatewayPlanner.d.ts +195 -0
- package/dist/gateway/GatewayPlanner.d.ts.map +1 -0
- package/dist/gateway/GatewayPlanner.js +379 -0
- package/dist/gateway/GatewayPolicyCompiler.d.ts +30 -0
- package/dist/gateway/GatewayPolicyCompiler.d.ts.map +1 -0
- package/dist/gateway/GatewayPolicyCompiler.js +114 -0
- package/dist/gateway/GatewaySecurityPolicy.d.ts +14 -0
- package/dist/gateway/GatewaySecurityPolicy.d.ts.map +1 -0
- package/dist/gateway/GatewaySecurityPolicy.js +350 -0
- package/dist/gateway/GatewayStateMachine.d.ts +165 -0
- package/dist/gateway/GatewayStateMachine.d.ts.map +1 -0
- package/dist/gateway/GatewayStateMachine.js +790 -0
- package/dist/gateway/GatewayTraceReplay.d.ts +120 -0
- package/dist/gateway/GatewayTraceReplay.d.ts.map +1 -0
- package/dist/gateway/GatewayTraceReplay.js +273 -0
- package/dist/gateway/ToolCapabilityCompiler.d.ts +50 -0
- package/dist/gateway/ToolCapabilityCompiler.d.ts.map +1 -0
- package/dist/gateway/ToolCapabilityCompiler.js +442 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -0
- package/dist/runtime/CodaliRuntime.d.ts +7 -0
- package/dist/runtime/CodaliRuntime.d.ts.map +1 -1
- package/dist/runtime/CodaliRuntime.js +98 -54
- package/dist/tools/ToolRegistry.d.ts.map +1 -1
- package/dist/tools/ToolRegistry.js +4 -0
- package/dist/tools/ToolTypes.d.ts +1 -1
- package/dist/tools/ToolTypes.d.ts.map +1 -1
- package/dist/tools/ToolTypes.js +5 -1
- package/package.json +3 -3
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
const MAX_DEPTH = 5;
|
|
3
|
+
const MAX_EXCERPT_CHARS = 1200;
|
|
4
|
+
const EVIDENCE_ARRAY_KEYS = [
|
|
5
|
+
"evidence",
|
|
6
|
+
"evidenceItems",
|
|
7
|
+
"evidence_items",
|
|
8
|
+
"facts",
|
|
9
|
+
"sources",
|
|
10
|
+
"sourceRecords",
|
|
11
|
+
"source_records",
|
|
12
|
+
"citations",
|
|
13
|
+
"results",
|
|
14
|
+
"hits",
|
|
15
|
+
"items",
|
|
16
|
+
"records",
|
|
17
|
+
];
|
|
18
|
+
const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
19
|
+
const readString = (record, keys) => {
|
|
20
|
+
for (const key of keys) {
|
|
21
|
+
const value = record[key];
|
|
22
|
+
if (typeof value === "string" && value.trim()) {
|
|
23
|
+
return value.trim();
|
|
24
|
+
}
|
|
25
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
26
|
+
return String(value);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
};
|
|
31
|
+
const readNumber = (record, keys) => {
|
|
32
|
+
for (const key of keys) {
|
|
33
|
+
const value = record[key];
|
|
34
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
if (typeof value === "string" && value.trim()) {
|
|
38
|
+
const parsed = Number(value);
|
|
39
|
+
if (Number.isFinite(parsed)) {
|
|
40
|
+
return parsed;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
};
|
|
46
|
+
const readBoolean = (record, keys) => {
|
|
47
|
+
for (const key of keys) {
|
|
48
|
+
const value = record[key];
|
|
49
|
+
if (typeof value === "boolean") {
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
};
|
|
55
|
+
const readRecord = (record, keys) => {
|
|
56
|
+
for (const key of keys) {
|
|
57
|
+
const value = record[key];
|
|
58
|
+
if (isRecord(value)) {
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
};
|
|
64
|
+
const clamp = (value, fallback) => {
|
|
65
|
+
const candidate = Number.isFinite(value) ? value : fallback;
|
|
66
|
+
return Math.max(0, Math.min(1, candidate));
|
|
67
|
+
};
|
|
68
|
+
const truncate = (value) => {
|
|
69
|
+
if (!value)
|
|
70
|
+
return undefined;
|
|
71
|
+
return value.length > MAX_EXCERPT_CHARS
|
|
72
|
+
? `${value.slice(0, MAX_EXCERPT_CHARS - 3)}...`
|
|
73
|
+
: value;
|
|
74
|
+
};
|
|
75
|
+
const canonicalize = (value) => (value ?? "").trim().toLowerCase().replace(/\s+/g, " ");
|
|
76
|
+
const stableHash = (value) => createHash("sha256").update(value).digest("hex").slice(0, 16);
|
|
77
|
+
const stableEvidenceId = (runId, taskId, candidate) => {
|
|
78
|
+
const fingerprint = [
|
|
79
|
+
runId,
|
|
80
|
+
taskId ?? "",
|
|
81
|
+
canonicalize(candidate.sourceType),
|
|
82
|
+
canonicalize(candidate.sourceId),
|
|
83
|
+
canonicalize(candidate.sourceUri),
|
|
84
|
+
canonicalize(candidate.sourceTitle),
|
|
85
|
+
canonicalize(candidate.claim),
|
|
86
|
+
].join("|");
|
|
87
|
+
return `ev-${stableHash(fingerprint)}`;
|
|
88
|
+
};
|
|
89
|
+
const fingerprintCandidate = (candidate) => [
|
|
90
|
+
canonicalize(candidate.sourceType),
|
|
91
|
+
canonicalize(candidate.sourceId),
|
|
92
|
+
canonicalize(candidate.sourceUri),
|
|
93
|
+
canonicalize(candidate.sourceTitle),
|
|
94
|
+
canonicalize(candidate.claim),
|
|
95
|
+
].join("|");
|
|
96
|
+
const metadataFromRecord = (record) => isRecord(record.metadata) ? record.metadata : undefined;
|
|
97
|
+
const sourceRecord = (record) => readRecord(record, ["source", "provenance", "citation"]);
|
|
98
|
+
const docdexTelemetryMetadata = (record) => {
|
|
99
|
+
if (!record)
|
|
100
|
+
return undefined;
|
|
101
|
+
const requestId = readString(record, [
|
|
102
|
+
"docdex_request_id",
|
|
103
|
+
"docdexRequestId",
|
|
104
|
+
"request_id",
|
|
105
|
+
"requestId",
|
|
106
|
+
"x-docdex-request-id",
|
|
107
|
+
"x_docdex_request_id",
|
|
108
|
+
"x-request-id",
|
|
109
|
+
"x_request_id",
|
|
110
|
+
"correlation_id",
|
|
111
|
+
"correlationId",
|
|
112
|
+
]);
|
|
113
|
+
const operation = readString(record, ["docdex_operation", "docdexOperation", "operation"]);
|
|
114
|
+
const metadata = {};
|
|
115
|
+
if (requestId)
|
|
116
|
+
metadata.docdex_request_id = requestId;
|
|
117
|
+
if (operation)
|
|
118
|
+
metadata.docdex_operation = operation;
|
|
119
|
+
return Object.keys(metadata).length > 0 ? metadata : undefined;
|
|
120
|
+
};
|
|
121
|
+
const mergeDocdexTelemetryMetadata = (base, ...records) => {
|
|
122
|
+
const metadata = { ...(base ?? {}) };
|
|
123
|
+
for (const record of records) {
|
|
124
|
+
Object.assign(metadata, docdexTelemetryMetadata(record) ?? {});
|
|
125
|
+
}
|
|
126
|
+
return Object.keys(metadata).length > 0 ? metadata : undefined;
|
|
127
|
+
};
|
|
128
|
+
const sourceTypeFromTool = (tool) => {
|
|
129
|
+
if (!tool)
|
|
130
|
+
return undefined;
|
|
131
|
+
if (tool.startsWith("docdex_"))
|
|
132
|
+
return "docdex";
|
|
133
|
+
return "app_tool";
|
|
134
|
+
};
|
|
135
|
+
const hasDocdexShape = (record) => Boolean(readString(record, ["doc_id", "docId", "documentId"]) ||
|
|
136
|
+
readString(record, ["rel_path", "relPath", "path", "file"]) ||
|
|
137
|
+
readString(record, ["snippet", "excerpt"]));
|
|
138
|
+
const provenancePresent = (candidate) => Boolean(candidate.sourceId ||
|
|
139
|
+
candidate.sourceUri ||
|
|
140
|
+
candidate.sourceTitle ||
|
|
141
|
+
candidate.rawExcerpt ||
|
|
142
|
+
candidate.usedTool);
|
|
143
|
+
const safeJsonExcerpt = (value) => {
|
|
144
|
+
try {
|
|
145
|
+
return truncate(JSON.stringify(value));
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
const parseMaybeJson = (value) => {
|
|
152
|
+
const trimmed = value.trim();
|
|
153
|
+
if (!trimmed)
|
|
154
|
+
return { malformed: false };
|
|
155
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
|
|
156
|
+
return { malformed: false };
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
return { parsed: JSON.parse(trimmed), malformed: false };
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return { malformed: true };
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
const buildCandidateFromRecord = (record, context) => {
|
|
166
|
+
const source = sourceRecord(record);
|
|
167
|
+
const docdexLike = hasDocdexShape(record);
|
|
168
|
+
const sourceType = readString(record, ["sourceType", "source_type", "type"]) ??
|
|
169
|
+
(source ? readString(source, ["sourceType", "source_type", "type"]) : undefined) ??
|
|
170
|
+
(docdexLike ? "docdex" : context.sourceType);
|
|
171
|
+
const sourceId = readString(record, ["sourceId", "source_id", "doc_id", "docId", "documentId", "id"]) ??
|
|
172
|
+
(source ? readString(source, ["sourceId", "source_id", "doc_id", "docId", "id"]) : undefined);
|
|
173
|
+
const sourceUri = readString(record, ["sourceUri", "source_uri", "url", "uri", "href"]) ??
|
|
174
|
+
(source ? readString(source, ["sourceUri", "source_uri", "url", "uri", "href"]) : undefined);
|
|
175
|
+
const sourceTitle = readString(record, ["sourceTitle", "source_title", "title", "name", "rel_path", "relPath", "path", "file"]) ??
|
|
176
|
+
(source ? readString(source, ["sourceTitle", "source_title", "title", "name", "path"]) : undefined);
|
|
177
|
+
const rawExcerpt = truncate(readString(record, ["rawExcerpt", "raw_excerpt", "excerpt", "snippet", "text"])) ??
|
|
178
|
+
(source ? truncate(readString(source, ["rawExcerpt", "raw_excerpt", "excerpt", "snippet", "text"])) : undefined);
|
|
179
|
+
const claim = readString(record, ["claim", "fact", "statement", "summary", "description", "text", "content"]) ??
|
|
180
|
+
rawExcerpt ??
|
|
181
|
+
sourceTitle;
|
|
182
|
+
if (!claim) {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
const tenantScoped = readBoolean(record, ["tenantScoped", "tenant_scoped"]) ??
|
|
186
|
+
(source ? readBoolean(source, ["tenantScoped", "tenant_scoped"]) : undefined) ??
|
|
187
|
+
context.tenantScoped;
|
|
188
|
+
const usedTool = readString(record, ["usedTool", "used_tool", "tool"]) ??
|
|
189
|
+
context.usedTool;
|
|
190
|
+
const recordMetadata = metadataFromRecord(record);
|
|
191
|
+
const metadata = {
|
|
192
|
+
...(context.metadata ?? {}),
|
|
193
|
+
...(recordMetadata ?? {}),
|
|
194
|
+
...(docdexTelemetryMetadata(record) ?? {}),
|
|
195
|
+
...(docdexTelemetryMetadata(recordMetadata) ?? {}),
|
|
196
|
+
...(source ? docdexTelemetryMetadata(source) ?? {} : {}),
|
|
197
|
+
};
|
|
198
|
+
const path = readString(record, ["rel_path", "relPath", "path", "file"]);
|
|
199
|
+
if (path)
|
|
200
|
+
metadata.path = path;
|
|
201
|
+
if (source && Object.keys(source).length > 0)
|
|
202
|
+
metadata.source = source;
|
|
203
|
+
const unprovenanced = !provenancePresent({
|
|
204
|
+
sourceId,
|
|
205
|
+
sourceUri,
|
|
206
|
+
sourceTitle,
|
|
207
|
+
rawExcerpt,
|
|
208
|
+
usedTool,
|
|
209
|
+
});
|
|
210
|
+
return {
|
|
211
|
+
claim,
|
|
212
|
+
summary: readString(record, ["summary"]),
|
|
213
|
+
sourceType: sourceType ?? (unprovenanced ? "model_observation" : "worker_output"),
|
|
214
|
+
sourceId,
|
|
215
|
+
sourceUri,
|
|
216
|
+
sourceTitle,
|
|
217
|
+
sourceTimestamp: readString(record, ["sourceTimestamp", "source_timestamp", "timestamp", "updatedAt", "updated_at"]) ??
|
|
218
|
+
(source ? readString(source, ["sourceTimestamp", "source_timestamp", "timestamp", "updatedAt", "updated_at"]) : undefined),
|
|
219
|
+
rawExcerpt,
|
|
220
|
+
rawPayloadRef: readString(record, ["rawPayloadRef", "raw_payload_ref"]),
|
|
221
|
+
confidence: readNumber(record, ["confidence", "score"]),
|
|
222
|
+
relevance: readNumber(record, ["relevance", "rankScore", "rank_score", "score"]),
|
|
223
|
+
freshness: readFreshness(record),
|
|
224
|
+
usedTool,
|
|
225
|
+
tenantScoped,
|
|
226
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
|
|
227
|
+
value: record,
|
|
228
|
+
unprovenanced,
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
const readFreshness = (record) => {
|
|
232
|
+
const freshness = readString(record, ["freshness"]);
|
|
233
|
+
if (freshness === "fresh" ||
|
|
234
|
+
freshness === "recent" ||
|
|
235
|
+
freshness === "stale" ||
|
|
236
|
+
freshness === "unknown") {
|
|
237
|
+
return freshness;
|
|
238
|
+
}
|
|
239
|
+
return undefined;
|
|
240
|
+
};
|
|
241
|
+
const collectCandidates = (value, context, warnings) => {
|
|
242
|
+
if (context.depth > MAX_DEPTH || value === undefined || value === null) {
|
|
243
|
+
return [];
|
|
244
|
+
}
|
|
245
|
+
if (typeof value === "string") {
|
|
246
|
+
const trimmed = value.trim();
|
|
247
|
+
if (!trimmed)
|
|
248
|
+
return [];
|
|
249
|
+
const parsed = parseMaybeJson(trimmed);
|
|
250
|
+
if (parsed.parsed !== undefined) {
|
|
251
|
+
return collectCandidates(parsed.parsed, { ...context, depth: context.depth + 1 }, warnings);
|
|
252
|
+
}
|
|
253
|
+
if (parsed.malformed) {
|
|
254
|
+
warnings.push("malformed_worker_json");
|
|
255
|
+
}
|
|
256
|
+
if (!context.rootStringMode) {
|
|
257
|
+
return [];
|
|
258
|
+
}
|
|
259
|
+
return [{
|
|
260
|
+
claim: trimmed,
|
|
261
|
+
rawExcerpt: truncate(trimmed),
|
|
262
|
+
sourceType: "model_observation",
|
|
263
|
+
confidence: 0.2,
|
|
264
|
+
relevance: 0.4,
|
|
265
|
+
usedTool: context.usedTool,
|
|
266
|
+
tenantScoped: context.tenantScoped,
|
|
267
|
+
metadata: context.metadata,
|
|
268
|
+
value,
|
|
269
|
+
unprovenanced: true,
|
|
270
|
+
}];
|
|
271
|
+
}
|
|
272
|
+
if (Array.isArray(value)) {
|
|
273
|
+
return value.flatMap((item) => collectCandidates(item, {
|
|
274
|
+
...context,
|
|
275
|
+
depth: context.depth + 1,
|
|
276
|
+
rootStringMode: true,
|
|
277
|
+
}, warnings));
|
|
278
|
+
}
|
|
279
|
+
if (!isRecord(value)) {
|
|
280
|
+
return [];
|
|
281
|
+
}
|
|
282
|
+
const recordMetadata = metadataFromRecord(value);
|
|
283
|
+
const metaRecord = readRecord(value, ["meta"]);
|
|
284
|
+
const scopedMetadata = mergeDocdexTelemetryMetadata(context.metadata, value, recordMetadata, metaRecord);
|
|
285
|
+
const scopedContext = scopedMetadata
|
|
286
|
+
? { ...context, metadata: scopedMetadata }
|
|
287
|
+
: context;
|
|
288
|
+
const candidates = [];
|
|
289
|
+
const directCandidate = buildCandidateFromRecord(value, scopedContext);
|
|
290
|
+
if (directCandidate) {
|
|
291
|
+
candidates.push(directCandidate);
|
|
292
|
+
}
|
|
293
|
+
for (const key of EVIDENCE_ARRAY_KEYS) {
|
|
294
|
+
const child = value[key];
|
|
295
|
+
if (child === undefined)
|
|
296
|
+
continue;
|
|
297
|
+
candidates.push(...collectCandidates(child, {
|
|
298
|
+
...scopedContext,
|
|
299
|
+
depth: context.depth + 1,
|
|
300
|
+
rootStringMode: key === "facts",
|
|
301
|
+
}, warnings));
|
|
302
|
+
}
|
|
303
|
+
if (candidates.length === 0 && context.allowGenericPayload && Object.keys(value).length > 0) {
|
|
304
|
+
candidates.push({
|
|
305
|
+
claim: context.usedTool
|
|
306
|
+
? `Tool ${context.usedTool} returned structured data.`
|
|
307
|
+
: "Worker returned structured data.",
|
|
308
|
+
summary: safeJsonExcerpt(value),
|
|
309
|
+
sourceType: context.sourceType ?? "app_tool",
|
|
310
|
+
rawExcerpt: safeJsonExcerpt(value),
|
|
311
|
+
confidence: 0.55,
|
|
312
|
+
relevance: 0.5,
|
|
313
|
+
usedTool: scopedContext.usedTool,
|
|
314
|
+
tenantScoped: scopedContext.tenantScoped,
|
|
315
|
+
metadata: scopedContext.metadata,
|
|
316
|
+
value,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
return candidates;
|
|
320
|
+
};
|
|
321
|
+
const normalizeCandidate = (input, candidate) => {
|
|
322
|
+
const claim = candidate.claim?.trim();
|
|
323
|
+
if (!claim) {
|
|
324
|
+
return undefined;
|
|
325
|
+
}
|
|
326
|
+
const unprovenanced = candidate.unprovenanced || !provenancePresent(candidate);
|
|
327
|
+
const sourceType = unprovenanced
|
|
328
|
+
? "model_observation"
|
|
329
|
+
: candidate.sourceType ?? input.defaultSourceType ?? "worker_output";
|
|
330
|
+
const fallbackConfidence = sourceType === "model_observation"
|
|
331
|
+
? 0.2
|
|
332
|
+
: sourceType === "docdex"
|
|
333
|
+
? 0.75
|
|
334
|
+
: sourceType === "app_tool"
|
|
335
|
+
? 0.7
|
|
336
|
+
: 0.55;
|
|
337
|
+
const fallbackRelevance = sourceType === "model_observation"
|
|
338
|
+
? 0.4
|
|
339
|
+
: sourceType === "docdex"
|
|
340
|
+
? 0.65
|
|
341
|
+
: 0.55;
|
|
342
|
+
const confidence = unprovenanced
|
|
343
|
+
? Math.min(0.25, clamp(candidate.confidence, fallbackConfidence))
|
|
344
|
+
: clamp(candidate.confidence, fallbackConfidence);
|
|
345
|
+
const relevance = clamp(candidate.relevance, fallbackRelevance);
|
|
346
|
+
return {
|
|
347
|
+
id: stableEvidenceId(input.runId, input.taskId, { ...candidate, claim, sourceType }),
|
|
348
|
+
runId: input.runId,
|
|
349
|
+
taskId: input.taskId,
|
|
350
|
+
stageId: input.stageId,
|
|
351
|
+
claim,
|
|
352
|
+
summary: candidate.summary,
|
|
353
|
+
sourceType,
|
|
354
|
+
sourceId: candidate.sourceId,
|
|
355
|
+
sourceUri: candidate.sourceUri,
|
|
356
|
+
sourceTitle: candidate.sourceTitle,
|
|
357
|
+
sourceTimestamp: candidate.sourceTimestamp,
|
|
358
|
+
rawExcerpt: candidate.rawExcerpt,
|
|
359
|
+
rawPayloadRef: candidate.rawPayloadRef,
|
|
360
|
+
confidence,
|
|
361
|
+
relevance,
|
|
362
|
+
freshness: candidate.freshness,
|
|
363
|
+
usedTool: candidate.usedTool ?? input.defaultTool,
|
|
364
|
+
tenantScoped: candidate.tenantScoped ?? input.defaultTenantScoped ?? false,
|
|
365
|
+
metadata: {
|
|
366
|
+
...(candidate.metadata ?? {}),
|
|
367
|
+
normalizedBy: "codali_gateway_evidence_normalizer",
|
|
368
|
+
unprovenanced,
|
|
369
|
+
originalQuery: input.originalQuery,
|
|
370
|
+
},
|
|
371
|
+
};
|
|
372
|
+
};
|
|
373
|
+
export const normalizeCodaliEvidence = (input) => {
|
|
374
|
+
const warnings = [];
|
|
375
|
+
const rejected = [];
|
|
376
|
+
const candidates = [];
|
|
377
|
+
for (const evidence of input.evidence ?? []) {
|
|
378
|
+
candidates.push(...collectCandidates(evidence, {
|
|
379
|
+
sourceType: input.defaultSourceType,
|
|
380
|
+
usedTool: input.defaultTool,
|
|
381
|
+
tenantScoped: input.defaultTenantScoped,
|
|
382
|
+
depth: 0,
|
|
383
|
+
rootStringMode: true,
|
|
384
|
+
}, warnings));
|
|
385
|
+
}
|
|
386
|
+
if (input.workerOutput !== undefined) {
|
|
387
|
+
candidates.push(...collectCandidates(input.workerOutput, {
|
|
388
|
+
sourceType: input.defaultSourceType,
|
|
389
|
+
usedTool: input.defaultTool,
|
|
390
|
+
tenantScoped: input.defaultTenantScoped,
|
|
391
|
+
depth: 0,
|
|
392
|
+
rootStringMode: true,
|
|
393
|
+
}, warnings));
|
|
394
|
+
}
|
|
395
|
+
for (const call of input.toolCalls ?? []) {
|
|
396
|
+
if (call.status && call.status !== "success") {
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
const toolSourceType = sourceTypeFromTool(call.tool) ?? input.defaultSourceType;
|
|
400
|
+
const before = candidates.length;
|
|
401
|
+
candidates.push(...collectCandidates(call.result, {
|
|
402
|
+
sourceType: toolSourceType,
|
|
403
|
+
usedTool: call.tool,
|
|
404
|
+
tenantScoped: input.defaultTenantScoped,
|
|
405
|
+
metadata: {
|
|
406
|
+
tool: call.tool,
|
|
407
|
+
toolArgs: call.args,
|
|
408
|
+
toolMetadata: call.metadata,
|
|
409
|
+
},
|
|
410
|
+
depth: 0,
|
|
411
|
+
rootStringMode: false,
|
|
412
|
+
allowGenericPayload: toolSourceType === "app_tool",
|
|
413
|
+
}, warnings));
|
|
414
|
+
if (candidates.length === before &&
|
|
415
|
+
toolSourceType === "app_tool" &&
|
|
416
|
+
call.result !== undefined) {
|
|
417
|
+
candidates.push({
|
|
418
|
+
claim: `Tool ${call.tool} returned structured data.`,
|
|
419
|
+
sourceType: "app_tool",
|
|
420
|
+
rawExcerpt: safeJsonExcerpt(call.result),
|
|
421
|
+
confidence: 0.55,
|
|
422
|
+
relevance: 0.5,
|
|
423
|
+
usedTool: call.tool,
|
|
424
|
+
tenantScoped: input.defaultTenantScoped,
|
|
425
|
+
metadata: { tool: call.tool, toolArgs: call.args, toolMetadata: call.metadata },
|
|
426
|
+
value: call.result,
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
const deduped = new Map();
|
|
431
|
+
let duplicateCount = 0;
|
|
432
|
+
for (const candidate of candidates) {
|
|
433
|
+
const normalized = normalizeCandidate(input, candidate);
|
|
434
|
+
if (!normalized) {
|
|
435
|
+
rejected.push({
|
|
436
|
+
reason: "missing_claim",
|
|
437
|
+
value: candidate.value,
|
|
438
|
+
});
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
if (input.requireTenantScope && !normalized.tenantScoped) {
|
|
442
|
+
rejected.push({
|
|
443
|
+
reason: "tenant_scope_required",
|
|
444
|
+
claim: normalized.claim,
|
|
445
|
+
sourceType: normalized.sourceType,
|
|
446
|
+
sourceId: normalized.sourceId,
|
|
447
|
+
sourceUri: normalized.sourceUri,
|
|
448
|
+
usedTool: normalized.usedTool,
|
|
449
|
+
value: candidate.value,
|
|
450
|
+
});
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
const fingerprint = fingerprintCandidate(normalized);
|
|
454
|
+
const existing = deduped.get(fingerprint);
|
|
455
|
+
if (existing) {
|
|
456
|
+
duplicateCount += 1;
|
|
457
|
+
existing.metadata = {
|
|
458
|
+
...(existing.metadata ?? {}),
|
|
459
|
+
duplicateCount: Number(existing.metadata?.duplicateCount ?? 0) + 1,
|
|
460
|
+
duplicateEvidenceIds: [
|
|
461
|
+
...(Array.isArray(existing.metadata?.duplicateEvidenceIds)
|
|
462
|
+
? existing.metadata.duplicateEvidenceIds
|
|
463
|
+
: []),
|
|
464
|
+
normalized.id,
|
|
465
|
+
],
|
|
466
|
+
};
|
|
467
|
+
existing.confidence = Math.max(existing.confidence, normalized.confidence);
|
|
468
|
+
existing.relevance = Math.max(existing.relevance, normalized.relevance);
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
deduped.set(fingerprint, normalized);
|
|
472
|
+
}
|
|
473
|
+
const evidence = [...deduped.values()]
|
|
474
|
+
.sort((left, right) => right.relevance - left.relevance ||
|
|
475
|
+
right.confidence - left.confidence ||
|
|
476
|
+
left.id.localeCompare(right.id))
|
|
477
|
+
.slice(0, Math.max(0, input.maxEvidenceItems ?? Number.MAX_SAFE_INTEGER));
|
|
478
|
+
if ((input.maxEvidenceItems ?? Number.MAX_SAFE_INTEGER) < deduped.size) {
|
|
479
|
+
warnings.push("evidence_truncated_to_budget");
|
|
480
|
+
}
|
|
481
|
+
return {
|
|
482
|
+
evidence,
|
|
483
|
+
rejected,
|
|
484
|
+
warnings,
|
|
485
|
+
duplicateCount,
|
|
486
|
+
};
|
|
487
|
+
};
|
|
488
|
+
export const normalizeGatewayEvidence = normalizeCodaliEvidence;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import type { Provider, ProviderMessage } from "../providers/ProviderTypes.js";
|
|
2
|
+
import type { CodaliGatewayClassifierOutput, CodaliGatewayPlannerOutput, CodaliGatewayRequest, CodaliGatewayValidationIssue } from "./CodaliGatewayTypes.js";
|
|
3
|
+
import { type GatewayPolicyCompilation } from "./GatewayPolicyCompiler.js";
|
|
4
|
+
export interface CodaliGatewayPlannerToolDescriptor {
|
|
5
|
+
name: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
inputSchema?: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
export interface GatewayPlannerInput {
|
|
10
|
+
request: CodaliGatewayRequest;
|
|
11
|
+
policyCompilation?: GatewayPolicyCompilation;
|
|
12
|
+
toolDescriptions?: Record<string, string | CodaliGatewayPlannerToolDescriptor>;
|
|
13
|
+
}
|
|
14
|
+
export interface CodaliGatewayPlanningResult {
|
|
15
|
+
policyCompilation: GatewayPolicyCompilation;
|
|
16
|
+
classifier: CodaliGatewayClassifierOutput;
|
|
17
|
+
planner: CodaliGatewayPlannerOutput;
|
|
18
|
+
warnings: string[];
|
|
19
|
+
classifierRepairAttempts: number;
|
|
20
|
+
plannerRepairAttempts: number;
|
|
21
|
+
classifierRawContent: string;
|
|
22
|
+
plannerRawContent: string;
|
|
23
|
+
}
|
|
24
|
+
export interface CodaliGatewayPlannerOptions {
|
|
25
|
+
maxRepairAttempts?: number;
|
|
26
|
+
maxTokens?: number;
|
|
27
|
+
temperature?: number;
|
|
28
|
+
}
|
|
29
|
+
export declare class CodaliGatewayPlannerError extends Error {
|
|
30
|
+
readonly code: string;
|
|
31
|
+
readonly issues?: CodaliGatewayValidationIssue[];
|
|
32
|
+
constructor(code: string, message: string, issues?: CodaliGatewayValidationIssue[]);
|
|
33
|
+
}
|
|
34
|
+
export declare const CODALI_GATEWAY_CLASSIFIER_SCHEMA: {
|
|
35
|
+
readonly type: "object";
|
|
36
|
+
readonly additionalProperties: false;
|
|
37
|
+
readonly required: readonly ["queryType", "needsPrivateData", "needsFreshData", "needsDocdex", "needsAppTools", "needsImageWorker"];
|
|
38
|
+
readonly properties: {
|
|
39
|
+
readonly queryType: {
|
|
40
|
+
readonly type: "string";
|
|
41
|
+
readonly minLength: 1;
|
|
42
|
+
};
|
|
43
|
+
readonly needsPrivateData: {
|
|
44
|
+
readonly type: "boolean";
|
|
45
|
+
};
|
|
46
|
+
readonly needsFreshData: {
|
|
47
|
+
readonly type: "boolean";
|
|
48
|
+
};
|
|
49
|
+
readonly needsDocdex: {
|
|
50
|
+
readonly type: "boolean";
|
|
51
|
+
};
|
|
52
|
+
readonly needsAppTools: {
|
|
53
|
+
readonly type: "boolean";
|
|
54
|
+
};
|
|
55
|
+
readonly needsImageWorker: {
|
|
56
|
+
readonly type: "boolean";
|
|
57
|
+
};
|
|
58
|
+
readonly directAnswerCandidate: {
|
|
59
|
+
readonly type: "string";
|
|
60
|
+
};
|
|
61
|
+
readonly rationale: {
|
|
62
|
+
readonly type: "string";
|
|
63
|
+
};
|
|
64
|
+
readonly confidence: {
|
|
65
|
+
readonly enum: readonly ["high", "medium", "low"];
|
|
66
|
+
};
|
|
67
|
+
readonly metadata: {
|
|
68
|
+
readonly type: "object";
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
export declare const CODALI_GATEWAY_PLANNER_SCHEMA: {
|
|
73
|
+
readonly type: "object";
|
|
74
|
+
readonly additionalProperties: true;
|
|
75
|
+
readonly required: readonly ["queryType", "subquestions", "workerTasks"];
|
|
76
|
+
readonly properties: {
|
|
77
|
+
readonly runId: {
|
|
78
|
+
readonly type: "string";
|
|
79
|
+
};
|
|
80
|
+
readonly queryType: {
|
|
81
|
+
readonly type: "string";
|
|
82
|
+
readonly minLength: 1;
|
|
83
|
+
};
|
|
84
|
+
readonly summary: {
|
|
85
|
+
readonly type: "string";
|
|
86
|
+
};
|
|
87
|
+
readonly subquestions: {
|
|
88
|
+
readonly type: "array";
|
|
89
|
+
readonly items: {
|
|
90
|
+
readonly type: "object";
|
|
91
|
+
readonly additionalProperties: true;
|
|
92
|
+
readonly required: readonly ["id", "question"];
|
|
93
|
+
readonly properties: {
|
|
94
|
+
readonly id: {
|
|
95
|
+
readonly type: "string";
|
|
96
|
+
readonly minLength: 1;
|
|
97
|
+
};
|
|
98
|
+
readonly question: {
|
|
99
|
+
readonly type: "string";
|
|
100
|
+
readonly minLength: 1;
|
|
101
|
+
};
|
|
102
|
+
readonly rationale: {
|
|
103
|
+
readonly type: "string";
|
|
104
|
+
};
|
|
105
|
+
readonly priority: {
|
|
106
|
+
readonly type: "number";
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
readonly workerTasks: {
|
|
112
|
+
readonly type: "array";
|
|
113
|
+
readonly items: {
|
|
114
|
+
readonly type: "object";
|
|
115
|
+
readonly additionalProperties: true;
|
|
116
|
+
readonly required: readonly ["id", "workerRole", "objective", "toolsAllowed", "outputFormat"];
|
|
117
|
+
readonly properties: {
|
|
118
|
+
readonly id: {
|
|
119
|
+
readonly type: "string";
|
|
120
|
+
readonly minLength: 1;
|
|
121
|
+
};
|
|
122
|
+
readonly workerRole: {
|
|
123
|
+
readonly type: "string";
|
|
124
|
+
readonly minLength: 1;
|
|
125
|
+
};
|
|
126
|
+
readonly objective: {
|
|
127
|
+
readonly type: "string";
|
|
128
|
+
readonly minLength: 1;
|
|
129
|
+
};
|
|
130
|
+
readonly query: {
|
|
131
|
+
readonly type: "string";
|
|
132
|
+
};
|
|
133
|
+
readonly toolsAllowed: {
|
|
134
|
+
readonly type: "array";
|
|
135
|
+
readonly items: {
|
|
136
|
+
readonly type: "string";
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
readonly outputFormat: {
|
|
140
|
+
readonly type: "string";
|
|
141
|
+
readonly minLength: 1;
|
|
142
|
+
};
|
|
143
|
+
readonly expectedSources: {
|
|
144
|
+
readonly type: "array";
|
|
145
|
+
readonly items: {
|
|
146
|
+
readonly type: "string";
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
readonly constraints: {
|
|
150
|
+
readonly type: "array";
|
|
151
|
+
readonly items: {
|
|
152
|
+
readonly type: "string";
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
readonly priority: {
|
|
156
|
+
readonly type: "number";
|
|
157
|
+
};
|
|
158
|
+
readonly metadata: {
|
|
159
|
+
readonly type: "object";
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
readonly expectedEvidenceCount: {
|
|
165
|
+
readonly type: "number";
|
|
166
|
+
};
|
|
167
|
+
readonly maxIterations: {
|
|
168
|
+
readonly type: "number";
|
|
169
|
+
};
|
|
170
|
+
readonly requiresFinalLargeModel: {
|
|
171
|
+
readonly type: "boolean";
|
|
172
|
+
};
|
|
173
|
+
readonly metadata: {
|
|
174
|
+
readonly type: "object";
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
export declare const buildCodaliGatewayClassifierMessages: (input: GatewayPlannerInput) => ProviderMessage[];
|
|
179
|
+
export declare const buildCodaliGatewayPlannerMessages: (input: GatewayPlannerInput, classifier: CodaliGatewayClassifierOutput) => ProviderMessage[];
|
|
180
|
+
export declare class CodaliGatewayPlanner {
|
|
181
|
+
private readonly provider;
|
|
182
|
+
private readonly options;
|
|
183
|
+
private readonly maxRepairAttempts;
|
|
184
|
+
constructor(provider: Provider, options?: CodaliGatewayPlannerOptions);
|
|
185
|
+
classify(input: GatewayPlannerInput): Promise<{
|
|
186
|
+
classifier: CodaliGatewayClassifierOutput;
|
|
187
|
+
repairAttempts: number;
|
|
188
|
+
rawContent: string;
|
|
189
|
+
warnings: string[];
|
|
190
|
+
}>;
|
|
191
|
+
plan(input: GatewayPlannerInput): Promise<CodaliGatewayPlanningResult>;
|
|
192
|
+
private generateValidated;
|
|
193
|
+
}
|
|
194
|
+
export declare const createCodaliGatewayPlanner: (provider: Provider, options?: CodaliGatewayPlannerOptions) => CodaliGatewayPlanner;
|
|
195
|
+
//# sourceMappingURL=GatewayPlanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GatewayPlanner.d.ts","sourceRoot":"","sources":["../../src/gateway/GatewayPlanner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EAEhB,MAAM,+BAA+B,CAAC;AAIvC,OAAO,KAAK,EACV,6BAA6B,EAC7B,0BAA0B,EAC1B,oBAAoB,EACpB,4BAA4B,EAE7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEL,KAAK,wBAAwB,EAC9B,MAAM,4BAA4B,CAAC;AAGpC,MAAM,WAAW,kCAAkC;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,oBAAoB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,kCAAkC,CAAC,CAAC;CAChF;AAED,MAAM,WAAW,2BAA2B;IAC1C,iBAAiB,EAAE,wBAAwB,CAAC;IAC5C,UAAU,EAAE,6BAA6B,CAAC;IAC1C,OAAO,EAAE,0BAA0B,CAAC;IACpC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,wBAAwB,EAAE,MAAM,CAAC;IACjC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,2BAA2B;IAC1C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,4BAA4B,EAAE,CAAC;gBAErC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,4BAA4B,EAAE;CAMnF;AAED,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBnC,CAAC;AAEX,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+ChC,CAAC;AA2IX,eAAO,MAAM,oCAAoC,GAC/C,OAAO,mBAAmB,KACzB,eAAe,EAyBjB,CAAC;AAEF,eAAO,MAAM,iCAAiC,GAC5C,OAAO,mBAAmB,EAC1B,YAAY,6BAA6B,KACxC,eAAe,EAsCjB,CAAC;AAuDF,qBAAa,oBAAoB;IAI7B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJ1B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;gBAGxB,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,2BAAgC;IAKtD,QAAQ,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC;QAClD,UAAU,EAAE,6BAA6B,CAAC;QAC1C,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IAiBI,IAAI,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,2BAA2B,CAAC;YA2C9D,iBAAiB;CA8ChC;AAED,eAAO,MAAM,0BAA0B,GACrC,UAAU,QAAQ,EAClB,UAAU,2BAA2B,KACpC,oBAAmE,CAAC"}
|