pullfrog 0.1.60 → 0.1.62
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 +10 -0
- package/dist/cli.mjs +108 -27
- package/dist/external.d.ts +7 -0
- package/dist/index.js +107 -26
- package/dist/toolState.d.ts +3 -1
- package/dist/utils/patchWorkflowRunFields.d.ts +1 -1
- package/dist/utils/payload.d.ts +2 -0
- package/dist/utils/providerErrors.d.ts +6 -0
- package/package.json +1 -1
package/dist/agents/shared.d.ts
CHANGED
|
@@ -52,6 +52,16 @@ export declare function hasPostRunIssues(issues: PostRunIssues): boolean;
|
|
|
52
52
|
* cache hit ratio at a glance. Dashboards that query `WorkflowRun.inputTokens`
|
|
53
53
|
* directly are seeing the full total, not the log column.
|
|
54
54
|
*/
|
|
55
|
+
/**
|
|
56
|
+
* Which credential actually paid for a run.
|
|
57
|
+
*
|
|
58
|
+
* `subscription` is the one that changes what a cost figure MEANS: a Claude
|
|
59
|
+
* Pro/Max or ChatGPT subscription moves no per-token money, so a dollar figure
|
|
60
|
+
* on such a run is what it WOULD have cost on the API, not spend. Without this
|
|
61
|
+
* recorded, `WorkflowRun.costUsd` silently mixes the two and there is no way
|
|
62
|
+
* after the fact to separate them.
|
|
63
|
+
*/
|
|
64
|
+
export type AgentCredential = "subscription" | "api_key" | "gateway" | "bedrock" | "vertex" | "foundry";
|
|
55
65
|
export interface AgentUsage {
|
|
56
66
|
agent: string;
|
|
57
67
|
/** full billable input: non-cached + cache read + cache write */
|
package/dist/cli.mjs
CHANGED
|
@@ -107293,6 +107293,9 @@ function isProviderNoRoutableEndpoints(text) {
|
|
|
107293
107293
|
function isOpenRouterKeyLimitExceeded(text) {
|
|
107294
107294
|
return /Key limit exceeded \(total limit\)/i.test(text) || /openrouter\.ai\/[^\s"')]*\/keys\//i.test(text);
|
|
107295
107295
|
}
|
|
107296
|
+
function isProviderMissingCredential(text) {
|
|
107297
|
+
return /API key is missing\. Pass it using the/i.test(text) || /Missing Authentication header/i.test(text);
|
|
107298
|
+
}
|
|
107296
107299
|
function isTransientUpstreamError(text) {
|
|
107297
107300
|
return /API Error:\s*5\d\d/i.test(text) || /\bOverloaded\b/.test(text) || /"error_type"\s*:\s*"(?:provider_unavailable|timeout)"/i.test(text) || /Streaming response failed:\s*\[5\d\d\]/i.test(text);
|
|
107298
107301
|
}
|
|
@@ -107355,7 +107358,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
107355
107358
|
// package.json
|
|
107356
107359
|
var package_default = {
|
|
107357
107360
|
name: "pullfrog",
|
|
107358
|
-
version: "0.1.
|
|
107361
|
+
version: "0.1.62",
|
|
107359
107362
|
type: "module",
|
|
107360
107363
|
bin: {
|
|
107361
107364
|
pullfrog: "dist/cli.mjs",
|
|
@@ -108446,7 +108449,6 @@ function getUnsubmittedReview(toolState, expectsReviewOutput2 = toolState.hadPro
|
|
|
108446
108449
|
}
|
|
108447
108450
|
function expectsReviewOutput(ctx) {
|
|
108448
108451
|
if (ctx.toolState.hadProgressComment) return true;
|
|
108449
|
-
if (ctx.payload.progressComments) return false;
|
|
108450
108452
|
return ctx.payload.event.silent !== true && ctx.payload.event.issue_number !== void 0;
|
|
108451
108453
|
}
|
|
108452
108454
|
function buildStopHookPrompt(failure2) {
|
|
@@ -108661,6 +108663,7 @@ async function runPostRunRetryLoop(params) {
|
|
|
108661
108663
|
result = preResume;
|
|
108662
108664
|
break;
|
|
108663
108665
|
}
|
|
108666
|
+
if (onlySummaryStale) result = { ...result, output: preResume.output || result.output };
|
|
108664
108667
|
gateResumeCount++;
|
|
108665
108668
|
}
|
|
108666
108669
|
if (gateResumeCount > 0 && result.success && hasPostRunIssues(finalIssues)) {
|
|
@@ -109481,6 +109484,19 @@ var claude = agent({
|
|
|
109481
109484
|
delete env2.CLAUDE_CODE_OAUTH_TOKEN;
|
|
109482
109485
|
}
|
|
109483
109486
|
}
|
|
109487
|
+
if (env2.CLAUDE_CODE_USE_BEDROCK) {
|
|
109488
|
+
ctx.toolState.credential = "bedrock";
|
|
109489
|
+
} else if (env2.CLAUDE_CODE_USE_VERTEX) {
|
|
109490
|
+
ctx.toolState.credential = "vertex";
|
|
109491
|
+
} else if (env2.CLAUDE_CODE_USE_FOUNDRY) {
|
|
109492
|
+
ctx.toolState.credential = "foundry";
|
|
109493
|
+
} else if (env2.ANTHROPIC_AUTH_TOKEN) {
|
|
109494
|
+
ctx.toolState.credential = "gateway";
|
|
109495
|
+
} else if (env2.ANTHROPIC_API_KEY) {
|
|
109496
|
+
ctx.toolState.credential = "api_key";
|
|
109497
|
+
} else if (env2.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
109498
|
+
ctx.toolState.credential = "subscription";
|
|
109499
|
+
}
|
|
109484
109500
|
const effortEnvOverride = env2[CLAUDE_EFFORT_ENV]?.trim();
|
|
109485
109501
|
if (effortEnvOverride) {
|
|
109486
109502
|
log2.warning(
|
|
@@ -109943,6 +109959,18 @@ function toTodoWriteInput(item) {
|
|
|
109943
109959
|
}))
|
|
109944
109960
|
};
|
|
109945
109961
|
}
|
|
109962
|
+
var CODEX_MODEL_PRICING = {
|
|
109963
|
+
"gpt-5.6-sol": { input: 5, cacheRead: 0.5, cacheWrite: 6.25, output: 30 },
|
|
109964
|
+
"gpt-5.6-luna": { input: 0.2, cacheRead: 0.02, cacheWrite: 0.25, output: 1.2 },
|
|
109965
|
+
"gpt-5.6-terra": { input: 2, cacheRead: 0.2, cacheWrite: 2.5, output: 12 }
|
|
109966
|
+
};
|
|
109967
|
+
function codexCostUsd(params) {
|
|
109968
|
+
const price = params.model ? CODEX_MODEL_PRICING[params.model] : void 0;
|
|
109969
|
+
if (!price) return void 0;
|
|
109970
|
+
const fresh = Math.max(0, params.input - params.cacheRead - params.cacheWrite);
|
|
109971
|
+
const usd = (fresh * price.input + params.cacheRead * price.cacheRead + params.cacheWrite * price.cacheWrite + params.output * price.output) / 1e6;
|
|
109972
|
+
return usd > 0 ? usd : void 0;
|
|
109973
|
+
}
|
|
109946
109974
|
async function runCodex2(params) {
|
|
109947
109975
|
const startTime = performance6.now();
|
|
109948
109976
|
const thinkingTimer = new ThinkingTimer();
|
|
@@ -109954,14 +109982,15 @@ async function runCodex2(params) {
|
|
|
109954
109982
|
let turnError = null;
|
|
109955
109983
|
let lastProviderError = null;
|
|
109956
109984
|
let stdoutBuffer = "";
|
|
109957
|
-
const tokens = { input: 0, cacheRead: 0, output: 0 };
|
|
109985
|
+
const tokens = { input: 0, cacheRead: 0, cacheWrite: 0, output: 0 };
|
|
109958
109986
|
function buildUsage2() {
|
|
109959
109987
|
if (tokens.input === 0 && tokens.output === 0) return void 0;
|
|
109960
109988
|
return {
|
|
109961
109989
|
agent: "codex",
|
|
109962
109990
|
inputTokens: tokens.input,
|
|
109963
109991
|
outputTokens: tokens.output,
|
|
109964
|
-
cacheReadTokens: tokens.cacheRead || void 0
|
|
109992
|
+
cacheReadTokens: tokens.cacheRead || void 0,
|
|
109993
|
+
costUsd: codexCostUsd({ model: params.model, ...tokens })
|
|
109965
109994
|
};
|
|
109966
109995
|
}
|
|
109967
109996
|
function onItem(item, phase) {
|
|
@@ -110026,6 +110055,7 @@ async function runCodex2(params) {
|
|
|
110026
110055
|
case "turn.completed":
|
|
110027
110056
|
tokens.input += event.usage.input_tokens ?? 0;
|
|
110028
110057
|
tokens.cacheRead += event.usage.cached_input_tokens ?? 0;
|
|
110058
|
+
tokens.cacheWrite += event.usage.cache_write_input_tokens ?? 0;
|
|
110029
110059
|
tokens.output += event.usage.output_tokens ?? 0;
|
|
110030
110060
|
return;
|
|
110031
110061
|
case "turn.failed":
|
|
@@ -110186,6 +110216,11 @@ var codex = agent({
|
|
|
110186
110216
|
} else if (process.env.OPENAI_API_KEY) {
|
|
110187
110217
|
env2.CODEX_API_KEY = process.env.OPENAI_API_KEY;
|
|
110188
110218
|
}
|
|
110219
|
+
if (codexHomeAuth) {
|
|
110220
|
+
ctx.toolState.credential = "subscription";
|
|
110221
|
+
} else if (env2.CODEX_API_KEY) {
|
|
110222
|
+
ctx.toolState.credential = "api_key";
|
|
110223
|
+
}
|
|
110189
110224
|
const securityFlags = securityOverrideFlags({
|
|
110190
110225
|
ctx,
|
|
110191
110226
|
sandboxMode: ctx.payload.push === "disabled" ? "read-only" : "workspace-write",
|
|
@@ -110194,7 +110229,13 @@ var codex = agent({
|
|
|
110194
110229
|
model: resolveCodexModel(ctx),
|
|
110195
110230
|
effortRung: effort.rung && CODEX_EFFORTS.includes(effort.rung) ? effort.rung : void 0
|
|
110196
110231
|
});
|
|
110197
|
-
const runnerArgs = {
|
|
110232
|
+
const runnerArgs = {
|
|
110233
|
+
cliPath,
|
|
110234
|
+
cwd: process.cwd(),
|
|
110235
|
+
env: env2,
|
|
110236
|
+
todoTracker: ctx.todoTracker,
|
|
110237
|
+
model: resolveCodexModel(ctx)
|
|
110238
|
+
};
|
|
110198
110239
|
const initial = await runCodex2({
|
|
110199
110240
|
...runnerArgs,
|
|
110200
110241
|
args: [...securityFlags, "exec", "--json", ctx.instructions.full],
|
|
@@ -115967,24 +116008,23 @@ async function installOpencodeCli(params) {
|
|
|
115967
116008
|
var AUTO_SELECT_WARNING = "select a model explicitly in the Pullfrog console (https://pullfrog.com/console) to avoid this \u2014 if the picker is locked, this run had no Pullfrog Router funding: add a card or top up your credit.";
|
|
115968
116009
|
function autoSelectModel() {
|
|
115969
116010
|
const authorized2 = getAuthorizedModels();
|
|
115970
|
-
|
|
115971
|
-
|
|
115972
|
-
|
|
115973
|
-
|
|
115974
|
-
|
|
115975
|
-
|
|
115976
|
-
|
|
115977
|
-
|
|
115978
|
-
log2.info(
|
|
115979
|
-
`\xBB model: ${match3.resolve} (auto-selected${match3.preferred ? " \u2014 preferred" : ""} curated match)`
|
|
115980
|
-
);
|
|
115981
|
-
log2.warning(`\xBB model auto-selected. ${AUTO_SELECT_WARNING}`);
|
|
115982
|
-
return match3.resolve;
|
|
115983
|
-
}
|
|
116011
|
+
const selectable = modelAliases.filter((a2) => !a2.hidden && !a2.fallback && !a2.routing);
|
|
116012
|
+
const servable = selectable.filter((a2) => {
|
|
116013
|
+
const envVars = getModelEnvVars(a2.resolve);
|
|
116014
|
+
return envVars.length === 0 || envVars.some((name) => process.env[name]);
|
|
116015
|
+
});
|
|
116016
|
+
const pick4 = (list) => list.find((a2) => a2.preferred) ?? list[0];
|
|
116017
|
+
const match3 = pick4(servable.filter((a2) => authorized2.has(a2.resolve))) ?? pick4(servable);
|
|
116018
|
+
if (match3) {
|
|
115984
116019
|
log2.info(
|
|
115985
|
-
`\xBB
|
|
116020
|
+
`\xBB model: ${match3.resolve} (auto-selected${match3.preferred ? " \u2014 preferred" : ""} curated match)`
|
|
115986
116021
|
);
|
|
116022
|
+
log2.warning(`\xBB model auto-selected. ${AUTO_SELECT_WARNING}`);
|
|
116023
|
+
return match3.resolve;
|
|
115987
116024
|
}
|
|
116025
|
+
log2.info(
|
|
116026
|
+
`\xBB opencode has ${authorized2.size} models but none match curated aliases and none hold a credential \u2014 letting OpenCode auto-select: ${[...authorized2].join(", ")}`
|
|
116027
|
+
);
|
|
115988
116028
|
log2.warning(`\xBB no model resolved. letting OpenCode auto-select. ${AUTO_SELECT_WARNING}`);
|
|
115989
116029
|
return void 0;
|
|
115990
116030
|
}
|
|
@@ -188596,8 +188636,8 @@ function validatePushDestination(repoState, branch, cwd) {
|
|
|
188596
188636
|
throw new Error(
|
|
188597
188637
|
`Push blocked: destination does not match expected repository.
|
|
188598
188638
|
Expected: ${pushUrl}
|
|
188599
|
-
Actual: ${dest.url}
|
|
188600
|
-
Git configuration may have been tampered with.`
|
|
188639
|
+
Actual: remote '${dest.remoteName}' -> ${dest.url}
|
|
188640
|
+
Git configuration may have been tampered with, or a url.*.insteadOf rewrite is in effect.`
|
|
188601
188641
|
);
|
|
188602
188642
|
}
|
|
188603
188643
|
return dest;
|
|
@@ -189416,7 +189456,9 @@ var STRING_KEYS = [
|
|
|
189416
189456
|
"reviewNodeId",
|
|
189417
189457
|
"planCommentNodeId",
|
|
189418
189458
|
"summarySnapshot",
|
|
189419
|
-
"model"
|
|
189459
|
+
"model",
|
|
189460
|
+
"agent",
|
|
189461
|
+
"credential"
|
|
189420
189462
|
];
|
|
189421
189463
|
var NUMBER_KEYS = [
|
|
189422
189464
|
"inputTokens",
|
|
@@ -190717,6 +190759,9 @@ async function configureRepoGit(params) {
|
|
|
190717
190759
|
removeIncludeIfEntries(repoDir);
|
|
190718
190760
|
const originUrl = `https://github.com/${params.owner}/${params.name}.git`;
|
|
190719
190761
|
$("git", ["remote", "set-url", "origin", originUrl], { cwd: repoDir });
|
|
190762
|
+
$("git", ["config", "--local", "--replace-all", "remote.origin.pushurl", originUrl], {
|
|
190763
|
+
cwd: repoDir
|
|
190764
|
+
});
|
|
190720
190765
|
repoState.pushUrl = originUrl;
|
|
190721
190766
|
$("git", ["config", "--local", "credential.helper", ""], { cwd: repoDir });
|
|
190722
190767
|
repoState.initialHead = captureInitialHead(repoDir);
|
|
@@ -191055,6 +191100,9 @@ async function checkoutPrBranch(pr, params) {
|
|
|
191055
191100
|
$("git", ["remote", "set-url", remoteName, forkUrl], { log: false });
|
|
191056
191101
|
log2.debug(`\xBB updated remote '${remoteName}' for fork ${pr.headRepoFullName}`);
|
|
191057
191102
|
}
|
|
191103
|
+
$("git", ["config", "--local", "--replace-all", `remote.${remoteName}.pushurl`, forkUrl], {
|
|
191104
|
+
log: false
|
|
191105
|
+
});
|
|
191058
191106
|
$("git", ["config", `branch.${localBranch}.pushRemote`, remoteName], { log: false });
|
|
191059
191107
|
$("git", ["config", `branch.${localBranch}.merge`, `refs/heads/${pr.headRef}`], { log: false });
|
|
191060
191108
|
log2.debug(`\xBB configured branch '${localBranch}' to push to '${remoteName}/${pr.headRef}'`);
|
|
@@ -196195,7 +196243,10 @@ var JsonPayload = type({
|
|
|
196195
196243
|
// optional so a payload from an older server build (pre-`checkRun`) still parses
|
|
196196
196244
|
// against a newer action across a rolling deploy.
|
|
196197
196245
|
"checkRun?": type({ id: "string" }).or("undefined"),
|
|
196198
|
-
"generateSummary?": "boolean | undefined"
|
|
196246
|
+
"generateSummary?": "boolean | undefined",
|
|
196247
|
+
// optional so a payload from a pre-canary server build still parses against a
|
|
196248
|
+
// newer action across a rolling deploy.
|
|
196249
|
+
"codexArm?": "boolean | undefined"
|
|
196199
196250
|
});
|
|
196200
196251
|
var COLLABORATOR_PERMISSIONS = ["admin", "maintain", "write"];
|
|
196201
196252
|
function isCollaborator(event) {
|
|
@@ -196324,6 +196375,7 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
|
196324
196375
|
progressComment: jsonPayload?.progressComment,
|
|
196325
196376
|
checkRun: jsonPayload?.checkRun,
|
|
196326
196377
|
generateSummary: jsonPayload?.generateSummary,
|
|
196378
|
+
codexArm: jsonPayload?.codexArm,
|
|
196327
196379
|
// permissions: inputs > repoSettings > fallbacks
|
|
196328
196380
|
push: inputs.push ?? repoSettings.push ?? "restricted",
|
|
196329
196381
|
shell: resolvedShell,
|
|
@@ -196872,7 +196924,7 @@ async function handleAgentResult(ctx) {
|
|
|
196872
196924
|
const mode = toolState.selectedMode;
|
|
196873
196925
|
const isReviewMode = mode === "Review" || mode === "IncrementalReview";
|
|
196874
196926
|
const payload = ctx.toolContext.payload;
|
|
196875
|
-
const hasCommentTarget = toolState.hadProgressComment ||
|
|
196927
|
+
const hasCommentTarget = toolState.hadProgressComment || payload.event.issue_number !== void 0;
|
|
196876
196928
|
if (!isReviewMode && !toolState.wasUpdated && hasCommentTarget && !ctx.silent) {
|
|
196877
196929
|
const tracker = toolState.todoTracker;
|
|
196878
196930
|
if (tracker) {
|
|
@@ -197306,6 +197358,19 @@ ${input.errorMessage}
|
|
|
197306
197358
|
\`\`\``
|
|
197307
197359
|
].join("\n");
|
|
197308
197360
|
}
|
|
197361
|
+
function formatProviderMissingCredential(input) {
|
|
197362
|
+
return [
|
|
197363
|
+
"**No credential reached the model provider.**",
|
|
197364
|
+
"",
|
|
197365
|
+
"The run started without a key for the provider it ended up using, so the request was refused before any model work happened. Nothing was billed, and no key of yours was rejected \u2014 add a provider key, or pick a model you already have one for.",
|
|
197366
|
+
"",
|
|
197367
|
+
`[Configure model \u2192](${getApiUrl()}/console/${input.owner}/${input.name})`,
|
|
197368
|
+
"",
|
|
197369
|
+
`\`\`\`
|
|
197370
|
+
${input.errorMessage}
|
|
197371
|
+
\`\`\``
|
|
197372
|
+
].join("\n");
|
|
197373
|
+
}
|
|
197309
197374
|
function formatProviderModelNotFoundSummary(input) {
|
|
197310
197375
|
return `The configured model is no longer available in OpenCode's catalog. Pick a different model in the Pullfrog console for \`${input.owner}/${input.name}\`, or contact support if this persists.
|
|
197311
197376
|
|
|
@@ -197351,6 +197416,16 @@ ${body}`, comment: body };
|
|
|
197351
197416
|
});
|
|
197352
197417
|
return { summary: `### \u274C Pullfrog failed
|
|
197353
197418
|
|
|
197419
|
+
${body}`, comment: body };
|
|
197420
|
+
}
|
|
197421
|
+
if (isProviderMissingCredential(input.errorMessage)) {
|
|
197422
|
+
const body = formatProviderMissingCredential({
|
|
197423
|
+
owner: input.repo.owner,
|
|
197424
|
+
name: input.repo.name,
|
|
197425
|
+
errorMessage: input.errorMessage
|
|
197426
|
+
});
|
|
197427
|
+
return { summary: `### \u274C Pullfrog failed
|
|
197428
|
+
|
|
197354
197429
|
${body}`, comment: body };
|
|
197355
197430
|
}
|
|
197356
197431
|
const apiKeySource = hangBody ?? input.errorMessage;
|
|
@@ -198268,8 +198343,12 @@ async function main() {
|
|
|
198268
198343
|
const agent2 = resolveAgent({
|
|
198269
198344
|
model: resolvedModel,
|
|
198270
198345
|
proxyModel: payload.proxyModel,
|
|
198271
|
-
|
|
198346
|
+
// the account opt-in and the canary arm are both admissions to codex, so
|
|
198347
|
+
// they OR: an account that opted in explicitly always gets it, and the
|
|
198348
|
+
// canary widens the pool without ever demoting a run that already had it.
|
|
198349
|
+
codexAgent: runContext.repoSettings.codexAgent || payload.codexArm === true
|
|
198272
198350
|
});
|
|
198351
|
+
toolState.agent = agent2.name;
|
|
198273
198352
|
const effectiveModel = payload.proxyModel ?? resolvedModel ?? payload.model;
|
|
198274
198353
|
toolState.model = effectiveModel;
|
|
198275
198354
|
if (!payload.proxyModel) {
|
|
@@ -198627,6 +198706,8 @@ ${instructions.user}` : null,
|
|
|
198627
198706
|
if (toolContext) {
|
|
198628
198707
|
const patch = aggregateUsage(toolState.usageEntries);
|
|
198629
198708
|
if (toolState.model) patch.model = toolState.model;
|
|
198709
|
+
if (toolState.agent) patch.agent = toolState.agent;
|
|
198710
|
+
if (toolState.credential) patch.credential = toolState.credential;
|
|
198630
198711
|
if (Object.keys(patch).length > 0) {
|
|
198631
198712
|
await patchWorkflowRunFields(toolContext, patch);
|
|
198632
198713
|
}
|
|
@@ -199184,7 +199265,7 @@ async function runCli4(input) {
|
|
|
199184
199265
|
}
|
|
199185
199266
|
|
|
199186
199267
|
// cli.ts
|
|
199187
|
-
var VERSION10 = "0.1.
|
|
199268
|
+
var VERSION10 = "0.1.62";
|
|
199188
199269
|
var bin = basename2(process.argv[1] || "");
|
|
199189
199270
|
var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
|
|
199190
199271
|
var rawArgs = process.argv.slice(2);
|
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
|
@@ -105126,6 +105126,9 @@ function isProviderNoRoutableEndpoints(text) {
|
|
|
105126
105126
|
function isOpenRouterKeyLimitExceeded(text) {
|
|
105127
105127
|
return /Key limit exceeded \(total limit\)/i.test(text) || /openrouter\.ai\/[^\s"')]*\/keys\//i.test(text);
|
|
105128
105128
|
}
|
|
105129
|
+
function isProviderMissingCredential(text) {
|
|
105130
|
+
return /API key is missing\. Pass it using the/i.test(text) || /Missing Authentication header/i.test(text);
|
|
105131
|
+
}
|
|
105129
105132
|
function isTransientUpstreamError(text) {
|
|
105130
105133
|
return /API Error:\s*5\d\d/i.test(text) || /\bOverloaded\b/.test(text) || /"error_type"\s*:\s*"(?:provider_unavailable|timeout)"/i.test(text) || /Streaming response failed:\s*\[5\d\d\]/i.test(text);
|
|
105131
105134
|
}
|
|
@@ -105188,7 +105191,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
105188
105191
|
// package.json
|
|
105189
105192
|
var package_default = {
|
|
105190
105193
|
name: "pullfrog",
|
|
105191
|
-
version: "0.1.
|
|
105194
|
+
version: "0.1.62",
|
|
105192
105195
|
type: "module",
|
|
105193
105196
|
bin: {
|
|
105194
105197
|
pullfrog: "dist/cli.mjs",
|
|
@@ -106279,7 +106282,6 @@ function getUnsubmittedReview(toolState, expectsReviewOutput2 = toolState.hadPro
|
|
|
106279
106282
|
}
|
|
106280
106283
|
function expectsReviewOutput(ctx) {
|
|
106281
106284
|
if (ctx.toolState.hadProgressComment) return true;
|
|
106282
|
-
if (ctx.payload.progressComments) return false;
|
|
106283
106285
|
return ctx.payload.event.silent !== true && ctx.payload.event.issue_number !== void 0;
|
|
106284
106286
|
}
|
|
106285
106287
|
function buildStopHookPrompt(failure2) {
|
|
@@ -106494,6 +106496,7 @@ async function runPostRunRetryLoop(params) {
|
|
|
106494
106496
|
result = preResume;
|
|
106495
106497
|
break;
|
|
106496
106498
|
}
|
|
106499
|
+
if (onlySummaryStale) result = { ...result, output: preResume.output || result.output };
|
|
106497
106500
|
gateResumeCount++;
|
|
106498
106501
|
}
|
|
106499
106502
|
if (gateResumeCount > 0 && result.success && hasPostRunIssues(finalIssues)) {
|
|
@@ -107314,6 +107317,19 @@ var claude = agent({
|
|
|
107314
107317
|
delete env2.CLAUDE_CODE_OAUTH_TOKEN;
|
|
107315
107318
|
}
|
|
107316
107319
|
}
|
|
107320
|
+
if (env2.CLAUDE_CODE_USE_BEDROCK) {
|
|
107321
|
+
ctx.toolState.credential = "bedrock";
|
|
107322
|
+
} else if (env2.CLAUDE_CODE_USE_VERTEX) {
|
|
107323
|
+
ctx.toolState.credential = "vertex";
|
|
107324
|
+
} else if (env2.CLAUDE_CODE_USE_FOUNDRY) {
|
|
107325
|
+
ctx.toolState.credential = "foundry";
|
|
107326
|
+
} else if (env2.ANTHROPIC_AUTH_TOKEN) {
|
|
107327
|
+
ctx.toolState.credential = "gateway";
|
|
107328
|
+
} else if (env2.ANTHROPIC_API_KEY) {
|
|
107329
|
+
ctx.toolState.credential = "api_key";
|
|
107330
|
+
} else if (env2.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
107331
|
+
ctx.toolState.credential = "subscription";
|
|
107332
|
+
}
|
|
107317
107333
|
const effortEnvOverride = env2[CLAUDE_EFFORT_ENV]?.trim();
|
|
107318
107334
|
if (effortEnvOverride) {
|
|
107319
107335
|
log.warning(
|
|
@@ -107823,6 +107839,18 @@ function toTodoWriteInput(item) {
|
|
|
107823
107839
|
}))
|
|
107824
107840
|
};
|
|
107825
107841
|
}
|
|
107842
|
+
var CODEX_MODEL_PRICING = {
|
|
107843
|
+
"gpt-5.6-sol": { input: 5, cacheRead: 0.5, cacheWrite: 6.25, output: 30 },
|
|
107844
|
+
"gpt-5.6-luna": { input: 0.2, cacheRead: 0.02, cacheWrite: 0.25, output: 1.2 },
|
|
107845
|
+
"gpt-5.6-terra": { input: 2, cacheRead: 0.2, cacheWrite: 2.5, output: 12 }
|
|
107846
|
+
};
|
|
107847
|
+
function codexCostUsd(params) {
|
|
107848
|
+
const price = params.model ? CODEX_MODEL_PRICING[params.model] : void 0;
|
|
107849
|
+
if (!price) return void 0;
|
|
107850
|
+
const fresh = Math.max(0, params.input - params.cacheRead - params.cacheWrite);
|
|
107851
|
+
const usd = (fresh * price.input + params.cacheRead * price.cacheRead + params.cacheWrite * price.cacheWrite + params.output * price.output) / 1e6;
|
|
107852
|
+
return usd > 0 ? usd : void 0;
|
|
107853
|
+
}
|
|
107826
107854
|
async function runCodex(params) {
|
|
107827
107855
|
const startTime = performance6.now();
|
|
107828
107856
|
const thinkingTimer = new ThinkingTimer();
|
|
@@ -107834,14 +107862,15 @@ async function runCodex(params) {
|
|
|
107834
107862
|
let turnError = null;
|
|
107835
107863
|
let lastProviderError = null;
|
|
107836
107864
|
let stdoutBuffer = "";
|
|
107837
|
-
const tokens = { input: 0, cacheRead: 0, output: 0 };
|
|
107865
|
+
const tokens = { input: 0, cacheRead: 0, cacheWrite: 0, output: 0 };
|
|
107838
107866
|
function buildUsage2() {
|
|
107839
107867
|
if (tokens.input === 0 && tokens.output === 0) return void 0;
|
|
107840
107868
|
return {
|
|
107841
107869
|
agent: "codex",
|
|
107842
107870
|
inputTokens: tokens.input,
|
|
107843
107871
|
outputTokens: tokens.output,
|
|
107844
|
-
cacheReadTokens: tokens.cacheRead || void 0
|
|
107872
|
+
cacheReadTokens: tokens.cacheRead || void 0,
|
|
107873
|
+
costUsd: codexCostUsd({ model: params.model, ...tokens })
|
|
107845
107874
|
};
|
|
107846
107875
|
}
|
|
107847
107876
|
function onItem(item, phase) {
|
|
@@ -107906,6 +107935,7 @@ async function runCodex(params) {
|
|
|
107906
107935
|
case "turn.completed":
|
|
107907
107936
|
tokens.input += event.usage.input_tokens ?? 0;
|
|
107908
107937
|
tokens.cacheRead += event.usage.cached_input_tokens ?? 0;
|
|
107938
|
+
tokens.cacheWrite += event.usage.cache_write_input_tokens ?? 0;
|
|
107909
107939
|
tokens.output += event.usage.output_tokens ?? 0;
|
|
107910
107940
|
return;
|
|
107911
107941
|
case "turn.failed":
|
|
@@ -108066,6 +108096,11 @@ var codex = agent({
|
|
|
108066
108096
|
} else if (process.env.OPENAI_API_KEY) {
|
|
108067
108097
|
env2.CODEX_API_KEY = process.env.OPENAI_API_KEY;
|
|
108068
108098
|
}
|
|
108099
|
+
if (codexHomeAuth) {
|
|
108100
|
+
ctx.toolState.credential = "subscription";
|
|
108101
|
+
} else if (env2.CODEX_API_KEY) {
|
|
108102
|
+
ctx.toolState.credential = "api_key";
|
|
108103
|
+
}
|
|
108069
108104
|
const securityFlags = securityOverrideFlags({
|
|
108070
108105
|
ctx,
|
|
108071
108106
|
sandboxMode: ctx.payload.push === "disabled" ? "read-only" : "workspace-write",
|
|
@@ -108074,7 +108109,13 @@ var codex = agent({
|
|
|
108074
108109
|
model: resolveCodexModel(ctx),
|
|
108075
108110
|
effortRung: effort.rung && CODEX_EFFORTS.includes(effort.rung) ? effort.rung : void 0
|
|
108076
108111
|
});
|
|
108077
|
-
const runnerArgs = {
|
|
108112
|
+
const runnerArgs = {
|
|
108113
|
+
cliPath,
|
|
108114
|
+
cwd: process.cwd(),
|
|
108115
|
+
env: env2,
|
|
108116
|
+
todoTracker: ctx.todoTracker,
|
|
108117
|
+
model: resolveCodexModel(ctx)
|
|
108118
|
+
};
|
|
108078
108119
|
const initial = await runCodex({
|
|
108079
108120
|
...runnerArgs,
|
|
108080
108121
|
args: [...securityFlags, "exec", "--json", ctx.instructions.full],
|
|
@@ -113847,24 +113888,23 @@ async function installOpencodeCli(params) {
|
|
|
113847
113888
|
var AUTO_SELECT_WARNING = "select a model explicitly in the Pullfrog console (https://pullfrog.com/console) to avoid this \u2014 if the picker is locked, this run had no Pullfrog Router funding: add a card or top up your credit.";
|
|
113848
113889
|
function autoSelectModel() {
|
|
113849
113890
|
const authorized2 = getAuthorizedModels();
|
|
113850
|
-
|
|
113851
|
-
|
|
113852
|
-
|
|
113853
|
-
|
|
113854
|
-
|
|
113855
|
-
|
|
113856
|
-
|
|
113857
|
-
|
|
113858
|
-
log.info(
|
|
113859
|
-
`\xBB model: ${match3.resolve} (auto-selected${match3.preferred ? " \u2014 preferred" : ""} curated match)`
|
|
113860
|
-
);
|
|
113861
|
-
log.warning(`\xBB model auto-selected. ${AUTO_SELECT_WARNING}`);
|
|
113862
|
-
return match3.resolve;
|
|
113863
|
-
}
|
|
113891
|
+
const selectable = modelAliases.filter((a) => !a.hidden && !a.fallback && !a.routing);
|
|
113892
|
+
const servable = selectable.filter((a) => {
|
|
113893
|
+
const envVars = getModelEnvVars(a.resolve);
|
|
113894
|
+
return envVars.length === 0 || envVars.some((name) => process.env[name]);
|
|
113895
|
+
});
|
|
113896
|
+
const pick4 = (list) => list.find((a) => a.preferred) ?? list[0];
|
|
113897
|
+
const match3 = pick4(servable.filter((a) => authorized2.has(a.resolve))) ?? pick4(servable);
|
|
113898
|
+
if (match3) {
|
|
113864
113899
|
log.info(
|
|
113865
|
-
`\xBB
|
|
113900
|
+
`\xBB model: ${match3.resolve} (auto-selected${match3.preferred ? " \u2014 preferred" : ""} curated match)`
|
|
113866
113901
|
);
|
|
113902
|
+
log.warning(`\xBB model auto-selected. ${AUTO_SELECT_WARNING}`);
|
|
113903
|
+
return match3.resolve;
|
|
113867
113904
|
}
|
|
113905
|
+
log.info(
|
|
113906
|
+
`\xBB opencode has ${authorized2.size} models but none match curated aliases and none hold a credential \u2014 letting OpenCode auto-select: ${[...authorized2].join(", ")}`
|
|
113907
|
+
);
|
|
113868
113908
|
log.warning(`\xBB no model resolved. letting OpenCode auto-select. ${AUTO_SELECT_WARNING}`);
|
|
113869
113909
|
return void 0;
|
|
113870
113910
|
}
|
|
@@ -186476,8 +186516,8 @@ function validatePushDestination(repoState, branch, cwd) {
|
|
|
186476
186516
|
throw new Error(
|
|
186477
186517
|
`Push blocked: destination does not match expected repository.
|
|
186478
186518
|
Expected: ${pushUrl}
|
|
186479
|
-
Actual: ${dest.url}
|
|
186480
|
-
Git configuration may have been tampered with.`
|
|
186519
|
+
Actual: remote '${dest.remoteName}' -> ${dest.url}
|
|
186520
|
+
Git configuration may have been tampered with, or a url.*.insteadOf rewrite is in effect.`
|
|
186481
186521
|
);
|
|
186482
186522
|
}
|
|
186483
186523
|
return dest;
|
|
@@ -187296,7 +187336,9 @@ var STRING_KEYS = [
|
|
|
187296
187336
|
"reviewNodeId",
|
|
187297
187337
|
"planCommentNodeId",
|
|
187298
187338
|
"summarySnapshot",
|
|
187299
|
-
"model"
|
|
187339
|
+
"model",
|
|
187340
|
+
"agent",
|
|
187341
|
+
"credential"
|
|
187300
187342
|
];
|
|
187301
187343
|
var NUMBER_KEYS = [
|
|
187302
187344
|
"inputTokens",
|
|
@@ -188597,6 +188639,9 @@ async function configureRepoGit(params) {
|
|
|
188597
188639
|
removeIncludeIfEntries(repoDir);
|
|
188598
188640
|
const originUrl = `https://github.com/${params.owner}/${params.name}.git`;
|
|
188599
188641
|
$("git", ["remote", "set-url", "origin", originUrl], { cwd: repoDir });
|
|
188642
|
+
$("git", ["config", "--local", "--replace-all", "remote.origin.pushurl", originUrl], {
|
|
188643
|
+
cwd: repoDir
|
|
188644
|
+
});
|
|
188600
188645
|
repoState.pushUrl = originUrl;
|
|
188601
188646
|
$("git", ["config", "--local", "credential.helper", ""], { cwd: repoDir });
|
|
188602
188647
|
repoState.initialHead = captureInitialHead(repoDir);
|
|
@@ -188935,6 +188980,9 @@ async function checkoutPrBranch(pr, params) {
|
|
|
188935
188980
|
$("git", ["remote", "set-url", remoteName, forkUrl], { log: false });
|
|
188936
188981
|
log.debug(`\xBB updated remote '${remoteName}' for fork ${pr.headRepoFullName}`);
|
|
188937
188982
|
}
|
|
188983
|
+
$("git", ["config", "--local", "--replace-all", `remote.${remoteName}.pushurl`, forkUrl], {
|
|
188984
|
+
log: false
|
|
188985
|
+
});
|
|
188938
188986
|
$("git", ["config", `branch.${localBranch}.pushRemote`, remoteName], { log: false });
|
|
188939
188987
|
$("git", ["config", `branch.${localBranch}.merge`, `refs/heads/${pr.headRef}`], { log: false });
|
|
188940
188988
|
log.debug(`\xBB configured branch '${localBranch}' to push to '${remoteName}/${pr.headRef}'`);
|
|
@@ -194075,7 +194123,10 @@ var JsonPayload = type({
|
|
|
194075
194123
|
// optional so a payload from an older server build (pre-`checkRun`) still parses
|
|
194076
194124
|
// against a newer action across a rolling deploy.
|
|
194077
194125
|
"checkRun?": type({ id: "string" }).or("undefined"),
|
|
194078
|
-
"generateSummary?": "boolean | undefined"
|
|
194126
|
+
"generateSummary?": "boolean | undefined",
|
|
194127
|
+
// optional so a payload from a pre-canary server build still parses against a
|
|
194128
|
+
// newer action across a rolling deploy.
|
|
194129
|
+
"codexArm?": "boolean | undefined"
|
|
194079
194130
|
});
|
|
194080
194131
|
var COLLABORATOR_PERMISSIONS = ["admin", "maintain", "write"];
|
|
194081
194132
|
function isCollaborator(event) {
|
|
@@ -194204,6 +194255,7 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
|
194204
194255
|
progressComment: jsonPayload?.progressComment,
|
|
194205
194256
|
checkRun: jsonPayload?.checkRun,
|
|
194206
194257
|
generateSummary: jsonPayload?.generateSummary,
|
|
194258
|
+
codexArm: jsonPayload?.codexArm,
|
|
194207
194259
|
// permissions: inputs > repoSettings > fallbacks
|
|
194208
194260
|
push: inputs.push ?? repoSettings.push ?? "restricted",
|
|
194209
194261
|
shell: resolvedShell,
|
|
@@ -194752,7 +194804,7 @@ async function handleAgentResult(ctx) {
|
|
|
194752
194804
|
const mode = toolState.selectedMode;
|
|
194753
194805
|
const isReviewMode = mode === "Review" || mode === "IncrementalReview";
|
|
194754
194806
|
const payload = ctx.toolContext.payload;
|
|
194755
|
-
const hasCommentTarget = toolState.hadProgressComment ||
|
|
194807
|
+
const hasCommentTarget = toolState.hadProgressComment || payload.event.issue_number !== void 0;
|
|
194756
194808
|
if (!isReviewMode && !toolState.wasUpdated && hasCommentTarget && !ctx.silent) {
|
|
194757
194809
|
const tracker = toolState.todoTracker;
|
|
194758
194810
|
if (tracker) {
|
|
@@ -195186,6 +195238,19 @@ ${input.errorMessage}
|
|
|
195186
195238
|
\`\`\``
|
|
195187
195239
|
].join("\n");
|
|
195188
195240
|
}
|
|
195241
|
+
function formatProviderMissingCredential(input) {
|
|
195242
|
+
return [
|
|
195243
|
+
"**No credential reached the model provider.**",
|
|
195244
|
+
"",
|
|
195245
|
+
"The run started without a key for the provider it ended up using, so the request was refused before any model work happened. Nothing was billed, and no key of yours was rejected \u2014 add a provider key, or pick a model you already have one for.",
|
|
195246
|
+
"",
|
|
195247
|
+
`[Configure model \u2192](${getApiUrl()}/console/${input.owner}/${input.name})`,
|
|
195248
|
+
"",
|
|
195249
|
+
`\`\`\`
|
|
195250
|
+
${input.errorMessage}
|
|
195251
|
+
\`\`\``
|
|
195252
|
+
].join("\n");
|
|
195253
|
+
}
|
|
195189
195254
|
function formatProviderModelNotFoundSummary(input) {
|
|
195190
195255
|
return `The configured model is no longer available in OpenCode's catalog. Pick a different model in the Pullfrog console for \`${input.owner}/${input.name}\`, or contact support if this persists.
|
|
195191
195256
|
|
|
@@ -195231,6 +195296,16 @@ ${body}`, comment: body };
|
|
|
195231
195296
|
});
|
|
195232
195297
|
return { summary: `### \u274C Pullfrog failed
|
|
195233
195298
|
|
|
195299
|
+
${body}`, comment: body };
|
|
195300
|
+
}
|
|
195301
|
+
if (isProviderMissingCredential(input.errorMessage)) {
|
|
195302
|
+
const body = formatProviderMissingCredential({
|
|
195303
|
+
owner: input.repo.owner,
|
|
195304
|
+
name: input.repo.name,
|
|
195305
|
+
errorMessage: input.errorMessage
|
|
195306
|
+
});
|
|
195307
|
+
return { summary: `### \u274C Pullfrog failed
|
|
195308
|
+
|
|
195234
195309
|
${body}`, comment: body };
|
|
195235
195310
|
}
|
|
195236
195311
|
const apiKeySource = hangBody ?? input.errorMessage;
|
|
@@ -196148,8 +196223,12 @@ async function main() {
|
|
|
196148
196223
|
const agent2 = resolveAgent({
|
|
196149
196224
|
model: resolvedModel,
|
|
196150
196225
|
proxyModel: payload.proxyModel,
|
|
196151
|
-
|
|
196226
|
+
// the account opt-in and the canary arm are both admissions to codex, so
|
|
196227
|
+
// they OR: an account that opted in explicitly always gets it, and the
|
|
196228
|
+
// canary widens the pool without ever demoting a run that already had it.
|
|
196229
|
+
codexAgent: runContext.repoSettings.codexAgent || payload.codexArm === true
|
|
196152
196230
|
});
|
|
196231
|
+
toolState.agent = agent2.name;
|
|
196153
196232
|
const effectiveModel = payload.proxyModel ?? resolvedModel ?? payload.model;
|
|
196154
196233
|
toolState.model = effectiveModel;
|
|
196155
196234
|
if (!payload.proxyModel) {
|
|
@@ -196507,6 +196586,8 @@ ${instructions.user}` : null,
|
|
|
196507
196586
|
if (toolContext) {
|
|
196508
196587
|
const patch = aggregateUsage(toolState.usageEntries);
|
|
196509
196588
|
if (toolState.model) patch.model = toolState.model;
|
|
196589
|
+
if (toolState.agent) patch.agent = toolState.agent;
|
|
196590
|
+
if (toolState.credential) patch.credential = toolState.credential;
|
|
196510
196591
|
if (Object.keys(patch).length > 0) {
|
|
196511
196592
|
await patchWorkflowRunFields(toolContext, patch);
|
|
196512
196593
|
}
|
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;
|
|
@@ -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;
|
|
@@ -50,6 +50,12 @@ export declare function isProviderNoRoutableEndpoints(text: string): boolean;
|
|
|
50
50
|
* …/settings/credits`) carries no `/keys/` path and correctly stays out.
|
|
51
51
|
*/
|
|
52
52
|
export declare function isOpenRouterKeyLimitExceeded(text: string): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* the provider was reached with NO credential at all — the AI SDK's shared `loadApiKey`
|
|
55
|
+
* refusal, so it is provider-agnostic. NOT `isApiKeyAuthError`, which is a key we hold
|
|
56
|
+
* being rejected: "rotate your key" names a credential that does not exist here.
|
|
57
|
+
*/
|
|
58
|
+
export declare function isProviderMissingCredential(text: string): boolean;
|
|
53
59
|
/**
|
|
54
60
|
* The upstream is having a moment: Anthropic's `API Error: 529 Overloaded`,
|
|
55
61
|
* OpenRouter's `provider_unavailable` / `timeout`, OpenCode Zen's `Streaming
|