@launchdarkly/server-sdk-ai 0.12.3 → 0.14.0
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 +44 -0
- package/README.md +2 -2
- package/__tests__/Judge.test.ts +496 -0
- package/__tests__/LDAIClientImpl.test.ts +530 -323
- package/__tests__/LDAIConfigTrackerImpl.test.ts +50 -290
- package/__tests__/TrackedChat.test.ts +4 -5
- package/dist/package.json +53 -0
- package/dist/src/LDAIClientImpl.d.ts +39 -0
- package/dist/src/LDAIClientImpl.d.ts.map +1 -0
- package/dist/src/LDAIClientImpl.js +164 -0
- package/dist/src/LDAIClientImpl.js.map +1 -0
- package/dist/{LDAIConfigTrackerImpl.d.ts → src/LDAIConfigTrackerImpl.d.ts} +13 -11
- package/dist/src/LDAIConfigTrackerImpl.d.ts.map +1 -0
- package/dist/{LDAIConfigTrackerImpl.js → src/LDAIConfigTrackerImpl.js} +59 -44
- package/dist/src/LDAIConfigTrackerImpl.js.map +1 -0
- package/dist/src/LDClientMin.d.ts.map +1 -0
- package/dist/{LDClientMin.js.map → src/LDClientMin.js.map} +1 -1
- package/dist/src/api/LDAIClient.d.ts +258 -0
- package/dist/src/api/LDAIClient.d.ts.map +1 -0
- package/dist/{api → src/api}/LDAIClient.js.map +1 -1
- package/dist/{api → src/api}/chat/TrackedChat.d.ts +22 -4
- package/dist/src/api/chat/TrackedChat.d.ts.map +1 -0
- package/dist/{api → src/api}/chat/TrackedChat.js +43 -2
- package/dist/src/api/chat/TrackedChat.js.map +1 -0
- package/dist/src/api/chat/index.d.ts.map +1 -0
- package/dist/src/api/chat/index.js.map +1 -0
- package/dist/src/api/chat/types.d.ts +22 -0
- package/dist/src/api/chat/types.d.ts.map +1 -0
- package/dist/{api → src/api}/chat/types.js.map +1 -1
- package/dist/{api → src/api}/config/LDAIConfigTracker.d.ts +41 -22
- package/dist/src/api/config/LDAIConfigTracker.d.ts.map +1 -0
- package/dist/src/api/config/LDAIConfigTracker.js.map +1 -0
- package/dist/src/api/config/LDAIConfigUtils.d.ts +2 -0
- package/dist/src/api/config/LDAIConfigUtils.d.ts.map +1 -0
- package/dist/src/api/config/LDAIConfigUtils.js +141 -0
- package/dist/src/api/config/LDAIConfigUtils.js.map +1 -0
- package/dist/src/api/config/index.d.ts +3 -0
- package/dist/src/api/config/index.d.ts.map +1 -0
- package/dist/{api/agents → src/api/config}/index.js +1 -1
- package/dist/src/api/config/index.js.map +1 -0
- package/dist/src/api/config/types.d.ts +202 -0
- package/dist/src/api/config/types.d.ts.map +1 -0
- package/dist/{api/agents/LDAIAgent.js → src/api/config/types.js} +1 -1
- package/dist/src/api/config/types.js.map +1 -0
- package/dist/{api → src/api}/index.d.ts +1 -1
- package/dist/src/api/index.d.ts.map +1 -0
- package/dist/{api → src/api}/index.js +1 -1
- package/dist/src/api/index.js.map +1 -0
- package/dist/src/api/judge/EvaluationSchemaBuilder.d.ts +11 -0
- package/dist/src/api/judge/EvaluationSchemaBuilder.d.ts.map +1 -0
- package/dist/src/api/judge/EvaluationSchemaBuilder.js +52 -0
- package/dist/src/api/judge/EvaluationSchemaBuilder.js.map +1 -0
- package/dist/src/api/judge/Judge.d.ts +63 -0
- package/dist/src/api/judge/Judge.d.ts.map +1 -0
- package/dist/src/api/judge/Judge.js +149 -0
- package/dist/src/api/judge/Judge.js.map +1 -0
- package/dist/src/api/judge/index.d.ts +3 -0
- package/dist/src/api/judge/index.d.ts.map +1 -0
- package/dist/src/api/judge/index.js +6 -0
- package/dist/src/api/judge/index.js.map +1 -0
- package/dist/src/api/judge/types.d.ts +35 -0
- package/dist/src/api/judge/types.d.ts.map +1 -0
- package/dist/{api/config/LDAIConfig.js → src/api/judge/types.js} +1 -1
- package/dist/src/api/judge/types.js.map +1 -0
- package/dist/src/api/metrics/BedrockTokenUsage.d.ts.map +1 -0
- package/dist/src/api/metrics/BedrockTokenUsage.js.map +1 -0
- package/dist/src/api/metrics/LDAIMetrics.d.ts.map +1 -0
- package/dist/src/api/metrics/LDAIMetrics.js.map +1 -0
- package/dist/src/api/metrics/LDFeedbackKind.d.ts.map +1 -0
- package/dist/src/api/metrics/LDFeedbackKind.js.map +1 -0
- package/dist/src/api/metrics/LDTokenUsage.d.ts.map +1 -0
- package/dist/src/api/metrics/LDTokenUsage.js.map +1 -0
- package/dist/src/api/metrics/OpenAiUsage.d.ts.map +1 -0
- package/dist/src/api/metrics/OpenAiUsage.js.map +1 -0
- package/dist/src/api/metrics/VercelAISDKTokenUsage.d.ts.map +1 -0
- package/dist/src/api/metrics/VercelAISDKTokenUsage.js.map +1 -0
- package/dist/src/api/metrics/index.d.ts.map +1 -0
- package/dist/src/api/metrics/index.js.map +1 -0
- package/dist/{api → src/api}/providers/AIProvider.d.ts +20 -3
- package/dist/src/api/providers/AIProvider.d.ts.map +1 -0
- package/dist/src/api/providers/AIProvider.js +88 -0
- package/dist/src/api/providers/AIProvider.js.map +1 -0
- package/dist/{api → src/api}/providers/AIProviderFactory.d.ts +2 -2
- package/dist/src/api/providers/AIProviderFactory.d.ts.map +1 -0
- package/dist/src/api/providers/AIProviderFactory.js.map +1 -0
- package/dist/src/api/providers/index.d.ts.map +1 -0
- package/dist/src/api/providers/index.js.map +1 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js.map +1 -0
- package/docs/assets/search.js +1 -1
- package/docs/classes/AIProvider.html +55 -20
- package/docs/classes/AIProviderFactory.html +27 -17
- package/docs/classes/Judge.html +322 -0
- package/docs/classes/TrackedChat.html +97 -29
- package/docs/enums/LDFeedbackKind.html +22 -12
- package/docs/functions/createBedrockTokenUsage.html +20 -10
- package/docs/functions/createOpenAiUsage.html +20 -10
- package/docs/functions/createVercelAISDKTokenUsage.html +20 -10
- package/docs/functions/initAi.html +20 -10
- package/docs/index.html +36 -16
- package/docs/interfaces/ChatResponse.html +35 -14
- package/docs/interfaces/EvalScore.html +119 -0
- package/docs/interfaces/JudgeResponse.html +129 -0
- package/docs/interfaces/LDAIAgentConfig.html +81 -33
- package/docs/interfaces/{LDAIAgent.html → LDAIAgentConfigDefault.html} +51 -41
- package/docs/interfaces/LDAIAgentRequestConfig.html +129 -0
- package/docs/interfaces/LDAIClient.html +234 -40
- package/docs/interfaces/{VercelAISDKConfig.html → LDAICompletionConfig.html} +86 -86
- package/docs/interfaces/LDAICompletionConfigDefault.html +155 -0
- package/docs/interfaces/LDAIConfig.html +45 -75
- package/docs/interfaces/LDAIConfigDefault.html +133 -0
- package/docs/interfaces/LDAIConfigTracker.html +140 -59
- package/docs/interfaces/LDAIJudgeConfig.html +167 -0
- package/docs/interfaces/LDAIJudgeConfigDefault.html +155 -0
- package/docs/interfaces/LDAIMetrics.html +22 -12
- package/docs/interfaces/LDJudge.html +119 -0
- package/docs/interfaces/{VercelAISDKMapOptions.html → LDJudgeConfiguration.html} +36 -19
- package/docs/interfaces/LDLogger.html +19 -9
- package/docs/interfaces/LDMessage.html +22 -12
- package/docs/interfaces/LDModelConfig.html +23 -13
- package/docs/interfaces/LDProviderConfig.html +21 -11
- package/docs/interfaces/LDTokenUsage.html +23 -13
- package/docs/interfaces/StructuredResponse.html +129 -0
- package/docs/types/{VercelAISDKProvider.html → LDAIConfigDefaultKind.html} +26 -31
- package/docs/types/{LDAIAgentDefaults.html → LDAIConfigKind.html} +24 -14
- package/docs/types/{LDAIDefaults.html → LDAIConfigMode.html} +24 -24
- package/docs/types/SupportedAIProvider.html +20 -10
- package/docs/variables/SUPPORTED_AI_PROVIDERS.html +20 -10
- package/package.json +3 -3
- package/src/LDAIClientImpl.ts +222 -176
- package/src/LDAIConfigTrackerImpl.ts +73 -54
- package/src/api/LDAIClient.ts +166 -33
- package/src/api/chat/TrackedChat.ts +64 -5
- package/src/api/chat/types.ts +8 -1
- package/src/api/config/LDAIConfigTracker.ts +46 -27
- package/src/api/config/LDAIConfigUtils.ts +201 -0
- package/src/api/config/index.ts +2 -2
- package/src/api/config/types.ts +256 -0
- package/src/api/index.ts +1 -1
- package/src/api/judge/EvaluationSchemaBuilder.ts +54 -0
- package/src/api/judge/Judge.ts +216 -0
- package/src/api/judge/index.ts +2 -0
- package/src/api/judge/types.ts +39 -0
- package/src/api/providers/AIProvider.ts +54 -3
- package/src/api/providers/AIProviderFactory.ts +4 -4
- package/tsconfig.json +3 -3
- package/tsconfig.ref.json +1 -1
- package/__tests__/LDAIConfigMapper.test.ts +0 -159
- package/dist/LDAIClientImpl.d.ts +0 -23
- package/dist/LDAIClientImpl.d.ts.map +0 -1
- package/dist/LDAIClientImpl.js +0 -128
- package/dist/LDAIClientImpl.js.map +0 -1
- package/dist/LDAIConfigMapper.d.ts +0 -10
- package/dist/LDAIConfigMapper.d.ts.map +0 -1
- package/dist/LDAIConfigMapper.js +0 -55
- package/dist/LDAIConfigMapper.js.map +0 -1
- package/dist/LDAIConfigTrackerImpl.d.ts.map +0 -1
- package/dist/LDAIConfigTrackerImpl.js.map +0 -1
- package/dist/LDClientMin.d.ts.map +0 -1
- package/dist/api/LDAIClient.d.ts +0 -169
- package/dist/api/LDAIClient.d.ts.map +0 -1
- package/dist/api/agents/LDAIAgent.d.ts +0 -32
- package/dist/api/agents/LDAIAgent.d.ts.map +0 -1
- package/dist/api/agents/LDAIAgent.js.map +0 -1
- package/dist/api/agents/index.d.ts +0 -2
- package/dist/api/agents/index.d.ts.map +0 -1
- package/dist/api/agents/index.js.map +0 -1
- package/dist/api/chat/TrackedChat.d.ts.map +0 -1
- package/dist/api/chat/TrackedChat.js.map +0 -1
- package/dist/api/chat/index.d.ts.map +0 -1
- package/dist/api/chat/index.js.map +0 -1
- package/dist/api/chat/types.d.ts +0 -16
- package/dist/api/chat/types.d.ts.map +0 -1
- package/dist/api/config/LDAIConfig.d.ts +0 -92
- package/dist/api/config/LDAIConfig.d.ts.map +0 -1
- package/dist/api/config/LDAIConfig.js.map +0 -1
- package/dist/api/config/LDAIConfigTracker.d.ts.map +0 -1
- package/dist/api/config/LDAIConfigTracker.js.map +0 -1
- package/dist/api/config/VercelAISDK.d.ts +0 -19
- package/dist/api/config/VercelAISDK.d.ts.map +0 -1
- package/dist/api/config/VercelAISDK.js +0 -3
- package/dist/api/config/VercelAISDK.js.map +0 -1
- package/dist/api/config/index.d.ts +0 -4
- package/dist/api/config/index.d.ts.map +0 -1
- package/dist/api/config/index.js +0 -19
- package/dist/api/config/index.js.map +0 -1
- package/dist/api/index.d.ts.map +0 -1
- package/dist/api/index.js.map +0 -1
- package/dist/api/metrics/BedrockTokenUsage.d.ts.map +0 -1
- package/dist/api/metrics/BedrockTokenUsage.js.map +0 -1
- package/dist/api/metrics/LDAIMetrics.d.ts.map +0 -1
- package/dist/api/metrics/LDAIMetrics.js.map +0 -1
- package/dist/api/metrics/LDFeedbackKind.d.ts.map +0 -1
- package/dist/api/metrics/LDFeedbackKind.js.map +0 -1
- package/dist/api/metrics/LDTokenUsage.d.ts.map +0 -1
- package/dist/api/metrics/LDTokenUsage.js.map +0 -1
- package/dist/api/metrics/OpenAiUsage.d.ts.map +0 -1
- package/dist/api/metrics/OpenAiUsage.js.map +0 -1
- package/dist/api/metrics/VercelAISDKTokenUsage.d.ts.map +0 -1
- package/dist/api/metrics/VercelAISDKTokenUsage.js.map +0 -1
- package/dist/api/metrics/index.d.ts.map +0 -1
- package/dist/api/metrics/index.js.map +0 -1
- package/dist/api/providers/AIProvider.d.ts.map +0 -1
- package/dist/api/providers/AIProvider.js +0 -31
- package/dist/api/providers/AIProvider.js.map +0 -1
- package/dist/api/providers/AIProviderFactory.d.ts.map +0 -1
- package/dist/api/providers/AIProviderFactory.js.map +0 -1
- package/dist/api/providers/index.d.ts.map +0 -1
- package/dist/api/providers/index.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/src/LDAIConfigMapper.ts +0 -65
- package/src/api/agents/LDAIAgent.ts +0 -36
- package/src/api/agents/index.ts +0 -1
- package/src/api/config/LDAIConfig.ts +0 -101
- package/src/api/config/VercelAISDK.ts +0 -21
- /package/dist/{LDClientMin.d.ts → src/LDClientMin.d.ts} +0 -0
- /package/dist/{LDClientMin.js → src/LDClientMin.js} +0 -0
- /package/dist/{api → src/api}/LDAIClient.js +0 -0
- /package/dist/{api → src/api}/chat/index.d.ts +0 -0
- /package/dist/{api → src/api}/chat/index.js +0 -0
- /package/dist/{api → src/api}/chat/types.js +0 -0
- /package/dist/{api → src/api}/config/LDAIConfigTracker.js +0 -0
- /package/dist/{api → src/api}/metrics/BedrockTokenUsage.d.ts +0 -0
- /package/dist/{api → src/api}/metrics/BedrockTokenUsage.js +0 -0
- /package/dist/{api → src/api}/metrics/LDAIMetrics.d.ts +0 -0
- /package/dist/{api → src/api}/metrics/LDAIMetrics.js +0 -0
- /package/dist/{api → src/api}/metrics/LDFeedbackKind.d.ts +0 -0
- /package/dist/{api → src/api}/metrics/LDFeedbackKind.js +0 -0
- /package/dist/{api → src/api}/metrics/LDTokenUsage.d.ts +0 -0
- /package/dist/{api → src/api}/metrics/LDTokenUsage.js +0 -0
- /package/dist/{api → src/api}/metrics/OpenAiUsage.d.ts +0 -0
- /package/dist/{api → src/api}/metrics/OpenAiUsage.js +0 -0
- /package/dist/{api → src/api}/metrics/VercelAISDKTokenUsage.d.ts +0 -0
- /package/dist/{api → src/api}/metrics/VercelAISDKTokenUsage.js +0 -0
- /package/dist/{api → src/api}/metrics/index.d.ts +0 -0
- /package/dist/{api → src/api}/metrics/index.js +0 -0
- /package/dist/{api → src/api}/providers/AIProviderFactory.js +0 -0
- /package/dist/{api → src/api}/providers/index.d.ts +0 -0
- /package/dist/{api → src/api}/providers/index.js +0 -0
- /package/dist/{index.d.ts → src/index.d.ts} +0 -0
- /package/dist/{index.js → src/index.js} +0 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import * as Mustache from 'mustache';
|
|
2
|
+
|
|
3
|
+
import { LDLogger } from '@launchdarkly/js-server-sdk-common';
|
|
4
|
+
|
|
5
|
+
import { ChatResponse } from '../chat/types';
|
|
6
|
+
import { LDAIConfigTracker } from '../config/LDAIConfigTracker';
|
|
7
|
+
import { LDAIJudgeConfig, LDMessage } from '../config/types';
|
|
8
|
+
import { AIProvider } from '../providers/AIProvider';
|
|
9
|
+
import { EvaluationSchemaBuilder } from './EvaluationSchemaBuilder';
|
|
10
|
+
import { EvalScore, JudgeResponse, StructuredResponse } from './types';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Judge implementation that handles evaluation functionality and conversation management.
|
|
14
|
+
*
|
|
15
|
+
* According to the AIEval spec, judges are AI Configs with mode: "judge" that evaluate
|
|
16
|
+
* other AI Configs using structured output.
|
|
17
|
+
*/
|
|
18
|
+
export class Judge {
|
|
19
|
+
private readonly _logger?: LDLogger;
|
|
20
|
+
private readonly _evaluationResponseStructure: Record<string, unknown>;
|
|
21
|
+
|
|
22
|
+
constructor(
|
|
23
|
+
private readonly _aiConfig: LDAIJudgeConfig,
|
|
24
|
+
private readonly _aiConfigTracker: LDAIConfigTracker,
|
|
25
|
+
private readonly _aiProvider: AIProvider,
|
|
26
|
+
logger?: LDLogger,
|
|
27
|
+
) {
|
|
28
|
+
this._logger = logger;
|
|
29
|
+
this._evaluationResponseStructure = EvaluationSchemaBuilder.build(
|
|
30
|
+
this._aiConfig.evaluationMetricKeys,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Evaluates an AI response using the judge's configuration.
|
|
36
|
+
*
|
|
37
|
+
* @param input The input prompt or question that was provided to the AI
|
|
38
|
+
* @param output The AI-generated response to be evaluated
|
|
39
|
+
* @param samplingRate Sampling rate (0-1) to determine if evaluation should be processed (defaults to 1)
|
|
40
|
+
* @returns Promise that resolves to evaluation results or undefined if not sampled
|
|
41
|
+
*/
|
|
42
|
+
async evaluate(
|
|
43
|
+
input: string,
|
|
44
|
+
output: string,
|
|
45
|
+
samplingRate: number = 1,
|
|
46
|
+
): Promise<JudgeResponse | undefined> {
|
|
47
|
+
try {
|
|
48
|
+
if (
|
|
49
|
+
!this._aiConfig.evaluationMetricKeys ||
|
|
50
|
+
this._aiConfig.evaluationMetricKeys.length === 0
|
|
51
|
+
) {
|
|
52
|
+
this._logger?.warn(
|
|
53
|
+
'Judge configuration is missing required evaluationMetricKeys',
|
|
54
|
+
this._aiConfigTracker.getTrackData(),
|
|
55
|
+
);
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!this._aiConfig.messages) {
|
|
60
|
+
this._logger?.warn(
|
|
61
|
+
'Judge configuration must include messages',
|
|
62
|
+
this._aiConfigTracker.getTrackData(),
|
|
63
|
+
);
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (Math.random() > samplingRate) {
|
|
68
|
+
this._logger?.debug(`Judge evaluation skipped due to sampling rate: ${samplingRate}`);
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const messages = this._constructEvaluationMessages(input, output);
|
|
73
|
+
|
|
74
|
+
const response = await this._aiConfigTracker.trackMetricsOf(
|
|
75
|
+
(result: StructuredResponse) => result.metrics,
|
|
76
|
+
() => this._aiProvider.invokeStructuredModel(messages, this._evaluationResponseStructure),
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
let { success } = response.metrics;
|
|
80
|
+
|
|
81
|
+
const evals = this._parseEvaluationResponse(response.data);
|
|
82
|
+
|
|
83
|
+
if (Object.keys(evals).length !== this._aiConfig.evaluationMetricKeys.length) {
|
|
84
|
+
this._logger?.warn(
|
|
85
|
+
'Judge evaluation did not return all evaluations',
|
|
86
|
+
this._aiConfigTracker.getTrackData(),
|
|
87
|
+
);
|
|
88
|
+
success = false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
evals,
|
|
93
|
+
success,
|
|
94
|
+
};
|
|
95
|
+
} catch (error) {
|
|
96
|
+
this._logger?.error('Judge evaluation failed:', error);
|
|
97
|
+
return {
|
|
98
|
+
evals: {},
|
|
99
|
+
success: false,
|
|
100
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Evaluates an AI response from chat messages and response.
|
|
107
|
+
*
|
|
108
|
+
* @param messages Array of messages representing the conversation history
|
|
109
|
+
* @param response The AI response to be evaluated
|
|
110
|
+
* @param samplingRatio Sampling ratio (0-1) to determine if evaluation should be processed (defaults to 1)
|
|
111
|
+
* @returns Promise that resolves to evaluation results or undefined if not sampled
|
|
112
|
+
*/
|
|
113
|
+
async evaluateMessages(
|
|
114
|
+
messages: LDMessage[],
|
|
115
|
+
response: ChatResponse,
|
|
116
|
+
samplingRatio: number = 1,
|
|
117
|
+
): Promise<JudgeResponse | undefined> {
|
|
118
|
+
const input = messages.length === 0 ? '' : messages.map((msg) => msg.content).join('\r\n');
|
|
119
|
+
const output = response.message.content;
|
|
120
|
+
|
|
121
|
+
return this.evaluate(input, output, samplingRatio);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Returns the AI Config used by this judge.
|
|
126
|
+
*/
|
|
127
|
+
getAIConfig(): LDAIJudgeConfig {
|
|
128
|
+
return this._aiConfig;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Returns the tracker associated with this judge.
|
|
133
|
+
*/
|
|
134
|
+
getTracker(): LDAIConfigTracker {
|
|
135
|
+
return this._aiConfigTracker;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Returns the AI provider used by this judge.
|
|
140
|
+
*/
|
|
141
|
+
getProvider(): AIProvider {
|
|
142
|
+
return this._aiProvider;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Constructs evaluation messages by combining judge's config messages with input/output.
|
|
147
|
+
*/
|
|
148
|
+
private _constructEvaluationMessages(input: string, output: string): LDMessage[] {
|
|
149
|
+
const messages: LDMessage[] = this._aiConfig.messages!.map((msg) => ({
|
|
150
|
+
...msg,
|
|
151
|
+
content: this._interpolateMessage(msg.content, {
|
|
152
|
+
message_history: input,
|
|
153
|
+
response_to_evaluate: output,
|
|
154
|
+
}),
|
|
155
|
+
}));
|
|
156
|
+
|
|
157
|
+
return messages;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Interpolates message content with variables using Mustache templating.
|
|
162
|
+
*/
|
|
163
|
+
private _interpolateMessage(content: string, variables: Record<string, string>): string {
|
|
164
|
+
return Mustache.render(content, variables, undefined, { escape: (item: any) => item });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Parses the structured evaluation response from the AI provider.
|
|
169
|
+
*/
|
|
170
|
+
private _parseEvaluationResponse(data: Record<string, unknown>): Record<string, EvalScore> {
|
|
171
|
+
const evaluations = data.evaluations as Record<string, unknown>;
|
|
172
|
+
const results: Record<string, EvalScore> = {};
|
|
173
|
+
|
|
174
|
+
if (!data.evaluations || typeof data.evaluations !== 'object') {
|
|
175
|
+
this._logger?.warn('Invalid response: missing or invalid evaluations object');
|
|
176
|
+
return results;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
this._aiConfig.evaluationMetricKeys.forEach((metricKey) => {
|
|
180
|
+
const evaluation = evaluations[metricKey];
|
|
181
|
+
|
|
182
|
+
if (!evaluation || typeof evaluation !== 'object') {
|
|
183
|
+
this._logger?.warn(
|
|
184
|
+
`Missing evaluation for metric key: ${metricKey}`,
|
|
185
|
+
this._aiConfigTracker.getTrackData(),
|
|
186
|
+
);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const evalData = evaluation as Record<string, unknown>;
|
|
191
|
+
|
|
192
|
+
if (typeof evalData.score !== 'number' || evalData.score < 0 || evalData.score > 1) {
|
|
193
|
+
this._logger?.warn(
|
|
194
|
+
`Invalid score evaluated for ${metricKey}: ${evalData.score}. Score must be a number between 0 and 1 inclusive`,
|
|
195
|
+
this._aiConfigTracker.getTrackData(),
|
|
196
|
+
);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (typeof evalData.reasoning !== 'string') {
|
|
201
|
+
this._logger?.warn(
|
|
202
|
+
`Invalid reasoning evaluated for ${metricKey}: ${evalData.reasoning}. Reasoning must be a string`,
|
|
203
|
+
this._aiConfigTracker.getTrackData(),
|
|
204
|
+
);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
results[metricKey] = {
|
|
209
|
+
score: evalData.score,
|
|
210
|
+
reasoning: evalData.reasoning,
|
|
211
|
+
};
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return results;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { LDAIMetrics } from '../metrics/LDAIMetrics';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Structured response from AI models.
|
|
5
|
+
*/
|
|
6
|
+
export interface StructuredResponse {
|
|
7
|
+
/** The structured data returned by the model */
|
|
8
|
+
data: Record<string, unknown>;
|
|
9
|
+
|
|
10
|
+
/** The raw response from the model */
|
|
11
|
+
rawResponse: string;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Metrics information including success status and token usage.
|
|
15
|
+
*/
|
|
16
|
+
metrics: LDAIMetrics;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Score and reasoning for a single evaluation metric.
|
|
21
|
+
*/
|
|
22
|
+
export interface EvalScore {
|
|
23
|
+
/** Score between 0.0 and 1.0 indicating the evaluation result for this metric */
|
|
24
|
+
score: number;
|
|
25
|
+
/** Reasoning behind the provided score for this metric */
|
|
26
|
+
reasoning: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Response from a judge evaluation containing scores and reasoning for multiple metrics.
|
|
31
|
+
*/
|
|
32
|
+
export interface JudgeResponse {
|
|
33
|
+
/** Dictionary where keys are metric names and values contain score and reasoning */
|
|
34
|
+
evals: Record<string, EvalScore>;
|
|
35
|
+
/** Whether the evaluation completed successfully */
|
|
36
|
+
success: boolean;
|
|
37
|
+
/** Error message if evaluation failed */
|
|
38
|
+
error?: string;
|
|
39
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { LDLogger } from '@launchdarkly/js-server-sdk-common';
|
|
2
2
|
|
|
3
3
|
import { ChatResponse } from '../chat/types';
|
|
4
|
-
import {
|
|
4
|
+
import { LDAIConfigKind, LDMessage } from '../config/types';
|
|
5
|
+
import { StructuredResponse } from '../judge/types';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Abstract base class for AI providers that implement chat model functionality.
|
|
@@ -22,10 +23,60 @@ export abstract class AIProvider {
|
|
|
22
23
|
* This method should convert messages to provider format, invoke the model,
|
|
23
24
|
* and return a ChatResponse with the result and metrics.
|
|
24
25
|
*
|
|
26
|
+
* Default implementation takes no action and returns a placeholder response.
|
|
27
|
+
* Provider implementations should override this method.
|
|
28
|
+
*
|
|
25
29
|
* @param messages Array of LDMessage objects representing the conversation
|
|
26
30
|
* @returns Promise that resolves to a ChatResponse containing the model's response
|
|
27
31
|
*/
|
|
28
|
-
|
|
32
|
+
async invokeModel(_messages: LDMessage[]): Promise<ChatResponse> {
|
|
33
|
+
this.logger?.warn('invokeModel not implemented by this provider');
|
|
34
|
+
return {
|
|
35
|
+
message: {
|
|
36
|
+
role: 'assistant',
|
|
37
|
+
content: '',
|
|
38
|
+
},
|
|
39
|
+
metrics: {
|
|
40
|
+
success: false,
|
|
41
|
+
usage: {
|
|
42
|
+
total: 0,
|
|
43
|
+
input: 0,
|
|
44
|
+
output: 0,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Invoke the chat model with structured output support.
|
|
52
|
+
* This method should convert messages to provider format, invoke the model with
|
|
53
|
+
* structured output configuration, and return a structured response.
|
|
54
|
+
*
|
|
55
|
+
* Default implementation takes no action and returns a placeholder response.
|
|
56
|
+
* Provider implementations should override this method.
|
|
57
|
+
*
|
|
58
|
+
* @param messages Array of LDMessage objects representing the conversation
|
|
59
|
+
* @param responseStructure Dictionary of output configurations keyed by output name
|
|
60
|
+
* @returns Promise that resolves to a structured response
|
|
61
|
+
*/
|
|
62
|
+
async invokeStructuredModel(
|
|
63
|
+
_messages: LDMessage[],
|
|
64
|
+
_responseStructure: Record<string, unknown>,
|
|
65
|
+
): Promise<StructuredResponse> {
|
|
66
|
+
this.logger?.warn('invokeStructuredModel not implemented by this provider');
|
|
67
|
+
return {
|
|
68
|
+
data: {},
|
|
69
|
+
rawResponse: '',
|
|
70
|
+
metrics: {
|
|
71
|
+
success: false,
|
|
72
|
+
usage: {
|
|
73
|
+
total: 0,
|
|
74
|
+
input: 0,
|
|
75
|
+
output: 0,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
29
80
|
|
|
30
81
|
/**
|
|
31
82
|
* Static method that constructs an instance of the provider.
|
|
@@ -37,7 +88,7 @@ export abstract class AIProvider {
|
|
|
37
88
|
* @returns Promise that resolves to a configured provider instance
|
|
38
89
|
*/
|
|
39
90
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
40
|
-
static async create(aiConfig:
|
|
91
|
+
static async create(aiConfig: LDAIConfigKind, logger?: LDLogger): Promise<AIProvider> {
|
|
41
92
|
throw new Error('Provider implementations must override the static create method');
|
|
42
93
|
}
|
|
43
94
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LDLogger } from '@launchdarkly/js-server-sdk-common';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { LDAIConfigKind } from '../config/types';
|
|
4
4
|
import { AIProvider } from './AIProvider';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -32,7 +32,7 @@ export class AIProviderFactory {
|
|
|
32
32
|
* @param defaultAiProvider Optional default AI provider to use
|
|
33
33
|
*/
|
|
34
34
|
static async create(
|
|
35
|
-
aiConfig:
|
|
35
|
+
aiConfig: LDAIConfigKind,
|
|
36
36
|
logger?: LDLogger,
|
|
37
37
|
defaultAiProvider?: SupportedAIProvider,
|
|
38
38
|
): Promise<AIProvider | undefined> {
|
|
@@ -91,7 +91,7 @@ export class AIProviderFactory {
|
|
|
91
91
|
*/
|
|
92
92
|
private static async _tryCreateProvider(
|
|
93
93
|
providerType: SupportedAIProvider,
|
|
94
|
-
aiConfig:
|
|
94
|
+
aiConfig: LDAIConfigKind,
|
|
95
95
|
logger?: LDLogger,
|
|
96
96
|
): Promise<AIProvider | undefined> {
|
|
97
97
|
switch (providerType) {
|
|
@@ -127,7 +127,7 @@ export class AIProviderFactory {
|
|
|
127
127
|
private static async _createProvider(
|
|
128
128
|
packageName: string,
|
|
129
129
|
providerClassName: string,
|
|
130
|
-
aiConfig:
|
|
130
|
+
aiConfig: LDAIConfigKind,
|
|
131
131
|
logger?: LDLogger,
|
|
132
132
|
): Promise<AIProvider | undefined> {
|
|
133
133
|
try {
|
package/tsconfig.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"
|
|
3
|
+
// Uses "." so it can load package.json.
|
|
4
|
+
"rootDir": ".",
|
|
4
5
|
"outDir": "dist",
|
|
5
6
|
"target": "es2017",
|
|
6
7
|
"lib": ["es6"],
|
|
@@ -16,6 +17,5 @@
|
|
|
16
17
|
"stripInternal": true,
|
|
17
18
|
"moduleResolution": "node"
|
|
18
19
|
},
|
|
19
|
-
"
|
|
20
|
-
"exclude": ["**/*.test.ts", "dist", "node_modules", "__tests__"]
|
|
20
|
+
"exclude": ["**/*.test.ts", "dist", "node_modules", "__tests__", "examples"]
|
|
21
21
|
}
|
package/tsconfig.ref.json
CHANGED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { LDMessage, VercelAISDKMapOptions } from '../src/api/config';
|
|
2
|
-
import { LDAIConfigMapper } from '../src/LDAIConfigMapper';
|
|
3
|
-
|
|
4
|
-
describe('_findParameter', () => {
|
|
5
|
-
it('handles undefined model and messages', () => {
|
|
6
|
-
const mapper = new LDAIConfigMapper();
|
|
7
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
8
|
-
expect(mapper['_findParameter']<number>('test-param')).toBeUndefined();
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('handles parameter not found', () => {
|
|
12
|
-
const mapper = new LDAIConfigMapper({
|
|
13
|
-
name: 'test-ai-model',
|
|
14
|
-
parameters: {
|
|
15
|
-
'test-param': 123,
|
|
16
|
-
},
|
|
17
|
-
custom: {
|
|
18
|
-
'test-param': 456,
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
22
|
-
expect(mapper['_findParameter']<number>('other-param')).toBeUndefined();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('finds parameter from single model parameter', () => {
|
|
26
|
-
const mapper = new LDAIConfigMapper({
|
|
27
|
-
name: 'test-ai-model',
|
|
28
|
-
parameters: {
|
|
29
|
-
'test-param': 123,
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
33
|
-
expect(mapper['_findParameter']<number>('test-param')).toEqual(123);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('finds parameter from multiple model parameters', () => {
|
|
37
|
-
const mapper = new LDAIConfigMapper({
|
|
38
|
-
name: 'test-ai-model',
|
|
39
|
-
parameters: {
|
|
40
|
-
testParam: 123,
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
44
|
-
expect(mapper['_findParameter']<number>('test-param', 'testParam')).toEqual(123);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('finds parameter from single model custom parameter', () => {
|
|
48
|
-
const mapper = new LDAIConfigMapper({
|
|
49
|
-
name: 'test-ai-model',
|
|
50
|
-
custom: {
|
|
51
|
-
'test-param': 123,
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
55
|
-
expect(mapper['_findParameter']<number>('test-param')).toEqual(123);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('finds parameter from multiple model custom parameters', () => {
|
|
59
|
-
const mapper = new LDAIConfigMapper({
|
|
60
|
-
name: 'test-ai-model',
|
|
61
|
-
custom: {
|
|
62
|
-
testParam: 123,
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
66
|
-
expect(mapper['_findParameter']<number>('test-param', 'testParam')).toEqual(123);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('gives precedence to model parameters over model custom parameters', () => {
|
|
70
|
-
const mapper = new LDAIConfigMapper({
|
|
71
|
-
name: 'test-ai-model',
|
|
72
|
-
parameters: {
|
|
73
|
-
'test-param': 123,
|
|
74
|
-
},
|
|
75
|
-
custom: {
|
|
76
|
-
'test-param': 456,
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
80
|
-
expect(mapper['_findParameter']<number>('test-param', 'testParam')).toEqual(123);
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
describe('toVercelAIAISDK', () => {
|
|
85
|
-
const mockModel = { name: 'mockModel' };
|
|
86
|
-
const mockMessages: LDMessage[] = [
|
|
87
|
-
{ role: 'user', content: 'test prompt' },
|
|
88
|
-
{ role: 'system', content: 'test instruction' },
|
|
89
|
-
];
|
|
90
|
-
const mockOptions: VercelAISDKMapOptions = {
|
|
91
|
-
nonInterpolatedMessages: [{ role: 'assistant', content: 'test assistant instruction' }],
|
|
92
|
-
};
|
|
93
|
-
const mockProvider = jest.fn().mockReturnValue(mockModel);
|
|
94
|
-
|
|
95
|
-
beforeEach(() => {
|
|
96
|
-
jest.clearAllMocks();
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('handles undefined model and messages', () => {
|
|
100
|
-
const mapper = new LDAIConfigMapper();
|
|
101
|
-
const result = mapper.toVercelAISDK(mockProvider);
|
|
102
|
-
|
|
103
|
-
expect(mockProvider).toHaveBeenCalledWith('');
|
|
104
|
-
expect(result).toEqual(
|
|
105
|
-
expect.objectContaining({
|
|
106
|
-
model: mockModel,
|
|
107
|
-
messages: undefined,
|
|
108
|
-
}),
|
|
109
|
-
);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('uses additional messages', () => {
|
|
113
|
-
const mapper = new LDAIConfigMapper({ name: 'test-ai-model' });
|
|
114
|
-
const result = mapper.toVercelAISDK(mockProvider, mockOptions);
|
|
115
|
-
|
|
116
|
-
expect(mockProvider).toHaveBeenCalledWith('test-ai-model');
|
|
117
|
-
expect(result).toEqual(
|
|
118
|
-
expect.objectContaining({
|
|
119
|
-
model: mockModel,
|
|
120
|
-
messages: mockOptions.nonInterpolatedMessages,
|
|
121
|
-
}),
|
|
122
|
-
);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('combines config messages and additional messages', () => {
|
|
126
|
-
const mapper = new LDAIConfigMapper({ name: 'test-ai-model' }, undefined, mockMessages);
|
|
127
|
-
const result = mapper.toVercelAISDK(mockProvider, mockOptions);
|
|
128
|
-
|
|
129
|
-
expect(mockProvider).toHaveBeenCalledWith('test-ai-model');
|
|
130
|
-
expect(result).toEqual(
|
|
131
|
-
expect.objectContaining({
|
|
132
|
-
model: mockModel,
|
|
133
|
-
messages: [...mockMessages, ...(mockOptions.nonInterpolatedMessages ?? [])],
|
|
134
|
-
}),
|
|
135
|
-
);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it('requests parameters correctly', () => {
|
|
139
|
-
const mapper = new LDAIConfigMapper({ name: 'test-ai-model' }, undefined, mockMessages);
|
|
140
|
-
const findParameterMock = jest.spyOn(mapper as any, '_findParameter');
|
|
141
|
-
const result = mapper.toVercelAISDK(mockProvider);
|
|
142
|
-
|
|
143
|
-
expect(mockProvider).toHaveBeenCalledWith('test-ai-model');
|
|
144
|
-
expect(result).toEqual(
|
|
145
|
-
expect.objectContaining({
|
|
146
|
-
model: mockModel,
|
|
147
|
-
messages: mockMessages,
|
|
148
|
-
}),
|
|
149
|
-
);
|
|
150
|
-
expect(findParameterMock).toHaveBeenCalledWith('max_tokens', 'maxTokens');
|
|
151
|
-
expect(findParameterMock).toHaveBeenCalledWith('temperature');
|
|
152
|
-
expect(findParameterMock).toHaveBeenCalledWith('top_p', 'topP');
|
|
153
|
-
expect(findParameterMock).toHaveBeenCalledWith('top_k', 'topK');
|
|
154
|
-
expect(findParameterMock).toHaveBeenCalledWith('presence_penalty', 'presencePenalty');
|
|
155
|
-
expect(findParameterMock).toHaveBeenCalledWith('frequency_penalty', 'frequencyPenalty');
|
|
156
|
-
expect(findParameterMock).toHaveBeenCalledWith('stop', 'stop_sequences', 'stopSequences');
|
|
157
|
-
expect(findParameterMock).toHaveBeenCalledWith('seed');
|
|
158
|
-
});
|
|
159
|
-
});
|
package/dist/LDAIClientImpl.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { LDContext } from '@launchdarkly/js-server-sdk-common';
|
|
2
|
-
import { LDAIAgent, LDAIAgentConfig, LDAIAgentDefaults } from './api/agents';
|
|
3
|
-
import { TrackedChat } from './api/chat';
|
|
4
|
-
import { LDAIConfig, LDAIDefaults } from './api/config';
|
|
5
|
-
import { LDAIClient } from './api/LDAIClient';
|
|
6
|
-
import { SupportedAIProvider } from './api/providers';
|
|
7
|
-
import { LDClientMin } from './LDClientMin';
|
|
8
|
-
export declare class LDAIClientImpl implements LDAIClient {
|
|
9
|
-
private _ldClient;
|
|
10
|
-
private _logger?;
|
|
11
|
-
constructor(_ldClient: LDClientMin);
|
|
12
|
-
private _interpolateTemplate;
|
|
13
|
-
private static _toLDFlagValue;
|
|
14
|
-
private _evaluate;
|
|
15
|
-
private _evaluateAgent;
|
|
16
|
-
config(key: string, context: LDContext, defaultValue: LDAIDefaults, variables?: Record<string, unknown>): Promise<LDAIConfig>;
|
|
17
|
-
agent(key: string, context: LDContext, defaultValue: LDAIAgentDefaults, variables?: Record<string, unknown>): Promise<LDAIAgent>;
|
|
18
|
-
agents<const T extends readonly (LDAIAgentConfig & {
|
|
19
|
-
defaultValue: LDAIAgentDefaults;
|
|
20
|
-
})[]>(agentConfigs: T, context: LDContext): Promise<Record<T[number]['key'], LDAIAgent>>;
|
|
21
|
-
initChat(key: string, context: LDContext, defaultValue: LDAIDefaults, variables?: Record<string, unknown>, defaultAiProvider?: SupportedAIProvider): Promise<TrackedChat | undefined>;
|
|
22
|
-
}
|
|
23
|
-
//# sourceMappingURL=LDAIClientImpl.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
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;IAI5B,OAAO,CAAC,MAAM,CAAC,cAAc;YAgBf,SAAS;YAsCT,cAAc;IAsCtB,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"}
|