utilitas 1999.1.20 → 1999.1.22

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/lib/alan.mjs CHANGED
@@ -38,7 +38,7 @@ You may be provided with some tools(functions) to help you gather information an
38
38
  - Unless otherwise specified to require the original result, in most cases, you may reorganize the information obtained after using the tool to solve the problem as needed.`;
39
39
 
40
40
  const _NEED = [
41
- '@anthropic-ai/sdk', '@anthropic-ai/vertex-sdk', '@google/generative-ai',
41
+ '@anthropic-ai/sdk', '@anthropic-ai/vertex-sdk', '@google/genai',
42
42
  'js-tiktoken', 'OpenAI',
43
43
  ];
44
44
 
@@ -65,7 +65,7 @@ const [
65
65
  TOOL, silent, GEMINI_EMBEDDING_M, INVALID_FILE, tokenSafeRatio,
66
66
  GPT_QUERY_LIMIT, CONTENT_IS_REQUIRED, OPENAI_HI_RES_SIZE, k, kT, m, minute,
67
67
  hour, gb, trimTailing, EBD, GEMINI_20_FLASH_EXP, IMAGE, JINA,
68
- JINA_DEEPSEARCH, JINA_CLIP,
68
+ JINA_DEEPSEARCH, JINA_CLIP, VERTEX,
69
69
  ] = [
70
70
  'OpenAI', 'Gemini', 'OPENAI_TRAINING', 'Ollama', 'gpt-4o-mini',
71
71
  'gpt-4o', 'o1', 'o3-mini', 'gemini-2.0-flash',
@@ -84,7 +84,7 @@ const [
84
84
  x => 1024 * 1024 * x, x => 60 * x, x => 60 * 60 * x,
85
85
  x => 1024 * 1024 * 1024 * x, x => x.replace(/[\.\s]*$/, ''),
86
86
  { embedding: true }, 'gemini-2.0-flash-exp', 'image', 'Jina',
87
- 'jina-deepsearch-v1', 'jina-clip-v2',
87
+ 'jina-deepsearch-v1', 'jina-clip-v2', 'Vertex',
88
88
  ];
89
89
 
90
90
  const [tool, messages, text]
@@ -236,9 +236,9 @@ const DEFAULT_EMBEDDING = {
236
236
  };
237
237
 
238
238
  const PROVIDER_ICONS = {
239
- [OPENAI]: '⚛️', [AZURE_OPENAI]: '⚛️',
239
+ [OPENAI]: '⚛️', [AZURE_OPENAI]: '⚛️', [AZURE]: '☁️', [JINA]: '✴️',
240
+ [GEMINI]: '♊️', [VERTEX]: '📖', [OLLAMA]: '🦙',
240
241
  [ANTHROPIC]: '✳️', [VERTEX_ANTHROPIC]: '✳️',
241
- [GEMINI]: '♊️', [AZURE]: '☁️', [OLLAMA]: '🦙', [JINA]: '✴️',
242
242
  };
243
243
 
244
244
  const FEATURE_ICONS = {
@@ -261,7 +261,7 @@ let tokeniser;
261
261
 
262
262
  const unifyProvider = provider => {
263
263
  assert(provider = (provider || '').trim(), 'AI provider is required.');
264
- for (let type of [OPENAI, AZURE_OPENAI, AZURE, GEMINI, ANTHROPIC,
264
+ for (let type of [OPENAI, AZURE_OPENAI, AZURE, GEMINI, VERTEX, ANTHROPIC,
265
265
  VERTEX_ANTHROPIC, JINA, OLLAMA]) {
266
266
  if (insensitiveCompare(provider, type)) { return type; }
267
267
  }
@@ -347,18 +347,18 @@ const toolsClaude = async () => (await toolsOpenAI()).map(x => ({
347
347
  }
348
348
  }));
349
349
 
350
- const toolsGemini = async () => (await toolsOpenAI()).map(x => ({
350
+ const toolsGemini = async (options) => (await toolsOpenAI()).map(x => ({
351
351
  ...x, def: {
352
- name: x.def.function.name,
353
- description: x.def.function.description,
352
+ name: x.def.function.name, description: x.def.function.description,
354
353
  parameters: {
355
354
  type: 'object',
356
355
  properties: x.def.function.parameters.properties,
357
356
  required: x.def.function.parameters.required,
358
- },
359
- response: x.def.function?.response ?? {
360
- type: 'string', description: 'It could be a string or JSON',
361
- },
357
+ }, ...options?.provider === 'VERTEX' ? {
358
+ response: x.def.function?.response ?? {
359
+ type: 'string', description: 'It could be a string or JSON',
360
+ }
361
+ } : {},
362
362
  }
363
363
  }));
364
364
 
@@ -426,9 +426,24 @@ const init = async (options = {}) => {
426
426
  setupAi({ provider, model, client, prompt: promptOpenAI });
427
427
  break;
428
428
  case GEMINI:
429
- assertApiKey(provider, options);
430
- const { GoogleGenerativeAI } = await need('@google/generative-ai');
431
- var client = new GoogleGenerativeAI(options.apiKey);
429
+ assert(options.apiKey, `${provider} api key is required.`);
430
+ var { GoogleGenAI } = await need('@google/genai');
431
+ var client = new GoogleGenAI(options);
432
+ for (let model of models) {
433
+ setupAi({
434
+ provider, model, client,
435
+ prompt: promptGemini, embedding: createGeminiEmbedding,
436
+ });
437
+ }
438
+ break;
439
+ case VERTEX:
440
+ assert(options.credentials && options.project,
441
+ `${provider} credentials and project id are required.`);
442
+ process.env['GOOGLE_APPLICATION_CREDENTIALS'] = options.credentials;
443
+ var { GoogleGenAI } = await need('@google/genai');
444
+ var client = new GoogleGenAI({
445
+ vertexai: true, location: 'us-east5', ...options
446
+ });
432
447
  for (let model of models) {
433
448
  setupAi({
434
449
  provider, model, client,
@@ -447,7 +462,8 @@ const init = async (options = {}) => {
447
462
  break;
448
463
  case VERTEX_ANTHROPIC:
449
464
  // https://github.com/anthropics/anthropic-sdk-typescript/tree/main/packages/vertex-sdk
450
- assert(options?.credentials, `${provider} api credentials are required.`);
465
+ assert(options.credentials && options.projectId,
466
+ `${provider} credentials and project id are required.`);
451
467
  process.env['GOOGLE_APPLICATION_CREDENTIALS'] = options.credentials;
452
468
  process.env['ANTHROPIC_VERTEX_PROJECT_ID'] = options.projectId;
453
469
  var model = models[0];
@@ -506,7 +522,7 @@ const packAi = (ais, options = {}) => {
506
522
  const getAi = async (id, options = {}) => {
507
523
  if (id) {
508
524
  const ai = ais.find(x => x.id === id);
509
- assert(ais, `AI not found: ${id}.`);
525
+ assert(ai, `AI not found: ${id}.`);
510
526
  return options?.client ? ai?.client : ai;
511
527
  } else if (options?.select) {
512
528
  const res = [];
@@ -795,6 +811,8 @@ const buildPrompts = async (model, input, options = {}) => {
795
811
  history.push(buildClaudeMessage(x.response, _assistant));
796
812
  break;
797
813
  case GEMINI:
814
+ // https://github.com/google/generative-ai-js/blob/main/samples/node/advanced-chat.js
815
+ // Google's bug: history is not allowed while using inline_data?
798
816
  if (options.attachments?.length) { return; }
799
817
  history.push(buildGeminiHistory(x.request, _user));
800
818
  history.push(buildGeminiHistory(x.response, { role: MODEL }));
@@ -826,9 +844,9 @@ const buildPrompts = async (model, input, options = {}) => {
826
844
  }
827
845
  };
828
846
  msgBuilder();
829
- await trimPrompt(() => [systemPrompt, history, prompt], () => {
830
- if (options.messages.length) {
831
- options.messages.shift();
847
+ await trimPrompt(() => [systemPrompt, history, content], () => {
848
+ if (options.messages?.length) {
849
+ options.messages?.shift();
832
850
  msgBuilder();
833
851
  } else {
834
852
  content = trimTailing(trimTailing(content).slice(0, -1)) + '...';
@@ -1110,15 +1128,6 @@ const deleteFile = async (aiId, file_id, options) => {
1110
1128
  return await client.files.del(file_id);
1111
1129
  };
1112
1130
 
1113
- const generationConfig = options => ({
1114
- generationConfig: {
1115
- responseMimeType: options.jsonMode ? MIME_JSON : MIME_TEXT,
1116
- responseModalities: options.modalities
1117
- || (options.imageMode ? [TEXT, IMAGE] : undefined),
1118
- ...options?.generationConfig || {},
1119
- },
1120
- });
1121
-
1122
1131
  const packGeminiReferences = (chunks, supports) => {
1123
1132
  let references = null;
1124
1133
  if (chunks?.length && supports?.length) {
@@ -1133,9 +1142,9 @@ const packGeminiReferences = (chunks, supports) => {
1133
1142
  };
1134
1143
 
1135
1144
  const promptGemini = async (aiId, content, options = {}) => {
1136
- let { client, model } = await getAi(aiId);
1137
- let [result, references, functionCalls, responded, images]
1138
- = [options.result ?? '', null, null, false, []];
1145
+ let { provider, client, model } = await getAi(aiId);
1146
+ let [event, result, references, functionCalls, responded, images] =
1147
+ [null, options.result ?? '', null, [], false, []];
1139
1148
  options.model = options.model || model.name;
1140
1149
  model?.image === true && (options.imageMode = true);
1141
1150
  assert(!(options.imageMode && !model.image), 'Image mode is not supported.');
@@ -1146,43 +1155,44 @@ const promptGemini = async (aiId, content, options = {}) => {
1146
1155
  }
1147
1156
  const { systemPrompt: systemInstruction, history, prompt }
1148
1157
  = await buildPrompts(model, content, { ...options, flavor: GEMINI });
1149
- const _client = client.getGenerativeModel({
1150
- model: options.model, systemInstruction,
1151
- ...model?.tools && !options.jsonMode
1152
- && options.model !== GEMINI_20_FLASH_EXP ? (options.tools ?? {
1153
- tools: [
1154
- // @todo: Gemini will failed when using these tools together.
1155
- // https://ai.google.dev/gemini-api/docs/function-calling
1156
- // { codeExecution: {} },
1157
- // { googleSearch: {} },
1158
- {
1159
- functionDeclarations: (
1160
- await toolsGemini()
1161
- ).map(x => x.def)
1162
- },
1163
- ],
1164
- toolConfig: { functionCallingConfig: { mode: 'AUTO' } },
1165
- }) : {},
1158
+ const chat = client.chats.create({
1159
+ model: options.model, history, config: {
1160
+ responseMimeType: options.jsonMode ? MIME_JSON : MIME_TEXT,
1161
+ systemInstruction, responseModalities: options.modalities || (
1162
+ options.imageMode ? [TEXT, IMAGE] : undefined
1163
+ ), ...options?.config || {}, ...model?.tools && !options.jsonMode
1164
+ && options.model !== GEMINI_20_FLASH_EXP ? (options.tools ?? {
1165
+ tools: [
1166
+ // @todo: Gemini will failed when using these tools together.
1167
+ // https://ai.google.dev/gemini-api/docs/function-calling
1168
+ // { codeExecution: {} },
1169
+ // { googleSearch: {} },
1170
+ {
1171
+ functionDeclarations: (
1172
+ await toolsGemini({ provider })
1173
+ ).map(x => x.def)
1174
+ },
1175
+ ], toolConfig: { functionCallingConfig: { mode: 'AUTO' } },
1176
+ }) : {},
1177
+ },
1166
1178
  });
1167
- // https://github.com/google/generative-ai-js/blob/main/samples/node/advanced-chat.js
1168
- // Google's bug: history is not allowed while using inline_data?
1169
- const chat = _client.startChat({ history, ...generationConfig(options) });
1170
- const resp = await chat.sendMessageStream(prompt);
1171
- for await (const chunk of resp.stream) {
1172
- const deltaImages = [];
1173
- chunk.candidates[0].content?.parts?.filter(
1174
- x => x?.inlineData?.mimeType === png
1175
- )?.map?.(x => {
1176
- deltaImages.push(x.inlineData);
1177
- images.push(x.inlineData);
1179
+ const resp = await chat.sendMessageStream({ message: prompt });
1180
+ for await (const chunk of resp) {
1181
+ event = chunk.candidates[0];
1182
+ let [deltaText, deltaImages] = ['', []];
1183
+ event?.content?.parts?.map(x => {
1184
+ if (x.text) { deltaText = x.text; }
1185
+ else if (x.functionCall) { functionCalls.push(x); }
1186
+ else if (x.inlineData?.mimeType === png) {
1187
+ deltaImages.push(x.inlineData);
1188
+ images.push(x.inlineData);
1189
+ }
1178
1190
  });
1179
- functionCalls || (functionCalls = chunk.functionCalls);
1180
1191
  const rfc = packGeminiReferences(
1181
- chunk.candidates[0]?.groundingMetadata?.groundingChunks,
1182
- chunk.candidates[0]?.groundingMetadata?.groundingSupports
1192
+ event?.groundingMetadata?.groundingChunks,
1193
+ event?.groundingMetadata?.groundingSupports
1183
1194
  );
1184
1195
  rfc && (references = rfc);
1185
- let deltaText = chunk?.text?.() || '';
1186
1196
  options.result && deltaText
1187
1197
  && (responded = responded || (deltaText = `\n\n${deltaText}`));
1188
1198
  result += deltaText;
@@ -1191,10 +1201,6 @@ const promptGemini = async (aiId, content, options = {}) => {
1191
1201
  images: options.delta ? deltaImages : images,
1192
1202
  }, options);
1193
1203
  }
1194
- const _resp = await resp.response;
1195
- functionCalls = (
1196
- functionCalls() || _resp.functionCalls() || []
1197
- ).map(x => ({ functionCall: x }));
1198
1204
  const { toolsResult, toolsResponse } = await handleToolsCall(
1199
1205
  { role: MODEL, parts: functionCalls },
1200
1206
  { ...options, result, flavor: GEMINI }
package/lib/manifest.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  const manifest = {
2
2
  "name": "utilitas",
3
3
  "description": "Just another common utility for JavaScript.",
4
- "version": "1999.1.20",
4
+ "version": "1999.1.22",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/utilitas",
7
7
  "main": "index.mjs",
@@ -19,7 +19,7 @@ const manifest = {
19
19
  "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.1/xlsx-0.20.1.tgz"
20
20
  },
21
21
  "dependencies": {
22
- "file-type": "^20.4.0",
22
+ "file-type": "^20.4.1",
23
23
  "mathjs": "^14.3.1",
24
24
  "uuid": "^11.1.0"
25
25
  },
@@ -28,14 +28,14 @@ const manifest = {
28
28
  "@anthropic-ai/vertex-sdk": "^0.7.0",
29
29
  "@ffmpeg-installer/ffmpeg": "^1.1.0",
30
30
  "@ffprobe-installer/ffprobe": "^2.1.2",
31
- "@google-cloud/speech": "^6.7.1",
31
+ "@google-cloud/speech": "^7.0.0",
32
32
  "@google-cloud/storage": "^7.15.2",
33
- "@google-cloud/text-to-speech": "^5.8.1",
34
- "@google-cloud/vision": "^4.3.3",
35
- "@google/generative-ai": "^0.24.0",
33
+ "@google-cloud/text-to-speech": "^6.0.0",
34
+ "@google-cloud/vision": "^5.0.0",
35
+ "@google/genai": "^0.4.0",
36
36
  "@mozilla/readability": "github:mozilla/readability",
37
- "@sentry/node": "^9.5.0",
38
- "@sentry/profiling-node": "^9.5.0",
37
+ "@sentry/node": "^9.6.0",
38
+ "@sentry/profiling-node": "^9.6.0",
39
39
  "acme-client": "^5.4.0",
40
40
  "browserify-fs": "^1.0.0",
41
41
  "buffer": "^6.0.3",
@@ -53,9 +53,9 @@ const manifest = {
53
53
  "node-mailjet": "^6.0.8",
54
54
  "node-polyfill-webpack-plugin": "^4.1.0",
55
55
  "office-text-extractor": "^3.0.3",
56
- "openai": "^4.87.3",
57
- "pdfjs-dist": "^4.10.38",
58
- "pg": "^8.14.0",
56
+ "openai": "^4.87.4",
57
+ "pdfjs-dist": "^5.0.375",
58
+ "pg": "^8.14.1",
59
59
  "pgvector": "^0.2.0",
60
60
  "ping": "^0.4.4",
61
61
  "process": "^0.11.10",
@@ -68,7 +68,7 @@ const manifest = {
68
68
  "url": "github:Leask/node-url",
69
69
  "webpack-cli": "^6.0.1",
70
70
  "whisper-node": "^1.1.1",
71
- "wrangler": "^3.114.1",
71
+ "wrangler": "^4.1.0",
72
72
  "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.1/xlsx-0.20.1.tgz",
73
73
  "youtube-transcript": "^1.2.1"
74
74
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "utilitas",
3
3
  "description": "Just another common utility for JavaScript.",
4
- "version": "1999.1.20",
4
+ "version": "1999.1.22",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/utilitas",
7
7
  "main": "index.mjs",
@@ -30,7 +30,7 @@
30
30
  "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.1/xlsx-0.20.1.tgz"
31
31
  },
32
32
  "dependencies": {
33
- "file-type": "^20.4.0",
33
+ "file-type": "^20.4.1",
34
34
  "mathjs": "^14.3.1",
35
35
  "uuid": "^11.1.0"
36
36
  },
@@ -39,14 +39,14 @@
39
39
  "@anthropic-ai/vertex-sdk": "^0.7.0",
40
40
  "@ffmpeg-installer/ffmpeg": "^1.1.0",
41
41
  "@ffprobe-installer/ffprobe": "^2.1.2",
42
- "@google-cloud/speech": "^6.7.1",
42
+ "@google-cloud/speech": "^7.0.0",
43
43
  "@google-cloud/storage": "^7.15.2",
44
- "@google-cloud/text-to-speech": "^5.8.1",
45
- "@google-cloud/vision": "^4.3.3",
46
- "@google/generative-ai": "^0.24.0",
44
+ "@google-cloud/text-to-speech": "^6.0.0",
45
+ "@google-cloud/vision": "^5.0.0",
46
+ "@google/genai": "^0.4.0",
47
47
  "@mozilla/readability": "github:mozilla/readability",
48
- "@sentry/node": "^9.5.0",
49
- "@sentry/profiling-node": "^9.5.0",
48
+ "@sentry/node": "^9.6.0",
49
+ "@sentry/profiling-node": "^9.6.0",
50
50
  "acme-client": "^5.4.0",
51
51
  "browserify-fs": "^1.0.0",
52
52
  "buffer": "^6.0.3",
@@ -64,9 +64,9 @@
64
64
  "node-mailjet": "^6.0.8",
65
65
  "node-polyfill-webpack-plugin": "^4.1.0",
66
66
  "office-text-extractor": "^3.0.3",
67
- "openai": "^4.87.3",
68
- "pdfjs-dist": "^4.10.38",
69
- "pg": "^8.14.0",
67
+ "openai": "^4.87.4",
68
+ "pdfjs-dist": "^5.0.375",
69
+ "pg": "^8.14.1",
70
70
  "pgvector": "^0.2.0",
71
71
  "ping": "^0.4.4",
72
72
  "process": "^0.11.10",
@@ -79,7 +79,7 @@
79
79
  "url": "github:Leask/node-url",
80
80
  "webpack-cli": "^6.0.1",
81
81
  "whisper-node": "^1.1.1",
82
- "wrangler": "^3.114.1",
82
+ "wrangler": "^4.1.0",
83
83
  "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.1/xlsx-0.20.1.tgz",
84
84
  "youtube-transcript": "^1.2.1"
85
85
  }