@apo-ai/sdk 0.3.0 → 0.4.0
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 +11 -0
- package/dist/agent-task/public.d.ts +257 -195
- package/dist/agent-task/public.js +140 -61
- package/dist/agent-task/public.js.map +1 -1
- package/package.json +1 -1
|
@@ -235,7 +235,8 @@ function levenshtein(a, b) {
|
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
// src/agent-task/checks/judge.ts
|
|
238
|
-
var
|
|
238
|
+
var JUDGE_RESPONSE_CONTRACT = 'Respond with ONLY a JSON object: {"pass": true/false, "reasoning": "your reasoning"}';
|
|
239
|
+
var JUDGE_SYSTEM_PROMPT = `You are an evaluation judge. Evaluate the given value(s) against the instruction. ${JUDGE_RESPONSE_CONTRACT}`;
|
|
239
240
|
function formatValue(value, depth = 0) {
|
|
240
241
|
const indent = " ".repeat(depth);
|
|
241
242
|
if (value === null || value === void 0) return String(value);
|
|
@@ -314,12 +315,11 @@ async function callJudge(args) {
|
|
|
314
315
|
const apiKey = args.apiKey ?? process.env.OPENROUTER_API_KEY ?? process.env.OPENAI_API_KEY;
|
|
315
316
|
const deliverableText = `Values to evaluate:
|
|
316
317
|
${formatJudgeValues(args.values)}`;
|
|
317
|
-
const instructionText =
|
|
318
|
-
|
|
319
|
-
const systemPromptText = `${JUDGE_SYSTEM_PROMPT}
|
|
318
|
+
const { briefingText, instructionText } = assembleBriefing(args);
|
|
319
|
+
const systemPromptText = `${briefingText}
|
|
320
320
|
|
|
321
321
|
${deliverableText}`;
|
|
322
|
-
const cacheKey = `${args.model}\0${deliverableText}`;
|
|
322
|
+
const cacheKey = `${args.model}\0${briefingText}\0${deliverableText}`;
|
|
323
323
|
return runWithSharedPrefix(cacheKey, async () => {
|
|
324
324
|
const startedAt = Date.now();
|
|
325
325
|
const response = await fetch(`${baseURL}/chat/completions`, {
|
|
@@ -334,7 +334,7 @@ ${deliverableText}`;
|
|
|
334
334
|
{
|
|
335
335
|
role: "system",
|
|
336
336
|
content: [
|
|
337
|
-
{ type: "text", text:
|
|
337
|
+
{ type: "text", text: briefingText },
|
|
338
338
|
{
|
|
339
339
|
type: "text",
|
|
340
340
|
text: deliverableText,
|
|
@@ -384,6 +384,33 @@ ${deliverableText}`;
|
|
|
384
384
|
};
|
|
385
385
|
});
|
|
386
386
|
}
|
|
387
|
+
function assembleBriefing(args) {
|
|
388
|
+
if (!args.prompt) {
|
|
389
|
+
return {
|
|
390
|
+
briefingText: JUDGE_SYSTEM_PROMPT,
|
|
391
|
+
instructionText: `Instruction:
|
|
392
|
+
${args.instruction}`
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
const ctx = {
|
|
396
|
+
taskId: args.context?.taskId ?? "",
|
|
397
|
+
checkName: args.context?.checkName ?? "",
|
|
398
|
+
...args.context?.taskDescription !== void 0 ? { taskDescription: args.context.taskDescription } : {},
|
|
399
|
+
...args.context?.deliverableNames !== void 0 && args.context.deliverableNames.length > 0 ? { deliverableNames: args.context.deliverableNames } : {},
|
|
400
|
+
instruction: args.instruction
|
|
401
|
+
};
|
|
402
|
+
const built = args.prompt(ctx);
|
|
403
|
+
const system = built.system?.trim();
|
|
404
|
+
const user = built.user?.trim();
|
|
405
|
+
return {
|
|
406
|
+
// The SDK appends its own response contract to any custom briefing.
|
|
407
|
+
briefingText: system ? `${system}
|
|
408
|
+
|
|
409
|
+
${JUDGE_RESPONSE_CONTRACT}` : JUDGE_SYSTEM_PROMPT,
|
|
410
|
+
instructionText: user ?? `Instruction:
|
|
411
|
+
${args.instruction}`
|
|
412
|
+
};
|
|
413
|
+
}
|
|
387
414
|
|
|
388
415
|
// src/agent-task/checks/t.ts
|
|
389
416
|
function resolveJudgeConfig(judgeConfig, override) {
|
|
@@ -392,7 +419,8 @@ function resolveJudgeConfig(judgeConfig, override) {
|
|
|
392
419
|
return {
|
|
393
420
|
model,
|
|
394
421
|
baseURL: override?.baseURL ?? judgeConfig?.baseURL,
|
|
395
|
-
apiKey: override?.apiKey ?? judgeConfig?.apiKey
|
|
422
|
+
apiKey: override?.apiKey ?? judgeConfig?.apiKey,
|
|
423
|
+
prompt: override?.prompt ?? judgeConfig?.prompt
|
|
396
424
|
};
|
|
397
425
|
}
|
|
398
426
|
var TEST_METHOD_NAMES = [
|
|
@@ -421,6 +449,67 @@ function matchName(name, m) {
|
|
|
421
449
|
if (m instanceof RegExp) return m.test(name);
|
|
422
450
|
return m(name);
|
|
423
451
|
}
|
|
452
|
+
function createJudgeMethod(rec, judgeConfig, judgeScope) {
|
|
453
|
+
return async (values, instruction, opts) => {
|
|
454
|
+
const label = opts?.label ?? "judge";
|
|
455
|
+
const location = rec.captureLocation();
|
|
456
|
+
const valueArray = Array.isArray(values) ? values : [values];
|
|
457
|
+
const effective = resolveJudgeConfig(judgeConfig, opts?.judge);
|
|
458
|
+
if (!effective) {
|
|
459
|
+
rec.record(
|
|
460
|
+
label,
|
|
461
|
+
false,
|
|
462
|
+
"No judge model configured. Set one of:\n\u2022 OPENROUTER_MODEL + OPENROUTER_API_KEY (OpenRouter \u2014 works with 200+ models, one account)\n\u2022 OPENAI_MODEL + OPENAI_API_KEY (OpenAI direct)\nOr pass { judge } to runTask() programmatically.",
|
|
463
|
+
{ evaluator_type: "llm", location }
|
|
464
|
+
);
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
const context2 = judgeScopeToContext(judgeScope);
|
|
468
|
+
try {
|
|
469
|
+
const { pass, reasoning, judge } = await callJudge({
|
|
470
|
+
values: valueArray,
|
|
471
|
+
instruction,
|
|
472
|
+
model: effective.model,
|
|
473
|
+
baseURL: effective.baseURL,
|
|
474
|
+
apiKey: effective.apiKey,
|
|
475
|
+
prompt: effective.prompt,
|
|
476
|
+
...context2 ? { context: context2 } : {}
|
|
477
|
+
});
|
|
478
|
+
rec.record(label, pass, reasoning, {
|
|
479
|
+
evaluator_type: "llm",
|
|
480
|
+
judge,
|
|
481
|
+
expected: instruction,
|
|
482
|
+
// Store the raw evaluated value (not a truncated string) so the
|
|
483
|
+
// dashboard can render it with the right viewer — Markdown for
|
|
484
|
+
// prose, a JSON tree for structured objects.
|
|
485
|
+
received: valueArray.length === 1 ? valueArray[0] : valueArray,
|
|
486
|
+
location
|
|
487
|
+
});
|
|
488
|
+
} catch (error) {
|
|
489
|
+
rec.record(
|
|
490
|
+
label,
|
|
491
|
+
false,
|
|
492
|
+
`judge failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
493
|
+
{
|
|
494
|
+
evaluator_type: "llm",
|
|
495
|
+
expected: instruction,
|
|
496
|
+
received: valueArray.length === 1 ? valueArray[0] : valueArray,
|
|
497
|
+
location
|
|
498
|
+
}
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
function judgeScopeToContext(scope) {
|
|
504
|
+
if (!scope) return void 0;
|
|
505
|
+
const deliverableNames = scope.readDeliverableNames?.();
|
|
506
|
+
return {
|
|
507
|
+
taskId: scope.taskId,
|
|
508
|
+
checkName: scope.checkName,
|
|
509
|
+
...scope.taskDescription !== void 0 ? { taskDescription: scope.taskDescription } : {},
|
|
510
|
+
...deliverableNames && deliverableNames.length > 0 ? { deliverableNames } : {}
|
|
511
|
+
};
|
|
512
|
+
}
|
|
424
513
|
var CAPABILITY_LABELS = {
|
|
425
514
|
messages: "message",
|
|
426
515
|
tools: "tool",
|
|
@@ -429,7 +518,7 @@ var CAPABILITY_LABELS = {
|
|
|
429
518
|
skills: "skill",
|
|
430
519
|
subagents: "subagent"
|
|
431
520
|
};
|
|
432
|
-
function createTraceTestContext(view, rec, judgeConfig) {
|
|
521
|
+
function createTraceTestContext(view, rec, judgeConfig, judgeScope) {
|
|
433
522
|
const unsupported = (id, capability) => {
|
|
434
523
|
const label = CAPABILITY_LABELS[capability];
|
|
435
524
|
rec.record(id, false, `${label} evidence is unavailable in this trace projection`, {
|
|
@@ -613,49 +702,9 @@ function createTraceTestContext(view, rec, judgeConfig) {
|
|
|
613
702
|
{ expected: matcher.label, received: describeValue(value) }
|
|
614
703
|
);
|
|
615
704
|
},
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
const valueArray = Array.isArray(values) ? values : [values];
|
|
620
|
-
const effective = resolveJudgeConfig(judgeConfig, opts?.judge);
|
|
621
|
-
if (!effective) {
|
|
622
|
-
rec.record(
|
|
623
|
-
label,
|
|
624
|
-
false,
|
|
625
|
-
"No judge model configured. Set one of:\n\u2022 OPENROUTER_MODEL + OPENROUTER_API_KEY (OpenRouter \u2014 works with 200+ models, one account)\n\u2022 OPENAI_MODEL + OPENAI_API_KEY (OpenAI direct)\nOr pass { judge } to runTask() programmatically.",
|
|
626
|
-
{ evaluator_type: "llm", location }
|
|
627
|
-
);
|
|
628
|
-
return;
|
|
629
|
-
}
|
|
630
|
-
try {
|
|
631
|
-
const { pass, reasoning, judge } = await callJudge({
|
|
632
|
-
values: valueArray,
|
|
633
|
-
instruction,
|
|
634
|
-
model: effective.model,
|
|
635
|
-
baseURL: effective.baseURL,
|
|
636
|
-
apiKey: effective.apiKey
|
|
637
|
-
});
|
|
638
|
-
rec.record(label, pass, reasoning, {
|
|
639
|
-
evaluator_type: "llm",
|
|
640
|
-
judge,
|
|
641
|
-
expected: instruction,
|
|
642
|
-
received: valueArray.length === 1 ? valueArray[0] : valueArray,
|
|
643
|
-
location
|
|
644
|
-
});
|
|
645
|
-
} catch (error) {
|
|
646
|
-
rec.record(
|
|
647
|
-
label,
|
|
648
|
-
false,
|
|
649
|
-
`judge failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
650
|
-
{
|
|
651
|
-
evaluator_type: "llm",
|
|
652
|
-
expected: instruction,
|
|
653
|
-
received: valueArray.length === 1 ? valueArray[0] : valueArray,
|
|
654
|
-
location
|
|
655
|
-
}
|
|
656
|
-
);
|
|
657
|
-
}
|
|
658
|
-
}
|
|
705
|
+
// judge does not consult trace capabilities; the scope carries the
|
|
706
|
+
// task/check frame for prompt builders (#161).
|
|
707
|
+
judge: createJudgeMethod(rec, judgeConfig, judgeScope)
|
|
659
708
|
};
|
|
660
709
|
}
|
|
661
710
|
function matchesTraceToolCall(call, name, opts) {
|
|
@@ -787,14 +836,21 @@ function describe(id, nameOrFn, fn) {
|
|
|
787
836
|
async function runTraceChecks(args) {
|
|
788
837
|
const view = new TraceView(args.snapshot);
|
|
789
838
|
const locate = args.moduleUrl && args.displayFile ? (stack) => parseCheckLocation(stack, args.moduleUrl, args.displayFile) : void 0;
|
|
839
|
+
const taskMeta = readTaskMeta(args.task);
|
|
790
840
|
const results = await Promise.all(
|
|
791
841
|
registry.map(async (check) => {
|
|
792
842
|
const rec = new Recorder(locate);
|
|
793
|
-
const
|
|
843
|
+
const reads = trackDeliverableReads(args.deliverables);
|
|
844
|
+
const t = createTraceTestContext(view, rec, args.judgeConfig, {
|
|
845
|
+
taskId: taskMeta.id ?? "",
|
|
846
|
+
...taskMeta.description !== void 0 ? { taskDescription: taskMeta.description } : {},
|
|
847
|
+
checkName: check.id,
|
|
848
|
+
readDeliverableNames: reads.names
|
|
849
|
+
});
|
|
794
850
|
let thrownLocation;
|
|
795
851
|
try {
|
|
796
852
|
await check.fn(t, {
|
|
797
|
-
deliverables:
|
|
853
|
+
deliverables: reads.proxied,
|
|
798
854
|
files: args.files,
|
|
799
855
|
task: args.task
|
|
800
856
|
});
|
|
@@ -866,6 +922,26 @@ function proxyBrokenDeliverables(deliverables, brokenDeliverables) {
|
|
|
866
922
|
}
|
|
867
923
|
});
|
|
868
924
|
}
|
|
925
|
+
function readTaskMeta(task2) {
|
|
926
|
+
if (!task2 || typeof task2 !== "object") return {};
|
|
927
|
+
const record = task2;
|
|
928
|
+
return {
|
|
929
|
+
...typeof record.id === "string" ? { id: record.id } : {},
|
|
930
|
+
...typeof record.description === "string" ? { description: record.description } : {}
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
function trackDeliverableReads(deliverables) {
|
|
934
|
+
const read = /* @__PURE__ */ new Set();
|
|
935
|
+
const proxied = new Proxy(deliverables, {
|
|
936
|
+
get(target, property, receiver) {
|
|
937
|
+
if (typeof property === "string" && Object.prototype.hasOwnProperty.call(target, property)) {
|
|
938
|
+
read.add(property);
|
|
939
|
+
}
|
|
940
|
+
return Reflect.get(target, property, receiver);
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
return { proxied, names: () => [...read] };
|
|
944
|
+
}
|
|
869
945
|
|
|
870
946
|
// src/agent-task/task/defineTask.ts
|
|
871
947
|
var TASK_ADAPTER_SYMBOL = /* @__PURE__ */ Symbol.for("agent-task.adapter-definition");
|
|
@@ -2076,6 +2152,7 @@ async function executeLoadedTask(loaded, options, rawTrace, traceRunId) {
|
|
|
2076
2152
|
summarize: (result2) => summarizeEvaluationResults(result2)
|
|
2077
2153
|
},
|
|
2078
2154
|
async () => {
|
|
2155
|
+
const judgeConfig = resolveJudgeConfig(options?.judge, task2.judge);
|
|
2079
2156
|
if (!inlineChecks) {
|
|
2080
2157
|
return loadAndRunFlowChecks(
|
|
2081
2158
|
checksPath,
|
|
@@ -2084,7 +2161,7 @@ async function executeLoadedTask(loaded, options, rawTrace, traceRunId) {
|
|
|
2084
2161
|
deliverables: collected,
|
|
2085
2162
|
files,
|
|
2086
2163
|
task: task2,
|
|
2087
|
-
judgeConfig:
|
|
2164
|
+
...judgeConfig ? { judgeConfig } : {}
|
|
2088
2165
|
},
|
|
2089
2166
|
validationResults.brokenDeliverables
|
|
2090
2167
|
);
|
|
@@ -2097,7 +2174,7 @@ async function executeLoadedTask(loaded, options, rawTrace, traceRunId) {
|
|
|
2097
2174
|
),
|
|
2098
2175
|
files,
|
|
2099
2176
|
task: task2,
|
|
2100
|
-
judgeConfig:
|
|
2177
|
+
...judgeConfig ? { judgeConfig } : {},
|
|
2101
2178
|
moduleUrl,
|
|
2102
2179
|
displayFile: evalFileName
|
|
2103
2180
|
});
|
|
@@ -2277,12 +2354,13 @@ async function evaluate(loaded, options, phase1) {
|
|
|
2277
2354
|
phase1.collected,
|
|
2278
2355
|
validationResults.brokenDeliverables
|
|
2279
2356
|
);
|
|
2357
|
+
const judgeConfig = resolveJudgeConfig(options?.judge, task2.judge);
|
|
2280
2358
|
const checksResults = await (inlineChecks ? runTraceChecks({
|
|
2281
2359
|
snapshot: phase1.snapshot,
|
|
2282
2360
|
deliverables,
|
|
2283
2361
|
files,
|
|
2284
2362
|
task: task2,
|
|
2285
|
-
judgeConfig:
|
|
2363
|
+
...judgeConfig ? { judgeConfig } : {},
|
|
2286
2364
|
moduleUrl,
|
|
2287
2365
|
displayFile: evalFileName
|
|
2288
2366
|
}) : loadAndRunFlowChecks(
|
|
@@ -2292,7 +2370,7 @@ async function evaluate(loaded, options, phase1) {
|
|
|
2292
2370
|
deliverables,
|
|
2293
2371
|
files,
|
|
2294
2372
|
task: task2,
|
|
2295
|
-
judgeConfig:
|
|
2373
|
+
...judgeConfig ? { judgeConfig } : {}
|
|
2296
2374
|
},
|
|
2297
2375
|
validationResults.brokenDeliverables
|
|
2298
2376
|
));
|
|
@@ -2449,9 +2527,10 @@ async function rejudgeTaskRun(runId, endpoints, options = {}) {
|
|
|
2449
2527
|
const proxied = proxyBrokenDeliverables(deliverables, validation.brokenDeliverables);
|
|
2450
2528
|
const passCounts = /* @__PURE__ */ new Map();
|
|
2451
2529
|
let primary = [];
|
|
2530
|
+
const judgeConfig = resolveJudgeConfig(options.judge, loaded.task.judge);
|
|
2452
2531
|
for (let sample = 0; sample < samples; sample++) {
|
|
2453
2532
|
if (samples > 1) progress(`judging sample ${sample + 1}/${samples}`);
|
|
2454
|
-
const results = await runChecksOnce(loaded, proxied, snapshot,
|
|
2533
|
+
const results = await runChecksOnce(loaded, proxied, snapshot, judgeConfig);
|
|
2455
2534
|
if (sample === 0) primary = results;
|
|
2456
2535
|
for (const result of results) {
|
|
2457
2536
|
passCounts.set(result.id, (passCounts.get(result.id) ?? 0) + (result.pass ? 1 : 0));
|
|
@@ -2468,9 +2547,9 @@ async function rejudgeTaskRun(runId, endpoints, options = {}) {
|
|
|
2468
2547
|
taskId: detail.task_id,
|
|
2469
2548
|
definitionRevisionId: revisionId,
|
|
2470
2549
|
definitionRevisionIsPinned: revisionIsPinned,
|
|
2471
|
-
judge:
|
|
2472
|
-
model:
|
|
2473
|
-
baseURL:
|
|
2550
|
+
judge: judgeConfig ? {
|
|
2551
|
+
model: judgeConfig.model,
|
|
2552
|
+
baseURL: judgeConfig.baseURL ?? process.env.OPENROUTER_BASE_URL
|
|
2474
2553
|
} : null,
|
|
2475
2554
|
samples,
|
|
2476
2555
|
checks: aggregate.checks,
|