@ztimson/ai-utils 0.1.20 → 0.1.21
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 +10 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +185 -184
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
import { createWorker as T } from "tesseract.js";
|
|
2
|
-
import { objectMap as k, JSONAttemptParse as y, findByProp as x, JSONSanitize as b, Http as
|
|
3
|
-
import { Anthropic as
|
|
4
|
-
import { Ollama as
|
|
5
|
-
import { OpenAI as
|
|
2
|
+
import { deepCopy as q, objectMap as k, JSONAttemptParse as y, findByProp as x, JSONSanitize as b, Http as v, consoleInterceptor as P, fn as A, ASet as E } from "@ztimson/utils";
|
|
3
|
+
import { Anthropic as M } from "@anthropic-ai/sdk";
|
|
4
|
+
import { Ollama as O } from "ollama";
|
|
5
|
+
import { OpenAI as D } from "openai";
|
|
6
6
|
import j from "node:fs/promises";
|
|
7
|
-
import
|
|
7
|
+
import U from "node:path";
|
|
8
8
|
import * as _ from "@tensorflow/tfjs";
|
|
9
|
-
import { spawn as
|
|
10
|
-
import {
|
|
9
|
+
import { spawn as $ } from "node:child_process";
|
|
10
|
+
import { $ as L, $Sync as R } from "@ztimson/node-utils";
|
|
11
11
|
class S {
|
|
12
12
|
}
|
|
13
|
-
class
|
|
13
|
+
class I extends S {
|
|
14
14
|
constructor(t, e, n) {
|
|
15
|
-
super(), this.ai = t, this.apiToken = e, this.model = n, this.client = new
|
|
15
|
+
super(), this.ai = t, this.apiToken = e, this.model = n, this.client = new M({ apiKey: e });
|
|
16
16
|
}
|
|
17
17
|
client;
|
|
18
18
|
toStandard(t) {
|
|
19
19
|
for (let e = 0; e < t.length; e++) {
|
|
20
20
|
const n = e;
|
|
21
|
-
typeof t[n].content != "string" && (t[n].role == "assistant" ? t[n].content.filter((
|
|
22
|
-
e++, t.splice(e, 0, { role: "tool", id:
|
|
23
|
-
}) : t[n].role == "user" && t[n].content.filter((
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
}), t[n].content = t[n].content.filter((
|
|
21
|
+
typeof t[n].content != "string" && (t[n].role == "assistant" ? t[n].content.filter((a) => a.type == "tool_use").forEach((a) => {
|
|
22
|
+
e++, t.splice(e, 0, { role: "tool", id: a.id, name: a.name, args: a.input, timestamp: Date.now() });
|
|
23
|
+
}) : t[n].role == "user" && t[n].content.filter((a) => a.type == "tool_result").forEach((a) => {
|
|
24
|
+
const i = t.find((f) => f.id == a.tool_use_id);
|
|
25
|
+
i[a.is_error ? "error" : "content"] = a.content;
|
|
26
|
+
}), t[n].content = t[n].content.filter((a) => a.type == "text").map((a) => a.text).join(`
|
|
27
27
|
|
|
28
28
|
`)), t[n].timestamp || (t[n].timestamp = Date.now());
|
|
29
29
|
}
|
|
@@ -43,80 +43,81 @@ class R extends S {
|
|
|
43
43
|
return t.map(({ timestamp: e, ...n }) => n);
|
|
44
44
|
}
|
|
45
45
|
ask(t, e = {}) {
|
|
46
|
-
const n = new AbortController(),
|
|
47
|
-
let
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
const n = new AbortController(), a = new Promise(async (i, f) => {
|
|
47
|
+
let c = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]);
|
|
48
|
+
const l = q(c);
|
|
49
|
+
e.compress && (c = await this.ai.llm.compress(c, e.compress.max, e.compress.min, e));
|
|
50
|
+
const d = {
|
|
50
51
|
model: e.model || this.model,
|
|
51
52
|
max_tokens: e.max_tokens || this.ai.options.max_tokens || 4096,
|
|
52
53
|
system: e.system || this.ai.options.system || "",
|
|
53
54
|
temperature: e.temperature || this.ai.options.temperature || 0.7,
|
|
54
|
-
tools: (e.tools || this.ai.options.tools || []).map((
|
|
55
|
-
name:
|
|
56
|
-
description:
|
|
55
|
+
tools: (e.tools || this.ai.options.tools || []).map((m) => ({
|
|
56
|
+
name: m.name,
|
|
57
|
+
description: m.description,
|
|
57
58
|
input_schema: {
|
|
58
59
|
type: "object",
|
|
59
|
-
properties:
|
|
60
|
-
required:
|
|
60
|
+
properties: m.args ? k(m.args, (r, s) => ({ ...s, required: void 0 })) : {},
|
|
61
|
+
required: m.args ? Object.entries(m.args).filter((r) => r[1].required).map((r) => r[0]) : []
|
|
61
62
|
},
|
|
62
63
|
fn: void 0
|
|
63
64
|
})),
|
|
64
|
-
messages:
|
|
65
|
+
messages: c,
|
|
65
66
|
stream: !!e.stream
|
|
66
67
|
};
|
|
67
|
-
let
|
|
68
|
-
const
|
|
68
|
+
let o;
|
|
69
|
+
const h = [];
|
|
69
70
|
do {
|
|
70
|
-
if (
|
|
71
|
-
|
|
71
|
+
if (o = await this.client.messages.create(d), e.stream) {
|
|
72
|
+
h.length && e.stream({ text: `
|
|
72
73
|
|
|
73
|
-
` }),
|
|
74
|
-
for await (const s of
|
|
74
|
+
` }), o.content = [];
|
|
75
|
+
for await (const s of o) {
|
|
75
76
|
if (n.signal.aborted) break;
|
|
76
77
|
if (s.type === "content_block_start")
|
|
77
|
-
s.content_block.type === "text" ?
|
|
78
|
+
s.content_block.type === "text" ? o.content.push({ type: "text", text: "" }) : s.content_block.type === "tool_use" && o.content.push({ type: "tool_use", id: s.content_block.id, name: s.content_block.name, input: "" });
|
|
78
79
|
else if (s.type === "content_block_delta")
|
|
79
80
|
if (s.delta.type === "text_delta") {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
} else s.delta.type === "input_json_delta" && (
|
|
81
|
+
const p = s.delta.text;
|
|
82
|
+
o.content.at(-1).text += p, e.stream({ text: p });
|
|
83
|
+
} else s.delta.type === "input_json_delta" && (o.content.at(-1).input += s.delta.partial_json);
|
|
83
84
|
else if (s.type === "content_block_stop") {
|
|
84
|
-
const
|
|
85
|
-
|
|
85
|
+
const p = o.content.at(-1);
|
|
86
|
+
p.input != null && (p.input = p.input ? y(p.input, {}) : {});
|
|
86
87
|
} else if (s.type === "message_stop")
|
|
87
88
|
break;
|
|
88
89
|
}
|
|
89
90
|
}
|
|
90
|
-
const
|
|
91
|
+
const m = o.content.filter((s) => s.type == "text").map((s) => s.text).join(`
|
|
91
92
|
|
|
92
93
|
`);
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
if (
|
|
96
|
-
l.push({ role: "assistant", content:
|
|
97
|
-
const s = await Promise.all(
|
|
98
|
-
const g = e.tools?.find(x("name",
|
|
99
|
-
if (!g) return { tool_use_id:
|
|
94
|
+
m && h.push(m);
|
|
95
|
+
const r = o.content.filter((s) => s.type === "tool_use");
|
|
96
|
+
if (r.length && !n.signal.aborted) {
|
|
97
|
+
c.push({ role: "assistant", content: o.content }), l.push({ role: "assistant", content: o.content });
|
|
98
|
+
const s = await Promise.all(r.map(async (p) => {
|
|
99
|
+
const g = e.tools?.find(x("name", p.name));
|
|
100
|
+
if (!g) return { tool_use_id: p.id, is_error: !0, content: "Tool not found" };
|
|
100
101
|
try {
|
|
101
|
-
const
|
|
102
|
-
return { type: "tool_result", tool_use_id:
|
|
103
|
-
} catch (
|
|
104
|
-
return { type: "tool_result", tool_use_id:
|
|
102
|
+
const w = await g.fn(p.input, this.ai);
|
|
103
|
+
return { type: "tool_result", tool_use_id: p.id, content: b(w) };
|
|
104
|
+
} catch (w) {
|
|
105
|
+
return { type: "tool_result", tool_use_id: p.id, is_error: !0, content: w?.message || w?.toString() || "Unknown" };
|
|
105
106
|
}
|
|
106
107
|
}));
|
|
107
|
-
l.push({ role: "user", content: s }),
|
|
108
|
+
c.push({ role: "user", content: s }), l.push({ role: "user", content: s }), d.messages = c;
|
|
108
109
|
}
|
|
109
|
-
} while (!n.signal.aborted &&
|
|
110
|
-
e.stream && e.stream({ done: !0 }),
|
|
110
|
+
} while (!n.signal.aborted && o.content.some((m) => m.type === "tool_use"));
|
|
111
|
+
e.stream && e.stream({ done: !0 }), i(this.toStandard([...l, { role: "assistant", content: h.join(`
|
|
111
112
|
|
|
112
113
|
`), timestamp: Date.now() }]));
|
|
113
114
|
});
|
|
114
|
-
return Object.assign(
|
|
115
|
+
return Object.assign(a, { abort: () => n.abort() });
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
|
-
class
|
|
118
|
+
class J extends S {
|
|
118
119
|
constructor(t, e, n) {
|
|
119
|
-
super(), this.ai = t, this.host = e, this.model = n, this.client = new
|
|
120
|
+
super(), this.ai = t, this.host = e, this.model = n, this.client = new O({ host: e });
|
|
120
121
|
}
|
|
121
122
|
client;
|
|
122
123
|
toStandard(t) {
|
|
@@ -133,90 +134,90 @@ class I extends S {
|
|
|
133
134
|
}
|
|
134
135
|
fromStandard(t) {
|
|
135
136
|
return t.map((e) => {
|
|
136
|
-
const { timestamp: n, ...
|
|
137
|
-
return e.role != "tool" ?
|
|
137
|
+
const { timestamp: n, ...a } = e;
|
|
138
|
+
return e.role != "tool" ? a : { role: "tool", tool_name: e.name, content: e.error || e.content };
|
|
138
139
|
});
|
|
139
140
|
}
|
|
140
141
|
ask(t, e = {}) {
|
|
141
|
-
const n = new AbortController(),
|
|
142
|
-
let
|
|
143
|
-
|
|
144
|
-
const
|
|
142
|
+
const n = new AbortController(), a = new Promise(async (i, f) => {
|
|
143
|
+
let c = e.system || this.ai.options.system, l = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]);
|
|
144
|
+
l[0].roll == "system" && (c ? l.shift() : c = l.shift()), e.compress && (l = await this.ai.llm.compress(l, e.compress.max, e.compress.min)), e.system && l.unshift({ role: "system", content: c });
|
|
145
|
+
const d = {
|
|
145
146
|
model: e.model || this.model,
|
|
146
|
-
messages:
|
|
147
|
+
messages: l,
|
|
147
148
|
stream: !!e.stream,
|
|
148
149
|
signal: n.signal,
|
|
149
150
|
options: {
|
|
150
151
|
temperature: e.temperature || this.ai.options.temperature || 0.7,
|
|
151
152
|
num_predict: e.max_tokens || this.ai.options.max_tokens || 4096
|
|
152
153
|
},
|
|
153
|
-
tools: (e.tools || this.ai.options.tools || []).map((
|
|
154
|
+
tools: (e.tools || this.ai.options.tools || []).map((r) => ({
|
|
154
155
|
type: "function",
|
|
155
156
|
function: {
|
|
156
|
-
name:
|
|
157
|
-
description:
|
|
157
|
+
name: r.name,
|
|
158
|
+
description: r.description,
|
|
158
159
|
parameters: {
|
|
159
160
|
type: "object",
|
|
160
|
-
properties:
|
|
161
|
-
required:
|
|
161
|
+
properties: r.args ? k(r.args, (s, p) => ({ ...p, required: void 0 })) : {},
|
|
162
|
+
required: r.args ? Object.entries(r.args).filter((s) => s[1].required).map((s) => s[0]) : []
|
|
162
163
|
}
|
|
163
164
|
}
|
|
164
165
|
}))
|
|
165
166
|
};
|
|
166
|
-
let
|
|
167
|
-
const
|
|
167
|
+
let o;
|
|
168
|
+
const h = [];
|
|
168
169
|
do {
|
|
169
|
-
if (
|
|
170
|
-
|
|
170
|
+
if (o = await this.client.chat(d), e.stream) {
|
|
171
|
+
h.length && e.stream({ text: `
|
|
171
172
|
|
|
172
|
-
` }),
|
|
173
|
-
for await (const
|
|
174
|
-
if (n.signal.aborted || (
|
|
173
|
+
` }), o.message = { role: "assistant", content: "", tool_calls: [] };
|
|
174
|
+
for await (const r of o)
|
|
175
|
+
if (n.signal.aborted || (r.message?.content && (o.message.content += r.message.content, e.stream({ text: r.message.content })), r.message?.tool_calls && (o.message.tool_calls = r.message.tool_calls), r.done)) break;
|
|
175
176
|
}
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
const
|
|
179
|
-
const
|
|
180
|
-
if (!
|
|
181
|
-
const
|
|
177
|
+
if (h.push({ role: "assistant", content: o.message?.content, timestamp: Date.now() }), o.message?.tool_calls?.length && !n.signal.aborted) {
|
|
178
|
+
l.push(o.message);
|
|
179
|
+
const r = await Promise.all(o.message.tool_calls.map(async (s) => {
|
|
180
|
+
const p = (e.tools || this.ai.options.tools)?.find(x("name", s.function.name));
|
|
181
|
+
if (!p) return { role: "tool", tool_name: s.function.name, content: '{"error": "Tool not found"}' };
|
|
182
|
+
const g = typeof s.function.arguments == "string" ? y(s.function.arguments, {}) : s.function.arguments;
|
|
182
183
|
try {
|
|
183
|
-
const w = await
|
|
184
|
-
return { role: "tool", tool_name:
|
|
184
|
+
const w = await p.fn(g, this.ai);
|
|
185
|
+
return { role: "tool", tool_name: s.function.name, args: g, content: b(w) };
|
|
185
186
|
} catch (w) {
|
|
186
|
-
return { role: "tool", tool_name:
|
|
187
|
+
return { role: "tool", tool_name: s.function.name, args: g, content: b({ error: w?.message || w?.toString() || "Unknown" }) };
|
|
187
188
|
}
|
|
188
189
|
}));
|
|
189
|
-
|
|
190
|
+
l.push(...r), h.push(...r.map((s) => ({ ...s, timestamp: Date.now() }))), d.messages = l;
|
|
190
191
|
}
|
|
191
|
-
} while (!n.signal.aborted &&
|
|
192
|
-
const
|
|
192
|
+
} while (!n.signal.aborted && o.message?.tool_calls?.length);
|
|
193
|
+
const m = h.filter((r) => r.role === "assistant").map((r) => r.content).filter((r) => r).join(`
|
|
193
194
|
|
|
194
195
|
`);
|
|
195
|
-
e.stream && e.stream({ done: !0 }),
|
|
196
|
+
e.stream && e.stream({ done: !0 }), i(this.toStandard([...l, { role: "assistant", content: m, timestamp: Date.now() }]));
|
|
196
197
|
});
|
|
197
|
-
return Object.assign(
|
|
198
|
+
return Object.assign(a, { abort: () => n.abort() });
|
|
198
199
|
}
|
|
199
200
|
}
|
|
200
|
-
class
|
|
201
|
+
class W extends S {
|
|
201
202
|
constructor(t, e, n) {
|
|
202
|
-
super(), this.ai = t, this.apiToken = e, this.model = n, this.client = new
|
|
203
|
+
super(), this.ai = t, this.apiToken = e, this.model = n, this.client = new D({ apiKey: e });
|
|
203
204
|
}
|
|
204
205
|
client;
|
|
205
206
|
toStandard(t) {
|
|
206
207
|
for (let e = 0; e < t.length; e++) {
|
|
207
208
|
const n = t[e];
|
|
208
209
|
if (n.role === "assistant" && n.tool_calls) {
|
|
209
|
-
const
|
|
210
|
+
const a = n.tool_calls.map((i) => ({
|
|
210
211
|
role: "tool",
|
|
211
|
-
id:
|
|
212
|
-
name:
|
|
213
|
-
args: y(
|
|
212
|
+
id: i.id,
|
|
213
|
+
name: i.function.name,
|
|
214
|
+
args: y(i.function.arguments, {}),
|
|
214
215
|
timestamp: n.timestamp
|
|
215
216
|
}));
|
|
216
|
-
t.splice(e, 1, ...
|
|
217
|
+
t.splice(e, 1, ...a), e += a.length - 1;
|
|
217
218
|
} else if (n.role === "tool" && n.content) {
|
|
218
|
-
const
|
|
219
|
-
|
|
219
|
+
const a = t.find((i) => n.tool_call_id == i.id);
|
|
220
|
+
a && (n.content.includes('"error":') ? a.error = n.content : a.content = n.content), t.splice(e, 1), e--;
|
|
220
221
|
}
|
|
221
222
|
t[e]?.timestamp || (t[e].timestamp = Date.now());
|
|
222
223
|
}
|
|
@@ -237,75 +238,75 @@ class J extends S {
|
|
|
237
238
|
content: n.error || n.content
|
|
238
239
|
});
|
|
239
240
|
else {
|
|
240
|
-
const { timestamp:
|
|
241
|
-
e.push(
|
|
241
|
+
const { timestamp: a, ...i } = n;
|
|
242
|
+
e.push(i);
|
|
242
243
|
}
|
|
243
244
|
return e;
|
|
244
245
|
}, []);
|
|
245
246
|
}
|
|
246
247
|
ask(t, e = {}) {
|
|
247
|
-
const n = new AbortController(),
|
|
248
|
-
let
|
|
249
|
-
e.compress && (
|
|
250
|
-
const
|
|
248
|
+
const n = new AbortController(), a = new Promise(async (i, f) => {
|
|
249
|
+
let c = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]);
|
|
250
|
+
e.compress && (c = await this.ai.llm.compress(c, e.compress.max, e.compress.min, e));
|
|
251
|
+
const l = {
|
|
251
252
|
model: e.model || this.model,
|
|
252
|
-
messages:
|
|
253
|
+
messages: c,
|
|
253
254
|
stream: !!e.stream,
|
|
254
255
|
max_tokens: e.max_tokens || this.ai.options.max_tokens || 4096,
|
|
255
256
|
temperature: e.temperature || this.ai.options.temperature || 0.7,
|
|
256
|
-
tools: (e.tools || this.ai.options.tools || []).map((
|
|
257
|
+
tools: (e.tools || this.ai.options.tools || []).map((m) => ({
|
|
257
258
|
type: "function",
|
|
258
259
|
function: {
|
|
259
|
-
name:
|
|
260
|
-
description:
|
|
260
|
+
name: m.name,
|
|
261
|
+
description: m.description,
|
|
261
262
|
parameters: {
|
|
262
263
|
type: "object",
|
|
263
|
-
properties:
|
|
264
|
-
required:
|
|
264
|
+
properties: m.args ? k(m.args, (r, s) => ({ ...s, required: void 0 })) : {},
|
|
265
|
+
required: m.args ? Object.entries(m.args).filter((r) => r[1].required).map((r) => r[0]) : []
|
|
265
266
|
}
|
|
266
267
|
}
|
|
267
268
|
}))
|
|
268
269
|
};
|
|
269
|
-
let
|
|
270
|
-
const
|
|
270
|
+
let d;
|
|
271
|
+
const o = [];
|
|
271
272
|
do {
|
|
272
|
-
if (
|
|
273
|
-
|
|
273
|
+
if (d = await this.client.chat.completions.create(l), e.stream) {
|
|
274
|
+
o.length && e.stream({ text: `
|
|
274
275
|
|
|
275
|
-
` }),
|
|
276
|
-
for await (const
|
|
276
|
+
` }), d.choices = [{ message: { content: "", tool_calls: [] } }];
|
|
277
|
+
for await (const r of d) {
|
|
277
278
|
if (n.signal.aborted) break;
|
|
278
|
-
|
|
279
|
+
r.choices[0].delta.content && (d.choices[0].message.content += r.choices[0].delta.content, e.stream({ text: r.choices[0].delta.content })), r.choices[0].delta.tool_calls && (d.choices[0].message.tool_calls = r.choices[0].delta.tool_calls);
|
|
279
280
|
}
|
|
280
281
|
}
|
|
281
|
-
|
|
282
|
-
const
|
|
283
|
-
if (
|
|
284
|
-
|
|
285
|
-
const
|
|
286
|
-
const
|
|
287
|
-
if (!
|
|
282
|
+
o.push({ role: "assistant", content: d.choices[0].message.content || "", timestamp: Date.now() });
|
|
283
|
+
const m = d.choices[0].message.tool_calls || [];
|
|
284
|
+
if (m.length && !n.signal.aborted) {
|
|
285
|
+
c.push(d.choices[0].message);
|
|
286
|
+
const r = await Promise.all(m.map(async (s) => {
|
|
287
|
+
const p = e.tools?.find(x("name", s.function.name));
|
|
288
|
+
if (!p) return { role: "tool", tool_call_id: s.id, content: '{"error": "Tool not found"}' };
|
|
288
289
|
try {
|
|
289
|
-
const
|
|
290
|
-
return { role: "tool", tool_call_id:
|
|
291
|
-
} catch (
|
|
292
|
-
return { role: "tool", tool_call_id:
|
|
290
|
+
const g = y(s.function.arguments, {}), w = await p.fn(g, this.ai);
|
|
291
|
+
return { role: "tool", tool_call_id: s.id, content: b(w) };
|
|
292
|
+
} catch (g) {
|
|
293
|
+
return { role: "tool", tool_call_id: s.id, content: b({ error: g?.message || g?.toString() || "Unknown" }) };
|
|
293
294
|
}
|
|
294
295
|
}));
|
|
295
|
-
|
|
296
|
+
c.push(...r), o.push(...r.map((s) => ({ ...s, timestamp: Date.now() }))), l.messages = c;
|
|
296
297
|
}
|
|
297
|
-
} while (!n.signal.aborted &&
|
|
298
|
-
const
|
|
298
|
+
} while (!n.signal.aborted && d.choices?.[0]?.message?.tool_calls?.length);
|
|
299
|
+
const h = o.filter((m) => m.role === "assistant").map((m) => m.content).filter((m) => m).join(`
|
|
299
300
|
|
|
300
301
|
`);
|
|
301
|
-
e.stream && e.stream({ done: !0 }),
|
|
302
|
+
e.stream && e.stream({ done: !0 }), i(this.toStandard([...c, { role: "assistant", content: h, timestamp: Date.now() }]));
|
|
302
303
|
});
|
|
303
|
-
return Object.assign(
|
|
304
|
+
return Object.assign(a, { abort: () => n.abort() });
|
|
304
305
|
}
|
|
305
306
|
}
|
|
306
|
-
class
|
|
307
|
+
class N {
|
|
307
308
|
constructor(t, e) {
|
|
308
|
-
this.ai = t, this.options = e, e.anthropic?.token && (this.providers.anthropic = new
|
|
309
|
+
this.ai = t, this.options = e, e.anthropic?.token && (this.providers.anthropic = new I(this.ai, e.anthropic.token, e.anthropic.model)), e.ollama?.host && (this.providers.ollama = new J(this.ai, e.ollama.host, e.ollama.model)), e.openAi?.token && (this.providers.openAi = new W(this.ai, e.openAi.token, e.openAi.model));
|
|
309
310
|
}
|
|
310
311
|
providers = {};
|
|
311
312
|
/**
|
|
@@ -327,17 +328,17 @@ class W {
|
|
|
327
328
|
* @param {LLMRequest} options LLM options
|
|
328
329
|
* @returns {Promise<LLMMessage[]>} New chat history will summary at index 0
|
|
329
330
|
*/
|
|
330
|
-
async compress(t, e, n,
|
|
331
|
+
async compress(t, e, n, a) {
|
|
331
332
|
if (this.estimateTokens(t) < e) return t;
|
|
332
|
-
let
|
|
333
|
-
for (let
|
|
334
|
-
if (f += this.estimateTokens(
|
|
333
|
+
let i = 0, f = 0;
|
|
334
|
+
for (let o of t.toReversed())
|
|
335
|
+
if (f += this.estimateTokens(o.content), f < n) i++;
|
|
335
336
|
else break;
|
|
336
|
-
if (t.length <=
|
|
337
|
-
const
|
|
338
|
-
return [{ role: "assistant", content: `Conversation Summary: ${await this.summarize(
|
|
337
|
+
if (t.length <= i) return t;
|
|
338
|
+
const c = i == 0 ? [] : t.slice(-i), l = (i == 0 ? t : t.slice(0, -i)).filter((o) => o.role === "assistant" || o.role === "user");
|
|
339
|
+
return [{ role: "assistant", content: `Conversation Summary: ${await this.summarize(l.map((o) => `${o.role}: ${o.content}`).join(`
|
|
339
340
|
|
|
340
|
-
`), 250,
|
|
341
|
+
`), 250, a)}`, timestamp: Date.now() }, ...c];
|
|
341
342
|
}
|
|
342
343
|
/**
|
|
343
344
|
* Estimate variable as tokens
|
|
@@ -369,12 +370,12 @@ class W {
|
|
|
369
370
|
* @returns {Promise<string>} Summary
|
|
370
371
|
*/
|
|
371
372
|
summarize(t, e, n) {
|
|
372
|
-
return this.ask(t, { system: `Generate a brief summary <= ${e} tokens. Output nothing else`, temperature: 0.3, ...n }).then((
|
|
373
|
+
return this.ask(t, { system: `Generate a brief summary <= ${e} tokens. Output nothing else`, temperature: 0.3, ...n }).then((a) => a.pop()?.content || null);
|
|
373
374
|
}
|
|
374
375
|
}
|
|
375
|
-
class
|
|
376
|
+
class ee {
|
|
376
377
|
constructor(t) {
|
|
377
|
-
this.options = t, this.llm = new
|
|
378
|
+
this.options = t, this.llm = new N(this, t), this.options.whisper?.binary && (this.whisperModel = this.options.whisper?.model.endsWith(".bin") ? this.options.whisper?.model : this.options.whisper?.model + ".bin", this.downloadAsrModel());
|
|
378
379
|
}
|
|
379
380
|
downloads = {};
|
|
380
381
|
whisperModel;
|
|
@@ -390,12 +391,12 @@ class Z {
|
|
|
390
391
|
if (!this.options.whisper?.binary) throw new Error("Whisper not configured");
|
|
391
392
|
let n = () => {
|
|
392
393
|
};
|
|
393
|
-
return { response: new Promise((
|
|
394
|
-
this.downloadAsrModel(e).then((
|
|
395
|
-
let
|
|
396
|
-
const
|
|
397
|
-
n = () =>
|
|
398
|
-
|
|
394
|
+
return { response: new Promise((i, f) => {
|
|
395
|
+
this.downloadAsrModel(e).then((c) => {
|
|
396
|
+
let l = "";
|
|
397
|
+
const d = $(this.options.whisper?.binary, ["-nt", "-np", "-m", c, "-f", t], { stdio: ["ignore", "pipe", "ignore"] });
|
|
398
|
+
n = () => d.kill("SIGTERM"), d.on("error", (o) => f(o)), d.stdout.on("data", (o) => l += o.toString()), d.on("close", (o) => {
|
|
399
|
+
o === 0 ? i(l.trim() || null) : f(new Error(`Exit code ${o}`));
|
|
399
400
|
});
|
|
400
401
|
});
|
|
401
402
|
}), abort: n };
|
|
@@ -409,7 +410,7 @@ class Z {
|
|
|
409
410
|
async downloadAsrModel(t = this.whisperModel) {
|
|
410
411
|
if (!this.options.whisper?.binary) throw new Error("Whisper not configured");
|
|
411
412
|
t.endsWith(".bin") || (t += ".bin");
|
|
412
|
-
const e =
|
|
413
|
+
const e = U.join(this.options.whisper.path, t);
|
|
413
414
|
return await j.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((n) => n.arrayBuffer()).then((n) => Buffer.from(n)).then(async (n) => (await j.writeFile(e, n), delete this.downloads[t], e)), this.downloads[t]);
|
|
414
415
|
}
|
|
415
416
|
/**
|
|
@@ -425,8 +426,8 @@ class Z {
|
|
|
425
426
|
},
|
|
426
427
|
response: new Promise(async (n) => {
|
|
427
428
|
e = await T("eng");
|
|
428
|
-
const { data:
|
|
429
|
-
await e.terminate(), n(
|
|
429
|
+
const { data: a } = await e.recognize(t);
|
|
430
|
+
await e.terminate(), n(a.text.trim() || null);
|
|
430
431
|
})
|
|
431
432
|
};
|
|
432
433
|
}
|
|
@@ -438,25 +439,25 @@ class Z {
|
|
|
438
439
|
*/
|
|
439
440
|
semanticSimilarity(t, ...e) {
|
|
440
441
|
if (e.length < 2) throw new Error("Requires at least 2 strings to compare");
|
|
441
|
-
const n = (
|
|
442
|
-
if (
|
|
443
|
-
const
|
|
444
|
-
return
|
|
445
|
-
},
|
|
446
|
-
return { avg: f.reduce((
|
|
442
|
+
const n = (c, l = 10) => c.toLowerCase().split("").map((d, o) => d.charCodeAt(0) * (o + 1) % l / l).slice(0, l), a = (c, l) => {
|
|
443
|
+
if (c.length !== l.length) throw new Error("Vectors must be same length");
|
|
444
|
+
const d = _.tensor1d(c), o = _.tensor1d(l), h = _.dot(d, o), m = _.norm(d), r = _.norm(o);
|
|
445
|
+
return m.dataSync()[0] === 0 || r.dataSync()[0] === 0 ? 0 : h.dataSync()[0] / (m.dataSync()[0] * r.dataSync()[0]);
|
|
446
|
+
}, i = n(t), f = e.map((c) => n(c)).map((c) => a(i, c));
|
|
447
|
+
return { avg: f.reduce((c, l) => c + l, 0) / f.length, max: Math.max(...f), similarities: f };
|
|
447
448
|
}
|
|
448
449
|
}
|
|
449
|
-
const
|
|
450
|
+
const z = {
|
|
450
451
|
name: "cli",
|
|
451
452
|
description: "Use the command line interface, returns any output",
|
|
452
453
|
args: { command: { type: "string", description: "Command to run", required: !0 } },
|
|
453
|
-
fn: (u) =>
|
|
454
|
-
},
|
|
454
|
+
fn: (u) => L`${u.command}`
|
|
455
|
+
}, te = {
|
|
455
456
|
name: "get_datetime",
|
|
456
457
|
description: "Get current date and time",
|
|
457
458
|
args: {},
|
|
458
459
|
fn: async () => (/* @__PURE__ */ new Date()).toISOString()
|
|
459
|
-
},
|
|
460
|
+
}, ne = {
|
|
460
461
|
name: "exec",
|
|
461
462
|
description: "Run code/scripts",
|
|
462
463
|
args: {
|
|
@@ -467,9 +468,9 @@ const N = {
|
|
|
467
468
|
try {
|
|
468
469
|
switch (u.type) {
|
|
469
470
|
case "bash":
|
|
470
|
-
return await
|
|
471
|
+
return await z.fn({ command: u.code }, t);
|
|
471
472
|
case "node":
|
|
472
|
-
return await
|
|
473
|
+
return await C.fn({ code: u.code }, t);
|
|
473
474
|
case "python":
|
|
474
475
|
return await G.fn({ code: u.code }, t);
|
|
475
476
|
}
|
|
@@ -477,7 +478,7 @@ const N = {
|
|
|
477
478
|
return { error: e?.message || e.toString() };
|
|
478
479
|
}
|
|
479
480
|
}
|
|
480
|
-
},
|
|
481
|
+
}, oe = {
|
|
481
482
|
name: "fetch",
|
|
482
483
|
description: "Make HTTP request to URL",
|
|
483
484
|
args: {
|
|
@@ -486,15 +487,15 @@ const N = {
|
|
|
486
487
|
headers: { type: "object", description: "HTTP headers to send", default: {} },
|
|
487
488
|
body: { type: "object", description: "HTTP body to send" }
|
|
488
489
|
},
|
|
489
|
-
fn: (u) => new
|
|
490
|
-
},
|
|
490
|
+
fn: (u) => new v({ url: u.url, headers: u.headers }).request({ method: u.method || "GET", body: u.body })
|
|
491
|
+
}, C = {
|
|
491
492
|
name: "exec_javascript",
|
|
492
493
|
description: "Execute commonjs javascript",
|
|
493
494
|
args: {
|
|
494
495
|
code: { type: "string", description: "CommonJS javascript", required: !0 }
|
|
495
496
|
},
|
|
496
497
|
fn: async (u) => {
|
|
497
|
-
const t =
|
|
498
|
+
const t = P(null), e = await A({ console: t }, u.code, !0).catch((n) => t.output.error.push(n));
|
|
498
499
|
return { ...t.output, return: e, stdout: void 0, stderr: void 0 };
|
|
499
500
|
}
|
|
500
501
|
}, G = {
|
|
@@ -503,7 +504,7 @@ const N = {
|
|
|
503
504
|
args: {
|
|
504
505
|
code: { type: "string", description: "CommonJS javascript", required: !0 }
|
|
505
506
|
},
|
|
506
|
-
fn: async (u) => ({ result:
|
|
507
|
+
fn: async (u) => ({ result: R`python -c "${u.code}"` })
|
|
507
508
|
}, se = {
|
|
508
509
|
name: "search",
|
|
509
510
|
description: "Use a search engine to find relevant URLs, should be changed with fetch to scrape sources",
|
|
@@ -514,25 +515,25 @@ const N = {
|
|
|
514
515
|
fn: async (u) => {
|
|
515
516
|
const t = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(u.query)}`, {
|
|
516
517
|
headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Accept-Language": "en-US,en;q=0.9" }
|
|
517
|
-
}).then((
|
|
518
|
+
}).then((i) => i.text());
|
|
518
519
|
let e, n = /<a .*?href="(.+?)".+?<\/a>/g;
|
|
519
|
-
const
|
|
520
|
+
const a = new E();
|
|
520
521
|
for (; (e = n.exec(t)) !== null; ) {
|
|
521
|
-
let
|
|
522
|
-
if (
|
|
522
|
+
let i = /uddg=(.+)&?/.exec(decodeURIComponent(e[1]))?.[1];
|
|
523
|
+
if (i && (i = decodeURIComponent(i)), i && a.add(i), a.size >= (u.length || 5)) break;
|
|
523
524
|
}
|
|
524
|
-
return
|
|
525
|
+
return a;
|
|
525
526
|
}
|
|
526
527
|
};
|
|
527
528
|
export {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
529
|
+
ee as Ai,
|
|
530
|
+
I as Anthropic,
|
|
531
|
+
z as CliTool,
|
|
532
|
+
te as DateTimeTool,
|
|
533
|
+
ne as ExecTool,
|
|
534
|
+
oe as FetchTool,
|
|
535
|
+
C as JSTool,
|
|
536
|
+
N as LLM,
|
|
536
537
|
G as PythonTool,
|
|
537
538
|
se as SearchTool
|
|
538
539
|
};
|