Skip to content

fix(models): route all Claude aliases through the protoLabs gateway#3671

Merged
mabry1985 merged 1 commit into
mainfrom
fix/gateway-routing-claude-aliases
May 24, 2026
Merged

fix(models): route all Claude aliases through the protoLabs gateway#3671
mabry1985 merged 1 commit into
mainfrom
fix/gateway-routing-claude-aliases

Conversation

@mabry1985
Copy link
Copy Markdown
Contributor

@mabry1985 mabry1985 commented May 24, 2026

Summary

Closes #3661. The gateway-issued API key only allows protolabs/* tier names, but CLAUDE_CANONICAL_MAP and CLAUDE_MODEL_MAP still resolved Claude aliases to versioned Anthropic strings (claude-sonnet-4-6, etc.). Every install with pre-cutover data/settings.json 401'd on the first agent turn.

The mapping

Alias Resolves to
claude-haiku / haiku protolabs/fast
claude-sonnet / sonnet protolabs/smart
claude-opus / opus protolabs/reasoning
claude-sonnet-4-6 (legacy versioned) protolabs/smart
claude-haiku-4-5-20251001 (legacy versioned) protolabs/fast
claude-opus-4-6 (legacy versioned) protolabs/reasoning

Changes

  • libs/types/src/model.ts: CLAUDE_CANONICAL_MAP + CLAUDE_MODEL_MAP values switched to gateway tiers. New LEGACY_CLAUDE_FULL_MODEL_MAP covers persisted versioned strings.
  • libs/types/src/model-migration.ts: migrateModelId now rewrites canonical IDs, short aliases, and full versioned strings to gateway tiers in one pass.
  • libs/types/src/global-settings.ts: SETTINGS_VERSION 6 → 7.
  • libs/types/src/index.ts: export LEGACY_CLAUDE_FULL_MODEL_MAP.

