@wix/pathgrade 1.0.37 → 1.0.39
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/README.md +3 -1
- package/dist/adapter-kit/index.d.ts +2 -2
- package/dist/adapter-kit/index.js +1 -1
- package/dist/adapters/jest/lifecycle.js +4 -2
- package/dist/adapters/node-test/index.js +4 -2
- package/dist/agents/claude/sdk-message-projector.js +4 -5
- package/dist/agents/claude/tool-permission-bridge.js +2 -1
- package/dist/agents/codex-app-server/item-projection.js +2 -2
- package/dist/agents/codex-app-server/mcp-approval-correlator.js +3 -2
- package/dist/agents/opencode.js +4 -5
- package/dist/commands/report.js +5 -25
- package/dist/internal/direct-mcp-v2/acp-author-projector.js +20 -7
- package/dist/reporters/cli.js +20 -1
- package/dist/reporters/github-comment.js +18 -7
- package/dist/reporters/loader.d.ts +4 -0
- package/dist/reporters/loader.js +26 -9
- package/dist/reporting/comparison-contract.js +20 -6
- package/dist/reporting/core.js +18 -8
- package/dist/reporting/report-parser.js +57 -2
- package/dist/reporting/types.d.ts +2 -1
- package/dist/runners/adapter.d.ts +4 -2
- package/dist/runners/lifecycle-hooks.js +6 -1
- package/dist/runners/orchestrator.js +3 -4
- package/dist/runners/repeated-invocation.js +2 -5
- package/dist/runners/report-projection.js +1 -0
- package/dist/runners/vitest-lifecycle.d.ts +1 -0
- package/dist/runners/vitest-lifecycle.js +21 -4
- package/dist/sdk/agent-flow.d.ts +51 -0
- package/dist/sdk/agent-flow.js +23 -0
- package/dist/sdk/agent.js +10 -1
- package/dist/sdk/evaluate.d.ts +2 -1
- package/dist/sdk/evaluate.js +114 -4
- package/dist/sdk/index.d.ts +4 -2
- package/dist/sdk/index.js +2 -2
- package/dist/sdk/judge-prompt-builder.js +11 -7
- package/dist/sdk/lifecycle.d.ts +3 -1
- package/dist/sdk/lifecycle.js +68 -5
- package/dist/sdk/mcp-event-input.d.ts +1 -0
- package/dist/sdk/mcp-event-input.js +3 -0
- package/dist/sdk/mcp-evidence.js +16 -3
- package/dist/sdk/mcp-safety.js +2 -2
- package/dist/sdk/result-capture.d.ts +14 -1
- package/dist/sdk/result-capture.js +49 -0
- package/dist/sdk/scripted-mcp-events.js +3 -2
- package/dist/sdk/tool-event-log.js +18 -3
- package/dist/sdk/tool-event-secrets.d.ts +4 -0
- package/dist/sdk/tool-event-secrets.js +33 -2
- package/dist/sdk/types.d.ts +6 -0
- package/dist/tool-event-results.d.ts +3 -0
- package/dist/tool-event-results.js +153 -23
- package/dist/types.d.ts +13 -7
- package/docs/agent-flow-evaluation.md +31 -0
- package/package.json +3 -2
|
@@ -24,6 +24,10 @@ const SECRET_KEY_NAMES = [
|
|
|
24
24
|
'connectionstring',
|
|
25
25
|
'credentials',
|
|
26
26
|
'credential',
|
|
27
|
+
'grant',
|
|
28
|
+
'capability',
|
|
29
|
+
'capabilityurl',
|
|
30
|
+
'cursor',
|
|
27
31
|
'svsession',
|
|
28
32
|
'smsession',
|
|
29
33
|
'wixsession',
|
|
@@ -32,6 +36,10 @@ const SECRET_KEY_NAMES = [
|
|
|
32
36
|
const EXACT_ONLY_SECRET_KEY_NAMES = new Set([
|
|
33
37
|
'auth',
|
|
34
38
|
'token',
|
|
39
|
+
'grant',
|
|
40
|
+
'capability',
|
|
41
|
+
'capabilityurl',
|
|
42
|
+
'cursor',
|
|
35
43
|
'svsession',
|
|
36
44
|
'smsession',
|
|
37
45
|
'wixsession',
|
|
@@ -39,6 +47,9 @@ const EXACT_ONLY_SECRET_KEY_NAMES = new Set([
|
|
|
39
47
|
]);
|
|
40
48
|
const NON_SECRET_ENVIRONMENT_KEY_NAMES = new Set(['tokencount', 'tokenizersparallelism', 'tokenusage']);
|
|
41
49
|
const BOUNDARY_ONLY_SENSITIVE_VALUE_MAX_LENGTH = 1;
|
|
50
|
+
const MAX_SANITIZE_DEPTH = 64;
|
|
51
|
+
const MAX_SENSITIVE_SCAN_NODES = 100_000;
|
|
52
|
+
const MAX_SENSITIVE_JSON_CHARS = 1024 * 1024;
|
|
42
53
|
export function collectSensitiveEnvValues(env) {
|
|
43
54
|
return [...new Set(Object.entries(env ?? {})
|
|
44
55
|
.filter((entry) => typeof entry[1] === 'string')
|
|
@@ -60,15 +71,36 @@ export function sanitizePersistenceValue(source, explicitSensitiveValues = []) {
|
|
|
60
71
|
])].sort((a, b) => b.length - a.length);
|
|
61
72
|
return sanitizeValue(source, '', sensitiveValues, new Set(explicitValues));
|
|
62
73
|
}
|
|
74
|
+
export function sanitizeUntrustedPersistenceValue(source, explicitSensitiveValues = []) {
|
|
75
|
+
try {
|
|
76
|
+
return sanitizePersistenceValue(source, explicitSensitiveValues);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (!isSensitiveValueScanLimitError(error))
|
|
80
|
+
throw error;
|
|
81
|
+
if (Array.isArray(source))
|
|
82
|
+
return [];
|
|
83
|
+
if (isRecord(source))
|
|
84
|
+
return { redacted: true };
|
|
85
|
+
return '<redacted>';
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export function isSensitiveValueScanLimitError(error) {
|
|
89
|
+
return error instanceof Error && error.message.startsWith('Sensitive-value scan exceeded');
|
|
90
|
+
}
|
|
63
91
|
export function sanitizeToolEventResult(source, sensitiveValues) {
|
|
64
92
|
const result = {};
|
|
65
93
|
let truncated = source.truncated === true;
|
|
66
94
|
const addBounded = (key, value) => {
|
|
67
95
|
if (typeof value !== 'string')
|
|
68
96
|
return;
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
97
|
+
const explicitValues = [...new Set(sensitiveValues.filter((entry) => entry.length > 0))];
|
|
98
|
+
const overlap = explicitValues.reduce((max, entry) => Math.max(max, entry.length), 0);
|
|
99
|
+
const prefix = value.slice(0, TOOL_RESULT_MAX_CHARS + Math.max(overlap, 1));
|
|
100
|
+
const bounded = boundText(redactSensitiveValues(prefix, explicitValues, new Set(explicitValues)));
|
|
101
|
+
const sanitized = boundText(sanitizePersistenceValue(bounded.value, sensitiveValues));
|
|
102
|
+
result[key] = sanitized.value;
|
|
103
|
+
truncated ||= value.length > prefix.length || bounded.truncated || sanitized.truncated;
|
|
72
104
|
};
|
|
73
105
|
addBounded('content', source.content);
|
|
74
106
|
addBounded('stdout', source.stdout);
|
|
@@ -96,56 +128,93 @@ function redactSensitiveValues(value, sensitiveValues, explicitSensitiveValues)
|
|
|
96
128
|
}
|
|
97
129
|
return redacted;
|
|
98
130
|
}
|
|
99
|
-
function collectStructuredSensitiveValues(source) {
|
|
131
|
+
export function collectStructuredSensitiveValues(source) {
|
|
100
132
|
const values = new Set();
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
133
|
+
let scannedNodes = 0;
|
|
134
|
+
let parsedJsonChars = 0;
|
|
135
|
+
const pending = [
|
|
136
|
+
{ value: source, key: '' },
|
|
137
|
+
];
|
|
138
|
+
while (pending.length > 0) {
|
|
139
|
+
if (++scannedNodes > MAX_SENSITIVE_SCAN_NODES) {
|
|
140
|
+
throw new Error('Sensitive-value scan exceeded the input node limit');
|
|
141
|
+
}
|
|
142
|
+
const { value, key } = pending.pop();
|
|
143
|
+
if (typeof value === 'string') {
|
|
144
|
+
if (value.length > 0 && !isNumericTokenTelemetry(key, value) && isSecretKey(key)) {
|
|
145
|
+
values.add(value);
|
|
146
|
+
}
|
|
147
|
+
for (const match of value.matchAll(/[?&](?:api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|token|secret|auth|password|passwd|session(?:id)?|cookie)=([^&#\s]+)/gi)) {
|
|
148
|
+
if (match[1])
|
|
149
|
+
values.add(match[1]);
|
|
150
|
+
}
|
|
151
|
+
for (const sensitiveValue of collectCredentialShapeSensitiveValues(value)) {
|
|
152
|
+
values.add(sensitiveValue);
|
|
153
|
+
}
|
|
154
|
+
const trimmed = value.trim();
|
|
155
|
+
const looksStructured = (trimmed.startsWith('{') && trimmed.endsWith('}'))
|
|
156
|
+
|| (trimmed.startsWith('[') && trimmed.endsWith(']'));
|
|
157
|
+
if (looksStructured && (parsedJsonChars += value.length) > MAX_SENSITIVE_JSON_CHARS) {
|
|
158
|
+
throw new Error('Sensitive-value scan exceeded the nested JSON limit');
|
|
159
|
+
}
|
|
160
|
+
const structured = looksStructured ? parseStructuredJson(value) : undefined;
|
|
161
|
+
if (structured !== undefined)
|
|
162
|
+
pending.push({ value: structured, key });
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if ((typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint')
|
|
166
|
+
&& !isNumericTokenTelemetry(key, value) && isSecretKey(key)) {
|
|
167
|
+
values.add(String(value));
|
|
168
|
+
continue;
|
|
106
169
|
}
|
|
107
170
|
if (Array.isArray(value)) {
|
|
108
171
|
for (const entry of value)
|
|
109
|
-
|
|
110
|
-
|
|
172
|
+
pending.push({ value: entry, key });
|
|
173
|
+
continue;
|
|
111
174
|
}
|
|
112
175
|
if (isRecord(value)) {
|
|
113
|
-
for (const [entryKey, entryValue] of Object.entries(value))
|
|
114
|
-
|
|
176
|
+
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
177
|
+
pending.push({ value: entryValue, key: entryKey });
|
|
178
|
+
}
|
|
115
179
|
}
|
|
116
|
-
}
|
|
117
|
-
visit(source, '');
|
|
180
|
+
}
|
|
118
181
|
return [...values];
|
|
119
182
|
}
|
|
120
|
-
function sanitizeValue(value, key, sensitiveValues, explicitSensitiveValues) {
|
|
183
|
+
function sanitizeValue(value, key, sensitiveValues, explicitSensitiveValues, depth = 0) {
|
|
121
184
|
if (!isNumericTokenTelemetry(key, value) && isSecretKey(key))
|
|
122
185
|
return '<redacted>';
|
|
123
186
|
if (typeof value === 'string') {
|
|
124
|
-
return redactCredentialShapes(redactSensitiveValues(value, sensitiveValues, explicitSensitiveValues), sensitiveValues, explicitSensitiveValues);
|
|
187
|
+
return redactCredentialShapes(redactSensitiveValues(value, sensitiveValues, explicitSensitiveValues), sensitiveValues, explicitSensitiveValues, depth);
|
|
125
188
|
}
|
|
189
|
+
if (depth >= MAX_SANITIZE_DEPTH && (Array.isArray(value) || isRecord(value)))
|
|
190
|
+
return '<redacted>';
|
|
126
191
|
if (Array.isArray(value)) {
|
|
127
|
-
return value.map((entry) => sanitizeValue(entry, key, sensitiveValues, explicitSensitiveValues));
|
|
192
|
+
return value.map((entry) => sanitizeValue(entry, key, sensitiveValues, explicitSensitiveValues, depth + 1));
|
|
128
193
|
}
|
|
129
194
|
if (isRecord(value)) {
|
|
130
195
|
return Object.fromEntries(Object.entries(value).map(([entryKey, entryValue]) => [
|
|
131
196
|
entryKey,
|
|
132
|
-
sanitizeValue(entryValue, entryKey, sensitiveValues, explicitSensitiveValues),
|
|
197
|
+
sanitizeValue(entryValue, entryKey, sensitiveValues, explicitSensitiveValues, depth + 1),
|
|
133
198
|
]));
|
|
134
199
|
}
|
|
135
200
|
return value;
|
|
136
201
|
}
|
|
137
|
-
function redactCredentialShapes(value, sensitiveValues, explicitSensitiveValues) {
|
|
202
|
+
function redactCredentialShapes(value, sensitiveValues, explicitSensitiveValues, depth) {
|
|
138
203
|
let redacted = value;
|
|
204
|
+
const credentialShapeValues = collectCredentialShapeSensitiveValues(redacted);
|
|
205
|
+
redacted = redactSensitiveValues(redacted, credentialShapeValues, new Set(credentialShapeValues));
|
|
139
206
|
const structured = parseStructuredJson(redacted);
|
|
140
207
|
if (structured !== undefined) {
|
|
141
208
|
const nestedSensitiveValues = [...new Set([
|
|
142
209
|
...sensitiveValues,
|
|
143
210
|
...collectStructuredSensitiveValues(structured),
|
|
144
211
|
])].sort((a, b) => b.length - a.length);
|
|
145
|
-
redacted = JSON.stringify(sanitizeValue(structured, '', nestedSensitiveValues, explicitSensitiveValues));
|
|
212
|
+
redacted = JSON.stringify(sanitizeValue(structured, '', nestedSensitiveValues, explicitSensitiveValues, depth + 1));
|
|
146
213
|
}
|
|
147
214
|
if (redacted.includes('PRIVATE KEY-----')) {
|
|
148
|
-
|
|
215
|
+
for (const block of findPrivateKeyBlocks(redacted).reverse()) {
|
|
216
|
+
redacted = `${redacted.slice(0, block.start)}<redacted>${redacted.slice(block.end)}`;
|
|
217
|
+
}
|
|
149
218
|
}
|
|
150
219
|
if (/\b(?:bearer|basic)\s/i.test(redacted)) {
|
|
151
220
|
redacted = redacted.replace(/(\b(?:bearer|basic)\s+)[^\s,;"']+/gi, '$1<redacted>');
|
|
@@ -154,10 +223,71 @@ function redactCredentialShapes(value, sensitiveValues, explicitSensitiveValues)
|
|
|
154
223
|
redacted = redacted.replace(/([a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:)[^\s/@]+(@)/gi, '$1<redacted>$2');
|
|
155
224
|
}
|
|
156
225
|
if (redacted.includes('=') || redacted.includes(':')) {
|
|
157
|
-
redacted = redacted.replace(/(\
|
|
226
|
+
redacted = redacted.replace(/((?:^|[\s{[(,;])["']?(?:api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|token|secret|auth|password|passwd|session(?:id)?|cookie)["']?\s*[=:]\s*["']?)[^\s,;"'}]+/gi, '$1<redacted>');
|
|
227
|
+
redacted = redacted.replace(/((?:^|[\s{[(,;])["'](?:grant|capability|capabilityurl|cursor)["']\s*:\s*["']?)[^\s,;"'}]+/gi, '$1<redacted>');
|
|
158
228
|
}
|
|
159
229
|
return redacted;
|
|
160
230
|
}
|
|
231
|
+
function collectCredentialShapeSensitiveValues(value) {
|
|
232
|
+
const values = new Set();
|
|
233
|
+
for (const match of value.matchAll(/https?:\/\/[^\s,;"']+\/(?:cap|capability)\/[^\s,;"']+/gi)) {
|
|
234
|
+
values.add(match[0]);
|
|
235
|
+
}
|
|
236
|
+
if (value.includes('PRIVATE KEY-----')) {
|
|
237
|
+
for (const block of findPrivateKeyBlocks(value)) {
|
|
238
|
+
values.add(value.slice(block.start, block.end));
|
|
239
|
+
if (block.body)
|
|
240
|
+
values.add(block.body);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (/\b(?:bearer|basic)\s/i.test(value)) {
|
|
244
|
+
for (const match of value.matchAll(/\b(?:bearer|basic)\s+([^\s,;"']+)/gi)) {
|
|
245
|
+
if (match[1])
|
|
246
|
+
values.add(match[1]);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (value.includes('://')) {
|
|
250
|
+
for (const match of value.matchAll(/[a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:([^\s/@]+)@/gi)) {
|
|
251
|
+
if (match[1])
|
|
252
|
+
values.add(match[1]);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (value.includes('=') || value.includes(':')) {
|
|
256
|
+
for (const match of value.matchAll(/(?:^|[\s{[(,;])["']?(?:api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|token|secret|auth|password|passwd|session(?:id)?|cookie)["']?\s*[=:]\s*["']?([^\s,;"'}]+)/gi)) {
|
|
257
|
+
if (match[1])
|
|
258
|
+
values.add(match[1]);
|
|
259
|
+
}
|
|
260
|
+
for (const match of value.matchAll(/(?:^|[\s{[(,;])["'](?:grant|capability|capabilityurl|cursor)["']\s*:\s*["']?([^\s,;"'}]+)/gi)) {
|
|
261
|
+
if (match[1])
|
|
262
|
+
values.add(match[1]);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return [...values].sort((a, b) => b.length - a.length);
|
|
266
|
+
}
|
|
267
|
+
function findPrivateKeyBlocks(value) {
|
|
268
|
+
const blocks = [];
|
|
269
|
+
let open;
|
|
270
|
+
let cursor = 0;
|
|
271
|
+
while (cursor < value.length) {
|
|
272
|
+
const start = value.indexOf('-----', cursor);
|
|
273
|
+
if (start < 0)
|
|
274
|
+
break;
|
|
275
|
+
const end = value.indexOf('-----', start + 5);
|
|
276
|
+
if (end < 0)
|
|
277
|
+
break;
|
|
278
|
+
const markerEnd = end + 5;
|
|
279
|
+
const marker = value.slice(start, markerEnd);
|
|
280
|
+
if (!open && marker.startsWith('-----BEGIN ') && marker.endsWith('PRIVATE KEY-----')) {
|
|
281
|
+
open = { start, bodyStart: markerEnd };
|
|
282
|
+
}
|
|
283
|
+
else if (open && marker.startsWith('-----END ') && marker.endsWith('PRIVATE KEY-----')) {
|
|
284
|
+
blocks.push({ start: open.start, end: markerEnd, body: value.slice(open.bodyStart, start).trim() });
|
|
285
|
+
open = undefined;
|
|
286
|
+
}
|
|
287
|
+
cursor = markerEnd;
|
|
288
|
+
}
|
|
289
|
+
return blocks;
|
|
290
|
+
}
|
|
161
291
|
function isSecretKey(key) {
|
|
162
292
|
const normalized = key.replace(/[^a-z0-9]/gi, '').toLowerCase();
|
|
163
293
|
if (normalized === 'tokens')
|
package/dist/types.d.ts
CHANGED
|
@@ -172,6 +172,8 @@ export interface TrialResult {
|
|
|
172
172
|
scoring_duration_ms?: number;
|
|
173
173
|
recorded_at?: string;
|
|
174
174
|
agent?: import('./sdk/types.js').AgentExecutionMetadata;
|
|
175
|
+
flow_summary?: import('./sdk/types.js').AgentFlowSummary;
|
|
176
|
+
flow_trace?: import('./sdk/types.js').AgentFlowTrace;
|
|
175
177
|
conversation?: {
|
|
176
178
|
turns: ConversationTurn[];
|
|
177
179
|
total_turns: number;
|
|
@@ -183,6 +185,10 @@ export interface EvalReport {
|
|
|
183
185
|
task: string;
|
|
184
186
|
/** Canonical status for this report or consolidated group when available. */
|
|
185
187
|
status?: 'pass' | 'fail';
|
|
188
|
+
/** Whether every reportable runner attempt passed. */
|
|
189
|
+
runner_status?: 'pass' | 'fail';
|
|
190
|
+
/** Whether mean reward meets the configured threshold. */
|
|
191
|
+
threshold_status?: 'pass' | 'fail' | 'not_configured';
|
|
186
192
|
/** Schema-v2 canonical average score. */
|
|
187
193
|
mean_reward?: number;
|
|
188
194
|
/** Binary success frequency, absent when attempts are ineligible. */
|
|
@@ -211,12 +217,12 @@ export interface ComparisonContract {
|
|
|
211
217
|
unavailable_reasons?: ComparisonUnavailableReason[];
|
|
212
218
|
}
|
|
213
219
|
/**
|
|
214
|
-
* TrialResult with
|
|
220
|
+
* TrialResult with large trace fields stripped. These fields
|
|
215
221
|
* live only in the per-group trace files; the consolidated results.json keeps
|
|
216
222
|
* the rest so consumers (preview, `pathgrade report`) can compute summaries
|
|
217
223
|
* without loading trace data.
|
|
218
224
|
*/
|
|
219
|
-
export type StrippedTrialResult = Omit<TrialResult, 'session_log' | 'conversation'>;
|
|
225
|
+
export type StrippedTrialResult = Omit<TrialResult, 'session_log' | 'conversation' | 'flow_trace'>;
|
|
220
226
|
/**
|
|
221
227
|
* Per-group entry in the consolidated `.pathgrade/results.json` report.
|
|
222
228
|
*/
|
|
@@ -264,11 +270,11 @@ export interface PathgradeReport {
|
|
|
264
270
|
overall_mean_reward?: number;
|
|
265
271
|
attempts_requested?: number;
|
|
266
272
|
attempts_completed?: number;
|
|
267
|
-
/**
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
273
|
+
/** Whether every reportable runner attempt passed. */
|
|
274
|
+
runner_status?: 'pass' | 'fail';
|
|
275
|
+
/** Whether overall mean reward meets the configured threshold. */
|
|
276
|
+
threshold_status?: 'pass' | 'fail' | 'not_configured';
|
|
277
|
+
/** Conjunction of runner assertions and the optional aggregate threshold. */
|
|
272
278
|
status: 'pass' | 'fail';
|
|
273
279
|
/** Agent Evals compatibility manifest when changed selection finds no runnable evals. */
|
|
274
280
|
run_kind?: 'evaluation' | 'no-affected';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Evaluating agent flows
|
|
2
|
+
|
|
3
|
+
Use `evaluateFlow()` when the subject is an already-observed interaction graph rather than a Pathgrade-managed coding agent. The input is protocol-neutral, so an adapter can project A2A or another orchestration protocol into the same evidence contract.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { check, evaluateFlow, type AgentFlowTrace } from '@wix/pathgrade';
|
|
7
|
+
|
|
8
|
+
const flow: AgentFlowTrace = {
|
|
9
|
+
version: 1,
|
|
10
|
+
protocol: 'a2a',
|
|
11
|
+
rootParticipantId: 'planner',
|
|
12
|
+
participants: [{ id: 'planner' }, { id: 'flights' }],
|
|
13
|
+
interactions: [{
|
|
14
|
+
id: 'delegate-1', sequence: 1,
|
|
15
|
+
sourceParticipantId: 'planner', targetParticipantId: 'flights',
|
|
16
|
+
operation: 'message/send', state: 'completed',
|
|
17
|
+
}],
|
|
18
|
+
outcome: { state: 'completed' },
|
|
19
|
+
completeness: {
|
|
20
|
+
topology: 'complete', outcomes: 'partial', timing: 'unavailable',
|
|
21
|
+
usage: 'unavailable', runtimeIdentity: 'partial',
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
await evaluateFlow(flow, [
|
|
26
|
+
check('delegated flight search', ({ flow }) =>
|
|
27
|
+
flow?.interactions.some(item => item.targetParticipantId === 'flights') === true),
|
|
28
|
+
]);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`check()`, `score()`, and `judge()` work with flow evidence through `ScorerContext.flow`. `toolUsage()` is agent-only and is rejected explicitly for flows. Consolidated reports retain a compact `flow_summary`; the full `flow_trace` stays in the trace artifact. Completeness fields describe evidence availability and must not be read as inferred downstream success or timing.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/pathgrade",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.39",
|
|
4
4
|
"packageManager": "yarn@4.12.0",
|
|
5
5
|
"description": "Evaluate whether AI agents discover and use your skills correctly",
|
|
6
6
|
"exports": {
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"!dist/**/*.d.ts.map",
|
|
65
65
|
"bin/",
|
|
66
66
|
"docs/OPENAI_OAUTH_JUDGE.md",
|
|
67
|
+
"docs/agent-flow-evaluation.md",
|
|
67
68
|
"templates/",
|
|
68
69
|
"README.md"
|
|
69
70
|
],
|
|
@@ -141,5 +142,5 @@
|
|
|
141
142
|
"typescript": "^5.9.3",
|
|
142
143
|
"zod": "4.3.6"
|
|
143
144
|
},
|
|
144
|
-
"falconPackageHash": "
|
|
145
|
+
"falconPackageHash": "df08d3b446a37c3224730fca89a408f6238eef420358705733692eee"
|
|
145
146
|
}
|