Skip to content

Commit 7d489b3

Browse files
committed
WIP: Comments and organization.
1 parent 9d22b8f commit 7d489b3

File tree

5 files changed

+145
-175
lines changed

5 files changed

+145
-175
lines changed

packages/sdk/ai/src/LDAIConfigTracker.ts

Lines changed: 0 additions & 151 deletions
This file was deleted.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { LDClient, LDContext } from '@launchdarkly/node-server-sdk';
2+
3+
import { LDAIConfigTracker } from './api/config';
4+
import { createBedrockTokenUsage, FeedbackKind, TokenUsage } from './api/metrics';
5+
import { createOpenAiUsage } from './api/metrics/OpenAiUsage';
6+
7+
export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
8+
private _ldClient: LDClient;
9+
private _variationId: string;
10+
private _configKey: string;
11+
private _context: LDContext;
12+
13+
constructor(ldClient: LDClient, configKey: string, versionId: string, context: LDContext) {
14+
this._ldClient = ldClient;
15+
this._variationId = versionId;
16+
this._configKey = configKey;
17+
this._context = context;
18+
}
19+
20+
private _getTrackData(): { variationId: string; configKey: string } {
21+
return {
22+
variationId: this._variationId,
23+
configKey: this._configKey,
24+
};
25+
}
26+
27+
trackDuration(duration: number): void {
28+
this._ldClient.track('$ld:ai:duration:total', this._context, this._getTrackData(), duration);
29+
}
30+
31+
async trackDurationOf(func: (...args: any[]) => Promise<any>, ...args: any[]): Promise<any> {
32+
const startTime = Date.now();
33+
const result = await func(...args);
34+
const endTime = Date.now();
35+
const duration = endTime - startTime; // duration in milliseconds
36+
this.trackDuration(duration);
37+
return result;
38+
}
39+
40+
trackError(error: number): void {
41+
this._ldClient.track('$ld:ai:error', this._context, this._getTrackData(), error);
42+
}
43+
44+
trackFeedback(feedback: { kind: FeedbackKind }): void {
45+
if (feedback.kind === FeedbackKind.Positive) {
46+
this._ldClient.track('$ld:ai:feedback:user:positive', this._context, this._getTrackData(), 1);
47+
} else if (feedback.kind === FeedbackKind.Negative) {
48+
this._ldClient.track('$ld:ai:feedback:user:negative', this._context, this._getTrackData(), 1);
49+
}
50+
}
51+
52+
trackGeneration(generation: number): void {
53+
this._ldClient.track('$ld:ai:generation', this._context, this._getTrackData(), generation);
54+
}
55+
56+
async trackOpenAI(func: (...args: any[]) => Promise<any>, ...args: any[]): Promise<any> {
57+
const result = await this.trackDurationOf(func, ...args);
58+
this.trackGeneration(1);
59+
if (result.usage) {
60+
this.trackTokens(createOpenAiUsage(result.usage));
61+
}
62+
return result;
63+
}
64+
65+
async trackBedrockConverse(res: {
66+
$metadata?: { httpStatusCode: number };
67+
metrics?: { latencyMs: number };
68+
usage?: {
69+
inputTokens: number;
70+
outputTokens: number;
71+
totalTokens: number;
72+
};
73+
}): Promise<any> {
74+
if (res.$metadata?.httpStatusCode === 200) {
75+
this.trackGeneration(1);
76+
} else if (res.$metadata?.httpStatusCode && res.$metadata.httpStatusCode >= 400) {
77+
this.trackError(res.$metadata.httpStatusCode);
78+
}
79+
if (res.metrics) {
80+
this.trackDuration(res.metrics.latencyMs);
81+
}
82+
if (res.usage) {
83+
this.trackTokens(createBedrockTokenUsage(res.usage));
84+
}
85+
return res;
86+
}
87+
88+
trackTokens(tokens: TokenUsage): void {
89+
const trackData = this._getTrackData();
90+
if (tokens.total > 0) {
91+
this._ldClient.track('$ld:ai:tokens:total', this._context, trackData, tokens.total);
92+
}
93+
if (tokens.input > 0) {
94+
this._ldClient.track('$ld:ai:tokens:input', this._context, trackData, tokens.input);
95+
}
96+
if (tokens.output > 0) {
97+
this._ldClient.track('$ld:ai:tokens:output', this._context, trackData, tokens.output);
98+
}
99+
}
100+
}
Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
1-
import { FeedbackKind, TokenUsage, UnderScoreTokenUsage } from '../metrics';
1+
import { FeedbackKind, TokenUsage } from '../metrics';
22

