Problem
Only openrouter.ts and kilo.ts are implemented in src/lib/llm/. The PROVIDER_MODELS map is hardcoded in index.ts. There is no way to add Anthropic Claude or a local Ollama endpoint without modifying core provider files. This makes the system brittle and not extensible.
Current State
src/lib/llm/
index.ts # hardcoded PROVIDER_MODELS map
openrouter.ts # OpenRouter provider
kilo.ts # KiloCode provider
types.ts # basic types
No ILLMProvider interface exists — providers are called directly without abstraction.
Proposed Implementation
1. Define ILLMProvider interface
// src/lib/llm/types.ts
export interface ILLMProvider {
id: string;
name: string;
chat(messages: Message[], options: ChatOptions): Promise<ChatResponse>;
stream?(messages: Message[], options: ChatOptions): AsyncIterable<string>;
listModels?(): Promise<ModelInfo[]>;
validate?(apiKey: string): Promise<boolean>;
}
export interface ChatOptions {
model: string;
temperature?: number;
maxTokens?: number;
systemPrompt?: string;
tools?: ToolDefinition[];
}
2. Provider registry
// src/lib/llm/registry.ts
const providers = new Map<string, ILLMProvider>();
export function registerProvider(provider: ILLMProvider) {
providers.set(provider.id, provider);
}
export function getProvider(id: string): ILLMProvider {
const p = providers.get(id);
if (!p) throw new Error(`Unknown LLM provider: ${id}`);
return p;
}
export function listProviders(): ILLMProvider[] {
return Array.from(providers.values());
}
3. Anthropic Claude adapter
// src/lib/llm/anthropic.ts
import Anthropic from '@anthropic-ai/sdk';
export class AnthropicProvider implements ILLMProvider {
id = 'anthropic';
name = 'Anthropic Claude';
async chat(messages: Message[], opts: ChatOptions): Promise<ChatResponse> {
const client = new Anthropic({ apiKey: opts.apiKey });
const response = await client.messages.create({
model: opts.model,
max_tokens: opts.maxTokens ?? 4096,
messages: messages.filter(m => m.role !== 'system').map(m => ({
role: m.role as 'user' | 'assistant',
content: m.content
})),
system: messages.find(m => m.role === 'system')?.content,
});
return { content: response.content[0].type === 'text' ? response.content[0].text : '' };
}
}
4. Ollama local adapter
// src/lib/llm/ollama.ts
export class OllamaProvider implements ILLMProvider {
id = 'ollama';
name = 'Ollama (Local)';
constructor(private baseURL = 'http://localhost:11434') {}
async chat(messages: Message[], opts: ChatOptions): Promise<ChatResponse> {
const res = await fetch(`${this.baseURL}/api/chat`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: opts.model,
messages,
stream: false,
}),
});
const data = await res.json();
return { content: data.message.content };
}
async listModels(): Promise<ModelInfo[]> {
const res = await fetch(`${this.baseURL}/api/tags`);
const data = await res.json();
return data.models.map((m: any) => ({ id: m.name, name: m.name }));
}
}
5. Settings UI additions
- Add
Provider dropdown in AI settings with: OpenRouter, KiloCode, Anthropic, Ollama
- Ollama: show
baseURL input field (default: http://localhost:11434)
- Auto-detect available Ollama models via
listModels() call
Acceptance Criteria
Problem
Only
openrouter.tsandkilo.tsare implemented insrc/lib/llm/. ThePROVIDER_MODELSmap is hardcoded inindex.ts. There is no way to add Anthropic Claude or a local Ollama endpoint without modifying core provider files. This makes the system brittle and not extensible.Current State
No
ILLMProviderinterface exists — providers are called directly without abstraction.Proposed Implementation
1. Define
ILLMProviderinterface2. Provider registry
3. Anthropic Claude adapter
4. Ollama local adapter
5. Settings UI additions
Providerdropdown in AI settings with: OpenRouter, KiloCode, Anthropic, OllamabaseURLinput field (default:http://localhost:11434)listModels()callAcceptance Criteria
ILLMProviderinterface defined intypes.tsProviderRegistryimplemented withregister/get/listfunctionsAnthropicProviderimplemented and unit tested with mockOllamaProviderimplemented and unit tested with mock HTTP serverbaseURLoverride support for custom OpenAI-compatible endpointsILLMProvider