@polderlabs/bizar 10.23.2 → 10.23.4

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.
@@ -923,16 +923,16 @@ export function partitionStalePicks({ liveIds, pickedIds, disabledProviders }) {
923
923
 
924
924
  /**
925
925
  * Sync `userSelected.models` into Claude Code's settings.json under
926
- * `modelOverrides` using the self-map pattern (`<id>` `<id>`). This
926
+ * `modelOverrides` using recognized Claude IDs as keys and gateway IDs as
927
+ * values. This
927
928
  * suppresses `[claude-code:unrecognized_model]` diagnostics on every turn
928
929
  * for any picked ID the gateway serves. Stale IDs (not returned by the
929
930
  * gateway) are excluded so the diagnostic still surfaces them.
930
931
  *
931
932
  * Behavior:
932
933
  * - Reads `settings.json` if present; preserves every other field.
933
- * - Writes `modelOverrides` as a sparse object: only picked IDs that
934
- * are also in `liveIds`. Self-map pattern keeps dispatch behavior
935
- * identical (Claude Code dispatches the literal ID).
934
+ * - Writes `modelOverrides` as a sparse object for picked IDs that are
935
+ * also in `liveIds`; Claude Code still dispatches each literal value.
936
936
  * - Atomic replace via temp-file + rename (matches `applyModels`).
937
937
  * - When `settingsJsonPath` is provided (tests), uses that instead of
938
938
  * `~/.claude/settings.json`.
@@ -962,13 +962,13 @@ export function applyModelOverrides({ settingsJsonPath, pickedIds, liveIds = [],
962
962
  }
963
963
  const live = new Set(Array.isArray(liveIds) ? liveIds : []);
964
964
  const incoming = Array.isArray(pickedIds) ? pickedIds.filter((id) => typeof id === 'string' && id.trim()) : [];
965
- // 10.22.0 / Phase 4: strip disabled-provider ids BEFORE the self-map
966
- // so Claude Code never sees an `anthropic/*` self-map entry. The
965
+ // 10.22.0 / Phase 4: strip disabled-provider ids BEFORE the mapping
966
+ // so Claude Code never sees an `anthropic/*` override value. The
967
967
  // skipped ids are reported back so the operator can see what was
968
968
  // dropped (without crashing on the disabled list).
969
969
  const disabled = Array.isArray(disabledProviders) ? disabledProviders : readDisabledProviders();
970
970
  const { kept: picks, stripped: skippedDisabled } = filterCandidatesByDisabledProviders(incoming, disabled);
971
- // Self-map only IDs the live gateway serves. Stale IDs intentionally stay
971
+ // Map only IDs the live gateway serves. Stale IDs intentionally stay
972
972
  // out so the `[claude-code:unrecognized_model]` diagnostic still fires
973
973
  // for them — the operator should re-run `bizar models` to drop them.
974
974
  const synced = live.size === 0
@@ -987,9 +987,10 @@ export function applyModelOverrides({ settingsJsonPath, pickedIds, liveIds = [],
987
987
  return { wrote: false, syncedIds: [], skippedStale: skipped, skippedDisabled, settingsPath: path };
988
988
  }
989
989
  }
990
- // Self-map pattern Claude Code uses modelOverrides to suppress
991
- // `[claude-code:unrecognized_model]` for any ID that maps to itself.
992
- settings.modelOverrides = Object.fromEntries(synced.map((id) => [id, id]));
990
+ // Claude Code ignores unknown override keys. Recognized Anthropic model IDs
991
+ // must be keys; configured gateway aliases are values. This also suppresses
992
+ // print-mode `[claude-code:unrecognized_model]` diagnostics for Agent SDK calls.
993
+ settings.modelOverrides = buildClaudeModelOverrides(synced);
993
994
  const previousModel = typeof settings.model === 'string' ? settings.model : null;
994
995
  const previousContext = profiles?.[previousModel]?.limits?.contextTokens;
995
996
  const nextModel = synced[0] || null;
@@ -1028,6 +1029,33 @@ export function configuredEnabledModels(router) {
1028
1029
  return selected.length > 0 ? selected : configuredFallbackModels(router);
1029
1030
  }
1030
1031
 
1032
+ export const CLAUDE_MODEL_OVERRIDE_KEYS = Object.freeze([
1033
+ 'claude-fable-5',
1034
+ 'claude-opus-5',
1035
+ 'claude-sonnet-5',
1036
+ 'claude-haiku-4-5-20251001',
1037
+ 'claude-opus-4-8',
1038
+ 'claude-opus-4-7',
1039
+ 'claude-opus-4-6',
1040
+ 'claude-sonnet-4-6',
1041
+ 'claude-opus-4-5-20251101',
1042
+ 'claude-sonnet-4-5-20250929',
1043
+ 'claude-opus-4-1-20250805',
1044
+ 'claude-opus-4-20250514',
1045
+ 'claude-sonnet-4-20250514',
1046
+ 'claude-3-7-sonnet-20250219',
1047
+ 'claude-3-5-haiku-20241022',
1048
+ 'claude-3-5-sonnet-20241022',
1049
+ ]);
1050
+
1051
+ export function buildClaudeModelOverrides(modelIds) {
1052
+ const unique = [...new Set((Array.isArray(modelIds) ? modelIds : [])
1053
+ .filter((id) => typeof id === 'string' && id.trim())
1054
+ .map((id) => id.trim()))];
1055
+ return Object.fromEntries(unique.slice(0, CLAUDE_MODEL_OVERRIDE_KEYS.length)
1056
+ .map((id, index) => [CLAUDE_MODEL_OVERRIDE_KEYS[index], id]));
1057
+ }
1058
+
1031
1059
  /**
1032
1060
  * Derive a human-readable label for a model ID. Used to populate the
1033
1061
  * `modelPicker` array in settings.json so Claude Code's `/model` picker
package/cli/provision.mjs CHANGED
@@ -32,6 +32,7 @@ import { homedir } from 'node:os';
32
32
  import { dirname, join, resolve, sep } from 'node:path';
33
33
  import { fileURLToPath } from 'node:url';
34
34
  import { resolveBizarHome } from './config-paths.mjs';
35
+ import { buildClaudeModelOverrides, configuredEnabledModels } from './commands/models.mjs';
35
36
 
36
37
  const __filename = fileURLToPath(import.meta.url);
37
38
  const __dirname = dirname(__filename);
@@ -944,11 +945,13 @@ export function writeClaudeSettings({ dryRun = false, force = false } = {}) {
944
945
  const legacyRouterPath = join(CLAUDE_DIR, 'model-router.json');
945
946
  let installModel;
946
947
  let installContextTokens;
948
+ let installModels = [];
947
949
  for (const p of [bizarRouterPath, legacyRouterPath]) {
948
950
  if (!existsSync(p)) continue;
949
951
  const parsed = readJsonSafe(p, null);
950
952
  if (!parsed || typeof parsed !== 'object') continue;
951
953
  installModel = configuredInstallModel(parsed);
954
+ installModels = configuredEnabledModels(parsed);
952
955
  installContextTokens = installModel ? configuredModelContextTokens(parsed, installModel) : undefined;
953
956
  if (installModel) break;
954
957
  // The Bizar path is authoritative even when it has no enabled candidates.
@@ -956,7 +959,7 @@ export function writeClaudeSettings({ dryRun = false, force = false } = {}) {
956
959
  }
957
960
  if (installModel) {
958
961
  bizarSettings.model = installModel;
959
- bizarSettings.modelOverrides = { [installModel]: installModel };
962
+ bizarSettings.modelOverrides = buildClaudeModelOverrides(installModels);
960
963
  const configuredContext = pickEnv('CLAUDE_CODE_MAX_CONTEXT_TOKENS') || installContextTokens;
961
964
  if (configuredContext) bizarSettings.env.CLAUDE_CODE_MAX_CONTEXT_TOKENS = String(configuredContext);
962
965
  } else {
@@ -997,7 +1000,7 @@ export function writeClaudeSettings({ dryRun = false, force = false } = {}) {
997
1000
  // malformed router has no enabled candidate; dispatch will fail closed.
998
1001
  if (installModel) {
999
1002
  merged.model = installModel;
1000
- merged.modelOverrides = { [installModel]: installModel };
1003
+ merged.modelOverrides = bizarSettings.modelOverrides;
1001
1004
  }
1002
1005
 
1003
1006
  // Auto-compaction is part of the Bizar reliability contract. Remove legacy
@@ -7,7 +7,7 @@
7
7
  * Claude Code settings keys that the operator owns:
8
8
  *
9
9
  * - modelPicker → { options: [{ model, label }] } in user pick order
10
- * - modelOverrides → { <id>: <id> } self-map for every live pick
10
+ * - modelOverrides → { <recognized Claude id>: <gateway id> }
11
11
  * - model → reset to the first user pick if the current value
12
12
  * starts with `claude-` (the dead gateway namespace —
13
13
  * the live gateway rejects it with model_not_found)
@@ -223,8 +223,19 @@ function syncOnce() {
223
223
  return option;
224
224
  });
225
225
 
226
+ const overrideKeys = [
227
+ 'claude-fable-5', 'claude-opus-5', 'claude-sonnet-5',
228
+ 'claude-haiku-4-5-20251001', 'claude-opus-4-8', 'claude-opus-4-7',
229
+ 'claude-opus-4-6', 'claude-sonnet-4-6', 'claude-opus-4-5-20251101',
230
+ 'claude-sonnet-4-5-20250929', 'claude-opus-4-1-20250805',
231
+ 'claude-opus-4-20250514', 'claude-sonnet-4-20250514',
232
+ 'claude-3-7-sonnet-20250219', 'claude-3-5-haiku-20241022',
233
+ 'claude-3-5-sonnet-20241022',
234
+ ];
226
235
  settings.modelPicker = { options };
227
- settings.modelOverrides = Object.fromEntries(liveIds.map((id) => [id, id]));
236
+ settings.modelOverrides = Object.fromEntries(
237
+ liveIds.slice(0, overrideKeys.length).map((id, index) => [overrideKeys[index], id]),
238
+ );
228
239
 
229
240
  let modelChanged = false;
230
241
  if (typeof settings.model !== 'string' || !liveIds.includes(settings.model)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polderlabs/bizar",
3
- "version": "10.23.2",
3
+ "version": "10.23.4",
4
4
  "description": "Autonomous, human-in-the-loop multi-agent harness for Claude Code with guarded workflows, typed SDK primitives, and MCP tools.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * SDK version constant. Keep synchronized with the workspace package versions.
3
3
  */
4
- export declare const SDK_VERSION: "10.23.2";
4
+ export declare const SDK_VERSION: "10.23.4";
5
5
  //# sourceMappingURL=version.d.ts.map
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * SDK version constant. Keep synchronized with the workspace package versions.
3
3
  */
4
- export const SDK_VERSION = "10.23.2";
4
+ export const SDK_VERSION = "10.23.4";
5
5
  //# sourceMappingURL=version.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polderlabs/bizar-sdk",
3
- "version": "10.23.2",
3
+ "version": "10.23.4",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",