utilitas 1998.2.59 → 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 +197 -183
- 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
|
-
'medium', 'think', '<think>', '</think>', 'AZURE', '<tools>',
|
|
69
|
-
'</tools>', 'tools', 'text', 'thinking', 'OK', 'function',
|
|
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
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,
|
|
@@ -342,24 +346,6 @@ const MODELS = {
|
|
|
342
346
|
embedding: true,
|
|
343
347
|
requestLimitsRPM: 1500,
|
|
344
348
|
},
|
|
345
|
-
[CLAUDE_35_SONNET]: { // https://docs.anthropic.com/en/docs/about-claude/models
|
|
346
|
-
contextWindow: 200 * 1000,
|
|
347
|
-
maxOutputTokens: 8192,
|
|
348
|
-
imageCostTokens: size8k / 750,
|
|
349
|
-
documentCostTokens: 3000 * 100, // 100 pages: https://docs.anthropic.com/en/docs/build-with-claude/pdf-support
|
|
350
|
-
maxImagePerPrompt: 5, // https://docs.anthropic.com/en/docs/build-with-claude/vision
|
|
351
|
-
maxImageSize: 1092, // by pixels
|
|
352
|
-
maxDocumentPages: 100,
|
|
353
|
-
maxDocumentFile: 1024 * 1024 * 32, // 32MB
|
|
354
|
-
requestLimitsRPM: 50,
|
|
355
|
-
tokenLimitsITPM: 40000,
|
|
356
|
-
tokenLimitsOTPM: 8000,
|
|
357
|
-
trainingData: 'Apr 2024',
|
|
358
|
-
tools: true,
|
|
359
|
-
supportedMimeTypes: [
|
|
360
|
-
png, jpeg, gif, webp, pdf,
|
|
361
|
-
],
|
|
362
|
-
},
|
|
363
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
|
|
364
350
|
[CLOUD_37_SONNET]: {
|
|
365
351
|
contextWindow: 200 * 1000,
|
|
@@ -382,9 +368,8 @@ const MODELS = {
|
|
|
382
368
|
},
|
|
383
369
|
};
|
|
384
370
|
|
|
385
|
-
MODELS[CLAUDE_35_HAIKU] = MODELS[CLAUDE_35_SONNET];
|
|
386
|
-
MODELS[DEEPSEEK_R1_32B] = MODELS[DEEPSEEK_R1];
|
|
387
371
|
MODELS[DEEPSEEK_R1_70B] = MODELS[DEEPSEEK_R1];
|
|
372
|
+
MODELS[GEMMA327B] = MODELS[GEMMA_3_27B];
|
|
388
373
|
|
|
389
374
|
for (const n in MODELS) {
|
|
390
375
|
MODELS[n]['name'] = n;
|
|
@@ -514,56 +499,90 @@ const toolsGemini = async () => (await toolsOpenAI()).map(x => ({
|
|
|
514
499
|
}
|
|
515
500
|
}));
|
|
516
501
|
|
|
517
|
-
const init = async (options) => {
|
|
502
|
+
const init = async (options = {}) => {
|
|
503
|
+
const id = newAiId();
|
|
518
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 };
|
|
519
510
|
switch (provider) {
|
|
520
|
-
case OPENAI:
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
)
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
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
|
+
};
|
|
530
537
|
break;
|
|
531
538
|
case GEMINI:
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
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
|
+
};
|
|
537
546
|
break;
|
|
538
|
-
case
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
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
|
+
};
|
|
555
566
|
break;
|
|
556
567
|
case OLLAMA:
|
|
557
|
-
|
|
568
|
+
ais[id] = {
|
|
569
|
+
id, provider, model,
|
|
558
570
|
client: new (await need('ollama', { raw: true })).Ollama(options),
|
|
559
|
-
|
|
560
|
-
}
|
|
571
|
+
prompt: async (cnt, opts) => await promptOllama(id, cnt, opts),
|
|
572
|
+
};
|
|
561
573
|
break;
|
|
562
574
|
default:
|
|
563
|
-
throwError(`Invalid AI provider: ${options
|
|
575
|
+
throwError(`Invalid AI provider: ${options.provider || 'null'}.`);
|
|
564
576
|
}
|
|
565
|
-
|
|
566
|
-
|
|
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;
|
|
567
586
|
};
|
|
568
587
|
|
|
569
588
|
const countTokens = async (input, options) => {
|
|
@@ -972,36 +991,32 @@ const mergeMsgs = (resp, calls) => [resp, ...calls.length ? [
|
|
|
972
991
|
`⚠️ Tools recursion limit reached: ${MAX_TOOL_RECURSION}`
|
|
973
992
|
] : []].map(x => x.trim()).join('\n\n');
|
|
974
993
|
|
|
975
|
-
const
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
} else {
|
|
981
|
-
options.model = DEFAULT_MODELS[CHATGPT];
|
|
982
|
-
}
|
|
983
|
-
let [_MODEL, result, resultAudio, event, resultTools, responded] = [
|
|
984
|
-
MODELS[options.model], options?.result ?? '', Buffer.alloc(0), null, [],
|
|
985
|
-
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
|
|
986
999
|
];
|
|
987
|
-
options.
|
|
988
|
-
|
|
989
|
-
const { client } = await getOpenAIClient(options);
|
|
1000
|
+
options.flavor = CHATGPT;
|
|
1001
|
+
options.model = options.model || model.name;
|
|
990
1002
|
const { history }
|
|
991
|
-
= 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);
|
|
992
1007
|
const modalities = options.modalities
|
|
993
1008
|
|| (options.audioMode ? [TEXT, AUDIO] : undefined);
|
|
994
1009
|
[options.audioMimeType, options.suffix] = [pcm16, 'pcm.wav'];
|
|
995
1010
|
const resp = await client.chat.completions.create({
|
|
1011
|
+
model: azure ? undefined : options.model, ...history,
|
|
1012
|
+
...options.jsonMode ? { response_format: { type: JSON_OBJECT } } : {},
|
|
996
1013
|
modalities, audio: options.audio || (
|
|
997
1014
|
modalities?.find?.(x => x === AUDIO)
|
|
998
1015
|
&& { voice: DEFAULT_MODELS[OPENAI_VOICE], format: 'pcm16' }
|
|
999
|
-
), ...
|
|
1016
|
+
), ...model.tools && !azure ? {
|
|
1000
1017
|
tools: options.tools ?? (await toolsOpenAI()).map(x => x.def),
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
} : {}, model: options.model, stream: true,
|
|
1004
|
-
store: true, tool_choice: 'auto',
|
|
1018
|
+
tool_choice: 'auto',
|
|
1019
|
+
} : {}, ...azure ? {} : { store: true }, stream: true,
|
|
1005
1020
|
});
|
|
1006
1021
|
for await (event of resp) {
|
|
1007
1022
|
event = event?.choices?.[0] || {};
|
|
@@ -1016,9 +1031,11 @@ const promptChatGPT = async (content, options = {}) => {
|
|
|
1016
1031
|
isSet(x.index, true) && (curFunc.index = x.index);
|
|
1017
1032
|
x.id && (curFunc.id = x.id);
|
|
1018
1033
|
x.type && (curFunc.type = x.type);
|
|
1019
|
-
curFunc.function
|
|
1034
|
+
curFunc.function
|
|
1035
|
+
|| (curFunc.function = { name: '', arguments: '' });
|
|
1020
1036
|
x?.function?.name && (curFunc.function.name += x.function.name);
|
|
1021
|
-
x?.function?.arguments
|
|
1037
|
+
x?.function?.arguments
|
|
1038
|
+
&& (curFunc.function.arguments += x.function.arguments);
|
|
1022
1039
|
}
|
|
1023
1040
|
options.result && deltaText
|
|
1024
1041
|
&& (responded = responded || (deltaText = `\n\n${deltaText}`));
|
|
@@ -1036,25 +1053,27 @@ const promptChatGPT = async (content, options = {}) => {
|
|
|
1036
1053
|
};
|
|
1037
1054
|
const { toolsResult, toolsResponse }
|
|
1038
1055
|
= await handleToolsCall(event, { ...options, result });
|
|
1039
|
-
if (toolsResult.length
|
|
1040
|
-
|
|
1056
|
+
if (toolsResult.length
|
|
1057
|
+
&& countToolCalls(toolsResponse) < MAX_TOOL_RECURSION) {
|
|
1058
|
+
return promptOpenAI(aiId, content, {
|
|
1059
|
+
...options, toolsResult, result: toolsResponse,
|
|
1060
|
+
});
|
|
1041
1061
|
}
|
|
1042
1062
|
event.text = mergeMsgs(toolsResponse, toolsResult);
|
|
1043
1063
|
return await packResp(event, options);
|
|
1044
1064
|
};
|
|
1045
1065
|
|
|
1046
|
-
const
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
const promptOllama = async (content, options = {}) => {
|
|
1050
|
-
const { client, model } = await getOllamaClient(options);
|
|
1066
|
+
const promptOllama = async (aiId, content, options = {}) => {
|
|
1067
|
+
const { client, model } = await getAi(aiId);
|
|
1051
1068
|
// https://github.com/ollama/ollama-js
|
|
1052
1069
|
// https://github.com/jmorganca/ollama/blob/main/examples/typescript-simplechat/client.ts
|
|
1053
|
-
options.model = options?.model || model;
|
|
1054
|
-
let [
|
|
1055
|
-
const { history
|
|
1056
|
-
= await buildPrompts(
|
|
1057
|
-
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
|
+
});
|
|
1058
1077
|
for await (chunk of resp) {
|
|
1059
1078
|
const delta = chunk.message.content || '';
|
|
1060
1079
|
result += delta;
|
|
@@ -1065,33 +1084,28 @@ const promptOllama = async (content, options = {}) => {
|
|
|
1065
1084
|
return await packResp({ text: result }, options);
|
|
1066
1085
|
};
|
|
1067
1086
|
|
|
1068
|
-
const
|
|
1069
|
-
|
|
1087
|
+
const promptAnthropic = async (aiId, content, options = {}) => {
|
|
1088
|
+
const { client, model } = await getAi(aiId);
|
|
1070
1089
|
let [
|
|
1071
|
-
|
|
1072
|
-
responded, redacted_thinking
|
|
1073
|
-
] = [
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
];
|
|
1077
|
-
// https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking
|
|
1078
|
-
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 && (
|
|
1079
1095
|
content += '\n\nANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_'
|
|
1080
1096
|
+ '46C9A13E193C177646C7398A98432ECCCE4C1253D5E2D82641AC0E52CC2876CB'
|
|
1081
|
-
);
|
|
1082
|
-
const { client } = await getClaudeClient(options);
|
|
1097
|
+
); // https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking
|
|
1083
1098
|
const { systemPrompt: system, history }
|
|
1084
|
-
= await buildPrompts(
|
|
1099
|
+
= await buildPrompts(model, content, { ...options, flavor: CLAUDE });
|
|
1085
1100
|
const resp = await client.beta.messages.create({
|
|
1086
|
-
model: options.model,
|
|
1087
|
-
max_tokens: options
|
|
1088
|
-
...
|
|
1089
|
-
...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) ? {
|
|
1090
1104
|
thinking: options.thinking || {
|
|
1091
1105
|
type: 'enabled',
|
|
1092
1106
|
budget_tokens: options?.extendedThinking ? 16000 : 1024,
|
|
1093
1107
|
},
|
|
1094
|
-
} : {}, ...
|
|
1108
|
+
} : {}, ...model?.tools ? {
|
|
1095
1109
|
tools: options.tools ?? (await toolsClaude()).map(x => x.def),
|
|
1096
1110
|
tool_choice: { type: 'auto' }, betas: [
|
|
1097
1111
|
// https://docs.anthropic.com/en/docs/build-with-claude/tool-use/token-efficient-tool-use
|
|
@@ -1136,7 +1150,7 @@ const promptClaude = async (content, options = {}) => {
|
|
|
1136
1150
|
event, { ...options, result, flavor: CLAUDE },
|
|
1137
1151
|
);
|
|
1138
1152
|
if (tool_use.length && countToolCalls(toolsResponse) < MAX_TOOL_RECURSION) {
|
|
1139
|
-
return await
|
|
1153
|
+
return await promptAnthropic(aiId, content, {
|
|
1140
1154
|
...options, toolsResult: [...options.toolsResult || [],
|
|
1141
1155
|
...toolsResult], result: toolsResponse,
|
|
1142
1156
|
});
|
|
@@ -1193,31 +1207,29 @@ const packGeminiReferences = (chunks, supports) => {
|
|
|
1193
1207
|
return references;
|
|
1194
1208
|
};
|
|
1195
1209
|
|
|
1196
|
-
const promptGemini = async (content, options = {}) => {
|
|
1197
|
-
|
|
1198
|
-
let [result, references, functionCalls, responded
|
|
1199
|
-
= [options.result ?? '', null, null, false
|
|
1200
|
-
|
|
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;
|
|
1201
1215
|
const { systemPrompt: systemInstruction, history, prompt }
|
|
1202
|
-
= await buildPrompts(
|
|
1203
|
-
const
|
|
1216
|
+
= await buildPrompts(model, content, { ...options, flavor: GEMINI });
|
|
1217
|
+
const _client = client.getGenerativeModel({
|
|
1204
1218
|
model: options.model, systemInstruction,
|
|
1205
|
-
...
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
}
|
|
1216
|
-
) : {},
|
|
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
|
+
}) : {},
|
|
1217
1229
|
});
|
|
1218
1230
|
// https://github.com/google/generative-ai-js/blob/main/samples/node/advanced-chat.js
|
|
1219
1231
|
// Google's bug: history is not allowed while using inline_data?
|
|
1220
|
-
const chat =
|
|
1232
|
+
const chat = _client.startChat({ history, ...generationConfig(options) });
|
|
1221
1233
|
const resp = await chat.sendMessageStream(prompt);
|
|
1222
1234
|
for await (const chunk of resp.stream) {
|
|
1223
1235
|
functionCalls || (functionCalls = chunk.functionCalls);
|
|
@@ -1242,10 +1254,11 @@ const promptGemini = async (content, options = {}) => {
|
|
|
1242
1254
|
{ role: MODEL, parts: functionCalls },
|
|
1243
1255
|
{ ...options, result, flavor: GEMINI }
|
|
1244
1256
|
);
|
|
1245
|
-
if (toolsResult.length
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
...
|
|
1257
|
+
if (toolsResult.length
|
|
1258
|
+
&& countToolCalls(toolsResponse) < MAX_TOOL_RECURSION) {
|
|
1259
|
+
return promptGemini(aiId, content, {
|
|
1260
|
+
...options || {}, result: toolsResponse,
|
|
1261
|
+
toolsResult: [...options?.toolsResult || [], ...toolsResult],
|
|
1249
1262
|
});
|
|
1250
1263
|
}
|
|
1251
1264
|
return await packResp({
|
|
@@ -1442,9 +1455,9 @@ const talk = async (input, options) => {
|
|
|
1442
1455
|
...options,
|
|
1443
1456
|
};
|
|
1444
1457
|
switch (engine) {
|
|
1445
|
-
case CHATGPT: resp = await
|
|
1458
|
+
case CHATGPT: resp = await promptOpenAI(input, pmtOptions); break;
|
|
1446
1459
|
case GEMINI: resp = await promptGemini(input, pmtOptions); break;
|
|
1447
|
-
case CLAUDE: resp = await
|
|
1460
|
+
case CLAUDE: resp = await promptAnthropic(input, pmtOptions); break;
|
|
1448
1461
|
case OLLAMA: resp = await promptOllama(input, pmtOptions); break;
|
|
1449
1462
|
case AZURE: resp = await promptAzure(input, pmtOptions); break;
|
|
1450
1463
|
default: throwError(`Invalid AI engine: '${engine}'.`);
|
|
@@ -1568,17 +1581,17 @@ const analyzeSessions = async (sessionIds, options) => {
|
|
|
1568
1581
|
};
|
|
1569
1582
|
|
|
1570
1583
|
const PREFERRED_ENGINES = [
|
|
1571
|
-
{ client: OPENAI, func:
|
|
1584
|
+
{ client: OPENAI, func: promptOpenAI, multimodal: 0 },
|
|
1572
1585
|
{ client: GEMINI, func: promptGemini, multimodal: 1 },
|
|
1573
|
-
{ client: CLAUDE, func:
|
|
1574
|
-
{ client: AZURE, func: promptAzure, multimodal: 3 },
|
|
1586
|
+
{ client: CLAUDE, func: promptAnthropic, multimodal: 2 },
|
|
1587
|
+
// { client: AZURE, func: promptAzure, multimodal: 3 },
|
|
1575
1588
|
{ client: OLLAMA, func: promptOllama, multimodal: 99 },
|
|
1576
1589
|
]; // keep gpt first to avoid gemini grounding by default
|
|
1577
1590
|
|
|
1578
1591
|
export default init;
|
|
1579
1592
|
export {
|
|
1580
1593
|
ATTACHMENT_TOKEN_COST, CLOUD_37_SONNET, CODE_INTERPRETER, DEEPSEEK_R1,
|
|
1581
|
-
|
|
1594
|
+
DEEPSEEK_R1_70B, DEFAULT_MODELS,
|
|
1582
1595
|
EMBEDDING_001,
|
|
1583
1596
|
FUNCTION, GEMINI_20_FLASH, GEMINI_20_FLASH_THINKING, GPT_45, GPT_4O, GPT_4O_MINI, GPT_O1, GPT_O3_MINI, INSTRUCTIONS, MODELS,
|
|
1584
1597
|
OPENAI_VOICE, RETRIEVAL,
|
|
@@ -1597,13 +1610,14 @@ export {
|
|
|
1597
1610
|
init,
|
|
1598
1611
|
initChat,
|
|
1599
1612
|
jpeg,
|
|
1613
|
+
getAi,
|
|
1600
1614
|
listFiles,
|
|
1601
1615
|
listGptFineTuningEvents,
|
|
1602
1616
|
listGptFineTuningJobs,
|
|
1603
1617
|
listOpenAIModels,
|
|
1604
1618
|
ogg,
|
|
1605
|
-
prompt,
|
|
1606
|
-
|
|
1619
|
+
prompt, promptOpenAI,
|
|
1620
|
+
promptAnthropic,
|
|
1607
1621
|
promptGemini,
|
|
1608
1622
|
promptOllama,
|
|
1609
1623
|
resetSession,
|
package/lib/manifest.mjs
CHANGED