github-router 0.3.153 → 0.3.162
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-ext/manifest.json +1 -1
- package/dist/engine-DHFa2_hK.js +6 -0
- package/dist/{lifecycle-CbcVnn0e.js → lifecycle-BAug_A5A.js} +2 -2
- package/dist/{lifecycle-C4k0pEvn.js → lifecycle-BUXxiltc.js} +2 -2
- package/dist/{lifecycle-C4k0pEvn.js.map → lifecycle-BUXxiltc.js.map} +1 -1
- package/dist/{lifecycle-VTQI28wT.js → lifecycle-ChPBRt6K.js} +2 -2
- package/dist/{lifecycle-VTQI28wT.js.map → lifecycle-ChPBRt6K.js.map} +1 -1
- package/dist/{lifecycle-CsxCFx1b.js → lifecycle-L7Y7RJl4.js} +2 -2
- package/dist/main.js +1807 -234
- package/dist/main.js.map +1 -1
- package/dist/{paths-Bt7sqiVr.js → paths-CTlT1nTo.js} +6 -3
- package/dist/paths-CTlT1nTo.js.map +1 -0
- package/dist/{paths-C9Nkr_NK.js → paths-DN3O54iE.js} +1 -1
- package/dist/{peer-mcp-personas-DMM1akDa.js → peer-mcp-personas-Bfq3FPKc.js} +373 -105
- package/dist/peer-mcp-personas-Bfq3FPKc.js.map +1 -0
- package/package.json +1 -1
- package/dist/engine-BP5EnZ-n.js +0 -6
- package/dist/paths-Bt7sqiVr.js.map +0 -1
- package/dist/peer-mcp-personas-DMM1akDa.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as PATHS } from "./paths-
|
|
2
|
-
import { d as runCommandCapture, l as parseBoolEnv, n as isPidAlive, o as trackChild, p as runManagedExeCapture, r as registerColbertExitHandlers, t as getColbertInstanceUuid, u as resolveExecutable } from "./lifecycle-
|
|
3
|
-
import { i as registerExitHandlers, n as getInstanceUuid, r as recordWorkerRepo, t as WorktreeRegistry } from "./lifecycle-
|
|
1
|
+
import { t as PATHS } from "./paths-CTlT1nTo.js";
|
|
2
|
+
import { d as runCommandCapture, l as parseBoolEnv, n as isPidAlive, o as trackChild, p as runManagedExeCapture, r as registerColbertExitHandlers, t as getColbertInstanceUuid, u as resolveExecutable } from "./lifecycle-ChPBRt6K.js";
|
|
3
|
+
import { i as registerExitHandlers, n as getInstanceUuid, r as recordWorkerRepo, t as WorktreeRegistry } from "./lifecycle-BUXxiltc.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import consola from "consola";
|
|
6
6
|
import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
@@ -12858,7 +12858,7 @@ function logAudit$1(record) {
|
|
|
12858
12858
|
try {
|
|
12859
12859
|
const fs$2 = await import("node:fs/promises");
|
|
12860
12860
|
const path$1 = await import("node:path");
|
|
12861
|
-
const { PATHS: PATHS$1 } = await import("./paths-
|
|
12861
|
+
const { PATHS: PATHS$1 } = await import("./paths-DN3O54iE.js");
|
|
12862
12862
|
const dir = path$1.join(PATHS$1.APP_DIR, "browser-mcp");
|
|
12863
12863
|
await fs$2.mkdir(dir, { recursive: true });
|
|
12864
12864
|
const line = JSON.stringify({
|
|
@@ -16818,7 +16818,7 @@ const runtimeBuffer = globalThis.Buffer;
|
|
|
16818
16818
|
//#endregion
|
|
16819
16819
|
//#region src/lib/worker-agent/budget.ts
|
|
16820
16820
|
const DEFAULT_MAX_TURNS = 500;
|
|
16821
|
-
const DEFAULT_MAX_WALLCLOCK_MS =
|
|
16821
|
+
const DEFAULT_MAX_WALLCLOCK_MS = 360 * 6e4;
|
|
16822
16822
|
const DEFAULT_MAX_TOOL_BYTES = 16 * 1024 * 1024;
|
|
16823
16823
|
const DEFAULT_MAX_TOOL_CALLS = 250;
|
|
16824
16824
|
const DEFAULT_MAX_REPEATED_CALLS = 3;
|
|
@@ -16850,6 +16850,44 @@ function envInt(name) {
|
|
|
16850
16850
|
return n;
|
|
16851
16851
|
}
|
|
16852
16852
|
/**
|
|
16853
|
+
* Default MCP per-tool-call timeout the launcher injects as
|
|
16854
|
+
* `MCP_TIMEOUT` / `MCP_TOOL_TIMEOUT` (see `server-setup.ts`). 6h15m —
|
|
16855
|
+
* one `MCP_TIMEOUT_HEADROOM_MS` above the 6h worker wall-clock default so a
|
|
16856
|
+
* non-converging worker aborts gracefully (partial work + `[halted:
|
|
16857
|
+
* wallclock]`) a full headroom before the harness hard-kills the call.
|
|
16858
|
+
*/
|
|
16859
|
+
const DEFAULT_MCP_TOOL_TIMEOUT_MS = 225e5;
|
|
16860
|
+
/**
|
|
16861
|
+
* Teardown headroom between the worker wall-clock ceiling and the MCP
|
|
16862
|
+
* per-tool-call timeout — the graceful-abort + result-delivery budget. The
|
|
16863
|
+
* worker wall-clock (default AND any per-call override) is clamped to
|
|
16864
|
+
* `MCP_TOOL_TIMEOUT − MCP_TIMEOUT_HEADROOM_MS` so a worker is never silently
|
|
16865
|
+
* hard-killed by the harness.
|
|
16866
|
+
*/
|
|
16867
|
+
const MCP_TIMEOUT_HEADROOM_MS = 15 * 6e4;
|
|
16868
|
+
/**
|
|
16869
|
+
* The MCP per-tool-call timeout the proxy injects into the spawned CLI, in ms.
|
|
16870
|
+
* Positive-integer override via `GH_ROUTER_MCP_TOOL_TIMEOUT_MS`; falls back to
|
|
16871
|
+
* `DEFAULT_MCP_TOOL_TIMEOUT_MS` on unset/garbage input (same lenient parse as
|
|
16872
|
+
* the worker-budget env overrides). Single source of truth for both
|
|
16873
|
+
* `server-setup.ts` (which stringifies it into the child env) and the worker
|
|
16874
|
+
* MCP boundary (which clamps a per-call wall-clock under it).
|
|
16875
|
+
*/
|
|
16876
|
+
function resolveMcpToolTimeoutMs() {
|
|
16877
|
+
return envInt("GH_ROUTER_MCP_TOOL_TIMEOUT_MS") ?? DEFAULT_MCP_TOOL_TIMEOUT_MS;
|
|
16878
|
+
}
|
|
16879
|
+
/**
|
|
16880
|
+
* The maximum wall-clock a single worker call may be granted: the MCP
|
|
16881
|
+
* tool-call timeout minus the teardown headroom. A per-call `maxWallClockMs`
|
|
16882
|
+
* override above this is clamped down to it (see `runWorkerToolCall`) so the
|
|
16883
|
+
* worker always aborts gracefully at least `MCP_TIMEOUT_HEADROOM_MS` before the
|
|
16884
|
+
* harness would hard-kill the MCP call. The 6h default equals this ceiling on
|
|
16885
|
+
* the default MCP timeout (22_500_000 − 900_000 === 21_600_000).
|
|
16886
|
+
*/
|
|
16887
|
+
function workerWallClockCeilingMs() {
|
|
16888
|
+
return resolveMcpToolTimeoutMs() - MCP_TIMEOUT_HEADROOM_MS;
|
|
16889
|
+
}
|
|
16890
|
+
/**
|
|
16853
16891
|
* Resolve a `BudgetConfig` from defaults + env overrides + caller-
|
|
16854
16892
|
* supplied overrides. Caller overrides win; env wins over defaults.
|
|
16855
16893
|
*
|
|
@@ -17330,6 +17368,148 @@ async function acquireWorkerSlot(signal) {
|
|
|
17330
17368
|
};
|
|
17331
17369
|
}
|
|
17332
17370
|
|
|
17371
|
+
//#endregion
|
|
17372
|
+
//#region src/services/copilot/responses-request.ts
|
|
17373
|
+
/**
|
|
17374
|
+
* Copilot's `/responses` endpoint rejects a positive `max_output_tokens` below
|
|
17375
|
+
* 16 with an HTTP 400 (verified live on gpt-5.5 and gpt-5.3-codex):
|
|
17376
|
+
* Invalid 'max_output_tokens': integer below minimum value. Expected a value
|
|
17377
|
+
* >= 16, but got 1 instead.
|
|
17378
|
+
* Anthropic's `/v1/messages` allows any `max_tokens >= 1`, so a valid low
|
|
17379
|
+
* Anthropic request (`max_tokens` 1..15) would otherwise 400 on the Responses
|
|
17380
|
+
* path. Clamp a positive sub-16 value UP to this minimum; leave `undefined`
|
|
17381
|
+
* and normal (>= 16) values EXACTLY as-is so the worker hot path and all
|
|
17382
|
+
* normal requests stay byte-identical. The chat path has NO such minimum
|
|
17383
|
+
* (gemini / `/chat/completions` accepts small values, verified HTTP 200), so
|
|
17384
|
+
* this clamp lives only here, never in `chat-request.ts`.
|
|
17385
|
+
*/
|
|
17386
|
+
const RESPONSES_MIN_MAX_OUTPUT_TOKENS = 16;
|
|
17387
|
+
/** Build the `data:` URI (base64) or return the verbatim URL for an image part. */
|
|
17388
|
+
function imageUrlFor(part) {
|
|
17389
|
+
if (typeof part.url === "string" && part.url.length > 0) return part.url;
|
|
17390
|
+
return `data:${part.mimeType ?? "image/png"};base64,${part.data ?? ""}`;
|
|
17391
|
+
}
|
|
17392
|
+
/**
|
|
17393
|
+
* Map a document part to a Responses `input_file` item. A base64 document is
|
|
17394
|
+
* wrapped into a `data:<mime>;base64,<data>` `file_data` URI (the verified-working
|
|
17395
|
+
* Copilot shape — gpt-5.5 reads it); a URL document carries `file_url`. Returns
|
|
17396
|
+
* null when neither source is present (malformed) so it's dropped, not emitted
|
|
17397
|
+
* as an invalid item.
|
|
17398
|
+
*/
|
|
17399
|
+
function documentInputFile(part) {
|
|
17400
|
+
const filename = part.filename ?? "document.pdf";
|
|
17401
|
+
if (typeof part.data === "string" && part.data.length > 0) return {
|
|
17402
|
+
type: "input_file",
|
|
17403
|
+
filename,
|
|
17404
|
+
file_data: `data:${part.mimeType ?? "application/pdf"};base64,${part.data}`
|
|
17405
|
+
};
|
|
17406
|
+
if (typeof part.url === "string" && part.url.length > 0) return {
|
|
17407
|
+
type: "input_file",
|
|
17408
|
+
filename,
|
|
17409
|
+
file_url: part.url
|
|
17410
|
+
};
|
|
17411
|
+
return null;
|
|
17412
|
+
}
|
|
17413
|
+
function joinText(parts) {
|
|
17414
|
+
let s = "";
|
|
17415
|
+
for (const p of parts) if (p.type === "text") s += p.text;
|
|
17416
|
+
return s;
|
|
17417
|
+
}
|
|
17418
|
+
function neutralUserToResponses(m) {
|
|
17419
|
+
if (typeof m.content === "string") return [{
|
|
17420
|
+
role: "user",
|
|
17421
|
+
content: m.content
|
|
17422
|
+
}];
|
|
17423
|
+
if (!m.content.some((c) => c.type === "image" || c.type === "document")) return [{
|
|
17424
|
+
role: "user",
|
|
17425
|
+
content: joinText(m.content)
|
|
17426
|
+
}];
|
|
17427
|
+
const parts = [];
|
|
17428
|
+
for (const c of m.content) if (c.type === "text") parts.push({
|
|
17429
|
+
type: "input_text",
|
|
17430
|
+
text: c.text
|
|
17431
|
+
});
|
|
17432
|
+
else if (c.type === "image") parts.push({
|
|
17433
|
+
type: "input_image",
|
|
17434
|
+
image_url: imageUrlFor(c)
|
|
17435
|
+
});
|
|
17436
|
+
else if (c.type === "document") {
|
|
17437
|
+
const item = documentInputFile(c);
|
|
17438
|
+
if (item) parts.push(item);
|
|
17439
|
+
}
|
|
17440
|
+
return [{
|
|
17441
|
+
role: "user",
|
|
17442
|
+
content: parts
|
|
17443
|
+
}];
|
|
17444
|
+
}
|
|
17445
|
+
function neutralAssistantToResponses(m) {
|
|
17446
|
+
const items = [];
|
|
17447
|
+
let buffer = "";
|
|
17448
|
+
const flush = () => {
|
|
17449
|
+
if (buffer.length === 0) return;
|
|
17450
|
+
items.push({
|
|
17451
|
+
role: "assistant",
|
|
17452
|
+
content: [{
|
|
17453
|
+
type: "output_text",
|
|
17454
|
+
text: buffer
|
|
17455
|
+
}]
|
|
17456
|
+
});
|
|
17457
|
+
buffer = "";
|
|
17458
|
+
};
|
|
17459
|
+
for (const c of m.content) if (c.type === "text") buffer += c.text;
|
|
17460
|
+
else if (c.type === "toolCall") {
|
|
17461
|
+
flush();
|
|
17462
|
+
items.push({
|
|
17463
|
+
type: "function_call",
|
|
17464
|
+
call_id: c.id,
|
|
17465
|
+
name: c.name,
|
|
17466
|
+
arguments: JSON.stringify(c.arguments ?? {})
|
|
17467
|
+
});
|
|
17468
|
+
}
|
|
17469
|
+
flush();
|
|
17470
|
+
return items;
|
|
17471
|
+
}
|
|
17472
|
+
/** Translate one neutral message into zero-or-more Responses input items. */
|
|
17473
|
+
function neutralMessageToResponsesInput(m) {
|
|
17474
|
+
if (m.role === "user") return neutralUserToResponses(m);
|
|
17475
|
+
if (m.role === "assistant") return neutralAssistantToResponses(m);
|
|
17476
|
+
return [{
|
|
17477
|
+
type: "function_call_output",
|
|
17478
|
+
call_id: m.toolCallId,
|
|
17479
|
+
output: m.output
|
|
17480
|
+
}];
|
|
17481
|
+
}
|
|
17482
|
+
function neutralToolsToResponses(tools) {
|
|
17483
|
+
if (!tools || tools.length === 0) return void 0;
|
|
17484
|
+
return tools.map((t) => ({
|
|
17485
|
+
type: "function",
|
|
17486
|
+
name: t.name,
|
|
17487
|
+
description: t.description,
|
|
17488
|
+
parameters: t.parameters
|
|
17489
|
+
}));
|
|
17490
|
+
}
|
|
17491
|
+
/** Assemble the full Responses payload from the neutral request shape. */
|
|
17492
|
+
function assembleResponsesPayload(opts) {
|
|
17493
|
+
const input = [];
|
|
17494
|
+
for (const m of opts.messages) for (const item of neutralMessageToResponsesInput(m)) input.push(item);
|
|
17495
|
+
const payload = {
|
|
17496
|
+
model: opts.model,
|
|
17497
|
+
input,
|
|
17498
|
+
stream: opts.stream
|
|
17499
|
+
};
|
|
17500
|
+
if (opts.instructions) payload.instructions = opts.instructions;
|
|
17501
|
+
const tools = neutralToolsToResponses(opts.tools);
|
|
17502
|
+
if (tools && tools.length > 0) {
|
|
17503
|
+
payload.tools = tools;
|
|
17504
|
+
payload.tool_choice = opts.toolChoice ?? "auto";
|
|
17505
|
+
}
|
|
17506
|
+
if (opts.reasoningEffort && opts.reasoningEffort !== "off") payload.reasoning = { effort: opts.reasoningEffort };
|
|
17507
|
+
if (typeof opts.maxOutputTokens === "number" && opts.maxOutputTokens > 0) payload.max_output_tokens = Math.max(opts.maxOutputTokens, RESPONSES_MIN_MAX_OUTPUT_TOKENS);
|
|
17508
|
+
if (opts.stopSequences && opts.stopSequences.length > 0) payload.stop = [...opts.stopSequences];
|
|
17509
|
+
if (opts.parallelToolCalls === false) payload.parallel_tool_calls = false;
|
|
17510
|
+
return payload;
|
|
17511
|
+
}
|
|
17512
|
+
|
|
17333
17513
|
//#endregion
|
|
17334
17514
|
//#region src/lib/worker-agent/context-budget.ts
|
|
17335
17515
|
/**
|
|
@@ -17943,86 +18123,68 @@ async function runResponsesStreamLoop(stream, context, opts, options) {
|
|
|
17943
18123
|
});
|
|
17944
18124
|
}
|
|
17945
18125
|
function buildResponsesPayload(context, resolved) {
|
|
17946
|
-
const
|
|
17947
|
-
for (const m of context.messages)
|
|
17948
|
-
|
|
18126
|
+
const messages = [];
|
|
18127
|
+
for (const m of context.messages) {
|
|
18128
|
+
const neutral = piMessageToNeutral(m);
|
|
18129
|
+
if (neutral) messages.push(neutral);
|
|
18130
|
+
}
|
|
18131
|
+
return assembleResponsesPayload({
|
|
17949
18132
|
model: resolved.modelId,
|
|
17950
|
-
|
|
18133
|
+
instructions: context.systemPrompt || void 0,
|
|
18134
|
+
messages,
|
|
18135
|
+
tools: piToolsToNeutral(context.tools),
|
|
18136
|
+
reasoningEffort: resolved.thinking,
|
|
17951
18137
|
stream: true
|
|
17952
|
-
};
|
|
17953
|
-
if (context.systemPrompt) payload.instructions = context.systemPrompt;
|
|
17954
|
-
const tools = translateToolsToResponses(context.tools);
|
|
17955
|
-
if (tools && tools.length > 0) {
|
|
17956
|
-
payload.tools = tools;
|
|
17957
|
-
payload.tool_choice = "auto";
|
|
17958
|
-
}
|
|
17959
|
-
if (resolved.thinking !== "off") payload.reasoning = { effort: resolved.thinking };
|
|
17960
|
-
return payload;
|
|
17961
|
-
}
|
|
17962
|
-
function translateMessageToResponses(m) {
|
|
17963
|
-
if (m.role === "user") return translateUserToResponses(m);
|
|
17964
|
-
if (m.role === "assistant") return translateAssistantToResponses(m);
|
|
17965
|
-
if (m.role === "toolResult") return [{
|
|
17966
|
-
type: "function_call_output",
|
|
17967
|
-
call_id: m.toolCallId,
|
|
17968
|
-
output: joinTextParts(m.content)
|
|
17969
|
-
}];
|
|
17970
|
-
return [];
|
|
17971
|
-
}
|
|
17972
|
-
function translateUserToResponses(m) {
|
|
17973
|
-
if (typeof m.content === "string") return [{
|
|
17974
|
-
role: "user",
|
|
17975
|
-
content: m.content
|
|
17976
|
-
}];
|
|
17977
|
-
if (!m.content.some((c) => c.type === "image")) return [{
|
|
17978
|
-
role: "user",
|
|
17979
|
-
content: joinTextParts(m.content)
|
|
17980
|
-
}];
|
|
17981
|
-
const parts = [];
|
|
17982
|
-
for (const c of m.content) if (c.type === "text") parts.push({
|
|
17983
|
-
type: "input_text",
|
|
17984
|
-
text: c.text
|
|
17985
|
-
});
|
|
17986
|
-
else if (c.type === "image") parts.push({
|
|
17987
|
-
type: "input_image",
|
|
17988
|
-
image_url: `data:${c.mimeType};base64,${c.data}`
|
|
17989
18138
|
});
|
|
17990
|
-
return [{
|
|
17991
|
-
role: "user",
|
|
17992
|
-
content: parts
|
|
17993
|
-
}];
|
|
17994
18139
|
}
|
|
17995
|
-
function
|
|
17996
|
-
|
|
17997
|
-
|
|
17998
|
-
|
|
17999
|
-
|
|
18000
|
-
|
|
18001
|
-
|
|
18002
|
-
|
|
18003
|
-
|
|
18004
|
-
|
|
18005
|
-
}]
|
|
18140
|
+
function piMessageToNeutral(m) {
|
|
18141
|
+
if (m.role === "user") {
|
|
18142
|
+
if (typeof m.content === "string") return {
|
|
18143
|
+
role: "user",
|
|
18144
|
+
content: m.content
|
|
18145
|
+
};
|
|
18146
|
+
const parts = [];
|
|
18147
|
+
for (const c of m.content) if (c.type === "text") parts.push({
|
|
18148
|
+
type: "text",
|
|
18149
|
+
text: c.text
|
|
18006
18150
|
});
|
|
18007
|
-
|
|
18008
|
-
|
|
18009
|
-
|
|
18010
|
-
|
|
18011
|
-
|
|
18012
|
-
|
|
18013
|
-
|
|
18014
|
-
|
|
18151
|
+
else if (c.type === "image") parts.push({
|
|
18152
|
+
type: "image",
|
|
18153
|
+
mimeType: c.mimeType,
|
|
18154
|
+
data: c.data
|
|
18155
|
+
});
|
|
18156
|
+
return {
|
|
18157
|
+
role: "user",
|
|
18158
|
+
content: parts
|
|
18159
|
+
};
|
|
18160
|
+
}
|
|
18161
|
+
if (m.role === "assistant") {
|
|
18162
|
+
const parts = [];
|
|
18163
|
+
for (const c of m.content) if (c.type === "text") parts.push({
|
|
18164
|
+
type: "text",
|
|
18165
|
+
text: c.text
|
|
18166
|
+
});
|
|
18167
|
+
else if (c.type === "toolCall") parts.push({
|
|
18168
|
+
type: "toolCall",
|
|
18169
|
+
id: c.id,
|
|
18015
18170
|
name: c.name,
|
|
18016
|
-
arguments:
|
|
18171
|
+
arguments: c.arguments
|
|
18017
18172
|
});
|
|
18173
|
+
return {
|
|
18174
|
+
role: "assistant",
|
|
18175
|
+
content: parts
|
|
18176
|
+
};
|
|
18018
18177
|
}
|
|
18019
|
-
|
|
18020
|
-
|
|
18178
|
+
if (m.role === "toolResult") return {
|
|
18179
|
+
role: "toolResult",
|
|
18180
|
+
toolCallId: m.toolCallId,
|
|
18181
|
+
output: joinTextParts(m.content)
|
|
18182
|
+
};
|
|
18183
|
+
return null;
|
|
18021
18184
|
}
|
|
18022
|
-
function
|
|
18185
|
+
function piToolsToNeutral(tools) {
|
|
18023
18186
|
if (!tools || tools.length === 0) return void 0;
|
|
18024
18187
|
return tools.map((t) => ({
|
|
18025
|
-
type: "function",
|
|
18026
18188
|
name: t.name,
|
|
18027
18189
|
description: t.description,
|
|
18028
18190
|
parameters: t.parameters
|
|
@@ -19301,6 +19463,15 @@ function standInToolEnabled() {
|
|
|
19301
19463
|
const hasGeminiPro = models.some((m) => /^gemini-3\..*pro/i.test(m.id));
|
|
19302
19464
|
return hasGpt55 && hasOpus && hasGeminiPro;
|
|
19303
19465
|
}
|
|
19466
|
+
const IMPLEMENTER_SUBAGENT_MODEL = "gpt-5.5";
|
|
19467
|
+
/** Return the native implementer subagent model iff it is live with tool calls. */
|
|
19468
|
+
function implementerSubagentModel() {
|
|
19469
|
+
const models = state.models?.data;
|
|
19470
|
+
if (!models) return void 0;
|
|
19471
|
+
const found = models.find((m) => m.id === IMPLEMENTER_SUBAGENT_MODEL);
|
|
19472
|
+
if (!found) return void 0;
|
|
19473
|
+
return found.capabilities?.supports?.tool_calls === true ? IMPLEMENTER_SUBAGENT_MODEL : void 0;
|
|
19474
|
+
}
|
|
19304
19475
|
/**
|
|
19305
19476
|
* Gate for the worker tools (`explore`, `review`, `implement`).
|
|
19306
19477
|
*
|
|
@@ -23252,7 +23423,16 @@ async function createWorktree(workspaceAbs, opts) {
|
|
|
23252
23423
|
])).stdout;
|
|
23253
23424
|
} catch {}
|
|
23254
23425
|
const lineCount = stat$1.split(/\r?\n/).filter((l) => l.length > 0).length;
|
|
23255
|
-
|
|
23426
|
+
const summary = `[diff truncated at 256KB; ${Math.max(0, lineCount - 1)} files changed]\n${stat$1}`;
|
|
23427
|
+
let savedPath = null;
|
|
23428
|
+
let saveError = null;
|
|
23429
|
+
try {
|
|
23430
|
+
savedPath = await saveOverflowPatch(dir);
|
|
23431
|
+
} catch (err) {
|
|
23432
|
+
saveError = err.message;
|
|
23433
|
+
}
|
|
23434
|
+
if (savedPath !== null) return `${summary}\nFull patch (git apply-able; includes binary blobs) saved to: ${savedPath}`;
|
|
23435
|
+
return `${summary}\n[full patch save failed: ${saveError ?? "unknown"}; only the summary above is available]`;
|
|
23256
23436
|
};
|
|
23257
23437
|
return {
|
|
23258
23438
|
dir,
|
|
@@ -23261,6 +23441,43 @@ async function createWorktree(workspaceAbs, opts) {
|
|
|
23261
23441
|
remove
|
|
23262
23442
|
};
|
|
23263
23443
|
}
|
|
23444
|
+
/**
|
|
23445
|
+
* Persist the FULL `git diff --binary --full-index HEAD` of `dir` to a
|
|
23446
|
+
* durable, router-owned file under `PATHS.WORKER_DIFFS_DIR` and return its
|
|
23447
|
+
* absolute path.
|
|
23448
|
+
*
|
|
23449
|
+
* Called by `finalize()` ONLY when the inline diff overflows
|
|
23450
|
+
* `DIFF_CAP_BYTES`: the worktree is removed immediately after finalize, so a
|
|
23451
|
+
* truncated inline diff would otherwise lose the actual patch forever. The
|
|
23452
|
+
* durable dir lives under the app dir — never inside the worktree (deleted)
|
|
23453
|
+
* nor the user's repo (don't pollute it).
|
|
23454
|
+
*
|
|
23455
|
+
* `--binary` keeps binary blobs recoverable (git base85-encodes them into
|
|
23456
|
+
* the patch) and `--full-index` writes exact 40-char object indexes, so the
|
|
23457
|
+
* saved patch reconstructs the change precisely under `git apply`. Uses the
|
|
23458
|
+
* same `execFileP` git mechanism the rest of `finalize()` uses (shell:false).
|
|
23459
|
+
*
|
|
23460
|
+
* Unique filename `<pid>-<8hex>.patch` — collision-free across concurrent
|
|
23461
|
+
* workers and repeated finalize calls.
|
|
23462
|
+
*/
|
|
23463
|
+
async function saveOverflowPatch(dir) {
|
|
23464
|
+
const patch = await execFileP("git", [
|
|
23465
|
+
"-C",
|
|
23466
|
+
dir,
|
|
23467
|
+
"diff",
|
|
23468
|
+
"--binary",
|
|
23469
|
+
"--full-index",
|
|
23470
|
+
"HEAD"
|
|
23471
|
+
], { maxBuffer: 256 * 1024 * 1024 });
|
|
23472
|
+
await fs.mkdir(PATHS.WORKER_DIFFS_DIR, { recursive: true });
|
|
23473
|
+
const name = `${process$1.pid}-${randomBytes(4).toString("hex")}.patch`;
|
|
23474
|
+
const patchPath = nodePath.join(PATHS.WORKER_DIFFS_DIR, name);
|
|
23475
|
+
await fs.writeFile(patchPath, patch.stdout, {
|
|
23476
|
+
mode: 384,
|
|
23477
|
+
flag: "wx"
|
|
23478
|
+
});
|
|
23479
|
+
return patchPath;
|
|
23480
|
+
}
|
|
23264
23481
|
|
|
23265
23482
|
//#endregion
|
|
23266
23483
|
//#region src/lib/worker-agent/engine.ts
|
|
@@ -23275,30 +23492,40 @@ async function createWorktree(workspaceAbs, opts) {
|
|
|
23275
23492
|
*/
|
|
23276
23493
|
const WORKTREE_REGISTRY = new WorktreeRegistry();
|
|
23277
23494
|
registerExitHandlers(WORKTREE_REGISTRY);
|
|
23278
|
-
/**
|
|
23279
|
-
*
|
|
23280
|
-
* function-calling-loop discipline
|
|
23281
|
-
*
|
|
23282
|
-
*
|
|
23283
|
-
* `
|
|
23284
|
-
*
|
|
23285
|
-
*
|
|
23286
|
-
*
|
|
23287
|
-
*
|
|
23288
|
-
*
|
|
23289
|
-
* Exported so the MCP handler + the gate (`workerToolsEnabled`) read the
|
|
23290
|
-
* same constant — drift would ship a tool whose docs/gate disagree with
|
|
23291
|
-
* its runtime default. Caller can override per call via the `model` arg. */
|
|
23495
|
+
/** Worker-availability GATE sentinel + final fallback. `gpt-5.4-mini` — cheap,
|
|
23496
|
+
* broadly-available, tool-call-capable, 400k-context, with tight
|
|
23497
|
+
* function-calling-loop discipline (earlier gemini-flash cheap defaults
|
|
23498
|
+
* early-stopped with empty turns on the function-calling loop; gpt-5.4-mini
|
|
23499
|
+
* does not). Exported and aliased as `WORKER_DEFAULT_MODEL`:
|
|
23500
|
+
* `workerToolsEnabled()` gates the ENTIRE worker surface on this id being
|
|
23501
|
+
* present with `tool_calls`. It is no longer `explore`'s default (see
|
|
23502
|
+
* `EXPLORE_DEFAULT_MODEL`) — it stays the gate sentinel because it's the
|
|
23503
|
+
* cheapest broadly-present tool-caller, and the fallback for any unmatched
|
|
23504
|
+
* mode. */
|
|
23292
23505
|
const DEFAULT_MODEL = "gpt-5.4-mini";
|
|
23293
23506
|
const DEFAULT_THINKING = "xhigh";
|
|
23294
|
-
/** Default model
|
|
23295
|
-
* `
|
|
23296
|
-
*
|
|
23297
|
-
*
|
|
23298
|
-
* input — if absent (e.g. a
|
|
23299
|
-
* at call time rather than
|
|
23300
|
-
*
|
|
23301
|
-
|
|
23507
|
+
/** Default model for the READ-ONLY `explore` mode. `claude-sonnet-5` at `xhigh`
|
|
23508
|
+
* (via `DEFAULT_THINKING`) — a strong, NATIVE (no-shim) tool-caller for repo
|
|
23509
|
+
* research. Native Claude models run as workers over `/chat/completions`, the
|
|
23510
|
+
* same path proven by `PLAN_DEFAULT_MODEL` (claude-opus-4.8). Like `implement`'s
|
|
23511
|
+
* gpt-5.5 this is NOT a `workerToolsEnabled` gate input — if absent (e.g. a
|
|
23512
|
+
* non-enterprise tier) `explore` errors helpfully at call time rather than
|
|
23513
|
+
* vanishing the whole worker surface. The caller (the main model) overrides
|
|
23514
|
+
* BOTH the model and the reasoning per call via the `model` / `thinking` args. */
|
|
23515
|
+
const EXPLORE_DEFAULT_MODEL = "claude-sonnet-5";
|
|
23516
|
+
/** Default model + thinking for the READ-ONLY `review` mode.
|
|
23517
|
+
* `gemini-3.1-pro-preview` at `xhigh` (clamped to `high` at call time — gemini
|
|
23518
|
+
* advertises no xhigh). DELIBERATELY DECORRELATED FROM THE IMPLEMENTER: bounded
|
|
23519
|
+
* implementation now defaults to gpt-5.5 (OpenAI) — both the `implement` worker
|
|
23520
|
+
* and the native `implementer` subagent — and the main orchestrator is Opus
|
|
23521
|
+
* (Anthropic), so review runs on a THIRD lab (Google) to maximize blind-spot
|
|
23522
|
+
* diversity. A reviewer sharing the implementer's lab catches a correlated slice
|
|
23523
|
+
* of defects; a cross-lab reviewer is the point of the review step. Like
|
|
23524
|
+
* `implement`, this is NOT a `workerToolsEnabled` gate input — if absent (e.g. a
|
|
23525
|
+
* non-enterprise tier) `review` errors helpfully at call time rather than
|
|
23526
|
+
* vanishing the whole worker surface. Caller can override per call via the
|
|
23527
|
+
* `model` arg (e.g. `claude-opus-4.8` for an Anthropic-lab reviewer). */
|
|
23528
|
+
const REVIEW_DEFAULT_MODEL = "gemini-3.1-pro-preview";
|
|
23302
23529
|
const REVIEW_DEFAULT_THINKING = "xhigh";
|
|
23303
23530
|
/** Default model + thinking for the READ+WRITE `implement` mode. `gpt-5.5`
|
|
23304
23531
|
* at `xhigh` — the strongest reasoning tier in the catalog, 1M+ context,
|
|
@@ -23428,7 +23655,8 @@ async function runWorkerAgentOnce(opts) {
|
|
|
23428
23655
|
const isPlan = opts.mode === "plan";
|
|
23429
23656
|
const isReview = opts.mode === "review";
|
|
23430
23657
|
const isWriteCapable = opts.mode === "implement" || opts.mode === "test";
|
|
23431
|
-
const
|
|
23658
|
+
const isExplore = opts.mode === "explore";
|
|
23659
|
+
const defaultModel = isBrowse ? BROWSE_DEFAULT_MODEL : isPlan ? PLAN_DEFAULT_MODEL : isReview ? REVIEW_DEFAULT_MODEL : isWriteCapable ? IMPLEMENT_DEFAULT_MODEL : isExplore ? EXPLORE_DEFAULT_MODEL : DEFAULT_MODEL;
|
|
23432
23660
|
const defaultThinking = isBrowse ? BROWSE_DEFAULT_THINKING : isPlan ? PLAN_DEFAULT_THINKING : isReview ? REVIEW_DEFAULT_THINKING : isWriteCapable ? IMPLEMENT_DEFAULT_THINKING : DEFAULT_THINKING;
|
|
23433
23661
|
const resolved = resolveModelAndThinking({
|
|
23434
23662
|
model: opts.model ?? defaultModel,
|
|
@@ -23467,7 +23695,7 @@ async function runWorkerAgentOnce(opts) {
|
|
|
23467
23695
|
};
|
|
23468
23696
|
}
|
|
23469
23697
|
else ws = makeNoWorktreeHandle(workspaceAbs);
|
|
23470
|
-
const budget = new Budget();
|
|
23698
|
+
const budget = new Budget({ maxWallClockMs: opts.maxWallClockMs });
|
|
23471
23699
|
const agentHolder = {};
|
|
23472
23700
|
const planState = createPlanState();
|
|
23473
23701
|
const getMessages = () => agentHolder.agent?.state.messages ?? [];
|
|
@@ -23566,7 +23794,7 @@ async function runWorkerAgentOnce(opts) {
|
|
|
23566
23794
|
} catch {}
|
|
23567
23795
|
const text = isBrowse ? terminalText ?? finalText : diff ? `${finalText}\n\n${diff}` : finalText;
|
|
23568
23796
|
if (lastStopReason === "error") return {
|
|
23569
|
-
text: (terminalText ?? finalText).trim() || "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.",
|
|
23797
|
+
text: [(terminalText ?? finalText).trim() || "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.", diff].filter(Boolean).join("\n\n"),
|
|
23570
23798
|
isError: true
|
|
23571
23799
|
};
|
|
23572
23800
|
if (!text.trim()) return {
|
|
@@ -23576,9 +23804,11 @@ async function runWorkerAgentOnce(opts) {
|
|
|
23576
23804
|
return { text };
|
|
23577
23805
|
} catch (err) {
|
|
23578
23806
|
let diff = "";
|
|
23579
|
-
|
|
23807
|
+
try {
|
|
23580
23808
|
diff = await ws.finalize();
|
|
23581
|
-
} catch {
|
|
23809
|
+
} catch (err$1) {
|
|
23810
|
+
diff = `[diff capture failed: ${err$1.message}]`;
|
|
23811
|
+
}
|
|
23582
23812
|
try {
|
|
23583
23813
|
await ws.remove();
|
|
23584
23814
|
} catch {}
|
|
@@ -26398,6 +26628,10 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
|
|
|
26398
26628
|
workspace: {
|
|
26399
26629
|
type: "string",
|
|
26400
26630
|
description: "Optional absolute path to the workspace the worker operates in. Defaults to the proxy's launch cwd. Use this when the parent agent has multiple workspaces open and the worker must operate in a specific one. Must be absolute (relative paths rejected)."
|
|
26631
|
+
},
|
|
26632
|
+
maxWallClockMs: {
|
|
26633
|
+
type: "integer",
|
|
26634
|
+
description: "Optional per-call wall-clock budget in ms; default 6h (21600000). Clamped just under the MCP tool-call ceiling (the injected MCP tool-call timeout minus a 15-min teardown headroom) so the worker aborts gracefully with its partial work rather than being hard-killed; the effective value is reported in the result when a larger value is clamped down."
|
|
26401
26635
|
}
|
|
26402
26636
|
}
|
|
26403
26637
|
},
|
|
@@ -26446,6 +26680,10 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
|
|
|
26446
26680
|
workspace: {
|
|
26447
26681
|
type: "string",
|
|
26448
26682
|
description: "Optional absolute path to the workspace the worker operates in. Defaults to the proxy's launch cwd. Use this when the parent agent has multiple workspaces open and the worker must operate in a specific one. Must be absolute (relative paths rejected). For worktree:true, must be inside a git repo."
|
|
26683
|
+
},
|
|
26684
|
+
maxWallClockMs: {
|
|
26685
|
+
type: "integer",
|
|
26686
|
+
description: "Optional per-call wall-clock budget in ms; default 6h (21600000). Clamped just under the MCP tool-call ceiling (the injected MCP tool-call timeout minus a 15-min teardown headroom) so the worker aborts gracefully with its partial work rather than being hard-killed; the effective value is reported in the result when a larger value is clamped down."
|
|
26449
26687
|
}
|
|
26450
26688
|
}
|
|
26451
26689
|
},
|
|
@@ -26490,6 +26728,10 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
|
|
|
26490
26728
|
workspace: {
|
|
26491
26729
|
type: "string",
|
|
26492
26730
|
description: "Optional absolute path to the workspace the worker operates in. Defaults to the proxy's launch cwd. Use this when the parent agent has multiple workspaces open and the worker must operate in a specific one. Must be absolute (relative paths rejected)."
|
|
26731
|
+
},
|
|
26732
|
+
maxWallClockMs: {
|
|
26733
|
+
type: "integer",
|
|
26734
|
+
description: "Optional per-call wall-clock budget in ms; default 6h (21600000). Clamped just under the MCP tool-call ceiling (the injected MCP tool-call timeout minus a 15-min teardown headroom) so the worker aborts gracefully with its partial work rather than being hard-killed; the effective value is reported in the result when a larger value is clamped down."
|
|
26493
26735
|
}
|
|
26494
26736
|
}
|
|
26495
26737
|
},
|
|
@@ -26534,6 +26776,10 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
|
|
|
26534
26776
|
workspace: {
|
|
26535
26777
|
type: "string",
|
|
26536
26778
|
description: "Optional absolute path to the workspace the worker operates in. Defaults to the proxy's launch cwd. Use this when the parent agent has multiple workspaces open and the worker must operate in a specific one. Must be absolute (relative paths rejected)."
|
|
26779
|
+
},
|
|
26780
|
+
maxWallClockMs: {
|
|
26781
|
+
type: "integer",
|
|
26782
|
+
description: "Optional per-call wall-clock budget in ms; default 6h (21600000). Clamped just under the MCP tool-call ceiling (the injected MCP tool-call timeout minus a 15-min teardown headroom) so the worker aborts gracefully with its partial work rather than being hard-killed; the effective value is reported in the result when a larger value is clamped down."
|
|
26537
26783
|
}
|
|
26538
26784
|
}
|
|
26539
26785
|
},
|
|
@@ -26582,6 +26828,10 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
|
|
|
26582
26828
|
workspace: {
|
|
26583
26829
|
type: "string",
|
|
26584
26830
|
description: "Optional absolute path to the workspace the worker operates in. Defaults to the proxy's launch cwd. Use this when the parent agent has multiple workspaces open and the worker must operate in a specific one. Must be absolute (relative paths rejected). For worktree:true, must be inside a git repo."
|
|
26831
|
+
},
|
|
26832
|
+
maxWallClockMs: {
|
|
26833
|
+
type: "integer",
|
|
26834
|
+
description: "Optional per-call wall-clock budget in ms; default 6h (21600000). Clamped just under the MCP tool-call ceiling (the injected MCP tool-call timeout minus a 15-min teardown headroom) so the worker aborts gracefully with its partial work rather than being hard-killed; the effective value is reported in the result when a larger value is clamped down."
|
|
26585
26835
|
}
|
|
26586
26836
|
}
|
|
26587
26837
|
},
|
|
@@ -26986,6 +27236,23 @@ async function runWorkerToolCall(call) {
|
|
|
26986
27236
|
};
|
|
26987
27237
|
workspace = args.workspace;
|
|
26988
27238
|
}
|
|
27239
|
+
let maxWallClockMs;
|
|
27240
|
+
let clampNote = "";
|
|
27241
|
+
if (args.maxWallClockMs !== void 0) {
|
|
27242
|
+
const raw = args.maxWallClockMs;
|
|
27243
|
+
if (typeof raw !== "number" || !Number.isInteger(raw) || raw <= 0) return {
|
|
27244
|
+
content: [{
|
|
27245
|
+
type: "text",
|
|
27246
|
+
text: `worker_${mode}: arguments.maxWallClockMs must be a positive integer (milliseconds) when provided`
|
|
27247
|
+
}],
|
|
27248
|
+
isError: true
|
|
27249
|
+
};
|
|
27250
|
+
const ceiling = workerWallClockCeilingMs();
|
|
27251
|
+
maxWallClockMs = Math.min(raw, ceiling);
|
|
27252
|
+
if (raw > ceiling) clampNote = `[note: maxWallClockMs ${raw} exceeds the per-call ceiling; clamped to ${ceiling} ms (the MCP tool-call timeout ${resolveMcpToolTimeoutMs()} ms minus the ${MCP_TIMEOUT_HEADROOM_MS} ms teardown headroom) so the worker aborts gracefully rather than being hard-killed mid-run.]
|
|
27253
|
+
|
|
27254
|
+
`;
|
|
27255
|
+
}
|
|
26989
27256
|
const result = await runWorkerAgent({
|
|
26990
27257
|
mode,
|
|
26991
27258
|
prompt,
|
|
@@ -26993,12 +27260,13 @@ async function runWorkerToolCall(call) {
|
|
|
26993
27260
|
model,
|
|
26994
27261
|
thinking,
|
|
26995
27262
|
worktree,
|
|
27263
|
+
maxWallClockMs,
|
|
26996
27264
|
signal
|
|
26997
27265
|
});
|
|
26998
27266
|
return {
|
|
26999
27267
|
content: [{
|
|
27000
27268
|
type: "text",
|
|
27001
|
-
text: result.text
|
|
27269
|
+
text: `${clampNote}${result.text}`
|
|
27002
27270
|
}],
|
|
27003
27271
|
isError: result.isError
|
|
27004
27272
|
};
|
|
@@ -27200,5 +27468,5 @@ async function runStandInToolCall(args, signal) {
|
|
|
27200
27468
|
}
|
|
27201
27469
|
|
|
27202
27470
|
//#endregion
|
|
27203
|
-
export {
|
|
27204
|
-
//# sourceMappingURL=peer-mcp-personas-
|
|
27471
|
+
export { buildOpenAIErrorEvent as $, resolveModel as $t, BROWSE_DEFAULT_MODEL as A, ArtifactClient as At, buildToolbeltAwareness as B, pickClaudeDefault as Bt, repoFingerprint as C, parseJsonOrDiagnose as Ct, trustRepo as D, extractTarGzMember as Dt, stopReviewStateDir as E, provisionAndIndexColbert as Et, REVIEW_DEFAULT_MODEL as F, DEFAULT_CODEX_MODEL_FALLBACKS as Ft, assetFor as G, setupGitHubToken as Gt, toolbeltSkipSet as H, withInstallLock as Ht, appendPlanReminder as I, DEFAULT_PORT as It, ADVISOR_TOOL_INSTRUCTIONS as J, cacheModels as Jt, searchWeb as K, tryRefreshAndRetry as Kt, runWorkerAgent as L, UPSTREAM_FETCH_TIMEOUT_MS as Lt, EXPLORE_DEFAULT_MODEL as M, toolbeltPathOverride as Mt, IMPLEMENT_DEFAULT_MODEL as N, DEFAULT_CLAUDE_MODEL_FALLBACKS as Nt, resolveSealedGate as O, extractZipMember as Ot, PLAN_DEFAULT_MODEL as P, DEFAULT_CODEX_MODEL as Pt, buildAnthropicErrorEvent as Q, resolveCodexModel as Qt, withNoOutputRetry as R, UPSTREAM_INACTIVITY_TIMEOUT_MS as Rt, isSubagentContext as S, readResponseBodyCapped as St, stopGateEnabledForRepo as T, hasSupportedBrowserInstalled as Tt, vscodeRipgrepPath as U, setupCopilotToken as Ut, toolbeltEnabled as V, getPackageVersion as Vt, TOOLBELT_TOOLS$1 as W, setupGitHubAgentToken as Wt, injectAdvisorTool as X, filterBetaHeader as Xt, buildAdvisorStream as Y, cacheVSCodeVersion as Yt, isAdvisorRequested as Z, isNullish as Zt, stopReviewEnabled as _, resolveMcpToolTimeoutMs as _t, buildPeerAwarenessSnippet as a, GITHUB_API_BASE_URL as an, handleMcpPost as at, fileLastPromptStore as b, createChatCompletions as bt, buildSessionBindHookCommand as c, githubHeaders as cn, browserToolsEnabled as ct, decideStopHook as d, standInToolEnabled as dt, sleep as en, isControllerClosedError as et, fileBlockBudget as f, workerToolsEnabled as ft, stopGateId as g, assembleResponsesPayload as gt, stopGateDisabled as h, getTokenCount as ht, buildAgentPrompt as i, forwardError as in, handleMcpDelete as it, DEFAULT_MODEL as j, collapsePathKeys as jt, liveExec as k, shouldUseInsecureTls as kt, buildStopHookCommand as l, state as ln, fleetToolsEnabled as lt, launchBaselineKey as m, createMessages as mt, MCP_GROUPS as n, fetchWithTransientRetry as nn, readIteratorWithTimeout as nt, personasFor as o, copilotBaseUrl as on, agentToolsEnabled as ot, injectStopHookIntoSettingsFile as p, countTokens as pt, ADVISOR_INTERNAL_TOOL_NAME as q, cacheCopilotVersion as qt, assertMcpToolSurfaceConsistent as r, HTTPError as rn, relayAnthropicStream as rt, buildArtifactOpenHookCommand as s, copilotHeaders as sn, browseAgentEnabled as st, GROUP_META as t, getModels as tn, logStreamError as tt, captureLaunchBaseline as u, implementerSubagentModel as ut, fileBaselineStore as v, pickEndpoint as vt, repoRoot as w, provisionBrowserAssets as wt, fileReviewDebounce as x, MAX_RESPONSE_BODY_BYTES as xt, fileFindingsStore as y, createResponses as yt, availableToolCommands as z, generateRandomPort as zt };
|
|
27472
|
+
//# sourceMappingURL=peer-mcp-personas-Bfq3FPKc.js.map
|