···66const registry = new Map<string, ProviderFactory>();
7788/**
99- * Register an AI provider factory. Call this at module load time
1010- * (e.g., at the bottom of each provider file).
99+ * Register an AI provider factory. Prefer the `@AIProviderRegistration`
1010+ * class decorator for built-in providers; use this for programmatic registration.
1111 */
1212export const registerAIProvider = (
1313 type: string,
···1515): void => {
1616 registry.set(type, factory);
1717};
1818+1919+interface AIProviderStatic {
2020+ new (...args: any[]): AIProvider;
2121+ fromConfigService(configService: ConfigService): AIProvider;
2222+}
2323+2424+/**
2525+ * Class decorator that auto-registers an AI provider.
2626+ * The decorated class must have a static `fromConfigService` method.
2727+ */
2828+export const AIProviderRegistration = (type: string) =>
2929+ <T extends AIProviderStatic>(target: T): T => {
3030+ registry.set(type, (cs) => target.fromConfigService(cs));
3131+ return target;
3232+ };
18331934/**
2035 * Resolve a registered AI provider by type.
+22
packages/ai-provider/src/ai.module.ts
···3030 exports: [AI_PROVIDER],
3131 };
3232 }
3333+3434+ /**
3535+ * Resolve the AI provider type from ConfigService (AI_PROVIDER env var)
3636+ * at factory time, avoiding raw process.env assertions at the call site.
3737+ */
3838+ static forConfig(): DynamicModule {
3939+ return {
4040+ module: AIModule,
4141+ imports: [ConfigModule],
4242+ providers: [
4343+ {
4444+ provide: AI_PROVIDER,
4545+ inject: [ConfigService],
4646+ useFactory: (configService: ConfigService): AIProvider => {
4747+ const type = configService.get<AIProviderType>('AI_PROVIDER', 'llama-cpp');
4848+ return resolveAIProvider(type, configService);
4949+ },
5050+ },
5151+ ],
5252+ exports: [AI_PROVIDER],
5353+ };
5454+ }
3355}
+8-1
packages/ai-provider/src/index.ts
···22export type {
33 AIProvider,
44 AIProviderConfig,
55+ AIProviderStatus,
66+ AIProviderStatusDetails,
77+ LlamaCppStatusDetails,
88+ ApiProviderStatusDetails,
59 AICompletionRequest,
610 AICompletionResponse,
711} from './types';
8121313+// Base class
1414+export { BaseAIProvider, type RequestOptions } from './providers/base.provider';
1515+916// Providers
1017export {
1118 LlamaCppProvider, type LlamaCppConfig,
···1421} from './providers';
15221623// Registry
1717-export { registerAIProvider, resolveAIProvider, registeredProviderTypes } from './ai-provider.registry';
2424+export { registerAIProvider, AIProviderRegistration, resolveAIProvider, registeredProviderTypes } from './ai-provider.registry';
18251926// NestJS Module
2027export { AIModule, AI_PROVIDER, type AIModuleOptions, type AIProviderType } from './ai.module';
···11+export { BaseAIProvider, type RequestOptions } from './base.provider';
12export { LlamaCppProvider, type LlamaCppConfig } from './llama-cpp.provider';
23export { OpenAIProvider, type OpenAIConfig } from './openai.provider';
34export { AnthropicProvider, type AnthropicConfig } from './anthropic.provider';