utilitas 1999.1.60 → 1999.1.62

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
@@ -5,7 +5,11 @@ import { end, loop } from './event.mjs';
5
5
  import { fileTypeFromBuffer } from 'file-type';
6
6
 
7
7
  import {
8
- BASE64, BUFFER, DATAURL, MIME_BINARY, MIME_JSON, MIME_TEXT, STREAM, convert,
8
+ BASE64, BUFFER, DATAURL, MIME_BINARY, MIME_JSON, MIME_TEXT, MIME_PNG,
9
+ MIME_JPEG, MIME_MOV, MIME_MPEG, MIME_MP4, MIME_MPG, MIME_AVI, MIME_WMV,
10
+ MIME_MPEGPS, MIME_FLV, MIME_GIF, MIME_WEBP, MIME_PDF, MIME_AAC, MIME_FLAC,
11
+ MIME_MP3, MIME_MPEGA, MIME_M4A, MIME_MPGA, MIME_OPUS, MIME_PCM, MIME_WAV,
12
+ MIME_WEBM, MIME_TGPP, MIME_PCM16, STREAM, convert,
9
13
  } from './storage.mjs';
10
14
 
11
15
  import {
@@ -43,18 +47,6 @@ const _NEED = [
43
47
  'js-tiktoken', 'OpenAI',
44
48
  ];
45
49
 
46
- const [
47
- png, jpeg, mov, mpeg, mp4, mpg, avi, wmv, mpegps, flv, gif, webp, pdf, aac,
48
- flac, mp3, mpega, m4a, mpga, opus, pcm, wav, webm, tgpp, pcm16, ogg,
49
- ] = [
50
- 'image/png', 'image/jpeg', 'video/mov', 'video/mpeg', 'video/mp4',
51
- 'video/mpg', 'video/avi', 'video/wmv', 'video/mpegps', 'video/x-flv',
52
- 'image/gif', 'image/webp', 'application/pdf', 'audio/aac', 'audio/flac',
53
- 'audio/mp3', 'audio/mpeg', 'audio/m4a', 'audio/mpga', 'audio/opus',
54
- 'audio/pcm', 'audio/wav', 'audio/webm', 'video/3gpp', 'audio/x-wav',
55
- 'audio/ogg',
56
- ];
57
-
58
50
  const [
59
51
  OPENAI, GEMINI, OPENAI_TRAINING, OLLAMA, GPT_4O, GPT_O3, GEMINI_25_FLASH,
60
52
  NOVA, DEEPSEEK_R1, MD_CODE, TEXT_EMBEDDING_3_SMALL, TEXT_EMBEDDING_3_LARGE,
@@ -112,8 +104,8 @@ const OPENAI_EBD = { ...EBD, maxInputTokens: k(8) - 1 };
112
104
  const OPENAI_RULES = {
113
105
  imageCostTokens: ~~(OPENAI_HI_RES_SIZE / (512 * 512) * 170 + 85),
114
106
  maxFileSize: m(20), maxImageSize: OPENAI_HI_RES_SIZE,
115
- supportedMimeTypes: [png, jpeg, gif, webp],
116
- supportedAudioTypes: [wav], audio: 'gpt-4o-audio-preview',
107
+ supportedMimeTypes: [MIME_PNG, MIME_JPEG, MIME_GIF, MIME_WEBP],
108
+ supportedAudioTypes: [MIME_WAV], audio: 'gpt-4o-audio-preview',
117
109
  json: true, tools: true, vision: true, defaultProvider: OPENAI,
118
110
  };
119
111
 
@@ -124,8 +116,10 @@ const GEMINI_RULES = {
124
116
  maxAudioPerPrompt: 1, maxFileSize: m(20), maxImagePerPrompt: 3000,
125
117
  maxImageSize: Infinity, maxUrlSize: gb(2), maxVideoLength: minute(45),
126
118
  maxVideoPerPrompt: 10, vision: true, supportedMimeTypes: [
127
- png, jpeg, mov, mpeg, mp4, mpg, avi, wmv, mpegps, flv, pdf, aac,
128
- flac, mp3, mpega, m4a, mpga, opus, pcm, wav, webm, tgpp,
119
+ MIME_PNG, MIME_JPEG, MIME_MOV, MIME_MPEG, MIME_MP4, MIME_MPG, MIME_AVI,
120
+ MIME_WMV, MIME_MPEGPS, MIME_FLV, MIME_PDF, MIME_AAC, MIME_FLAC,
121
+ MIME_MP3, MIME_MPEGA, MIME_M4A, MIME_MPGA, MIME_OPUS, MIME_PCM,
122
+ MIME_WAV, MIME_WEBM, MIME_TGPP,
129
123
  ], defaultProvider: GEMINI,
130
124
  };
131
125
 
@@ -150,15 +144,16 @@ const MODELS = {
150
144
  [GEMMA_3_27B]: {
151
145
  contextWindow: kT(128), maxOutputTokens: k(8),
152
146
  imageCostTokens: 256, maxImageSize: 896 * 896,
153
- supportedMimeTypes: [png, jpeg, gif],
147
+ supportedMimeTypes: [MIME_PNG, MIME_JPEG, MIME_GIF],
154
148
  fast: true, json: true, vision: true,
155
149
  defaultProvider: OLLAMA,
156
150
  },
157
151
  [JINA_DEEPSEARCH]: {
158
152
  contextWindow: Infinity, maxInputTokens: Infinity,
159
153
  maxOutputTokens: Infinity, imageCostTokens: 0, maxImageSize: Infinity,
160
- supportedMimeTypes: [png, jpeg, MIME_TEXT, webp, pdf], reasoning: true,
161
- json: true, vision: true, deepsearch: true, defaultProvider: JINA,
154
+ supportedMimeTypes: [MIME_PNG, MIME_JPEG, MIME_TEXT, MIME_WEBP, MIME_PDF],
155
+ reasoning: true, json: true, vision: true,
156
+ deepsearch: true, defaultProvider: JINA,
162
157
  },
163
158
  [DEEPSEEK_R1]: {
164
159
  contextWindow: kT(128), maxOutputTokens: k(8),
@@ -180,7 +175,7 @@ const MODELS = {
180
175
  maxDocumentPages: 100, imageCostTokens: ~~(v8k / 750),
181
176
  maxImagePerPrompt: Math.min(/*Anthropic:*/100, /*Vertex:*/20),
182
177
  maxFileSize: /*Vertex*/m(5), maxImageSize: 2000 * 2000,
183
- supportedMimeTypes: [png, jpeg, gif, webp, pdf],
178
+ supportedMimeTypes: [MIME_PNG, MIME_JPEG, MIME_GIF, MIME_WEBP, MIME_PDF],
184
179
  json: true, reasoning: true, tools: true, vision: true,
185
180
  defaultProvider: [ANTHROPIC, VERTEX_ANTHROPIC],
186
181
  }, // https://docs.anthropic.com/en/docs/build-with-claude/vision
@@ -623,9 +618,9 @@ const buildClaudeMessage = (text, options) => {
623
618
  assert(text, 'Text is required.');
624
619
  const attachments = (options?.attachments?.length ? options?.attachments : []).map(x => {
625
620
  let type = '';
626
- if ([pdf].includes(x.mime_type)) {
621
+ if ([MIME_PDF].includes(x.mime_type)) {
627
622
  type = 'document';
628
- } else if ([png, jpeg, gif, webp].includes(x.mime_type)) {
623
+ } else if ([MIME_PNG, MIME_JPEG, MIME_GIF, MIME_WEBP].includes(x.mime_type)) {
629
624
  type = 'image';
630
625
  } else { throwError(`Unsupported mime type: ${x.mime_type}`); }
631
626
  return {
@@ -785,10 +780,13 @@ const buildPrompts = async (model, input, options = {}) => {
785
780
  assert(!(
786
781
  options.reasoning && !model?.reasoning
787
782
  ), `This model does not support reasoning: ${options.model}`);
788
- let [systemPrompt, history, content, prompt, _system, _user, _assistant] = [
789
- null, null, input || ATTACHMENTS, null, // length hack: ATTACHMENTS
790
- { role: system }, { role: user }, { role: assistant },
791
- ];
783
+ let [
784
+ systemPrompt, history, content, prompt, _system, _model, _assistant,
785
+ _history,
786
+ ] = [
787
+ null, null, input || ATTACHMENTS, null, // length hack: ATTACHMENTS
788
+ { role: system }, { role: MODEL }, { role: assistant }, null,
789
+ ];
792
790
  options.systemPrompt = options.systemPrompt || INSTRUCTIONS;
793
791
  options.attachments = (
794
792
  options.attachments?.length ? options.attachments : []
@@ -798,68 +796,71 @@ const buildPrompts = async (model, input, options = {}) => {
798
796
  switch (options.flavor) {
799
797
  case OPENAI:
800
798
  systemPrompt = buildGptMessage(options.systemPrompt, _system);
801
- prompt = buildGptMessage(content, options);
802
799
  break;
803
800
  case ANTHROPIC:
804
801
  systemPrompt = options.systemPrompt;
805
- prompt = buildClaudeMessage(content, { ...options, cache_control: true });
806
802
  break;
807
803
  case GEMINI:
808
804
  const _role = {
809
- role: [GEMINI_20_FLASH].includes(options.model)
810
- ? user : system
805
+ role: [GEMINI_20_FLASH].includes(options.model) ? user : system
811
806
  };
812
807
  systemPrompt = buildGeminiHistory(options.systemPrompt, _role);
813
- prompt = options.toolsResult?.[options.toolsResult?.length - 1]?.parts
814
- || buildGeminiMessage(content, options)
815
808
  break;
816
809
  }
817
810
  const msgBuilder = () => {
818
- history = [];
811
+ [history, _history] = [[], []];
819
812
  (options.messages?.length ? options.messages : []).map((x, i) => {
820
813
  switch (options.flavor) {
821
814
  case OPENAI:
822
- history.push(buildGptMessage(x.request, _user));
823
- history.push(buildGptMessage(x.response, _assistant));
815
+ _history.push(buildGptMessage(x.request));
816
+ _history.push(buildGptMessage(x.response, _assistant));
824
817
  break;
825
818
  case ANTHROPIC:
826
- history.push(buildClaudeMessage(x.request, _user));
827
- history.push(buildClaudeMessage(x.response, _assistant));
819
+ _history.push(buildClaudeMessage(x.request));
820
+ _history.push(buildClaudeMessage(x.response, _assistant));
828
821
  break;
829
822
  case GEMINI:
830
823
  // https://github.com/google/generative-ai-js/blob/main/samples/node/advanced-chat.js
831
824
  // Google's bug: history is not allowed while using inline_data?
832
825
  if (options.attachments?.length) { return; }
833
- history.push(buildGeminiHistory(x.request, _user));
834
- history.push(buildGeminiHistory(x.response, { role: MODEL }));
826
+ _history.push(buildGeminiHistory(x.request));
827
+ _history.push(buildGeminiHistory(x.response, _model));
835
828
  break;
836
829
  }
837
830
  });
838
831
  switch (options.flavor) {
839
832
  case OPENAI:
840
833
  history = messages([
841
- systemPrompt, ...history, prompt,
834
+ systemPrompt, ..._history, buildGptMessage(content, options),
842
835
  ...options.toolsResult?.length ? options.toolsResult : []
843
836
  ]);
844
837
  break;
845
838
  case ANTHROPIC:
846
839
  history = messages([
847
- ...history, prompt,
848
- ...options.toolsResult?.length ? options.toolsResult : []
840
+ ..._history, buildClaudeMessage(content, {
841
+ ...options, cache_control: true
842
+ }), ...options.toolsResult?.length ? options.toolsResult : []
849
843
  ]);
850
844
  break;
851
845
  case GEMINI:
852
- history.push(
853
- ...options.toolsResult?.length ? [
854
- buildGeminiHistory(content, { ...options, role: user }),
855
- ...options.toolsResult.slice(0, options.toolsResult.length - 1)
856
- ] : []
857
- );
846
+ [history, prompt] = options.toolsResult?.length ? [
847
+ [
848
+ ..._history,
849
+ buildGeminiHistory(content, options),
850
+ ...options.toolsResult.slice(0, options.toolsResult.length - 1),
851
+ ],
852
+ options.toolsResult[options.toolsResult?.length - 1].parts,
853
+ ] : [
854
+ [..._history],
855
+ buildGeminiMessage(content, options),
856
+ ];
858
857
  break;
859
858
  }
860
859
  };
861
860
  msgBuilder();
862
- await trimPrompt(() => [systemPrompt, history, content], () => {
861
+ await trimPrompt(() => [
862
+ systemPrompt, _history, content, options.toolsResult
863
+ ], () => {
863
864
  if (options.messages?.length) {
864
865
  options.messages?.shift();
865
866
  msgBuilder();
@@ -978,11 +979,11 @@ const promptOpenAI = async (aiId, content, options = {}) => {
978
979
  const { history }
979
980
  = await buildPrompts(MODELS[options.model], content, options);
980
981
  model = MODELS[options.model];
981
- model.reasoning && !azure && !options.reasoning_effort
982
+ model?.reasoning && !azure && !options.reasoning_effort
982
983
  && (options.reasoning_effort = GPT_REASONING_EFFORT);
983
984
  const modalities = options.modalities
984
985
  || (options.audioMode ? [TEXT, AUDIO] : undefined);
985
- [options.audioMimeType, options.suffix] = [pcm16, 'pcm.wav'];
986
+ [options.audioMimeType, options.suffix] = [MIME_PCM16, 'pcm.wav'];
986
987
  const resp = await client.chat.completions.create({
987
988
  model: azure ? undefined : options.model, ...history,
988
989
  ...options.jsonMode ? { response_format: { type: JSON_OBJECT } } : {},
@@ -990,7 +991,7 @@ const promptOpenAI = async (aiId, content, options = {}) => {
990
991
  modalities, audio: options.audio || (
991
992
  modalities?.find?.(x => x === AUDIO)
992
993
  && { voice: DEFAULT_MODELS[OPENAI_VOICE], format: 'pcm16' }
993
- ), ...model.tools && !azure ? {
994
+ ), ...model?.tools && !azure ? {
994
995
  tools: options.tools ?? (await toolsOpenAI()).map(x => x.def),
995
996
  tool_choice: 'auto',
996
997
  } : {}, ...azure ? {} : { store: true }, stream: true,
@@ -1198,7 +1199,7 @@ const promptGemini = async (aiId, content, options = {}) => {
1198
1199
  event?.content?.parts?.map(x => {
1199
1200
  if (x.text) { deltaText = x.text; }
1200
1201
  else if (x.functionCall) { functionCalls.push(x); }
1201
- else if (x.inlineData?.mimeType === png) {
1202
+ else if (x.inlineData?.mimeType === MIME_PNG) {
1202
1203
  deltaImages.push(x.inlineData);
1203
1204
  images.push(x.inlineData);
1204
1205
  }
@@ -1536,6 +1537,7 @@ export {
1536
1537
  MODELS,
1537
1538
  OPENAI_VOICE,
1538
1539
  RETRIEVAL,
1540
+ TEXT_EMBEDDING_3_SMALL,
1539
1541
  analyzeSessions,
1540
1542
  buildGptTrainingCase,
1541
1543
  buildGptTrainingCases,
@@ -1553,18 +1555,10 @@ export {
1553
1555
  getSession,
1554
1556
  init,
1555
1557
  initChat,
1556
- jpeg,
1557
1558
  listFiles,
1558
1559
  listGptFineTuningEvents,
1559
1560
  listGptFineTuningJobs,
1560
1561
  listOpenAIModels,
1561
- m4a,
1562
- mp3,
1563
- mp4,
1564
- mpeg,
1565
- mpega,
1566
- mpga,
1567
- ogg,
1568
1562
  prompt,
1569
1563
  promptAnthropic,
1570
1564
  promptGemini,
@@ -1572,10 +1566,7 @@ export {
1572
1566
  resetSession,
1573
1567
  tailGptFineTuningEvents,
1574
1568
  talk,
1575
- TEXT_EMBEDDING_3_SMALL,
1576
1569
  trimPrompt,
1577
1570
  uploadFile,
1578
1571
  uploadFileForFineTuning,
1579
- wav,
1580
- webm,
1581
1572
  };
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.60",
4
+ "version": "1999.1.62",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/utilitas",
7
7
  "main": "index.mjs",
package/lib/storage.mjs CHANGED
@@ -27,10 +27,19 @@ const sanitizeFilename = (s, r) => s.replace(/[\/?<>\\:*|"]/g, r || '_').trim();
27
27
  const [
28
28
  NULL, BASE64, BUFFER, FILE, STREAM, TEXT, _JSON, encoding, BINARY, BLOB,
29
29
  DATAURL, mode, dirMode, MIME_TEXT, MIME_BINARY, MIME_JSON, MIME_PNG,
30
+ MIME_JPEG, MIME_MOV, MIME_MPEG, MIME_MP4, MIME_MPG, MIME_AVI, MIME_WMV,
31
+ MIME_MPEGPS, MIME_FLV, MIME_GIF, MIME_WEBP, MIME_PDF, MIME_AAC, MIME_FLAC,
32
+ MIME_MP3, MIME_MPEGA, MIME_M4A, MIME_MPGA, MIME_OPUS, MIME_PCM, MIME_WAV,
33
+ MIME_WEBM, MIME_TGPP, MIME_PCM16, MIME_OGG,
30
34
  ] = [
31
35
  'NULL', 'BASE64', 'BUFFER', 'FILE', 'STREAM', 'TEXT', 'JSON', 'utf8',
32
36
  'binary', 'BLOB', 'DATAURL', '0644', '0755', 'text/plain',
33
37
  'application/octet-stream', 'application/json', 'image/png',
38
+ 'image/jpeg', 'video/mov', 'video/mpeg', 'video/mp4', 'video/mpg',
39
+ 'video/avi', 'video/wmv', 'video/mpegps', 'video/x-flv', 'image/gif',
40
+ 'image/webp', 'application/pdf', 'audio/aac', 'audio/flac', 'audio/mp3',
41
+ 'audio/mpeg', 'audio/m4a', 'audio/mpga', 'audio/opus', 'audio/pcm',
42
+ 'audio/wav', 'audio/webm', 'video/3gpp', 'audio/x-wav', 'audio/ogg',
34
43
  ];
35
44
 
36
45
  const [encodeBase64, encodeBinary, encodeNull]
@@ -473,10 +482,35 @@ export {
473
482
  BUFFER,
474
483
  DATAURL,
475
484
  FILE,
485
+ MIME_AAC,
486
+ MIME_AVI,
476
487
  MIME_BINARY,
488
+ MIME_FLAC,
489
+ MIME_FLV,
490
+ MIME_GIF,
491
+ MIME_JPEG,
477
492
  MIME_JSON,
493
+ MIME_M4A,
494
+ MIME_MOV,
495
+ MIME_MP3,
496
+ MIME_MP4,
497
+ MIME_MPEG,
498
+ MIME_MPEGA,
499
+ MIME_MPEGPS,
500
+ MIME_MPG,
501
+ MIME_MPGA,
502
+ MIME_OGG,
503
+ MIME_OPUS,
504
+ MIME_PCM,
505
+ MIME_PCM16,
506
+ MIME_PDF,
478
507
  MIME_PNG,
479
508
  MIME_TEXT,
509
+ MIME_TGPP,
510
+ MIME_WAV,
511
+ MIME_WEBM,
512
+ MIME_WEBP,
513
+ MIME_WMV,
480
514
  STREAM,
481
515
  analyzeFile,
482
516
  assertPath,
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.60",
4
+ "version": "1999.1.62",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/utilitas",
7
7
  "main": "index.mjs",