pullfrog 0.1.77 → 0.1.79

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.
@@ -76,23 +76,57 @@ export declare function providerGatewayOverride(model: string | undefined): Reco
76
76
  * openai-compatible's do; `validateAzureSetup` guarantees they parse.
77
77
  */
78
78
  export declare function azureProvider(model: string | undefined): Record<string, AzureProviderEntry>;
79
+ export type OpenRouterDataCollection = "allow" | "deny";
79
80
  /**
80
- * Build the `provider.openrouter.models[id].options` map that pins every Kimi
81
- * K2 OpenRouter alias away from the Enforcer-less providers via OpenRouter's
82
- * `provider: {ignore:[...]}` routing directive. Sourced from the model registry
83
- * so a Kimi alias/route change in `action/models.ts` flows through automatically.
81
+ * OpenRouter's request-level `provider.data_collection` decides whether hosts
82
+ * that retain or train on prompts may serve a run. The account-wide privacy
83
+ * setting is only a ceiling a request can tighten, so the policy rides on the
84
+ * run instead: OSS-funded runs `allow` (public code on headless runs — and the
85
+ * cheapest V4.1 Flash host, DeepSeek's own, is a training host), Router runs
86
+ * `deny` (a customer's private code never reaches one; every catalog target
87
+ * was still served under `deny` on 2026-09-11), and a BYOK OpenRouter key gets
88
+ * no preference — the customer's own account decides. see wiki/muse-spark.md.
89
+ */
90
+ export declare function openRouterDataCollection(ctx: {
91
+ payload: {
92
+ proxyModel?: string | undefined;
93
+ };
94
+ toolState: {
95
+ oss?: boolean | undefined;
96
+ };
97
+ }): OpenRouterDataCollection | undefined;
98
+ /**
99
+ * The `provider.openrouter` config block: the run's data policy as `extraBody`
100
+ * (the SDK merges it into every request), plus the per-model `options` that
101
+ * carry OpenRouter's `provider` routing object where a model needs its own —
102
+ * Kimi K2 pinned away from the Enforcer-less providers, and the Muse Spark
103
+ * contributor tier opened to data collection whatever the run's policy, since
104
+ * Meta training on the traffic is what that tier is. Sourced from the model
105
+ * registry so an alias/route change in `action/models.ts` flows through.
84
106
  *
85
107
  * Wiring: the per-model `options` object merges into the request options
86
108
  * (opencode `session/llm/request.ts` `mergeOptions(base, model.options)`),
87
109
  * gets wrapped under `providerOptions.openrouter` (`provider/transform.ts`
88
110
  * `sdkKey("@openrouter/ai-sdk-provider") === "openrouter"`), and the OpenRouter
89
- * AI-SDK provider spreads everything under `providerOptions.openrouter` straight
90
- * into the request body (`@openrouter/ai-sdk-provider` `doStream`/`doGenerate`),
91
- * so `provider` lands as the top-level routing object OpenRouter expects.
111
+ * AI-SDK provider spreads everything under `providerOptions.openrouter` into the
112
+ * request body LAST — after `extraBody` — so a per-model `provider` object
113
+ * replaces the run-level one wholesale. that is why the Kimi entry restates
114
+ * the run's `data_collection` beside its `ignore` list.
92
115
  */
