github-router 0.3.211 → 0.3.219
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/browser-bridge/index.js +1 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/engine-DyY5qdpL.js +6 -0
- package/dist/main.js +4 -4
- package/dist/main.js.map +1 -1
- package/dist/{peer-mcp-personas-CxpFD-rW.js → peer-mcp-personas-A6PytLD6.js} +1013 -680
- package/dist/peer-mcp-personas-A6PytLD6.js.map +1 -0
- package/package.json +3 -1
- package/dist/engine-DFuchRoh.js +0 -6
- package/dist/peer-mcp-personas-CxpFD-rW.js.map +0 -1
|
@@ -23,12 +23,13 @@ import { Worker } from "node:worker_threads";
|
|
|
23
23
|
import { gunzipSync, inflateRawSync } from "node:zlib";
|
|
24
24
|
import WebSocket from "ws";
|
|
25
25
|
import { events } from "fetch-event-stream";
|
|
26
|
-
import { Type } from "typebox";
|
|
26
|
+
import { Type, Type as Type$1 } from "typebox";
|
|
27
27
|
import "partial-json";
|
|
28
28
|
import { Compile } from "typebox/compile";
|
|
29
29
|
import { Value } from "typebox/value";
|
|
30
30
|
import "yaml";
|
|
31
31
|
import "ignore";
|
|
32
|
+
import "diff";
|
|
32
33
|
|
|
33
34
|
//#region rolldown:runtime
|
|
34
35
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
@@ -637,9 +638,9 @@ function resolveModel(modelId) {
|
|
|
637
638
|
if (oneMMatch) {
|
|
638
639
|
const stripped = oneMMatch[1];
|
|
639
640
|
const resolved = resolveModel(stripped);
|
|
640
|
-
if (
|
|
641
|
+
if (!(/-1m(?:$|-)/.test(resolved) || (models.find((m) => m.id === resolved)?.capabilities?.limits?.max_context_window_tokens ?? 0) >= 1e6) && !warnedOneMDowngrade.has(modelId)) {
|
|
641
642
|
warnedOneMDowngrade.add(modelId);
|
|
642
|
-
consola.warn(`Model "${modelId}" requested 1M context but no
|
|
643
|
+
consola.warn(`Model "${modelId}" requested 1M context but no 1M backend is in Copilot's catalog for this tier/family; downgrading upstream to "${resolved}" (200K). Claude Code's local context accounting will still assume 1M — expect premature auto-compact. Drop the [1m] suffix (or unset CLAUDE_CODE_DISABLE_1M_CONTEXT if you set it) to silence.`);
|
|
643
644
|
}
|
|
644
645
|
return resolved;
|
|
645
646
|
}
|
|
@@ -649,8 +650,8 @@ function resolveModel(modelId) {
|
|
|
649
650
|
if (ciMatch) return ciMatch.id;
|
|
650
651
|
if (lower.includes("opus")) {
|
|
651
652
|
const oneMs = models.filter((m) => m.id.includes("opus") && /-1m(?:$|-)/.test(m.id));
|
|
652
|
-
const versionMatch = lower.match(/opus-(\d+)[.-](\d+)
|
|
653
|
-
const requestedVersion = versionMatch ? `${versionMatch[1]}.${versionMatch[2]}` : void 0;
|
|
653
|
+
const versionMatch = lower.match(/opus-(\d+)(?:[.-](\d+))?/);
|
|
654
|
+
const requestedVersion = versionMatch ? versionMatch[2] ? `${versionMatch[1]}.${versionMatch[2]}` : versionMatch[1] : void 0;
|
|
654
655
|
const oneM = (requestedVersion ? oneMs.find((m) => m.id.includes(`opus-${requestedVersion}-`)) : void 0) ?? (requestedVersion ? void 0 : oneMs[0]);
|
|
655
656
|
if (oneM) return oneM.id;
|
|
656
657
|
}
|
|
@@ -1005,15 +1006,15 @@ function getPackageVersion() {
|
|
|
1005
1006
|
//#region src/lib/port.ts
|
|
1006
1007
|
const DEFAULT_PORT = 8787;
|
|
1007
1008
|
const DEFAULT_CLAUDE_MODEL_FALLBACKS = [
|
|
1009
|
+
"claude-opus-4-8",
|
|
1008
1010
|
"claude-opus-4-7",
|
|
1009
|
-
"claude-opus-4-6"
|
|
1010
|
-
"claude-opus-4-5"
|
|
1011
|
+
"claude-opus-4-6"
|
|
1011
1012
|
];
|
|
1012
1013
|
/**
|
|
1013
1014
|
* Cap-aware default picker for `ANTHROPIC_MODEL` on the implicit-default
|
|
1014
1015
|
* path. Returns `claude-opus-${family}[1m]` when the live Copilot catalog
|
|
1015
1016
|
* shows the family is 1M-capable, else the bare `claude-opus-${family}`
|
|
1016
|
-
* slug. `family` defaults to `"
|
|
1017
|
+
* slug. `family` defaults to `"5"` so the no-arg call selects the
|
|
1017
1018
|
* current default; explicit values like `"4.7"` or `"4.6"` are used to
|
|
1018
1019
|
* honor the `github-router claude -m <version>` family shorthand.
|
|
1019
1020
|
*
|
|
@@ -1027,8 +1028,8 @@ const DEFAULT_CLAUDE_MODEL_FALLBACKS = [
|
|
|
1027
1028
|
* 2. **Base-slug capability signal** — the catalog entry whose id IS
|
|
1028
1029
|
* the base `opus-${family}` slug advertises
|
|
1029
1030
|
* `capabilities.limits.max_context_window_tokens >= 1_000_000`. This
|
|
1030
|
-
* is how 4.8
|
|
1031
|
-
* `claude-opus-4.8` id is the 1M variant.
|
|
1031
|
+
* is how 4.8 and 5 ship — there is no `-1m` sibling; the single
|
|
1032
|
+
* `claude-opus-4.8` / `claude-opus-5` id is itself the 1M variant.
|
|
1032
1033
|
* Either signal flips on the `[1m]` decoration. Both signals together
|
|
1033
1034
|
* also flip it on (no double-counting). The breadcrumb log names which
|
|
1034
1035
|
* signal fired so users can spot catalog shape changes.
|
|
@@ -1058,7 +1059,7 @@ const DEFAULT_CLAUDE_MODEL_FALLBACKS = [
|
|
|
1058
1059
|
* can't tell the difference between "no catalog yet" and "no 1M
|
|
1059
1060
|
* variant" — defaulting safe-side preserves the pre-change behavior).
|
|
1060
1061
|
*/
|
|
1061
|
-
const DEFAULT_OPUS_FAMILY = "
|
|
1062
|
+
const DEFAULT_OPUS_FAMILY = "5";
|
|
1062
1063
|
const ONE_M_TOKENS = 1e6;
|
|
1063
1064
|
function pickClaudeDefault(opusFamily = DEFAULT_OPUS_FAMILY) {
|
|
1064
1065
|
const dotted = opusFamily.replace(/-/g, ".");
|
|
@@ -6187,19 +6188,19 @@ function resolveTierModel(tier$1) {
|
|
|
6187
6188
|
|
|
6188
6189
|
//#endregion
|
|
6189
6190
|
//#region src/lib/first-mate/classifier.ts
|
|
6190
|
-
function isRecord$
|
|
6191
|
+
function isRecord$1(value) {
|
|
6191
6192
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6192
6193
|
}
|
|
6193
6194
|
function firstMessageContent$1(value) {
|
|
6194
|
-
if (!isRecord$
|
|
6195
|
+
if (!isRecord$1(value) || !Array.isArray(value.choices)) return null;
|
|
6195
6196
|
const first = value.choices[0];
|
|
6196
|
-
if (!isRecord$
|
|
6197
|
+
if (!isRecord$1(first) || !isRecord$1(first.message)) return null;
|
|
6197
6198
|
return typeof first.message.content === "string" ? first.message.content : null;
|
|
6198
6199
|
}
|
|
6199
6200
|
function parseJsonObject(value) {
|
|
6200
6201
|
try {
|
|
6201
6202
|
const parsed = JSON.parse(value);
|
|
6202
|
-
return isRecord$
|
|
6203
|
+
return isRecord$1(parsed) ? parsed : null;
|
|
6203
6204
|
} catch {
|
|
6204
6205
|
return null;
|
|
6205
6206
|
}
|
|
@@ -6269,7 +6270,7 @@ async function classifyPlanReady(logExcerpt) {
|
|
|
6269
6270
|
schemaHint: "{\"planReady\":boolean,\"planExcerpt\":\"<=1200 chars from the completed plan, or empty\",\"confidence\":number}",
|
|
6270
6271
|
maxTokens: 500,
|
|
6271
6272
|
validate(value) {
|
|
6272
|
-
if (!isRecord$
|
|
6273
|
+
if (!isRecord$1(value)) return null;
|
|
6273
6274
|
const planReady = booleanValue$1(value.planReady);
|
|
6274
6275
|
const planExcerpt = stringValue$1(value.planExcerpt);
|
|
6275
6276
|
if (planReady === null || planExcerpt === null) return null;
|
|
@@ -6286,7 +6287,7 @@ async function classifyQuestionAnswerable(question, acceptanceCriteria) {
|
|
|
6286
6287
|
user: `Acceptance criteria:\n${acceptanceCriteria}\n\nAgent question:\n${question}`,
|
|
6287
6288
|
schemaHint: "{\"answerable\":boolean,\"answer\":\"present only when answerable\",\"confidence\":number}",
|
|
6288
6289
|
validate(value) {
|
|
6289
|
-
if (!isRecord$
|
|
6290
|
+
if (!isRecord$1(value)) return null;
|
|
6290
6291
|
const answerable = booleanValue$1(value.answerable);
|
|
6291
6292
|
if (answerable === null) return null;
|
|
6292
6293
|
const answer = stringValue$1(value.answer);
|
|
@@ -6304,7 +6305,7 @@ async function classifyFixAddressed(failureSummary, latestLogExcerpt) {
|
|
|
6304
6305
|
user: `Failure summary:\n${failureSummary}\n\nLatest log excerpt:\n${latestLogExcerpt}`,
|
|
6305
6306
|
schemaHint: "{\"addressed\":boolean,\"confidence\":number}",
|
|
6306
6307
|
validate(value) {
|
|
6307
|
-
if (!isRecord$
|
|
6308
|
+
if (!isRecord$1(value)) return null;
|
|
6308
6309
|
const addressed = booleanValue$1(value.addressed);
|
|
6309
6310
|
return addressed === null ? null : { addressed };
|
|
6310
6311
|
}
|
|
@@ -6316,7 +6317,7 @@ async function classifyStuck(logExcerpt) {
|
|
|
6316
6317
|
user: `Log excerpt:\n${logExcerpt}`,
|
|
6317
6318
|
schemaHint: "{\"stuck\":boolean,\"confidence\":number}",
|
|
6318
6319
|
validate(value) {
|
|
6319
|
-
if (!isRecord$
|
|
6320
|
+
if (!isRecord$1(value)) return null;
|
|
6320
6321
|
const stuck = booleanValue$1(value.stuck);
|
|
6321
6322
|
return stuck === null ? null : { stuck };
|
|
6322
6323
|
}
|
|
@@ -12715,7 +12716,7 @@ function parsePackageJson(text) {
|
|
|
12715
12716
|
if (text === void 0) return void 0;
|
|
12716
12717
|
try {
|
|
12717
12718
|
const parsed = JSON.parse(text);
|
|
12718
|
-
if (!isRecord
|
|
12719
|
+
if (!isRecord(parsed)) return void 0;
|
|
12719
12720
|
return {
|
|
12720
12721
|
scripts: stringRecord(parsed.scripts),
|
|
12721
12722
|
dependencies: stringRecord(parsed.dependencies),
|
|
@@ -12727,9 +12728,9 @@ function parsePackageJson(text) {
|
|
|
12727
12728
|
return;
|
|
12728
12729
|
}
|
|
12729
12730
|
}
|
|
12730
|
-
function detectCommands(packageJson, overrides) {
|
|
12731
|
+
function detectCommands(packageJson, overrides$1) {
|
|
12731
12732
|
const commands = {};
|
|
12732
|
-
const pm = overrides?.package_manager ?? packageJson?.packageManager?.split("@")[0];
|
|
12733
|
+
const pm = overrides$1?.package_manager ?? packageJson?.packageManager?.split("@")[0];
|
|
12733
12734
|
const runner = pm === "bun" || pm === "pnpm" || pm === "yarn" || pm === "npm" ? pm : "npm";
|
|
12734
12735
|
const scripts = packageJson?.scripts ?? {};
|
|
12735
12736
|
if (packageJson !== void 0) {
|
|
@@ -12742,11 +12743,11 @@ function detectCommands(packageJson, overrides) {
|
|
|
12742
12743
|
"dev"
|
|
12743
12744
|
]) if (scripts[key] !== void 0) commands[key] = runScriptCommand(runner, key);
|
|
12744
12745
|
}
|
|
12745
|
-
if (overrides?.build_command !== void 0) commands.build = overrides.build_command;
|
|
12746
|
-
if (overrides?.typecheck_command !== void 0) commands.typecheck = overrides.typecheck_command;
|
|
12747
|
-
if (overrides?.lint_command !== void 0) commands.lint = overrides.lint_command;
|
|
12748
|
-
if (overrides?.test_command !== void 0) commands.test = overrides.test_command;
|
|
12749
|
-
if (overrides?.dev_command !== void 0) commands.dev = overrides.dev_command;
|
|
12746
|
+
if (overrides$1?.build_command !== void 0) commands.build = overrides$1.build_command;
|
|
12747
|
+
if (overrides$1?.typecheck_command !== void 0) commands.typecheck = overrides$1.typecheck_command;
|
|
12748
|
+
if (overrides$1?.lint_command !== void 0) commands.lint = overrides$1.lint_command;
|
|
12749
|
+
if (overrides$1?.test_command !== void 0) commands.test = overrides$1.test_command;
|
|
12750
|
+
if (overrides$1?.dev_command !== void 0) commands.dev = overrides$1.dev_command;
|
|
12750
12751
|
return commands;
|
|
12751
12752
|
}
|
|
12752
12753
|
function detectPackageManager(rootNames, packageJsonText) {
|
|
@@ -12915,11 +12916,11 @@ function buildScaffoldPrBody(reports) {
|
|
|
12915
12916
|
"No factory protocol files are seeded; orchestration remains external to the repository."
|
|
12916
12917
|
].join("\n");
|
|
12917
12918
|
}
|
|
12918
|
-
function isRecord
|
|
12919
|
+
function isRecord(value) {
|
|
12919
12920
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12920
12921
|
}
|
|
12921
12922
|
function stringRecord(value) {
|
|
12922
|
-
if (!isRecord
|
|
12923
|
+
if (!isRecord(value)) return {};
|
|
12923
12924
|
const result = {};
|
|
12924
12925
|
for (const [key, entry] of Object.entries(value)) if (typeof entry === "string") result[key] = entry;
|
|
12925
12926
|
return result;
|
|
@@ -17432,7 +17433,7 @@ function hasSupportedBrowserInstalled() {
|
|
|
17432
17433
|
* `src/lib/paths.ts`, which has no win32 branch). On Windows the
|
|
17433
17434
|
* writer and reader never met, so the install-check returned
|
|
17434
17435
|
* `bridge_not_running` even with a healthy bridge. Centralized here so
|
|
17435
|
-
* the regression test in `tests/browser-bridge-discovery-path.test.ts`
|
|
17436
|
+
* the regression test in `tests/isolated/browser-bridge-discovery-path.test.ts`
|
|
17436
17437
|
* can pin the round-trip.
|
|
17437
17438
|
*
|
|
17438
17439
|
* Mirrors `PATHS.APP_DIR` from `src/lib/paths.ts` (XDG-style on every
|
|
@@ -21340,58 +21341,6 @@ function registerExitHandlers$1() {
|
|
|
21340
21341
|
}
|
|
21341
21342
|
registerExitHandlers$1();
|
|
21342
21343
|
|
|
21343
|
-
//#endregion
|
|
21344
|
-
//#region src/vendor/pi/ai/api-registry.ts
|
|
21345
|
-
const apiProviderRegistry = /* @__PURE__ */ new Map();
|
|
21346
|
-
function getApiProvider(api) {
|
|
21347
|
-
return apiProviderRegistry.get(api)?.provider;
|
|
21348
|
-
}
|
|
21349
|
-
|
|
21350
|
-
//#endregion
|
|
21351
|
-
//#region src/vendor/pi/ai/env-api-keys.ts
|
|
21352
|
-
let _existsSync = null;
|
|
21353
|
-
let _homedir = null;
|
|
21354
|
-
let _join = null;
|
|
21355
|
-
const dynamicImport = (specifier) => import(specifier);
|
|
21356
|
-
const NODE_FS_SPECIFIER = "node:fs";
|
|
21357
|
-
const NODE_OS_SPECIFIER = "node:os";
|
|
21358
|
-
const NODE_PATH_SPECIFIER = "node:path";
|
|
21359
|
-
if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
|
|
21360
|
-
dynamicImport(NODE_FS_SPECIFIER).then((m) => {
|
|
21361
|
-
_existsSync = m.existsSync;
|
|
21362
|
-
});
|
|
21363
|
-
dynamicImport(NODE_OS_SPECIFIER).then((m) => {
|
|
21364
|
-
_homedir = m.homedir;
|
|
21365
|
-
});
|
|
21366
|
-
dynamicImport(NODE_PATH_SPECIFIER).then((m) => {
|
|
21367
|
-
_join = m.join;
|
|
21368
|
-
});
|
|
21369
|
-
}
|
|
21370
|
-
|
|
21371
|
-
//#endregion
|
|
21372
|
-
//#region src/vendor/pi/ai/models.generated.ts
|
|
21373
|
-
const MODELS = {};
|
|
21374
|
-
|
|
21375
|
-
//#endregion
|
|
21376
|
-
//#region src/vendor/pi/ai/models.ts
|
|
21377
|
-
const modelRegistry = /* @__PURE__ */ new Map();
|
|
21378
|
-
for (const [provider, models] of Object.entries(MODELS)) {
|
|
21379
|
-
const providerModels = /* @__PURE__ */ new Map();
|
|
21380
|
-
for (const [id, model] of Object.entries(models)) providerModels.set(id, model);
|
|
21381
|
-
modelRegistry.set(provider, providerModels);
|
|
21382
|
-
}
|
|
21383
|
-
|
|
21384
|
-
//#endregion
|
|
21385
|
-
//#region src/vendor/pi/ai/stream.ts
|
|
21386
|
-
function resolveApiProvider(api) {
|
|
21387
|
-
const provider = getApiProvider(api);
|
|
21388
|
-
if (!provider) throw new Error(`No API provider registered for api: ${api}`);
|
|
21389
|
-
return provider;
|
|
21390
|
-
}
|
|
21391
|
-
function streamSimple(model, context, options) {
|
|
21392
|
-
return resolveApiProvider(model.api).streamSimple(model, context, options);
|
|
21393
|
-
}
|
|
21394
|
-
|
|
21395
21344
|
//#endregion
|
|
21396
21345
|
//#region src/vendor/pi/ai/utils/event-stream.ts
|
|
21397
21346
|
var EventStream = class {
|
|
@@ -21453,19 +21402,89 @@ var AssistantMessageEventStream = class extends EventStream {
|
|
|
21453
21402
|
}
|
|
21454
21403
|
};
|
|
21455
21404
|
|
|
21405
|
+
//#endregion
|
|
21406
|
+
//#region src/vendor/pi/ai/env-api-keys.ts
|
|
21407
|
+
let _existsSync = null;
|
|
21408
|
+
let _homedir = null;
|
|
21409
|
+
let _join = null;
|
|
21410
|
+
const dynamicImport = (specifier) => import(specifier);
|
|
21411
|
+
const NODE_FS_SPECIFIER = "node:fs";
|
|
21412
|
+
const NODE_OS_SPECIFIER = "node:os";
|
|
21413
|
+
const NODE_PATH_SPECIFIER = "node:path";
|
|
21414
|
+
if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
|
|
21415
|
+
dynamicImport(NODE_FS_SPECIFIER).then((m) => {
|
|
21416
|
+
_existsSync = m.existsSync;
|
|
21417
|
+
});
|
|
21418
|
+
dynamicImport(NODE_OS_SPECIFIER).then((m) => {
|
|
21419
|
+
_homedir = m.homedir;
|
|
21420
|
+
});
|
|
21421
|
+
dynamicImport(NODE_PATH_SPECIFIER).then((m) => {
|
|
21422
|
+
_join = m.join;
|
|
21423
|
+
});
|
|
21424
|
+
}
|
|
21425
|
+
|
|
21426
|
+
//#endregion
|
|
21427
|
+
//#region src/vendor/pi/ai/utils/retry.ts
|
|
21428
|
+
function buildProviderErrorPattern(patterns) {
|
|
21429
|
+
return new RegExp(patterns.join("|"), "i");
|
|
21430
|
+
}
|
|
21431
|
+
const NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN = buildProviderErrorPattern([
|
|
21432
|
+
"GoUsageLimitError",
|
|
21433
|
+
"FreeUsageLimitError",
|
|
21434
|
+
"Monthly usage limit reached",
|
|
21435
|
+
"available balance",
|
|
21436
|
+
"insufficient_quota",
|
|
21437
|
+
"out of budget",
|
|
21438
|
+
"quota exceeded",
|
|
21439
|
+
"billing"
|
|
21440
|
+
]);
|
|
21441
|
+
const RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([
|
|
21442
|
+
"overloaded",
|
|
21443
|
+
"rate.?limit",
|
|
21444
|
+
"too many requests",
|
|
21445
|
+
"429",
|
|
21446
|
+
"500",
|
|
21447
|
+
"502",
|
|
21448
|
+
"503",
|
|
21449
|
+
"504",
|
|
21450
|
+
"524",
|
|
21451
|
+
"service.?unavailable",
|
|
21452
|
+
"server.?error",
|
|
21453
|
+
"internal.?error",
|
|
21454
|
+
"provider.?returned.?error",
|
|
21455
|
+
"network.?error",
|
|
21456
|
+
"connection.?error",
|
|
21457
|
+
"connection.?refused",
|
|
21458
|
+
"connection.?lost",
|
|
21459
|
+
"other side closed",
|
|
21460
|
+
"fetch failed",
|
|
21461
|
+
"getaddrinfo",
|
|
21462
|
+
"ENOTFOUND",
|
|
21463
|
+
"EAI_AGAIN",
|
|
21464
|
+
"upstream.?connect",
|
|
21465
|
+
"reset before headers",
|
|
21466
|
+
"socket hang up",
|
|
21467
|
+
"socket connection was closed",
|
|
21468
|
+
"timed? out",
|
|
21469
|
+
"timeout",
|
|
21470
|
+
"terminated",
|
|
21471
|
+
"websocket.?closed",
|
|
21472
|
+
"websocket.?error",
|
|
21473
|
+
"ended without",
|
|
21474
|
+
"stream ended before message_stop",
|
|
21475
|
+
"stream ended before a terminal response event",
|
|
21476
|
+
"http2 request did not get a response",
|
|
21477
|
+
"retry delay",
|
|
21478
|
+
"you can retry your request",
|
|
21479
|
+
"try your request again",
|
|
21480
|
+
"please retry your request",
|
|
21481
|
+
"ResourceExhausted"
|
|
21482
|
+
]);
|
|
21483
|
+
|
|
21456
21484
|
//#endregion
|
|
21457
21485
|
//#region src/vendor/pi/ai/utils/validation.ts
|
|
21458
21486
|
const validatorCache = /* @__PURE__ */ new WeakMap();
|
|
21459
21487
|
const TYPEBOX_KIND = Symbol.for("TypeBox.Kind");
|
|
21460
|
-
function isRecord(value) {
|
|
21461
|
-
return typeof value === "object" && value !== null;
|
|
21462
|
-
}
|
|
21463
|
-
function isJsonSchemaObject(value) {
|
|
21464
|
-
return isRecord(value);
|
|
21465
|
-
}
|
|
21466
|
-
function hasTypeBoxMetadata(schema) {
|
|
21467
|
-
return isRecord(schema) && Object.getOwnPropertySymbols(schema).includes(TYPEBOX_KIND);
|
|
21468
|
-
}
|
|
21469
21488
|
function getSchemaTypes(schema) {
|
|
21470
21489
|
if (typeof schema.type === "string") return [schema.type];
|
|
21471
21490
|
if (Array.isArray(schema.type)) return schema.type.filter((type) => typeof type === "string");
|
|
@@ -21479,15 +21498,11 @@ function matchesJsonType(value, type) {
|
|
|
21479
21498
|
case "string": return typeof value === "string";
|
|
21480
21499
|
case "null": return value === null;
|
|
21481
21500
|
case "array": return Array.isArray(value);
|
|
21482
|
-
case "object": return
|
|
21501
|
+
case "object": return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21483
21502
|
default: return false;
|
|
21484
21503
|
}
|
|
21485
21504
|
}
|
|
21486
|
-
function isValidatorSchema(value) {
|
|
21487
|
-
return isRecord(value);
|
|
21488
|
-
}
|
|
21489
21505
|
function getSubSchemaValidator(schema) {
|
|
21490
|
-
if (!isValidatorSchema(schema)) return;
|
|
21491
21506
|
try {
|
|
21492
21507
|
return getValidator(schema);
|
|
21493
21508
|
} catch {
|
|
@@ -21540,7 +21555,7 @@ function applySchemaObjectCoercion(value, schema) {
|
|
|
21540
21555
|
if (!(key in value)) continue;
|
|
21541
21556
|
value[key] = coerceWithJsonSchema(value[key], propertySchema);
|
|
21542
21557
|
}
|
|
21543
|
-
if (schema.additionalProperties &&
|
|
21558
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === "object") for (const [key, propertyValue] of Object.entries(value)) {
|
|
21544
21559
|
if (definedKeys.has(key)) continue;
|
|
21545
21560
|
value[key] = coerceWithJsonSchema(propertyValue, schema.additionalProperties);
|
|
21546
21561
|
}
|
|
@@ -21554,7 +21569,7 @@ function applySchemaArrayCoercion(value, schema) {
|
|
|
21554
21569
|
}
|
|
21555
21570
|
return;
|
|
21556
21571
|
}
|
|
21557
|
-
if (
|
|
21572
|
+
if (schema.items && typeof schema.items === "object") for (let index = 0; index < value.length; index++) value[index] = coerceWithJsonSchema(value[index], schema.items);
|
|
21558
21573
|
}
|
|
21559
21574
|
function coerceWithUnionSchema(value, schemas) {
|
|
21560
21575
|
for (const schema of schemas) {
|
|
@@ -21577,7 +21592,7 @@ function coerceWithJsonSchema(value, schema) {
|
|
|
21577
21592
|
break;
|
|
21578
21593
|
}
|
|
21579
21594
|
}
|
|
21580
|
-
if (schemaTypes.includes("object") &&
|
|
21595
|
+
if (schemaTypes.includes("object") && typeof nextValue === "object" && nextValue !== null && !Array.isArray(nextValue)) applySchemaObjectCoercion(nextValue, schema);
|
|
21581
21596
|
if (schemaTypes.includes("array") && Array.isArray(nextValue)) applySchemaArrayCoercion(nextValue, schema);
|
|
21582
21597
|
return nextValue;
|
|
21583
21598
|
}
|
|
@@ -21610,9 +21625,9 @@ function validateToolArguments(tool$1, toolCall) {
|
|
|
21610
21625
|
const args = structuredClone(toolCall.arguments);
|
|
21611
21626
|
Value.Convert(tool$1.parameters, args);
|
|
21612
21627
|
const validator = getValidator(tool$1.parameters);
|
|
21613
|
-
if (!
|
|
21628
|
+
if (!Object.getOwnPropertySymbols(tool$1.parameters).includes(TYPEBOX_KIND)) {
|
|
21614
21629
|
const coerced = coerceWithJsonSchema(args, tool$1.parameters);
|
|
21615
|
-
if (coerced !== args) if (
|
|
21630
|
+
if (coerced !== args) if (typeof args === "object" && args !== null && typeof coerced === "object" && coerced !== null) {
|
|
21616
21631
|
for (const key of Object.keys(args)) delete args[key];
|
|
21617
21632
|
Object.assign(args, coerced);
|
|
21618
21633
|
} else return validator.Check(coerced) ? coerced : args;
|
|
@@ -21623,6 +21638,14 @@ function validateToolArguments(tool$1, toolCall) {
|
|
|
21623
21638
|
throw new Error(errorMessage);
|
|
21624
21639
|
}
|
|
21625
21640
|
|
|
21641
|
+
//#endregion
|
|
21642
|
+
//#region src/vendor/pi/agent/stream-fn.ts
|
|
21643
|
+
let defaultStreamFn;
|
|
21644
|
+
function getDefaultStreamFn() {
|
|
21645
|
+
if (!defaultStreamFn) throw new Error("No default stream function configured. Pass streamFn explicitly or call setDefaultStreamFn().");
|
|
21646
|
+
return defaultStreamFn;
|
|
21647
|
+
}
|
|
21648
|
+
|
|
21626
21649
|
//#endregion
|
|
21627
21650
|
//#region src/vendor/pi/agent/agent-loop.ts
|
|
21628
21651
|
async function runAgentLoop(prompts, context, config, emit, signal, streamFn) {
|
|
@@ -21643,7 +21666,7 @@ async function runAgentLoop(prompts, context, config, emit, signal, streamFn) {
|
|
|
21643
21666
|
message: prompt
|
|
21644
21667
|
});
|
|
21645
21668
|
}
|
|
21646
|
-
await runLoop(currentContext, newMessages, config, signal, emit, streamFn);
|
|
21669
|
+
await runLoop(currentContext, newMessages, config, signal, emit, streamFn ?? getDefaultStreamFn());
|
|
21647
21670
|
return newMessages;
|
|
21648
21671
|
}
|
|
21649
21672
|
async function runAgentLoopContinue(context, config, emit, signal, streamFn) {
|
|
@@ -21653,13 +21676,13 @@ async function runAgentLoopContinue(context, config, emit, signal, streamFn) {
|
|
|
21653
21676
|
const currentContext = { ...context };
|
|
21654
21677
|
await emit({ type: "agent_start" });
|
|
21655
21678
|
await emit({ type: "turn_start" });
|
|
21656
|
-
await runLoop(currentContext, newMessages, config, signal, emit, streamFn);
|
|
21679
|
+
await runLoop(currentContext, newMessages, config, signal, emit, streamFn ?? getDefaultStreamFn());
|
|
21657
21680
|
return newMessages;
|
|
21658
21681
|
}
|
|
21659
21682
|
/**
|
|
21660
21683
|
* Main loop logic shared by agentLoop and agentLoopContinue.
|
|
21661
21684
|
*/
|
|
21662
|
-
async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
21685
|
+
async function runLoop(initialContext, newMessages, initialConfig, signal, emit, streamFunction) {
|
|
21663
21686
|
let currentContext = initialContext;
|
|
21664
21687
|
let config = initialConfig;
|
|
21665
21688
|
let firstTurn = true;
|
|
@@ -21684,7 +21707,7 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
|
21684
21707
|
}
|
|
21685
21708
|
pendingMessages = [];
|
|
21686
21709
|
}
|
|
21687
|
-
const message = await streamAssistantResponse(currentContext, config, signal, emit,
|
|
21710
|
+
const message = await streamAssistantResponse(currentContext, config, signal, emit, streamFunction);
|
|
21688
21711
|
newMessages.push(message);
|
|
21689
21712
|
if (message.stopReason === "error" || message.stopReason === "aborted") {
|
|
21690
21713
|
await emit({
|
|
@@ -21702,7 +21725,7 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
|
21702
21725
|
const toolResults = [];
|
|
21703
21726
|
hasMoreToolCalls = false;
|
|
21704
21727
|
if (toolCalls.length > 0) {
|
|
21705
|
-
const executedToolBatch = await executeToolCalls(currentContext, message, config, signal, emit);
|
|
21728
|
+
const executedToolBatch = message.stopReason === "length" ? await failToolCallsFromTruncatedMessage(toolCalls, emit) : await executeToolCalls(currentContext, message, config, signal, emit);
|
|
21706
21729
|
toolResults.push(...executedToolBatch.messages);
|
|
21707
21730
|
hasMoreToolCalls = !executedToolBatch.terminate;
|
|
21708
21731
|
for (const result of toolResults) {
|
|
@@ -21760,7 +21783,7 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
|
|
|
21760
21783
|
* Stream an assistant response from the LLM.
|
|
21761
21784
|
* This is where AgentMessage[] gets transformed to Message[] for the LLM.
|
|
21762
21785
|
*/
|
|
21763
|
-
async function streamAssistantResponse(context, config, signal, emit,
|
|
21786
|
+
async function streamAssistantResponse(context, config, signal, emit, streamFunction) {
|
|
21764
21787
|
let messages = context.messages;
|
|
21765
21788
|
if (config.transformContext) messages = await config.transformContext(messages, signal);
|
|
21766
21789
|
const llmMessages = await config.convertToLlm(messages);
|
|
@@ -21769,7 +21792,6 @@ async function streamAssistantResponse(context, config, signal, emit, streamFn)
|
|
|
21769
21792
|
messages: llmMessages,
|
|
21770
21793
|
tools: context.tools
|
|
21771
21794
|
};
|
|
21772
|
-
const streamFunction = streamFn || streamSimple;
|
|
21773
21795
|
const resolvedApiKey = (config.getApiKey ? await config.getApiKey(config.model.provider) : void 0) || config.apiKey;
|
|
21774
21796
|
const response = await streamFunction(config.model, llmContext, {
|
|
21775
21797
|
...config,
|
|
@@ -21839,6 +21861,37 @@ async function streamAssistantResponse(context, config, signal, emit, streamFn)
|
|
|
21839
21861
|
return finalMessage;
|
|
21840
21862
|
}
|
|
21841
21863
|
/**
|
|
21864
|
+
* Fail all tool calls from an assistant message that was truncated by the
|
|
21865
|
+
* output token limit. Streamed tool-call arguments are finalized with a
|
|
21866
|
+
* best-effort JSON salvage parser, so a truncated message can yield tool calls
|
|
21867
|
+
* whose arguments parse and validate but are silently incomplete. None of them
|
|
21868
|
+
* are safe to execute; report each as an error so the model can re-issue them.
|
|
21869
|
+
*/
|
|
21870
|
+
async function failToolCallsFromTruncatedMessage(toolCalls, emit) {
|
|
21871
|
+
const messages = [];
|
|
21872
|
+
for (const toolCall of toolCalls) {
|
|
21873
|
+
await emit({
|
|
21874
|
+
type: "tool_execution_start",
|
|
21875
|
+
toolCallId: toolCall.id,
|
|
21876
|
+
toolName: toolCall.name,
|
|
21877
|
+
args: toolCall.arguments
|
|
21878
|
+
});
|
|
21879
|
+
const finalized = {
|
|
21880
|
+
toolCall,
|
|
21881
|
+
result: createErrorToolResult(`Tool call "${toolCall.name}" was not executed: the response hit the output token limit, so its arguments may be truncated. Re-issue the tool call with complete arguments.`),
|
|
21882
|
+
isError: true
|
|
21883
|
+
};
|
|
21884
|
+
await emitToolExecutionEnd(finalized, emit);
|
|
21885
|
+
const toolResultMessage = createToolResultMessage(finalized);
|
|
21886
|
+
await emitToolResultMessage(toolResultMessage, emit);
|
|
21887
|
+
messages.push(toolResultMessage);
|
|
21888
|
+
}
|
|
21889
|
+
return {
|
|
21890
|
+
messages,
|
|
21891
|
+
terminate: false
|
|
21892
|
+
};
|
|
21893
|
+
}
|
|
21894
|
+
/**
|
|
21842
21895
|
* Execute tool calls from an assistant message.
|
|
21843
21896
|
*/
|
|
21844
21897
|
async function executeToolCalls(currentContext, assistantMessage, config, signal, emit) {
|
|
@@ -21977,8 +22030,10 @@ async function prepareToolCall(currentContext, assistantMessage, toolCall, confi
|
|
|
21977
22030
|
}
|
|
21978
22031
|
async function executePreparedToolCall(prepared, signal, emit) {
|
|
21979
22032
|
const updateEvents = [];
|
|
22033
|
+
let acceptingUpdates = true;
|
|
21980
22034
|
try {
|
|
21981
22035
|
const result = await prepared.tool.execute(prepared.toolCall.id, prepared.args, signal, (partialResult) => {
|
|
22036
|
+
if (!acceptingUpdates) return;
|
|
21982
22037
|
updateEvents.push(Promise.resolve(emit({
|
|
21983
22038
|
type: "tool_execution_update",
|
|
21984
22039
|
toolCallId: prepared.toolCall.id,
|
|
@@ -21987,17 +22042,21 @@ async function executePreparedToolCall(prepared, signal, emit) {
|
|
|
21987
22042
|
partialResult
|
|
21988
22043
|
})));
|
|
21989
22044
|
});
|
|
22045
|
+
acceptingUpdates = false;
|
|
21990
22046
|
await Promise.all(updateEvents);
|
|
21991
22047
|
return {
|
|
21992
22048
|
result,
|
|
21993
22049
|
isError: false
|
|
21994
22050
|
};
|
|
21995
22051
|
} catch (error) {
|
|
22052
|
+
acceptingUpdates = false;
|
|
21996
22053
|
await Promise.all(updateEvents);
|
|
21997
22054
|
return {
|
|
21998
22055
|
result: createErrorToolResult(error instanceof Error ? error.message : String(error)),
|
|
21999
22056
|
isError: true
|
|
22000
22057
|
};
|
|
22058
|
+
} finally {
|
|
22059
|
+
acceptingUpdates = false;
|
|
22001
22060
|
}
|
|
22002
22061
|
}
|
|
22003
22062
|
async function finalizeExecutedToolCall(currentContext, assistantMessage, prepared, executed, config, signal) {
|
|
@@ -22014,8 +22073,10 @@ async function finalizeExecutedToolCall(currentContext, assistantMessage, prepar
|
|
|
22014
22073
|
}, signal);
|
|
22015
22074
|
if (afterResult) {
|
|
22016
22075
|
result = {
|
|
22076
|
+
...result,
|
|
22017
22077
|
content: afterResult.content ?? result.content,
|
|
22018
22078
|
details: afterResult.details ?? result.details,
|
|
22079
|
+
usage: afterResult.usage ?? result.usage,
|
|
22019
22080
|
terminate: afterResult.terminate ?? result.terminate
|
|
22020
22081
|
};
|
|
22021
22082
|
isError = afterResult.isError ?? isError;
|
|
@@ -22053,8 +22114,10 @@ function createToolResultMessage(finalized) {
|
|
|
22053
22114
|
role: "toolResult",
|
|
22054
22115
|
toolCallId: finalized.toolCall.id,
|
|
22055
22116
|
toolName: finalized.toolCall.name,
|
|
22056
|
-
content: finalized.result.content,
|
|
22117
|
+
content: finalized.result.content ?? [],
|
|
22057
22118
|
details: finalized.result.details,
|
|
22119
|
+
usage: finalized.result.usage,
|
|
22120
|
+
...finalized.result.addedToolNames?.length ? { addedToolNames: finalized.result.addedToolNames } : {},
|
|
22058
22121
|
isError: finalized.isError,
|
|
22059
22122
|
timestamp: Date.now()
|
|
22060
22123
|
};
|
|
@@ -22171,13 +22234,15 @@ var Agent$1 = class {
|
|
|
22171
22234
|
followUpQueue;
|
|
22172
22235
|
convertToLlm;
|
|
22173
22236
|
transformContext;
|
|
22174
|
-
|
|
22237
|
+
streamFunction;
|
|
22175
22238
|
getApiKey;
|
|
22176
22239
|
onPayload;
|
|
22177
22240
|
onResponse;
|
|
22178
22241
|
beforeToolCall;
|
|
22179
22242
|
afterToolCall;
|
|
22243
|
+
shouldStopAfterTurn;
|
|
22180
22244
|
prepareNextTurn;
|
|
22245
|
+
prepareNextTurnWithContext;
|
|
22181
22246
|
activeRun;
|
|
22182
22247
|
/** Session identifier forwarded to providers for cache-aware backends. */
|
|
22183
22248
|
sessionId;
|
|
@@ -22189,24 +22254,27 @@ var Agent$1 = class {
|
|
|
22189
22254
|
maxRetryDelayMs;
|
|
22190
22255
|
/** Tool execution strategy for assistant messages that contain multiple tool calls. */
|
|
22191
22256
|
toolExecution;
|
|
22192
|
-
constructor(options
|
|
22193
|
-
|
|
22194
|
-
this.
|
|
22195
|
-
this.
|
|
22196
|
-
this.
|
|
22197
|
-
this.
|
|
22198
|
-
this.
|
|
22199
|
-
this.
|
|
22200
|
-
this.
|
|
22201
|
-
this.
|
|
22202
|
-
this.
|
|
22203
|
-
this.
|
|
22204
|
-
this.
|
|
22205
|
-
this.
|
|
22206
|
-
this.
|
|
22207
|
-
this.
|
|
22208
|
-
this.
|
|
22209
|
-
this.
|
|
22257
|
+
constructor(options) {
|
|
22258
|
+
const runtimeOptions = options ?? {};
|
|
22259
|
+
this._state = createMutableAgentState(runtimeOptions.initialState);
|
|
22260
|
+
this.convertToLlm = runtimeOptions.convertToLlm ?? defaultConvertToLlm;
|
|
22261
|
+
this.transformContext = runtimeOptions.transformContext;
|
|
22262
|
+
this.streamFunction = runtimeOptions.streamFn ?? getDefaultStreamFn();
|
|
22263
|
+
this.getApiKey = runtimeOptions.getApiKey;
|
|
22264
|
+
this.onPayload = runtimeOptions.onPayload;
|
|
22265
|
+
this.onResponse = runtimeOptions.onResponse;
|
|
22266
|
+
this.beforeToolCall = runtimeOptions.beforeToolCall;
|
|
22267
|
+
this.afterToolCall = runtimeOptions.afterToolCall;
|
|
22268
|
+
this.shouldStopAfterTurn = runtimeOptions.shouldStopAfterTurn;
|
|
22269
|
+
this.prepareNextTurn = runtimeOptions.prepareNextTurn;
|
|
22270
|
+
this.prepareNextTurnWithContext = runtimeOptions.prepareNextTurnWithContext;
|
|
22271
|
+
this.steeringQueue = new PendingMessageQueue(runtimeOptions.steeringMode ?? "one-at-a-time");
|
|
22272
|
+
this.followUpQueue = new PendingMessageQueue(runtimeOptions.followUpMode ?? "one-at-a-time");
|
|
22273
|
+
this.sessionId = runtimeOptions.sessionId;
|
|
22274
|
+
this.thinkingBudgets = runtimeOptions.thinkingBudgets;
|
|
22275
|
+
this.transport = runtimeOptions.transport ?? "auto";
|
|
22276
|
+
this.maxRetryDelayMs = runtimeOptions.maxRetryDelayMs;
|
|
22277
|
+
this.toolExecution = runtimeOptions.toolExecution ?? "parallel";
|
|
22210
22278
|
}
|
|
22211
22279
|
/**
|
|
22212
22280
|
* Subscribe to agent lifecycle events.
|
|
@@ -22336,12 +22404,12 @@ var Agent$1 = class {
|
|
|
22336
22404
|
}
|
|
22337
22405
|
async runPromptMessages(messages, options = {}) {
|
|
22338
22406
|
await this.runWithLifecycle(async (signal) => {
|
|
22339
|
-
await runAgentLoop(messages, this.createContextSnapshot(), this.createLoopConfig(options), (event) => this.processEvents(event), signal, this.
|
|
22407
|
+
await runAgentLoop(messages, this.createContextSnapshot(), this.createLoopConfig(options), (event) => this.processEvents(event), signal, this.streamFunction);
|
|
22340
22408
|
});
|
|
22341
22409
|
}
|
|
22342
22410
|
async runContinuation() {
|
|
22343
22411
|
await this.runWithLifecycle(async (signal) => {
|
|
22344
|
-
await runAgentLoopContinue(this.createContextSnapshot(), this.createLoopConfig(), (event) => this.processEvents(event), signal, this.
|
|
22412
|
+
await runAgentLoopContinue(this.createContextSnapshot(), this.createLoopConfig(), (event) => this.processEvents(event), signal, this.streamFunction);
|
|
22345
22413
|
});
|
|
22346
22414
|
}
|
|
22347
22415
|
createContextSnapshot() {
|
|
@@ -22365,7 +22433,11 @@ var Agent$1 = class {
|
|
|
22365
22433
|
toolExecution: this.toolExecution,
|
|
22366
22434
|
beforeToolCall: this.beforeToolCall,
|
|
22367
22435
|
afterToolCall: this.afterToolCall,
|
|
22368
|
-
|
|
22436
|
+
shouldStopAfterTurn: this.shouldStopAfterTurn,
|
|
22437
|
+
prepareNextTurn: this.prepareNextTurnWithContext || this.prepareNextTurn ? async (context) => {
|
|
22438
|
+
if (this.prepareNextTurnWithContext) return await this.prepareNextTurnWithContext(context, this.signal);
|
|
22439
|
+
return await this.prepareNextTurn?.(this.signal);
|
|
22440
|
+
} : void 0,
|
|
22369
22441
|
convertToLlm: this.convertToLlm,
|
|
22370
22442
|
transformContext: this.transformContext,
|
|
22371
22443
|
getApiKey: this.getApiKey,
|
|
@@ -22490,28 +22562,49 @@ var Agent$1 = class {
|
|
|
22490
22562
|
const DEFAULT_MAX_BYTES = 50 * 1024;
|
|
22491
22563
|
const runtimeBuffer = globalThis.Buffer;
|
|
22492
22564
|
|
|
22565
|
+
//#endregion
|
|
22566
|
+
//#region src/vendor/pi/agent/harness/tools/bash.ts
|
|
22567
|
+
const MAX_TIMEOUT_SECONDS = 2147483647 / 1e3;
|
|
22568
|
+
const bashSchema = Type.Object({
|
|
22569
|
+
command: Type.String({ description: "Bash command to execute" }),
|
|
22570
|
+
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" }))
|
|
22571
|
+
});
|
|
22572
|
+
|
|
22573
|
+
//#endregion
|
|
22574
|
+
//#region src/vendor/pi/agent/harness/tools/edit.ts
|
|
22575
|
+
const replaceEditSchema = Type.Object({
|
|
22576
|
+
oldText: Type.String({ description: "Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call." }),
|
|
22577
|
+
newText: Type.String({ description: "Replacement text for this targeted edit." })
|
|
22578
|
+
}, {});
|
|
22579
|
+
const editSchema = Type.Object({
|
|
22580
|
+
path: Type.String({ description: "Path to the file to edit (relative or absolute)" }),
|
|
22581
|
+
edits: Type.Array(replaceEditSchema, { description: "One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead." })
|
|
22582
|
+
}, {});
|
|
22583
|
+
|
|
22584
|
+
//#endregion
|
|
22585
|
+
//#region src/vendor/pi/agent/harness/tools/read.ts
|
|
22586
|
+
const readSchema = Type.Object({
|
|
22587
|
+
path: Type.String({ description: "Path to the file to read (relative or absolute)" }),
|
|
22588
|
+
offset: Type.Optional(Type.Number({ description: "Line number to start reading from (1-indexed)" })),
|
|
22589
|
+
limit: Type.Optional(Type.Number({ description: "Maximum number of lines to read" }))
|
|
22590
|
+
});
|
|
22591
|
+
|
|
22592
|
+
//#endregion
|
|
22593
|
+
//#region src/vendor/pi/agent/harness/tools/write.ts
|
|
22594
|
+
const writeSchema = Type.Object({
|
|
22595
|
+
path: Type.String({ description: "Path to the file to write (relative or absolute)" }),
|
|
22596
|
+
content: Type.String({ description: "Content to write to the file" })
|
|
22597
|
+
});
|
|
22598
|
+
|
|
22493
22599
|
//#endregion
|
|
22494
22600
|
//#region src/lib/worker-agent/budget.ts
|
|
22495
22601
|
const DEFAULT_MAX_TURNS = 500;
|
|
22496
22602
|
const DEFAULT_MAX_WALLCLOCK_MS = 360 * 6e4;
|
|
22603
|
+
const DEFAULT_MODEL_CALL_TIMEOUT_MS = 15 * 6e4;
|
|
22497
22604
|
const DEFAULT_MAX_TOOL_BYTES = 16 * 1024 * 1024;
|
|
22498
22605
|
const DEFAULT_MAX_TOOL_CALLS = 250;
|
|
22499
22606
|
const DEFAULT_MAX_REPEATED_CALLS = 3;
|
|
22500
22607
|
/**
|
|
22501
|
-
* Thrown when the wall-clock budget is exceeded. Engine catches this
|
|
22502
|
-
* around `agent.prompt()` / `agent.continue()` and converts it to a
|
|
22503
|
-
* terse `[halted: wallclock]` reply. Carries no extra metadata — by
|
|
22504
|
-
* design (no advice).
|
|
22505
|
-
*/
|
|
22506
|
-
var WorkerAbort = class extends Error {
|
|
22507
|
-
reason;
|
|
22508
|
-
constructor(reason) {
|
|
22509
|
-
super(`[halted: ${reason}]`);
|
|
22510
|
-
this.reason = reason;
|
|
22511
|
-
this.name = "WorkerAbort";
|
|
22512
|
-
}
|
|
22513
|
-
};
|
|
22514
|
-
/**
|
|
22515
22608
|
* Read a positive-integer env override. Returns `undefined` if the
|
|
22516
22609
|
* env var is unset, empty, or doesn't parse to a positive integer —
|
|
22517
22610
|
* keeping the constructor defaults intact. We don't throw on bad input
|
|
@@ -22540,6 +22633,8 @@ const DEFAULT_MCP_TOOL_TIMEOUT_MS = 225e5;
|
|
|
22540
22633
|
* hard-killed by the harness.
|
|
22541
22634
|
*/
|
|
22542
22635
|
const MCP_TIMEOUT_HEADROOM_MS = 15 * 6e4;
|
|
22636
|
+
/** Smallest useful worker deadline when the MCP timeout is misconfigured below headroom. */
|
|
22637
|
+
const MIN_WORKER_WALLCLOCK_MS = 1e3;
|
|
22543
22638
|
/**
|
|
22544
22639
|
* The MCP per-tool-call timeout the proxy injects into the spawned CLI, in ms.
|
|
22545
22640
|
* Positive-integer override via `GH_ROUTER_MCP_TOOL_TIMEOUT_MS`; falls back to
|
|
@@ -22551,6 +22646,10 @@ const MCP_TIMEOUT_HEADROOM_MS = 15 * 6e4;
|
|
|
22551
22646
|
function resolveMcpToolTimeoutMs() {
|
|
22552
22647
|
return envInt("GH_ROUTER_MCP_TOOL_TIMEOUT_MS") ?? DEFAULT_MCP_TOOL_TIMEOUT_MS;
|
|
22553
22648
|
}
|
|
22649
|
+
/** Whole-call deadline for one worker model turn, including SSE consumption. */
|
|
22650
|
+
function resolveWorkerModelCallTimeoutMs() {
|
|
22651
|
+
return envInt("GH_ROUTER_WORKER_MODEL_CALL_TIMEOUT_MS") ?? DEFAULT_MODEL_CALL_TIMEOUT_MS;
|
|
22652
|
+
}
|
|
22554
22653
|
/**
|
|
22555
22654
|
* The maximum wall-clock a single worker call may be granted: the MCP
|
|
22556
22655
|
* tool-call timeout minus the teardown headroom. A per-call `maxWallClockMs`
|
|
@@ -22560,7 +22659,7 @@ function resolveMcpToolTimeoutMs() {
|
|
|
22560
22659
|
* the default MCP timeout (22_500_000 − 900_000 === 21_600_000).
|
|
22561
22660
|
*/
|
|
22562
22661
|
function workerWallClockCeilingMs() {
|
|
22563
|
-
return resolveMcpToolTimeoutMs() - MCP_TIMEOUT_HEADROOM_MS;
|
|
22662
|
+
return Math.max(MIN_WORKER_WALLCLOCK_MS, resolveMcpToolTimeoutMs() - MCP_TIMEOUT_HEADROOM_MS);
|
|
22564
22663
|
}
|
|
22565
22664
|
/**
|
|
22566
22665
|
* Resolve a `BudgetConfig` from defaults + env overrides + caller-
|
|
@@ -22570,13 +22669,14 @@ function workerWallClockCeilingMs() {
|
|
|
22570
22669
|
* can introspect the merged config without spinning up the `Budget`
|
|
22571
22670
|
* class.
|
|
22572
22671
|
*/
|
|
22573
|
-
function resolveBudgetConfig(overrides) {
|
|
22672
|
+
function resolveBudgetConfig(overrides$1) {
|
|
22673
|
+
const requestedWallClockMs = overrides$1?.maxWallClockMs ?? envInt("GH_ROUTER_WORKER_MAX_WALLCLOCK_MS") ?? DEFAULT_MAX_WALLCLOCK_MS;
|
|
22574
22674
|
return {
|
|
22575
|
-
maxTurns: overrides?.maxTurns ?? envInt("GH_ROUTER_WORKER_MAX_TURNS") ?? DEFAULT_MAX_TURNS,
|
|
22576
|
-
maxWallClockMs:
|
|
22577
|
-
maxToolBytes: overrides?.maxToolBytes ?? envInt("GH_ROUTER_WORKER_MAX_TOOL_BYTES") ?? DEFAULT_MAX_TOOL_BYTES,
|
|
22578
|
-
maxToolCalls: overrides?.maxToolCalls ?? envInt("GH_ROUTER_WORKER_MAX_TOOL_CALLS") ?? DEFAULT_MAX_TOOL_CALLS,
|
|
22579
|
-
maxRepeatedCalls: overrides?.maxRepeatedCalls ?? envInt("GH_ROUTER_WORKER_MAX_REPEATED_CALLS") ?? DEFAULT_MAX_REPEATED_CALLS
|
|
22675
|
+
maxTurns: overrides$1?.maxTurns ?? envInt("GH_ROUTER_WORKER_MAX_TURNS") ?? DEFAULT_MAX_TURNS,
|
|
22676
|
+
maxWallClockMs: Math.min(requestedWallClockMs, workerWallClockCeilingMs()),
|
|
22677
|
+
maxToolBytes: overrides$1?.maxToolBytes ?? envInt("GH_ROUTER_WORKER_MAX_TOOL_BYTES") ?? DEFAULT_MAX_TOOL_BYTES,
|
|
22678
|
+
maxToolCalls: overrides$1?.maxToolCalls ?? envInt("GH_ROUTER_WORKER_MAX_TOOL_CALLS") ?? DEFAULT_MAX_TOOL_CALLS,
|
|
22679
|
+
maxRepeatedCalls: overrides$1?.maxRepeatedCalls ?? envInt("GH_ROUTER_WORKER_MAX_REPEATED_CALLS") ?? DEFAULT_MAX_REPEATED_CALLS
|
|
22580
22680
|
};
|
|
22581
22681
|
}
|
|
22582
22682
|
/**
|
|
@@ -22588,11 +22688,10 @@ function resolveBudgetConfig(overrides) {
|
|
|
22588
22688
|
* - `checkBeforeCall(name, args)` is called from Pi's
|
|
22589
22689
|
* `beforeToolCall` hook. Returns `{block: true, reason: "[halted:
|
|
22590
22690
|
* turns]"}` etc. when a cap fires.
|
|
22591
|
-
* - `recordToolBytes(result)` is called from Pi's `afterToolCall`
|
|
22592
|
-
*
|
|
22593
|
-
*
|
|
22594
|
-
*
|
|
22595
|
-
* `Date.now() - startMs > maxWallClockMs`.
|
|
22691
|
+
* - `recordToolBytes(result)` is called from Pi's `afterToolCall` hook.
|
|
22692
|
+
* - A hard cap latches `hardStopReason`; the engine's
|
|
22693
|
+
* `shouldStopAfterTurn` hook reads it and ends the loop before another
|
|
22694
|
+
* provider request. The repeated-call guard remains a non-terminal block.
|
|
22596
22695
|
*/
|
|
22597
22696
|
var Budget = class {
|
|
22598
22697
|
config;
|
|
@@ -22600,10 +22699,11 @@ var Budget = class {
|
|
|
22600
22699
|
turnCount = 0;
|
|
22601
22700
|
toolBytes = 0;
|
|
22602
22701
|
toolCallCount = 0;
|
|
22702
|
+
hardStopReasonValue = null;
|
|
22603
22703
|
lastCallKey = null;
|
|
22604
22704
|
consecutiveRepeats = 0;
|
|
22605
|
-
constructor(overrides) {
|
|
22606
|
-
this.config = resolveBudgetConfig(overrides);
|
|
22705
|
+
constructor(overrides$1) {
|
|
22706
|
+
this.config = resolveBudgetConfig(overrides$1);
|
|
22607
22707
|
this.startMs = Date.now();
|
|
22608
22708
|
}
|
|
22609
22709
|
/** Record a turn. Does NOT throw — `checkBeforeCall` surfaces the cap. */
|
|
@@ -22622,16 +22722,16 @@ var Budget = class {
|
|
|
22622
22722
|
get elapsedMs() {
|
|
22623
22723
|
return Date.now() - this.startMs;
|
|
22624
22724
|
}
|
|
22625
|
-
/**
|
|
22626
|
-
|
|
22627
|
-
|
|
22628
|
-
|
|
22629
|
-
|
|
22630
|
-
|
|
22631
|
-
|
|
22632
|
-
|
|
22633
|
-
|
|
22634
|
-
|
|
22725
|
+
/** First hard cap reached during this run, or null while work may continue. */
|
|
22726
|
+
get hardStopReason() {
|
|
22727
|
+
return this.hardStopReasonValue;
|
|
22728
|
+
}
|
|
22729
|
+
halt(reason) {
|
|
22730
|
+
this.hardStopReasonValue ??= reason;
|
|
22731
|
+
return {
|
|
22732
|
+
block: true,
|
|
22733
|
+
reason: `[halted: ${reason}]`
|
|
22734
|
+
};
|
|
22635
22735
|
}
|
|
22636
22736
|
/**
|
|
22637
22737
|
* Pi `beforeToolCall` integration. Returns `{block: true, reason}`
|
|
@@ -22650,23 +22750,12 @@ var Budget = class {
|
|
|
22650
22750
|
* signature in Pi without forcing the engine into a wrapper.
|
|
22651
22751
|
*/
|
|
22652
22752
|
checkBeforeCall(toolName, args) {
|
|
22653
|
-
if (this.
|
|
22654
|
-
|
|
22655
|
-
|
|
22656
|
-
|
|
22657
|
-
if (this.elapsedMs > this.config.maxWallClockMs) return {
|
|
22658
|
-
block: true,
|
|
22659
|
-
reason: "[halted: wallclock]"
|
|
22660
|
-
};
|
|
22661
|
-
if (this.toolBytes > this.config.maxToolBytes) return {
|
|
22662
|
-
block: true,
|
|
22663
|
-
reason: "[halted: tool-bytes]"
|
|
22664
|
-
};
|
|
22753
|
+
if (this.hardStopReasonValue) return this.halt(this.hardStopReasonValue);
|
|
22754
|
+
if (this.turnCount > this.config.maxTurns) return this.halt("turns");
|
|
22755
|
+
if (this.elapsedMs > this.config.maxWallClockMs) return this.halt("wallclock");
|
|
22756
|
+
if (this.toolBytes > this.config.maxToolBytes) return this.halt("tool-bytes");
|
|
22665
22757
|
this.toolCallCount += 1;
|
|
22666
|
-
if (this.toolCallCount > this.config.maxToolCalls) return
|
|
22667
|
-
block: true,
|
|
22668
|
-
reason: "[halted: tool-calls]"
|
|
22669
|
-
};
|
|
22758
|
+
if (this.toolCallCount > this.config.maxToolCalls) return this.halt("tool-calls");
|
|
22670
22759
|
const key = `${toolName}:${stableArgs(args)}`;
|
|
22671
22760
|
if (key === this.lastCallKey) this.consecutiveRepeats += 1;
|
|
22672
22761
|
else {
|
|
@@ -22735,14 +22824,15 @@ function extractTextByteLength(result) {
|
|
|
22735
22824
|
* the clamp logic. Lower index = less thinking. `"off"` is below
|
|
22736
22825
|
* everything; `"xhigh"` is the cap.
|
|
22737
22826
|
*/
|
|
22738
|
-
const
|
|
22827
|
+
const WORKER_THINKING_LEVELS = Object.freeze([
|
|
22739
22828
|
"off",
|
|
22740
22829
|
"minimal",
|
|
22741
22830
|
"low",
|
|
22742
22831
|
"medium",
|
|
22743
22832
|
"high",
|
|
22744
22833
|
"xhigh"
|
|
22745
|
-
];
|
|
22834
|
+
]);
|
|
22835
|
+
const THINKING_ORDER = WORKER_THINKING_LEVELS;
|
|
22746
22836
|
function tier(level) {
|
|
22747
22837
|
const i = THINKING_ORDER.indexOf(level);
|
|
22748
22838
|
return i < 0 ? THINKING_ORDER.indexOf("high") : i;
|
|
@@ -22784,13 +22874,7 @@ function resolveModelAndThinking(opts) {
|
|
|
22784
22874
|
});
|
|
22785
22875
|
const allowedRaw = found.capabilities?.supports?.reasoning_effort;
|
|
22786
22876
|
if (!allowedRaw || allowedRaw.length === 0) return mkOk("off");
|
|
22787
|
-
const allowed = allowedRaw.filter((l) =>
|
|
22788
|
-
"minimal",
|
|
22789
|
-
"low",
|
|
22790
|
-
"medium",
|
|
22791
|
-
"high",
|
|
22792
|
-
"xhigh"
|
|
22793
|
-
].includes(l)).sort((a, b) => tier(a) - tier(b));
|
|
22877
|
+
const allowed = allowedRaw.filter((l) => WORKER_THINKING_LEVELS.includes(l) && l !== "off").sort((a, b) => tier(a) - tier(b));
|
|
22794
22878
|
if (allowed.length === 0) return mkOk("off");
|
|
22795
22879
|
if (opts.thinking === "off") return mkOk("off");
|
|
22796
22880
|
if (allowed.includes(opts.thinking)) return mkOk(opts.thinking);
|
|
@@ -22804,6 +22888,40 @@ function resolveModelAndThinking(opts) {
|
|
|
22804
22888
|
return mkOk(clamp$1);
|
|
22805
22889
|
}
|
|
22806
22890
|
|
|
22891
|
+
//#endregion
|
|
22892
|
+
//#region src/lib/worker-agent/session-defaults.ts
|
|
22893
|
+
const MODES = Object.freeze([
|
|
22894
|
+
"explore",
|
|
22895
|
+
"review",
|
|
22896
|
+
"plan",
|
|
22897
|
+
"implement",
|
|
22898
|
+
"test",
|
|
22899
|
+
"browse"
|
|
22900
|
+
]);
|
|
22901
|
+
/**
|
|
22902
|
+
* Process-global, in-memory overrides. They are intentionally not persisted.
|
|
22903
|
+
* In `serve` mode one process may serve multiple client sessions, so these
|
|
22904
|
+
* values are process-wide rather than isolated to an individual client.
|
|
22905
|
+
*/
|
|
22906
|
+
const overrides = {};
|
|
22907
|
+
function getWorkerSessionDefault(mode) {
|
|
22908
|
+
return { ...overrides[mode] };
|
|
22909
|
+
}
|
|
22910
|
+
function setWorkerSessionDefault(mode, value) {
|
|
22911
|
+
const next = { ...overrides[mode] };
|
|
22912
|
+
if (value.model !== void 0) next.model = value.model;
|
|
22913
|
+
if (value.thinking !== void 0) next.thinking = value.thinking;
|
|
22914
|
+
overrides[mode] = next;
|
|
22915
|
+
return { ...next };
|
|
22916
|
+
}
|
|
22917
|
+
function resetWorkerSessionDefault(mode) {
|
|
22918
|
+
delete overrides[mode];
|
|
22919
|
+
}
|
|
22920
|
+
function resetAllWorkerSessionDefaults() {
|
|
22921
|
+
for (const mode of MODES) delete overrides[mode];
|
|
22922
|
+
}
|
|
22923
|
+
const WORKER_MODES = MODES;
|
|
22924
|
+
|
|
22807
22925
|
//#endregion
|
|
22808
22926
|
//#region src/lib/worker-agent/prompts.ts
|
|
22809
22927
|
/**
|
|
@@ -22855,7 +22973,7 @@ const READ_TOOL_NOTES = [
|
|
|
22855
22973
|
const WRITE_TOOL_NOTES = [
|
|
22856
22974
|
"`edit` — exact-string replacement in a file.",
|
|
22857
22975
|
"`write` — overwrite or create a file.",
|
|
22858
|
-
"`bash` — run a
|
|
22976
|
+
"`bash` — run builds, tests, git, package managers, and programs; reading, searching, and editing have dedicated tools (`read`/`glob`/`grep`/`code_search`/`edit`/`write`/`toolbelt`), so a `python`/`node`/`powershell` one-off script for those jobs is unnecessary.",
|
|
22859
22977
|
"`codex_review` — code review by `codex-reviewer` (gpt-5.3-codex, code-specialist critic). Returns line-level findings on a diff or single file."
|
|
22860
22978
|
];
|
|
22861
22979
|
function buildToolBlock(tools) {
|
|
@@ -23220,6 +23338,13 @@ function assembleResponsesPayload(opts) {
|
|
|
23220
23338
|
*/
|
|
23221
23339
|
/** Conservative bytes/token for dense DOM-JSON; over-counts tokens by design. */
|
|
23222
23340
|
const BYTES_PER_TOKEN = 3;
|
|
23341
|
+
/**
|
|
23342
|
+
* Conservative context floor when the live catalog omits or reports an invalid window.
|
|
23343
|
+
* This is deliberately not a hardcoded per-model window table: duplicating the
|
|
23344
|
+
* live catalog would go stale on every model launch and violate the rule to
|
|
23345
|
+
* gate on catalog capabilities rather than model slugs.
|
|
23346
|
+
*/
|
|
23347
|
+
const FALLBACK_WINDOW_TOKENS = 128e3;
|
|
23223
23348
|
const OUTPUT_RESERVE_TOKENS = 12e3;
|
|
23224
23349
|
const TOOL_SCHEMA_RESERVE_TOKENS = 6e3;
|
|
23225
23350
|
const SYSTEM_RESERVE_TOKENS = 2e3;
|
|
@@ -23253,17 +23378,19 @@ function tokensFromBytes(bytes) {
|
|
|
23253
23378
|
/**
|
|
23254
23379
|
* Build a per-run budget from the model's catalog context window (tokens).
|
|
23255
23380
|
*
|
|
23256
|
-
*
|
|
23257
|
-
*
|
|
23258
|
-
*
|
|
23259
|
-
*
|
|
23381
|
+
* Unknown, non-finite, and non-positive windows use the conservative fallback
|
|
23382
|
+
* floor so compaction and the dynamic result cap remain engaged. The returned
|
|
23383
|
+
* `windowKnown` flag keeps the request backstop advisory in that case: upstream
|
|
23384
|
+
* remains authoritative when the model's real window is unknown.
|
|
23260
23385
|
*/
|
|
23261
23386
|
function makeContextBudget(windowTokens) {
|
|
23262
|
-
|
|
23263
|
-
const
|
|
23387
|
+
const windowKnown = windowTokens !== void 0 && Number.isFinite(windowTokens) && windowTokens > 0;
|
|
23388
|
+
const effectiveWindowTokens = windowKnown ? windowTokens : FALLBACK_WINDOW_TOKENS;
|
|
23389
|
+
const inputHardLimitTokens = Math.max(0, Math.floor(effectiveWindowTokens * (1 - ASSEMBLY_MARGIN_FRACTION)) - OUTPUT_RESERVE_TOKENS);
|
|
23264
23390
|
const promptBudgetTokens = Math.max(0, inputHardLimitTokens - TOOL_SCHEMA_RESERVE_TOKENS - SYSTEM_RESERVE_TOKENS);
|
|
23265
23391
|
return {
|
|
23266
|
-
|
|
23392
|
+
windowKnown,
|
|
23393
|
+
windowTokens: effectiveWindowTokens,
|
|
23267
23394
|
inputHardLimitTokens,
|
|
23268
23395
|
promptBudgetTokens,
|
|
23269
23396
|
compactTriggerTokens: Math.floor(promptBudgetTokens * COMPACT_TRIGGER_FRACTION),
|
|
@@ -23271,7 +23398,7 @@ function makeContextBudget(windowTokens) {
|
|
|
23271
23398
|
hardLimitTokens: Math.floor(promptBudgetTokens * HARD_LIMIT_FRACTION),
|
|
23272
23399
|
keepRecentTokens: Math.max(KEEP_RECENT_FLOOR_TOKENS, Math.floor(promptBudgetTokens * KEEP_RECENT_FRACTION)),
|
|
23273
23400
|
maxProtectedTokens: Math.max(Math.max(KEEP_RECENT_FLOOR_TOKENS, Math.floor(promptBudgetTokens * KEEP_RECENT_FRACTION)), Math.floor(promptBudgetTokens * MAX_PROTECTED_FRACTION)),
|
|
23274
|
-
perResultCapBytes: clamp(Math.round(
|
|
23401
|
+
perResultCapBytes: clamp(Math.round(effectiveWindowTokens * PER_RESULT_CAP_FRACTION * BYTES_PER_TOKEN), PER_RESULT_CAP_MIN_BYTES, PER_RESULT_CAP_MAX_BYTES)
|
|
23275
23402
|
};
|
|
23276
23403
|
}
|
|
23277
23404
|
|
|
@@ -23294,11 +23421,52 @@ function createCopilotStreamFn(opts) {
|
|
|
23294
23421
|
return stream;
|
|
23295
23422
|
};
|
|
23296
23423
|
}
|
|
23424
|
+
async function runModelCallAttempts(stream, resolved, options, timeoutMs, runAttempt) {
|
|
23425
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
23426
|
+
const deadline = new AbortController();
|
|
23427
|
+
let localDeadlineFired = false;
|
|
23428
|
+
let rejectDeadline = () => {};
|
|
23429
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
23430
|
+
rejectDeadline = reject;
|
|
23431
|
+
});
|
|
23432
|
+
timeoutPromise.catch(() => {});
|
|
23433
|
+
const timer = setTimeout(() => {
|
|
23434
|
+
localDeadlineFired = true;
|
|
23435
|
+
const error = new DOMException("Worker model call timed out", "TimeoutError");
|
|
23436
|
+
deadline.abort(error);
|
|
23437
|
+
rejectDeadline(error);
|
|
23438
|
+
}, timeoutMs);
|
|
23439
|
+
const signal = options?.signal ? AbortSignal.any([options.signal, deadline.signal]) : deadline.signal;
|
|
23440
|
+
const state$1 = {
|
|
23441
|
+
emitted: false,
|
|
23442
|
+
active: true
|
|
23443
|
+
};
|
|
23444
|
+
const attemptPromise = runAttempt(signal, state$1);
|
|
23445
|
+
attemptPromise.catch(() => {});
|
|
23446
|
+
try {
|
|
23447
|
+
await Promise.race([attemptPromise, timeoutPromise]);
|
|
23448
|
+
return;
|
|
23449
|
+
} catch (err) {
|
|
23450
|
+
if (options?.signal?.aborted) {
|
|
23451
|
+
pushTerminalError(stream, resolved, options.signal.reason ?? err);
|
|
23452
|
+
return;
|
|
23453
|
+
}
|
|
23454
|
+
if (!state$1.emitted && attempt === 0) continue;
|
|
23455
|
+
if (localDeadlineFired) pushModelCallTimeoutDiagnostic(stream, resolved, timeoutMs, state$1.emitted);
|
|
23456
|
+
else pushTerminalError(stream, resolved, err);
|
|
23457
|
+
return;
|
|
23458
|
+
} finally {
|
|
23459
|
+
state$1.active = false;
|
|
23460
|
+
clearTimeout(timer);
|
|
23461
|
+
}
|
|
23462
|
+
}
|
|
23463
|
+
}
|
|
23297
23464
|
async function runStreamLoop(stream, context, opts, options) {
|
|
23298
23465
|
const { resolved } = opts;
|
|
23299
23466
|
if (opts.contextBudget) {
|
|
23300
23467
|
const assembledTokens = tokensFromBytes(estimateContextBytes(context));
|
|
23301
|
-
if (assembledTokens > opts.contextBudget.inputHardLimitTokens) {
|
|
23468
|
+
if (assembledTokens > opts.contextBudget.inputHardLimitTokens) if (!opts.contextBudget.windowKnown) consola.warn(`[worker] assembled request estimate ${assembledTokens} tokens exceeds fallback input limit ${opts.contextBudget.inputHardLimitTokens}; proceeding because the catalog window is unknown`);
|
|
23469
|
+
else {
|
|
23302
23470
|
pushBackstopDiagnostic(stream, resolved, assembledTokens, opts.contextBudget.inputHardLimitTokens);
|
|
23303
23471
|
return;
|
|
23304
23472
|
}
|
|
@@ -23314,15 +23482,13 @@ async function runStreamLoop(stream, context, opts, options) {
|
|
|
23314
23482
|
pushTerminalError(stream, resolved, err);
|
|
23315
23483
|
return;
|
|
23316
23484
|
}
|
|
23317
|
-
|
|
23318
|
-
|
|
23319
|
-
|
|
23320
|
-
|
|
23321
|
-
|
|
23322
|
-
|
|
23323
|
-
|
|
23324
|
-
return;
|
|
23325
|
-
}
|
|
23485
|
+
await runModelCallAttempts(stream, resolved, options, opts.modelCallTimeoutMs ?? 15 * 6e4, (signal, state$1) => runChatAttempt(stream, payload, opts, signal, state$1));
|
|
23486
|
+
}
|
|
23487
|
+
async function runChatAttempt(stream, payload, opts, signal, state$1) {
|
|
23488
|
+
const { resolved } = opts;
|
|
23489
|
+
const result = await createChatCompletions(payload, void 0, signal, false);
|
|
23490
|
+
if (result == null || typeof result[Symbol.asyncIterator] !== "function") throw new Error("Upstream did not return an SSE stream (stream: true expected)");
|
|
23491
|
+
const sseStream = result;
|
|
23326
23492
|
const accum = {
|
|
23327
23493
|
blocks: [],
|
|
23328
23494
|
textChunksByIndex: /* @__PURE__ */ new Map(),
|
|
@@ -23331,100 +23497,102 @@ async function runStreamLoop(stream, context, opts, options) {
|
|
|
23331
23497
|
let nextContentIndex = 0;
|
|
23332
23498
|
let activeTextIndex = null;
|
|
23333
23499
|
const toolPiIndexByOAI = /* @__PURE__ */ new Map();
|
|
23334
|
-
|
|
23335
|
-
|
|
23336
|
-
|
|
23337
|
-
|
|
23338
|
-
|
|
23339
|
-
|
|
23340
|
-
|
|
23341
|
-
|
|
23342
|
-
|
|
23343
|
-
|
|
23500
|
+
for await (const evt of sseStream) {
|
|
23501
|
+
const data = evt?.data;
|
|
23502
|
+
if (data == null) continue;
|
|
23503
|
+
if (data === "[DONE]") break;
|
|
23504
|
+
let chunk;
|
|
23505
|
+
try {
|
|
23506
|
+
chunk = JSON.parse(data);
|
|
23507
|
+
} catch {
|
|
23508
|
+
continue;
|
|
23509
|
+
}
|
|
23510
|
+
try {
|
|
23511
|
+
opts.onChunk?.(chunk);
|
|
23512
|
+
} catch {}
|
|
23513
|
+
if (chunk.usage) accum.usage = chunk.usage;
|
|
23514
|
+
const choice = chunk.choices?.[0];
|
|
23515
|
+
if (!choice) continue;
|
|
23516
|
+
const delta = choice.delta ?? {};
|
|
23517
|
+
if (typeof delta.content === "string" && delta.content.length > 0) {
|
|
23518
|
+
if (activeTextIndex == null) {
|
|
23519
|
+
state$1.emitted = true;
|
|
23520
|
+
activeTextIndex = nextContentIndex++;
|
|
23521
|
+
accum.blocks.push({
|
|
23522
|
+
kind: "text",
|
|
23523
|
+
contentIndex: activeTextIndex
|
|
23524
|
+
});
|
|
23525
|
+
accum.textChunksByIndex.set(activeTextIndex, []);
|
|
23526
|
+
if (!state$1.active) return;
|
|
23527
|
+
stream.push({
|
|
23528
|
+
type: "text_start",
|
|
23529
|
+
contentIndex: activeTextIndex,
|
|
23530
|
+
partial: buildPartial(resolved, accum)
|
|
23531
|
+
});
|
|
23344
23532
|
}
|
|
23345
|
-
|
|
23346
|
-
|
|
23347
|
-
|
|
23348
|
-
|
|
23349
|
-
|
|
23350
|
-
|
|
23351
|
-
|
|
23352
|
-
|
|
23353
|
-
|
|
23354
|
-
|
|
23355
|
-
|
|
23356
|
-
kind: "text",
|
|
23357
|
-
contentIndex: activeTextIndex
|
|
23358
|
-
});
|
|
23359
|
-
accum.textChunksByIndex.set(activeTextIndex, []);
|
|
23360
|
-
stream.push({
|
|
23361
|
-
type: "text_start",
|
|
23362
|
-
contentIndex: activeTextIndex,
|
|
23363
|
-
partial: buildPartial(resolved, accum)
|
|
23364
|
-
});
|
|
23365
|
-
}
|
|
23366
|
-
accum.textChunksByIndex.get(activeTextIndex).push(delta.content);
|
|
23533
|
+
accum.textChunksByIndex.get(activeTextIndex).push(delta.content);
|
|
23534
|
+
stream.push({
|
|
23535
|
+
type: "text_delta",
|
|
23536
|
+
contentIndex: activeTextIndex,
|
|
23537
|
+
delta: delta.content,
|
|
23538
|
+
partial: buildPartial(resolved, accum)
|
|
23539
|
+
});
|
|
23540
|
+
}
|
|
23541
|
+
if (Array.isArray(delta.tool_calls) && delta.tool_calls.length > 0) {
|
|
23542
|
+
if (activeTextIndex != null) {
|
|
23543
|
+
if (!state$1.active) return;
|
|
23367
23544
|
stream.push({
|
|
23368
|
-
type: "
|
|
23545
|
+
type: "text_end",
|
|
23369
23546
|
contentIndex: activeTextIndex,
|
|
23370
|
-
|
|
23547
|
+
content: joinTextChunks(accum, activeTextIndex),
|
|
23371
23548
|
partial: buildPartial(resolved, accum)
|
|
23372
23549
|
});
|
|
23550
|
+
activeTextIndex = null;
|
|
23373
23551
|
}
|
|
23374
|
-
|
|
23375
|
-
if (
|
|
23552
|
+
for (const tcd of delta.tool_calls) {
|
|
23553
|
+
if (tcd == null || tcd.index == null) continue;
|
|
23554
|
+
let piIdx = toolPiIndexByOAI.get(tcd.index);
|
|
23555
|
+
if (piIdx == null) {
|
|
23556
|
+
state$1.emitted = true;
|
|
23557
|
+
piIdx = nextContentIndex++;
|
|
23558
|
+
toolPiIndexByOAI.set(tcd.index, piIdx);
|
|
23559
|
+
accum.blocks.push({
|
|
23560
|
+
kind: "tool",
|
|
23561
|
+
contentIndex: piIdx,
|
|
23562
|
+
openaiIndex: tcd.index
|
|
23563
|
+
});
|
|
23564
|
+
accum.toolByIndex.set(piIdx, {
|
|
23565
|
+
id: "",
|
|
23566
|
+
name: "",
|
|
23567
|
+
argumentChunks: []
|
|
23568
|
+
});
|
|
23569
|
+
if (!state$1.active) return;
|
|
23376
23570
|
stream.push({
|
|
23377
|
-
type: "
|
|
23378
|
-
contentIndex:
|
|
23379
|
-
content: joinTextChunks(accum, activeTextIndex),
|
|
23571
|
+
type: "toolcall_start",
|
|
23572
|
+
contentIndex: piIdx,
|
|
23380
23573
|
partial: buildPartial(resolved, accum)
|
|
23381
23574
|
});
|
|
23382
|
-
activeTextIndex = null;
|
|
23383
23575
|
}
|
|
23384
|
-
|
|
23385
|
-
|
|
23386
|
-
|
|
23387
|
-
|
|
23388
|
-
|
|
23389
|
-
|
|
23390
|
-
|
|
23391
|
-
|
|
23392
|
-
|
|
23393
|
-
|
|
23394
|
-
|
|
23395
|
-
|
|
23396
|
-
|
|
23397
|
-
|
|
23398
|
-
argumentChunks: []
|
|
23399
|
-
});
|
|
23400
|
-
stream.push({
|
|
23401
|
-
type: "toolcall_start",
|
|
23402
|
-
contentIndex: piIdx,
|
|
23403
|
-
partial: buildPartial(resolved, accum)
|
|
23404
|
-
});
|
|
23405
|
-
}
|
|
23406
|
-
const entry = accum.toolByIndex.get(piIdx);
|
|
23407
|
-
if (!entry) continue;
|
|
23408
|
-
if (tcd.id) entry.id = tcd.id;
|
|
23409
|
-
if (tcd.function?.name) entry.name = tcd.function.name;
|
|
23410
|
-
const argDelta = tcd.function?.arguments;
|
|
23411
|
-
if (typeof argDelta === "string" && argDelta.length > 0) {
|
|
23412
|
-
entry.argumentChunks.push(argDelta);
|
|
23413
|
-
stream.push({
|
|
23414
|
-
type: "toolcall_delta",
|
|
23415
|
-
contentIndex: piIdx,
|
|
23416
|
-
delta: argDelta,
|
|
23417
|
-
partial: buildPartial(resolved, accum)
|
|
23418
|
-
});
|
|
23419
|
-
}
|
|
23576
|
+
const entry = accum.toolByIndex.get(piIdx);
|
|
23577
|
+
if (!entry) continue;
|
|
23578
|
+
if (tcd.id) entry.id = tcd.id;
|
|
23579
|
+
if (tcd.function?.name) entry.name = tcd.function.name;
|
|
23580
|
+
const argDelta = tcd.function?.arguments;
|
|
23581
|
+
if (typeof argDelta === "string" && argDelta.length > 0) {
|
|
23582
|
+
entry.argumentChunks.push(argDelta);
|
|
23583
|
+
if (!state$1.active) return;
|
|
23584
|
+
stream.push({
|
|
23585
|
+
type: "toolcall_delta",
|
|
23586
|
+
contentIndex: piIdx,
|
|
23587
|
+
delta: argDelta,
|
|
23588
|
+
partial: buildPartial(resolved, accum)
|
|
23589
|
+
});
|
|
23420
23590
|
}
|
|
23421
23591
|
}
|
|
23422
|
-
if (choice.finish_reason) accum.finishReason = choice.finish_reason;
|
|
23423
23592
|
}
|
|
23424
|
-
|
|
23425
|
-
pushTerminalError(stream, resolved, err);
|
|
23426
|
-
return;
|
|
23593
|
+
if (choice.finish_reason) accum.finishReason = choice.finish_reason;
|
|
23427
23594
|
}
|
|
23595
|
+
if (!state$1.active) return;
|
|
23428
23596
|
if (activeTextIndex != null) {
|
|
23429
23597
|
stream.push({
|
|
23430
23598
|
type: "text_end",
|
|
@@ -23587,15 +23755,13 @@ async function runResponsesStreamLoop(stream, context, opts, options) {
|
|
|
23587
23755
|
pushTerminalError(stream, resolved, err);
|
|
23588
23756
|
return;
|
|
23589
23757
|
}
|
|
23590
|
-
|
|
23591
|
-
|
|
23592
|
-
|
|
23593
|
-
|
|
23594
|
-
|
|
23595
|
-
|
|
23596
|
-
|
|
23597
|
-
return;
|
|
23598
|
-
}
|
|
23758
|
+
await runModelCallAttempts(stream, resolved, options, opts.modelCallTimeoutMs ?? 15 * 6e4, (signal, state$1) => runResponsesAttempt(stream, payload, opts, signal, state$1));
|
|
23759
|
+
}
|
|
23760
|
+
async function runResponsesAttempt(stream, payload, opts, signal, state$1) {
|
|
23761
|
+
const { resolved } = opts;
|
|
23762
|
+
const result = await createResponses(payload, void 0, signal, false);
|
|
23763
|
+
if (result == null || typeof result[Symbol.asyncIterator] !== "function") throw new Error("Upstream did not return an SSE stream (stream: true expected)");
|
|
23764
|
+
const sseStream = result;
|
|
23599
23765
|
const accum = {
|
|
23600
23766
|
blocks: [],
|
|
23601
23767
|
textChunksByIndex: /* @__PURE__ */ new Map(),
|
|
@@ -23615,166 +23781,173 @@ async function runResponsesStreamLoop(stream, context, opts, options) {
|
|
|
23615
23781
|
});
|
|
23616
23782
|
activeTextIndex = null;
|
|
23617
23783
|
};
|
|
23618
|
-
|
|
23619
|
-
|
|
23620
|
-
|
|
23621
|
-
|
|
23622
|
-
|
|
23623
|
-
|
|
23624
|
-
|
|
23625
|
-
|
|
23626
|
-
|
|
23627
|
-
|
|
23628
|
-
|
|
23629
|
-
|
|
23630
|
-
|
|
23631
|
-
|
|
23632
|
-
|
|
23633
|
-
|
|
23634
|
-
|
|
23635
|
-
|
|
23636
|
-
|
|
23637
|
-
|
|
23638
|
-
|
|
23639
|
-
|
|
23640
|
-
|
|
23641
|
-
type: "text_start",
|
|
23642
|
-
contentIndex: activeTextIndex,
|
|
23643
|
-
partial: buildPartial(resolved, accum)
|
|
23644
|
-
});
|
|
23645
|
-
}
|
|
23646
|
-
accum.textChunksByIndex.get(activeTextIndex).push(delta);
|
|
23784
|
+
for await (const evt of sseStream) {
|
|
23785
|
+
const data = evt?.data;
|
|
23786
|
+
if (data == null) continue;
|
|
23787
|
+
if (data === "[DONE]") break;
|
|
23788
|
+
let ev;
|
|
23789
|
+
try {
|
|
23790
|
+
ev = JSON.parse(data);
|
|
23791
|
+
} catch {
|
|
23792
|
+
continue;
|
|
23793
|
+
}
|
|
23794
|
+
switch (ev.type) {
|
|
23795
|
+
case "response.output_text.delta": {
|
|
23796
|
+
const delta = ev.delta;
|
|
23797
|
+
if (typeof delta !== "string" || delta.length === 0) break;
|
|
23798
|
+
if (activeTextIndex == null) {
|
|
23799
|
+
state$1.emitted = true;
|
|
23800
|
+
activeTextIndex = nextContentIndex++;
|
|
23801
|
+
accum.blocks.push({
|
|
23802
|
+
kind: "text",
|
|
23803
|
+
contentIndex: activeTextIndex
|
|
23804
|
+
});
|
|
23805
|
+
accum.textChunksByIndex.set(activeTextIndex, []);
|
|
23806
|
+
if (!state$1.active) return;
|
|
23647
23807
|
stream.push({
|
|
23648
|
-
type: "
|
|
23808
|
+
type: "text_start",
|
|
23649
23809
|
contentIndex: activeTextIndex,
|
|
23650
|
-
delta,
|
|
23651
23810
|
partial: buildPartial(resolved, accum)
|
|
23652
23811
|
});
|
|
23653
|
-
break;
|
|
23654
23812
|
}
|
|
23655
|
-
|
|
23656
|
-
|
|
23657
|
-
|
|
23658
|
-
|
|
23659
|
-
|
|
23660
|
-
|
|
23661
|
-
|
|
23662
|
-
|
|
23663
|
-
|
|
23664
|
-
|
|
23665
|
-
|
|
23666
|
-
|
|
23667
|
-
|
|
23668
|
-
|
|
23669
|
-
stream.push({
|
|
23670
|
-
type: "text_delta",
|
|
23671
|
-
contentIndex: activeTextIndex,
|
|
23672
|
-
delta: ev.text,
|
|
23673
|
-
partial: buildPartial(resolved, accum)
|
|
23674
|
-
});
|
|
23675
|
-
}
|
|
23676
|
-
closeActiveText();
|
|
23677
|
-
break;
|
|
23678
|
-
case "response.output_item.added": {
|
|
23679
|
-
const item = ev.item;
|
|
23680
|
-
if (item?.type !== "function_call") break;
|
|
23681
|
-
const key = responsesToolKey(ev.output_index, item.id);
|
|
23682
|
-
if (key == null) break;
|
|
23683
|
-
if (toolPiIndexByKey.has(key)) break;
|
|
23684
|
-
closeActiveText();
|
|
23685
|
-
const piIdx = nextContentIndex++;
|
|
23686
|
-
toolPiIndexByKey.set(key, piIdx);
|
|
23813
|
+
accum.textChunksByIndex.get(activeTextIndex).push(delta);
|
|
23814
|
+
if (!state$1.active) return;
|
|
23815
|
+
stream.push({
|
|
23816
|
+
type: "text_delta",
|
|
23817
|
+
contentIndex: activeTextIndex,
|
|
23818
|
+
delta,
|
|
23819
|
+
partial: buildPartial(resolved, accum)
|
|
23820
|
+
});
|
|
23821
|
+
break;
|
|
23822
|
+
}
|
|
23823
|
+
case "response.output_text.done":
|
|
23824
|
+
if (activeTextIndex == null && typeof ev.text === "string" && ev.text.length > 0) {
|
|
23825
|
+
state$1.emitted = true;
|
|
23826
|
+
activeTextIndex = nextContentIndex++;
|
|
23687
23827
|
accum.blocks.push({
|
|
23688
|
-
kind: "
|
|
23689
|
-
contentIndex:
|
|
23690
|
-
openaiIndex: piIdx
|
|
23691
|
-
});
|
|
23692
|
-
accum.toolByIndex.set(piIdx, {
|
|
23693
|
-
id: item.call_id ?? item.id ?? key,
|
|
23694
|
-
name: item.name ?? "",
|
|
23695
|
-
argumentChunks: []
|
|
23696
|
-
});
|
|
23697
|
-
stream.push({
|
|
23698
|
-
type: "toolcall_start",
|
|
23699
|
-
contentIndex: piIdx,
|
|
23700
|
-
partial: buildPartial(resolved, accum)
|
|
23828
|
+
kind: "text",
|
|
23829
|
+
contentIndex: activeTextIndex
|
|
23701
23830
|
});
|
|
23702
|
-
|
|
23703
|
-
|
|
23704
|
-
case "response.function_call_arguments.delta": {
|
|
23705
|
-
const key = responsesToolKey(ev.output_index, ev.item_id);
|
|
23706
|
-
if (key == null) break;
|
|
23707
|
-
const piIdx = toolPiIndexByKey.get(key);
|
|
23708
|
-
if (piIdx == null) break;
|
|
23709
|
-
const entry = accum.toolByIndex.get(piIdx);
|
|
23710
|
-
if (!entry) break;
|
|
23711
|
-
const delta = ev.delta;
|
|
23712
|
-
if (typeof delta !== "string" || delta.length === 0) break;
|
|
23713
|
-
entry.argumentChunks.push(delta);
|
|
23831
|
+
accum.textChunksByIndex.set(activeTextIndex, []);
|
|
23832
|
+
if (!state$1.active) return;
|
|
23714
23833
|
stream.push({
|
|
23715
|
-
type: "
|
|
23716
|
-
contentIndex:
|
|
23717
|
-
delta,
|
|
23834
|
+
type: "text_start",
|
|
23835
|
+
contentIndex: activeTextIndex,
|
|
23718
23836
|
partial: buildPartial(resolved, accum)
|
|
23719
23837
|
});
|
|
23720
|
-
|
|
23721
|
-
|
|
23722
|
-
case "response.function_call_arguments.done": {
|
|
23723
|
-
const key = responsesToolKey(ev.output_index, ev.item_id);
|
|
23724
|
-
if (key == null) break;
|
|
23725
|
-
const piIdx = toolPiIndexByKey.get(key);
|
|
23726
|
-
if (piIdx == null) break;
|
|
23727
|
-
const entry = accum.toolByIndex.get(piIdx);
|
|
23728
|
-
if (entry && typeof ev.arguments === "string") entry.argumentChunks = [ev.arguments];
|
|
23729
|
-
break;
|
|
23730
|
-
}
|
|
23731
|
-
case "response.output_item.done": {
|
|
23732
|
-
const item = ev.item;
|
|
23733
|
-
if (item?.type !== "function_call") break;
|
|
23734
|
-
const key = responsesToolKey(ev.output_index, item.id);
|
|
23735
|
-
if (key == null) break;
|
|
23736
|
-
const piIdx = toolPiIndexByKey.get(key);
|
|
23737
|
-
if (piIdx == null) break;
|
|
23738
|
-
const entry = accum.toolByIndex.get(piIdx);
|
|
23739
|
-
if (!entry) break;
|
|
23740
|
-
if (item.call_id) entry.id = item.call_id;
|
|
23741
|
-
if (item.name) entry.name = item.name;
|
|
23742
|
-
if (typeof item.arguments === "string") entry.argumentChunks = [item.arguments];
|
|
23838
|
+
accum.textChunksByIndex.get(activeTextIndex).push(ev.text);
|
|
23839
|
+
if (!state$1.active) return;
|
|
23743
23840
|
stream.push({
|
|
23744
|
-
type: "
|
|
23745
|
-
contentIndex:
|
|
23746
|
-
|
|
23841
|
+
type: "text_delta",
|
|
23842
|
+
contentIndex: activeTextIndex,
|
|
23843
|
+
delta: ev.text,
|
|
23747
23844
|
partial: buildPartial(resolved, accum)
|
|
23748
23845
|
});
|
|
23749
|
-
closedToolItems.add(piIdx);
|
|
23750
|
-
break;
|
|
23751
23846
|
}
|
|
23752
|
-
|
|
23753
|
-
|
|
23754
|
-
|
|
23755
|
-
|
|
23756
|
-
|
|
23757
|
-
|
|
23758
|
-
|
|
23759
|
-
|
|
23760
|
-
|
|
23761
|
-
|
|
23762
|
-
|
|
23763
|
-
|
|
23764
|
-
|
|
23765
|
-
|
|
23766
|
-
|
|
23767
|
-
|
|
23768
|
-
|
|
23769
|
-
|
|
23770
|
-
|
|
23771
|
-
|
|
23847
|
+
closeActiveText();
|
|
23848
|
+
break;
|
|
23849
|
+
case "response.output_item.added": {
|
|
23850
|
+
const item = ev.item;
|
|
23851
|
+
if (item?.type !== "function_call") break;
|
|
23852
|
+
const key = responsesToolKey(ev.output_index, item.id);
|
|
23853
|
+
if (key == null) break;
|
|
23854
|
+
if (toolPiIndexByKey.has(key)) break;
|
|
23855
|
+
closeActiveText();
|
|
23856
|
+
state$1.emitted = true;
|
|
23857
|
+
const piIdx = nextContentIndex++;
|
|
23858
|
+
toolPiIndexByKey.set(key, piIdx);
|
|
23859
|
+
accum.blocks.push({
|
|
23860
|
+
kind: "tool",
|
|
23861
|
+
contentIndex: piIdx,
|
|
23862
|
+
openaiIndex: piIdx
|
|
23863
|
+
});
|
|
23864
|
+
accum.toolByIndex.set(piIdx, {
|
|
23865
|
+
id: item.call_id ?? item.id ?? key,
|
|
23866
|
+
name: item.name ?? "",
|
|
23867
|
+
argumentChunks: []
|
|
23868
|
+
});
|
|
23869
|
+
if (!state$1.active) return;
|
|
23870
|
+
stream.push({
|
|
23871
|
+
type: "toolcall_start",
|
|
23872
|
+
contentIndex: piIdx,
|
|
23873
|
+
partial: buildPartial(resolved, accum)
|
|
23874
|
+
});
|
|
23875
|
+
break;
|
|
23876
|
+
}
|
|
23877
|
+
case "response.function_call_arguments.delta": {
|
|
23878
|
+
const key = responsesToolKey(ev.output_index, ev.item_id);
|
|
23879
|
+
if (key == null) break;
|
|
23880
|
+
const piIdx = toolPiIndexByKey.get(key);
|
|
23881
|
+
if (piIdx == null) break;
|
|
23882
|
+
const entry = accum.toolByIndex.get(piIdx);
|
|
23883
|
+
if (!entry) break;
|
|
23884
|
+
const delta = ev.delta;
|
|
23885
|
+
if (typeof delta !== "string" || delta.length === 0) break;
|
|
23886
|
+
entry.argumentChunks.push(delta);
|
|
23887
|
+
if (!state$1.active) return;
|
|
23888
|
+
stream.push({
|
|
23889
|
+
type: "toolcall_delta",
|
|
23890
|
+
contentIndex: piIdx,
|
|
23891
|
+
delta,
|
|
23892
|
+
partial: buildPartial(resolved, accum)
|
|
23893
|
+
});
|
|
23894
|
+
break;
|
|
23895
|
+
}
|
|
23896
|
+
case "response.function_call_arguments.done": {
|
|
23897
|
+
const key = responsesToolKey(ev.output_index, ev.item_id);
|
|
23898
|
+
if (key == null) break;
|
|
23899
|
+
const piIdx = toolPiIndexByKey.get(key);
|
|
23900
|
+
if (piIdx == null) break;
|
|
23901
|
+
const entry = accum.toolByIndex.get(piIdx);
|
|
23902
|
+
if (entry && typeof ev.arguments === "string") entry.argumentChunks = [ev.arguments];
|
|
23903
|
+
break;
|
|
23904
|
+
}
|
|
23905
|
+
case "response.output_item.done": {
|
|
23906
|
+
const item = ev.item;
|
|
23907
|
+
if (item?.type !== "function_call") break;
|
|
23908
|
+
const key = responsesToolKey(ev.output_index, item.id);
|
|
23909
|
+
if (key == null) break;
|
|
23910
|
+
const piIdx = toolPiIndexByKey.get(key);
|
|
23911
|
+
if (piIdx == null) break;
|
|
23912
|
+
const entry = accum.toolByIndex.get(piIdx);
|
|
23913
|
+
if (!entry) break;
|
|
23914
|
+
if (item.call_id) entry.id = item.call_id;
|
|
23915
|
+
if (item.name) entry.name = item.name;
|
|
23916
|
+
if (typeof item.arguments === "string") entry.argumentChunks = [item.arguments];
|
|
23917
|
+
if (!state$1.active) return;
|
|
23918
|
+
stream.push({
|
|
23919
|
+
type: "toolcall_end",
|
|
23920
|
+
contentIndex: piIdx,
|
|
23921
|
+
toolCall: makePiToolCall(entry),
|
|
23922
|
+
partial: buildPartial(resolved, accum)
|
|
23923
|
+
});
|
|
23924
|
+
closedToolItems.add(piIdx);
|
|
23925
|
+
break;
|
|
23772
23926
|
}
|
|
23927
|
+
case "response.completed":
|
|
23928
|
+
case "response.incomplete":
|
|
23929
|
+
accum.usage = mapResponsesUsage(ev.response?.usage);
|
|
23930
|
+
if (ev.type === "response.incomplete" && ev.response?.incomplete_details?.reason === "max_output_tokens") accum.finishReason = "length";
|
|
23931
|
+
if (opts.onChunk && accum.usage) try {
|
|
23932
|
+
opts.onChunk({
|
|
23933
|
+
id: "",
|
|
23934
|
+
object: "chat.completion.chunk",
|
|
23935
|
+
created: 0,
|
|
23936
|
+
model: resolved.modelId,
|
|
23937
|
+
choices: [],
|
|
23938
|
+
usage: accum.usage
|
|
23939
|
+
});
|
|
23940
|
+
} catch {}
|
|
23941
|
+
break;
|
|
23942
|
+
case "response.failed":
|
|
23943
|
+
if (!state$1.active) return;
|
|
23944
|
+
closeActiveText();
|
|
23945
|
+
pushTerminalError(stream, resolved, new Error(ev.response?.error?.message ?? "response.failed"));
|
|
23946
|
+
return;
|
|
23947
|
+
default: break;
|
|
23773
23948
|
}
|
|
23774
|
-
} catch (err) {
|
|
23775
|
-
pushTerminalError(stream, resolved, err);
|
|
23776
|
-
return;
|
|
23777
23949
|
}
|
|
23950
|
+
if (!state$1.active) return;
|
|
23778
23951
|
closeActiveText();
|
|
23779
23952
|
for (const block of accum.blocks) {
|
|
23780
23953
|
if (block.kind !== "tool") continue;
|
|
@@ -24092,6 +24265,23 @@ function fieldBytes(v) {
|
|
|
24092
24265
|
* the engine marks the result isError). No upstream call is made — this
|
|
24093
24266
|
* replaces an opaque upstream 4xx with an actionable, sanitized message.
|
|
24094
24267
|
*/
|
|
24268
|
+
function pushModelCallTimeoutDiagnostic(stream, resolved, timeoutMs, emitted) {
|
|
24269
|
+
const text = `Worker model call timed out after ${timeoutMs}ms${emitted ? " after emitting partial output" : " after two attempts with no output"}. The upstream stream stopped making progress. Retry the worker call; if it repeats, choose a different model.`;
|
|
24270
|
+
const final = {
|
|
24271
|
+
...makeBaseMessage(resolved),
|
|
24272
|
+
content: [{
|
|
24273
|
+
type: "text",
|
|
24274
|
+
text
|
|
24275
|
+
}],
|
|
24276
|
+
stopReason: "error",
|
|
24277
|
+
errorMessage: "worker model-call deadline exceeded"
|
|
24278
|
+
};
|
|
24279
|
+
stream.push({
|
|
24280
|
+
type: "error",
|
|
24281
|
+
reason: "error",
|
|
24282
|
+
error: final
|
|
24283
|
+
});
|
|
24284
|
+
}
|
|
24095
24285
|
function pushBackstopDiagnostic(stream, resolved, assembledTokens, limitTokens) {
|
|
24096
24286
|
const text = `Request too large: the assembled input is ~${assembledTokens} tokens, over the ~${limitTokens}-token budget for ${resolved.modelId}. The run was stopped before an overflow error. Retry with a narrower task — target a specific section / file / element rather than reading everything at once.`;
|
|
24097
24287
|
const final = {
|
|
@@ -25143,7 +25333,7 @@ function shimDefaultsToXhigh(id) {
|
|
|
25143
25333
|
* ALL THREE peer models the consensus protocol needs:
|
|
25144
25334
|
* - an OpenAI frontier model (`gpt-5.6-sol`, else `gpt-5.5` — see
|
|
25145
25335
|
* `resolveOpenAiFrontier`)
|
|
25146
|
-
* - `claude-opus-
|
|
25336
|
+
* - `claude-opus-5` (stand_in's Anthropic slot)
|
|
25147
25337
|
* - any `gemini-3.X.*pro` (gemini_critic's model family — matches the
|
|
25148
25338
|
* same regex `geminiAvailable()` uses, so the gate stays in sync if
|
|
25149
25339
|
* the GA slug renames `gemini-3.1-pro-preview` → `gemini-3.1-pro`)
|
|
@@ -25152,11 +25342,8 @@ function shimDefaultsToXhigh(id) {
|
|
|
25152
25342
|
* fails `tools/call` with -32601 (mirroring the `worker` capability's
|
|
25153
25343
|
* defense-in-depth pattern — the gated tool is functionally invisible).
|
|
25154
25344
|
*
|
|
25155
|
-
*
|
|
25156
|
-
*
|
|
25157
|
-
* slug). For the catalog probe we use the Anthropic-published dashed
|
|
25158
|
-
* slug too — `state.models?.data` mirrors Copilot's catalog where these
|
|
25159
|
-
* land under the dotted slug, so we match by Copilot's actual id shape.
|
|
25345
|
+
* `claude-opus-5` is a single-segment slug (dotted == dashed), so the
|
|
25346
|
+
* catalog probe matches Copilot's actual id shape directly.
|
|
25160
25347
|
*/
|
|
25161
25348
|
function geminiAvailable(source = state) {
|
|
25162
25349
|
const models = source.models?.data;
|
|
@@ -25183,7 +25370,7 @@ function standInToolEnabled() {
|
|
|
25183
25370
|
const models = state.models?.data;
|
|
25184
25371
|
if (!models) return false;
|
|
25185
25372
|
const hasOpenAi = resolveOpenAiFrontier() != null;
|
|
25186
|
-
const hasOpus = models.some((m) => m.id === "claude-opus-
|
|
25373
|
+
const hasOpus = models.some((m) => m.id === "claude-opus-5");
|
|
25187
25374
|
const hasGeminiPro = geminiAvailable();
|
|
25188
25375
|
return hasOpenAi && hasOpus && hasGeminiPro;
|
|
25189
25376
|
}
|
|
@@ -25461,27 +25648,42 @@ function checkAuth(c) {
|
|
|
25461
25648
|
return { ok: true };
|
|
25462
25649
|
}
|
|
25463
25650
|
/**
|
|
25464
|
-
*
|
|
25465
|
-
*
|
|
25466
|
-
*
|
|
25467
|
-
*
|
|
25468
|
-
*
|
|
25469
|
-
*
|
|
25470
|
-
*
|
|
25471
|
-
*
|
|
25472
|
-
*
|
|
25473
|
-
*
|
|
25651
|
+
* opus_critic's effective model, resolved against the live catalog.
|
|
25652
|
+
*
|
|
25653
|
+
* Prefers `claude-opus-5` — a single-segment slug that is natively 1M
|
|
25654
|
+
* (no `-1m` sibling), so it takes large artifacts in one shot (the whole
|
|
25655
|
+
* point of pairing it with gpt-5.6-sol as the big-window peers). When opus-5
|
|
25656
|
+
* isn't in the catalog (e.g. a lesser tier), falls back to the older
|
|
25657
|
+
* 1M-context Opus 4.6 variant (`claude-opus-4.6-1m`, `max_prompt_tokens`
|
|
25658
|
+
* 936K), then to the 200K `claude-opus-4-6`. The 4.6 regex is
|
|
25659
|
+
* version-anchored AND requires a `-1m` suffix boundary (not a permissive
|
|
25660
|
+
* `.*1m`), so it does NOT false-positive on `claude-opus-4.7-1m-internal`,
|
|
25661
|
+
* `claude-opus-4.6-1max`, or a 1M-without-sibling base slug. Tolerates
|
|
25662
|
+
* dotted (`opus-4.6-1m`) and dashed (`opus-4-6-1m`) catalog separators.
|
|
25474
25663
|
*/
|
|
25475
25664
|
const OPUS_1M_RE = /opus-4[.-]6-1m(?:$|-)/i;
|
|
25476
25665
|
function resolveOpusCriticModel() {
|
|
25477
|
-
const
|
|
25666
|
+
const models = state.models?.data;
|
|
25667
|
+
if (models?.some((m) => m.id === "claude-opus-5")) return "claude-opus-5";
|
|
25668
|
+
const oneM = models?.find((m) => OPUS_1M_RE.test(m.id));
|
|
25478
25669
|
return oneM ? oneM.id : "claude-opus-4-6";
|
|
25479
25670
|
}
|
|
25480
25671
|
function activePersonas() {
|
|
25481
|
-
return PERSONAS_READ.filter((p) => !p.requiresGeminiCatalog || geminiAvailable()).map((p) =>
|
|
25482
|
-
|
|
25483
|
-
model
|
|
25484
|
-
|
|
25672
|
+
return PERSONAS_READ.filter((p) => !p.requiresGeminiCatalog || geminiAvailable()).map((p) => {
|
|
25673
|
+
if (p.toolNameHttp !== "opus_critic") return p;
|
|
25674
|
+
const model = resolveOpusCriticModel();
|
|
25675
|
+
const allowedEfforts = model === "claude-opus-5" ? [
|
|
25676
|
+
"low",
|
|
25677
|
+
"medium",
|
|
25678
|
+
"high",
|
|
25679
|
+
"xhigh"
|
|
25680
|
+
] : p.allowedEfforts;
|
|
25681
|
+
return {
|
|
25682
|
+
...p,
|
|
25683
|
+
model,
|
|
25684
|
+
allowedEfforts
|
|
25685
|
+
};
|
|
25686
|
+
});
|
|
25485
25687
|
}
|
|
25486
25688
|
function toolEntries(scope) {
|
|
25487
25689
|
const personaEntries = scope === "all" || scope === "peers" ? activePersonas().map((p) => ({
|
|
@@ -25672,7 +25874,9 @@ async function predictedWindowOverflow(persona, prompt, context) {
|
|
|
25672
25874
|
return;
|
|
25673
25875
|
}
|
|
25674
25876
|
if (tokens <= budget) return void 0;
|
|
25675
|
-
const
|
|
25877
|
+
const criticModel = resolveOpusCriticModel();
|
|
25878
|
+
const criticIs1M = criticModel === "claude-opus-5" || OPUS_1M_RE.test(criticModel);
|
|
25879
|
+
const opusHint = id === "claude-opus-5" || OPUS_1M_RE.test(id) || !criticIs1M ? "" : " / `opus_critic` (Opus 5, 1M context ≈ 1M tokens)";
|
|
25676
25880
|
return `pre-flight rejected: this ${persona.toolNameHttp} brief is ≈${tokens} tokens, over the ${budget}-token budget for ${persona.model} (its ${maxPromptTokens}-token prompt window minus a ${PEER_PROMPT_TOKEN_RESERVE}-token framing reserve). Do NOT summarize or truncate the artifact to fit. Route the full artifact to a larger-window peer — \`codex_critic\` (gpt-5.6-sol ≈ 1M tokens)${opusHint} — or split it into focused sub-calls BY CONCERN and call them in parallel, then aggregate.`;
|
|
25677
25881
|
}
|
|
25678
25882
|
/**
|
|
@@ -25732,7 +25936,7 @@ function jsonPathPreflightCap(body, scope) {
|
|
|
25732
25936
|
* the `stand_in` orchestrator in `src/lib/stand-in.ts` — can reuse the
|
|
25733
25937
|
* same per-endpoint request shaping without re-implementing it. The
|
|
25734
25938
|
* stand_in tool needs to drive its own per-round system prompts across
|
|
25735
|
-
* three concrete models (gpt-5.6-sol, claude-opus-
|
|
25939
|
+
* three concrete models (gpt-5.6-sol, claude-opus-5, gemini-3.1-pro-preview),
|
|
25736
25940
|
* each on a different endpoint; doing that with a `PersonaSpec` would
|
|
25737
25941
|
* require either inventing throwaway personas per round or duplicating
|
|
25738
25942
|
* the dispatch switch.
|
|
@@ -28033,13 +28237,13 @@ function atomicWriteSync(absPath, contents) {
|
|
|
28033
28237
|
throw err;
|
|
28034
28238
|
}
|
|
28035
28239
|
}
|
|
28036
|
-
const READ_PARAMS = Type.Object({
|
|
28037
|
-
path: Type.String({ description: "Workspace-relative or absolute path." }),
|
|
28038
|
-
offset: Type.Optional(Type.Integer({
|
|
28240
|
+
const READ_PARAMS = Type$1.Object({
|
|
28241
|
+
path: Type$1.String({ description: "Workspace-relative or absolute path." }),
|
|
28242
|
+
offset: Type$1.Optional(Type$1.Integer({
|
|
28039
28243
|
minimum: 0,
|
|
28040
28244
|
description: "Line offset (0-indexed)."
|
|
28041
28245
|
})),
|
|
28042
|
-
limit: Type.Optional(Type.Integer({
|
|
28246
|
+
limit: Type$1.Optional(Type$1.Integer({
|
|
28043
28247
|
minimum: 1,
|
|
28044
28248
|
description: "Max lines to return."
|
|
28045
28249
|
}))
|
|
@@ -28064,9 +28268,9 @@ function readTool(workspace) {
|
|
|
28064
28268
|
}
|
|
28065
28269
|
};
|
|
28066
28270
|
}
|
|
28067
|
-
const GLOB_PARAMS = Type.Object({
|
|
28068
|
-
pattern: Type.String({ description: "ripgrep glob pattern, e.g. `src/**/*.ts`." }),
|
|
28069
|
-
limit: Type.Optional(Type.Integer({
|
|
28271
|
+
const GLOB_PARAMS = Type$1.Object({
|
|
28272
|
+
pattern: Type$1.String({ description: "ripgrep glob pattern, e.g. `src/**/*.ts`." }),
|
|
28273
|
+
limit: Type$1.Optional(Type$1.Integer({
|
|
28070
28274
|
minimum: 1,
|
|
28071
28275
|
maximum: SEARCH_HARD_MAX
|
|
28072
28276
|
}))
|
|
@@ -28093,11 +28297,11 @@ function globTool(workspace) {
|
|
|
28093
28297
|
}
|
|
28094
28298
|
};
|
|
28095
28299
|
}
|
|
28096
|
-
const GREP_PARAMS = Type.Object({
|
|
28097
|
-
query: Type.String({ description: "Pattern to search for." }),
|
|
28098
|
-
mode: Type.Optional(Type.Union([Type.Literal("literal"), Type.Literal("regex")], { description: "`literal` (default) = fixed-string; `regex` = PCRE2." })),
|
|
28099
|
-
file_glob: Type.Optional(Type.String({ description: "ripgrep glob filter, e.g. `*.ts`." })),
|
|
28100
|
-
limit: Type.Optional(Type.Integer({
|
|
28300
|
+
const GREP_PARAMS = Type$1.Object({
|
|
28301
|
+
query: Type$1.String({ description: "Pattern to search for." }),
|
|
28302
|
+
mode: Type$1.Optional(Type$1.Union([Type$1.Literal("literal"), Type$1.Literal("regex")], { description: "`literal` (default) = fixed-string; `regex` = PCRE2." })),
|
|
28303
|
+
file_glob: Type$1.Optional(Type$1.String({ description: "ripgrep glob filter, e.g. `*.ts`." })),
|
|
28304
|
+
limit: Type$1.Optional(Type$1.Integer({
|
|
28101
28305
|
minimum: 1,
|
|
28102
28306
|
maximum: SEARCH_HARD_MAX
|
|
28103
28307
|
}))
|
|
@@ -28133,10 +28337,10 @@ function grepTool(workspace) {
|
|
|
28133
28337
|
}
|
|
28134
28338
|
};
|
|
28135
28339
|
}
|
|
28136
|
-
const EDIT_PARAMS = Type.Object({
|
|
28137
|
-
path: Type.String({ description: "Workspace-relative or absolute path." }),
|
|
28138
|
-
old_string: Type.String({ description: "Exact text to find. Must match exactly once; tool returns `not found` (0 matches) or `matches N times` (>1) without editing." }),
|
|
28139
|
-
new_string: Type.String({ description: "Replacement text. May be empty (deletes old_string)." })
|
|
28340
|
+
const EDIT_PARAMS = Type$1.Object({
|
|
28341
|
+
path: Type$1.String({ description: "Workspace-relative or absolute path." }),
|
|
28342
|
+
old_string: Type$1.String({ description: "Exact text to find. Must match exactly once; tool returns `not found` (0 matches) or `matches N times` (>1) without editing." }),
|
|
28343
|
+
new_string: Type$1.String({ description: "Replacement text. May be empty (deletes old_string)." })
|
|
28140
28344
|
});
|
|
28141
28345
|
function editTool(workspace) {
|
|
28142
28346
|
return {
|
|
@@ -28164,9 +28368,9 @@ function editTool(workspace) {
|
|
|
28164
28368
|
}
|
|
28165
28369
|
};
|
|
28166
28370
|
}
|
|
28167
|
-
const WRITE_PARAMS = Type.Object({
|
|
28168
|
-
path: Type.String({ description: "Workspace-relative or absolute path." }),
|
|
28169
|
-
contents: Type.String({ description: "Full file contents. Refused if >10 MiB." })
|
|
28371
|
+
const WRITE_PARAMS = Type$1.Object({
|
|
28372
|
+
path: Type$1.String({ description: "Workspace-relative or absolute path." }),
|
|
28373
|
+
contents: Type$1.String({ description: "Full file contents. Refused if >10 MiB." })
|
|
28170
28374
|
});
|
|
28171
28375
|
function writeTool(workspace) {
|
|
28172
28376
|
return {
|
|
@@ -28182,9 +28386,9 @@ function writeTool(workspace) {
|
|
|
28182
28386
|
}
|
|
28183
28387
|
};
|
|
28184
28388
|
}
|
|
28185
|
-
const BASH_PARAMS = Type.Object({
|
|
28186
|
-
cmd: Type.String({ description: "Shell command line." }),
|
|
28187
|
-
timeout_ms: Type.Optional(Type.Integer({
|
|
28389
|
+
const BASH_PARAMS = Type$1.Object({
|
|
28390
|
+
cmd: Type$1.String({ description: "Shell command line." }),
|
|
28391
|
+
timeout_ms: Type$1.Optional(Type$1.Integer({
|
|
28188
28392
|
minimum: 100,
|
|
28189
28393
|
maximum: BASH_MAX_TIMEOUT_MS,
|
|
28190
28394
|
description: `Per-call timeout (default ${BASH_DEFAULT_TIMEOUT_MS} ms).`
|
|
@@ -28194,7 +28398,7 @@ function bashTool(workspace) {
|
|
|
28194
28398
|
return {
|
|
28195
28399
|
name: "bash",
|
|
28196
28400
|
label: "Run bash",
|
|
28197
|
-
description: "Run a shell command in the worker's workspace under a strict env allowlist (credentials stripped) with a bounded timeout. Non-zero exit returns `<stdout>\\n<stderr>\\nexit=N` as text, not an error.",
|
|
28401
|
+
description: "Run a shell command in the worker's workspace under a strict env allowlist (credentials stripped) with a bounded timeout. Non-zero exit returns `<stdout>\\n<stderr>\\nexit=N` as text, not an error. Prefer the dedicated tools (read/glob/grep/code_search/edit/write/toolbelt) for reading, searching, and editing; reserve bash for builds, tests, git, package managers, and running programs — don't reimplement a file read/search/edit as a python/node/powershell one-off script.",
|
|
28198
28402
|
parameters: BASH_PARAMS,
|
|
28199
28403
|
executionMode: "sequential",
|
|
28200
28404
|
async execute(_toolCallId, params, signal) {
|
|
@@ -28217,7 +28421,7 @@ function bashTool(workspace) {
|
|
|
28217
28421
|
}
|
|
28218
28422
|
};
|
|
28219
28423
|
}
|
|
28220
|
-
const WEB_SEARCH_PARAMS = Type.Object({ query: Type.String({ description: "Natural-language search query." }) });
|
|
28424
|
+
const WEB_SEARCH_PARAMS = Type$1.Object({ query: Type$1.String({ description: "Natural-language search query." }) });
|
|
28221
28425
|
function webSearchTool() {
|
|
28222
28426
|
return {
|
|
28223
28427
|
name: "web_search",
|
|
@@ -28233,12 +28437,12 @@ function webSearchTool() {
|
|
|
28233
28437
|
}
|
|
28234
28438
|
};
|
|
28235
28439
|
}
|
|
28236
|
-
const FETCH_URL_PARAMS = Type.Object({ url: Type.String({ description: "Absolute URL (http/https only)." }) });
|
|
28440
|
+
const FETCH_URL_PARAMS = Type$1.Object({ url: Type$1.String({ description: "Absolute URL (http/https only)." }) });
|
|
28237
28441
|
function fetchUrlTool() {
|
|
28238
28442
|
return {
|
|
28239
28443
|
name: "fetch_url",
|
|
28240
28444
|
label: "Fetch URL",
|
|
28241
|
-
description: "Fetch a URL (HTTP/HTTPS only) and return the response body as text. Bounded to 1 MiB and 30 s. No HTML→markdown conversion
|
|
28445
|
+
description: "Fetch a URL (HTTP/HTTPS only) and return the response body as text. Bounded to 1 MiB and 30 s. No HTML→markdown conversion.",
|
|
28242
28446
|
parameters: FETCH_URL_PARAMS,
|
|
28243
28447
|
async execute(_toolCallId, params, signal) {
|
|
28244
28448
|
if (networkDisabled()) throw new Error("rejected: network disabled");
|
|
@@ -28287,26 +28491,26 @@ function fetchUrlTool() {
|
|
|
28287
28491
|
}
|
|
28288
28492
|
};
|
|
28289
28493
|
}
|
|
28290
|
-
const CODE_SEARCH_PARAMS = Type.Object({
|
|
28291
|
-
query: Type.String({ description: "Search text. Natural-language intent in the default `semantic` mode; a literal string in `lexical`/`exact`; a PCRE2 regex in `regex`." }),
|
|
28292
|
-
mode: Type.Optional(Type.Union([
|
|
28293
|
-
Type.Literal("semantic"),
|
|
28294
|
-
Type.Literal("lexical"),
|
|
28295
|
-
Type.Literal("exact"),
|
|
28296
|
-
Type.Literal("regex"),
|
|
28297
|
-
Type.Literal("ast")
|
|
28494
|
+
const CODE_SEARCH_PARAMS = Type$1.Object({
|
|
28495
|
+
query: Type$1.String({ description: "Search text. Natural-language intent in the default `semantic` mode; a literal string in `lexical`/`exact`; a PCRE2 regex in `regex`." }),
|
|
28496
|
+
mode: Type$1.Optional(Type$1.Union([
|
|
28497
|
+
Type$1.Literal("semantic"),
|
|
28498
|
+
Type$1.Literal("lexical"),
|
|
28499
|
+
Type$1.Literal("exact"),
|
|
28500
|
+
Type$1.Literal("regex"),
|
|
28501
|
+
Type$1.Literal("ast")
|
|
28298
28502
|
], { description: "Search mode. `semantic` (DEFAULT): ColBERT meaning-based ranking, falls back to lexical when the index isn't ready (response `source` says which engine ran). `lexical`: BM25F + tree-sitter (best for exact symbols). `exact`: fixed-string. `regex`: PCRE2. `ast`: ast-grep structural (needs `ast_pattern` + `ast_lang`)." })),
|
|
28299
|
-
pattern: Type.Optional(Type.String({ description: "Semantic mode only: regex pre-filter (colgrep -e) — grep first, then rank semantically. Ignored in lexical modes." })),
|
|
28300
|
-
file_glob: Type.Optional(Type.String({ description: "ripgrep glob filter." })),
|
|
28301
|
-
limit: Type.Optional(Type.Integer({
|
|
28503
|
+
pattern: Type$1.Optional(Type$1.String({ description: "Semantic mode only: regex pre-filter (colgrep -e) — grep first, then rank semantically. Ignored in lexical modes." })),
|
|
28504
|
+
file_glob: Type$1.Optional(Type$1.String({ description: "ripgrep glob filter." })),
|
|
28505
|
+
limit: Type$1.Optional(Type$1.Integer({
|
|
28302
28506
|
minimum: 1,
|
|
28303
28507
|
description: "Max hits to return."
|
|
28304
28508
|
})),
|
|
28305
|
-
structural: Type.Optional(Type.Union([Type.Literal("full"), Type.Literal("topN")], { description: "Structural-ranking depth (lexical mode only)." })),
|
|
28306
|
-
complete: Type.Optional(Type.Boolean({ description: "Lexical mode: when true, return the COMPLETE match set (every line ripgrep would find, capped only by `limit`) — disables the default precision shoulder cut + per-file cap. Use it when you must not miss any occurrence (every caller of X, a rename, an audit). The default response `notice` says when matches were hidden." })),
|
|
28307
|
-
multiline: Type.Optional(Type.Boolean({ description: "Set true with mode:'regex' to let a pattern span newlines (ripgrep -U), e.g. 'foo[\\s\\S]*?bar' across lines. (literal/lexical queries can't contain a newline.)" })),
|
|
28308
|
-
ast_pattern: Type.Optional(Type.String({ description: "mode:'ast' structural pattern (e.g. 'function $F($$$) { $$$ }'). Matches come from ast-grep instead of ripgrep — for multi-line AST shapes the regex modes can't express. Takes precedence over `query`. REQUIRES `ast_lang`. If ast-grep isn't installed you get a `notice`; it never falls back to regex." })),
|
|
28309
|
-
ast_lang: Type.Optional(Type.String({ description: "Language grammar for `ast_pattern` (REQUIRED with it): 'ts' | 'tsx' | 'js' | 'py' | 'rust' | 'go' | … Without it ast-grep cross-matches every language and returns garbage." }))
|
|
28509
|
+
structural: Type$1.Optional(Type$1.Union([Type$1.Literal("full"), Type$1.Literal("topN")], { description: "Structural-ranking depth (lexical mode only)." })),
|
|
28510
|
+
complete: Type$1.Optional(Type$1.Boolean({ description: "Lexical mode: when true, return the COMPLETE match set (every line ripgrep would find, capped only by `limit`) — disables the default precision shoulder cut + per-file cap. Use it when you must not miss any occurrence (every caller of X, a rename, an audit). The default response `notice` says when matches were hidden." })),
|
|
28511
|
+
multiline: Type$1.Optional(Type$1.Boolean({ description: "Set true with mode:'regex' to let a pattern span newlines (ripgrep -U), e.g. 'foo[\\s\\S]*?bar' across lines. (literal/lexical queries can't contain a newline.)" })),
|
|
28512
|
+
ast_pattern: Type$1.Optional(Type$1.String({ description: "mode:'ast' structural pattern (e.g. 'function $F($$$) { $$$ }'). Matches come from ast-grep instead of ripgrep — for multi-line AST shapes the regex modes can't express. Takes precedence over `query`. REQUIRES `ast_lang`. If ast-grep isn't installed you get a `notice`; it never falls back to regex." })),
|
|
28513
|
+
ast_lang: Type$1.Optional(Type$1.String({ description: "Language grammar for `ast_pattern` (REQUIRED with it): 'ts' | 'tsx' | 'js' | 'py' | 'rust' | 'go' | … Without it ast-grep cross-matches every language and returns garbage." }))
|
|
28310
28514
|
});
|
|
28311
28515
|
function codeSearchTool(workspace) {
|
|
28312
28516
|
return {
|
|
@@ -28465,9 +28669,9 @@ const GIT_DIFF_PRODUCING = new Set([
|
|
|
28465
28669
|
"show",
|
|
28466
28670
|
"diff"
|
|
28467
28671
|
]);
|
|
28468
|
-
const TOOLBELT_PARAMS = Type.Object({
|
|
28469
|
-
tool: Type.Union(TOOLBELT_TOOLS.map((t) => Type.Literal(t)), { description: "Which read-only analysis CLI to run: rg (ripgrep search), fd (file find), sg (ast-grep structural search), jq (JSON), yq (YAML/TOML/XML), gron (flatten JSON to greppable lines), scc (code stats: LOC + complexity), tokei (code stats), difft (difftastic structural diff), git (read-only subcommands only)." }),
|
|
28470
|
-
args: Type.Optional(Type.Array(Type.String(), { description: "Arguments passed LITERALLY to the tool (no shell: no pipes, redirects, chaining, or glob expansion). For git, args[0] must be a read-only subcommand (log/show/diff/blame/ls-files/…)." }))
|
|
28672
|
+
const TOOLBELT_PARAMS = Type$1.Object({
|
|
28673
|
+
tool: Type$1.Union(TOOLBELT_TOOLS.map((t) => Type$1.Literal(t)), { description: "Which read-only analysis CLI to run: rg (ripgrep search), fd (file find), sg (ast-grep structural search), jq (JSON), yq (YAML/TOML/XML), gron (flatten JSON to greppable lines), scc (code stats: LOC + complexity), tokei (code stats), difft (difftastic structural diff), git (read-only subcommands only)." }),
|
|
28674
|
+
args: Type$1.Optional(Type$1.Array(Type$1.String(), { description: "Arguments passed LITERALLY to the tool (no shell: no pipes, redirects, chaining, or glob expansion). For git, args[0] must be a read-only subcommand (log/show/diff/blame/ls-files/…)." }))
|
|
28471
28675
|
});
|
|
28472
28676
|
/**
|
|
28473
28677
|
* True iff `arg` triggers a denied flag. Long flags (`--foo`) match on the
|
|
@@ -28576,10 +28780,10 @@ function toolbeltTool(workspace) {
|
|
|
28576
28780
|
};
|
|
28577
28781
|
}
|
|
28578
28782
|
const PEER_CRITIC_TUPLE = [
|
|
28579
|
-
Type.Literal("codex_critic"),
|
|
28580
|
-
Type.Literal("gemini_critic"),
|
|
28581
|
-
Type.Literal("codex_reviewer"),
|
|
28582
|
-
Type.Literal("opus_critic")
|
|
28783
|
+
Type$1.Literal("codex_critic"),
|
|
28784
|
+
Type$1.Literal("gemini_critic"),
|
|
28785
|
+
Type$1.Literal("codex_reviewer"),
|
|
28786
|
+
Type$1.Literal("opus_critic")
|
|
28583
28787
|
];
|
|
28584
28788
|
/**
|
|
28585
28789
|
* Critic names accepted by `peer_review.critic`. Exported for the
|
|
@@ -28587,17 +28791,17 @@ const PEER_CRITIC_TUPLE = [
|
|
|
28587
28791
|
* against `PERSONAS_READ` from `~/lib/peer-mcp-personas`.
|
|
28588
28792
|
*/
|
|
28589
28793
|
const PEER_CRITIC_NAMES = PEER_CRITIC_TUPLE.map((l) => l.const);
|
|
28590
|
-
const PEER_EFFORT_UNION = Type.Union([
|
|
28591
|
-
Type.Literal("low"),
|
|
28592
|
-
Type.Literal("medium"),
|
|
28593
|
-
Type.Literal("high"),
|
|
28594
|
-
Type.Literal("xhigh")
|
|
28794
|
+
const PEER_EFFORT_UNION = Type$1.Union([
|
|
28795
|
+
Type$1.Literal("low"),
|
|
28796
|
+
Type$1.Literal("medium"),
|
|
28797
|
+
Type$1.Literal("high"),
|
|
28798
|
+
Type$1.Literal("xhigh")
|
|
28595
28799
|
], { description: "Reasoning depth. Per-critic allowedEfforts gate; out-of-band values are clamped to the critic's default." });
|
|
28596
|
-
const PEER_REVIEW_PARAMS = Type.Object({
|
|
28597
|
-
critic: Type.Union([...PEER_CRITIC_TUPLE], { description: "Critic tool name. One of " + PEER_CRITIC_NAMES.map((n) => `\`${n}\``).join(", ") + ". `gemini_critic` is only valid when gemini-3.x is in the Copilot catalog; otherwise the call is refused." }),
|
|
28598
|
-
prompt: Type.String({ description: "The brief — artifact under review plus constraints. Pasted verbatim into the critic's user message." }),
|
|
28599
|
-
context: Type.Optional(Type.String({ description: "Optional extra context concatenated to the brief." })),
|
|
28600
|
-
effort: Type.Optional(PEER_EFFORT_UNION)
|
|
28800
|
+
const PEER_REVIEW_PARAMS = Type$1.Object({
|
|
28801
|
+
critic: Type$1.Union([...PEER_CRITIC_TUPLE], { description: "Critic tool name. One of " + PEER_CRITIC_NAMES.map((n) => `\`${n}\``).join(", ") + ". `gemini_critic` is only valid when gemini-3.x is in the Copilot catalog; otherwise the call is refused." }),
|
|
28802
|
+
prompt: Type$1.String({ description: "The brief — artifact under review plus constraints. Pasted verbatim into the critic's user message." }),
|
|
28803
|
+
context: Type$1.Optional(Type$1.String({ description: "Optional extra context concatenated to the brief." })),
|
|
28804
|
+
effort: Type$1.Optional(PEER_EFFORT_UNION)
|
|
28601
28805
|
});
|
|
28602
28806
|
function lookupPersona(critic) {
|
|
28603
28807
|
const persona = PERSONAS_READ.find((p) => p.toolNameHttp === critic);
|
|
@@ -28618,10 +28822,10 @@ function lookupPersona(critic) {
|
|
|
28618
28822
|
* `acquireInFlightSlot`, and `callPersona` keeps the slot accounting,
|
|
28619
28823
|
* effort clamping, and isError-promotion semantics identical.
|
|
28620
28824
|
*/
|
|
28621
|
-
const CODEX_REVIEW_PARAMS = Type.Object({
|
|
28622
|
-
prompt: Type.String({ description: "The code-review brief — diff or single file under review plus constraints. Pasted verbatim into codex-reviewer's user message." }),
|
|
28623
|
-
context: Type.Optional(Type.String({ description: "Optional extra context concatenated to the brief." })),
|
|
28624
|
-
effort: Type.Optional(PEER_EFFORT_UNION)
|
|
28825
|
+
const CODEX_REVIEW_PARAMS = Type$1.Object({
|
|
28826
|
+
prompt: Type$1.String({ description: "The code-review brief — diff or single file under review plus constraints. Pasted verbatim into codex-reviewer's user message." }),
|
|
28827
|
+
context: Type$1.Optional(Type$1.String({ description: "Optional extra context concatenated to the brief." })),
|
|
28828
|
+
effort: Type$1.Optional(PEER_EFFORT_UNION)
|
|
28625
28829
|
});
|
|
28626
28830
|
function codexReviewTool() {
|
|
28627
28831
|
return {
|
|
@@ -28632,7 +28836,7 @@ function codexReviewTool() {
|
|
|
28632
28836
|
executionMode: "sequential",
|
|
28633
28837
|
async execute(_toolCallId, params, signal) {
|
|
28634
28838
|
if (networkDisabled()) throw new Error("rejected: network disabled");
|
|
28635
|
-
const persona = lookupPersona("
|
|
28839
|
+
const persona = lookupPersona("codex_reviewer");
|
|
28636
28840
|
const requested = params.effort;
|
|
28637
28841
|
const effort = requested && persona.allowedEfforts.includes(requested) ? requested : persona.defaultEffort;
|
|
28638
28842
|
const release = acquireInFlightSlot();
|
|
@@ -28655,7 +28859,7 @@ function geminiInCatalog() {
|
|
|
28655
28859
|
if (!models) return false;
|
|
28656
28860
|
return models.some((m) => /^gemini-3\..*pro/i.test(m.id));
|
|
28657
28861
|
}
|
|
28658
|
-
const ADVISOR_PARAMS = Type.Object({ concern: Type.String({
|
|
28862
|
+
const ADVISOR_PARAMS = Type$1.Object({ concern: Type$1.String({
|
|
28659
28863
|
description: "What you want a second pair of eyes on — your current approach, the blocker you're stuck on, or the decision you're about to commit. Required: the advisor needs a focal point.",
|
|
28660
28864
|
minLength: 1
|
|
28661
28865
|
}) });
|
|
@@ -28770,22 +28974,22 @@ function advisorTool(getMessages) {
|
|
|
28770
28974
|
}
|
|
28771
28975
|
};
|
|
28772
28976
|
}
|
|
28773
|
-
const UPDATE_PLAN_PARAMS = Type.Object({
|
|
28774
|
-
steps: Type.Array(Type.Object({
|
|
28775
|
-
title: Type.String({
|
|
28977
|
+
const UPDATE_PLAN_PARAMS = Type$1.Object({
|
|
28978
|
+
steps: Type$1.Array(Type$1.Object({
|
|
28979
|
+
title: Type$1.String({
|
|
28776
28980
|
minLength: 1,
|
|
28777
28981
|
description: "Short imperative description of the step."
|
|
28778
28982
|
}),
|
|
28779
|
-
status: Type.Union([
|
|
28780
|
-
Type.Literal("pending"),
|
|
28781
|
-
Type.Literal("in_progress"),
|
|
28782
|
-
Type.Literal("completed")
|
|
28983
|
+
status: Type$1.Union([
|
|
28984
|
+
Type$1.Literal("pending"),
|
|
28985
|
+
Type$1.Literal("in_progress"),
|
|
28986
|
+
Type$1.Literal("completed")
|
|
28783
28987
|
], { description: "Current status of this step." })
|
|
28784
28988
|
}), {
|
|
28785
28989
|
minItems: 1,
|
|
28786
28990
|
description: "The FULL ordered plan. Each call replaces the previous plan, so always send every step (not just the changed one)."
|
|
28787
28991
|
}),
|
|
28788
|
-
explanation: Type.Optional(Type.String({ description: "Optional one-line note on what changed this update." }))
|
|
28992
|
+
explanation: Type$1.Optional(Type$1.String({ description: "Optional one-line note on what changed this update." }))
|
|
28789
28993
|
});
|
|
28790
28994
|
function createPlanState() {
|
|
28791
28995
|
return { current: [] };
|
|
@@ -29380,15 +29584,21 @@ registerExitHandlers(WORKTREE_REGISTRY);
|
|
|
29380
29584
|
* mode. */
|
|
29381
29585
|
const DEFAULT_MODEL = "gpt-5.4-mini";
|
|
29382
29586
|
const DEFAULT_THINKING = "xhigh";
|
|
29383
|
-
/** Default model for the READ-ONLY `explore` mode. `
|
|
29384
|
-
* (via `
|
|
29385
|
-
*
|
|
29386
|
-
*
|
|
29387
|
-
* gpt-5.6-sol this is NOT a
|
|
29388
|
-
*
|
|
29389
|
-
*
|
|
29390
|
-
*
|
|
29391
|
-
|
|
29587
|
+
/** Default model for the READ-ONLY `explore` mode. `gemini-3.6-flash` at `high`
|
|
29588
|
+
* (via `EXPLORE_DEFAULT_THINKING`; flash advertises no xhigh) — a fast, cheap,
|
|
29589
|
+
* 1M-context tool-caller for read-only repo research. Routes over
|
|
29590
|
+
* `/chat/completions` via the translation shim (the same proven path the
|
|
29591
|
+
* `review` worker uses for gemini). Like `implement`'s gpt-5.6-sol this is NOT a
|
|
29592
|
+
* `workerToolsEnabled` gate input — if absent (e.g. a non-enterprise tier)
|
|
29593
|
+
* `explore` errors helpfully at call time rather than vanishing the whole worker
|
|
29594
|
+
* surface. The caller (the main model) overrides BOTH the model and the reasoning
|
|
29595
|
+
* per call via the `model` / `thinking` args — see the tier ladder (gpt-5.6-sol
|
|
29596
|
+
* heavy / gpt-5.6-terra moderate / gemini-3.6-flash light) in the MCP tool desc. */
|
|
29597
|
+
const EXPLORE_DEFAULT_MODEL = "gemini-3.6-flash";
|
|
29598
|
+
/** Default thinking for `explore`. `high` (flash has no xhigh); explicit rather
|
|
29599
|
+
* than inherited from `DEFAULT_THINKING` so the explore effort can't drift if the
|
|
29600
|
+
* shared fallback changes. */
|
|
29601
|
+
const EXPLORE_DEFAULT_THINKING = "high";
|
|
29392
29602
|
/** Default model + thinking for the READ-ONLY `review` mode.
|
|
29393
29603
|
* `gemini-3.1-pro-preview` at `xhigh` (clamped to `high` at call time — gemini
|
|
29394
29604
|
* advertises no xhigh). DELIBERATELY DECORRELATED FROM THE IMPLEMENTER: bounded
|
|
@@ -29410,6 +29620,10 @@ const REVIEW_DEFAULT_THINKING = "xhigh";
|
|
|
29410
29620
|
* autonomous implementation. An explicit `opts.model` still wins. */
|
|
29411
29621
|
const IMPLEMENT_DEFAULT_MODEL = "gpt-5.6-sol";
|
|
29412
29622
|
const IMPLEMENT_DEFAULT_THINKING = "xhigh";
|
|
29623
|
+
/** `test` starts with the same built-in pair as `implement`, but remains an
|
|
29624
|
+
* independent mode so either can be overridden without affecting the other. */
|
|
29625
|
+
const TEST_DEFAULT_MODEL = "gpt-5.6-sol";
|
|
29626
|
+
const TEST_DEFAULT_THINKING = "xhigh";
|
|
29413
29627
|
/** Default model for `browse` mode. `gpt-5.4-mini` — the Gate-B-winning
|
|
29414
29628
|
* browse model (small + fast enough to drive a tab at human pace, with
|
|
29415
29629
|
* enough tool-calling discipline to terminate). This is DISTINCT from the
|
|
@@ -29429,14 +29643,53 @@ const BROWSE_DEFAULT_THINKING = "high";
|
|
|
29429
29643
|
/** Default model + thinking for the read-only `plan` mode. `claude-opus-4.8`
|
|
29430
29644
|
* at `xhigh` — planning is the highest-leverage read-only step (the plan
|
|
29431
29645
|
* shapes everything downstream), so it gets the strongest reasoning model
|
|
29432
|
-
* rather than the
|
|
29646
|
+
* rather than the lightweight `gemini-3.6-flash` explore default. Uses the DOTTED
|
|
29433
29647
|
* Copilot catalog id (the worker resolver exact-matches `catalog.id`, it does
|
|
29434
|
-
* NOT translate the Anthropic dashed slug
|
|
29435
|
-
*
|
|
29436
|
-
* non-enterprise tier), exactly like
|
|
29437
|
-
* arg still wins. */
|
|
29438
|
-
const PLAN_DEFAULT_MODEL = "claude-opus-
|
|
29439
|
-
const
|
|
29648
|
+
* NOT translate the Anthropic dashed slug; `claude-opus-5` is a single-segment
|
|
29649
|
+
* slug so dotted == dashed). Falls back to a helpful unknown-model error at call
|
|
29650
|
+
* time if opus-5 isn't in the catalog (e.g. a non-enterprise tier), exactly like
|
|
29651
|
+
* `implement`'s `gpt-5.6-sol`. Caller's `model` arg still wins. */
|
|
29652
|
+
const PLAN_DEFAULT_MODEL = "claude-opus-5";
|
|
29653
|
+
const BUILT_IN_MODE_DEFAULTS = Object.freeze({
|
|
29654
|
+
explore: {
|
|
29655
|
+
model: EXPLORE_DEFAULT_MODEL,
|
|
29656
|
+
thinking: EXPLORE_DEFAULT_THINKING
|
|
29657
|
+
},
|
|
29658
|
+
review: {
|
|
29659
|
+
model: REVIEW_DEFAULT_MODEL,
|
|
29660
|
+
thinking: REVIEW_DEFAULT_THINKING
|
|
29661
|
+
},
|
|
29662
|
+
plan: {
|
|
29663
|
+
model: PLAN_DEFAULT_MODEL,
|
|
29664
|
+
thinking: "xhigh"
|
|
29665
|
+
},
|
|
29666
|
+
implement: {
|
|
29667
|
+
model: IMPLEMENT_DEFAULT_MODEL,
|
|
29668
|
+
thinking: IMPLEMENT_DEFAULT_THINKING
|
|
29669
|
+
},
|
|
29670
|
+
test: {
|
|
29671
|
+
model: TEST_DEFAULT_MODEL,
|
|
29672
|
+
thinking: TEST_DEFAULT_THINKING
|
|
29673
|
+
},
|
|
29674
|
+
browse: {
|
|
29675
|
+
model: BROWSE_DEFAULT_MODEL,
|
|
29676
|
+
thinking: BROWSE_DEFAULT_THINKING
|
|
29677
|
+
}
|
|
29678
|
+
});
|
|
29679
|
+
/** Resolve the effective mode ladder without changing the gate sentinel. */
|
|
29680
|
+
function resolveModeDefaults(mode, ignoreSessionDefaults = false) {
|
|
29681
|
+
const builtIn = BUILT_IN_MODE_DEFAULTS[mode] ?? {
|
|
29682
|
+
model: DEFAULT_MODEL,
|
|
29683
|
+
thinking: DEFAULT_THINKING
|
|
29684
|
+
};
|
|
29685
|
+
const override = ignoreSessionDefaults ? {} : getWorkerSessionDefault(mode);
|
|
29686
|
+
return {
|
|
29687
|
+
model: override.model ?? builtIn.model,
|
|
29688
|
+
thinking: override.thinking ?? builtIn.thinking,
|
|
29689
|
+
modelSource: override.model === void 0 ? "built-in" : "override",
|
|
29690
|
+
thinkingSource: override.thinking === void 0 ? "built-in" : "override"
|
|
29691
|
+
};
|
|
29692
|
+
}
|
|
29440
29693
|
/**
|
|
29441
29694
|
* `Model<any>` shim used to satisfy `Agent.initialState.model` typing.
|
|
29442
29695
|
*
|
|
@@ -29450,6 +29703,7 @@ const PLAN_DEFAULT_THINKING = "xhigh";
|
|
|
29450
29703
|
* diagnostics (e.g. error-message AssistantMessage's `model` field
|
|
29451
29704
|
* if Pi ever inspects it) faithful to what the caller asked for.
|
|
29452
29705
|
*/
|
|
29706
|
+
let agentOptionsObserverForTests;
|
|
29453
29707
|
function makeModelShim(modelId) {
|
|
29454
29708
|
return {
|
|
29455
29709
|
id: modelId,
|
|
@@ -29487,6 +29741,34 @@ function extractAssistantText(content) {
|
|
|
29487
29741
|
for (const part of content) if (part.type === "text") out += part.text;
|
|
29488
29742
|
return out;
|
|
29489
29743
|
}
|
|
29744
|
+
const MAX_EMPTY_OUTPUT_NUDGES = 3;
|
|
29745
|
+
const EMPTY_OUTPUT_NUDGES = [
|
|
29746
|
+
"Summarize your findings so far.",
|
|
29747
|
+
"Your previous reply was empty. Provide the answer now in plain text.",
|
|
29748
|
+
"Reply with plain text only. Do not call any tool."
|
|
29749
|
+
];
|
|
29750
|
+
/**
|
|
29751
|
+
* Resolve the per-run nudge cap. Zero explicitly disables nudging; malformed,
|
|
29752
|
+
* negative, and fractional values fall back to the default.
|
|
29753
|
+
*/
|
|
29754
|
+
function resolveMaxEmptyOutputNudges() {
|
|
29755
|
+
const raw = process$1.env.GH_ROUTER_WORKER_MAX_NUDGES;
|
|
29756
|
+
if (raw === void 0 || raw === "") return MAX_EMPTY_OUTPUT_NUDGES;
|
|
29757
|
+
const parsed = Number(raw);
|
|
29758
|
+
if (!Number.isFinite(parsed) || parsed < 0 || !Number.isInteger(parsed)) return MAX_EMPTY_OUTPUT_NUDGES;
|
|
29759
|
+
return parsed;
|
|
29760
|
+
}
|
|
29761
|
+
function emptyOutputNudge(attempt) {
|
|
29762
|
+
return EMPTY_OUTPUT_NUDGES[Math.min(attempt, EMPTY_OUTPUT_NUDGES.length) - 1];
|
|
29763
|
+
}
|
|
29764
|
+
/** True only for a clean, empty assistant stop with no pending tool calls. */
|
|
29765
|
+
function shouldNudgeForEmptyOutput(message) {
|
|
29766
|
+
if (message.role !== "assistant") return false;
|
|
29767
|
+
const assistant = message;
|
|
29768
|
+
if (assistant.stopReason !== "stop" || !Array.isArray(assistant.content)) return false;
|
|
29769
|
+
if (assistant.content.some((part) => part.type === "toolCall")) return false;
|
|
29770
|
+
return extractAssistantText(assistant.content).trim() === "";
|
|
29771
|
+
}
|
|
29490
29772
|
/**
|
|
29491
29773
|
* Trivial stub for the no-worktree path. `dir` is the workspace
|
|
29492
29774
|
* itself; `finalize` returns an empty diff (the response text won't
|
|
@@ -29527,21 +29809,15 @@ async function runWorkerAgentOnce(opts) {
|
|
|
29527
29809
|
isError: true
|
|
29528
29810
|
};
|
|
29529
29811
|
try {
|
|
29530
|
-
const isBrowse = opts.mode === "browse";
|
|
29531
|
-
const isPlan = opts.mode === "plan";
|
|
29532
|
-
const isReview = opts.mode === "review";
|
|
29533
|
-
const isWriteCapable = opts.mode === "implement" || opts.mode === "test";
|
|
29534
|
-
const isExplore = opts.mode === "explore";
|
|
29535
|
-
const defaultModel = isBrowse ? BROWSE_DEFAULT_MODEL : isPlan ? PLAN_DEFAULT_MODEL : isReview ? REVIEW_DEFAULT_MODEL : isWriteCapable ? IMPLEMENT_DEFAULT_MODEL : isExplore ? EXPLORE_DEFAULT_MODEL : DEFAULT_MODEL;
|
|
29536
|
-
const defaultThinking = isBrowse ? BROWSE_DEFAULT_THINKING : isPlan ? PLAN_DEFAULT_THINKING : isReview ? REVIEW_DEFAULT_THINKING : isWriteCapable ? IMPLEMENT_DEFAULT_THINKING : DEFAULT_THINKING;
|
|
29537
29812
|
const resolved = resolveModelAndThinking({
|
|
29538
|
-
model: opts.model
|
|
29539
|
-
thinking: opts.thinking
|
|
29813
|
+
model: opts.model,
|
|
29814
|
+
thinking: opts.thinking
|
|
29540
29815
|
});
|
|
29541
29816
|
if (!resolved.ok) return {
|
|
29542
29817
|
text: resolved.error,
|
|
29543
29818
|
isError: true
|
|
29544
29819
|
};
|
|
29820
|
+
const isBrowse = opts.mode === "browse";
|
|
29545
29821
|
const ctxBudget = makeContextBudget(resolved.contextWindow);
|
|
29546
29822
|
const workspaceInput = opts.workspace ?? (isBrowse ? process$1.cwd() : void 0);
|
|
29547
29823
|
if (workspaceInput === void 0) return {
|
|
@@ -29581,7 +29857,7 @@ async function runWorkerAgentOnce(opts) {
|
|
|
29581
29857
|
getMessages,
|
|
29582
29858
|
planState
|
|
29583
29859
|
});
|
|
29584
|
-
const
|
|
29860
|
+
const agentOptions = {
|
|
29585
29861
|
initialState: {
|
|
29586
29862
|
systemPrompt: systemPromptFor(opts.mode),
|
|
29587
29863
|
model: makeModelShim(resolved.modelId),
|
|
@@ -29590,7 +29866,8 @@ async function runWorkerAgentOnce(opts) {
|
|
|
29590
29866
|
},
|
|
29591
29867
|
streamFn: createCopilotStreamFn({
|
|
29592
29868
|
resolved,
|
|
29593
|
-
contextBudget: ctxBudget
|
|
29869
|
+
contextBudget: ctxBudget,
|
|
29870
|
+
modelCallTimeoutMs: resolveWorkerModelCallTimeoutMs()
|
|
29594
29871
|
}),
|
|
29595
29872
|
toolExecution: "parallel",
|
|
29596
29873
|
transformContext: async (messages) => {
|
|
@@ -29623,6 +29900,7 @@ async function runWorkerAgentOnce(opts) {
|
|
|
29623
29900
|
if (a.trim()) terminalText = a;
|
|
29624
29901
|
}
|
|
29625
29902
|
},
|
|
29903
|
+
shouldStopAfterTurn: () => budget.hardStopReason !== null,
|
|
29626
29904
|
afterToolCall: async (ctx) => {
|
|
29627
29905
|
budget.recordToolBytes(ctx.result);
|
|
29628
29906
|
if (ctxBudget) {
|
|
@@ -29633,15 +29911,32 @@ async function runWorkerAgentOnce(opts) {
|
|
|
29633
29911
|
prepareNextTurn: async () => {
|
|
29634
29912
|
budget.addTurn();
|
|
29635
29913
|
}
|
|
29636
|
-
}
|
|
29914
|
+
};
|
|
29915
|
+
agentOptionsObserverForTests?.(agentOptions);
|
|
29916
|
+
const agent = new Agent$1(agentOptions);
|
|
29637
29917
|
agentHolder.agent = agent;
|
|
29638
|
-
const abortHandler = () => agent
|
|
29639
|
-
if (opts.signal)
|
|
29640
|
-
else opts.signal.addEventListener("abort", abortHandler, { once: true });
|
|
29918
|
+
const abortHandler = () => agent.abort();
|
|
29919
|
+
if (opts.signal) opts.signal.addEventListener("abort", abortHandler, { once: true });
|
|
29641
29920
|
let finalText = "";
|
|
29642
29921
|
let lastStopReason = null;
|
|
29922
|
+
let nudgeCount = 0;
|
|
29923
|
+
const maxEmptyOutputNudges = resolveMaxEmptyOutputNudges();
|
|
29643
29924
|
let terminalText = null;
|
|
29644
29925
|
const unsubscribe = agent.subscribe((event) => {
|
|
29926
|
+
if (event.type === "turn_end") {
|
|
29927
|
+
if (nudgeCount < maxEmptyOutputNudges && shouldNudgeForEmptyOutput(event.message)) {
|
|
29928
|
+
nudgeCount += 1;
|
|
29929
|
+
agent.followUp({
|
|
29930
|
+
role: "user",
|
|
29931
|
+
content: [{
|
|
29932
|
+
type: "text",
|
|
29933
|
+
text: emptyOutputNudge(nudgeCount)
|
|
29934
|
+
}],
|
|
29935
|
+
timestamp: Date.now()
|
|
29936
|
+
});
|
|
29937
|
+
}
|
|
29938
|
+
return;
|
|
29939
|
+
}
|
|
29645
29940
|
if (event.type !== "message_end") return;
|
|
29646
29941
|
const msg = event.message;
|
|
29647
29942
|
if (typeof msg !== "object" || msg === null) return;
|
|
@@ -29652,11 +29947,14 @@ async function runWorkerAgentOnce(opts) {
|
|
|
29652
29947
|
const sr = msg.stopReason;
|
|
29653
29948
|
if (typeof sr === "string") lastStopReason = sr;
|
|
29654
29949
|
});
|
|
29950
|
+
let wallClockExpired = false;
|
|
29655
29951
|
const wallClockTimer = setTimeout(() => {
|
|
29656
|
-
|
|
29952
|
+
wallClockExpired = true;
|
|
29953
|
+
agent.abort();
|
|
29657
29954
|
}, budget.config.maxWallClockMs);
|
|
29658
29955
|
wallClockTimer.unref?.();
|
|
29659
29956
|
try {
|
|
29957
|
+
if (opts.signal?.aborted) throw new Error("[halted: cancelled]");
|
|
29660
29958
|
await agent.prompt(opts.prompt);
|
|
29661
29959
|
await agent.waitForIdle();
|
|
29662
29960
|
let diff = "";
|
|
@@ -29669,12 +29967,26 @@ async function runWorkerAgentOnce(opts) {
|
|
|
29669
29967
|
await ws.remove();
|
|
29670
29968
|
} catch {}
|
|
29671
29969
|
const text = isBrowse ? terminalText ?? finalText : diff ? `${finalText}\n\n${diff}` : finalText;
|
|
29672
|
-
if (lastStopReason === "error")
|
|
29673
|
-
|
|
29970
|
+
if (lastStopReason === "error" || lastStopReason === "aborted") {
|
|
29971
|
+
const diag = (terminalText ?? finalText).trim();
|
|
29972
|
+
let diagnostic;
|
|
29973
|
+
if (lastStopReason === "aborted") diagnostic = wallClockExpired ? "[halted: wallclock]" : "[halted: cancelled]";
|
|
29974
|
+
else diagnostic = diag || "Worker run failed before producing an answer — the model's input likely overflowed (a large tool result), or the upstream errored. Retry with a narrower task: target a specific section / file / element rather than reading everything at once.";
|
|
29975
|
+
return {
|
|
29976
|
+
text: lastStopReason === "aborted" ? [
|
|
29977
|
+
diag,
|
|
29978
|
+
diff,
|
|
29979
|
+
diagnostic
|
|
29980
|
+
].filter(Boolean).join("\n\n") : [diagnostic, diff].filter(Boolean).join("\n\n"),
|
|
29981
|
+
isError: true
|
|
29982
|
+
};
|
|
29983
|
+
}
|
|
29984
|
+
if (budget.hardStopReason) return {
|
|
29985
|
+
text: [text, `[halted: ${budget.hardStopReason}]`].filter(Boolean).join("\n\n"),
|
|
29674
29986
|
isError: true
|
|
29675
29987
|
};
|
|
29676
29988
|
if (!text.trim()) return {
|
|
29677
|
-
text: `${NO_OUTPUT_PREFIX} (stopReason=${lastStopReason ?? "unknown"}, turns=${budget.turns}, elapsed=${budget.elapsedMs}ms)]
|
|
29989
|
+
text: `${NO_OUTPUT_PREFIX} after ${nudgeCount} nudges (stopReason=${lastStopReason ?? "unknown"}, turns=${budget.turns}, elapsed=${budget.elapsedMs}ms)]; retry with a different model via worker_defaults, or narrow/split the task.`,
|
|
29678
29990
|
isError: true
|
|
29679
29991
|
};
|
|
29680
29992
|
return { text };
|
|
@@ -29708,42 +30020,21 @@ async function runWorkerAgentOnce(opts) {
|
|
|
29708
30020
|
}
|
|
29709
30021
|
/**
|
|
29710
30022
|
* Prefix of the sentinel `runWorkerAgentOnce` returns when a worker stops
|
|
29711
|
-
*
|
|
29712
|
-
*
|
|
29713
|
-
* exactly this case. Distinct from a budget cap (`WorkerAbort` → halt message),
|
|
29714
|
-
* a stream error (`stopReason="error"` → overflow/upstream diagnostic), and a
|
|
29715
|
-
* real failure — none of which carry this prefix, so none are retried.
|
|
30023
|
+
* cleanly but emits no usable text even after its bounded in-run nudges. Kept
|
|
30024
|
+
* stable for callers that recognize the existing sentinel shape.
|
|
29716
30025
|
*/
|
|
29717
30026
|
const NO_OUTPUT_PREFIX = "[worker exited with no output";
|
|
29718
|
-
/**
|
|
29719
|
-
|
|
29720
|
-
|
|
29721
|
-
|
|
29722
|
-
|
|
29723
|
-
|
|
29724
|
-
|
|
29725
|
-
}
|
|
29726
|
-
/**
|
|
29727
|
-
* Run `runOnce`, and on the transient no-output sentinel retry EXACTLY ONCE with
|
|
29728
|
-
* a fresh run before surfacing it. Real errors, budget caps, and stream errors
|
|
29729
|
-
* are returned as-is (they have distinct, actionable messages and a retry would
|
|
29730
|
-
* not help). A consumed abort signal short-circuits the retry. If the retry also
|
|
29731
|
-
* produces no output, the ORIGINAL is returned (one is enough signal; the
|
|
29732
|
-
* failure isn't hidden). Extracted + injected for unit-testability.
|
|
29733
|
-
*/
|
|
29734
|
-
async function withNoOutputRetry(runOnce, opts) {
|
|
29735
|
-
const first = await runOnce(opts);
|
|
29736
|
-
if (!isTransientNoOutput(first) || opts.signal?.aborted) return first;
|
|
29737
|
-
const second = await runOnce(opts);
|
|
29738
|
-
return isTransientNoOutput(second) ? first : second;
|
|
30027
|
+
/** Public entry. Resolve model/thinking once, then run under one transcript and Budget. */
|
|
30028
|
+
function resolveWorkerRunOpts(opts) {
|
|
30029
|
+
const defaults = resolveModeDefaults(opts.mode, opts.ignoreSessionDefaults === true);
|
|
30030
|
+
return {
|
|
30031
|
+
...opts,
|
|
30032
|
+
model: opts.model ?? defaults.model,
|
|
30033
|
+
thinking: opts.thinking ?? defaults.thinking
|
|
30034
|
+
};
|
|
29739
30035
|
}
|
|
29740
|
-
/**
|
|
29741
|
-
* Public entry: a worker run with a single transient-no-output retry. Wraps the
|
|
29742
|
-
* implementation (`runWorkerAgentOnce`); the signature is unchanged so every
|
|
29743
|
-
* caller (MCP dispatch, the orchestration runner) gets the retry for free.
|
|
29744
|
-
*/
|
|
29745
30036
|
async function runWorkerAgent(opts) {
|
|
29746
|
-
return
|
|
30037
|
+
return runWorkerAgentOnce(resolveWorkerRunOpts(opts));
|
|
29747
30038
|
}
|
|
29748
30039
|
/**
|
|
29749
30040
|
* Test-only exports. The public surface of the engine is
|
|
@@ -29794,8 +30085,8 @@ const STAND_IN_MODELS = Object.freeze([
|
|
|
29794
30085
|
effort: "xhigh"
|
|
29795
30086
|
},
|
|
29796
30087
|
{
|
|
29797
|
-
key: "claude-opus-
|
|
29798
|
-
model: "claude-opus-
|
|
30088
|
+
key: "claude-opus-5",
|
|
30089
|
+
model: "claude-opus-5",
|
|
29799
30090
|
endpoint: "/v1/messages",
|
|
29800
30091
|
effort: "xhigh"
|
|
29801
30092
|
},
|
|
@@ -31891,7 +32182,8 @@ async function runWorkflowLive(opts) {
|
|
|
31891
32182
|
mode,
|
|
31892
32183
|
prompt,
|
|
31893
32184
|
workspace,
|
|
31894
|
-
signal: opts.signal
|
|
32185
|
+
signal: opts.signal,
|
|
32186
|
+
ignoreSessionDefaults: true
|
|
31895
32187
|
});
|
|
31896
32188
|
return {
|
|
31897
32189
|
text: r.text,
|
|
@@ -32011,10 +32303,11 @@ function isMcpGroup(s) {
|
|
|
32011
32303
|
* (handler.ts:handleToolsCallSSE). Claude Code's MCP HTTP client honors
|
|
32012
32304
|
* `text/event-stream` responses without applying the ~60s per-tool-call
|
|
32013
32305
|
* timer that previously broke xhigh on gpt-5.5 (~56s wall) and on
|
|
32014
|
-
* Anthropic Opus families (high+ thinking budgets). opus-critic
|
|
32015
|
-
*
|
|
32016
|
-
*
|
|
32017
|
-
*
|
|
32306
|
+
* Anthropic Opus families (high+ thinking budgets). opus-critic caps its
|
|
32307
|
+
* exposed effort at `high` (its effective model can fall back to
|
|
32308
|
+
* claude-opus-4-6, which doesn't advertise xhigh), so the SSE long-tail
|
|
32309
|
+
* concern there is moot; the SSE machinery still applies to the other
|
|
32310
|
+
* personas that do expose xhigh.
|
|
32018
32311
|
*/
|
|
32019
32312
|
const EFFORT_LEVELS = [
|
|
32020
32313
|
"low",
|
|
@@ -32147,7 +32440,7 @@ Reply format (markdown):
|
|
|
32147
32440
|
|
|
32148
32441
|
Resilience reminder:
|
|
32149
32442
|
If your session terminates abnormally before "Status: complete", the lead will retry once. On recovery, ask the lead to confirm what's already been done before re-applying changes — duplicate edits are worse than a slow restart.`;
|
|
32150
|
-
const OPUS_CRITIC_BASE = `You are opus-critic, a fresh-context same-lab adversarial reviewer running on Opus
|
|
32443
|
+
const OPUS_CRITIC_BASE = `You are opus-critic, a fresh-context same-lab adversarial reviewer running on Opus 5. The lead orchestrator that just delegated to you runs Opus-family context too, but you are NOT the lead. You did not see the lead's reasoning trace. You only see the brief.
|
|
32151
32444
|
|
|
32152
32445
|
Your job is to spot what the lead missed because of cognitive momentum, sunk-cost on a plan, or motivated reasoning toward a particular fix. Your blind-spot diversification is LIMITED compared to codex-critic (gpt-5.6-sol) and gemini-critic (gemini-3.1-pro), same lab, adjacent model family, related priors. Use that honestly: don't pretend to find a different perspective when the obvious read is "the lead got it right." Silence on good work is a valid and welcome answer.
|
|
32153
32446
|
|
|
@@ -32232,9 +32525,9 @@ const PERSONAS_READ = Object.freeze([
|
|
|
32232
32525
|
{
|
|
32233
32526
|
agentName: "opus-critic",
|
|
32234
32527
|
toolNameHttp: "opus_critic",
|
|
32235
|
-
model: "claude-opus-
|
|
32528
|
+
model: "claude-opus-5",
|
|
32236
32529
|
endpoint: "/v1/messages",
|
|
32237
|
-
description: "Adversarial same-lab critic backed by fresh-context Opus
|
|
32530
|
+
description: "Adversarial same-lab critic backed by fresh-context Opus 5, with limited blind-spot diversity compared with cross-lab critics. It reviews plans, designs, or code tradeoffs for cognitive momentum, sunk-cost reasoning, and confabulated assumptions, then returns a calibrated objection or no material objection. Use when a same-family sanity check can catch lead-context drift or when comparing against codex_critic / gemini_critic findings. Not a substitute for cross-lab review on security-sensitive or high-risk changes; use codex_critic or gemini_critic for stronger diversity. Runs with the full 1M-context Opus 5 window (native, no -1m sibling needed). Pass artifact verbatim.",
|
|
32238
32531
|
baseInstructions: OPUS_CRITIC_BASE,
|
|
32239
32532
|
agentPrompt: "",
|
|
32240
32533
|
writeCapable: false,
|
|
@@ -32383,7 +32676,7 @@ function buildPeerAwarenessSnippet(opts) {
|
|
|
32383
32676
|
criticList.push("`gemini_reviewer` (gemini-3.1-pro, line-level code review)");
|
|
32384
32677
|
criticList.push("`gemini_critic` (gemini-3.1-pro)");
|
|
32385
32678
|
}
|
|
32386
|
-
criticList.push("`opus_critic` (Opus
|
|
32679
|
+
criticList.push("`opus_critic` (Opus 5)");
|
|
32387
32680
|
const codexCliClause = opts.codexCli ? " `mcp__codex-cli__codex` dispatches to `codex-implementer` (gpt-5.3-codex with workspace-write) for end-to-end coding tasks." : "";
|
|
32388
32681
|
const para2Parts = [`\`mcp__${searchKey}__code\` is the one-stop code search (no extra model call). Its DEFAULT mode (or \`mode:"semantic"\`) ranks by MEANING via ColBERT over a per-workspace index, the first thing to reach for on intent/concept questions ("where is retry/backoff handled", "how does auth work"); when that index isn't ready it transparently falls back to lexical (the response \`source\` says which engine ran). Forced modes cover the rest: \`lexical\` (BM25F-ranked + tree-sitter, best for exact symbols), \`exact\`, \`regex\`, \`complete\` (exhaustive set), \`ast_pattern\`+\`ast_lang\` for multi-line AST shapes, \`scan\` for a whole-workspace symbol outline, \`multiline\` for cross-line regex. Multiple queries can run in a single turn. The index covers code-shaped files; for unstructured files (logs, \`.csv\`, \`.env*\`, config-only wiring), \`grep\`/\`glob\` still apply.`];
|
|
32389
32682
|
if (opts.workerToolsAvailable) para2Parts.push(`\`worker-*\` are background Agent subagents (subagent_type) that run the matching worker in its own context and deliver the result as a completion notification, so a long run never blocks the turn: \`worker-explore\` (read-only research), \`worker-review\` (reads the code to verify a change or claim), \`worker-plan\` (ordered implementation plan), \`worker-implement\` (edit/write/bash; ALWAYS runs in an isolated git worktree and returns the diff via a saved patch file; for in-place edits use the \`implementer\` subagent), \`worker-test\` (independent test author; also always worktree-isolated). The raw \`mcp__${workersKey}__*\` tools they call are guarded (a direct main-thread call is redirected to the matching agent); Workers themselves have \`code_search\`.`);
|
|
@@ -32460,6 +32753,15 @@ function formatWebSearchResult(results) {
|
|
|
32460
32753
|
const refsLine = results.references.map((r) => `- [${r.title}](${r.url})`).join("\n");
|
|
32461
32754
|
return `${results.content}\n\n## References\n${refsLine}`;
|
|
32462
32755
|
}
|
|
32756
|
+
/**
|
|
32757
|
+
* Model-override tier ladder surfaced on the read-heavy workers
|
|
32758
|
+
* (explore / implement / review). The caller picks a model by task weight;
|
|
32759
|
+
* all three tiers are 1M-context, and `high` is the recommended reasoning
|
|
32760
|
+
* depth for the ladder (flash tops out at high; sol/terra go higher if the
|
|
32761
|
+
* caller wants). Appended to those tools' `model` param description so the
|
|
32762
|
+
* lead has actionable override guidance instead of a bare free string.
|
|
32763
|
+
*/
|
|
32764
|
+
const WORKER_TIER_GUIDANCE = " Override by task weight: `gpt-5.6-sol` (heavy/deep), `gpt-5.6-terra` (moderate), `gemini-3.6-flash` (light/cheap) — all 1M context; pair with thinking:'high'.";
|
|
32463
32765
|
const NON_PERSONA_MCP_TOOLS = Object.freeze([
|
|
32464
32766
|
{
|
|
32465
32767
|
toolNameHttp: "web",
|
|
@@ -32647,11 +32949,84 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
|
|
|
32647
32949
|
}
|
|
32648
32950
|
}
|
|
32649
32951
|
},
|
|
32952
|
+
{
|
|
32953
|
+
toolNameHttp: "worker_defaults",
|
|
32954
|
+
group: "workers",
|
|
32955
|
+
capability: "worker",
|
|
32956
|
+
description: "Sets or clears process-wide worker model/reasoning defaults and returns the full effective table. Omit arguments to inspect current values. Per-call worker arguments still take precedence; values are in-memory and apply to every client served by this process.",
|
|
32957
|
+
inputSchema: {
|
|
32958
|
+
type: "object",
|
|
32959
|
+
additionalProperties: false,
|
|
32960
|
+
properties: {
|
|
32961
|
+
mode: {
|
|
32962
|
+
type: "string",
|
|
32963
|
+
enum: WORKER_MODES,
|
|
32964
|
+
description: "Worker mode to set or clear."
|
|
32965
|
+
},
|
|
32966
|
+
model: {
|
|
32967
|
+
type: "string",
|
|
32968
|
+
description: "Copilot catalog model id to use by default for the mode."
|
|
32969
|
+
},
|
|
32970
|
+
thinking: {
|
|
32971
|
+
type: "string",
|
|
32972
|
+
enum: WORKER_THINKING_LEVELS,
|
|
32973
|
+
description: "Requested default reasoning level; clamped per run for the selected model."
|
|
32974
|
+
},
|
|
32975
|
+
clear: {
|
|
32976
|
+
type: "boolean",
|
|
32977
|
+
description: "When true, clears both overrides for the selected mode."
|
|
32978
|
+
},
|
|
32979
|
+
clearAll: {
|
|
32980
|
+
type: "boolean",
|
|
32981
|
+
description: "When true, clears overrides for every worker mode."
|
|
32982
|
+
}
|
|
32983
|
+
}
|
|
32984
|
+
},
|
|
32985
|
+
async handler(args) {
|
|
32986
|
+
const mode = typeof args.mode === "string" && WORKER_MODES.includes(args.mode) ? args.mode : void 0;
|
|
32987
|
+
const model = typeof args.model === "string" ? args.model : void 0;
|
|
32988
|
+
const thinking = typeof args.thinking === "string" && WORKER_THINKING_LEVELS.includes(args.thinking) ? args.thinking : void 0;
|
|
32989
|
+
const clear = args.clear === true;
|
|
32990
|
+
const clearAll = args.clearAll === true;
|
|
32991
|
+
if (args.mode !== void 0 && mode === void 0 || args.model !== void 0 && model === void 0 || args.thinking !== void 0 && thinking === void 0 || args.clear !== void 0 && typeof args.clear !== "boolean" || args.clearAll !== void 0 && typeof args.clearAll !== "boolean" || clearAll && (mode !== void 0 || model !== void 0 || thinking !== void 0 || args.clear !== void 0) || clear && (mode === void 0 || model !== void 0 || thinking !== void 0) || !clearAll && !clear && (model !== void 0 || thinking !== void 0) && mode === void 0) return {
|
|
32992
|
+
content: [{
|
|
32993
|
+
type: "text",
|
|
32994
|
+
text: "worker_defaults: use mode with model/thinking or clear:true; clearAll:true must stand alone"
|
|
32995
|
+
}],
|
|
32996
|
+
isError: true
|
|
32997
|
+
};
|
|
32998
|
+
if (clearAll) resetAllWorkerSessionDefaults();
|
|
32999
|
+
else if (clear && mode) resetWorkerSessionDefault(mode);
|
|
33000
|
+
else if (mode && (model !== void 0 || thinking !== void 0)) {
|
|
33001
|
+
const current = resolveModeDefaults(mode);
|
|
33002
|
+
const validation = resolveModelAndThinking({
|
|
33003
|
+
model: model ?? current.model,
|
|
33004
|
+
thinking: thinking ?? current.thinking
|
|
33005
|
+
});
|
|
33006
|
+
if (!validation.ok) return {
|
|
33007
|
+
content: [{
|
|
33008
|
+
type: "text",
|
|
33009
|
+
text: validation.error
|
|
33010
|
+
}],
|
|
33011
|
+
isError: true
|
|
33012
|
+
};
|
|
33013
|
+
setWorkerSessionDefault(mode, {
|
|
33014
|
+
model,
|
|
33015
|
+
thinking
|
|
33016
|
+
});
|
|
33017
|
+
}
|
|
33018
|
+
const table = Object.fromEntries(WORKER_MODES.map((workerMode) => [workerMode, resolveModeDefaults(workerMode)]));
|
|
33019
|
+
return { content: [{
|
|
33020
|
+
type: "text",
|
|
33021
|
+
text: JSON.stringify(table)
|
|
33022
|
+
}] };
|
|
33023
|
+
}
|
|
33024
|
+
},
|
|
32650
33025
|
{
|
|
32651
33026
|
toolNameHttp: "explore",
|
|
32652
33027
|
group: "workers",
|
|
32653
33028
|
capability: "worker",
|
|
32654
|
-
description: "Runs as the background `worker-explore` agent. Dispatch via the Agent tool (subagent_type: worker-explore) so the turn is never blocked; the result arrives as a completion notification. Read-only investigation by an autonomous worker (Pi runtime; default model `
|
|
33029
|
+
description: "Runs as the background `worker-explore` agent. Dispatch via the Agent tool (subagent_type: worker-explore) so the turn is never blocked; the result arrives as a completion notification. Read-only investigation by an autonomous worker (Pi runtime; default model `gemini-3.6-flash` at high reasoning, override via the `model` arg with any Copilot-catalog model that advertises `tool_calls`). It has read, glob, grep, semantic-first code search, web search, fetch_url, advisor, update_plan, and read-only toolbelt tools, and it returns a single text answer. Use for bounded research, repo discovery, dependency investigation, or multi-file reading that would otherwise consume the lead context window. Not for implementation, test authoring, or verification of a concrete diff; use implement, test, or review for those scopes. Brief the investigation goal and constraints, not step-by-step tool semantics.",
|
|
32655
33030
|
inputSchema: {
|
|
32656
33031
|
type: "object",
|
|
32657
33032
|
required: ["prompt"],
|
|
@@ -32663,19 +33038,12 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
|
|
|
32663
33038
|
},
|
|
32664
33039
|
model: {
|
|
32665
33040
|
type: "string",
|
|
32666
|
-
description: "Optional Copilot catalog model id (defaults to
|
|
33041
|
+
description: "Optional Copilot catalog model id (defaults to gemini-3.6-flash). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch." + WORKER_TIER_GUIDANCE
|
|
32667
33042
|
},
|
|
32668
33043
|
thinking: {
|
|
32669
33044
|
type: "string",
|
|
32670
|
-
enum:
|
|
32671
|
-
|
|
32672
|
-
"minimal",
|
|
32673
|
-
"low",
|
|
32674
|
-
"medium",
|
|
32675
|
-
"high",
|
|
32676
|
-
"xhigh"
|
|
32677
|
-
],
|
|
32678
|
-
description: "Optional reasoning depth (default xhigh). Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
|
|
33045
|
+
enum: WORKER_THINKING_LEVELS,
|
|
33046
|
+
description: "Optional reasoning depth. Use worker_defaults to inspect the effective value. Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
|
|
32679
33047
|
},
|
|
32680
33048
|
workspace: {
|
|
32681
33049
|
type: "string",
|
|
@@ -32715,19 +33083,12 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
|
|
|
32715
33083
|
},
|
|
32716
33084
|
model: {
|
|
32717
33085
|
type: "string",
|
|
32718
|
-
description: "Optional Copilot catalog model id (defaults to gpt-5.6-sol). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch."
|
|
33086
|
+
description: "Optional Copilot catalog model id (defaults to gpt-5.6-sol). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch." + WORKER_TIER_GUIDANCE
|
|
32719
33087
|
},
|
|
32720
33088
|
thinking: {
|
|
32721
33089
|
type: "string",
|
|
32722
|
-
enum:
|
|
32723
|
-
|
|
32724
|
-
"minimal",
|
|
32725
|
-
"low",
|
|
32726
|
-
"medium",
|
|
32727
|
-
"high",
|
|
32728
|
-
"xhigh"
|
|
32729
|
-
],
|
|
32730
|
-
description: "Optional reasoning depth (default xhigh). Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
|
|
33090
|
+
enum: WORKER_THINKING_LEVELS,
|
|
33091
|
+
description: "Optional reasoning depth. Use worker_defaults to inspect the effective value. Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
|
|
32731
33092
|
},
|
|
32732
33093
|
workspace: {
|
|
32733
33094
|
type: "string",
|
|
@@ -32763,18 +33124,11 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
|
|
|
32763
33124
|
},
|
|
32764
33125
|
model: {
|
|
32765
33126
|
type: "string",
|
|
32766
|
-
description: "Optional Copilot catalog model id (defaults to gemini-3.1-pro-preview). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch."
|
|
33127
|
+
description: "Optional Copilot catalog model id (defaults to gemini-3.1-pro-preview). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch." + WORKER_TIER_GUIDANCE
|
|
32767
33128
|
},
|
|
32768
33129
|
thinking: {
|
|
32769
33130
|
type: "string",
|
|
32770
|
-
enum:
|
|
32771
|
-
"off",
|
|
32772
|
-
"minimal",
|
|
32773
|
-
"low",
|
|
32774
|
-
"medium",
|
|
32775
|
-
"high",
|
|
32776
|
-
"xhigh"
|
|
32777
|
-
],
|
|
33131
|
+
enum: WORKER_THINKING_LEVELS,
|
|
32778
33132
|
description: "Optional reasoning depth (defaults to xhigh, clamped to high for the default review model). Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
|
|
32779
33133
|
},
|
|
32780
33134
|
workspace: {
|
|
@@ -32799,7 +33153,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
|
|
|
32799
33153
|
toolNameHttp: "plan",
|
|
32800
33154
|
group: "workers",
|
|
32801
33155
|
capability: "worker",
|
|
32802
|
-
description: "Runs as the background `worker-plan` agent. Dispatch via the Agent tool (subagent_type: worker-plan) so the turn is never blocked; the result arrives as a completion notification. Read-only implementation planning by an autonomous worker (Pi runtime; default model `claude-opus-
|
|
33156
|
+
description: "Runs as the background `worker-plan` agent. Dispatch via the Agent tool (subagent_type: worker-plan) so the turn is never blocked; the result arrives as a completion notification. Read-only implementation planning by an autonomous worker (Pi runtime; default model `claude-opus-5` at xhigh reasoning, override via `model` with any Copilot-catalog model that advertises `tool_calls`). It has the same read-only toolset as explore and returns a concrete, ordered implementation plan covering files, approach, risks, and how acceptance criteria will be verified. Use before coding when the task needs repo-grounded sequencing or acceptance criteria translated into implementation steps. Not for editing files, running an implementation, writing tests, or adversarial review; use implement, test, or review for those scopes.",
|
|
32803
33157
|
inputSchema: {
|
|
32804
33158
|
type: "object",
|
|
32805
33159
|
required: ["prompt"],
|
|
@@ -32811,19 +33165,12 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
|
|
|
32811
33165
|
},
|
|
32812
33166
|
model: {
|
|
32813
33167
|
type: "string",
|
|
32814
|
-
description: "Optional Copilot catalog model id (defaults to claude-opus-
|
|
33168
|
+
description: "Optional Copilot catalog model id (defaults to claude-opus-5). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch."
|
|
32815
33169
|
},
|
|
32816
33170
|
thinking: {
|
|
32817
33171
|
type: "string",
|
|
32818
|
-
enum:
|
|
32819
|
-
|
|
32820
|
-
"minimal",
|
|
32821
|
-
"low",
|
|
32822
|
-
"medium",
|
|
32823
|
-
"high",
|
|
32824
|
-
"xhigh"
|
|
32825
|
-
],
|
|
32826
|
-
description: "Optional reasoning depth (default xhigh). Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
|
|
33172
|
+
enum: WORKER_THINKING_LEVELS,
|
|
33173
|
+
description: "Optional reasoning depth. Use worker_defaults to inspect the effective value. Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
|
|
32827
33174
|
},
|
|
32828
33175
|
workspace: {
|
|
32829
33176
|
type: "string",
|
|
@@ -32867,15 +33214,8 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
|
|
|
32867
33214
|
},
|
|
32868
33215
|
thinking: {
|
|
32869
33216
|
type: "string",
|
|
32870
|
-
enum:
|
|
32871
|
-
|
|
32872
|
-
"minimal",
|
|
32873
|
-
"low",
|
|
32874
|
-
"medium",
|
|
32875
|
-
"high",
|
|
32876
|
-
"xhigh"
|
|
32877
|
-
],
|
|
32878
|
-
description: "Optional reasoning depth (default xhigh). Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
|
|
33217
|
+
enum: WORKER_THINKING_LEVELS,
|
|
33218
|
+
description: "Optional reasoning depth. Use worker_defaults to inspect the effective value. Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
|
|
32879
33219
|
},
|
|
32880
33220
|
workspace: {
|
|
32881
33221
|
type: "string",
|
|
@@ -33248,14 +33588,7 @@ async function runWorkerToolCall(call) {
|
|
|
33248
33588
|
isError: true
|
|
33249
33589
|
};
|
|
33250
33590
|
const thinkingRaw = args.thinking;
|
|
33251
|
-
const ALLOWED_THINKING =
|
|
33252
|
-
"off",
|
|
33253
|
-
"minimal",
|
|
33254
|
-
"low",
|
|
33255
|
-
"medium",
|
|
33256
|
-
"high",
|
|
33257
|
-
"xhigh"
|
|
33258
|
-
];
|
|
33591
|
+
const ALLOWED_THINKING = WORKER_THINKING_LEVELS;
|
|
33259
33592
|
let thinking;
|
|
33260
33593
|
if (thinkingRaw !== void 0) {
|
|
33261
33594
|
if (typeof thinkingRaw !== "string" || !ALLOWED_THINKING.includes(thinkingRaw)) return {
|
|
@@ -33568,5 +33901,5 @@ function enumerateInjectedMcpToolNames(groupKeys, opts = {}) {
|
|
|
33568
33901
|
}
|
|
33569
33902
|
|
|
33570
33903
|
//#endregion
|
|
33571
|
-
export {
|
|
33572
|
-
//# sourceMappingURL=peer-mcp-personas-
|
|
33904
|
+
export { searchWeb as $, UPSTREAM_INACTIVITY_TIMEOUT_MS as $t, trustRepo as A, createResponses as At, TEST_DEFAULT_MODEL as B, CONDENSED_OPERATING_SEQUENCE as Bt, fileLastPromptStore as C, copilotHeaders as Cn, shimDefaultsToXhigh as Ct, repoRoot as D, assembleResponsesPayload as Dt, repoFingerprint as E, getTokenCount as Et, EXPLORE_DEFAULT_MODEL as F, provisionBrowserAssets as Ft, buildEnv as G, buildWorkspaceHeaderJson as Gt, resolveModeDefaults as H, shouldUseInsecureTls as Ht, EXPLORE_DEFAULT_THINKING as I, hasSupportedBrowserInstalled as It, toolbeltEnabled as J, DEFAULT_CLAUDE_MODEL_FALLBACKS as Jt, availableToolCommands as K, collapsePathKeys as Kt, IMPLEMENT_DEFAULT_MODEL as L, provisionAndIndexColbert as Lt, resolveSealedGate as M, MAX_RESPONSE_BODY_BYTES as Mt, BROWSE_DEFAULT_MODEL as N, readResponseBodyCapped as Nt, stopGateEnabledForRepo as O, resolveMcpToolTimeoutMs as Ot, DEFAULT_MODEL as P, parseJsonOrDiagnose as Pt, assetFor as Q, UPSTREAM_FETCH_TIMEOUT_MS as Qt, PLAN_DEFAULT_MODEL as R, extractTarGzMember as Rt, fileFindingsStore as S, copilotBaseUrl as Sn, workerToolsEnabled as St, isSubagentContext as T, state as Tn, createMessages as Tt, resolveWorkerRunOpts as U, ArtifactClient as Ut, appendPlanReminder as V, DEFINITION_OF_GREATNESS as Vt, runWorkerAgent as W, buildWorkspaceHeaderHelperCommand as Wt, vscodeRipgrepPath as X, DEFAULT_CODEX_MODEL_FALLBACKS as Xt, toolbeltSkipSet as Y, DEFAULT_CODEX_MODEL as Yt, TOOLBELT_TOOLS$1 as Z, DEFAULT_PORT as Zt, stopGateDisabled as _, getGitHubUser as _n, browserToolsEnabled as _t, buildPeerAwarenessSnippet as a, setupGitHubAgentToken as an, buildAnthropicErrorEvent as at, stopReviewEnabled as b, forwardError as bn, nativeSubagentModel as bt, personasFor as c, cacheCopilotVersion as cn, logStreamError as ct, buildStopHookCommand as d, filterBetaHeader as dn, handleMcpDelete as dt, generateRandomPort as en, ADVISOR_INTERNAL_TOOL_NAME as et, captureLaunchBaseline as f, isNullish as fn, handleMcpPost as ft, launchBaselineKey as g, getModels as gn, browserCompoundToolsEnabled as gt, injectStopHookIntoSettingsFile as h, sleep as hn, browseAgentEnabled as ht, buildAgentPrompt as i, setupCopilotToken as in, isAdvisorRequested as it, liveExec as j, createChatCompletions as jt, stopReviewStateDir as k, pickEndpoint as kt, buildArtifactOpenHookCommand as l, cacheModels as ln, readIteratorWithTimeout as lt, fileBlockBudget as m, resolveModel as mn, artifactToolsEnabled as mt, MCP_GROUPS as n, getPackageVersion as nn, buildAdvisorStream as nt, buildPeerAwarenessSummary as o, setupGitHubToken as on, buildOpenAIErrorEvent as ot, decideStopHook as p, resolveCodexModel as pn, agentToolsEnabled as pt, buildToolbeltAwareness as q, toolbeltPathOverride as qt, assertMcpToolSurfaceConsistent as r, withInstallLock as rn, injectAdvisorTool as rt, enumerateInjectedMcpToolNames as s, tryRefreshAndRetry as sn, isControllerClosedError as st, GROUP_META as t, pickClaudeDefault as tn, ADVISOR_TOOL_INSTRUCTIONS as tt, buildSessionBindHookCommand as u, cacheVSCodeVersion as un, relayAnthropicStream as ut, stopGateId as v, fetchWithTransientRetry as vn, fleetToolsEnabled as vt, fileReviewDebounce as w, githubHeaders as wn, countTokens as wt, fileBaselineStore as x, GITHUB_API_BASE_URL as xn, standInToolEnabled as xt, stopGatePlanMode as y, HTTPError as yn, geminiAvailable as yt, REVIEW_DEFAULT_MODEL as z, extractZipMember as zt };
|
|
33905
|
+
//# sourceMappingURL=peer-mcp-personas-A6PytLD6.js.map
|