utilitas 1998.2.36 → 1998.2.38
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/dist/utilitas.lite.mjs +1 -1
- package/dist/utilitas.lite.mjs.map +1 -1
- package/lib/alan.mjs +66 -63
- package/lib/manifest.mjs +1 -1
- package/lib/shot.mjs +21 -58
- package/package.json +1 -1
package/lib/alan.mjs
CHANGED
|
@@ -54,7 +54,7 @@ const [
|
|
|
54
54
|
CLAUDE_35_HAIKU, CLOUD_37_SONNET, AUDIO, WAV, CHATGPT_MINI, ATTACHMENTS,
|
|
55
55
|
CHAT, OPENAI_VOICE, MEDIUM, LOW, HIGH, GPT_REASONING_EFFORT, THINK,
|
|
56
56
|
THINK_STR, THINK_END, AZURE, TOOLS_STR, TOOLS_END, TOOLS, TEXT, THINKING,
|
|
57
|
-
OK,
|
|
57
|
+
OK, FUNC,
|
|
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', 'OK',
|
|
69
|
+
'</tools>', 'tools', 'text', 'thinking', 'OK', 'function',
|
|
70
70
|
];
|
|
71
71
|
|
|
72
72
|
const [
|
|
@@ -90,7 +90,7 @@ const [tool, provider, messages, text] = [
|
|
|
90
90
|
const [name, user, system, assistant, MODEL, JSON_OBJECT, TOOL, silent]
|
|
91
91
|
= ['Alan', 'user', 'system', 'assistant', 'model', 'json_object', 'tool', true];
|
|
92
92
|
const [CODE_INTERPRETER, RETRIEVAL, FUNCTION]
|
|
93
|
-
= ['code_interpreter', 'retrieval',
|
|
93
|
+
= ['code_interpreter', 'retrieval', FUNC].map(tool);
|
|
94
94
|
const [NOT_INIT, INVALID_FILE]
|
|
95
95
|
= ['AI engine has not been initialized.', 'Invalid file data.'];
|
|
96
96
|
const chatConfig
|
|
@@ -442,7 +442,10 @@ const tools = [
|
|
|
442
442
|
parameters: {
|
|
443
443
|
type: 'object',
|
|
444
444
|
properties: {
|
|
445
|
-
keyword: { type: 'string', description: 'The keyword you need to search for.' }
|
|
445
|
+
keyword: { type: 'string', description: 'The keyword you need to search for.' },
|
|
446
|
+
num: { type: 'integer', description: 'The number of search results you need, default `10`.' },
|
|
447
|
+
start: { type: 'integer', description: 'The start index of the search results, default `1`.' },
|
|
448
|
+
image: { type: 'boolean', description: 'Whether to search for images, default `false`.' },
|
|
446
449
|
},
|
|
447
450
|
required: ['keyword'],
|
|
448
451
|
additionalProperties: false
|
|
@@ -751,8 +754,7 @@ const streamResp = async (resp, options) => {
|
|
|
751
754
|
|
|
752
755
|
const packGptResp = async (resp, options) => {
|
|
753
756
|
// simple mode is not recommended for streaming responses
|
|
754
|
-
let text = resp.text // ChatGPT / Claude
|
|
755
|
-
|| (Function.isFunction(resp?.text) ? resp.text() : resp?.text) // Gemini
|
|
757
|
+
let text = resp.text // ChatGPT / Claude / Gemini
|
|
756
758
|
|| resp?.message?.content || ''; // Ollama
|
|
757
759
|
const audio = resp?.message?.audio?.data; // ChatGPT audio mode
|
|
758
760
|
if (options?.raw) { return resp; }
|
|
@@ -783,27 +785,30 @@ const handleToolsCall = async (msg, options) => {
|
|
|
783
785
|
toolsResponse = (toolsResponse + m).trim();
|
|
784
786
|
await streamResp({ text: options?.delta ? m : toolsResponse }, options);
|
|
785
787
|
};
|
|
786
|
-
const calls = msg.tool_calls || msg.content || [];
|
|
788
|
+
const calls = msg.tool_calls || msg.content || msg.parts || [];
|
|
787
789
|
if (calls.length) {
|
|
788
790
|
switch (options?.flavor) {
|
|
789
791
|
case CLAUDE: preRes.push(msg); break;
|
|
790
|
-
case GEMINI: preRes.push(
|
|
792
|
+
case GEMINI: preRes.push(msg); break;
|
|
791
793
|
case CHATGPT: default: preRes.push(msg); break;
|
|
792
794
|
}
|
|
793
795
|
for (const fn of calls) {
|
|
794
796
|
switch (options?.flavor) {
|
|
795
797
|
case CLAUDE:
|
|
796
|
-
input = fn.input = String.isString(fn?.input)
|
|
798
|
+
input = fn.input = String.isString(fn?.input)
|
|
799
|
+
? parseJson(fn.input) : fn?.input;
|
|
797
800
|
packMsg = (content, is_error) => ({
|
|
798
|
-
type: 'tool_result', tool_use_id: fn.id,
|
|
801
|
+
type: 'tool_result', tool_use_id: fn.id,
|
|
802
|
+
content, is_error,
|
|
799
803
|
});
|
|
800
804
|
break;
|
|
801
805
|
case GEMINI:
|
|
802
|
-
input = fn
|
|
806
|
+
input = fn?.functionCall?.args;
|
|
803
807
|
packMsg = (t, e) => ({
|
|
804
808
|
functionResponse: {
|
|
805
|
-
name: fn
|
|
806
|
-
name: fn
|
|
809
|
+
name: fn?.functionCall?.name, response: {
|
|
810
|
+
name: fn?.functionCall?.name,
|
|
811
|
+
content: e ? `[Error] ${t}` : t,
|
|
807
812
|
}
|
|
808
813
|
}
|
|
809
814
|
});
|
|
@@ -816,7 +821,7 @@ const handleToolsCall = async (msg, options) => {
|
|
|
816
821
|
});
|
|
817
822
|
break;
|
|
818
823
|
}
|
|
819
|
-
const name = fn?.function?.
|
|
824
|
+
const name = (fn?.function || fn?.functionCall || fn)?.name;
|
|
820
825
|
if (!name) { continue; }
|
|
821
826
|
await resp(`\nName: ${name}`);
|
|
822
827
|
const f = tools.find(x => insensitiveCompare(
|
|
@@ -843,13 +848,18 @@ const handleToolsCall = async (msg, options) => {
|
|
|
843
848
|
log(rt);
|
|
844
849
|
}
|
|
845
850
|
}
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
851
|
+
if (content.length) {
|
|
852
|
+
switch (options?.flavor) {
|
|
853
|
+
case CLAUDE: content = [{ role: user, content }]; break;
|
|
854
|
+
case GEMINI: content = [{ role: FUNC, parts: content }]; break;
|
|
855
|
+
}
|
|
849
856
|
}
|
|
850
857
|
responded && await resp(`\n${TOOLS_END}`);
|
|
851
858
|
}
|
|
852
|
-
return {
|
|
859
|
+
return {
|
|
860
|
+
toolsResult: [...content.length ? preRes : [], ...content],
|
|
861
|
+
toolsResponse,
|
|
862
|
+
};
|
|
853
863
|
};
|
|
854
864
|
|
|
855
865
|
const mergeMsgs = (resp, calls) => [resp, ...calls.length ? [
|
|
@@ -1012,7 +1022,8 @@ const promptClaude = async (content, options = {}) => {
|
|
|
1012
1022
|
);
|
|
1013
1023
|
if (tool_use.length && countToolCalls(toolsResponse) < MAX_TOOL_RECURSION) {
|
|
1014
1024
|
return await promptClaude(content, {
|
|
1015
|
-
...options, toolsResult: [...options?.toolsResult || [],
|
|
1025
|
+
...options, toolsResult: [...options?.toolsResult || [],
|
|
1026
|
+
...toolsResult], result: toolsResponse,
|
|
1016
1027
|
});
|
|
1017
1028
|
}
|
|
1018
1029
|
return packGptResp({ text: mergeMsgs(toolsResponse, tool_use) }, options);
|
|
@@ -1078,54 +1089,46 @@ const promptGemini = async (content, options = {}) => {
|
|
|
1078
1089
|
options.model = genModel;
|
|
1079
1090
|
const chat = generative.startChat({
|
|
1080
1091
|
history: [
|
|
1081
|
-
...options?.messages && !options?.attachments?.length
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1092
|
+
...options?.messages && !options?.attachments?.length ? options.messages : [],
|
|
1093
|
+
...options?.toolsResult ? [
|
|
1094
|
+
buildGeminiMessage(content, { ...options, history: true }),
|
|
1095
|
+
...options.toolsResult.slice(0, options.toolsResult.length - 1)
|
|
1096
|
+
] : []
|
|
1086
1097
|
], ...generationConfig(options),
|
|
1087
1098
|
});
|
|
1088
|
-
const resp = await chat
|
|
1089
|
-
options?.
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
let [result, references, functionCalls]
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
references = rfc;
|
|
1106
|
-
await ignoreErrFunc(async () => await options.stream(
|
|
1107
|
-
await packGptResp({
|
|
1108
|
-
text: () => options?.delta ? delta : result, references,
|
|
1109
|
-
}, { ...options, processing: true })
|
|
1110
|
-
), LOG);
|
|
1111
|
-
}
|
|
1099
|
+
const resp = await chat.sendMessageStream(
|
|
1100
|
+
options?.toolsResult?.[options?.toolsResult?.length]?.parts
|
|
1101
|
+
|| buildGeminiMessage(content, options)
|
|
1102
|
+
);
|
|
1103
|
+
let [result, references, functionCalls, responded]
|
|
1104
|
+
= [options?.result ?? '', null, null];
|
|
1105
|
+
for await (const chunk of resp.stream) {
|
|
1106
|
+
functionCalls || (functionCalls = chunk.functionCalls);
|
|
1107
|
+
const rfc = packGeminiReferences(
|
|
1108
|
+
chunk.candidates[0]?.groundingMetadata?.groundingChunks,
|
|
1109
|
+
chunk.candidates[0]?.groundingMetadata?.groundingSupports
|
|
1110
|
+
);
|
|
1111
|
+
rfc && (references = rfc);
|
|
1112
|
+
let delta = chunk?.text?.() || '';
|
|
1113
|
+
delta && (responded = responded || (delta = `\n\n${delta}`));
|
|
1114
|
+
result += delta;
|
|
1115
|
+
await streamResp({ text: options?.delta ? delta : result }, options);
|
|
1112
1116
|
}
|
|
1113
1117
|
const _resp = await resp.response;
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
content, {
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
}, options));
|
|
1118
|
+
functionCalls = (functionCalls() || _resp.functionCalls() || []).map(x => ({ functionCall: x }));
|
|
1119
|
+
const { toolsResult, toolsResponse } = await handleToolsCall(
|
|
1120
|
+
{ role: MODEL, parts: functionCalls },
|
|
1121
|
+
{ ...options, result, flavor: GEMINI }
|
|
1122
|
+
);
|
|
1123
|
+
if (toolsResult.length && countToolCalls(toolsResponse) < MAX_TOOL_RECURSION) {
|
|
1124
|
+
return promptGemini(content, {
|
|
1125
|
+
...options || {}, toolsResult: [...options?.toolsResult || [],
|
|
1126
|
+
...toolsResult], result: toolsResponse,
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
return await packGptResp({
|
|
1130
|
+
text: mergeMsgs(toolsResponse, toolsResult), references,
|
|
1131
|
+
}, options);
|
|
1129
1132
|
};
|
|
1130
1133
|
|
|
1131
1134
|
const checkEmbeddingInput = async (input, model) => {
|
package/lib/manifest.mjs
CHANGED
package/lib/shot.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { sha256 } from './encryption.mjs';
|
|
|
5
5
|
import { distillHtml } from './web.mjs';
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
|
+
ensureInt,
|
|
8
9
|
ensureString, extract, ignoreErrFunc, inBrowser, parseJson, parseVersion,
|
|
9
10
|
throwError, which
|
|
10
11
|
} from './utilitas.mjs';
|
|
@@ -160,66 +161,28 @@ const initSearch = (options) => {
|
|
|
160
161
|
};
|
|
161
162
|
|
|
162
163
|
const search = async (query, options) => {
|
|
164
|
+
const [key, cx, min, max]
|
|
165
|
+
= [options?.apiKey || googleApiKey, options?.cx || googleCx, 1, 10];
|
|
163
166
|
assert(query, 'Query is required.');
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
assert(cx, 'CX is required.');
|
|
174
|
-
url = 'https://www.googleapis.com/customsearch/v1'
|
|
175
|
-
+ `?key=${encodeURIComponent(apiKey)}`
|
|
176
|
-
+ `&cx=${encodeURIComponent(cx)}`
|
|
177
|
-
+ `&q=${encodeURIComponent(query)}`;
|
|
178
|
-
break;
|
|
179
|
-
case DUCKDUCKGO:
|
|
180
|
-
url = 'https://api.duckduckgo.com/'
|
|
181
|
-
+ `?q=${encodeURIComponent(query)}&format=json&skip_disambig=1`;
|
|
182
|
-
parser = x => x.FirstURL ? {
|
|
183
|
-
title: x.FirstURL.replace(/^.*\/([^\/]*)$/, '$1').replace(/_/g, ' '),
|
|
184
|
-
link: x.FirstURL, snippet: x.Text,
|
|
185
|
-
image: `https://duckduckgo.com${x.Icon.URL}`, source: null,
|
|
186
|
-
} : null;
|
|
187
|
-
break;
|
|
188
|
-
default:
|
|
189
|
-
throwError(`Invalid provider: ${provider}.`);
|
|
190
|
-
}
|
|
167
|
+
assert(key, 'API key is required.');
|
|
168
|
+
assert(cx, 'CX is required.');
|
|
169
|
+
const num = ensureInt(options?.num || max, { min, max });
|
|
170
|
+
const start = ensureInt(options?.start || min, { min });
|
|
171
|
+
assert(start + num <= 100, 'Reached maximum search limit.');
|
|
172
|
+
const url = 'https://www.googleapis.com/customsearch/v1'
|
|
173
|
+
+ `?key=${encodeURIComponent(key)}&cx=${encodeURIComponent(cx)}`
|
|
174
|
+
+ `&q=${encodeURIComponent(query)}&num=${num}&start=${start}`
|
|
175
|
+
+ (options?.image ? `&searchType=image` : '');
|
|
191
176
|
const resp = await get(url, { encode: _JSON, ...options || {} });
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
image: x.pagemap?.cse_image?.[0]?.src || null,
|
|
199
|
-
}))
|
|
200
|
-
}
|
|
201
|
-
const cnt = resp?.content;
|
|
202
|
-
if (cnt?.Abstract) {
|
|
203
|
-
result.push({
|
|
204
|
-
title: cnt?.Heading + (cnt?.Entity ? ` (${cnt.Entity})` : ''),
|
|
205
|
-
link: cnt?.AbstractURL, snippet: cnt?.AbstractText,
|
|
206
|
-
image: cnt?.Image ? `https://duckduckgo.com${cnt.Image}` : null,
|
|
207
|
-
source: cnt?.AbstractSource,
|
|
208
|
-
});
|
|
209
|
-
if (cnt?.Results) {
|
|
210
|
-
result.push(...cnt.Results.map(x => ({
|
|
211
|
-
title: x.Text, link: x.FirstURL, snippet: null,
|
|
212
|
-
image: x.Icon ? `https://duckduckgo.com${x.Icon.URL}` : null,
|
|
213
|
-
source: null,
|
|
214
|
-
})));
|
|
215
|
-
}
|
|
216
|
-
} else if (cnt?.RelatedTopics?.[0] && !options?.no_recurse) {
|
|
217
|
-
result = await search(cnt.RelatedTopics[0].FirstURL.replace(
|
|
218
|
-
/^.*\/([^\/]*)$/, '$1'
|
|
219
|
-
).replace(/_/g, ' '), { ...options, no_recurse: true });
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
return result;
|
|
177
|
+
return options?.raw ? resp.content : {
|
|
178
|
+
totalResults: resp?.content?.searchInformation?.totalResults || 0,
|
|
179
|
+
startIndex: resp?.content?.queries?.request?.[0]?.startIndex || 1,
|
|
180
|
+
items: resp?.content?.items.map(x => ({
|
|
181
|
+
title: x.title, link: options?.image ? null : x.link,
|
|
182
|
+
snippet: x.snippet,
|
|
183
|
+
image: (options?.image ? x.link : x.pagemap?.cse_image?.[0]?.src) || null,
|
|
184
|
+
})),
|
|
185
|
+
};
|
|
223
186
|
};
|
|
224
187
|
|
|
225
188
|
export default get;
|