utilitas 1998.2.34 → 1998.2.36

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,8 +38,7 @@ You may be provided with some tools(functions) to help you gather information an
38
38
  - Use tools when appropriate to enhance efficiency and accuracy, and to gain the contextual knowledge needed to solve problems.
39
39
  - Be sure to use tools only when necessary and avoid overuse, you can answer questions based on your own understanding.
40
40
  - When the tools are not suitable and you have to answer questions based on your understanding, please do not mention any tool-related information in your response.
41
- - 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.
42
- - If the tool fails, do not retry unless requested by the user.`;
41
+ - 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.`;
43
42
 
44
43
  const _NEED = [
45
44
  '@anthropic-ai/sdk', '@anthropic-ai/vertex-sdk', '@google/generative-ai',
@@ -55,6 +54,7 @@ const [
55
54
  CLAUDE_35_HAIKU, CLOUD_37_SONNET, AUDIO, WAV, CHATGPT_MINI, ATTACHMENTS,
56
55
  CHAT, OPENAI_VOICE, MEDIUM, LOW, HIGH, GPT_REASONING_EFFORT, THINK,
57
56
  THINK_STR, THINK_END, AZURE, TOOLS_STR, TOOLS_END, TOOLS, TEXT, THINKING,
57
+ OK,
58
58
  ] = [
59
59
  'OPENAI', 'GEMINI', 'CHATGPT', 'OPENAI_EMBEDDING', 'GEMINI_EMEDDING',
60
60
  'OPENAI_TRAINING', 'OLLAMA', 'CLAUDE', 'gpt-4o-mini', 'gpt-4o', 'o1',
@@ -66,7 +66,7 @@ const [
66
66
  'claude-3-7-sonnet@20250219', 'audio', 'wav', 'CHATGPT_MINI',
67
67
  '[ATTACHMENTS]', 'CHAT', 'OPENAI_VOICE', 'medium', 'low', 'high',
68
68
  'medium', 'think', '<think>', '</think>', 'AZURE', '<tools>',
69
- '</tools>', 'tools', 'text', 'thinking',
69
+ '</tools>', 'tools', 'text', 'thinking', 'OK',
70
70
  ];
71
71
 
72
72
  const [
@@ -99,6 +99,7 @@ const [tokenSafeRatio, GPT_QUERY_LIMIT, minsOfDay] = [1.1, 100, 60 * 24];
99
99
  const tokenSafe = count => Math.ceil(count * tokenSafeRatio);
100
100
  const clients = {};
101
101
  const size8k = 7680 * 4320;
102
+ const MAX_TOOL_RECURSION = 10;
102
103
  const LOG = { log: true };
103
104
  const OPENAI_BASE_URL = 'https://api.openai.com/v1';
104
105
  const sessionType = `${name.toUpperCase()}-SESSION`;
@@ -111,6 +112,7 @@ const log = (cnt, opt) => _log(cnt, import.meta.url, { time: 1, ...opt || {} });
111
112
  const CONTENT_IS_REQUIRED = 'Content is required.';
112
113
  const assertContent = content => assert(content.length, CONTENT_IS_REQUIRED);
113
114
  const packThink = thk => thk ? [`${THINK_STR}\n${thk}\n${THINK_END}`] : [];
115
+ const countToolCalls = r => r?.split('\n').filter(x => x === TOOLS_STR).length;
114
116
 
115
117
  const DEFAULT_MODELS = {
116
118
  [CHATGPT_MINI]: GPT_4O_MINI,
@@ -412,6 +414,7 @@ const tools = [
412
414
  }
413
415
  },
414
416
  func: async () => new Date().toLocaleString(),
417
+ showRes: true,
415
418
  },
416
419
  {
417
420
  def: {
@@ -429,6 +432,7 @@ const tools = [
429
432
  }
430
433
  },
431
434
  func: async args => (await distill(args?.url))?.summary,
435
+ showReq: true,
432
436
  },
433
437
  {
434
438
  def: {
@@ -446,6 +450,7 @@ const tools = [
446
450
  }
447
451
  },
448
452
  func: async args => await search(args?.keyword),
453
+ showReq: true,
449
454
  },
450
455
  ];
451
456
 
@@ -738,14 +743,18 @@ const packResp = async (resp, options) => {
738
743
  };
739
744
  };
740
745
 
