@apo-ai/sdk 0.11.0 → 0.13.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/dist/agent-task/integrations/ai-sdk.d.ts +1 -1
- package/dist/agent-task/integrations/anthropic.d.ts +1 -1
- package/dist/agent-task/integrations/anthropic.js +2 -2
- package/dist/agent-task/integrations/openai.d.ts +1 -1
- package/dist/agent-task/integrations/openai.js +2 -2
- package/dist/agent-task/public.d.ts +10 -3
- package/dist/agent-task/public.js +272 -35
- package/dist/agent-task/public.js.map +1 -1
- package/dist/{chunk-P43KL5AR.js → chunk-A3UYQ7M4.js} +3 -2
- package/dist/{chunk-P43KL5AR.js.map → chunk-A3UYQ7M4.js.map} +1 -1
- package/dist/{chunk-Z64A566W.js → chunk-JTWQD27M.js} +2 -1
- package/dist/chunk-JTWQD27M.js.map +1 -0
- package/dist/{chunk-LO343UZO.js → chunk-P24ECOI3.js} +4 -2
- package/dist/chunk-P24ECOI3.js.map +1 -0
- package/dist/{chunk-6H2GACBG.js → chunk-X73JGMK3.js} +3 -2
- package/dist/{chunk-6H2GACBG.js.map → chunk-X73JGMK3.js.map} +1 -1
- package/dist/otel/index.js +1 -1
- package/dist/{tracing-DoIGvJW1.d.ts → tracing-FqFObrmt.d.ts} +5 -0
- package/package.json +1 -1
- package/dist/chunk-LO343UZO.js.map +0 -1
- package/dist/chunk-Z64A566W.js.map +0 -1
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// Do not edit by hand — edit the src/ originals and rebuild.
|
|
3
3
|
import {
|
|
4
4
|
createApoAnthropic
|
|
5
|
-
} from "../../chunk-
|
|
6
|
-
import "../../chunk-
|
|
5
|
+
} from "../../chunk-X73JGMK3.js";
|
|
6
|
+
import "../../chunk-JTWQD27M.js";
|
|
7
7
|
export {
|
|
8
8
|
createApoAnthropic
|
|
9
9
|
};
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// Do not edit by hand — edit the src/ originals and rebuild.
|
|
3
3
|
import {
|
|
4
4
|
createApoOpenAI
|
|
5
|
-
} from "../../chunk-
|
|
6
|
-
import "../../chunk-
|
|
5
|
+
} from "../../chunk-A3UYQ7M4.js";
|
|
6
|
+
import "../../chunk-JTWQD27M.js";
|
|
7
7
|
export {
|
|
8
8
|
createApoOpenAI
|
|
9
9
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as AgentTaskTraceContext, a as AgentTaskTraceOptions } from '../tracing-
|
|
1
|
+
import { A as AgentTaskTraceContext, a as AgentTaskTraceOptions } from '../tracing-FqFObrmt.js';
|
|
2
2
|
export { CreateApoTracerOptions, createApoTracer } from './integrations/ai-sdk.js';
|
|
3
3
|
export { CreateApoOpenAIOptions, createApoOpenAI } from './integrations/openai.js';
|
|
4
4
|
export { CreateApoAnthropicOptions, createApoAnthropic } from './integrations/anthropic.js';
|
|
@@ -673,6 +673,13 @@ type JudgeMetadata = {
|
|
|
673
673
|
* the decision model, and `response` carries its typed verdict.
|
|
674
674
|
*/
|
|
675
675
|
verdict_by?: "second-judge";
|
|
676
|
+
/**
|
|
677
|
+
* How many attempts of this call were cut because the judge's stream fell
|
|
678
|
+
* into a repetition loop (`t.judge` only). Absent = none. 1 with a verdict:
|
|
679
|
+
* the first draw looped and the retry answered. A call whose last draw
|
|
680
|
+
* looped has no verdict and is recorded as a judge error.
|
|
681
|
+
*/
|
|
682
|
+
reasoning_loops?: number;
|
|
676
683
|
};
|
|
677
684
|
/**
|
|
678
685
|
* Evidence from the second grader. `error` is set when the decisions
|
|
@@ -2318,8 +2325,8 @@ declare function getActiveApoRun(): ApoRunContext | undefined;
|
|
|
2318
2325
|
*
|
|
2319
2326
|
* Pure, dependency-free canonicalizer. Both this module and its Python twin
|
|
2320
2327
|
* (`backend/apo/execution/task_revision_manifest.py`) MUST produce
|
|
2321
|
-
* byte-identical canonical JSON and digests for
|
|
2322
|
-
*
|
|
2328
|
+
* byte-identical canonical JSON and digests for any given file tree — the
|
|
2329
|
+
* task-revision identity is content-addressed on both sides of the wire.
|
|
2323
2330
|
*
|
|
2324
2331
|
* Canonicalization rules:
|
|
2325
2332
|
* - `/` path separators (caller `\` normalized to `/`);
|
|
@@ -9,20 +9,20 @@ import {
|
|
|
9
9
|
resolveApoAuthHeaders,
|
|
10
10
|
withApoRun,
|
|
11
11
|
withApoRunSync
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-P24ECOI3.js";
|
|
13
13
|
import {
|
|
14
14
|
createApoTracer
|
|
15
15
|
} from "../chunk-OZWOLCJ5.js";
|
|
16
16
|
import "../chunk-HRYXLRXJ.js";
|
|
17
17
|
import {
|
|
18
18
|
createApoOpenAI
|
|
19
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-A3UYQ7M4.js";
|
|
20
20
|
import {
|
|
21
21
|
createApoAnthropic
|
|
22
|
-
} from "../chunk-
|
|
22
|
+
} from "../chunk-X73JGMK3.js";
|
|
23
23
|
import {
|
|
24
24
|
servingHostFromBaseURL
|
|
25
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-JTWQD27M.js";
|
|
26
26
|
|
|
27
27
|
// src/agent-task/run/steer-scheduler.ts
|
|
28
28
|
var TASK_STEER_SPAN_NAME = "task.steer";
|
|
@@ -644,6 +644,158 @@ function levenshtein(a, b) {
|
|
|
644
644
|
// src/agent-task/checks/judge.ts
|
|
645
645
|
import { createHash } from "crypto";
|
|
646
646
|
|
|
647
|
+
// src/agent-task/checks/reasoning-loop.ts
|
|
648
|
+
var MAX_UNIT_CHARS = 64;
|
|
649
|
+
var MIN_UNIT_COPIES = 100;
|
|
650
|
+
var MIN_REPEAT_CHARS = 1e3;
|
|
651
|
+
var MAX_CHAR_RUN = 3;
|
|
652
|
+
var GRAM = 24;
|
|
653
|
+
var DIVERSITY_WINDOW = 3e3;
|
|
654
|
+
var MIN_DIVERSITY = 0.1;
|
|
655
|
+
var DIVERSITY_STRIDE = 256;
|
|
656
|
+
var MAX_DIVERSITY_LINE_CHARS = 2e3;
|
|
657
|
+
var RECYCLE_GRAM = 32;
|
|
658
|
+
var RECYCLE_WINDOW = 5e3;
|
|
659
|
+
var MAX_RECYCLED = 0.95;
|
|
660
|
+
var isFoldable = (ch) => /[\p{L}\p{N}]/u.test(ch);
|
|
661
|
+
function foldForRepetition(text) {
|
|
662
|
+
let out = "";
|
|
663
|
+
let last = "";
|
|
664
|
+
let run = 0;
|
|
665
|
+
for (const raw of text) {
|
|
666
|
+
if (!isFoldable(raw)) continue;
|
|
667
|
+
const ch = raw.toLowerCase();
|
|
668
|
+
run = ch === last ? run + 1 : 1;
|
|
669
|
+
last = ch;
|
|
670
|
+
if (run <= MAX_CHAR_RUN) out += ch;
|
|
671
|
+
}
|
|
672
|
+
return out;
|
|
673
|
+
}
|
|
674
|
+
function isTableLine(line) {
|
|
675
|
+
const trimmed = line.trim();
|
|
676
|
+
if (trimmed.startsWith("|")) return true;
|
|
677
|
+
return (trimmed.match(/\|/g)?.length ?? 0) >= 3;
|
|
678
|
+
}
|
|
679
|
+
function diversity(folded) {
|
|
680
|
+
const total = folded.length - GRAM + 1;
|
|
681
|
+
if (total <= 0) return 1;
|
|
682
|
+
const grams = /* @__PURE__ */ new Set();
|
|
683
|
+
for (let i = 0; i < total; i++) grams.add(folded.slice(i, i + GRAM));
|
|
684
|
+
return grams.size / total;
|
|
685
|
+
}
|
|
686
|
+
var RepetitionGuard = class {
|
|
687
|
+
constructor(opts) {
|
|
688
|
+
this.rawChars = 0;
|
|
689
|
+
// Repeated-unit state: the folded tail, and for each period p the number
|
|
690
|
+
// of consecutive folded chars equal to the char p before them.
|
|
691
|
+
this.tail = "";
|
|
692
|
+
this.lastChar = "";
|
|
693
|
+
this.charRun = 0;
|
|
694
|
+
this.periodRuns = new Array(MAX_UNIT_CHARS + 1).fill(0);
|
|
695
|
+
// Low-diversity state: the current raw line, and the folded window built
|
|
696
|
+
// from finished lines that are not tables.
|
|
697
|
+
this.line = "";
|
|
698
|
+
this.window = "";
|
|
699
|
+
this.sinceMeasured = 0;
|
|
700
|
+
// Recycled state: every gram of the filtered folded stream so far, and for
|
|
701
|
+
// the window's grams whether each had been seen when it arrived.
|
|
702
|
+
this.seenGrams = /* @__PURE__ */ new Set();
|
|
703
|
+
this.gramTail = "";
|
|
704
|
+
this.windowFlags = [];
|
|
705
|
+
this.flagHead = 0;
|
|
706
|
+
this.recycledInWindow = 0;
|
|
707
|
+
this.checkDiversity = opts.diversity;
|
|
708
|
+
}
|
|
709
|
+
get tripped() {
|
|
710
|
+
return this.trip;
|
|
711
|
+
}
|
|
712
|
+
push(delta) {
|
|
713
|
+
if (this.trip || !delta) return this.trip;
|
|
714
|
+
for (const raw of delta) {
|
|
715
|
+
this.rawChars++;
|
|
716
|
+
if (this.checkDiversity) this.pushLineChar(raw);
|
|
717
|
+
if (isFoldable(raw)) this.pushFolded(raw.toLowerCase());
|
|
718
|
+
if (this.trip) break;
|
|
719
|
+
}
|
|
720
|
+
return this.trip;
|
|
721
|
+
}
|
|
722
|
+
pushFolded(ch) {
|
|
723
|
+
this.charRun = ch === this.lastChar ? this.charRun + 1 : 1;
|
|
724
|
+
this.lastChar = ch;
|
|
725
|
+
if (this.charRun > MAX_CHAR_RUN) return;
|
|
726
|
+
this.tail += ch;
|
|
727
|
+
const n = this.tail.length - 1;
|
|
728
|
+
for (let p = 1; p <= MAX_UNIT_CHARS; p++) {
|
|
729
|
+
this.periodRuns[p] = n >= p && this.tail[n - p] === ch ? this.periodRuns[p] + 1 : 0;
|
|
730
|
+
const span = this.periodRuns[p] + p;
|
|
731
|
+
if (span >= MIN_REPEAT_CHARS && span / p >= MIN_UNIT_COPIES) {
|
|
732
|
+
this.trip = {
|
|
733
|
+
rule: "repeated-unit",
|
|
734
|
+
atChar: this.rawChars,
|
|
735
|
+
unit: this.tail.slice(-p),
|
|
736
|
+
copies: Math.floor(span / p)
|
|
737
|
+
};
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
if (this.tail.length > MAX_UNIT_CHARS * 2) this.tail = this.tail.slice(-MAX_UNIT_CHARS);
|
|
742
|
+
}
|
|
743
|
+
pushLineChar(raw) {
|
|
744
|
+
if (raw !== "\n") {
|
|
745
|
+
if (this.line.length <= MAX_DIVERSITY_LINE_CHARS) this.line += raw;
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
const line = this.line;
|
|
749
|
+
this.line = "";
|
|
750
|
+
if (line.length > MAX_DIVERSITY_LINE_CHARS || isTableLine(line)) return;
|
|
751
|
+
const folded = foldForRepetition(line);
|
|
752
|
+
if (!folded) return;
|
|
753
|
+
this.pushRecycled(folded);
|
|
754
|
+
this.window = (this.window + folded).slice(-DIVERSITY_WINDOW);
|
|
755
|
+
this.sinceMeasured += folded.length;
|
|
756
|
+
if (this.window.length < DIVERSITY_WINDOW || this.sinceMeasured < DIVERSITY_STRIDE) return;
|
|
757
|
+
this.sinceMeasured = 0;
|
|
758
|
+
const ratio = diversity(this.window);
|
|
759
|
+
if (ratio < MIN_DIVERSITY) {
|
|
760
|
+
this.trip = { rule: "low-diversity", atChar: this.rawChars, diversity: ratio };
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
const windowGrams = this.windowFlags.length - this.flagHead;
|
|
764
|
+
if (windowGrams < RECYCLE_WINDOW) return;
|
|
765
|
+
const recycled = this.recycledInWindow / windowGrams;
|
|
766
|
+
if (recycled >= MAX_RECYCLED) {
|
|
767
|
+
this.trip = { rule: "recycled", atChar: this.rawChars, recycled };
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
pushRecycled(folded) {
|
|
771
|
+
for (const ch of folded) {
|
|
772
|
+
this.gramTail = (this.gramTail + ch).slice(-RECYCLE_GRAM);
|
|
773
|
+
if (this.gramTail.length < RECYCLE_GRAM) continue;
|
|
774
|
+
const seen = this.seenGrams.has(this.gramTail);
|
|
775
|
+
if (!seen) this.seenGrams.add(this.gramTail);
|
|
776
|
+
this.windowFlags.push(seen);
|
|
777
|
+
if (seen) this.recycledInWindow++;
|
|
778
|
+
if (this.windowFlags.length - this.flagHead > RECYCLE_WINDOW) {
|
|
779
|
+
if (this.windowFlags[this.flagHead++]) this.recycledInWindow--;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
if (this.flagHead > RECYCLE_WINDOW * 4) {
|
|
783
|
+
this.windowFlags.splice(0, this.flagHead);
|
|
784
|
+
this.flagHead = 0;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
function describeTrip(trip) {
|
|
789
|
+
switch (trip.rule) {
|
|
790
|
+
case "repeated-unit":
|
|
791
|
+
return `"${trip.unit}" repeated ${trip.copies}\xD7 at char ${trip.atChar}`;
|
|
792
|
+
case "low-diversity":
|
|
793
|
+
return `distinct-${GRAM}-gram ratio ${trip.diversity.toFixed(3)} at char ${trip.atChar}`;
|
|
794
|
+
case "recycled":
|
|
795
|
+
return `${Math.round(trip.recycled * 100)}% of the last ${RECYCLE_WINDOW} chars replay earlier reasoning, at char ${trip.atChar}`;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
647
799
|
// src/agent-task/checks/second-judge.ts
|
|
648
800
|
function secondJudgeFacts(check) {
|
|
649
801
|
const sj = check.judge?.secondJudge;
|
|
@@ -828,6 +980,16 @@ var JudgeUnavailableError = class extends Error {
|
|
|
828
980
|
this.name = "JudgeUnavailableError";
|
|
829
981
|
}
|
|
830
982
|
};
|
|
983
|
+
var JudgeReasoningLoopError = class extends JudgeUnavailableError {
|
|
984
|
+
constructor(trip, channel) {
|
|
985
|
+
super(`judge reasoning loop: ${channel} ${describeTrip(trip)}`);
|
|
986
|
+
this.name = "JudgeReasoningLoopError";
|
|
987
|
+
}
|
|
988
|
+
};
|
|
989
|
+
function isJudgeLoopGuardEnabled() {
|
|
990
|
+
const value = process.env.APO_JUDGE_LOOP_GUARD?.trim().toLowerCase();
|
|
991
|
+
return value !== "0" && value !== "false" && value !== "off";
|
|
992
|
+
}
|
|
831
993
|
var QUOTE_RULE = " Inside the reasoning, quote the output with single quotes, never with unescaped double quotes.";
|
|
832
994
|
var VERDICT_FIRST_CONTRACT = 'Respond with ONLY a JSON object: {"pass": true/false, "reasoning": "your reasoning"}.' + QUOTE_RULE;
|
|
833
995
|
var REASONING_FIRST_CONTRACT = 'Respond with ONLY a JSON object: {"reasoning": "your reasoning", "pass": true/false}.' + QUOTE_RULE;
|
|
@@ -952,7 +1114,7 @@ function retryDelayMs(retryAfter) {
|
|
|
952
1114
|
if (!Number.isFinite(ms)) return JUDGE_RETRY_DELAY_MS;
|
|
953
1115
|
return Math.min(Math.max(ms, JUDGE_RETRY_DELAY_MS), JUDGE_RETRY_AFTER_CAP_MS);
|
|
954
1116
|
}
|
|
955
|
-
async function readCompletion(response, onData) {
|
|
1117
|
+
async function readCompletion(response, onData, guards) {
|
|
956
1118
|
const contentType = response.headers.get("content-type") ?? "";
|
|
957
1119
|
if (!contentType.includes("text/event-stream")) {
|
|
958
1120
|
const data = await response.json();
|
|
@@ -989,7 +1151,15 @@ async function readCompletion(response, onData) {
|
|
|
989
1151
|
}
|
|
990
1152
|
if (!chunk) return;
|
|
991
1153
|
const choice = chunk.choices?.[0];
|
|
992
|
-
|
|
1154
|
+
const content = choice?.delta?.content ?? "";
|
|
1155
|
+
text += content;
|
|
1156
|
+
if (guards) {
|
|
1157
|
+
const thinking = choice?.delta?.reasoning_content ?? choice?.delta?.reasoning ?? "";
|
|
1158
|
+
const reasoningTrip = guards.reasoning.push(thinking);
|
|
1159
|
+
if (reasoningTrip) throw new JudgeReasoningLoopError(reasoningTrip, "reasoning");
|
|
1160
|
+
const contentTrip = guards.content.push(content);
|
|
1161
|
+
if (contentTrip) throw new JudgeReasoningLoopError(contentTrip, "content");
|
|
1162
|
+
}
|
|
993
1163
|
if (choice?.finish_reason) finishReason = choice.finish_reason;
|
|
994
1164
|
if (chunk.usage) usage = chunk.usage;
|
|
995
1165
|
};
|
|
@@ -1023,7 +1193,13 @@ async function readCompletion(response, onData) {
|
|
|
1023
1193
|
dispatch();
|
|
1024
1194
|
return { text, usage, finishReason };
|
|
1025
1195
|
}
|
|
1026
|
-
var
|
|
1196
|
+
var prefixLanes = /* @__PURE__ */ new Map();
|
|
1197
|
+
function judgeConcurrency() {
|
|
1198
|
+
const raw = process.env.APO_JUDGE_CONCURRENCY?.trim();
|
|
1199
|
+
if (!raw) return 1;
|
|
1200
|
+
const n = Number(raw);
|
|
1201
|
+
return Number.isInteger(n) && n >= 1 ? n : 1;
|
|
1202
|
+
}
|
|
1027
1203
|
function promptCacheKey(prefix) {
|
|
1028
1204
|
return `apo-${createHash("sha256").update(prefix).digest("hex").slice(0, 32)}`;
|
|
1029
1205
|
}
|
|
@@ -1055,16 +1231,36 @@ async function fetchWithPromptCacheKey(input, init) {
|
|
|
1055
1231
|
return retry;
|
|
1056
1232
|
}
|
|
1057
1233
|
function runWithSharedPrefix(key, task2) {
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
key,
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1234
|
+
const existing = prefixLanes.get(key);
|
|
1235
|
+
if (!existing) {
|
|
1236
|
+
const warmer = task2();
|
|
1237
|
+
prefixLanes.set(key, {
|
|
1238
|
+
warmed: warmer.then(
|
|
1239
|
+
() => void 0,
|
|
1240
|
+
() => void 0
|
|
1241
|
+
),
|
|
1242
|
+
active: 0,
|
|
1243
|
+
waiting: []
|
|
1244
|
+
});
|
|
1245
|
+
return warmer;
|
|
1246
|
+
}
|
|
1247
|
+
const lane = existing;
|
|
1248
|
+
const acquire = () => new Promise((resolve5) => {
|
|
1249
|
+
if (lane.active < judgeConcurrency()) {
|
|
1250
|
+
lane.active += 1;
|
|
1251
|
+
resolve5();
|
|
1252
|
+
} else {
|
|
1253
|
+
lane.waiting.push(() => {
|
|
1254
|
+
lane.active += 1;
|
|
1255
|
+
resolve5();
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
1258
|
+
});
|
|
1259
|
+
const release = () => {
|
|
1260
|
+
lane.active -= 1;
|
|
1261
|
+
lane.waiting.shift()?.();
|
|
1262
|
+
};
|
|
1263
|
+
return lane.warmed.then(acquire).then(() => task2().finally(release));
|
|
1068
1264
|
}
|
|
1069
1265
|
function defaultJudgeBaseURL(baseURL) {
|
|
1070
1266
|
return baseURL ?? process.env.OPENROUTER_BASE_URL ?? "https://openrouter.ai/api/v1";
|
|
@@ -1166,9 +1362,16 @@ async function callJudge(args) {
|
|
|
1166
1362
|
...schema && response.status === 400 && /json_schema|response_format/.test(body) ? { schemaRejected: true } : {}
|
|
1167
1363
|
};
|
|
1168
1364
|
}
|
|
1365
|
+
const guards = isJudgeLoopGuardEnabled() ? {
|
|
1366
|
+
reasoning: new RepetitionGuard({ diversity: true }),
|
|
1367
|
+
content: new RepetitionGuard({ diversity: false })
|
|
1368
|
+
} : void 0;
|
|
1169
1369
|
try {
|
|
1170
|
-
return { kind: "completion", completion: await readCompletion(response, onData) };
|
|
1370
|
+
return { kind: "completion", completion: await readCompletion(response, onData, guards) };
|
|
1171
1371
|
} catch (error) {
|
|
1372
|
+
if (error instanceof JudgeReasoningLoopError) {
|
|
1373
|
+
return { kind: "unavailable", error, retryable: true, loop: true };
|
|
1374
|
+
}
|
|
1172
1375
|
return transportFailure("Judge response failed", controller.signal.reason ?? error);
|
|
1173
1376
|
}
|
|
1174
1377
|
} finally {
|
|
@@ -1202,6 +1405,7 @@ async function callJudge(args) {
|
|
|
1202
1405
|
if (result.schemaRejected) schema = false;
|
|
1203
1406
|
result = await attempt(stream, schema, deadline);
|
|
1204
1407
|
}
|
|
1408
|
+
let loops = result.kind === "unavailable" && result.loop ? 1 : 0;
|
|
1205
1409
|
const noVerdict = (r) => r.kind === "completion" && (isTruncated(r.completion) || judgeVerdict(r.completion.text) === void 0);
|
|
1206
1410
|
const retryable = result.kind === "unavailable" && result.retryable;
|
|
1207
1411
|
if (noVerdict(result) || retryable) {
|
|
@@ -1210,6 +1414,7 @@ async function callJudge(args) {
|
|
|
1210
1414
|
await new Promise((resolve5) => setTimeout(resolve5, delay));
|
|
1211
1415
|
const first = result;
|
|
1212
1416
|
result = await attempt(stream, schema, deadline);
|
|
1417
|
+
if (result.kind === "unavailable" && result.loop) loops++;
|
|
1213
1418
|
if (result.kind === "unavailable" && first.kind === "unavailable") {
|
|
1214
1419
|
result = {
|
|
1215
1420
|
...result,
|
|
@@ -1220,17 +1425,25 @@ async function callJudge(args) {
|
|
|
1220
1425
|
}
|
|
1221
1426
|
}
|
|
1222
1427
|
}
|
|
1223
|
-
|
|
1224
|
-
const { text, usage } = result.completion;
|
|
1225
|
-
const judge = {
|
|
1428
|
+
const judgeMetadata = async (completion) => ({
|
|
1226
1429
|
model: args.model,
|
|
1227
1430
|
contract: judgeContractInUse(),
|
|
1228
1431
|
prompt: { system: systemPromptText, user: instructionText },
|
|
1229
|
-
response: text,
|
|
1230
|
-
tokens: parseJudgeUsage(usage),
|
|
1432
|
+
...completion ? { response: completion.text, tokens: parseJudgeUsage(completion.usage) } : {},
|
|
1231
1433
|
latency_ms: Date.now() - startedAt,
|
|
1232
|
-
secondJudge: await secondJudgePromise
|
|
1233
|
-
|
|
1434
|
+
secondJudge: await secondJudgePromise,
|
|
1435
|
+
...loops > 0 ? { reasoning_loops: loops } : {}
|
|
1436
|
+
});
|
|
1437
|
+
if (result.kind === "unavailable" && result.loop) {
|
|
1438
|
+
return {
|
|
1439
|
+
pass: false,
|
|
1440
|
+
reasoning: `Judge reasoning loop \u2014 the judge's stream degenerated into repetition and was cut${loops > 1 ? ", on the retry too" : ""} (${result.error.message}). The verdict is unknown, so this check is recorded as a judge error, not a verdict.`,
|
|
1441
|
+
judge: await judgeMetadata(),
|
|
1442
|
+
unavailable: true
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1445
|
+
if (result.kind === "unavailable") throw result.error;
|
|
1446
|
+
const judge = await judgeMetadata(result.completion);
|
|
1234
1447
|
if (isTruncated(result.completion)) {
|
|
1235
1448
|
return {
|
|
1236
1449
|
pass: false,
|
|
@@ -1239,11 +1452,11 @@ async function callJudge(args) {
|
|
|
1239
1452
|
unavailable: true
|
|
1240
1453
|
};
|
|
1241
1454
|
}
|
|
1242
|
-
const verdict = judgeVerdict(text);
|
|
1455
|
+
const verdict = judgeVerdict(result.completion.text);
|
|
1243
1456
|
if (verdict === void 0) {
|
|
1244
1457
|
return {
|
|
1245
1458
|
pass: false,
|
|
1246
|
-
reasoning: "Judge reply carried no verdict (no boolean `pass`)
|
|
1459
|
+
reasoning: "Judge reply carried no verdict (no boolean `pass`). The verdict is unknown, so this check is recorded as a judge error, not a verdict. The raw reply is on the judge metadata.",
|
|
1247
1460
|
judge,
|
|
1248
1461
|
unavailable: true
|
|
1249
1462
|
};
|
|
@@ -1886,10 +2099,15 @@ function buildEvidenceTools(args) {
|
|
|
1886
2099
|
}
|
|
1887
2100
|
const unsupported = rejectUnsupportedPcreConstructs(pattern);
|
|
1888
2101
|
if (unsupported) return { error: unsupported };
|
|
2102
|
+
let translated;
|
|
2103
|
+
try {
|
|
2104
|
+
translated = stripLeadingPcreFlags(pattern);
|
|
2105
|
+
} catch (error) {
|
|
2106
|
+
return { error: `invalid regex: ${error instanceof Error ? error.message : String(error)}` };
|
|
2107
|
+
}
|
|
1889
2108
|
let re;
|
|
1890
2109
|
try {
|
|
1891
|
-
|
|
1892
|
-
re = new RegExp(stripped.pattern, stripped.flags);
|
|
2110
|
+
re = new RegExp(translated.pattern, translated.flags);
|
|
1893
2111
|
} catch (error) {
|
|
1894
2112
|
return {
|
|
1895
2113
|
error: `invalid regex: ${error instanceof Error ? error.message : String(error)} \u2014 patterns compile as case-insensitive multiline; leading PCRE flags like (?i) are stripped automatically`
|
|
@@ -4410,12 +4628,13 @@ function sleep(ms) {
|
|
|
4410
4628
|
|
|
4411
4629
|
// src/agent-task/checks/agent-history.ts
|
|
4412
4630
|
function createBackendReaderFromEnv(env = process.env) {
|
|
4631
|
+
const apiKey = env.APO_API_KEY;
|
|
4413
4632
|
const token = env.APO_AUTH_TOKEN;
|
|
4414
4633
|
const publicKey = env.APO_PUBLIC_KEY;
|
|
4415
4634
|
const secretKey = env.APO_SECRET_KEY;
|
|
4416
|
-
const headers = token ? { Authorization: `Bearer ${token}` } : publicKey && secretKey ? { Authorization: `Basic ${Buffer.from(`${publicKey}:${secretKey}`).toString("base64")}` } : void 0;
|
|
4635
|
+
const headers = apiKey ? { Authorization: `Bearer ${apiKey}` } : token ? { Authorization: `Bearer ${token}` } : publicKey && secretKey ? { Authorization: `Basic ${Buffer.from(`${publicKey}:${secretKey}`).toString("base64")}` } : void 0;
|
|
4417
4636
|
if (!headers) return void 0;
|
|
4418
|
-
const endpoint = env.APO_BACKEND_URL ??
|
|
4637
|
+
const endpoint = env.APO_BACKEND_URL ?? "http://127.0.0.1:8000";
|
|
4419
4638
|
return {
|
|
4420
4639
|
async get(path) {
|
|
4421
4640
|
const res = await fetch(`${endpoint.replace(/\/$/, "")}/v1${path}`, { headers });
|
|
@@ -4429,10 +4648,23 @@ function createBackendReaderFromEnv(env = process.env) {
|
|
|
4429
4648
|
function freezeHistoryPlane(args) {
|
|
4430
4649
|
const { reader, taskId, selfRunId } = args;
|
|
4431
4650
|
const detailCache = /* @__PURE__ */ new Map();
|
|
4651
|
+
const listByTaskId = async (id) => await reader.get(
|
|
4652
|
+
`/agent-task-runs?task_id=${encodeURIComponent(id)}&limit=50`
|
|
4653
|
+
);
|
|
4432
4654
|
const loadRuns = (async () => {
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4655
|
+
let raw = await listByTaskId(taskId);
|
|
4656
|
+
if ((raw ?? []).length === 0 && selfRunId) {
|
|
4657
|
+
try {
|
|
4658
|
+
const self = await reader.get(
|
|
4659
|
+
`/agent-task-runs/${encodeURIComponent(selfRunId)}`
|
|
4660
|
+
);
|
|
4661
|
+
const canonical = self?.task_id;
|
|
4662
|
+
if (typeof canonical === "string" && canonical !== taskId) {
|
|
4663
|
+
raw = await listByTaskId(canonical);
|
|
4664
|
+
}
|
|
4665
|
+
} catch {
|
|
4666
|
+
}
|
|
4667
|
+
}
|
|
4436
4668
|
return (raw ?? []).map(
|
|
4437
4669
|
(r) => ({
|
|
4438
4670
|
id: String(r.id),
|
|
@@ -4496,7 +4728,9 @@ async function freezeHistoryPlaneFromEnv(taskId, env = process.env) {
|
|
|
4496
4728
|
taskId,
|
|
4497
4729
|
...env.AGENT_TASK_RUN_ID ? { selfRunId: env.AGENT_TASK_RUN_ID } : {}
|
|
4498
4730
|
});
|
|
4499
|
-
} catch {
|
|
4731
|
+
} catch (error) {
|
|
4732
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
4733
|
+
console.warn(`apo: judge history plane unavailable \u2014 ${reason}`);
|
|
4500
4734
|
return void 0;
|
|
4501
4735
|
}
|
|
4502
4736
|
}
|
|
@@ -6365,6 +6599,9 @@ function createOtelAgentTaskTraceClient(config) {
|
|
|
6365
6599
|
params.reasoning_tokens
|
|
6366
6600
|
);
|
|
6367
6601
|
}
|
|
6602
|
+
if (params.served_model) {
|
|
6603
|
+
active.span.setAttribute("gen_ai.response.model", params.served_model);
|
|
6604
|
+
}
|
|
6368
6605
|
if (params.status_message) {
|
|
6369
6606
|
active.span.setAttribute("apo.status_message", params.status_message);
|
|
6370
6607
|
}
|