diff --git a/packages/ai-providers/server-ai-langchain/README.md b/packages/ai-providers/server-ai-langchain/README.md index bfc35f7d27..f899682093 100644 --- a/packages/ai-providers/server-ai-langchain/README.md +++ b/packages/ai-providers/server-ai-langchain/README.md @@ -20,7 +20,7 @@ ## Quick Setup -This package provides LangChain integration for the LaunchDarkly AI SDK. The simplest way to use it is with the LaunchDarkly AI SDK's `initChat` method: +This package provides LangChain integration for the LaunchDarkly AI SDK. The simplest way to use it is with the LaunchDarkly AI SDK's `createModel` method: 1. Install the required packages: @@ -30,7 +30,7 @@ npm install @launchdarkly/server-sdk-ai @launchdarkly/server-sdk-ai-langchain -- yarn add @launchdarkly/server-sdk-ai @launchdarkly/server-sdk-ai-langchain ``` -2. Create a chat session and use it: +2. Create a managed model and run it: ```typescript import { init } from '@launchdarkly/node-server-sdk'; @@ -40,17 +40,17 @@ import { initAi } from '@launchdarkly/server-sdk-ai'; const ldClient = init(sdkKey); const aiClient = initAi(ldClient); -// Create a chat session -const defaultConfig = { - enabled: true, +// Create a managed model +const defaultConfig = { + enabled: true, model: { name: 'gpt-4' }, provider: { name: 'openai' } }; -const chat = await aiClient.initChat('my-chat-config', context, defaultConfig); +const model = await aiClient.createModel('my-chat-config', context, defaultConfig); -if (chat) { - const response = await chat.invoke('What is the capital of France?'); - console.log(response.message.content); +if (model) { + const result = await model.run('What is the capital of France?'); + console.log(result.content); } ``` diff --git a/packages/ai-providers/server-ai-langchain/src/LangChainRunnerFactory.ts b/packages/ai-providers/server-ai-langchain/src/LangChainRunnerFactory.ts index 482447c900..f00cfb0e14 100644 --- a/packages/ai-providers/server-ai-langchain/src/LangChainRunnerFactory.ts +++ b/packages/ai-providers/server-ai-langchain/src/LangChainRunnerFactory.ts @@ -29,7 +29,7 @@ export class LangChainRunnerFactory extends AIProvider { */ async createModel(config: LDAICompletionConfig): Promise { const llm = await createLangChainModel(config); - return new LangChainModelRunner(llm, config, this.logger); + return new LangChainModelRunner(llm, config, this._logger); } /** @@ -51,7 +51,7 @@ export class LangChainRunnerFactory extends AIProvider { }; const llm = await createLangChainModel(configForModel); - const lcTools = buildStructuredTools(toolDefinitions, tools ?? {}, this.logger); + const lcTools = buildStructuredTools(toolDefinitions, tools ?? {}, this._logger); const instructions = config.instructions ?? ''; const agent = createAgent({ @@ -60,7 +60,7 @@ export class LangChainRunnerFactory extends AIProvider { systemPrompt: instructions || undefined, }); - return new LangChainAgentRunner(agent as any, this.logger); + return new LangChainAgentRunner(agent as any, this._logger); } /** diff --git a/packages/ai-providers/server-ai-openai/README.md b/packages/ai-providers/server-ai-openai/README.md index 6cc18807df..dbc01cd941 100644 --- a/packages/ai-providers/server-ai-openai/README.md +++ b/packages/ai-providers/server-ai-openai/README.md @@ -23,7 +23,7 @@ ## Quick Setup -This package provides OpenAI integration for the LaunchDarkly AI SDK. The simplest way to use it is with the LaunchDarkly AI SDK's `initChat` method: +This package provides OpenAI integration for the LaunchDarkly AI SDK. The simplest way to use it is with the LaunchDarkly AI SDK's `createModel` method: 1. Install the required packages: @@ -31,7 +31,7 @@ This package provides OpenAI integration for the LaunchDarkly AI SDK. The simple npm install @launchdarkly/server-sdk-ai @launchdarkly/server-sdk-ai-openai --save ``` -2. Create a chat session and use it: +2. Create a managed model and run it: ```typescript import { init } from '@launchdarkly/node-server-sdk'; @@ -41,17 +41,17 @@ import { initAi } from '@launchdarkly/server-sdk-ai'; const ldClient = init(sdkKey); const aiClient = initAi(ldClient); -// Create a chat session -const defaultConfig = { - enabled: true, +// Create a managed model +const defaultConfig = { + enabled: true, model: { name: 'gpt-4' }, provider: { name: 'openai' } }; -const chat = await aiClient.initChat('my-chat-config', context, defaultConfig); +const model = await aiClient.createModel('my-chat-config', context, defaultConfig); -if (chat) { - const response = await chat.invoke("What is the capital of France?"); - console.log(response.message.content); +if (model) { + const result = await model.run('What is the capital of France?'); + console.log(result.content); } ``` diff --git a/packages/ai-providers/server-ai-openai/src/OpenAIRunnerFactory.ts b/packages/ai-providers/server-ai-openai/src/OpenAIRunnerFactory.ts index 97eebf64bb..9f99f7d798 100644 --- a/packages/ai-providers/server-ai-openai/src/OpenAIRunnerFactory.ts +++ b/packages/ai-providers/server-ai-openai/src/OpenAIRunnerFactory.ts @@ -30,7 +30,7 @@ export class OpenAIRunnerFactory extends AIProvider { * Create a model runner from a completion AI configuration. */ async createModel(config: LDAICompletionConfig): Promise { - return new OpenAIModelRunner(this._client, config, this.logger); + return new OpenAIModelRunner(this._client, config, this._logger); } /** @@ -67,7 +67,12 @@ export class OpenAIRunnerFactory extends AIProvider { const parameters = mapParameterKeys({ ...(config.model?.parameters ?? {}) }); delete parameters.tools; - const { agentTools, toolNameMap } = buildAgentTools(toolHelper, configTools, registry, this.logger); + const { agentTools, toolNameMap } = buildAgentTools( + toolHelper, + configTools, + registry, + this._logger, + ); const agent = new Agent({ name: 'ldai-agent', instructions: config.instructions || undefined, @@ -76,7 +81,7 @@ export class OpenAIRunnerFactory extends AIProvider { modelSettings: parameters, }); - return new OpenAIAgentRunner(agent, agentRun, toolNameMap, this.logger); + return new OpenAIAgentRunner(agent, agentRun, toolNameMap, this._logger); } /** diff --git a/packages/ai-providers/server-ai-vercel/README.md b/packages/ai-providers/server-ai-vercel/README.md index fb65d1832f..f320194983 100644 --- a/packages/ai-providers/server-ai-vercel/README.md +++ b/packages/ai-providers/server-ai-vercel/README.md @@ -20,7 +20,7 @@ ## Quick Setup -This package provides Vercel AI SDK integration for the LaunchDarkly AI SDK. The simplest way to use it is with the LaunchDarkly AI SDK's `initChat` method: +This package provides Vercel AI SDK integration for the LaunchDarkly AI SDK. The simplest way to use it is with the LaunchDarkly AI SDK's `createModel` method: 1. Install the required packages: @@ -30,7 +30,7 @@ npm install @launchdarkly/server-sdk-ai @launchdarkly/server-sdk-ai-vercel --sav yarn add @launchdarkly/server-sdk-ai @launchdarkly/server-sdk-ai-vercel ``` -2. Create a chat session and use it: +2. Create a managed model and run it: ```typescript import { init } from '@launchdarkly/node-server-sdk'; @@ -40,17 +40,17 @@ import { initAi } from '@launchdarkly/server-sdk-ai'; const ldClient = init(sdkKey); const aiClient = initAi(ldClient); -// Create a chat session -const defaultConfig = { - enabled: true, +// Create a managed model +const defaultConfig = { + enabled: true, model: { name: 'gpt-4' }, provider: { name: 'openai' } }; -const chat = await aiClient.initChat('my-chat-config', context, defaultConfig); +const model = await aiClient.createModel('my-chat-config', context, defaultConfig); -if (chat) { - const response = await chat.invoke('What is the capital of France?'); - console.log(response.message.content); +if (model) { + const result = await model.run('What is the capital of France?'); + console.log(result.content); } ``` diff --git a/packages/ai-providers/server-ai-vercel/src/VercelRunnerFactory.ts b/packages/ai-providers/server-ai-vercel/src/VercelRunnerFactory.ts index 0510900e3d..9869301314 100644 --- a/packages/ai-providers/server-ai-vercel/src/VercelRunnerFactory.ts +++ b/packages/ai-providers/server-ai-vercel/src/VercelRunnerFactory.ts @@ -25,7 +25,7 @@ export class VercelRunnerFactory extends AIProvider { async createModel(config: LDAICompletionConfig): Promise { const model = await VercelRunnerFactory.createVercelModel(config); const parameters = VercelRunnerFactory.mapParameters(config.model?.parameters); - return new VercelModelRunner(model, config, parameters, this.logger); + return new VercelModelRunner(model, config, parameters, this._logger); } /** diff --git a/packages/sdk/server-ai/README.md b/packages/sdk/server-ai/README.md index 96e2faf4b0..081bfbc831 100644 --- a/packages/sdk/server-ai/README.md +++ b/packages/sdk/server-ai/README.md @@ -79,37 +79,34 @@ if (aiConfig.enabled) { } ``` -## TrackedChat for Conversational AI +## ManagedModel for Tracked Model Invocations -`TrackedChat` provides a high-level interface for conversational AI with automatic conversation management and metrics tracking: +`ManagedModel` provides a high-level interface for invoking AI models with automatic metrics tracking and judge evaluation: - Automatically configures models based on AI configuration -- Maintains conversation history across multiple interactions - Automatically tracks token usage, latency, and success rates +- Runs configured judges asynchronously and reports their results - Works with any supported AI provider (see [AI Providers](https://github.com/launchdarkly/js-core#ai-providers) for available packages) -### Using TrackedChat +### Using ManagedModel ```typescript // Use the same defaultConfig from the retrieval section above -const chat = await aiClient.createChat( +const model = await aiClient.createModel( 'customer-support-chat', context, defaultConfig, { customerName: 'John' } ); -if (chat) { - // Simple conversation flow - metrics are automatically tracked by invoke() - const response1 = await chat.invoke('I need help with my order'); - console.log(response1.message.content); - - const response2 = await chat.invoke("What's the status?"); - console.log(response2.message.content); - - // Access conversation history - const messages = chat.getMessages(); - console.log(`Conversation has ${messages.length} messages`); +if (model) { + // Metrics are automatically tracked by run() + const result = await model.run('I need help with my order'); + console.log(result.content); + + // Judge evaluations run asynchronously; await if you need their results + const evals = await result.evaluations; + console.log('Judge results:', evals); } ``` diff --git a/packages/sdk/server-ai/__tests__/LDAIClientImpl.test.ts b/packages/sdk/server-ai/__tests__/LDAIClientImpl.test.ts index 0e5ca6de0e..29a33aec1a 100644 --- a/packages/sdk/server-ai/__tests__/LDAIClientImpl.test.ts +++ b/packages/sdk/server-ai/__tests__/LDAIClientImpl.test.ts @@ -634,7 +634,7 @@ describe('createJudge method', () => { beforeEach(() => { mockProvider = { - invokeStructuredModel: jest.fn(), + run: jest.fn(), }; mockJudge = { diff --git a/packages/sdk/server-ai/__tests__/RunnerFactory.test.ts b/packages/sdk/server-ai/__tests__/RunnerFactory.test.ts index f76ca556e9..b7aa331fa7 100644 --- a/packages/sdk/server-ai/__tests__/RunnerFactory.test.ts +++ b/packages/sdk/server-ai/__tests__/RunnerFactory.test.ts @@ -1,4 +1,7 @@ -import { LDAIConfigKind } from '../src/api/config/types'; +import { + LDAIAgentConfig, + LDAICompletionConfig, +} from '../src/api/config/types'; import { AIProvider, ToolRegistry } from '../src/api/providers/AIProvider'; import { AgentGraphRunner, Runner } from '../src/api/providers/Runner'; import { RunnerFactory, SupportedAIProvider } from '../src/api/providers/RunnerFactory'; @@ -7,14 +10,23 @@ import { RunnerFactory, SupportedAIProvider } from '../src/api/providers/RunnerF // Helpers // --------------------------------------------------------------------------- -const makeConfig = (providerName: string): LDAIConfigKind => +const makeConfig = (providerName: string): LDAICompletionConfig => ({ key: 'test-config', enabled: true, provider: { name: providerName }, createTracker: () => ({}) as any, evaluator: {} as any, - }) as unknown as LDAIConfigKind; + }) as unknown as LDAICompletionConfig; + +const makeAgentConfig = (providerName: string): LDAIAgentConfig => + ({ + key: 'test-agent-config', + enabled: true, + provider: { name: providerName }, + createTracker: () => ({}) as any, + evaluator: {} as any, + }) as unknown as LDAIAgentConfig; const makeRunner = (): Runner => ({ run: jest.fn() }); const makeGraphRunner = (): AgentGraphRunner => ({ run: jest.fn() }); @@ -162,7 +174,7 @@ describe('RunnerFactory.createAgent', () => { jest.spyOn(RunnerFactory as any, '_getProviderFactory').mockResolvedValue(mockFactory); - const result = await RunnerFactory.createAgent(makeConfig('openai'), tools); + const result = await RunnerFactory.createAgent(makeAgentConfig('openai'), tools); expect(result).toBe(runner); expect(mockFactory.createAgent).toHaveBeenCalledWith( @@ -177,7 +189,11 @@ describe('RunnerFactory.createAgent', () => { jest.spyOn(RunnerFactory as any, '_getProviderFactory').mockResolvedValue(undefined); - const result = await RunnerFactory.createAgent(makeConfig('openai'), undefined, logger as any); + const result = await RunnerFactory.createAgent( + makeAgentConfig('openai'), + undefined, + logger as any, + ); expect(result).toBeUndefined(); expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('not supported')); @@ -243,7 +259,7 @@ describe('AIProvider default factory methods', () => { it('createAgent returns undefined by default', async () => { const provider = new ConcreteProvider(); - const result = await provider.createAgent(makeConfig('openai')); + const result = await provider.createAgent(makeAgentConfig('openai')); expect(result).toBeUndefined(); }); @@ -252,25 +268,4 @@ describe('AIProvider default factory methods', () => { const result = await provider.createAgentGraph({} as any); expect(result).toBeUndefined(); }); - - it('createModel warns when not overridden', async () => { - const warnSpy = jest.fn(); - const provider = new ConcreteProvider({ warn: warnSpy } as any); - await provider.createModel(makeConfig('openai')); - expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('createModel not implemented')); - }); - - it('createAgent warns when not overridden', async () => { - const warnSpy = jest.fn(); - const provider = new ConcreteProvider({ warn: warnSpy } as any); - await provider.createAgent(makeConfig('openai')); - expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('createAgent not implemented')); - }); - - it('createAgentGraph warns when not overridden', async () => { - const warnSpy = jest.fn(); - const provider = new ConcreteProvider({ warn: warnSpy } as any); - await provider.createAgentGraph({} as any); - expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('createAgentGraph not implemented')); - }); }); diff --git a/packages/sdk/server-ai/examples/openai-observability/README.md b/packages/sdk/server-ai/examples/openai-observability/README.md index 2e43d77f58..a958d45575 100644 --- a/packages/sdk/server-ai/examples/openai-observability/README.md +++ b/packages/sdk/server-ai/examples/openai-observability/README.md @@ -1,6 +1,6 @@ # Provider-Specific Observability Example (OpenAI) -This example shows how to use the LaunchDarkly observability plugin when calling an AI provider directly — without the higher-level `createChat` abstraction. It uses OpenAI as the provider, but the same pattern applies to any provider (Bedrock, Anthropic, Vercel AI SDK, etc.). +This example shows how to use the LaunchDarkly observability plugin when calling an AI provider directly — without the higher-level `createModel` abstraction. It uses OpenAI as the provider, but the same pattern applies to any provider (Bedrock, Anthropic, Vercel AI SDK, etc.). ## How it works diff --git a/packages/sdk/server-ai/src/LDAIClientImpl.ts b/packages/sdk/server-ai/src/LDAIClientImpl.ts index c655db2551..8ff4c59769 100644 --- a/packages/sdk/server-ai/src/LDAIClientImpl.ts +++ b/packages/sdk/server-ai/src/LDAIClientImpl.ts @@ -340,19 +340,6 @@ export class LDAIClientImpl implements LDAIClient { return this.agentConfigs(agentConfigs, context); } - /** - * @deprecated Use `createModel` instead. This method will be removed in a future version. - */ - async createChat( - key: string, - context: LDContext, - defaultValue?: LDAICompletionConfigDefault, - variables?: Record, - defaultAiProvider?: SupportedAIProvider, - ): Promise { - return this.createModel(key, context, defaultValue, variables, defaultAiProvider); - } - async createJudge( key: string, context: LDContext, @@ -483,6 +470,19 @@ export class LDAIClientImpl implements LDAIClient { return new ManagedAgent(config, runner, this._logger); } + /** + * @deprecated Use `createModel` instead. This method will be removed in a future version. + */ + async createChat( + key: string, + context: LDContext, + defaultValue?: LDAICompletionConfigDefault, + variables?: Record, + defaultAiProvider?: SupportedAIProvider, + ): Promise { + return this.createModel(key, context, defaultValue, variables, defaultAiProvider); + } + /** * @deprecated Use `createModel` instead. This method will be removed in a future version. */ diff --git a/packages/sdk/server-ai/src/api/judge/index.ts b/packages/sdk/server-ai/src/api/judge/index.ts index ca86630278..4fa3bbb60a 100644 --- a/packages/sdk/server-ai/src/api/judge/index.ts +++ b/packages/sdk/server-ai/src/api/judge/index.ts @@ -1,2 +1,2 @@ export { Judge } from './Judge'; -export type { LDJudgeResult, StructuredResponse } from './types'; +export type { LDJudgeResult } from './types'; diff --git a/packages/sdk/server-ai/src/api/judge/types.ts b/packages/sdk/server-ai/src/api/judge/types.ts index b9d8a05a46..381eb97d90 100644 --- a/packages/sdk/server-ai/src/api/judge/types.ts +++ b/packages/sdk/server-ai/src/api/judge/types.ts @@ -1,21 +1,3 @@ -import { LDAIMetrics } from '../metrics/LDAIMetrics'; - -/** - * Structured response from AI models. - */ -export interface StructuredResponse { - /** The structured data returned by the model */ - data: Record; - - /** The raw response from the model */ - rawResponse: string; - - /** - * Metrics information including success status and token usage. - */ - metrics: LDAIMetrics; -} - /** * Result from a judge evaluation containing score, reasoning, and metadata. */ diff --git a/packages/sdk/server-ai/src/api/providers/AIProvider.ts b/packages/sdk/server-ai/src/api/providers/AIProvider.ts index 62a1fd55e5..c795f36d35 100644 --- a/packages/sdk/server-ai/src/api/providers/AIProvider.ts +++ b/packages/sdk/server-ai/src/api/providers/AIProvider.ts @@ -1,9 +1,7 @@ import { LDLogger } from '@launchdarkly/js-server-sdk-common'; -import { ChatResponse } from '../chat/types'; -import { LDAIConfigKind, LDMessage } from '../config/types'; +import { LDAIAgentConfig, LDAICompletionConfig, LDAIJudgeConfig } from '../config/types'; import { AgentGraphDefinition } from '../graph/AgentGraphDefinition'; -import { StructuredResponse } from '../judge/types'; import { AgentGraphRunner, Runner } from './Runner'; /** @@ -14,97 +12,36 @@ import { AgentGraphRunner, Runner } from './Runner'; export type ToolRegistry = Record unknown>; /** - * Abstract base class for AI providers that implement chat model functionality. - * This class provides the contract that all provider implementations must follow - * to integrate with LaunchDarkly's tracking and configuration capabilities. + * Abstract base class for AI providers. * - * Following the AICHAT spec recommendation to use base classes with non-abstract methods - * for better extensibility and backwards compatibility. + * An `AIProvider` is a per-provider factory: it is instantiated once per + * provider package and is responsible for constructing focused runtime + * capability objects via {@link createModel}, {@link createAgent}, and + * {@link createAgentGraph}. + * + * Provider packages subclass `AIProvider` and override the methods they + * support. The default implementations return `undefined`, mirroring Python's + * base-class behaviour, so providers only need to implement the modes they + * actually support. */ export abstract class AIProvider { - protected readonly logger?: LDLogger; + // eslint-disable-next-line @typescript-eslint/naming-convention + protected _logger?: LDLogger; constructor(logger?: LDLogger) { - this.logger = logger; - } - /** - * Invoke the chat model with an array of messages. - * - * Default implementation takes no action and returns a placeholder response. - * Provider implementations should override this method. - * - * @deprecated Use the `Runner` interface and its `run` method instead. - * @param messages Array of LDMessage objects representing the conversation - * @returns Promise that resolves to a ChatResponse containing the model's response - */ - async invokeModel(_messages: LDMessage[]): Promise { - this.logger?.warn('invokeModel not implemented by this provider'); - return { - message: { - role: 'assistant', - content: '', - }, - metrics: { - success: false, - usage: { - total: 0, - input: 0, - output: 0, - }, - }, - }; - } - - /** - * Invoke the chat model with structured output support. - * - * Default implementation takes no action and returns a placeholder response. - * Provider implementations should override this method. - * - * @deprecated Use the `Runner` interface and its `run` method with `outputType` instead. - * @param messages Array of LDMessage objects representing the conversation - * @param responseStructure Dictionary of output configurations keyed by output name - * @returns Promise that resolves to a structured response - */ - async invokeStructuredModel( - _messages: LDMessage[], - _responseStructure: Record, - ): Promise { - this.logger?.warn('invokeStructuredModel not implemented by this provider'); - return { - data: {}, - rawResponse: '', - metrics: { - success: false, - usage: { - total: 0, - input: 0, - output: 0, - }, - }, - }; + this._logger = logger; } - - // ============================================================================ - // Factory instance methods (Python AIProvider pattern) - // - // Provider packages override these to return a configured Runner for the - // relevant mode. The default implementations log a warning and return - // undefined, mirroring Python's base-class behaviour. - // ============================================================================ - /** * Create a Runner for a completion or judge AI Config. * * Override in provider subclasses to return a configured {@link Runner}. - * Default implementation logs a warning and returns `undefined`. + * Default implementation returns `undefined`. * * @param config The completion or judge AI configuration. * @returns Promise resolving to a {@link Runner}, or `undefined` if this * provider does not support model creation. */ - async createModel(_config: LDAIConfigKind): Promise { - this.logger?.warn('createModel not implemented by this provider'); + async createModel(_config: LDAICompletionConfig | LDAIJudgeConfig): Promise { return undefined; } @@ -112,15 +49,14 @@ export abstract class AIProvider { * Create a Runner for an agent AI Config. * * Override in provider subclasses to return a configured {@link Runner}. - * Default implementation logs a warning and returns `undefined`. + * Default implementation returns `undefined`. * * @param config The agent AI configuration. * @param tools Optional registry of callable tools. * @returns Promise resolving to a {@link Runner}, or `undefined` if this * provider does not support agent creation. */ - async createAgent(_config: LDAIConfigKind, _tools?: ToolRegistry): Promise { - this.logger?.warn('createAgent not implemented by this provider'); + async createAgent(_config: LDAIAgentConfig, _tools?: ToolRegistry): Promise { return undefined; } @@ -128,7 +64,7 @@ export abstract class AIProvider { * Create an AgentGraphRunner for an agent graph definition. * * Override in provider subclasses to return a configured {@link AgentGraphRunner}. - * Default implementation logs a warning and returns `undefined`. + * Default implementation returns `undefined`. * * @param graphDef The agent graph definition. * @param tools Optional registry of callable tools. @@ -139,26 +75,6 @@ export abstract class AIProvider { _graphDef: AgentGraphDefinition, _tools?: ToolRegistry, ): Promise { - this.logger?.warn('createAgentGraph not implemented by this provider'); return undefined; } - - // ============================================================================ - // Legacy static factory (retained for backward compatibility) - // ============================================================================ - - /** - * Static method that constructs an instance of the provider. - * Each provider implementation must provide their own static create method - * that accepts an AIConfig and returns a configured instance. - * - * @deprecated Use the `createModel` factory method instead. - * @param aiConfig The LaunchDarkly AI configuration - * @param logger Optional logger for the provider - * @returns Promise that resolves to a configured provider instance - */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - static async create(aiConfig: LDAIConfigKind, logger?: LDLogger): Promise { - throw new Error('Provider implementations must override the static create method'); - } } diff --git a/packages/sdk/server-ai/src/api/providers/RunnerFactory.ts b/packages/sdk/server-ai/src/api/providers/RunnerFactory.ts index d02c79d445..0451118495 100644 --- a/packages/sdk/server-ai/src/api/providers/RunnerFactory.ts +++ b/packages/sdk/server-ai/src/api/providers/RunnerFactory.ts @@ -1,6 +1,10 @@ import { LDLogger } from '@launchdarkly/js-server-sdk-common'; -import { LDAIConfigKind } from '../config/types'; +import { + LDAIAgentConfig, + LDAICompletionConfig, + LDAIJudgeConfig, +} from '../config/types'; import { AgentGraphDefinition } from '../graph/AgentGraphDefinition'; import { AIProvider, ToolRegistry } from './AIProvider'; import { AgentGraphRunner, Runner } from './Runner'; @@ -29,21 +33,16 @@ export type SupportedAIProvider = (typeof SUPPORTED_AI_PROVIDERS)[number]; * via {@link _getProviderFactory}, and delegates creation to the factory * instance methods on {@link AIProvider}. * - * Provider packages implement {@link AIProvider} factory methods - * (`createModel`, `createAgent`, `createAgentGraph`). The legacy - * {@link AIProvider} abstract class is retained for backward compatibility, - * and the {@link _LegacyProviderAdapter} shim wraps packages that have not - * yet migrated to the new pattern. + * Provider packages subclass {@link AIProvider} and override its factory + * methods (`createModel`, `createAgent`, `createAgentGraph`). */ export class RunnerFactory { /** * Load and return the AIProvider factory for the given provider type. * * This is the single place in the codebase that knows provider package names. - * If the provider package exports the new `*RunnerFactory` class, it is - * instantiated directly. Otherwise a {@link _LegacyProviderAdapter} wrapping - * the old `static create()` class is returned to keep CI green during the - * transition. + * Each supported provider package exports a `*RunnerFactory` class that + * extends {@link AIProvider}; this method instantiates it directly. * * @param providerType One of the {@link SUPPORTED_AI_PROVIDERS} values. * @param logger Optional logger forwarded to the provider factory. @@ -163,7 +162,7 @@ export class RunnerFactory { * `undefined` if no suitable provider could be loaded. */ static async createModel( - config: LDAIConfigKind, + config: LDAICompletionConfig | LDAIJudgeConfig, logger?: LDLogger, defaultAiProvider?: SupportedAIProvider, ): Promise { @@ -200,7 +199,7 @@ export class RunnerFactory { * provider could be loaded. */ static async createAgent( - config: LDAIConfigKind, + config: LDAIAgentConfig, tools?: ToolRegistry, logger?: LDLogger, defaultAiProvider?: SupportedAIProvider,