746
+ const streamResp = async (resp, options) => {
747
+ const msg = await packGptResp(resp, { ...options, processing: true });
748
+ return options?.stream && (msg?.text || msg?.audio?.length)
749
+ && await ignoreErrFunc(async () => await options.stream(msg), LOG);
750
+ };
751
+
741
752
  const packGptResp = async (resp, options) => {
742
753
  // simple mode is not recommended for streaming responses
743
- let text = resp?.choices?.[0]?.message?.content // ChatGPT
744
- || resp?.choices?.[0]?.message?.audio?.transcript // ChatGPT audio mode
754
+ let text = resp.text // ChatGPT / Claude
745
755
  || (Function.isFunction(resp?.text) ? resp.text() : resp?.text) // Gemini
746
- || resp?.content?.find(x => x.type === TEXT)?.text // Claude
747
756
  || resp?.message?.content || ''; // Ollama
748
- const audio = resp?.choices?.[0]?.message?.audio?.data; // ChatGPT audio mode
757
+ const audio = resp?.message?.audio?.data; // ChatGPT audio mode
749
758
  if (options?.raw) { return resp; }
750
759
  else if (options?.simple && options?.jsonMode) { return parseJson(text); }
751
760
  else if (options?.simple && options?.audioMode) { return audio; }
@@ -764,30 +773,29 @@ const packGptResp = async (resp, options) => {
764
773
  };
765
774
 
766
775
  const handleToolsCall = async (msg, options) => {
767
- let [content, preRes, input, packMsg, toolsResponse] = [
768
- [], [], [], null,
769
- options?.currentResponse ? `${options?.currentResponse}\n` : '',
776
+ let [content, preRes, input, packMsg, toolsResponse, responded] = [
777
+ [], [], [], null, options?.result ? options?.result.trim() : '', false
770
778
  ];
771
- const resp = async (msg) => {
772
- toolsResponse = [...toolsResponse ? [toolsResponse] : [], msg].join('\n');
773
- await ignoreErrFunc(async () => await options?.stream?.(await packGptResp({
774
- choices: [{ message: { content: options?.delta ? msg : toolsResponse } }]
775
- }, { ...options || {}, processing: true })), LOG);
779
+ const resp = async m => {
780
+ m = `\n${m}`;
781
+ responded || (m = `\n\n${TOOLS_STR}${m}`);
782
+ responded = true;
783
+ toolsResponse = (toolsResponse + m).trim();
784
+ await streamResp({ text: options?.delta ? m : toolsResponse }, options);
776
785
  };
777
- if (msg?.tool_calls?.length) {
778
- await resp(TOOLS_STR);
786
+ const calls = msg.tool_calls || msg.content || [];
787
+ if (calls.length) {
779
788
  switch (options?.flavor) {
780
- case CLAUDE: preRes.push({ role: assistant, content: msg?.tool_calls }); break;
789
+ case CLAUDE: preRes.push(msg); break;
781
790
  case GEMINI: preRes.push({ role: MODEL, parts: msg?.tool_calls.map(x => ({ functionCall: x })) }); break;
782
- case CHATGPT: default: preRes.push({ role: assistant, ...msg }); break;
791
+ case CHATGPT: default: preRes.push(msg); break;
783
792
  }
784
- for (const fn of msg.tool_calls) {
793
+ for (const fn of calls) {
785
794
  switch (options?.flavor) {
786
795
  case CLAUDE:
787
796
  input = fn.input = String.isString(fn?.input) ? parseJson(fn.input) : fn?.input;
788
- packMsg = (c, is_error) => ({
789
- type: 'tool_result', tool_use_id: fn.id,
790
- content: JSON.stringify(c), is_error,
797
+ packMsg = (content, is_error) => ({
798
+ type: 'tool_result', tool_use_id: fn.id, content, is_error,
791
799
  });
792
800
  break;
793
801
  case GEMINI:
@@ -795,8 +803,7 @@ const handleToolsCall = async (msg, options) => {
795
803
  packMsg = (t, e) => ({
796
804
  functionResponse: {
797
805
  name: fn.name, response: {
798
- name: fn.name,
799
- content: e ? `[Error] ${t}` : JSON.stringify(t),
806
+ name: fn.name, content: e ? `[Error] ${t}` : t,
800
807
  }
801
808
  }
802
809
  });
@@ -810,34 +817,45 @@ const handleToolsCall = async (msg, options) => {
810
817
  break;
811
818
  }
812
819
  const name = fn?.function?.name || fn?.name;
820
+ if (!name) { continue; }
813
821
  await resp(`\nName: ${name}`);
814
822
  const f = tools.find(x => insensitiveCompare(
815
823
  x.def?.function?.name || x?.def?.name, name
816
824
  ));
817
825
  if (!f?.func) {
818
- content.push(packMsg(`Function call failed, invalid function name: ${name}`, true));
826
+ const rt = `Failed: invalid function name \`${name}\``;
827
+ content.push(packMsg(rt, true));
828
+ await resp(rt);
819
829
  continue;
820
830
  }
821
831
  const description = f.def?.function?.description || f.def?.description;
822
832
  description && await resp(`Description: ${description}`);
833
+ f.showReq && isSet(input, true) && Object.keys(input).length
834
+ && await resp(`Input: ${JSON.stringify(input)}`);
823
835
  try {
824
- content.push(packMsg((await f?.func(input)) ?? 'OK'));
825
- await resp(`Status: OK`);
836
+ const output = JSON.stringify((await f?.func(input)) ?? OK);
837
+ content.push(packMsg(output));
838
+ await resp(f.showRes ? `Output: ${output}` : `Status: OK`);
826
839
  } catch (err) {
827
- content.push(packMsg(`Function call failed: ${err.message}`, true));
828
- await resp(`Failed: ${err.message}`);
829
- log(`Function call failed: ${err.message}`);
840
+ const rt = `Failed: ${err.message}`;
841
+ content.push(packMsg(rt, true));
842
+ await resp(rt);
843
+ log(rt);
830
844
  }
831
845
  }
832
846
  switch (options?.flavor) {
833
- case CLAUDE: content = [{ role: user, content }]; break;
847
+ case CLAUDE: content = content.length ? [{ role: user, content }] : []; break;
834
848
  case GEMINI: content = [{ role: user, parts: content }]; break;
835
849
  }
836
- await resp(`\n${TOOLS_END}`);
850
+ responded && await resp(`\n${TOOLS_END}`);
837
851
  }
838
- return { toolsResult: [...preRes, ...content], toolsResponse };
852
+ return { toolsResult: [...content.length ? preRes : [], ...content], toolsResponse };
839
853
  };
840
854
 
855
+ const mergeMsgs = (resp, calls) => [resp, ...calls.length ? [
856
+ `⚠️ Tools recursion limit reached: ${MAX_TOOL_RECURSION}`
857
+ ] : []].map(x => x.trim()).join('\n\n');
858
+
841
859
  const promptChatGPT = async (content, options = {}) => {
842
860
  const { client } = await getOpenAIClient(options);
843
861
  // https://github.com/openai/openai-node?tab=readme-ov-file#streaming-responses
@@ -864,81 +882,63 @@ const promptChatGPT = async (content, options = {}) => {
864
882
  assert(!(
865
883
  options?.reasoning && !MODELS[options.model]?.reasoning
866
884
  ), `This model does not support reasoning: ${options.model}`);
867
- let format;
868
- [format, options.audioMimeType, options.suffix]
869
- = options?.stream ? ['pcm16', pcm16, 'pcm.wav'] : [WAV, wav, WAV];
870
- let [resp, resultText, resultAudio, chunk, resultTools] = [
871
- await client.chat.completions.create({
872
- modalities, audio: options?.audio || (
873
- modalities?.find?.(x => x === AUDIO) && {
874
- voice: DEFAULT_MODELS[OPENAI_VOICE], format
875
- }
876
- ), ...messages([
877
- ...options?.messages || [], message,
878
- ...options?.toolsResult || [],
879
- ]), ...MODELS[options.model]?.tools ? {
880
- tools: options?.tools ?? tools.map(x => x.def),
881
- } : {}, ...options?.jsonMode ? {
882
- response_format: { type: JSON_OBJECT }
883
- } : {}, model: options.model, stream: !!options?.stream,
884
- store: true, tool_choice: 'auto',
885
- }), options?.toolsResponse ? `${options?.toolsResponse}\n\n` : '',
886
- Buffer.alloc(0), null, [],
887
- ];
888
- if (options?.stream) {
889
- for await (chunk of resp) {
890
- const deltaText = chunk.choices[0]?.delta?.content
891
- || chunk.choices[0]?.delta?.audio?.transcript || '';
892
- const deltaAudio = chunk.choices[0]?.delta?.audio?.data ? await convert(
893
- chunk.choices[0].delta.audio.data, { input: BASE64, expected: BUFFER }
894
- ) : Buffer.alloc(0);
895
- const deltaFunc = chunk.choices[0]?.delta?.tool_calls || [];
896
- for (const x in deltaFunc) {
897
- let curFunc = resultTools.find(z => z.index === deltaFunc[x].index);
898
- curFunc || (resultTools.push(curFunc = {}));
899
- isSet(deltaFunc[x].index, true) && (curFunc.index = deltaFunc[x].index);
900
- deltaFunc[x].id && (curFunc.id = deltaFunc[x].id);
901
- deltaFunc[x].type && (curFunc.type = deltaFunc[x].type);
902
- curFunc.function || (curFunc.function = { name: '', arguments: '' });
903
- if (deltaFunc[x].function) {
904
- deltaFunc[x].function.name && (curFunc.function.name += deltaFunc[x].function.name);
905
- deltaFunc[x].function.arguments && (curFunc.function.arguments += deltaFunc[x].function.arguments);
906
- }
907
- }
908
- if (deltaText === '' && !deltaAudio.length) { continue; }
909
- resultText += deltaText;
910
- resultAudio = Buffer.concat([resultAudio, deltaAudio]);
911
- const respAudio = options?.delta ? deltaAudio : resultAudio;
912
- chunk.choices[0].message = {
913
- content: options?.delta ? deltaText : resultText,
914
- ...respAudio.length ? { audio: { data: respAudio } } : {},
915
- };
916
- await ignoreErrFunc(async () => await options?.stream?.(
917
- await packGptResp(chunk, { ...options || {}, processing: true })
918
- ), LOG);
885
+ [options.audioMimeType, options.suffix] = [pcm16, 'pcm.wav'];
886
+ let [result, resultAudio, event, resultTools, responded]
887
+ = [options?.result ?? '', Buffer.alloc(0), null, [], false];
888
+ const resp = await client.chat.completions.create({
889
+ modalities, audio: options?.audio || (
890
+ modalities?.find?.(x => x === AUDIO)
891
+ && { voice: DEFAULT_MODELS[OPENAI_VOICE], format: 'pcm16' }
892
+ ), ...messages([
893
+ ...options?.messages || [], message, ...options?.toolsResult || [],
894
+ ]), ...MODELS[options.model]?.tools ? {
895
+ tools: options?.tools ?? tools.map(x => x.def),
896
+ } : {}, ...options?.jsonMode ? {
897
+ response_format: { type: JSON_OBJECT }
898
+ } : {}, model: options.model, stream: true,
899
+ store: true, tool_choice: 'auto',
900
+ });
901
+ for await (event of resp) {
902
+ event = event?.choices?.[0] || {};
903
+ const delta = event.delta || {};
904
+ let deltaText = delta.content || delta.audio?.transcript || '';
905
+ const deltaAudio = delta.audio?.data ? await convert(
906
+ delta.audio.data, { input: BASE64, expected: BUFFER }
907
+ ) : Buffer.alloc(0);
908
+ for (const x of delta.tool_calls || []) {
909
+ let curFunc = resultTools.find(y => y.index === x.index);
910
+ curFunc || (resultTools.push(curFunc = {}));
911
+ isSet(x.index, true) && (curFunc.index = x.index);
912
+ x.id && (curFunc.id = x.id);
913
+ x.type && (curFunc.type = x.type);
914
+ curFunc.function || (curFunc.function = { name: '', arguments: '' });
915
+ x?.function?.name && (curFunc.function.name += x.function.name);
916
+ x?.function?.arguments && (curFunc.function.arguments += x.function.arguments);
919
917
  }
920
- chunk.choices?.[0] || (chunk.choices = [{}]); // handle empty choices for Azure APIs
921
- chunk.choices[0].message = {
922
- content: resultText, tool_calls: resultTools,
923
- ...resultAudio.length ? { audio: { data: resultAudio } } : {},
924
- };
925
- resp = chunk;
918
+ deltaText && (responded = responded || (deltaText = `\n\n${deltaText}`));
919
+ result += deltaText;
920
+ resultAudio = Buffer.concat([resultAudio, deltaAudio]);
921
+ const respAudio = options?.delta ? deltaAudio : resultAudio;
922
+ await streamResp({
923
+ text: options?.delta ? deltaText : result,
924
+ ...respAudio.length ? { audio: { data: respAudio } } : {},
925
+ }, options);
926
926
  }
927
+ event = {
928
+ role: assistant, text: result, tool_calls: resultTools,
929
+ ...resultAudio.length ? { audio: { data: resultAudio } } : {},
930
+ };
927
931
  const { toolsResult, toolsResponse }
928
- = await handleToolsCall(resp?.choices?.[0]?.message, options);
929
- options?.toolsResponse && !options?.stream && (
930
- resp.choices[0].message.content = [
931
- options?.toolsResponse, resp.choices[0].message.content,
932
- ].join('\n\n')
933
- );
934
- return await (toolsResult.length && !options?.toolsResult ? promptChatGPT(
935
- content, { ...options || {}, toolsResult, toolsResponse }
936
- ) : packGptResp(resp, options));
932
+ = await handleToolsCall(event, { ...options, result });
933
+ if (toolsResult.length && countToolCalls(toolsResponse) < MAX_TOOL_RECURSION) {
934
+ return promptChatGPT(content, { ...options, toolsResult, result: toolsResponse });
935
+ }
936
+ event.text = mergeMsgs(toolsResponse, toolsResult);
937
+ return await packGptResp(event, options);
937
938
  };
938
939
 
939
- const promptAzure = async (content, options = {}) => await promptChatGPT(
940
- content, { ...options, provider: AZURE }
941
- );
940
+ const promptAzure = async (content, options = {}) =>
941
+ await promptChatGPT(content, { ...options, provider: AZURE });
942
942
 
943
943
  const promptOllama = async (content, options = {}) => {
944
944
  const { client, model } = await getOllamaClient(options);
@@ -966,13 +966,13 @@ const promptOllama = async (content, options = {}) => {
966
966
  const promptClaude = async (content, options = {}) => {
967
967
  const { client } = await getClaudeClient(options);
968
968
  options.model = options?.model || DEFAULT_MODELS[CLAUDE];
969
- const reasoning = options?.reasoning ?? MODELS[options.model]?.reasoning;
970
969
  const resp = await client.messages.create({
971
970
  model: options.model, max_tokens: MODELS[options.model].maxOutputTokens,
972
971
  messages: [
973
972
  ...options?.messages || [], buildClaudeMessage(content, options),
974
973
  ...options?.toolsResult || [],
975
- ], stream: !!options?.stream, ...reasoning ? {
974
+ ], stream: true,
975
+ ...options?.reasoning ?? MODELS[options.model]?.reasoning ? {
976
976
  thinking: options?.thinking || { type: 'enabled', budget_tokens: 1024 },
977
977
  } : {}, // https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking
978
978
  ...MODELS[options.model]?.tools ? {
@@ -980,68 +980,42 @@ const promptClaude = async (content, options = {}) => {
980
980
  tool_choice: { type: 'auto' },
981
981
  } : {},
982
982
  });
983
- let [event, txtResult, thinking, signature, result, thinkEnd, tool_calls]
984
- = [null, '', '', '', options?.toolsResponse || '', '', []];
985
- if (options?.stream) {
986
- for await (event of resp) {
987
- let [thkDelta, txtDelta] = [
988
- event?.content_block?.thinking || event?.delta?.thinking || '',
989
- event?.content_block?.text || event?.delta?.text || '',
990
- ];
991
- txtResult += txtDelta;
992
- thinking += thkDelta;
993
- signature = signature || event?.content_block?.signature || event?.delta?.signature || '';
994
- if (reasoning) {
995
- thkDelta && (thkDelta === thinking)
996
- && (thkDelta = `${THINK_STR}\n${thkDelta}`);
997
- thinking && txtDelta && !thinkEnd
998
- && (thinkEnd = thkDelta = `${thkDelta}\n${THINK_END}\n\n`);
999
- }
1000
- if (event?.content_block?.type === 'tool_use') {
1001
- tool_calls.push({ ...event?.content_block, input: '' });
1002
- } else if (event?.delta?.partial_json) {
1003
- tool_calls[tool_calls.length - 1].input += event?.delta?.partial_json;
1004
- }
1005
- const delta = thkDelta + txtDelta;
1006
- if (delta === '') { continue; }
1007
- result += delta;
1008
- event.content = [{ type: TEXT, text: options?.delta ? delta : result }];
1009
- await ignoreErrFunc(async () => await options.stream(
1010
- await packGptResp(event, { ...options, processing: true })
1011
- ), LOG);
983
+ let [event, text, thinking, signature, result, thinkEnd, tool_use]
984
+ = [null, '', '', '', options?.result ?? '', '', []];
985
+ for await (const chunk of resp) {
986
+ event = chunk?.content_block || chunk?.delta || {};
987
+ let [thkDelta, txtDelta] = [event.thinking || '', event.text || ''];
988
+ text += txtDelta;
989
+ thinking += thkDelta;
990
+ signature = signature || event?.signature || '';
991
+ thkDelta && thkDelta === thinking
992
+ && (thkDelta = `${THINK_STR}\n${thkDelta}`);
993
+ thinking && txtDelta && !thinkEnd
994
+ && (thinkEnd = thkDelta = `${thkDelta}\n${THINK_END}\n\n`);
995
+ if (event?.type === 'tool_use') {
996
+ tool_use.push({ ...event, input: '' });
997
+ } else if (event.partial_json) {
998
+ tool_use[tool_use.length - 1].input += event.partial_json;
1012
999
  }
1013
- event.content = [{
1014
- type: TEXT, text: tool_calls.length ? txtResult : result,
1015
- }];
1016
- tool_calls.length && thinking
1017
- && event.content.unshift({ type: THINKING, thinking, signature });
1018
- } else {
1019
- event = resp;
1020
- tool_calls = resp?.content?.filter?.(x => x.type === 'tool_use') || [];
1000
+ txtDelta = thkDelta + txtDelta;
1001
+ result += txtDelta;
1002
+ await streamResp({ text: options?.delta ? txtDelta : result }, options);
1021
1003
  }
1004
+ event = {
1005
+ role: assistant, content: [
1006
+ ...thinking ? [{ type: THINKING, thinking, signature }] : [],
1007
+ ...text ? [{ type: TEXT, text }] : [], ...tool_use,
1008
+ ]
1009
+ };
1022
1010
  const { toolsResult, toolsResponse } = await handleToolsCall(
1023
- { tool_calls }, { ...options, currentResponse: result, flavor: CLAUDE },
1011
+ event, { ...options, result, flavor: CLAUDE },
1024
1012
  );
1025
- if (toolsResult.length && !options?.toolsResult) {
1026
- toolsResult[0].content.unshift(
1027
- ...event?.content.filter(x => x?.type !== 'tool_use')
1028
- );
1013
+ if (tool_use.length && countToolCalls(toolsResponse) < MAX_TOOL_RECURSION) {
1029
1014
  return await promptClaude(content, {
1030
- ...options, toolsResult, toolsResponse,
1015
+ ...options, toolsResult: [...options?.toolsResult || [], ...toolsResult], result: toolsResponse,
1031
1016
  });
1032
- } else {
1033
- const textPart = event.content.find(x => x.type == TEXT);
1034
- const thinkPart = event.content.find(x => x.type == THINKING);
1035
- const prvThink = options?.toolsResult?.find(
1036
- x => x?.content?.find(y => y?.type === THINKING)
1037
- )?.content?.find(x => x?.type === THINKING);
1038
- textPart.text = [
1039
- ...packThink(options?.stream ? null : prvThink?.thinking),
1040
- ...packThink(options?.stream ? null : thinkPart?.thinking),
1041
- ...options?.toolsResponse ? [options?.toolsResponse] : [],
1042
- textPart.text,
1043
- ].join('\n\n');
1044
- } return packGptResp(event, options);
1017
+ }
1018
+ return packGptResp({ text: mergeMsgs(toolsResponse, tool_use) }, options);
1045
1019
  };
1046
1020
 
1047
1021
  const uploadFile = async (input, options) => {
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": "1998.2.34",
4
+ "version": "1998.2.36",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/utilitas",
7
7
  "main": "index.mjs",
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": "1998.2.34",
4
+ "version": "1998.2.36",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/utilitas",
7
7
  "main": "index.mjs",