feat(M3-001): refactor ProviderService into IProviderAdapter pattern
Introduces the IProviderAdapter interface as the architecture foundation for multi-provider support. Extracts Ollama logic into OllamaAdapter and makes ProviderService adapter-aware while preserving the full existing API. ## What changed ### @mosaic/types — new provider adapter types - IProviderAdapter interface: register(), listModels(), healthCheck(), createCompletion() - ProviderHealth / ProviderHealthStatus — health check result - CompletionParams / CompletionMessage / CompletionTool — completion request - CompletionEvent / CompletionUsage — streamed completion response ### apps/gateway — adapter implementation - apps/gateway/src/agent/adapters/ollama.adapter.ts — OllamaAdapter (extracted from ProviderService) - apps/gateway/src/agent/adapters/index.ts — barrel export - ProviderService.onModuleInit() is now async (awaits registerAll()) - New ProviderService methods: registerAll(), getAdapter(), healthCheckAll() - PROVIDER_ADAPTERS symbol exported as future DI injection token - Anthropic/OpenAI/Z.ai remain as direct registry calls (M3-002 to M3-005 scope) - Updated provider.service.test.ts: all tests now await onModuleInit() ## Pi SDK compatibility findings Pi SDK uses ModelRegistry as central registry. The adapter pattern is a Mosaic abstraction layered on top — adapters call registry.registerProvider() during register(). Pi SDK has no native adapter concept; it does not conflict. createCompletion() is defined in the interface but not called by the Pi layer. Pi SDK's AgentSession.prompt() and ModelRegistry.getAvailable() handle all actual completions. createCompletion() is reserved for future direct-completion use cases (post-M3 scope). OllamaAdapter throws NotImplementedError for now. No Pi SDK friction was found for the adapter pattern. The registry integration point (registerProvider()) is exactly what the existing code already used. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -52,3 +52,100 @@ export interface CustomProviderConfig {
|
||||
maxTokens?: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// IProviderAdapter pattern — M3-001
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Health status of a provider */
|
||||
export type ProviderHealthStatus = 'healthy' | 'degraded' | 'down';
|
||||
|
||||
/** Result of a provider health check */
|
||||
export interface ProviderHealth {
|
||||
status: ProviderHealthStatus;
|
||||
/** Round-trip latency in milliseconds (undefined when provider is down) */
|
||||
latencyMs?: number;
|
||||
/** ISO-8601 timestamp of the check */
|
||||
lastChecked: string;
|
||||
/** Human-readable error message (defined when status is not healthy) */
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/** A single message in a completion request */
|
||||
export interface CompletionMessage {
|
||||
role: 'system' | 'user' | 'assistant';
|
||||
content: string;
|
||||
}
|
||||
|
||||
/** Tool definition for completion requests */
|
||||
export interface CompletionTool {
|
||||
name: string;
|
||||
description: string;
|
||||
parameters: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/** Parameters for a completion request */
|
||||
export interface CompletionParams {
|
||||
model: string;
|
||||
messages: CompletionMessage[];
|
||||
tools?: CompletionTool[];
|
||||
temperature?: number;
|
||||
maxTokens?: number;
|
||||
stream?: boolean;
|
||||
}
|
||||
|
||||
/** Usage statistics for a completion event */
|
||||
export interface CompletionUsage {
|
||||
inputTokens: number;
|
||||
outputTokens: number;
|
||||
}
|
||||
|
||||
/** A streamed completion event */
|
||||
export type CompletionEvent =
|
||||
| { type: 'text_delta'; content: string }
|
||||
| { type: 'tool_call'; name: string; arguments: string }
|
||||
| { type: 'done'; usage?: CompletionUsage };
|
||||
|
||||
/**
|
||||
* Pluggable provider adapter interface.
|
||||
*
|
||||
* Each LLM provider (Anthropic, OpenAI, Ollama, etc.) implements this interface
|
||||
* to integrate with Mosaic's provider layer. The ProviderService aggregates all
|
||||
* registered adapters and routes requests accordingly.
|
||||
*
|
||||
* Note on createCompletion: this method is part of the interface for future
|
||||
* direct-completion use cases. The current Pi SDK integration routes completions
|
||||
* through the Pi session/ModelRegistry layer rather than calling adapters directly.
|
||||
* Adapters MUST still implement register() and healthCheck() correctly — those are
|
||||
* used by ProviderService today.
|
||||
*/
|
||||
export interface IProviderAdapter {
|
||||
/** Unique provider identifier (e.g. 'anthropic', 'openai', 'ollama') */
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* Initialize the provider — connect, discover models, register with the
|
||||
* Pi ModelRegistry. Called once at module startup by ProviderService.registerAll().
|
||||
*/
|
||||
register(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Return the list of models this adapter makes available.
|
||||
* Returns an empty array when the provider is not configured.
|
||||
*/
|
||||
listModels(): ModelInfo[];
|
||||
|
||||
/**
|
||||
* Check whether the provider endpoint is reachable and responsive.
|
||||
*/
|
||||
healthCheck(): Promise<ProviderHealth>;
|
||||
|
||||
/**
|
||||
* Stream a completion from the provider.
|
||||
*
|
||||
* Note: Currently reserved for future use. The Pi SDK integration routes
|
||||
* completions through ModelRegistry / AgentSession rather than this method.
|
||||
* Implementations may throw NotImplementedError until M3+ tasks wire this up.
|
||||
*/
|
||||
createCompletion(params: CompletionParams): AsyncIterable<CompletionEvent>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user