mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 08:13:37 +00:00
feat(ui): Enhance AI model handling with Cursor support
- Refactor model handling to support both Claude and Cursor models across various components. - Introduce `stripProviderPrefix` utility for consistent model ID processing. - Update `CursorProvider` to utilize `isCursorModel` for model validation. - Implement model override functionality in GitHub issue validation and enhancement routes. - Add `useCursorStatusInit` hook to initialize Cursor CLI status on app startup. - Update UI components to reflect changes in model selection and validation processes. This update improves the flexibility of AI model usage and enhances user experience by allowing quick model overrides.
This commit is contained in:
@@ -33,7 +33,7 @@ export type { ErrorType, ErrorInfo } from './error.js';
|
||||
export type { ImageData, ImageContentBlock } from './image.js';
|
||||
|
||||
// Model types and constants
|
||||
export { CLAUDE_MODEL_MAP, DEFAULT_MODELS, type ModelAlias, type AgentModel } from './model.js';
|
||||
export { CLAUDE_MODEL_MAP, DEFAULT_MODELS, type ModelAlias } from './model.js';
|
||||
|
||||
// Event types
|
||||
export type { EventType, EventCallback } from './event.js';
|
||||
@@ -114,3 +114,15 @@ export type {
|
||||
// Cursor types
|
||||
export * from './cursor-models.js';
|
||||
export * from './cursor-cli.js';
|
||||
|
||||
// Provider utilities
|
||||
export {
|
||||
PROVIDER_PREFIXES,
|
||||
isCursorModel,
|
||||
isClaudeModel,
|
||||
getModelProvider,
|
||||
stripProviderPrefix,
|
||||
addProviderPrefix,
|
||||
getBareModelId,
|
||||
normalizeModelString,
|
||||
} from './provider-utils.js';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Types for validating GitHub issues against the codebase using Claude SDK.
|
||||
*/
|
||||
|
||||
import type { AgentModel } from './model.js';
|
||||
import type { ModelAlias } from './model.js';
|
||||
|
||||
/**
|
||||
* Verdict from issue validation
|
||||
@@ -102,7 +102,7 @@ export type IssueValidationEvent =
|
||||
result: IssueValidationResult;
|
||||
projectPath: string;
|
||||
/** Model used for validation (opus, sonnet, haiku) */
|
||||
model: AgentModel;
|
||||
model: ModelAlias;
|
||||
}
|
||||
| {
|
||||
type: 'issue_validation_error';
|
||||
@@ -127,7 +127,7 @@ export interface StoredValidation {
|
||||
/** ISO timestamp when validation was performed */
|
||||
validatedAt: string;
|
||||
/** Model used for validation (opus, sonnet, haiku) */
|
||||
model: AgentModel;
|
||||
model: ModelAlias;
|
||||
/** The validation result */
|
||||
result: IssueValidationResult;
|
||||
/** ISO timestamp when user viewed this validation (undefined = not yet viewed) */
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* and thinking levels used throughout the application UI.
|
||||
*/
|
||||
|
||||
import type { AgentModel, ThinkingLevel, ModelProvider } from './settings.js';
|
||||
import type { ModelAlias, ThinkingLevel, ModelProvider } from './settings.js';
|
||||
import type { CursorModelId } from './cursor-models.js';
|
||||
|
||||
/**
|
||||
@@ -13,7 +13,7 @@ import type { CursorModelId } from './cursor-models.js';
|
||||
*/
|
||||
export interface ModelOption {
|
||||
/** Model identifier (supports both Claude and Cursor models) */
|
||||
id: AgentModel | CursorModelId;
|
||||
id: ModelAlias | CursorModelId;
|
||||
/** Display name shown to user */
|
||||
label: string;
|
||||
/** Descriptive text explaining model capabilities */
|
||||
@@ -102,7 +102,7 @@ export const THINKING_LEVEL_LABELS: Record<ThinkingLevel, string> = {
|
||||
* getModelDisplayName("claude-opus-4-20250514"); // "claude-opus-4-20250514"
|
||||
* ```
|
||||
*/
|
||||
export function getModelDisplayName(model: AgentModel | string): string {
|
||||
export function getModelDisplayName(model: ModelAlias | string): string {
|
||||
const displayNames: Record<string, string> = {
|
||||
haiku: 'Claude Haiku',
|
||||
sonnet: 'Claude Sonnet',
|
||||
|
||||
@@ -16,9 +16,3 @@ export const DEFAULT_MODELS = {
|
||||
} as const;
|
||||
|
||||
export type ModelAlias = keyof typeof CLAUDE_MODEL_MAP;
|
||||
|
||||
/**
|
||||
* AgentModel - Alias for ModelAlias for backward compatibility
|
||||
* Represents available Claude models: "opus" | "sonnet" | "haiku"
|
||||
*/
|
||||
export type AgentModel = ModelAlias;
|
||||
|
||||
140
libs/types/src/provider-utils.ts
Normal file
140
libs/types/src/provider-utils.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Provider utility functions
|
||||
*
|
||||
* Centralized utilities for determining model providers.
|
||||
* When adding new providers, update these functions instead of
|
||||
* scattering .startsWith() checks throughout the codebase.
|
||||
*/
|
||||
|
||||
import type { ModelProvider } from './settings.js';
|
||||
import { CURSOR_MODEL_MAP, type CursorModelId } from './cursor-models.js';
|
||||
import { CLAUDE_MODEL_MAP } from './model.js';
|
||||
|
||||
/** Provider prefix constants */
|
||||
export const PROVIDER_PREFIXES = {
|
||||
cursor: 'cursor-',
|
||||
// Add new provider prefixes here
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Check if a model string represents a Cursor model
|
||||
*
|
||||
* @param model - Model string to check (e.g., "cursor-composer-1" or "composer-1")
|
||||
* @returns true if the model is a Cursor model
|
||||
*/
|
||||
export function isCursorModel(model: string | undefined | null): boolean {
|
||||
if (!model || typeof model !== 'string') return false;
|
||||
|
||||
// Check for explicit cursor- prefix
|
||||
if (model.startsWith(PROVIDER_PREFIXES.cursor)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if it's a bare Cursor model ID
|
||||
return model in CURSOR_MODEL_MAP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a model string represents a Claude model
|
||||
*
|
||||
* @param model - Model string to check (e.g., "sonnet", "opus", "claude-sonnet-4-20250514")
|
||||
* @returns true if the model is a Claude model
|
||||
*/
|
||||
export function isClaudeModel(model: string | undefined | null): boolean {
|
||||
if (!model || typeof model !== 'string') return false;
|
||||
|
||||
// Check if it's a Claude model alias (haiku, sonnet, opus)
|
||||
if (model in CLAUDE_MODEL_MAP) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if it contains 'claude-' in the string (full model ID)
|
||||
return model.includes('claude-');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the provider for a model string
|
||||
*
|
||||
* @param model - Model string to check
|
||||
* @returns The provider type, defaults to 'claude' for unknown models
|
||||
*/
|
||||
export function getModelProvider(model: string | undefined | null): ModelProvider {
|
||||
if (isCursorModel(model)) {
|
||||
return 'cursor';
|
||||
}
|
||||
return 'claude';
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip the provider prefix from a model string
|
||||
*
|
||||
* @param model - Model string that may have a provider prefix
|
||||
* @returns Model string without provider prefix
|
||||
*
|
||||
* @example
|
||||
* stripProviderPrefix('cursor-composer-1') // 'composer-1'
|
||||
* stripProviderPrefix('sonnet') // 'sonnet'
|
||||
*/
|
||||
export function stripProviderPrefix(model: string): string {
|
||||
if (!model || typeof model !== 'string') return model;
|
||||
|
||||
for (const prefix of Object.values(PROVIDER_PREFIXES)) {
|
||||
if (model.startsWith(prefix)) {
|
||||
return model.slice(prefix.length);
|
||||
}
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the provider prefix to a model string if not already present
|
||||
*
|
||||
* @param model - Bare model ID
|
||||
* @param provider - Provider to add prefix for
|
||||
* @returns Model string with provider prefix
|
||||
*
|
||||
* @example
|
||||
* addProviderPrefix('composer-1', 'cursor') // 'cursor-composer-1'
|
||||
* addProviderPrefix('cursor-composer-1', 'cursor') // 'cursor-composer-1' (no change)
|
||||
* addProviderPrefix('sonnet', 'claude') // 'sonnet' (Claude doesn't use prefix)
|
||||
*/
|
||||
export function addProviderPrefix(model: string, provider: ModelProvider): string {
|
||||
if (!model || typeof model !== 'string') return model;
|
||||
|
||||
if (provider === 'cursor') {
|
||||
if (!model.startsWith(PROVIDER_PREFIXES.cursor)) {
|
||||
return `${PROVIDER_PREFIXES.cursor}${model}`;
|
||||
}
|
||||
}
|
||||
// Claude models don't use prefixes
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bare model ID from a model string (without provider prefix)
|
||||
*
|
||||
* @param model - Model string that may have a provider prefix
|
||||
* @returns The bare model ID
|
||||
*/
|
||||
export function getBareModelId(model: string): string {
|
||||
return stripProviderPrefix(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a model string to its canonical form
|
||||
* - For Cursor: adds cursor- prefix if missing
|
||||
* - For Claude: returns as-is
|
||||
*
|
||||
* @param model - Model string to normalize
|
||||
* @returns Normalized model string
|
||||
*/
|
||||
export function normalizeModelString(model: string | undefined | null): string {
|
||||
if (!model || typeof model !== 'string') return 'sonnet'; // Default
|
||||
|
||||
// If it's a Cursor model without prefix, add the prefix
|
||||
if (model in CURSOR_MODEL_MAP && !model.startsWith(PROVIDER_PREFIXES.cursor)) {
|
||||
return `${PROVIDER_PREFIXES.cursor}${model}`;
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
@@ -6,12 +6,12 @@
|
||||
* (for file I/O via SettingsService) and the UI (for state management and sync).
|
||||
*/
|
||||
|
||||
import type { AgentModel } from './model.js';
|
||||
import type { ModelAlias } from './model.js';
|
||||
import type { CursorModelId } from './cursor-models.js';
|
||||
import { CURSOR_MODEL_MAP, getAllCursorModelIds } from './cursor-models.js';
|
||||
|
||||
// Re-export AgentModel for convenience
|
||||
export type { AgentModel };
|
||||
// Re-export ModelAlias for convenience
|
||||
export type { ModelAlias };
|
||||
|
||||
/**
|
||||
* ThemeMode - Available color themes for the UI
|
||||
@@ -82,25 +82,25 @@ export type ModelProvider = 'claude' | 'cursor';
|
||||
export interface PhaseModelConfig {
|
||||
// Quick tasks - recommend fast/cheap models (Haiku, Cursor auto)
|
||||
/** Model for enhancing feature names and descriptions */
|
||||
enhancementModel: AgentModel | CursorModelId;
|
||||
enhancementModel: ModelAlias | CursorModelId;
|
||||
/** Model for generating file context descriptions */
|
||||
fileDescriptionModel: AgentModel | CursorModelId;
|
||||
fileDescriptionModel: ModelAlias | CursorModelId;
|
||||
/** Model for analyzing and describing context images */
|
||||
imageDescriptionModel: AgentModel | CursorModelId;
|
||||
imageDescriptionModel: ModelAlias | CursorModelId;
|
||||
|
||||
// Validation tasks - recommend smart models (Sonnet, Opus)
|
||||
/** Model for validating and improving GitHub issues */
|
||||
validationModel: AgentModel | CursorModelId;
|
||||
validationModel: ModelAlias | CursorModelId;
|
||||
|
||||
// Generation tasks - recommend powerful models (Opus, Sonnet)
|
||||
/** Model for generating full application specifications */
|
||||
specGenerationModel: AgentModel | CursorModelId;
|
||||
specGenerationModel: ModelAlias | CursorModelId;
|
||||
/** Model for creating features from specifications */
|
||||
featureGenerationModel: AgentModel | CursorModelId;
|
||||
featureGenerationModel: ModelAlias | CursorModelId;
|
||||
/** Model for reorganizing and prioritizing backlog */
|
||||
backlogPlanningModel: AgentModel | CursorModelId;
|
||||
backlogPlanningModel: ModelAlias | CursorModelId;
|
||||
/** Model for analyzing project structure */
|
||||
projectAnalysisModel: AgentModel | CursorModelId;
|
||||
projectAnalysisModel: ModelAlias | CursorModelId;
|
||||
}
|
||||
|
||||
/** Keys of PhaseModelConfig for type-safe access */
|
||||
@@ -196,7 +196,7 @@ export interface AIProfile {
|
||||
|
||||
// Claude-specific settings
|
||||
/** Which Claude model to use (opus, sonnet, haiku) - only for Claude provider */
|
||||
model?: AgentModel;
|
||||
model?: ModelAlias;
|
||||
/** Extended thinking level for reasoning-based tasks - only for Claude provider */
|
||||
thinkingLevel?: ThinkingLevel;
|
||||
|
||||
@@ -338,9 +338,9 @@ export interface GlobalSettings {
|
||||
|
||||
// Legacy AI Model Selection (deprecated - use phaseModels instead)
|
||||
/** @deprecated Use phaseModels.enhancementModel instead */
|
||||
enhancementModel: AgentModel;
|
||||
enhancementModel: ModelAlias;
|
||||
/** @deprecated Use phaseModels.validationModel instead */
|
||||
validationModel: AgentModel;
|
||||
validationModel: ModelAlias;
|
||||
|
||||
// Cursor CLI Settings (global)
|
||||
/** Which Cursor models are available in feature modal (empty = all) */
|
||||
|
||||
Reference in New Issue
Block a user