pullfrog 0.1.67 → 0.1.68
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/README.md +72 -150
- package/dist/cli.mjs +199 -64
- package/dist/effort.d.ts +10 -0
- package/dist/external.d.ts +9 -1
- package/dist/index.js +197 -62
- package/dist/internal/index.d.ts +1 -1
- package/dist/internal.js +82 -2
- package/dist/toolState.d.ts +1 -1
- package/dist/utils/apiKeys.d.ts +19 -0
- package/dist/utils/billingErrors.d.ts +1 -2
- package/dist/utils/buildPullfrogFooter.d.ts +4 -1
- package/dist/utils/payload.d.ts +1 -0
- package/dist/utils/providerErrors.d.ts +8 -0
- package/dist/utils/proxy.d.ts +24 -0
- package/dist/utils/runContext.d.ts +7 -0
- package/dist/utils/runContextData.d.ts +9 -0
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -110208,6 +110208,7 @@ import { performance as performance5 } from "node:perf_hooks";
|
|
|
110208
110208
|
|
|
110209
110209
|
// effort.ts
|
|
110210
110210
|
var DEFAULT_EFFORT_POSITION = 0.5;
|
|
110211
|
+
var SUBSIDY_RUNG = "high";
|
|
110211
110212
|
var EFFORT_ALIASES = {
|
|
110212
110213
|
low: 0,
|
|
110213
110214
|
medium: 0.25,
|
|
@@ -110611,6 +110612,15 @@ var providers = {
|
|
|
110611
110612
|
// the model does cost nothing.
|
|
110612
110613
|
isFree: true
|
|
110613
110614
|
},
|
|
110615
|
+
// Zen meters Fable like any other model, so this route reaches it without
|
|
110616
|
+
// the Anthropic access grant `anthropic/claude-fable` still needs.
|
|
110617
|
+
"claude-fable": {
|
|
110618
|
+
displayName: "Claude Fable",
|
|
110619
|
+
resolve: "opencode/claude-fable-5-1",
|
|
110620
|
+
effort: ["low", "medium", "high", "xhigh", "max"],
|
|
110621
|
+
openRouterResolve: "openrouter/~anthropic/claude-fable-latest",
|
|
110622
|
+
subagentModel: "claude-sonnet"
|
|
110623
|
+
},
|
|
110614
110624
|
"claude-opus": {
|
|
110615
110625
|
displayName: "Claude Opus",
|
|
110616
110626
|
resolve: "opencode/claude-opus-5",
|
|
@@ -110724,6 +110734,17 @@ var providers = {
|
|
|
110724
110734
|
effort: ["minimal", "low", "medium", "high"],
|
|
110725
110735
|
openRouterResolve: "openrouter/google/gemini-3.6-flash"
|
|
110726
110736
|
},
|
|
110737
|
+
// Zen serves K3, but rule 7 can only move a mirror when its upstream moves,
|
|
110738
|
+
// so the K3 generation could never reach this block by bumping `kimi-k2`.
|
|
110739
|
+
"kimi-k3": {
|
|
110740
|
+
displayName: "Kimi K3",
|
|
110741
|
+
resolve: "opencode/kimi-k3",
|
|
110742
|
+
// Zen publishes a single rung for K3 where OpenRouter publishes three.
|
|
110743
|
+
effort: ["max"],
|
|
110744
|
+
openRouterEffort: ["low", "high", "max"],
|
|
110745
|
+
openRouterResolve: "openrouter/moonshotai/kimi-k3",
|
|
110746
|
+
subagentModel: "kimi-k2"
|
|
110747
|
+
},
|
|
110727
110748
|
"kimi-k2": {
|
|
110728
110749
|
displayName: "Kimi K2",
|
|
110729
110750
|
// k2.7-code is UNDEPLOYED on Zen — still listed in /zen/v1/models, but
|
|
@@ -110735,25 +110756,58 @@ var providers = {
|
|
|
110735
110756
|
resolve: "opencode/kimi-k2.6",
|
|
110736
110757
|
openRouterResolve: "openrouter/moonshotai/kimi-k2.7-code"
|
|
110737
110758
|
},
|
|
110759
|
+
// M3 is its own line beside M2, not a bump of it — same reason `kimi-k3`
|
|
110760
|
+
// sits beside `kimi-k2` rather than replacing it.
|
|
110761
|
+
"minimax-m3": {
|
|
110762
|
+
displayName: "MiniMax M3",
|
|
110763
|
+
resolve: "opencode/minimax-m3",
|
|
110764
|
+
openRouterResolve: "openrouter/minimax/minimax-m3"
|
|
110765
|
+
},
|
|
110738
110766
|
// slug pins the m2 line for DB stability; resolve tracks the current m2.7.
|
|
110739
110767
|
"minimax-m2.5": {
|
|
110740
110768
|
displayName: "MiniMax M2",
|
|
110741
110769
|
resolve: "opencode/minimax-m2.7",
|
|
110742
110770
|
openRouterResolve: "openrouter/minimax/minimax-m2.7"
|
|
110743
110771
|
},
|
|
110772
|
+
// Z.ai and xAI reach Zen subscribers only here — before this, `opencode-go`
|
|
110773
|
+
// was the catalog's only GLM route, and Grok had no Zen route at all.
|
|
110774
|
+
glm: {
|
|
110775
|
+
displayName: "GLM",
|
|
110776
|
+
resolve: "opencode/glm-5.2",
|
|
110777
|
+
effort: ["high", "max"],
|
|
110778
|
+
openRouterEffort: ["high", "xhigh"],
|
|
110779
|
+
openRouterResolve: "openrouter/z-ai/glm-5.2"
|
|
110780
|
+
},
|
|
110781
|
+
grok: {
|
|
110782
|
+
displayName: "Grok",
|
|
110783
|
+
resolve: "opencode/grok-4.6",
|
|
110784
|
+
effort: ["low", "medium", "high", "xhigh"],
|
|
110785
|
+
openRouterResolve: "openrouter/x-ai/grok-4.6"
|
|
110786
|
+
},
|
|
110744
110787
|
"gpt-5-nano": {
|
|
110745
110788
|
displayName: "GPT Nano",
|
|
110746
110789
|
resolve: "opencode/gpt-5-nano",
|
|
110747
110790
|
effort: ["minimal", "low", "medium", "high"],
|
|
110748
110791
|
openRouterResolve: "openrouter/openai/gpt-5-nano"
|
|
110749
110792
|
},
|
|
110793
|
+
// Zen's live free MiMo, and the second free row in a menu that big-pickle
|
|
110794
|
+
// was alone in since `mimo-v2-pro-free` lost its model.
|
|
110795
|
+
mimo: {
|
|
110796
|
+
displayName: "MiMo",
|
|
110797
|
+
resolve: "opencode/mimo-v2.5-free",
|
|
110798
|
+
// free to run, still gated on the provider's own OPENCODE_API_KEY —
|
|
110799
|
+
// see the big-pickle note above (#1077).
|
|
110800
|
+
isFree: true
|
|
110801
|
+
},
|
|
110750
110802
|
"mimo-v2-pro-free": {
|
|
110751
110803
|
displayName: "MiMo V2 Pro",
|
|
110752
110804
|
resolve: "opencode/mimo-v2-pro-free",
|
|
110753
110805
|
// free to run, still gated on the provider's own OPENCODE_API_KEY —
|
|
110754
110806
|
// see the big-pickle note above (#1077).
|
|
110755
110807
|
isFree: true,
|
|
110756
|
-
|
|
110808
|
+
// the model id Zen dropped; land a stored MiMo pick back on MiMo rather
|
|
110809
|
+
// than on the unrelated model it had to settle for while none was live.
|
|
110810
|
+
fallback: "opencode/mimo"
|
|
110757
110811
|
},
|
|
110758
110812
|
"minimax-m2.5-free": {
|
|
110759
110813
|
displayName: "MiniMax M2",
|
|
@@ -110848,6 +110902,16 @@ var providers = {
|
|
|
110848
110902
|
resolve: "opencode-go/qwen3.7-plus",
|
|
110849
110903
|
openRouterResolve: "openrouter/qwen/qwen3.7-plus"
|
|
110850
110904
|
},
|
|
110905
|
+
// the cheap rung Alibaba added under Plus (0.15/0.47 against 0.5/3), and
|
|
110906
|
+
// the only model either OpenCode plan has added since this block was written.
|
|
110907
|
+
"qwen-flash": {
|
|
110908
|
+
displayName: "Qwen Flash",
|
|
110909
|
+
resolve: "opencode-go/qwen3.8-flash",
|
|
110910
|
+
effort: ["low", "medium", "xhigh"],
|
|
110911
|
+
// the Go route publishes rungs where OpenRouter publishes none.
|
|
110912
|
+
openRouterEffort: [],
|
|
110913
|
+
openRouterResolve: "openrouter/qwen/qwen3.8-flash"
|
|
110914
|
+
},
|
|
110851
110915
|
// MiniMax — parity with opencode/* and openrouter/*; the m2 slug pins the
|
|
110852
110916
|
// line for DB stability while the resolve tracks the current m2.7.
|
|
110853
110917
|
"minimax-m3": {
|
|
@@ -111972,6 +112036,7 @@ async function installFromNpmTarball(params) {
|
|
|
111972
112036
|
// utils/providerErrors.ts
|
|
111973
112037
|
var PROVIDER_BILLING_EXHAUSTED_LABEL = "provider billing exhausted";
|
|
111974
112038
|
var PROVIDER_NO_ENDPOINTS_LABEL = "provider no routable endpoints";
|
|
112039
|
+
var PROVIDER_USAGE_LIMIT_LABEL = "provider usage limit reached";
|
|
111975
112040
|
var statusKey = `\\b(?:status[_ ]?code|http[_ ]?status|status)["']?\\s*[:=]\\s*["']?`;
|
|
111976
112041
|
var ANTHROPIC_SPEND_CAP_PATTERN = /reached your specified API usage limits\.?(?:\s*You will regain access on ([^"\n]+?)\.)?/i;
|
|
111977
112042
|
function findAnthropicSpendCap(text) {
|
|
@@ -112017,6 +112082,14 @@ var PROVIDER_ERROR_PATTERNS = [
|
|
|
112017
112082
|
// the wallet-shaped patterns above reach, and its 400 sits nowhere near a
|
|
112018
112083
|
// `status:` key either — so the whole message was dropped on the floor (#1208).
|
|
112019
112084
|
{ regex: ANTHROPIC_SPEND_CAP_PATTERN, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
|
|
112085
|
+
// OpenCode Zen / Codex-subscription cap: `AI_APICallError: The usage limit has
|
|
112086
|
+
// been reached`. Its noun is "usage limit" with no "rate", no status code and
|
|
112087
|
+
// no wallet wording, so every pattern here missed it and `lastProviderError`
|
|
112088
|
+
// stayed unset — which suppresses nothing, so the run was reported as "The
|
|
112089
|
+
// model produced no output at all … usually transient; re-running often
|
|
112090
|
+
// succeeds" while the same log held nine of these. Measured on a live account
|
|
112091
|
+
// whose ChatGPT subscription was capped.
|
|
112092
|
+
{ regex: /\bthe usage limit has been reached\b/i, label: PROVIDER_USAGE_LIMIT_LABEL },
|
|
112020
112093
|
// the OpenRouter shapes `isRouterKeylimitExhaustedError` matches. on a Router
|
|
112021
112094
|
// run those mean the PULLFROG wallet is empty and `renderRunError` returns a
|
|
112022
112095
|
// `BillingError` before ever reaching this list; on a BYOK run the very same
|
|
@@ -112147,7 +112220,7 @@ function ossEffortFloor(ctx) {
|
|
|
112147
112220
|
const alias = resolveRunAlias(ctx);
|
|
112148
112221
|
const published = alias?.openRouterEffort ?? alias?.effort;
|
|
112149
112222
|
if (!published) return 0;
|
|
112150
|
-
return rungPosition({ rung:
|
|
112223
|
+
return rungPosition({ rung: SUBSIDY_RUNG, published }) ?? 0;
|
|
112151
112224
|
}
|
|
112152
112225
|
function resolveRunEffort(ctx) {
|
|
112153
112226
|
const configured = ctx.payload.effort !== void 0;
|
|
@@ -112179,7 +112252,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
112179
112252
|
// package.json
|
|
112180
112253
|
var package_default = {
|
|
112181
112254
|
name: "pullfrog",
|
|
112182
|
-
version: "0.1.
|
|
112255
|
+
version: "0.1.68",
|
|
112183
112256
|
type: "module",
|
|
112184
112257
|
bin: {
|
|
112185
112258
|
pullfrog: "dist/cli.mjs",
|
|
@@ -194790,6 +194863,9 @@ function formatModelLabel(params) {
|
|
|
194790
194863
|
if (params.fallbackFrom) {
|
|
194791
194864
|
return `${base} (credentials for ${providerDisplayName(params.fallbackFrom)} were rejected by the provider)`;
|
|
194792
194865
|
}
|
|
194866
|
+
if (params.clamped?.reason === "trial") {
|
|
194867
|
+
return `${base} (free trial)`;
|
|
194868
|
+
}
|
|
194793
194869
|
if (params.clamped) {
|
|
194794
194870
|
const target = isAutoTier(params.clamped.from) ? "the intelligent tier" : `\`${resolveDisplayAlias(params.clamped.from)?.displayName ?? params.clamped.from}\``;
|
|
194795
194871
|
return params.clamped.reason === "card" ? `${base} (${target} needs a [card on file](https://docs.pullfrog.com/models))` : `${base} (${target} needs a [provider key](https://docs.pullfrog.com/models) \u2014 no Router support yet)`;
|
|
@@ -194799,6 +194875,15 @@ function formatModelLabel(params) {
|
|
|
194799
194875
|
}
|
|
194800
194876
|
return base;
|
|
194801
194877
|
}
|
|
194878
|
+
function buildTrialDisclosure(owner) {
|
|
194879
|
+
const consoleUrl2 = owner ? `https://pullfrog.com/console/${owner}` : "https://pullfrog.com/console";
|
|
194880
|
+
return [
|
|
194881
|
+
"---",
|
|
194882
|
+
"",
|
|
194883
|
+
"> [!IMPORTANT]",
|
|
194884
|
+
`> **This run used the free trial model.** \`DeepSeek Flash\` is fast and cheap \u2014 expect lighter work than a frontier model. [Connect a subscription or API key \u2192](${consoleUrl2})`
|
|
194885
|
+
].join("\n");
|
|
194886
|
+
}
|
|
194802
194887
|
function buildPullfrogFooter(params) {
|
|
194803
194888
|
const parts = [];
|
|
194804
194889
|
if (params.shaPinned) {
|
|
@@ -194831,10 +194916,13 @@ function buildPullfrogFooter(params) {
|
|
|
194831
194916
|
);
|
|
194832
194917
|
}
|
|
194833
194918
|
const allParts = [...parts, "[\u{1D54F}](https://x.com/pullfrogai)"];
|
|
194919
|
+
const disclosure = params.clamped?.reason === "trial" ? `${buildTrialDisclosure(params.owner)}
|
|
194920
|
+
|
|
194921
|
+
` : "";
|
|
194834
194922
|
return `
|
|
194835
194923
|
|
|
194836
194924
|
${PULLFROG_DIVIDER}
|
|
194837
|
-
<sup>${FROG_LOGO} \uFF5C ${allParts.join(" \uFF5C ")}</sup>`;
|
|
194925
|
+
${disclosure}<sup>${FROG_LOGO} \uFF5C ${allParts.join(" \uFF5C ")}</sup>`;
|
|
194838
194926
|
}
|
|
194839
194927
|
function stripExistingFooter(body) {
|
|
194840
194928
|
const dividerIndex = body.indexOf(PULLFROG_DIVIDER);
|
|
@@ -194988,7 +195076,8 @@ function buildCommentFooter(ctx, customParts) {
|
|
|
194988
195076
|
clamped: ctx.toolState.modelClamped,
|
|
194989
195077
|
unselectedProxyDefault: ctx.toolState.unselectedProxyDefault,
|
|
194990
195078
|
shaPinned: ctx.toolState.shaPinned,
|
|
194991
|
-
oss: ctx.oss
|
|
195079
|
+
oss: ctx.oss,
|
|
195080
|
+
owner: ctx.repo.owner
|
|
194992
195081
|
});
|
|
194993
195082
|
}
|
|
194994
195083
|
function buildImplementPlanLink(ctx, issueNumber, commentId) {
|
|
@@ -195987,7 +196076,8 @@ async function createAndSubmitWithFooter(ctx, params, opts) {
|
|
|
195987
196076
|
clamped: ctx.toolState.modelClamped,
|
|
195988
196077
|
unselectedProxyDefault: ctx.toolState.unselectedProxyDefault,
|
|
195989
196078
|
shaPinned: ctx.toolState.shaPinned,
|
|
195990
|
-
oss: ctx.oss
|
|
196079
|
+
oss: ctx.oss,
|
|
196080
|
+
owner: ctx.repo.owner
|
|
195991
196081
|
});
|
|
195992
196082
|
return await ctx.octokit.rest.pulls.submitReview({
|
|
195993
196083
|
owner: params.owner,
|
|
@@ -198748,7 +198838,8 @@ function buildPrBodyWithFooter(ctx, body) {
|
|
|
198748
198838
|
clamped: ctx.toolState.modelClamped,
|
|
198749
198839
|
unselectedProxyDefault: ctx.toolState.unselectedProxyDefault,
|
|
198750
198840
|
shaPinned: ctx.toolState.shaPinned,
|
|
198751
|
-
oss: ctx.oss
|
|
198841
|
+
oss: ctx.oss,
|
|
198842
|
+
owner: ctx.repo.owner
|
|
198752
198843
|
});
|
|
198753
198844
|
const bodyWithoutFooter = stripExistingFooter(fixDoubleEscapedString(body));
|
|
198754
198845
|
return `${bodyWithoutFooter}${footer}`;
|
|
@@ -200055,10 +200146,12 @@ function isByokSetupError(text) {
|
|
|
200055
200146
|
var SECRETS_UNAVAILABLE_MARKER = "couldn't load your Pullfrog secrets";
|
|
200056
200147
|
var ROUTER_UNFUNDED_MARKER = "your Pullfrog Router balance is empty";
|
|
200057
200148
|
var CREDENTIAL_REJECTED_MARKER = "was rejected by its provider";
|
|
200058
|
-
|
|
200059
|
-
|
|
200060
|
-
|
|
200061
|
-
|
|
200149
|
+
var NoUsableCredentialError = class extends Error {
|
|
200150
|
+
};
|
|
200151
|
+
function throwKeyError(params) {
|
|
200152
|
+
if (params.secretsUnavailable) throw new Error(buildSecretsUnavailableError(params));
|
|
200153
|
+
if (params.routerUnfunded) throw new NoUsableCredentialError(buildRouterUnfundedError(params));
|
|
200154
|
+
throw new NoUsableCredentialError(buildMissingApiKeyError(params));
|
|
200062
200155
|
}
|
|
200063
200156
|
function buildRouterUnfundedError(params) {
|
|
200064
200157
|
const billingUrl = `${getApiUrl()}/console/${params.owner}#billing`;
|
|
@@ -200257,57 +200350,51 @@ function validateAgentApiKey(params) {
|
|
|
200257
200350
|
validateVertexSetup({ owner: params.owner, name: params.name });
|
|
200258
200351
|
return;
|
|
200259
200352
|
}
|
|
200260
|
-
|
|
200261
|
-
|
|
200353
|
+
if (process.env[BEDROCK_MODEL_ID_ENV]?.trim() === params.model) {
|
|
200354
|
+
validateBedrockSetup({ owner: params.owner, name: params.name });
|
|
200355
|
+
return;
|
|
200356
|
+
}
|
|
200262
200357
|
}
|
|
200263
200358
|
if (params.agent.name === "opencode") {
|
|
200264
200359
|
if (params.authorized.has(params.model)) return;
|
|
200265
200360
|
const reason = getModelsFailure();
|
|
200266
200361
|
if (reason) throw new Error(reason);
|
|
200267
200362
|
if (getModelEnvVars(params.model).some(hasEnvVar2)) return;
|
|
200268
|
-
|
|
200269
|
-
buildKeyError({
|
|
200270
|
-
owner: params.owner,
|
|
200271
|
-
name: params.name,
|
|
200272
|
-
model: params.model,
|
|
200273
|
-
secretsUnavailable: params.secretsUnavailable,
|
|
200274
|
-
routerUnfunded: params.routerUnfunded
|
|
200275
|
-
})
|
|
200276
|
-
);
|
|
200277
|
-
}
|
|
200278
|
-
if (hasSingleProviderAuth(params.agent.name)) return;
|
|
200279
|
-
throw new Error(
|
|
200280
|
-
buildKeyError({
|
|
200363
|
+
throwKeyError({
|
|
200281
200364
|
owner: params.owner,
|
|
200282
200365
|
name: params.name,
|
|
200283
200366
|
model: params.model,
|
|
200284
200367
|
secretsUnavailable: params.secretsUnavailable,
|
|
200285
200368
|
routerUnfunded: params.routerUnfunded
|
|
200286
|
-
})
|
|
200287
|
-
|
|
200369
|
+
});
|
|
200370
|
+
}
|
|
200371
|
+
if (hasSingleProviderAuth(params.agent.name)) return;
|
|
200372
|
+
throwKeyError({
|
|
200373
|
+
owner: params.owner,
|
|
200374
|
+
name: params.name,
|
|
200375
|
+
model: params.model,
|
|
200376
|
+
secretsUnavailable: params.secretsUnavailable,
|
|
200377
|
+
routerUnfunded: params.routerUnfunded
|
|
200378
|
+
});
|
|
200288
200379
|
}
|
|
200289
200380
|
if (params.agent.name === "opencode") {
|
|
200290
200381
|
if ([...params.authorized].some(modelHasRuntimeAuth)) return;
|
|
200291
200382
|
const reason = getModelsFailure();
|
|
200292
200383
|
if (reason) throw new Error(reason);
|
|
200293
|
-
|
|
200294
|
-
buildKeyError({
|
|
200295
|
-
owner: params.owner,
|
|
200296
|
-
name: params.name,
|
|
200297
|
-
secretsUnavailable: params.secretsUnavailable,
|
|
200298
|
-
routerUnfunded: params.routerUnfunded
|
|
200299
|
-
})
|
|
200300
|
-
);
|
|
200301
|
-
}
|
|
200302
|
-
if (hasSingleProviderAuth(params.agent.name)) return;
|
|
200303
|
-
throw new Error(
|
|
200304
|
-
buildKeyError({
|
|
200384
|
+
throwKeyError({
|
|
200305
200385
|
owner: params.owner,
|
|
200306
200386
|
name: params.name,
|
|
200307
200387
|
secretsUnavailable: params.secretsUnavailable,
|
|
200308
200388
|
routerUnfunded: params.routerUnfunded
|
|
200309
|
-
})
|
|
200310
|
-
|
|
200389
|
+
});
|
|
200390
|
+
}
|
|
200391
|
+
if (hasSingleProviderAuth(params.agent.name)) return;
|
|
200392
|
+
throwKeyError({
|
|
200393
|
+
owner: params.owner,
|
|
200394
|
+
name: params.name,
|
|
200395
|
+
secretsUnavailable: params.secretsUnavailable,
|
|
200396
|
+
routerUnfunded: params.routerUnfunded
|
|
200397
|
+
});
|
|
200311
200398
|
}
|
|
200312
200399
|
function isApiKeyAuthError(text) {
|
|
200313
200400
|
if (!text) return false;
|
|
@@ -200432,9 +200519,9 @@ function formatApiKeyErrorSummary(params) {
|
|
|
200432
200519
|
].join("\n");
|
|
200433
200520
|
}
|
|
200434
200521
|
return [
|
|
200435
|
-
`**Your LLM provider API key was rejected.** Rotate the key in your provider dashboard, then update the
|
|
200522
|
+
`**Your LLM provider API key was rejected.** Rotate the key in your provider dashboard, then update the copy Pullfrog uses \u2014 wherever you saved it.`,
|
|
200436
200523
|
"",
|
|
200437
|
-
`[
|
|
200524
|
+
`[Pullfrog secrets \u2192](${getApiUrl()}/console/${params.owner}) \xB7 [Repo secrets \u2192](${githubSecretsUrl}) \xB7 [Model settings \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](https://docs.pullfrog.com/keys) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`
|
|
200438
200525
|
].join("\n");
|
|
200439
200526
|
}
|
|
200440
200527
|
|
|
@@ -201660,6 +201747,9 @@ var DebugInput = type.enumerated("disabled", "enabled");
|
|
|
201660
201747
|
var JsonPayload = type({
|
|
201661
201748
|
"~pullfrog": "true",
|
|
201662
201749
|
version: "string",
|
|
201750
|
+
// the server's run type, forwarded verbatim to run-context. optional so a
|
|
201751
|
+
// payload from an older server build still parses against a newer action.
|
|
201752
|
+
"type?": "string | undefined",
|
|
201663
201753
|
"model?": "string | undefined",
|
|
201664
201754
|
"modelExplicit?": "boolean | undefined",
|
|
201665
201755
|
"effort?": "number | string | undefined",
|
|
@@ -202145,7 +202235,8 @@ ${ctx.error}` : ctx.error;
|
|
|
202145
202235
|
clamped: ctx.toolState.modelClamped,
|
|
202146
202236
|
unselectedProxyDefault: ctx.toolState.unselectedProxyDefault,
|
|
202147
202237
|
shaPinned: ctx.toolState.shaPinned,
|
|
202148
|
-
oss: ctx.toolState.oss
|
|
202238
|
+
oss: ctx.toolState.oss,
|
|
202239
|
+
owner: repoContext.owner
|
|
202149
202240
|
});
|
|
202150
202241
|
const body = `${formattedError}${footer}`;
|
|
202151
202242
|
const comment = ctx.toolState.progressComment;
|
|
@@ -202228,7 +202319,7 @@ async function mintProxyKey(ctx) {
|
|
|
202228
202319
|
}
|
|
202229
202320
|
}
|
|
202230
202321
|
async function buildProxyTokenHeaders(ctx) {
|
|
202231
|
-
const fundingSource = ctx.
|
|
202322
|
+
const fundingSource = ctx.fundingSource;
|
|
202232
202323
|
if (ctx.oidcCredentials) {
|
|
202233
202324
|
const creds = ctx.oidcCredentials;
|
|
202234
202325
|
const oidcToken = await op(() => fetchIdTokenFromStash(creds), {
|
|
@@ -202260,7 +202351,7 @@ async function resolveProxyModel(ctx) {
|
|
|
202260
202351
|
const key = await mintProxyKey({
|
|
202261
202352
|
oidcCredentials: ctx.oidcCredentials,
|
|
202262
202353
|
repo: ctx.repo,
|
|
202263
|
-
|
|
202354
|
+
fundingSource: ctx.oss ? "oss" : "router"
|
|
202264
202355
|
});
|
|
202265
202356
|
if (!key) return;
|
|
202266
202357
|
process.env.OPENROUTER_API_KEY = key;
|
|
@@ -202332,6 +202423,26 @@ async function runProxyResolution(ctx) {
|
|
|
202332
202423
|
throw error62;
|
|
202333
202424
|
}
|
|
202334
202425
|
}
|
|
202426
|
+
async function resolveTrialFallback(ctx) {
|
|
202427
|
+
if (process.env.PULLFROG_MODEL?.trim()) return false;
|
|
202428
|
+
if (!ctx.oidcCredentials && !isLocalApiUrl()) return false;
|
|
202429
|
+
const key = await mintProxyKey({
|
|
202430
|
+
oidcCredentials: ctx.oidcCredentials,
|
|
202431
|
+
repo: ctx.repo,
|
|
202432
|
+
fundingSource: "trial"
|
|
202433
|
+
});
|
|
202434
|
+
if (!key) return false;
|
|
202435
|
+
process.env.OPENROUTER_API_KEY = key;
|
|
202436
|
+
core9.setSecret(key);
|
|
202437
|
+
ctx.payload.proxyModel = DEFAULT_PROXY_MODEL;
|
|
202438
|
+
ctx.toolState.model = DEFAULT_PROXY_MODEL;
|
|
202439
|
+
ctx.toolState.modelClamped = {
|
|
202440
|
+
from: ctx.configuredModel ?? DEFAULT_PROXY_MODEL,
|
|
202441
|
+
reason: "trial"
|
|
202442
|
+
};
|
|
202443
|
+
log2.info(`\xBB proxy: trial \u2192 ${DEFAULT_PROXY_MODEL}`);
|
|
202444
|
+
return true;
|
|
202445
|
+
}
|
|
202335
202446
|
|
|
202336
202447
|
// utils/prSummary.ts
|
|
202337
202448
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
|
|
@@ -202509,8 +202620,9 @@ async function fetchRunContext(params) {
|
|
|
202509
202620
|
if (params.oidcToken) {
|
|
202510
202621
|
headers["X-GitHub-OIDC-Token"] = params.oidcToken;
|
|
202511
202622
|
}
|
|
202623
|
+
const query = params.runType ? `?type=${encodeURIComponent(params.runType)}` : "";
|
|
202512
202624
|
const response = await apiFetch({
|
|
202513
|
-
path: `/api/repo/${params.repoContext.owner}/${params.repoContext.name}/run-context`,
|
|
202625
|
+
path: `/api/repo/${params.repoContext.owner}/${params.repoContext.name}/run-context${query}`,
|
|
202514
202626
|
headers,
|
|
202515
202627
|
signal: controller.signal
|
|
202516
202628
|
});
|
|
@@ -202547,7 +202659,8 @@ async function fetchRunContext(params) {
|
|
|
202547
202659
|
proxyModel: data.proxyModel,
|
|
202548
202660
|
dbSecrets: data.dbSecrets,
|
|
202549
202661
|
secretsUnavailable: data.secretsUnavailable,
|
|
202550
|
-
routerUnfunded: data.routerUnfunded
|
|
202662
|
+
routerUnfunded: data.routerUnfunded,
|
|
202663
|
+
trialFallback: data.trialFallback
|
|
202551
202664
|
};
|
|
202552
202665
|
} catch {
|
|
202553
202666
|
clearTimeout(timeoutId);
|
|
@@ -202588,7 +202701,7 @@ async function resolveRunContextData(params) {
|
|
|
202588
202701
|
retries: [100, 500],
|
|
202589
202702
|
bail: (error62) => !isTransientOctokitError(error62)
|
|
202590
202703
|
})(),
|
|
202591
|
-
fetchRunContext({ token: params.token, repoContext, oidcToken })
|
|
202704
|
+
fetchRunContext({ token: params.token, repoContext, oidcToken, runType: params.runType })
|
|
202592
202705
|
]);
|
|
202593
202706
|
return {
|
|
202594
202707
|
repo: {
|
|
@@ -202606,7 +202719,8 @@ async function resolveRunContextData(params) {
|
|
|
202606
202719
|
// a failed mint on a runner that should have been able to mint is the same
|
|
202607
202720
|
// outcome as the server-side failure: the run never sees stored secrets.
|
|
202608
202721
|
secretsUnavailable: runContext.secretsUnavailable || !!process.env.ACTIONS_ID_TOKEN_REQUEST_URL && oidcToken === void 0,
|
|
202609
|
-
routerUnfunded: runContext.routerUnfunded
|
|
202722
|
+
routerUnfunded: runContext.routerUnfunded,
|
|
202723
|
+
trialFallback: runContext.trialFallback
|
|
202610
202724
|
};
|
|
202611
202725
|
}
|
|
202612
202726
|
|
|
@@ -203686,7 +203800,11 @@ async function main() {
|
|
|
203686
203800
|
resolveGit();
|
|
203687
203801
|
const jobToken = getJobToken();
|
|
203688
203802
|
const initialOctokit = createOctokit(jobToken);
|
|
203689
|
-
const runContext = await resolveRunContextData({
|
|
203803
|
+
const runContext = await resolveRunContextData({
|
|
203804
|
+
octokit: initialOctokit,
|
|
203805
|
+
token: jobToken,
|
|
203806
|
+
runType: typeof resolvedPromptInput === "string" ? void 0 : resolvedPromptInput.type
|
|
203807
|
+
});
|
|
203690
203808
|
timer.checkpoint("runContextData");
|
|
203691
203809
|
const payload = resolvePayload(resolvedPromptInput, runContext.repoSettings);
|
|
203692
203810
|
const toolState = initToolState({
|
|
@@ -203867,7 +203985,7 @@ async function main() {
|
|
|
203867
203985
|
}
|
|
203868
203986
|
const resolvedModel = credentials.kind === "fellBack" ? credentials.replacement : configuredModel;
|
|
203869
203987
|
vertexCredentials = materializeVertexCredentials({ model: resolvedModel });
|
|
203870
|
-
|
|
203988
|
+
let agent2 = resolveAgent({
|
|
203871
203989
|
model: resolvedModel,
|
|
203872
203990
|
proxyModel: payload.proxyModel,
|
|
203873
203991
|
// the account opt-in and the canary arm are both admissions to codex, so
|
|
@@ -203879,15 +203997,32 @@ async function main() {
|
|
|
203879
203997
|
const effectiveModel = payload.proxyModel ?? resolvedModel ?? payload.model;
|
|
203880
203998
|
toolState.model = effectiveModel;
|
|
203881
203999
|
if (!payload.proxyModel) {
|
|
203882
|
-
|
|
203883
|
-
|
|
203884
|
-
|
|
203885
|
-
|
|
203886
|
-
|
|
203887
|
-
|
|
203888
|
-
|
|
203889
|
-
|
|
203890
|
-
|
|
204000
|
+
try {
|
|
204001
|
+
validateAgentApiKey({
|
|
204002
|
+
agent: agent2,
|
|
204003
|
+
model: effectiveModel,
|
|
204004
|
+
authorized: getAuthorizedModels(),
|
|
204005
|
+
owner: runContext.repo.owner,
|
|
204006
|
+
name: runContext.repo.name,
|
|
204007
|
+
secretsUnavailable: runContext.secretsUnavailable,
|
|
204008
|
+
routerUnfunded: runContext.routerUnfunded
|
|
204009
|
+
});
|
|
204010
|
+
} catch (missingKey) {
|
|
204011
|
+
const funded = runContext.trialFallback && missingKey instanceof NoUsableCredentialError ? await resolveTrialFallback({
|
|
204012
|
+
payload,
|
|
204013
|
+
configuredModel: effectiveModel,
|
|
204014
|
+
oidcCredentials,
|
|
204015
|
+
repo: runContext.repo,
|
|
204016
|
+
toolState
|
|
204017
|
+
}) : false;
|
|
204018
|
+
if (!funded) throw missingKey;
|
|
204019
|
+
agent2 = resolveAgent({
|
|
204020
|
+
model: resolvedModel,
|
|
204021
|
+
proxyModel: payload.proxyModel,
|
|
204022
|
+
codexAgent: runContext.repoSettings.codexAgent || payload.codexArm === true
|
|
204023
|
+
});
|
|
204024
|
+
toolState.agent = agent2.name;
|
|
204025
|
+
}
|
|
203891
204026
|
}
|
|
203892
204027
|
await setupGit({
|
|
203893
204028
|
gitToken: tokenRef.gitToken,
|
|
@@ -204797,7 +204932,7 @@ function resolveTarget(repo) {
|
|
|
204797
204932
|
return { owner: match3[1], repo: match3[2] };
|
|
204798
204933
|
}
|
|
204799
204934
|
function cliVersion() {
|
|
204800
|
-
const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.
|
|
204935
|
+
const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.68");
|
|
204801
204936
|
if (!parts) return "0.0.0";
|
|
204802
204937
|
return `${Number(parts[1])}.${Number(parts[2])}.${Number(parts[3])}`;
|
|
204803
204938
|
}
|
|
@@ -204964,7 +205099,7 @@ async function runCli5(input2) {
|
|
|
204964
205099
|
}
|
|
204965
205100
|
|
|
204966
205101
|
// cli.ts
|
|
204967
|
-
var VERSION10 = "0.1.
|
|
205102
|
+
var VERSION10 = "0.1.68";
|
|
204968
205103
|
var bin = basename2(process.argv[1] || "");
|
|
204969
205104
|
var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
|
|
204970
205105
|
var rawArgs = process.argv.slice(2);
|
package/dist/effort.d.ts
CHANGED
|
@@ -32,6 +32,16 @@ export type EffortPosition = number;
|
|
|
32
32
|
* ran at before this setting existed.
|
|
33
33
|
*/
|
|
34
34
|
export declare const DEFAULT_EFFORT_POSITION: EffortPosition;
|
|
35
|
+
/**
|
|
36
|
+
* the rung a Pullfrog-subsidised OSS run is pinned to, whatever the repo or a
|
|
37
|
+
* per-kind-of-work row has stored — see `ossEffortFloor`, which spends it, and
|
|
38
|
+
* the console's Model card, which stops offering the control because of it.
|
|
39
|
+
*
|
|
40
|
+
* shared rather than written twice: the runtime pins the run and the console
|
|
41
|
+
* says so, and a console that names a different rung than the one that runs is
|
|
42
|
+
* the same class of bug as the Router opt-out the two surfaces disagreed on.
|
|
43
|
+
*/
|
|
44
|
+
export declare const SUBSIDY_RUNG = "high";
|
|
35
45
|
/**
|
|
36
46
|
* names we accept on user-facing surfaces (`--effort=`, the action input),
|
|
37
47
|
* mapped to fixed points on the axis. these are a typing convenience, NOT an
|
package/dist/external.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ export declare function findDanglingPromptToolRefs(params: {
|
|
|
50
50
|
toolNames: string[];
|
|
51
51
|
}): string[];
|
|
52
52
|
export type { EffortPosition } from "./effort.ts";
|
|
53
|
-
export { DEFAULT_EFFORT_POSITION, EFFORT_ALIASES, isEffortPosition, offeredRungs, parseEffortPosition, resolveRung, rungLabel, rungPosition, } from "./effort.ts";
|
|
53
|
+
export { DEFAULT_EFFORT_POSITION, EFFORT_ALIASES, isEffortPosition, offeredRungs, parseEffortPosition, resolveRung, rungLabel, rungPosition, SUBSIDY_RUNG, } from "./effort.ts";
|
|
54
54
|
export type { AutoTier, ModelAlias, ModelProvider, ProviderConfig } from "./models.ts";
|
|
55
55
|
export { AUTO_EFFICIENT, AUTO_INTELLIGENT, DEFAULT_PROXY_MODEL, defaultAutoTier, getAutoSelectHintModel, getModelEffortLevels, getModelEnvVars, getModelManagedCredentials, getModelProvider, getProviderDisplayName, isAutoTier, isCardGatedModel, isOssAllowedModel, modelAliases, modelHasStoredAuth, OSS_MODEL_ALLOWLIST, OSS_RECOMMENDED_MODEL, ossFundedModelNames, parseModel, providers, resolveAutoTier, resolveCliModel, resolveDisplayAlias, resolveModelRung, resolveModelSlug, resolveOpenRouterModel, } from "./models.ts";
|
|
56
56
|
export type ToolPermission = "disabled" | "enabled";
|
|
@@ -257,6 +257,14 @@ export interface WriteablePayload {
|
|
|
257
257
|
"~pullfrog": true;
|
|
258
258
|
/** semantic version of the payload to ensure compatibility */
|
|
259
259
|
version: string;
|
|
260
|
+
/**
|
|
261
|
+
* which kind of work this run is (`pr-created`, `issue-created`, …). the
|
|
262
|
+
* server's own run-type vocabulary, opaque here: the action only forwards it
|
|
263
|
+
* to `run-context`, which resolves the repo's per-trigger model override
|
|
264
|
+
* against it. absent ⇒ the repo default, which is what every run got before
|
|
265
|
+
* overrides existed.
|
|
266
|
+
*/
|
|
267
|
+
type?: string | undefined;
|
|
260
268
|
/** provider/model slug (e.g. "anthropic/claude-opus") */
|
|
261
269
|
model?: string | undefined;
|
|
262
270
|
/**
|