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