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/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,58 @@ 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.2",
583
+ effort: ["high", "max"],
584
+ openRouterEffort: ["high", "xhigh"],
585
+ openRouterResolve: "openrouter/z-ai/glm-5.2"
586
+ },
587
+ grok: {
588
+ displayName: "Grok",
589
+ resolve: "opencode/grok-4.6",
590
+ effort: ["low", "medium", "high", "xhigh"],
591
+ openRouterResolve: "openrouter/x-ai/grok-4.6"
592
+ },
550
593
  "gpt-5-nano": {
551
594
  displayName: "GPT Nano",
552
595
  resolve: "opencode/gpt-5-nano",
553
596
  effort: ["minimal", "low", "medium", "high"],
554
597
  openRouterResolve: "openrouter/openai/gpt-5-nano"
555
598
  },
599
+ // Zen's live free MiMo, and the second free row in a menu that big-pickle
600
+ // was alone in since `mimo-v2-pro-free` lost its model.
601
+ mimo: {
602
+ displayName: "MiMo",
603
+ resolve: "opencode/mimo-v2.5-free",
604
+ // free to run, still gated on the provider's own OPENCODE_API_KEY —
605
+ // see the big-pickle note above (#1077).
606
+ isFree: true
607
+ },
556
608
  "mimo-v2-pro-free": {
557
609
  displayName: "MiMo V2 Pro",
558
610
  resolve: "opencode/mimo-v2-pro-free",
559
611
  // free to run, still gated on the provider's own OPENCODE_API_KEY —
560
612
  // see the big-pickle note above (#1077).
561
613
  isFree: true,
562
- fallback: "opencode/big-pickle"
614
+ // the model id Zen dropped; land a stored MiMo pick back on MiMo rather
615
+ // than on the unrelated model it had to settle for while none was live.
616
+ fallback: "opencode/mimo"
563
617
  },
564
618
  "minimax-m2.5-free": {
565
619
  displayName: "MiniMax M2",
@@ -654,6 +708,16 @@ var providers = {
654
708
  resolve: "opencode-go/qwen3.7-plus",
655
709
  openRouterResolve: "openrouter/qwen/qwen3.7-plus"
656
710
  },
711
+ // the cheap rung Alibaba added under Plus (0.15/0.47 against 0.5/3), and
712
+ // the only model either OpenCode plan has added since this block was written.
713
+ "qwen-flash": {
714
+ displayName: "Qwen Flash",
715
+ resolve: "opencode-go/qwen3.8-flash",
716
+ effort: ["low", "medium", "xhigh"],
717
+ // the Go route publishes rungs where OpenRouter publishes none.
718
+ openRouterEffort: [],
719
+ openRouterResolve: "openrouter/qwen/qwen3.8-flash"
720
+ },
657
721
  // MiniMax — parity with opencode/* and openrouter/*; the m2 slug pins the
658
722
  // line for DB stability while the resolve tracks the current m2.7.
659
723
  "minimax-m3": {
@@ -1635,6 +1699,9 @@ function formatModelLabel(params) {
1635
1699
  if (params.fallbackFrom) {
1636
1700
  return `${base} (credentials for ${providerDisplayName(params.fallbackFrom)} were rejected by the provider)`;
1637
1701
  }
1702
+ if (params.clamped?.reason === "trial") {
1703
+ return `${base} (free trial)`;
1704
+ }
1638
1705
  if (params.clamped) {
1639
1706
  const target = isAutoTier(params.clamped.from) ? "the intelligent tier" : `\`${resolveDisplayAlias(params.clamped.from)?.displayName ?? params.clamped.from}\``;
1640
1707
  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 +1711,15 @@ function formatModelLabel(params) {
1644
1711
  }
1645
1712
  return base;
1646
1713
  }
1714
+ function buildTrialDisclosure(owner) {
1715
+ const consoleUrl = owner ? `https://pullfrog.com/console/${owner}` : "https://pullfrog.com/console";
1716
+ return [
1717
+ "---",
1718
+ "",
1719
+ "> [!IMPORTANT]",
1720
+ `> **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})`
1721
+ ].join("\n");
1722
+ }
1647
1723
  function buildPullfrogFooter(params) {
1648
1724
  const parts = [];
1649
1725
  if (params.shaPinned) {
@@ -1676,10 +1752,13 @@ function buildPullfrogFooter(params) {
1676
1752
  );
1677
1753
  }
1678
1754
  const allParts = [...parts, "[\u{1D54F}](https://x.com/pullfrogai)"];
1755
+ const disclosure = params.clamped?.reason === "trial" ? `${buildTrialDisclosure(params.owner)}
1756
+
1757
+ ` : "";
1679
1758
  return `
1680
1759
 
1681
1760
  ${PULLFROG_DIVIDER}
1682
- <sup>${FROG_LOGO}&nbsp;&nbsp;\uFF5C ${allParts.join(" \uFF5C ")}</sup>`;
1761
+ ${disclosure}<sup>${FROG_LOGO}&nbsp;&nbsp;\uFF5C ${allParts.join(" \uFF5C ")}</sup>`;
1683
1762
  }
1684
1763
  function stripExistingFooter(body) {
1685
1764
  const dividerIndex = body.indexOf(PULLFROG_DIVIDER);
@@ -2230,6 +2309,7 @@ export {
2230
2309
  OSS_RECOMMENDED_MODEL,
2231
2310
  PULLFROG_DIVIDER,
2232
2311
  RUN_STATUS_CHECK_NAME,
2312
+ SUBSIDY_RUNG,
2233
2313
  TIMEOUT_DISABLED,
2234
2314
  buildPullfrogFooter,
2235
2315
  commercialPaywallBody,
@@ -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;
@@ -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 that does not retrigger the full LLM CI matrix (`action/main.ts` is
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
@@ -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;
@@ -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`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pullfrog",
3
- "version": "0.1.67",
3
+ "version": "0.1.68",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "pullfrog": "dist/cli.mjs",