Test plan

  • New libs/types/tests/model-migration-gateway.test.ts — 22 tests covering all input forms and passthrough behavior
  • Updated 14 assertions across resolver/execution-service/settings-service/sdk-options test files to expect protolabs/* outputs (greenfield-first — no direct-Anthropic path)
  • Full server suite: 3397/3397 pass
  • Packages: 1152/1152 pass
  • Typecheck: clean

What this unblocks

After this lands and the server restarts, the three crew features that 401'd this morning (#3601, #3600, #3605) can redispatch and actually run.

Still outstanding: #3662 (state machine ticking to review despite agent hard-fail) — separate PR.

Closes #3661

Summary by CodeRabbit

  • Chores
    • Updated model identifier mappings to route through gateway tier system instead of direct model references.
    • Settings schema incremented to version 7 to support new model routing infrastructure.
    • Legacy model configurations will be automatically migrated to new gateway tier format.

Review Change Stack

The gateway-issued API key only allows `protolabs/*` tier names. Every
piece of routing now consistently resolves Claude aliases to one of the
three gateway tiers:

  claude-haiku  / haiku  → protolabs/fast
  claude-sonnet / sonnet → protolabs/smart
  claude-opus   / opus   → protolabs/reasoning

This was a half-finished cutover — DEFAULT_MODELS and DEFAULT_PHASE_MODELS
already pointed at gateway tiers, but CLAUDE_CANONICAL_MAP / CLAUDE_MODEL_MAP
still resolved to versioned Anthropic strings (claude-sonnet-4-6 etc.).
Any install that had stored those legacy strings in data/settings.json
(every install from before the cutover) got a hard 401 on the first
agent turn:

  [API Error: 401 key not allowed to access model. This key can only
   access models=['protolabs/smart', ...]. Tried to access claude-sonnet-4-6]

Changes:

- libs/types/src/model.ts: CLAUDE_CANONICAL_MAP and CLAUDE_MODEL_MAP
  values updated to protolabs/* tiers. New LEGACY_CLAUDE_FULL_MODEL_MAP
  covers persisted versioned strings (claude-sonnet-4-6 etc.) so any
  stored settings get rewritten on next load.
- libs/types/src/model-migration.ts: migrateModelId rewrites legacy
  canonical IDs and full versioned strings to gateway tiers. Short
  aliases also map directly to tiers (no claude-* intermediate).
- libs/types/src/global-settings.ts: SETTINGS_VERSION bumped 6 → 7 to
  signal one-shot migration on next load. SettingsService already
  re-runs migratePhaseModels every load, so no new migration code is
  needed — the bumped version is for telemetry / future schema fences.
- libs/types/src/index.ts: export LEGACY_CLAUDE_FULL_MODEL_MAP.

Tests:

- New libs/types/tests/model-migration-gateway.test.ts: 22 tests covering
  canonical IDs, short aliases, versioned legacy strings, protolabs/*
  passthrough, and unrecognized-string passthrough.
- Updated 14 existing assertions across model-resolver, execution-service,
  settings-service, and sdk-options test files to expect protolabs/*
  outputs instead of versioned claude-* strings. Per the greenfield-first
  rule, there is no direct-Anthropic path anymore — these assertions had
  become aspirational rather than describing real behavior.

Full server suite passes: 3397/3397. Packages: 1152/1152. Typecheck: clean.

Closes #3661
@mabry1985 mabry1985 enabled auto-merge (squash) May 24, 2026 08:24
@github-actions
Copy link
Copy Markdown
Contributor

ghost commented May 24, 2026

Code Review — ? finding(s)

Async review running parallel to CodeRabbit. Findings are advisory; not all are merge blockers.

protoLabs Code Review Report

  • Generated: 2026-05-24T08:25:09Z
  • Git head: 356684aea3aca96166a0785d58c663f6c0574aef
  • Features mapped: 3
  • Findings: 0

No findings recorded.

Copy link
Copy Markdown

@protoquinn protoquinn Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA Audit — PR #3671 | fix(models): route all Claude aliases through the protoLabs gateway

VERDICT: WARN


CI Status

  • test: queued
  • checks: in_progress
  • build: in_progress

Diff Review

  • Updates model resolution maps to route Claude aliases (haiku, sonnet, opus) to protoLabs gateway tiers (protolabs/fast, protolabs/smart, protolabs/reasoning).
  • Updates migrateModelId to rewrite legacy versioned strings to gateway tiers.
  • Bumps SETTINGS_VERSION to 7.
  • Updates test suites to assert on the new gateway tier strings.

Observations

  • LOW: CI checks are currently in progress or queued. Review is based on the provided diff and author's local test results.

@protoquinn
Copy link
Copy Markdown

protoquinn Bot commented May 24, 2026

I have submitted a COMMENT review on #3671.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 24, 2026

📝 Walkthrough

Walkthrough

This PR migrates Claude-family model identifiers to route through a Protolabs gateway tier system. Model aliases (haiku, sonnet, opus) and legacy full Claude version strings now resolve to gateway-routed tier identifiers (protolabs/fast, protolabs/smart, protolabs/reasoning). The settings schema version is incremented to trigger migration, and comprehensive test coverage validates the new behavior across all affected services.

Changes

Claude Model Gateway Tier Migration

Layer / File(s) Summary
Gateway tier model maps and legacy routing
libs/types/src/model.ts
CLAUDE_CANONICAL_MAP and CLAUDE_MODEL_MAP values changed to protolabs/* gateway tier identifiers; new LEGACY_CLAUDE_FULL_MODEL_MAP maps previously persisted versioned Claude full model strings (e.g., claude-opus-4-6) to their corresponding gateway tiers.
Model ID migration semantics
libs/types/src/model-migration.ts
migrateModelId updated to handle legacy full Claude model strings via LEGACY_CLAUDE_FULL_MODEL_MAP, return mapped gateway tier values for canonical aliases instead of preserving claude- prefixes, and resolve bare short aliases through the new maps to ensure gateway-tier output.
Settings version bump and exports
libs/types/src/global-settings.ts, libs/types/src/index.ts
Settings schema version incremented from 6 to 7 to trigger migration; LEGACY_CLAUDE_FULL_MODEL_MAP added to public exports.
Gateway migration regression test suite
libs/types/tests/model-migration-gateway.test.ts
New comprehensive Vitest suite validating migrateModelId behavior: canonical IDs and aliases route to protolabs/*, legacy versioned Claude strings migrate to gateway tiers, protolabs/* inputs pass through unchanged, mapping constants contain only gateway tier values, and edge cases (undefined, null, empty string) are preserved.
Service and resolver test updates
apps/server/tests/unit/lib/model-resolver.test.ts, apps/server/tests/unit/lib/sdk-options.test.ts, apps/server/tests/unit/services/execution-service.test.ts, apps/server/tests/unit/services/settings-service.test.ts, libs/model-resolver/tests/resolver.test.ts
Test assertions updated across all affected services to expect protolabs/* gateway tier outputs instead of claude-* model IDs; precedence/priority logic, manifest overrides, settings integration, and phase model migration expectations remain unchanged with only output values adjusted.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly Related Issues

  • protoLabsAI/protoMaker#3661: This PR directly addresses the migration of legacy Claude aliases and full IDs to protolabs gateway tier IDs to prevent 401 errors, including the core model map updates, migration logic, and settings version bump.

Possibly Related PRs

  • protoLabsAI/protoMaker#3652: Aligns Claude-family model mappings to the same three protoLabs gateway tiers (protolabs/fast|smart|reasoning), with overlapping changes to libs/types/src/model.ts and model alias routing behavior.
  • protoLabsAI/protoMaker#3626: Implements isProtoModel routing logic that treats claude-* aliases as ProtoProvider models; this PR's gateway-tier remapping ensures those aliases now correctly resolve to protolabs/* for provider selection.
  • protoLabsAI/protoMaker#3625: Introduces ProtoProvider routing based on isProtoModel(model) matching; this PR's output change from claude-* to protolabs/* aligns model resolution with the proto cutover expectations.

Poem

🐰 Aliases dance through gateways now,
No more Claude versioned strings we vow,
Fast, smart, reasoning tiers align,
Legacy paths migrate just fine,
The proto-route awaits us all!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly summarizes the main change: routing all Claude aliases through the protoLabs gateway, which is the core problem being fixed across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/gateway-routing-claude-aliases

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed: one or more packages not found in the registry.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@protoquinn protoquinn Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR fixes the issue reported in #3678 by routing Claude aliases through the protoLabs gateway, which bypasses the need for a direct Anthropic API key. Approving to unblock bug triage.

Copy link
Copy Markdown

@protoquinn protoquinn Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR fixes the issue described in #3661 and #3674. I have created a follow-up issue #3682 to track the ergonomics issue mentioned in the repro (requiring a server restart for manual settings.json edits to take effect due to in-memory caching).

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
libs/types/tests/model-migration-gateway.test.ts (1)

10-15: ⚡ Quick win

Use @protolabsai/* imports instead of relative ../src/* imports.

Line 10 and Lines 11-15 should import shared types APIs through the package namespace to keep tests aligned with the public/shared contract.

♻️ Suggested import update
-import { migrateModelId } from '../src/model-migration.js';
-import {
-  CLAUDE_CANONICAL_MAP,
-  CLAUDE_MODEL_MAP,
-  LEGACY_CLAUDE_FULL_MODEL_MAP,
-} from '../src/model.js';
+import {
+  migrateModelId,
+  CLAUDE_CANONICAL_MAP,
+  CLAUDE_MODEL_MAP,
+  LEGACY_CLAUDE_FULL_MODEL_MAP,
+} from '`@protolabsai/types`';

As per coding guidelines: "Import from shared packages using the @protolabsai/* namespace rather than importing from old paths or relative paths within the codebase."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/types/tests/model-migration-gateway.test.ts` around lines 10 - 15,
Replace the relative imports in the test with the public package namespace:
import migrateModelId, CLAUDE_CANONICAL_MAP, CLAUDE_MODEL_MAP, and
LEGACY_CLAUDE_FULL_MODEL_MAP from the appropriate `@protolabsai/`* package(s)
instead of '../src/*'; update the import statements that reference
migrateModelId and the three map constants so the test consumes the shared
public API (e.g., import { migrateModelId } from '`@protolabsai/`<pkg>' and import
{ CLAUDE_CANONICAL_MAP, CLAUDE_MODEL_MAP, LEGACY_CLAUDE_FULL_MODEL_MAP } from
'`@protolabsai/`<pkg>') to align with the package contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libs/types/src/model-migration.ts`:
- Around line 79-98: The map lookups in migrateModelId and isLegacyClaudeAlias
use the `in` operator (e.g. `legacyId in LEGACY_CLAUDE_FULL_MODEL_MAP`,
`legacyId in CLAUDE_CANONICAL_MAP`, and `id in LEGACY_CLAUDE_ALIAS_MAP`) which
can match prototype keys like "__proto__"; change them to own-property checks
using either `Object.prototype.hasOwnProperty.call(OBJ, key)` or
`Object.hasOwn(OBJ, key)` so only actual map keys are matched, and ensure the
code paths in migrateModelId and isLegacyClaudeAlias then use the returned
string values directly (no prototype values).

---

Nitpick comments:
In `@libs/types/tests/model-migration-gateway.test.ts`:
- Around line 10-15: Replace the relative imports in the test with the public
package namespace: import migrateModelId, CLAUDE_CANONICAL_MAP,
CLAUDE_MODEL_MAP, and LEGACY_CLAUDE_FULL_MODEL_MAP from the appropriate
`@protolabsai/`* package(s) instead of '../src/*'; update the import statements
that reference migrateModelId and the three map constants so the test consumes
the shared public API (e.g., import { migrateModelId } from '`@protolabsai/`<pkg>'
and import { CLAUDE_CANONICAL_MAP, CLAUDE_MODEL_MAP,
LEGACY_CLAUDE_FULL_MODEL_MAP } from '`@protolabsai/`<pkg>') to align with the
package contract.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a12f932a-a988-459d-9eb4-53f5d950a993

📥 Commits

Reviewing files that changed from the base of the PR and between 485df2f and 6d79830.

📒 Files selected for processing (10)
  • apps/server/tests/unit/lib/model-resolver.test.ts
  • apps/server/tests/unit/lib/sdk-options.test.ts
  • apps/server/tests/unit/services/execution-service.test.ts
  • apps/server/tests/unit/services/settings-service.test.ts
  • libs/model-resolver/tests/resolver.test.ts
  • libs/types/src/global-settings.ts
  • libs/types/src/index.ts
  • libs/types/src/model-migration.ts
  • libs/types/src/model.ts
  • libs/types/tests/model-migration-gateway.test.ts

Comment on lines +79 to 98
// Full versioned Claude model strings from before the gateway cutover
// (e.g. 'claude-sonnet-4-6'). Rewrite to the gateway tier so the
// gateway-only API key accepts them.
if (legacyId in LEGACY_CLAUDE_FULL_MODEL_MAP) {
return LEGACY_CLAUDE_FULL_MODEL_MAP[legacyId];
}

// Already has claude- prefix and is in canonical map. CLAUDE_CANONICAL_MAP
// now points at gateway tiers — return the mapped tier, not the prefixed
// alias, so any callsite that stored a stale canonical ID gets the right
// resolution on the next load.
if (legacyId.startsWith('claude-') && legacyId in CLAUDE_CANONICAL_MAP) {
return legacyId;
return CLAUDE_CANONICAL_MAP[legacyId as keyof typeof CLAUDE_CANONICAL_MAP];
}

// Legacy Claude alias (short name)
// Legacy Claude alias (short name) — map directly to the gateway tier.
if (isLegacyClaudeAlias(legacyId)) {
return LEGACY_CLAUDE_ALIAS_MAP[legacyId];
const canonical = LEGACY_CLAUDE_ALIAS_MAP[legacyId];
return CLAUDE_CANONICAL_MAP[canonical];
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate migrateModelId and the relevant lines
echo "==> model-migration.ts: migrateModelId section"
FILE="libs/types/src/model-migration.ts"
test -f "$FILE"
rg -n "function migrateModelId|migrateModelId" "$FILE" || true
# Print surrounding lines near the in-operators mentioned
rg -n "in LEGACY_CLAUDE_FULL_MODEL_MAP|in CLAUDE_CANONICAL_MAP|LEGACY_CLAUDE_ALIAS_MAP" "$FILE" || true
# Show ~120 lines around first match
LINE1=$(rg -n "in LEGACY_CLAUDE_FULL_MODEL_MAP" "$FILE" | head -n1 | cut -d: -f1 || true)
if [ -n "${LINE1:-}" ]; then
  START=$((LINE1-15)); END=$((LINE1+25))
  sed -n "${START},${END}p" "$FILE" | nl -ba -w2 -s: | head -n 120
fi

echo
echo "==> model.ts: map declarations"
MODEL_FILE="libs/types/src/model.ts"
test -f "$MODEL_FILE"
rg -n "LEGACY_CLAUDE_FULL_MODEL_MAP|CLAUDE_CANONICAL_MAP|LEGACY_CLAUDE_ALIAS_MAP" "$MODEL_FILE" || true

for sym in LEGACY_CLAUDE_FULL_MODEL_MAP CLAUDE_CANONICAL_MAP LEGACY_CLAUDE_ALIAS_MAP; do
  L=$(rg -n "${sym}" "$MODEL_FILE" | head -n1 | cut -d: -f1 || true)
  if [ -n "${L:-}" ]; then
    START=$((L-10)); END=$((L+40))
    echo "-- ${sym} excerpt"
    sed -n "${START},${END}p" "$MODEL_FILE" | nl -ba -w2 -s: | head -n 120
  fi
done

echo
echo "==> model-migration.ts: helper isLegacyClaudeAlias"
rg -n "isLegacyClaudeAlias" "$FILE" || true
L2=$(rg -n "isLegacyClaudeAlias" "$FILE" | head -n1 | cut -d: -f1 || true)
if [ -n "${L2:-}" ]; then
  START=$((L2-10)); END=$((L2+40))
  sed -n "${START},${END}p" "$FILE" | nl -ba -w2 -s: | head -n 120
fi

Repository: protoLabsAI/protoMaker

Length of output: 614


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE_MIG="libs/types/src/model-migration.ts"
FILE_MODEL="libs/types/src/model.ts"

echo "==> model-migration.ts: helper isLegacyClaudeAlias (context)"
L2=$(rg -n "function isLegacyClaudeAlias" "$FILE_MIG" | head -n1 | cut -d: -f1 || true)
if [ -n "${L2:-}" ]; then
  START=$((L2-20)); END=$((L2+40))
  sed -n "${START},${END}p" "$FILE_MIG"
fi

echo
echo "==> model-migration.ts: migrateModelId block (context around in-operators)"
for pat in "in LEGACY_CLAUDE_FULL_MODEL_MAP" "in CLAUDE_CANONICAL_MAP" "LEGACY_CLAUDE_ALIAS_MAP\\[legacyId\\]"; do
  L=$(rg -n "$pat" "$FILE_MIG" | head -n1 | cut -d: -f1 || true)
  if [ -n "${L:-}" ]; then
    START=$((L-15)); END=$((L+25))
    echo "--- match: $pat at line $L ---"
    sed -n "${START},${END}p" "$FILE_MIG"
  fi
done

echo
echo "==> model.ts: map declarations (context)"
for sym in "LEGACY_CLAUDE_FULL_MODEL_MAP" "CLAUDE_CANONICAL_MAP" "LEGACY_CLAUDE_ALIAS_MAP"; do
  L=$(rg -n "export const $sym" "$FILE_MODEL" | head -n1 | cut -d: -f1 || true)
  if [ -n "${L:-}" ]; then
    START=$((L-15)); END=$((L+60))
    echo "--- $sym at line $L ---"
    sed -n "${START},${END}p" "$FILE_MODEL"
  fi
done

Repository: protoLabsAI/protoMaker

Length of output: 15144


Use own-property checks for Claude model map lookups.

legacyId in LEGACY_CLAUDE_FULL_MODEL_MAP (~line 82), legacyId in CLAUDE_CANONICAL_MAP (~line 90), and isLegacyClaudeAlias (id in LEGACY_CLAUDE_ALIAS_MAP, ~line 39) use in on prototype-backed plain objects, so keys like __proto__ can match and cause migrateModelId to return non-string values.

🔧 Suggested fix
-  if (legacyId in LEGACY_CLAUDE_FULL_MODEL_MAP) {
+  if (Object.prototype.hasOwnProperty.call(LEGACY_CLAUDE_FULL_MODEL_MAP, legacyId)) {
     return LEGACY_CLAUDE_FULL_MODEL_MAP[legacyId];
   }
@@
-  if (legacyId.startsWith('claude-') && legacyId in CLAUDE_CANONICAL_MAP) {
+  if (
+    legacyId.startsWith('claude-') &&
+    Object.prototype.hasOwnProperty.call(CLAUDE_CANONICAL_MAP, legacyId)
+  ) {
     return CLAUDE_CANONICAL_MAP[legacyId as keyof typeof CLAUDE_CANONICAL_MAP];
   }
@@
-  if (isLegacyClaudeAlias(legacyId)) {
-    const canonical = LEGACY_CLAUDE_ALIAS_MAP[legacyId];
+  if (Object.prototype.hasOwnProperty.call(LEGACY_CLAUDE_ALIAS_MAP, legacyId)) {
+    const canonical = LEGACY_CLAUDE_ALIAS_MAP[
+      legacyId as keyof typeof LEGACY_CLAUDE_ALIAS_MAP
+    ];
     return CLAUDE_CANONICAL_MAP[canonical];
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/types/src/model-migration.ts` around lines 79 - 98, The map lookups in
migrateModelId and isLegacyClaudeAlias use the `in` operator (e.g. `legacyId in
LEGACY_CLAUDE_FULL_MODEL_MAP`, `legacyId in CLAUDE_CANONICAL_MAP`, and `id in
LEGACY_CLAUDE_ALIAS_MAP`) which can match prototype keys like "__proto__";
change them to own-property checks using either
`Object.prototype.hasOwnProperty.call(OBJ, key)` or `Object.hasOwn(OBJ, key)` so
only actual map keys are matched, and ensure the code paths in migrateModelId
and isLegacyClaudeAlias then use the returned string values directly (no
prototype values).

This was referenced May 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(settings): legacy claude-sonnet/claude-haiku aliases in data/settings.json bypass DEFAULT_PHASE_MODELS and fail gateway with 401

1 participant