Browse Source

fix: installer model provider detection

Alvin Unreal 1 month ago
parent
commit
02172d9b0b
2 changed files with 49 additions and 11 deletions
  1. 25 0
      src/cli/config-io.test.ts
  2. 24 11
      src/cli/config-io.ts

+ 25 - 0
src/cli/config-io.test.ts

@@ -580,6 +580,31 @@ describe('config-io', () => {
     expect(detected.hasTmux).toBe(true);
     expect(detected.hasTmux).toBe(true);
   });
   });
 
 
+  test('detectCurrentConfig detects provider models in arrays', () => {
+    const configPath = join(tmpDir, 'opencode', 'opencode.json');
+    const litePath = join(tmpDir, 'opencode', 'oh-my-opencode-slim.json');
+    paths.ensureConfigDir();
+
+    writeFileSync(configPath, JSON.stringify({ plugin: ['oh-my-opencode-slim'] }));
+    writeFileSync(
+      litePath,
+      JSON.stringify({
+        preset: 'dev',
+        presets: {
+          dev: {
+            orchestrator: {
+              model: ['openai/gpt-5.4-mini', { id: 'anthropic/claude-opus-4-6' }],
+            },
+          },
+        },
+      }),
+    );
+
+    const detected = detectCurrentConfig();
+    expect(detected.hasOpenAI).toBe(true);
+    expect(detected.hasAnthropic).toBe(true);
+  });
+
   test('detectCurrentConfig treats local repo path entries as installed', () => {
   test('detectCurrentConfig treats local repo path entries as installed', () => {
     const configPath = join(tmpDir, 'opencode', 'opencode.json');
     const configPath = join(tmpDir, 'opencode', 'opencode.json');
     const packageRoot = join(tmpDir, 'repo');
     const packageRoot = join(tmpDir, 'repo');

+ 24 - 11
src/cli/config-io.ts

@@ -34,6 +34,19 @@ function isString(value: unknown): value is string {
   return typeof value === 'string';
   return typeof value === 'string';
 }
 }
 
 
+function getModelIds(model: unknown): string[] {
+  if (isString(model)) return [model];
+  if (!Array.isArray(model)) return [];
+
+  return model.flatMap((entry) => {
+    if (isString(entry)) return [entry];
+    if (entry && typeof entry === 'object' && isString(entry.id)) {
+      return [entry.id];
+    }
+    return [];
+  });
+}
+
 function getPlugins(config: OpenCodeConfig): unknown[] {
 function getPlugins(config: OpenCodeConfig): unknown[] {
   return Array.isArray(config.plugin) ? config.plugin : [];
   return Array.isArray(config.plugin) ? config.plugin : [];
 }
 }
@@ -669,22 +682,22 @@ export function detectCurrentConfig(): DetectedConfig {
     const presetName = configObj.preset as string;
     const presetName = configObj.preset as string;
     const presets = configObj.presets as Record<string, unknown>;
     const presets = configObj.presets as Record<string, unknown>;
     const agents = presets?.[presetName] as
     const agents = presets?.[presetName] as
-      | Record<string, { model?: string }>
+      | Record<string, { model?: unknown }>
       | undefined;
       | undefined;
 
 
-    if (agents) {
+    if (agents && typeof agents === 'object') {
       const models = Object.values(agents)
       const models = Object.values(agents)
-        .map((a) => a?.model)
-        .filter(Boolean);
-      result.hasOpenAI = models.some((m) => m?.startsWith('openai/'));
-      result.hasAnthropic = models.some((m) => m?.startsWith('anthropic/'));
-      result.hasCopilot = models.some((m) => m?.startsWith('github-copilot/'));
-      result.hasZaiPlan = models.some((m) => m?.startsWith('zai-coding-plan/'));
-      result.hasOpencodeZen = models.some((m) => m?.startsWith('opencode/'));
-      if (models.some((m) => m?.startsWith('google/'))) {
+        .filter((a) => a && typeof a === 'object')
+        .flatMap((a) => getModelIds(a.model));
+      result.hasOpenAI ||= models.some((m) => m.startsWith('openai/'));
+      result.hasAnthropic ||= models.some((m) => m.startsWith('anthropic/'));
+      result.hasCopilot ||= models.some((m) => m.startsWith('github-copilot/'));
+      result.hasZaiPlan ||= models.some((m) => m.startsWith('zai-coding-plan/'));
+      result.hasOpencodeZen ||= models.some((m) => m.startsWith('opencode/'));
+      if (models.some((m) => m.startsWith('google/'))) {
         result.hasAntigravity = true;
         result.hasAntigravity = true;
       }
       }
-      if (models.some((m) => m?.startsWith('chutes/'))) {
+      if (models.some((m) => m.startsWith('chutes/'))) {
         result.hasChutes = true;
         result.hasChutes = true;
       }
       }
     }
     }