mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-17 10:03:08 +00:00
feat: Address review comments, add stage/unstage functionality, conflict resolution improvements, support for Sonnet 4.6
This commit is contained in:
@@ -30,6 +30,13 @@ export interface CopilotModelConfig {
|
||||
*/
|
||||
export const COPILOT_MODEL_MAP = {
|
||||
// Claude models (Anthropic via GitHub Copilot)
|
||||
'copilot-claude-sonnet-4.6': {
|
||||
label: 'Claude Sonnet 4.6',
|
||||
description: 'Anthropic Claude Sonnet 4.6 via GitHub Copilot.',
|
||||
supportsVision: true,
|
||||
supportsTools: true,
|
||||
contextWindow: 200000,
|
||||
},
|
||||
'copilot-claude-sonnet-4.5': {
|
||||
label: 'Claude Sonnet 4.5',
|
||||
description: 'Anthropic Claude Sonnet 4.5 via GitHub Copilot.',
|
||||
@@ -147,7 +154,7 @@ export function getAllCopilotModelIds(): CopilotModelId[] {
|
||||
/**
|
||||
* Default Copilot model
|
||||
*/
|
||||
export const DEFAULT_COPILOT_MODEL: CopilotModelId = 'copilot-claude-sonnet-4.5';
|
||||
export const DEFAULT_COPILOT_MODEL: CopilotModelId = 'copilot-claude-sonnet-4.6';
|
||||
|
||||
/**
|
||||
* GitHub Copilot authentication status
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
export type CursorModelId =
|
||||
| 'cursor-auto' // Auto-select best model
|
||||
| 'cursor-composer-1' // Cursor Composer agent model
|
||||
| 'cursor-sonnet-4.6' // Claude Sonnet 4.6
|
||||
| 'cursor-sonnet-4.6-thinking' // Claude Sonnet 4.6 with extended thinking
|
||||
| 'cursor-sonnet-4.5' // Claude Sonnet 4.5
|
||||
| 'cursor-sonnet-4.5-thinking' // Claude Sonnet 4.5 with extended thinking
|
||||
| 'cursor-opus-4.5' // Claude Opus 4.5
|
||||
@@ -35,6 +37,8 @@ export type CursorModelId =
|
||||
export type LegacyCursorModelId =
|
||||
| 'auto'
|
||||
| 'composer-1'
|
||||
| 'sonnet-4.6'
|
||||
| 'sonnet-4.6-thinking'
|
||||
| 'sonnet-4.5'
|
||||
| 'sonnet-4.5-thinking'
|
||||
| 'opus-4.5'
|
||||
@@ -75,6 +79,20 @@ export const CURSOR_MODEL_MAP: Record<CursorModelId, CursorModelConfig> = {
|
||||
hasThinking: false,
|
||||
supportsVision: false,
|
||||
},
|
||||
'cursor-sonnet-4.6': {
|
||||
id: 'cursor-sonnet-4.6',
|
||||
label: 'Claude Sonnet 4.6',
|
||||
description: 'Anthropic Claude Sonnet 4.6 via Cursor',
|
||||
hasThinking: false,
|
||||
supportsVision: false, // Model supports vision but Cursor CLI doesn't pass images
|
||||
},
|
||||
'cursor-sonnet-4.6-thinking': {
|
||||
id: 'cursor-sonnet-4.6-thinking',
|
||||
label: 'Claude Sonnet 4.6 (Thinking)',
|
||||
description: 'Claude Sonnet 4.6 with extended thinking enabled',
|
||||
hasThinking: true,
|
||||
supportsVision: false,
|
||||
},
|
||||
'cursor-sonnet-4.5': {
|
||||
id: 'cursor-sonnet-4.5',
|
||||
label: 'Claude Sonnet 4.5',
|
||||
@@ -223,6 +241,8 @@ export const CURSOR_MODEL_MAP: Record<CursorModelId, CursorModelConfig> = {
|
||||
export const LEGACY_CURSOR_MODEL_MAP: Record<LegacyCursorModelId, CursorModelId> = {
|
||||
auto: 'cursor-auto',
|
||||
'composer-1': 'cursor-composer-1',
|
||||
'sonnet-4.6': 'cursor-sonnet-4.6',
|
||||
'sonnet-4.6-thinking': 'cursor-sonnet-4.6-thinking',
|
||||
'sonnet-4.5': 'cursor-sonnet-4.5',
|
||||
'sonnet-4.5-thinking': 'cursor-sonnet-4.5-thinking',
|
||||
'opus-4.5': 'cursor-opus-4.5',
|
||||
@@ -378,6 +398,22 @@ export const CURSOR_MODEL_GROUPS: GroupedModel[] = [
|
||||
},
|
||||
],
|
||||
},
|
||||
// Sonnet 4.6 group (thinking mode)
|
||||
{
|
||||
baseId: 'cursor-sonnet-4.6-group',
|
||||
label: 'Claude Sonnet 4.6',
|
||||
description: 'Anthropic Claude Sonnet 4.6 via Cursor',
|
||||
variantType: 'thinking',
|
||||
variants: [
|
||||
{ id: 'cursor-sonnet-4.6', label: 'Standard', description: 'Fast responses' },
|
||||
{
|
||||
id: 'cursor-sonnet-4.6-thinking',
|
||||
label: 'Thinking',
|
||||
description: 'Extended reasoning',
|
||||
badge: 'Reasoning',
|
||||
},
|
||||
],
|
||||
},
|
||||
// Sonnet 4.5 group (thinking mode)
|
||||
{
|
||||
baseId: 'cursor-sonnet-4.5-group',
|
||||
|
||||
@@ -253,7 +253,7 @@ export const REASONING_EFFORT_LABELS: Record<ReasoningEffort, string> = {
|
||||
* ```typescript
|
||||
* getModelDisplayName("haiku"); // "Claude Haiku"
|
||||
* getModelDisplayName("sonnet"); // "Claude Sonnet"
|
||||
* getModelDisplayName("claude-opus-4-20250514"); // "claude-opus-4-20250514"
|
||||
* getModelDisplayName("claude-sonnet-4-6"); // "Claude Sonnet 4.6"
|
||||
* ```
|
||||
*/
|
||||
export function getModelDisplayName(model: ModelAlias | string): string {
|
||||
@@ -261,6 +261,11 @@ export function getModelDisplayName(model: ModelAlias | string): string {
|
||||
haiku: 'Claude Haiku',
|
||||
sonnet: 'Claude Sonnet',
|
||||
opus: 'Claude Opus',
|
||||
'claude-haiku': 'Claude Haiku',
|
||||
'claude-sonnet': 'Claude Sonnet',
|
||||
'claude-opus': 'Claude Opus',
|
||||
'claude-sonnet-4-6': 'Claude Sonnet 4.6',
|
||||
'claude-opus-4-6': 'Claude Opus 4.6',
|
||||
[CODEX_MODEL_MAP.gpt53Codex]: 'GPT-5.3-Codex',
|
||||
[CODEX_MODEL_MAP.gpt53CodexSpark]: 'GPT-5.3-Codex-Spark',
|
||||
[CODEX_MODEL_MAP.gpt52Codex]: 'GPT-5.2-Codex',
|
||||
|
||||
@@ -8,7 +8,11 @@
|
||||
import type { CursorModelId, LegacyCursorModelId } from './cursor-models.js';
|
||||
import { LEGACY_CURSOR_MODEL_MAP, CURSOR_MODEL_MAP } from './cursor-models.js';
|
||||
import type { OpencodeModelId, LegacyOpencodeModelId } from './opencode-models.js';
|
||||
import { LEGACY_OPENCODE_MODEL_MAP, OPENCODE_MODEL_CONFIG_MAP } from './opencode-models.js';
|
||||
import {
|
||||
LEGACY_OPENCODE_MODEL_MAP,
|
||||
OPENCODE_MODEL_CONFIG_MAP,
|
||||
RETIRED_OPENCODE_MODEL_MAP,
|
||||
} from './opencode-models.js';
|
||||
import type { ClaudeCanonicalId } from './model.js';
|
||||
import { LEGACY_CLAUDE_ALIAS_MAP, CLAUDE_CANONICAL_MAP, CLAUDE_MODEL_MAP } from './model.js';
|
||||
import type { PhaseModelEntry } from './settings.js';
|
||||
@@ -61,11 +65,16 @@ export function migrateModelId(legacyId: string | undefined | null): string {
|
||||
return LEGACY_CURSOR_MODEL_MAP[legacyId];
|
||||
}
|
||||
|
||||
// Already has opencode- prefix - it's canonical
|
||||
// Already has opencode- prefix - check if it's a current canonical ID
|
||||
if (legacyId.startsWith('opencode-') && legacyId in OPENCODE_MODEL_CONFIG_MAP) {
|
||||
return legacyId;
|
||||
}
|
||||
|
||||
// Retired opencode- canonical IDs (e.g., 'opencode-grok-code' → 'opencode-big-pickle')
|
||||
if (legacyId.startsWith('opencode-') && legacyId in RETIRED_OPENCODE_MODEL_MAP) {
|
||||
return RETIRED_OPENCODE_MODEL_MAP[legacyId];
|
||||
}
|
||||
|
||||
// Legacy OpenCode model ID (with slash format)
|
||||
if (isLegacyOpencodeModelId(legacyId)) {
|
||||
return LEGACY_OPENCODE_MODEL_MAP[legacyId];
|
||||
@@ -128,29 +137,36 @@ export function migrateOpencodeModelIds(ids: string[]): OpencodeModelId[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
return ids.map((id) => {
|
||||
// Already canonical (dash format)
|
||||
if (id.startsWith('opencode-') && id in OPENCODE_MODEL_CONFIG_MAP) {
|
||||
return ids
|
||||
.map((id) => {
|
||||
// Already canonical (dash format) and current
|
||||
if (id.startsWith('opencode-') && id in OPENCODE_MODEL_CONFIG_MAP) {
|
||||
return id as OpencodeModelId;
|
||||
}
|
||||
|
||||
// Retired canonical IDs (e.g., 'opencode-grok-code') → replacement
|
||||
if (id.startsWith('opencode-') && id in RETIRED_OPENCODE_MODEL_MAP) {
|
||||
return RETIRED_OPENCODE_MODEL_MAP[id];
|
||||
}
|
||||
|
||||
// Legacy ID (slash format)
|
||||
if (isLegacyOpencodeModelId(id)) {
|
||||
return LEGACY_OPENCODE_MODEL_MAP[id];
|
||||
}
|
||||
|
||||
// Convert slash to dash format for unknown models
|
||||
if (id.startsWith('opencode/')) {
|
||||
return id.replace('opencode/', 'opencode-') as OpencodeModelId;
|
||||
}
|
||||
|
||||
// Add prefix if not present
|
||||
if (!id.startsWith('opencode-')) {
|
||||
return `opencode-${id}` as OpencodeModelId;
|
||||
}
|
||||
|
||||
return id as OpencodeModelId;
|
||||
}
|
||||
|
||||
// Legacy ID (slash format)
|
||||
if (isLegacyOpencodeModelId(id)) {
|
||||
return LEGACY_OPENCODE_MODEL_MAP[id];
|
||||
}
|
||||
|
||||
// Convert slash to dash format for unknown models
|
||||
if (id.startsWith('opencode/')) {
|
||||
return id.replace('opencode/', 'opencode-') as OpencodeModelId;
|
||||
}
|
||||
|
||||
// Add prefix if not present
|
||||
if (!id.startsWith('opencode-')) {
|
||||
return `opencode-${id}` as OpencodeModelId;
|
||||
}
|
||||
|
||||
return id as OpencodeModelId;
|
||||
});
|
||||
})
|
||||
.filter((id, index, self) => self.indexOf(id) === index); // Deduplicate after migration
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,7 @@ export type ClaudeCanonicalId = 'claude-haiku' | 'claude-sonnet' | 'claude-opus'
|
||||
*/
|
||||
export const CLAUDE_CANONICAL_MAP: Record<ClaudeCanonicalId, string> = {
|
||||
'claude-haiku': 'claude-haiku-4-5-20251001',
|
||||
'claude-sonnet': 'claude-sonnet-4-5-20250929',
|
||||
'claude-sonnet': 'claude-sonnet-4-6',
|
||||
'claude-opus': 'claude-opus-4-6',
|
||||
} as const;
|
||||
|
||||
@@ -28,7 +28,7 @@ export const CLAUDE_CANONICAL_MAP: Record<ClaudeCanonicalId, string> = {
|
||||
*/
|
||||
export const CLAUDE_MODEL_MAP: Record<string, string> = {
|
||||
haiku: 'claude-haiku-4-5-20251001',
|
||||
sonnet: 'claude-sonnet-4-5-20250929',
|
||||
sonnet: 'claude-sonnet-4-6',
|
||||
opus: 'claude-opus-4-6',
|
||||
} as const;
|
||||
|
||||
|
||||
@@ -8,18 +8,23 @@
|
||||
export type OpencodeModelId =
|
||||
// OpenCode Free Tier Models
|
||||
| 'opencode-big-pickle'
|
||||
| 'opencode-glm-4.7-free'
|
||||
| 'opencode-glm-5-free'
|
||||
| 'opencode-gpt-5-nano'
|
||||
| 'opencode-grok-code'
|
||||
| 'opencode-minimax-m2.1-free';
|
||||
| 'opencode-kimi-k2.5-free'
|
||||
| 'opencode-minimax-m2.5-free';
|
||||
|
||||
/**
|
||||
* Legacy OpenCode model IDs (with slash format) for migration support
|
||||
* Includes both current and previously-available models for backward compatibility.
|
||||
*/
|
||||
export type LegacyOpencodeModelId =
|
||||
| 'opencode/big-pickle'
|
||||
| 'opencode/glm-4.7-free'
|
||||
| 'opencode/glm-5-free'
|
||||
| 'opencode/gpt-5-nano'
|
||||
| 'opencode/kimi-k2.5-free'
|
||||
| 'opencode/minimax-m2.5-free'
|
||||
// Retired models (kept for migration from older settings)
|
||||
| 'opencode/glm-4.7-free'
|
||||
| 'opencode/grok-code'
|
||||
| 'opencode/minimax-m2.1-free';
|
||||
|
||||
@@ -35,23 +40,40 @@ export const OPENCODE_MODEL_MAP: Record<string, OpencodeModelId> = {
|
||||
// OpenCode free tier aliases
|
||||
'big-pickle': 'opencode-big-pickle',
|
||||
pickle: 'opencode-big-pickle',
|
||||
'glm-free': 'opencode-glm-4.7-free',
|
||||
'glm-free': 'opencode-glm-5-free',
|
||||
'glm-5': 'opencode-glm-5-free',
|
||||
'gpt-nano': 'opencode-gpt-5-nano',
|
||||
nano: 'opencode-gpt-5-nano',
|
||||
'grok-code': 'opencode-grok-code',
|
||||
grok: 'opencode-grok-code',
|
||||
minimax: 'opencode-minimax-m2.1-free',
|
||||
'kimi-free': 'opencode-kimi-k2.5-free',
|
||||
kimi: 'opencode-kimi-k2.5-free',
|
||||
minimax: 'opencode-minimax-m2.5-free',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Map from legacy slash-format model IDs to canonical prefixed IDs
|
||||
* Map from legacy slash-format model IDs to canonical prefixed IDs.
|
||||
* Retired models are mapped to their closest replacement.
|
||||
*/
|
||||
export const LEGACY_OPENCODE_MODEL_MAP: Record<LegacyOpencodeModelId, OpencodeModelId> = {
|
||||
// Current models
|
||||
'opencode/big-pickle': 'opencode-big-pickle',
|
||||
'opencode/glm-4.7-free': 'opencode-glm-4.7-free',
|
||||
'opencode/glm-5-free': 'opencode-glm-5-free',
|
||||
'opencode/gpt-5-nano': 'opencode-gpt-5-nano',
|
||||
'opencode/grok-code': 'opencode-grok-code',
|
||||
'opencode/minimax-m2.1-free': 'opencode-minimax-m2.1-free',
|
||||
'opencode/kimi-k2.5-free': 'opencode-kimi-k2.5-free',
|
||||
'opencode/minimax-m2.5-free': 'opencode-minimax-m2.5-free',
|
||||
// Retired models → mapped to replacements
|
||||
'opencode/glm-4.7-free': 'opencode-glm-5-free',
|
||||
'opencode/grok-code': 'opencode-big-pickle', // grok-code retired, fallback to default
|
||||
'opencode/minimax-m2.1-free': 'opencode-minimax-m2.5-free',
|
||||
};
|
||||
|
||||
/**
|
||||
* Map from retired canonical (dash-format) model IDs to their replacements.
|
||||
* Used to migrate settings that reference models no longer available.
|
||||
*/
|
||||
export const RETIRED_OPENCODE_MODEL_MAP: Record<string, OpencodeModelId> = {
|
||||
'opencode-glm-4.7-free': 'opencode-glm-5-free',
|
||||
'opencode-grok-code': 'opencode-big-pickle',
|
||||
'opencode-minimax-m2.1-free': 'opencode-minimax-m2.5-free',
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -81,8 +103,8 @@ export const OPENCODE_MODELS: OpencodeModelConfig[] = [
|
||||
tier: 'free',
|
||||
},
|
||||
{
|
||||
id: 'opencode-glm-4.7-free',
|
||||
label: 'GLM 4.7 Free',
|
||||
id: 'opencode-glm-5-free',
|
||||
label: 'GLM 5 Free',
|
||||
description: 'OpenCode free tier GLM model',
|
||||
supportsVision: false,
|
||||
provider: 'opencode',
|
||||
@@ -97,16 +119,16 @@ export const OPENCODE_MODELS: OpencodeModelConfig[] = [
|
||||
tier: 'free',
|
||||
},
|
||||
{
|
||||
id: 'opencode-grok-code',
|
||||
label: 'Grok Code',
|
||||
description: 'OpenCode free tier Grok model for coding',
|
||||
id: 'opencode-kimi-k2.5-free',
|
||||
label: 'Kimi K2.5 Free',
|
||||
description: 'OpenCode free tier Kimi model for coding',
|
||||
supportsVision: false,
|
||||
provider: 'opencode',
|
||||
tier: 'free',
|
||||
},
|
||||
{
|
||||
id: 'opencode-minimax-m2.1-free',
|
||||
label: 'MiniMax M2.1 Free',
|
||||
id: 'opencode-minimax-m2.5-free',
|
||||
label: 'MiniMax M2.5 Free',
|
||||
description: 'OpenCode free tier MiniMax model',
|
||||
supportsVision: false,
|
||||
provider: 'opencode',
|
||||
@@ -160,7 +182,8 @@ export function getOpencodeModelProvider(modelId: OpencodeModelId): OpencodeProv
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Resolve an alias or partial model ID to a full model ID
|
||||
* Helper: Resolve an alias or partial model ID to a full model ID.
|
||||
* Also handles retired model IDs by mapping them to their replacements.
|
||||
*/
|
||||
export function resolveOpencodeModelId(input: string): OpencodeModelId | undefined {
|
||||
// Check if it's already a valid model ID
|
||||
@@ -168,6 +191,11 @@ export function resolveOpencodeModelId(input: string): OpencodeModelId | undefin
|
||||
return input as OpencodeModelId;
|
||||
}
|
||||
|
||||
// Check retired model map (handles old canonical IDs like 'opencode-grok-code')
|
||||
if (input in RETIRED_OPENCODE_MODEL_MAP) {
|
||||
return RETIRED_OPENCODE_MODEL_MAP[input];
|
||||
}
|
||||
|
||||
// Check alias map
|
||||
const normalized = input.toLowerCase();
|
||||
return OPENCODE_MODEL_MAP[normalized];
|
||||
|
||||
@@ -9,7 +9,11 @@
|
||||
import type { ModelProvider } from './settings.js';
|
||||
import { LEGACY_CURSOR_MODEL_MAP } from './cursor-models.js';
|
||||
import { CLAUDE_MODEL_MAP, CODEX_MODEL_MAP } from './model.js';
|
||||
import { OPENCODE_MODEL_CONFIG_MAP, LEGACY_OPENCODE_MODEL_MAP } from './opencode-models.js';
|
||||
import {
|
||||
OPENCODE_MODEL_CONFIG_MAP,
|
||||
LEGACY_OPENCODE_MODEL_MAP,
|
||||
RETIRED_OPENCODE_MODEL_MAP,
|
||||
} from './opencode-models.js';
|
||||
import { GEMINI_MODEL_MAP } from './gemini-models.js';
|
||||
import { COPILOT_MODEL_MAP } from './copilot-models.js';
|
||||
|
||||
@@ -51,7 +55,7 @@ export function isCursorModel(model: string | undefined | null): boolean {
|
||||
/**
|
||||
* Check if a model string represents a Claude model
|
||||
*
|
||||
* @param model - Model string to check (e.g., "sonnet", "opus", "claude-sonnet-4-20250514")
|
||||
* @param model - Model string to check (e.g., "sonnet", "opus", "claude-sonnet-4-6")
|
||||
* @returns true if the model is a Claude model
|
||||
*/
|
||||
export function isClaudeModel(model: string | undefined | null): boolean {
|
||||
@@ -310,7 +314,10 @@ export function getBareModelId(model: string): string {
|
||||
export function normalizeModelString(model: string | undefined | null): string {
|
||||
if (!model || typeof model !== 'string') return 'claude-sonnet'; // Default to canonical
|
||||
|
||||
// Already has a canonical prefix - return as-is
|
||||
// Already has a canonical prefix - return as-is (but check for retired opencode models first)
|
||||
if (model.startsWith(PROVIDER_PREFIXES.opencode) && model in RETIRED_OPENCODE_MODEL_MAP) {
|
||||
return RETIRED_OPENCODE_MODEL_MAP[model];
|
||||
}
|
||||
if (
|
||||
model.startsWith(PROVIDER_PREFIXES.cursor) ||
|
||||
model.startsWith(PROVIDER_PREFIXES.codex) ||
|
||||
@@ -364,7 +371,7 @@ export function normalizeModelString(model: string | undefined | null): string {
|
||||
*
|
||||
* @example
|
||||
* supportsStructuredOutput('sonnet') // true (Claude)
|
||||
* supportsStructuredOutput('claude-sonnet-4-20250514') // true (Claude)
|
||||
* supportsStructuredOutput('claude-sonnet-4-6') // true (Claude)
|
||||
* supportsStructuredOutput('codex-gpt-5.2') // true (Codex/OpenAI)
|
||||
* supportsStructuredOutput('cursor-auto') // false
|
||||
* supportsStructuredOutput('gemini-2.5-pro') // false
|
||||
|
||||
Reference in New Issue
Block a user