33
export interface LDAIConfigTracker {
44
trackDuration: (duration: number) => void;
5-
trackTokens: (
6-
tokens:
7-
| TokenUsage
8-
| UnderScoreTokenUsage
9-
| { totalTokens: number; inputTokens: number; outputTokens: number },
10-
) => void;
5+
trackTokens: (tokens: TokenUsage) => void;
116
trackError: (error: number) => void;
127
trackGeneration: (generation: number) => void;
138
trackFeedback: (feedback: { kind: FeedbackKind }) => void;
149
trackDurationOf: (func: (...args: any[]) => Promise<any>, ...args: any[]) => Promise<any>;
15-
trackOpenAI: (func: Function, ...args: any[]) => any;
10+
trackOpenAI: (func: (...args: any[]) => Promise<any>, ...args: any[]) => any;
1611
trackBedrockConverse: (res: any) => any;
1712
}

packages/sdk/ai/src/api/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './config';
2+
export * from './metrics';

packages/sdk/ai/src/index.ts

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,20 @@ import Mustache from 'mustache';
33
import { LDClient, LDContext } from '@launchdarkly/node-server-sdk';
44

55
import { LDAIConfig } from './api/config';
6-
import { LDAIConfigTracker } from './LDAIConfigTracker';
7-
8-
export class AIClient {
9-
private ldClient: LDClient;
10-
11-
constructor(ldClient: LDClient) {
12-
this.ldClient = ldClient;
13-
}
6+
import { LDAIConfigTrackerImpl } from './LDAIConfigTrackerImpl';
147

8+
/**
9+
* Interface for performing AI operations using LaunchDarkly.
10+
*/
11+
export interface AIClient {
1512
/**
1613
* Parses and interpolates a template string with the provided variables.
1714
*
1815
* @param template - The template string to be parsed and interpolated.
1916
* @param variables - An object containing the variables to be used for interpolation.
2017
* @returns The interpolated string.
2118
*/
22-
interpolateTemplate(template: string, variables: Record<string, unknown>): string {
23-
return Mustache.render(template, variables, undefined, { escape: (item: any) => item });
24-
}
19+
interpolateTemplate(template: string, variables: Record<string, unknown>): string;
2520

2621
/**
2722
* Retrieves and processes a prompt template based on the provided key, LaunchDarkly context, and variables.
@@ -60,13 +55,32 @@ export class AIClient {
6055
* }
6156
* ```
6257
*/
58+
modelConfig(
59+
key: string,
60+
context: LDContext,
61+
defaultValue: string,
62+
variables?: Record<string, unknown>,
63+
): Promise<LDAIConfig>;
64+
}
65+
66+
export class AIClientImpl implements AIClient {
67+
private _ldClient: LDClient;
68+
69+
constructor(ldClient: LDClient) {
70+
this._ldClient = ldClient;
71+
}
72+
73+
interpolateTemplate(template: string, variables: Record<string, unknown>): string {
74+
return Mustache.render(template, variables, undefined, { escape: (item: any) => item });
75+
}
76+
6377
async modelConfig(
6478
key: string,
6579
context: LDContext,
6680
defaultValue: string,
6781
variables?: Record<string, unknown>,
6882
): Promise<LDAIConfig> {
69-
const detail = await this.ldClient.variation(key, context, defaultValue);
83+
const detail = await this._ldClient.variation(key, context, defaultValue);
7084

7185
const allVariables = { ldctx: context, ...variables };
7286

@@ -78,15 +92,25 @@ export class AIClient {
7892
return {
7993
config: detail.value,
8094
// eslint-disable-next-line no-underscore-dangle
81-
tracker: new LDAIConfigTracker(this.ldClient, key, detail.value._ldMeta.variationId, context),
95+
tracker: new LDAIConfigTrackerImpl(
96+
this._ldClient,
97+
key,
98+
// eslint-disable-next-line no-underscore-dangle
99+
detail.value._ldMeta.variationId,
100+
context,
101+
),
82102
noConfiguration: Object.keys(detail).length === 0,
83103
};
84104
}
85105
}
86106

107+
/**
108+
* Initialize a new AI client. This client will be used to perform any AI operations.
109+
* @param ldClient The base LaunchDarkly client.
110+
* @returns A new AI client.
111+
*/
87112
export function init(ldClient: LDClient): AIClient {
88-
return new AIClient(ldClient);
113+
return new AIClientImpl(ldClient);
89114
}
90115

91-
export * from './api/config/LDAIConfigTracker';
92-
export * from './api/metrics';
116+
export * from './api';

0 commit comments

Comments
 (0)