93
- export declare function kimiOpenRouterProviderOverrides(): Record<string, {
94
- options: object;
95
- }>;
116
+ export declare function openRouterProvider(policy: OpenRouterDataCollection | undefined): {
117
+ options?: {
118
+ extraBody: {
119
+ provider: {
120
+ data_collection: OpenRouterDataCollection;
121
+ };
122
+ };
123
+ };
124
+ models: Record<string, {
125
+ options: {
126
+ provider: object;
127
+ };
128
+ }>;
129
+ };
96
130
  /**
97
131
  * Read-only `reviewfrog` subagent for lens-based review. Non-mutative +
98
132
  * non-recursive — enforced by the system prompt in reviewer.ts.
package/dist/cli.mjs CHANGED
@@ -123000,7 +123000,7 @@ var import_picocolors = __toESM(require_picocolors(), 1);
123000
123000
  // package.json
123001
123001
  var package_default = {
123002
123002
  name: "pullfrog",
123003
- version: "0.1.77",
123003
+ version: "0.1.79",
123004
123004
  cliContractVersion: "1",
123005
123005
  type: "module",
123006
123006
  bin: {
@@ -125122,26 +125122,34 @@ var providers = {
125122
125122
  models: {
125123
125123
  grok: {
125124
125124
  displayName: "Grok",
125125
- resolve: "xai/grok-4.5",
125126
- effort: ["low", "medium", "high"],
125127
- openRouterResolve: "openrouter/x-ai/grok-4.5",
125125
+ resolve: "xai/grok-4.6",
125126
+ effort: ["low", "medium", "high", "xhigh"],
125127
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
125128
125128
  preferred: true
125129
125129
  },
125130
+ // the Smart ladder's cheap rung: 1.25/2.5 against 4.6's 2/6, and a 0.2
125131
+ // cache read against 0.5 — the only live xAI model a rung can save on.
125132
+ "grok-4.3": {
125133
+ displayName: "Grok 4.3",
125134
+ resolve: "xai/grok-4.3",
125135
+ effort: ["none", "low", "medium", "high"],
125136
+ openRouterResolve: "openrouter/x-ai/grok-4.3"
125137
+ },
125130
125138
  // legacy aliases — xAI retired the entire fast/code-fast line on
125131
125139
  // 2026-05-15 (https://docs.x.ai/developers/migration/may-15-deprecation)
125132
125140
  // and now redirects every deprecated text-model slug to grok-4.3 at
125133
125141
  // standard pricing. fall back to the live `xai/grok` so the alias
125134
- // chain resolves to grok-4.5 for both direct-key and OpenRouter users.
125142
+ // chain resolves to grok-4.6 for both direct-key and OpenRouter users.
125135
125143
  "grok-fast": {
125136
125144
  displayName: "Grok Fast",
125137
125145
  resolve: "xai/grok-4-1-fast",
125138
- openRouterResolve: "openrouter/x-ai/grok-4.5",
125146
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
125139
125147
  fallback: "xai/grok"
125140
125148
  },
125141
125149
  "grok-code-fast": {
125142
125150
  displayName: "Grok Code Fast",
125143
125151
  resolve: "xai/grok-code-fast-1",
125144
- openRouterResolve: "openrouter/x-ai/grok-4.5",
125152
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
125145
125153
  fallback: "xai/grok"
125146
125154
  }
125147
125155
  }
@@ -125160,6 +125168,12 @@ var providers = {
125160
125168
  // $0.0405. there is no `~deepseek/*-pro-latest` pointer to track, so this
125161
125169
  // one has to be a dated pin; the `models-catalog` drift test is what
125162
125170
  // catches the next release.
125171
+ // from 2026-09-14 DeepSeek serves every direct `deepseek-v4-pro` call with
125172
+ // V4.1-Flash at Flash rates until V4.1-Pro ships. it is still the only Pro
125173
+ // id the vendor lists, and the OpenRouter 0813 pin is third-party-hosted
125174
+ // and unaffected — so no `fallback` to Flash, which would drag the Router
125175
+ // route down with it. the OSS program dropped Pro from its menu instead;
125176
+ // see `OSS_MODEL_ALLOWLIST`.
125163
125177
  "deepseek-pro": {
125164
125178
  displayName: "DeepSeek Pro",
125165
125179
  resolve: "deepseek/deepseek-v4-pro",
@@ -125168,30 +125182,24 @@ var providers = {
125168
125182
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro-0813",
125169
125183
  preferred: true
125170
125184
  },
125171
- // DeepSeek upgrades the `deepseek-v4-flash` API model in place, so the
125172
- // direct `resolve` needs no version. OpenRouter instead forked the 0731
125173
- // release into its own id and left the April preview live under the
125174
- // unversioned one at a HIGHER price ($0.14/$0.28 vs $0.09/$0.18) — so the
125175
- // OpenRouter route can never use the bare id. it tracks the rolling
125176
- // `~deepseek/*-latest` pointer (rule 4), which follows the next in-place
125177
- // upgrade on its own rather than pinning a dated snapshot that goes stale
125178
- // every release. that pointer is NOT priced like 0731 — its listed rates
125179
- // run +40% on output and +57.5% on cache read, and it costs 12% more per
125180
- // run on authoritative spend ($0.0405 vs $0.0361). kept anyway: ~$45/yr
125181
- // buys auto-following the upgrade, and the listed gap overstates the real
125182
- // one because a rolling alias prices at its routing ceiling.
125183
- // 0731 gained a `low` rung and renamed the top to `max`, and that ladder
125184
- // now reads the same on BOTH routes — the in-place direct upgrade caught
125185
- // up to the fork. so `low`, not `high`, is position 0 either way, which is
125186
- // why the OSS effort floor in `main.ts` pins the `high` rung by name. Pro
125187
- // is the same shape via OpenRouter since 0813; only its direct route still
125188
- // starts at `high`.
125185
+ // V4.1-Flash (2026-09-10) retired `deepseek-v4-flash`; DeepSeek's /models
125186
+ // now lists the unversioned `deepseek-flash`, so the direct resolve is the
125187
+ // rolling id at the same price. OpenRouter treats V4.1 as its own id
125188
+ // (`deepseek/deepseek-v4.1-flash`, $0.15/$0.6, cache $0.003) and its
125189
+ // `~deepseek/deepseek-v4-flash-latest` pointer still served 0731 on
125190
+ // 2026-09-11, so this is a pinned id rather than the pointer and the next
125191
+ // Flash release is a catalog edit (the bump cron flags it). this target is
125192
+ // the funded OSS default: priced on the measured OSS token mix at x1.34
125193
+ // the pointer's $0.0531/run on the DeepSeek-hosted endpoint — see
125194
+ // wiki/oss-model-allowlist.md. the bare `deepseek-v4-flash` on OpenRouter
125195
+ // is still the April preview, so that route can never use it. both routes
125196
+ // publish `low, high, max`; the OSS effort floor pins `high` by name.
125189
125197
  "deepseek-flash": {
125190
125198
  displayName: "DeepSeek Flash",
125191
- resolve: "deepseek/deepseek-v4-flash",
125199
+ resolve: "deepseek/deepseek-flash",
125192
125200
  effort: ["low", "high", "max"],
125193
125201
  openRouterEffort: ["low", "high", "max"],
125194
- openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
125202
+ openRouterResolve: "openrouter/deepseek/deepseek-v4.1-flash"
125195
125203
  },
125196
125204
  // legacy aliases — deepseek retires these on 2026-07-24; transparently
125197
125205
  // upgrade existing users to the v4 family via the fallback chain.
@@ -125285,7 +125293,10 @@ var providers = {
125285
125293
  "kimi-k2": {
125286
125294
  displayName: "Kimi K2",
125287
125295
  description: "Included in every Kimi membership tier",
125288
- resolve: "kimi-for-coding/kimi-for-coding"
125296
+ resolve: "kimi-for-coding/kimi-for-coding",
125297
+ // models.dev published this ladder on 2026-09-14; the catalog gate
125298
+ // mirrors it, so main was red until the alias carried it too.
125299
+ effort: ["low", "high", "max"]
125289
125300
  },
125290
125301
  "kimi-k2-highspeed": {
125291
125302
  displayName: "Kimi K2 HighSpeed",
@@ -125294,6 +125305,40 @@ var providers = {
125294
125305
  }
125295
125306
  }
125296
125307
  }),
125308
+ // Meta Model API — the direct route to Muse Spark. a registry entry, like
125309
+ // kimi-for-coding: models.dev carries `meta` (`https://api.meta.ai/v1`, npm
125310
+ // `@ai-sdk/openai`) and opencode 1.18.29 enables it from a bare
125311
+ // META_MODEL_API_KEY — all five ids list in `opencode models`, and a bogus key
125312
+ // reaches Meta's own auth check (`invalid_api_key`). see wiki/muse-spark.md.
125313
+ meta: provider({
125314
+ displayName: "Meta",
125315
+ envVars: ["META_MODEL_API_KEY"],
125316
+ models: {
125317
+ // the Standard tier. no `subagentModel`: the contributor tier below is
125318
+ // the same model, not a cheaper sibling.
125319
+ "muse-spark": {
125320
+ displayName: "Muse Spark",
125321
+ resolve: "meta/muse-spark-1.3",
125322
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
125323
+ openRouterResolve: "openrouter/meta/muse-spark-1.3",
125324
+ preferred: true
125325
+ },
125326
+ // the Contributor tier: the same model at $0.10 / $0.20 (cache read
125327
+ // $0.002) because Meta trains on the prompts and completions. an opt-in
125328
+ // pick on the OSS menu (public code, headless runs), never the default.
125329
+ // OpenRouter only serves it when the account allows paid-model training,
125330
+ // so the runtime opens data collection for this id alone — see
125331
+ // `openRouterProvider` in opencodeShared.ts.
125332
+ "muse-spark-contributor": {
125333
+ displayName: "Muse Spark Contributor",
125334
+ description: "Meta trains on prompts and completions",
125335
+ resolve: "meta/muse-spark-1.3-contributor",
125336
+ effort: ["minimal", "low", "medium", "high", "xhigh"],
125337
+ openRouterEffort: ["minimal", "low", "medium", "high", "xhigh", "max"],
125338
+ openRouterResolve: "openrouter/meta/muse-spark-1.3-contributor"
125339
+ }
125340
+ }
125341
+ }),
125297
125342
  opencode: provider({
125298
125343
  displayName: "OpenCode Zen",
125299
125344
  envVars: ["OPENCODE_API_KEY"],
@@ -125494,6 +125539,27 @@ var providers = {
125494
125539
  effort: ["minimal", "low", "medium", "high"],
125495
125540
  openRouterResolve: "openrouter/openai/gpt-5-nano"
125496
125541
  },
125542
+ // Zen's PAID Muse Spark, priced like Meta's own Standard tier. answered
125543
+ // `OK` through the harness on 2026-09-12 once the workspace was funded.
125544
+ "muse-spark": {
125545
+ displayName: "Muse Spark",
125546
+ resolve: "opencode/muse-spark-1.3",
125547
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
125548
+ openRouterResolve: "openrouter/meta/muse-spark-1.3"
125549
+ },
125550
+ // Zen's FREE contributor tier: the same model at $0 because Meta trains
125551
+ // on the prompts and completions. Zen served it to our key on 2026-09-12
125552
+ // without the DataPolicyError Go raises for its contributor id. see
125553
+ // wiki/muse-spark.md.
125554
+ "muse-spark-contributor": {
125555
+ displayName: "Muse Spark Contributor",
125556
+ description: "Meta trains on prompts and completions",
125557
+ resolve: "opencode/muse-spark-1.3-contributor-free",
125558
+ effort: ["minimal", "low", "medium", "high", "xhigh"],
125559
+ // free to run, still gated on the provider's own OPENCODE_API_KEY —
125560
+ // see the big-pickle note above (#1077).
125561
+ isFree: true
125562
+ },
125497
125563
  // Zen's live free MiMo, and the second free row in a menu that big-pickle
125498
125564
  // was alone in since `mimo-v2-pro-free` lost its model.
125499
125565
  mimo: {
@@ -125873,9 +125939,9 @@ var providers = {
125873
125939
  },
125874
125940
  grok: {
125875
125941
  displayName: "Grok",
125876
- resolve: "openrouter/x-ai/grok-4.5",
125877
- effort: ["low", "medium", "high"],
125878
- openRouterResolve: "openrouter/x-ai/grok-4.5"
125942
+ resolve: "openrouter/x-ai/grok-4.6",
125943
+ effort: ["low", "medium", "high", "xhigh"],
125944
+ openRouterResolve: "openrouter/x-ai/grok-4.6"
125879
125945
  },
125880
125946
  // dated pin, not the bare id — see `deepseek/deepseek-pro` for why
125881
125947
  // OpenRouter's unversioned `deepseek-v4-pro` is the stale April preview.
@@ -125885,13 +125951,14 @@ var providers = {
125885
125951
  effort: ["low", "high", "max"],
125886
125952
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro-0813"
125887
125953
  },
125888
- // rolling pointer, not the bare id — see `deepseek/deepseek-flash` for why
125889
- // OpenRouter's unversioned `deepseek-v4-flash` is the stale April preview.
125954
+ // the V4.1 id, not the bare one — see `deepseek/deepseek-flash` for why
125955
+ // OpenRouter's unversioned `deepseek-v4-flash` is the stale April preview
125956
+ // and why the `~deepseek/*-latest` pointer is no longer the target.
125890
125957
  "deepseek-flash": {
125891
125958
  displayName: "DeepSeek Flash",
125892
- resolve: "openrouter/~deepseek/deepseek-v4-flash-latest",
125959
+ resolve: "openrouter/deepseek/deepseek-v4.1-flash",
125893
125960
  effort: ["low", "high", "max"],
125894
- openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
125961
+ openRouterResolve: "openrouter/deepseek/deepseek-v4.1-flash"
125895
125962
  },
125896
125963
  // legacy alias — deepseek retires this on 2026-07-24; transparently
125897
125964
  // upgrade existing users to the v4 family via the fallback chain.
@@ -125922,6 +125989,23 @@ var providers = {
125922
125989
  displayName: "MiniMax M3",
125923
125990
  resolve: "openrouter/minimax/minimax-m3",
125924
125991
  openRouterResolve: "openrouter/minimax/minimax-m3"
125992
+ },
125993
+ // OpenRouter gates Meta models on an ACCOUNT-level 18+ confirmation
125994
+ // (openrouter.ai/settings/preferences). Pullfrog's account has it, so the
125995
+ // Router path runs; a BYOK OpenRouter key without it refuses with that
125996
+ // link before the request reaches Meta. see wiki/muse-spark.md.
125997
+ "muse-spark": {
125998
+ displayName: "Muse Spark",
125999
+ resolve: "openrouter/meta/muse-spark-1.3",
126000
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
126001
+ openRouterResolve: "openrouter/meta/muse-spark-1.3"
126002
+ },
126003
+ "muse-spark-contributor": {
126004
+ displayName: "Muse Spark Contributor",
126005
+ description: "Meta trains on prompts and completions",
126006
+ resolve: "openrouter/meta/muse-spark-1.3-contributor",
126007
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
126008
+ openRouterResolve: "openrouter/meta/muse-spark-1.3-contributor"
125925
126009
  }
125926
126010
  }
125927
126011
  }),
@@ -125989,10 +126073,13 @@ var providers = {
125989
126073
  resolve: "vercel/deepseek/deepseek-v4-pro-0813",
125990
126074
  effort: ["high", "xhigh"]
125991
126075
  },
126076
+ // the gateway's bare `deepseek-v4-flash` is the April preview — the same
126077
+ // fork trap as OpenRouter, with `deepseek-v4-flash-0731` beside it — so
126078
+ // this entry sat on the preview until V4.1. the gateway publishes no
126079
+ // effort ladder for the V4.1 id.
125992
126080
  "deepseek-flash": {
125993
126081
  displayName: "DeepSeek Flash",
125994
- resolve: "vercel/deepseek/deepseek-v4-flash",
125995
- effort: ["high", "xhigh"]
126082
+ resolve: "vercel/deepseek/deepseek-v4.1-flash"
125996
126083
  },
125997
126084
  glm: {
125998
126085
  displayName: "GLM",
@@ -126003,6 +126090,11 @@ var providers = {
126003
126090
  displayName: "Kimi K3",
126004
126091
  resolve: "vercel/moonshotai/kimi-k3",
126005
126092
  effort: ["low", "high", "max"]
126093
+ },
126094
+ // the gateway publishes no effort ladder for this id.
126095
+ "muse-spark": {
126096
+ displayName: "Muse Spark",
126097
+ resolve: "vercel/meta/muse-spark-1.3"
126006
126098
  }
126007
126099
  }
126008
126100
  })
@@ -126098,8 +126190,8 @@ var PROVIDER_LADDERS = {
126098
126190
  deep: "deepseek/deepseek-pro"
126099
126191
  },
126100
126192
  xai: {
126101
- minimal: "xai/grok-fast",
126102
- light: "xai/grok-fast",
126193
+ minimal: "xai/grok-4.3",
126194
+ light: "xai/grok-4.3",
126103
126195
  standard: "xai/grok",
126104
126196
  deep: "xai/grok"
126105
126197
  },
@@ -126181,15 +126273,22 @@ if (!defaultProxyAlias?.openRouterResolve) {
126181
126273
  var DEFAULT_PROXY_MODEL = defaultProxyAlias.openRouterResolve;
126182
126274
  var defaultProxyDisplayName = defaultProxyAlias.displayName;
126183
126275
  for (const [name, ladder] of Object.entries({ ...PROVIDER_LADDERS, router: ROUTER_LADDER })) {
126276
+ const terminal = /* @__PURE__ */ new Set();
126184
126277
  for (const slug2 of Object.values(ladder)) {
126185
- if (!resolveDisplayAlias(slug2)) throw new Error(`${name} ladder names unknown alias ${slug2}`);
126278
+ const alias = resolveDisplayAlias(slug2);
126279
+ if (!alias) throw new Error(`${name} ladder names unknown alias ${slug2}`);
126280
+ terminal.add(alias.slug);
126186
126281
  }
