pullfrog 0.1.47 → 0.1.48

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.
@@ -2,10 +2,11 @@
2
2
  * Internal entrypoint for the root app.
3
3
  * Re-exports shared types, values, and utilities needed by the Next.js app.
4
4
  */
5
- export type { AuthorPermission, AutoTier, ModelAlias, ModelProvider, Payload, PayloadEvent, ProviderConfig, PushPermission, ShellPermission, ToolPermission, WriteablePayload, XrepoConfig, } from "../external.ts";
6
- export { AUTO_EFFICIENT, AUTO_INTELLIGENT, DEFAULT_PROXY_MODEL, defaultAutoTier, getAutoSelectHintModel, getModelEnvVars, getModelManagedCredentials, getModelProvider, getProviderDisplayName, isAutoTier, isCardGatedModel, modelAliases, parseModel, providers, pullfrogMcpName, resolveAutoTier, resolveCliModel, resolveDisplayAlias, resolveModelSlug, resolveOpenRouterModel, } from "../external.ts";
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, modelAliases, offeredRungs, parseEffortPosition, parseModel, providers, pullfrogMcpName, resolveAutoTier, resolveCliModel, resolveDisplayAlias, resolveModelRung, resolveModelSlug, resolveOpenRouterModel, resolveRung, rungLabel, rungPosition, } from "../external.ts";
7
7
  export type { Mode } from "../modes.ts";
8
8
  export { modes } from "../modes.ts";
9
+ export { commercialPaywallBody } from "../utils/billingErrors.ts";
9
10
  export type { BuildPullfrogFooterParams, WorkflowRunFooterInfo, } from "../utils/buildPullfrogFooter.ts";
10
11
  export { buildPullfrogFooter, PULLFROG_DIVIDER, stripExistingFooter, } from "../utils/buildPullfrogFooter.ts";
11
12
  export type { CodexAuthBody } from "../utils/codexOAuth.ts";
package/dist/internal.js CHANGED
@@ -1,5 +1,53 @@
1
1
  import { createRequire as __createRequire } from 'module'; import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __dirnameFn } from 'path'; const require = __createRequire(import.meta.url); const __filename = __fileURLToPath(import.meta.url); const __dirname = __dirnameFn(__filename);
2
2
 
3
+ // effort.ts
4
+ var DEFAULT_EFFORT_POSITION = 0.75;
5
+ var EFFORT_ALIASES = {
6
+ low: 0,
7
+ medium: 0.25,
8
+ high: 0.5,
9
+ xhigh: 0.75,
10
+ max: 1
11
+ };
12
+ var DISABLING_RUNGS = ["none", "minimal"];
13
+ function isEffortPosition(value) {
14
+ return Number.isFinite(value) && value >= 0 && value <= 1;
15
+ }
16
+ function parseEffortPosition(raw) {
17
+ const normalized = raw.trim().toLowerCase();
18
+ const named = EFFORT_ALIASES[normalized === "med" ? "medium" : normalized];
19
+ if (named !== void 0) return named;
20
+ const numeric = Number(normalized);
21
+ return normalized !== "" && isEffortPosition(numeric) ? numeric : void 0;
22
+ }
23
+ function offeredRungs(published) {
24
+ return published.filter((rung) => !DISABLING_RUNGS.includes(rung));
25
+ }
26
+ function resolveRung(params) {
27
+ const rungs = offeredRungs(params.published);
28
+ if (rungs.length === 0) return void 0;
29
+ const clamped = Math.min(1, Math.max(0, params.position));
30
+ return rungs[Math.floor(clamped * (rungs.length - 1))];
31
+ }
32
+ function rungPosition(params) {
33
+ const rungs = offeredRungs(params.published);
34
+ const index = rungs.indexOf(params.rung);
35
+ if (index === -1) return void 0;
36
+ return rungs.length > 1 ? index / (rungs.length - 1) : 0;
37
+ }
38
+ function rungLabel(rung) {
39
+ const known = {
40
+ none: "None",
41
+ minimal: "Minimal",
42
+ low: "Low",
43
+ medium: "Medium",
44
+ high: "High",
45
+ xhigh: "Extra high",
46
+ max: "Max"
47
+ };
48
+ return known[rung] ?? rung.charAt(0).toUpperCase() + rung.slice(1);
49
+ }
50
+
3
51
  // models.ts
