pullfrog 0.1.59 → 0.1.61
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/agents/shared.d.ts +17 -0
- package/dist/cli.mjs +218 -551
- package/dist/external.d.ts +7 -0
- package/dist/index.js +163 -45
- package/dist/internal.js +13 -3
- package/dist/toolState.d.ts +3 -1
- package/dist/utils/activity.d.ts +12 -0
- package/dist/utils/credentialCheck.d.ts +7 -1
- package/dist/utils/patchWorkflowRunFields.d.ts +1 -1
- package/dist/utils/payload.d.ts +2 -0
- package/package.json +1 -1
package/dist/external.d.ts
CHANGED
|
@@ -322,6 +322,13 @@ export interface WriteablePayload {
|
|
|
322
322
|
} | undefined;
|
|
323
323
|
/** when true, seed the PR summary tmpfile + persist edits at run end */
|
|
324
324
|
generateSummary?: boolean | undefined;
|
|
325
|
+
/**
|
|
326
|
+
* the codex canary assigned this run to the EXPERIMENTAL codex harness. rolled
|
|
327
|
+
* once server-side at reservation and stamped on the run row, so the row and the
|
|
328
|
+
* run always agree on which arm this was. ORed with the account opt-in in
|
|
329
|
+
* `resolveAgent` — it widens who reaches codex, never narrows it.
|
|
330
|
+
*/
|
|
331
|
+
codexArm?: boolean | undefined;
|
|
325
332
|
}
|
|
326
333
|
export type Payload = Readonly<WriteablePayload>;
|
|
327
334
|
/**
|
package/dist/index.js
CHANGED
|
@@ -104420,6 +104420,11 @@ var DEFAULT_ACTIVITY_TIMEOUT_MS = 3e5;
|
|
|
104420
104420
|
var AGENT_ACTIVITY_TIMEOUT_MS = 9e5;
|
|
104421
104421
|
var AGENT_FIRST_EVENT_TIMEOUT_MS = 12e4;
|
|
104422
104422
|
var DEFAULT_ACTIVITY_CHECK_INTERVAL_MS = 5e3;
|
|
104423
|
+
function watchdogBudgetMs(compiled, envVar) {
|
|
104424
|
+
const raw2 = Number(process.env[envVar]);
|
|
104425
|
+
if (!Number.isFinite(raw2) || raw2 <= 0) return compiled;
|
|
104426
|
+
return Math.min(compiled, raw2);
|
|
104427
|
+
}
|
|
104423
104428
|
var DEBUG_TS_PREFIX = /^(?:\[\d{4}-\d{2}-\d{2}T[^\]]+\]\s+)?/.source;
|
|
104424
104429
|
var ACTIVITY_NOISE_PATTERNS = [
|
|
104425
104430
|
new RegExp(`${DEBUG_TS_PREFIX}\\[mcp-proxy\\]`),
|
|
@@ -105183,7 +105188,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
105183
105188
|
// package.json
|
|
105184
105189
|
var package_default = {
|
|
105185
105190
|
name: "pullfrog",
|
|
105186
|
-
version: "0.1.
|
|
105191
|
+
version: "0.1.61",
|
|
105187
105192
|
type: "module",
|
|
105188
105193
|
bin: {
|
|
105189
105194
|
pullfrog: "dist/cli.mjs",
|
|
@@ -107292,7 +107297,7 @@ var claude = agent({
|
|
|
107292
107297
|
if ((isBedrockRoute || isVertexRoute2) && specifier && effort.alias?.effort) {
|
|
107293
107298
|
applyHostedEffortCapabilities({ env: env2, modelId: specifier, levels: effort.alias.effort });
|
|
107294
107299
|
}
|
|
107295
|
-
if (env2.CLAUDE_CODE_OAUTH_TOKEN && !isBedrockRoute && env2.ANTHROPIC_API_KEY) {
|
|
107300
|
+
if (env2.CLAUDE_CODE_OAUTH_TOKEN && !isBedrockRoute && !isVertexRoute2 && !env2.ANTHROPIC_BASE_URL && !env2.ANTHROPIC_AUTH_TOKEN && env2.ANTHROPIC_API_KEY) {
|
|
107296
107301
|
const preflight = await preflightClaudeSubscription({
|
|
107297
107302
|
token: env2.CLAUDE_CODE_OAUTH_TOKEN,
|
|
107298
107303
|
model
|
|
@@ -107309,6 +107314,19 @@ var claude = agent({
|
|
|
107309
107314
|
delete env2.CLAUDE_CODE_OAUTH_TOKEN;
|
|
107310
107315
|
}
|
|
107311
107316
|
}
|
|
107317
|
+
if (env2.CLAUDE_CODE_USE_BEDROCK) {
|
|
107318
|
+
ctx.toolState.credential = "bedrock";
|
|
107319
|
+
} else if (env2.CLAUDE_CODE_USE_VERTEX) {
|
|
107320
|
+
ctx.toolState.credential = "vertex";
|
|
107321
|
+
} else if (env2.CLAUDE_CODE_USE_FOUNDRY) {
|
|
107322
|
+
ctx.toolState.credential = "foundry";
|
|
107323
|
+
} else if (env2.ANTHROPIC_AUTH_TOKEN) {
|
|
107324
|
+
ctx.toolState.credential = "gateway";
|
|
107325
|
+
} else if (env2.ANTHROPIC_API_KEY) {
|
|
107326
|
+
ctx.toolState.credential = "api_key";
|
|
107327
|
+
} else if (env2.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
107328
|
+
ctx.toolState.credential = "subscription";
|
|
107329
|
+
}
|
|
107312
107330
|
const effortEnvOverride = env2[CLAUDE_EFFORT_ENV]?.trim();
|
|
107313
107331
|
if (effortEnvOverride) {
|
|
107314
107332
|
log.warning(
|
|
@@ -107818,6 +107836,18 @@ function toTodoWriteInput(item) {
|
|
|
107818
107836
|
}))
|
|
107819
107837
|
};
|
|
107820
107838
|
}
|
|
107839
|
+
var CODEX_MODEL_PRICING = {
|
|
107840
|
+
"gpt-5.6-sol": { input: 5, cacheRead: 0.5, cacheWrite: 6.25, output: 30 },
|
|
107841
|
+
"gpt-5.6-luna": { input: 0.2, cacheRead: 0.02, cacheWrite: 0.25, output: 1.2 },
|
|
107842
|
+
"gpt-5.6-terra": { input: 2, cacheRead: 0.2, cacheWrite: 2.5, output: 12 }
|
|
107843
|
+
};
|
|
107844
|
+
function codexCostUsd(params) {
|
|
107845
|
+
const price = params.model ? CODEX_MODEL_PRICING[params.model] : void 0;
|
|
107846
|
+
if (!price) return void 0;
|
|
107847
|
+
const fresh = Math.max(0, params.input - params.cacheRead - params.cacheWrite);
|
|
107848
|
+
const usd = (fresh * price.input + params.cacheRead * price.cacheRead + params.cacheWrite * price.cacheWrite + params.output * price.output) / 1e6;
|
|
107849
|
+
return usd > 0 ? usd : void 0;
|
|
107850
|
+
}
|
|
107821
107851
|
async function runCodex(params) {
|
|
107822
107852
|
const startTime = performance6.now();
|
|
107823
107853
|
const thinkingTimer = new ThinkingTimer();
|
|
@@ -107829,14 +107859,15 @@ async function runCodex(params) {
|
|
|
107829
107859
|
let turnError = null;
|
|
107830
107860
|
let lastProviderError = null;
|
|
107831
107861
|
let stdoutBuffer = "";
|
|
107832
|
-
const tokens = { input: 0, cacheRead: 0, output: 0 };
|
|
107862
|
+
const tokens = { input: 0, cacheRead: 0, cacheWrite: 0, output: 0 };
|
|
107833
107863
|
function buildUsage2() {
|
|
107834
107864
|
if (tokens.input === 0 && tokens.output === 0) return void 0;
|
|
107835
107865
|
return {
|
|
107836
107866
|
agent: "codex",
|
|
107837
107867
|
inputTokens: tokens.input,
|
|
107838
107868
|
outputTokens: tokens.output,
|
|
107839
|
-
cacheReadTokens: tokens.cacheRead || void 0
|
|
107869
|
+
cacheReadTokens: tokens.cacheRead || void 0,
|
|
107870
|
+
costUsd: codexCostUsd({ model: params.model, ...tokens })
|
|
107840
107871
|
};
|
|
107841
107872
|
}
|
|
107842
107873
|
function onItem(item, phase) {
|
|
@@ -107901,6 +107932,7 @@ async function runCodex(params) {
|
|
|
107901
107932
|
case "turn.completed":
|
|
107902
107933
|
tokens.input += event.usage.input_tokens ?? 0;
|
|
107903
107934
|
tokens.cacheRead += event.usage.cached_input_tokens ?? 0;
|
|
107935
|
+
tokens.cacheWrite += event.usage.cache_write_input_tokens ?? 0;
|
|
107904
107936
|
tokens.output += event.usage.output_tokens ?? 0;
|
|
107905
107937
|
return;
|
|
107906
107938
|
case "turn.failed":
|
|
@@ -108061,6 +108093,11 @@ var codex = agent({
|
|
|
108061
108093
|
} else if (process.env.OPENAI_API_KEY) {
|
|
108062
108094
|
env2.CODEX_API_KEY = process.env.OPENAI_API_KEY;
|
|
108063
108095
|
}
|
|
108096
|
+
if (codexHomeAuth) {
|
|
108097
|
+
ctx.toolState.credential = "subscription";
|
|
108098
|
+
} else if (env2.CODEX_API_KEY) {
|
|
108099
|
+
ctx.toolState.credential = "api_key";
|
|
108100
|
+
}
|
|
108064
108101
|
const securityFlags = securityOverrideFlags({
|
|
108065
108102
|
ctx,
|
|
108066
108103
|
sandboxMode: ctx.payload.push === "disabled" ? "read-only" : "workspace-write",
|
|
@@ -108069,7 +108106,13 @@ var codex = agent({
|
|
|
108069
108106
|
model: resolveCodexModel(ctx),
|
|
108070
108107
|
effortRung: effort.rung && CODEX_EFFORTS.includes(effort.rung) ? effort.rung : void 0
|
|
108071
108108
|
});
|
|
108072
|
-
const runnerArgs = {
|
|
108109
|
+
const runnerArgs = {
|
|
108110
|
+
cliPath,
|
|
108111
|
+
cwd: process.cwd(),
|
|
108112
|
+
env: env2,
|
|
108113
|
+
todoTracker: ctx.todoTracker,
|
|
108114
|
+
model: resolveCodexModel(ctx)
|
|
108115
|
+
};
|
|
108073
108116
|
const initial = await runCodex({
|
|
108074
108117
|
...runnerArgs,
|
|
108075
108118
|
args: [...securityFlags, "exec", "--json", ctx.instructions.full],
|
|
@@ -114157,6 +114200,7 @@ function processTerminalToolPart(ctx, part, label, isOrchestrator) {
|
|
|
114157
114200
|
const callLine = inputFormatted !== "{}" ? `\xBB ${toolName}(${inputFormatted})` : `\xBB ${toolName}()`;
|
|
114158
114201
|
log.info(withLabel(label, callLine));
|
|
114159
114202
|
if (isOrchestrator) ctx.loggedToolCallIDs.add(toolId);
|
|
114203
|
+
if (isOrchestrator && toolName.startsWith("pullfrog_")) ctx.mcpToolCalls++;
|
|
114160
114204
|
if (state.status === "completed") {
|
|
114161
114205
|
log.debug(withLabel(label, ` output: ${state.output}`));
|
|
114162
114206
|
} else {
|
|
@@ -114395,21 +114439,28 @@ function formatConfigError(name, data) {
|
|
|
114395
114439
|
).join("");
|
|
114396
114440
|
return `${name}${detail}${bullets}`;
|
|
114397
114441
|
}
|
|
114442
|
+
var WATCHDOG_SALVAGE_PROMPT = "Your previous turn was cut off mid-response by a provider stall. Nothing you had not already submitted through a tool was saved. Continue from where you stopped and submit your work now \u2014 do not restart your analysis.";
|
|
114398
114443
|
function startInnerActivityWatchdog(params) {
|
|
114399
114444
|
let fired = false;
|
|
114445
|
+
let everFired = false;
|
|
114400
114446
|
const id = setInterval(() => {
|
|
114401
114447
|
if (fired) return;
|
|
114402
114448
|
const idleMs = performance7.now() - params.ctx.lastEventAt;
|
|
114403
|
-
const
|
|
114449
|
+
const compiledMs = params.ctx.sawModelOutput ? params.timeoutMs : AGENT_FIRST_EVENT_TIMEOUT_MS;
|
|
114450
|
+
const budgetMs = everFired ? compiledMs : watchdogBudgetMs(
|
|
114451
|
+
compiledMs,
|
|
114452
|
+
params.ctx.sawModelOutput ? "PULLFROG_E2E_ACTIVITY_TIMEOUT_MS" : "PULLFROG_E2E_FIRST_EVENT_TIMEOUT_MS"
|
|
114453
|
+
);
|
|
114404
114454
|
if (idleMs <= budgetMs) return;
|
|
114405
114455
|
fired = true;
|
|
114456
|
+
everFired = true;
|
|
114406
114457
|
const idleSec = Math.round(idleMs / 1e3);
|
|
114407
114458
|
params.ctx.diagnostic.idleSec = idleSec;
|
|
114408
114459
|
params.ctx.diagnostic.sawModelOutput = params.ctx.sawModelOutput;
|
|
114409
114460
|
log.info(
|
|
114410
114461
|
params.ctx.sawModelOutput ? `\xBB no opencode events for ${idleSec}s \u2014 aborting in-flight prompt and notifying harness` : `\xBB no opencode events for ${idleSec}s \u2014 the provider never returned a first token; aborting in-flight prompt and notifying harness`
|
|
114411
114462
|
);
|
|
114412
|
-
params.
|
|
114463
|
+
params.abortTurn();
|
|
114413
114464
|
try {
|
|
114414
114465
|
params.ctx.onActivityTimeout?.();
|
|
114415
114466
|
} catch (err) {
|
|
@@ -114419,7 +114470,22 @@ function startInnerActivityWatchdog(params) {
|
|
|
114419
114470
|
}
|
|
114420
114471
|
}, 5e3);
|
|
114421
114472
|
id.unref?.();
|
|
114422
|
-
return {
|
|
114473
|
+
return {
|
|
114474
|
+
stop: () => clearInterval(id),
|
|
114475
|
+
/**
|
|
114476
|
+
* Start a turn's idle budget from now. The clock must be reset with the
|
|
114477
|
+
* latch: `lastEventAt` only advances on model output, so a turn following a
|
|
114478
|
+
* stall would inherit the full stalled interval and be aborted on the very
|
|
114479
|
+
* next 5s tick — killing the salvage before the provider could answer. It
|
|
114480
|
+
* is the right semantics for an ordinary resume too, whose budget should
|
|
114481
|
+
* not be pre-spent by the post-run gate checks that ran between turns.
|
|
114482
|
+
*/
|
|
114483
|
+
armForTurn: () => {
|
|
114484
|
+
fired = false;
|
|
114485
|
+
params.ctx.lastEventAt = performance7.now();
|
|
114486
|
+
},
|
|
114487
|
+
firedThisTurn: () => fired
|
|
114488
|
+
};
|
|
114423
114489
|
}
|
|
114424
114490
|
var opencode = agent({
|
|
114425
114491
|
name: "opencode",
|
|
@@ -114531,6 +114597,7 @@ var opencode = agent({
|
|
|
114531
114597
|
variant: effort.rung,
|
|
114532
114598
|
todoTracker: ctx.todoTracker,
|
|
114533
114599
|
onActivityTimeout: ctx.onActivityTimeout,
|
|
114600
|
+
onTurnRecovered: ctx.onTurnRecovered,
|
|
114534
114601
|
onToolUse: ctx.onToolUse,
|
|
114535
114602
|
currentTurn: null,
|
|
114536
114603
|
eventCount: 0,
|
|
@@ -114539,6 +114606,7 @@ var opencode = agent({
|
|
|
114539
114606
|
promptMessageID: void 0,
|
|
114540
114607
|
taskDispatchByCallID: /* @__PURE__ */ new Map(),
|
|
114541
114608
|
loggedToolCallIDs: /* @__PURE__ */ new Set(),
|
|
114609
|
+
mcpToolCalls: 0,
|
|
114542
114610
|
recentStderr: server.recentStderr,
|
|
114543
114611
|
diagnostic: {
|
|
114544
114612
|
label: "Pullfrog",
|
|
@@ -114562,9 +114630,14 @@ var opencode = agent({
|
|
|
114562
114630
|
}
|
|
114563
114631
|
}
|
|
114564
114632
|
});
|
|
114565
|
-
const
|
|
114566
|
-
|
|
114567
|
-
|
|
114633
|
+
const runController = new AbortController();
|
|
114634
|
+
let turnController = new AbortController();
|
|
114635
|
+
const nextTurnSignal = () => {
|
|
114636
|
+
turnController = new AbortController();
|
|
114637
|
+
return AbortSignal.any([runController.signal, turnController.signal]);
|
|
114638
|
+
};
|
|
114639
|
+
const eventLoopPromise = consumeEvents(runnerCtx, runController.signal).catch((err) => {
|
|
114640
|
+
if (!runController.signal.aborted) {
|
|
114568
114641
|
log.warning(
|
|
114569
114642
|
`\xBB opencode event subscription ended: ${err instanceof Error ? err.message : String(err)}`
|
|
114570
114643
|
);
|
|
@@ -114580,31 +114653,48 @@ var opencode = agent({
|
|
|
114580
114653
|
// a long synchronous tool call (no part.updated while it runs) can't
|
|
114581
114654
|
// false-positive it.
|
|
114582
114655
|
timeoutMs: AGENT_ACTIVITY_TIMEOUT_MS,
|
|
114583
|
-
|
|
114656
|
+
abortTurn: () => turnController.abort()
|
|
114584
114657
|
});
|
|
114585
114658
|
const sdkModel = parseModel2(model);
|
|
114659
|
+
let salvagesLeft = 1;
|
|
114660
|
+
const runTurn = async (text) => {
|
|
114661
|
+
const attempt = (prompt) => {
|
|
114662
|
+
watchdog.armForTurn();
|
|
114663
|
+
return runTurnGuarded(
|
|
114664
|
+
runnerCtx,
|
|
114665
|
+
() => runPromptTurn(runnerCtx, { text: prompt, model: sdkModel, signal: nextTurnSignal() })
|
|
114666
|
+
);
|
|
114667
|
+
};
|
|
114668
|
+
const standDownIfRecovered = (turn) => {
|
|
114669
|
+
if (watchdog.firedThisTurn() && turn.success) ctx.onTurnRecovered?.();
|
|
114670
|
+
return turn;
|
|
114671
|
+
};
|
|
114672
|
+
const result = await attempt(text);
|
|
114673
|
+
if (!watchdog.firedThisTurn()) return result;
|
|
114674
|
+
if (result.success) return standDownIfRecovered(result);
|
|
114675
|
+
if (salvagesLeft <= 0) return result;
|
|
114676
|
+
salvagesLeft--;
|
|
114677
|
+
ctx.onTurnRecovered?.();
|
|
114678
|
+
log.info("\xBB activity watchdog cut the turn off \u2014 re-prompting once on the same session");
|
|
114679
|
+
const mcpCallsBefore = runnerCtx.mcpToolCalls;
|
|
114680
|
+
const salvaged = await attempt(WATCHDOG_SALVAGE_PROMPT);
|
|
114681
|
+
const usage = mergeAgentUsage(result.usage, salvaged.usage);
|
|
114682
|
+
if (runnerCtx.mcpToolCalls === mcpCallsBefore) {
|
|
114683
|
+
log.info(
|
|
114684
|
+
"\xBB salvage turn reached no Pullfrog tool \u2014 keeping the activity-timeout failure"
|
|
114685
|
+
);
|
|
114686
|
+
return { ...result, usage };
|
|
114687
|
+
}
|
|
114688
|
+
return standDownIfRecovered({ ...salvaged, usage });
|
|
114689
|
+
};
|
|
114586
114690
|
try {
|
|
114587
|
-
const initial = await
|
|
114588
|
-
runnerCtx,
|
|
114589
|
-
() => runPromptTurn(runnerCtx, {
|
|
114590
|
-
text: ctx.instructions.full,
|
|
114591
|
-
model: sdkModel,
|
|
114592
|
-
signal: abortController.signal
|
|
114593
|
-
})
|
|
114594
|
-
);
|
|
114691
|
+
const initial = await runTurn(ctx.instructions.full);
|
|
114595
114692
|
const result = await runPostRunRetryLoop({
|
|
114596
114693
|
ctx,
|
|
114597
114694
|
initialResult: initial,
|
|
114598
114695
|
initialUsage: initial.usage,
|
|
114599
114696
|
reflectionPrompt: buildReflectionPrompt(ctx.toolState),
|
|
114600
|
-
resume: async (c) =>
|
|
114601
|
-
runnerCtx,
|
|
114602
|
-
() => runPromptTurn(runnerCtx, {
|
|
114603
|
-
text: c.prompt,
|
|
114604
|
-
model: sdkModel,
|
|
114605
|
-
signal: abortController.signal
|
|
114606
|
-
})
|
|
114607
|
-
)
|
|
114697
|
+
resume: async (c) => runTurn(c.prompt)
|
|
114608
114698
|
});
|
|
114609
114699
|
if (result.success) {
|
|
114610
114700
|
await ctx.todoTracker?.flush();
|
|
@@ -114614,7 +114704,7 @@ var opencode = agent({
|
|
|
114614
114704
|
return result;
|
|
114615
114705
|
} finally {
|
|
114616
114706
|
watchdog.stop();
|
|
114617
|
-
|
|
114707
|
+
runController.abort();
|
|
114618
114708
|
await eventLoopPromise.catch(() => {
|
|
114619
114709
|
});
|
|
114620
114710
|
}
|
|
@@ -187244,7 +187334,9 @@ var STRING_KEYS = [
|
|
|
187244
187334
|
"reviewNodeId",
|
|
187245
187335
|
"planCommentNodeId",
|
|
187246
187336
|
"summarySnapshot",
|
|
187247
|
-
"model"
|
|
187337
|
+
"model",
|
|
187338
|
+
"agent",
|
|
187339
|
+
"credential"
|
|
187248
187340
|
];
|
|
187249
187341
|
var NUMBER_KEYS = [
|
|
187250
187342
|
"inputTokens",
|
|
@@ -192405,7 +192497,7 @@ function hasEnvVar2(name) {
|
|
|
192405
192497
|
return typeof val === "string" && val.length > 0;
|
|
192406
192498
|
}
|
|
192407
192499
|
function hasClaudeCodeAuth() {
|
|
192408
|
-
return hasEnvVar2("CLAUDE_CODE_OAUTH_TOKEN") || hasEnvVar2("ANTHROPIC_API_KEY");
|
|
192500
|
+
return hasEnvVar2("CLAUDE_CODE_OAUTH_TOKEN") || hasEnvVar2("ANTHROPIC_API_KEY") || hasEnvVar2("ANTHROPIC_AUTH_TOKEN");
|
|
192409
192501
|
}
|
|
192410
192502
|
function hasCodexAuth() {
|
|
192411
192503
|
return hasEnvVar2("CODEX_AUTH_JSON") || hasEnvVar2("OPENAI_API_KEY");
|
|
@@ -192498,8 +192590,11 @@ function resolveAgent(ctx) {
|
|
|
192498
192590
|
} catch {
|
|
192499
192591
|
}
|
|
192500
192592
|
}
|
|
192501
|
-
if (!ctx.model
|
|
192502
|
-
|
|
192593
|
+
if (!ctx.model) {
|
|
192594
|
+
if (hasEnvVar2("ANTHROPIC_AUTH_TOKEN") && !hasEnvVar2("ANTHROPIC_API_KEY") && !hasEnvVar2("CLAUDE_CODE_OAUTH_TOKEN")) {
|
|
192595
|
+
return agents.claude;
|
|
192596
|
+
}
|
|
192597
|
+
if (ctx.codexAgent && hasCodexAuth() && !hasClaudeCodeAuth()) return agents.codex;
|
|
192503
192598
|
}
|
|
192504
192599
|
return agents.opencode;
|
|
192505
192600
|
}
|
|
@@ -192685,7 +192780,7 @@ function hasSingleProviderAuth(agentName) {
|
|
|
192685
192780
|
if (agentName === "codex") {
|
|
192686
192781
|
return hasEnvVar3("OPENAI_API_KEY") || hasEnvVar3("CODEX_AUTH_JSON");
|
|
192687
192782
|
}
|
|
192688
|
-
return hasEnvVar3("ANTHROPIC_API_KEY") || hasEnvVar3("CLAUDE_CODE_OAUTH_TOKEN");
|
|
192783
|
+
return hasEnvVar3("ANTHROPIC_API_KEY") || hasEnvVar3("ANTHROPIC_AUTH_TOKEN") || hasEnvVar3("CLAUDE_CODE_OAUTH_TOKEN");
|
|
192689
192784
|
}
|
|
192690
192785
|
function validateAgentApiKey(params) {
|
|
192691
192786
|
if (params.model) {
|
|
@@ -193017,7 +193112,8 @@ var PROBES = {
|
|
|
193017
193112
|
request: (value2) => ({
|
|
193018
193113
|
url: "https://api.anthropic.com/v1/models",
|
|
193019
193114
|
headers: { "x-api-key": value2, "anthropic-version": "2023-06-01" }
|
|
193020
|
-
})
|
|
193115
|
+
}),
|
|
193116
|
+
hostConfigurable: true
|
|
193021
193117
|
},
|
|
193022
193118
|
OPENROUTER_API_KEY: {
|
|
193023
193119
|
request: (value2) => ({
|
|
@@ -193066,12 +193162,18 @@ function hasEnvVar4(name) {
|
|
|
193066
193162
|
const value2 = process.env[name];
|
|
193067
193163
|
return typeof value2 === "string" && value2.length > 0;
|
|
193068
193164
|
}
|
|
193165
|
+
var HOST_OVERRIDES = {
|
|
193166
|
+
ANTHROPIC_API_KEY: "ANTHROPIC_BASE_URL",
|
|
193167
|
+
CLAUDE_CODE_OAUTH_TOKEN: "ANTHROPIC_BASE_URL"
|
|
193168
|
+
};
|
|
193069
193169
|
function envVarsFor(model) {
|
|
193070
193170
|
return model.includes("/") ? getModelEnvVars(model) : [];
|
|
193071
193171
|
}
|
|
193072
193172
|
async function checkOne(params) {
|
|
193073
193173
|
const value2 = process.env[params.envVar];
|
|
193074
193174
|
if (!value2) return null;
|
|
193175
|
+
const hostOverride = HOST_OVERRIDES[params.envVar];
|
|
193176
|
+
if (hostOverride && hasEnvVar4(hostOverride)) return null;
|
|
193075
193177
|
if (params.envVar === "CLAUDE_CODE_OAUTH_TOKEN") {
|
|
193076
193178
|
const preflight = await preflightClaudeSubscription({
|
|
193077
193179
|
token: value2,
|
|
@@ -194013,7 +194115,10 @@ var JsonPayload = type({
|
|
|
194013
194115
|
// optional so a payload from an older server build (pre-`checkRun`) still parses
|
|
194014
194116
|
// against a newer action across a rolling deploy.
|
|
194015
194117
|
"checkRun?": type({ id: "string" }).or("undefined"),
|
|
194016
|
-
"generateSummary?": "boolean | undefined"
|
|
194118
|
+
"generateSummary?": "boolean | undefined",
|
|
194119
|
+
// optional so a payload from a pre-canary server build still parses against a
|
|
194120
|
+
// newer action across a rolling deploy.
|
|
194121
|
+
"codexArm?": "boolean | undefined"
|
|
194017
194122
|
});
|
|
194018
194123
|
var COLLABORATOR_PERMISSIONS = ["admin", "maintain", "write"];
|
|
194019
194124
|
function isCollaborator(event) {
|
|
@@ -194142,6 +194247,7 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
|
194142
194247
|
progressComment: jsonPayload?.progressComment,
|
|
194143
194248
|
checkRun: jsonPayload?.checkRun,
|
|
194144
194249
|
generateSummary: jsonPayload?.generateSummary,
|
|
194250
|
+
codexArm: jsonPayload?.codexArm,
|
|
194145
194251
|
// permissions: inputs > repoSettings > fallbacks
|
|
194146
194252
|
push: inputs.push ?? repoSettings.push ?? "restricted",
|
|
194147
194253
|
shell: resolvedShell,
|
|
@@ -196086,8 +196192,12 @@ async function main() {
|
|
|
196086
196192
|
const agent2 = resolveAgent({
|
|
196087
196193
|
model: resolvedModel,
|
|
196088
196194
|
proxyModel: payload.proxyModel,
|
|
196089
|
-
|
|
196195
|
+
// the account opt-in and the canary arm are both admissions to codex, so
|
|
196196
|
+
// they OR: an account that opted in explicitly always gets it, and the
|
|
196197
|
+
// canary widens the pool without ever demoting a run that already had it.
|
|
196198
|
+
codexAgent: runContext.repoSettings.codexAgent || payload.codexArm === true
|
|
196090
196199
|
});
|
|
196200
|
+
toolState.agent = agent2.name;
|
|
196091
196201
|
const effectiveModel = payload.proxyModel ?? resolvedModel ?? payload.model;
|
|
196092
196202
|
toolState.model = effectiveModel;
|
|
196093
196203
|
if (!payload.proxyModel) {
|
|
@@ -196304,16 +196414,14 @@ ${instructions.user}` : null,
|
|
|
196304
196414
|
const onInnerActivityTimeout = () => {
|
|
196305
196415
|
if (innerTimeoutFired) return;
|
|
196306
196416
|
innerTimeoutFired = true;
|
|
196307
|
-
log.info(
|
|
196308
|
-
"\xBB inner activity timeout fired \u2014 stopping MCP server and starting 5min safety-net timer"
|
|
196309
|
-
);
|
|
196310
|
-
mcpHttpServer[Symbol.asyncDispose]().catch((err) => {
|
|
196311
|
-
log.debug(
|
|
196312
|
-
`mcp server stop after inner kill failed: ${err instanceof Error ? err.message : String(err)}`
|
|
196313
|
-
);
|
|
196314
|
-
});
|
|
196417
|
+
log.info("\xBB inner activity timeout fired \u2014 starting 5min safety-net timer");
|
|
196315
196418
|
safetyNetTimer = setTimeout(
|
|
196316
196419
|
() => {
|
|
196420
|
+
mcpHttpServer[Symbol.asyncDispose]().catch((err) => {
|
|
196421
|
+
log.debug(
|
|
196422
|
+
`mcp server stop after inner kill failed: ${err instanceof Error ? err.message : String(err)}`
|
|
196423
|
+
);
|
|
196424
|
+
});
|
|
196317
196425
|
activityTimeout?.forceReject(
|
|
196318
196426
|
"agent still pending 5min after inner activity kill \u2014 forcing exit"
|
|
196319
196427
|
);
|
|
@@ -196322,6 +196430,13 @@ ${instructions.user}` : null,
|
|
|
196322
196430
|
);
|
|
196323
196431
|
safetyNetTimer.unref?.();
|
|
196324
196432
|
};
|
|
196433
|
+
const onTurnRecovered = () => {
|
|
196434
|
+
if (!innerTimeoutFired) return;
|
|
196435
|
+
innerTimeoutFired = false;
|
|
196436
|
+
if (safetyNetTimer) clearTimeout(safetyNetTimer);
|
|
196437
|
+
safetyNetTimer = void 0;
|
|
196438
|
+
log.info("\xBB inner activity safety net stood down \u2014 turn recovered");
|
|
196439
|
+
};
|
|
196325
196440
|
const agentPromise = agent2.run({
|
|
196326
196441
|
payload,
|
|
196327
196442
|
resolvedModel,
|
|
@@ -196342,6 +196457,7 @@ ${instructions.user}` : null,
|
|
|
196342
196457
|
toolState,
|
|
196343
196458
|
apiToken: runContext.apiToken,
|
|
196344
196459
|
onActivityTimeout: onInnerActivityTimeout,
|
|
196460
|
+
onTurnRecovered,
|
|
196345
196461
|
onToolUse: (event) => {
|
|
196346
196462
|
const wasTracked = recordDiffReadFromToolUse({
|
|
196347
196463
|
state: primaryRepoState(toolState).diffCoverage,
|
|
@@ -196439,6 +196555,8 @@ ${instructions.user}` : null,
|
|
|
196439
196555
|
if (toolContext) {
|
|
196440
196556
|
const patch = aggregateUsage(toolState.usageEntries);
|
|
196441
196557
|
if (toolState.model) patch.model = toolState.model;
|
|
196558
|
+
if (toolState.agent) patch.agent = toolState.agent;
|
|
196559
|
+
if (toolState.credential) patch.credential = toolState.credential;
|
|
196442
196560
|
if (Object.keys(patch).length > 0) {
|
|
196443
196561
|
await patchWorkflowRunFields(toolContext, patch);
|
|
196444
196562
|
}
|
package/dist/internal.js
CHANGED
|
@@ -777,9 +777,16 @@ function getModelManagedCredentials(slug) {
|
|
|
777
777
|
const providerConfig = providers[parsed.provider];
|
|
778
778
|
return providerConfig?.managedCredentials?.slice() ?? [];
|
|
779
779
|
}
|
|
780
|
+
var HARNESS_ONLY_CREDENTIALS = {
|
|
781
|
+
anthropic: ["ANTHROPIC_AUTH_TOKEN"]
|
|
782
|
+
};
|
|
780
783
|
function modelHasStoredAuth(params) {
|
|
781
784
|
const slug = resolveDisplayAlias(params.model)?.slug ?? params.model;
|
|
782
|
-
const authVars = [
|
|
785
|
+
const authVars = [
|
|
786
|
+
...getModelEnvVars(slug),
|
|
787
|
+
...getModelManagedCredentials(slug),
|
|
788
|
+
...HARNESS_ONLY_CREDENTIALS[getModelProvider(slug)] ?? []
|
|
789
|
+
];
|
|
783
790
|
return authVars.some((v) => params.secretNames.includes(v));
|
|
784
791
|
}
|
|
785
792
|
var modelAliases = Object.entries(providers).flatMap(
|
|
@@ -1542,7 +1549,8 @@ var PROBES = {
|
|
|
1542
1549
|
request: (value) => ({
|
|
1543
1550
|
url: "https://api.anthropic.com/v1/models",
|
|
1544
1551
|
headers: { "x-api-key": value, "anthropic-version": "2023-06-01" }
|
|
1545
|
-
})
|
|
1552
|
+
}),
|
|
1553
|
+
hostConfigurable: true
|
|
1546
1554
|
},
|
|
1547
1555
|
OPENROUTER_API_KEY: {
|
|
1548
1556
|
request: (value) => ({
|
|
@@ -1565,7 +1573,9 @@ async function verifyClaudeSubscription(value) {
|
|
|
1565
1573
|
return preflight.status === 401 ? "dead" : "alive";
|
|
1566
1574
|
}
|
|
1567
1575
|
function isCredentialProbeable(envVar) {
|
|
1568
|
-
|
|
1576
|
+
if (envVar === "CLAUDE_CODE_OAUTH_TOKEN") return true;
|
|
1577
|
+
const probe = PROBES[envVar];
|
|
1578
|
+
return probe !== void 0 && !probe.hostConfigurable;
|
|
1569
1579
|
}
|
|
1570
1580
|
async function verifyCredential(params) {
|
|
1571
1581
|
const value = params.value.trim();
|
package/dist/toolState.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentUsage } from "./agents/shared.ts";
|
|
1
|
+
import type { AgentCredential, AgentUsage } from "./agents/shared.ts";
|
|
2
2
|
import type { PrepResult } from "./prep/types.ts";
|
|
3
3
|
import type { AgentDiagnostic } from "./utils/agentHangReport.ts";
|
|
4
4
|
import type { DiffCoverageState } from "./utils/diffCoverage.ts";
|
|
@@ -136,6 +136,8 @@ export interface ToolState {
|
|
|
136
136
|
output?: string | undefined;
|
|
137
137
|
usageEntries: AgentUsage[];
|
|
138
138
|
model?: string | undefined;
|
|
139
|
+
agent?: string | undefined;
|
|
140
|
+
credential?: AgentCredential | undefined;
|
|
139
141
|
modelFallback?: {
|
|
140
142
|
from: string;
|
|
141
143
|
} | undefined;
|
package/dist/utils/activity.d.ts
CHANGED
|
@@ -50,6 +50,18 @@ export declare const AGENT_ACTIVITY_TIMEOUT_MS = 900000;
|
|
|
50
50
|
*/
|
|
51
51
|
export declare const AGENT_FIRST_EVENT_TIMEOUT_MS = 120000;
|
|
52
52
|
export declare const DEFAULT_ACTIVITY_CHECK_INTERVAL_MS = 5000;
|
|
53
|
+
/**
|
|
54
|
+
* E2E affordance: shorten a watchdog budget for one dispatch, so the stall path
|
|
55
|
+
* can be exercised on demand. A real provider stall is not provocable, which is
|
|
56
|
+
* how #1085 shipped three escalations deep with its salvage branch never once
|
|
57
|
+
* run end to end.
|
|
58
|
+
*
|
|
59
|
+
* **Shorten-only, deliberately.** The value is clamped to the compiled budget,
|
|
60
|
+
* so an override can make the watchdog stricter but can never relax or disable
|
|
61
|
+
* it. That keeps this unable to manufacture the zombie run the watchdog exists
|
|
62
|
+
* to prevent, even if a customer sets it in their own workflow env.
|
|
63
|
+
*/
|
|
64
|
+
export declare function watchdogBudgetMs(compiled: number, envVar: string): number;
|
|
53
65
|
export declare const ACTIVITY_NOISE_PATTERNS: readonly RegExp[];
|
|
54
66
|
export declare function isActivityNoise(chunk: string | Uint8Array): boolean;
|
|
55
67
|
type ActivityTimeoutContext = {
|
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
* provider outage rewrite a working account's configuration.
|
|
8
8
|
*/
|
|
9
9
|
export type CredentialVerdict = "alive" | "dead" | "unknown";
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Whether asking the provider about this credential would tell us anything —
|
|
12
|
+
* the paste-time gate, where the caller stores a secret and cannot see the run
|
|
13
|
+
* env. A `hostConfigurable` credential is excluded here and stays probeable at
|
|
14
|
+
* run time, because only the runner knows whether a gateway is in play: the
|
|
15
|
+
* base URL usually lives in the workflow file, which the console never reads.
|
|
16
|
+
*/
|
|
11
17
|
export declare function isCredentialProbeable(envVar: string): boolean;
|
|
12
18
|
/**
|
|
13
19
|
* Ask the provider whether it still accepts this credential. Used at the two
|
|
@@ -10,7 +10,7 @@ import type { ToolContext } from "../mcp/server.ts";
|
|
|
10
10
|
* don't parse the audit-only `payload`.
|
|
11
11
|
* Keep in sync with `STRING_FIELDS` in `app/api/workflow-run/[runId]/route.ts`.
|
|
12
12
|
*/
|
|
13
|
-
declare const STRING_KEYS: readonly ["prNodeId", "issueNodeId", "reviewNodeId", "planCommentNodeId", "summarySnapshot", "model"];
|
|
13
|
+
declare const STRING_KEYS: readonly ["prNodeId", "issueNodeId", "reviewNodeId", "planCommentNodeId", "summarySnapshot", "model", "agent", "credential"];
|
|
14
14
|
/**
|
|
15
15
|
* Number-valued usage fields — aggregated across all agent calls and PATCHed
|
|
16
16
|
* once at end-of-run. Token counts are Int4 on the DB side (ample for any
|
package/dist/utils/payload.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export declare const JsonPayload: import("arktype/internal/variants/object.ts").
|
|
|
28
28
|
id: string;
|
|
29
29
|
} | undefined;
|
|
30
30
|
generateSummary?: boolean | undefined;
|
|
31
|
+
codexArm?: boolean | undefined;
|
|
31
32
|
}, {}>;
|
|
32
33
|
export declare const Inputs: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
33
34
|
prompt?: string | undefined;
|
|
@@ -75,6 +76,7 @@ export declare function resolvePayload(resolvedPromptInput: ResolvedPromptInput,
|
|
|
75
76
|
id: string;
|
|
76
77
|
} | undefined;
|
|
77
78
|
generateSummary: boolean | undefined;
|
|
79
|
+
codexArm: boolean | undefined;
|
|
78
80
|
push: import("../external.ts").PushPermission;
|
|
79
81
|
shell: import("../external.ts").ShellPermission;
|
|
80
82
|
runStatusCheck: boolean;
|