utilitas 1998.2.58 → 1998.2.60
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 +7 -8
- package/dist/utilitas.lite.mjs +1 -1
- package/dist/utilitas.lite.mjs.map +1 -1
- package/lib/alan.mjs +214 -185
- package/lib/manifest.mjs +1 -1
- package/package.json +1 -1
package/lib/alan.mjs
CHANGED
|
@@ -49,25 +49,30 @@ const [
|
|
|
49
49
|
OPENAI, GEMINI, CHATGPT, OPENAI_EMBEDDING, GEMINI_EMEDDING, OPENAI_TRAINING,
|
|
50
50
|
OLLAMA, CLAUDE, GPT_4O_MINI, GPT_4O, GPT_O1, GPT_O3_MINI, GEMINI_20_FLASH,
|
|
51
51
|
GEMINI_20_FLASH_THINKING, GEMINI_20_PRO, NOVA, EMBEDDING_001, DEEPSEEK_R1,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
DEEPSEEK_R1_70B, MD_CODE, CHATGPT_REASONING, TEXT_EMBEDDING_3_SMALL,
|
|
53
|
+
TEXT_EMBEDDING_3_LARGE, CLOUD_37_SONNET, AUDIO, WAV, CHATGPT_MINI,
|
|
54
|
+
ATTACHMENTS, CHAT, OPENAI_VOICE, MEDIUM, LOW, HIGH, GPT_REASONING_EFFORT,
|
|
55
|
+
THINK, THINK_STR, THINK_END, AZURE, TOOLS_STR, TOOLS_END, TOOLS, TEXT,
|
|
56
|
+
THINKING, OK, FUNC, GPT_45, REDACTED_THINKING, GEMMA_3_27B, AZURE_OPENAI,
|
|
57
|
+
ANTHROPIC, VERTEX_ANTHROPIC, GEMMA327B, size8k, ais, MAX_TOOL_RECURSION,
|
|
58
|
+
LOG, name, user, system, assistant, MODEL, JSON_OBJECT, TOOL, silent,
|
|
59
|
+
NOT_INIT, INVALID_FILE, tokenSafeRatio, GPT_QUERY_LIMIT, minsOfDay,
|
|
58
60
|
] = [
|
|
59
61
|
'OPENAI', 'GEMINI', 'CHATGPT', 'OPENAI_EMBEDDING', 'GEMINI_EMEDDING',
|
|
60
62
|
'OPENAI_TRAINING', 'OLLAMA', 'CLAUDE', 'gpt-4o-mini', 'gpt-4o', 'o1',
|
|
61
63
|
'o3-mini', 'gemini-2.0-flash', 'gemini-2.0-flash-thinking-exp',
|
|
62
64
|
'gemini-2.0-pro-exp', 'nova', 'embedding-001', 'deepseek-r1',
|
|
63
|
-
'deepseek-r1:
|
|
64
|
-
'text-embedding-3-
|
|
65
|
-
'
|
|
66
|
-
'
|
|
67
|
-
'
|
|
68
|
-
'
|
|
69
|
-
'
|
|
70
|
-
'
|
|
65
|
+
'deepseek-r1:70b', '```', 'CHATGPT_REASONING', 'text-embedding-3-small',
|
|
66
|
+
'text-embedding-3-large', 'claude-3-7-sonnet@20250219', 'audio', 'wav',
|
|
67
|
+
'CHATGPT_MINI', '[ATTACHMENTS]', 'CHAT', 'OPENAI_VOICE', 'medium',
|
|
68
|
+
'low', 'high', 'medium', 'think', '<think>', '</think>', 'AZURE',
|
|
69
|
+
'<tools>', '</tools>', 'tools', 'text', 'thinking', 'OK', 'function',
|
|
70
|
+
'gpt-4.5-preview', 'redacted_thinking', 'gemma-3-27b-it',
|
|
71
|
+
'AZURE OPENAI', 'ANTHROPIC', 'VERTEX ANTHROPIC', 'gemma3:27b',
|
|
72
|
+
7680 * 4320, {}, 10, { log: true }, 'Alan', 'user', 'system',
|
|
73
|
+
'assistant', 'model', 'json_object', 'tool', true,
|
|
74
|
+
'AI engine has not been initialized.', 'Invalid file data.', 1.1, 100,
|
|
75
|
+
60 * 24,
|
|
71
76
|
];
|
|
72
77
|
|
|
73
78
|
const [
|
|
@@ -88,45 +93,52 @@ const [tool, provider, messages, text] = [
|
|
|
88
93
|
messages => ({ messages }), text => ({ text }),
|
|
89
94
|
];
|
|
90
95
|
|
|
91
|
-
const [name, user, system, assistant, MODEL, JSON_OBJECT, TOOL, silent]
|
|
92
|
-
= ['Alan', 'user', 'system', 'assistant', 'model', 'json_object', 'tool', true];
|
|
93
96
|
const [CODE_INTERPRETER, RETRIEVAL, FUNCTION]
|
|
94
97
|
= ['code_interpreter', 'retrieval', FUNC].map(tool);
|
|
95
|
-
const [NOT_INIT, INVALID_FILE]
|
|
96
|
-
= ['AI engine has not been initialized.', 'Invalid file data.'];
|
|
97
98
|
const chatConfig
|
|
98
99
|
= { sessions: new Map(), engines: {}, systemPrompt: INSTRUCTIONS };
|
|
99
|
-
const [
|
|
100
|
+
const [sessionType, aiType]
|
|
101
|
+
= [`${name.toUpperCase()}-SESSION`, `${name.toUpperCase()}-AI`];
|
|
102
|
+
const [newSessionId, newAiId]
|
|
103
|
+
= [sessionType, aiType].map(type => () => createUoid({ type }));
|
|
100
104
|
const tokenSafe = count => Math.ceil(count * tokenSafeRatio);
|
|
101
105
|
const clients = {};
|
|
102
|
-
const size8k = 7680 * 4320;
|
|
103
|
-
const MAX_TOOL_RECURSION = 10;
|
|
104
|
-
const LOG = { log: true };
|
|
105
|
-
const sessionType = `${name.toUpperCase()}-SESSION`;
|
|
106
106
|
const unifyProvider = options => unifyType(options?.provider, 'AI provider');
|
|
107
107
|
const unifyEngine = options => unifyType(options?.engine, 'AI engine');
|
|
108
108
|
const trimTailing = text => text.replace(/[\.\s]*$/, '');
|
|
109
|
-
const newSessionId = () => createUoid({ type: sessionType });
|
|
110
109
|
const renderText = (t, o) => _renderText(t, { extraCodeBlock: 0, ...o || {} });
|
|
111
110
|
const log = (cnt, opt) => _log(cnt, import.meta.url, { time: 1, ...opt || {} });
|
|
112
111
|
const CONTENT_IS_REQUIRED = 'Content is required.';
|
|
113
112
|
const assertContent = content => assert(content.length, CONTENT_IS_REQUIRED);
|
|
114
113
|
const countToolCalls = r => r?.split('\n').filter(x => x === TOOLS_STR).length;
|
|
114
|
+
const assertApiKey = (p, o) => assert(o?.apiKey, `${p} api key is required.`);
|
|
115
|
+
const libOpenAi = async opts => await need('openai', { ...opts, raw: true });
|
|
116
|
+
const OpenAI = async opts => new (await libOpenAi(opts)).OpenAI(opts);
|
|
117
|
+
const AzureOpenAI = async opts => new (await libOpenAi(opts)).AzureOpenAI(opts);
|
|
115
118
|
|
|
116
119
|
const DEFAULT_MODELS = {
|
|
117
|
-
[
|
|
118
|
-
[
|
|
119
|
-
[CHATGPT]: GPT_4O,
|
|
120
|
-
[CLAUDE]: CLOUD_37_SONNET,
|
|
121
|
-
[GEMINI_EMEDDING]: EMBEDDING_001,
|
|
120
|
+
[OPENAI]: GPT_4O,
|
|
121
|
+
[AZURE_OPENAI]: GPT_4O,
|
|
122
122
|
[GEMINI]: GEMINI_20_FLASH,
|
|
123
|
-
[
|
|
124
|
-
[
|
|
123
|
+
[ANTHROPIC]: CLOUD_37_SONNET,
|
|
124
|
+
[VERTEX_ANTHROPIC]: CLOUD_37_SONNET,
|
|
125
|
+
[OLLAMA]: GEMMA327B,
|
|
126
|
+
[OPENAI_VOICE]: NOVA,
|
|
125
127
|
[OPENAI_EMBEDDING]: TEXT_EMBEDDING_3_SMALL,
|
|
128
|
+
[GEMINI_EMEDDING]: EMBEDDING_001,
|
|
126
129
|
[OPENAI_TRAINING]: GPT_4O_MINI, // https://platform.openai.com/docs/guides/fine-tuning
|
|
127
|
-
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
[CHATGPT_MINI]: GPT_4O_MINI,
|
|
133
|
+
[CHATGPT_REASONING]: GPT_O3_MINI,
|
|
128
134
|
};
|
|
129
135
|
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
130
142
|
DEFAULT_MODELS[CHAT] = DEFAULT_MODELS[GEMINI];
|
|
131
143
|
|
|
132
144
|
const tokenRatioByWords = Math.min(
|
|
@@ -194,13 +206,9 @@ const MODELS = {
|
|
|
194
206
|
reasoning: true,
|
|
195
207
|
vision: true,
|
|
196
208
|
tools: true,
|
|
197
|
-
// audio: 'gpt-4o-audio-preview', // fallback to GPT-4O to support audio
|
|
198
209
|
supportedMimeTypes: [
|
|
199
210
|
png, jpeg, gif, webp,
|
|
200
211
|
],
|
|
201
|
-
// supportedAudioTypes: [ // fallback to GPT-4O to support audio
|
|
202
|
-
// wav,
|
|
203
|
-
// ],
|
|
204
212
|
},
|
|
205
213
|
[GPT_O3_MINI]: {
|
|
206
214
|
contextWindow: 200000,
|
|
@@ -214,13 +222,9 @@ const MODELS = {
|
|
|
214
222
|
reasoning: true,
|
|
215
223
|
vision: true,
|
|
216
224
|
tools: true,
|
|
217
|
-
// audio: 'gpt-4o-mini-audio-preview', // fallback to GPT-4O-MINI to support audio
|
|
218
225
|
supportedMimeTypes: [
|
|
219
226
|
png, jpeg, gif, webp,
|
|
220
227
|
],
|
|
221
|
-
// supportedAudioTypes: [ // fallback to GPT-4O-MINI to support audio
|
|
222
|
-
// wav,
|
|
223
|
-
// ],
|
|
224
228
|
},
|
|
225
229
|
[GPT_45]: {
|
|
226
230
|
contextWindow: 128000,
|
|
@@ -305,6 +309,15 @@ const MODELS = {
|
|
|
305
309
|
flac, mp3, m4a, mpga, opus, pcm, wav, webm, tgpp,
|
|
306
310
|
],
|
|
307
311
|
},
|
|
312
|
+
[GEMMA_3_27B]: {
|
|
313
|
+
contextWindow: 128 * 1000,
|
|
314
|
+
imageCostTokens: 256,
|
|
315
|
+
maxImageSize: 896 * 896,
|
|
316
|
+
maxOutputTokens: 1024 * 8,
|
|
317
|
+
vision: true,
|
|
318
|
+
json: true,
|
|
319
|
+
supportedMimeTypes: [png, jpeg],
|
|
320
|
+
},
|
|
308
321
|
[DEEPSEEK_R1]: {
|
|
309
322
|
contextWindow: 128 * 1000,
|
|
310
323
|
maxOutputTokens: 32768,
|
|
@@ -333,24 +346,6 @@ const MODELS = {
|
|
|
333
346
|
embedding: true,
|
|
334
347
|
requestLimitsRPM: 1500,
|
|
335
348
|
},
|
|
336
|
-
[CLAUDE_35_SONNET]: { // https://docs.anthropic.com/en/docs/about-claude/models
|
|
337
|
-
contextWindow: 200 * 1000,
|
|
338
|
-
maxOutputTokens: 8192,
|
|
339
|
-
imageCostTokens: size8k / 750,
|
|
340
|
-
documentCostTokens: 3000 * 100, // 100 pages: https://docs.anthropic.com/en/docs/build-with-claude/pdf-support
|
|
341
|
-
maxImagePerPrompt: 5, // https://docs.anthropic.com/en/docs/build-with-claude/vision
|
|
342
|
-
maxImageSize: 1092, // by pixels
|
|
343
|
-
maxDocumentPages: 100,
|
|
344
|
-
maxDocumentFile: 1024 * 1024 * 32, // 32MB
|
|
345
|
-
requestLimitsRPM: 50,
|
|
346
|
-
tokenLimitsITPM: 40000,
|
|
347
|
-
tokenLimitsOTPM: 8000,
|
|
348
|
-
trainingData: 'Apr 2024',
|
|
349
|
-
tools: true,
|
|
350
|
-
supportedMimeTypes: [
|
|
351
|
-
png, jpeg, gif, webp, pdf,
|
|
352
|
-
],
|
|
353
|
-
},
|
|
354
349
|
// https://console.cloud.google.com/vertex-ai/publishers/anthropic/model-garden/claude-3-7-sonnet?authuser=5&inv=1&invt=Abqftg&project=backend-alpha-97077
|
|
355
350
|
[CLOUD_37_SONNET]: {
|
|
356
351
|
contextWindow: 200 * 1000,
|
|
@@ -373,9 +368,8 @@ const MODELS = {
|
|
|
373
368
|
},
|
|
374
369
|
};
|
|
375
370
|
|
|
376
|
-
MODELS[CLAUDE_35_HAIKU] = MODELS[CLAUDE_35_SONNET];
|
|
377
|
-
MODELS[DEEPSEEK_R1_32B] = MODELS[DEEPSEEK_R1];
|
|
378
371
|
MODELS[DEEPSEEK_R1_70B] = MODELS[DEEPSEEK_R1];
|
|
372
|
+
MODELS[GEMMA327B] = MODELS[GEMMA_3_27B];
|
|
379
373
|
|
|
380
374
|
for (const n in MODELS) {
|
|
381
375
|
MODELS[n]['name'] = n;
|
|
@@ -505,56 +499,90 @@ const toolsGemini = async () => (await toolsOpenAI()).map(x => ({
|
|
|
505
499
|
}
|
|
506
500
|
}));
|
|
507
501
|
|
|
508
|
-
const init = async (options) => {
|
|
502
|
+
const init = async (options = {}) => {
|
|
503
|
+
const id = newAiId();
|
|
509
504
|
const provider = unifyProvider(options);
|
|
505
|
+
const modelName = options.model || DEFAULT_MODELS[provider];
|
|
506
|
+
assert(modelName, `Model is required for provider: ${provider}.`);
|
|
507
|
+
let model = options.modelConfig || MODELS[modelName];
|
|
508
|
+
assert(model, `The model has not been configured yet: ${modelName}.`);
|
|
509
|
+
model = { name: modelName, ...model };
|
|
510
510
|
switch (provider) {
|
|
511
|
-
case OPENAI:
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
)
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
511
|
+
case OPENAI:
|
|
512
|
+
assertApiKey(provider, options);
|
|
513
|
+
ais[id] = {
|
|
514
|
+
id, provider, model, client: await OpenAI(options),
|
|
515
|
+
prompt: async (cnt, opts) => await promptOpenAI(id, cnt, opts),
|
|
516
|
+
};
|
|
517
|
+
break;
|
|
518
|
+
case AZURE_OPENAI:
|
|
519
|
+
assertApiKey(provider, options);
|
|
520
|
+
assert(options.endpoint,
|
|
521
|
+
`{provider} api endpoint and deployment are required.`);
|
|
522
|
+
ais[id] = {
|
|
523
|
+
id, provider, model, client: await AzureOpenAI({
|
|
524
|
+
apiVersion: '2025-01-01-preview',
|
|
525
|
+
deployment: model.name, ...options,
|
|
526
|
+
}),
|
|
527
|
+
prompt: async (cnt, opts) => await promptOpenAI(id, cnt, opts),
|
|
528
|
+
};
|
|
529
|
+
break;
|
|
530
|
+
case AZURE:
|
|
531
|
+
assertApiKey(provider, options);
|
|
532
|
+
assert(options.baseURL, `${provider} api endpoint is required.`);
|
|
533
|
+
ais[id] = {
|
|
534
|
+
id, provider, model, client: await OpenAI(options),
|
|
535
|
+
prompt: async (cnt, opts) => await promptOpenAI(id, cnt, opts),
|
|
536
|
+
};
|
|
521
537
|
break;
|
|
522
538
|
case GEMINI:
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
539
|
+
assertApiKey(provider, options);
|
|
540
|
+
const { GoogleGenerativeAI } = await need('@google/generative-ai');
|
|
541
|
+
ais[id] = {
|
|
542
|
+
id, provider, model,
|
|
543
|
+
client: new GoogleGenerativeAI(options.apiKey),
|
|
544
|
+
prompt: async (cnt, opts) => await promptGemini(id, cnt, opts),
|
|
545
|
+
};
|
|
528
546
|
break;
|
|
529
|
-
case
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
547
|
+
case ANTHROPIC:
|
|
548
|
+
assertApiKey(provider, options);
|
|
549
|
+
const Anthropic = (await need('@anthropic-ai/sdk')).Anthropic;
|
|
550
|
+
ais[id] = {
|
|
551
|
+
id, provider, model, client: new Anthropic(options),
|
|
552
|
+
prompt: async (cnt, opts) => await promptAnthropic(id, cnt, opts),
|
|
553
|
+
};
|
|
554
|
+
break;
|
|
555
|
+
case VERTEX_ANTHROPIC:
|
|
556
|
+
// https://github.com/anthropics/anthropic-sdk-typescript/tree/main/packages/vertex-sdk
|
|
557
|
+
assert(options?.credentials, `${provider} api credentials are required.`);
|
|
558
|
+
const AnthropicVertex = (await need('@anthropic-ai/vertex-sdk')).AnthropicVertex;
|
|
559
|
+
process.env['GOOGLE_APPLICATION_CREDENTIALS'] = options.credentials;
|
|
560
|
+
process.env['ANTHROPIC_VERTEX_PROJECT_ID'] = options.projectId;
|
|
561
|
+
ais[id] = {
|
|
562
|
+
id, provider, model,
|
|
563
|
+
client: new AnthropicVertex({ region: options?.region || 'us-east5' }),
|
|
564
|
+
prompt: async (cnt, opts) => await promptAnthropic(id, cnt, opts),
|
|
565
|
+
};
|
|
546
566
|
break;
|
|
547
567
|
case OLLAMA:
|
|
548
|
-
|
|
568
|
+
ais[id] = {
|
|
569
|
+
id, provider, model,
|
|
549
570
|
client: new (await need('ollama', { raw: true })).Ollama(options),
|
|
550
|
-
|
|
551
|
-
}
|
|
571
|
+
prompt: async (cnt, opts) => await promptOllama(id, cnt, opts),
|
|
572
|
+
};
|
|
552
573
|
break;
|
|
553
574
|
default:
|
|
554
|
-
throwError(`Invalid AI provider: ${options
|
|
575
|
+
throwError(`Invalid AI provider: ${options.provider || 'null'}.`);
|
|
555
576
|
}
|
|
556
|
-
|
|
557
|
-
|
|
577
|
+
return ais[id];
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
const getAi = async (id, options) => {
|
|
581
|
+
if (id) {
|
|
582
|
+
if (ais[id]) { return options?.client ? ais[id]?.client : ais[id]; }
|
|
583
|
+
else { throwError(`AI not found: ${id}.`); }
|
|
584
|
+
}
|
|
585
|
+
return ais;
|
|
558
586
|
};
|
|
559
587
|
|
|
560
588
|
const countTokens = async (input, options) => {
|
|
@@ -806,7 +834,8 @@ const buildPrompts = async (model, input, options = {}) => {
|
|
|
806
834
|
prompt = buildOllamaMessage(content, options);
|
|
807
835
|
break;
|
|
808
836
|
case GEMINI:
|
|
809
|
-
|
|
837
|
+
const _role = { role: options.model === GEMMA_3_27B ? user : system };
|
|
838
|
+
systemPrompt = buildGeminiHistory(options.systemPrompt, _role);
|
|
810
839
|
prompt = options.toolsResult?.[options.toolsResult?.length - 1]?.parts
|
|
811
840
|
|| buildGeminiMessage(content, options)
|
|
812
841
|
break;
|
|
@@ -844,6 +873,7 @@ const buildPrompts = async (model, input, options = {}) => {
|
|
|
844
873
|
break;
|
|
845
874
|
case GEMINI:
|
|
846
875
|
history.push(
|
|
876
|
+
...options.model === GEMMA_3_27B ? [systemPrompt] : [],
|
|
847
877
|
...options.toolsResult?.length ? [
|
|
848
878
|
buildGeminiHistory(content, { ...options, role: user }),
|
|
849
879
|
...options.toolsResult.slice(0, options.toolsResult.length - 1)
|
|
@@ -861,6 +891,10 @@ const buildPrompts = async (model, input, options = {}) => {
|
|
|
861
891
|
content = trimTailing(trimTailing(content).slice(0, -1)) + '...';
|
|
862
892
|
}
|
|
863
893
|
}, model.maxInputTokens - options.attachments?.length * ATTACHMENT_TOKEN_COST);
|
|
894
|
+
if ([CHATGPT, OLLAMA].includes(options.flavor)
|
|
895
|
+
|| options.model === GEMMA_3_27B) {
|
|
896
|
+
systemPrompt = null;
|
|
897
|
+
}
|
|
864
898
|
return { systemPrompt, history, prompt };
|
|
865
899
|
};
|
|
866
900
|
|
|
@@ -957,36 +991,32 @@ const mergeMsgs = (resp, calls) => [resp, ...calls.length ? [
|
|
|
957
991
|
`⚠️ Tools recursion limit reached: ${MAX_TOOL_RECURSION}`
|
|
958
992
|
] : []].map(x => x.trim()).join('\n\n');
|
|
959
993
|
|
|
960
|
-
const
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
} else {
|
|
966
|
-
options.model = DEFAULT_MODELS[CHATGPT];
|
|
967
|
-
}
|
|
968
|
-
let [_MODEL, result, resultAudio, event, resultTools, responded] = [
|
|
969
|
-
MODELS[options.model], options?.result ?? '', Buffer.alloc(0), null, [],
|
|
970
|
-
false
|
|
994
|
+
const promptOpenAI = async (aiId, content, options = {}) => {
|
|
995
|
+
let { provider, client, model } = await getAi(aiId);
|
|
996
|
+
let [result, resultAudio, event, resultTools, responded, azure] = [
|
|
997
|
+
options.result ?? '', Buffer.alloc(0), null, [], false,
|
|
998
|
+
provider === AZURE
|
|
971
999
|
];
|
|
972
|
-
options.
|
|
973
|
-
|
|
974
|
-
const { client } = await getOpenAIClient(options);
|
|
1000
|
+
options.flavor = CHATGPT;
|
|
1001
|
+
options.model = options.model || model.name;
|
|
975
1002
|
const { history }
|
|
976
|
-
= await buildPrompts(
|
|
1003
|
+
= await buildPrompts(MODELS[options.model], content, options);
|
|
1004
|
+
model = MODELS[options.model];
|
|
1005
|
+
model.reasoning && !azure && !options.reasoning_effort
|
|
1006
|
+
&& (options.reasoning_effort = GPT_REASONING_EFFORT);
|
|
977
1007
|
const modalities = options.modalities
|
|
978
1008
|
|| (options.audioMode ? [TEXT, AUDIO] : undefined);
|
|
979
1009
|
[options.audioMimeType, options.suffix] = [pcm16, 'pcm.wav'];
|
|
980
1010
|
const resp = await client.chat.completions.create({
|
|
1011
|
+
model: azure ? undefined : options.model, ...history,
|
|
1012
|
+
...options.jsonMode ? { response_format: { type: JSON_OBJECT } } : {},
|
|
981
1013
|
modalities, audio: options.audio || (
|
|
982
1014
|
modalities?.find?.(x => x === AUDIO)
|
|
983
1015
|
&& { voice: DEFAULT_MODELS[OPENAI_VOICE], format: 'pcm16' }
|
|
984
|
-
), ...
|
|
1016
|
+
), ...model.tools && !azure ? {
|
|
985
1017
|
tools: options.tools ?? (await toolsOpenAI()).map(x => x.def),
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
} : {}, model: options.model, stream: true,
|
|
989
|
-
store: true, tool_choice: 'auto',
|
|
1018
|
+
tool_choice: 'auto',
|
|
1019
|
+
} : {}, ...azure ? {} : { store: true }, stream: true,
|
|
990
1020
|
});
|
|
991
1021
|
for await (event of resp) {
|
|
992
1022
|
event = event?.choices?.[0] || {};
|
|
@@ -1001,9 +1031,11 @@ const promptChatGPT = async (content, options = {}) => {
|
|
|
1001
1031
|
isSet(x.index, true) && (curFunc.index = x.index);
|
|
1002
1032
|
x.id && (curFunc.id = x.id);
|
|
1003
1033
|
x.type && (curFunc.type = x.type);
|
|
1004
|
-
curFunc.function
|
|
1034
|
+
curFunc.function
|
|
1035
|
+
|| (curFunc.function = { name: '', arguments: '' });
|
|
1005
1036
|
x?.function?.name && (curFunc.function.name += x.function.name);
|
|
1006
|
-
x?.function?.arguments
|
|
1037
|
+
x?.function?.arguments
|
|
1038
|
+
&& (curFunc.function.arguments += x.function.arguments);
|
|
1007
1039
|
}
|
|
1008
1040
|
options.result && deltaText
|
|
1009
1041
|
&& (responded = responded || (deltaText = `\n\n${deltaText}`));
|
|
@@ -1021,25 +1053,27 @@ const promptChatGPT = async (content, options = {}) => {
|
|
|
1021
1053
|
};
|
|
1022
1054
|
const { toolsResult, toolsResponse }
|
|
1023
1055
|
= await handleToolsCall(event, { ...options, result });
|
|
1024
|
-
if (toolsResult.length
|
|
1025
|
-
|
|
1056
|
+
if (toolsResult.length
|
|
1057
|
+
&& countToolCalls(toolsResponse) < MAX_TOOL_RECURSION) {
|
|
1058
|
+
return promptOpenAI(aiId, content, {
|
|
1059
|
+
...options, toolsResult, result: toolsResponse,
|
|
1060
|
+
});
|
|
1026
1061
|
}
|
|
1027
1062
|
event.text = mergeMsgs(toolsResponse, toolsResult);
|
|
1028
1063
|
return await packResp(event, options);
|
|
1029
1064
|
};
|
|
1030
1065
|
|
|
1031
|
-
const
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
const promptOllama = async (content, options = {}) => {
|
|
1035
|
-
const { client, model } = await getOllamaClient(options);
|
|
1066
|
+
const promptOllama = async (aiId, content, options = {}) => {
|
|
1067
|
+
const { client, model } = await getAi(aiId);
|
|
1036
1068
|
// https://github.com/ollama/ollama-js
|
|
1037
1069
|
// https://github.com/jmorganca/ollama/blob/main/examples/typescript-simplechat/client.ts
|
|
1038
|
-
options.model = options?.model || model;
|
|
1039
|
-
let [
|
|
1040
|
-
const { history
|
|
1041
|
-
= await buildPrompts(
|
|
1042
|
-
const resp = await client.chat({
|
|
1070
|
+
options.model = options?.model || model.name;
|
|
1071
|
+
let [chunk, result] = [null, ''];
|
|
1072
|
+
const { history }
|
|
1073
|
+
= await buildPrompts(model, content, { ...options, flavor: OLLAMA });
|
|
1074
|
+
const resp = await client.chat({
|
|
1075
|
+
model: options.model, stream: true, ...history,
|
|
1076
|
+
});
|
|
1043
1077
|
for await (chunk of resp) {
|
|
1044
1078
|
const delta = chunk.message.content || '';
|
|
1045
1079
|
result += delta;
|
|
@@ -1050,33 +1084,28 @@ const promptOllama = async (content, options = {}) => {
|
|
|
1050
1084
|
return await packResp({ text: result }, options);
|
|
1051
1085
|
};
|
|
1052
1086
|
|
|
1053
|
-
const
|
|
1054
|
-
|
|
1087
|
+
const promptAnthropic = async (aiId, content, options = {}) => {
|
|
1088
|
+
const { client, model } = await getAi(aiId);
|
|
1055
1089
|
let [
|
|
1056
|
-
|
|
1057
|
-
responded, redacted_thinking
|
|
1058
|
-
] = [
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
];
|
|
1062
|
-
// https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking
|
|
1063
|
-
options?.test_redacted_thinking && !options?.result && (
|
|
1090
|
+
event, text, thinking, signature, result, thinkEnd, tool_use,
|
|
1091
|
+
responded, redacted_thinking
|
|
1092
|
+
] = [null, '', '', '', options.result ?? '', '', [], false, []];
|
|
1093
|
+
options.model = options.model || model.name;
|
|
1094
|
+
options.test_redacted_thinking && !result && (
|
|
1064
1095
|
content += '\n\nANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_'
|
|
1065
1096
|
+ '46C9A13E193C177646C7398A98432ECCCE4C1253D5E2D82641AC0E52CC2876CB'
|
|
1066
|
-
);
|
|
1067
|
-
const { client } = await getClaudeClient(options);
|
|
1097
|
+
); // https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking
|
|
1068
1098
|
const { systemPrompt: system, history }
|
|
1069
|
-
= await buildPrompts(
|
|
1099
|
+
= await buildPrompts(model, content, { ...options, flavor: CLAUDE });
|
|
1070
1100
|
const resp = await client.beta.messages.create({
|
|
1071
|
-
model: options.model,
|
|
1072
|
-
max_tokens: options
|
|
1073
|
-
...
|
|
1074
|
-
...options.reasoning ?? _MODEL?.reasoning ? {
|
|
1101
|
+
model: options.model, ...history, system, stream: true,
|
|
1102
|
+
max_tokens: options.extendedThinking ? 128000 : model.maxOutputTokens,
|
|
1103
|
+
...(options.reasoning ?? model.reasoning) ? {
|
|
1075
1104
|
thinking: options.thinking || {
|
|
1076
1105
|
type: 'enabled',
|
|
1077
1106
|
budget_tokens: options?.extendedThinking ? 16000 : 1024,
|
|
1078
1107
|
},
|
|
1079
|
-
} : {}, ...
|
|
1108
|
+
} : {}, ...model?.tools ? {
|
|
1080
1109
|
tools: options.tools ?? (await toolsClaude()).map(x => x.def),
|
|
1081
1110
|
tool_choice: { type: 'auto' }, betas: [
|
|
1082
1111
|
// https://docs.anthropic.com/en/docs/build-with-claude/tool-use/token-efficient-tool-use
|
|
@@ -1121,7 +1150,7 @@ const promptClaude = async (content, options = {}) => {
|
|
|
1121
1150
|
event, { ...options, result, flavor: CLAUDE },
|
|
1122
1151
|
);
|
|
1123
1152
|
if (tool_use.length && countToolCalls(toolsResponse) < MAX_TOOL_RECURSION) {
|
|
1124
|
-
return await
|
|
1153
|
+
return await promptAnthropic(aiId, content, {
|
|
1125
1154
|
...options, toolsResult: [...options.toolsResult || [],
|
|
1126
1155
|
...toolsResult], result: toolsResponse,
|
|
1127
1156
|
});
|
|
@@ -1178,31 +1207,29 @@ const packGeminiReferences = (chunks, supports) => {
|
|
|
1178
1207
|
return references;
|
|
1179
1208
|
};
|
|
1180
1209
|
|
|
1181
|
-
const promptGemini = async (content, options = {}) => {
|
|
1182
|
-
|
|
1183
|
-
let [result, references, functionCalls, responded
|
|
1184
|
-
= [options.result ?? '', null, null, false
|
|
1185
|
-
|
|
1210
|
+
const promptGemini = async (aiId, content, options = {}) => {
|
|
1211
|
+
const { client, model } = await getAi(aiId);
|
|
1212
|
+
let [result, references, functionCalls, responded]
|
|
1213
|
+
= [options.result ?? '', null, null, false];
|
|
1214
|
+
options.model = options.model || model.name;
|
|
1186
1215
|
const { systemPrompt: systemInstruction, history, prompt }
|
|
1187
|
-
= await buildPrompts(
|
|
1188
|
-
const
|
|
1216
|
+
= await buildPrompts(model, content, { ...options, flavor: GEMINI });
|
|
1217
|
+
const _client = client.getGenerativeModel({
|
|
1189
1218
|
model: options.model, systemInstruction,
|
|
1190
|
-
...
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
}
|
|
1201
|
-
) : {},
|
|
1219
|
+
...model?.tools && !options.jsonMode ? (options.tools ?? {
|
|
1220
|
+
tools: [
|
|
1221
|
+
// @todo: Gemini will failed when using these tools together.
|
|
1222
|
+
// https://ai.google.dev/gemini-api/docs/function-calling
|
|
1223
|
+
// { codeExecution: {} },
|
|
1224
|
+
// { googleSearch: {} },
|
|
1225
|
+
{ functionDeclarations: (await toolsGemini()).map(x => x.def) },
|
|
1226
|
+
],
|
|
1227
|
+
toolConfig: { functionCallingConfig: { mode: 'AUTO' } },
|
|
1228
|
+
}) : {},
|
|
1202
1229
|
});
|
|
1203
1230
|
// https://github.com/google/generative-ai-js/blob/main/samples/node/advanced-chat.js
|
|
1204
1231
|
// Google's bug: history is not allowed while using inline_data?
|
|
1205
|
-
const chat =
|
|
1232
|
+
const chat = _client.startChat({ history, ...generationConfig(options) });
|
|
1206
1233
|
const resp = await chat.sendMessageStream(prompt);
|
|
1207
1234
|
for await (const chunk of resp.stream) {
|
|
1208
1235
|
functionCalls || (functionCalls = chunk.functionCalls);
|
|
@@ -1227,10 +1254,11 @@ const promptGemini = async (content, options = {}) => {
|
|
|
1227
1254
|
{ role: MODEL, parts: functionCalls },
|
|
1228
1255
|
{ ...options, result, flavor: GEMINI }
|
|
1229
1256
|
);
|
|
1230
|
-
if (toolsResult.length
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
...
|
|
1257
|
+
if (toolsResult.length
|
|
1258
|
+
&& countToolCalls(toolsResponse) < MAX_TOOL_RECURSION) {
|
|
1259
|
+
return promptGemini(aiId, content, {
|
|
1260
|
+
...options || {}, result: toolsResponse,
|
|
1261
|
+
toolsResult: [...options?.toolsResult || [], ...toolsResult],
|
|
1234
1262
|
});
|
|
1235
1263
|
}
|
|
1236
1264
|
return await packResp({
|
|
@@ -1427,9 +1455,9 @@ const talk = async (input, options) => {
|
|
|
1427
1455
|
...options,
|
|
1428
1456
|
};
|
|
1429
1457
|
switch (engine) {
|
|
1430
|
-
case CHATGPT: resp = await
|
|
1458
|
+
case CHATGPT: resp = await promptOpenAI(input, pmtOptions); break;
|
|
1431
1459
|
case GEMINI: resp = await promptGemini(input, pmtOptions); break;
|
|
1432
|
-
case CLAUDE: resp = await
|
|
1460
|
+
case CLAUDE: resp = await promptAnthropic(input, pmtOptions); break;
|
|
1433
1461
|
case OLLAMA: resp = await promptOllama(input, pmtOptions); break;
|
|
1434
1462
|
case AZURE: resp = await promptAzure(input, pmtOptions); break;
|
|
1435
1463
|
default: throwError(`Invalid AI engine: '${engine}'.`);
|
|
@@ -1553,17 +1581,17 @@ const analyzeSessions = async (sessionIds, options) => {
|
|
|
1553
1581
|
};
|
|
1554
1582
|
|
|
1555
1583
|
const PREFERRED_ENGINES = [
|
|
1556
|
-
{ client: OPENAI, func:
|
|
1584
|
+
{ client: OPENAI, func: promptOpenAI, multimodal: 0 },
|
|
1557
1585
|
{ client: GEMINI, func: promptGemini, multimodal: 1 },
|
|
1558
|
-
{ client: CLAUDE, func:
|
|
1559
|
-
{ client: AZURE, func: promptAzure, multimodal: 3 },
|
|
1586
|
+
{ client: CLAUDE, func: promptAnthropic, multimodal: 2 },
|
|
1587
|
+
// { client: AZURE, func: promptAzure, multimodal: 3 },
|
|
1560
1588
|
{ client: OLLAMA, func: promptOllama, multimodal: 99 },
|
|
1561
1589
|
]; // keep gpt first to avoid gemini grounding by default
|
|
1562
1590
|
|
|
1563
1591
|
export default init;
|
|
1564
1592
|
export {
|
|
1565
1593
|
ATTACHMENT_TOKEN_COST, CLOUD_37_SONNET, CODE_INTERPRETER, DEEPSEEK_R1,
|
|
1566
|
-
|
|
1594
|
+
DEEPSEEK_R1_70B, DEFAULT_MODELS,
|
|
1567
1595
|
EMBEDDING_001,
|
|
1568
1596
|
FUNCTION, GEMINI_20_FLASH, GEMINI_20_FLASH_THINKING, GPT_45, GPT_4O, GPT_4O_MINI, GPT_O1, GPT_O3_MINI, INSTRUCTIONS, MODELS,
|
|
1569
1597
|
OPENAI_VOICE, RETRIEVAL,
|
|
@@ -1582,13 +1610,14 @@ export {
|
|
|
1582
1610
|
init,
|
|
1583
1611
|
initChat,
|
|
1584
1612
|
jpeg,
|
|
1613
|
+
getAi,
|
|
1585
1614
|
listFiles,
|
|
1586
1615
|
listGptFineTuningEvents,
|
|
1587
1616
|
listGptFineTuningJobs,
|
|
1588
1617
|
listOpenAIModels,
|
|
1589
1618
|
ogg,
|
|
1590
|
-
prompt,
|
|
1591
|
-
|
|
1619
|
+
prompt, promptOpenAI,
|
|
1620
|
+
promptAnthropic,
|
|
1592
1621
|
promptGemini,
|
|
1593
1622
|
promptOllama,
|
|
1594
1623
|
resetSession,
|
package/lib/manifest.mjs
CHANGED