feat(cli): redesign model fallback with native cross-fallback and OpenAI separation
- Add OpenAI/ChatGPT as separate subscription option (--openai flag) - Implement native tier cross-fallback (Claude → OpenAI → Gemini) - Change fallback order: Native → OpenCode Zen → GitHub Copilot → Z.ai - Add explore agent special logic: max20 → haiku, else → grok-code - Add critical warning when Claude is not configured - Add tests for ChatGPT-only and explore agent cases
This commit is contained in:
@@ -41,19 +41,23 @@ Ask the user these questions to determine CLI options:
|
|||||||
- **not max20** → `--claude=yes`
|
- **not max20** → `--claude=yes`
|
||||||
- If **no** → `--claude=no`
|
- If **no** → `--claude=no`
|
||||||
|
|
||||||
2. **Will you integrate Gemini models?**
|
2. **Do you have an OpenAI/ChatGPT Plus Subscription?**
|
||||||
|
- If **yes** → `--openai=yes` (GPT-5.2 for Oracle agent)
|
||||||
|
- If **no** → `--openai=no` (default)
|
||||||
|
|
||||||
|
3. **Will you integrate Gemini models?**
|
||||||
- If **yes** → `--gemini=yes`
|
- If **yes** → `--gemini=yes`
|
||||||
- If **no** → `--gemini=no`
|
- If **no** → `--gemini=no`
|
||||||
|
|
||||||
3. **Do you have a GitHub Copilot Subscription?**
|
4. **Do you have a GitHub Copilot Subscription?**
|
||||||
- If **yes** → `--copilot=yes`
|
- If **yes** → `--copilot=yes`
|
||||||
- If **no** → `--copilot=no`
|
- If **no** → `--copilot=no`
|
||||||
|
|
||||||
4. **Do you have access to OpenCode Zen (opencode/ models)?**
|
5. **Do you have access to OpenCode Zen (opencode/ models)?**
|
||||||
- If **yes** → `--opencode-zen=yes`
|
- If **yes** → `--opencode-zen=yes`
|
||||||
- If **no** → `--opencode-zen=no` (default)
|
- If **no** → `--opencode-zen=no` (default)
|
||||||
|
|
||||||
5. **Do you have a Z.ai Coding Plan subscription?**
|
6. **Do you have a Z.ai Coding Plan subscription?**
|
||||||
- If **yes** → `--zai-coding-plan=yes`
|
- If **yes** → `--zai-coding-plan=yes`
|
||||||
- If **no** → `--zai-coding-plan=no` (default)
|
- If **no** → `--zai-coding-plan=no` (default)
|
||||||
|
|
||||||
@@ -80,12 +84,13 @@ Spawn a subagent to handle installation and report back - to save context.
|
|||||||
Based on user's answers, run the CLI installer with appropriate flags:
|
Based on user's answers, run the CLI installer with appropriate flags:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bunx oh-my-opencode install --no-tui --claude=<yes|no|max20> --gemini=<yes|no> --copilot=<yes|no> [--opencode-zen=<yes|no>] [--zai-coding-plan=<yes|no>]
|
bunx oh-my-opencode install --no-tui --claude=<yes|no|max20> --gemini=<yes|no> --copilot=<yes|no> [--openai=<yes|no>] [--opencode-zen=<yes|no>] [--zai-coding-plan=<yes|no>]
|
||||||
```
|
```
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
- User has all native subscriptions: `bunx oh-my-opencode install --no-tui --claude=max20 --gemini=yes --copilot=no`
|
- User has all native subscriptions: `bunx oh-my-opencode install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no`
|
||||||
- User has only Claude: `bunx oh-my-opencode install --no-tui --claude=yes --gemini=no --copilot=no`
|
- User has only Claude: `bunx oh-my-opencode install --no-tui --claude=yes --gemini=no --copilot=no`
|
||||||
|
- User has Claude + OpenAI: `bunx oh-my-opencode install --no-tui --claude=yes --openai=yes --gemini=no --copilot=no`
|
||||||
- User has only GitHub Copilot: `bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=yes`
|
- User has only GitHub Copilot: `bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=yes`
|
||||||
- User has Z.ai for Librarian: `bunx oh-my-opencode install --no-tui --claude=yes --gemini=no --copilot=no --zai-coding-plan=yes`
|
- User has Z.ai for Librarian: `bunx oh-my-opencode install --no-tui --claude=yes --gemini=no --copilot=no --zai-coding-plan=yes`
|
||||||
- User has only OpenCode Zen: `bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=no --opencode-zen=yes`
|
- User has only OpenCode Zen: `bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=no --opencode-zen=yes`
|
||||||
|
|||||||
@@ -201,11 +201,12 @@ describe("config-manager ANTIGRAVITY_PROVIDER_CONFIG", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("generateOmoConfig - model fallback system", () => {
|
describe("generateOmoConfig - model fallback system", () => {
|
||||||
test("generates native models when Claude available", () => {
|
test("generates native sonnet models when Claude standard subscription", () => {
|
||||||
// #given user has Claude subscription
|
// #given user has Claude standard subscription (not max20)
|
||||||
const config: InstallConfig = {
|
const config: InstallConfig = {
|
||||||
hasClaude: true,
|
hasClaude: true,
|
||||||
isMax20: false,
|
isMax20: false,
|
||||||
|
hasOpenAI: false,
|
||||||
hasGemini: false,
|
hasGemini: false,
|
||||||
hasCopilot: false,
|
hasCopilot: false,
|
||||||
hasOpencodeZen: false,
|
hasOpencodeZen: false,
|
||||||
@@ -215,17 +216,37 @@ describe("generateOmoConfig - model fallback system", () => {
|
|||||||
// #when generating config
|
// #when generating config
|
||||||
const result = generateOmoConfig(config)
|
const result = generateOmoConfig(config)
|
||||||
|
|
||||||
// #then should use native anthropic models
|
// #then should use native anthropic sonnet (cost-efficient for standard plan)
|
||||||
expect(result.$schema).toBe("https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json")
|
expect(result.$schema).toBe("https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json")
|
||||||
expect(result.agents).toBeDefined()
|
expect(result.agents).toBeDefined()
|
||||||
|
expect((result.agents as Record<string, { model: string }>).Sisyphus.model).toBe("anthropic/claude-sonnet-4-5")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("generates native opus models when Claude max20 subscription", () => {
|
||||||
|
// #given user has Claude max20 subscription
|
||||||
|
const config: InstallConfig = {
|
||||||
|
hasClaude: true,
|
||||||
|
isMax20: true,
|
||||||
|
hasOpenAI: false,
|
||||||
|
hasGemini: false,
|
||||||
|
hasCopilot: false,
|
||||||
|
hasOpencodeZen: false,
|
||||||
|
hasZaiCodingPlan: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// #when generating config
|
||||||
|
const result = generateOmoConfig(config)
|
||||||
|
|
||||||
|
// #then should use native anthropic opus (max power for max20 plan)
|
||||||
expect((result.agents as Record<string, { model: string }>).Sisyphus.model).toBe("anthropic/claude-opus-4-5")
|
expect((result.agents as Record<string, { model: string }>).Sisyphus.model).toBe("anthropic/claude-opus-4-5")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("uses github-copilot fallback when only copilot available", () => {
|
test("uses github-copilot sonnet fallback when only copilot available", () => {
|
||||||
// #given user has only copilot
|
// #given user has only copilot (no max plan)
|
||||||
const config: InstallConfig = {
|
const config: InstallConfig = {
|
||||||
hasClaude: false,
|
hasClaude: false,
|
||||||
isMax20: false,
|
isMax20: false,
|
||||||
|
hasOpenAI: false,
|
||||||
hasGemini: false,
|
hasGemini: false,
|
||||||
hasCopilot: true,
|
hasCopilot: true,
|
||||||
hasOpencodeZen: false,
|
hasOpencodeZen: false,
|
||||||
@@ -235,8 +256,8 @@ describe("generateOmoConfig - model fallback system", () => {
|
|||||||
// #when generating config
|
// #when generating config
|
||||||
const result = generateOmoConfig(config)
|
const result = generateOmoConfig(config)
|
||||||
|
|
||||||
// #then should use github-copilot models
|
// #then should use github-copilot sonnet models
|
||||||
expect((result.agents as Record<string, { model: string }>).Sisyphus.model).toBe("github-copilot/claude-opus-4.5")
|
expect((result.agents as Record<string, { model: string }>).Sisyphus.model).toBe("github-copilot/claude-sonnet-4.5")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("uses ultimate fallback when no providers configured", () => {
|
test("uses ultimate fallback when no providers configured", () => {
|
||||||
@@ -244,6 +265,7 @@ describe("generateOmoConfig - model fallback system", () => {
|
|||||||
const config: InstallConfig = {
|
const config: InstallConfig = {
|
||||||
hasClaude: false,
|
hasClaude: false,
|
||||||
isMax20: false,
|
isMax20: false,
|
||||||
|
hasOpenAI: false,
|
||||||
hasGemini: false,
|
hasGemini: false,
|
||||||
hasCopilot: false,
|
hasCopilot: false,
|
||||||
hasOpencodeZen: false,
|
hasOpencodeZen: false,
|
||||||
@@ -259,10 +281,11 @@ describe("generateOmoConfig - model fallback system", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test("uses zai-coding-plan/glm-4.7 for librarian when Z.ai available", () => {
|
test("uses zai-coding-plan/glm-4.7 for librarian when Z.ai available", () => {
|
||||||
// #given user has Z.ai and Claude
|
// #given user has Z.ai and Claude max20
|
||||||
const config: InstallConfig = {
|
const config: InstallConfig = {
|
||||||
hasClaude: true,
|
hasClaude: true,
|
||||||
isMax20: false,
|
isMax20: true,
|
||||||
|
hasOpenAI: false,
|
||||||
hasGemini: false,
|
hasGemini: false,
|
||||||
hasCopilot: false,
|
hasCopilot: false,
|
||||||
hasOpencodeZen: false,
|
hasOpencodeZen: false,
|
||||||
@@ -274,7 +297,68 @@ describe("generateOmoConfig - model fallback system", () => {
|
|||||||
|
|
||||||
// #then librarian should use zai-coding-plan/glm-4.7
|
// #then librarian should use zai-coding-plan/glm-4.7
|
||||||
expect((result.agents as Record<string, { model: string }>).librarian.model).toBe("zai-coding-plan/glm-4.7")
|
expect((result.agents as Record<string, { model: string }>).librarian.model).toBe("zai-coding-plan/glm-4.7")
|
||||||
// #then other agents should use native
|
// #then other agents should use native opus (max20 plan)
|
||||||
expect((result.agents as Record<string, { model: string }>).Sisyphus.model).toBe("anthropic/claude-opus-4-5")
|
expect((result.agents as Record<string, { model: string }>).Sisyphus.model).toBe("anthropic/claude-opus-4-5")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("uses native OpenAI models when only ChatGPT available", () => {
|
||||||
|
// #given user has only ChatGPT subscription
|
||||||
|
const config: InstallConfig = {
|
||||||
|
hasClaude: false,
|
||||||
|
isMax20: false,
|
||||||
|
hasOpenAI: true,
|
||||||
|
hasGemini: false,
|
||||||
|
hasCopilot: false,
|
||||||
|
hasOpencodeZen: false,
|
||||||
|
hasZaiCodingPlan: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// #when generating config
|
||||||
|
const result = generateOmoConfig(config)
|
||||||
|
|
||||||
|
// #then Sisyphus should use native OpenAI (fallback within native tier)
|
||||||
|
expect((result.agents as Record<string, { model: string }>).Sisyphus.model).toBe("openai/gpt-5.2")
|
||||||
|
// #then Oracle should use native OpenAI (primary for ultrabrain)
|
||||||
|
expect((result.agents as Record<string, { model: string }>).oracle.model).toBe("openai/gpt-5.2-codex")
|
||||||
|
// #then multimodal-looker should use native OpenAI (fallback within native tier)
|
||||||
|
expect((result.agents as Record<string, { model: string }>)["multimodal-looker"].model).toBe("openai/gpt-5.2")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("uses haiku for explore when Claude max20", () => {
|
||||||
|
// #given user has Claude max20
|
||||||
|
const config: InstallConfig = {
|
||||||
|
hasClaude: true,
|
||||||
|
isMax20: true,
|
||||||
|
hasOpenAI: false,
|
||||||
|
hasGemini: false,
|
||||||
|
hasCopilot: false,
|
||||||
|
hasOpencodeZen: false,
|
||||||
|
hasZaiCodingPlan: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// #when generating config
|
||||||
|
const result = generateOmoConfig(config)
|
||||||
|
|
||||||
|
// #then explore should use haiku (max20 plan uses Claude quota)
|
||||||
|
expect((result.agents as Record<string, { model: string }>).explore.model).toBe("anthropic/claude-haiku-4-5")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("uses grok-code for explore when not max20", () => {
|
||||||
|
// #given user has Claude but not max20
|
||||||
|
const config: InstallConfig = {
|
||||||
|
hasClaude: true,
|
||||||
|
isMax20: false,
|
||||||
|
hasOpenAI: false,
|
||||||
|
hasGemini: false,
|
||||||
|
hasCopilot: false,
|
||||||
|
hasOpencodeZen: false,
|
||||||
|
hasZaiCodingPlan: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// #when generating config
|
||||||
|
const result = generateOmoConfig(config)
|
||||||
|
|
||||||
|
// #then explore should use grok-code (preserve Claude quota)
|
||||||
|
expect((result.agents as Record<string, { model: string }>).explore.model).toBe("opencode/grok-code")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -575,11 +575,36 @@ export function addProviderConfig(config: InstallConfig): ConfigMergeResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function detectProvidersFromOmoConfig(): { hasOpenAI: boolean; hasOpencodeZen: boolean; hasZaiCodingPlan: boolean } {
|
||||||
|
const omoConfigPath = getOmoConfig()
|
||||||
|
if (!existsSync(omoConfigPath)) {
|
||||||
|
return { hasOpenAI: true, hasOpencodeZen: true, hasZaiCodingPlan: false }
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const content = readFileSync(omoConfigPath, "utf-8")
|
||||||
|
const omoConfig = parseJsonc<Record<string, unknown>>(content)
|
||||||
|
if (!omoConfig || typeof omoConfig !== "object") {
|
||||||
|
return { hasOpenAI: true, hasOpencodeZen: true, hasZaiCodingPlan: false }
|
||||||
|
}
|
||||||
|
|
||||||
|
const configStr = JSON.stringify(omoConfig)
|
||||||
|
const hasOpenAI = configStr.includes('"openai/')
|
||||||
|
const hasOpencodeZen = configStr.includes('"opencode/')
|
||||||
|
const hasZaiCodingPlan = configStr.includes('"zai-coding-plan/')
|
||||||
|
|
||||||
|
return { hasOpenAI, hasOpencodeZen, hasZaiCodingPlan }
|
||||||
|
} catch {
|
||||||
|
return { hasOpenAI: true, hasOpencodeZen: true, hasZaiCodingPlan: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function detectCurrentConfig(): DetectedConfig {
|
export function detectCurrentConfig(): DetectedConfig {
|
||||||
const result: DetectedConfig = {
|
const result: DetectedConfig = {
|
||||||
isInstalled: false,
|
isInstalled: false,
|
||||||
hasClaude: true,
|
hasClaude: true,
|
||||||
isMax20: true,
|
isMax20: true,
|
||||||
|
hasOpenAI: true,
|
||||||
hasGemini: false,
|
hasGemini: false,
|
||||||
hasCopilot: false,
|
hasCopilot: false,
|
||||||
hasOpencodeZen: true,
|
hasOpencodeZen: true,
|
||||||
@@ -607,5 +632,10 @@ export function detectCurrentConfig(): DetectedConfig {
|
|||||||
// Gemini auth plugin detection still works via plugin presence
|
// Gemini auth plugin detection still works via plugin presence
|
||||||
result.hasGemini = plugins.some((p) => p.startsWith("opencode-antigravity-auth"))
|
result.hasGemini = plugins.some((p) => p.startsWith("opencode-antigravity-auth"))
|
||||||
|
|
||||||
|
const { hasOpenAI, hasOpencodeZen, hasZaiCodingPlan } = detectProvidersFromOmoConfig()
|
||||||
|
result.hasOpenAI = hasOpenAI
|
||||||
|
result.hasOpencodeZen = hasOpencodeZen
|
||||||
|
result.hasZaiCodingPlan = hasZaiCodingPlan
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ program
|
|||||||
.description("Install and configure oh-my-opencode with interactive setup")
|
.description("Install and configure oh-my-opencode with interactive setup")
|
||||||
.option("--no-tui", "Run in non-interactive mode (requires all options)")
|
.option("--no-tui", "Run in non-interactive mode (requires all options)")
|
||||||
.option("--claude <value>", "Claude subscription: no, yes, max20")
|
.option("--claude <value>", "Claude subscription: no, yes, max20")
|
||||||
|
.option("--openai <value>", "OpenAI/ChatGPT subscription: no, yes (default: no)")
|
||||||
.option("--gemini <value>", "Gemini integration: no, yes")
|
.option("--gemini <value>", "Gemini integration: no, yes")
|
||||||
.option("--copilot <value>", "GitHub Copilot subscription: no, yes")
|
.option("--copilot <value>", "GitHub Copilot subscription: no, yes")
|
||||||
.option("--opencode-zen <value>", "OpenCode Zen access: no, yes (default: no)")
|
.option("--opencode-zen <value>", "OpenCode Zen access: no, yes (default: no)")
|
||||||
@@ -32,11 +33,12 @@ program
|
|||||||
.addHelpText("after", `
|
.addHelpText("after", `
|
||||||
Examples:
|
Examples:
|
||||||
$ bunx oh-my-opencode install
|
$ bunx oh-my-opencode install
|
||||||
$ bunx oh-my-opencode install --no-tui --claude=max20 --gemini=yes --copilot=no
|
$ bunx oh-my-opencode install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no
|
||||||
$ bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=yes --opencode-zen=yes
|
$ bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=yes --opencode-zen=yes
|
||||||
|
|
||||||
Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai):
|
Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai):
|
||||||
Claude Native anthropic/ models (Opus, Sonnet, Haiku)
|
Claude Native anthropic/ models (Opus, Sonnet, Haiku)
|
||||||
|
OpenAI Native openai/ models (GPT-5.2 for Oracle)
|
||||||
Gemini Native google/ models (Gemini 3 Pro, Flash)
|
Gemini Native google/ models (Gemini 3 Pro, Flash)
|
||||||
Copilot github-copilot/ models (fallback)
|
Copilot github-copilot/ models (fallback)
|
||||||
OpenCode Zen opencode/ models (opencode/claude-opus-4-5, etc.)
|
OpenCode Zen opencode/ models (opencode/claude-opus-4-5, etc.)
|
||||||
@@ -46,6 +48,7 @@ Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai):
|
|||||||
const args: InstallArgs = {
|
const args: InstallArgs = {
|
||||||
tui: options.tui !== false,
|
tui: options.tui !== false,
|
||||||
claude: options.claude,
|
claude: options.claude,
|
||||||
|
openai: options.openai,
|
||||||
gemini: options.gemini,
|
gemini: options.gemini,
|
||||||
copilot: options.copilot,
|
copilot: options.copilot,
|
||||||
opencodeZen: options.opencodeZen,
|
opencodeZen: options.opencodeZen,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
addProviderConfig,
|
addProviderConfig,
|
||||||
detectCurrentConfig,
|
detectCurrentConfig,
|
||||||
} from "./config-manager"
|
} from "./config-manager"
|
||||||
|
import { shouldShowChatGPTOnlyWarning } from "./model-fallback"
|
||||||
import packageJson from "../../package.json" with { type: "json" }
|
import packageJson from "../../package.json" with { type: "json" }
|
||||||
|
|
||||||
const VERSION = packageJson.version
|
const VERSION = packageJson.version
|
||||||
@@ -39,6 +40,7 @@ function formatConfigSummary(config: InstallConfig): string {
|
|||||||
|
|
||||||
const claudeDetail = config.hasClaude ? (config.isMax20 ? "max20" : "standard") : undefined
|
const claudeDetail = config.hasClaude ? (config.isMax20 ? "max20" : "standard") : undefined
|
||||||
lines.push(formatProvider("Claude", config.hasClaude, claudeDetail))
|
lines.push(formatProvider("Claude", config.hasClaude, claudeDetail))
|
||||||
|
lines.push(formatProvider("OpenAI/ChatGPT", config.hasOpenAI, "GPT-5.2 for Oracle"))
|
||||||
lines.push(formatProvider("Gemini", config.hasGemini))
|
lines.push(formatProvider("Gemini", config.hasGemini))
|
||||||
lines.push(formatProvider("GitHub Copilot", config.hasCopilot, "fallback"))
|
lines.push(formatProvider("GitHub Copilot", config.hasCopilot, "fallback"))
|
||||||
lines.push(formatProvider("OpenCode Zen", config.hasOpencodeZen, "opencode/ models"))
|
lines.push(formatProvider("OpenCode Zen", config.hasOpencodeZen, "opencode/ models"))
|
||||||
@@ -127,6 +129,10 @@ function validateNonTuiArgs(args: InstallArgs): { valid: boolean; errors: string
|
|||||||
errors.push(`Invalid --copilot value: ${args.copilot} (expected: no, yes)`)
|
errors.push(`Invalid --copilot value: ${args.copilot} (expected: no, yes)`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args.openai !== undefined && !["no", "yes"].includes(args.openai)) {
|
||||||
|
errors.push(`Invalid --openai value: ${args.openai} (expected: no, yes)`)
|
||||||
|
}
|
||||||
|
|
||||||
if (args.opencodeZen !== undefined && !["no", "yes"].includes(args.opencodeZen)) {
|
if (args.opencodeZen !== undefined && !["no", "yes"].includes(args.opencodeZen)) {
|
||||||
errors.push(`Invalid --opencode-zen value: ${args.opencodeZen} (expected: no, yes)`)
|
errors.push(`Invalid --opencode-zen value: ${args.opencodeZen} (expected: no, yes)`)
|
||||||
}
|
}
|
||||||
@@ -142,6 +148,7 @@ function argsToConfig(args: InstallArgs): InstallConfig {
|
|||||||
return {
|
return {
|
||||||
hasClaude: args.claude !== "no",
|
hasClaude: args.claude !== "no",
|
||||||
isMax20: args.claude === "max20",
|
isMax20: args.claude === "max20",
|
||||||
|
hasOpenAI: args.openai === "yes",
|
||||||
hasGemini: args.gemini === "yes",
|
hasGemini: args.gemini === "yes",
|
||||||
hasCopilot: args.copilot === "yes",
|
hasCopilot: args.copilot === "yes",
|
||||||
hasOpencodeZen: args.opencodeZen === "yes",
|
hasOpencodeZen: args.opencodeZen === "yes",
|
||||||
@@ -149,7 +156,7 @@ function argsToConfig(args: InstallArgs): InstallConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function detectedToInitialValues(detected: DetectedConfig): { claude: ClaudeSubscription; gemini: BooleanArg; copilot: BooleanArg; opencodeZen: BooleanArg; zaiCodingPlan: BooleanArg } {
|
function detectedToInitialValues(detected: DetectedConfig): { claude: ClaudeSubscription; openai: BooleanArg; gemini: BooleanArg; copilot: BooleanArg; opencodeZen: BooleanArg; zaiCodingPlan: BooleanArg } {
|
||||||
let claude: ClaudeSubscription = "no"
|
let claude: ClaudeSubscription = "no"
|
||||||
if (detected.hasClaude) {
|
if (detected.hasClaude) {
|
||||||
claude = detected.isMax20 ? "max20" : "yes"
|
claude = detected.isMax20 ? "max20" : "yes"
|
||||||
@@ -157,6 +164,7 @@ function detectedToInitialValues(detected: DetectedConfig): { claude: ClaudeSubs
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
claude,
|
claude,
|
||||||
|
openai: detected.hasOpenAI ? "yes" : "no",
|
||||||
gemini: detected.hasGemini ? "yes" : "no",
|
gemini: detected.hasGemini ? "yes" : "no",
|
||||||
copilot: detected.hasCopilot ? "yes" : "no",
|
copilot: detected.hasCopilot ? "yes" : "no",
|
||||||
opencodeZen: detected.hasOpencodeZen ? "yes" : "no",
|
opencodeZen: detected.hasOpencodeZen ? "yes" : "no",
|
||||||
@@ -182,6 +190,20 @@ async function runTuiMode(detected: DetectedConfig): Promise<InstallConfig | nul
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const openai = await p.select({
|
||||||
|
message: "Do you have an OpenAI/ChatGPT Plus subscription?",
|
||||||
|
options: [
|
||||||
|
{ value: "no" as const, label: "No", hint: "Oracle will use fallback models" },
|
||||||
|
{ value: "yes" as const, label: "Yes", hint: "GPT-5.2 for Oracle (high-IQ debugging)" },
|
||||||
|
],
|
||||||
|
initialValue: initial.openai,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (p.isCancel(openai)) {
|
||||||
|
p.cancel("Installation cancelled.")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
const gemini = await p.select({
|
const gemini = await p.select({
|
||||||
message: "Will you integrate Google Gemini?",
|
message: "Will you integrate Google Gemini?",
|
||||||
options: [
|
options: [
|
||||||
@@ -241,6 +263,7 @@ async function runTuiMode(detected: DetectedConfig): Promise<InstallConfig | nul
|
|||||||
return {
|
return {
|
||||||
hasClaude: claude !== "no",
|
hasClaude: claude !== "no",
|
||||||
isMax20: claude === "max20",
|
isMax20: claude === "max20",
|
||||||
|
hasOpenAI: openai === "yes",
|
||||||
hasGemini: gemini === "yes",
|
hasGemini: gemini === "yes",
|
||||||
hasCopilot: copilot === "yes",
|
hasCopilot: copilot === "yes",
|
||||||
hasOpencodeZen: opencodeZen === "yes",
|
hasOpencodeZen: opencodeZen === "yes",
|
||||||
@@ -326,7 +349,21 @@ async function runNonTuiInstall(args: InstallArgs): Promise<number> {
|
|||||||
|
|
||||||
printBox(formatConfigSummary(config), isUpdate ? "Updated Configuration" : "Installation Complete")
|
printBox(formatConfigSummary(config), isUpdate ? "Updated Configuration" : "Installation Complete")
|
||||||
|
|
||||||
if (!config.hasClaude && !config.hasGemini && !config.hasCopilot) {
|
if (!config.hasClaude) {
|
||||||
|
console.log()
|
||||||
|
console.log(color.bgRed(color.white(color.bold(" ⚠️ CRITICAL WARNING "))))
|
||||||
|
console.log()
|
||||||
|
console.log(color.red(color.bold(" Sisyphus agent is STRONGLY optimized for Claude Opus 4.5.")))
|
||||||
|
console.log(color.red(" Without Claude, you may experience significantly degraded performance:"))
|
||||||
|
console.log(color.dim(" • Reduced orchestration quality"))
|
||||||
|
console.log(color.dim(" • Weaker tool selection and delegation"))
|
||||||
|
console.log(color.dim(" • Less reliable task completion"))
|
||||||
|
console.log()
|
||||||
|
console.log(color.yellow(" Consider subscribing to Claude Pro/Max for the best experience."))
|
||||||
|
console.log()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.hasClaude && !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && !config.hasOpencodeZen) {
|
||||||
printWarning("No model providers configured. Using opencode/glm-4.7-free as fallback.")
|
printWarning("No model providers configured. Using opencode/glm-4.7-free as fallback.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,7 +468,21 @@ export async function install(args: InstallArgs): Promise<number> {
|
|||||||
}
|
}
|
||||||
s.stop(`Config written to ${color.cyan(omoResult.configPath)}`)
|
s.stop(`Config written to ${color.cyan(omoResult.configPath)}`)
|
||||||
|
|
||||||
if (!config.hasClaude && !config.hasGemini && !config.hasCopilot) {
|
if (!config.hasClaude) {
|
||||||
|
console.log()
|
||||||
|
console.log(color.bgRed(color.white(color.bold(" ⚠️ CRITICAL WARNING "))))
|
||||||
|
console.log()
|
||||||
|
console.log(color.red(color.bold(" Sisyphus agent is STRONGLY optimized for Claude Opus 4.5.")))
|
||||||
|
console.log(color.red(" Without Claude, you may experience significantly degraded performance:"))
|
||||||
|
console.log(color.dim(" • Reduced orchestration quality"))
|
||||||
|
console.log(color.dim(" • Weaker tool selection and delegation"))
|
||||||
|
console.log(color.dim(" • Less reliable task completion"))
|
||||||
|
console.log()
|
||||||
|
console.log(color.yellow(" Consider subscribing to Claude Pro/Max for the best experience."))
|
||||||
|
console.log()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.hasClaude && !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && !config.hasOpencodeZen) {
|
||||||
p.log.warn("No model providers configured. Using opencode/glm-4.7-free as fallback.")
|
p.log.warn("No model providers configured. Using opencode/glm-4.7-free as fallback.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import type { InstallConfig } from "./types"
|
import type { InstallConfig } from "./types"
|
||||||
|
|
||||||
type ProviderTier = "native" | "github-copilot" | "opencode" | "zai-coding-plan"
|
type NativeProvider = "claude" | "openai" | "gemini"
|
||||||
|
|
||||||
type ModelCapability =
|
type ModelCapability =
|
||||||
| "opus-level"
|
| "unspecified-high"
|
||||||
| "sonnet-level"
|
| "unspecified-low"
|
||||||
| "haiku-level"
|
| "quick"
|
||||||
| "reasoning"
|
| "ultrabrain"
|
||||||
| "codex"
|
| "visual-engineering"
|
||||||
| "visual"
|
| "artistry"
|
||||||
| "fast"
|
| "writing"
|
||||||
| "glm"
|
| "glm"
|
||||||
|
|
||||||
interface ProviderAvailability {
|
interface ProviderAvailability {
|
||||||
@@ -18,79 +18,127 @@ interface ProviderAvailability {
|
|||||||
openai: boolean
|
openai: boolean
|
||||||
gemini: boolean
|
gemini: boolean
|
||||||
}
|
}
|
||||||
|
opencodeZen: boolean
|
||||||
copilot: boolean
|
copilot: boolean
|
||||||
opencode: boolean
|
|
||||||
zai: boolean
|
zai: boolean
|
||||||
|
isMaxPlan: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AgentConfig {
|
||||||
|
model: string
|
||||||
|
variant?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CategoryConfig {
|
||||||
|
model: string
|
||||||
|
variant?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GeneratedOmoConfig {
|
export interface GeneratedOmoConfig {
|
||||||
$schema: string
|
$schema: string
|
||||||
agents?: Record<string, { model: string }>
|
agents?: Record<string, AgentConfig>
|
||||||
categories?: Record<string, { model: string }>
|
categories?: Record<string, CategoryConfig>
|
||||||
[key: string]: unknown
|
[key: string]: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
const MODEL_CATALOG: Record<ProviderTier, Partial<Record<ModelCapability, string>>> = {
|
interface NativeFallbackEntry {
|
||||||
native: {
|
provider: NativeProvider
|
||||||
"opus-level": "anthropic/claude-opus-4-5",
|
model: string
|
||||||
"sonnet-level": "anthropic/claude-sonnet-4-5",
|
|
||||||
"haiku-level": "anthropic/claude-haiku-4-5",
|
|
||||||
reasoning: "openai/gpt-5.2",
|
|
||||||
codex: "openai/gpt-5.2-codex",
|
|
||||||
visual: "google/gemini-3-pro-preview",
|
|
||||||
fast: "google/gemini-3-flash-preview",
|
|
||||||
},
|
|
||||||
"github-copilot": {
|
|
||||||
"opus-level": "github-copilot/claude-opus-4.5",
|
|
||||||
"sonnet-level": "github-copilot/claude-sonnet-4.5",
|
|
||||||
"haiku-level": "github-copilot/claude-haiku-4.5",
|
|
||||||
reasoning: "github-copilot/gpt-5.2",
|
|
||||||
codex: "github-copilot/gpt-5.2-codex",
|
|
||||||
visual: "github-copilot/gemini-3-pro-preview",
|
|
||||||
fast: "github-copilot/grok-code-fast-1",
|
|
||||||
},
|
|
||||||
opencode: {
|
|
||||||
"opus-level": "opencode/claude-opus-4-5",
|
|
||||||
"sonnet-level": "opencode/claude-sonnet-4-5",
|
|
||||||
"haiku-level": "opencode/claude-haiku-4-5",
|
|
||||||
reasoning: "opencode/gpt-5.2",
|
|
||||||
codex: "opencode/gpt-5.2-codex",
|
|
||||||
visual: "opencode/gemini-3-pro",
|
|
||||||
fast: "opencode/grok-code",
|
|
||||||
glm: "opencode/glm-4.7-free",
|
|
||||||
},
|
|
||||||
"zai-coding-plan": {
|
|
||||||
"opus-level": "zai-coding-plan/glm-4.7",
|
|
||||||
"sonnet-level": "zai-coding-plan/glm-4.7",
|
|
||||||
"haiku-level": "zai-coding-plan/glm-4.7-flash",
|
|
||||||
reasoning: "zai-coding-plan/glm-4.7",
|
|
||||||
codex: "zai-coding-plan/glm-4.7",
|
|
||||||
visual: "zai-coding-plan/glm-4.7",
|
|
||||||
fast: "zai-coding-plan/glm-4.7-flash",
|
|
||||||
glm: "zai-coding-plan/glm-4.7",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const AGENT_REQUIREMENTS: Record<string, ModelCapability> = {
|
const NATIVE_FALLBACK_CHAINS: Record<ModelCapability, NativeFallbackEntry[]> = {
|
||||||
Sisyphus: "opus-level",
|
"unspecified-high": [
|
||||||
oracle: "reasoning",
|
{ provider: "claude", model: "anthropic/claude-opus-4-5" },
|
||||||
librarian: "glm",
|
{ provider: "openai", model: "openai/gpt-5.2" },
|
||||||
explore: "fast",
|
{ provider: "gemini", model: "google/gemini-3-pro-preview" },
|
||||||
"multimodal-looker": "visual",
|
],
|
||||||
"Prometheus (Planner)": "opus-level",
|
"unspecified-low": [
|
||||||
"Metis (Plan Consultant)": "sonnet-level",
|
{ provider: "claude", model: "anthropic/claude-sonnet-4-5" },
|
||||||
"Momus (Plan Reviewer)": "sonnet-level",
|
{ provider: "openai", model: "openai/gpt-5.2" },
|
||||||
Atlas: "opus-level",
|
{ provider: "gemini", model: "google/gemini-3-flash-preview" },
|
||||||
|
],
|
||||||
|
quick: [
|
||||||
|
{ provider: "claude", model: "anthropic/claude-haiku-4-5" },
|
||||||
|
{ provider: "openai", model: "openai/gpt-5.1-codex-mini" },
|
||||||
|
{ provider: "gemini", model: "google/gemini-3-flash-preview" },
|
||||||
|
],
|
||||||
|
ultrabrain: [
|
||||||
|
{ provider: "openai", model: "openai/gpt-5.2-codex" },
|
||||||
|
{ provider: "claude", model: "anthropic/claude-opus-4-5" },
|
||||||
|
{ provider: "gemini", model: "google/gemini-3-pro-preview" },
|
||||||
|
],
|
||||||
|
"visual-engineering": [
|
||||||
|
{ provider: "gemini", model: "google/gemini-3-pro-preview" },
|
||||||
|
{ provider: "openai", model: "openai/gpt-5.2" },
|
||||||
|
{ provider: "claude", model: "anthropic/claude-sonnet-4-5" },
|
||||||
|
],
|
||||||
|
artistry: [
|
||||||
|
{ provider: "gemini", model: "google/gemini-3-pro-preview" },
|
||||||
|
{ provider: "openai", model: "openai/gpt-5.2" },
|
||||||
|
{ provider: "claude", model: "anthropic/claude-opus-4-5" },
|
||||||
|
],
|
||||||
|
writing: [
|
||||||
|
{ provider: "gemini", model: "google/gemini-3-flash-preview" },
|
||||||
|
{ provider: "openai", model: "openai/gpt-5.2" },
|
||||||
|
{ provider: "claude", model: "anthropic/claude-sonnet-4-5" },
|
||||||
|
],
|
||||||
|
glm: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
const CATEGORY_REQUIREMENTS: Record<string, ModelCapability> = {
|
const OPENCODE_ZEN_MODELS: Record<ModelCapability, string> = {
|
||||||
"visual-engineering": "visual",
|
"unspecified-high": "opencode/claude-opus-4-5",
|
||||||
ultrabrain: "codex",
|
"unspecified-low": "opencode/claude-sonnet-4-5",
|
||||||
artistry: "visual",
|
quick: "opencode/claude-haiku-4-5",
|
||||||
quick: "haiku-level",
|
ultrabrain: "opencode/gpt-5.2-codex",
|
||||||
"unspecified-low": "sonnet-level",
|
"visual-engineering": "opencode/gemini-3-pro",
|
||||||
"unspecified-high": "opus-level",
|
artistry: "opencode/gemini-3-pro",
|
||||||
writing: "fast",
|
writing: "opencode/gemini-3-flash",
|
||||||
|
glm: "opencode/glm-4.7-free",
|
||||||
|
}
|
||||||
|
|
||||||
|
const GITHUB_COPILOT_MODELS: Record<ModelCapability, string> = {
|
||||||
|
"unspecified-high": "github-copilot/claude-opus-4.5",
|
||||||
|
"unspecified-low": "github-copilot/claude-sonnet-4.5",
|
||||||
|
quick: "github-copilot/claude-haiku-4.5",
|
||||||
|
ultrabrain: "github-copilot/gpt-5.2-codex",
|
||||||
|
"visual-engineering": "github-copilot/gemini-3-pro-preview",
|
||||||
|
artistry: "github-copilot/gemini-3-pro-preview",
|
||||||
|
writing: "github-copilot/gemini-3-flash-preview",
|
||||||
|
glm: "github-copilot/gpt-5.2",
|
||||||
|
}
|
||||||
|
|
||||||
|
const ZAI_MODEL = "zai-coding-plan/glm-4.7"
|
||||||
|
|
||||||
|
interface AgentRequirement {
|
||||||
|
capability: ModelCapability
|
||||||
|
variant?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const AGENT_REQUIREMENTS: Record<string, AgentRequirement> = {
|
||||||
|
Sisyphus: { capability: "unspecified-high" },
|
||||||
|
oracle: { capability: "ultrabrain", variant: "high" },
|
||||||
|
librarian: { capability: "glm" },
|
||||||
|
explore: { capability: "quick" },
|
||||||
|
"multimodal-looker": { capability: "visual-engineering" },
|
||||||
|
"Prometheus (Planner)": { capability: "unspecified-high" },
|
||||||
|
"Metis (Plan Consultant)": { capability: "unspecified-high" },
|
||||||
|
"Momus (Plan Reviewer)": { capability: "ultrabrain", variant: "medium" },
|
||||||
|
Atlas: { capability: "unspecified-high" },
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CategoryRequirement {
|
||||||
|
capability: ModelCapability
|
||||||
|
variant?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const CATEGORY_REQUIREMENTS: Record<string, CategoryRequirement> = {
|
||||||
|
"visual-engineering": { capability: "visual-engineering" },
|
||||||
|
ultrabrain: { capability: "ultrabrain" },
|
||||||
|
artistry: { capability: "artistry", variant: "max" },
|
||||||
|
quick: { capability: "quick" },
|
||||||
|
"unspecified-low": { capability: "unspecified-low" },
|
||||||
|
"unspecified-high": { capability: "unspecified-high" },
|
||||||
|
writing: { capability: "writing" },
|
||||||
}
|
}
|
||||||
|
|
||||||
const ULTIMATE_FALLBACK = "opencode/glm-4.7-free"
|
const ULTIMATE_FALLBACK = "opencode/glm-4.7-free"
|
||||||
@@ -100,73 +148,51 @@ function toProviderAvailability(config: InstallConfig): ProviderAvailability {
|
|||||||
return {
|
return {
|
||||||
native: {
|
native: {
|
||||||
claude: config.hasClaude,
|
claude: config.hasClaude,
|
||||||
openai: config.hasClaude,
|
openai: config.hasOpenAI,
|
||||||
gemini: config.hasGemini,
|
gemini: config.hasGemini,
|
||||||
},
|
},
|
||||||
|
opencodeZen: config.hasOpencodeZen,
|
||||||
copilot: config.hasCopilot,
|
copilot: config.hasCopilot,
|
||||||
opencode: config.hasOpencodeZen,
|
|
||||||
zai: config.hasZaiCodingPlan,
|
zai: config.hasZaiCodingPlan,
|
||||||
|
isMaxPlan: config.isMax20,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProviderPriority(avail: ProviderAvailability): ProviderTier[] {
|
|
||||||
const tiers: ProviderTier[] = []
|
|
||||||
|
|
||||||
if (avail.native.claude || avail.native.openai || avail.native.gemini) {
|
|
||||||
tiers.push("native")
|
|
||||||
}
|
|
||||||
if (avail.copilot) tiers.push("github-copilot")
|
|
||||||
if (avail.opencode) tiers.push("opencode")
|
|
||||||
if (avail.zai) tiers.push("zai-coding-plan")
|
|
||||||
|
|
||||||
return tiers
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasCapability(
|
|
||||||
tier: ProviderTier,
|
|
||||||
capability: ModelCapability,
|
|
||||||
avail: ProviderAvailability
|
|
||||||
): boolean {
|
|
||||||
if (tier === "native") {
|
|
||||||
switch (capability) {
|
|
||||||
case "opus-level":
|
|
||||||
case "sonnet-level":
|
|
||||||
case "haiku-level":
|
|
||||||
return avail.native.claude
|
|
||||||
case "reasoning":
|
|
||||||
case "codex":
|
|
||||||
return avail.native.openai || avail.native.claude
|
|
||||||
case "visual":
|
|
||||||
case "fast":
|
|
||||||
return avail.native.gemini
|
|
||||||
case "glm":
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveModel(capability: ModelCapability, avail: ProviderAvailability): string {
|
function resolveModel(capability: ModelCapability, avail: ProviderAvailability): string {
|
||||||
const tiers = getProviderPriority(avail)
|
const nativeChain = NATIVE_FALLBACK_CHAINS[capability]
|
||||||
|
for (const entry of nativeChain) {
|
||||||
for (const tier of tiers) {
|
if (avail.native[entry.provider]) {
|
||||||
if (hasCapability(tier, capability, avail)) {
|
return entry.model
|
||||||
const model = MODEL_CATALOG[tier][capability]
|
|
||||||
if (model) return model
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (avail.opencodeZen) {
|
||||||
|
return OPENCODE_ZEN_MODELS[capability]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avail.copilot) {
|
||||||
|
return GITHUB_COPILOT_MODELS[capability]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avail.zai) {
|
||||||
|
return ZAI_MODEL
|
||||||
|
}
|
||||||
|
|
||||||
return ULTIMATE_FALLBACK
|
return ULTIMATE_FALLBACK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveClaudeCapability(avail: ProviderAvailability): ModelCapability {
|
||||||
|
return avail.isMaxPlan ? "unspecified-high" : "unspecified-low"
|
||||||
|
}
|
||||||
|
|
||||||
export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig {
|
export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig {
|
||||||
const avail = toProviderAvailability(config)
|
const avail = toProviderAvailability(config)
|
||||||
const hasAnyProvider =
|
const hasAnyProvider =
|
||||||
avail.native.claude ||
|
avail.native.claude ||
|
||||||
avail.native.openai ||
|
avail.native.openai ||
|
||||||
avail.native.gemini ||
|
avail.native.gemini ||
|
||||||
|
avail.opencodeZen ||
|
||||||
avail.copilot ||
|
avail.copilot ||
|
||||||
avail.opencode ||
|
|
||||||
avail.zai
|
avail.zai
|
||||||
|
|
||||||
if (!hasAnyProvider) {
|
if (!hasAnyProvider) {
|
||||||
@@ -181,19 +207,31 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const agents: Record<string, { model: string }> = {}
|
const agents: Record<string, AgentConfig> = {}
|
||||||
const categories: Record<string, { model: string }> = {}
|
const categories: Record<string, CategoryConfig> = {}
|
||||||
|
|
||||||
for (const [role, capability] of Object.entries(AGENT_REQUIREMENTS)) {
|
const claudeCapability = resolveClaudeCapability(avail)
|
||||||
|
|
||||||
|
for (const [role, req] of Object.entries(AGENT_REQUIREMENTS)) {
|
||||||
if (role === "librarian" && avail.zai) {
|
if (role === "librarian" && avail.zai) {
|
||||||
agents[role] = { model: "zai-coding-plan/glm-4.7" }
|
agents[role] = { model: ZAI_MODEL }
|
||||||
|
} else if (role === "explore") {
|
||||||
|
if (avail.native.claude && avail.isMaxPlan) {
|
||||||
|
agents[role] = { model: "anthropic/claude-haiku-4-5" }
|
||||||
|
} else {
|
||||||
|
agents[role] = { model: "opencode/grok-code" }
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
agents[role] = { model: resolveModel(capability, avail) }
|
const capability = req.capability === "unspecified-high" ? claudeCapability : req.capability
|
||||||
|
const model = resolveModel(capability, avail)
|
||||||
|
agents[role] = req.variant ? { model, variant: req.variant } : { model }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [cat, capability] of Object.entries(CATEGORY_REQUIREMENTS)) {
|
for (const [cat, req] of Object.entries(CATEGORY_REQUIREMENTS)) {
|
||||||
categories[cat] = { model: resolveModel(capability, avail) }
|
const capability = req.capability === "unspecified-high" ? claudeCapability : req.capability
|
||||||
|
const model = resolveModel(capability, avail)
|
||||||
|
categories[cat] = req.variant ? { model, variant: req.variant } : { model }
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -202,3 +240,7 @@ export function generateModelConfig(config: InstallConfig): GeneratedOmoConfig {
|
|||||||
categories,
|
categories,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function shouldShowChatGPTOnlyWarning(config: InstallConfig): boolean {
|
||||||
|
return !config.hasClaude && !config.hasGemini && config.hasOpenAI
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export type BooleanArg = "no" | "yes"
|
|||||||
export interface InstallArgs {
|
export interface InstallArgs {
|
||||||
tui: boolean
|
tui: boolean
|
||||||
claude?: ClaudeSubscription
|
claude?: ClaudeSubscription
|
||||||
|
openai?: BooleanArg
|
||||||
gemini?: BooleanArg
|
gemini?: BooleanArg
|
||||||
copilot?: BooleanArg
|
copilot?: BooleanArg
|
||||||
opencodeZen?: BooleanArg
|
opencodeZen?: BooleanArg
|
||||||
@@ -14,6 +15,7 @@ export interface InstallArgs {
|
|||||||
export interface InstallConfig {
|
export interface InstallConfig {
|
||||||
hasClaude: boolean
|
hasClaude: boolean
|
||||||
isMax20: boolean
|
isMax20: boolean
|
||||||
|
hasOpenAI: boolean
|
||||||
hasGemini: boolean
|
hasGemini: boolean
|
||||||
hasCopilot: boolean
|
hasCopilot: boolean
|
||||||
hasOpencodeZen: boolean
|
hasOpencodeZen: boolean
|
||||||
@@ -30,6 +32,7 @@ export interface DetectedConfig {
|
|||||||
isInstalled: boolean
|
isInstalled: boolean
|
||||||
hasClaude: boolean
|
hasClaude: boolean
|
||||||
isMax20: boolean
|
isMax20: boolean
|
||||||
|
hasOpenAI: boolean
|
||||||
hasGemini: boolean
|
hasGemini: boolean
|
||||||
hasCopilot: boolean
|
hasCopilot: boolean
|
||||||
hasOpencodeZen: boolean
|
hasOpencodeZen: boolean
|
||||||
|
|||||||
Reference in New Issue
Block a user