pullfrog 0.1.67 → 0.1.69
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 +236 -77
- package/dist/effort.d.ts +10 -0
- package/dist/external.d.ts +18 -1
- package/dist/index.js +234 -75
- package/dist/internal/index.d.ts +1 -1
- package/dist/internal.js +91 -8
- package/dist/mcp/reviewComments.d.ts +42 -0
- 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/internal/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Re-exports shared types, values, and utilities needed by the Next.js app.
|
|
4
4
|
*/
|
|
5
5
|
export type { AuthorPermission, AutoTier, EffortPosition, ModelAlias, ModelProvider, Payload, PayloadEvent, ProviderConfig, PushPermission, ShellPermission, ToolPermission, WriteablePayload, XrepoConfig, } from "../external.ts";
|
|
6
|
-
export { AUTO_EFFICIENT, AUTO_INTELLIGENT, DEFAULT_EFFORT_POSITION, DEFAULT_PROXY_MODEL, defaultAutoTier, EFFORT_ALIASES, getAutoSelectHintModel, getModelEffortLevels, getModelEnvVars, getModelManagedCredentials, getModelProvider, getProviderDisplayName, isAutoTier, isCardGatedModel, isEffortPosition, isOssAllowedModel, modelAliases, modelHasStoredAuth, OSS_MODEL_ALLOWLIST, OSS_RECOMMENDED_MODEL, offeredRungs, ossFundedModelNames, parseEffortPosition, parseModel, providers, pullfrogMcpName, resolveAutoTier, resolveCliModel, resolveDisplayAlias, resolveModelRung, resolveModelSlug, resolveOpenRouterModel, resolveRung, rungLabel, rungPosition, } from "../external.ts";
|
|
6
|
+
export { AUTO_EFFICIENT, AUTO_INTELLIGENT, DEFAULT_EFFORT_POSITION, DEFAULT_PROXY_MODEL, defaultAutoTier, EFFORT_ALIASES, getAutoSelectHintModel, getModelEffortLevels, getModelEnvVars, getModelManagedCredentials, getModelProvider, getProviderDisplayName, isAutoTier, isCardGatedModel, isEffortPosition, isOssAllowedModel, modelAliases, modelHasStoredAuth, OSS_MODEL_ALLOWLIST, OSS_RECOMMENDED_MODEL, offeredRungs, ossFundedModelNames, parseEffortPosition, parseModel, providers, pullfrogMcpName, resolveAutoTier, resolveCliModel, resolveDisplayAlias, resolveModelRung, resolveModelSlug, resolveOpenRouterModel, resolveRung, rungLabel, rungPosition, SUBSIDY_RUNG, } from "../external.ts";
|
|
7
7
|
export type { Mode } from "../modes.ts";
|
|
8
8
|
export { modes } from "../modes.ts";
|
|
9
9
|
export { commercialPaywallBody } from "../utils/billingErrors.ts";
|
package/dist/internal.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createRequire as __createRequire } from 'module'; import { fileURLToPat
|
|
|
2
2
|
|
|
3
3
|
// effort.ts
|
|
4
4
|
var DEFAULT_EFFORT_POSITION = 0.5;
|
|
5
|
+
var SUBSIDY_RUNG = "high";
|
|
5
6
|
var EFFORT_ALIASES = {
|
|
6
7
|
low: 0,
|
|
7
8
|
medium: 0.25,
|
|
@@ -417,6 +418,15 @@ var providers = {
|
|
|
417
418
|
// the model does cost nothing.
|
|
418
419
|
isFree: true
|
|
419
420
|
},
|
|
421
|
+
// Zen meters Fable like any other model, so this route reaches it without
|
|
422
|
+
// the Anthropic access grant `anthropic/claude-fable` still needs.
|
|
423
|
+
"claude-fable": {
|
|
424
|
+
displayName: "Claude Fable",
|
|
425
|
+
resolve: "opencode/claude-fable-5-1",
|
|
426
|
+
effort: ["low", "medium", "high", "xhigh", "max"],
|
|
427
|
+
openRouterResolve: "openrouter/~anthropic/claude-fable-latest",
|
|
428
|
+
subagentModel: "claude-sonnet"
|
|
429
|
+
},
|
|
420
430
|
"claude-opus": {
|
|
421
431
|
displayName: "Claude Opus",
|
|
422
432
|
resolve: "opencode/claude-opus-5",
|
|
@@ -530,6 +540,17 @@ var providers = {
|
|
|
530
540
|
effort: ["minimal", "low", "medium", "high"],
|
|
531
541
|
openRouterResolve: "openrouter/google/gemini-3.6-flash"
|
|
532
542
|
},
|
|
543
|
+
// Zen serves K3, but rule 7 can only move a mirror when its upstream moves,
|
|
544
|
+
// so the K3 generation could never reach this block by bumping `kimi-k2`.
|
|
545
|
+
"kimi-k3": {
|
|
546
|
+
displayName: "Kimi K3",
|
|
547
|
+
resolve: "opencode/kimi-k3",
|
|
548
|
+
// Zen publishes a single rung for K3 where OpenRouter publishes three.
|
|
549
|
+
effort: ["max"],
|
|
550
|
+
openRouterEffort: ["low", "high", "max"],
|
|
551
|
+
openRouterResolve: "openrouter/moonshotai/kimi-k3",
|
|
552
|
+
subagentModel: "kimi-k2"
|
|
553
|
+
},
|
|
533
554
|
"kimi-k2": {
|
|
534
555
|
displayName: "Kimi K2",
|
|
535
556
|
// k2.7-code is UNDEPLOYED on Zen — still listed in /zen/v1/models, but
|
|
@@ -541,25 +562,57 @@ var providers = {
|
|
|
541
562
|
resolve: "opencode/kimi-k2.6",
|
|
542
563
|
openRouterResolve: "openrouter/moonshotai/kimi-k2.7-code"
|
|
543
564
|
},
|
|
565
|
+
// M3 is its own line beside M2, not a bump of it — same reason `kimi-k3`
|
|
566
|
+
// sits beside `kimi-k2` rather than replacing it.
|
|
567
|
+
"minimax-m3": {
|
|
568
|
+
displayName: "MiniMax M3",
|
|
569
|
+
resolve: "opencode/minimax-m3",
|
|
570
|
+
openRouterResolve: "openrouter/minimax/minimax-m3"
|
|
571
|
+
},
|
|
544
572
|
// slug pins the m2 line for DB stability; resolve tracks the current m2.7.
|
|
545
573
|
"minimax-m2.5": {
|
|
546
574
|
displayName: "MiniMax M2",
|
|
547
575
|
resolve: "opencode/minimax-m2.7",
|
|
548
576
|
openRouterResolve: "openrouter/minimax/minimax-m2.7"
|
|
549
577
|
},
|
|
578
|
+
// Z.ai and xAI reach Zen subscribers only here — before this, `opencode-go`
|
|
579
|
+
// was the catalog's only GLM route, and Grok had no Zen route at all.
|
|
580
|
+
glm: {
|
|
581
|
+
displayName: "GLM",
|
|
582
|
+
resolve: "opencode/glm-5.3",
|
|
583
|
+
effort: ["low", "high", "max"],
|
|
584
|
+
openRouterResolve: "openrouter/z-ai/glm-5.3"
|
|
585
|
+
},
|
|
586
|
+
grok: {
|
|
587
|
+
displayName: "Grok",
|
|
588
|
+
resolve: "opencode/grok-4.6",
|
|
589
|
+
effort: ["low", "medium", "high", "xhigh"],
|
|
590
|
+
openRouterResolve: "openrouter/x-ai/grok-4.6"
|
|
591
|
+
},
|
|
550
592
|
"gpt-5-nano": {
|
|
551
593
|
displayName: "GPT Nano",
|
|
552
594
|
resolve: "opencode/gpt-5-nano",
|
|
553
595
|
effort: ["minimal", "low", "medium", "high"],
|
|
554
596
|
openRouterResolve: "openrouter/openai/gpt-5-nano"
|
|
555
597
|
},
|
|
598
|
+
// Zen's live free MiMo, and the second free row in a menu that big-pickle
|
|
599
|
+
// was alone in since `mimo-v2-pro-free` lost its model.
|
|
600
|
+
mimo: {
|
|
601
|
+
displayName: "MiMo",
|
|
602
|
+
resolve: "opencode/mimo-v2.5-free",
|
|
603
|
+
// free to run, still gated on the provider's own OPENCODE_API_KEY —
|
|
604
|
+
// see the big-pickle note above (#1077).
|
|
605
|
+
isFree: true
|
|
606
|
+
},
|
|
556
607
|
"mimo-v2-pro-free": {
|
|
557
608
|
displayName: "MiMo V2 Pro",
|
|
558
609
|
resolve: "opencode/mimo-v2-pro-free",
|
|
559
610
|
// free to run, still gated on the provider's own OPENCODE_API_KEY —
|
|
560
611
|
// see the big-pickle note above (#1077).
|
|
561
612
|
isFree: true,
|
|
562
|
-
|
|
613
|
+
// the model id Zen dropped; land a stored MiMo pick back on MiMo rather
|
|
614
|
+
// than on the unrelated model it had to settle for while none was live.
|
|
615
|
+
fallback: "opencode/mimo"
|
|
563
616
|
},
|
|
564
617
|
"minimax-m2.5-free": {
|
|
565
618
|
displayName: "MiniMax M2",
|
|
@@ -575,10 +628,11 @@ var providers = {
|
|
|
575
628
|
// OpenCode Go is a separate $10/mo subscription from Zen, served on its own
|
|
576
629
|
// base URL (`https://opencode.ai/zen/go/v1`) but authenticated with the SAME
|
|
577
630
|
// `OPENCODE_API_KEY`. it carries the open-weight coding models plus a couple
|
|
578
|
-
// of frontier ones,
|
|
579
|
-
//
|
|
580
|
-
//
|
|
581
|
-
//
|
|
631
|
+
// of frontier ones, six of which are served ONLY here — Zen's `/v1/models`
|
|
632
|
+
// does not list qwen3.7/3.8-*, mimo-v2.5-pro, longcat-2.0 or hy3. (it listed
|
|
633
|
+
// no glm-5.3* either until 2026-09, which is why `opencode/glm` trailed on
|
|
634
|
+
// 5.2.) so for a Go subscriber this provider is not a duplicate route to Zen,
|
|
635
|
+
// it is the only route to a large part of what they pay for.
|
|
582
636
|
// like `opencode` and `openrouter` this is a ROUTER, not a vendor: slugs and
|
|
583
637
|
// display names mirror the upstream brand tier, and the picker groups them
|
|
584
638
|
// under the upstream vendor.
|
|
@@ -647,13 +701,25 @@ var providers = {
|
|
|
647
701
|
// `high` the Go route does not.
|
|
648
702
|
effort: ["low", "medium", "xhigh"],
|
|
649
703
|
openRouterEffort: ["minimal", "low", "medium", "high", "xhigh"],
|
|
650
|
-
|
|
704
|
+
// OpenRouter retired the rolling `qwen3.8-max` for a dated snapshot, so
|
|
705
|
+
// this side has to pin one; the Go route still carries the rolling id.
|
|
706
|
+
openRouterResolve: "openrouter/qwen/qwen3.8-max-0902"
|
|
651
707
|
},
|
|
652
708
|
"qwen-plus": {
|
|
653
709
|
displayName: "Qwen Plus",
|
|
654
710
|
resolve: "opencode-go/qwen3.7-plus",
|
|
655
711
|
openRouterResolve: "openrouter/qwen/qwen3.7-plus"
|
|
656
712
|
},
|
|
713
|
+
// the cheap rung Alibaba added under Plus (0.15/0.47 against 0.5/3), and
|
|
714
|
+
// the only model either OpenCode plan has added since this block was written.
|
|
715
|
+
"qwen-flash": {
|
|
716
|
+
displayName: "Qwen Flash",
|
|
717
|
+
resolve: "opencode-go/qwen3.8-flash",
|
|
718
|
+
effort: ["low", "medium", "xhigh"],
|
|
719
|
+
// the Go route publishes rungs where OpenRouter publishes none.
|
|
720
|
+
openRouterEffort: [],
|
|
721
|
+
openRouterResolve: "openrouter/qwen/qwen3.8-flash"
|
|
722
|
+
},
|
|
657
723
|
// MiniMax — parity with opencode/* and openrouter/*; the m2 slug pins the
|
|
658
724
|
// line for DB stability while the resolve tracks the current m2.7.
|
|
659
725
|
"minimax-m3": {
|
|
@@ -1319,6 +1385,7 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
|
|
|
1319
1385
|
- record what was done (or why nothing was done)
|
|
1320
1386
|
|
|
1321
1387
|
5. Quality check:
|
|
1388
|
+
- re-call \`${t("get_review_comments")}\` with \`fresh: true\` before committing: reviewers keep commenting while you work, and any thread it now returns that you have not addressed is in scope for this run.
|
|
1322
1389
|
- test changes, then review the diff before committing \u2014 verify only intended changes are present, no debug artifacts remain, no fix turned out to be bloat in context (revert any that did), and the changes are clean enough that a senior engineer would approve without hesitation
|
|
1323
1390
|
- ${commitStep}
|
|
1324
1391
|
|
|
@@ -1328,7 +1395,7 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
|
|
|
1328
1395
|
- **once the fix is live on the remote**, for each thread you acted on:
|
|
1329
1396
|
- reply ONCE via \`${t("reply_to_review_comment")}\`. The \`comment_id\` parameter takes the root comment's numeric \`id=\` (from the first \`comment author=...\` tag in the \`${t("get_review_comments")}\` output) \u2014 NOT the \`thread=\` value; that's a separate GraphQL ID used by resolve. The runtime dedupes identical bodies within a session.
|
|
1330
1397
|
- **immediately** call \`${t("resolve_review_thread")}\` with that thread's \`thread=\` value as \`thread_id\`. Resolve every thread where you (a) made the requested code change in full \u2014 partial fixes leave the thread open \u2014 OR (b) replied with a substantive answer the user explicitly asked for. Do NOT resolve threads where you pushed back on the request and the disagreement is unresolved; leave those open for the human to mediate.
|
|
1331
|
-
- call \`${t("report_progress")}\` with a brief summary
|
|
1398
|
+
- call \`${t("report_progress")}\` with a brief summary. If your last \`${t("get_review_comments")}\` turned up threads you did not address, name them there \u2014 a review arriving this late is suppressed as a duplicate and nothing else will pick it up.`
|
|
1332
1399
|
},
|
|
1333
1400
|
// Review and IncrementalReview route the minimum reviewfrog specialists
|
|
1334
1401
|
// needed to cover unresolved, disposition-changing hypotheses. Most runs
|
|
@@ -1635,6 +1702,9 @@ function formatModelLabel(params) {
|
|
|
1635
1702
|
if (params.fallbackFrom) {
|
|
1636
1703
|
return `${base} (credentials for ${providerDisplayName(params.fallbackFrom)} were rejected by the provider)`;
|
|
1637
1704
|
}
|
|
1705
|
+
if (params.clamped?.reason === "trial") {
|
|
1706
|
+
return `${base} (free trial)`;
|
|
1707
|
+
}
|
|
1638
1708
|
if (params.clamped) {
|
|
1639
1709
|
const target = isAutoTier(params.clamped.from) ? "the intelligent tier" : `\`${resolveDisplayAlias(params.clamped.from)?.displayName ?? params.clamped.from}\``;
|
|
1640
1710
|
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)`;
|
|
@@ -1644,6 +1714,15 @@ function formatModelLabel(params) {
|
|
|
1644
1714
|
}
|
|
1645
1715
|
return base;
|
|
1646
1716
|
}
|
|
1717
|
+
function buildTrialDisclosure(owner) {
|
|
1718
|
+
const consoleUrl = owner ? `https://pullfrog.com/console/${owner}` : "https://pullfrog.com/console";
|
|
1719
|
+
return [
|
|
1720
|
+
"---",
|
|
1721
|
+
"",
|
|
1722
|
+
"> [!IMPORTANT]",
|
|
1723
|
+
`> **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](${consoleUrl})`
|
|
1724
|
+
].join("\n");
|
|
1725
|
+
}
|
|
1647
1726
|
function buildPullfrogFooter(params) {
|
|
1648
1727
|
const parts = [];
|
|
1649
1728
|
if (params.shaPinned) {
|
|
@@ -1676,10 +1755,13 @@ function buildPullfrogFooter(params) {
|
|
|
1676
1755
|
);
|
|
1677
1756
|
}
|
|
1678
1757
|
const allParts = [...parts, "[\u{1D54F}](https://x.com/pullfrogai)"];
|
|
1758
|
+
const disclosure = params.clamped?.reason === "trial" ? `${buildTrialDisclosure(params.owner)}
|
|
1759
|
+
|
|
1760
|
+
` : "";
|
|
1679
1761
|
return `
|
|
1680
1762
|
|
|
1681
1763
|
${PULLFROG_DIVIDER}
|
|
1682
|
-
<sup>${FROG_LOGO} \uFF5C ${allParts.join(" \uFF5C ")}</sup>`;
|
|
1764
|
+
${disclosure}<sup>${FROG_LOGO} \uFF5C ${allParts.join(" \uFF5C ")}</sup>`;
|
|
1683
1765
|
}
|
|
1684
1766
|
function stripExistingFooter(body) {
|
|
1685
1767
|
const dividerIndex = body.indexOf(PULLFROG_DIVIDER);
|
|
@@ -2230,6 +2312,7 @@ export {
|
|
|
2230
2312
|
OSS_RECOMMENDED_MODEL,
|
|
2231
2313
|
PULLFROG_DIVIDER,
|
|
2232
2314
|
RUN_STATUS_CHECK_NAME,
|
|
2315
|
+
SUBSIDY_RUNG,
|
|
2233
2316
|
TIMEOUT_DISABLED,
|
|
2234
2317
|
buildPullfrogFooter,
|
|
2235
2318
|
commercialPaywallBody,
|
|
@@ -67,6 +67,7 @@ export declare function parseFilePatches(patch: string): ParsedHunk[];
|
|
|
67
67
|
export declare const GetReviewComments: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
68
68
|
pull_number: number;
|
|
69
69
|
review_id: number;
|
|
70
|
+
fresh?: boolean;
|
|
70
71
|
}, {}>;
|
|
71
72
|
/**
|
|
72
73
|
* formats thread blocks into markdown with TOC and line numbers.
|
|
@@ -94,6 +95,37 @@ export declare function buildThreadBlocks(threads: ReviewThread[], filePatchMap:
|
|
|
94
95
|
lineRange: string;
|
|
95
96
|
content: string[];
|
|
96
97
|
}[];
|
|
98
|
+
/**
|
|
99
|
+
* Open threads on the PR that this run should also address, beyond the review
|
|
100
|
+
* that dispatched it.
|
|
101
|
+
*
|
|
102
|
+
* A reviewer working through a PR emits one `pull_request_review_submitted` per
|
|
103
|
+
* submission, so a second review lands seconds after the first — and until this
|
|
104
|
+
* existed, the run already working on the PR could never see it: the filter
|
|
105
|
+
* above keeps only threads carrying a comment from the *dispatched* `reviewId`,
|
|
106
|
+
* so a new comment on a different line was invisible no matter how often the
|
|
107
|
+
* agent re-read. That is what made the in-flight cap in `handleWebhook.ts` a
|
|
108
|
+
* silent loss rather than the coalescing it was documented as (#1103).
|
|
109
|
+
*
|
|
110
|
+
* `fetchAllReviewThreads` already pulls every thread on the PR and caches it for
|
|
111
|
+
* 60s, so this costs no extra round trip and a re-read mid-run picks up whatever
|
|
112
|
+
* landed behind the run.
|
|
113
|
+
*
|
|
114
|
+
* Three exclusions, each load-bearing:
|
|
115
|
+
* - resolved threads are done, and re-opening that conversation is noise.
|
|
116
|
+
* - a thread Pullfrog has already spoken in was handled by an earlier run.
|
|
117
|
+
* That deliberately includes the pushbacks AddressReviews leaves open for a
|
|
118
|
+
* human to mediate — re-addressing one re-litigates a settled disagreement —
|
|
119
|
+
* and it is also what stops this mode replying to Pullfrog's own reviews.
|
|
120
|
+
* - under `mentions` a concurrent thread is in scope only if it actually asked
|
|
121
|
+
* for Pullfrog. Deliberately asymmetric with `threadsForReview`, which is
|
|
122
|
+
* returned whole and always was: the dispatching review is the one the
|
|
123
|
+
* server already adjudicated, and the agent needs its unmentioned threads as
|
|
124
|
+
* context for the comment that did mention it. Which of those to ACT on stays
|
|
125
|
+
* the mode prompt's job. A concurrent review has had no such adjudication, so
|
|
126
|
+
* the mention is the only thing that can authorize it.
|
|
127
|
+
*/
|
|
128
|
+
export declare function concurrentThreads(allThreads: (ReviewThread | null)[], threadsForReview: ReviewThread[], input: GetReviewDataInput): ReviewThread[];
|
|
97
129
|
interface GetReviewDataInput {
|
|
98
130
|
octokit: Octokit;
|
|
99
131
|
owner: string;
|
|
@@ -101,6 +133,14 @@ interface GetReviewDataInput {
|
|
|
101
133
|
pullNumber: number;
|
|
102
134
|
reviewId: number;
|
|
103
135
|
approvedBy?: string | undefined;
|
|
136
|
+
/**
|
|
137
|
+
* Widen the read past the dispatching review to the other open threads on the
|
|
138
|
+
* PR — `all` on a Pullfrog-authored PR, `mentions` when only `@pullfrog`-
|
|
139
|
+
* mentioning threads are in scope. Absent (console `fix_review`, and any
|
|
140
|
+
* payload from a server build that predates the field) keeps the read scoped
|
|
141
|
+
* to the dispatching review exactly as before.
|
|
142
|
+
*/
|
|
143
|
+
addressScope?: "all" | "mentions" | undefined;
|
|
104
144
|
tmpdir: string;
|
|
105
145
|
githubToken: string;
|
|
106
146
|
}
|
|
@@ -148,9 +188,11 @@ export declare function getReviewData(input: GetReviewDataInput): Promise<{
|
|
|
148
188
|
export declare function GetReviewCommentsTool(ctx: ToolContext): import("fastmcp").Tool<any, import("@standard-schema/spec").StandardSchemaV1<{
|
|
149
189
|
pull_number: number;
|
|
150
190
|
review_id: number;
|
|
191
|
+
fresh?: boolean;
|
|
151
192
|
}, {
|
|
152
193
|
pull_number: number;
|
|
153
194
|
review_id: number;
|
|
195
|
+
fresh?: boolean;
|
|
154
196
|
}>> & {
|
|
155
197
|
mutates?: boolean;
|
|
156
198
|
};
|
package/dist/toolState.d.ts
CHANGED
|
@@ -144,7 +144,7 @@ export interface ToolState {
|
|
|
144
144
|
unselectedProxyDefault?: boolean | undefined;
|
|
145
145
|
modelClamped?: {
|
|
146
146
|
from: string;
|
|
147
|
-
reason: "card" | "noRouterPath" | "oss";
|
|
147
|
+
reason: "card" | "noRouterPath" | "oss" | "trial";
|
|
148
148
|
} | undefined;
|
|
149
149
|
shaPinned?: boolean | undefined;
|
|
150
150
|
oss?: boolean | undefined;
|
package/dist/utils/apiKeys.d.ts
CHANGED
|
@@ -49,6 +49,25 @@ export declare const ROUTER_UNFUNDED_MARKER = "your Pullfrog Router balance is e
|
|
|
49
49
|
* hand that agent the ability to suppress every other error body.
|
|
50
50
|
*/
|
|
51
51
|
export declare const CREDENTIAL_REJECTED_MARKER = "was rejected by its provider";
|
|
52
|
+
/**
|
|
53
|
+
* Three ways to arrive at "the runner has no key", each with a different CTA:
|
|
54
|
+
* we couldn't read the key you stored, your Router wallet ran dry and you have
|
|
55
|
+
* no key of your own, or you genuinely have no key. Every throw site picks by
|
|
56
|
+
* these flags.
|
|
57
|
+
*/
|
|
58
|
+
/**
|
|
59
|
+
* Nothing in the environment can pay for this run — as distinct from a
|
|
60
|
+
* credential that IS configured but incompletely (the Bedrock/Vertex/Azure/
|
|
61
|
+
* OpenAI-compatible setup validators), an agent that could not start
|
|
62
|
+
* (`getModelsFailure`), or Pullfrog failing to hand its own secrets over.
|
|
63
|
+
*
|
|
64
|
+
* The trial fallback keys on this class, and that is the whole reason it
|
|
65
|
+
* exists: every other failure in `validateAgentApiKey` means the user HAS
|
|
66
|
+
* brought a key, so falling back would swap their model for a cheap one and
|
|
67
|
+
* swallow the message telling them what to fix.
|
|
68
|
+
*/
|
|
69
|
+
export declare class NoUsableCredentialError extends Error {
|
|
70
|
+
}
|
|
52
71
|
/**
|
|
53
72
|
* Validate that the resolved model can actually be served by the chosen
|
|
54
73
|
* agent. For routing slugs (Bedrock / Vertex) the auth shape is multi-var
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
* Actions job summary and the PR progress comment.
|
|
10
10
|
*
|
|
11
11
|
* Lives outside `main.ts` so adding a new error `code` branch is a one-file
|
|
12
|
-
* edit
|
|
13
|
-
* in `action/test/coverage.ts::ALWAYS_RUN_ALL`).
|
|
12
|
+
* edit rather than an orchestrator edit (see wiki/main.md).
|
|
14
13
|
*/
|
|
15
14
|
/**
|
|
16
15
|
* Billing-layer error surfaced from `/api/proxy-token` as a 402. User-actionable,
|
|
@@ -36,7 +36,7 @@ export interface BuildPullfrogFooterParams {
|
|
|
36
36
|
*/
|
|
37
37
|
clamped?: {
|
|
38
38
|
from: string;
|
|
39
|
-
reason: "card" | "noRouterPath" | "oss";
|
|
39
|
+
reason: "card" | "noRouterPath" | "oss" | "trial";
|
|
40
40
|
} | undefined;
|
|
41
41
|
/**
|
|
42
42
|
* true when the run used the default proxy model only because no model was
|
|
@@ -57,6 +57,9 @@ export interface BuildPullfrogFooterParams {
|
|
|
57
57
|
* with the phrase linking to the OSS application page.
|
|
58
58
|
*/
|
|
59
59
|
oss?: boolean | undefined;
|
|
60
|
+
/** repo owner, used to deep-link the trial disclosure at that account's own
|
|
61
|
+
* console rather than the generic landing page. */
|
|
62
|
+
owner?: string | undefined;
|
|
60
63
|
}
|
|
61
64
|
/**
|
|
62
65
|
* build a pullfrog footer with configurable parts
|
package/dist/utils/payload.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export declare const JsonPayload: import("arktype/internal/variants/object.ts").
|
|
|
4
4
|
"~pullfrog": true;
|
|
5
5
|
version: string;
|
|
6
6
|
prompt: string;
|
|
7
|
+
type?: string | undefined;
|
|
7
8
|
model?: string | undefined;
|
|
8
9
|
modelExplicit?: boolean | undefined;
|
|
9
10
|
effort?: string | number | undefined;
|
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
export declare const PROVIDER_BILLING_EXHAUSTED_LABEL = "provider billing exhausted";
|
|
3
3
|
/** Stable label for "OpenRouter can route this model nowhere you permit". */
|
|
4
4
|
export declare const PROVIDER_NO_ENDPOINTS_LABEL = "provider no routable endpoints";
|
|
5
|
+
/**
|
|
6
|
+
* A SUBSCRIPTION usage window that has run out, which is deliberately NOT
|
|
7
|
+
* `PROVIDER_BILLING_EXHAUSTED_LABEL`: that label routes to a body whose CTA is
|
|
8
|
+
* "Top up your provider balance", and a capped ChatGPT or Zen plan has no
|
|
9
|
+
* balance to top up — it resets on its own. This label carries the cause into
|
|
10
|
+
* the headline and lets the generic body stand.
|
|
11
|
+
*/
|
|
12
|
+
export declare const PROVIDER_USAGE_LIMIT_LABEL = "provider usage limit reached";
|
|
5
13
|
export declare function findAnthropicSpendCap(text: string): {
|
|
6
14
|
regainAt: string | null;
|
|
7
15
|
} | null;
|
package/dist/utils/proxy.d.ts
CHANGED
|
@@ -44,3 +44,27 @@ export declare function runProxyResolution(ctx: {
|
|
|
44
44
|
};
|
|
45
45
|
toolState: ToolState;
|
|
46
46
|
}): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Late fallback for a run inside the no-card trial whose own key search came up
|
|
49
|
+
* dry. Mints a Pullfrog-funded key on the efficient tier so a new account's
|
|
50
|
+
* first run produces a review rather than a credentials error.
|
|
51
|
+
*
|
|
52
|
+
* Deliberately runs AFTER `validateAgentApiKey` rather than beside the ordinary
|
|
53
|
+
* proxy resolution: the server grants permission but cannot see workflow `env:`
|
|
54
|
+
* keys, so only the runner knows whether anything else could have paid. Minting
|
|
55
|
+
* eagerly would silently downgrade every account whose key lives in GitHub
|
|
56
|
+
* Actions secrets.
|
|
57
|
+
*
|
|
58
|
+
* Returns false when the mint is unavailable (no OIDC, server declined), leaving
|
|
59
|
+
* the caller to raise the original missing-key error unchanged.
|
|
60
|
+
*/
|
|
61
|
+
export declare function resolveTrialFallback(ctx: {
|
|
62
|
+
payload: ResolvedPayload;
|
|
63
|
+
configuredModel: string | undefined;
|
|
64
|
+
oidcCredentials: OidcCredentials | null;
|
|
65
|
+
repo: {
|
|
66
|
+
owner: string;
|
|
67
|
+
name: string;
|
|
68
|
+
};
|
|
69
|
+
toolState: ToolState;
|
|
70
|
+
}): Promise<boolean>;
|
|
@@ -87,6 +87,10 @@ export interface RunContext {
|
|
|
87
87
|
* funding state. see wiki/billing.md.
|
|
88
88
|
*/
|
|
89
89
|
routerUnfunded?: boolean | undefined;
|
|
90
|
+
/** the account is inside its no-card trial and nothing else could fund this
|
|
91
|
+
* run — the runner may mint a subsidized efficient-tier key if, and only if,
|
|
92
|
+
* its own key search comes up dry. see the run-context route. */
|
|
93
|
+
trialFallback?: boolean | undefined;
|
|
90
94
|
}
|
|
91
95
|
/**
|
|
92
96
|
* fetch run context from Pullfrog API
|
|
@@ -97,4 +101,7 @@ export declare function fetchRunContext(params: {
|
|
|
97
101
|
token: string;
|
|
98
102
|
repoContext: RepoContext;
|
|
99
103
|
oidcToken?: string | undefined;
|
|
104
|
+
/** `payload.type` — lets the server apply this repo's per-trigger model
|
|
105
|
+
* override, which it cannot derive from owner/repo alone. */
|
|
106
|
+
runType?: string | undefined;
|
|
100
107
|
}): Promise<RunContext>;
|
|
@@ -20,10 +20,19 @@ export interface RunContextData {
|
|
|
20
20
|
/** the Router was declined because the wallet is empty. see
|
|
21
21
|
* `RunContext.routerUnfunded`. */
|
|
22
22
|
routerUnfunded?: boolean | undefined;
|
|
23
|
+
/** the account is inside its no-card trial and nothing else could fund this
|
|
24
|
+
* run, so the runner MAY mint a subsidized key on the efficient tier if its
|
|
25
|
+
* own key search comes up dry. a permission, not a routing decision — the
|
|
26
|
+
* server cannot see workflow `env:` keys. see `RunContext.trialFallback`. */
|
|
27
|
+
trialFallback?: boolean | undefined;
|
|
23
28
|
}
|
|
24
29
|
interface ResolveRunContextDataParams {
|
|
25
30
|
octokit: OctokitWithPlugins;
|
|
26
31
|
token: string;
|
|
32
|
+
/** the dispatch payload's run type, read before the payload is resolved
|
|
33
|
+
* because run-context is fetched first and needs it to pick this trigger's
|
|
34
|
+
* model override. */
|
|
35
|
+
runType?: string | undefined;
|
|
27
36
|
}
|
|
28
37
|
/**
|
|
29
38
|
* true when the action is pinned to a full commit SHA (vs the moving `@v0`
|