Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions packages/ai-providers/server-ai-langchain/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -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';
Expand All @@ -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);
}
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class LangChainRunnerFactory extends AIProvider {
*/
async createModel(config: LDAICompletionConfig): Promise<LangChainModelRunner> {
const llm = await createLangChainModel(config);
return new LangChainModelRunner(llm, config, this.logger);
return new LangChainModelRunner(llm, config, this._logger);
}

/**
Expand All @@ -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({
Expand All @@ -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);
}

/**
Expand Down
18 changes: 9 additions & 9 deletions packages/ai-providers/server-ai-openai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@

## 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:

```shell
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';
Expand All @@ -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);
}
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class OpenAIRunnerFactory extends AIProvider {
* Create a model runner from a completion AI configuration.
*/
async createModel(config: LDAICompletionConfig): Promise<OpenAIModelRunner> {
return new OpenAIModelRunner(this._client, config, this.logger);
return new OpenAIModelRunner(this._client, config, this._logger);
}

/**
Expand Down Expand Up @@ -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,
Expand All @@ -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);
}

/**
Expand Down
18 changes: 9 additions & 9 deletions packages/ai-providers/server-ai-vercel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -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';
Expand All @@ -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);
}
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class VercelRunnerFactory extends AIProvider {
async createModel(config: LDAICompletionConfig): Promise<VercelModelRunner> {
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);
}

/**
Expand Down
29 changes: 13 additions & 16 deletions packages/sdk/server-ai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
```

Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/server-ai/__tests__/LDAIClientImpl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ describe('createJudge method', () => {

beforeEach(() => {
mockProvider = {
invokeStructuredModel: jest.fn(),
run: jest.fn(),
};

mockJudge = {
Expand Down
49 changes: 22 additions & 27 deletions packages/sdk/server-ai/__tests__/RunnerFactory.test.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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() });
Expand Down Expand Up @@ -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(
Expand All @@ -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'));
Expand Down Expand Up @@ -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();
});

Expand All @@ -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'));
});
});
Original file line number Diff line number Diff line change
@@ -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

Expand Down
26 changes: 13 additions & 13 deletions packages/sdk/server-ai/src/LDAIClientImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, unknown>,
defaultAiProvider?: SupportedAIProvider,
): Promise<ManagedModel | undefined> {
return this.createModel(key, context, defaultValue, variables, defaultAiProvider);
}

async createJudge(
key: string,
context: LDContext,
Expand Down Expand Up @@ -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<string, unknown>,
defaultAiProvider?: SupportedAIProvider,
): Promise<ManagedModel | undefined> {
return this.createModel(key, context, defaultValue, variables, defaultAiProvider);
}

/**
* @deprecated Use `createModel` instead. This method will be removed in a future version.
*/
Expand Down
Loading
Loading