Files
simple-ai-provider/src/utils/factory.ts
Jan-Marlon Leibl e10ce7f53a feat: add ClaudeCodeProvider for subscription users
Wraps @anthropic-ai/claude-agent-sdk so Claude Pro/Max subscribers (who
do not have a console API key) can use this library by authenticating
through the local `claude` CLI. Subscribers run `claude login` once and
the provider picks up the credentials automatically.

Provider behavior:
- query() is invoked in single-turn mode (maxTurns: 1, allowedTools: [])
  to behave as plain text completion by default. Both knobs are
  configurable for agentic use cases.
- Conversation history is flattened to a single prompt with role labels.
- doStream() emits text deltas as the SDK yields successive assistant
  messages. doComplete() accumulates and returns the final result.
- SDKAssistantMessageError codes (authentication_failed, billing_error,
  rate_limit, model_not_found, ...) map to AIErrorType variants.
- ClaudeCodeConfig.apiKey is optional — when omitted the SDK falls back
  to ANTHROPIC_API_KEY or local subscription credentials. The base
  validator is overridden to allow this.

Tradeoffs:
- Requires the `claude` CLI installed and logged in on the host. This
  is not suitable for typical server-side production deployments; it is
  the official path for subscription accounts.
- Higher latency (CLI process spawn) than the direct Anthropic API.
- The agent SDK is heavy. Bundle grows ~750KB; bun build now uses
  --target node so the SDK's Node built-in imports resolve correctly.

Wired into PROVIDER_REGISTRY ('claude-code'), createClaudeCodeProvider,
SUPPORTED_PROVIDERS, and re-exported from the package entry.
2026-05-21 14:16:11 +02:00

71 lines
2.0 KiB
TypeScript

/**
* Factory utilities for creating AI providers.
*/
import { ClaudeProvider, type ClaudeConfig } from '../providers/claude.js';
import { OpenAIProvider, type OpenAIConfig } from '../providers/openai.js';
import { GeminiProvider, type GeminiConfig } from '../providers/gemini.js';
import { OpenWebUIProvider, type OpenWebUIConfig } from '../providers/openwebui.js';
import { ClaudeCodeProvider, type ClaudeCodeConfig } from '../providers/claude-code.js';
import { BaseAIProvider } from '../providers/base.js';
export const PROVIDER_REGISTRY = {
claude: ClaudeProvider,
openai: OpenAIProvider,
gemini: GeminiProvider,
openwebui: OpenWebUIProvider,
'claude-code': ClaudeCodeProvider
} as const;
export type ProviderType = keyof typeof PROVIDER_REGISTRY;
export interface ProviderConfigMap {
claude: ClaudeConfig;
openai: OpenAIConfig;
gemini: GeminiConfig;
openwebui: OpenWebUIConfig;
'claude-code': ClaudeCodeConfig;
}
export function createProvider<T extends ProviderType>(
type: T,
config: ProviderConfigMap[T]
): BaseAIProvider {
const ProviderClass = PROVIDER_REGISTRY[type];
if (!ProviderClass) {
throw new Error(`Unsupported provider type: ${type}`);
}
return new ProviderClass(config as any);
}
export function createClaudeProvider(
apiKey: string,
options: Partial<Omit<ClaudeConfig, 'apiKey'>> = {}
): ClaudeProvider {
return new ClaudeProvider({ apiKey, ...options });
}
export function createOpenAIProvider(
apiKey: string,
options: Partial<Omit<OpenAIConfig, 'apiKey'>> = {}
): OpenAIProvider {
return new OpenAIProvider({ apiKey, ...options });
}
export function createGeminiProvider(
apiKey: string,
options: Partial<Omit<GeminiConfig, 'apiKey'>> = {}
): GeminiProvider {
return new GeminiProvider({ apiKey, ...options });
}
export function createOpenWebUIProvider(config: OpenWebUIConfig): OpenWebUIProvider {
return new OpenWebUIProvider(config);
}
export function createClaudeCodeProvider(
options: Partial<ClaudeCodeConfig> = {}
): ClaudeCodeProvider {
return new ClaudeCodeProvider(options);
}