utilitas 2001.1.136 → 2001.1.139
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/README.md +10 -8
- package/dist/utilitas.lite.mjs +1 -1
- package/dist/utilitas.lite.mjs.map +1 -1
- package/lib/alan.mjs +169 -301
- package/lib/dbio.mjs +355 -34
- package/lib/manifest.mjs +20 -20
- package/lib/rag.mjs +85 -43
- package/lib/storage.mjs +4 -2
- package/package.json +20 -20
package/lib/alan.mjs
CHANGED
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
STREAM, FILE, BASE64, BUFFER, DATAURL, MIME_TEXT, MIME_PNG, MIME_JPEG,
|
|
9
9
|
MIME_MOV, MIME_MPEG, MIME_MP4, MIME_MPG, MIME_AVI, MIME_WMV, MIME_MPEGPS,
|
|
10
10
|
MIME_FLV, MIME_GIF, MIME_WEBP, MIME_PDF, MIME_AAC, MIME_FLAC, MIME_MP3,
|
|
11
|
-
MIME_MPEGA, MIME_M4A, MIME_MPGA, MIME_OPUS, MIME_PCM, MIME_WAV,
|
|
12
|
-
MIME_TGPP, MIME_PCM16, MIME_OGG, convert, decodeBase64DataURL,
|
|
13
|
-
getMime, getTempPath,
|
|
11
|
+
MIME_MPEGA, MIME_M4A, MIME_MPGA, MIME_OPUS, MIME_PCM, MIME_WAV, MIME_WAVE,
|
|
12
|
+
MIME_WEBM, MIME_TGPP, MIME_PCM16, MIME_OGG, convert, decodeBase64DataURL,
|
|
13
|
+
getImageSize, getMime, getTempPath,
|
|
14
14
|
} from './storage.mjs';
|
|
15
15
|
|
|
16
16
|
import {
|
|
@@ -45,37 +45,32 @@ const STT_PROMPT = 'Please transcribe the audio into clean text. Return only the
|
|
|
45
45
|
const _NEED = ['OpenAI', '@google/genai'];
|
|
46
46
|
|
|
47
47
|
const [
|
|
48
|
-
OPENAI, GOOGLE, OLLAMA, NOVA,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
GEMINI_30_PRO_IMAGE, IMAGE,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
PROCESSING, CURSOR, LN1, LN2, TOP, DEEPSEEK, DEEP_RESEARCH_PRO,
|
|
59
|
-
MD_CODE_ESCAPED, VERTEX, LYRIA_002,
|
|
48
|
+
OPENAI, GOOGLE, OLLAMA, NOVA, MD_CODE, CLOUD_OPUS_47, AUDIO, WAV,
|
|
49
|
+
OPENAI_VOICE, GPT_REASONING_EFFORT, THINK, THINK_STR, THINK_END, TOOLS_STR,
|
|
50
|
+
TOOLS_END, TOOLS, TEXT, OK, FUNC, GPT_55, GPT_IMAGE_2, GEMMA_4_31B,
|
|
51
|
+
ANTHROPIC, ais, MAX_TOOL_RECURSION, LOG, name, user, system, assistant,
|
|
52
|
+
JSON_OBJECT, PROMPT_IS_REQUIRED, k, trimTailing, trimBeginning,
|
|
53
|
+
GEMINI_30_PRO_IMAGE, IMAGE, OPENROUTER_API, OPENROUTER, AUTO, TOOL, ONLINE,
|
|
54
|
+
GEMINI_31_PRO, GEMINI_30_FLASH, VEO_31, IMAGEN_4_UPSCALE, ERROR_GENERATING,
|
|
55
|
+
GEMINI_25_PRO_TTS, wav, GPT_AUDIO, ELLIPSIS, TOP_LIMIT, ATTACHMENT,
|
|
56
|
+
PROCESSING, CURSOR, LN1, LN2, TOP, DEEP_RESEARCH_MAX, MD_CODE_ESCAPED,
|
|
57
|
+
VERTEX, LYRIA_3, GPT_55_MINI,
|
|
60
58
|
] = [
|
|
61
|
-
'OpenAI', 'Google', 'Ollama', 'nova', '
|
|
62
|
-
'
|
|
63
|
-
'<
|
|
64
|
-
'
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
x =>
|
|
68
|
-
|
|
69
|
-
'
|
|
70
|
-
'
|
|
71
|
-
':online', 'gemini-3.1-pro-preview', 'gemini-3-flash-preview',
|
|
59
|
+
'OpenAI', 'Google', 'Ollama', 'nova', '```', 'claude-opus-4.7', 'audio',
|
|
60
|
+
'wav', 'OPENAI_VOICE', 'medium', 'think', '<think>', '</think>',
|
|
61
|
+
'<tools>', '</tools>', 'tools', 'text', 'OK', 'function', 'gpt-5.5',
|
|
62
|
+
'gpt-5.4-image-2', 'gemma4:31b', 'Anthropic', [], 30, { log: true },
|
|
63
|
+
'Alan', 'user', { role: 'system' }, { role: 'assistant' },
|
|
64
|
+
'json_object', 'Prompt is required.', x => 1000 * x,
|
|
65
|
+
x => x.replace(/[\.\s]*$/, ''), x => x.replace(/^[\.\s]*/, ''),
|
|
66
|
+
'gemini-3-pro-image-preview', 'image', 'https://openrouter.ai/api/v1',
|
|
67
|
+
'OpenRouter', 'openrouter/auto', 'tool', ':online',
|
|
68
|
+
'gemini-3.1-pro-preview', 'gemini-3-flash-preview',
|
|
72
69
|
'veo-3.1-generate-preview', 'imagen-4.0-upscale-preview',
|
|
73
|
-
'Error generating content.', 'gemini-2.5-
|
|
74
|
-
'
|
|
75
|
-
'
|
|
76
|
-
'
|
|
77
|
-
'DeepSeek', 'deep-research-pro-preview-12-2025', '\`\`\`', 'Vertex',
|
|
78
|
-
'lyria-002',
|
|
70
|
+
'Error generating content.', 'gemini-2.5-pro-preview-tts', 'wav',
|
|
71
|
+
'gpt-audio', '...', 3, 'ATTACHMENT', { processing: true }, ' █', '\n\n',
|
|
72
|
+
'\n\n\n', 'top', 'deep-research-max-preview-04-2026', '\`\`\`',
|
|
73
|
+
'Vertex', 'lyria-3-pro-preview', 'gpt-5-mini',
|
|
79
74
|
];
|
|
80
75
|
|
|
81
76
|
const [joinL1, joinL2]
|
|
@@ -98,70 +93,41 @@ const m = x => k(k(x));
|
|
|
98
93
|
const [MAX_TOKENS, ATTACHMENT_TOKEN_COST] = [m(1), k(10)];
|
|
99
94
|
|
|
100
95
|
const MODEL_ICONS = {
|
|
101
|
-
[OPENROUTER]: '🔀', [OPENAI]: '⚛️', [GOOGLE]: '♊️',
|
|
102
|
-
[
|
|
103
|
-
[VERTEX]: '📐',
|
|
96
|
+
[OPENROUTER]: '🔀', [OPENAI]: '⚛️', [GOOGLE]: '♊️', [OLLAMA]: '🦙',
|
|
97
|
+
[ANTHROPIC]: '✳️', [VERTEX]: '❇️',
|
|
104
98
|
};
|
|
105
99
|
|
|
106
100
|
const FEATURE_ICONS = {
|
|
107
101
|
audio: '🔊', 'deep-research': '🔍', fast: '⚡️', hearing: '👂', hidden: '🙈',
|
|
108
|
-
image: '🎨', reasoning: '🧠', structured: '📊', tools: '🧰',
|
|
109
|
-
vision: '👁️', // finetune: '🔧',
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
const DEEPSEEK_32_RULES = {
|
|
113
|
-
source: DEEPSEEK, contextWindow: k(163.8), maxOutputTokens: k(65.5),
|
|
114
|
-
structured: true, tools: true, reasoning: true,
|
|
102
|
+
image: '🎨', music: '🎵', reasoning: '🧠', structured: '📊', tools: '🧰',
|
|
103
|
+
video: '🎬', vision: '👁️', // finetune: '🔧',
|
|
115
104
|
};
|
|
116
105
|
|
|
117
106
|
const MODELS = {
|
|
118
107
|
// models with generation capabilities
|
|
119
|
-
[
|
|
120
|
-
source: VERTEX, maxInputTokens: 480,
|
|
121
|
-
audio: true, defaultProvider: VERTEX,
|
|
122
|
-
},
|
|
108
|
+
[LYRIA_3]: { music: true },
|
|
123
109
|
[IMAGEN_4_UPSCALE]: {
|
|
124
110
|
source: GOOGLE, maxInputTokens: 0, image: true, vision: true,
|
|
125
111
|
supportedMimeTypes: [MIME_PNG, MIME_JPEG], defaultProvider: VERTEX,
|
|
126
112
|
},
|
|
127
113
|
[VEO_31]: {
|
|
128
|
-
source: GOOGLE, maxInputTokens:
|
|
114
|
+
source: GOOGLE, maxInputTokens: k(1), attachmentTokenCost: 0,
|
|
129
115
|
video: true, vision: true,
|
|
130
116
|
supportedMimeTypes: [MIME_PNG, MIME_JPEG], defaultProvider: GOOGLE,
|
|
131
117
|
},
|
|
132
|
-
[GPT_IMAGE_15]: {
|
|
133
|
-
source: OPENAI, contextWindow: k(400), maxOutputTokens: k(128),
|
|
134
|
-
hearing: true, image: true, reasoning: true, structured: true,
|
|
135
|
-
tools: true, vision: true, defaultProvider: OPENAI,
|
|
136
|
-
supportedMimeTypes: [MIME_PNG, MIME_JPEG, MIME_GIF, MIME_WEBP],
|
|
137
|
-
},
|
|
138
118
|
// tts/stt models
|
|
139
|
-
[GEMINI_25_FLASH_TTS]: {
|
|
140
|
-
source: GOOGLE, maxInputTokens: k(32),
|
|
141
|
-
audio: true, fast: true, hidden: true, defaultProvider: GOOGLE,
|
|
142
|
-
},
|
|
143
119
|
[GEMINI_25_PRO_TTS]: {
|
|
144
120
|
source: GOOGLE, maxInputTokens: k(32),
|
|
145
121
|
audio: true, hidden: true, defaultProvider: GOOGLE,
|
|
146
122
|
},
|
|
147
|
-
[
|
|
148
|
-
source: OPENAI, maxInputTokens: k(2),
|
|
149
|
-
audio: true, fast: true, hidden: true, defaultProvider: OPENAI,
|
|
150
|
-
},
|
|
151
|
-
[GPT_4O_TRANSCRIBE]: {
|
|
152
|
-
source: OPENAI, maxInputTokens: 0,
|
|
153
|
-
hearing: true, fast: true, hidden: true, defaultProvider: OPENAI,
|
|
154
|
-
},
|
|
123
|
+
[GPT_AUDIO]: { hidden: true, },
|
|
155
124
|
// agents with deep-research capabilities
|
|
156
|
-
[
|
|
125
|
+
[DEEP_RESEARCH_MAX]: { // https://ai.google.dev/gemini-api/docs/deep-research
|
|
157
126
|
source: GOOGLE, contextWindow: m(1.05), maxOutputTokens: k(65.5),
|
|
158
127
|
'deep-research': true, reasoning: true, defaultProvider: GOOGLE,
|
|
159
128
|
},
|
|
160
|
-
// best Chinese models
|
|
161
|
-
[DEEPSEEK_32]: DEEPSEEK_32_RULES,
|
|
162
|
-
[SF_DEEPSEEK_32]: { ...DEEPSEEK_32_RULES, defaultProvider: SILICONFLOW },
|
|
163
129
|
// best local model
|
|
164
|
-
[
|
|
130
|
+
[GEMMA_4_31B]: {
|
|
165
131
|
source: GOOGLE, contextWindow: k(128), maxOutputTokens: k(8),
|
|
166
132
|
fast: true, structured: true, vision: true,
|
|
167
133
|
supportedMimeTypes: [MIME_PNG, MIME_JPEG, MIME_GIF],
|
|
@@ -186,7 +152,7 @@ for (const n in MODELS) {
|
|
|
186
152
|
}
|
|
187
153
|
// Auto model have some issues with tools and reasoning, so we disable them here
|
|
188
154
|
// MODELS[AUTO] = { name: AUTO, defaultProvider: OPENROUTER, };
|
|
189
|
-
// for (const n of [
|
|
155
|
+
// for (const n of [GPT_55, GEMINI_31_PRO, GEMINI_30_FLASH]) {
|
|
190
156
|
// // get the most restrictive limits
|
|
191
157
|
// for (const key of [
|
|
192
158
|
// 'contextWindow', 'maxInputTokens', 'maxOutputTokens',
|
|
@@ -224,19 +190,23 @@ for (const n in MODELS) {
|
|
|
224
190
|
// Default models for each provider
|
|
225
191
|
const DEFAULT_MODELS = {
|
|
226
192
|
[OPENROUTER]: [
|
|
227
|
-
// fast
|
|
193
|
+
// GPT: fast
|
|
194
|
+
GPT_55_MINI,
|
|
195
|
+
// GPT: strong
|
|
196
|
+
GPT_55,
|
|
197
|
+
// Gemini: fast
|
|
228
198
|
GEMINI_30_FLASH,
|
|
229
|
-
// strong
|
|
230
|
-
GPT_54,
|
|
231
|
-
// stronger but slow
|
|
199
|
+
// Gemini: strong
|
|
232
200
|
GEMINI_31_PRO,
|
|
233
|
-
//
|
|
201
|
+
// Claude: Opus
|
|
202
|
+
CLOUD_OPUS_47,
|
|
203
|
+
// Multimedia generation models
|
|
234
204
|
GEMINI_30_PRO_IMAGE,
|
|
235
|
-
|
|
236
|
-
|
|
205
|
+
LYRIA_3,
|
|
206
|
+
// tts/stt models
|
|
207
|
+
// GPT_AUDIO,
|
|
237
208
|
],
|
|
238
|
-
[
|
|
239
|
-
[OLLAMA]: GEMMA_3_27B,
|
|
209
|
+
[OLLAMA]: GEMMA_4_31B,
|
|
240
210
|
[OPENAI_VOICE]: NOVA,
|
|
241
211
|
};
|
|
242
212
|
|
|
@@ -273,13 +243,6 @@ const adaptOpenRouterModels = async () => {
|
|
|
273
243
|
model.source = model.label.split(':')[0] || model.id.split('/')[0];
|
|
274
244
|
model.outputModalities = model.architecture.output_modalities;
|
|
275
245
|
model.defaultProvider = OPENROUTER;
|
|
276
|
-
[
|
|
277
|
-
'architecture', 'canonical_slug', 'context_length', 'created',
|
|
278
|
-
'default_parameters', 'expiration_date', 'hugging_face_id',
|
|
279
|
-
'per_request_limits', 'pricing', 'supported_parameters',
|
|
280
|
-
'top_provider',
|
|
281
|
-
].map(key => delete model[key]);
|
|
282
|
-
// Backward compatibility: {
|
|
283
246
|
if (model.inputModalities.includes('image')
|
|
284
247
|
|| model.inputModalities.includes('video')
|
|
285
248
|
|| model.inputModalities.includes('file')) {
|
|
@@ -294,18 +257,15 @@ const adaptOpenRouterModels = async () => {
|
|
|
294
257
|
if (model.outputModalities.includes('image')) {
|
|
295
258
|
model.image = true;
|
|
296
259
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
260
|
+
if (model.outputModalities.includes('audio')) {
|
|
261
|
+
model.audio = true;
|
|
262
|
+
}
|
|
300
263
|
// https://gemini.google.com/app/c680748b3307790b
|
|
301
264
|
// issue with json output via OpenRouter
|
|
302
|
-
|
|
303
|
-
&& model.name
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if (/tool/i.test(model.description)) {
|
|
307
|
-
model.tools = true;
|
|
308
|
-
}
|
|
265
|
+
model.structured = !!(model.supported_parameters?.includes('structured_outputs')
|
|
266
|
+
&& ![GEMINI_30_FLASH].includes(model.name));
|
|
267
|
+
model.tools = !!(model.supported_parameters?.includes('tools')
|
|
268
|
+
|| model.supported_parameters?.includes('tool_choice'));
|
|
309
269
|
if (/flash|lite|mini|nano|tiny|small/i.test(model.name)) {
|
|
310
270
|
model.fast = true;
|
|
311
271
|
}
|
|
@@ -322,7 +282,8 @@ const adaptOpenRouterModels = async () => {
|
|
|
322
282
|
if (model.hearing) {
|
|
323
283
|
model.supportedMimeTypes.push(
|
|
324
284
|
MIME_AAC, MIME_FLAC, MIME_MP3, MIME_MPEGA, MIME_M4A,
|
|
325
|
-
MIME_MPGA, MIME_OPUS, MIME_PCM, MIME_WAV,
|
|
285
|
+
MIME_MPGA, MIME_OPUS, MIME_PCM, MIME_WAV, MIME_WAVE,
|
|
286
|
+
MIME_OGG,
|
|
326
287
|
);
|
|
327
288
|
}
|
|
328
289
|
if (model.name === GEMINI_30_PRO_IMAGE) {
|
|
@@ -344,10 +305,7 @@ const adaptOpenRouterModels = async () => {
|
|
|
344
305
|
);
|
|
345
306
|
}
|
|
346
307
|
if (model.hearing) {
|
|
347
|
-
model.supportedMimeTypes.push(MIME_WAV);
|
|
348
|
-
}
|
|
349
|
-
if (model.name === GPT_54) {
|
|
350
|
-
model.fast = true;
|
|
308
|
+
model.supportedMimeTypes.push(MIME_WAV, MIME_WAVE);
|
|
351
309
|
}
|
|
352
310
|
break;
|
|
353
311
|
case ANTHROPIC:
|
|
@@ -359,15 +317,21 @@ const adaptOpenRouterModels = async () => {
|
|
|
359
317
|
}
|
|
360
318
|
break;
|
|
361
319
|
}
|
|
362
|
-
|
|
320
|
+
[
|
|
321
|
+
'architecture', 'canonical_slug', 'context_length', 'created',
|
|
322
|
+
'default_parameters', 'expiration_date', 'hugging_face_id',
|
|
323
|
+
'per_request_limits', 'pricing', 'top_provider',
|
|
324
|
+
'supported_parameters',
|
|
325
|
+
].map(key => delete model[key]);
|
|
363
326
|
model.label = model.label.split(':').pop().trim();
|
|
364
|
-
MODELS[model.name] = model;
|
|
327
|
+
MODELS[model.name] = { ...MODELS[model.name] || {}, ...model };
|
|
328
|
+
MODELS[model.name].music && (MODELS[model.name].audio = false);
|
|
365
329
|
}
|
|
366
330
|
};
|
|
367
331
|
|
|
368
332
|
const unifyProvider = provider => {
|
|
369
333
|
assert(provider = (provider || '').trim(), 'AI provider is required.');
|
|
370
|
-
for (let type of [OPENROUTER, GOOGLE, OPENAI, OLLAMA,
|
|
334
|
+
for (let type of [OPENROUTER, GOOGLE, OPENAI, OLLAMA, VERTEX]) {
|
|
371
335
|
if (insensitiveCompare(provider, type)) { return type; }
|
|
372
336
|
}
|
|
373
337
|
throwError(`Invalid AI provider: ${provider}.`);
|
|
@@ -487,7 +451,7 @@ const setupAi = ai => {
|
|
|
487
451
|
|
|
488
452
|
const OpenAI = async opts => {
|
|
489
453
|
const lib = await libOpenAi(opts);
|
|
490
|
-
return {
|
|
454
|
+
return { client: new (lib).OpenAI(opts) };
|
|
491
455
|
};
|
|
492
456
|
|
|
493
457
|
const init = async (options = {}) => {
|
|
@@ -537,6 +501,10 @@ const init = async (options = {}) => {
|
|
|
537
501
|
const location = options.location || 'global';
|
|
538
502
|
var client = new GoogleGenAI({
|
|
539
503
|
vertexai: true, location, ...options,
|
|
504
|
+
googleAuthOptions: {
|
|
505
|
+
keyFile: options.credentials,
|
|
506
|
+
scopes: ['https://www.googleapis.com/auth/cloud-platform']
|
|
507
|
+
},
|
|
540
508
|
});
|
|
541
509
|
const auth = new GoogleAuth({
|
|
542
510
|
keyFile: options.credentials,
|
|
@@ -550,17 +518,6 @@ const init = async (options = {}) => {
|
|
|
550
518
|
});
|
|
551
519
|
}
|
|
552
520
|
break;
|
|
553
|
-
case OPENAI:
|
|
554
|
-
assertApiKey(provider, options);
|
|
555
|
-
var { client, toFile } = await OpenAI({ ...options });
|
|
556
|
-
for (let model of models) {
|
|
557
|
-
setupAi({
|
|
558
|
-
provider, model, client, toFile,
|
|
559
|
-
prompt: model.defaultProvider === OPENAI
|
|
560
|
-
? promptOpenAI : promptOpenRouter, priority,
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
break;
|
|
564
521
|
case OLLAMA:
|
|
565
522
|
// https://github.com/ollama/ollama/blob/main/docs/openai.md
|
|
566
523
|
const baseURL = 'http://localhost:11434/v1/';
|
|
@@ -570,7 +527,7 @@ const init = async (options = {}) => {
|
|
|
570
527
|
});
|
|
571
528
|
for (let model of models) {
|
|
572
529
|
setupAi({
|
|
573
|
-
provider, model, client, prompt:
|
|
530
|
+
provider, model, client, prompt: promptOpenAI, priority,
|
|
574
531
|
});
|
|
575
532
|
ignoreErrFunc(async () => {
|
|
576
533
|
phLog(await (await fetch(`${baseURL}completions`, {
|
|
@@ -581,26 +538,16 @@ const init = async (options = {}) => {
|
|
|
581
538
|
}, { log: phLog });
|
|
582
539
|
}
|
|
583
540
|
break;
|
|
584
|
-
case SILICONFLOW:
|
|
585
|
-
assertApiKey(provider, options);
|
|
586
|
-
var client = await OpenAI({
|
|
587
|
-
baseURL: 'https://api.siliconflow.cn/v1', ...options,
|
|
588
|
-
});
|
|
589
|
-
for (let model of models) {
|
|
590
|
-
setupAi({
|
|
591
|
-
provider, model, client, prompt: promptOpenRouter, priority,
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
break;
|
|
595
541
|
default:
|
|
596
542
|
assertApiKey(provider, options);
|
|
597
543
|
var { client } = await OpenAI({
|
|
598
|
-
baseURL: OPENROUTER_API
|
|
544
|
+
baseURL: provider === OPENROUTER ? OPENROUTER_API : undefined,
|
|
545
|
+
...options || {},
|
|
599
546
|
});
|
|
600
547
|
for (let model of models) {
|
|
601
548
|
setupAi({
|
|
602
|
-
provider
|
|
603
|
-
|
|
549
|
+
provider, model, client, prompt: promptOpenAI, priority,
|
|
550
|
+
options: { ...options || {} },
|
|
604
551
|
});
|
|
605
552
|
}
|
|
606
553
|
}
|
|
@@ -610,9 +557,9 @@ const init = async (options = {}) => {
|
|
|
610
557
|
|
|
611
558
|
const packAi = (ais, options = {}) => {
|
|
612
559
|
let res = options.basic ? ais.map(x => ({
|
|
613
|
-
id: x.id, name: x.name, features: x.features,
|
|
614
|
-
|
|
615
|
-
|
|
560
|
+
id: x.id, name: x.name, features: x.features, initOrder: x.initOrder,
|
|
561
|
+
priority: x.priority, provider: x.provider, model: x.model,
|
|
562
|
+
options: x.options,
|
|
616
563
|
})) : ais;
|
|
617
564
|
if (options.all && !Object.keys(options.select).length && !options.withHidden) {
|
|
618
565
|
res = res.filter(x => !x.model.hidden);
|
|
@@ -684,7 +631,8 @@ const buildMessage = async (content, options) => {
|
|
|
684
631
|
};
|
|
685
632
|
} else if ([
|
|
686
633
|
MIME_AAC, MIME_FLAC, MIME_MP3, MIME_MPEGA, MIME_M4A, MIME_MPGA,
|
|
687
|
-
MIME_OPUS, MIME_PCM, MIME_WAV, MIME_TGPP, MIME_PCM16,
|
|
634
|
+
MIME_OPUS, MIME_PCM, MIME_WAV, MIME_WAVE, MIME_TGPP, MIME_PCM16,
|
|
635
|
+
MIME_OGG,
|
|
688
636
|
].includes?.(x.mime_type)) {
|
|
689
637
|
return {
|
|
690
638
|
type: 'input_audio',
|
|
@@ -745,13 +693,14 @@ const packResp = async (resp, options) => {
|
|
|
745
693
|
if (options?.raw) { return resp; }
|
|
746
694
|
let [
|
|
747
695
|
txt, audio, images, annotations, simpleText, annotationsMarkdown, end,
|
|
748
|
-
json, audioMimeType,
|
|
696
|
+
json, audioMimeType, audioSuffix,
|
|
749
697
|
] = [
|
|
750
698
|
resp.text || '', // ChatGPT / Claude / Gemini / Ollama
|
|
751
699
|
resp?.audio?.data, // ChatGPT audio mode
|
|
752
700
|
resp?.images || [], // Gemini images via Openrouter
|
|
753
701
|
resp?.references, // Gemini references
|
|
754
|
-
'', '', '', null, MIME_PCM16,
|
|
702
|
+
'', '', '', null, resp?.audio?.mimeType || resp?.audio?.mime || MIME_PCM16,
|
|
703
|
+
null,
|
|
755
704
|
];
|
|
756
705
|
simpleText = txt;
|
|
757
706
|
while ((end = getInfoEnd(simpleText))) {
|
|
@@ -762,10 +711,17 @@ const packResp = async (resp, options) => {
|
|
|
762
711
|
const str = simpleText.indexOf(x);
|
|
763
712
|
str >= 0 && (simpleText = simpleText.slice(0, str).trim());
|
|
764
713
|
});
|
|
714
|
+
audioSuffix = audioMimeType === MIME_MPEGA
|
|
715
|
+
? 'mp3' : audioMimeType.split('/').pop();
|
|
765
716
|
audio = await ignoreErrFunc(async () => ({
|
|
766
|
-
data:
|
|
767
|
-
|
|
768
|
-
|
|
717
|
+
data: [MIME_PCM, MIME_PCM16].includes(audioMimeType)
|
|
718
|
+
? await packPcmToWav(audio, {
|
|
719
|
+
input: BUFFER, expected: BUFFER, suffix: 'pcm.wav', ...options
|
|
720
|
+
})
|
|
721
|
+
: await convert(audio, {
|
|
722
|
+
input: BUFFER, expected: BUFFER, suffix: audioSuffix, ...options
|
|
723
|
+
}),
|
|
724
|
+
mime: audioMimeType, mimeType: audioMimeType,
|
|
769
725
|
}));
|
|
770
726
|
// bug fix: Google Gemini returns duplicate first image: {
|
|
771
727
|
images && images.length > 1 && images.shift();
|
|
@@ -793,7 +749,6 @@ const packResp = async (resp, options) => {
|
|
|
793
749
|
// "title": "在線時鐘- 目前時間- 線上時鐘- 時鐘線上 - 鬧鐘",
|
|
794
750
|
// "url": "https://naozhong.tw/shijian/",
|
|
795
751
|
// "content": "- [鬧鐘](https://naozhong.tw/)\n- [計時器](https://naozhong.tw/jishiqi/)\n- [碼錶](https://naozhong.tw/miaobiao/)\n- [時間](https://naozhong.tw/shijian/)\n\n# 現在時間\n\n加入\n\n- [編輯](javascript:;)\n- [移至頂端](javascript:;)\n- [上移](javascript:;)\n- [下移](javascript:;)\n- [刪除](javascript:;)\n\n# 最常用\n\n| | |\n| --- | --- |\n| [台北](https://naozhong.tw/shijian/%E5%8F%B0%E5%8C%97/) | 10:09:14 |\n| [北京,中國](https://naozhong.tw/shijian/%E5%8C%97%E4%BA%AC-%E4%B8%AD%E5%9C%8B/) | 10:09:14 |\n| [上海,中國](https://naozhong.tw/shijian/%E4%B8%8A%E6%B5%B7-%E4%B8%AD%E5%9C%8B/) | 10:09:14 |\n| [烏魯木齊,中國](https://naozhong.tw/shijian/%E7%83%8F%E9%AD%AF%",
|
|
796
|
-
// "dateTime": "2025-03-13 06:48:01" // jina deep-research only
|
|
797
752
|
// }
|
|
798
753
|
// },
|
|
799
754
|
// ];
|
|
@@ -806,22 +761,6 @@ const packResp = async (resp, options) => {
|
|
|
806
761
|
).join('\n');
|
|
807
762
|
}
|
|
808
763
|
txt = txt.split('\n');
|
|
809
|
-
// const [reJinaStr, reJinaEnd]
|
|
810
|
-
// = [`^\s*(${THINK_STR})`, `(${THINK_END})\s*$`].map(x => new RegExp(x));
|
|
811
|
-
// const fixJina = [];
|
|
812
|
-
// for (let l of txt) {
|
|
813
|
-
// let catched = false;
|
|
814
|
-
// if (reJinaStr.test(l)) {
|
|
815
|
-
// fixJina.push(THINK_STR);
|
|
816
|
-
// l = l.replace(reJinaStr, '');
|
|
817
|
-
// }
|
|
818
|
-
// if (reJinaEnd.test(l)) {
|
|
819
|
-
// l = l.replace(reJinaEnd, '');
|
|
820
|
-
// catched = true;
|
|
821
|
-
// }
|
|
822
|
-
// fixJina.push(l, ...catched ? [THINK_END, ''] : []);
|
|
823
|
-
// }
|
|
824
|
-
// txt = fixJina;
|
|
825
764
|
// Fixed Markdown ``` not in new line for Gemini {
|
|
826
765
|
for (let i in txt) {
|
|
827
766
|
const reCode = new RegExp(`^(.+)(${MD_CODE})$`);
|
|
@@ -977,8 +916,8 @@ const mergeMsgs = (resp, calls) => [resp, ...calls.length ? [
|
|
|
977
916
|
`⚠️ Tools recursion limit reached: ${MAX_TOOL_RECURSION}`
|
|
978
917
|
] : []].map(x => x.trim()).join('\n\n');
|
|
979
918
|
|
|
980
|
-
const
|
|
981
|
-
let { provider, client, model } = await getAi(aiId);
|
|
919
|
+
const promptOpenAI = async (aiId, content, options = {}) => {
|
|
920
|
+
let { provider, client, model, options: opts } = await getAi(aiId);
|
|
982
921
|
let [
|
|
983
922
|
result, resultAudio, resultImages, resultReasoning, event, resultTools,
|
|
984
923
|
responded, modalities, source, reasoningEnd, reasoning_details,
|
|
@@ -998,11 +937,19 @@ const promptOpenRouter = async (aiId, content, options = {}) => {
|
|
|
998
937
|
} else if (!modalities && model.image) {
|
|
999
938
|
modalities = [TEXT, IMAGE];
|
|
1000
939
|
}
|
|
940
|
+
const audioConfig = options.audio || (
|
|
941
|
+
source === OPENAI && modalities?.find?.(x => x === AUDIO)
|
|
942
|
+
&& { voice: DEFAULT_MODELS[OPENAI_VOICE], format: 'pcm16' }
|
|
943
|
+
);
|
|
944
|
+
const audioMimeType = model.name === LYRIA_3 ? MIME_MPEGA : MIME_PCM16;
|
|
1001
945
|
const googleImageMode = source === GOOGLE && modalities?.includes?.(IMAGE);
|
|
946
|
+
const imageConfig = model.name === GPT_IMAGE_2
|
|
947
|
+
? { aspect_ratio: '16:9', image_size: '2K' } : googleImageMode
|
|
948
|
+
? { aspect_ratio: '16:9', image_size: '4K' } : null;
|
|
1002
949
|
const packedTools = _tools.map(x => x.def);
|
|
1003
950
|
const ext = provider === OPENROUTER && !packedTools?.find(
|
|
1004
951
|
x => x.function.name === 'searchWeb'
|
|
1005
|
-
) && !options.jsonMode ? ONLINE : '';
|
|
952
|
+
) && !options.jsonMode && !options.select ? ONLINE : ''; // `select` typically comes from a tool invocation.
|
|
1006
953
|
// if (provider === OPENAI) {
|
|
1007
954
|
// // need more debug, currently openrouter is priority
|
|
1008
955
|
// packedTools.push(...[
|
|
@@ -1022,20 +969,19 @@ const promptOpenRouter = async (aiId, content, options = {}) => {
|
|
|
1022
969
|
]);
|
|
1023
970
|
}
|
|
1024
971
|
const resp = await client.chat.completions.create({
|
|
1025
|
-
model:
|
|
1026
|
-
|
|
972
|
+
model: isOpenrouter(provider, model) ? (
|
|
973
|
+
`${source}/${options.model}${ext}`.toLowerCase()
|
|
974
|
+
+ (opts?.preset || '')
|
|
975
|
+
) : `${options.model}${ext}`, ...history,
|
|
1027
976
|
...options.jsonMode ? { response_format: { type: JSON_OBJECT } } : {},
|
|
1028
977
|
...provider === OLLAMA ? { keep_alive: -1 } : {},
|
|
1029
|
-
modalities, audio:
|
|
1030
|
-
|
|
1031
|
-
&& { voice: DEFAULT_MODELS[OPENAI_VOICE], format: 'pcm16' }
|
|
1032
|
-
), ...model?.tools ? {
|
|
978
|
+
modalities, ...audioConfig ? { audio: audioConfig } : {},
|
|
979
|
+
...model?.tools ? {
|
|
1033
980
|
tools: options.tools ?? packedTools, tool_choice: 'auto',
|
|
1034
|
-
} : {}, store: true, stream: true, ...
|
|
1035
|
-
// bug: image_size not working
|
|
981
|
+
} : {}, store: true, stream: true, ...imageConfig ? {
|
|
1036
982
|
// https://openrouter.ai/docs/features/multimodal/image-generation
|
|
1037
983
|
// https://openrouter.ai/google/gemini-3-pro-image-preview/api
|
|
1038
|
-
image_config:
|
|
984
|
+
image_config: imageConfig,
|
|
1039
985
|
} : {}, ...options.reasoning_effort ? {
|
|
1040
986
|
reasoning: { effort: options.reasoning_effort },
|
|
1041
987
|
} : {},
|
|
@@ -1104,14 +1050,18 @@ const promptOpenRouter = async (aiId, content, options = {}) => {
|
|
|
1104
1050
|
(deltaText || deltaAudio?.length || deltaImages.length)
|
|
1105
1051
|
&& await streamResp({
|
|
1106
1052
|
text: options.delta ? deltaText : result,
|
|
1107
|
-
...respAudio.length ? {
|
|
1053
|
+
...respAudio.length ? {
|
|
1054
|
+
audio: { data: respAudio, mimeType: audioMimeType }
|
|
1055
|
+
} : {},
|
|
1108
1056
|
...respImages.length ? { images: respImages } : {},
|
|
1109
1057
|
}, options);
|
|
1110
1058
|
}
|
|
1111
1059
|
event = {
|
|
1112
1060
|
...assistant, text: result, tool_calls: resultTools,
|
|
1113
1061
|
...resultImages.length ? { images: resultImages } : {},
|
|
1114
|
-
...resultAudio.length ? {
|
|
1062
|
+
...resultAudio.length ? {
|
|
1063
|
+
audio: { data: resultAudio, mimeType: audioMimeType }
|
|
1064
|
+
} : {},
|
|
1115
1065
|
...annotations.length ? { annotations } : {},
|
|
1116
1066
|
};
|
|
1117
1067
|
switch (source) {
|
|
@@ -1129,7 +1079,7 @@ const promptOpenRouter = async (aiId, content, options = {}) => {
|
|
|
1129
1079
|
= await handleToolsCall(event, { ...options, result });
|
|
1130
1080
|
if (toolsResult.length
|
|
1131
1081
|
&& countToolCalls(toolsResponse) < MAX_TOOL_RECURSION) {
|
|
1132
|
-
return
|
|
1082
|
+
return promptOpenAI(aiId, content, {
|
|
1133
1083
|
...options, toolsResult, result: toolsResponse,
|
|
1134
1084
|
});
|
|
1135
1085
|
}
|
|
@@ -1138,11 +1088,11 @@ const promptOpenRouter = async (aiId, content, options = {}) => {
|
|
|
1138
1088
|
};
|
|
1139
1089
|
|
|
1140
1090
|
const promptGoogle = async (aiId, prompt, options = {}) => {
|
|
1141
|
-
let { provider, client, model
|
|
1091
|
+
let { provider, client, model } = await getAi(aiId);
|
|
1142
1092
|
const target_model = options?.model || model.name;
|
|
1143
1093
|
const M = MODELS[target_model];
|
|
1144
1094
|
prompt = ensureString(prompt, { trim: true });
|
|
1145
|
-
[IMAGEN_4_UPSCALE,
|
|
1095
|
+
[IMAGEN_4_UPSCALE, LYRIA_3].includes(M.name) || assertPrompt(prompt);
|
|
1146
1096
|
M.tts && (prompt = `${options?.prompt || TTS_PROMPT}:\n\n${prompt}`);
|
|
1147
1097
|
prompt = trimText(prompt, { limit: M.maxInputTokens });
|
|
1148
1098
|
if (M.name === IMAGEN_4_UPSCALE) {
|
|
@@ -1236,30 +1186,38 @@ const promptGoogle = async (aiId, prompt, options = {}) => {
|
|
|
1236
1186
|
};
|
|
1237
1187
|
}
|
|
1238
1188
|
} else if (M?.audio) { // https://ai.google.dev/gemini-api/docs/speech-generation#voices
|
|
1239
|
-
if (M.name ===
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
const response = await fetch(url, {
|
|
1245
|
-
method: 'POST',
|
|
1246
|
-
headers: {
|
|
1247
|
-
'Authorization': `Bearer ${token.token}`,
|
|
1248
|
-
'Content-Type': 'application/json'
|
|
1249
|
-
},
|
|
1250
|
-
body: JSON.stringify(payload)
|
|
1189
|
+
if (M.name === LYRIA_3) {
|
|
1190
|
+
var resp = await client.interactions.create({
|
|
1191
|
+
model: M.name,
|
|
1192
|
+
input: [{ type: TEXT, text: prompt }],
|
|
1193
|
+
...(options?.config ? { generation_config: options.config } : {}),
|
|
1251
1194
|
});
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1195
|
+
assert(!resp?.error, resp?.error?.message || ERROR_GENERATING);
|
|
1196
|
+
if (options?.generateRaw) { return resp; }
|
|
1197
|
+
await tryUntil(async () => {
|
|
1198
|
+
if (resp?.status === 'completed') { return; }
|
|
1199
|
+
assert(
|
|
1200
|
+
!['failed', 'cancelled', 'incomplete'].includes(resp?.status),
|
|
1201
|
+
`Google music generation failed: ${resp?.status}`,
|
|
1202
|
+
);
|
|
1203
|
+
resp = await client.interactions.get(resp.id);
|
|
1204
|
+
assert(
|
|
1205
|
+
resp?.status === 'completed',
|
|
1206
|
+
`Waiting for Google music generation: ${resp.id}`,
|
|
1207
|
+
);
|
|
1208
|
+
}, { maxTry: 60 * 10, log });
|
|
1209
|
+
const outputs = resp?.outputs || [];
|
|
1210
|
+
const rawAudio = outputs.find(x => x?.type === AUDIO && x?.data);
|
|
1211
|
+
const mimeType = rawAudio?.mime_type || rawAudio?.mimeType || MIME_MPEGA;
|
|
1212
|
+
const suffix = mimeType === MIME_MPEGA ? 'mp3' : mimeType.split('/').pop();
|
|
1213
|
+
assert(rawAudio?.data, ERROR_GENERATING);
|
|
1258
1214
|
resp = {
|
|
1259
|
-
text:
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1215
|
+
text: outputs.filter(x => x?.type === TEXT && x?.text)
|
|
1216
|
+
.map(x => x.text).join(LN1),
|
|
1217
|
+
audio: {
|
|
1218
|
+
data: await convert(rawAudio.data, {
|
|
1219
|
+
input: BASE64, suffix, ...options || {},
|
|
1220
|
+
}), mimeType,
|
|
1263
1221
|
}, model: packModelId([provider, M.source, M.name]),
|
|
1264
1222
|
};
|
|
1265
1223
|
} else {
|
|
@@ -1352,97 +1310,6 @@ const promptGoogle = async (aiId, prompt, options = {}) => {
|
|
|
1352
1310
|
return { ...resp, processing: false };
|
|
1353
1311
|
};
|
|
1354
1312
|
|
|
1355
|
-
const promptOpenAI = async (aiId, prompt, options = {}) => {
|
|
1356
|
-
let { provider, client, toFile, model } = await getAi(aiId);
|
|
1357
|
-
const target_model = options?.model || model.name;
|
|
1358
|
-
const M = MODELS[target_model];
|
|
1359
|
-
prompt = ensureString(prompt, { trim: true });
|
|
1360
|
-
if (M?.image) {
|
|
1361
|
-
assertPrompt(prompt);
|
|
1362
|
-
prompt = trimText(prompt, { limit: M.maxInputTokens });
|
|
1363
|
-
var resp = await client.images.generate({
|
|
1364
|
-
model: M.name, moderation: 'low', output_format: 'png',
|
|
1365
|
-
prompt, quality: 'high', size: '1536x1024',
|
|
1366
|
-
// n = 1, // 1 ~ 10
|
|
1367
|
-
// @TODO: 支持 streaming image generation
|
|
1368
|
-
// https://platform.openai.com/docs/guides/image-generation?api=responses
|
|
1369
|
-
// Please note that right now, only gpt-image-1 and gpt-image-1-mini are
|
|
1370
|
-
// supported in the Responses API. We're working on support for gpt-image-1.5.
|
|
1371
|
-
// partial_images: 3, stream: true,
|
|
1372
|
-
// @TODO: 支持 image editing {}
|
|
1373
|
-
...options?.params || {},
|
|
1374
|
-
});
|
|
1375
|
-
if (!options?.raw) {
|
|
1376
|
-
// print(resp);
|
|
1377
|
-
resp = {
|
|
1378
|
-
text: '', images: await Promise.all(resp.data.map(
|
|
1379
|
-
async (x, i) => {
|
|
1380
|
-
const buffer = await convert(
|
|
1381
|
-
x.b64_json, { input: BASE64 }
|
|
1382
|
-
);
|
|
1383
|
-
return {
|
|
1384
|
-
data: await convert(buffer, {
|
|
1385
|
-
input: BUFFER, suffix: PNG_EXT, ...options || {}
|
|
1386
|
-
}),
|
|
1387
|
-
mimeType: (await getMime(
|
|
1388
|
-
buffer, `${i}.${resp.output_format}`
|
|
1389
|
-
))?.mime || MIME_PNG,
|
|
1390
|
-
}
|
|
1391
|
-
})
|
|
1392
|
-
), model: packModelId([provider, M.source, M.name]),
|
|
1393
|
-
};
|
|
1394
|
-
}
|
|
1395
|
-
} else if (M?.audio) {
|
|
1396
|
-
assertPrompt(prompt);
|
|
1397
|
-
const ins_prompt = options?.prompt || `${TTS_PROMPT}.`;
|
|
1398
|
-
prompt = trimText(prompt, {
|
|
1399
|
-
limit: M.maxInputTokens - countTokens(ins_prompt),
|
|
1400
|
-
});
|
|
1401
|
-
// https://platform.openai.com/docs/api-reference/audio/createSpeech
|
|
1402
|
-
var resp = await client.audio.speech.create({
|
|
1403
|
-
model: M.name, voice: DEFAULT_MODELS[OPENAI_VOICE],
|
|
1404
|
-
instructions: ins_prompt, response_format: 'opus',
|
|
1405
|
-
input: prompt, ...options?.params || {},
|
|
1406
|
-
});
|
|
1407
|
-
if (!options?.raw) {
|
|
1408
|
-
resp = {
|
|
1409
|
-
text: '', audio: {
|
|
1410
|
-
data: await convert(Buffer.from(
|
|
1411
|
-
await resp.arrayBuffer()
|
|
1412
|
-
), { suffix: OGG_EXT, ...options || {} }),
|
|
1413
|
-
mimeType: MIME_OGG,
|
|
1414
|
-
}, model: packModelId([provider, M.source, M.name]),
|
|
1415
|
-
};
|
|
1416
|
-
}
|
|
1417
|
-
} else if (M?.hearing) {
|
|
1418
|
-
const audio = options?.attachments?.[0]?.data || options?.attachments?.[0];
|
|
1419
|
-
assert(audio, 'Audio attachment is required.');
|
|
1420
|
-
const input = ensureString(options?.input, { case: 'UP' });
|
|
1421
|
-
const { content, cleanup } = await convert(audio, {
|
|
1422
|
-
input: options?.input, ...options || {}, expected: STREAM, INVALID_AUDIO,
|
|
1423
|
-
suffix: ['', BUFFER].includes(input) ? OGG_EXT : null,
|
|
1424
|
-
withCleanupFunc: true,
|
|
1425
|
-
});
|
|
1426
|
-
var resp = await client.audio.transcriptions.create({
|
|
1427
|
-
file: await toFile(content), model: M.name,
|
|
1428
|
-
response_format: 'text', ...options?.params || {},
|
|
1429
|
-
});
|
|
1430
|
-
await cleanup();
|
|
1431
|
-
if (!options?.raw) {
|
|
1432
|
-
resp = {
|
|
1433
|
-
text: resp.trim(),
|
|
1434
|
-
model: packModelId([provider, M.source, M.name]),
|
|
1435
|
-
};
|
|
1436
|
-
}
|
|
1437
|
-
} else {
|
|
1438
|
-
throwError('Unsupported model.');
|
|
1439
|
-
}
|
|
1440
|
-
await streamResp(
|
|
1441
|
-
{ ...resp, processing: true }, { ...options, noPack: true }
|
|
1442
|
-
);
|
|
1443
|
-
return { ...resp, processing: false };
|
|
1444
|
-
};
|
|
1445
|
-
|
|
1446
1313
|
const initChat = async (options = {}) => {
|
|
1447
1314
|
if (options.sessions) {
|
|
1448
1315
|
assert(
|
|
@@ -1461,7 +1328,7 @@ const initChat = async (options = {}) => {
|
|
|
1461
1328
|
countTokens(chatConfig.systemPrompt), await getAi(null, { all: true })
|
|
1462
1329
|
];
|
|
1463
1330
|
for (const ai of ais.filter(x => ![
|
|
1464
|
-
IMAGEN_4_UPSCALE, VEO_31,
|
|
1331
|
+
IMAGEN_4_UPSCALE, VEO_31,
|
|
1465
1332
|
].includes(x.model.name))) {
|
|
1466
1333
|
const mxPmpt = ai.model.maxInputTokens / 2;
|
|
1467
1334
|
assert(spTokens < mxPmpt,
|
|
@@ -1666,15 +1533,17 @@ const distillFile = async (attachments, o) => {
|
|
|
1666
1533
|
};
|
|
1667
1534
|
|
|
1668
1535
|
const tts = async (content, options = {}) => {
|
|
1669
|
-
const resp = await prompt(
|
|
1670
|
-
|
|
1671
|
-
|
|
1536
|
+
const resp = await prompt(content, {
|
|
1537
|
+
select: { audio: true, fast: true }, ...options, raw: false,
|
|
1538
|
+
audioMode: true,
|
|
1539
|
+
});
|
|
1672
1540
|
return options.raw ? resp : resp?.audio?.data;
|
|
1673
1541
|
};
|
|
1674
1542
|
|
|
1675
|
-
const stt = async (audio, options = {}) => await distillFile(
|
|
1676
|
-
|
|
1677
|
-
|
|
1543
|
+
const stt = async (audio, options = {}) => await distillFile(audio, {
|
|
1544
|
+
select: { hearing: true, fast: true },
|
|
1545
|
+
prompt: STT_PROMPT, ...options
|
|
1546
|
+
});
|
|
1678
1547
|
|
|
1679
1548
|
const prompt = async (input, options = {}) => {
|
|
1680
1549
|
const ai = await getAi(options?.aiId, options);
|
|
@@ -1789,19 +1658,18 @@ export default init;
|
|
|
1789
1658
|
export {
|
|
1790
1659
|
_NEED,
|
|
1791
1660
|
_NO_RENDER,
|
|
1792
|
-
|
|
1661
|
+
CLOUD_OPUS_47,
|
|
1793
1662
|
CODE_INTERPRETER,
|
|
1794
|
-
DEEPSEEK_32,
|
|
1795
1663
|
DEFAULT_MODELS,
|
|
1796
1664
|
FEATURE_ICONS,
|
|
1797
1665
|
FUNCTION,
|
|
1798
|
-
GEMINI_25_FLASH_TTS,
|
|
1799
1666
|
GEMINI_30_FLASH,
|
|
1800
1667
|
GEMINI_25_PRO_TTS,
|
|
1801
1668
|
GEMINI_30_PRO_IMAGE,
|
|
1802
1669
|
GEMINI_31_PRO,
|
|
1803
|
-
|
|
1804
|
-
|
|
1670
|
+
GPT_IMAGE_2,
|
|
1671
|
+
GPT_55,
|
|
1672
|
+
GPT_55_MINI,
|
|
1805
1673
|
INSTRUCTIONS,
|
|
1806
1674
|
MODELS,
|
|
1807
1675
|
OPENAI_VOICE,
|
|
@@ -1822,7 +1690,7 @@ export {
|
|
|
1822
1690
|
k,
|
|
1823
1691
|
listOpenAIModels,
|
|
1824
1692
|
prompt,
|
|
1825
|
-
|
|
1693
|
+
promptOpenAI,
|
|
1826
1694
|
resetSession,
|
|
1827
1695
|
setSession,
|
|
1828
1696
|
stt,
|