126282
+ if (terminal.size < 2) throw new Error(`${name} ladder runs every tier on ${[...terminal][0]}`);
126187
126283
  }
126188
126284
  var OSS_MODEL_ALLOWLIST = [
126189
126285
  "deepseek/deepseek-flash",
126190
- "deepseek/deepseek-pro",
126191
126286
  "openai/gpt-luna",
126192
- "openrouter/minimax-m2.5"
126287
+ "openrouter/minimax-m2.5",
126288
+ // opt-in: 0.86x the old default on the measured mix, and Meta trains on the
126289
+ // traffic — fine for public code on headless runs, the human decided
126290
+ // 2026-09-11. unmeasured on a real run; not the default until it is.
126291
+ "meta/muse-spark-contributor"
126193
126292
  ];
126194
126293
  var OSS_RECOMMENDED_MODEL = AUTO_TIER_TARGET[AUTO_EFFICIENT];
126195
126294
  function ossFundedModelNames() {
@@ -135865,13 +135964,29 @@ function azureProvider(model) {
135865
135964
  };
135866
135965
  }
135867
135966
  var KIMI_ENFORCERLESS_PROVIDERS = ["siliconflow", "together"];
135868
- function kimiOpenRouterProviderOverrides() {
135869
- return Object.fromEntries(
135870
- modelAliases.map((a2) => a2.openRouterResolve).filter((r2) => r2?.includes("kimi") ?? false).map((r2) => [
135871
- r2.replace(/^openrouter\//, ""),
135872
- { options: { provider: { ignore: KIMI_ENFORCERLESS_PROVIDERS } } }
135873
- ])
135874
- );
135967
+ function openRouterDataCollection(ctx) {
135968
+ if (!ctx.payload.proxyModel) return void 0;
135969
+ return ctx.toolState.oss ? "allow" : "deny";
135970
+ }
135971
+ function dataCollectionPreference(policy) {
135972
+ if (!policy) return {};
135973
+ return { data_collection: policy };
135974
+ }
135975
+ function openRouterProvider(policy) {
135976
+ const models = {};
135977
+ for (const alias of modelAliases) {
135978
+ const id = alias.openRouterResolve?.replace(/^openrouter\//, "");
135979
+ if (!id) continue;
135980
+ if (id.endsWith("-contributor")) {
135981
+ models[id] = { options: { provider: { data_collection: "allow" } } };
135982
+ }
135983
+ if (id.includes("kimi")) {
135984
+ const provider2 = { ...dataCollectionPreference(policy), ignore: KIMI_ENFORCERLESS_PROVIDERS };
135985
+ models[id] = { options: { provider: provider2 } };
135986
+ }
135987
+ }
135988
+ if (!policy) return { models };
135989
+ return { options: { extraBody: { provider: { data_collection: policy } } }, models };
135875
135990
  }
135876
135991
  function buildReviewerAgentConfig(orchestratorModel) {
135877
135992
  const overrides = deriveSubagentModels(orchestratorModel);
@@ -135947,13 +136062,12 @@ function buildSecurityConfig(ctx, model) {
135947
136062
  log2.info(`\xBB subagent models: reviewfrog=${reviewerModel}`);
135948
136063
  return cfg;
135949
136064
  })(),
135950
- // kimi pinned away from Enforcer-less openrouter providers (siliconflow /
135951
- // together) that drop optional tool-call params — per-model on the
135952
- // openrouter route, so other models are unaffected. this is routing, not
135953
- // reasoning: every model's effort now rides the per-prompt `variant`.
135954
- // see opencodeShared.ts.
136065
+ // openrouter routing, not reasoning (every model's effort rides the
136066
+ // per-prompt `variant`): the run's data-collection policy, kimi pinned
136067
+ // away from Enforcer-less providers, the Muse Spark contributor tier
136068
+ // opened to training hosts. see opencodeShared.ts.
135955
136069
  provider: {
135956
- openrouter: { models: kimiOpenRouterProviderOverrides() },
136070
+ openrouter: openRouterProvider(openRouterDataCollection(ctx)),
135957
136071
  ...openAICompatibleProvider(model),
135958
136072
  ...azureProvider(model),
135959
136073
  ...providerGatewayOverride(model)
@@ -219871,7 +219985,7 @@ function resolveTarget2(repo) {
219871
219985
  return { owner: match3[1], repo: match3[2] };
219872
219986
  }
219873
219987
  function cliVersion() {
219874
- const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.77");
219988
+ const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.79");
219875
219989
  if (!parts) return "0.0.0";
219876
219990
  return `${Number(parts[1])}.${Number(parts[2])}.${Number(parts[3])}`;
219877
219991
  }
@@ -220038,7 +220152,7 @@ async function runCli8(input2) {
220038
220152
  }
220039
220153
 
220040
220154
  // cli.ts
220041
- var VERSION10 = "0.1.77";
220155
+ var VERSION10 = "0.1.79";
220042
220156
  var bin = basename2(process.argv[1] || "");
220043
220157
  var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
220044
220158
  var rawArgs = process.argv.slice(2);
package/dist/index.js CHANGED
@@ -107941,26 +107941,34 @@ var providers = {
107941
107941
  models: {
107942
107942
  grok: {
107943
107943
  displayName: "Grok",
107944
- resolve: "xai/grok-4.5",
107945
- effort: ["low", "medium", "high"],
107946
- openRouterResolve: "openrouter/x-ai/grok-4.5",
107944
+ resolve: "xai/grok-4.6",
107945
+ effort: ["low", "medium", "high", "xhigh"],
107946
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
107947
107947
  preferred: true
107948
107948
  },
107949
+ // the Smart ladder's cheap rung: 1.25/2.5 against 4.6's 2/6, and a 0.2
107950
+ // cache read against 0.5 — the only live xAI model a rung can save on.
107951
+ "grok-4.3": {
107952
+ displayName: "Grok 4.3",
107953
+ resolve: "xai/grok-4.3",
107954
+ effort: ["none", "low", "medium", "high"],
107955
+ openRouterResolve: "openrouter/x-ai/grok-4.3"
107956
+ },
107949
107957
  // legacy aliases — xAI retired the entire fast/code-fast line on
107950
107958
  // 2026-05-15 (https://docs.x.ai/developers/migration/may-15-deprecation)
107951
107959
  // and now redirects every deprecated text-model slug to grok-4.3 at
107952
107960
  // standard pricing. fall back to the live `xai/grok` so the alias
107953
- // chain resolves to grok-4.5 for both direct-key and OpenRouter users.
107961
+ // chain resolves to grok-4.6 for both direct-key and OpenRouter users.
107954
107962
  "grok-fast": {
107955
107963
  displayName: "Grok Fast",
107956
107964
  resolve: "xai/grok-4-1-fast",
107957
- openRouterResolve: "openrouter/x-ai/grok-4.5",
107965
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
107958
107966
  fallback: "xai/grok"
107959
107967
  },
107960
107968
  "grok-code-fast": {
107961
107969
  displayName: "Grok Code Fast",
107962
107970
  resolve: "xai/grok-code-fast-1",
107963
- openRouterResolve: "openrouter/x-ai/grok-4.5",
107971
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
107964
107972
  fallback: "xai/grok"
107965
107973
  }
107966
107974
  }
@@ -107979,6 +107987,12 @@ var providers = {
107979
107987
  // $0.0405. there is no `~deepseek/*-pro-latest` pointer to track, so this
107980
107988
  // one has to be a dated pin; the `models-catalog` drift test is what
107981
107989
  // catches the next release.
107990
+ // from 2026-09-14 DeepSeek serves every direct `deepseek-v4-pro` call with
107991
+ // V4.1-Flash at Flash rates until V4.1-Pro ships. it is still the only Pro
107992
+ // id the vendor lists, and the OpenRouter 0813 pin is third-party-hosted
107993
+ // and unaffected — so no `fallback` to Flash, which would drag the Router
107994
+ // route down with it. the OSS program dropped Pro from its menu instead;
107995
+ // see `OSS_MODEL_ALLOWLIST`.
107982
107996
  "deepseek-pro": {
107983
107997
  displayName: "DeepSeek Pro",
107984
107998
  resolve: "deepseek/deepseek-v4-pro",
@@ -107987,30 +108001,24 @@ var providers = {
107987
108001
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro-0813",
107988
108002
  preferred: true
107989
108003
  },
107990
- // DeepSeek upgrades the `deepseek-v4-flash` API model in place, so the
107991
- // direct `resolve` needs no version. OpenRouter instead forked the 0731
107992
- // release into its own id and left the April preview live under the
107993
- // unversioned one at a HIGHER price ($0.14/$0.28 vs $0.09/$0.18) — so the
107994
- // OpenRouter route can never use the bare id. it tracks the rolling
107995
- // `~deepseek/*-latest` pointer (rule 4), which follows the next in-place
107996
- // upgrade on its own rather than pinning a dated snapshot that goes stale
107997
- // every release. that pointer is NOT priced like 0731 — its listed rates
107998
- // run +40% on output and +57.5% on cache read, and it costs 12% more per
107999
- // run on authoritative spend ($0.0405 vs $0.0361). kept anyway: ~$45/yr
108000
- // buys auto-following the upgrade, and the listed gap overstates the real
108001
- // one because a rolling alias prices at its routing ceiling.
108002
- // 0731 gained a `low` rung and renamed the top to `max`, and that ladder
108003
- // now reads the same on BOTH routes — the in-place direct upgrade caught
108004
- // up to the fork. so `low`, not `high`, is position 0 either way, which is
108005
- // why the OSS effort floor in `main.ts` pins the `high` rung by name. Pro
108006
- // is the same shape via OpenRouter since 0813; only its direct route still
108007
- // starts at `high`.
108004
+ // V4.1-Flash (2026-09-10) retired `deepseek-v4-flash`; DeepSeek's /models
108005
+ // now lists the unversioned `deepseek-flash`, so the direct resolve is the
108006
+ // rolling id at the same price. OpenRouter treats V4.1 as its own id
108007
+ // (`deepseek/deepseek-v4.1-flash`, $0.15/$0.6, cache $0.003) and its
108008
+ // `~deepseek/deepseek-v4-flash-latest` pointer still served 0731 on
108009
+ // 2026-09-11, so this is a pinned id rather than the pointer and the next
108010
+ // Flash release is a catalog edit (the bump cron flags it). this target is
108011
+ // the funded OSS default: priced on the measured OSS token mix at x1.34
108012
+ // the pointer's $0.0531/run on the DeepSeek-hosted endpoint — see
108013
+ // wiki/oss-model-allowlist.md. the bare `deepseek-v4-flash` on OpenRouter
108014
+ // is still the April preview, so that route can never use it. both routes
108015
+ // publish `low, high, max`; the OSS effort floor pins `high` by name.
108008
108016
  "deepseek-flash": {
108009
108017
  displayName: "DeepSeek Flash",
108010
- resolve: "deepseek/deepseek-v4-flash",
108018
+ resolve: "deepseek/deepseek-flash",
108011
108019
  effort: ["low", "high", "max"],
108012
108020
  openRouterEffort: ["low", "high", "max"],
108013
- openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
108021
+ openRouterResolve: "openrouter/deepseek/deepseek-v4.1-flash"
108014
108022
  },
108015
108023
  // legacy aliases — deepseek retires these on 2026-07-24; transparently
108016
108024
  // upgrade existing users to the v4 family via the fallback chain.
@@ -108104,7 +108112,10 @@ var providers = {
108104
108112
  "kimi-k2": {
108105
108113
  displayName: "Kimi K2",
108106
108114
  description: "Included in every Kimi membership tier",
108107
- resolve: "kimi-for-coding/kimi-for-coding"
108115
+ resolve: "kimi-for-coding/kimi-for-coding",
108116
+ // models.dev published this ladder on 2026-09-14; the catalog gate
108117
+ // mirrors it, so main was red until the alias carried it too.
108118
+ effort: ["low", "high", "max"]
108108
108119
  },
108109
108120
  "kimi-k2-highspeed": {
108110
108121
  displayName: "Kimi K2 HighSpeed",
@@ -108113,6 +108124,40 @@ var providers = {
108113
108124
  }
108114
108125
  }
108115
108126
  }),
108127
+ // Meta Model API — the direct route to Muse Spark. a registry entry, like
108128
+ // kimi-for-coding: models.dev carries `meta` (`https://api.meta.ai/v1`, npm
108129
+ // `@ai-sdk/openai`) and opencode 1.18.29 enables it from a bare
108130
+ // META_MODEL_API_KEY — all five ids list in `opencode models`, and a bogus key
108131
+ // reaches Meta's own auth check (`invalid_api_key`). see wiki/muse-spark.md.
108132
+ meta: provider({
108133
+ displayName: "Meta",
108134
+ envVars: ["META_MODEL_API_KEY"],
108135
+ models: {
108136
+ // the Standard tier. no `subagentModel`: the contributor tier below is
108137
+ // the same model, not a cheaper sibling.
108138
+ "muse-spark": {
108139
+ displayName: "Muse Spark",
108140
+ resolve: "meta/muse-spark-1.3",
108141
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
108142
+ openRouterResolve: "openrouter/meta/muse-spark-1.3",
108143
+ preferred: true
108144
+ },
108145
+ // the Contributor tier: the same model at $0.10 / $0.20 (cache read
108146
+ // $0.002) because Meta trains on the prompts and completions. an opt-in
108147
+ // pick on the OSS menu (public code, headless runs), never the default.
108148
+ // OpenRouter only serves it when the account allows paid-model training,
108149
+ // so the runtime opens data collection for this id alone — see
108150
+ // `openRouterProvider` in opencodeShared.ts.
108151
+ "muse-spark-contributor": {
108152
+ displayName: "Muse Spark Contributor",
108153
+ description: "Meta trains on prompts and completions",
108154
+ resolve: "meta/muse-spark-1.3-contributor",
108155
+ effort: ["minimal", "low", "medium", "high", "xhigh"],
108156
+ openRouterEffort: ["minimal", "low", "medium", "high", "xhigh", "max"],
108157
+ openRouterResolve: "openrouter/meta/muse-spark-1.3-contributor"
108158
+ }
108159
+ }
108160
+ }),
108116
108161
  opencode: provider({
108117
108162
  displayName: "OpenCode Zen",
108118
108163
  envVars: ["OPENCODE_API_KEY"],
@@ -108313,6 +108358,27 @@ var providers = {
108313
108358
  effort: ["minimal", "low", "medium", "high"],
108314
108359
  openRouterResolve: "openrouter/openai/gpt-5-nano"
108315
108360
  },
108361
+ // Zen's PAID Muse Spark, priced like Meta's own Standard tier. answered
108362
+ // `OK` through the harness on 2026-09-12 once the workspace was funded.
108363
+ "muse-spark": {
108364
+ displayName: "Muse Spark",
108365
+ resolve: "opencode/muse-spark-1.3",
108366
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
108367
+ openRouterResolve: "openrouter/meta/muse-spark-1.3"
108368
+ },
108369
+ // Zen's FREE contributor tier: the same model at $0 because Meta trains
108370
+ // on the prompts and completions. Zen served it to our key on 2026-09-12
108371
+ // without the DataPolicyError Go raises for its contributor id. see
108372
+ // wiki/muse-spark.md.
108373
+ "muse-spark-contributor": {
108374
+ displayName: "Muse Spark Contributor",
108375
+ description: "Meta trains on prompts and completions",
108376
+ resolve: "opencode/muse-spark-1.3-contributor-free",
108377
+ effort: ["minimal", "low", "medium", "high", "xhigh"],
108378
+ // free to run, still gated on the provider's own OPENCODE_API_KEY —
108379
+ // see the big-pickle note above (#1077).
108380
+ isFree: true
108381
+ },
108316
108382
  // Zen's live free MiMo, and the second free row in a menu that big-pickle
108317
108383
  // was alone in since `mimo-v2-pro-free` lost its model.
108318
108384
  mimo: {
@@ -108692,9 +108758,9 @@ var providers = {
108692
108758
  },
108693
108759
  grok: {
108694
108760
  displayName: "Grok",
108695
- resolve: "openrouter/x-ai/grok-4.5",
108696
- effort: ["low", "medium", "high"],
108697
- openRouterResolve: "openrouter/x-ai/grok-4.5"
108761
+ resolve: "openrouter/x-ai/grok-4.6",
108762
+ effort: ["low", "medium", "high", "xhigh"],
108763
+ openRouterResolve: "openrouter/x-ai/grok-4.6"
108698
108764
  },
108699
108765
  // dated pin, not the bare id — see `deepseek/deepseek-pro` for why
108700
108766
  // OpenRouter's unversioned `deepseek-v4-pro` is the stale April preview.
@@ -108704,13 +108770,14 @@ var providers = {
108704
108770
  effort: ["low", "high", "max"],
108705
108771
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro-0813"
108706
108772
  },
108707
- // rolling pointer, not the bare id — see `deepseek/deepseek-flash` for why
108708
- // OpenRouter's unversioned `deepseek-v4-flash` is the stale April preview.
108773
+ // the V4.1 id, not the bare one — see `deepseek/deepseek-flash` for why
108774
+ // OpenRouter's unversioned `deepseek-v4-flash` is the stale April preview
108775
+ // and why the `~deepseek/*-latest` pointer is no longer the target.
108709
108776
  "deepseek-flash": {
108710
108777
  displayName: "DeepSeek Flash",
108711
- resolve: "openrouter/~deepseek/deepseek-v4-flash-latest",
108778
+ resolve: "openrouter/deepseek/deepseek-v4.1-flash",
108712
108779
  effort: ["low", "high", "max"],
108713
- openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
108780
+ openRouterResolve: "openrouter/deepseek/deepseek-v4.1-flash"
108714
108781
  },
108715
108782
  // legacy alias — deepseek retires this on 2026-07-24; transparently
108716
108783
  // upgrade existing users to the v4 family via the fallback chain.
@@ -108741,6 +108808,23 @@ var providers = {
108741
108808
  displayName: "MiniMax M3",
108742
108809
  resolve: "openrouter/minimax/minimax-m3",
108743
108810
  openRouterResolve: "openrouter/minimax/minimax-m3"
108811
+ },
108812
+ // OpenRouter gates Meta models on an ACCOUNT-level 18+ confirmation
108813
+ // (openrouter.ai/settings/preferences). Pullfrog's account has it, so the
108814
+ // Router path runs; a BYOK OpenRouter key without it refuses with that
108815
+ // link before the request reaches Meta. see wiki/muse-spark.md.
108816
+ "muse-spark": {
108817
+ displayName: "Muse Spark",
108818
+ resolve: "openrouter/meta/muse-spark-1.3",
108819
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
108820
+ openRouterResolve: "openrouter/meta/muse-spark-1.3"
108821
+ },
108822
+ "muse-spark-contributor": {
108823
+ displayName: "Muse Spark Contributor",
108824
+ description: "Meta trains on prompts and completions",
108825
+ resolve: "openrouter/meta/muse-spark-1.3-contributor",
108826
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
108827
+ openRouterResolve: "openrouter/meta/muse-spark-1.3-contributor"
108744
108828
  }
108745
108829
  }
108746
108830
  }),
@@ -108808,10 +108892,13 @@ var providers = {
108808
108892
  resolve: "vercel/deepseek/deepseek-v4-pro-0813",
108809
108893
  effort: ["high", "xhigh"]
108810
108894
  },
108895
+ // the gateway's bare `deepseek-v4-flash` is the April preview — the same
108896
+ // fork trap as OpenRouter, with `deepseek-v4-flash-0731` beside it — so
108897
+ // this entry sat on the preview until V4.1. the gateway publishes no
108898
+ // effort ladder for the V4.1 id.
108811
108899
  "deepseek-flash": {
108812
108900
  displayName: "DeepSeek Flash",
108813
- resolve: "vercel/deepseek/deepseek-v4-flash",
108814
- effort: ["high", "xhigh"]
108901
+ resolve: "vercel/deepseek/deepseek-v4.1-flash"
108815
108902
  },
108816
108903
  glm: {
108817
108904
  displayName: "GLM",
@@ -108822,6 +108909,11 @@ var providers = {
108822
108909
  displayName: "Kimi K3",
108823
108910
  resolve: "vercel/moonshotai/kimi-k3",
108824
108911
  effort: ["low", "high", "max"]
108912
+ },
108913
+ // the gateway publishes no effort ladder for this id.
108914
+ "muse-spark": {
108915
+ displayName: "Muse Spark",
108916
+ resolve: "vercel/meta/muse-spark-1.3"
108825
108917
  }
108826
108918
  }
108827
108919
  })
@@ -108917,8 +109009,8 @@ var PROVIDER_LADDERS = {
108917
109009
  deep: "deepseek/deepseek-pro"
108918
109010
  },
108919
109011
  xai: {
108920
- minimal: "xai/grok-fast",
108921
- light: "xai/grok-fast",
109012
+ minimal: "xai/grok-4.3",
109013
+ light: "xai/grok-4.3",
108922
109014
  standard: "xai/grok",
108923
109015
  deep: "xai/grok"
108924
109016
  },
@@ -109000,15 +109092,22 @@ if (!defaultProxyAlias?.openRouterResolve) {
109000
109092
  var DEFAULT_PROXY_MODEL = defaultProxyAlias.openRouterResolve;
109001
109093
  var defaultProxyDisplayName = defaultProxyAlias.displayName;
109002
109094
  for (const [name, ladder] of Object.entries({ ...PROVIDER_LADDERS, router: ROUTER_LADDER })) {
109095
+ const terminal = /* @__PURE__ */ new Set();
109003
109096
  for (const slug2 of Object.values(ladder)) {
109004
- if (!resolveDisplayAlias(slug2)) throw new Error(`${name} ladder names unknown alias ${slug2}`);
109097
+ const alias = resolveDisplayAlias(slug2);
109098
+ if (!alias) throw new Error(`${name} ladder names unknown alias ${slug2}`);
109099
+ terminal.add(alias.slug);
109005
109100
  }
109101
+ if (terminal.size < 2) throw new Error(`${name} ladder runs every tier on ${[...terminal][0]}`);
109006
109102
  }
109007
109103
  var OSS_MODEL_ALLOWLIST = [
109008
109104
  "deepseek/deepseek-flash",
109009
- "deepseek/deepseek-pro",
109010
109105
  "openai/gpt-luna",
109011
- "openrouter/minimax-m2.5"
109106
+ "openrouter/minimax-m2.5",
109107
+ // opt-in: 0.86x the old default on the measured mix, and Meta trains on the
109108
+ // traffic — fine for public code on headless runs, the human decided
109109
+ // 2026-09-11. unmeasured on a real run; not the default until it is.
109110
+ "meta/muse-spark-contributor"
109012
109111
  ];
109013
109112
  var OSS_RECOMMENDED_MODEL = AUTO_TIER_TARGET[AUTO_EFFICIENT];
109014
109113
  function ossFundedModelNames() {
@@ -109876,7 +109975,7 @@ var import_semver = __toESM(require_semver2(), 1);
109876
109975
  // package.json
109877
109976
  var package_default = {
109878
109977
  name: "pullfrog",
109879
- version: "0.1.77",
109978
+ version: "0.1.79",
109880
109979
  cliContractVersion: "1",
109881
109980
  type: "module",
109882
109981
  bin: {
@@ -118725,13 +118824,29 @@ function azureProvider(model) {
118725
118824
  };
118726
118825
  }
118727
118826
  var KIMI_ENFORCERLESS_PROVIDERS = ["siliconflow", "together"];
118728
- function kimiOpenRouterProviderOverrides() {
118729
- return Object.fromEntries(
118730
- modelAliases.map((a) => a.openRouterResolve).filter((r) => r?.includes("kimi") ?? false).map((r) => [
118731
- r.replace(/^openrouter\//, ""),
118732
- { options: { provider: { ignore: KIMI_ENFORCERLESS_PROVIDERS } } }
118733
- ])
118734
- );
118827
+ function openRouterDataCollection(ctx) {
118828
+ if (!ctx.payload.proxyModel) return void 0;
118829
+ return ctx.toolState.oss ? "allow" : "deny";
118830
+ }
118831
+ function dataCollectionPreference(policy) {
118832
+ if (!policy) return {};
118833
+ return { data_collection: policy };
118834
+ }
118835
+ function openRouterProvider(policy) {
118836
+ const models = {};
118837
+ for (const alias of modelAliases) {
118838
+ const id = alias.openRouterResolve?.replace(/^openrouter\//, "");
118839
+ if (!id) continue;
118840
+ if (id.endsWith("-contributor")) {
118841
+ models[id] = { options: { provider: { data_collection: "allow" } } };
118842
+ }
118843
+ if (id.includes("kimi")) {
118844
+ const provider2 = { ...dataCollectionPreference(policy), ignore: KIMI_ENFORCERLESS_PROVIDERS };
118845
+ models[id] = { options: { provider: provider2 } };
118846
+ }
118847
+ }
118848
+ if (!policy) return { models };
118849
+ return { options: { extraBody: { provider: { data_collection: policy } } }, models };
118735
118850
  }
118736
118851
  function buildReviewerAgentConfig(orchestratorModel) {
118737
118852
  const overrides = deriveSubagentModels(orchestratorModel);
@@ -118807,13 +118922,12 @@ function buildSecurityConfig(ctx, model) {
118807
118922
  log.info(`\xBB subagent models: reviewfrog=${reviewerModel}`);
118808
118923
  return cfg;
118809
118924
  })(),
118810
- // kimi pinned away from Enforcer-less openrouter providers (siliconflow /
118811
- // together) that drop optional tool-call params — per-model on the
118812
- // openrouter route, so other models are unaffected. this is routing, not
118813
- // reasoning: every model's effort now rides the per-prompt `variant`.
118814
- // see opencodeShared.ts.
118925
+ // openrouter routing, not reasoning (every model's effort rides the
118926
+ // per-prompt `variant`): the run's data-collection policy, kimi pinned
118927
+ // away from Enforcer-less providers, the Muse Spark contributor tier
118928
+ // opened to training hosts. see opencodeShared.ts.
118815
118929
  provider: {
118816
- openrouter: { models: kimiOpenRouterProviderOverrides() },
118930
+ openrouter: openRouterProvider(openRouterDataCollection(ctx)),
118817
118931
  ...openAICompatibleProvider(model),
118818
118932
  ...azureProvider(model),
118819
118933
  ...providerGatewayOverride(model)
package/dist/internal.js CHANGED
@@ -8,7 +8,7 @@ var __export = (target, all) => {
8
8
  // package.json
9
9
  var package_default = {
10
10
  name: "pullfrog",
11
- version: "0.1.77",
11
+ version: "0.1.79",
12
12
  cliContractVersion: "1",
13
13
  type: "module",
14
14
  bin: {
@@ -14509,26 +14509,34 @@ var providers = {
14509
14509
  models: {
14510
14510
  grok: {
14511
14511
  displayName: "Grok",
14512
- resolve: "xai/grok-4.5",
14513
- effort: ["low", "medium", "high"],
14514
- openRouterResolve: "openrouter/x-ai/grok-4.5",
14512
+ resolve: "xai/grok-4.6",
14513
+ effort: ["low", "medium", "high", "xhigh"],
14514
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
14515
14515
  preferred: true
14516
14516
  },
14517
+ // the Smart ladder's cheap rung: 1.25/2.5 against 4.6's 2/6, and a 0.2
14518
+ // cache read against 0.5 — the only live xAI model a rung can save on.
14519
+ "grok-4.3": {
14520
+ displayName: "Grok 4.3",
14521
+ resolve: "xai/grok-4.3",
14522
+ effort: ["none", "low", "medium", "high"],
14523
+ openRouterResolve: "openrouter/x-ai/grok-4.3"
14524
+ },
14517
14525
  // legacy aliases — xAI retired the entire fast/code-fast line on
14518
14526
  // 2026-05-15 (https://docs.x.ai/developers/migration/may-15-deprecation)
14519
14527
  // and now redirects every deprecated text-model slug to grok-4.3 at
14520
14528
  // standard pricing. fall back to the live `xai/grok` so the alias
14521
- // chain resolves to grok-4.5 for both direct-key and OpenRouter users.
14529
+ // chain resolves to grok-4.6 for both direct-key and OpenRouter users.
14522
14530
  "grok-fast": {
14523
14531
  displayName: "Grok Fast",
14524
14532
  resolve: "xai/grok-4-1-fast",
14525
- openRouterResolve: "openrouter/x-ai/grok-4.5",
14533
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
14526
14534
  fallback: "xai/grok"
14527
14535
  },
14528
14536
  "grok-code-fast": {
14529
14537
  displayName: "Grok Code Fast",
14530
14538
  resolve: "xai/grok-code-fast-1",
14531
- openRouterResolve: "openrouter/x-ai/grok-4.5",
14539
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
14532
14540
  fallback: "xai/grok"
14533
14541
  }
14534
14542
  }
@@ -14547,6 +14555,12 @@ var providers = {
14547
14555
  // $0.0405. there is no `~deepseek/*-pro-latest` pointer to track, so this
14548
14556
  // one has to be a dated pin; the `models-catalog` drift test is what
14549
14557
  // catches the next release.
14558
+ // from 2026-09-14 DeepSeek serves every direct `deepseek-v4-pro` call with
14559
+ // V4.1-Flash at Flash rates until V4.1-Pro ships. it is still the only Pro
14560
+ // id the vendor lists, and the OpenRouter 0813 pin is third-party-hosted
14561
+ // and unaffected — so no `fallback` to Flash, which would drag the Router
14562
+ // route down with it. the OSS program dropped Pro from its menu instead;
14563
+ // see `OSS_MODEL_ALLOWLIST`.
14550
14564
  "deepseek-pro": {
14551
14565
  displayName: "DeepSeek Pro",
14552
14566
  resolve: "deepseek/deepseek-v4-pro",
@@ -14555,30 +14569,24 @@ var providers = {
14555
14569
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro-0813",
14556
14570
  preferred: true
14557
14571
  },
14558
- // DeepSeek upgrades the `deepseek-v4-flash` API model in place, so the
14559
- // direct `resolve` needs no version. OpenRouter instead forked the 0731
14560
- // release into its own id and left the April preview live under the
14561
- // unversioned one at a HIGHER price ($0.14/$0.28 vs $0.09/$0.18) — so the
14562
- // OpenRouter route can never use the bare id. it tracks the rolling
14563
- // `~deepseek/*-latest` pointer (rule 4), which follows the next in-place
14564
- // upgrade on its own rather than pinning a dated snapshot that goes stale
14565
- // every release. that pointer is NOT priced like 0731 — its listed rates
14566
- // run +40% on output and +57.5% on cache read, and it costs 12% more per
14567
- // run on authoritative spend ($0.0405 vs $0.0361). kept anyway: ~$45/yr
14568
- // buys auto-following the upgrade, and the listed gap overstates the real
14569
- // one because a rolling alias prices at its routing ceiling.
14570
- // 0731 gained a `low` rung and renamed the top to `max`, and that ladder
14571
- // now reads the same on BOTH routes — the in-place direct upgrade caught
14572
- // up to the fork. so `low`, not `high`, is position 0 either way, which is
14573
- // why the OSS effort floor in `main.ts` pins the `high` rung by name. Pro
14574
- // is the same shape via OpenRouter since 0813; only its direct route still
14575
- // starts at `high`.
14572
+ // V4.1-Flash (2026-09-10) retired `deepseek-v4-flash`; DeepSeek's /models
14573
+ // now lists the unversioned `deepseek-flash`, so the direct resolve is the
14574
+ // rolling id at the same price. OpenRouter treats V4.1 as its own id
14575
+ // (`deepseek/deepseek-v4.1-flash`, $0.15/$0.6, cache $0.003) and its
14576
+ // `~deepseek/deepseek-v4-flash-latest` pointer still served 0731 on
14577
+ // 2026-09-11, so this is a pinned id rather than the pointer and the next
14578
+ // Flash release is a catalog edit (the bump cron flags it). this target is
14579
+ // the funded OSS default: priced on the measured OSS token mix at x1.34
14580
+ // the pointer's $0.0531/run on the DeepSeek-hosted endpoint — see
14581
+ // wiki/oss-model-allowlist.md. the bare `deepseek-v4-flash` on OpenRouter
14582
+ // is still the April preview, so that route can never use it. both routes
14583
+ // publish `low, high, max`; the OSS effort floor pins `high` by name.
14576
14584
  "deepseek-flash": {
14577
14585
  displayName: "DeepSeek Flash",
14578
- resolve: "deepseek/deepseek-v4-flash",
14586
+ resolve: "deepseek/deepseek-flash",
14579
14587
  effort: ["low", "high", "max"],
14580
14588
  openRouterEffort: ["low", "high", "max"],
14581
- openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
14589
+ openRouterResolve: "openrouter/deepseek/deepseek-v4.1-flash"
14582
14590
  },
14583
14591
  // legacy aliases — deepseek retires these on 2026-07-24; transparently
14584
14592
  // upgrade existing users to the v4 family via the fallback chain.
@@ -14672,7 +14680,10 @@ var providers = {
14672
14680
  "kimi-k2": {
14673
14681
  displayName: "Kimi K2",
14674
14682
  description: "Included in every Kimi membership tier",
14675
- resolve: "kimi-for-coding/kimi-for-coding"
14683
+ resolve: "kimi-for-coding/kimi-for-coding",
14684
+ // models.dev published this ladder on 2026-09-14; the catalog gate
14685
+ // mirrors it, so main was red until the alias carried it too.
14686
+ effort: ["low", "high", "max"]
14676
14687
  },
14677
14688
  "kimi-k2-highspeed": {
14678
14689
  displayName: "Kimi K2 HighSpeed",
@@ -14681,6 +14692,40 @@ var providers = {
14681
14692
  }
14682
14693
  }
14683
14694
  }),
14695
+ // Meta Model API — the direct route to Muse Spark. a registry entry, like
14696
+ // kimi-for-coding: models.dev carries `meta` (`https://api.meta.ai/v1`, npm
14697
+ // `@ai-sdk/openai`) and opencode 1.18.29 enables it from a bare
14698
+ // META_MODEL_API_KEY — all five ids list in `opencode models`, and a bogus key
14699
+ // reaches Meta's own auth check (`invalid_api_key`). see wiki/muse-spark.md.
14700
+ meta: provider({
14701
+ displayName: "Meta",
14702
+ envVars: ["META_MODEL_API_KEY"],
14703
+ models: {
14704
+ // the Standard tier. no `subagentModel`: the contributor tier below is
14705
+ // the same model, not a cheaper sibling.
14706
+ "muse-spark": {
14707
+ displayName: "Muse Spark",
14708
+ resolve: "meta/muse-spark-1.3",
14709
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
14710
+ openRouterResolve: "openrouter/meta/muse-spark-1.3",
14711
+ preferred: true
14712
+ },
14713
+ // the Contributor tier: the same model at $0.10 / $0.20 (cache read
14714
+ // $0.002) because Meta trains on the prompts and completions. an opt-in
14715
+ // pick on the OSS menu (public code, headless runs), never the default.
14716
+ // OpenRouter only serves it when the account allows paid-model training,
14717
+ // so the runtime opens data collection for this id alone — see
14718
+ // `openRouterProvider` in opencodeShared.ts.
14719
+ "muse-spark-contributor": {
14720
+ displayName: "Muse Spark Contributor",
14721
+ description: "Meta trains on prompts and completions",
14722
+ resolve: "meta/muse-spark-1.3-contributor",
14723
+ effort: ["minimal", "low", "medium", "high", "xhigh"],
14724
+ openRouterEffort: ["minimal", "low", "medium", "high", "xhigh", "max"],
14725
+ openRouterResolve: "openrouter/meta/muse-spark-1.3-contributor"
14726
+ }
14727
+ }
14728
+ }),
14684
14729
  opencode: provider({
14685
14730
  displayName: "OpenCode Zen",
14686
14731
  envVars: ["OPENCODE_API_KEY"],
@@ -14881,6 +14926,27 @@ var providers = {
14881
14926
  effort: ["minimal", "low", "medium", "high"],
14882
14927
  openRouterResolve: "openrouter/openai/gpt-5-nano"
14883
14928
  },
14929
+ // Zen's PAID Muse Spark, priced like Meta's own Standard tier. answered
14930
+ // `OK` through the harness on 2026-09-12 once the workspace was funded.
14931
+ "muse-spark": {
14932
+ displayName: "Muse Spark",
14933
+ resolve: "opencode/muse-spark-1.3",
14934
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
14935
+ openRouterResolve: "openrouter/meta/muse-spark-1.3"
14936
+ },
14937
+ // Zen's FREE contributor tier: the same model at $0 because Meta trains
14938
+ // on the prompts and completions. Zen served it to our key on 2026-09-12
14939
+ // without the DataPolicyError Go raises for its contributor id. see
14940
+ // wiki/muse-spark.md.
14941
+ "muse-spark-contributor": {
14942
+ displayName: "Muse Spark Contributor",
14943
+ description: "Meta trains on prompts and completions",
14944
+ resolve: "opencode/muse-spark-1.3-contributor-free",
14945
+ effort: ["minimal", "low", "medium", "high", "xhigh"],
14946
+ // free to run, still gated on the provider's own OPENCODE_API_KEY —
14947
+ // see the big-pickle note above (#1077).
14948
+ isFree: true
14949
+ },
14884
14950
  // Zen's live free MiMo, and the second free row in a menu that big-pickle
14885
14951
  // was alone in since `mimo-v2-pro-free` lost its model.
14886
14952
  mimo: {
@@ -15260,9 +15326,9 @@ var providers = {
15260
15326
  },
15261
15327
  grok: {
15262
15328
  displayName: "Grok",
15263
- resolve: "openrouter/x-ai/grok-4.5",
15264
- effort: ["low", "medium", "high"],
15265
- openRouterResolve: "openrouter/x-ai/grok-4.5"
15329
+ resolve: "openrouter/x-ai/grok-4.6",
15330
+ effort: ["low", "medium", "high", "xhigh"],
15331
+ openRouterResolve: "openrouter/x-ai/grok-4.6"
15266
15332
  },
15267
15333
  // dated pin, not the bare id — see `deepseek/deepseek-pro` for why
15268
15334
  // OpenRouter's unversioned `deepseek-v4-pro` is the stale April preview.
@@ -15272,13 +15338,14 @@ var providers = {
15272
15338
  effort: ["low", "high", "max"],
15273
15339
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro-0813"
15274
15340
  },
15275
- // rolling pointer, not the bare id — see `deepseek/deepseek-flash` for why
15276
- // OpenRouter's unversioned `deepseek-v4-flash` is the stale April preview.
15341
+ // the V4.1 id, not the bare one — see `deepseek/deepseek-flash` for why
15342
+ // OpenRouter's unversioned `deepseek-v4-flash` is the stale April preview
15343
+ // and why the `~deepseek/*-latest` pointer is no longer the target.
15277
15344
  "deepseek-flash": {
15278
15345
  displayName: "DeepSeek Flash",
15279
- resolve: "openrouter/~deepseek/deepseek-v4-flash-latest",
15346
+ resolve: "openrouter/deepseek/deepseek-v4.1-flash",
15280
15347
  effort: ["low", "high", "max"],
15281
- openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
15348
+ openRouterResolve: "openrouter/deepseek/deepseek-v4.1-flash"
15282
15349
  },
15283
15350
  // legacy alias — deepseek retires this on 2026-07-24; transparently
15284
15351
  // upgrade existing users to the v4 family via the fallback chain.
@@ -15309,6 +15376,23 @@ var providers = {
15309
15376
  displayName: "MiniMax M3",
15310
15377
  resolve: "openrouter/minimax/minimax-m3",
15311
15378
  openRouterResolve: "openrouter/minimax/minimax-m3"
15379
+ },
15380
+ // OpenRouter gates Meta models on an ACCOUNT-level 18+ confirmation
15381
+ // (openrouter.ai/settings/preferences). Pullfrog's account has it, so the
15382
+ // Router path runs; a BYOK OpenRouter key without it refuses with that
15383
+ // link before the request reaches Meta. see wiki/muse-spark.md.
15384
+ "muse-spark": {
15385
+ displayName: "Muse Spark",
15386
+ resolve: "openrouter/meta/muse-spark-1.3",
15387
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
15388
+ openRouterResolve: "openrouter/meta/muse-spark-1.3"
15389
+ },
15390
+ "muse-spark-contributor": {
15391
+ displayName: "Muse Spark Contributor",
15392
+ description: "Meta trains on prompts and completions",
15393
+ resolve: "openrouter/meta/muse-spark-1.3-contributor",
15394
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
15395
+ openRouterResolve: "openrouter/meta/muse-spark-1.3-contributor"
15312
15396
  }
15313
15397
  }
15314
15398
  }),
@@ -15376,10 +15460,13 @@ var providers = {
15376
15460
  resolve: "vercel/deepseek/deepseek-v4-pro-0813",
15377
15461
  effort: ["high", "xhigh"]
15378
15462
  },
15463
+ // the gateway's bare `deepseek-v4-flash` is the April preview — the same
15464
+ // fork trap as OpenRouter, with `deepseek-v4-flash-0731` beside it — so
15465
+ // this entry sat on the preview until V4.1. the gateway publishes no
15466
+ // effort ladder for the V4.1 id.
15379
15467
  "deepseek-flash": {
15380
15468
  displayName: "DeepSeek Flash",
15381
- resolve: "vercel/deepseek/deepseek-v4-flash",
15382
- effort: ["high", "xhigh"]
15469
+ resolve: "vercel/deepseek/deepseek-v4.1-flash"
15383
15470
  },
15384
15471
  glm: {
15385
15472
  displayName: "GLM",
@@ -15390,6 +15477,11 @@ var providers = {
15390
15477
  displayName: "Kimi K3",
15391
15478
  resolve: "vercel/moonshotai/kimi-k3",
15392
15479
  effort: ["low", "high", "max"]
15480
+ },
15481
+ // the gateway publishes no effort ladder for this id.
15482
+ "muse-spark": {
15483
+ displayName: "Muse Spark",
15484
+ resolve: "vercel/meta/muse-spark-1.3"
15393
15485
  }
15394
15486
  }
15395
15487
  })
@@ -15505,8 +15597,8 @@ var PROVIDER_LADDERS = {
15505
15597
  deep: "deepseek/deepseek-pro"
15506
15598
  },
15507
15599
  xai: {
15508
- minimal: "xai/grok-fast",
15509
- light: "xai/grok-fast",
15600
+ minimal: "xai/grok-4.3",
15601
+ light: "xai/grok-4.3",
15510
15602
  standard: "xai/grok",
15511
15603
  deep: "xai/grok"
15512
15604
  },
@@ -15610,15 +15702,22 @@ if (!defaultProxyAlias?.openRouterResolve) {
15610
15702
  var DEFAULT_PROXY_MODEL = defaultProxyAlias.openRouterResolve;
15611
15703
  var defaultProxyDisplayName = defaultProxyAlias.displayName;
15612
15704
  for (const [name, ladder] of Object.entries({ ...PROVIDER_LADDERS, router: ROUTER_LADDER })) {
15705
+ const terminal = /* @__PURE__ */ new Set();
15613
15706
  for (const slug of Object.values(ladder)) {
15614
- if (!resolveDisplayAlias(slug)) throw new Error(`${name} ladder names unknown alias ${slug}`);
15707
+ const alias = resolveDisplayAlias(slug);
15708
+ if (!alias) throw new Error(`${name} ladder names unknown alias ${slug}`);
15709
+ terminal.add(alias.slug);
15615
15710
  }
15711
+ if (terminal.size < 2) throw new Error(`${name} ladder runs every tier on ${[...terminal][0]}`);
15616
15712
  }
15617
15713
  var OSS_MODEL_ALLOWLIST = [
15618
15714
  "deepseek/deepseek-flash",
15619
- "deepseek/deepseek-pro",
15620
15715
  "openai/gpt-luna",
15621
- "openrouter/minimax-m2.5"
15716
+ "openrouter/minimax-m2.5",
15717
+ // opt-in: 0.86x the old default on the measured mix, and Meta trains on the
15718
+ // traffic — fine for public code on headless runs, the human decided
15719
+ // 2026-09-11. unmeasured on a real run; not the default until it is.
15720
+ "meta/muse-spark-contributor"
15622
15721
  ];
15623
15722
  var OSS_RECOMMENDED_MODEL = AUTO_TIER_TARGET[AUTO_EFFICIENT];
15624
15723
  function ossFundedModelNames() {
package/dist/models.d.ts CHANGED
@@ -121,6 +121,7 @@ export declare const providers: {
121
121
  deepseek: ProviderConfig;
122
122
  moonshotai: ProviderConfig;
123
123
  "kimi-for-coding": ProviderConfig;
124
+ meta: ProviderConfig;
124
125
  opencode: ProviderConfig;
125
126
  "opencode-go": ProviderConfig;
126
127
  bedrock: ProviderConfig;
@@ -344,6 +345,12 @@ export declare const DEFAULT_PROXY_MODEL: string;
344
345
  * over 2,203 real runs ($0.4782 vs $0.0362), almost entirely on its cache-read
345
346
  * RATE — 8.5x Flash's. it also fails 2.9% of runs against Flash's 0.0%. best
346
347
  * achievable was 10.9x (cheapest OpenRouter endpoint), so no routing fixes it.
348
+ *
349
+ * DeepSeek Pro was funded and then dropped on 2026-09-11: 88% of OSS spend at
350
+ * $0.3117/run authoritative over 4,795 runs (30d), against Flash's $0.0531 —
351
+ * and DeepSeek's V4.1-Flash release says it beats V4-Pro and phases Pro out.
352
+ * a subsidised Pro pick now runs V4.1 Flash; BYOK and Router Pro are untouched.
353
+ * re-add it only after V4.1-Pro ships AND is priced on a real run.
347
354
  * see wiki/oss-model-allowlist.md.
348
355
  */
349
356
  export declare const OSS_MODEL_ALLOWLIST: readonly string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pullfrog",
3
- "version": "0.1.77",
3
+ "version": "0.1.79",
4
4
  "cliContractVersion": "1",
5
5
  "type": "module",
6
6
  "bin": {