Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/__tests__/unit/mimo-model-mapping.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ describe('MiMo resolver honors a user-set model (no silent revert) — #577A', (

// ── Wiring source pins (connect dialog pre-fill) ─────────────────────────────

describe('connect dialog pre-fills the model field from the preset default (#577A)', () => {
describe('connect dialog pre-fills exposed model fields from the preset default (#577A)', () => {
const presetsSrc = fs.readFileSync(
path.resolve(__dirname, '../../components/settings/provider-presets.tsx'),
'utf8',
Expand All @@ -144,11 +144,11 @@ describe('connect dialog pre-fills the model field from the preset default (#577
);
});

it('create mode pre-fills modelName from preset.defaultModelId (not empty)', () => {
it('create mode pre-fills modelName only when the preset exposes model_names', () => {
assert.match(
dialogSrc,
/setModelName\(preset\.defaultModelId \|\| ""\)/,
'create mode must pre-fill the model field from the preset default',
/setModelName\(\s*preset\.fields\.includes\("model_names"\)\s*\?\s*\(preset\.defaultModelId \|\| ""\)\s*:\s*""\s*,?\s*\)/,
'create mode must pre-fill the model field from the preset default without seeding a hidden default for mapping-only presets',
);
});
});
Expand Down
49 changes: 49 additions & 0 deletions src/__tests__/unit/provider-connection-test-model.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';
import { resolveConnectionTestModelName } from '../../lib/provider-connection-test-model';

describe('resolveConnectionTestModelName', () => {
it('uses the mapped Sonnet model when no default model is configured', () => {
assert.equal(
resolveConnectionTestModelName('', 'claude-sonnet-4-6'),
'claude-sonnet-4-6',
);
});

it('prefers an explicitly configured default model over the Sonnet mapping', () => {
assert.equal(
resolveConnectionTestModelName('custom-default-model', 'claude-sonnet-4-6'),
'custom-default-model',
);
});

it('leaves model selection to the existing connection-test fallback when both fields are empty', () => {
assert.equal(resolveConnectionTestModelName('', ''), undefined);
});

it('uses the resolver when building the connection-test payload', () => {
const dialogSource = fs.readFileSync(
path.resolve(process.cwd(), 'src/components/settings/PresetConnectDialog.tsx'),
'utf8',
);

assert.match(
dialogSource,
/modelName:\s*resolveConnectionTestModelName\(modelName,\s*mapSonnet\)/,
);
});

it('does not seed a hidden default model for mapping-only presets', () => {
const dialogSource = fs.readFileSync(
path.resolve(process.cwd(), 'src/components/settings/PresetConnectDialog.tsx'),
'utf8',
);

assert.match(
dialogSource,
/setModelName\(\s*preset\.fields\.includes\("model_names"\)\s*\?\s*\(preset\.defaultModelId \|\| ""\)\s*:\s*""\s*,?\s*\)/,
);
});
});
17 changes: 10 additions & 7 deletions src/components/settings/PresetConnectDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { QUICK_PRESETS } from "./provider-presets";
import type { ApiProvider } from "@/types";
import { useTranslation } from "@/hooks/useTranslation";
import type { TranslationKey } from "@/i18n";
import { resolveConnectionTestModelName } from "@/lib/provider-connection-test-model";

/** Infer auth style from base URL by fuzzy-matching preset hostnames */
function inferAuthStyleFromUrl(url: string): "api_key" | "auth_token" | null {
Expand Down Expand Up @@ -156,7 +157,7 @@ export function PresetConnectDialog({
protocol: preset?.protocol || 'anthropic',
authStyle: preset?.key === 'anthropic-thirdparty' ? authStyle : (preset?.authStyle || authStyle),
envOverrides,
modelName: modelName || undefined,
modelName: resolveConnectionTestModelName(modelName, mapSonnet),
providerName: name || preset?.name,
};
if (isEdit && editProvider) {
Expand Down Expand Up @@ -272,12 +273,14 @@ export function PresetConnectDialog({
setBaseUrl(preset.base_url);
setName(preset.name);
setExtraEnv(preset.extra_env);
// Pre-fill the model-name field with the preset's default model id so a
// preset that requires a user-specified model (e.g. MiMo) shows its
// current model (editable) rather than an empty box (#577). Harmless for
// presets without the model_names field — the value is only read on save
// when that field is exposed.
setModelName(preset.defaultModelId || "");
// Pre-fill only an exposed model-name field with the preset default so a
// provider such as MiMo shows its editable current model (#577).
// Mapping-only presets must keep this empty: otherwise their hidden
// catalog alias (for example, "sonnet") overrides a Sonnet mapping in
// the connection-test payload.
setModelName(
preset.fields.includes("model_names") ? (preset.defaultModelId || "") : "",
);
// Use authStyle directly from preset (single source of truth)
const detectedStyle = (preset.authStyle === 'auth_token' ? 'auth_token' : 'api_key') as 'api_key' | 'auth_token';
// If preset doesn't expose api_key field, pre-fill from extra_env default
Expand Down
6 changes: 6 additions & 0 deletions src/lib/provider-connection-test-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export function resolveConnectionTestModelName(
defaultModelName: string,
mappedSonnetModelName: string,
): string | undefined {
return defaultModelName || mappedSonnetModelName || undefined;
}
Loading