@apo-ai/sdk 0.9.2 → 0.9.3
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.
|
@@ -377,6 +377,9 @@ function levenshtein(a, b) {
|
|
|
377
377
|
return prev[n];
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
+
// src/agent-task/checks/judge.ts
|
|
381
|
+
import { createHash } from "crypto";
|
|
382
|
+
|
|
380
383
|
// src/agent-task/checks/second-judge.ts
|
|
381
384
|
var SECOND_JUDGE_TIMEOUT_MS = 3e4;
|
|
382
385
|
function resolveSecondJudgeModel() {
|
|
@@ -644,6 +647,36 @@ async function readCompletion(response, onData) {
|
|
|
644
647
|
return { text, usage, finishReason };
|
|
645
648
|
}
|
|
646
649
|
var prefixQueues = /* @__PURE__ */ new Map();
|
|
650
|
+
function promptCacheKey(prefix) {
|
|
651
|
+
return `apo-${createHash("sha256").update(prefix).digest("hex").slice(0, 32)}`;
|
|
652
|
+
}
|
|
653
|
+
var cacheKeyRejectedBy = /* @__PURE__ */ new Set();
|
|
654
|
+
var CACHE_KEY_REJECTED = /(unknown|unrecogni[sz]ed|unsupported|unexpected|extra|not permitted|not allowed|cannot find|invalid)[^\n]{0,80}prompt_cache_key|prompt_cache_key[^\n]{0,80}(unknown|unrecogni[sz]ed|unsupported|unexpected|not permitted|not allowed|not supported|extra)/i;
|
|
655
|
+
function rejectsPromptCacheKey(status, body) {
|
|
656
|
+
return status === 400 && CACHE_KEY_REJECTED.test(body);
|
|
657
|
+
}
|
|
658
|
+
async function fetchWithPromptCacheKey(input, init) {
|
|
659
|
+
let body;
|
|
660
|
+
try {
|
|
661
|
+
body = typeof init?.body === "string" ? JSON.parse(init.body) : void 0;
|
|
662
|
+
} catch {
|
|
663
|
+
body = void 0;
|
|
664
|
+
}
|
|
665
|
+
if (!body || !("prompt_cache_key" in body)) return fetch(input, init);
|
|
666
|
+
const scope = `${input instanceof Request ? input.url : String(input)}\0${String(body.model)}`;
|
|
667
|
+
const { prompt_cache_key: _omitted, ...rest } = body;
|
|
668
|
+
const withoutKey = () => fetch(input, { ...init, body: JSON.stringify(rest) });
|
|
669
|
+
if (cacheKeyRejectedBy.has(scope)) return withoutKey();
|
|
670
|
+
const response = await fetch(input, init);
|
|
671
|
+
if (response.status !== 400) return response;
|
|
672
|
+
const text = await response.text();
|
|
673
|
+
if (!rejectsPromptCacheKey(response.status, text)) {
|
|
674
|
+
return new Response(text, { status: response.status, statusText: response.statusText, headers: response.headers });
|
|
675
|
+
}
|
|
676
|
+
const retry = await withoutKey();
|
|
677
|
+
if (retry.ok) cacheKeyRejectedBy.add(scope);
|
|
678
|
+
return retry;
|
|
679
|
+
}
|
|
647
680
|
function runWithSharedPrefix(key, task2) {
|
|
648
681
|
const prev = prefixQueues.get(key) ?? Promise.resolve();
|
|
649
682
|
const next = prev.then(task2, task2);
|
|
@@ -684,6 +717,7 @@ ${instructionText}`,
|
|
|
684
717
|
const cacheKey = `${args.model}\0${briefingText}\0${deliverableText}`;
|
|
685
718
|
const requestBody = (stream) => JSON.stringify({
|
|
686
719
|
model: args.model,
|
|
720
|
+
prompt_cache_key: promptCacheKey(cacheKey),
|
|
687
721
|
messages: [
|
|
688
722
|
{
|
|
689
723
|
role: "system",
|
|
@@ -718,7 +752,7 @@ ${instructionText}`,
|
|
|
718
752
|
try {
|
|
719
753
|
let response;
|
|
720
754
|
try {
|
|
721
|
-
response = await
|
|
755
|
+
response = await fetchWithPromptCacheKey(`${baseURL}/chat/completions`, {
|
|
722
756
|
method: "POST",
|
|
723
757
|
signal: controller.signal,
|
|
724
758
|
headers: {
|
|
@@ -860,7 +894,7 @@ ${args.instruction}`
|
|
|
860
894
|
}
|
|
861
895
|
|
|
862
896
|
// src/agent-task/checks/agent-session.ts
|
|
863
|
-
import { createHash as
|
|
897
|
+
import { createHash as createHash3 } from "crypto";
|
|
864
898
|
|
|
865
899
|
// src/agent-task/tracing.ts
|
|
866
900
|
function createNoopAgentTaskTraceContext() {
|
|
@@ -908,7 +942,7 @@ function isTraceableSpanId(spanId) {
|
|
|
908
942
|
}
|
|
909
943
|
|
|
910
944
|
// src/agent-task/checks/mcp-tools.ts
|
|
911
|
-
import { createHash } from "crypto";
|
|
945
|
+
import { createHash as createHash2 } from "crypto";
|
|
912
946
|
import { isAbsolute, resolve } from "path";
|
|
913
947
|
import { readFile } from "fs/promises";
|
|
914
948
|
var DEFAULT_TOOL_TIMEOUT_MS = 3e4;
|
|
@@ -1065,7 +1099,7 @@ function validateMcpServerConfig(server, where) {
|
|
|
1065
1099
|
}
|
|
1066
1100
|
}
|
|
1067
1101
|
function sha256(text) {
|
|
1068
|
-
return
|
|
1102
|
+
return createHash2("sha256").update(text).digest("hex");
|
|
1069
1103
|
}
|
|
1070
1104
|
function renderValue(value) {
|
|
1071
1105
|
if (typeof value === "string") return value;
|
|
@@ -1259,8 +1293,17 @@ var RECORD_TEXT_LIMIT = 2 * 1024;
|
|
|
1259
1293
|
var RECORD_BRIEFING_LIMIT = 16 * 1024;
|
|
1260
1294
|
var RECORD_MAX_STEPS = 64;
|
|
1261
1295
|
var RECORD_KEEP_HEAD = 56;
|
|
1296
|
+
function sessionPrefix(body) {
|
|
1297
|
+
const messages = body.messages ?? [];
|
|
1298
|
+
const firstUser = messages.find((m) => m.role === "user");
|
|
1299
|
+
return [
|
|
1300
|
+
String(body.model),
|
|
1301
|
+
...messages.filter((m) => m.role === "system").map((m) => m.content),
|
|
1302
|
+
firstUser?.content
|
|
1303
|
+
].map((part) => typeof part === "string" ? part : JSON.stringify(part ?? null)).join("\0");
|
|
1304
|
+
}
|
|
1262
1305
|
function sha2562(text) {
|
|
1263
|
-
return
|
|
1306
|
+
return createHash3("sha256").update(text).digest("hex");
|
|
1264
1307
|
}
|
|
1265
1308
|
function renderValue2(value) {
|
|
1266
1309
|
if (typeof value === "string") return value;
|
|
@@ -1543,11 +1586,16 @@ async function runAgentSession(spec) {
|
|
|
1543
1586
|
const provider = createOpenAICompatible({
|
|
1544
1587
|
name: "openrouter",
|
|
1545
1588
|
baseURL: spec.baseURL ?? "https://openrouter.ai/api/v1",
|
|
1589
|
+
fetch: fetchWithPromptCacheKey,
|
|
1546
1590
|
apiKey: spec.apiKey ?? process.env.OPENROUTER_API_KEY ?? process.env.OPENAI_API_KEY,
|
|
1547
1591
|
// Mark the briefing prefix cacheable — repeated samples (rejudge) re-bill
|
|
1548
|
-
// nothing for the shared turn-0 context
|
|
1592
|
+
// nothing for the shared turn-0 context — and keep every step of one
|
|
1593
|
+
// session on the replica holding its growing prefix. The key is per
|
|
1594
|
+
// session (briefing + criterion): sessions run concurrently, unlike
|
|
1595
|
+
// t.judge calls, and one key per task would pile them onto one replica.
|
|
1549
1596
|
transformRequestBody: (body) => ({
|
|
1550
1597
|
...body,
|
|
1598
|
+
prompt_cache_key: promptCacheKey(sessionPrefix(body)),
|
|
1551
1599
|
messages: body.messages?.map(
|
|
1552
1600
|
(m) => m.role === "system" && typeof m.content === "string" ? { ...m, content: [{ type: "text", text: m.content, cache_control: { type: "ephemeral" } }] } : m
|
|
1553
1601
|
)
|
|
@@ -2290,7 +2338,7 @@ var Recorder = class {
|
|
|
2290
2338
|
};
|
|
2291
2339
|
|
|
2292
2340
|
// src/agent-task/checks/compact.ts
|
|
2293
|
-
import { createHash as
|
|
2341
|
+
import { createHash as createHash4 } from "crypto";
|
|
2294
2342
|
var RECEIVED_VALUE_LIMIT = 4 * 1024;
|
|
2295
2343
|
var JUDGE_SEGMENT_LIMIT = 16 * 1024;
|
|
2296
2344
|
var PREVIEW_CHARS = 256;
|
|
@@ -2398,7 +2446,7 @@ function marker(bytes) {
|
|
|
2398
2446
|
kind: "truncated",
|
|
2399
2447
|
preview,
|
|
2400
2448
|
size_bytes: bytes.length,
|
|
2401
|
-
sha256:
|
|
2449
|
+
sha256: createHash4("sha256").update(bytes).digest("hex")
|
|
2402
2450
|
};
|
|
2403
2451
|
}
|
|
2404
2452
|
function truncateSessionText(session) {
|
|
@@ -3043,7 +3091,7 @@ function isFileArtifact(value) {
|
|
|
3043
3091
|
}
|
|
3044
3092
|
|
|
3045
3093
|
// src/agent-task/deliverables/upload.ts
|
|
3046
|
-
import { createHash as
|
|
3094
|
+
import { createHash as createHash5 } from "crypto";
|
|
3047
3095
|
import { createReadStream } from "fs";
|
|
3048
3096
|
import { Readable } from "stream";
|
|
3049
3097
|
var DEFAULT_FETCH = typeof fetch === "function" ? fetch : void 0;
|
|
@@ -3098,7 +3146,7 @@ async function uploadOne(name, artifact, config) {
|
|
|
3098
3146
|
}
|
|
3099
3147
|
async function hashFile(path) {
|
|
3100
3148
|
return new Promise((resolve5, reject) => {
|
|
3101
|
-
const hash =
|
|
3149
|
+
const hash = createHash5("sha256");
|
|
3102
3150
|
let size = 0;
|
|
3103
3151
|
const stream = createReadStream(path);
|
|
3104
3152
|
stream.on("data", (chunk) => {
|
|
@@ -4338,7 +4386,7 @@ function usageOf2(raw) {
|
|
|
4338
4386
|
}
|
|
4339
4387
|
|
|
4340
4388
|
// src/agent-task/transcript-replay/otlp.ts
|
|
4341
|
-
import { createHash as
|
|
4389
|
+
import { createHash as createHash6 } from "crypto";
|
|
4342
4390
|
var SPAN_KIND_INTERNAL = 1;
|
|
4343
4391
|
var STATUS_CODE_UNSET = 0;
|
|
4344
4392
|
function transcriptSessionToOtlp(session, options = {}) {
|
|
@@ -4485,7 +4533,7 @@ function messageAttrValue(role, content) {
|
|
|
4485
4533
|
return JSON.stringify([{ role, content }]);
|
|
4486
4534
|
}
|
|
4487
4535
|
function sha256Hex(input) {
|
|
4488
|
-
return
|
|
4536
|
+
return createHash6("sha256").update(input).digest("hex");
|
|
4489
4537
|
}
|
|
4490
4538
|
function deriveTraceId(source, sessionId) {
|
|
4491
4539
|
return sha256Hex(`apo-transcript-replay|${source}|${sessionId}`).slice(0, 32);
|
|
@@ -6148,12 +6196,12 @@ function printOverallSummary(summaries, hasErrors) {
|
|
|
6148
6196
|
}
|
|
6149
6197
|
|
|
6150
6198
|
// src/agent-task/task-revision-manifest.ts
|
|
6151
|
-
import { createHash as
|
|
6199
|
+
import { createHash as createHash7 } from "crypto";
|
|
6152
6200
|
function normalizeManifestPath(path) {
|
|
6153
6201
|
return path.split("\\").join("/").normalize("NFC");
|
|
6154
6202
|
}
|
|
6155
6203
|
function sha256Hex2(bytes) {
|
|
6156
|
-
return
|
|
6204
|
+
return createHash7("sha256").update(bytes).digest("hex");
|
|
6157
6205
|
}
|
|
6158
6206
|
function compareBytewiseUtf8(a, b) {
|
|
6159
6207
|
const ba = Buffer.from(a, "utf8");
|