pullfrog 0.1.99 → 0.1.101
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/cli.mjs +689 -737
- package/dist/external.d.ts +1 -1
- package/dist/index.js +687 -735
- package/dist/internal/index.d.ts +3 -2
- package/dist/internal.js +70 -19
- package/dist/models.d.ts +4 -0
- package/dist/toolState.d.ts +2 -4
- package/dist/utils/agentHangReport.d.ts +6 -10
- package/dist/utils/apiKeys.d.ts +47 -7
- package/dist/utils/billingErrors.d.ts +6 -3
- package/dist/utils/buildPullfrogFooter.d.ts +17 -4
- package/dist/utils/errorReport.d.ts +0 -1
- package/dist/utils/failureBody.d.ts +27 -0
- package/dist/utils/leapingComment.d.ts +9 -0
- package/dist/utils/proxy.d.ts +1 -0
- package/dist/utils/roleMirror.d.ts +3 -2
- package/dist/utils/runContext.d.ts +3 -0
- package/dist/utils/runContextData.d.ts +2 -0
- package/dist/utils/runErrorRenderer.d.ts +44 -69
- package/dist/utils/secretCommands.d.ts +5 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -64099,7 +64099,7 @@ var require_receiver2 = __commonJS({
|
|
|
64099
64099
|
const buffer = this.consume(2);
|
|
64100
64100
|
const fin = (buffer[0] & 128) !== 0;
|
|
64101
64101
|
const opcode = buffer[0] & 15;
|
|
64102
|
-
const
|
|
64102
|
+
const masked2 = (buffer[1] & 128) === 128;
|
|
64103
64103
|
const fragmented = !fin && opcode !== opcodes.CONTINUATION;
|
|
64104
64104
|
const payloadLength = buffer[1] & 127;
|
|
64105
64105
|
const rsv1 = buffer[0] & 64;
|
|
@@ -64109,7 +64109,7 @@ var require_receiver2 = __commonJS({
|
|
|
64109
64109
|
failWebsocketConnection(this.#handler, 1002, "Invalid opcode received");
|
|
64110
64110
|
return callback();
|
|
64111
64111
|
}
|
|
64112
|
-
if (
|
|
64112
|
+
if (masked2) {
|
|
64113
64113
|
failWebsocketConnection(this.#handler, 1002, "Frame cannot be masked");
|
|
64114
64114
|
return callback();
|
|
64115
64115
|
}
|
|
@@ -64157,7 +64157,7 @@ var require_receiver2 = __commonJS({
|
|
|
64157
64157
|
this.#info.compressed = rsv1 !== 0;
|
|
64158
64158
|
}
|
|
64159
64159
|
this.#info.opcode = opcode;
|
|
64160
|
-
this.#info.masked =
|
|
64160
|
+
this.#info.masked = masked2;
|
|
64161
64161
|
this.#info.fin = fin;
|
|
64162
64162
|
this.#info.fragmented = fragmented;
|
|
64163
64163
|
} else if (this.#state === parserStates.PAYLOADLENGTH_16) {
|
|
@@ -103526,9 +103526,9 @@ var providers = {
|
|
|
103526
103526
|
models: {
|
|
103527
103527
|
"gemini-pro": {
|
|
103528
103528
|
displayName: "Gemini Pro",
|
|
103529
|
-
resolve: "google/gemini-
|
|
103529
|
+
resolve: "google/gemini-4-argon",
|
|
103530
103530
|
effort: ["low", "medium", "high"],
|
|
103531
|
-
openRouterResolve: "openrouter/google/gemini-
|
|
103531
|
+
openRouterResolve: "openrouter/google/gemini-4-argon",
|
|
103532
103532
|
preferred: true
|
|
103533
103533
|
// Inherit (subagents stay on Pro). Google has no in-between tier;
|
|
103534
103534
|
// dropping to Flash for review work was a meaningful capability cliff
|
|
@@ -103718,7 +103718,7 @@ var providers = {
|
|
|
103718
103718
|
displayName: "Kimi K3",
|
|
103719
103719
|
description: "1M context, but only on Allegretto and above \xB7 Moderato caps it at 256K",
|
|
103720
103720
|
resolve: "kimi-code-plan-cn/k3",
|
|
103721
|
-
effort: ["low", "high", "max"],
|
|
103721
|
+
effort: ["none", "low", "high", "max"],
|
|
103722
103722
|
subagentModel: "kimi-k2"
|
|
103723
103723
|
},
|
|
103724
103724
|
// `preferred` sits on the 256K variant rather than the 1M flagship, which
|
|
@@ -103733,7 +103733,7 @@ var providers = {
|
|
|
103733
103733
|
displayName: "Kimi K3 256K",
|
|
103734
103734
|
description: "Same model at 256K for ~half the quota \xB7 Moderato or above",
|
|
103735
103735
|
resolve: "kimi-code-plan-cn/k3-256k",
|
|
103736
|
-
effort: ["low", "high", "max"],
|
|
103736
|
+
effort: ["none", "low", "high", "max"],
|
|
103737
103737
|
preferred: true,
|
|
103738
103738
|
subagentModel: "kimi-k2"
|
|
103739
103739
|
},
|
|
@@ -103741,9 +103741,10 @@ var providers = {
|
|
|
103741
103741
|
displayName: "Kimi K2",
|
|
103742
103742
|
description: "Included in every Kimi membership tier",
|
|
103743
103743
|
resolve: "kimi-code-plan-cn/kimi-for-coding",
|
|
103744
|
-
// models.dev published
|
|
103745
|
-
// mirrors it, so main was red until the
|
|
103746
|
-
|
|
103744
|
+
// models.dev published `low, high, max` on 2026-09-14 and added `none`
|
|
103745
|
+
// on 2026-10-19; the catalog gate mirrors it, so main was red until the
|
|
103746
|
+
// alias carried it too.
|
|
103747
|
+
effort: ["none", "low", "high", "max"]
|
|
103747
103748
|
},
|
|
103748
103749
|
"kimi-k2-highspeed": {
|
|
103749
103750
|
displayName: "Kimi K2 HighSpeed",
|
|
@@ -103913,9 +103914,9 @@ var providers = {
|
|
|
103913
103914
|
},
|
|
103914
103915
|
"gemini-pro": {
|
|
103915
103916
|
displayName: "Gemini Pro",
|
|
103916
|
-
resolve: "opencode/gemini-
|
|
103917
|
+
resolve: "opencode/gemini-4-argon",
|
|
103917
103918
|
effort: ["low", "medium", "high"],
|
|
103918
|
-
openRouterResolve: "openrouter/google/gemini-
|
|
103919
|
+
openRouterResolve: "openrouter/google/gemini-4-argon"
|
|
103919
103920
|
// Inherit — see google/gemini-pro for rationale.
|
|
103920
103921
|
},
|
|
103921
103922
|
"gemini-flash": {
|
|
@@ -104647,8 +104648,8 @@ var providers = {
|
|
|
104647
104648
|
},
|
|
104648
104649
|
"gemini-pro": {
|
|
104649
104650
|
displayName: "Gemini Pro",
|
|
104650
|
-
resolve: "vercel/google/gemini-
|
|
104651
|
-
effort: ["low", "high"]
|
|
104651
|
+
resolve: "vercel/google/gemini-4-argon",
|
|
104652
|
+
effort: ["low", "medium", "high"]
|
|
104652
104653
|
},
|
|
104653
104654
|
"gemini-flash": {
|
|
104654
104655
|
displayName: "Gemini Flash",
|
|
@@ -104867,6 +104868,13 @@ if (!defaultProxyAlias?.openRouterResolve) {
|
|
|
104867
104868
|
}
|
|
104868
104869
|
var DEFAULT_PROXY_MODEL = defaultProxyAlias.openRouterResolve;
|
|
104869
104870
|
var defaultProxyDisplayName = defaultProxyAlias.displayName;
|
|
104871
|
+
var trialProxyAlias = resolveDisplayAlias("openai/gpt-luna");
|
|
104872
|
+
if (!trialProxyAlias?.openRouterResolve) {
|
|
104873
|
+
throw new Error("TRIAL_PROXY_MODEL: openai/gpt-luna has no openRouterResolve");
|
|
104874
|
+
}
|
|
104875
|
+
var TRIAL_PROXY_MODEL = trialProxyAlias.openRouterResolve;
|
|
104876
|
+
var TRIAL_PROXY_DISPLAY_NAME = trialProxyAlias.displayName;
|
|
104877
|
+
var TRIAL_FUNDED_USD_LIMIT = 10;
|
|
104870
104878
|
for (const [name, ladder] of Object.entries({ ...PROVIDER_LADDERS, router: ROUTER_LADDER })) {
|
|
104871
104879
|
const terminal = /* @__PURE__ */ new Set();
|
|
104872
104880
|
for (const slug2 of Object.values(ladder)) {
|
|
@@ -105574,6 +105582,8 @@ var PROVIDER_ERROR_PATTERNS = [
|
|
|
105574
105582
|
},
|
|
105575
105583
|
// OpenAI's `You have no credits remaining` (#1474).
|
|
105576
105584
|
{ regex: /no credits remaining/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
|
|
105585
|
+
// Codex on a ChatGPT workspace: `Your workspace is out of credits. Add credits to continue.`
|
|
105586
|
+
{ regex: /workspace is out of credits/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
|
|
105577
105587
|
{ regex: /credit balance is too low/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
|
|
105578
105588
|
// "spending cap" (Gemini) and "spending limit" (xAI, #1076) are the same
|
|
105579
105589
|
// condition in two house styles — a configured ceiling was reached.
|
|
@@ -105603,6 +105613,9 @@ var PROVIDER_ERROR_PATTERNS = [
|
|
|
105603
105613
|
// succeeds" while the same log held nine of these. Measured on a live account
|
|
105604
105614
|
// whose ChatGPT subscription was capped.
|
|
105605
105615
|
{ regex: /\bthe usage limit has been reached\b/i, label: PROVIDER_USAGE_LIMIT_LABEL },
|
|
105616
|
+
// the Codex CLI's wording for the same capped plan: `You’ve hit your usage limit. … try
|
|
105617
|
+
// again at 7:58 AM.` Claude's `hit your session limit` names its window and stays out.
|
|
105618
|
+
{ regex: /\bhit your usage limit\b/i, label: PROVIDER_USAGE_LIMIT_LABEL },
|
|
105606
105619
|
// the OpenRouter shapes `isRouterKeylimitExhaustedError` matches. on a Router
|
|
105607
105620
|
// run those mean the PULLFROG wallet is empty and `renderRunError` returns a
|
|
105608
105621
|
// `BillingError` before ever reaching this list; on a BYOK run the very same
|
|
@@ -105707,7 +105720,8 @@ function isProviderMissingCredential(text) {
|
|
|
105707
105720
|
return /API key is missing\. Pass it using the/i.test(text) || /Missing Authentication header/i.test(text);
|
|
105708
105721
|
}
|
|
105709
105722
|
function isTransientUpstreamError(text) {
|
|
105710
|
-
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)
|
|
105723
|
+
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) || // the Codex CLI's `Selected model is at capacity. Please try a different model.`
|
|
105724
|
+
/\bmodel is at capacity\b/i.test(text);
|
|
105711
105725
|
}
|
|
105712
105726
|
function extractProviderId(text) {
|
|
105713
105727
|
const match3 = text.match(/\bproviderID=([a-z0-9_-]+)/i);
|
|
@@ -105768,7 +105782,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
105768
105782
|
// package.json
|
|
105769
105783
|
var package_default = {
|
|
105770
105784
|
name: "pullfrog",
|
|
105771
|
-
version: "0.1.
|
|
105785
|
+
version: "0.1.101",
|
|
105772
105786
|
cliContractVersion: "1",
|
|
105773
105787
|
type: "module",
|
|
105774
105788
|
bin: {
|
|
@@ -110267,9 +110281,20 @@ var SUBSCRIPTION_DATA_DIR_STATE = "subscription_data_dir";
|
|
|
110267
110281
|
|
|
110268
110282
|
// utils/secretCommands.ts
|
|
110269
110283
|
var core3 = __toESM(require_core(), 1);
|
|
110284
|
+
var masked = /* @__PURE__ */ new Set();
|
|
110270
110285
|
function maskSecret(value2) {
|
|
110286
|
+
masked.add(value2);
|
|
110271
110287
|
if (isGitHubActions) core3.setSecret(value2);
|
|
110272
110288
|
}
|
|
110289
|
+
function redactSecrets(text) {
|
|
110290
|
+
let redacted = text;
|
|
110291
|
+
for (const value2 of masked) {
|
|
110292
|
+
for (const part of [value2, ...value2.split("\n").map((line) => line.trim())]) {
|
|
110293
|
+
if (part.length >= 8) redacted = redacted.replaceAll(part, "***");
|
|
110294
|
+
}
|
|
110295
|
+
}
|
|
110296
|
+
return redacted;
|
|
110297
|
+
}
|
|
110273
110298
|
function saveSecretState(name, value2) {
|
|
110274
110299
|
if (isGitHubActions) core3.saveState(name, value2);
|
|
110275
110300
|
}
|
|
@@ -189091,7 +189116,7 @@ function formatModelLabel(params) {
|
|
|
189091
189116
|
}
|
|
189092
189117
|
const base = alias?.isFree ? `\`${modelName}\` (free)` : `\`${modelName}\``;
|
|
189093
189118
|
if (params.clamped?.reason === "trial") {
|
|
189094
|
-
return `${base} (
|
|
189119
|
+
return `${base} (free trial credits)`;
|
|
189095
189120
|
}
|
|
189096
189121
|
if (params.clamped) {
|
|
189097
189122
|
const target = isAutoTier(params.clamped.from) ? "the intelligent tier" : `\`${resolveDisplayAlias(params.clamped.from)?.displayName ?? params.clamped.from}\``;
|
|
@@ -189102,13 +189127,14 @@ function formatModelLabel(params) {
|
|
|
189102
189127
|
}
|
|
189103
189128
|
return base;
|
|
189104
189129
|
}
|
|
189105
|
-
function buildTrialDisclosure(
|
|
189106
|
-
const consoleUrl = owner ? `https://pullfrog.com/console/${owner}` : "https://pullfrog.com/console";
|
|
189130
|
+
function buildTrialDisclosure(params) {
|
|
189131
|
+
const consoleUrl = params.owner ? `https://pullfrog.com/console/${params.owner}#billing` : "https://pullfrog.com/console";
|
|
189132
|
+
const left = params.creditsLeftUsd === void 0 ? "" : ` ($${Math.max(0, params.creditsLeftUsd).toFixed(2)} of $${TRIAL_FUNDED_USD_LIMIT} left)`;
|
|
189107
189133
|
return [
|
|
189108
189134
|
"---",
|
|
189109
189135
|
"",
|
|
189110
189136
|
"> [!IMPORTANT]",
|
|
189111
|
-
`> **
|
|
189137
|
+
`> **This run used your free trial credits**${left} on \`${TRIAL_PROXY_DISPLAY_NAME}\`, a fast, lightweight model. [Connect a provider \u2192](${consoleUrl}) to run the model you choose.`
|
|
189112
189138
|
].join("\n");
|
|
189113
189139
|
}
|
|
189114
189140
|
function buildPullfrogFooter(params) {
|
|
@@ -189131,13 +189157,13 @@ function buildPullfrogFooter(params) {
|
|
|
189131
189157
|
`Using ${formatModelLabel({
|
|
189132
189158
|
model: params.model,
|
|
189133
189159
|
clamped: params.clamped,
|
|
189134
|
-
unselectedProxyDefault: params.unselectedProxyDefault,
|
|
189160
|
+
unselectedProxyDefault: params.unselectedProxyDefault && !params.failed,
|
|
189135
189161
|
oss: params.oss
|
|
189136
189162
|
})}`
|
|
189137
189163
|
);
|
|
189138
189164
|
}
|
|
189139
|
-
const allParts = [...parts, "[\u{1D54F}](https://x.com/pullfrogai)"];
|
|
189140
|
-
const disclosure = params.clamped?.reason === "trial" ? `${buildTrialDisclosure(params.owner)}
|
|
189165
|
+
const allParts = params.failed ? parts : [...parts, "[\u{1D54F}](https://x.com/pullfrogai)"];
|
|
189166
|
+
const disclosure = params.clamped?.reason === "trial" && !params.failed ? `${buildTrialDisclosure({ owner: params.owner, creditsLeftUsd: params.clamped.creditsLeftUsd })}
|
|
189141
189167
|
|
|
189142
189168
|
` : "";
|
|
189143
189169
|
return `
|
|
@@ -189315,7 +189341,8 @@ async function fetchRunContext(params) {
|
|
|
189315
189341
|
credentialAccess: data.credentialAccess,
|
|
189316
189342
|
secretsUnavailable: data.secretsUnavailable,
|
|
189317
189343
|
routerUnfunded: data.routerUnfunded,
|
|
189318
|
-
trialFallback: data.trialFallback
|
|
189344
|
+
trialFallback: data.trialFallback,
|
|
189345
|
+
trialCreditsLeftUsd: data.trialCreditsLeftUsd
|
|
189319
189346
|
};
|
|
189320
189347
|
} catch {
|
|
189321
189348
|
clearTimeout(timeoutId);
|
|
@@ -189429,6 +189456,9 @@ function aggregateUsage(entries) {
|
|
|
189429
189456
|
return out;
|
|
189430
189457
|
}
|
|
189431
189458
|
|
|
189459
|
+
// utils/leapingComment.ts
|
|
189460
|
+
var TODO_SPINNER_URL = "https://uploads.pullfrog.com/Progress%20Indicator.gif";
|
|
189461
|
+
|
|
189432
189462
|
// mcp/comment.ts
|
|
189433
189463
|
function isNotFoundError(error49) {
|
|
189434
189464
|
return error49 instanceof Error && error49.message.includes("Not Found");
|
|
@@ -191540,7 +191570,7 @@ function mirrorRolePermissions(role) {
|
|
|
191540
191570
|
case "maintain":
|
|
191541
191571
|
case "write":
|
|
191542
191572
|
case "triage":
|
|
191543
|
-
return { contents: "read", issues: "write", pull_requests: "write" };
|
|
191573
|
+
return { checks: "read", contents: "read", issues: "write", pull_requests: "write" };
|
|
191544
191574
|
case "read":
|
|
191545
191575
|
case "none":
|
|
191546
191576
|
case void 0:
|
|
@@ -194209,6 +194239,40 @@ function subagentDeniedToolNames(ctx, outputSchema) {
|
|
|
194209
194239
|
return names;
|
|
194210
194240
|
}
|
|
194211
194241
|
|
|
194242
|
+
// utils/failureBody.ts
|
|
194243
|
+
function renderFailure(params) {
|
|
194244
|
+
const blocks = [
|
|
194245
|
+
params.detail ? `**${params.headline}** ${params.detail}` : `**${params.headline}**`
|
|
194246
|
+
];
|
|
194247
|
+
if (params.list) blocks.push(params.list.map((item) => `- ${item}`).join("\n"));
|
|
194248
|
+
if (params.error) blocks.push(fenced(params.error));
|
|
194249
|
+
if (params.details) {
|
|
194250
|
+
blocks.push(
|
|
194251
|
+
`<details><summary>${params.details.summary}</summary>
|
|
194252
|
+
|
|
194253
|
+
${fenced(params.details.text)}
|
|
194254
|
+
|
|
194255
|
+
</details>`
|
|
194256
|
+
);
|
|
194257
|
+
}
|
|
194258
|
+
if (params.links?.length) {
|
|
194259
|
+
blocks.push(params.links.map((link) => `[${link.label} \u2192](${link.url})`).join(" \xB7 "));
|
|
194260
|
+
}
|
|
194261
|
+
return blocks.join("\n\n");
|
|
194262
|
+
}
|
|
194263
|
+
function fenced(text) {
|
|
194264
|
+
let longest = 0;
|
|
194265
|
+
for (const match3 of text.matchAll(/`+/g)) longest = Math.max(longest, match3[0].length);
|
|
194266
|
+
const fence = "`".repeat(Math.max(3, longest + 1));
|
|
194267
|
+
return `${fence}
|
|
194268
|
+
${text}
|
|
194269
|
+
${fence}`;
|
|
194270
|
+
}
|
|
194271
|
+
var DISCORD_LINK = {
|
|
194272
|
+
label: "Ask in Discord",
|
|
194273
|
+
url: "https://discord.gg/8y96raFg8e"
|
|
194274
|
+
};
|
|
194275
|
+
|
|
194212
194276
|
// utils/providerDashboards.ts
|
|
194213
194277
|
var PROVIDER_DASHBOARDS = {
|
|
194214
194278
|
anthropic: {
|
|
@@ -194319,134 +194383,145 @@ var PROVIDER_DASHBOARDS = {
|
|
|
194319
194383
|
};
|
|
194320
194384
|
|
|
194321
194385
|
// utils/apiKeys.ts
|
|
194322
|
-
var MISSING_KEY_MARKER = "
|
|
194323
|
-
var BYOK_SLUG_MARKER = "
|
|
194324
|
-
var BYOK_CONFIG_MARKER = "
|
|
194386
|
+
var MISSING_KEY_MARKER = "No API key found";
|
|
194387
|
+
var BYOK_SLUG_MARKER = "must be set when the model is";
|
|
194388
|
+
var BYOK_CONFIG_MARKER = "is missing required settings:";
|
|
194325
194389
|
var BYOK_SETUP_PATTERN = new RegExp(
|
|
194326
|
-
`^(
|
|
194390
|
+
`^(?:\`[A-Z][A-Z0-9_]+\` ${BYOK_SLUG_MARKER}|[A-Z][\\w-]*(?: [\\w-]+){0,3} ${BYOK_CONFIG_MARKER})`
|
|
194327
194391
|
);
|
|
194328
194392
|
function isByokSetupError(text) {
|
|
194329
194393
|
return BYOK_SETUP_PATTERN.test(text);
|
|
194330
194394
|
}
|
|
194331
|
-
var SECRETS_UNAVAILABLE_MARKER = "couldn't load your
|
|
194332
|
-
var ROUTER_UNFUNDED_MARKER = "
|
|
194395
|
+
var SECRETS_UNAVAILABLE_MARKER = "couldn't load your stored secrets";
|
|
194396
|
+
var ROUTER_UNFUNDED_MARKER = "Your Pullfrog Router balance is empty";
|
|
194397
|
+
var TRIAL_SPENT_MARKER = "reached the limit of your free trial credits";
|
|
194398
|
+
function buildTrialSpentError(params) {
|
|
194399
|
+
return renderFailure({
|
|
194400
|
+
headline: `You've ${TRIAL_SPENT_MARKER}.`,
|
|
194401
|
+
detail: `Your $${TRIAL_FUNDED_USD_LIMIT} of trial usage credits have been used up, so you'll need to connect a provider to continue using Pullfrog.`,
|
|
194402
|
+
links: [providerLink(params.owner)]
|
|
194403
|
+
});
|
|
194404
|
+
}
|
|
194405
|
+
function repoConsoleUrl(repo) {
|
|
194406
|
+
return `${getApiUrl()}/console/${repo.owner}/${repo.name}`;
|
|
194407
|
+
}
|
|
194408
|
+
function pickModelLink(repo) {
|
|
194409
|
+
return { label: "Pick another model", url: repoConsoleUrl(repo) };
|
|
194410
|
+
}
|
|
194411
|
+
function providerLink(owner) {
|
|
194412
|
+
return { label: "Connect a provider", url: `${getApiUrl()}/console/${owner}#billing` };
|
|
194413
|
+
}
|
|
194333
194414
|
var CREDENTIAL_REJECTED_MARKER = "was rejected by its provider";
|
|
194334
194415
|
var CREDENTIAL_POOL_REFUSED_MARKER = "No configured credential can serve this run";
|
|
194335
194416
|
var NoUsableCredentialError = class extends Error {
|
|
194336
194417
|
};
|
|
194337
194418
|
function throwKeyError(params) {
|
|
194338
|
-
if (params.secretsUnavailable) throw new Error(buildSecretsUnavailableError(
|
|
194419
|
+
if (params.secretsUnavailable) throw new Error(buildSecretsUnavailableError());
|
|
194339
194420
|
if (params.routerUnfunded) throw new NoUsableCredentialError(buildRouterUnfundedError(params));
|
|
194340
194421
|
throw new NoUsableCredentialError(buildMissingApiKeyError(params));
|
|
194341
194422
|
}
|
|
194342
194423
|
function buildRouterUnfundedError(params) {
|
|
194343
|
-
|
|
194344
|
-
|
|
194345
|
-
|
|
194346
|
-
|
|
194347
|
-
|
|
194348
|
-
|
|
194349
|
-
|
|
194350
|
-
"",
|
|
194351
|
-
`[Top up Router \u2192](${billingUrl}) \xB7 [Model settings \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](https://docs.pullfrog.com/keys) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`
|
|
194352
|
-
].join("\n");
|
|
194424
|
+
return renderFailure({
|
|
194425
|
+
headline: `${ROUTER_UNFUNDED_MARKER}, and this repo has no API key to fall back on.`,
|
|
194426
|
+
detail: "Add Router credit, or connect your own provider key or subscription.",
|
|
194427
|
+
links: [
|
|
194428
|
+
{ label: "Billing and providers", url: `${getApiUrl()}/console/${params.owner}#billing` }
|
|
194429
|
+
]
|
|
194430
|
+
});
|
|
194353
194431
|
}
|
|
194354
|
-
function buildSecretsUnavailableError(
|
|
194355
|
-
|
|
194356
|
-
|
|
194357
|
-
|
|
194358
|
-
|
|
194359
|
-
|
|
194360
|
-
"**To fix:** re-run the job. If it keeps happening, tell us in Discord.",
|
|
194361
|
-
"",
|
|
194362
|
-
`[Model settings \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](https://docs.pullfrog.com/keys) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`
|
|
194363
|
-
].join("\n");
|
|
194432
|
+
function buildSecretsUnavailableError() {
|
|
194433
|
+
return renderFailure({
|
|
194434
|
+
headline: `Pullfrog ${SECRETS_UNAVAILABLE_MARKER} for this run.`,
|
|
194435
|
+
detail: "They're still saved; this is a temporary failure on our side. Re-trigger to try again, and tell us in Discord if it keeps happening.",
|
|
194436
|
+
links: [DISCORD_LINK]
|
|
194437
|
+
});
|
|
194364
194438
|
}
|
|
194365
194439
|
function buildMissingApiKeyError(params) {
|
|
194366
|
-
const githubSecretsUrl = `https://github.com/${params.owner}/${params.name}/settings/secrets/actions`;
|
|
194367
|
-
const settingsUrl = `${getApiUrl()}/console/${params.owner}/${params.name}`;
|
|
194368
194440
|
const envVars = params.model?.includes("/") ? getModelEnvVars(params.model) : [];
|
|
194369
194441
|
const [primary, ...alternates] = envVars;
|
|
194370
194442
|
const envVarList = primary ? `\`${primary}\`${alternates.length > 0 ? ` (or ${alternates.map((v) => `\`${v}\``).join(" / ")})` : ""}` : void 0;
|
|
194371
|
-
const
|
|
194443
|
+
const alias = params.model ? resolveDisplayAlias(params.model) ?? modelAliases.find((a) => !a.fallback && a.resolve === params.model) : void 0;
|
|
194444
|
+
const modelName = params.model ? alias?.displayName ?? `\`${params.model}\`` : void 0;
|
|
194372
194445
|
const unhosted = params.model?.includes("/") ? getModelManagedCredentials(params.model).find((name) => unhostedSubscriptions.has(name)) : void 0;
|
|
194373
|
-
const
|
|
194446
|
+
const detail = unhosted ? `Your ${SUBSCRIPTION_CREDENTIALS[unhosted]?.label} is stored, but this runner has no passwordless \`sudo\`, which Pullfrog needs to keep it in \`${PULLFROG_DATA_DIR}\`, out of the agent's reach. Allow passwordless \`sudo\` for the runner user, run on a GitHub-hosted runner, or add an API key.` : envVarList ? `It needs ${envVarList}. Connect it in Pullfrog or add it as a GitHub Actions secret, or pick a model you already have a key for.` : "Pullfrog needs a key or subscription for at least one model provider. Connect one in Pullfrog, or add a key as a GitHub Actions secret.";
|
|
194447
|
+
return renderFailure({
|
|
194448
|
+
headline: envVarList && modelName ? `${MISSING_KEY_MARKER} for ${modelName}.` : `${MISSING_KEY_MARKER}.`,
|
|
194449
|
+
detail,
|
|
194450
|
+
links: [providerLink(params.owner), pickModelLink(params)]
|
|
194451
|
+
});
|
|
194452
|
+
}
|
|
194453
|
+
function buildSetupError(params) {
|
|
194454
|
+
const missing = params.missing.map((name) => `\`${name}\``).join(", ");
|
|
194374
194455
|
return [
|
|
194375
|
-
|
|
194376
|
-
|
|
194377
|
-
|
|
194378
|
-
|
|
194379
|
-
|
|
194380
|
-
].join("\n");
|
|
194456
|
+
`${params.provider} ${BYOK_CONFIG_MARKER} ${missing}. ${params.where}`,
|
|
194457
|
+
`\`\`\`yaml
|
|
194458
|
+
${params.env.join("\n")}
|
|
194459
|
+
\`\`\``,
|
|
194460
|
+
`${params.note ? `${params.note} ` : ""}[${params.provider} setup guide](${params.guide})`
|
|
194461
|
+
].join("\n\n");
|
|
194462
|
+
}
|
|
194463
|
+
function secretsUrl(params) {
|
|
194464
|
+
return `https://github.com/${params.owner}/${params.name}/settings/secrets/actions`;
|
|
194381
194465
|
}
|
|
194382
194466
|
function buildBedrockSetupError(params) {
|
|
194383
|
-
|
|
194384
|
-
|
|
194385
|
-
|
|
194386
|
-
|
|
194387
|
-
|
|
194388
|
-
|
|
194389
|
-
|
|
194390
|
-
|
|
194391
|
-
|
|
194392
|
-
|
|
194393
|
-
|
|
194394
|
-
|
|
194467
|
+
return buildSetupError({
|
|
194468
|
+
provider: "Amazon Bedrock",
|
|
194469
|
+
missing: params.missing,
|
|
194470
|
+
where: `Add them to [this repo's Actions secrets](${secretsUrl(params)}) and pass them in the workflow's \`env:\` block:`,
|
|
194471
|
+
env: [
|
|
194472
|
+
`AWS_BEARER_TOKEN_BEDROCK: \${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}`,
|
|
194473
|
+
`AWS_REGION: \${{ secrets.AWS_REGION }}`,
|
|
194474
|
+
`${BEDROCK_MODEL_ID_ENV}: \${{ secrets.${BEDROCK_MODEL_ID_ENV} }}`
|
|
194475
|
+
],
|
|
194476
|
+
note: "`AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` (plus `AWS_SESSION_TOKEN` if you use one) can replace the bearer token.",
|
|
194477
|
+
guide: "https://docs.pullfrog.com/bedrock"
|
|
194478
|
+
});
|
|
194395
194479
|
}
|
|
194396
194480
|
function buildVertexSetupError(params) {
|
|
194397
|
-
|
|
194398
|
-
|
|
194399
|
-
|
|
194400
|
-
|
|
194401
|
-
|
|
194402
|
-
|
|
194403
|
-
|
|
194404
|
-
|
|
194405
|
-
|
|
194406
|
-
|
|
194407
|
-
|
|
194481
|
+
return buildSetupError({
|
|
194482
|
+
provider: "Google Vertex AI",
|
|
194483
|
+
missing: params.missing,
|
|
194484
|
+
where: `Add the service account to [this repo's Actions secrets](${secretsUrl(params)}) and set the rest in the workflow's \`env:\` block:`,
|
|
194485
|
+
env: [
|
|
194486
|
+
`${VERTEX_SERVICE_ACCOUNT_JSON_ENV}: \${{ secrets.${VERTEX_SERVICE_ACCOUNT_JSON_ENV} }}`,
|
|
194487
|
+
`${GOOGLE_CLOUD_PROJECT_ENV}: my-project`,
|
|
194488
|
+
`${VERTEX_LOCATION_ENV}: global`,
|
|
194489
|
+
`${VERTEX_MODEL_ID_ENV}: <vertex-model-id>`
|
|
194490
|
+
],
|
|
194491
|
+
guide: "https://docs.pullfrog.com/vertex"
|
|
194492
|
+
});
|
|
194408
194493
|
}
|
|
194409
194494
|
function buildOpenAICompatibleSetupError(params) {
|
|
194410
|
-
|
|
194411
|
-
|
|
194412
|
-
|
|
194413
|
-
|
|
194414
|
-
|
|
194415
|
-
|
|
194416
|
-
|
|
194417
|
-
|
|
194418
|
-
|
|
194419
|
-
|
|
194420
|
-
|
|
194421
|
-
|
|
194422
|
-
|
|
194423
|
-
|
|
194424
|
-
auto-compaction is disabled, so long runs grow until your endpoint refuses them.
|
|
194425
|
-
|
|
194426
|
-
for full setup instructions, see https://docs.pullfrog.com/openai-compatible`;
|
|
194495
|
+
return buildSetupError({
|
|
194496
|
+
provider: "OpenAI-compatible endpoint",
|
|
194497
|
+
missing: params.missing,
|
|
194498
|
+
where: `Set them on the OpenAI-compatible provider in [Pullfrog's provider settings](${getApiUrl()}/console/${params.owner}#billing), or in the workflow's \`env:\` block with the key as an [Actions secret](${secretsUrl(params)}):`,
|
|
194499
|
+
env: [
|
|
194500
|
+
`${OPENAI_COMPATIBLE_BASE_URL_ENV}: https://your-endpoint.example.com/v1`,
|
|
194501
|
+
`${OPENAI_COMPATIBLE_API_KEY_ENV}: \${{ secrets.${OPENAI_COMPATIBLE_API_KEY_ENV} }}`,
|
|
194502
|
+
`${OPENAI_COMPATIBLE_MODEL_ENV}: <model-id>`,
|
|
194503
|
+
`${OPENAI_COMPATIBLE_CONTEXT_ENV}: "128000"`,
|
|
194504
|
+
`${OPENAI_COMPATIBLE_MAX_OUTPUT_ENV}: "16384"`
|
|
194505
|
+
],
|
|
194506
|
+
note: "Use the real context and output limits of the model your endpoint serves: Pullfrog can't discover them, and without them long runs grow until the endpoint refuses them.",
|
|
194507
|
+
guide: "https://docs.pullfrog.com/openai-compatible"
|
|
194508
|
+
});
|
|
194427
194509
|
}
|
|
194428
194510
|
function buildAzureSetupError(params) {
|
|
194429
|
-
|
|
194430
|
-
|
|
194431
|
-
|
|
194432
|
-
|
|
194433
|
-
|
|
194434
|
-
|
|
194435
|
-
|
|
194436
|
-
|
|
194437
|
-
|
|
194438
|
-
|
|
194439
|
-
|
|
194440
|
-
|
|
194441
|
-
|
|
194442
|
-
|
|
194443
|
-
|
|
194444
|
-
set the last two to the real limits of whichever model your deployment serves. Pullfrog can't
|
|
194445
|
-
discover them \u2014 a deployment name carries no catalog metadata \u2014 and without them completions
|
|
194446
|
-
are capped at 32000 tokens (rejected outright by models with a smaller cap) and auto-compaction
|
|
194447
|
-
is disabled, so long runs grow until Azure refuses them.
|
|
194448
|
-
|
|
194449
|
-
for full setup instructions, see https://docs.pullfrog.com/azure`;
|
|
194511
|
+
return buildSetupError({
|
|
194512
|
+
provider: "Azure OpenAI",
|
|
194513
|
+
missing: params.missing,
|
|
194514
|
+
where: `Set them on the Azure OpenAI provider in [Pullfrog's provider settings](${getApiUrl()}/console/${params.owner}#billing), or in the workflow's \`env:\` block with the key as an [Actions secret](${secretsUrl(params)}):`,
|
|
194515
|
+
env: [
|
|
194516
|
+
`${AZURE_RESOURCE_NAME_ENV}: <name>`,
|
|
194517
|
+
`${AZURE_API_KEY_ENV}: \${{ secrets.${AZURE_API_KEY_ENV} }}`,
|
|
194518
|
+
`${AZURE_DEPLOYMENT_ENV}: <deployment-name>`,
|
|
194519
|
+
`${AZURE_CONTEXT_ENV}: "400000"`,
|
|
194520
|
+
`${AZURE_MAX_OUTPUT_ENV}: "128000"`
|
|
194521
|
+
],
|
|
194522
|
+
note: `\`${AZURE_RESOURCE_NAME_ENV}\` is the \`<name>\` in \`https://<name>.openai.azure.com\`, and \`${AZURE_DEPLOYMENT_ENV}\` is the deployment's name, not the model it serves. Use that model's real context and output limits: Pullfrog can't discover them, and without them long runs grow until Azure refuses them.`,
|
|
194523
|
+
guide: "https://docs.pullfrog.com/azure"
|
|
194524
|
+
});
|
|
194450
194525
|
}
|
|
194451
194526
|
function hasEnvVar2(name) {
|
|
194452
194527
|
const value2 = process.env[name];
|
|
@@ -194606,7 +194681,7 @@ function isMalformedKeyError(text) {
|
|
|
194606
194681
|
return /Header '\d+' has invalid value/i.test(text);
|
|
194607
194682
|
}
|
|
194608
194683
|
function isClaudeSubscriptionDisabledError(text) {
|
|
194609
|
-
return /disabled Claude subscription access/i.test(text);
|
|
194684
|
+
return /disabled Claude subscription access/i.test(text) || /OAuth authentication is currently not allowed for this organization/i.test(text);
|
|
194610
194685
|
}
|
|
194611
194686
|
function isKimiPlanTierError(text) {
|
|
194612
194687
|
return /Your current (?:subscription does not have access to|plan supports only)\b/i.test(text);
|
|
@@ -194619,138 +194694,179 @@ var SUBSCRIPTION_CREDENTIALS = {
|
|
|
194619
194694
|
CLAUDE_CODE_OAUTH_TOKEN: {
|
|
194620
194695
|
label: "Claude Pro/Max subscription",
|
|
194621
194696
|
command: "pullfrog auth claude",
|
|
194622
|
-
|
|
194697
|
+
provider: "anthropic"
|
|
194623
194698
|
},
|
|
194624
194699
|
CODEX_AUTH_JSON: {
|
|
194625
194700
|
label: "ChatGPT subscription",
|
|
194626
194701
|
command: "pullfrog auth codex",
|
|
194627
|
-
|
|
194702
|
+
provider: "openai"
|
|
194628
194703
|
},
|
|
194629
194704
|
GROK_AUTH_JSON: {
|
|
194630
194705
|
label: "Grok subscription",
|
|
194631
194706
|
command: "pullfrog auth grok",
|
|
194632
|
-
|
|
194707
|
+
provider: "xai"
|
|
194633
194708
|
}
|
|
194634
194709
|
};
|
|
194710
|
+
function subscriptionFor(model) {
|
|
194711
|
+
const provider2 = model?.split("/")[0];
|
|
194712
|
+
for (const [env2, subscription] of Object.entries(SUBSCRIPTION_CREDENTIALS)) {
|
|
194713
|
+
if (subscription.provider === provider2) return { env: env2, ...subscription };
|
|
194714
|
+
}
|
|
194715
|
+
return void 0;
|
|
194716
|
+
}
|
|
194717
|
+
var SIGN_IN_AGAIN = (command) => `Sign in again by running \`${command}\` in a terminal`;
|
|
194718
|
+
var CLAUDE_ORG_DISABLED = {
|
|
194719
|
+
headline: "Your Claude organization doesn't allow subscription sign-in for Claude Code.",
|
|
194720
|
+
detail: "Ask its admin to allow it in the Claude Console, or connect an Anthropic API key instead."
|
|
194721
|
+
};
|
|
194722
|
+
function providerDisplayName(id) {
|
|
194723
|
+
for (const [key, provider2] of Object.entries(providers)) {
|
|
194724
|
+
if (key === id) return provider2.displayName;
|
|
194725
|
+
}
|
|
194726
|
+
return void 0;
|
|
194727
|
+
}
|
|
194635
194728
|
function buildRejectedCredentialError(params) {
|
|
194636
|
-
const settingsUrl = `${getApiUrl()}/console/${params.owner}/${params.name}`;
|
|
194637
194729
|
const subscription = SUBSCRIPTION_CREDENTIALS[params.credential];
|
|
194638
|
-
const
|
|
194730
|
+
const details = params.reason ? { summary: "The provider's response", text: params.reason } : void 0;
|
|
194639
194731
|
if (subscription) {
|
|
194640
|
-
|
|
194641
|
-
|
|
194642
|
-
|
|
194643
|
-
|
|
194644
|
-
|
|
194645
|
-
|
|
194646
|
-
|
|
194647
|
-
}
|
|
194648
|
-
const
|
|
194649
|
-
const keysUrl =
|
|
194650
|
-
const
|
|
194651
|
-
|
|
194652
|
-
|
|
194653
|
-
|
|
194654
|
-
|
|
194655
|
-
""
|
|
194656
|
-
|
|
194657
|
-
|
|
194658
|
-
}
|
|
194659
|
-
|
|
194732
|
+
const orgDisabled = params.reason !== void 0 && isClaudeSubscriptionDisabledError(params.reason);
|
|
194733
|
+
return renderFailure({
|
|
194734
|
+
headline: `Your ${subscription.label} ${CREDENTIAL_REJECTED_MARKER}.`,
|
|
194735
|
+
detail: orgDisabled ? `${CLAUDE_ORG_DISABLED.headline} ${CLAUDE_ORG_DISABLED.detail}` : `${SIGN_IN_AGAIN(subscription.command)}, or pick a model you have an API key for.`,
|
|
194736
|
+
details,
|
|
194737
|
+
links: [orgDisabled ? providerLink(params.owner) : pickModelLink(params)]
|
|
194738
|
+
});
|
|
194739
|
+
}
|
|
194740
|
+
const provider2 = credentialProvider(params.credential);
|
|
194741
|
+
const keysUrl = provider2 ? PROVIDER_DASHBOARDS[provider2.id]?.keys : void 0;
|
|
194742
|
+
const update = params.inPullfrogStore ? {
|
|
194743
|
+
label: "Update it in Pullfrog",
|
|
194744
|
+
url: `${getApiUrl()}/console/${params.owner}/${params.name}`
|
|
194745
|
+
} : { label: "Update the Actions secret", url: secretsUrl(params) };
|
|
194746
|
+
return renderFailure({
|
|
194747
|
+
headline: `Your ${provider2 ? `${provider2.displayName} key` : "key"} \`${params.credential}\` ${CREDENTIAL_REJECTED_MARKER}.`,
|
|
194748
|
+
detail: `Issue a new key and update the copy ${params.inPullfrogStore ? "stored in Pullfrog" : "in this repo's GitHub Actions secrets"}.`,
|
|
194749
|
+
details,
|
|
194750
|
+
links: keysUrl ? [{ label: "Issue a new key", url: keysUrl }, update] : [update]
|
|
194751
|
+
});
|
|
194752
|
+
}
|
|
194753
|
+
function credentialProvider(credential) {
|
|
194660
194754
|
for (const [id, provider2] of Object.entries(providers)) {
|
|
194661
|
-
if (provider2.envVars.includes(credential)) return
|
|
194755
|
+
if (provider2.envVars.includes(credential)) return { id, displayName: provider2.displayName };
|
|
194662
194756
|
}
|
|
194663
194757
|
return void 0;
|
|
194664
194758
|
}
|
|
194665
194759
|
function buildCredentialPoolRefusedError(params) {
|
|
194666
|
-
const
|
|
194667
|
-
|
|
194668
|
-
|
|
194669
|
-
|
|
194670
|
-
|
|
194671
|
-
|
|
194672
|
-
|
|
194673
|
-
|
|
194674
|
-
|
|
194675
|
-
|
|
194760
|
+
const [first = "", second, ...rest] = params.refused.map(
|
|
194761
|
+
(credential) => describeRefusal({ credential, owner: params.owner, name: params.name })
|
|
194762
|
+
);
|
|
194763
|
+
return renderFailure({
|
|
194764
|
+
headline: `${CREDENTIAL_POOL_REFUSED_MARKER}.`,
|
|
194765
|
+
detail: second === void 0 ? first : `Every credential for \`${params.model}\` was turned down:`,
|
|
194766
|
+
list: second === void 0 ? void 0 : [first, second, ...rest],
|
|
194767
|
+
details: {
|
|
194768
|
+
summary: "The providers' responses",
|
|
194769
|
+
text: params.refused.map((credential) => `${credential.name}: ${credential.verdict.detail}`).join("\n")
|
|
194770
|
+
},
|
|
194771
|
+
links: [pickModelLink(params)]
|
|
194772
|
+
});
|
|
194676
194773
|
}
|
|
194677
194774
|
function describeRefusal(params) {
|
|
194678
194775
|
const credential = params.credential;
|
|
194679
194776
|
const verdict = credential.verdict;
|
|
194680
|
-
const workflow = credential.source === "workflow";
|
|
194681
|
-
const head = `\`${credential.name}\` from ${workflow ? "the workflow" : `${credential.source} scope`}: \`${verdict.detail}\` \u2014`;
|
|
194682
194777
|
const subscription = SUBSCRIPTION_CREDENTIALS[credential.name];
|
|
194683
|
-
const dashboard =
|
|
194778
|
+
const dashboard = PROVIDER_DASHBOARDS[credentialProvider(credential.name)?.id ?? ""];
|
|
194779
|
+
const what = subscription ? `Your ${subscription.label}` : `Your \`${credential.name}\``;
|
|
194684
194780
|
if (verdict.status === "exhausted" && subscription) {
|
|
194685
|
-
const
|
|
194686
|
-
return `${
|
|
194781
|
+
const reset = verdict.resetAt ? `, which resets at **${verdict.resetAt.toISOString().slice(0, 16).replace("T", " ")} UTC**` : "";
|
|
194782
|
+
return `${what} has hit its usage limit${reset}. Re-trigger after it resets, or add an API key for this provider, which Pullfrog falls back to automatically.`;
|
|
194783
|
+
}
|
|
194784
|
+
if (verdict.status === "exhausted") {
|
|
194785
|
+
return `${what} is out of credit or quota. ${dashboard ? `[Add credit](${dashboard.billing})` : "Add credit"} with the provider, or raise its quota.`;
|
|
194687
194786
|
}
|
|
194688
|
-
if (verdict.
|
|
194689
|
-
return `${
|
|
194690
|
-
|
|
194691
|
-
|
|
194692
|
-
const
|
|
194693
|
-
const
|
|
194694
|
-
return `${
|
|
194787
|
+
if (subscription && isClaudeSubscriptionDisabledError(verdict.detail)) {
|
|
194788
|
+
return `${CLAUDE_ORG_DISABLED.headline} ${CLAUDE_ORG_DISABLED.detail}`;
|
|
194789
|
+
}
|
|
194790
|
+
if (subscription) return `${what} was rejected. ${SIGN_IN_AGAIN(subscription.command)}.`;
|
|
194791
|
+
const issue3 = dashboard?.keys ? `[Issue a new key](${dashboard.keys})` : "Issue a new key";
|
|
194792
|
+
const where = credential.source === "workflow" ? `in [this repo's GitHub Actions secrets](${secretsUrl(params)})` : `in [Pullfrog](${getApiUrl()}/console/${params.owner}#billing)`;
|
|
194793
|
+
return `${what} was rejected. ${issue3} and update it ${where}.`;
|
|
194695
194794
|
}
|
|
194696
194795
|
function formatApiKeyErrorSummary(params) {
|
|
194697
194796
|
if (params.raw.includes(MISSING_KEY_MARKER)) {
|
|
194698
|
-
if (params.raw.startsWith(`**${MISSING_KEY_MARKER}
|
|
194797
|
+
if (params.raw.startsWith(`**${MISSING_KEY_MARKER}`)) return params.raw;
|
|
194699
194798
|
return buildMissingApiKeyError({ owner: params.owner, name: params.name });
|
|
194700
194799
|
}
|
|
194701
|
-
const
|
|
194702
|
-
const
|
|
194800
|
+
const details = params.output ? { summary: "The provider's response", text: params.output } : void 0;
|
|
194801
|
+
const subscription = subscriptionFor(params.model);
|
|
194703
194802
|
if (isClaudeSessionLimitError(params.raw)) {
|
|
194704
194803
|
const reset = CLAUDE_SESSION_LIMIT_PATTERN.exec(params.raw)?.[1]?.trim();
|
|
194705
|
-
|
|
194706
|
-
|
|
194707
|
-
|
|
194708
|
-
|
|
194709
|
-
|
|
194710
|
-
|
|
194804
|
+
return renderFailure({
|
|
194805
|
+
headline: "Your Claude Pro/Max subscription has hit its usage limit.",
|
|
194806
|
+
detail: `${reset ? `It resets at **${reset}**. ` : ""}Re-trigger after that, or connect an Anthropic API key, which Pullfrog falls back to automatically.`,
|
|
194807
|
+
details,
|
|
194808
|
+
links: [providerLink(params.owner)]
|
|
194809
|
+
});
|
|
194711
194810
|
}
|
|
194712
194811
|
if (isMalformedKeyError(params.raw)) {
|
|
194713
|
-
return
|
|
194714
|
-
"
|
|
194715
|
-
"",
|
|
194716
|
-
|
|
194717
|
-
|
|
194812
|
+
return renderFailure({
|
|
194813
|
+
headline: "Your stored API key can't be sent as an HTTP header.",
|
|
194814
|
+
detail: "It contains a line break or control character, usually from a key pasted across several lines. Re-save it as a single line; the key itself is likely fine.",
|
|
194815
|
+
links: [
|
|
194816
|
+
{
|
|
194817
|
+
label: "Pullfrog provider settings",
|
|
194818
|
+
url: `${getApiUrl()}/console/${params.owner}#billing`
|
|
194819
|
+
},
|
|
194820
|
+
{ label: "GitHub Actions secrets", url: secretsUrl(params) }
|
|
194821
|
+
]
|
|
194822
|
+
});
|
|
194718
194823
|
}
|
|
194719
194824
|
if (isClaudeSubscriptionDisabledError(params.raw)) {
|
|
194720
|
-
return
|
|
194721
|
-
|
|
194722
|
-
|
|
194723
|
-
|
|
194724
|
-
|
|
194825
|
+
return renderFailure({
|
|
194826
|
+
...CLAUDE_ORG_DISABLED,
|
|
194827
|
+
details,
|
|
194828
|
+
links: [providerLink(params.owner)]
|
|
194829
|
+
});
|
|
194725
194830
|
}
|
|
194726
194831
|
if (isKimiPlanTierError(params.raw)) {
|
|
194727
|
-
return
|
|
194728
|
-
"
|
|
194729
|
-
"",
|
|
194730
|
-
|
|
194731
|
-
|
|
194832
|
+
return renderFailure({
|
|
194833
|
+
headline: "Your Kimi membership doesn't include the model this run asked for.",
|
|
194834
|
+
detail: "Kimi K3 needs a Moderato plan or above, and K3's 1M context and Kimi K2 HighSpeed need Allegretto or above. Upgrade the membership, or switch this repo to **Kimi K2**, which every tier includes.",
|
|
194835
|
+
details,
|
|
194836
|
+
links: [
|
|
194837
|
+
{ label: "Kimi plans", url: "https://www.kimi.com/membership/pricing" },
|
|
194838
|
+
pickModelLink(params)
|
|
194839
|
+
]
|
|
194840
|
+
});
|
|
194732
194841
|
}
|
|
194733
194842
|
if (isOAuthCredentialExpiredError(params.raw)) {
|
|
194734
|
-
return
|
|
194735
|
-
|
|
194736
|
-
"",
|
|
194737
|
-
|
|
194738
|
-
|
|
194739
|
-
|
|
194740
|
-
|
|
194741
|
-
if (subscription &&
|
|
194742
|
-
|
|
194743
|
-
|
|
194744
|
-
|
|
194745
|
-
|
|
194746
|
-
|
|
194747
|
-
|
|
194748
|
-
}
|
|
194749
|
-
return
|
|
194750
|
-
|
|
194751
|
-
"",
|
|
194752
|
-
|
|
194753
|
-
|
|
194843
|
+
return renderFailure({
|
|
194844
|
+
headline: subscription ? `Your ${subscription.label}'s sign-in has expired or been revoked.` : "Your provider sign-in has expired or been revoked.",
|
|
194845
|
+
detail: subscription ? `${SIGN_IN_AGAIN(subscription.command)}, then re-trigger.` : "Sign in again with `pullfrog auth claude`, `pullfrog auth codex` or `pullfrog auth grok` in a terminal, whichever this repo uses, then re-trigger.",
|
|
194846
|
+
details,
|
|
194847
|
+
links: [pickModelLink(params)]
|
|
194848
|
+
});
|
|
194849
|
+
}
|
|
194850
|
+
if (subscription && hasEnvVar2(subscription.env) && params.credential !== "api_key") {
|
|
194851
|
+
return renderFailure({
|
|
194852
|
+
headline: `Your ${subscription.label} was rejected during this run.`,
|
|
194853
|
+
detail: `${SIGN_IN_AGAIN(subscription.command)}, then re-trigger.`,
|
|
194854
|
+
details,
|
|
194855
|
+
links: [pickModelLink(params)]
|
|
194856
|
+
});
|
|
194857
|
+
}
|
|
194858
|
+
return renderFailure({
|
|
194859
|
+
headline: `Your ${providerDisplayName(params.model?.split("/")[0]) ?? "model provider"} API key was rejected.`,
|
|
194860
|
+
detail: "Issue a new key with the provider, then update the copy Pullfrog uses, in Pullfrog or in this repo's GitHub Actions secrets.",
|
|
194861
|
+
details,
|
|
194862
|
+
links: [
|
|
194863
|
+
{
|
|
194864
|
+
label: "Pullfrog provider settings",
|
|
194865
|
+
url: `${getApiUrl()}/console/${params.owner}#billing`
|
|
194866
|
+
},
|
|
194867
|
+
{ label: "GitHub Actions secrets", url: secretsUrl(params) }
|
|
194868
|
+
]
|
|
194869
|
+
});
|
|
194754
194870
|
}
|
|
194755
194871
|
|
|
194756
194872
|
// utils/agent.ts
|
|
@@ -194776,7 +194892,7 @@ function resolveSlug(slug2) {
|
|
|
194776
194892
|
const bedrockId = process.env[BEDROCK_MODEL_ID_ENV]?.trim();
|
|
194777
194893
|
if (!bedrockId) {
|
|
194778
194894
|
throw new Error(
|
|
194779
|
-
|
|
194895
|
+
`\`${BEDROCK_MODEL_ID_ENV}\` ${BYOK_SLUG_MARKER} \`${slug2}\`. Set it in the workflow's \`env:\` block to a Bedrock model ID from the AWS console. [Amazon Bedrock setup guide](https://docs.pullfrog.com/bedrock)`
|
|
194780
194896
|
);
|
|
194781
194897
|
}
|
|
194782
194898
|
return bedrockId;
|
|
@@ -194785,7 +194901,7 @@ function resolveSlug(slug2) {
|
|
|
194785
194901
|
const vertexId = process.env[VERTEX_MODEL_ID_ENV]?.trim();
|
|
194786
194902
|
if (!vertexId) {
|
|
194787
194903
|
throw new Error(
|
|
194788
|
-
|
|
194904
|
+
`\`${VERTEX_MODEL_ID_ENV}\` ${BYOK_SLUG_MARKER} \`${slug2}\`. Set it in the workflow's \`env:\` block to a Vertex AI model ID from Model Garden. [Google Vertex AI setup guide](https://docs.pullfrog.com/vertex)`
|
|
194789
194905
|
);
|
|
194790
194906
|
}
|
|
194791
194907
|
return vertexId;
|
|
@@ -194794,7 +194910,7 @@ function resolveSlug(slug2) {
|
|
|
194794
194910
|
const deployment = process.env[AZURE_DEPLOYMENT_ENV]?.trim();
|
|
194795
194911
|
if (!deployment) {
|
|
194796
194912
|
throw new Error(
|
|
194797
|
-
|
|
194913
|
+
`\`${AZURE_DEPLOYMENT_ENV}\` ${BYOK_SLUG_MARKER} \`${slug2}\`. Set it to your deployment's name, not the model it serves, on the Azure OpenAI provider in Pullfrog or in the workflow's \`env:\` block. [Azure OpenAI setup guide](https://docs.pullfrog.com/azure)`
|
|
194798
194914
|
);
|
|
194799
194915
|
}
|
|
194800
194916
|
return `${AZURE_PROVIDER}/${deployment}`;
|
|
@@ -194803,7 +194919,7 @@ function resolveSlug(slug2) {
|
|
|
194803
194919
|
const modelId = process.env[OPENAI_COMPATIBLE_MODEL_ENV]?.trim();
|
|
194804
194920
|
if (!modelId) {
|
|
194805
194921
|
throw new Error(
|
|
194806
|
-
|
|
194922
|
+
`\`${OPENAI_COMPATIBLE_MODEL_ENV}\` ${BYOK_SLUG_MARKER} \`${slug2}\`. Set it to the model ID your endpoint serves, on the OpenAI-compatible provider in Pullfrog or in the workflow's \`env:\` block. [OpenAI-compatible setup guide](https://docs.pullfrog.com/openai-compatible)`
|
|
194807
194923
|
);
|
|
194808
194924
|
}
|
|
194809
194925
|
return `${OPENAI_COMPATIBLE_PROVIDER}/${modelId}`;
|
|
@@ -194875,9 +194991,12 @@ var BillingError = class extends Error {
|
|
|
194875
194991
|
}
|
|
194876
194992
|
};
|
|
194877
194993
|
var TransientError = class extends Error {
|
|
194878
|
-
|
|
194994
|
+
/** the customer-facing follow-up to `message`, which is the headline. */
|
|
194995
|
+
detail;
|
|
194996
|
+
constructor(message2, detail = "This is on our side, and nothing was billed. The next run should succeed; if it keeps failing, check [status.pullfrog.com](https://status.pullfrog.com).") {
|
|
194879
194997
|
super(message2);
|
|
194880
194998
|
this.name = "TransientError";
|
|
194999
|
+
this.detail = detail;
|
|
194881
195000
|
}
|
|
194882
195001
|
};
|
|
194883
195002
|
function billingConsoleUrl(owner) {
|
|
@@ -194912,41 +195031,34 @@ function formatCommercialGateSummary(params) {
|
|
|
194912
195031
|
});
|
|
194913
195032
|
}
|
|
194914
195033
|
function formatBillingErrorSummary(error49, owner) {
|
|
195034
|
+
const billing = { label: "Add credit", url: billingConsoleUrl(owner) };
|
|
194915
195035
|
if (error49.code === "router_requires_card") {
|
|
194916
|
-
return
|
|
194917
|
-
"
|
|
194918
|
-
"",
|
|
194919
|
-
|
|
194920
|
-
|
|
194921
|
-
`[Add a card to top up \u2192](${billingConsoleUrl(owner)}) \xB7 [Bring your own key \u2192](${billingConsoleUrl(owner)})`
|
|
194922
|
-
].join("\n");
|
|
195036
|
+
return renderFailure({
|
|
195037
|
+
headline: "Your Pullfrog Router balance is empty.",
|
|
195038
|
+
detail: "Add a card to top it up, or connect your own provider key. Router usage is billed at provider cost with no markup.",
|
|
195039
|
+
links: [{ label: "Billing and providers", url: billingConsoleUrl(owner) }]
|
|
195040
|
+
});
|
|
194923
195041
|
}
|
|
194924
195042
|
if (error49.code === "router_balance_exhausted") {
|
|
194925
|
-
return
|
|
194926
|
-
"
|
|
194927
|
-
"",
|
|
194928
|
-
|
|
194929
|
-
|
|
194930
|
-
`[Top up balance \u2192](${billingConsoleUrl(owner)}) \xB7 [Enable auto-reload \u2192](${billingConsoleUrl(owner)})`
|
|
194931
|
-
].join("\n");
|
|
195043
|
+
return renderFailure({
|
|
195044
|
+
headline: "Your Pullfrog Router balance is used up.",
|
|
195045
|
+
detail: "Auto-reload is off, so runs paused once the balance passed its overdraft buffer. Add credit or turn on auto-reload.",
|
|
195046
|
+
links: [billing]
|
|
195047
|
+
});
|
|
194932
195048
|
}
|
|
194933
195049
|
if (error49.code === "router_keylimit_exhausted") {
|
|
194934
|
-
return
|
|
194935
|
-
|
|
194936
|
-
"",
|
|
194937
|
-
|
|
194938
|
-
|
|
194939
|
-
`[Top up balance \u2192](${billingConsoleUrl(owner)}) \xB7 [Enable auto-reload \u2192](${billingConsoleUrl(owner)})`
|
|
194940
|
-
].join("\n");
|
|
195050
|
+
return renderFailure({
|
|
195051
|
+
headline: "Your Pullfrog Router balance ran out partway through this run.",
|
|
195052
|
+
detail: "Add credit or turn on auto-reload to keep runs going.",
|
|
195053
|
+
links: [billing]
|
|
195054
|
+
});
|
|
194941
195055
|
}
|
|
194942
195056
|
if (error49.code === "router_monthly_limit") {
|
|
194943
|
-
return
|
|
194944
|
-
"
|
|
194945
|
-
"",
|
|
194946
|
-
|
|
194947
|
-
|
|
194948
|
-
`[Top up balance \u2192](${billingConsoleUrl(owner)}) \xB7 [Adjust limit \u2192](${billingConsoleUrl(owner)})`
|
|
194949
|
-
].join("\n");
|
|
195057
|
+
return renderFailure({
|
|
195058
|
+
headline: "Your Pullfrog Router balance is empty, and the monthly spend limit blocks the next auto-reload.",
|
|
195059
|
+
detail: "Add credit by hand, ask an org owner to raise the limit, or wait for it to reset at 00:00 UTC on the 1st.",
|
|
195060
|
+
links: [billing]
|
|
195061
|
+
});
|
|
194950
195062
|
}
|
|
194951
195063
|
if (error49.code === "commercial_plan_required") {
|
|
194952
195064
|
return formatCommercialGateSummary({
|
|
@@ -194968,39 +195080,27 @@ function formatBillingErrorSummary(error49, owner) {
|
|
|
194968
195080
|
}
|
|
194969
195081
|
if (error49.needsReauthentication) {
|
|
194970
195082
|
const code = error49.declineCode ?? "authentication_required";
|
|
194971
|
-
return
|
|
194972
|
-
|
|
194973
|
-
"",
|
|
194974
|
-
|
|
194975
|
-
|
|
194976
|
-
`[Top up balance \u2192](${billingConsoleUrl(owner)})`
|
|
194977
|
-
].join("\n");
|
|
195083
|
+
return renderFailure({
|
|
195084
|
+
headline: `Your card issuer requires 3D Secure on every charge (\`${code}\`).`,
|
|
195085
|
+
detail: "Pullfrog can't complete a 3D Secure check from inside a workflow. Add credit once by hand, and later runs draw on that balance without another check.",
|
|
195086
|
+
links: [billing]
|
|
195087
|
+
});
|
|
194978
195088
|
}
|
|
194979
195089
|
if (error49.declineCode) {
|
|
194980
|
-
return
|
|
194981
|
-
|
|
194982
|
-
"",
|
|
194983
|
-
"Update
|
|
194984
|
-
|
|
194985
|
-
`[Update payment method \u2192](${billingConsoleUrl(owner)})`
|
|
194986
|
-
].join("\n");
|
|
195090
|
+
return renderFailure({
|
|
195091
|
+
headline: `Your card was declined (\`${error49.declineCode}\`).`,
|
|
195092
|
+
detail: "Update your payment method, and Pullfrog will retry on the next run.",
|
|
195093
|
+
links: [{ label: "Update payment method", url: billingConsoleUrl(owner) }]
|
|
195094
|
+
});
|
|
194987
195095
|
}
|
|
194988
|
-
return
|
|
194989
|
-
"
|
|
194990
|
-
"",
|
|
194991
|
-
|
|
194992
|
-
|
|
194993
|
-
`[Manage billing \u2192](${billingConsoleUrl(owner)})`
|
|
194994
|
-
].join("\n");
|
|
195096
|
+
return renderFailure({
|
|
195097
|
+
headline: "Your Pullfrog balance is empty.",
|
|
195098
|
+
detail: "Add credit or turn on auto-reload to keep runs going.",
|
|
195099
|
+
links: [billing]
|
|
195100
|
+
});
|
|
194995
195101
|
}
|
|
194996
|
-
function formatTransientErrorSummary(error49
|
|
194997
|
-
return
|
|
194998
|
-
"**Pullfrog billing is temporarily unavailable.**",
|
|
194999
|
-
"",
|
|
195000
|
-
error49.message,
|
|
195001
|
-
"",
|
|
195002
|
-
`Usually transient; the next dispatch should succeed. If it persists, check [status.pullfrog.com](https://status.pullfrog.com) or [your console](${billingConsoleUrl(owner)}).`
|
|
195003
|
-
].join("\n");
|
|
195102
|
+
function formatTransientErrorSummary(error49) {
|
|
195103
|
+
return renderFailure({ headline: error49.message, detail: error49.detail });
|
|
195004
195104
|
}
|
|
195005
195105
|
|
|
195006
195106
|
// utils/credentialCheck.ts
|
|
@@ -195373,10 +195473,7 @@ var select = mutation({
|
|
|
195373
195473
|
signal: ctx.signal
|
|
195374
195474
|
});
|
|
195375
195475
|
if (response.status === 404) return null;
|
|
195376
|
-
if (!response.ok)
|
|
195377
|
-
throw new Error("could not load a configured credential; no fallback was charged", {
|
|
195378
|
-
cause: response.status
|
|
195379
|
-
});
|
|
195476
|
+
if (!response.ok) throw new Error(buildSecretsUnavailableError(), { cause: response.status });
|
|
195380
195477
|
return selectedCredentialSchema.parse(await response.json());
|
|
195381
195478
|
},
|
|
195382
195479
|
retry: (error49, attempt) => error49 instanceof Error && typeof error49.cause === "number" && error49.cause >= 400 && error49.cause < 500 ? -1 : delay2([250, 1e3], attempt),
|
|
@@ -196190,26 +196287,16 @@ function ossAllowedLabels() {
|
|
|
196190
196287
|
return ossFundedModelNames().map((name) => `\`${name}\``).join(", ");
|
|
196191
196288
|
}
|
|
196192
196289
|
function buildModelAccessError(input) {
|
|
196193
|
-
const
|
|
196194
|
-
|
|
196195
|
-
|
|
196196
|
-
|
|
196197
|
-
const branch = {
|
|
196198
|
-
oss: {
|
|
196199
|
-
why: `This repo runs on Pullfrog's OSS subsidy, which funds a set of pre-approved models: ${ossAllowedLabels()}. Pick one of those, or add your own provider key to run a different one.`,
|
|
196200
|
-
cta: `[Configure model \u2192](${settingsUrl}) \xB7 [Add a provider key \u2192](${secretsUrl}) \xB7 [Setup docs \u2192](${docsUrl})`
|
|
196201
|
-
},
|
|
196202
|
-
byok_no_key: {
|
|
196203
|
-
why: `No provider key for \`${input.model}\` is present in this run's environment. Add the matching provider key as a GitHub Actions secret, or pick a model you already have a key for.`,
|
|
196204
|
-
cta: `[Open repo secrets \u2192](${secretsUrl}) \xB7 [Configure model \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](${docsUrl})`
|
|
196205
|
-
},
|
|
196206
|
-
router: {
|
|
196207
|
-
why: "Pullfrog Router can't serve this model. Pick a Router-supported model, or add your own provider key to run it directly.",
|
|
196208
|
-
cta: `[Configure model \u2192](${settingsUrl}) \xB7 [Add a provider key \u2192](${secretsUrl})`
|
|
196209
|
-
}
|
|
196290
|
+
const why = {
|
|
196291
|
+
oss: `This repo runs on Pullfrog's OSS subsidy, which funds a set of pre-approved models: ${ossAllowedLabels()}. Pick one of those, or connect your own provider to run a different one.`,
|
|
196292
|
+
byok_no_key: `This run has no API key for \`${input.model}\`. Connect one, or pick a model you already have a key for.`,
|
|
196293
|
+
router: "Pullfrog Router can't serve this model. Pick a Router-supported model, or connect your own provider to run it directly."
|
|
196210
196294
|
};
|
|
196211
|
-
|
|
196212
|
-
|
|
196295
|
+
return renderFailure({
|
|
196296
|
+
headline: `The ${MODEL_ACCESS_MARKER}: \`${input.model}\`.`,
|
|
196297
|
+
detail: why[input.reason],
|
|
196298
|
+
links: [pickModelLink(input), providerLink(input.owner)]
|
|
196299
|
+
});
|
|
196213
196300
|
}
|
|
196214
196301
|
|
|
196215
196302
|
// utils/overrides.ts
|
|
@@ -196766,9 +196853,6 @@ async function revokeGitHubInstallationToken(token) {
|
|
|
196766
196853
|
|
|
196767
196854
|
// utils/errorReport.ts
|
|
196768
196855
|
async function reportErrorToComment(ctx) {
|
|
196769
|
-
const formattedError = ctx.title ? `${ctx.title}
|
|
196770
|
-
|
|
196771
|
-
${ctx.error}` : ctx.error;
|
|
196772
196856
|
const repoContext = parseRepoContext();
|
|
196773
196857
|
const octokit = createOctokit(getGitHubInstallationToken(), getMcpTokenRefresh());
|
|
196774
196858
|
const runId = process.env.GITHUB_RUN_ID ? Number.parseInt(process.env.GITHUB_RUN_ID, 10) : void 0;
|
|
@@ -196787,9 +196871,10 @@ ${ctx.error}` : ctx.error;
|
|
|
196787
196871
|
clamped: ctx.toolState.modelClamped,
|
|
196788
196872
|
unselectedProxyDefault: ctx.toolState.unselectedProxyDefault,
|
|
196789
196873
|
oss: ctx.toolState.oss,
|
|
196790
|
-
owner: repoContext.owner
|
|
196874
|
+
owner: repoContext.owner,
|
|
196875
|
+
failed: true
|
|
196791
196876
|
});
|
|
196792
|
-
const body = `${
|
|
196877
|
+
const body = `${redactSecrets(ctx.error)}${footer}`;
|
|
196793
196878
|
const comment = ctx.toolState.progressComment;
|
|
196794
196879
|
if (comment) {
|
|
196795
196880
|
await updateProgressComment(
|
|
@@ -196829,8 +196914,9 @@ async function mintProxyKey(ctx) {
|
|
|
196829
196914
|
const r = await apiFetch({ path: "/api/proxy-token", method: "POST", headers });
|
|
196830
196915
|
if (r.status >= 500) {
|
|
196831
196916
|
const body = await r.json().catch(() => null);
|
|
196917
|
+
log.warning(`proxy key mint: ${r.status} ${body?.error ?? ""}`);
|
|
196832
196918
|
throw new TransientError(
|
|
196833
|
-
|
|
196919
|
+
"Pullfrog's billing service is temporarily unavailable, so this run didn't start."
|
|
196834
196920
|
);
|
|
196835
196921
|
}
|
|
196836
196922
|
return r;
|
|
@@ -196848,7 +196934,8 @@ async function mintProxyKey(ctx) {
|
|
|
196848
196934
|
}
|
|
196849
196935
|
if (response.status === 404) {
|
|
196850
196936
|
throw new TransientError(
|
|
196851
|
-
"Pullfrog couldn't match this repository to its account
|
|
196937
|
+
"Pullfrog couldn't match this repository to its account.",
|
|
196938
|
+
"It may have just been renamed or transferred, and the link refreshes on the next run. If it keeps failing, reinstall the GitHub App on the repository's current owner."
|
|
196852
196939
|
);
|
|
196853
196940
|
}
|
|
196854
196941
|
if (!response.ok) {
|
|
@@ -196957,7 +197044,7 @@ async function runProxyResolution(ctx) {
|
|
|
196957
197044
|
throw error49;
|
|
196958
197045
|
}
|
|
196959
197046
|
if (error49 instanceof TransientError) {
|
|
196960
|
-
const summary3 = formatTransientErrorSummary(error49
|
|
197047
|
+
const summary3 = formatTransientErrorSummary(error49);
|
|
196961
197048
|
await writeSummary(summary3).catch(() => {
|
|
196962
197049
|
});
|
|
196963
197050
|
await reportErrorToComment({
|
|
@@ -196982,13 +197069,14 @@ async function resolveTrialFallback(ctx) {
|
|
|
196982
197069
|
if (!key) return false;
|
|
196983
197070
|
process.env.OPENROUTER_API_KEY = key;
|
|
196984
197071
|
maskSecret(key);
|
|
196985
|
-
ctx.payload.proxyModel =
|
|
196986
|
-
ctx.toolState.model =
|
|
197072
|
+
ctx.payload.proxyModel = TRIAL_PROXY_MODEL;
|
|
197073
|
+
ctx.toolState.model = TRIAL_PROXY_MODEL;
|
|
196987
197074
|
ctx.toolState.modelClamped = {
|
|
196988
|
-
from: ctx.configuredModel ??
|
|
196989
|
-
reason: "trial"
|
|
197075
|
+
from: ctx.configuredModel ?? TRIAL_PROXY_MODEL,
|
|
197076
|
+
reason: "trial",
|
|
197077
|
+
creditsLeftUsd: ctx.creditsLeftUsd
|
|
196990
197078
|
};
|
|
196991
|
-
log.info(`\xBB proxy: trial \u2192 ${
|
|
197079
|
+
log.info(`\xBB proxy: trial \u2192 ${TRIAL_PROXY_MODEL}`);
|
|
196992
197080
|
return true;
|
|
196993
197081
|
}
|
|
196994
197082
|
|
|
@@ -197101,14 +197189,27 @@ ${collapsible}` : output;
|
|
|
197101
197189
|
return { success: true, output: ctx.result.output || "" };
|
|
197102
197190
|
} catch (writeError) {
|
|
197103
197191
|
const error50 = `failed to deliver agent result: ${getErrorMessage2(writeError)}`;
|
|
197104
|
-
await reportErrorToComment({
|
|
197192
|
+
await reportErrorToComment({
|
|
197193
|
+
toolState,
|
|
197194
|
+
error: renderFailure({
|
|
197195
|
+
headline: "Pullfrog couldn't post its answer to GitHub.",
|
|
197196
|
+
detail: "GitHub refused the write; its error is below. Re-trigger to try again.",
|
|
197197
|
+
error: getErrorMessage2(writeError)
|
|
197198
|
+
})
|
|
197199
|
+
}).catch(() => {
|
|
197105
197200
|
});
|
|
197106
197201
|
return { success: false, error: error50, output: ctx.result.output || "" };
|
|
197107
197202
|
}
|
|
197108
197203
|
}
|
|
197109
197204
|
const error49 = ctx.result.error || "agent completed without reporting progress";
|
|
197110
197205
|
try {
|
|
197111
|
-
await reportErrorToComment({
|
|
197206
|
+
await reportErrorToComment({
|
|
197207
|
+
toolState,
|
|
197208
|
+
error: renderFailure({
|
|
197209
|
+
headline: "The agent finished without posting anything.",
|
|
197210
|
+
detail: "Re-trigger to try again."
|
|
197211
|
+
})
|
|
197212
|
+
});
|
|
197112
197213
|
} catch {
|
|
197113
197214
|
}
|
|
197114
197215
|
return { success: false, error: error49, output: ctx.result.output || "" };
|
|
@@ -197169,63 +197270,57 @@ async function resolveRunContextData(params) {
|
|
|
197169
197270
|
// outcome as the server-side failure: the run never sees stored secrets.
|
|
197170
197271
|
secretsUnavailable: runContext.secretsUnavailable || !!process.env.ACTIONS_ID_TOKEN_REQUEST_URL && oidcToken === void 0,
|
|
197171
197272
|
routerUnfunded: runContext.routerUnfunded,
|
|
197172
|
-
trialFallback: runContext.trialFallback
|
|
197273
|
+
trialFallback: runContext.trialFallback,
|
|
197274
|
+
trialCreditsLeftUsd: runContext.trialCreditsLeftUsd
|
|
197173
197275
|
};
|
|
197174
197276
|
}
|
|
197175
197277
|
|
|
197176
197278
|
// utils/agentHangReport.ts
|
|
197177
197279
|
var MAX_STDERR_BYTES = 3e3;
|
|
197178
197280
|
function formatAgentHangBody(input) {
|
|
197179
|
-
|
|
197180
|
-
if (
|
|
197181
|
-
|
|
197182
|
-
}
|
|
197183
|
-
const
|
|
197184
|
-
|
|
197185
|
-
|
|
197186
|
-
|
|
197187
|
-
|
|
197188
|
-
|
|
197189
|
-
|
|
197190
|
-
|
|
197191
|
-
|
|
197192
|
-
const tail = renderStderrTail(input.diagnostic.recentStderr);
|
|
197193
|
-
if (tail) {
|
|
197194
|
-
const fence = pickFence(tail);
|
|
197195
|
-
parts.push(
|
|
197196
|
-
"",
|
|
197197
|
-
"<details><summary>Recent agent stderr</summary>",
|
|
197198
|
-
"",
|
|
197199
|
-
fence,
|
|
197200
|
-
tail,
|
|
197201
|
-
fence,
|
|
197202
|
-
"",
|
|
197203
|
-
"</details>"
|
|
197204
|
-
);
|
|
197281
|
+
const diagnostic = input.diagnostic;
|
|
197282
|
+
if (!diagnostic) return null;
|
|
197283
|
+
const output = renderStderrTail(diagnostic.recentStderr);
|
|
197284
|
+
const details = output ? { summary: "Last agent output", text: output } : void 0;
|
|
197285
|
+
const idle = formatIdle(diagnostic.idleSec ?? parseIdleSec(input.errorMessage));
|
|
197286
|
+
if (diagnostic.lastProviderError === PROVIDER_BILLING_EXHAUSTED_LABEL) {
|
|
197287
|
+
const billingUrl = extractBillingUrl(diagnostic.recentStderr);
|
|
197288
|
+
return renderFailure({
|
|
197289
|
+
headline: "Your model provider's account is out of credit.",
|
|
197290
|
+
detail: "The provider kept refusing the request, so Pullfrog stopped the run. Top up the account, then re-trigger.",
|
|
197291
|
+
details,
|
|
197292
|
+
links: billingUrl ? [{ label: "Top up", url: billingUrl }] : []
|
|
197293
|
+
});
|
|
197205
197294
|
}
|
|
197206
|
-
|
|
197207
|
-
|
|
197208
|
-
|
|
197209
|
-
|
|
197210
|
-
|
|
197211
|
-
|
|
197212
|
-
|
|
197295
|
+
if (diagnostic.lastProviderError) {
|
|
197296
|
+
return renderFailure({
|
|
197297
|
+
headline: "The model provider kept returning errors, so Pullfrog stopped this run.",
|
|
197298
|
+
detail: `The last one was \`${diagnostic.lastProviderError}\`. Re-trigger to try again.`,
|
|
197299
|
+
details
|
|
197300
|
+
});
|
|
197301
|
+
}
|
|
197302
|
+
if (!diagnostic.sawModelOutput) {
|
|
197303
|
+
return renderFailure({
|
|
197304
|
+
headline: `The model never responded, so Pullfrog stopped this run${idle ? ` after ${idle}` : ""}.`,
|
|
197305
|
+
detail: "The request went out but nothing came back. This is usually temporary, so re-trigger to try again.",
|
|
197306
|
+
details
|
|
197307
|
+
});
|
|
197213
197308
|
}
|
|
197214
|
-
return
|
|
197309
|
+
return renderFailure({
|
|
197310
|
+
headline: `The agent went quiet${idle ? ` for ${idle}` : ""}, so Pullfrog stopped this run.`,
|
|
197311
|
+
detail: "Re-trigger to try again.",
|
|
197312
|
+
details
|
|
197313
|
+
});
|
|
197314
|
+
}
|
|
197315
|
+
function formatIdle(seconds) {
|
|
197316
|
+
if (seconds === void 0) return void 0;
|
|
197317
|
+
if (seconds < 90) return `${seconds} seconds`;
|
|
197318
|
+
return `${Math.round(seconds / 60)} minutes`;
|
|
197215
197319
|
}
|
|
197216
197320
|
function parseIdleSec(message2) {
|
|
197217
197321
|
const match3 = /no output for (\d+)s/.exec(message2);
|
|
197218
197322
|
return match3 ? Number(match3[1]) : void 0;
|
|
197219
197323
|
}
|
|
197220
|
-
function formatEventsPart(diagnostic) {
|
|
197221
|
-
if (diagnostic.lastProviderError) {
|
|
197222
|
-
return `${diagnostic.eventCount} events were processed before the failure.`;
|
|
197223
|
-
}
|
|
197224
|
-
if (!diagnostic.sawModelOutput) {
|
|
197225
|
-
return "The model produced no output at all before the stall \u2014 the request was sent but nothing came back. This is usually transient; re-running often succeeds.";
|
|
197226
|
-
}
|
|
197227
|
-
return `${diagnostic.eventCount} events were processed before the failure.`;
|
|
197228
|
-
}
|
|
197229
197324
|
function renderStderrTail(lines) {
|
|
197230
197325
|
if (lines.length === 0) return "";
|
|
197231
197326
|
const joined = lines.join("\n");
|
|
@@ -197233,13 +197328,6 @@ function renderStderrTail(lines) {
|
|
|
197233
197328
|
return `... (older lines truncated)
|
|
197234
197329
|
${joined.slice(-MAX_STDERR_BYTES)}`;
|
|
197235
197330
|
}
|
|
197236
|
-
function pickFence(content) {
|
|
197237
|
-
let max = 0;
|
|
197238
|
-
for (const match3 of content.matchAll(/`+/g)) {
|
|
197239
|
-
if (match3[0].length > max) max = match3[0].length;
|
|
197240
|
-
}
|
|
197241
|
-
return "`".repeat(Math.max(3, max + 1));
|
|
197242
|
-
}
|
|
197243
197331
|
function extractBillingUrl(lines) {
|
|
197244
197332
|
const urlPattern = /https:\/\/(?:opencode\.ai\/[^\s"]*billing[^\s"]*|console\.anthropic\.com[^\s"]*|console\.cloud\.google\.com[^\s"]*billing[^\s"]*)/i;
|
|
197245
197333
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
@@ -197248,28 +197336,6 @@ function extractBillingUrl(lines) {
|
|
|
197248
197336
|
}
|
|
197249
197337
|
return void 0;
|
|
197250
197338
|
}
|
|
197251
|
-
function formatBillingExhaustedBody(diagnostic) {
|
|
197252
|
-
const headline = `**${diagnostic.label} stopped** \u2014 your model provider returned a billing-exhausted response.`;
|
|
197253
|
-
const billingUrl = extractBillingUrl(diagnostic.recentStderr);
|
|
197254
|
-
const cta = billingUrl ? `Top up your provider balance, then re-run: [${billingUrl}](${billingUrl})` : "Top up your model-provider balance (or rotate to a key with remaining credits) and re-run.";
|
|
197255
|
-
const explanation = "The agent kept retrying the request because the provider marked the failure as transient. Pullfrog's activity-timeout watchdog ended the run after no further events were emitted.";
|
|
197256
|
-
const parts = [headline, "", explanation, "", cta];
|
|
197257
|
-
const tail = renderStderrTail(diagnostic.recentStderr);
|
|
197258
|
-
if (tail) {
|
|
197259
|
-
const fence = pickFence(tail);
|
|
197260
|
-
parts.push(
|
|
197261
|
-
"",
|
|
197262
|
-
"<details><summary>Recent agent stderr</summary>",
|
|
197263
|
-
"",
|
|
197264
|
-
fence,
|
|
197265
|
-
tail,
|
|
197266
|
-
fence,
|
|
197267
|
-
"",
|
|
197268
|
-
"</details>"
|
|
197269
|
-
);
|
|
197270
|
-
}
|
|
197271
|
-
return parts.join("\n");
|
|
197272
|
-
}
|
|
197273
197339
|
|
|
197274
197340
|
// utils/runErrorRenderer.ts
|
|
197275
197341
|
function isProviderModelNotFoundError(message2) {
|
|
@@ -197284,84 +197350,9 @@ function isNoProviderAvailableError(message2) {
|
|
|
197284
197350
|
function isZenFreeTierGateError(message2) {
|
|
197285
197351
|
return /free tier can only be used from within OpenCode/i.test(message2);
|
|
197286
197352
|
}
|
|
197287
|
-
|
|
197288
|
-
|
|
197289
|
-
|
|
197290
|
-
"**Zen's free tier refused a request this run made.** OpenCode Zen currently rejects free-model requests whose tool list is missing one of the built-in tools it expects ([upstream issue](https://github.com/anomalyco/opencode/issues/49587)). Pullfrog sends all of them, but opencode's mid-run context-compaction request carries no tools at all, and a repo-level `opencode.json` that denies `bash`, `glob`, `grep` or `read` strips that tool from every request.",
|
|
197291
|
-
"",
|
|
197292
|
-
'Pick a paid model for this repo, drop any `"deny"` on `bash`, `glob`, `grep` or `read` from the repo\'s `opencode.json` if it sets one, or split the PR so the run stays under the compaction threshold and re-trigger.',
|
|
197293
|
-
"",
|
|
197294
|
-
`[Model settings \u2192](${settingsUrl}) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`,
|
|
197295
|
-
"",
|
|
197296
|
-
`\`\`\`
|
|
197297
|
-
${input.raw}
|
|
197298
|
-
\`\`\``
|
|
197299
|
-
].join("\n");
|
|
197300
|
-
}
|
|
197301
|
-
function formatNoProviderAvailableSummary(input) {
|
|
197302
|
-
const settingsUrl = `${getApiUrl()}/console/${input.owner}/${input.name}`;
|
|
197303
|
-
return [
|
|
197304
|
-
"**The provider refused to serve this model.** It's listed in the catalog, but the account this run used has no access to it \u2014 so the request was accepted and then declined.",
|
|
197305
|
-
"",
|
|
197306
|
-
"This often happens when Pullfrog auto-selects a model your account can't reach. Pin an explicit model for this repo, or add credentials for the provider that was picked.",
|
|
197307
|
-
"",
|
|
197308
|
-
`[Model settings \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](https://docs.pullfrog.com/keys) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`,
|
|
197309
|
-
"",
|
|
197310
|
-
`\`\`\`
|
|
197311
|
-
${input.raw}
|
|
197312
|
-
\`\`\``
|
|
197313
|
-
].join("\n");
|
|
197314
|
-
}
|
|
197315
|
-
function isRunTimeoutError(message2) {
|
|
197316
|
-
return message2.startsWith("agent run timed out after");
|
|
197317
|
-
}
|
|
197318
|
-
function formatRunTimeoutSummary(input) {
|
|
197319
|
-
const settingsUrl = `${getApiUrl()}/console/${input.owner}/${input.name}`;
|
|
197320
|
-
return [
|
|
197321
|
-
"**This run hit its time limit while still working, so it stopped before finishing.**",
|
|
197322
|
-
"",
|
|
197323
|
-
"Give runs longer with `--timeout=2h` (or `--notimeout`) in this repo's instructions \u2014 or raise the workflow's `timeout` input if it sets one, since that input wins. A smaller PR or a lower effort also finishes sooner.",
|
|
197324
|
-
"",
|
|
197325
|
-
`[Repo settings \u2192](${settingsUrl}) \xB7 [Flags \u2192](https://docs.pullfrog.com/flags)`,
|
|
197326
|
-
"",
|
|
197327
|
-
`\`\`\`
|
|
197328
|
-
${input.raw}
|
|
197329
|
-
\`\`\``
|
|
197330
|
-
].join("\n");
|
|
197331
|
-
}
|
|
197332
|
-
function formatContextOverflowSummary(input) {
|
|
197333
|
-
const settingsUrl = `${getApiUrl()}/console/${input.owner}/${input.name}`;
|
|
197334
|
-
return [
|
|
197335
|
-
"**This run exceeded the model's context window.** Pullfrog read more than the model could hold, so it stopped before finishing.",
|
|
197336
|
-
"",
|
|
197337
|
-
`Pick a model with a larger context window, or split this PR into smaller ones and re-trigger.`,
|
|
197338
|
-
"",
|
|
197339
|
-
`[Model settings \u2192](${settingsUrl}) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`,
|
|
197340
|
-
"",
|
|
197341
|
-
`\`\`\`
|
|
197342
|
-
${input.raw}
|
|
197343
|
-
\`\`\``
|
|
197344
|
-
].join("\n");
|
|
197345
|
-
}
|
|
197346
|
-
function formatGenericFailure(errorMessage) {
|
|
197347
|
-
return [
|
|
197348
|
-
"Pullfrog ran into an unexpected error and couldn't finish this run. The underlying error is below \u2014 re-trigger Pullfrog to try again, and reach out to support if it keeps happening.",
|
|
197349
|
-
"",
|
|
197350
|
-
"```",
|
|
197351
|
-
errorMessage,
|
|
197352
|
-
"```"
|
|
197353
|
-
].join("\n");
|
|
197354
|
-
}
|
|
197355
|
-
function formatMinimalFailureComment(repo) {
|
|
197356
|
-
const runId = process.env.GITHUB_RUN_ID;
|
|
197357
|
-
if (!runId) return "**Run failed.**";
|
|
197358
|
-
const server = process.env.GITHUB_SERVER_URL ?? "https://github.com";
|
|
197359
|
-
const url4 = `${server}/${repo.owner}/${repo.name}/actions/runs/${runId}`;
|
|
197360
|
-
return `**Run failed.** [View the logs \u2192](${url4})`;
|
|
197361
|
-
}
|
|
197362
|
-
var PROVIDER_BILLING_URLS = Object.fromEntries(
|
|
197363
|
-
Object.entries(PROVIDER_DASHBOARDS).map(([id, dashboard]) => [id, dashboard.billing])
|
|
197364
|
-
);
|
|
197353
|
+
var RUN_TIMEOUT_PATTERN = /^agent run timed out after (\S+)/;
|
|
197354
|
+
var STOP_SCRIPT_PATTERN = /^stop hook failed \(exit code (-?\d+)\): ([\s\S]*)$/;
|
|
197355
|
+
var UNSUBMITTED_REVIEW_PATTERN = /^\w+ mode finished without calling /;
|
|
197365
197356
|
function detectProviderId(message2) {
|
|
197366
197357
|
const harnessId = extractProviderId(message2);
|
|
197367
197358
|
if (harnessId) return harnessId;
|
|
@@ -197373,292 +197364,242 @@ function detectProviderId(message2) {
|
|
|
197373
197364
|
if (/platform\.openai\.com/i.test(message2)) return "openai";
|
|
197374
197365
|
return null;
|
|
197375
197366
|
}
|
|
197376
|
-
|
|
197377
|
-
|
|
197378
|
-
|
|
197379
|
-
|
|
197380
|
-
|
|
197381
|
-
|
|
197382
|
-
|
|
197383
|
-
|
|
197384
|
-
|
|
197385
|
-
|
|
197386
|
-
|
|
197387
|
-
|
|
197388
|
-
`\`\`\`
|
|
197389
|
-
${input.errorMessage}
|
|
197390
|
-
\`\`\``
|
|
197391
|
-
].join("\n");
|
|
197392
|
-
}
|
|
197393
|
-
const spendCap = findAnthropicSpendCap(input.errorMessage);
|
|
197394
|
-
if (spendCap) {
|
|
197395
|
-
const regains = spendCap.regainAt ? ` Access returns on **${spendCap.regainAt}**.` : "";
|
|
197396
|
-
return [
|
|
197397
|
-
`**Your \`anthropic\` account has reached its configured API usage limit.**${regains}`,
|
|
197398
|
-
"",
|
|
197399
|
-
"Anthropic refused the request against a spend limit set in your Console, not an empty balance \u2014 raise or remove that limit to run before it resets.",
|
|
197400
|
-
"",
|
|
197401
|
-
`[Anthropic billing settings \u2192](${PROVIDER_BILLING_URLS.anthropic})`,
|
|
197402
|
-
"",
|
|
197403
|
-
`\`\`\`
|
|
197404
|
-
${input.errorMessage}
|
|
197405
|
-
\`\`\``
|
|
197406
|
-
].join("\n");
|
|
197367
|
+
function resolveAccount(input) {
|
|
197368
|
+
const subscription = input.credential === "subscription" ? subscriptionFor(input.model) : void 0;
|
|
197369
|
+
if (subscription) {
|
|
197370
|
+
const plan = Object.values(PROVIDER_DASHBOARDS).find(
|
|
197371
|
+
(dashboard2) => dashboard2.credential === subscription.env
|
|
197372
|
+
);
|
|
197373
|
+
return {
|
|
197374
|
+
name: plan?.name ?? null,
|
|
197375
|
+
phrase: subscription.label,
|
|
197376
|
+
billingUrl: plan?.billing,
|
|
197377
|
+
subscription: true
|
|
197378
|
+
};
|
|
197407
197379
|
}
|
|
197408
|
-
const
|
|
197409
|
-
const
|
|
197410
|
-
|
|
197411
|
-
|
|
197412
|
-
|
|
197413
|
-
|
|
197414
|
-
|
|
197415
|
-
|
|
197416
|
-
|
|
197417
|
-
`\`\`\`
|
|
197418
|
-
${input.errorMessage}
|
|
197419
|
-
\`\`\``
|
|
197420
|
-
].join("\n");
|
|
197380
|
+
const id = detectProviderId(input.errorMessage) ?? input.model?.split("/")[0] ?? null;
|
|
197381
|
+
const dashboard = id ? PROVIDER_DASHBOARDS[id] : void 0;
|
|
197382
|
+
const name = dashboard?.name ?? providerDisplayName(id) ?? null;
|
|
197383
|
+
return {
|
|
197384
|
+
name,
|
|
197385
|
+
phrase: name ? `${name} account` : "model provider account",
|
|
197386
|
+
billingUrl: dashboard?.billing,
|
|
197387
|
+
subscription: false
|
|
197388
|
+
};
|
|
197421
197389
|
}
|
|
197422
|
-
function
|
|
197423
|
-
|
|
197424
|
-
|
|
197425
|
-
|
|
197426
|
-
|
|
197427
|
-
"",
|
|
197428
|
-
"The provider refused or dropped the request mid-run \u2014 nothing in your repo or your credentials is at fault. Re-trigger Pullfrog; if it keeps happening, check the provider's status page.",
|
|
197429
|
-
"",
|
|
197430
|
-
`\`\`\`
|
|
197431
|
-
${errorMessage}
|
|
197432
|
-
\`\`\``
|
|
197433
|
-
].join("\n");
|
|
197390
|
+
function providerResponse(ctx) {
|
|
197391
|
+
return {
|
|
197392
|
+
summary: ctx.account.name ? `${ctx.account.name}'s response` : "The provider's response",
|
|
197393
|
+
text: ctx.errorMessage
|
|
197394
|
+
};
|
|
197434
197395
|
}
|
|
197435
|
-
function
|
|
197436
|
-
|
|
197437
|
-
|
|
197438
|
-
|
|
197439
|
-
|
|
197440
|
-
|
|
197441
|
-
|
|
197442
|
-
|
|
197443
|
-
|
|
197444
|
-
|
|
197445
|
-
|
|
197446
|
-
|
|
197396
|
+
function formatProviderBillingExhausted(ctx) {
|
|
197397
|
+
if (isOpenRouterKeyLimitExceeded(ctx.errorMessage)) {
|
|
197398
|
+
const openrouter = PROVIDER_DASHBOARDS.openrouter;
|
|
197399
|
+
return renderFailure({
|
|
197400
|
+
headline: "Your OpenRouter key's spending limit is too low for this request.",
|
|
197401
|
+
detail: "OpenRouter checks the key's own limit as well as your balance, so raise or remove the limit; adding credit alone may not be enough.",
|
|
197402
|
+
details: providerResponse(ctx),
|
|
197403
|
+
links: openrouter?.keys ? [
|
|
197404
|
+
{ label: "Raise the key's limit", url: openrouter.keys },
|
|
197405
|
+
{ label: "Add credit", url: openrouter.billing }
|
|
197406
|
+
] : []
|
|
197407
|
+
});
|
|
197408
|
+
}
|
|
197409
|
+
const spendCap = findAnthropicSpendCap(ctx.errorMessage);
|
|
197410
|
+
if (spendCap) {
|
|
197411
|
+
const regains = spendCap.regainAt ? `Access returns on **${spendCap.regainAt}**. ` : "";
|
|
197412
|
+
const anthropic = PROVIDER_DASHBOARDS.anthropic;
|
|
197413
|
+
return renderFailure({
|
|
197414
|
+
headline: "Your Anthropic account has reached its API spend limit.",
|
|
197415
|
+
detail: `${regains}This is a limit set in your Anthropic Console, not an empty balance; raise or remove it to run before then.`,
|
|
197416
|
+
details: providerResponse(ctx),
|
|
197417
|
+
links: anthropic ? [{ label: "Anthropic billing settings", url: anthropic.billing }] : []
|
|
197418
|
+
});
|
|
197419
|
+
}
|
|
197420
|
+
return renderFailure({
|
|
197421
|
+
headline: `Your ${ctx.account.phrase} is out of credit.`,
|
|
197422
|
+
detail: "Top it up, then re-trigger Pullfrog.",
|
|
197423
|
+
details: providerResponse(ctx),
|
|
197424
|
+
links: ctx.account.billingUrl ? [{ label: `Top up ${ctx.account.name}`, url: ctx.account.billingUrl }] : []
|
|
197425
|
+
});
|
|
197426
|
+
}
|
|
197427
|
+
function formatProviderUsageLimit(ctx) {
|
|
197428
|
+
const tryAgainAt = /try again at (\d{1,2}:\d{2}\s*[AP]M)/i.exec(ctx.errorMessage)?.[1];
|
|
197429
|
+
const resets = tryAgainAt ? `${ctx.account.name ?? "The provider"} says to try again at ${tryAgainAt}. ` : "";
|
|
197430
|
+
return renderFailure({
|
|
197431
|
+
headline: `Your ${ctx.account.phrase} has hit its usage limit.`,
|
|
197432
|
+
detail: ctx.account.subscription ? `${resets}It resets on its own, so re-trigger after that, or connect an API key, which Pullfrog falls back to automatically.` : `${resets}Raise the limit with the provider, or re-trigger once it resets.`,
|
|
197433
|
+
details: providerResponse(ctx),
|
|
197434
|
+
links: [providerLink(ctx.repo.owner), pickModelLink(ctx.repo)]
|
|
197435
|
+
});
|
|
197436
|
+
}
|
|
197437
|
+
function formatTransientUpstreamBody(ctx) {
|
|
197438
|
+
if (/\bmodel is at capacity\b/i.test(ctx.errorMessage)) {
|
|
197439
|
+
return renderFailure({
|
|
197440
|
+
headline: `${ctx.account.name ? `${ctx.account.name}'s model` : "The model"} is at capacity right now.`,
|
|
197441
|
+
detail: "Re-trigger in a few minutes, or pick another model.",
|
|
197442
|
+
details: providerResponse(ctx),
|
|
197443
|
+
links: [pickModelLink(ctx.repo)]
|
|
197444
|
+
});
|
|
197445
|
+
}
|
|
197446
|
+
return renderFailure({
|
|
197447
|
+
headline: `${ctx.account.name ?? "The model provider"} had a temporary failure.`,
|
|
197448
|
+
detail: "Nothing on your side is at fault. Re-trigger to try again; if it keeps happening, check the provider's status page.",
|
|
197449
|
+
details: providerResponse(ctx)
|
|
197450
|
+
});
|
|
197451
|
+
}
|
|
197452
|
+
function formatProviderNoRoutableEndpoints(ctx) {
|
|
197453
|
+
return renderFailure({
|
|
197454
|
+
headline: "OpenRouter can't route this model anywhere your account allows.",
|
|
197455
|
+
detail: "Your OpenRouter data policy excludes every provider serving it, so nothing ran and nothing was billed. Allow more providers, or pick a model your policy covers.",
|
|
197456
|
+
details: providerResponse(ctx),
|
|
197457
|
+
links: [
|
|
197458
|
+
{ label: "OpenRouter data policy", url: "https://openrouter.ai/settings/privacy" },
|
|
197459
|
+
pickModelLink(ctx.repo)
|
|
197460
|
+
]
|
|
197461
|
+
});
|
|
197447
197462
|
}
|
|
197448
|
-
function formatProviderMissingCredential(
|
|
197449
|
-
return
|
|
197450
|
-
"
|
|
197451
|
-
"",
|
|
197452
|
-
|
|
197453
|
-
|
|
197454
|
-
|
|
197455
|
-
"",
|
|
197456
|
-
`\`\`\`
|
|
197457
|
-
${input.errorMessage}
|
|
197458
|
-
\`\`\``
|
|
197459
|
-
].join("\n");
|
|
197463
|
+
function formatProviderMissingCredential(ctx) {
|
|
197464
|
+
return renderFailure({
|
|
197465
|
+
headline: "No credential reached the model provider.",
|
|
197466
|
+
detail: "The run used a provider it had no key for, so nothing was billed and no key of yours was rejected. Connect a key for that provider, or pick a model you have one for.",
|
|
197467
|
+
details: providerResponse(ctx),
|
|
197468
|
+
links: [providerLink(ctx.repo.owner), pickModelLink(ctx.repo)]
|
|
197469
|
+
});
|
|
197460
197470
|
}
|
|
197461
|
-
function
|
|
197462
|
-
|
|
197463
|
-
|
|
197464
|
-
|
|
197465
|
-
|
|
197466
|
-
"",
|
|
197467
|
-
`
|
|
197468
|
-
|
|
197471
|
+
function formatProviderModelNotFound(ctx) {
|
|
197472
|
+
const model = /Model not found: (\S+?)\.?(?:\s|$)/.exec(ctx.errorMessage)?.[1];
|
|
197473
|
+
const suggestions = /Did you mean: ([^?\n]+)\?/.exec(ctx.errorMessage)?.[1]?.split(",").map((id) => `\`${id.trim()}\``);
|
|
197474
|
+
const suggested = suggestions?.length ? ` OpenCode suggests ${suggestions.slice(0, -1).join(", ")}${suggestions.length > 1 ? " or " : ""}${suggestions.at(-1)}.` : "";
|
|
197475
|
+
return renderFailure({
|
|
197476
|
+
headline: model ? `\`${model}\` isn't in OpenCode's catalog.` : "This repo's model isn't in OpenCode's catalog.",
|
|
197477
|
+
detail: `Pick another model wherever this repo sets it: the Pullfrog console, the workflow's \`model\` input or the \`PULLFROG_MODEL\` variable.${suggested}`,
|
|
197478
|
+
details: { summary: "OpenCode's response", text: ctx.errorMessage },
|
|
197479
|
+
links: [pickModelLink(ctx.repo)]
|
|
197480
|
+
});
|
|
197469
197481
|
}
|
|
197470
|
-
function
|
|
197471
|
-
return
|
|
197472
|
-
|
|
197473
|
-
|
|
197474
|
-
|
|
197475
|
-
|
|
197482
|
+
function formatNoProviderAvailable(ctx) {
|
|
197483
|
+
return renderFailure({
|
|
197484
|
+
headline: "The provider won't serve this model to this account.",
|
|
197485
|
+
detail: "It's in the catalog, but this account's plan can't reach it, which often happens when Pullfrog auto-selects it. Pin a model for this repo, or connect the provider that was picked.",
|
|
197486
|
+
details: providerResponse(ctx),
|
|
197487
|
+
links: [pickModelLink(ctx.repo), providerLink(ctx.repo.owner)]
|
|
197488
|
+
});
|
|
197476
197489
|
}
|
|
197477
|
-
function
|
|
197478
|
-
return
|
|
197479
|
-
"
|
|
197480
|
-
"",
|
|
197481
|
-
|
|
197482
|
-
|
|
197483
|
-
|
|
197484
|
-
"",
|
|
197485
|
-
`\`\`\`
|
|
197486
|
-
${input.raw}
|
|
197487
|
-
\`\`\``
|
|
197488
|
-
].join("\n");
|
|
197490
|
+
function formatZenFreeTierGate(ctx) {
|
|
197491
|
+
return renderFailure({
|
|
197492
|
+
headline: "OpenCode Zen's free tier refused a request from this run.",
|
|
197493
|
+
detail: "Zen rejects free-model requests that don't list its built-in tools, and OpenCode's mid-run context compaction sends none ([upstream issue](https://github.com/anomalyco/opencode/issues/49587)). Pick a paid model, or split the PR so the run finishes before compaction. If this repo's `opencode.json` denies `bash`, `glob`, `grep` or `read`, remove that too.",
|
|
197494
|
+
details: { summary: "OpenCode Zen's response", text: ctx.errorMessage },
|
|
197495
|
+
links: [pickModelLink(ctx.repo)]
|
|
197496
|
+
});
|
|
197489
197497
|
}
|
|
197490
|
-
function
|
|
197491
|
-
return
|
|
197492
|
-
"
|
|
197493
|
-
"",
|
|
197494
|
-
|
|
197495
|
-
|
|
197496
|
-
|
|
197497
|
-
"",
|
|
197498
|
-
`\`\`\`
|
|
197499
|
-
${input.raw}
|
|
197500
|
-
\`\`\``
|
|
197501
|
-
].join("\n");
|
|
197498
|
+
function formatUnrecognized(ctx) {
|
|
197499
|
+
return renderFailure({
|
|
197500
|
+
headline: "An unrecognized error occurred.",
|
|
197501
|
+
detail: "The error is below.",
|
|
197502
|
+
error: ctx.errorMessage,
|
|
197503
|
+
links: [DISCORD_LINK]
|
|
197504
|
+
});
|
|
197502
197505
|
}
|
|
197503
|
-
function
|
|
197504
|
-
const
|
|
197505
|
-
if (
|
|
197506
|
-
|
|
197507
|
-
return { summary: body, comment: body };
|
|
197508
|
-
}
|
|
197509
|
-
if (input.errorMessage.includes(MODEL_ACCESS_MARKER)) {
|
|
197510
|
-
return { summary: input.errorMessage, comment: input.errorMessage };
|
|
197511
|
-
}
|
|
197512
|
-
if (input.errorMessage.includes(SECRETS_UNAVAILABLE_MARKER)) {
|
|
197513
|
-
return { summary: input.errorMessage, comment: input.errorMessage };
|
|
197514
|
-
}
|
|
197515
|
-
if (input.errorMessage.includes(ROUTER_UNFUNDED_MARKER)) {
|
|
197516
|
-
return { summary: input.errorMessage, comment: input.errorMessage };
|
|
197517
|
-
}
|
|
197518
|
-
if (input.errorMessage.includes(CREDENTIAL_REJECTED_MARKER) || input.errorMessage.includes(CREDENTIAL_POOL_REFUSED_MARKER)) {
|
|
197519
|
-
return { summary: input.errorMessage, comment: input.errorMessage };
|
|
197520
|
-
}
|
|
197521
|
-
const isHang = input.errorMessage.startsWith("activity timeout") || input.errorMessage.startsWith("agent still pending");
|
|
197522
|
-
const hangBody = isHang ? formatAgentHangBody({
|
|
197523
|
-
diagnostic: input.agentDiagnostic,
|
|
197524
|
-
isHang: true,
|
|
197525
|
-
errorMessage: input.errorMessage
|
|
197526
|
-
}) : null;
|
|
197527
|
-
if (isProviderBillingExhausted(input.errorMessage)) {
|
|
197528
|
-
const body = formatProviderBillingExhausted({ errorMessage: input.errorMessage });
|
|
197529
|
-
return { summary: `### \u274C Pullfrog failed
|
|
197530
|
-
|
|
197531
|
-
${body}`, comment: body };
|
|
197532
|
-
}
|
|
197533
|
-
if (isProviderNoRoutableEndpoints(input.errorMessage)) {
|
|
197534
|
-
const body = formatProviderNoRoutableEndpoints({
|
|
197535
|
-
owner: input.repo.owner,
|
|
197536
|
-
name: input.repo.name,
|
|
197537
|
-
errorMessage: input.errorMessage
|
|
197538
|
-
});
|
|
197539
|
-
return { summary: `### \u274C Pullfrog failed
|
|
197540
|
-
|
|
197541
|
-
${body}`, comment: body };
|
|
197542
|
-
}
|
|
197543
|
-
if (isProviderUsageLimit(input.errorMessage)) {
|
|
197544
|
-
const body = formatProviderUsageLimit({
|
|
197545
|
-
owner: input.repo.owner,
|
|
197546
|
-
name: input.repo.name,
|
|
197547
|
-
raw: input.errorMessage
|
|
197548
|
-
});
|
|
197549
|
-
return { summary: `### \u274C Pullfrog failed
|
|
197550
|
-
|
|
197551
|
-
${body}`, comment: body };
|
|
197506
|
+
function renderRunErrorBody(ctx) {
|
|
197507
|
+
const message2 = ctx.errorMessage;
|
|
197508
|
+
if (ctx.trial && isRouterKeylimitExhaustedError(message2)) {
|
|
197509
|
+
return buildTrialSpentError({ owner: ctx.repo.owner });
|
|
197552
197510
|
}
|
|
197553
|
-
if (
|
|
197554
|
-
|
|
197555
|
-
|
|
197556
|
-
|
|
197557
|
-
|
|
197558
|
-
});
|
|
197559
|
-
return { summary: `### \u274C Pullfrog failed
|
|
197560
|
-
|
|
197561
|
-
${body}`, comment: body };
|
|
197511
|
+
if (ctx.routerActive && isRouterKeylimitExhaustedError(message2)) {
|
|
197512
|
+
return formatBillingErrorSummary(
|
|
197513
|
+
new BillingError(message2, { code: "router_keylimit_exhausted" }),
|
|
197514
|
+
ctx.repo.owner
|
|
197515
|
+
);
|
|
197562
197516
|
}
|
|
197563
|
-
if (
|
|
197564
|
-
|
|
197565
|
-
|
|
197566
|
-
|
|
197567
|
-
|
|
197517
|
+
if ([
|
|
197518
|
+
MODEL_ACCESS_MARKER,
|
|
197519
|
+
SECRETS_UNAVAILABLE_MARKER,
|
|
197520
|
+
ROUTER_UNFUNDED_MARKER,
|
|
197521
|
+
TRIAL_SPENT_MARKER,
|
|
197522
|
+
CREDENTIAL_REJECTED_MARKER,
|
|
197523
|
+
CREDENTIAL_POOL_REFUSED_MARKER
|
|
197524
|
+
].some((marker) => message2.includes(marker))) {
|
|
197525
|
+
return message2;
|
|
197526
|
+
}
|
|
197527
|
+
const isHang = message2.startsWith("activity timeout") || message2.startsWith("agent still pending");
|
|
197528
|
+
const hangBody = isHang ? formatAgentHangBody({ diagnostic: ctx.agentDiagnostic, errorMessage: message2 }) : null;
|
|
197529
|
+
if (isProviderBillingExhausted(message2)) return formatProviderBillingExhausted(ctx);
|
|
197530
|
+
if (isProviderNoRoutableEndpoints(message2)) return formatProviderNoRoutableEndpoints(ctx);
|
|
197531
|
+
if (isProviderUsageLimit(message2)) return formatProviderUsageLimit(ctx);
|
|
197532
|
+
if (isProviderMissingCredential(message2)) return formatProviderMissingCredential(ctx);
|
|
197533
|
+
if (isByokSetupError(message2)) {
|
|
197534
|
+
return renderFailure({
|
|
197535
|
+
headline: "This repo's model isn't fully set up yet.",
|
|
197536
|
+
detail: message2
|
|
197537
|
+
});
|
|
197538
|
+
}
|
|
197539
|
+
const apiKeySource = hangBody ?? message2;
|
|
197540
|
+
if (isApiKeyAuthError(apiKeySource)) {
|
|
197541
|
+
return formatApiKeyErrorSummary({
|
|
197542
|
+
owner: ctx.repo.owner,
|
|
197543
|
+
name: ctx.repo.name,
|
|
197544
|
+
raw: apiKeySource,
|
|
197545
|
+
model: ctx.model,
|
|
197546
|
+
credential: ctx.credential,
|
|
197547
|
+
output: hangBody ? void 0 : message2
|
|
197548
|
+
});
|
|
197549
|
+
}
|
|
197550
|
+
if (isProviderModelNotFoundError(message2)) return formatProviderModelNotFound(ctx);
|
|
197551
|
+
if (isNoProviderAvailableError(message2)) return formatNoProviderAvailable(ctx);
|
|
197552
|
+
if (isZenFreeTierGateError(message2)) return formatZenFreeTierGate(ctx);
|
|
197553
|
+
if (isContextOverflowError(message2)) {
|
|
197554
|
+
return renderFailure({
|
|
197555
|
+
headline: "This run outgrew the model's context window.",
|
|
197556
|
+
detail: "Pick a model with a larger context window, or split the PR into smaller ones and re-trigger.",
|
|
197557
|
+
links: [pickModelLink(ctx.repo)]
|
|
197558
|
+
});
|
|
197559
|
+
}
|
|
197560
|
+
const timeout = RUN_TIMEOUT_PATTERN.exec(message2)?.[1];
|
|
197561
|
+
if (timeout) {
|
|
197562
|
+
return renderFailure({
|
|
197563
|
+
headline: `This run hit its ${timeout} time limit while still working.`,
|
|
197564
|
+
detail: "Give runs longer with `--timeout=2h` (or `--notimeout`) in this repo's instructions, or raise the workflow's `timeout` input if it sets one, since that input wins. A smaller PR or a lower effort also finishes sooner.",
|
|
197565
|
+
links: [
|
|
197566
|
+
{ label: "Repo settings", url: repoConsoleUrl(ctx.repo) },
|
|
197567
|
+
{ label: "Flags", url: "https://docs.pullfrog.com/flags" }
|
|
197568
|
+
]
|
|
197568
197569
|
});
|
|
197569
|
-
return { summary: `### \u274C Pullfrog failed
|
|
197570
|
-
|
|
197571
|
-
${body}`, comment: body };
|
|
197572
|
-
}
|
|
197573
|
-
const apiKeySource = hangBody ?? input.errorMessage;
|
|
197574
|
-
const apiKeyErrorSummary = isApiKeyAuthError(apiKeySource) ? formatApiKeyErrorSummary({
|
|
197575
|
-
owner: input.repo.owner,
|
|
197576
|
-
name: input.repo.name,
|
|
197577
|
-
raw: apiKeySource
|
|
197578
|
-
}) : null;
|
|
197579
|
-
if (apiKeyErrorSummary) {
|
|
197580
|
-
return { summary: apiKeyErrorSummary, comment: apiKeyErrorSummary };
|
|
197581
197570
|
}
|
|
197582
|
-
|
|
197583
|
-
|
|
197584
|
-
|
|
197585
|
-
|
|
197586
|
-
|
|
197571
|
+
const stopScript = STOP_SCRIPT_PATTERN.exec(message2);
|
|
197572
|
+
if (stopScript) {
|
|
197573
|
+
return renderFailure({
|
|
197574
|
+
headline: "This repo's stop script failed, so the run ended without finishing.",
|
|
197575
|
+
detail: `It exited with code ${stopScript[1]}. Fix the script in this repo's settings, or re-trigger if the failure was temporary.`,
|
|
197576
|
+
details: stopScript[2]?.trim() ? { summary: "Script output", text: stopScript[2].trim() } : void 0,
|
|
197577
|
+
links: [{ label: "Repo settings", url: repoConsoleUrl(ctx.repo) }]
|
|
197587
197578
|
});
|
|
197588
|
-
return { summary: body, comment: body };
|
|
197589
197579
|
}
|
|
197590
|
-
if (
|
|
197591
|
-
|
|
197592
|
-
|
|
197593
|
-
|
|
197594
|
-
raw: input.errorMessage
|
|
197580
|
+
if (UNSUBMITTED_REVIEW_PATTERN.test(message2)) {
|
|
197581
|
+
return renderFailure({
|
|
197582
|
+
headline: "The agent finished without posting its review.",
|
|
197583
|
+
detail: "It was reminded and still didn't, so the run stopped. Re-trigger to try again."
|
|
197595
197584
|
});
|
|
197596
|
-
return { summary: `### \u274C Pullfrog failed
|
|
197597
|
-
|
|
197598
|
-
${body}`, comment: body };
|
|
197599
197585
|
}
|
|
197600
|
-
if (
|
|
197601
|
-
|
|
197602
|
-
|
|
197603
|
-
|
|
197604
|
-
|
|
197586
|
+
if (isTransientUpstreamError(message2)) return formatTransientUpstreamBody(ctx);
|
|
197587
|
+
if (hangBody) return hangBody;
|
|
197588
|
+
if (message2.startsWith("provider error: ")) {
|
|
197589
|
+
return renderFailure({
|
|
197590
|
+
headline: `${ctx.account.name ?? "The model provider"} returned an error, so this run stopped.`,
|
|
197591
|
+
detail: "If it names your key, plan or balance, fix that with the provider or pick another model.",
|
|
197592
|
+
error: message2.slice("provider error: ".length),
|
|
197593
|
+
links: [pickModelLink(ctx.repo)]
|
|
197605
197594
|
});
|
|
197606
|
-
return { summary: `### \u274C Pullfrog failed
|
|
197607
|
-
|
|
197608
|
-
${body}`, comment: body };
|
|
197609
197595
|
}
|
|
197610
|
-
|
|
197611
|
-
|
|
197612
|
-
|
|
197613
|
-
|
|
197614
|
-
|
|
197615
|
-
});
|
|
197616
|
-
return { summary: `### \u274C Pullfrog failed
|
|
197617
|
-
|
|
197618
|
-
${body}`, comment: body };
|
|
197619
|
-
}
|
|
197620
|
-
if (isRunTimeoutError(input.errorMessage)) {
|
|
197621
|
-
const body = formatRunTimeoutSummary({
|
|
197622
|
-
owner: input.repo.owner,
|
|
197623
|
-
name: input.repo.name,
|
|
197624
|
-
raw: input.errorMessage
|
|
197625
|
-
});
|
|
197626
|
-
return { summary: `### \u274C Pullfrog failed
|
|
197627
|
-
|
|
197628
|
-
${body}`, comment: body };
|
|
197629
|
-
}
|
|
197630
|
-
if (isTransientUpstreamError(input.errorMessage)) {
|
|
197631
|
-
const body = formatTransientUpstreamBody(input.errorMessage);
|
|
197632
|
-
return { summary: `### \u274C Pullfrog failed
|
|
197633
|
-
|
|
197634
|
-
${body}`, comment: body };
|
|
197635
|
-
}
|
|
197636
|
-
if (hangBody) {
|
|
197637
|
-
const explained = input.agentDiagnostic?.lastProviderError !== void 0 || input.agentDiagnostic?.sawModelOutput === false;
|
|
197638
|
-
return {
|
|
197639
|
-
summary: `### \u274C Pullfrog failed
|
|
197640
|
-
|
|
197641
|
-
${hangBody}`,
|
|
197642
|
-
comment: explained ? hangBody : formatMinimalFailureComment(input.repo)
|
|
197643
|
-
};
|
|
197644
|
-
}
|
|
197645
|
-
if (input.errorMessage.startsWith("provider error: ")) {
|
|
197646
|
-
const body = formatProviderErrorBody({
|
|
197647
|
-
owner: input.repo.owner,
|
|
197648
|
-
name: input.repo.name,
|
|
197649
|
-
raw: input.errorMessage
|
|
197650
|
-
});
|
|
197651
|
-
return { summary: `### \u274C Pullfrog failed
|
|
197596
|
+
return formatUnrecognized(ctx);
|
|
197597
|
+
}
|
|
197598
|
+
function renderRunError(input) {
|
|
197599
|
+
const body = renderRunErrorBody({ ...input, account: resolveAccount(input) });
|
|
197600
|
+
return { summary: `### \u274C Pullfrog failed
|
|
197652
197601
|
|
|
197653
197602
|
${body}`, comment: body };
|
|
197654
|
-
}
|
|
197655
|
-
const genericBody = formatGenericFailure(input.errorMessage);
|
|
197656
|
-
return {
|
|
197657
|
-
summary: `### \u274C Pullfrog failed
|
|
197658
|
-
|
|
197659
|
-
${genericBody}`,
|
|
197660
|
-
comment: formatMinimalFailureComment(input.repo)
|
|
197661
|
-
};
|
|
197662
197603
|
}
|
|
197663
197604
|
|
|
197664
197605
|
// utils/runLifecycle.ts
|
|
@@ -198084,7 +198025,10 @@ async function finalizeSuccessRun(input) {
|
|
|
198084
198025
|
errorMessage: input.result.error || "agent run failed",
|
|
198085
198026
|
repo: input.repo,
|
|
198086
198027
|
agentDiagnostic: input.toolState.agentDiagnostic,
|
|
198087
|
-
routerActive: !!input.toolContext.payload.proxyModel
|
|
198028
|
+
routerActive: !!input.toolContext.payload.proxyModel,
|
|
198029
|
+
model: input.toolState.model,
|
|
198030
|
+
credential: input.toolState.credential,
|
|
198031
|
+
trial: input.toolState.modelClamped?.reason === "trial"
|
|
198088
198032
|
}) : null;
|
|
198089
198033
|
if (rendered) {
|
|
198090
198034
|
await reportErrorToComment({
|
|
@@ -198245,7 +198189,7 @@ function renderTodoMarkdown(todos) {
|
|
|
198245
198189
|
case "cancelled":
|
|
198246
198190
|
return `- ~~${todo.content}~~`;
|
|
198247
198191
|
case "in_progress":
|
|
198248
|
-
return `- [ ] <img src="
|
|
198192
|
+
return `- [ ] <img src="${TODO_SPINNER_URL}" width="11" style="visibility: visible; max-width: 100%;" /> ${todo.content}`;
|
|
198249
198193
|
case "pending":
|
|
198250
198194
|
return `- [ ] ${todo.content}`;
|
|
198251
198195
|
default:
|
|
@@ -198632,10 +198576,15 @@ async function main() {
|
|
|
198632
198576
|
const funded = runContext.trialFallback && missingKey instanceof NoUsableCredentialError ? await resolveTrialFallback({
|
|
198633
198577
|
payload,
|
|
198634
198578
|
configuredModel: effectiveModel,
|
|
198579
|
+
creditsLeftUsd: runContext.trialCreditsLeftUsd,
|
|
198635
198580
|
oidcCredentials,
|
|
198636
198581
|
repo: runContext.repo,
|
|
198637
198582
|
toolState
|
|
198638
198583
|
}) : false;
|
|
198584
|
+
const trialSpent = runContext.trialCreditsLeftUsd !== void 0 && runContext.trialCreditsLeftUsd <= 0;
|
|
198585
|
+
if (!funded && trialSpent && missingKey instanceof NoUsableCredentialError) {
|
|
198586
|
+
throw new Error(buildTrialSpentError({ owner: runContext.repo.owner }));
|
|
198587
|
+
}
|
|
198639
198588
|
if (!funded) throw missingKey;
|
|
198640
198589
|
agent2 = resolveAgent2({
|
|
198641
198590
|
model: resolvedModel,
|
|
@@ -198966,7 +198915,10 @@ ${instructions.user}` : null,
|
|
|
198966
198915
|
errorMessage,
|
|
198967
198916
|
repo: runContext.repo,
|
|
198968
198917
|
agentDiagnostic: toolState.agentDiagnostic,
|
|
198969
|
-
routerActive: !!payload.proxyModel
|
|
198918
|
+
routerActive: !!payload.proxyModel,
|
|
198919
|
+
model: toolState.model,
|
|
198920
|
+
credential: toolState.credential,
|
|
198921
|
+
trial: toolState.modelClamped?.reason === "trial"
|
|
198970
198922
|
});
|
|
198971
198923
|
await writeRunErrorOutputs({ rendered, toolState });
|
|
198972
198924
|
if (toolContext) {
|