@ztimson/ai-utils 0.2.6 → 0.2.7
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/index.js +14 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +197 -196
- package/dist/index.mjs.map +1 -1
- package/dist/llm.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import { deepCopy as
|
|
1
|
+
import * as j from "node:os";
|
|
2
|
+
import { deepCopy as T, objectMap as y, JSONAttemptParse as _, findByProp as k, JSONSanitize as b, Http as M, consoleInterceptor as A, fn as q, ASet as P } from "@ztimson/utils";
|
|
3
3
|
import { Anthropic as O } from "@anthropic-ai/sdk";
|
|
4
4
|
import { Ollama as $ } from "ollama";
|
|
5
5
|
import { OpenAI as E } from "openai";
|
|
@@ -21,12 +21,12 @@ class I extends x {
|
|
|
21
21
|
toStandard(t) {
|
|
22
22
|
for (let e = 0; e < t.length; e++) {
|
|
23
23
|
const s = e;
|
|
24
|
-
typeof t[s].content != "string" && (t[s].role == "assistant" ? t[s].content.filter((
|
|
25
|
-
e++, t.splice(e, 0, { role: "tool", id:
|
|
26
|
-
}) : t[s].role == "user" && t[s].content.filter((
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
}), t[s].content = t[s].content.filter((
|
|
24
|
+
typeof t[s].content != "string" && (t[s].role == "assistant" ? t[s].content.filter((n) => n.type == "tool_use").forEach((n) => {
|
|
25
|
+
e++, t.splice(e, 0, { role: "tool", id: n.id, name: n.name, args: n.input, timestamp: Date.now() });
|
|
26
|
+
}) : t[s].role == "user" && t[s].content.filter((n) => n.type == "tool_result").forEach((n) => {
|
|
27
|
+
const i = t.find((d) => d.id == n.tool_use_id);
|
|
28
|
+
i[n.is_error ? "error" : "content"] = n.content;
|
|
29
|
+
}), t[s].content = t[s].content.filter((n) => n.type == "text").map((n) => n.text).join(`
|
|
30
30
|
|
|
31
31
|
`)), t[s].timestamp || (t[s].timestamp = Date.now());
|
|
32
32
|
}
|
|
@@ -46,76 +46,76 @@ class I extends x {
|
|
|
46
46
|
return t.map(({ timestamp: e, ...s }) => s);
|
|
47
47
|
}
|
|
48
48
|
ask(t, e = {}) {
|
|
49
|
-
const s = new AbortController(),
|
|
50
|
-
let
|
|
51
|
-
const
|
|
52
|
-
e.compress && (
|
|
53
|
-
const
|
|
49
|
+
const s = new AbortController(), n = new Promise(async (i, d) => {
|
|
50
|
+
let r = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]);
|
|
51
|
+
const l = T(r);
|
|
52
|
+
e.compress && (r = await this.ai.language.compressHistory(r, e.compress.max, e.compress.min, e));
|
|
53
|
+
const u = e.tools || this.ai.options.tools || [], c = {
|
|
54
54
|
model: e.model || this.model,
|
|
55
55
|
max_tokens: e.max_tokens || this.ai.options.max_tokens || 4096,
|
|
56
56
|
system: e.system || this.ai.options.system || "",
|
|
57
57
|
temperature: e.temperature || this.ai.options.temperature || 0.7,
|
|
58
|
-
tools:
|
|
59
|
-
name:
|
|
60
|
-
description:
|
|
58
|
+
tools: u.map((o) => ({
|
|
59
|
+
name: o.name,
|
|
60
|
+
description: o.description,
|
|
61
61
|
input_schema: {
|
|
62
62
|
type: "object",
|
|
63
|
-
properties:
|
|
64
|
-
required:
|
|
63
|
+
properties: o.args ? y(o.args, (a, f) => ({ ...f, required: void 0 })) : {},
|
|
64
|
+
required: o.args ? Object.entries(o.args).filter((a) => a[1].required).map((a) => a[0]) : []
|
|
65
65
|
},
|
|
66
66
|
fn: void 0
|
|
67
67
|
})),
|
|
68
|
-
messages:
|
|
68
|
+
messages: r,
|
|
69
69
|
stream: !!e.stream
|
|
70
70
|
};
|
|
71
|
-
let
|
|
71
|
+
let m, h = !0;
|
|
72
72
|
do {
|
|
73
|
-
if (
|
|
74
|
-
throw
|
|
73
|
+
if (m = await this.client.messages.create(c).catch((a) => {
|
|
74
|
+
throw a.message += `
|
|
75
75
|
|
|
76
76
|
Messages:
|
|
77
|
-
${JSON.stringify(
|
|
77
|
+
${JSON.stringify(r, null, 2)}`, a;
|
|
78
78
|
}), e.stream) {
|
|
79
|
-
|
|
79
|
+
h ? h = !1 : e.stream({ text: `
|
|
80
80
|
|
|
81
|
-
` }),
|
|
82
|
-
for await (const
|
|
81
|
+
` }), m.content = [];
|
|
82
|
+
for await (const a of m) {
|
|
83
83
|
if (s.signal.aborted) break;
|
|
84
|
-
if (
|
|
85
|
-
|
|
86
|
-
else if (
|
|
87
|
-
if (
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
} else
|
|
91
|
-
else if (
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
} else if (
|
|
84
|
+
if (a.type === "content_block_start")
|
|
85
|
+
a.content_block.type === "text" ? m.content.push({ type: "text", text: "" }) : a.content_block.type === "tool_use" && m.content.push({ type: "tool_use", id: a.content_block.id, name: a.content_block.name, input: "" });
|
|
86
|
+
else if (a.type === "content_block_delta")
|
|
87
|
+
if (a.delta.type === "text_delta") {
|
|
88
|
+
const f = a.delta.text;
|
|
89
|
+
m.content.at(-1).text += f, e.stream({ text: f });
|
|
90
|
+
} else a.delta.type === "input_json_delta" && (m.content.at(-1).input += a.delta.partial_json);
|
|
91
|
+
else if (a.type === "content_block_stop") {
|
|
92
|
+
const f = m.content.at(-1);
|
|
93
|
+
f.input != null && (f.input = f.input ? _(f.input, {}) : {});
|
|
94
|
+
} else if (a.type === "message_stop")
|
|
95
95
|
break;
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
-
const
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
const g =
|
|
103
|
-
if (!g) return { tool_use_id:
|
|
98
|
+
const o = m.content.filter((a) => a.type === "tool_use");
|
|
99
|
+
if (o.length && !s.signal.aborted) {
|
|
100
|
+
r.push({ role: "assistant", content: m.content }), l.push({ role: "assistant", content: m.content });
|
|
101
|
+
const a = await Promise.all(o.map(async (f) => {
|
|
102
|
+
const g = u.find(k("name", f.name));
|
|
103
|
+
if (!g) return { tool_use_id: f.id, is_error: !0, content: "Tool not found" };
|
|
104
104
|
try {
|
|
105
|
-
const w = await g.fn(
|
|
106
|
-
return { type: "tool_result", tool_use_id:
|
|
105
|
+
const w = await g.fn(f.input, this.ai);
|
|
106
|
+
return { type: "tool_result", tool_use_id: f.id, content: b(w) };
|
|
107
107
|
} catch (w) {
|
|
108
|
-
return { type: "tool_result", tool_use_id:
|
|
108
|
+
return { type: "tool_result", tool_use_id: f.id, is_error: !0, content: w?.message || w?.toString() || "Unknown" };
|
|
109
109
|
}
|
|
110
110
|
}));
|
|
111
|
-
|
|
111
|
+
r.push({ role: "user", content: a }), c.messages = r;
|
|
112
112
|
}
|
|
113
|
-
} while (!s.signal.aborted &&
|
|
114
|
-
e.stream && e.stream({ done: !0 }),
|
|
113
|
+
} while (!s.signal.aborted && m.content.some((o) => o.type === "tool_use"));
|
|
114
|
+
e.stream && e.stream({ done: !0 }), i(this.toStandard([...r, { role: "assistant", content: m.content.filter((o) => o.type == "text").map((o) => o.text).join(`
|
|
115
115
|
|
|
116
116
|
`) }]));
|
|
117
117
|
});
|
|
118
|
-
return Object.assign(
|
|
118
|
+
return Object.assign(n, { abort: () => s.abort() });
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
class z extends x {
|
|
@@ -137,69 +137,69 @@ class z extends x {
|
|
|
137
137
|
}
|
|
138
138
|
fromStandard(t) {
|
|
139
139
|
return t.map((e) => {
|
|
140
|
-
const { timestamp: s, ...
|
|
141
|
-
return e.role != "tool" ?
|
|
140
|
+
const { timestamp: s, ...n } = e;
|
|
141
|
+
return e.role != "tool" ? n : { role: "tool", tool_name: e.name, content: e.error || e.content };
|
|
142
142
|
});
|
|
143
143
|
}
|
|
144
144
|
ask(t, e = {}) {
|
|
145
|
-
const s = new AbortController(),
|
|
146
|
-
let
|
|
147
|
-
|
|
148
|
-
const
|
|
145
|
+
const s = new AbortController(), n = new Promise(async (i, d) => {
|
|
146
|
+
let r = e.system || this.ai.options.system, l = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]);
|
|
147
|
+
l[0].roll == "system" && (r ? l.shift() : r = l.shift()), e.compress && (l = await this.ai.language.compressHistory(l, e.compress.max, e.compress.min)), e.system && l.unshift({ role: "system", content: r });
|
|
148
|
+
const u = e.tools || this.ai.options.tools || [], c = {
|
|
149
149
|
model: e.model || this.model,
|
|
150
|
-
messages:
|
|
150
|
+
messages: l,
|
|
151
151
|
stream: !!e.stream,
|
|
152
152
|
signal: s.signal,
|
|
153
153
|
options: {
|
|
154
154
|
temperature: e.temperature || this.ai.options.temperature || 0.7,
|
|
155
155
|
num_predict: e.max_tokens || this.ai.options.max_tokens || 4096
|
|
156
156
|
},
|
|
157
|
-
tools:
|
|
157
|
+
tools: u.map((o) => ({
|
|
158
158
|
type: "function",
|
|
159
159
|
function: {
|
|
160
|
-
name:
|
|
161
|
-
description:
|
|
160
|
+
name: o.name,
|
|
161
|
+
description: o.description,
|
|
162
162
|
parameters: {
|
|
163
163
|
type: "object",
|
|
164
|
-
properties:
|
|
165
|
-
required:
|
|
164
|
+
properties: o.args ? y(o.args, (a, f) => ({ ...f, required: void 0 })) : {},
|
|
165
|
+
required: o.args ? Object.entries(o.args).filter((a) => a[1].required).map((a) => a[0]) : []
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
}))
|
|
169
169
|
};
|
|
170
|
-
let
|
|
170
|
+
let m, h = !0;
|
|
171
171
|
do {
|
|
172
|
-
if (
|
|
173
|
-
throw
|
|
172
|
+
if (m = await this.client.chat(c).catch((o) => {
|
|
173
|
+
throw o.message += `
|
|
174
174
|
|
|
175
175
|
Messages:
|
|
176
|
-
${JSON.stringify(
|
|
176
|
+
${JSON.stringify(l, null, 2)}`, o;
|
|
177
177
|
}), e.stream) {
|
|
178
|
-
|
|
178
|
+
h ? h = !1 : e.stream({ text: `
|
|
179
179
|
|
|
180
|
-
` }),
|
|
181
|
-
for await (const
|
|
182
|
-
if (s.signal.aborted || (
|
|
180
|
+
` }), m.message = { role: "assistant", content: "", tool_calls: [] };
|
|
181
|
+
for await (const o of m)
|
|
182
|
+
if (s.signal.aborted || (o.message?.content && (m.message.content += o.message.content, e.stream({ text: o.message.content })), o.message?.tool_calls && (m.message.tool_calls = o.message.tool_calls), o.done)) break;
|
|
183
183
|
}
|
|
184
|
-
if (
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
const
|
|
188
|
-
if (!
|
|
189
|
-
const g = typeof
|
|
184
|
+
if (m.message?.tool_calls?.length && !s.signal.aborted) {
|
|
185
|
+
l.push(m.message);
|
|
186
|
+
const o = await Promise.all(m.message.tool_calls.map(async (a) => {
|
|
187
|
+
const f = u.find(k("name", a.function.name));
|
|
188
|
+
if (!f) return { role: "tool", tool_name: a.function.name, content: '{"error": "Tool not found"}' };
|
|
189
|
+
const g = typeof a.function.arguments == "string" ? _(a.function.arguments, {}) : a.function.arguments;
|
|
190
190
|
try {
|
|
191
|
-
const w = await
|
|
192
|
-
return { role: "tool", tool_name:
|
|
191
|
+
const w = await f.fn(g, this.ai);
|
|
192
|
+
return { role: "tool", tool_name: a.function.name, args: g, content: b(w) };
|
|
193
193
|
} catch (w) {
|
|
194
|
-
return { role: "tool", tool_name:
|
|
194
|
+
return { role: "tool", tool_name: a.function.name, args: g, content: b({ error: w?.message || w?.toString() || "Unknown" }) };
|
|
195
195
|
}
|
|
196
196
|
}));
|
|
197
|
-
|
|
197
|
+
l.push(...o), c.messages = l;
|
|
198
198
|
}
|
|
199
|
-
} while (!s.signal.aborted &&
|
|
200
|
-
e.stream && e.stream({ done: !0 }),
|
|
199
|
+
} while (!s.signal.aborted && m.message?.tool_calls?.length);
|
|
200
|
+
e.stream && e.stream({ done: !0 }), i(this.toStandard([...l, { role: "assistant", content: m.message?.content }]));
|
|
201
201
|
});
|
|
202
|
-
return Object.assign(
|
|
202
|
+
return Object.assign(n, { abort: () => s.abort() });
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
class F extends x {
|
|
@@ -211,17 +211,17 @@ class F extends x {
|
|
|
211
211
|
for (let e = 0; e < t.length; e++) {
|
|
212
212
|
const s = t[e];
|
|
213
213
|
if (s.role === "assistant" && s.tool_calls) {
|
|
214
|
-
const
|
|
214
|
+
const n = s.tool_calls.map((i) => ({
|
|
215
215
|
role: "tool",
|
|
216
|
-
id:
|
|
217
|
-
name:
|
|
218
|
-
args: _(
|
|
216
|
+
id: i.id,
|
|
217
|
+
name: i.function.name,
|
|
218
|
+
args: _(i.function.arguments, {}),
|
|
219
219
|
timestamp: s.timestamp
|
|
220
220
|
}));
|
|
221
|
-
t.splice(e, 1, ...
|
|
221
|
+
t.splice(e, 1, ...n), e += n.length - 1;
|
|
222
222
|
} else if (s.role === "tool" && s.content) {
|
|
223
|
-
const
|
|
224
|
-
|
|
223
|
+
const n = t.find((i) => s.tool_call_id == i.id);
|
|
224
|
+
n && (s.content.includes('"error":') ? n.error = s.content : n.content = s.content), t.splice(e, 1), e--;
|
|
225
225
|
}
|
|
226
226
|
t[e]?.timestamp || (t[e].timestamp = Date.now());
|
|
227
227
|
}
|
|
@@ -242,77 +242,77 @@ class F extends x {
|
|
|
242
242
|
content: s.error || s.content
|
|
243
243
|
});
|
|
244
244
|
else {
|
|
245
|
-
const { timestamp:
|
|
246
|
-
e.push(
|
|
245
|
+
const { timestamp: n, ...i } = s;
|
|
246
|
+
e.push(i);
|
|
247
247
|
}
|
|
248
248
|
return e;
|
|
249
249
|
}, []);
|
|
250
250
|
}
|
|
251
251
|
ask(t, e = {}) {
|
|
252
|
-
const s = new AbortController(),
|
|
253
|
-
let
|
|
254
|
-
e.compress && (
|
|
255
|
-
const
|
|
252
|
+
const s = new AbortController(), n = new Promise(async (i, d) => {
|
|
253
|
+
let r = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]);
|
|
254
|
+
e.compress && (r = await this.ai.language.compressHistory(r, e.compress.max, e.compress.min, e));
|
|
255
|
+
const l = e.tools || this.ai.options.tools || [], u = {
|
|
256
256
|
model: e.model || this.model,
|
|
257
|
-
messages:
|
|
257
|
+
messages: r,
|
|
258
258
|
stream: !!e.stream,
|
|
259
259
|
max_tokens: e.max_tokens || this.ai.options.max_tokens || 4096,
|
|
260
260
|
temperature: e.temperature || this.ai.options.temperature || 0.7,
|
|
261
|
-
tools:
|
|
261
|
+
tools: l.map((h) => ({
|
|
262
262
|
type: "function",
|
|
263
263
|
function: {
|
|
264
|
-
name:
|
|
265
|
-
description:
|
|
264
|
+
name: h.name,
|
|
265
|
+
description: h.description,
|
|
266
266
|
parameters: {
|
|
267
267
|
type: "object",
|
|
268
|
-
properties:
|
|
269
|
-
required:
|
|
268
|
+
properties: h.args ? y(h.args, (o, a) => ({ ...a, required: void 0 })) : {},
|
|
269
|
+
required: h.args ? Object.entries(h.args).filter((o) => o[1].required).map((o) => o[0]) : []
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
272
|
}))
|
|
273
273
|
};
|
|
274
|
-
let
|
|
274
|
+
let c, m = !0;
|
|
275
275
|
do {
|
|
276
|
-
if (
|
|
277
|
-
throw
|
|
276
|
+
if (c = await this.client.chat.completions.create(u).catch((o) => {
|
|
277
|
+
throw o.message += `
|
|
278
278
|
|
|
279
279
|
Messages:
|
|
280
|
-
${JSON.stringify(
|
|
280
|
+
${JSON.stringify(r, null, 2)}`, o;
|
|
281
281
|
}), e.stream) {
|
|
282
|
-
|
|
282
|
+
m ? m = !1 : e.stream({ text: `
|
|
283
283
|
|
|
284
|
-
` }),
|
|
285
|
-
for await (const
|
|
284
|
+
` }), c.choices = [{ message: { content: "", tool_calls: [] } }];
|
|
285
|
+
for await (const o of c) {
|
|
286
286
|
if (s.signal.aborted) break;
|
|
287
|
-
|
|
287
|
+
o.choices[0].delta.content && (c.choices[0].message.content += o.choices[0].delta.content, e.stream({ text: o.choices[0].delta.content })), o.choices[0].delta.tool_calls && (c.choices[0].message.tool_calls = o.choices[0].delta.tool_calls);
|
|
288
288
|
}
|
|
289
289
|
}
|
|
290
|
-
const
|
|
291
|
-
if (
|
|
292
|
-
|
|
293
|
-
const
|
|
294
|
-
const
|
|
295
|
-
if (!
|
|
290
|
+
const h = c.choices[0].message.tool_calls || [];
|
|
291
|
+
if (h.length && !s.signal.aborted) {
|
|
292
|
+
r.push(c.choices[0].message);
|
|
293
|
+
const o = await Promise.all(h.map(async (a) => {
|
|
294
|
+
const f = l?.find(k("name", a.function.name));
|
|
295
|
+
if (!f) return { role: "tool", tool_call_id: a.id, content: '{"error": "Tool not found"}' };
|
|
296
296
|
try {
|
|
297
|
-
const g = _(
|
|
298
|
-
return { role: "tool", tool_call_id:
|
|
297
|
+
const g = _(a.function.arguments, {}), w = await f.fn(g, this.ai);
|
|
298
|
+
return { role: "tool", tool_call_id: a.id, content: b(w) };
|
|
299
299
|
} catch (g) {
|
|
300
|
-
return { role: "tool", tool_call_id:
|
|
300
|
+
return { role: "tool", tool_call_id: a.id, content: b({ error: g?.message || g?.toString() || "Unknown" }) };
|
|
301
301
|
}
|
|
302
302
|
}));
|
|
303
|
-
|
|
303
|
+
r.push(...o), u.messages = r;
|
|
304
304
|
}
|
|
305
|
-
} while (!s.signal.aborted &&
|
|
306
|
-
e.stream && e.stream({ done: !0 }),
|
|
305
|
+
} while (!s.signal.aborted && c.choices?.[0]?.message?.tool_calls?.length);
|
|
306
|
+
e.stream && e.stream({ done: !0 }), i(this.toStandard([...r, { role: "assistant", content: c.choices[0].message.content || "" }]));
|
|
307
307
|
});
|
|
308
|
-
return Object.assign(
|
|
308
|
+
return Object.assign(n, { abort: () => s.abort() });
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
311
|
class G {
|
|
312
312
|
constructor(t) {
|
|
313
313
|
this.ai = t, this.embedWorker = new v(U(L(R(import.meta.url)), "embedder.js")), this.embedWorker.on("message", ({ id: e, embedding: s }) => {
|
|
314
|
-
const
|
|
315
|
-
|
|
314
|
+
const n = this.embedQueue.get(e);
|
|
315
|
+
n && (n.resolve(s), this.embedQueue.delete(e));
|
|
316
316
|
}), t.options.anthropic?.token && (this.providers.anthropic = new I(this.ai, t.options.anthropic.token, t.options.anthropic.model)), t.options.ollama?.host && (this.providers.ollama = new z(this.ai, t.options.ollama.host, t.options.ollama.model)), t.options.openAi?.token && (this.providers.openAi = new F(this.ai, t.options.openAi.token, t.options.openAi.model));
|
|
317
317
|
}
|
|
318
318
|
embedWorker = null;
|
|
@@ -338,56 +338,57 @@ class G {
|
|
|
338
338
|
* @param {LLMRequest} options LLM options
|
|
339
339
|
* @returns {Promise<LLMMessage[]>} New chat history will summary at index 0
|
|
340
340
|
*/
|
|
341
|
-
async compressHistory(t, e, s,
|
|
341
|
+
async compressHistory(t, e, s, n) {
|
|
342
342
|
if (this.estimateTokens(t) < e) return t;
|
|
343
|
-
let
|
|
344
|
-
for (let
|
|
345
|
-
if (
|
|
343
|
+
let i = 0, d = 0;
|
|
344
|
+
for (let c of t.toReversed())
|
|
345
|
+
if (d += this.estimateTokens(c.content), d < s) i++;
|
|
346
346
|
else break;
|
|
347
|
-
if (t.length <=
|
|
348
|
-
const
|
|
349
|
-
return [{ role: "assistant", content: `Conversation Summary: ${await this.summarize(
|
|
347
|
+
if (t.length <= i) return t;
|
|
348
|
+
const r = i == 0 ? [] : t.slice(-i), l = (i == 0 ? t : t.slice(0, -i)).filter((c) => c.role === "assistant" || c.role === "user");
|
|
349
|
+
return [{ role: "assistant", content: `Conversation Summary: ${await this.summarize(l.map((c) => `${c.role}: ${c.content}`).join(`
|
|
350
350
|
|
|
351
|
-
`), 250,
|
|
351
|
+
`), 250, n)}`, timestamp: Date.now() }, ...r];
|
|
352
352
|
}
|
|
353
353
|
cosineSimilarity(t, e) {
|
|
354
354
|
if (t.length !== e.length) throw new Error("Vectors must be same length");
|
|
355
|
-
let s = 0,
|
|
356
|
-
for (let
|
|
357
|
-
s += t[
|
|
358
|
-
const
|
|
359
|
-
return
|
|
355
|
+
let s = 0, n = 0, i = 0;
|
|
356
|
+
for (let r = 0; r < t.length; r++)
|
|
357
|
+
s += t[r] * e[r], n += t[r] * t[r], i += e[r] * e[r];
|
|
358
|
+
const d = Math.sqrt(n) * Math.sqrt(i);
|
|
359
|
+
return d === 0 ? 0 : s / d;
|
|
360
360
|
}
|
|
361
|
-
|
|
362
|
-
const
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
let i = h, l = "";
|
|
376
|
-
for (; i < a.length; ) {
|
|
377
|
-
const n = a[i], r = l + (l ? " " : "") + n;
|
|
378
|
-
if (this.estimateTokens(r.replace(/\s*\n\s*/g, `
|
|
379
|
-
`)) > e && l) break;
|
|
380
|
-
l = r, i++;
|
|
361
|
+
chunk(t, e = 500, s = 50) {
|
|
362
|
+
const n = (l, u = "") => l ? Object.entries(l).flatMap(([c, m]) => {
|
|
363
|
+
const h = u ? `${u}${isNaN(+c) ? `.${c}` : `[${c}]`}` : c;
|
|
364
|
+
return typeof m == "object" && !Array.isArray(m) ? n(m, h) : `${h}: ${Array.isArray(m) ? m.join(", ") : m}`;
|
|
365
|
+
}) : [], d = (typeof t == "object" ? n(t) : t.split(`
|
|
366
|
+
`)).flatMap((l) => [...l.split(/\s+/).filter(Boolean), `
|
|
367
|
+
`]), r = [];
|
|
368
|
+
for (let l = 0; l < d.length; ) {
|
|
369
|
+
let u = "", c = l;
|
|
370
|
+
for (; c < d.length; ) {
|
|
371
|
+
const h = u + (u ? " " : "") + d[c];
|
|
372
|
+
if (this.estimateTokens(h.replace(/\s*\n\s*/g, `
|
|
373
|
+
`)) > e && u) break;
|
|
374
|
+
u = h, c++;
|
|
381
375
|
}
|
|
382
|
-
const
|
|
376
|
+
const m = u.replace(/\s*\n\s*/g, `
|
|
383
377
|
`).trim();
|
|
384
|
-
|
|
378
|
+
m && r.push(m), l = Math.max(c - s, c === l ? l + 1 : c);
|
|
385
379
|
}
|
|
386
|
-
return
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
380
|
+
return r;
|
|
381
|
+
}
|
|
382
|
+
embedding(t, e = 500, s = 50) {
|
|
383
|
+
const n = (d) => new Promise((r, l) => {
|
|
384
|
+
const u = this.embedId++;
|
|
385
|
+
this.embedQueue.set(u, { resolve: r, reject: l }), this.embedWorker?.postMessage({ id: u, text: d });
|
|
386
|
+
}), i = this.chunk(t, e, s);
|
|
387
|
+
return Promise.all(i.map(async (d, r) => ({
|
|
388
|
+
index: r,
|
|
389
|
+
embedding: await n(d),
|
|
390
|
+
text: d,
|
|
391
|
+
tokens: this.estimateTokens(d)
|
|
391
392
|
})));
|
|
392
393
|
}
|
|
393
394
|
/**
|
|
@@ -407,8 +408,8 @@ class G {
|
|
|
407
408
|
*/
|
|
408
409
|
fuzzyMatch(t, ...e) {
|
|
409
410
|
if (e.length < 2) throw new Error("Requires at least 2 strings to compare");
|
|
410
|
-
const s = (
|
|
411
|
-
return { avg:
|
|
411
|
+
const s = (d, r = 10) => d.toLowerCase().split("").map((l, u) => l.charCodeAt(0) * (u + 1) % r / r).slice(0, r), n = s(t), i = e.map((d) => s(d)).map((d) => this.cosineSimilarity(n, d));
|
|
412
|
+
return { avg: i.reduce((d, r) => d + r, 0) / i.length, max: Math.max(...i), similarities: i };
|
|
412
413
|
}
|
|
413
414
|
/**
|
|
414
415
|
* Ask a question with JSON response
|
|
@@ -431,10 +432,10 @@ class G {
|
|
|
431
432
|
* @returns {Promise<string>} Summary
|
|
432
433
|
*/
|
|
433
434
|
summarize(t, e, s) {
|
|
434
|
-
return this.ask(t, { system: `Generate a brief summary <= ${e} tokens. Output nothing else`, temperature: 0.3, ...s }).then((
|
|
435
|
+
return this.ask(t, { system: `Generate a brief summary <= ${e} tokens. Output nothing else`, temperature: 0.3, ...s }).then((n) => n.pop()?.content || null);
|
|
435
436
|
}
|
|
436
437
|
}
|
|
437
|
-
class
|
|
438
|
+
class B {
|
|
438
439
|
constructor(t) {
|
|
439
440
|
this.ai = t, t.options.whisper?.binary && (this.whisperModel = t.options.whisper?.model.endsWith(".bin") ? t.options.whisper?.model : t.options.whisper?.model + ".bin", this.downloadAsrModel());
|
|
440
441
|
}
|
|
@@ -450,12 +451,12 @@ class C {
|
|
|
450
451
|
if (!this.ai.options.whisper?.binary) throw new Error("Whisper not configured");
|
|
451
452
|
let s = () => {
|
|
452
453
|
};
|
|
453
|
-
return { response: new Promise((
|
|
454
|
-
this.downloadAsrModel(e).then((
|
|
455
|
-
let
|
|
456
|
-
const
|
|
457
|
-
s = () =>
|
|
458
|
-
|
|
454
|
+
return { response: new Promise((i, d) => {
|
|
455
|
+
this.downloadAsrModel(e).then((r) => {
|
|
456
|
+
let l = "";
|
|
457
|
+
const u = N(this.ai.options.whisper?.binary, ["-nt", "-np", "-m", r, "-f", t], { stdio: ["ignore", "pipe", "ignore"] });
|
|
458
|
+
s = () => u.kill("SIGTERM"), u.on("error", (c) => d(c)), u.stdout.on("data", (c) => l += c.toString()), u.on("close", (c) => {
|
|
459
|
+
c === 0 ? i(l.trim() || null) : d(new Error(`Exit code ${c}`));
|
|
459
460
|
});
|
|
460
461
|
});
|
|
461
462
|
}), abort: s };
|
|
@@ -473,7 +474,7 @@ class C {
|
|
|
473
474
|
return await S.stat(e).then(() => !0).catch(() => !1) ? e : this.downloads[t] ? this.downloads[t] : (this.downloads[t] = fetch(`https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${t}`).then((s) => s.arrayBuffer()).then((s) => Buffer.from(s)).then(async (s) => (await S.writeFile(e, s), delete this.downloads[t], e)), this.downloads[t]);
|
|
474
475
|
}
|
|
475
476
|
}
|
|
476
|
-
class
|
|
477
|
+
class C {
|
|
477
478
|
constructor(t) {
|
|
478
479
|
this.ai = t;
|
|
479
480
|
}
|
|
@@ -490,15 +491,15 @@ class B {
|
|
|
490
491
|
},
|
|
491
492
|
response: new Promise(async (s) => {
|
|
492
493
|
e = await D(this.ai.options.tesseract?.model || "eng", 2, { cachePath: this.ai.options.path });
|
|
493
|
-
const { data:
|
|
494
|
-
await e.terminate(), s(
|
|
494
|
+
const { data: n } = await e.recognize(t);
|
|
495
|
+
await e.terminate(), s(n.text.trim() || null);
|
|
495
496
|
})
|
|
496
497
|
};
|
|
497
498
|
}
|
|
498
499
|
}
|
|
499
500
|
class le {
|
|
500
501
|
constructor(t) {
|
|
501
|
-
this.options = t, t.path || (t.path =
|
|
502
|
+
this.options = t, t.path || (t.path = j.tmpdir()), process.env.TRANSFORMERS_CACHE = t.path, this.audio = new B(this), this.language = new G(this), this.vision = new C(this);
|
|
502
503
|
}
|
|
503
504
|
/** Audio processing AI */
|
|
504
505
|
audio;
|
|
@@ -511,7 +512,7 @@ const Q = {
|
|
|
511
512
|
name: "cli",
|
|
512
513
|
description: "Use the command line interface, returns any output",
|
|
513
514
|
args: { command: { type: "string", description: "Command to run", required: !0 } },
|
|
514
|
-
fn: (
|
|
515
|
+
fn: (p) => J`${p.command}`
|
|
515
516
|
}, me = {
|
|
516
517
|
name: "get_datetime",
|
|
517
518
|
description: "Get current date and time",
|
|
@@ -524,15 +525,15 @@ const Q = {
|
|
|
524
525
|
language: { type: "string", description: "Execution language", enum: ["cli", "node", "python"], required: !0 },
|
|
525
526
|
code: { type: "string", description: "Code to execute", required: !0 }
|
|
526
527
|
},
|
|
527
|
-
fn: async (
|
|
528
|
+
fn: async (p, t) => {
|
|
528
529
|
try {
|
|
529
|
-
switch (
|
|
530
|
+
switch (p.type) {
|
|
530
531
|
case "bash":
|
|
531
|
-
return await Q.fn({ command:
|
|
532
|
+
return await Q.fn({ command: p.code }, t);
|
|
532
533
|
case "node":
|
|
533
|
-
return await K.fn({ code:
|
|
534
|
+
return await K.fn({ code: p.code }, t);
|
|
534
535
|
case "python":
|
|
535
|
-
return await V.fn({ code:
|
|
536
|
+
return await V.fn({ code: p.code }, t);
|
|
536
537
|
}
|
|
537
538
|
} catch (e) {
|
|
538
539
|
return { error: e?.message || e.toString() };
|
|
@@ -547,15 +548,15 @@ const Q = {
|
|
|
547
548
|
headers: { type: "object", description: "HTTP headers to send", default: {} },
|
|
548
549
|
body: { type: "object", description: "HTTP body to send" }
|
|
549
550
|
},
|
|
550
|
-
fn: (
|
|
551
|
+
fn: (p) => new M({ url: p.url, headers: p.headers }).request({ method: p.method || "GET", body: p.body })
|
|
551
552
|
}, K = {
|
|
552
553
|
name: "exec_javascript",
|
|
553
554
|
description: "Execute commonjs javascript",
|
|
554
555
|
args: {
|
|
555
556
|
code: { type: "string", description: "CommonJS javascript", required: !0 }
|
|
556
557
|
},
|
|
557
|
-
fn: async (
|
|
558
|
-
const t = A(null), e = await q({ console: t },
|
|
558
|
+
fn: async (p) => {
|
|
559
|
+
const t = A(null), e = await q({ console: t }, p.code, !0).catch((s) => t.output.error.push(s));
|
|
559
560
|
return { ...t.output, return: e, stdout: void 0, stderr: void 0 };
|
|
560
561
|
}
|
|
561
562
|
}, V = {
|
|
@@ -564,7 +565,7 @@ const Q = {
|
|
|
564
565
|
args: {
|
|
565
566
|
code: { type: "string", description: "CommonJS javascript", required: !0 }
|
|
566
567
|
},
|
|
567
|
-
fn: async (
|
|
568
|
+
fn: async (p) => ({ result: H`python -c "${p.code}"` })
|
|
568
569
|
}, pe = {
|
|
569
570
|
name: "search",
|
|
570
571
|
description: "Use a search engine to find relevant URLs, should be changed with fetch to scrape sources",
|
|
@@ -572,17 +573,17 @@ const Q = {
|
|
|
572
573
|
query: { type: "string", description: "Search string", required: !0 },
|
|
573
574
|
length: { type: "string", description: "Number of results to return", default: 5 }
|
|
574
575
|
},
|
|
575
|
-
fn: async (
|
|
576
|
-
const t = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(
|
|
576
|
+
fn: async (p) => {
|
|
577
|
+
const t = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(p.query)}`, {
|
|
577
578
|
headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Accept-Language": "en-US,en;q=0.9" }
|
|
578
|
-
}).then((
|
|
579
|
+
}).then((i) => i.text());
|
|
579
580
|
let e, s = /<a .*?href="(.+?)".+?<\/a>/g;
|
|
580
|
-
const
|
|
581
|
+
const n = new P();
|
|
581
582
|
for (; (e = s.exec(t)) !== null; ) {
|
|
582
|
-
let
|
|
583
|
-
if (
|
|
583
|
+
let i = /uddg=(.+)&?/.exec(decodeURIComponent(e[1]))?.[1];
|
|
584
|
+
if (i && (i = decodeURIComponent(i)), i && n.add(i), n.size >= (p.length || 5)) break;
|
|
584
585
|
}
|
|
585
|
-
return
|
|
586
|
+
return n;
|
|
586
587
|
}
|
|
587
588
|
};
|
|
588
589
|
export {
|