@wrongstack/core 0.292.0 → 0.292.1
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/coordination/index.d.ts +1 -1
- package/dist/coordination/index.d.ts.map +1 -1
- package/dist/coordination/index.js +163 -39
- package/dist/coordination/index.js.map +3 -3
- package/dist/coordination/mailbox-http-router.d.ts +38 -0
- package/dist/coordination/mailbox-http-router.d.ts.map +1 -1
- package/dist/coordination/provider-status-tracker.d.ts.map +1 -1
- package/dist/core/fallback-model.d.ts.map +1 -1
- package/dist/defaults/index.js +5 -1
- package/dist/defaults/index.js.map +2 -2
- package/dist/execution/index.js +8 -1
- package/dist/execution/index.js.map +2 -2
- package/dist/execution/one-shot-llm.d.ts.map +1 -1
- package/dist/index.js +305 -139
- package/dist/index.js.map +4 -4
- package/dist/tools/index.js +8 -1
- package/dist/tools/index.js.map +2 -2
- package/dist/types/index.js +5 -1
- package/dist/types/index.js.map +2 -2
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/utils/connectivity.d.ts +36 -0
- package/dist/utils/connectivity.d.ts.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +44 -11
- package/dist/utils/index.js.map +4 -4
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1366,12 +1366,43 @@ async function backupConfigFile(filePath, paths) {
|
|
|
1366
1366
|
}
|
|
1367
1367
|
}
|
|
1368
1368
|
|
|
1369
|
+
// src/utils/connectivity.ts
|
|
1370
|
+
var DEFAULT_PROBE_URL = "https://1.1.1.1";
|
|
1371
|
+
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
1372
|
+
var DEFAULT_TTL_MS = 3e4;
|
|
1373
|
+
var cached;
|
|
1374
|
+
async function checkConnectivity(opts) {
|
|
1375
|
+
const url = opts?.probeUrl ?? DEFAULT_PROBE_URL;
|
|
1376
|
+
const timeout = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
1377
|
+
const ttl = opts?.ttlMs ?? DEFAULT_TTL_MS;
|
|
1378
|
+
if (cached && ttl > 0 && Date.now() - cached.at < ttl) {
|
|
1379
|
+
return cached.ok;
|
|
1380
|
+
}
|
|
1381
|
+
cached = { ok: await probe(url, timeout), at: Date.now() };
|
|
1382
|
+
return cached.ok;
|
|
1383
|
+
}
|
|
1384
|
+
async function probe(url, timeoutMs) {
|
|
1385
|
+
const controller = new AbortController();
|
|
1386
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
1387
|
+
try {
|
|
1388
|
+
await fetch(url, { method: "HEAD", signal: controller.signal });
|
|
1389
|
+
return true;
|
|
1390
|
+
} catch {
|
|
1391
|
+
return false;
|
|
1392
|
+
} finally {
|
|
1393
|
+
clearTimeout(timer);
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
function resetConnectivityCache() {
|
|
1397
|
+
cached = void 0;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1369
1400
|
// src/utils/cache-key.ts
|
|
1370
1401
|
import { createHash } from "node:crypto";
|
|
1371
1402
|
var keyCache = /* @__PURE__ */ new WeakMap();
|
|
1372
1403
|
function deriveCachePrefixKey(systemPrompt) {
|
|
1373
|
-
const
|
|
1374
|
-
if (
|
|
1404
|
+
const cached2 = keyCache.get(systemPrompt);
|
|
1405
|
+
if (cached2 !== void 0) return cached2;
|
|
1375
1406
|
const h = createHash("sha256");
|
|
1376
1407
|
for (const block of systemPrompt) h.update(block.text).update("\0");
|
|
1377
1408
|
const key = `ws-${h.digest("hex").slice(0, 32)}`;
|
|
@@ -3099,8 +3130,8 @@ ${agentList}`;
|
|
|
3099
3130
|
modelCapabilities?.supportsVision ? 1 : 0,
|
|
3100
3131
|
modelCapabilities?.supportsReasoning ? 1 : 0
|
|
3101
3132
|
].join("\0");
|
|
3102
|
-
const
|
|
3103
|
-
if (
|
|
3133
|
+
const cached2 = this.envCacheByRoot.get(cacheKey);
|
|
3134
|
+
if (cached2) return cached2;
|
|
3104
3135
|
const today = this.opts.todayIso ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3105
3136
|
const platform4 = `${os2.platform()} ${os2.release()}`;
|
|
3106
3137
|
const effShell = effectiveShell(os2.platform(), process.env["WRONGSTACK_SHELL"]);
|
|
@@ -3460,8 +3491,8 @@ var compactCache = /* @__PURE__ */ new WeakMap();
|
|
|
3460
3491
|
function compactToolDefinitionForWire(tool, opts = {}) {
|
|
3461
3492
|
const useDefaultOptions = opts.descriptionMaxChars === void 0 && opts.schemaDescriptionMaxChars === void 0;
|
|
3462
3493
|
if (useDefaultOptions && typeof tool === "object" && tool !== null) {
|
|
3463
|
-
const
|
|
3464
|
-
if (
|
|
3494
|
+
const cached2 = compactCache.get(tool);
|
|
3495
|
+
if (cached2) return cached2;
|
|
3465
3496
|
}
|
|
3466
3497
|
const compact = {
|
|
3467
3498
|
name: tool.name,
|
|
@@ -3649,8 +3680,8 @@ function realAnchoredInputTokens(messages, anchorTokens, anchorMsgCount) {
|
|
|
3649
3680
|
return anchorTokens + delta;
|
|
3650
3681
|
}
|
|
3651
3682
|
function estimateToolDefTokens(tool) {
|
|
3652
|
-
const
|
|
3653
|
-
if (typeof
|
|
3683
|
+
const cached2 = tool._estDefTokens;
|
|
3684
|
+
if (typeof cached2 === "number" && cached2 > 0) return cached2;
|
|
3654
3685
|
const compact = compactToolDefinitionForWire(tool);
|
|
3655
3686
|
return RoughTokenEstimate(tool.name) + RoughTokenEstimate(compact.description) + RoughTokenEstimate(JSON.stringify(compact.inputSchema));
|
|
3656
3687
|
}
|
|
@@ -3661,9 +3692,9 @@ function estimateRequestTokens(messages, systemPrompt, tools, calibrationKey = C
|
|
|
3661
3692
|
} else if (Array.isArray(messages)) {
|
|
3662
3693
|
for (const m of messages) {
|
|
3663
3694
|
if (typeof m === "object" && m !== null && "content" in m) {
|
|
3664
|
-
const
|
|
3665
|
-
if (typeof
|
|
3666
|
-
messagesTokens +=
|
|
3695
|
+
const cached2 = m._estTokens;
|
|
3696
|
+
if (typeof cached2 === "number" && cached2 > 0) {
|
|
3697
|
+
messagesTokens += cached2;
|
|
3667
3698
|
continue;
|
|
3668
3699
|
}
|
|
3669
3700
|
const content = m.content;
|
|
@@ -4291,8 +4322,8 @@ var COMPILED_GLOB_CACHE = /* @__PURE__ */ new Map();
|
|
|
4291
4322
|
var CACHE_MAX_SIZE = 2e3;
|
|
4292
4323
|
var NEVER_MATCH = /[^\s\S]/;
|
|
4293
4324
|
function getCachedGlob(pattern) {
|
|
4294
|
-
const
|
|
4295
|
-
if (
|
|
4325
|
+
const cached2 = COMPILED_GLOB_CACHE.get(pattern);
|
|
4326
|
+
if (cached2) return cached2;
|
|
4296
4327
|
if (COMPILED_GLOB_CACHE.size >= CACHE_MAX_SIZE) {
|
|
4297
4328
|
const keys = [...COMPILED_GLOB_CACHE.keys()];
|
|
4298
4329
|
for (let i = 0; i < Math.floor(CACHE_MAX_SIZE / 4); i++) {
|
|
@@ -7978,9 +8009,9 @@ var DefaultConfigLoader = class _DefaultConfigLoader {
|
|
|
7978
8009
|
try {
|
|
7979
8010
|
const stat27 = await fs9.stat(file);
|
|
7980
8011
|
mtimeMs = stat27.mtimeMs;
|
|
7981
|
-
const
|
|
7982
|
-
if (
|
|
7983
|
-
return structuredClone(
|
|
8012
|
+
const cached2 = this.jsonCache.get(file);
|
|
8013
|
+
if (cached2 && cached2.mtimeMs === mtimeMs) {
|
|
8014
|
+
return structuredClone(cached2.value);
|
|
7984
8015
|
}
|
|
7985
8016
|
} catch (err) {
|
|
7986
8017
|
if (err.code === "ENOENT") {
|
|
@@ -11759,8 +11790,8 @@ var candidateCache = /* @__PURE__ */ new Map();
|
|
|
11759
11790
|
function agentPrompt(id) {
|
|
11760
11791
|
const envDir = process.env["WRONGSTACK_AGENT_INSTRUCTIONS_DIR"] ?? "";
|
|
11761
11792
|
const cacheKey = `${envDir}\0${id}`;
|
|
11762
|
-
const
|
|
11763
|
-
if (
|
|
11793
|
+
const cached2 = promptCache.get(cacheKey);
|
|
11794
|
+
if (cached2 !== void 0) return cached2;
|
|
11764
11795
|
const fileName = `${id}.md`;
|
|
11765
11796
|
let resolved = "";
|
|
11766
11797
|
for (const dir of agentPromptDirCandidates(envDir)) {
|
|
@@ -11776,8 +11807,8 @@ function agentPrompt(id) {
|
|
|
11776
11807
|
function agentPromptDirCandidates(envDir) {
|
|
11777
11808
|
const globalRoot = process.env["WRONGSTACK_HOME"] || path19.join(os6.homedir(), ".wrongstack");
|
|
11778
11809
|
const candKey = `${envDir}\0${globalRoot}`;
|
|
11779
|
-
const
|
|
11780
|
-
if (
|
|
11810
|
+
const cached2 = candidateCache.get(candKey);
|
|
11811
|
+
if (cached2 !== void 0) return cached2;
|
|
11781
11812
|
const here = path19.dirname(fileURLToPath3(import.meta.url));
|
|
11782
11813
|
const explicitDir = envDir || void 0;
|
|
11783
11814
|
const candidates = [
|
|
@@ -15839,8 +15870,8 @@ import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
|
15839
15870
|
var textCache = /* @__PURE__ */ new Map();
|
|
15840
15871
|
var rootCandidates;
|
|
15841
15872
|
function readBundledInstructionText(relativePath) {
|
|
15842
|
-
const
|
|
15843
|
-
if (
|
|
15873
|
+
const cached2 = textCache.get(relativePath);
|
|
15874
|
+
if (cached2 !== void 0) return cached2;
|
|
15844
15875
|
let resolved = "";
|
|
15845
15876
|
for (const root of instructionRootCandidates()) {
|
|
15846
15877
|
try {
|
|
@@ -17815,7 +17846,8 @@ function effectiveInputTokens(usage) {
|
|
|
17815
17846
|
}
|
|
17816
17847
|
var CONTEXT_OVERFLOW_RE = /context.length|context.window|maximum context|max.*tokens?.*exceeded|prompt is too long|too long|exceeds the context|\btokens\b.*exceed|too many tokens|reduce the length|resulted in \d+ tokens|input.{0,12}too (?:large|long)|context_length_exceeded/i;
|
|
17817
17848
|
var CONTENT_FILTER_RE = /content.(filter|policy|moderation)|safety (system|filter)/i;
|
|
17818
|
-
var QUOTA_EXHAUSTED_RE = /(?:insufficient|exhausted|depleted|exceeded|no|not enough)[-_\s]*(?:quota|credit|balance)|(?:quota|credit|balance)[-_\s]*(?:exhausted|depleted|exceeded|insufficient)|billing[_\s-]*(?:hard[_\s-]*)?limit|payment required|spending limit|plan limit/i;
|
|
17849
|
+
var QUOTA_EXHAUSTED_RE = /(?:insufficient|exhausted|depleted|exceeded|no|not enough)[-_\s]*(?:quota|credit|balance)|(?:quota|credit|balance)[-_\s]*(?:exhausted|depleted|exceeded|insufficient)|billing[_\s-]*(?:hard[_\s-]*)?limit|payment required|spending limit|plan limit|usage[-_\s]*limit[-_\s]*(?:reached|exceeded)/i;
|
|
17850
|
+
var RATE_LIMIT_EXCEEDED_RE = /rate[-_\s]*limit[-_\s]*exceeded/i;
|
|
17819
17851
|
function classifyProviderError(status, body, message) {
|
|
17820
17852
|
const type = body?.type;
|
|
17821
17853
|
const text2 = [message, body?.message, type, body?.raw].filter(Boolean).join("\n");
|
|
@@ -17823,6 +17855,9 @@ function classifyProviderError(status, body, message) {
|
|
|
17823
17855
|
if (status === 408) return "timeout";
|
|
17824
17856
|
if (status === 599) return "stream_hang";
|
|
17825
17857
|
if (status === 402 || QUOTA_EXHAUSTED_RE.test(text2)) return "quota_exhausted";
|
|
17858
|
+
if (status === 429 && body?.message && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {
|
|
17859
|
+
return "quota_exhausted";
|
|
17860
|
+
}
|
|
17826
17861
|
if (type === "rate_limit_error" || status === 429) return "rate_limit";
|
|
17827
17862
|
if (type === "overloaded_error" || status === 529) return "overloaded";
|
|
17828
17863
|
if (status >= 500) return "server";
|
|
@@ -18545,6 +18580,12 @@ function createFallbackModelExtension(deps) {
|
|
|
18545
18580
|
continue;
|
|
18546
18581
|
const status = shouldFallback(lastErr);
|
|
18547
18582
|
if (status === null) break;
|
|
18583
|
+
if (tracker && !tracker.isAvailable(entry.providerId, entry.model)) {
|
|
18584
|
+
deps.logger?.warn(
|
|
18585
|
+
`provider-status: "${entry.providerId}/${entry.model}" entered the waiting room since the chain was computed \u2014 skipping`
|
|
18586
|
+
);
|
|
18587
|
+
continue;
|
|
18588
|
+
}
|
|
18548
18589
|
const targetProviderId = entry.providerId;
|
|
18549
18590
|
const targetModel = entry.model;
|
|
18550
18591
|
if (targetProviderId === ctx_.provider.id && targetModel === ctx_.model) continue;
|
|
@@ -19350,8 +19391,8 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
19350
19391
|
async awaitTasks(taskIds) {
|
|
19351
19392
|
return Promise.all(
|
|
19352
19393
|
taskIds.map((id) => {
|
|
19353
|
-
const
|
|
19354
|
-
if (
|
|
19394
|
+
const cached2 = this.completedResults.find((r) => r.taskId === id);
|
|
19395
|
+
if (cached2) return cached2;
|
|
19355
19396
|
return new Promise((resolve34, reject) => {
|
|
19356
19397
|
const timeout = setTimeout(() => {
|
|
19357
19398
|
this.off("task.completed", handler);
|
|
@@ -21318,8 +21359,8 @@ var Director = class _Director {
|
|
|
21318
21359
|
awaitTasks(taskIds) {
|
|
21319
21360
|
return Promise.all(
|
|
21320
21361
|
taskIds.map((id) => {
|
|
21321
|
-
const
|
|
21322
|
-
if (
|
|
21362
|
+
const cached2 = this.completed.get(id);
|
|
21363
|
+
if (cached2) return cached2;
|
|
21323
21364
|
const existing = this.taskWaiters.get(id);
|
|
21324
21365
|
if (existing) return existing.promise;
|
|
21325
21366
|
let resolve34;
|
|
@@ -22815,17 +22856,17 @@ var SessionCheckpointCas = class {
|
|
|
22815
22856
|
if (!normalized) throw new Error("invalid relative path");
|
|
22816
22857
|
const output = path25.resolve(target, ...normalized.split("/"));
|
|
22817
22858
|
if (!isInside(target, output)) throw new Error("path escapes checkpoint target");
|
|
22818
|
-
let
|
|
22859
|
+
let probe2 = output;
|
|
22819
22860
|
for (; ; ) {
|
|
22820
22861
|
try {
|
|
22821
|
-
const real = await fsp9.realpath(
|
|
22862
|
+
const real = await fsp9.realpath(probe2);
|
|
22822
22863
|
if (!isInside(realTarget, real)) throw new Error("path resolves through a symlink outside checkpoint target");
|
|
22823
22864
|
return output;
|
|
22824
22865
|
} catch (err) {
|
|
22825
22866
|
if (err.code !== "ENOENT") throw err;
|
|
22826
|
-
const parent = path25.dirname(
|
|
22827
|
-
if (parent ===
|
|
22828
|
-
|
|
22867
|
+
const parent = path25.dirname(probe2);
|
|
22868
|
+
if (parent === probe2) throw err;
|
|
22869
|
+
probe2 = parent;
|
|
22829
22870
|
}
|
|
22830
22871
|
}
|
|
22831
22872
|
}
|
|
@@ -23422,13 +23463,13 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
23422
23463
|
try {
|
|
23423
23464
|
const s = await fsp11.stat(file);
|
|
23424
23465
|
const stat27 = { mtimeMs: s.mtimeMs, size: s.size };
|
|
23425
|
-
const
|
|
23426
|
-
if (
|
|
23466
|
+
const cached2 = this._loadCache.get(id);
|
|
23467
|
+
if (cached2 && cached2.mtimeMs === stat27.mtimeMs && cached2.size === stat27.size) {
|
|
23427
23468
|
cacheHit = true;
|
|
23428
23469
|
this._loadCache.delete(id);
|
|
23429
|
-
this._loadCache.set(id,
|
|
23430
|
-
if (mode.full) return
|
|
23431
|
-
return { ...
|
|
23470
|
+
this._loadCache.set(id, cached2);
|
|
23471
|
+
if (mode.full) return cached2.data;
|
|
23472
|
+
return { ...cached2.data, messages: [] };
|
|
23432
23473
|
}
|
|
23433
23474
|
const events = [];
|
|
23434
23475
|
let sessionStartEvent;
|
|
@@ -23959,8 +24000,8 @@ var DefaultSessionStore = class _DefaultSessionStore {
|
|
|
23959
24000
|
return shardKeys;
|
|
23960
24001
|
}
|
|
23961
24002
|
async readOrBuildShardManifest(shardKey) {
|
|
23962
|
-
const
|
|
23963
|
-
if (
|
|
24003
|
+
const cached2 = this.shardManifestCache.get(shardKey);
|
|
24004
|
+
if (cached2) return cached2;
|
|
23964
24005
|
const manifestPath = this.shardManifestPath(shardKey);
|
|
23965
24006
|
try {
|
|
23966
24007
|
const raw = await fsp11.readFile(manifestPath, "utf8");
|
|
@@ -28102,6 +28143,8 @@ import { timingSafeEqual } from "node:crypto";
|
|
|
28102
28143
|
var MAILBOX_HTTP_MAX_BODY_BYTES = 256 * 1024;
|
|
28103
28144
|
var MAILBOX_HTTP_RATE_LIMIT_PER_MINUTE = 120;
|
|
28104
28145
|
var MAILBOX_HTTP_RATE_LIMIT_WINDOW_MS = 6e4;
|
|
28146
|
+
var MAILBOX_HTTP_DEFAULT_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
28147
|
+
var MAILBOX_HTTP_MAX_AGE_CEILING_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
28105
28148
|
function authorizeMailboxBearerToken(request, expectedToken) {
|
|
28106
28149
|
const header = request.headers.authorization;
|
|
28107
28150
|
if (typeof header !== "string") return { allowed: false };
|
|
@@ -28145,6 +28188,7 @@ var MailboxHttpRateLimiter = class {
|
|
|
28145
28188
|
};
|
|
28146
28189
|
function createMailboxHttpRouter(options) {
|
|
28147
28190
|
const maxBodyBytes = options.maxBodyBytes ?? MAILBOX_HTTP_MAX_BODY_BYTES;
|
|
28191
|
+
const defaultMaxAgeMs = options.defaultMaxAgeMs ?? void 0;
|
|
28148
28192
|
const closeSseStreams = /* @__PURE__ */ new Set();
|
|
28149
28193
|
return {
|
|
28150
28194
|
async handle(request, response, routePath) {
|
|
@@ -28159,15 +28203,17 @@ function createMailboxHttpRouter(options) {
|
|
|
28159
28203
|
if (!access10.allowed) {
|
|
28160
28204
|
const forwardedFor = request.headers["x-forwarded-for"];
|
|
28161
28205
|
const clientIp = (Array.isArray(forwardedFor) ? forwardedFor[0] : forwardedFor)?.split(",")[0]?.trim() ?? request.socket?.remoteAddress ?? "unknown";
|
|
28162
|
-
console.warn(
|
|
28163
|
-
|
|
28164
|
-
|
|
28165
|
-
|
|
28166
|
-
|
|
28167
|
-
|
|
28168
|
-
|
|
28169
|
-
|
|
28170
|
-
|
|
28206
|
+
console.warn(
|
|
28207
|
+
JSON.stringify({
|
|
28208
|
+
level: "warn",
|
|
28209
|
+
event: "mailbox.http_auth_failure",
|
|
28210
|
+
message: `Mailbox HTTP auth rejected for ${request.method ?? "?"} ${request.url ?? "?"} from ${clientIp}`,
|
|
28211
|
+
method: request.method,
|
|
28212
|
+
url: request.url,
|
|
28213
|
+
clientIp,
|
|
28214
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
28215
|
+
})
|
|
28216
|
+
);
|
|
28171
28217
|
writeJson(
|
|
28172
28218
|
response,
|
|
28173
28219
|
access10.status ?? 401,
|
|
@@ -28194,7 +28240,9 @@ function createMailboxHttpRouter(options) {
|
|
|
28194
28240
|
method,
|
|
28195
28241
|
url,
|
|
28196
28242
|
maxBodyBytes,
|
|
28197
|
-
|
|
28243
|
+
defaultMaxAgeMs,
|
|
28244
|
+
closeSseStreams,
|
|
28245
|
+
routePath
|
|
28198
28246
|
);
|
|
28199
28247
|
} catch (error2) {
|
|
28200
28248
|
const code = error2 instanceof MailboxHttpValidationError ? "VALIDATION_ERROR" : "INTERNAL_ERROR";
|
|
@@ -28213,85 +28261,134 @@ function createMailboxHttpRouter(options) {
|
|
|
28213
28261
|
}
|
|
28214
28262
|
};
|
|
28215
28263
|
}
|
|
28216
|
-
async function dispatchMailboxRoute(mailbox, eventEmitter, request, response, method, url, maxBodyBytes, closeSseStreams) {
|
|
28217
|
-
if (
|
|
28264
|
+
async function dispatchMailboxRoute(mailbox, eventEmitter, request, response, method, url, maxBodyBytes, defaultMaxAgeMs, closeSseStreams, routePath) {
|
|
28265
|
+
if (routePath !== void 0 && routePath.indexOf("?") === 0) {
|
|
28266
|
+
throw validationError(`routePath must not start with '?' (got ${JSON.stringify(routePath)})`);
|
|
28267
|
+
}
|
|
28268
|
+
const queryIndex = url.indexOf("?");
|
|
28269
|
+
const path76 = queryIndex === -1 ? url : url.slice(0, queryIndex);
|
|
28270
|
+
if (method === "POST" && path76 === "/mailbox/send") {
|
|
28218
28271
|
const input = validateSend(await readJsonBody(request, maxBodyBytes));
|
|
28219
28272
|
writeJson(response, 201, await mailbox.send(input));
|
|
28220
28273
|
return;
|
|
28221
28274
|
}
|
|
28222
|
-
if (method === "POST" &&
|
|
28275
|
+
if (method === "POST" && path76 === "/mailbox/query") {
|
|
28276
|
+
const queryContext = parseSinceMs(url, defaultMaxAgeMs);
|
|
28277
|
+
if ("error" in queryContext) {
|
|
28278
|
+
writeJson(response, 400, { error: queryContext.error });
|
|
28279
|
+
return;
|
|
28280
|
+
}
|
|
28223
28281
|
const messages = await mailbox.query(validateQuery(await readJsonBody(request, maxBodyBytes)));
|
|
28224
|
-
|
|
28282
|
+
const filtered = filterMailboxMessagesByTimestamp(messages, queryContext.minTimestampIso);
|
|
28283
|
+
writeJson(response, 200, { data: filtered, count: filtered.length });
|
|
28225
28284
|
return;
|
|
28226
28285
|
}
|
|
28227
|
-
if (method === "POST" &&
|
|
28286
|
+
if (method === "POST" && path76 === "/mailbox/check") {
|
|
28287
|
+
const queryContext = parseSinceMs(url, defaultMaxAgeMs);
|
|
28288
|
+
if ("error" in queryContext) {
|
|
28289
|
+
writeJson(response, 400, { error: queryContext.error });
|
|
28290
|
+
return;
|
|
28291
|
+
}
|
|
28228
28292
|
const result = await checkMailbox(
|
|
28229
28293
|
mailbox,
|
|
28230
|
-
validateCheck(await readJsonBody(request, maxBodyBytes))
|
|
28294
|
+
validateCheck(await readJsonBody(request, maxBodyBytes)),
|
|
28295
|
+
queryContext.minTimestampIso
|
|
28231
28296
|
);
|
|
28232
28297
|
writeJson(response, 200, result);
|
|
28233
28298
|
return;
|
|
28234
28299
|
}
|
|
28235
|
-
if (method === "POST" &&
|
|
28300
|
+
if (method === "POST" && path76 === "/mailbox/ack") {
|
|
28236
28301
|
const updated = await mailbox.ack(validateAck(await readJsonBody(request, maxBodyBytes)));
|
|
28237
28302
|
writeJson(response, 200, { updated });
|
|
28238
28303
|
return;
|
|
28239
28304
|
}
|
|
28240
|
-
if (method === "POST" &&
|
|
28305
|
+
if (method === "POST" && path76 === "/mailbox/ack-many") {
|
|
28241
28306
|
const updated = await mailbox.ackMany(
|
|
28242
28307
|
validateAckMany(await readJsonBody(request, maxBodyBytes))
|
|
28243
28308
|
);
|
|
28244
28309
|
writeJson(response, 200, { updated, count: updated.length });
|
|
28245
28310
|
return;
|
|
28246
28311
|
}
|
|
28247
|
-
if (method === "POST" &&
|
|
28312
|
+
if (method === "POST" && path76 === "/mailbox/unread-count") {
|
|
28248
28313
|
const body = await readJsonBody(request, maxBodyBytes);
|
|
28249
|
-
writeJson(response, 200, {
|
|
28314
|
+
writeJson(response, 200, {
|
|
28315
|
+
count: await mailbox.unreadCount(requireString(body, "forAgentId"))
|
|
28316
|
+
});
|
|
28250
28317
|
return;
|
|
28251
28318
|
}
|
|
28252
|
-
if (method === "POST" &&
|
|
28253
|
-
await mailbox.registerAgent(
|
|
28319
|
+
if (method === "POST" && path76 === "/mailbox/agents/register") {
|
|
28320
|
+
await mailbox.registerAgent(
|
|
28321
|
+
validateAgentRegistration(await readJsonBody(request, maxBodyBytes))
|
|
28322
|
+
);
|
|
28254
28323
|
writeJson(response, 200, { ok: true });
|
|
28255
28324
|
return;
|
|
28256
28325
|
}
|
|
28257
|
-
if (method === "POST" &&
|
|
28326
|
+
if (method === "POST" && path76 === "/mailbox/agents/heartbeat") {
|
|
28258
28327
|
await mailbox.heartbeat(validateAgentHeartbeat(await readJsonBody(request, maxBodyBytes)));
|
|
28259
28328
|
writeJson(response, 200, { ok: true });
|
|
28260
28329
|
return;
|
|
28261
28330
|
}
|
|
28262
|
-
if (method === "POST" &&
|
|
28263
|
-
await mailbox.registerClient(
|
|
28331
|
+
if (method === "POST" && path76 === "/mailbox/register-client") {
|
|
28332
|
+
await mailbox.registerClient(
|
|
28333
|
+
validateClientRegistration(await readJsonBody(request, maxBodyBytes))
|
|
28334
|
+
);
|
|
28264
28335
|
writeJson(response, 200, { ok: true });
|
|
28265
28336
|
return;
|
|
28266
28337
|
}
|
|
28267
|
-
if (method === "POST" &&
|
|
28268
|
-
await mailbox.clientHeartbeat(
|
|
28338
|
+
if (method === "POST" && path76 === "/mailbox/heartbeat") {
|
|
28339
|
+
await mailbox.clientHeartbeat(
|
|
28340
|
+
validateClientHeartbeat(await readJsonBody(request, maxBodyBytes))
|
|
28341
|
+
);
|
|
28269
28342
|
writeJson(response, 200, { ok: true });
|
|
28270
28343
|
return;
|
|
28271
28344
|
}
|
|
28272
|
-
if (method === "POST" &&
|
|
28345
|
+
if (method === "POST" && path76 === "/mailbox/purge-clients") {
|
|
28273
28346
|
writeJson(response, 200, { ok: true, purged: await mailbox.purgeClients() });
|
|
28274
28347
|
return;
|
|
28275
28348
|
}
|
|
28276
|
-
if (method === "GET" &&
|
|
28349
|
+
if (method === "GET" && path76 === "/mailbox/agents") {
|
|
28277
28350
|
const agents = await mailbox.getAgentStatuses();
|
|
28278
28351
|
writeJson(response, 200, { data: agents, count: agents.length });
|
|
28279
28352
|
return;
|
|
28280
28353
|
}
|
|
28281
|
-
if (method === "GET" &&
|
|
28354
|
+
if (method === "GET" && path76 === "/mailbox/agents/online") {
|
|
28282
28355
|
const agents = await mailbox.getOnlineAgents();
|
|
28283
28356
|
writeJson(response, 200, { data: agents, count: agents.length });
|
|
28284
28357
|
return;
|
|
28285
28358
|
}
|
|
28286
|
-
if (method === "GET" &&
|
|
28287
|
-
|
|
28359
|
+
if (method === "GET" && path76 === "/mailbox/events" && eventEmitter) {
|
|
28360
|
+
const queryContext = parseSinceMs(url, defaultMaxAgeMs);
|
|
28361
|
+
if ("error" in queryContext) {
|
|
28362
|
+
writeJson(response, 400, { error: queryContext.error });
|
|
28363
|
+
return;
|
|
28364
|
+
}
|
|
28365
|
+
handleSse(request, response, eventEmitter, queryContext.minTimestampIso, closeSseStreams);
|
|
28288
28366
|
return;
|
|
28289
28367
|
}
|
|
28290
28368
|
writeJson(response, 404, {
|
|
28291
28369
|
error: { code: "NOT_FOUND", message: `no route for ${method} ${url}` }
|
|
28292
28370
|
});
|
|
28293
28371
|
}
|
|
28294
|
-
function
|
|
28372
|
+
function extractEventTimestamp(event) {
|
|
28373
|
+
if (event === null || typeof event !== "object") return void 0;
|
|
28374
|
+
const top = event.timestamp;
|
|
28375
|
+
if (typeof top === "string") return top;
|
|
28376
|
+
const nestedKeys = ["messageSent", "ackUpdated"];
|
|
28377
|
+
for (const key of nestedKeys) {
|
|
28378
|
+
const nested = event[key];
|
|
28379
|
+
if (nested !== null && typeof nested === "object") {
|
|
28380
|
+
const inner = nested.timestamp;
|
|
28381
|
+
if (typeof inner === "string") return inner;
|
|
28382
|
+
}
|
|
28383
|
+
}
|
|
28384
|
+
return void 0;
|
|
28385
|
+
}
|
|
28386
|
+
function isEventOlderThan(event, minTimestampIso) {
|
|
28387
|
+
const eventTimestamp = extractEventTimestamp(event);
|
|
28388
|
+
if (eventTimestamp === void 0) return false;
|
|
28389
|
+
return eventTimestamp < minTimestampIso;
|
|
28390
|
+
}
|
|
28391
|
+
function handleSse(request, response, eventEmitter, minTimestampIso, closeSseStreams) {
|
|
28295
28392
|
response.writeHead(200, {
|
|
28296
28393
|
"Content-Type": "text/event-stream",
|
|
28297
28394
|
"Cache-Control": "no-store",
|
|
@@ -28301,6 +28398,9 @@ function handleSse(request, response, eventEmitter, closeSseStreams) {
|
|
|
28301
28398
|
response.write(": connected\n\n");
|
|
28302
28399
|
const unsubscribe2 = eventEmitter.subscribe((event) => {
|
|
28303
28400
|
try {
|
|
28401
|
+
if (minTimestampIso !== void 0 && isEventOlderThan(event, minTimestampIso)) {
|
|
28402
|
+
return;
|
|
28403
|
+
}
|
|
28304
28404
|
response.write(`data: ${JSON.stringify(event)}
|
|
28305
28405
|
|
|
28306
28406
|
`);
|
|
@@ -28410,6 +28510,52 @@ function optionalNumber(object, key) {
|
|
|
28410
28510
|
}
|
|
28411
28511
|
return value;
|
|
28412
28512
|
}
|
|
28513
|
+
function parseSinceMs(url, defaultMaxAgeMs) {
|
|
28514
|
+
const queryStart = url.indexOf("?");
|
|
28515
|
+
if (queryStart === -1) return resolveDefault(defaultMaxAgeMs, Date.now());
|
|
28516
|
+
const params = new URLSearchParams(url.slice(queryStart + 1));
|
|
28517
|
+
if (!params.has("sinceMs")) return resolveDefault(defaultMaxAgeMs, Date.now());
|
|
28518
|
+
const raw = params.get("sinceMs");
|
|
28519
|
+
if (raw === null || raw === void 0 || raw === "") {
|
|
28520
|
+
return {
|
|
28521
|
+
error: {
|
|
28522
|
+
code: "VALIDATION_ERROR",
|
|
28523
|
+
message: 'query parameter "sinceMs" is required (integer in milliseconds) when present'
|
|
28524
|
+
}
|
|
28525
|
+
};
|
|
28526
|
+
}
|
|
28527
|
+
if (!/^\d+$/.test(raw)) {
|
|
28528
|
+
return {
|
|
28529
|
+
error: {
|
|
28530
|
+
code: "VALIDATION_ERROR",
|
|
28531
|
+
message: 'query parameter "sinceMs" must be a non-negative integer (milliseconds)'
|
|
28532
|
+
}
|
|
28533
|
+
};
|
|
28534
|
+
}
|
|
28535
|
+
const requestedMs = Number(raw);
|
|
28536
|
+
if (!Number.isFinite(requestedMs) || requestedMs > Number.MAX_SAFE_INTEGER) {
|
|
28537
|
+
return {
|
|
28538
|
+
error: {
|
|
28539
|
+
code: "VALIDATION_ERROR",
|
|
28540
|
+
message: `query parameter "sinceMs" is out of range (max ${Number.MAX_SAFE_INTEGER})`
|
|
28541
|
+
}
|
|
28542
|
+
};
|
|
28543
|
+
}
|
|
28544
|
+
const now = Date.now();
|
|
28545
|
+
if (requestedMs === 0) return { minTimestampIso: void 0 };
|
|
28546
|
+
const effectiveMs = Math.min(requestedMs, MAILBOX_HTTP_MAX_AGE_CEILING_MS);
|
|
28547
|
+
return { minTimestampIso: new Date(now - effectiveMs).toISOString() };
|
|
28548
|
+
}
|
|
28549
|
+
function resolveDefault(defaultMaxAgeMs, now) {
|
|
28550
|
+
if (defaultMaxAgeMs === void 0 || !Number.isFinite(defaultMaxAgeMs) || defaultMaxAgeMs < 0 || defaultMaxAgeMs === 0) {
|
|
28551
|
+
return { minTimestampIso: void 0 };
|
|
28552
|
+
}
|
|
28553
|
+
return { minTimestampIso: new Date(now - defaultMaxAgeMs).toISOString() };
|
|
28554
|
+
}
|
|
28555
|
+
function filterMailboxMessagesByTimestamp(messages, minTimestampIso) {
|
|
28556
|
+
if (minTimestampIso === void 0) return messages.slice();
|
|
28557
|
+
return messages.filter((message) => message.timestamp >= minTimestampIso);
|
|
28558
|
+
}
|
|
28413
28559
|
function optionalBoolean(object, key) {
|
|
28414
28560
|
if (typeof object !== "object" || object === null) return void 0;
|
|
28415
28561
|
const value = object[key];
|
|
@@ -28530,7 +28676,7 @@ function validateQuery(body) {
|
|
|
28530
28676
|
if (incompleteOnly !== void 0) result.incompleteOnly = incompleteOnly;
|
|
28531
28677
|
return result;
|
|
28532
28678
|
}
|
|
28533
|
-
async function checkMailbox(mailbox, input) {
|
|
28679
|
+
async function checkMailbox(mailbox, input, minTimestampIso) {
|
|
28534
28680
|
const limit = input.limit ?? 20;
|
|
28535
28681
|
const markRead = input.markRead ?? true;
|
|
28536
28682
|
const completed = input.completed ?? false;
|
|
@@ -28538,8 +28684,9 @@ async function checkMailbox(mailbox, input) {
|
|
|
28538
28684
|
const batches = await Promise.all(
|
|
28539
28685
|
targets.map((to) => mailbox.query({ to, unreadBy: input.agentId, limit }))
|
|
28540
28686
|
);
|
|
28687
|
+
const withinWindow = filterMailboxMessagesByTimestamp(batches.flat(), minTimestampIso);
|
|
28541
28688
|
const seen = /* @__PURE__ */ new Set();
|
|
28542
|
-
const messages =
|
|
28689
|
+
const messages = withinWindow.filter((message) => {
|
|
28543
28690
|
if (seen.has(message.id) || message.from === input.agentId) return false;
|
|
28544
28691
|
seen.add(message.id);
|
|
28545
28692
|
return true;
|
|
@@ -28913,11 +29060,11 @@ var DefaultMailbox = class {
|
|
|
28913
29060
|
async query(q) {
|
|
28914
29061
|
const queryType = q.type === void 0 ? void 0 : normalizeMailboxMessageType(q.type);
|
|
28915
29062
|
const needFullScan = q.unreadBy !== void 0 || q.since !== void 0;
|
|
28916
|
-
const
|
|
29063
|
+
const cached2 = await this._readAllCached(false);
|
|
28917
29064
|
let candidates;
|
|
28918
|
-
let candidatesComplete = !this._messageCacheTruncated ||
|
|
29065
|
+
let candidatesComplete = !this._messageCacheTruncated || cached2 !== this._messageCache;
|
|
28919
29066
|
if (needFullScan) {
|
|
28920
|
-
candidates =
|
|
29067
|
+
candidates = cached2;
|
|
28921
29068
|
} else {
|
|
28922
29069
|
if (q.to !== void 0) {
|
|
28923
29070
|
const direct = this._byTo.get(q.to);
|
|
@@ -28931,7 +29078,7 @@ var DefaultMailbox = class {
|
|
|
28931
29078
|
candidates = Array.from(this._byFrom.get(q.from) ?? []);
|
|
28932
29079
|
candidatesComplete = !this._messageCacheTruncated;
|
|
28933
29080
|
} else {
|
|
28934
|
-
candidates =
|
|
29081
|
+
candidates = cached2;
|
|
28935
29082
|
}
|
|
28936
29083
|
}
|
|
28937
29084
|
const limit = q.limit ?? 50;
|
|
@@ -30102,19 +30249,24 @@ var ProviderModelStatusTracker = class {
|
|
|
30102
30249
|
let newState = s.state;
|
|
30103
30250
|
let reason = "";
|
|
30104
30251
|
const quotaExhausted = kind === "quota_exhausted" || isQuotaExhausted(kind, status, message);
|
|
30252
|
+
const endpointUnreachable = isEndpointUnreachable(kind, status, message);
|
|
30105
30253
|
if (quotaExhausted) {
|
|
30106
30254
|
newState = "blocked";
|
|
30107
30255
|
reason = "quota_exhausted";
|
|
30108
30256
|
s.stateExpiresAt = now + this.cfg.quotaBlockDurationMs;
|
|
30257
|
+
} else if (endpointUnreachable) {
|
|
30258
|
+
newState = "blocked";
|
|
30259
|
+
reason = "endpoint_unreachable";
|
|
30260
|
+
s.stateExpiresAt = now + this.cfg.quotaBlockDurationMs;
|
|
30109
30261
|
}
|
|
30110
|
-
if (!quotaExhausted && s.state === "healthy") {
|
|
30262
|
+
if (!quotaExhausted && !endpointUnreachable && s.state === "healthy") {
|
|
30111
30263
|
if (s.consecutiveFailures >= this.cfg.degradedAfterFailures) {
|
|
30112
30264
|
newState = "degraded";
|
|
30113
30265
|
reason = `consecutive_failures_${s.consecutiveFailures}`;
|
|
30114
30266
|
s.stateExpiresAt = now + this.cfg.degradedDurationMs;
|
|
30115
30267
|
}
|
|
30116
30268
|
}
|
|
30117
|
-
if (!quotaExhausted && (s.state === "degraded" || s.state === "healthy")) {
|
|
30269
|
+
if (!quotaExhausted && !endpointUnreachable && (s.state === "degraded" || s.state === "healthy")) {
|
|
30118
30270
|
if (s.rateLimitHits >= this.cfg.blockAfterRateLimitHits) {
|
|
30119
30271
|
newState = "blocked";
|
|
30120
30272
|
reason = `rate_limit_threshold_${this.cfg.blockAfterRateLimitHits}`;
|
|
@@ -30444,13 +30596,20 @@ function unpairKey(key) {
|
|
|
30444
30596
|
if (idx === -1) return [key, ""];
|
|
30445
30597
|
return [key.slice(0, idx), key.slice(idx + 1)];
|
|
30446
30598
|
}
|
|
30447
|
-
var QUOTA_EXHAUSTED_RE2 = /(?:insufficient|exhausted|depleted|exceeded|no|not enough)[-_\s]*(?:quota|credit|balance)|(?:quota|credit|balance)[-_\s]*(?:exhausted|depleted|exceeded|insufficient)|billing[_\s-]*(?:hard[_\s-]*)?limit|payment required|spending limit|plan limit/i;
|
|
30599
|
+
var QUOTA_EXHAUSTED_RE2 = /(?:insufficient|exhausted|depleted|exceeded|no|not enough)[-_\s]*(?:quota|credit|balance)|(?:quota|credit|balance)[-_\s]*(?:exhausted|depleted|exceeded|insufficient)|billing[_\s-]*(?:hard[_\s-]*)?limit|payment required|spending limit|plan limit|usage[-_\s]*limit[-_\s]*(?:reached|exceeded)|rate[-_\s]*limit[-_\s]*exceeded/i;
|
|
30448
30600
|
function isQuotaExhausted(kind, status, message) {
|
|
30449
30601
|
if (status === 402) return true;
|
|
30450
30602
|
if (kind !== "rate_limit" && kind !== "quota_exhausted" && kind !== "invalid_request" && kind !== "auth")
|
|
30451
30603
|
return false;
|
|
30452
30604
|
return QUOTA_EXHAUSTED_RE2.test(message);
|
|
30453
30605
|
}
|
|
30606
|
+
var ENDPOINT_UNREACHABLE_RE = /(?:upstream|origin|backend|endpoint)[-_\s]*(?:unreachable|refused|connect(?:ion)?[-_\s]*(?:refused|error|fail)|unavailable|down|timeout)|no[-_\s]*(?:healthy|valid)[-_\s]*upstream|cannot[-_\s]*connect|connection[-_\s]*(?:refused|reset|closed|timed?[-_\s]out)/i;
|
|
30607
|
+
function isEndpointUnreachable(kind, status, message) {
|
|
30608
|
+
if (status !== 502 && status !== 503 && status !== 0) return false;
|
|
30609
|
+
if (kind !== "server" && kind !== "network" && kind !== "overloaded" && kind !== "timeout")
|
|
30610
|
+
return false;
|
|
30611
|
+
return ENDPOINT_UNREACHABLE_RE.test(message);
|
|
30612
|
+
}
|
|
30454
30613
|
function safeCount(value) {
|
|
30455
30614
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : 0;
|
|
30456
30615
|
}
|
|
@@ -39578,8 +39737,8 @@ function eliseOldToolResults(messages, opts) {
|
|
|
39578
39737
|
const preserveStart = findPreserveStart(messages, opts.preserveK);
|
|
39579
39738
|
const tokenCache = /* @__PURE__ */ new Map();
|
|
39580
39739
|
const tokensFor = (b) => {
|
|
39581
|
-
const
|
|
39582
|
-
if (
|
|
39740
|
+
const cached2 = tokenCache.get(b);
|
|
39741
|
+
if (cached2 !== void 0) return cached2;
|
|
39583
39742
|
const t2 = b.type === "tool_result" ? estimateToolResultTokens(b.content) : b.type === "tool_use" ? estimateToolInputTokens(b.input) : 0;
|
|
39584
39743
|
tokenCache.set(b, t2);
|
|
39585
39744
|
return t2;
|
|
@@ -41436,8 +41595,8 @@ var DefaultDesignKitLoader = class {
|
|
|
41436
41595
|
}
|
|
41437
41596
|
async readBody(id, stack) {
|
|
41438
41597
|
const key = `${id.toLowerCase()}:${stack ?? "*"}`;
|
|
41439
|
-
const
|
|
41440
|
-
if (
|
|
41598
|
+
const cached2 = this.bodyCache.get(key);
|
|
41599
|
+
if (cached2 !== void 0) return cached2;
|
|
41441
41600
|
const m = await this.find(id);
|
|
41442
41601
|
if (!m) throw new Error(`Design kit "${id}" not found`);
|
|
41443
41602
|
const raw = await fs20.readFile(m.path, "utf8");
|
|
@@ -45305,8 +45464,8 @@ var DefaultSkillLoader = class {
|
|
|
45305
45464
|
}
|
|
45306
45465
|
async readBody(name) {
|
|
45307
45466
|
const key = name.toLowerCase();
|
|
45308
|
-
const
|
|
45309
|
-
if (
|
|
45467
|
+
const cached2 = this.bodyCache.get(key);
|
|
45468
|
+
if (cached2 !== void 0) return cached2;
|
|
45310
45469
|
const m = await this.find(name);
|
|
45311
45470
|
if (!m) throw new Error(`Skill "${name}" not found`);
|
|
45312
45471
|
const body = await fs22.readFile(m.path, "utf8");
|
|
@@ -45315,8 +45474,8 @@ var DefaultSkillLoader = class {
|
|
|
45315
45474
|
}
|
|
45316
45475
|
async readSaveBody(name) {
|
|
45317
45476
|
const key = `save:${name.toLowerCase()}`;
|
|
45318
|
-
const
|
|
45319
|
-
if (
|
|
45477
|
+
const cached2 = this.bodyCache.get(key);
|
|
45478
|
+
if (cached2 !== void 0) return cached2;
|
|
45320
45479
|
const m = await this.find(name);
|
|
45321
45480
|
if (!m) throw new Error(`Skill "${name}" not found`);
|
|
45322
45481
|
const savePath = path42.join(path42.dirname(m.path), "SKILL.save.md");
|
|
@@ -46059,19 +46218,19 @@ async function canonicalizeCandidatePath(candidate, ctx) {
|
|
|
46059
46218
|
if (path45.isAbsolute(candidate)) return candidate;
|
|
46060
46219
|
const absolute = path45.resolve(ctx.projectRoot, candidate);
|
|
46061
46220
|
const canonicalRoot = await realpath3(ctx.projectRoot).catch(() => ctx.projectRoot);
|
|
46062
|
-
let
|
|
46221
|
+
let probe2 = absolute;
|
|
46063
46222
|
const missingSegments = [];
|
|
46064
46223
|
while (true) {
|
|
46065
46224
|
try {
|
|
46066
|
-
const canonical = path45.join(await realpath3(
|
|
46225
|
+
const canonical = path45.join(await realpath3(probe2), ...missingSegments);
|
|
46067
46226
|
return relativeToProject(canonical, canonicalRoot);
|
|
46068
46227
|
} catch (cause) {
|
|
46069
46228
|
const code = cause.code;
|
|
46070
46229
|
if (code !== "ENOENT" && code !== "ENOTDIR") return absolute;
|
|
46071
|
-
const parent = path45.dirname(
|
|
46072
|
-
if (parent ===
|
|
46073
|
-
missingSegments.unshift(path45.basename(
|
|
46074
|
-
|
|
46230
|
+
const parent = path45.dirname(probe2);
|
|
46231
|
+
if (parent === probe2) return absolute;
|
|
46232
|
+
missingSegments.unshift(path45.basename(probe2));
|
|
46233
|
+
probe2 = parent;
|
|
46075
46234
|
}
|
|
46076
46235
|
}
|
|
46077
46236
|
}
|
|
@@ -47993,23 +48152,23 @@ var DefaultModelsRegistry = class {
|
|
|
47993
48152
|
*/
|
|
47994
48153
|
async loadBase(opts = {}, overlayAvailable = false) {
|
|
47995
48154
|
if (!opts.force) {
|
|
47996
|
-
const
|
|
47997
|
-
if (
|
|
47998
|
-
this.fetchedAt = new Date(
|
|
47999
|
-
return
|
|
48155
|
+
const cached2 = await this.readCacheAt(this.cacheFile);
|
|
48156
|
+
if (cached2 && this.isFresh(cached2.fetchedAt)) {
|
|
48157
|
+
this.fetchedAt = new Date(cached2.fetchedAt);
|
|
48158
|
+
return cached2.payload;
|
|
48000
48159
|
}
|
|
48001
48160
|
}
|
|
48002
48161
|
try {
|
|
48003
48162
|
return await this.refreshBase();
|
|
48004
48163
|
} catch (err) {
|
|
48005
|
-
const
|
|
48006
|
-
if (
|
|
48007
|
-
this.fetchedAt = new Date(
|
|
48164
|
+
const cached2 = await this.readCacheAt(this.cacheFile);
|
|
48165
|
+
if (cached2 && this.isWithinMaxStaleAge(cached2.fetchedAt)) {
|
|
48166
|
+
this.fetchedAt = new Date(cached2.fetchedAt);
|
|
48008
48167
|
const ageSeconds = Math.floor((Date.now() - this.fetchedAt.getTime()) / 1e3);
|
|
48009
48168
|
console.warn(
|
|
48010
48169
|
`ModelsRegistry: models.dev unavailable (${toErrorMessage(err)}); using stale cache from ${formatAge(ageSeconds)} ago. Run \`wstack models refresh\` to retry.`
|
|
48011
48170
|
);
|
|
48012
|
-
return
|
|
48171
|
+
return cached2.payload;
|
|
48013
48172
|
}
|
|
48014
48173
|
if (overlayAvailable) {
|
|
48015
48174
|
console.warn(
|
|
@@ -48084,8 +48243,8 @@ var DefaultModelsRegistry = class {
|
|
|
48084
48243
|
async loadOverlayFromUrl(opts) {
|
|
48085
48244
|
if (!this.overlayUrl || !this.overlayCacheFile) return void 0;
|
|
48086
48245
|
if (!opts.force) {
|
|
48087
|
-
const
|
|
48088
|
-
if (
|
|
48246
|
+
const cached2 = await this.readCacheAt(this.overlayCacheFile);
|
|
48247
|
+
if (cached2 && this.isFresh(cached2.fetchedAt)) return cached2.payload;
|
|
48089
48248
|
}
|
|
48090
48249
|
try {
|
|
48091
48250
|
const res = await this.fetchImpl(this.overlayUrl, {
|
|
@@ -48108,13 +48267,13 @@ var DefaultModelsRegistry = class {
|
|
|
48108
48267
|
});
|
|
48109
48268
|
return json;
|
|
48110
48269
|
} catch {
|
|
48111
|
-
const
|
|
48112
|
-
if (
|
|
48113
|
-
const ageSeconds = Math.floor((Date.now() - new Date(
|
|
48270
|
+
const cached2 = await this.readCacheAt(this.overlayCacheFile);
|
|
48271
|
+
if (cached2 && this.isWithinMaxStaleAge(cached2.fetchedAt)) {
|
|
48272
|
+
const ageSeconds = Math.floor((Date.now() - new Date(cached2.fetchedAt).getTime()) / 1e3);
|
|
48114
48273
|
console.warn(
|
|
48115
48274
|
`ModelsRegistry: overlay unavailable; using stale overlay from ${formatAge(ageSeconds)} ago.`
|
|
48116
48275
|
);
|
|
48117
|
-
return
|
|
48276
|
+
return cached2.payload;
|
|
48118
48277
|
}
|
|
48119
48278
|
return void 0;
|
|
48120
48279
|
}
|
|
@@ -48175,9 +48334,9 @@ var DefaultModelsRegistry = class {
|
|
|
48175
48334
|
}
|
|
48176
48335
|
async ageSeconds() {
|
|
48177
48336
|
if (!this.fetchedAt) {
|
|
48178
|
-
const
|
|
48179
|
-
if (!
|
|
48180
|
-
return (Date.now() - new Date(
|
|
48337
|
+
const cached2 = await this.readCacheAt(this.cacheFile);
|
|
48338
|
+
if (!cached2) return Number.POSITIVE_INFINITY;
|
|
48339
|
+
return (Date.now() - new Date(cached2.fetchedAt).getTime()) / 1e3;
|
|
48181
48340
|
}
|
|
48182
48341
|
return (Date.now() - this.fetchedAt.getTime()) / 1e3;
|
|
48183
48342
|
}
|
|
@@ -48716,7 +48875,7 @@ async function startMetricsServer(opts) {
|
|
|
48716
48875
|
|
|
48717
48876
|
// src/observability/otlp-metrics.ts
|
|
48718
48877
|
var DEFAULT_INTERVAL_MS = 3e4;
|
|
48719
|
-
var
|
|
48878
|
+
var DEFAULT_TIMEOUT_MS2 = 1e4;
|
|
48720
48879
|
function joinEndpoint(base) {
|
|
48721
48880
|
if (/\/v1\/metrics\/?$/.test(base)) return base;
|
|
48722
48881
|
return base.replace(/\/$/, "") + "/v1/metrics";
|
|
@@ -48779,7 +48938,7 @@ function buildOtlpMetricsRequest(sink, opts = {}) {
|
|
|
48779
48938
|
function startOtlpMetricsExporter(opts) {
|
|
48780
48939
|
const url = joinEndpoint(opts.endpoint);
|
|
48781
48940
|
const intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
48782
|
-
const timeoutMs = opts.timeoutMs ??
|
|
48941
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
48783
48942
|
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
48784
48943
|
const onError = opts.onError ?? (() => {
|
|
48785
48944
|
});
|
|
@@ -48869,7 +49028,7 @@ var CapturingSpan = class {
|
|
|
48869
49028
|
};
|
|
48870
49029
|
var DEFAULT_INTERVAL_MS2 = 5e3;
|
|
48871
49030
|
var DEFAULT_BUFFER_CAP = 2048;
|
|
48872
|
-
var
|
|
49031
|
+
var DEFAULT_TIMEOUT_MS3 = 1e4;
|
|
48873
49032
|
function joinEndpoint2(base) {
|
|
48874
49033
|
if (/\/v1\/traces\/?$/.test(base)) return base;
|
|
48875
49034
|
return base.replace(/\/$/, "") + "/v1/traces";
|
|
@@ -48910,7 +49069,7 @@ function startOtlpTraceExporter(opts) {
|
|
|
48910
49069
|
const url = joinEndpoint2(opts.endpoint);
|
|
48911
49070
|
const intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS2;
|
|
48912
49071
|
const maxBuffered = opts.maxBufferedSpans ?? DEFAULT_BUFFER_CAP;
|
|
48913
|
-
const timeoutMs = opts.timeoutMs ??
|
|
49072
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS3;
|
|
48914
49073
|
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
48915
49074
|
const onError = opts.onError ?? (() => {
|
|
48916
49075
|
});
|
|
@@ -49441,8 +49600,8 @@ var DefaultPermissionPolicy = class {
|
|
|
49441
49600
|
const subject = subjectForToolInput(tool.name, input, tool.subjectKey);
|
|
49442
49601
|
const cacheKey = `${tool.name}::${subject ?? tool.name}`;
|
|
49443
49602
|
if (tool.name !== "write") {
|
|
49444
|
-
const
|
|
49445
|
-
if (
|
|
49603
|
+
const cached2 = this._evalCache.get(cacheKey);
|
|
49604
|
+
if (cached2 !== void 0) return cached2;
|
|
49446
49605
|
}
|
|
49447
49606
|
if (this.sessionDenied.has(cacheKey)) {
|
|
49448
49607
|
this._logDeny(tool.name, subject, "session soft deny (user pressed no)");
|
|
@@ -53519,7 +53678,7 @@ function applyModelRuntime(req, opts) {
|
|
|
53519
53678
|
}
|
|
53520
53679
|
|
|
53521
53680
|
// src/execution/one-shot-llm.ts
|
|
53522
|
-
var
|
|
53681
|
+
var DEFAULT_TIMEOUT_MS4 = 3e4;
|
|
53523
53682
|
var DEFAULT_MAX_TOKENS = 1024;
|
|
53524
53683
|
var OneShotOrchestrator = class {
|
|
53525
53684
|
opts;
|
|
@@ -53599,6 +53758,9 @@ var OneShotOrchestrator = class {
|
|
|
53599
53758
|
for (const entry of usableChain) {
|
|
53600
53759
|
if (!evaluateModelCalendar(config.modelAvailabilitySchedule, entry.providerId, entry.model).allowed)
|
|
53601
53760
|
continue;
|
|
53761
|
+
if (tracker && !tracker.isAvailable(entry.providerId, entry.model)) {
|
|
53762
|
+
continue;
|
|
53763
|
+
}
|
|
53602
53764
|
if (entry.providerId === provider.id && entry.model === target.model) continue;
|
|
53603
53765
|
let fbProvider;
|
|
53604
53766
|
try {
|
|
@@ -53682,7 +53844,7 @@ var OneShotOrchestrator = class {
|
|
|
53682
53844
|
* timeout, composed with external cancellation when the caller supplies it.
|
|
53683
53845
|
*/
|
|
53684
53846
|
resolveSignal(input) {
|
|
53685
|
-
const timeoutSignal = AbortSignal.timeout(input.timeoutMs ??
|
|
53847
|
+
const timeoutSignal = AbortSignal.timeout(input.timeoutMs ?? DEFAULT_TIMEOUT_MS4);
|
|
53686
53848
|
return input.signal ? AbortSignal.any([input.signal, timeoutSignal]) : timeoutSignal;
|
|
53687
53849
|
}
|
|
53688
53850
|
/**
|
|
@@ -55294,8 +55456,8 @@ var PhaseOrchestrator = class {
|
|
|
55294
55456
|
});
|
|
55295
55457
|
}
|
|
55296
55458
|
getTrackerForPhase(phase) {
|
|
55297
|
-
const
|
|
55298
|
-
if (
|
|
55459
|
+
const cached2 = this.trackerCache.get(phase.id);
|
|
55460
|
+
if (cached2) return cached2;
|
|
55299
55461
|
const tracker = new TaskTracker({ store: new DefaultTaskStore() });
|
|
55300
55462
|
tracker.setGraph(phase.taskGraph);
|
|
55301
55463
|
this.trackerCache.set(phase.id, tracker);
|
|
@@ -56315,7 +56477,7 @@ var CheckpointManager = class {
|
|
|
56315
56477
|
|
|
56316
56478
|
// src/hooks/shell-executor.ts
|
|
56317
56479
|
import { spawn as spawn4 } from "node:child_process";
|
|
56318
|
-
var
|
|
56480
|
+
var DEFAULT_TIMEOUT_MS5 = 5e3;
|
|
56319
56481
|
var MAX_OUTPUT_BYTES = 64 * 1024;
|
|
56320
56482
|
var ALLOWED_SHELL_COMMANDS = /* @__PURE__ */ new Set([
|
|
56321
56483
|
// POSIX shells + Windows shells
|
|
@@ -56441,7 +56603,7 @@ async function runShellHook(spec, input, logger) {
|
|
|
56441
56603
|
return result.outcome;
|
|
56442
56604
|
}
|
|
56443
56605
|
async function runShellHookDetailed(spec, input, logger, options = {}) {
|
|
56444
|
-
const timeoutMs = Math.max(1, Math.min(spec.timeoutMs ??
|
|
56606
|
+
const timeoutMs = Math.max(1, Math.min(spec.timeoutMs ?? DEFAULT_TIMEOUT_MS5, 10 * 6e4));
|
|
56445
56607
|
const argv = isCommandAllowed(spec.command);
|
|
56446
56608
|
if (!argv) {
|
|
56447
56609
|
logger?.warn?.(`hook rejected: command not in allowlist: ${spec.command}`);
|
|
@@ -56594,7 +56756,7 @@ function parseHookOutcome(stdout) {
|
|
|
56594
56756
|
}
|
|
56595
56757
|
|
|
56596
56758
|
// src/hooks/http-executor.ts
|
|
56597
|
-
var
|
|
56759
|
+
var DEFAULT_TIMEOUT_MS6 = 5e3;
|
|
56598
56760
|
var MAX_OUTPUT_BYTES2 = 64 * 1024;
|
|
56599
56761
|
function isAllowedUrl(raw) {
|
|
56600
56762
|
try {
|
|
@@ -56616,7 +56778,7 @@ async function runHttpHookDetailed(spec, input, logger, options = {}) {
|
|
|
56616
56778
|
}
|
|
56617
56779
|
};
|
|
56618
56780
|
}
|
|
56619
|
-
const timeoutMs = Math.max(1, Math.min(spec.timeoutMs ??
|
|
56781
|
+
const timeoutMs = Math.max(1, Math.min(spec.timeoutMs ?? DEFAULT_TIMEOUT_MS6, 10 * 6e4));
|
|
56620
56782
|
const timeoutController = new AbortController();
|
|
56621
56783
|
const timer = setTimeout(() => timeoutController.abort(new Error("hook timeout")), timeoutMs);
|
|
56622
56784
|
timer.unref?.();
|
|
@@ -56821,7 +56983,7 @@ function hookMatcherMatches(matcher, toolName) {
|
|
|
56821
56983
|
}
|
|
56822
56984
|
|
|
56823
56985
|
// src/hooks/runner.ts
|
|
56824
|
-
var
|
|
56986
|
+
var DEFAULT_TIMEOUT_MS7 = 5e3;
|
|
56825
56987
|
var MAX_TIMEOUT_MS = 10 * 6e4;
|
|
56826
56988
|
function normalizePreToolOutcome(outcome) {
|
|
56827
56989
|
if ("action" in outcome) return outcome;
|
|
@@ -57007,7 +57169,7 @@ var HookRunner = class {
|
|
|
57007
57169
|
return this.failureOutcome(entry, payload, result.failure);
|
|
57008
57170
|
}
|
|
57009
57171
|
async invokeInProcess(entry, payload, env) {
|
|
57010
|
-
const timeoutMs = Math.max(1, Math.min(entry.timeoutMs ??
|
|
57172
|
+
const timeoutMs = Math.max(1, Math.min(entry.timeoutMs ?? DEFAULT_TIMEOUT_MS7, MAX_TIMEOUT_MS));
|
|
57011
57173
|
const controller = new AbortController();
|
|
57012
57174
|
let timedOut = false;
|
|
57013
57175
|
const onParentAbort = () => controller.abort(env.signal?.reason);
|
|
@@ -59720,8 +59882,8 @@ function makePluginLLM(owner, hostLLM, providerRegistry, config, getLiveConfig,
|
|
|
59720
59882
|
return { provider: liveProvider, providerName };
|
|
59721
59883
|
}
|
|
59722
59884
|
const cacheKey = `${providerName}|${model}`;
|
|
59723
|
-
const
|
|
59724
|
-
if (
|
|
59885
|
+
const cached2 = providerCache.get(cacheKey);
|
|
59886
|
+
if (cached2) return { provider: cached2, providerName };
|
|
59725
59887
|
let created;
|
|
59726
59888
|
if (hostLLM.createProvider) {
|
|
59727
59889
|
created = hostLLM.createProvider(providerName, model);
|
|
@@ -64102,9 +64264,9 @@ var ReplayProviderRunner = class {
|
|
|
64102
64264
|
opts;
|
|
64103
64265
|
async run(runOpts) {
|
|
64104
64266
|
const hash4 = hashRequest(runOpts.request);
|
|
64105
|
-
const
|
|
64267
|
+
const cached2 = await this.opts.log.lookup(this.opts.sessionId, hash4);
|
|
64106
64268
|
if (this.opts.mode === "replay") {
|
|
64107
|
-
if (!
|
|
64269
|
+
if (!cached2) {
|
|
64108
64270
|
this.opts.logger?.warn?.(
|
|
64109
64271
|
`replay: no recorded response for hash ${hash4} (model ${runOpts.request.model})`
|
|
64110
64272
|
);
|
|
@@ -64113,15 +64275,15 @@ var ReplayProviderRunner = class {
|
|
|
64113
64275
|
);
|
|
64114
64276
|
}
|
|
64115
64277
|
this.opts.logger?.debug?.(
|
|
64116
|
-
`replay: served cached response for hash ${hash4} (recorded ${
|
|
64278
|
+
`replay: served cached response for hash ${hash4} (recorded ${cached2.ts})`
|
|
64117
64279
|
);
|
|
64118
|
-
return
|
|
64280
|
+
return cached2.response;
|
|
64119
64281
|
}
|
|
64120
|
-
if (this.opts.mode === "auto" &&
|
|
64282
|
+
if (this.opts.mode === "auto" && cached2) {
|
|
64121
64283
|
this.opts.logger?.debug?.(
|
|
64122
64284
|
`replay: auto-hit hash ${hash4}, served cached response`
|
|
64123
64285
|
);
|
|
64124
|
-
return
|
|
64286
|
+
return cached2.response;
|
|
64125
64287
|
}
|
|
64126
64288
|
const response = await this.inner.run(runOpts);
|
|
64127
64289
|
await this.opts.log.record({
|
|
@@ -64341,9 +64503,9 @@ var FileMemoryBackend = class {
|
|
|
64341
64503
|
}
|
|
64342
64504
|
async getIndex(file, scope) {
|
|
64343
64505
|
const mtime = await this.getMtime(file);
|
|
64344
|
-
const
|
|
64345
|
-
if (
|
|
64346
|
-
return
|
|
64506
|
+
const cached2 = this.indexCache.get(file);
|
|
64507
|
+
if (cached2 && cached2.mtimeMs === mtime) {
|
|
64508
|
+
return cached2;
|
|
64347
64509
|
}
|
|
64348
64510
|
const entries = await this.loadEntries(file, scope, mtime);
|
|
64349
64511
|
const index = buildInvertedIndex(entries);
|
|
@@ -70189,6 +70351,8 @@ export {
|
|
|
70189
70351
|
MAILBOX_HEALTH_DEFAULT_FROM,
|
|
70190
70352
|
MAILBOX_HEALTH_DEFAULT_INTERVAL_MS,
|
|
70191
70353
|
MAILBOX_HEALTH_DEFAULT_TIMEOUT_MS,
|
|
70354
|
+
MAILBOX_HTTP_DEFAULT_MAX_AGE_MS,
|
|
70355
|
+
MAILBOX_HTTP_MAX_AGE_CEILING_MS,
|
|
70192
70356
|
MAILBOX_HTTP_MAX_BODY_BYTES,
|
|
70193
70357
|
MAILBOX_HTTP_RATE_LIMIT_PER_MINUTE,
|
|
70194
70358
|
MAILBOX_HTTP_RATE_LIMIT_WINDOW_MS,
|
|
@@ -70352,6 +70516,7 @@ export {
|
|
|
70352
70516
|
buildTranscriptFromEvents,
|
|
70353
70517
|
buildUserContentBlocks,
|
|
70354
70518
|
canonicalProjectRoot,
|
|
70519
|
+
checkConnectivity,
|
|
70355
70520
|
childChronicleContext,
|
|
70356
70521
|
classifyFamily,
|
|
70357
70522
|
classifyMailboxRecipient,
|
|
@@ -70728,6 +70893,7 @@ export {
|
|
|
70728
70893
|
repairToolUseAdjacency,
|
|
70729
70894
|
repeatedReadPressure,
|
|
70730
70895
|
resetCalibration,
|
|
70896
|
+
resetConnectivityCache,
|
|
70731
70897
|
resolveAuditLevel,
|
|
70732
70898
|
resolveBrainConfigDefaults,
|
|
70733
70899
|
resolveBundledDesignKitsDir,
|