Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
26 changes: 20 additions & 6 deletions packages/sdk/server-ai/__tests__/LDAIClientImpl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,14 @@ it('passes the default value to the underlying client', async () => {
enabled: true,
};

mockLdClient.variation.mockResolvedValue(defaultValue);
const expectedLDFlagValue = {
_ldMeta: { enabled: true },
model: defaultValue.model,
messages: defaultValue.messages,
provider: defaultValue.provider,
};

mockLdClient.variation.mockResolvedValue(expectedLDFlagValue);

const result = await client.config(key, testContext, defaultValue);

Expand All @@ -136,11 +143,11 @@ it('passes the default value to the underlying client', async () => {
messages: defaultValue.messages,
provider: defaultValue.provider,
tracker: expect.any(Object),
enabled: false,
enabled: defaultValue.enabled,
toVercelAISDK: expect.any(Function),
});

expect(mockLdClient.variation).toHaveBeenCalledWith(key, testContext, defaultValue);
expect(mockLdClient.variation).toHaveBeenCalledWith(key, testContext, expectedLDFlagValue);
});

// New agent-related tests
Expand Down Expand Up @@ -253,7 +260,14 @@ it('passes the default value to the underlying client for single agent', async (
enabled: true,
};

mockLdClient.variation.mockResolvedValue(defaultValue);
const expectedLDFlagValue = {
_ldMeta: { enabled: defaultValue.enabled },
model: defaultValue.model,
provider: defaultValue.provider,
instructions: defaultValue.instructions,
};

mockLdClient.variation.mockResolvedValue(expectedLDFlagValue);

const result = await client.agent(key, testContext, defaultValue);

Expand All @@ -262,10 +276,10 @@ it('passes the default value to the underlying client for single agent', async (
instructions: defaultValue.instructions,
provider: defaultValue.provider,
tracker: expect.any(Object),
enabled: false,
enabled: defaultValue.enabled,
});

expect(mockLdClient.variation).toHaveBeenCalledWith(key, testContext, defaultValue);
expect(mockLdClient.variation).toHaveBeenCalledWith(key, testContext, expectedLDFlagValue);
});

it('returns multiple agents config with interpolated instructions', async () => {
Expand Down
37 changes: 29 additions & 8 deletions packages/sdk/server-ai/src/LDAIClientImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,31 @@ export class LDAIClientImpl implements LDAIClient {
return Mustache.render(template, variables, undefined, { escape: (item: any) => item });
}

private _toLDFlagValue(defaultValue: LDAIDefaults | LDAIAgentDefaults): {
_ldMeta: { enabled: boolean };
model?: LDModelConfig;
messages?: LDMessage[];
provider?: LDProviderConfig;
instructions?: string;
} {
return {
_ldMeta: { enabled: defaultValue.enabled ?? false },
model: defaultValue.model,
messages: 'messages' in defaultValue ? defaultValue.messages : undefined,
provider: defaultValue.provider,
instructions: 'instructions' in defaultValue ? defaultValue.instructions : undefined,
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be static. Does it need to be defined on LDAIClientImpl?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally this would be defined in api/config as a utility method but this could create a circular dependency. I wanted to avoid any breaking changes to the SDK for this.

Current flow:

  • api/agents → imports from api/config (line 1 in LDAIAgent.ts)
  • api/config → would need to import from api/agents (for LDAIAgentDefaults)

This creates a cycle:

  • api/agents → api/config → api/agents ❌


private async _evaluate(
key: string,
context: LDContext,
defaultValue: LDAIDefaults,
): Promise<EvaluationResult> {
const value: VariationContent = await this._ldClient.variation(key, context, defaultValue);
// Convert default value to LDFlagValue format
const ldFlagValue = this._toLDFlagValue(defaultValue);

const value: VariationContent = await this._ldClient.variation(key, context, ldFlagValue);

const tracker = new LDAIConfigTrackerImpl(
this._ldClient,
Expand Down Expand Up @@ -109,11 +128,13 @@ export class LDAIClientImpl implements LDAIClient {
defaultValue: LDAIAgentDefaults,
variables?: Record<string, unknown>,
): Promise<LDAIAgent> {
const { tracker, enabled, model, provider, instructions } = await this._evaluate(
key,
context,
defaultValue,
);
const {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just a consistency formatting change to align with how we format in the config method.

tracker,
enabled,
model,
provider: configProvider,
instructions,
} = await this._evaluate(key, context, defaultValue);

const agent: LDAIAgent = {
tracker,
Expand All @@ -126,8 +147,8 @@ export class LDAIClientImpl implements LDAIClient {
agent.model = { ...model };
}

if (provider) {
agent.provider = { ...provider };
if (configProvider) {
agent.provider = { ...configProvider };
}

const allVariables = { ...variables, ldctx: context };
Expand Down