mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 14:22:02 +00:00
This commit introduces significant updates to the cursor model handling and auto mode features. The cursor model IDs have been standardized to a canonical format, ensuring backward compatibility while migrating legacy IDs. New endpoints for starting and stopping the auto mode loop have been added, allowing for better control over project-specific auto mode operations. Key changes: - Updated cursor model IDs to use the 'cursor-' prefix for consistency. - Added new API endpoints: `/start` and `/stop` for managing auto mode. - Enhanced the status endpoint to provide detailed project-specific auto mode information. - Improved error handling and logging throughout the auto mode service. - Migrated legacy model IDs to their canonical counterparts in various components. This update aims to streamline the user experience and ensure a smooth transition for existing users while providing new functionalities.
168 lines
5.8 KiB
TypeScript
168 lines
5.8 KiB
TypeScript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
import {
|
|
resolveModelString,
|
|
getEffectiveModel,
|
|
CLAUDE_MODEL_MAP,
|
|
CURSOR_MODEL_MAP,
|
|
DEFAULT_MODELS,
|
|
} from '@automaker/model-resolver';
|
|
|
|
describe('model-resolver.ts', () => {
|
|
let consoleSpy: any;
|
|
|
|
beforeEach(() => {
|
|
consoleSpy = {
|
|
log: vi.spyOn(console, 'log').mockImplementation(() => {}),
|
|
warn: vi.spyOn(console, 'warn').mockImplementation(() => {}),
|
|
};
|
|
});
|
|
|
|
afterEach(() => {
|
|
consoleSpy.log.mockRestore();
|
|
consoleSpy.warn.mockRestore();
|
|
});
|
|
|
|
describe('resolveModelString', () => {
|
|
it("should resolve 'haiku' alias to full model string", () => {
|
|
const result = resolveModelString('haiku');
|
|
expect(result).toBe(CLAUDE_MODEL_MAP.haiku);
|
|
});
|
|
|
|
it("should resolve 'sonnet' alias to full model string", () => {
|
|
const result = resolveModelString('sonnet');
|
|
expect(result).toBe(CLAUDE_MODEL_MAP.sonnet);
|
|
});
|
|
|
|
it("should resolve 'opus' alias to full model string", () => {
|
|
const result = resolveModelString('opus');
|
|
expect(result).toBe('claude-opus-4-5-20251101');
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining('Migrated legacy ID: "opus" -> "claude-opus"')
|
|
);
|
|
});
|
|
|
|
it('should treat unknown models as falling back to default', () => {
|
|
// Note: Don't include valid Cursor model IDs here (e.g., 'gpt-5.2' is in CURSOR_MODEL_MAP)
|
|
const models = ['o1', 'o1-mini', 'o3', 'unknown-model', 'fake-model-123'];
|
|
models.forEach((model) => {
|
|
const result = resolveModelString(model);
|
|
// Should fall back to default since these aren't supported
|
|
expect(result).toBe(DEFAULT_MODELS.claude);
|
|
});
|
|
});
|
|
|
|
it('should pass through full Claude model strings', () => {
|
|
const models = [CLAUDE_MODEL_MAP.opus, CLAUDE_MODEL_MAP.sonnet, CLAUDE_MODEL_MAP.haiku];
|
|
models.forEach((model) => {
|
|
const result = resolveModelString(model);
|
|
expect(result).toBe(model);
|
|
});
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining('Using full Claude model string')
|
|
);
|
|
});
|
|
|
|
it('should return default model when modelKey is undefined', () => {
|
|
const result = resolveModelString(undefined);
|
|
expect(result).toBe(DEFAULT_MODELS.claude);
|
|
});
|
|
|
|
it('should return custom default model when provided', () => {
|
|
const customDefault = 'custom-model';
|
|
const result = resolveModelString(undefined, customDefault);
|
|
expect(result).toBe(customDefault);
|
|
});
|
|
|
|
it('should return default for unknown model key', () => {
|
|
const result = resolveModelString('unknown-model');
|
|
expect(result).toBe(DEFAULT_MODELS.claude);
|
|
expect(consoleSpy.warn).toHaveBeenCalledWith(
|
|
expect.stringContaining('Unknown model key "unknown-model"')
|
|
);
|
|
});
|
|
|
|
it('should handle empty string', () => {
|
|
const result = resolveModelString('');
|
|
expect(result).toBe(DEFAULT_MODELS.claude);
|
|
});
|
|
|
|
describe('Cursor models', () => {
|
|
it('should pass through cursor-prefixed models unchanged', () => {
|
|
const result = resolveModelString('cursor-composer-1');
|
|
expect(result).toBe('cursor-composer-1');
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(expect.stringContaining('Using Cursor model'));
|
|
});
|
|
|
|
it('should add cursor- prefix to bare Cursor model IDs', () => {
|
|
const result = resolveModelString('composer-1');
|
|
expect(result).toBe('cursor-composer-1');
|
|
});
|
|
|
|
it('should handle cursor-auto model', () => {
|
|
const result = resolveModelString('cursor-auto');
|
|
expect(result).toBe('cursor-auto');
|
|
});
|
|
|
|
it('should handle all known Cursor model IDs with prefix', () => {
|
|
const cursorModelIds = Object.keys(CURSOR_MODEL_MAP);
|
|
cursorModelIds.forEach((modelId) => {
|
|
const result = resolveModelString(`cursor-${modelId}`);
|
|
expect(result).toBe(`cursor-${modelId}`);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('getEffectiveModel', () => {
|
|
it('should prioritize explicit model over session and default', () => {
|
|
const result = getEffectiveModel('opus', 'haiku', 'gpt-5.2');
|
|
expect(result).toBe('claude-opus-4-5-20251101');
|
|
});
|
|
|
|
it('should use session model when explicit is not provided', () => {
|
|
const result = getEffectiveModel(undefined, 'sonnet', 'gpt-5.2');
|
|
expect(result).toBe(CLAUDE_MODEL_MAP.sonnet);
|
|
});
|
|
|
|
it('should use default when neither explicit nor session is provided', () => {
|
|
const customDefault = CLAUDE_MODEL_MAP.haiku;
|
|
const result = getEffectiveModel(undefined, undefined, customDefault);
|
|
expect(result).toBe(customDefault);
|
|
});
|
|
|
|
it('should use Claude default when no arguments provided', () => {
|
|
const result = getEffectiveModel();
|
|
expect(result).toBe(DEFAULT_MODELS.claude);
|
|
});
|
|
|
|
it('should handle explicit empty strings as undefined', () => {
|
|
const result = getEffectiveModel('', 'haiku');
|
|
expect(result).toBe(CLAUDE_MODEL_MAP.haiku);
|
|
});
|
|
});
|
|
|
|
describe('CLAUDE_MODEL_MAP', () => {
|
|
it('should have haiku, sonnet, opus mappings', () => {
|
|
expect(CLAUDE_MODEL_MAP).toHaveProperty('haiku');
|
|
expect(CLAUDE_MODEL_MAP).toHaveProperty('sonnet');
|
|
expect(CLAUDE_MODEL_MAP).toHaveProperty('opus');
|
|
});
|
|
|
|
it('should have valid Claude model strings', () => {
|
|
expect(CLAUDE_MODEL_MAP.haiku).toContain('haiku');
|
|
expect(CLAUDE_MODEL_MAP.sonnet).toContain('sonnet');
|
|
expect(CLAUDE_MODEL_MAP.opus).toContain('opus');
|
|
});
|
|
});
|
|
|
|
describe('DEFAULT_MODELS', () => {
|
|
it('should have claude default', () => {
|
|
expect(DEFAULT_MODELS).toHaveProperty('claude');
|
|
});
|
|
|
|
it('should have valid default model', () => {
|
|
expect(DEFAULT_MODELS.claude).toContain('claude');
|
|
});
|
|
});
|
|
});
|