@happyvertical/ai 0.74.8
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/AGENT.md +33 -0
- package/LICENSE +7 -0
- package/README.md +384 -0
- package/dist/chunks/anthropic-BRwbhwIl.js +463 -0
- package/dist/chunks/anthropic-BRwbhwIl.js.map +1 -0
- package/dist/chunks/bedrock-Cf1xUerN.js +808 -0
- package/dist/chunks/bedrock-Cf1xUerN.js.map +1 -0
- package/dist/chunks/bifrost-3mXtQsTj.js +233 -0
- package/dist/chunks/bifrost-3mXtQsTj.js.map +1 -0
- package/dist/chunks/claude-cli-BrHRfkry.js +603 -0
- package/dist/chunks/claude-cli-BrHRfkry.js.map +1 -0
- package/dist/chunks/gateway-admin-C4GFPbZF.js +359 -0
- package/dist/chunks/gateway-admin-C4GFPbZF.js.map +1 -0
- package/dist/chunks/gemini-BfpHXDIQ.js +662 -0
- package/dist/chunks/gemini-BfpHXDIQ.js.map +1 -0
- package/dist/chunks/huggingface-280qv9iv.js +366 -0
- package/dist/chunks/huggingface-280qv9iv.js.map +1 -0
- package/dist/chunks/index-BT4thAvS.js +934 -0
- package/dist/chunks/index-BT4thAvS.js.map +1 -0
- package/dist/chunks/litellm-DhPKa_Jz.js +220 -0
- package/dist/chunks/litellm-DhPKa_Jz.js.map +1 -0
- package/dist/chunks/ollama-Di1ldur0.js +851 -0
- package/dist/chunks/ollama-Di1ldur0.js.map +1 -0
- package/dist/chunks/openai-5snI2diE.js +749 -0
- package/dist/chunks/openai-5snI2diE.js.map +1 -0
- package/dist/chunks/qwen-tts-DgPgdXxG.js +365 -0
- package/dist/chunks/qwen-tts-DgPgdXxG.js.map +1 -0
- package/dist/chunks/usage-DMWiJ2oB.js +21 -0
- package/dist/chunks/usage-DMWiJ2oB.js.map +1 -0
- package/dist/cli/claude-context.d.ts +3 -0
- package/dist/cli/claude-context.d.ts.map +1 -0
- package/dist/cli/claude-context.js +21 -0
- package/dist/cli/claude-context.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/node/factory.d.ts +27 -0
- package/dist/node/factory.d.ts.map +1 -0
- package/dist/shared/client.d.ts +410 -0
- package/dist/shared/client.d.ts.map +1 -0
- package/dist/shared/factory.d.ts +83 -0
- package/dist/shared/factory.d.ts.map +1 -0
- package/dist/shared/message.d.ts +71 -0
- package/dist/shared/message.d.ts.map +1 -0
- package/dist/shared/providers/anthropic.d.ts +82 -0
- package/dist/shared/providers/anthropic.d.ts.map +1 -0
- package/dist/shared/providers/bedrock.d.ts +49 -0
- package/dist/shared/providers/bedrock.d.ts.map +1 -0
- package/dist/shared/providers/bifrost.d.ts +25 -0
- package/dist/shared/providers/bifrost.d.ts.map +1 -0
- package/dist/shared/providers/claude-cli.d.ts +139 -0
- package/dist/shared/providers/claude-cli.d.ts.map +1 -0
- package/dist/shared/providers/gateway-admin.d.ts +35 -0
- package/dist/shared/providers/gateway-admin.d.ts.map +1 -0
- package/dist/shared/providers/gemini.d.ts +116 -0
- package/dist/shared/providers/gemini.d.ts.map +1 -0
- package/dist/shared/providers/huggingface.d.ts +33 -0
- package/dist/shared/providers/huggingface.d.ts.map +1 -0
- package/dist/shared/providers/litellm.d.ts +25 -0
- package/dist/shared/providers/litellm.d.ts.map +1 -0
- package/dist/shared/providers/ollama.d.ts +47 -0
- package/dist/shared/providers/ollama.d.ts.map +1 -0
- package/dist/shared/providers/openai.d.ts +272 -0
- package/dist/shared/providers/openai.d.ts.map +1 -0
- package/dist/shared/providers/qwen-tts.d.ts +85 -0
- package/dist/shared/providers/qwen-tts.d.ts.map +1 -0
- package/dist/shared/providers/usage.d.ts +14 -0
- package/dist/shared/providers/usage.d.ts.map +1 -0
- package/dist/shared/rate-limit.d.ts +13 -0
- package/dist/shared/rate-limit.d.ts.map +1 -0
- package/dist/shared/thread.d.ts +104 -0
- package/dist/shared/thread.d.ts.map +1 -0
- package/dist/shared/types.d.ts +1779 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/metadata.json +35 -0
- package/package.json +62 -0
|
@@ -0,0 +1,934 @@
|
|
|
1
|
+
import { ValidationError, ApiError, loadEnvConfig } from "@happyvertical/utils";
|
|
2
|
+
import OpenAI from "openai";
|
|
3
|
+
const AI_PROVIDER_TYPES = [
|
|
4
|
+
"openai",
|
|
5
|
+
"litellm",
|
|
6
|
+
"bifrost",
|
|
7
|
+
"ollama",
|
|
8
|
+
"gemini",
|
|
9
|
+
"anthropic",
|
|
10
|
+
"huggingface",
|
|
11
|
+
"bedrock",
|
|
12
|
+
"claude-cli",
|
|
13
|
+
"qwen3-tts"
|
|
14
|
+
];
|
|
15
|
+
function extractTextContent(content) {
|
|
16
|
+
if (typeof content === "string") {
|
|
17
|
+
return content;
|
|
18
|
+
}
|
|
19
|
+
return content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
|
|
20
|
+
}
|
|
21
|
+
class AIError extends Error {
|
|
22
|
+
constructor(message, code, provider, model, retryable = false) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.code = code;
|
|
25
|
+
this.provider = provider;
|
|
26
|
+
this.model = model;
|
|
27
|
+
this.retryable = retryable;
|
|
28
|
+
this.name = "AIError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
class AuthenticationError extends AIError {
|
|
32
|
+
constructor(provider) {
|
|
33
|
+
super("Authentication failed", "AUTH_ERROR", provider, void 0, false);
|
|
34
|
+
this.name = "AuthenticationError";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
class RateLimitError extends AIError {
|
|
38
|
+
retryAfter;
|
|
39
|
+
constructor(provider, retryAfter) {
|
|
40
|
+
super(
|
|
41
|
+
`Rate limit exceeded${retryAfter ? `, retry after ${retryAfter}s` : ""}`,
|
|
42
|
+
"RATE_LIMIT",
|
|
43
|
+
provider,
|
|
44
|
+
void 0,
|
|
45
|
+
true
|
|
46
|
+
);
|
|
47
|
+
this.name = "RateLimitError";
|
|
48
|
+
this.retryAfter = retryAfter;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
class ModelNotFoundError extends AIError {
|
|
52
|
+
constructor(model, provider) {
|
|
53
|
+
super(
|
|
54
|
+
`Model not found: ${model}`,
|
|
55
|
+
"MODEL_NOT_FOUND",
|
|
56
|
+
provider,
|
|
57
|
+
model,
|
|
58
|
+
false
|
|
59
|
+
);
|
|
60
|
+
this.name = "ModelNotFoundError";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
class ContextLengthError extends AIError {
|
|
64
|
+
constructor(provider, model) {
|
|
65
|
+
super(
|
|
66
|
+
"Input exceeds maximum context length",
|
|
67
|
+
"CONTEXT_LENGTH_EXCEEDED",
|
|
68
|
+
provider,
|
|
69
|
+
model,
|
|
70
|
+
false
|
|
71
|
+
);
|
|
72
|
+
this.name = "ContextLengthError";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
class ContentFilterError extends AIError {
|
|
76
|
+
constructor(provider, model) {
|
|
77
|
+
super(
|
|
78
|
+
"Content filtered by safety systems",
|
|
79
|
+
"CONTENT_FILTERED",
|
|
80
|
+
provider,
|
|
81
|
+
model,
|
|
82
|
+
false
|
|
83
|
+
);
|
|
84
|
+
this.name = "ContentFilterError";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function isOpenAIClientOptions(options) {
|
|
88
|
+
return options.type === "openai" && "apiKey" in options && !!options.apiKey;
|
|
89
|
+
}
|
|
90
|
+
function isAIClientInstance(value) {
|
|
91
|
+
return value instanceof AIClient;
|
|
92
|
+
}
|
|
93
|
+
class AIClient {
|
|
94
|
+
/**
|
|
95
|
+
* Configuration options for this client
|
|
96
|
+
*/
|
|
97
|
+
options;
|
|
98
|
+
/**
|
|
99
|
+
* Creates a new AIClient
|
|
100
|
+
*
|
|
101
|
+
* @param options - Client configuration options
|
|
102
|
+
*/
|
|
103
|
+
constructor(options) {
|
|
104
|
+
this.options = options;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Sends a message to the AI
|
|
108
|
+
* Base implementation returns a placeholder response
|
|
109
|
+
*
|
|
110
|
+
* @param text - Message text
|
|
111
|
+
* @param options - Message options
|
|
112
|
+
* @returns Promise resolving to a placeholder response
|
|
113
|
+
*/
|
|
114
|
+
async message(_text, _options = { role: "user" }) {
|
|
115
|
+
return "not a real ai message, this is the base class!";
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Factory method to create appropriate AI client based on options
|
|
119
|
+
*
|
|
120
|
+
* @param options - Client configuration options
|
|
121
|
+
* @returns Promise resolving to an initialized AI client
|
|
122
|
+
* @throws Error if client type is invalid
|
|
123
|
+
*/
|
|
124
|
+
static async create(options) {
|
|
125
|
+
if (isAIClientInstance(options)) {
|
|
126
|
+
return options;
|
|
127
|
+
}
|
|
128
|
+
const clientOptions = options;
|
|
129
|
+
if (isOpenAIClientOptions(clientOptions)) {
|
|
130
|
+
return OpenAIClient.create(clientOptions);
|
|
131
|
+
}
|
|
132
|
+
const providedType = clientOptions.type;
|
|
133
|
+
if (providedType && providedType !== "openai") {
|
|
134
|
+
const { getAI: getAI2 } = await Promise.resolve().then(() => factory);
|
|
135
|
+
return await getAI2(clientOptions);
|
|
136
|
+
}
|
|
137
|
+
if (providedType === "openai") {
|
|
138
|
+
throw new ValidationError(
|
|
139
|
+
"OpenAI API key is required but missing or empty",
|
|
140
|
+
{
|
|
141
|
+
supportedTypes: [...AI_PROVIDER_TYPES],
|
|
142
|
+
providedType,
|
|
143
|
+
hint: "Set OPENAI_API_KEY environment variable or pass apiKey in options"
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
throw new ValidationError("Invalid client type specified", {
|
|
148
|
+
supportedTypes: [...AI_PROVIDER_TYPES],
|
|
149
|
+
providedType
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Gets a text completion from the AI
|
|
154
|
+
* In base class, delegates to message method
|
|
155
|
+
*
|
|
156
|
+
* @param text - Input text for completion
|
|
157
|
+
* @param options - Completion options
|
|
158
|
+
* @returns Promise resolving to the completion result
|
|
159
|
+
*/
|
|
160
|
+
textCompletion(text, options = {
|
|
161
|
+
role: "user"
|
|
162
|
+
}) {
|
|
163
|
+
return this.message(text, options);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async function getOpenAI(options) {
|
|
167
|
+
return new OpenAI({
|
|
168
|
+
apiKey: options.apiKey,
|
|
169
|
+
baseURL: options.baseUrl
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
class OpenAIClient extends AIClient {
|
|
173
|
+
/**
|
|
174
|
+
* OpenAI client instance
|
|
175
|
+
*/
|
|
176
|
+
openai;
|
|
177
|
+
/**
|
|
178
|
+
* Configuration options for this client
|
|
179
|
+
*/
|
|
180
|
+
options;
|
|
181
|
+
/**
|
|
182
|
+
* Creates a new OpenAIClient
|
|
183
|
+
*
|
|
184
|
+
* @param options - OpenAI client configuration options
|
|
185
|
+
*/
|
|
186
|
+
constructor(options) {
|
|
187
|
+
super(options);
|
|
188
|
+
this.options = options;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Sends a message to OpenAI
|
|
192
|
+
*
|
|
193
|
+
* @param text - Message text
|
|
194
|
+
* @param options - Message options
|
|
195
|
+
* @returns Promise resolving to the OpenAI response
|
|
196
|
+
*/
|
|
197
|
+
async message(text, options = { role: "user" }) {
|
|
198
|
+
const response = await this.textCompletion(text, options);
|
|
199
|
+
return response;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Factory method to create and initialize an OpenAIClient
|
|
203
|
+
*
|
|
204
|
+
* @param options - OpenAI client configuration options
|
|
205
|
+
* @returns Promise resolving to an initialized OpenAIClient
|
|
206
|
+
*/
|
|
207
|
+
static async create(options) {
|
|
208
|
+
const client = new OpenAIClient(options);
|
|
209
|
+
await client.initialize();
|
|
210
|
+
return client;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Initializes the OpenAI client
|
|
214
|
+
*/
|
|
215
|
+
async initialize() {
|
|
216
|
+
this.openai = new OpenAI({
|
|
217
|
+
apiKey: this.options.apiKey,
|
|
218
|
+
baseURL: this.options.baseUrl
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Sends a text completion request to the OpenAI API
|
|
223
|
+
*
|
|
224
|
+
* @param message - The message to send
|
|
225
|
+
* @param options - Configuration options for the completion request
|
|
226
|
+
* @returns Promise resolving to the completion text
|
|
227
|
+
* @throws Error if the OpenAI API response is invalid
|
|
228
|
+
*/
|
|
229
|
+
async textCompletion(message, options = {}) {
|
|
230
|
+
const {
|
|
231
|
+
model = "gpt-4o",
|
|
232
|
+
role = "user",
|
|
233
|
+
history = [],
|
|
234
|
+
name: _name,
|
|
235
|
+
frequencyPenalty = 0,
|
|
236
|
+
logitBias,
|
|
237
|
+
logprobs = false,
|
|
238
|
+
topLogprobs,
|
|
239
|
+
maxTokens,
|
|
240
|
+
n = 1,
|
|
241
|
+
presencePenalty = 0,
|
|
242
|
+
responseFormat,
|
|
243
|
+
seed,
|
|
244
|
+
stop,
|
|
245
|
+
stream: _stream = false,
|
|
246
|
+
temperature = 1,
|
|
247
|
+
topProbability: topP = 1,
|
|
248
|
+
tools,
|
|
249
|
+
toolChoice,
|
|
250
|
+
user,
|
|
251
|
+
onProgress
|
|
252
|
+
} = options;
|
|
253
|
+
const messages = [
|
|
254
|
+
...history,
|
|
255
|
+
{
|
|
256
|
+
role,
|
|
257
|
+
content: message
|
|
258
|
+
}
|
|
259
|
+
];
|
|
260
|
+
if (onProgress) {
|
|
261
|
+
const stream = await this.openai.chat.completions.create({
|
|
262
|
+
model,
|
|
263
|
+
messages,
|
|
264
|
+
stream: true,
|
|
265
|
+
frequency_penalty: frequencyPenalty,
|
|
266
|
+
logit_bias: logitBias,
|
|
267
|
+
logprobs,
|
|
268
|
+
top_logprobs: topLogprobs,
|
|
269
|
+
max_tokens: maxTokens,
|
|
270
|
+
n,
|
|
271
|
+
presence_penalty: presencePenalty,
|
|
272
|
+
response_format: responseFormat,
|
|
273
|
+
seed,
|
|
274
|
+
stop,
|
|
275
|
+
temperature,
|
|
276
|
+
top_p: topP,
|
|
277
|
+
tools,
|
|
278
|
+
tool_choice: toolChoice,
|
|
279
|
+
user
|
|
280
|
+
});
|
|
281
|
+
let fullContent = "";
|
|
282
|
+
for await (const chunk of stream) {
|
|
283
|
+
const content = chunk.choices[0]?.delta?.content || "";
|
|
284
|
+
fullContent += content;
|
|
285
|
+
onProgress(content);
|
|
286
|
+
}
|
|
287
|
+
return fullContent;
|
|
288
|
+
}
|
|
289
|
+
const response = await this.openai.chat.completions.create({
|
|
290
|
+
model,
|
|
291
|
+
messages,
|
|
292
|
+
frequency_penalty: frequencyPenalty,
|
|
293
|
+
logit_bias: logitBias,
|
|
294
|
+
logprobs,
|
|
295
|
+
top_logprobs: topLogprobs,
|
|
296
|
+
max_tokens: maxTokens,
|
|
297
|
+
n,
|
|
298
|
+
presence_penalty: presencePenalty,
|
|
299
|
+
response_format: responseFormat,
|
|
300
|
+
seed,
|
|
301
|
+
stop,
|
|
302
|
+
stream: false,
|
|
303
|
+
temperature,
|
|
304
|
+
top_p: topP,
|
|
305
|
+
tools,
|
|
306
|
+
tool_choice: toolChoice,
|
|
307
|
+
user
|
|
308
|
+
});
|
|
309
|
+
const choice = response.choices[0];
|
|
310
|
+
if (!choice || !choice.message || !choice.message.content) {
|
|
311
|
+
throw new ApiError("Invalid response from OpenAI API: Missing content", {
|
|
312
|
+
model,
|
|
313
|
+
responseId: response.id,
|
|
314
|
+
choices: response.choices?.length || 0,
|
|
315
|
+
hasChoice: !!choice,
|
|
316
|
+
hasMessage: !!choice?.message,
|
|
317
|
+
hasContent: !!choice?.message?.content
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
return choice.message.content;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
async function getAIClient(options) {
|
|
324
|
+
const { getAI: getAI2 } = await Promise.resolve().then(() => factory);
|
|
325
|
+
return await getAI2(options);
|
|
326
|
+
}
|
|
327
|
+
const RATE_LIMITED_METHODS = /* @__PURE__ */ new Set([
|
|
328
|
+
"chat",
|
|
329
|
+
"complete",
|
|
330
|
+
"message",
|
|
331
|
+
"embed",
|
|
332
|
+
"embedImage",
|
|
333
|
+
"describeImage",
|
|
334
|
+
"generateImage",
|
|
335
|
+
"getModels",
|
|
336
|
+
"synthesizeSpeech",
|
|
337
|
+
"cloneVoice",
|
|
338
|
+
"designVoice",
|
|
339
|
+
"getVoices"
|
|
340
|
+
]);
|
|
341
|
+
const MAX_BUDGET_COORDINATORS = 128;
|
|
342
|
+
const BUDGET_COORDINATOR_TTL_MS = 15 * 60 * 1e3;
|
|
343
|
+
class BudgetCoordinator {
|
|
344
|
+
nextAvailableAt = 0;
|
|
345
|
+
pendingSchedules = 0;
|
|
346
|
+
tail = Promise.resolve();
|
|
347
|
+
lastUsedAt = Date.now();
|
|
348
|
+
touch() {
|
|
349
|
+
this.lastUsedAt = Date.now();
|
|
350
|
+
}
|
|
351
|
+
schedule(work) {
|
|
352
|
+
this.pendingSchedules += 1;
|
|
353
|
+
this.touch();
|
|
354
|
+
const run = this.tail.then(work, work);
|
|
355
|
+
this.tail = run.then(
|
|
356
|
+
() => void 0,
|
|
357
|
+
() => void 0
|
|
358
|
+
);
|
|
359
|
+
return run.finally(() => {
|
|
360
|
+
this.pendingSchedules = Math.max(0, this.pendingSchedules - 1);
|
|
361
|
+
this.touch();
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
async waitUntilReady() {
|
|
365
|
+
this.touch();
|
|
366
|
+
const delayMs = this.nextAvailableAt - Date.now();
|
|
367
|
+
if (delayMs > 0) {
|
|
368
|
+
await sleep(delayMs);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
delayFor(delayMs) {
|
|
372
|
+
this.touch();
|
|
373
|
+
if (delayMs <= 0) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
this.nextAvailableAt = Math.max(this.nextAvailableAt, Date.now() + delayMs);
|
|
377
|
+
}
|
|
378
|
+
isEvictable(now) {
|
|
379
|
+
return this.pendingSchedules === 0 && now >= this.nextAvailableAt;
|
|
380
|
+
}
|
|
381
|
+
isExpired(now) {
|
|
382
|
+
return this.isEvictable(now) && now - this.lastUsedAt >= BUDGET_COORDINATOR_TTL_MS;
|
|
383
|
+
}
|
|
384
|
+
getLastUsedAt() {
|
|
385
|
+
return this.lastUsedAt;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
const budgetCoordinators = /* @__PURE__ */ new Map();
|
|
389
|
+
function sleep(delayMs) {
|
|
390
|
+
return new Promise((resolve) => {
|
|
391
|
+
setTimeout(resolve, delayMs);
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
function pruneBudgetCoordinators() {
|
|
395
|
+
const now = Date.now();
|
|
396
|
+
for (const [key, coordinator] of budgetCoordinators.entries()) {
|
|
397
|
+
if (coordinator.isExpired(now)) {
|
|
398
|
+
budgetCoordinators.delete(key);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
while (budgetCoordinators.size > MAX_BUDGET_COORDINATORS) {
|
|
402
|
+
const evictableEntries = [...budgetCoordinators.entries()].filter(([, coordinator]) => coordinator.isEvictable(now)).sort(
|
|
403
|
+
([, leftCoordinator], [, rightCoordinator]) => leftCoordinator.getLastUsedAt() - rightCoordinator.getLastUsedAt()
|
|
404
|
+
);
|
|
405
|
+
if (evictableEntries.length === 0) {
|
|
406
|
+
break;
|
|
407
|
+
}
|
|
408
|
+
budgetCoordinators.delete(evictableEntries[0][0]);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function getBudgetCoordinator(key) {
|
|
412
|
+
pruneBudgetCoordinators();
|
|
413
|
+
let coordinator = budgetCoordinators.get(key);
|
|
414
|
+
if (!coordinator) {
|
|
415
|
+
coordinator = new BudgetCoordinator();
|
|
416
|
+
budgetCoordinators.set(key, coordinator);
|
|
417
|
+
pruneBudgetCoordinators();
|
|
418
|
+
}
|
|
419
|
+
coordinator.touch();
|
|
420
|
+
return coordinator;
|
|
421
|
+
}
|
|
422
|
+
function hasPacingConfig(rateLimit) {
|
|
423
|
+
if (!rateLimit || rateLimit.enabled === false) {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
return rateLimit.enabled === true || rateLimit.key !== void 0 || rateLimit.cooldownMs !== void 0 || rateLimit.initialDelayMs !== void 0 || rateLimit.maxAttempts !== void 0;
|
|
427
|
+
}
|
|
428
|
+
function normalizeNonNegativeInteger(value, fallback) {
|
|
429
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
430
|
+
return fallback;
|
|
431
|
+
}
|
|
432
|
+
return Math.max(0, Math.trunc(value));
|
|
433
|
+
}
|
|
434
|
+
function hashKey(value) {
|
|
435
|
+
let hash = 2166136261;
|
|
436
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
437
|
+
hash ^= value.charCodeAt(index);
|
|
438
|
+
hash = Math.imul(hash, 16777619);
|
|
439
|
+
}
|
|
440
|
+
return (hash >>> 0).toString(36);
|
|
441
|
+
}
|
|
442
|
+
function deriveBudgetKey(options) {
|
|
443
|
+
const type = options.type;
|
|
444
|
+
const provider = typeof type === "string" && type ? type : "openai";
|
|
445
|
+
const credentialLikeValues = [
|
|
446
|
+
"apiKey" in options ? options.apiKey : void 0,
|
|
447
|
+
"apiToken" in options ? options.apiToken : void 0,
|
|
448
|
+
"credentials" in options ? options.credentials?.accessKeyId : void 0,
|
|
449
|
+
"endpoint" in options ? options.endpoint : void 0,
|
|
450
|
+
"baseUrl" in options ? options.baseUrl : void 0,
|
|
451
|
+
"cliPath" in options ? options.cliPath : void 0
|
|
452
|
+
];
|
|
453
|
+
const seed = credentialLikeValues.find(
|
|
454
|
+
(value) => typeof value === "string" && value.length > 0
|
|
455
|
+
);
|
|
456
|
+
return seed ? `${provider}:${hashKey(seed)}` : `${provider}:default`;
|
|
457
|
+
}
|
|
458
|
+
function normalizeRateLimitConfig(options) {
|
|
459
|
+
const rateLimit = "rateLimit" in options ? options.rateLimit : void 0;
|
|
460
|
+
if (!hasPacingConfig(rateLimit)) {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
return {
|
|
464
|
+
cooldownMs: normalizeNonNegativeInteger(rateLimit?.cooldownMs, 0),
|
|
465
|
+
initialDelayMs: normalizeNonNegativeInteger(
|
|
466
|
+
rateLimit?.initialDelayMs,
|
|
467
|
+
5e3
|
|
468
|
+
),
|
|
469
|
+
key: rateLimit?.key?.trim() || deriveBudgetKey(options),
|
|
470
|
+
maxAttempts: Math.max(
|
|
471
|
+
1,
|
|
472
|
+
normalizeNonNegativeInteger(rateLimit?.maxAttempts, 3)
|
|
473
|
+
)
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
function getRetryDelayMs(error, config) {
|
|
477
|
+
const hintedDelayMs = typeof error.retryAfter === "number" && Number.isFinite(error.retryAfter) ? Math.max(0, Math.ceil(error.retryAfter * 1e3)) : void 0;
|
|
478
|
+
if (hintedDelayMs !== void 0) {
|
|
479
|
+
return Math.max(config.cooldownMs, hintedDelayMs);
|
|
480
|
+
}
|
|
481
|
+
return Math.max(config.cooldownMs, config.initialDelayMs);
|
|
482
|
+
}
|
|
483
|
+
async function invokeWithPacing(execute, coordinator, config) {
|
|
484
|
+
let attempt = 1;
|
|
485
|
+
while (true) {
|
|
486
|
+
await coordinator.waitUntilReady();
|
|
487
|
+
try {
|
|
488
|
+
const result = await execute();
|
|
489
|
+
coordinator.delayFor(config.cooldownMs);
|
|
490
|
+
return result;
|
|
491
|
+
} catch (error) {
|
|
492
|
+
if (error instanceof RateLimitError) {
|
|
493
|
+
coordinator.delayFor(getRetryDelayMs(error, config));
|
|
494
|
+
if (error.retryable && attempt < config.maxAttempts) {
|
|
495
|
+
attempt += 1;
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
throw error;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
function parseRetryAfterSeconds(retryAfter) {
|
|
504
|
+
if (typeof retryAfter === "number" && Number.isFinite(retryAfter)) {
|
|
505
|
+
return Math.max(0, retryAfter);
|
|
506
|
+
}
|
|
507
|
+
if (typeof retryAfter !== "string") {
|
|
508
|
+
return void 0;
|
|
509
|
+
}
|
|
510
|
+
const trimmed = retryAfter.trim();
|
|
511
|
+
if (!trimmed) {
|
|
512
|
+
return void 0;
|
|
513
|
+
}
|
|
514
|
+
const seconds = Number.parseFloat(trimmed);
|
|
515
|
+
if (!Number.isNaN(seconds)) {
|
|
516
|
+
return Math.max(0, seconds);
|
|
517
|
+
}
|
|
518
|
+
const retryAt = Date.parse(trimmed);
|
|
519
|
+
if (Number.isNaN(retryAt)) {
|
|
520
|
+
return void 0;
|
|
521
|
+
}
|
|
522
|
+
return Math.max(0, Math.ceil((retryAt - Date.now()) / 1e3));
|
|
523
|
+
}
|
|
524
|
+
function getHeaderValue(headers, headerName) {
|
|
525
|
+
if (!headers || typeof headers !== "object") {
|
|
526
|
+
return void 0;
|
|
527
|
+
}
|
|
528
|
+
if ("get" in headers && typeof headers.get === "function") {
|
|
529
|
+
return headers.get(headerName) ?? headers.get(headerName.toLowerCase());
|
|
530
|
+
}
|
|
531
|
+
const objectHeaders = headers;
|
|
532
|
+
return objectHeaders[headerName] ?? objectHeaders[headerName.toLowerCase()];
|
|
533
|
+
}
|
|
534
|
+
function extractRetryAfterSeconds(error) {
|
|
535
|
+
if (!error || typeof error !== "object") {
|
|
536
|
+
return void 0;
|
|
537
|
+
}
|
|
538
|
+
if ("retryAfter" in error) {
|
|
539
|
+
const retryAfter = parseRetryAfterSeconds(
|
|
540
|
+
error.retryAfter
|
|
541
|
+
);
|
|
542
|
+
if (retryAfter !== void 0) {
|
|
543
|
+
return retryAfter;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
if ("headers" in error) {
|
|
547
|
+
const retryAfter = parseRetryAfterSeconds(
|
|
548
|
+
getHeaderValue(error.headers, "retry-after")
|
|
549
|
+
);
|
|
550
|
+
if (retryAfter !== void 0) {
|
|
551
|
+
return retryAfter;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
const message = "message" in error && typeof error.message === "string" ? error.message : "";
|
|
555
|
+
const retryAfterMatch = message.match(/retry after\s+(\d+(?:\.\d+)?)\s*s?/i) ?? message.match(/retryDelay[^\d]*(\d+(?:\.\d+)?)s/i);
|
|
556
|
+
return retryAfterMatch ? parseRetryAfterSeconds(retryAfterMatch[1]) : void 0;
|
|
557
|
+
}
|
|
558
|
+
function createRateLimitedAI(client, options) {
|
|
559
|
+
const config = normalizeRateLimitConfig(options);
|
|
560
|
+
if (!config) {
|
|
561
|
+
return client;
|
|
562
|
+
}
|
|
563
|
+
const wrappedMethods = /* @__PURE__ */ new Map();
|
|
564
|
+
return new Proxy(client, {
|
|
565
|
+
get(target, property, receiver) {
|
|
566
|
+
const value = Reflect.get(target, property, receiver);
|
|
567
|
+
if (typeof value !== "function") {
|
|
568
|
+
return value;
|
|
569
|
+
}
|
|
570
|
+
if (!RATE_LIMITED_METHODS.has(property)) {
|
|
571
|
+
if (!wrappedMethods.has(property)) {
|
|
572
|
+
wrappedMethods.set(property, value.bind(target));
|
|
573
|
+
}
|
|
574
|
+
return wrappedMethods.get(property);
|
|
575
|
+
}
|
|
576
|
+
if (!wrappedMethods.has(property)) {
|
|
577
|
+
wrappedMethods.set(property, (...args) => {
|
|
578
|
+
const coordinator = getBudgetCoordinator(config.key);
|
|
579
|
+
return coordinator.schedule(
|
|
580
|
+
() => invokeWithPacing(
|
|
581
|
+
() => Reflect.apply(value, target, args),
|
|
582
|
+
coordinator,
|
|
583
|
+
config
|
|
584
|
+
)
|
|
585
|
+
);
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
return wrappedMethods.get(property);
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
function isOpenAIOptions(options) {
|
|
593
|
+
return !options.type || options.type === "openai";
|
|
594
|
+
}
|
|
595
|
+
function isLiteLLMOptions(options) {
|
|
596
|
+
return options.type === "litellm";
|
|
597
|
+
}
|
|
598
|
+
function isBifrostOptions(options) {
|
|
599
|
+
return options.type === "bifrost";
|
|
600
|
+
}
|
|
601
|
+
function isOllamaOptions(options) {
|
|
602
|
+
return options.type === "ollama";
|
|
603
|
+
}
|
|
604
|
+
function isGeminiOptions(options) {
|
|
605
|
+
return options.type === "gemini";
|
|
606
|
+
}
|
|
607
|
+
function isAnthropicOptions(options) {
|
|
608
|
+
return options.type === "anthropic";
|
|
609
|
+
}
|
|
610
|
+
function isHuggingFaceOptions(options) {
|
|
611
|
+
return options.type === "huggingface";
|
|
612
|
+
}
|
|
613
|
+
function isBedrockOptions(options) {
|
|
614
|
+
return options.type === "bedrock";
|
|
615
|
+
}
|
|
616
|
+
function isClaudeCliOptions(options) {
|
|
617
|
+
return options.type === "claude-cli";
|
|
618
|
+
}
|
|
619
|
+
function isQwen3TTSOptions(options) {
|
|
620
|
+
return options.type === "qwen3-tts";
|
|
621
|
+
}
|
|
622
|
+
async function getAI(options = {}) {
|
|
623
|
+
options = loadEnvConfig(options, {
|
|
624
|
+
packageName: "ai",
|
|
625
|
+
schema: {
|
|
626
|
+
provider: "string",
|
|
627
|
+
type: "string",
|
|
628
|
+
// Alias for provider
|
|
629
|
+
model: "string",
|
|
630
|
+
defaultModel: "string",
|
|
631
|
+
timeout: "number",
|
|
632
|
+
maxRetries: "number",
|
|
633
|
+
apiKey: "string",
|
|
634
|
+
baseUrl: "string",
|
|
635
|
+
adminApiKey: "string",
|
|
636
|
+
adminBaseUrl: "string",
|
|
637
|
+
adminUrl: "string",
|
|
638
|
+
adminUser: "string",
|
|
639
|
+
adminUsername: "string",
|
|
640
|
+
adminPassword: "string"
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
if ("provider" in options && !options.type) {
|
|
644
|
+
options.type = options.provider;
|
|
645
|
+
}
|
|
646
|
+
if ("model" in options && !options.defaultModel) {
|
|
647
|
+
options.defaultModel = options.model;
|
|
648
|
+
}
|
|
649
|
+
let client;
|
|
650
|
+
if (isOpenAIOptions(options)) {
|
|
651
|
+
const { OpenAIProvider } = await import("./openai-5snI2diE.js");
|
|
652
|
+
client = new OpenAIProvider(options);
|
|
653
|
+
} else if (isLiteLLMOptions(options)) {
|
|
654
|
+
const { LiteLLMProvider } = await import("./litellm-DhPKa_Jz.js");
|
|
655
|
+
client = new LiteLLMProvider(options);
|
|
656
|
+
} else if (isBifrostOptions(options)) {
|
|
657
|
+
const { BifrostProvider } = await import("./bifrost-3mXtQsTj.js");
|
|
658
|
+
client = new BifrostProvider(options);
|
|
659
|
+
} else if (isOllamaOptions(options)) {
|
|
660
|
+
const { OllamaProvider } = await import("./ollama-Di1ldur0.js");
|
|
661
|
+
client = new OllamaProvider(options);
|
|
662
|
+
} else if (isGeminiOptions(options)) {
|
|
663
|
+
const { GeminiProvider } = await import("./gemini-BfpHXDIQ.js");
|
|
664
|
+
client = new GeminiProvider(options);
|
|
665
|
+
} else if (isAnthropicOptions(options)) {
|
|
666
|
+
const { AnthropicProvider } = await import("./anthropic-BRwbhwIl.js");
|
|
667
|
+
client = new AnthropicProvider(options);
|
|
668
|
+
} else if (isHuggingFaceOptions(options)) {
|
|
669
|
+
const { HuggingFaceProvider } = await import("./huggingface-280qv9iv.js");
|
|
670
|
+
client = new HuggingFaceProvider(options);
|
|
671
|
+
} else if (isBedrockOptions(options)) {
|
|
672
|
+
const { BedrockProvider } = await import("./bedrock-Cf1xUerN.js");
|
|
673
|
+
client = new BedrockProvider(options);
|
|
674
|
+
} else if (isClaudeCliOptions(options)) {
|
|
675
|
+
const { ClaudeCliProvider } = await import("./claude-cli-BrHRfkry.js");
|
|
676
|
+
client = new ClaudeCliProvider(options);
|
|
677
|
+
} else if (isQwen3TTSOptions(options)) {
|
|
678
|
+
const { Qwen3TTSProvider } = await import("./qwen-tts-DgPgdXxG.js");
|
|
679
|
+
client = new Qwen3TTSProvider(options);
|
|
680
|
+
} else {
|
|
681
|
+
throw new ValidationError("Unsupported AI provider type", {
|
|
682
|
+
supportedTypes: [...AI_PROVIDER_TYPES],
|
|
683
|
+
providedType: options.type
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
return createRateLimitedAI(client, options);
|
|
687
|
+
}
|
|
688
|
+
async function getAIAuto(options) {
|
|
689
|
+
const baseUrl = String(options.baseUrl || "");
|
|
690
|
+
const hasKeepAliveOption = "keepAlive" in options && options.keepAlive !== void 0;
|
|
691
|
+
if (/((?:localhost|127\.0\.0\.1)(?::11434)?(?:\/(?:api|v1))?|ollama(?:\.com)?(?:\/(?:api|v1))?)\/?$/i.test(
|
|
692
|
+
baseUrl
|
|
693
|
+
) || hasKeepAliveOption) {
|
|
694
|
+
return getAI({ ...options, type: "ollama" });
|
|
695
|
+
}
|
|
696
|
+
if (options.apiKey && !options.type) {
|
|
697
|
+
return getAI({ ...options, type: "openai" });
|
|
698
|
+
}
|
|
699
|
+
if (options.apiToken) {
|
|
700
|
+
return getAI({ ...options, type: "huggingface" });
|
|
701
|
+
}
|
|
702
|
+
if (options.region && options.credentials) {
|
|
703
|
+
return getAI({ ...options, type: "bedrock" });
|
|
704
|
+
}
|
|
705
|
+
if (options.projectId || options.anthropicVersion) {
|
|
706
|
+
if (options.anthropicVersion) {
|
|
707
|
+
return getAI({ ...options, type: "anthropic" });
|
|
708
|
+
}
|
|
709
|
+
if (options.projectId) {
|
|
710
|
+
return getAI({ ...options, type: "gemini" });
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
throw new ValidationError("Could not auto-detect AI provider from options", {
|
|
714
|
+
hint: 'Please specify a "type" field in options or provide provider-specific credentials',
|
|
715
|
+
supportedTypes: [...AI_PROVIDER_TYPES],
|
|
716
|
+
providedOptions: Object.keys(options)
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
const factory = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
720
|
+
__proto__: null,
|
|
721
|
+
getAI,
|
|
722
|
+
getAIAuto
|
|
723
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
724
|
+
class AIMessage {
|
|
725
|
+
/**
|
|
726
|
+
* Original options used to create this message
|
|
727
|
+
*/
|
|
728
|
+
options;
|
|
729
|
+
/**
|
|
730
|
+
* Name of the message sender
|
|
731
|
+
*/
|
|
732
|
+
name;
|
|
733
|
+
/**
|
|
734
|
+
* Content of the message
|
|
735
|
+
*/
|
|
736
|
+
content;
|
|
737
|
+
/**
|
|
738
|
+
* Role of the message sender in the conversation
|
|
739
|
+
*/
|
|
740
|
+
role;
|
|
741
|
+
/**
|
|
742
|
+
* Creates a new AI message
|
|
743
|
+
*
|
|
744
|
+
* @param options - Message configuration
|
|
745
|
+
* @param options.role - Role of the message sender
|
|
746
|
+
* @param options.content - Content of the message
|
|
747
|
+
* @param options.name - Name of the message sender
|
|
748
|
+
*/
|
|
749
|
+
constructor(options) {
|
|
750
|
+
this.options = options;
|
|
751
|
+
this.role = options.role;
|
|
752
|
+
this.content = options.content;
|
|
753
|
+
this.name = options.name;
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Factory method to create a new AI message
|
|
757
|
+
*
|
|
758
|
+
* @param options - Message configuration
|
|
759
|
+
* @param options.thread - Thread this message belongs to
|
|
760
|
+
* @param options.role - Role of the message sender
|
|
761
|
+
* @param options.content - Content of the message
|
|
762
|
+
* @param options.name - Name of the message sender
|
|
763
|
+
* @returns Promise resolving to a new AIMessage instance
|
|
764
|
+
*/
|
|
765
|
+
static async create(options) {
|
|
766
|
+
return new AIMessage(options);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
class AIThread {
|
|
770
|
+
/**
|
|
771
|
+
* AI client instance for this thread
|
|
772
|
+
*/
|
|
773
|
+
ai;
|
|
774
|
+
/**
|
|
775
|
+
* Options used to configure this thread
|
|
776
|
+
*/
|
|
777
|
+
options;
|
|
778
|
+
/**
|
|
779
|
+
* Messages in this conversation thread
|
|
780
|
+
*/
|
|
781
|
+
messages = [];
|
|
782
|
+
/**
|
|
783
|
+
* Reference materials to include in the conversation context
|
|
784
|
+
*/
|
|
785
|
+
references = {};
|
|
786
|
+
/**
|
|
787
|
+
* Creates a new AI thread
|
|
788
|
+
*
|
|
789
|
+
* @param options - Thread configuration options
|
|
790
|
+
*/
|
|
791
|
+
constructor(options) {
|
|
792
|
+
this.options = options;
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Factory method to create and initialize a new AI thread
|
|
796
|
+
*
|
|
797
|
+
* @param options - Thread configuration options
|
|
798
|
+
* @returns Promise resolving to an initialized AIThread
|
|
799
|
+
*/
|
|
800
|
+
static async create(options) {
|
|
801
|
+
const thread = new AIThread(options);
|
|
802
|
+
await thread.initialize();
|
|
803
|
+
return thread;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Initializes the AI client for this thread
|
|
807
|
+
*/
|
|
808
|
+
async initialize() {
|
|
809
|
+
this.ai = await AIClient.create(this.options.ai);
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Adds a system message to the conversation
|
|
813
|
+
*
|
|
814
|
+
* @param prompt - System message content
|
|
815
|
+
* @returns Promise resolving to the created AIMessage
|
|
816
|
+
*/
|
|
817
|
+
async addSystem(prompt) {
|
|
818
|
+
const message = await AIMessage.create({
|
|
819
|
+
thread: this,
|
|
820
|
+
role: "system",
|
|
821
|
+
name: "system",
|
|
822
|
+
content: prompt
|
|
823
|
+
});
|
|
824
|
+
this.messages.push(message);
|
|
825
|
+
return message;
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Adds a message to the conversation
|
|
829
|
+
*
|
|
830
|
+
* @param options - Message options
|
|
831
|
+
* @param options.role - Role of the message sender
|
|
832
|
+
* @param options.name - Optional name of the message sender
|
|
833
|
+
* @param options.content - Content of the message
|
|
834
|
+
* @returns Promise resolving to the created AIMessage
|
|
835
|
+
*/
|
|
836
|
+
async add(options) {
|
|
837
|
+
const message = await AIMessage.create({
|
|
838
|
+
thread: this,
|
|
839
|
+
role: options.role,
|
|
840
|
+
name: options.name || options.role,
|
|
841
|
+
// Default name to role if not provided
|
|
842
|
+
content: options.content
|
|
843
|
+
});
|
|
844
|
+
this.messages.push(message);
|
|
845
|
+
return message;
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Gets all messages in this thread
|
|
849
|
+
*
|
|
850
|
+
* @returns Array of AIMessage objects
|
|
851
|
+
*/
|
|
852
|
+
get() {
|
|
853
|
+
return this.messages;
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Adds a reference to be included in the conversation context
|
|
857
|
+
*
|
|
858
|
+
* @param name - Name of the reference
|
|
859
|
+
* @param body - Content of the reference
|
|
860
|
+
*/
|
|
861
|
+
addReference(name, body) {
|
|
862
|
+
this.references[name] = body;
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Assembles the conversation history for sending to the AI
|
|
866
|
+
* Properly orders system message, references, and conversation messages
|
|
867
|
+
*
|
|
868
|
+
* @returns Array of message parameters formatted for the OpenAI API
|
|
869
|
+
*/
|
|
870
|
+
assembleHistory() {
|
|
871
|
+
const history = [];
|
|
872
|
+
const systemMessage = this.messages.find((m) => m.role === "system");
|
|
873
|
+
if (systemMessage) {
|
|
874
|
+
history.push({
|
|
875
|
+
role: systemMessage.role,
|
|
876
|
+
content: systemMessage.content
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
for (const name in this.references) {
|
|
880
|
+
history.push({
|
|
881
|
+
role: "user",
|
|
882
|
+
content: `Reference - ${name}:
|
|
883
|
+
${this.references[name]}`
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
this.messages.filter((m) => m.role !== "system").forEach((message) => {
|
|
887
|
+
history.push({ role: message.role, content: message.content });
|
|
888
|
+
});
|
|
889
|
+
return history;
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Sends a prompt to the AI and gets a response
|
|
893
|
+
*
|
|
894
|
+
* @param prompt - Prompt message to send
|
|
895
|
+
* @param options - Options for the AI response
|
|
896
|
+
* @param options.responseFormat - Format for the AI to respond with
|
|
897
|
+
* @returns Promise resolving to the AI response
|
|
898
|
+
*/
|
|
899
|
+
async do(prompt, options = {
|
|
900
|
+
responseFormat: "text"
|
|
901
|
+
}) {
|
|
902
|
+
const { responseFormat } = options;
|
|
903
|
+
const history = this.assembleHistory();
|
|
904
|
+
const response = await this.ai.textCompletion(prompt, {
|
|
905
|
+
history,
|
|
906
|
+
responseFormat: {
|
|
907
|
+
type: responseFormat === "json" ? "json_object" : "text"
|
|
908
|
+
}
|
|
909
|
+
});
|
|
910
|
+
return response;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
const PACKAGE_VERSION_INITIALIZED = true;
|
|
914
|
+
export {
|
|
915
|
+
AIError as A,
|
|
916
|
+
ContentFilterError as C,
|
|
917
|
+
ModelNotFoundError as M,
|
|
918
|
+
OpenAIClient as O,
|
|
919
|
+
PACKAGE_VERSION_INITIALIZED as P,
|
|
920
|
+
RateLimitError as R,
|
|
921
|
+
ContextLengthError as a,
|
|
922
|
+
AuthenticationError as b,
|
|
923
|
+
extractTextContent as c,
|
|
924
|
+
AIClient as d,
|
|
925
|
+
extractRetryAfterSeconds as e,
|
|
926
|
+
AIMessage as f,
|
|
927
|
+
AIThread as g,
|
|
928
|
+
AI_PROVIDER_TYPES as h,
|
|
929
|
+
getAI as i,
|
|
930
|
+
getAIAuto as j,
|
|
931
|
+
getAIClient as k,
|
|
932
|
+
getOpenAI as l
|
|
933
|
+
};
|
|
934
|
+
//# sourceMappingURL=index-BT4thAvS.js.map
|