Skip to content
Closed
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
88 changes: 88 additions & 0 deletions packages/sdk/server-ai/__tests__/LDAIConfigTrackerImpl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,80 @@ it('tracks negative feedback', () => {
);
});

it('tracks custom event with data', () => {
const tracker = new LDAIConfigTrackerImpl(
mockLdClient,
configKey,
variationKey,
version,
testContext,
);
const customData = { property: 'value', count: 42 };
tracker.trackCustomEvent('test-event', customData);

expect(mockTrack).toHaveBeenCalledWith(
'$ld:ai:custom:test-event',
testContext,
{ configKey, variationKey, version, custom: customData },
undefined,
);
});

it('tracks custom event with metric value', () => {
const tracker = new LDAIConfigTrackerImpl(
mockLdClient,
configKey,
variationKey,
version,
testContext,
);
tracker.trackCustomEvent('test-event', undefined, 123.45);

expect(mockTrack).toHaveBeenCalledWith(
'$ld:ai:custom:test-event',
testContext,
{ configKey, variationKey, version, custom: undefined },
123.45,
);
});

it('tracks custom event with both data and metric value', () => {
const tracker = new LDAIConfigTrackerImpl(
mockLdClient,
configKey,
variationKey,
version,
testContext,
);
const customData = { property: 'value' };
tracker.trackCustomEvent('test-event', customData, 123.45);

expect(mockTrack).toHaveBeenCalledWith(
'$ld:ai:custom:test-event',
testContext,
{ configKey, variationKey, version, custom: customData },
123.45,
);
});

it('tracks custom event with no data or metric value', () => {
const tracker = new LDAIConfigTrackerImpl(
mockLdClient,
configKey,
variationKey,
version,
testContext,
);
tracker.trackCustomEvent('test-event');

expect(mockTrack).toHaveBeenCalledWith(
'$ld:ai:custom:test-event',
testContext,
{ configKey, variationKey, version, custom: undefined },
undefined,
);
});

it('tracks success', () => {
const tracker = new LDAIConfigTrackerImpl(
mockLdClient,
Expand Down Expand Up @@ -429,6 +503,8 @@ it('summarizes tracked metrics', () => {
});
tracker.trackFeedback({ kind: LDFeedbackKind.Positive });
tracker.trackSuccess();
tracker.trackCustomEvent('event1', { test: 'data' });
tracker.trackCustomEvent('event2', undefined, 42);

const summary = tracker.getSummary();

Expand All @@ -443,6 +519,18 @@ it('summarizes tracked metrics', () => {
kind: 'positive',
},
success: true,
customEvents: [
{
name: 'event1',
data: { test: 'data' },
metricValue: undefined,
},
{
name: 'event2',
data: undefined,
metricValue: 42,
},
],
});
});

Expand Down
14 changes: 14 additions & 0 deletions packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
}
}

trackCustomEvent(eventName: string, data?: any, metricValue?: number): void {
if (!this._trackedMetrics.customEvents) {
this._trackedMetrics.customEvents = [];
}
this._trackedMetrics.customEvents.push({
name: eventName,
data,
metricValue,
});

const trackData = { ...this._getTrackData(), custom: data };
this._ldClient.track(`$ld:ai:custom:${eventName}`, this._context, trackData, metricValue);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there any sanitization you want to consider on the event name or is it ok to append it no matter what the supplied value is?

}

trackSuccess(): void {
this._trackedMetrics.success = true;
this._ldClient.track('$ld:ai:generation', this._context, this._getTrackData(), 1);
Expand Down
31 changes: 31 additions & 0 deletions packages/sdk/server-ai/src/api/config/LDAIConfigTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@ export interface LDAIMetricSummary {
* Time to first token for this generation.
*/
timeToFirstTokenMs?: number;

/**
* Custom events tracked for this operation.
*/
customEvents?: Array<{
/**
* The name of the custom event.
*/
name: string;

/**
* Optional additional information associated with the event.
*/
data?: any;

/**
* Optional numeric value for analytics.
*/
metricValue?: number;
}>;
}

/**
Expand Down Expand Up @@ -67,6 +87,17 @@ export interface LDAIConfigTracker {
*/
trackFeedback(feedback: { kind: LDFeedbackKind }): void;

/**
* Track a custom event related to AI operations.
*
* This method allows for tracking arbitrary custom events specific to AI operations.
*
* @param eventName The name of the custom event.
* @param data Optional additional information to associate with the event.
* @param metricValue A numeric value that can be used for analytics. Can be omitted if not needed.
*/
trackCustomEvent(eventName: string, data?: any, metricValue?: number): void;

/**
* Track the time to first token for this generation.
*
Expand Down
Loading