@launchdarkly/server-sdk-ai 0.11.4 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +128 -6
- package/__tests__/LDAIConfigTrackerImpl.test.ts +155 -0
- package/__tests__/TrackedChat.test.ts +231 -0
- package/dist/LDAIClientImpl.d.ts +4 -0
- package/dist/LDAIClientImpl.d.ts.map +1 -1
- package/dist/LDAIClientImpl.js +21 -0
- package/dist/LDAIClientImpl.js.map +1 -1
- package/dist/LDAIConfigTrackerImpl.d.ts +2 -1
- package/dist/LDAIConfigTrackerImpl.d.ts.map +1 -1
- package/dist/LDAIConfigTrackerImpl.js +24 -0
- package/dist/LDAIConfigTrackerImpl.js.map +1 -1
- package/dist/LDClientMin.d.ts +2 -1
- package/dist/LDClientMin.d.ts.map +1 -1
- package/dist/api/LDAIClient.d.ts +39 -0
- package/dist/api/LDAIClient.d.ts.map +1 -1
- package/dist/api/chat/TrackedChat.d.ts +54 -0
- package/dist/api/chat/TrackedChat.d.ts.map +1 -0
- package/dist/api/chat/TrackedChat.js +84 -0
- package/dist/api/chat/TrackedChat.js.map +1 -0
- package/dist/api/chat/index.d.ts +3 -0
- package/dist/api/chat/index.d.ts.map +1 -0
- package/dist/api/chat/index.js +19 -0
- package/dist/api/chat/index.js.map +1 -0
- package/dist/api/chat/types.d.ts +16 -0
- package/dist/api/chat/types.d.ts.map +1 -0
- package/dist/api/chat/types.js +3 -0
- package/dist/api/chat/types.js.map +1 -0
- package/dist/api/config/LDAIConfigTracker.d.ts +16 -1
- package/dist/api/config/LDAIConfigTracker.d.ts.map +1 -1
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +2 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/metrics/LDAIMetrics.d.ts +17 -0
- package/dist/api/metrics/LDAIMetrics.d.ts.map +1 -0
- package/dist/api/metrics/LDAIMetrics.js +3 -0
- package/dist/api/metrics/LDAIMetrics.js.map +1 -0
- package/dist/api/metrics/index.d.ts +1 -0
- package/dist/api/metrics/index.d.ts.map +1 -1
- package/dist/api/metrics/index.js +1 -0
- package/dist/api/metrics/index.js.map +1 -1
- package/dist/api/providers/AIProvider.d.ts +35 -0
- package/dist/api/providers/AIProvider.d.ts.map +1 -0
- package/dist/api/providers/AIProvider.js +31 -0
- package/dist/api/providers/AIProvider.js.map +1 -0
- package/dist/api/providers/AIProviderFactory.d.ts +39 -0
- package/dist/api/providers/AIProviderFactory.d.ts.map +1 -0
- package/dist/api/providers/AIProviderFactory.js +102 -0
- package/dist/api/providers/AIProviderFactory.js.map +1 -0
- package/dist/api/providers/index.d.ts +3 -0
- package/dist/api/providers/index.d.ts.map +1 -0
- package/dist/api/providers/index.js +19 -0
- package/dist/api/providers/index.js.map +1 -0
- package/docs/assets/search.js +1 -1
- package/docs/classes/AIProvider.html +174 -0
- package/docs/classes/AIProviderFactory.html +197 -0
- package/docs/classes/TrackedChat.html +253 -0
- package/docs/enums/LDFeedbackKind.html +14 -7
- package/docs/functions/createBedrockTokenUsage.html +12 -5
- package/docs/functions/createOpenAiUsage.html +12 -5
- package/docs/functions/createVercelAISDKTokenUsage.html +12 -5
- package/docs/functions/initAi.html +12 -5
- package/docs/index.html +25 -5
- package/docs/interfaces/ChatResponse.html +108 -0
- package/docs/interfaces/LDAIAgent.html +17 -10
- package/docs/interfaces/LDAIAgentConfig.html +15 -8
- package/docs/interfaces/LDAIClient.html +55 -9
- package/docs/interfaces/LDAIConfig.html +18 -11
- package/docs/interfaces/LDAIConfigTracker.html +76 -17
- package/docs/interfaces/LDAIMetrics.html +110 -0
- package/docs/interfaces/LDMessage.html +14 -7
- package/docs/interfaces/LDModelConfig.html +15 -8
- package/docs/interfaces/LDProviderConfig.html +13 -6
- package/docs/interfaces/LDTokenUsage.html +15 -8
- package/docs/interfaces/VercelAISDKConfig.html +23 -16
- package/docs/interfaces/VercelAISDKMapOptions.html +13 -6
- package/docs/types/LDAIAgentDefaults.html +12 -5
- package/docs/types/LDAIDefaults.html +12 -5
- package/docs/types/SupportedAIProvider.html +70 -0
- package/docs/types/VercelAISDKProvider.html +12 -5
- package/docs/variables/SUPPORTED_AI_PROVIDERS.html +70 -0
- package/package.json +1 -1
- package/src/LDAIClientImpl.ts +36 -2
- package/src/LDAIConfigTrackerImpl.ts +32 -0
- package/src/LDClientMin.ts +3 -1
- package/src/api/LDAIClient.ts +46 -0
- package/src/api/chat/TrackedChat.ts +100 -0
- package/src/api/chat/index.ts +2 -0
- package/src/api/chat/types.ts +17 -0
- package/src/api/config/LDAIConfigTracker.ts +20 -1
- package/src/api/index.ts +2 -0
- package/src/api/metrics/LDAIMetrics.ts +18 -0
- package/src/api/metrics/index.ts +1 -0
- package/src/api/providers/AIProvider.ts +43 -0
- package/src/api/providers/AIProviderFactory.ts +152 -0
- package/src/api/providers/index.ts +2 -0
- package/tsconfig.eslint.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.12.1](https://github.com/launchdarkly/js-core/compare/server-sdk-ai-v0.12.0...server-sdk-ai-v0.12.1) (2025-10-14)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* Improve documentation for AI SDK and AIProvider ([#958](https://github.com/launchdarkly/js-core/issues/958)) ([17d595a](https://github.com/launchdarkly/js-core/commit/17d595aff301998030cfb62724b8eb37fea9adbf))
|
|
9
|
+
|
|
10
|
+
## [0.12.0](https://github.com/launchdarkly/js-core/compare/server-sdk-ai-v0.11.4...server-sdk-ai-v0.12.0) (2025-10-13)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* Add support for TrackedChats in the AI SDK ([#939](https://github.com/launchdarkly/js-core/issues/939)) ([a7ad0ea](https://github.com/launchdarkly/js-core/commit/a7ad0ead1408fdd80b333baa085c462f47ea5ac1))
|
|
16
|
+
* Add support for OpenAI AIProvider to the AI SDK ([#939](https://github.com/launchdarkly/js-core/issues/939)) ([a7ad0ea](https://github.com/launchdarkly/js-core/commit/a7ad0ead1408fdd80b333baa085c462f47ea5ac1))
|
|
17
|
+
* Add support for LangChain AIProvider to the AI SDK ([#939](https://github.com/launchdarkly/js-core/issues/939)) ([a7ad0ea](https://github.com/launchdarkly/js-core/commit/a7ad0ead1408fdd80b333baa085c462f47ea5ac1))
|
|
18
|
+
* Add support for Vercel AIProvider to the AI SDK ([#946](https://github.com/launchdarkly/js-core/issues/946)) ([8553f24](https://github.com/launchdarkly/js-core/commit/8553f2482a3437975b63992f622b4396cc4ac7e7))
|
|
19
|
+
|
|
3
20
|
## [0.11.4](https://github.com/launchdarkly/js-core/compare/server-sdk-ai-v0.11.3...server-sdk-ai-v0.11.4) (2025-09-15)
|
|
4
21
|
|
|
5
22
|
|
package/README.md
CHANGED
|
@@ -27,6 +27,8 @@ This assumes that you have already installed the LaunchDarkly Node.js (server-si
|
|
|
27
27
|
|
|
28
28
|
```shell
|
|
29
29
|
npm install @launchdarkly/server-sdk-ai --save
|
|
30
|
+
# or
|
|
31
|
+
yarn add @launchdarkly/server-sdk-ai
|
|
30
32
|
```
|
|
31
33
|
|
|
32
34
|
2. Create an AI SDK instance:
|
|
@@ -36,18 +38,138 @@ npm install @launchdarkly/server-sdk-ai --save
|
|
|
36
38
|
const aiClient = initAi(ldClient);
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
## Setting Default AI Configurations
|
|
42
|
+
|
|
43
|
+
When retrieving AI configurations, you need to provide default values that will be used if the configuration is not available from LaunchDarkly:
|
|
44
|
+
|
|
45
|
+
### Fully Configured Default
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const defaultConfig = {
|
|
49
|
+
enabled: true,
|
|
50
|
+
model: {
|
|
51
|
+
name: 'gpt-4',
|
|
52
|
+
parameters: { temperature: 0.7, maxTokens: 1000 }
|
|
53
|
+
},
|
|
54
|
+
messages: [
|
|
55
|
+
{ role: 'system', content: 'You are a helpful assistant.' }
|
|
56
|
+
]
|
|
57
|
+
};
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Disabled Default
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const defaultConfig = {
|
|
64
|
+
enabled: false
|
|
65
|
+
};
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Retrieving AI Configurations
|
|
69
|
+
|
|
70
|
+
The `config` method retrieves AI configurations from LaunchDarkly with support for dynamic variables and fallback values:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
const aiConfig = await aiClient.config(
|
|
74
|
+
aiConfigKey,
|
|
75
|
+
context,
|
|
76
|
+
defaultConfig,
|
|
77
|
+
{ myVariable: 'My User Defined Variable' } // Variables for template interpolation
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// Ensure configuration is enabled
|
|
81
|
+
if (aiConfig.enabled) {
|
|
82
|
+
const { messages, model, tracker } = aiConfig;
|
|
83
|
+
// Use with your AI provider
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## TrackedChat for Conversational AI
|
|
88
|
+
|
|
89
|
+
`TrackedChat` provides a high-level interface for conversational AI with automatic conversation management and metrics tracking:
|
|
90
|
+
|
|
91
|
+
- Automatically configures models based on AI configuration
|
|
92
|
+
- Maintains conversation history across multiple interactions
|
|
93
|
+
- Automatically tracks token usage, latency, and success rates
|
|
94
|
+
- Works with any supported AI provider (see [AI Providers](https://github.com/launchdarkly/js-core#ai-providers) for available packages)
|
|
95
|
+
|
|
96
|
+
### Using TrackedChat
|
|
40
97
|
|
|
41
98
|
```typescript
|
|
42
|
-
|
|
43
|
-
|
|
99
|
+
// Use the same defaultConfig from the retrieval section above
|
|
100
|
+
const chat = await aiClient.initChat(
|
|
101
|
+
'customer-support-chat',
|
|
44
102
|
context,
|
|
45
|
-
|
|
46
|
-
{
|
|
103
|
+
defaultConfig,
|
|
104
|
+
{ customerName: 'John' }
|
|
47
105
|
);
|
|
106
|
+
|
|
107
|
+
if (chat) {
|
|
108
|
+
// Simple conversation flow - metrics are automatically tracked by invoke()
|
|
109
|
+
const response1 = await chat.invoke('I need help with my order');
|
|
110
|
+
console.log(response1.message.content);
|
|
111
|
+
|
|
112
|
+
const response2 = await chat.invoke("What's the status?");
|
|
113
|
+
console.log(response2.message.content);
|
|
114
|
+
|
|
115
|
+
// Access conversation history
|
|
116
|
+
const messages = chat.getMessages();
|
|
117
|
+
console.log(`Conversation has ${messages.length} messages`);
|
|
118
|
+
}
|
|
48
119
|
```
|
|
49
120
|
|
|
50
|
-
|
|
121
|
+
## Advanced Usage with Providers
|
|
122
|
+
|
|
123
|
+
For more control, you can use the configuration directly with AI providers. We recommend using [LaunchDarkly AI Provider packages](https://github.com/launchdarkly/js-core#ai-providers) when available:
|
|
124
|
+
|
|
125
|
+
### Using AI Provider Packages
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { LangChainProvider } from '@launchdarkly/server-sdk-ai-langchain';
|
|
129
|
+
|
|
130
|
+
const aiConfig = await aiClient.config(aiConfigKey, context, defaultValue);
|
|
131
|
+
|
|
132
|
+
// Create LangChain model from configuration
|
|
133
|
+
const llm = await LangChainProvider.createLangChainModel(aiConfig);
|
|
134
|
+
|
|
135
|
+
// Use with tracking
|
|
136
|
+
const response = await aiConfig.tracker.trackMetricsOf(
|
|
137
|
+
(result) => LangChainProvider.createAIMetrics(result),
|
|
138
|
+
() => llm.invoke(messages)
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
console.log('AI Response:', response.content);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Using Custom Providers
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { LDAIMetrics } from '@launchdarkly/server-sdk-ai';
|
|
148
|
+
|
|
149
|
+
const aiConfig = await aiClient.config(aiConfigKey, context, defaultValue);
|
|
150
|
+
|
|
151
|
+
// Define custom metrics mapping for your provider
|
|
152
|
+
const mapCustomProviderMetrics = (response: any): LDAIMetrics => ({
|
|
153
|
+
success: true,
|
|
154
|
+
usage: {
|
|
155
|
+
total: response.usage?.total_tokens || 0,
|
|
156
|
+
input: response.usage?.prompt_tokens || 0,
|
|
157
|
+
output: response.usage?.completion_tokens || 0,
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Use with custom provider and tracking
|
|
162
|
+
const result = await aiConfig.tracker.trackMetricsOf(
|
|
163
|
+
mapCustomProviderMetrics,
|
|
164
|
+
() => customProvider.generate({
|
|
165
|
+
messages: aiConfig.messages || [],
|
|
166
|
+
model: aiConfig.model?.name || 'custom-model',
|
|
167
|
+
temperature: aiConfig.model?.parameters?.temperature ?? 0.5,
|
|
168
|
+
})
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
console.log('AI Response:', result.content);
|
|
172
|
+
```
|
|
51
173
|
|
|
52
174
|
## Contributing
|
|
53
175
|
|
|
@@ -898,3 +898,158 @@ it('tracks error', () => {
|
|
|
898
898
|
1,
|
|
899
899
|
);
|
|
900
900
|
});
|
|
901
|
+
|
|
902
|
+
describe('trackMetricsOf', () => {
|
|
903
|
+
it('tracks success and token usage from metrics', async () => {
|
|
904
|
+
const tracker = new LDAIConfigTrackerImpl(
|
|
905
|
+
mockLdClient,
|
|
906
|
+
configKey,
|
|
907
|
+
variationKey,
|
|
908
|
+
version,
|
|
909
|
+
modelName,
|
|
910
|
+
providerName,
|
|
911
|
+
testContext,
|
|
912
|
+
);
|
|
913
|
+
|
|
914
|
+
const mockResult = { response: 'test' };
|
|
915
|
+
const mockMetrics = {
|
|
916
|
+
success: true,
|
|
917
|
+
usage: { total: 100, input: 50, output: 50 },
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
const metricsExtractor = jest.fn().mockReturnValue(mockMetrics);
|
|
921
|
+
const operation = jest.fn().mockResolvedValue(mockResult);
|
|
922
|
+
|
|
923
|
+
const result = await tracker.trackMetricsOf(metricsExtractor, operation);
|
|
924
|
+
|
|
925
|
+
expect(result).toBe(mockResult);
|
|
926
|
+
expect(metricsExtractor).toHaveBeenCalledWith(mockResult);
|
|
927
|
+
expect(operation).toHaveBeenCalled();
|
|
928
|
+
|
|
929
|
+
// Should track success
|
|
930
|
+
expect(mockTrack).toHaveBeenCalledWith(
|
|
931
|
+
'$ld:ai:generation:success',
|
|
932
|
+
testContext,
|
|
933
|
+
{ configKey, variationKey, version, modelName, providerName },
|
|
934
|
+
1,
|
|
935
|
+
);
|
|
936
|
+
|
|
937
|
+
// Should track token usage
|
|
938
|
+
expect(mockTrack).toHaveBeenCalledWith(
|
|
939
|
+
'$ld:ai:tokens:total',
|
|
940
|
+
testContext,
|
|
941
|
+
{ configKey, variationKey, version, modelName, providerName },
|
|
942
|
+
100,
|
|
943
|
+
);
|
|
944
|
+
expect(mockTrack).toHaveBeenCalledWith(
|
|
945
|
+
'$ld:ai:tokens:input',
|
|
946
|
+
testContext,
|
|
947
|
+
{ configKey, variationKey, version, modelName, providerName },
|
|
948
|
+
50,
|
|
949
|
+
);
|
|
950
|
+
expect(mockTrack).toHaveBeenCalledWith(
|
|
951
|
+
'$ld:ai:tokens:output',
|
|
952
|
+
testContext,
|
|
953
|
+
{ configKey, variationKey, version, modelName, providerName },
|
|
954
|
+
50,
|
|
955
|
+
);
|
|
956
|
+
});
|
|
957
|
+
|
|
958
|
+
it('tracks failure when metrics indicate failure', async () => {
|
|
959
|
+
const tracker = new LDAIConfigTrackerImpl(
|
|
960
|
+
mockLdClient,
|
|
961
|
+
configKey,
|
|
962
|
+
variationKey,
|
|
963
|
+
version,
|
|
964
|
+
modelName,
|
|
965
|
+
providerName,
|
|
966
|
+
testContext,
|
|
967
|
+
);
|
|
968
|
+
|
|
969
|
+
const mockResult = { response: 'test' };
|
|
970
|
+
const mockMetrics = {
|
|
971
|
+
success: false,
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
const metricsExtractor = jest.fn().mockReturnValue(mockMetrics);
|
|
975
|
+
const operation = jest.fn().mockResolvedValue(mockResult);
|
|
976
|
+
|
|
977
|
+
await tracker.trackMetricsOf(metricsExtractor, operation);
|
|
978
|
+
|
|
979
|
+
// Should track error
|
|
980
|
+
expect(mockTrack).toHaveBeenCalledWith(
|
|
981
|
+
'$ld:ai:generation:error',
|
|
982
|
+
testContext,
|
|
983
|
+
{ configKey, variationKey, version, modelName, providerName },
|
|
984
|
+
1,
|
|
985
|
+
);
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
it('tracks failure when operation throws', async () => {
|
|
989
|
+
const tracker = new LDAIConfigTrackerImpl(
|
|
990
|
+
mockLdClient,
|
|
991
|
+
configKey,
|
|
992
|
+
variationKey,
|
|
993
|
+
version,
|
|
994
|
+
modelName,
|
|
995
|
+
providerName,
|
|
996
|
+
testContext,
|
|
997
|
+
);
|
|
998
|
+
|
|
999
|
+
const error = new Error('Operation failed');
|
|
1000
|
+
const metricsExtractor = jest.fn();
|
|
1001
|
+
const operation = jest.fn().mockRejectedValue(error);
|
|
1002
|
+
|
|
1003
|
+
await expect(tracker.trackMetricsOf(metricsExtractor, operation)).rejects.toThrow(error);
|
|
1004
|
+
|
|
1005
|
+
// Should track error
|
|
1006
|
+
expect(mockTrack).toHaveBeenCalledWith(
|
|
1007
|
+
'$ld:ai:generation:error',
|
|
1008
|
+
testContext,
|
|
1009
|
+
{ configKey, variationKey, version, modelName, providerName },
|
|
1010
|
+
1,
|
|
1011
|
+
);
|
|
1012
|
+
|
|
1013
|
+
// Should not call metrics extractor when operation fails
|
|
1014
|
+
expect(metricsExtractor).not.toHaveBeenCalled();
|
|
1015
|
+
});
|
|
1016
|
+
|
|
1017
|
+
it('tracks metrics without token usage', async () => {
|
|
1018
|
+
const tracker = new LDAIConfigTrackerImpl(
|
|
1019
|
+
mockLdClient,
|
|
1020
|
+
configKey,
|
|
1021
|
+
variationKey,
|
|
1022
|
+
version,
|
|
1023
|
+
modelName,
|
|
1024
|
+
providerName,
|
|
1025
|
+
testContext,
|
|
1026
|
+
);
|
|
1027
|
+
|
|
1028
|
+
const mockResult = { response: 'test' };
|
|
1029
|
+
const mockMetrics = {
|
|
1030
|
+
success: true,
|
|
1031
|
+
// No usage provided
|
|
1032
|
+
};
|
|
1033
|
+
|
|
1034
|
+
const metricsExtractor = jest.fn().mockReturnValue(mockMetrics);
|
|
1035
|
+
const operation = jest.fn().mockResolvedValue(mockResult);
|
|
1036
|
+
|
|
1037
|
+
await tracker.trackMetricsOf(metricsExtractor, operation);
|
|
1038
|
+
|
|
1039
|
+
// Should track success but not token usage
|
|
1040
|
+
expect(mockTrack).toHaveBeenCalledWith(
|
|
1041
|
+
'$ld:ai:generation:success',
|
|
1042
|
+
testContext,
|
|
1043
|
+
{ configKey, variationKey, version, modelName, providerName },
|
|
1044
|
+
1,
|
|
1045
|
+
);
|
|
1046
|
+
|
|
1047
|
+
// Should not track token usage
|
|
1048
|
+
expect(mockTrack).not.toHaveBeenCalledWith(
|
|
1049
|
+
'$ld:ai:tokens:total',
|
|
1050
|
+
expect.any(Object),
|
|
1051
|
+
expect.any(Object),
|
|
1052
|
+
expect.any(Number),
|
|
1053
|
+
);
|
|
1054
|
+
});
|
|
1055
|
+
});
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { TrackedChat } from '../src/api/chat/TrackedChat';
|
|
2
|
+
import { ChatResponse } from '../src/api/chat/types';
|
|
3
|
+
import { LDAIConfig, LDMessage } from '../src/api/config/LDAIConfig';
|
|
4
|
+
import { LDAIConfigTracker } from '../src/api/config/LDAIConfigTracker';
|
|
5
|
+
import { AIProvider } from '../src/api/providers/AIProvider';
|
|
6
|
+
|
|
7
|
+
describe('TrackedChat', () => {
|
|
8
|
+
let mockProvider: jest.Mocked<AIProvider>;
|
|
9
|
+
let mockTracker: jest.Mocked<LDAIConfigTracker>;
|
|
10
|
+
let aiConfig: LDAIConfig;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
// Mock the AIProvider
|
|
14
|
+
mockProvider = {
|
|
15
|
+
invokeModel: jest.fn(),
|
|
16
|
+
} as any;
|
|
17
|
+
|
|
18
|
+
// Mock the LDAIConfigTracker
|
|
19
|
+
mockTracker = {
|
|
20
|
+
trackMetricsOf: jest.fn(),
|
|
21
|
+
trackDuration: jest.fn(),
|
|
22
|
+
trackTokens: jest.fn(),
|
|
23
|
+
trackSuccess: jest.fn(),
|
|
24
|
+
trackError: jest.fn(),
|
|
25
|
+
trackFeedback: jest.fn(),
|
|
26
|
+
trackTimeToFirstToken: jest.fn(),
|
|
27
|
+
trackDurationOf: jest.fn(),
|
|
28
|
+
trackOpenAIMetrics: jest.fn(),
|
|
29
|
+
trackBedrockConverseMetrics: jest.fn(),
|
|
30
|
+
trackVercelAIMetrics: jest.fn(),
|
|
31
|
+
getSummary: jest.fn(),
|
|
32
|
+
} as any;
|
|
33
|
+
|
|
34
|
+
// Create a basic AI config
|
|
35
|
+
aiConfig = {
|
|
36
|
+
enabled: true,
|
|
37
|
+
messages: [{ role: 'system', content: 'You are a helpful assistant.' }],
|
|
38
|
+
model: { name: 'gpt-4' },
|
|
39
|
+
provider: { name: 'openai' },
|
|
40
|
+
tracker: mockTracker,
|
|
41
|
+
toVercelAISDK: jest.fn(),
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('appendMessages', () => {
|
|
46
|
+
it('appends messages to the conversation history', () => {
|
|
47
|
+
const chat = new TrackedChat(aiConfig, mockTracker, mockProvider);
|
|
48
|
+
|
|
49
|
+
const messagesToAppend: LDMessage[] = [
|
|
50
|
+
{ role: 'user', content: 'Hello' },
|
|
51
|
+
{ role: 'assistant', content: 'Hi there!' },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
chat.appendMessages(messagesToAppend);
|
|
55
|
+
|
|
56
|
+
const messages = chat.getMessages(false);
|
|
57
|
+
expect(messages).toHaveLength(2);
|
|
58
|
+
expect(messages[0]).toEqual({ role: 'user', content: 'Hello' });
|
|
59
|
+
expect(messages[1]).toEqual({ role: 'assistant', content: 'Hi there!' });
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('appends multiple message batches sequentially', () => {
|
|
63
|
+
const chat = new TrackedChat(aiConfig, mockTracker, mockProvider);
|
|
64
|
+
|
|
65
|
+
chat.appendMessages([{ role: 'user', content: 'First message' }]);
|
|
66
|
+
chat.appendMessages([{ role: 'assistant', content: 'Second message' }]);
|
|
67
|
+
chat.appendMessages([{ role: 'user', content: 'Third message' }]);
|
|
68
|
+
|
|
69
|
+
const messages = chat.getMessages(false);
|
|
70
|
+
expect(messages).toHaveLength(3);
|
|
71
|
+
expect(messages[0].content).toBe('First message');
|
|
72
|
+
expect(messages[1].content).toBe('Second message');
|
|
73
|
+
expect(messages[2].content).toBe('Third message');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('handles empty message array', () => {
|
|
77
|
+
const chat = new TrackedChat(aiConfig, mockTracker, mockProvider);
|
|
78
|
+
|
|
79
|
+
chat.appendMessages([]);
|
|
80
|
+
|
|
81
|
+
const messages = chat.getMessages(false);
|
|
82
|
+
expect(messages).toHaveLength(0);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('getMessages', () => {
|
|
87
|
+
it('returns only conversation history when includeConfigMessages is false', () => {
|
|
88
|
+
const chat = new TrackedChat(aiConfig, mockTracker, mockProvider);
|
|
89
|
+
|
|
90
|
+
chat.appendMessages([
|
|
91
|
+
{ role: 'user', content: 'User message' },
|
|
92
|
+
{ role: 'assistant', content: 'Assistant message' },
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
const messages = chat.getMessages(false);
|
|
96
|
+
|
|
97
|
+
expect(messages).toHaveLength(2);
|
|
98
|
+
expect(messages[0]).toEqual({ role: 'user', content: 'User message' });
|
|
99
|
+
expect(messages[1]).toEqual({ role: 'assistant', content: 'Assistant message' });
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('returns only conversation history when includeConfigMessages is omitted (defaults to false)', () => {
|
|
103
|
+
const chat = new TrackedChat(aiConfig, mockTracker, mockProvider);
|
|
104
|
+
|
|
105
|
+
chat.appendMessages([{ role: 'user', content: 'User message' }]);
|
|
106
|
+
|
|
107
|
+
const messages = chat.getMessages();
|
|
108
|
+
|
|
109
|
+
expect(messages).toHaveLength(1);
|
|
110
|
+
expect(messages[0]).toEqual({ role: 'user', content: 'User message' });
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('returns config messages prepended when includeConfigMessages is true', () => {
|
|
114
|
+
const chat = new TrackedChat(aiConfig, mockTracker, mockProvider);
|
|
115
|
+
|
|
116
|
+
chat.appendMessages([
|
|
117
|
+
{ role: 'user', content: 'User message' },
|
|
118
|
+
{ role: 'assistant', content: 'Assistant message' },
|
|
119
|
+
]);
|
|
120
|
+
|
|
121
|
+
const messages = chat.getMessages(true);
|
|
122
|
+
|
|
123
|
+
expect(messages).toHaveLength(3);
|
|
124
|
+
expect(messages[0]).toEqual({ role: 'system', content: 'You are a helpful assistant.' });
|
|
125
|
+
expect(messages[1]).toEqual({ role: 'user', content: 'User message' });
|
|
126
|
+
expect(messages[2]).toEqual({ role: 'assistant', content: 'Assistant message' });
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('returns only config messages when no conversation history exists and includeConfigMessages is true', () => {
|
|
130
|
+
const chat = new TrackedChat(aiConfig, mockTracker, mockProvider);
|
|
131
|
+
|
|
132
|
+
const messages = chat.getMessages(true);
|
|
133
|
+
|
|
134
|
+
expect(messages).toHaveLength(1);
|
|
135
|
+
expect(messages[0]).toEqual({ role: 'system', content: 'You are a helpful assistant.' });
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('returns empty array when no messages exist and includeConfigMessages is false', () => {
|
|
139
|
+
const configWithoutMessages: LDAIConfig = {
|
|
140
|
+
...aiConfig,
|
|
141
|
+
messages: [],
|
|
142
|
+
};
|
|
143
|
+
const chat = new TrackedChat(configWithoutMessages, mockTracker, mockProvider);
|
|
144
|
+
|
|
145
|
+
const messages = chat.getMessages(false);
|
|
146
|
+
|
|
147
|
+
expect(messages).toHaveLength(0);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('returns a copy of the messages array (not a reference)', () => {
|
|
151
|
+
const chat = new TrackedChat(aiConfig, mockTracker, mockProvider);
|
|
152
|
+
|
|
153
|
+
chat.appendMessages([{ role: 'user', content: 'Original message' }]);
|
|
154
|
+
|
|
155
|
+
const messages1 = chat.getMessages();
|
|
156
|
+
const messages2 = chat.getMessages();
|
|
157
|
+
|
|
158
|
+
expect(messages1).not.toBe(messages2);
|
|
159
|
+
expect(messages1).toEqual(messages2);
|
|
160
|
+
|
|
161
|
+
// Modifying returned array should not affect internal state
|
|
162
|
+
messages1.push({ role: 'assistant', content: 'Modified' });
|
|
163
|
+
|
|
164
|
+
const messages3 = chat.getMessages();
|
|
165
|
+
expect(messages3).toHaveLength(1);
|
|
166
|
+
expect(messages3[0].content).toBe('Original message');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('handles undefined config messages gracefully', () => {
|
|
170
|
+
const configWithoutMessages: LDAIConfig = {
|
|
171
|
+
...aiConfig,
|
|
172
|
+
messages: undefined,
|
|
173
|
+
};
|
|
174
|
+
const chat = new TrackedChat(configWithoutMessages, mockTracker, mockProvider);
|
|
175
|
+
|
|
176
|
+
chat.appendMessages([{ role: 'user', content: 'User message' }]);
|
|
177
|
+
|
|
178
|
+
const messagesWithConfig = chat.getMessages(true);
|
|
179
|
+
expect(messagesWithConfig).toHaveLength(1);
|
|
180
|
+
expect(messagesWithConfig[0].content).toBe('User message');
|
|
181
|
+
|
|
182
|
+
const messagesWithoutConfig = chat.getMessages(false);
|
|
183
|
+
expect(messagesWithoutConfig).toHaveLength(1);
|
|
184
|
+
expect(messagesWithoutConfig[0].content).toBe('User message');
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe('integration with invoke', () => {
|
|
189
|
+
it('adds messages from invoke to history accessible via getMessages', async () => {
|
|
190
|
+
const mockResponse: ChatResponse = {
|
|
191
|
+
message: { role: 'assistant', content: 'Response from model' },
|
|
192
|
+
metrics: { success: true },
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
mockTracker.trackMetricsOf.mockImplementation(async (extractor, func) => func());
|
|
196
|
+
|
|
197
|
+
mockProvider.invokeModel.mockResolvedValue(mockResponse);
|
|
198
|
+
|
|
199
|
+
const chat = new TrackedChat(aiConfig, mockTracker, mockProvider);
|
|
200
|
+
|
|
201
|
+
await chat.invoke('Hello');
|
|
202
|
+
|
|
203
|
+
const messages = chat.getMessages(false);
|
|
204
|
+
expect(messages).toHaveLength(2);
|
|
205
|
+
expect(messages[0]).toEqual({ role: 'user', content: 'Hello' });
|
|
206
|
+
expect(messages[1]).toEqual({ role: 'assistant', content: 'Response from model' });
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('preserves appended messages when invoking', async () => {
|
|
210
|
+
const mockResponse: ChatResponse = {
|
|
211
|
+
message: { role: 'assistant', content: 'Response' },
|
|
212
|
+
metrics: { success: true },
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
mockTracker.trackMetricsOf.mockImplementation(async (extractor, func) => func());
|
|
216
|
+
|
|
217
|
+
mockProvider.invokeModel.mockResolvedValue(mockResponse);
|
|
218
|
+
|
|
219
|
+
const chat = new TrackedChat(aiConfig, mockTracker, mockProvider);
|
|
220
|
+
|
|
221
|
+
chat.appendMessages([{ role: 'user', content: 'Pre-appended message' }]);
|
|
222
|
+
await chat.invoke('New user input');
|
|
223
|
+
|
|
224
|
+
const messages = chat.getMessages(false);
|
|
225
|
+
expect(messages).toHaveLength(3);
|
|
226
|
+
expect(messages[0].content).toBe('Pre-appended message');
|
|
227
|
+
expect(messages[1].content).toBe('New user input');
|
|
228
|
+
expect(messages[2].content).toBe('Response');
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
});
|
package/dist/LDAIClientImpl.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { LDContext } from '@launchdarkly/js-server-sdk-common';
|
|
2
2
|
import { LDAIAgent, LDAIAgentConfig, LDAIAgentDefaults } from './api/agents';
|
|
3
|
+
import { TrackedChat } from './api/chat';
|
|
3
4
|
import { LDAIConfig, LDAIDefaults } from './api/config';
|
|
4
5
|
import { LDAIClient } from './api/LDAIClient';
|
|
6
|
+
import { SupportedAIProvider } from './api/providers';
|
|
5
7
|
import { LDClientMin } from './LDClientMin';
|
|
6
8
|
export declare class LDAIClientImpl implements LDAIClient {
|
|
7
9
|
private _ldClient;
|
|
10
|
+
private _logger?;
|
|
8
11
|
constructor(_ldClient: LDClientMin);
|
|
9
12
|
private _interpolateTemplate;
|
|
10
13
|
private _evaluate;
|
|
@@ -14,5 +17,6 @@ export declare class LDAIClientImpl implements LDAIClient {
|
|
|
14
17
|
agents<const T extends readonly (LDAIAgentConfig & {
|
|
15
18
|
defaultValue: LDAIAgentDefaults;
|
|
16
19
|
})[]>(agentConfigs: T, context: LDContext): Promise<Record<T[number]['key'], LDAIAgent>>;
|
|
20
|
+
initChat(key: string, context: LDContext, defaultValue: LDAIDefaults, variables?: Record<string, unknown>, defaultAiProvider?: SupportedAIProvider): Promise<TrackedChat | undefined>;
|
|
17
21
|
}
|
|
18
22
|
//# sourceMappingURL=LDAIClientImpl.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LDAIClientImpl.d.ts","sourceRoot":"","sources":["../src/LDAIClientImpl.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"LDAIClientImpl.d.ts","sourceRoot":"","sources":["../src/LDAIClientImpl.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAY,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EACL,UAAU,EAEV,YAAY,EAOb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAqB,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAGzE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAuC5C,qBAAa,cAAe,YAAW,UAAU;IAGnC,OAAO,CAAC,SAAS;IAF7B,OAAO,CAAC,OAAO,CAAC,CAAW;gBAEP,SAAS,EAAE,WAAW;IAI1C,OAAO,CAAC,oBAAoB;YAId,SAAS;YAkCT,cAAc;IAoCtB,MAAM,CACV,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,SAAS,EAClB,YAAY,EAAE,YAAY,EAC1B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,UAAU,CAAC;IA4ChB,KAAK,CACT,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,SAAS,EAClB,YAAY,EAAE,iBAAiB,EAC/B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,SAAS,CAAC;IAOf,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,SAAS,CAAC,eAAe,GAAG;QAAE,YAAY,EAAE,iBAAiB,CAAA;KAAE,CAAC,EAAE,EAC7F,YAAY,EAAE,CAAC,EACf,OAAO,EAAE,SAAS,GACjB,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC;IA0BzC,QAAQ,CACZ,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,SAAS,EAClB,YAAY,EAAE,YAAY,EAC1B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,iBAAiB,CAAC,EAAE,mBAAmB,GACtC,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;CAqBpC"}
|
package/dist/LDAIClientImpl.js
CHANGED
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LDAIClientImpl = void 0;
|
|
4
4
|
const Mustache = require("mustache");
|
|
5
|
+
const chat_1 = require("./api/chat");
|
|
6
|
+
const providers_1 = require("./api/providers");
|
|
5
7
|
const LDAIConfigMapper_1 = require("./LDAIConfigMapper");
|
|
6
8
|
const LDAIConfigTrackerImpl_1 = require("./LDAIConfigTrackerImpl");
|
|
7
9
|
class LDAIClientImpl {
|
|
8
10
|
constructor(_ldClient) {
|
|
9
11
|
this._ldClient = _ldClient;
|
|
12
|
+
this._logger = _ldClient.logger;
|
|
10
13
|
}
|
|
11
14
|
_interpolateTemplate(template, variables) {
|
|
12
15
|
return Mustache.render(template, variables, undefined, { escape: (item) => item });
|
|
@@ -89,6 +92,24 @@ class LDAIClientImpl {
|
|
|
89
92
|
}));
|
|
90
93
|
return agents;
|
|
91
94
|
}
|
|
95
|
+
async initChat(key, context, defaultValue, variables, defaultAiProvider) {
|
|
96
|
+
var _a;
|
|
97
|
+
// Track chat initialization
|
|
98
|
+
this._ldClient.track('$ld:ai:config:function:initChat', context, key, 1);
|
|
99
|
+
const aiConfig = await this.config(key, context, defaultValue, variables);
|
|
100
|
+
// Return undefined if the configuration is disabled
|
|
101
|
+
if (!aiConfig.enabled) {
|
|
102
|
+
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.info(`Chat configuration is disabled: ${key}`);
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
// Create the AIProvider instance
|
|
106
|
+
const provider = await providers_1.AIProviderFactory.create(aiConfig, this._logger, defaultAiProvider);
|
|
107
|
+
if (!provider) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
// Create the TrackedChat instance with the provider
|
|
111
|
+
return new chat_1.TrackedChat(aiConfig, aiConfig.tracker, provider);
|
|
112
|
+
}
|
|
92
113
|
}
|
|
93
114
|
exports.LDAIClientImpl = LDAIClientImpl;
|
|
94
115
|
//# sourceMappingURL=LDAIClientImpl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LDAIClientImpl.js","sourceRoot":"","sources":["../src/LDAIClientImpl.ts"],"names":[],"mappings":";;;AAAA,qCAAqC;
|
|
1
|
+
{"version":3,"file":"LDAIClientImpl.js","sourceRoot":"","sources":["../src/LDAIClientImpl.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { LDContext } from '@launchdarkly/js-server-sdk-common';
|
|
2
2
|
import { LDAIConfigTracker } from './api/config';
|
|
3
3
|
import { LDAIMetricSummary } from './api/config/LDAIConfigTracker';
|
|
4
|
-
import { LDFeedbackKind, LDTokenUsage } from './api/metrics';
|
|
4
|
+
import { LDAIMetrics, LDFeedbackKind, LDTokenUsage } from './api/metrics';
|
|
5
5
|
import { LDClientMin } from './LDClientMin';
|
|
6
6
|
export declare class LDAIConfigTrackerImpl implements LDAIConfigTracker {
|
|
7
7
|
private _ldClient;
|
|
@@ -22,6 +22,7 @@ export declare class LDAIConfigTrackerImpl implements LDAIConfigTracker {
|
|
|
22
22
|
}): void;
|
|
23
23
|
trackSuccess(): void;
|
|
24
24
|
trackError(): void;
|
|
25
|
+
trackMetricsOf<TRes>(metricsExtractor: (result: TRes) => LDAIMetrics, func: () => Promise<TRes>): Promise<TRes>;
|
|
25
26
|
trackOpenAIMetrics<TRes extends {
|
|
26
27
|
usage?: {
|
|
27
28
|
total_tokens?: number;
|