4
52
  function provider(config) {
5
53
  return config;
@@ -19,6 +67,7 @@ var providers = {
19
67
  "claude-fable": {
20
68
  displayName: "Claude Fable",
21
69
  resolve: "anthropic/claude-fable-5",
70
+ effort: ["low", "medium", "high", "xhigh", "max"],
22
71
  // rolling alias: models.dev's OpenRouter mirror lags brand-new pinned
23
72
  // versions (claude-fable-5 isn't indexed yet), so track ~…-latest to
24
73
  // stay catalog-valid and auto-follow version bumps.
@@ -28,6 +77,7 @@ var providers = {
28
77
  "claude-opus": {
29
78
  displayName: "Claude Opus",
30
79
  resolve: "anthropic/claude-opus-5",
80
+ effort: ["low", "medium", "high", "xhigh", "max"],
31
81
  openRouterResolve: "openrouter/anthropic/claude-opus-5",
32
82
  preferred: true,
33
83
  subagentModel: "claude-sonnet"
@@ -35,6 +85,7 @@ var providers = {
35
85
  "claude-sonnet": {
36
86
  displayName: "Claude Sonnet",
37
87
  resolve: "anthropic/claude-sonnet-5",
88
+ effort: ["low", "medium", "high", "xhigh", "max"],
38
89
  openRouterResolve: "openrouter/anthropic/claude-sonnet-5"
39
90
  },
40
91
  "claude-haiku": {
@@ -52,6 +103,7 @@ var providers = {
52
103
  gpt: {
53
104
  displayName: "GPT Sol",
54
105
  resolve: "openai/gpt-5.6-sol",
106
+ effort: ["none", "low", "medium", "high", "xhigh", "max"],
55
107
  openRouterResolve: "openrouter/openai/gpt-5.6-sol",
56
108
  preferred: true,
57
109
  subagentModel: "gpt-terra"
@@ -63,6 +115,7 @@ var providers = {
63
115
  displayName: "GPT Sol Pro",
64
116
  description: "Maximum reasoning effort",
65
117
  resolve: "openai/gpt-5.6-sol",
118
+ effort: ["none", "low", "medium", "high", "xhigh", "max"],
66
119
  openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
67
120
  subagentModel: "gpt"
68
121
  },
@@ -72,11 +125,13 @@ var providers = {
72
125
  "gpt-terra": {
73
126
  displayName: "GPT Terra",
74
127
  resolve: "openai/gpt-5.6-terra",
128
+ effort: ["none", "low", "medium", "high", "xhigh", "max"],
75
129
  openRouterResolve: "openrouter/openai/gpt-5.6-terra"
76
130
  },
77
131
  "gpt-mini": {
78
132
  displayName: "GPT Luna",
79
133
  resolve: "openai/gpt-5.6-luna",
134
+ effort: ["none", "low", "medium", "high", "xhigh", "max"],
80
135
  openRouterResolve: "openrouter/openai/gpt-5.6-luna"
81
136
  },
82
137
  // legacy aliases — openai unified the codex line into the main GPT family
@@ -106,6 +161,7 @@ var providers = {
106
161
  o3: {
107
162
  displayName: "O3",
108
163
  resolve: "openai/o3",
164
+ effort: ["low", "medium", "high"],
109
165
  openRouterResolve: "openrouter/openai/o3"
110
166
  }
111
167
  }
@@ -117,6 +173,7 @@ var providers = {
117
173
  "gemini-pro": {
118
174
  displayName: "Gemini Pro",
119
175
  resolve: "google/gemini-3.1-pro-preview",
176
+ effort: ["low", "medium", "high"],
120
177
  openRouterResolve: "openrouter/google/gemini-3.1-pro-preview",
121
178
  preferred: true
122
179
  // Inherit (subagents stay on Pro). Google has no in-between tier;
@@ -128,6 +185,7 @@ var providers = {
128
185
  "gemini-flash": {
129
186
  displayName: "Gemini Flash",
130
187
  resolve: "google/gemini-3.5-flash",
188
+ effort: ["minimal", "low", "medium", "high"],
131
189
  openRouterResolve: "openrouter/google/gemini-3.5-flash"
132
190
  }
133
191
  }
@@ -139,6 +197,7 @@ var providers = {
139
197
  grok: {
140
198
  displayName: "Grok",
141
199
  resolve: "xai/grok-4.3",
200
+ effort: ["none", "low", "medium", "high"],
142
201
  openRouterResolve: "openrouter/x-ai/grok-4.3",
143
202
  preferred: true
144
203
  },
@@ -168,12 +227,16 @@ var providers = {
168
227
  "deepseek-pro": {
169
228
  displayName: "DeepSeek Pro",
170
229
  resolve: "deepseek/deepseek-v4-pro",
230
+ effort: ["high", "max"],
231
+ openRouterEffort: ["high", "xhigh"],
171
232
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro",
172
233
  preferred: true
173
234
  },
174
235
  "deepseek-flash": {
175
236
  displayName: "DeepSeek Flash",
176
237
  resolve: "deepseek/deepseek-v4-flash",
238
+ effort: ["high", "max"],
239
+ openRouterEffort: ["high", "xhigh"],
177
240
  openRouterResolve: "openrouter/deepseek/deepseek-v4-flash"
178
241
  },
179
242
  // legacy aliases — deepseek retires these on 2026-07-24; transparently
@@ -202,6 +265,7 @@ var providers = {
202
265
  "kimi-k3": {
203
266
  displayName: "Kimi K3",
204
267
  resolve: "moonshotai/kimi-k3",
268
+ effort: ["low", "high", "max"],
205
269
  openRouterResolve: "openrouter/moonshotai/kimi-k3",
206
270
  preferred: true,
207
271
  subagentModel: "kimi-k2"
@@ -214,7 +278,7 @@ var providers = {
214
278
  }
215
279
  }),
216
280
  opencode: provider({
217
- displayName: "OpenCode",
281
+ displayName: "OpenCode Zen",
218
282
  envVars: ["OPENCODE_API_KEY"],
219
283
  models: {
220
284
  "big-pickle": {
@@ -227,12 +291,14 @@ var providers = {
227
291
  "claude-opus": {
228
292
  displayName: "Claude Opus",
229
293
  resolve: "opencode/claude-opus-5",
294
+ effort: ["low", "medium", "high", "xhigh", "max"],
230
295
  openRouterResolve: "openrouter/anthropic/claude-opus-5",
231
296
  subagentModel: "claude-sonnet"
232
297
  },
233
298
  "claude-sonnet": {
234
299
  displayName: "Claude Sonnet",
235
300
  resolve: "opencode/claude-sonnet-5",
301
+ effort: ["low", "medium", "high", "xhigh", "max"],
236
302
  openRouterResolve: "openrouter/anthropic/claude-sonnet-5"
237
303
  },
238
304
  "claude-haiku": {
@@ -243,6 +309,7 @@ var providers = {
243
309
  gpt: {
244
310
  displayName: "GPT Sol",
245
311
  resolve: "opencode/gpt-5.6-sol",
312
+ effort: ["none", "low", "medium", "high", "xhigh", "max"],
246
313
  openRouterResolve: "openrouter/openai/gpt-5.6-sol",
247
314
  subagentModel: "gpt-terra"
248
315
  },
@@ -251,6 +318,7 @@ var providers = {
251
318
  displayName: "GPT Sol Pro",
252
319
  description: "Maximum reasoning effort",
253
320
  resolve: "opencode/gpt-5.6-sol",
321
+ effort: ["none", "low", "medium", "high", "xhigh", "max"],
254
322
  openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
255
323
  subagentModel: "gpt"
256
324
  },
@@ -258,11 +326,13 @@ var providers = {
258
326
  "gpt-terra": {
259
327
  displayName: "GPT Terra",
260
328
  resolve: "opencode/gpt-5.6-terra",
329
+ effort: ["none", "low", "medium", "high", "xhigh", "max"],
261
330
  openRouterResolve: "openrouter/openai/gpt-5.6-terra"
262
331
  },
263
332
  "gpt-mini": {
264
333
  displayName: "GPT Luna",
265
334
  resolve: "opencode/gpt-5.6-luna",
335
+ effort: ["none", "low", "medium", "high", "xhigh", "max"],
266
336
  openRouterResolve: "openrouter/openai/gpt-5.6-luna"
267
337
  },
268
338
  // legacy aliases — see openai provider above for context.
@@ -288,12 +358,14 @@ var providers = {
288
358
  "gemini-pro": {
289
359
  displayName: "Gemini Pro",
290
360
  resolve: "opencode/gemini-3.1-pro",
361
+ effort: ["low", "medium", "high"],
291
362
  openRouterResolve: "openrouter/google/gemini-3.1-pro-preview"
292
363
  // Inherit — see google/gemini-pro for rationale.
293
364
  },
294
365
  "gemini-flash": {
295
366
  displayName: "Gemini Flash",
296
367
  resolve: "opencode/gemini-3.5-flash",
368
+ effort: ["minimal", "low", "medium", "high"],
297
369
  openRouterResolve: "openrouter/google/gemini-3.5-flash"
298
370
  },
299
371
  "kimi-k2": {
@@ -312,6 +384,7 @@ var providers = {
312
384
  "gpt-5-nano": {
313
385
  displayName: "GPT Nano",
314
386
  resolve: "opencode/gpt-5-nano",
387
+ effort: ["minimal", "low", "medium", "high"],
315
388
  openRouterResolve: "openrouter/openai/gpt-5-nano"
316
389
  },
317
390
  "mimo-v2-pro-free": {
@@ -338,6 +411,8 @@ var providers = {
338
411
  "glm-5.1": {
339
412
  displayName: "GLM 5.2",
340
413
  resolve: "opencode-go/glm-5.2",
414
+ effort: ["high", "max"],
415
+ openRouterEffort: ["high", "xhigh"],
341
416
  openRouterResolve: "openrouter/z-ai/glm-5.2",
342
417
  preferred: true
343
418
  },
@@ -391,6 +466,10 @@ var providers = {
391
466
  // bring-your-own generic OpenAI-compatible endpoint — Cloudflare AI Gateway,
392
467
  // Alibaba DashScope, self-hosted vLLM, or any compatible gateway. base URL +
393
468
  // key + model ID are all supplied via env; nothing is cataloged or bumped.
469
+ // the two token limits are deliberately absent: this list is the auth
470
+ // heuristic (`hasPullfrogStoredAuthForModel`, `validateAgentApiKey`), and a
471
+ // stored context number is config, not proof of a key. the console picks
472
+ // them up from `PROVIDER_EXTRA_SECRET_NAMES` instead.
394
473
  envVars: ["OPENAI_COMPATIBLE_BASE_URL", "OPENAI_COMPATIBLE_API_KEY", "OPENAI_COMPATIBLE_MODEL"],
395
474
  models: {
396
475
  // single routing entry — the actual model ID is read from
@@ -410,6 +489,7 @@ var providers = {
410
489
  "claude-opus": {
411
490
  displayName: "Claude Opus",
412
491
  resolve: "openrouter/~anthropic/claude-opus-latest",
492
+ effort: ["low", "medium", "high", "xhigh", "max"],
413
493
  openRouterResolve: "openrouter/~anthropic/claude-opus-latest",
414
494
  preferred: true,
415
495
  subagentModel: "claude-sonnet"
@@ -417,6 +497,7 @@ var providers = {
417
497
  "claude-sonnet": {
418
498
  displayName: "Claude Sonnet",
419
499
  resolve: "openrouter/~anthropic/claude-sonnet-latest",
500
+ effort: ["low", "medium", "high", "xhigh", "max"],
420
501
  openRouterResolve: "openrouter/~anthropic/claude-sonnet-latest"
421
502
  },
422
503
  "claude-haiku": {
@@ -431,6 +512,7 @@ var providers = {
431
512
  gpt: {
432
513
  displayName: "GPT Sol",
433
514
  resolve: "openrouter/openai/gpt-5.6-sol",
515
+ effort: ["none", "low", "medium", "high", "xhigh", "max"],
434
516
  openRouterResolve: "openrouter/openai/gpt-5.6-sol",
435
517
  subagentModel: "gpt-terra"
436
518
  },
@@ -439,6 +521,7 @@ var providers = {
439
521
  displayName: "GPT Sol Pro",
440
522
  description: "Maximum reasoning effort",
441
523
  resolve: "openrouter/openai/gpt-5.6-sol-pro",
524
+ effort: ["none", "low", "medium", "high", "xhigh", "max"],
442
525
  openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
443
526
  subagentModel: "gpt"
444
527
  },
@@ -446,11 +529,13 @@ var providers = {
446
529
  "gpt-terra": {
447
530
  displayName: "GPT Terra",
448
531
  resolve: "openrouter/openai/gpt-5.6-terra",
532
+ effort: ["none", "low", "medium", "high", "xhigh", "max"],
449
533
  openRouterResolve: "openrouter/openai/gpt-5.6-terra"
450
534
  },
451
535
  "gpt-mini": {
452
536
  displayName: "GPT Luna",
453
537
  resolve: "openrouter/openai/gpt-5.6-luna",
538
+ effort: ["none", "low", "medium", "high", "xhigh", "max"],
454
539
  openRouterResolve: "openrouter/openai/gpt-5.6-luna"
455
540
  },
456
541
  // legacy aliases — see openai provider for context.
@@ -476,32 +561,38 @@ var providers = {
476
561
  "o4-mini": {
477
562
  displayName: "O4 Mini",
478
563
  resolve: "openrouter/openai/o4-mini",
564
+ effort: ["low", "medium", "high"],
479
565
  openRouterResolve: "openrouter/openai/o4-mini"
480
566
  },
481
567
  "gemini-pro": {
482
568
  displayName: "Gemini Pro",
483
569
  resolve: "openrouter/~google/gemini-pro-latest",
570
+ effort: ["low", "medium", "high"],
484
571
  openRouterResolve: "openrouter/~google/gemini-pro-latest"
485
572
  // Inherit — see google/gemini-pro for rationale.
486
573
  },
487
574
  "gemini-flash": {
488
575
  displayName: "Gemini Flash",
489
576
  resolve: "openrouter/~google/gemini-flash-latest",
577
+ effort: ["minimal", "low", "medium", "high"],
490
578
  openRouterResolve: "openrouter/~google/gemini-flash-latest"
491
579
  },
492
580
  grok: {
493
581
  displayName: "Grok",
494
582
  resolve: "openrouter/x-ai/grok-4.3",
583
+ effort: ["none", "low", "medium", "high"],
495
584
  openRouterResolve: "openrouter/x-ai/grok-4.3"
496
585
  },
497
586
  "deepseek-pro": {
498
587
  displayName: "DeepSeek Pro",
499
588
  resolve: "openrouter/deepseek/deepseek-v4-pro",
589
+ effort: ["high", "xhigh"],
500
590
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro"
501
591
  },
502
592
  "deepseek-flash": {
503
593
  displayName: "DeepSeek Flash",
504
594
  resolve: "openrouter/deepseek/deepseek-v4-flash",
595
+ effort: ["high", "xhigh"],
505
596
  openRouterResolve: "openrouter/deepseek/deepseek-v4-flash"
506
597
  },
507
598
  // legacy alias — deepseek retires this on 2026-07-24; transparently
@@ -520,6 +611,7 @@ var providers = {
520
611
  "kimi-k3": {
521
612
  displayName: "Kimi K3",
522
613
  resolve: "openrouter/moonshotai/kimi-k3",
614
+ effort: ["low", "high", "max"],
523
615
  openRouterResolve: "openrouter/moonshotai/kimi-k3"
524
616
  },
525
617
  // slug pins the m2 line for DB stability; resolve tracks the current m2.7.
@@ -583,6 +675,8 @@ var modelAliases = Object.entries(providers).flatMap(
583
675
  // here to a fully-qualified slug so callers can look up the target alias
584
676
  // directly without re-deriving the provider.
585
677
  subagentModel: def.subagentModel ? `${providerKey}/${def.subagentModel}` : void 0,
678
+ effort: def.effort,
679
+ openRouterEffort: def.openRouterEffort,
586
680
  hidden: def.hidden ?? false
587
681
  }))
588
682
  );
@@ -628,6 +722,17 @@ function resolveCliModel(slug) {
628
722
  function resolveOpenRouterModel(slug) {
629
723
  return resolveDisplayAlias(slug)?.openRouterResolve;
630
724
  }
725
+ function getModelEffortLevels(params) {
726
+ const alias = resolveDisplayAlias(params.slug);
727
+ if (!alias) return void 0;
728
+ if (params.useOpenRouter) return alias.openRouterEffort ?? alias.effort;
729
+ return alias.effort;
730
+ }
731
+ function resolveModelRung(params) {
732
+ const published = getModelEffortLevels(params);
733
+ if (!published) return void 0;
734
+ return resolveRung({ position: params.position, published });
735
+ }
631
736
  var defaultProxyAlias = resolveDisplayAlias(AUTO_EFFICIENT);
632
737
  if (!defaultProxyAlias?.openRouterResolve) {
633
738
  throw new Error(`DEFAULT_PROXY_MODEL: ${AUTO_EFFICIENT} has no openRouterResolve`);
@@ -1043,6 +1148,27 @@ ${PR_SUMMARY_FORMAT}`
1043
1148
  }
1044
1149
  var modes = computeModes("opencode");
1045
1150
 
1151
+ // utils/billingErrors.ts
1152
+ function commercialPaywallBody(params) {
1153
+ if (params.reason === "commercial") {
1154
+ return [
1155
+ `**Pullfrog needs a confirmed Pro plan for ${params.ownerLogin}, so this run paused.**`,
1156
+ "",
1157
+ "Open Plan and payment to confirm Pro or review the organization's billing status.",
1158
+ "",
1159
+ `[Review plan and payment \u2192](${params.url})`
1160
+ ].join("\n");
1161
+ }
1162
+ params.reason;
1163
+ return [
1164
+ `**Pullfrog paused runs on ${params.ownerLogin}: the Pro renewal failed.**`,
1165
+ "",
1166
+ "Update the card on file to resume runs.",
1167
+ "",
1168
+ `[Update billing \u2192](${params.url})`
1169
+ ].join("\n");
1170
+ }
1171
+
1046
1172
  // utils/buildPullfrogFooter.ts
1047
1173
  var PULLFROG_DIVIDER = "<!-- PULLFROG_DIVIDER_DO_NOT_REMOVE_PLZ -->";
1048
1174
  var FROG_LOGO = `<a href="https://pullfrog.com"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pullfrog.com/logos/frog-white-full-18px.png"><img src="https://pullfrog.com/logos/frog-green-full-18px.png" width="9px" height="9px" style="vertical-align: middle; " alt="Pullfrog"></picture></a>`;
@@ -1454,7 +1580,9 @@ export {
1454
1580
  APPROVAL_CHECK_NAME,
1455
1581
  AUTO_EFFICIENT,
1456
1582
  AUTO_INTELLIGENT,
1583
+ DEFAULT_EFFORT_POSITION,
1457
1584
  DEFAULT_PROXY_MODEL,
1585
+ EFFORT_ALIASES,
1458
1586
  LEAPING_INTO_ACTION_PREFIX,
1459
1587
  MAX_LEARNINGS_LENGTH,
1460
1588
  OAuthInvalidGrantError,
@@ -1462,6 +1590,7 @@ export {
1462
1590
  RUN_STATUS_CHECK_NAME,
1463
1591
  TIMEOUT_DISABLED,
1464
1592
  buildPullfrogFooter,
1593
+ commercialPaywallBody,
1465
1594
  createLeapingProgressComment,
1466
1595
  createRunStatusCheck,
1467
1596
  decodeJwtExpMs,
@@ -1469,6 +1598,7 @@ export {
1469
1598
  deleteProgressCommentApi,
1470
1599
  finalizeRunStatusCheck,
1471
1600
  getAutoSelectHintModel,
1601
+ getModelEffortLevels,
1472
1602
  getModelEnvVars,
1473
1603
  getModelManagedCredentials,
1474
1604
  getModelProvider,
@@ -1476,11 +1606,14 @@ export {
1476
1606
  getProviderDisplayName,
1477
1607
  isAutoTier,
1478
1608
  isCardGatedModel,
1609
+ isEffortPosition,
1479
1610
  isLeapingIntoActionCommentBody,
1480
1611
  isValidTimeString,
1481
1612
  modelAliases,
1482
1613
  modes,
1614
+ offeredRungs,
1483
1615
  parseCodexAuthBody,
1616
+ parseEffortPosition,
1484
1617
  parseModel,
1485
1618
  parseTimeString,
1486
1619
  providers,
@@ -1489,9 +1622,13 @@ export {
1489
1622
  resolveAutoTier,
1490
1623
  resolveCliModel,
1491
1624
  resolveDisplayAlias,
1625
+ resolveModelRung,
1492
1626
  resolveModelSlug,
1493
1627
  resolveOpenRouterModel,
1628
+ resolveRung,
1494
1629
  runStatusCheckNeedsFinalizing,
1630
+ rungLabel,
1631
+ rungPosition,
1495
1632
  stringifyCodexAuthBody,
1496
1633
  stripExistingFooter,
1497
1634
  truncateAtLineBoundary,
package/dist/models.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  * slugs use the format `provider/model-id` (e.g. "anthropic/claude-opus").
5
5
  * bump `resolve` when a new model generation ships — the alias (slug) stays stable.
6
6
  */
7
+ import { type EffortPosition } from "./effort.ts";
7
8
  /**
8
9
  * routing discriminant for entries whose `resolve` is dynamic — looked up
9
10
  * from a separate env var at run time rather than fixed in the catalog.
@@ -50,6 +51,14 @@ export interface ModelAlias {
50
51
  /** alias key (within same provider) of the cheaper sibling reviewfrog should
51
52
  * use as its lens-fanout subagent. e.g. claude-opus → "claude-sonnet". */
52
53
  subagentModel: string | undefined;
54
+ /** reasoning-effort rungs this model accepts on the direct route, ascending.
55
+ * mirrors models.dev `reasoning_options[type=effort].values`. undefined means
56
+ * the model has no effort control and the setting is a documented no-op. */
57
+ effort: readonly string[] | undefined;
58
+ /** effort rungs on the OpenRouter route, when they differ from `effort` (the
59
+ * DeepSeek/GLM top rung is `max` natively but `xhigh` via OpenRouter).
60
+ * undefined falls back to `effort`. */
61
+ openRouterEffort: readonly string[] | undefined;
53
62
  /** hide from selectable lists (UI dropdowns, CLI pickers). does NOT affect
54
63
  * resolution — for that use `fallback`. used to keep a redundant alias out of
55
64
  * pickers (e.g. the free `minimax-m2.5-free` duplicate). */
@@ -75,6 +84,10 @@ interface ModelDef {
75
84
  /** alias key (within same provider) of the cheaper sibling reviewfrog should
76
85
  * use as its lens-fanout subagent (e.g. claude-opus → "claude-sonnet"). */
77
86
  subagentModel?: string;
87
+ /** effort rungs accepted on the direct route, ascending — see ModelAlias.effort */
88
+ effort?: readonly string[];
89
+ /** effort rungs on the OpenRouter route when they differ — see ModelAlias.openRouterEffort */
90
+ openRouterEffort?: readonly string[];
78
91
  /** hide from selectable lists. does NOT affect resolution; for that use `fallback`. */
79
92
  hidden?: boolean;
80
93
  }
@@ -123,8 +136,8 @@ export declare const modelAliases: ModelAlias[];
123
136
  * (CLI resolve, OpenRouter resolve, footer label) handles them transparently.
124
137
  *
125
138
  * `efficient` mirrors the OSS/default subsidy model (DeepSeek V4 Pro — beats
126
- * Kimi K2.7 on agentic-review quality at ~4-5x lower cost, run at high
127
- * reasoning effort via `deepseekHighEffortOverrides`); `intelligent` is the
139
+ * Kimi K2.7 on agentic-review quality at ~4-5x lower cost, run at whatever
140
+ * effort the repo asks for, clamped to its published ladder); `intelligent` is the
128
141
  * frontier pick (Claude Opus). a `null` model means the tier hasn't been
129
142
  * pinned: callers default by card status via `defaultAutoTier`.
130
143
  */
@@ -190,6 +203,27 @@ export declare function resolveCliModel(slug: string): string | undefined;
190
203
  * (e.g. free opencode models).
191
204
  */
192
205
  export declare function resolveOpenRouterModel(slug: string): string | undefined;
206
+ /**
207
+ * the effort rungs `slug` accepts on the route being used, or undefined when the
208
+ * model has no effort control at all. walks the fallback chain, so a deprecated
209
+ * slug is judged by the model that actually runs. drives both the console's
210
+ * level list and the runtime clamp, so the two can't disagree.
211
+ */
212
+ export declare function getModelEffortLevels(params: {
213
+ slug: string;
214
+ useOpenRouter: boolean;
215
+ }): readonly string[] | undefined;
216
+ /**
217
+ * the rung a run actually sends: a position landed on this model's own published
218
+ * ladder. the result is always a rung the model offers, so there is no arithmetic
219
+ * anywhere that can produce a level it doesn't have. undefined means the model
220
+ * publishes no rungs and the harness gets no flag.
221
+ */
222
+ export declare function resolveModelRung(params: {
223
+ slug: string;
224
+ position: EffortPosition;
225
+ useOpenRouter: boolean;
226
+ }): string | undefined;
193
227
  export declare const DEFAULT_PROXY_MODEL: string;
194
228
  /** short label for the model auto-select picks today (console hint copy). */
195
229
  export declare function getAutoSelectHintModel(): string;
@@ -13,8 +13,8 @@
13
13
  * in `action/test/coverage.ts::ALWAYS_RUN_ALL`).
14
14
  */
15
15
  /**
16
- * Billing-layer error surfaced from `/api/proxy-token` as a 402. User-actionable
17
- * distinct from TransientError (503 / transient sync issue) so the job
16
+ * Billing-layer error surfaced from `/api/proxy-token` as a 402. User-actionable,
17
+ * distinct from TransientError (503 / transient sync issue) so the job
18
18
  * summary + PR comment can use affirmative "you need to do X" copy rather than
19
19
  * the ambiguous "billing error" label that makes transient outages look like
20
20
  * the user's fault.
@@ -37,28 +37,45 @@ export declare class BillingError extends Error {
37
37
  }
38
38
  /**
39
39
  * Transient service failures from `/api/proxy-token` (503: partial OpenRouter
40
- * usage sync, DB flake, in-flight payment intent). Not the user's fault the
40
+ * usage sync, DB flake, in-flight payment intent). Not the user's fault, the
41
41
  * summary uses "temporarily unavailable" framing, and the non-zero exit lets
42
42
  * GH Actions apply whatever retry policy the workflow has configured.
43
43
  */
44
44
  export declare class TransientError extends Error {
45
45
  constructor(message: string);
46
46
  }
47
+ /**
48
+ * Canonical paused-run paywall body (billing model v2). Single source of truth so
49
+ * the two surfaces that show it can never drift: the trigger-time comment (a run
50
+ * refused before it starts, `triggerWorkflow.postPaywallComment`) and the mid-run
51
+ * 402 render (`formatBillingErrorSummary` via `renderRunError`). `url` is the
52
+ * caller's billing surface (each passes its own, internal plan page vs console).
53
+ */
54
+ export declare function commercialPaywallBody(params: {
55
+ reason: "commercial" | "subscription_unpaid";
56
+ ownerLogin: string;
57
+ url: string;
58
+ }): string;
59
+ /** commercial-gate copy for action runs, linked to the account billing card. */
60
+ export declare function formatCommercialGateSummary(params: {
61
+ reason: "commercial" | "subscription_unpaid";
62
+ ownerLogin: string;
63
+ }): string;
47
64
  /**
48
65
  * Render a BillingError as user-facing markdown (shared between GH job summary
49
66
  * and the PR progress comment). Goals:
50
67
  *
51
- * - quiet, not alarmist bold first line instead of an `### ❌` H3, since
68
+ * - quiet, not alarmist, bold first line instead of an `### ❌` H3, since
52
69
  * the comment already has Pullfrog branding in the footer
53
- * - actionable every branch ends in a single CTA deep-linked to the
70
+ * - actionable, every branch ends in a single CTA deep-linked to the
54
71
  * correct section of the owner's console
55
- * - honest say what actually went wrong (card declined vs. balance
72
+ * - honest, say what actually went wrong (card declined vs. balance
56
73
  * empty vs. 3DS required), don't lump them under "billing error"
57
74
  *
58
75
  * Branches:
59
76
  * - `router_requires_card`: user is on Router mode with no card AND no
60
- * wallet balance (signup credit exhausted or not granted). Frame as
61
- * "add a card to continue", link to `#model-access` where the Add
77
+ * wallet balance. Frame as
78
+ * "add a card to continue", link to `#billing` where the Add
62
79
  * Card flow lives.
63
80
  * - `router_balance_exhausted`: user has a card on file but auto-reload is
64
81
  * disabled and they've spent past their $5 overdraft buffer. Frame as
@@ -69,7 +86,7 @@ export declare class TransientError extends Error {
69
86
  * wallet is now negative; same remediation as `router_balance_exhausted`
70
87
  * but framed for the after-the-fact case ("this run was cut short").
71
88
  * - `needsReauthentication`: issuer requires 3DS on every off-session
72
- * charge. Re-adding the card won't help the only escape is a manual
89
+ * charge. Re-adding the card won't help, the only escape is a manual
73
90
  * top-up where 3DS runs interactively in Stripe Checkout.
74
91
  * - `declineCode` set: Stripe declined a real charge. Show the sub-code
75
92
  * so support can act on it; tell the user we'll retry on next dispatch.
@@ -80,6 +97,6 @@ export declare function formatBillingErrorSummary(error: BillingError, owner: st
80
97
  /**
81
98
  * Render a TransientError as user-facing markdown. Distinct framing from
82
99
  * BillingError so the user doesn't read an alarm and assume their card
83
- * failed this branch is "our fault, retry shortly", not theirs.
100
+ * failed, this branch is "our fault, retry shortly", not theirs.
84
101
  */
85
102
  export declare function formatTransientErrorSummary(error: TransientError, owner: string): string;
@@ -1,4 +1,4 @@
1
- import type { PayloadEvent } from "../external.ts";
1
+ import { type PayloadEvent } from "../external.ts";
2
2
  import type { RepoSettings } from "./runContext.ts";
3
3
  export declare const JsonPayload: import("arktype/internal/variants/object.ts").ObjectType<{
4
4
  "~pullfrog": true;
@@ -6,6 +6,7 @@ export declare const JsonPayload: import("arktype/internal/variants/object.ts").
6
6
  prompt: string;
7
7
  model?: string | undefined;
8
8
  modelExplicit?: boolean | undefined;
9
+ effort?: string | number | undefined;
9
10
  triggerer?: string | undefined;
10
11
  baseInstructions?: string | undefined;
11
12
  eventInstructions?: string;
@@ -31,6 +32,7 @@ export declare const Inputs: import("arktype/internal/variants/object.ts").Objec
31
32
  prompt?: string | undefined;
32
33
  prompt_file?: string | undefined;
33
34
  model?: string | undefined;
35
+ effort?: string | undefined;
34
36
  timeout?: string | undefined;
35
37
  push?: "disabled" | "enabled" | "restricted" | undefined;
36
38
  shell?: "disabled" | "enabled" | "restricted" | undefined;
@@ -53,6 +55,7 @@ export declare function resolvePayload(resolvedPromptInput: ResolvedPromptInput,
53
55
  version: string;
54
56
  model: string | undefined;
55
57
  modelExplicit: boolean;
58
+ effort: number | undefined;
56
59
  prompt: string;
57
60
  triggerer: string | undefined;
58
61
  baseInstructions: string | undefined;