Skip to content

Commit a33b9ef

Browse files
authored
chore: Clarify runId purpose and per-method tracker semantics (#1378)
1 parent 6d120af commit a33b9ef

10 files changed

Lines changed: 136 additions & 101 deletions

packages/sdk/server-ai/__tests__/LDAIConfigTrackerImpl.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -973,7 +973,7 @@ describe('at-most-once semantics', () => {
973973

974974
expect(mockTrack).toHaveBeenCalledTimes(1);
975975
expect(mockWarn).toHaveBeenCalledTimes(1);
976-
expect(mockWarn).toHaveBeenCalledWith(expect.stringContaining('Duration'));
976+
expect(mockWarn).toHaveBeenCalledWith(expect.stringContaining('trackDuration'));
977977
});
978978

979979
it('drops duplicate trackSuccess call with warning', () => {

packages/sdk/server-ai/__tests__/LDGraphTrackerImpl.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ it('drops second trackInvocationSuccess call and warns', () => {
151151
tracker.trackInvocationSuccess();
152152
expect(mockTrack).toHaveBeenCalledTimes(1);
153153
expect(mockWarn).toHaveBeenCalledWith(
154-
expect.stringContaining('invocation success/failure already recorded for this run'),
154+
expect.stringContaining('invocation result already recorded on this graph tracker'),
155155
);
156156
});
157157

@@ -161,7 +161,7 @@ it('drops trackInvocationFailure after trackInvocationSuccess and warns', () =>
161161
tracker.trackInvocationFailure();
162162
expect(mockTrack).toHaveBeenCalledTimes(1);
163163
expect(mockWarn).toHaveBeenCalledWith(
164-
expect.stringContaining('invocation success/failure already recorded for this run'),
164+
expect.stringContaining('invocation result already recorded on this graph tracker'),
165165
);
166166
});
167167

packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
8282
trackDuration(duration: number): void {
8383
if (this._trackedMetrics.durationMs !== undefined) {
8484
this._ldClient.logger?.warn(
85-
'Duration has already been tracked for this execution. Use createTracker() for a new execution.',
85+
'Skipping trackDuration: duration already recorded on this tracker. Call createTracker on the AI Config for a new run.',
8686
);
8787
return;
8888
}
@@ -106,7 +106,7 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
106106
trackTimeToFirstToken(timeToFirstTokenMs: number) {
107107
if (this._trackedMetrics.timeToFirstTokenMs !== undefined) {
108108
this._ldClient.logger?.warn(
109-
'Time to first token has already been tracked for this execution. Use createTracker() for a new execution.',
109+
'Skipping trackTimeToFirstToken: time-to-first-token already recorded on this tracker. Call createTracker on the AI Config for a new run.',
110110
);
111111
return;
112112
}
@@ -148,7 +148,7 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
148148
trackFeedback(feedback: { kind: LDFeedbackKind }): void {
149149
if (this._trackedMetrics.feedback !== undefined) {
150150
this._ldClient.logger?.warn(
151-
'Feedback has already been tracked for this execution. Use createTracker() for a new execution.',
151+
'Skipping trackFeedback: feedback already recorded on this tracker. Call createTracker on the AI Config for a new run.',
152152
);
153153
return;
154154
}
@@ -163,7 +163,7 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
163163
trackSuccess(): void {
164164
if (this._trackedMetrics.success !== undefined) {
165165
this._ldClient.logger?.warn(
166-
'Generation result has already been tracked for this execution. Use createTracker() for a new execution.',
166+
'Skipping trackSuccess: success/error already recorded on this tracker. Call createTracker on the AI Config for a new run.',
167167
);
168168
return;
169169
}
@@ -174,7 +174,7 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
174174
trackError(): void {
175175
if (this._trackedMetrics.success !== undefined) {
176176
this._ldClient.logger?.warn(
177-
'Generation result has already been tracked for this execution. Use createTracker() for a new execution.',
177+
'Skipping trackError: success/error already recorded on this tracker. Call createTracker on the AI Config for a new run.',
178178
);
179179
return;
180180
}
@@ -303,7 +303,7 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
303303
trackTokens(tokens: LDTokenUsage): void {
304304
if (this._trackedMetrics.tokens !== undefined) {
305305
this._ldClient.logger?.warn(
306-
'Token usage has already been tracked for this execution. Use createTracker() for a new execution.',
306+
'Skipping trackTokens: token usage already recorded on this tracker. Call createTracker on the AI Config for a new run.',
307307
);
308308
return;
309309
}

packages/sdk/server-ai/src/LDGraphTrackerImpl.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export class LDGraphTrackerImpl implements LDGraphTracker {
8989
trackInvocationSuccess(): void {
9090
if (this._summary.success !== undefined) {
9191
this._ldClient.logger?.warn(
92-
'LDGraphTracker: invocation success/failure already recorded for this run — dropping duplicate call.',
92+
'Skipping trackInvocationSuccess: invocation result already recorded on this graph tracker. Call createTracker on the agent graph for a new run.',
9393
);
9494
return;
9595
}
@@ -100,7 +100,7 @@ export class LDGraphTrackerImpl implements LDGraphTracker {
100100
trackInvocationFailure(): void {
101101
if (this._summary.success !== undefined) {
102102
this._ldClient.logger?.warn(
103-
'LDGraphTracker: invocation success/failure already recorded for this run — dropping duplicate call.',
103+
'Skipping trackInvocationFailure: invocation result already recorded on this graph tracker. Call createTracker on the agent graph for a new run.',
104104
);
105105
return;
106106
}
@@ -111,7 +111,7 @@ export class LDGraphTrackerImpl implements LDGraphTracker {
111111
trackDuration(durationMs: number): void {
112112
if (this._summary.durationMs !== undefined) {
113113
this._ldClient.logger?.warn(
114-
'LDGraphTracker: trackDuration already called for this run — dropping duplicate call.',
114+
'Skipping trackDuration: duration already recorded on this graph tracker. Call createTracker on the agent graph for a new run.',
115115
);
116116
return;
117117
}
@@ -127,7 +127,7 @@ export class LDGraphTrackerImpl implements LDGraphTracker {
127127
trackTotalTokens(tokens: LDTokenUsage): void {
128128
if (this._summary.tokens !== undefined) {
129129
this._ldClient.logger?.warn(
130-
'LDGraphTracker: trackTotalTokens already called for this run — dropping duplicate call.',
130+
'Skipping trackTotalTokens: tokens already recorded on this graph tracker. Call createTracker on the agent graph for a new run.',
131131
);
132132
return;
133133
}
@@ -143,7 +143,7 @@ export class LDGraphTrackerImpl implements LDGraphTracker {
143143
trackPath(path: string[]): void {
144144
if (this._summary.path !== undefined) {
145145
this._ldClient.logger?.warn(
146-
'LDGraphTracker: trackPath already called for this run — dropping duplicate call.',
146+
'Skipping trackPath: path already recorded on this graph tracker. Call createTracker on the agent graph for a new run.',
147147
);
148148
return;
149149
}

packages/sdk/server-ai/src/api/LDAIClient.ts

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ export interface LDAIClient {
3434
* the message content. The keys correspond to placeholders within the template, and the values
3535
* are the corresponding replacements.
3636
*
37-
* @returns The AI `config`, customized `messages`, and a `tracker`. If the configuration cannot be accessed from
38-
* LaunchDarkly, then the return value will include information from the `defaultValue`. The returned `tracker` can
39-
* be used to track AI operation metrics (latency, token usage, etc.).
37+
* @returns An {@link LDAICompletionConfig} with `enabled`, `model`, `provider`,
38+
* `messages`, and a `createTracker()` factory. Call `createTracker()` on the
39+
* returned config to obtain a tracker for each AI run. If the configuration
40+
* cannot be accessed from LaunchDarkly, the return value will include
41+
* information from the `defaultValue`.
4042
*
4143
* @example
4244
* ```
@@ -49,27 +51,11 @@ export interface LDAIClient {
4951
* provider: { name: 'openai' },
5052
* };
5153
*
52-
* const result = completionConfig(key, context, defaultValue, variables);
53-
* // Output:
54-
* {
55-
* enabled: true,
56-
* config: {
57-
* modelId: "gpt-4o",
58-
* temperature: 0.2,
59-
* maxTokens: 4096,
60-
* userDefinedKey: "myValue",
61-
* },
62-
* messages: [
63-
* {
64-
* role: "system",
65-
* content: "You are an amazing GPT."
66-
* },
67-
* {
68-
* role: "user",
69-
* content: "Explain how you're an amazing GPT."
70-
* }
71-
* ],
72-
* tracker: ...
54+
* const completionConfig = await client.completionConfig(key, context, defaultValue, variables);
55+
* if (completionConfig.enabled) {
56+
* const tracker = completionConfig.createTracker();
57+
* // Use completionConfig.messages and completionConfig.model with your LLM,
58+
* // then record metrics with tracker.trackSuccess(), tracker.trackTokens(), etc.
7359
* }
7460
* ```
7561
*/
@@ -95,9 +81,11 @@ export interface LDAIClient {
9581
* the instructions. The keys correspond to placeholders within the template, and the values
9682
* are the corresponding replacements.
9783
*
98-
* @returns An AI agent with customized `instructions` and a `tracker`. If the configuration
99-
* cannot be accessed from LaunchDarkly, then the return value will include information from the
100-
* `defaultValue`. The returned `tracker` can be used to track AI operation metrics (latency, token usage, etc.).
84+
* @returns An {@link LDAIAgentConfig} with customized `instructions`, `model`,
85+
* `provider`, and a `createTracker()` factory. Call `createTracker()` on the
86+
* returned config to obtain a tracker for each AI run. If the configuration
87+
* cannot be accessed from LaunchDarkly, the return value will include
88+
* information from the `defaultValue`.
10189
*
10290
* @example
10391
* ```
@@ -111,8 +99,11 @@ export interface LDAIClient {
11199
* instructions: 'You are a research assistant.',
112100
* }, variables);
113101
*
114-
* const researchResult = agentConfig.instructions; // Interpolated instructions
115-
* agentConfig.tracker.trackSuccess();
102+
* if (agentConfig.enabled) {
103+
* const tracker = agentConfig.createTracker();
104+
* const researchResult = agentConfig.instructions; // Interpolated instructions
105+
* tracker.trackSuccess();
106+
* }
116107
* ```
117108
*/
118109
agentConfig(
@@ -134,7 +125,10 @@ export interface LDAIClient {
134125
* @param defaultValue Optional fallback when the configuration is not available from LaunchDarkly.
135126
* When omitted or null, a disabled default is used.
136127
* @param variables Optional variables for template interpolation in messages and instructions.
137-
* @returns A promise that resolves to a tracked judge configuration.
128+
* @returns A promise that resolves to an {@link LDAIJudgeConfig} with `enabled`,
129+
* `model`, `provider`, `messages`, `evaluationMetricKey`, and a `createTracker()`
130+
* factory. Call `createTracker()` on the returned config to obtain a tracker for
131+
* each AI run.
138132
*
139133
* @example
140134
* ```typescript
@@ -146,8 +140,11 @@ export interface LDAIClient {
146140
* messages: [{ role: 'system', content: 'You are a relevance judge.' }]
147141
* }, variables);
148142
*
149-
* const config = judgeConf.config; // Interpolated configuration
150-
* judgeConf.tracker.trackSuccess();
143+
* if (judgeConf.enabled) {
144+
* const tracker = judgeConf.createTracker();
145+
* // Use judgeConf.messages and judgeConf.model with your LLM,
146+
* // then record metrics with tracker.trackSuccess(), tracker.trackJudgeResult(), etc.
147+
* }
151148
* ```
152149
*/
153150
judgeConfig(
@@ -167,10 +164,11 @@ export interface LDAIClient {
167164
* current environment, user, or session. This context may influence how the configuration is
168165
* processed or personalized.
169166
*
170-
* @returns A map of agent keys to their respective AI agents with customized `instructions` and `tracker`.
171-
* If a configuration cannot be accessed from LaunchDarkly, then the return value will include information
172-
* from the respective `defaultValue`. The returned `tracker` can be used to track AI operation metrics
173-
* (latency, token usage, etc.).
167+
* @returns A map of agent keys to their respective {@link LDAIAgentConfig}s,
168+
* each with customized `instructions` and a `createTracker()` factory. Call
169+
* `createTracker()` on a returned config to obtain a tracker for each AI run.
170+
* If a configuration cannot be accessed from LaunchDarkly, the return value
171+
* will include information from the respective `defaultValue`.
174172
*
175173
* @example
176174
* ```
@@ -199,8 +197,11 @@ export interface LDAIClient {
199197
* const context = {...};
200198
*
201199
* const configs = await client.agentConfigs(agentConfigsList, context);
202-
* const researchResult = configs["research_agent"].instructions; // Interpolated instructions
203-
* configs["research_agent"].tracker.trackSuccess();
200+
* if (configs["research_agent"].enabled) {
201+
* const tracker = configs["research_agent"].createTracker();
202+
* const researchResult = configs["research_agent"].instructions; // Interpolated instructions
203+
* tracker.trackSuccess();
204+
* }
204205
* ```
205206
*/
206207
agentConfigs<const T extends readonly LDAIAgentRequestConfig[]>(
@@ -316,7 +317,7 @@ export interface LDAIClient {
316317
/**
317318
* Reconstructs an AIConfigTracker from a resumption token string previously
318319
* obtained from a tracker's `resumptionToken` property. Use this to associate
319-
* deferred events (such as user feedback) with the original invocation's runId.
320+
* deferred events (such as user feedback) with the original tracker's runId.
320321
*
321322
* @param token A URL-safe Base64-encoded resumption token string.
322323
* @param context The evaluation context to use for subsequent track calls.

0 commit comments

Comments
 (0)