@ztimson/ai-utils 0.1.16 → 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 +14 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +216 -201
- 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,39 +1,33 @@
|
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}), i.content = i.content.filter((o) => o.type == "text").map((o) => o.text).join(`
|
|
28
|
-
|
|
29
|
-
`)), i.content) {
|
|
30
|
-
const o = e.at(-1);
|
|
31
|
-
o && o.role == "assistant" && i.role == "assistant" ? o.content += `
|
|
19
|
+
for (let e = 0; e < t.length; e++) {
|
|
20
|
+
const n = e;
|
|
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(`
|
|
32
27
|
|
|
33
|
-
`
|
|
34
|
-
}
|
|
28
|
+
`)), t[n].timestamp || (t[n].timestamp = Date.now());
|
|
35
29
|
}
|
|
36
|
-
return e;
|
|
30
|
+
return t.filter((e) => !!e.content);
|
|
37
31
|
}
|
|
38
32
|
fromStandard(t) {
|
|
39
33
|
for (let e = 0; e < t.length; e++)
|
|
@@ -42,17 +36,17 @@ class L extends k {
|
|
|
42
36
|
t.splice(
|
|
43
37
|
e,
|
|
44
38
|
1,
|
|
45
|
-
{ role: "assistant", content: [{ type: "tool_use", id: n.id, name: n.name, input: n.args }] },
|
|
46
|
-
{ 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() }
|
|
47
41
|
), e++;
|
|
48
42
|
}
|
|
49
43
|
return t;
|
|
50
44
|
}
|
|
51
45
|
ask(t, e = {}) {
|
|
52
|
-
const n = new AbortController(),
|
|
53
|
-
let c = this.fromStandard([...e.history || [], { role: "user", content: t }]);
|
|
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() }]);
|
|
54
48
|
e.compress && (c = await this.ai.llm.compress(c, e.compress.max, e.compress.min, e));
|
|
55
|
-
const
|
|
49
|
+
const d = {
|
|
56
50
|
model: e.model || this.model,
|
|
57
51
|
max_tokens: e.max_tokens || this.ai.options.max_tokens || 4096,
|
|
58
52
|
system: e.system || this.ai.options.system || "",
|
|
@@ -62,154 +56,166 @@ class L extends k {
|
|
|
62
56
|
description: a.description,
|
|
63
57
|
input_schema: {
|
|
64
58
|
type: "object",
|
|
65
|
-
properties: a.args ?
|
|
66
|
-
required: a.args ? Object.entries(a.args).filter((
|
|
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]) : []
|
|
67
61
|
},
|
|
68
62
|
fn: void 0
|
|
69
63
|
})),
|
|
70
64
|
messages: c,
|
|
71
65
|
stream: !!e.stream
|
|
72
66
|
};
|
|
73
|
-
let
|
|
67
|
+
let i;
|
|
68
|
+
const r = [];
|
|
74
69
|
do {
|
|
75
|
-
if (
|
|
76
|
-
|
|
70
|
+
if (i = await this.client.messages.create(d), e.stream) {
|
|
71
|
+
r.length && e.stream({ text: `
|
|
77
72
|
|
|
78
|
-
` }),
|
|
79
|
-
for await (const
|
|
73
|
+
` }), i.content = [];
|
|
74
|
+
for await (const s of i) {
|
|
80
75
|
if (n.signal.aborted) break;
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
else if (
|
|
84
|
-
if (
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
} else
|
|
88
|
-
else if (
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
} 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")
|
|
92
87
|
break;
|
|
93
88
|
}
|
|
94
89
|
}
|
|
95
|
-
|
|
90
|
+
r.push({ role: "assistant", content: i.content, timestamp: Date.now() });
|
|
91
|
+
const a = i.content.filter((s) => s.type === "tool_use");
|
|
96
92
|
if (a.length && !n.signal.aborted) {
|
|
97
|
-
c.push({ role: "assistant", content:
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
if (!
|
|
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" };
|
|
101
97
|
try {
|
|
102
|
-
const
|
|
103
|
-
return { type: "tool_result", tool_use_id:
|
|
104
|
-
} catch (
|
|
105
|
-
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" };
|
|
106
102
|
}
|
|
107
|
-
}));
|
|
108
|
-
c.push(
|
|
103
|
+
})), timestamp: Date.now() };
|
|
104
|
+
c.push(l), r.push(l), d.messages = c;
|
|
109
105
|
}
|
|
110
|
-
} while (!n.signal.aborted &&
|
|
111
|
-
|
|
112
|
-
role: "assistant",
|
|
113
|
-
content: l.content.filter((a) => a.type == "text").map((a) => a.text).join(`
|
|
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(`
|
|
114
108
|
|
|
115
|
-
`)
|
|
116
|
-
|
|
109
|
+
`)).filter((a) => a).join(`
|
|
110
|
+
|
|
111
|
+
`);
|
|
112
|
+
e.stream && e.stream({ done: !0 }), m(this.toStandard([...c, { role: "assistant", content: w, timestamp: Date.now() }]));
|
|
117
113
|
});
|
|
118
|
-
return Object.assign(
|
|
114
|
+
return Object.assign(o, { abort: () => n.abort() });
|
|
119
115
|
}
|
|
120
116
|
}
|
|
121
|
-
class
|
|
117
|
+
class I extends S {
|
|
122
118
|
constructor(t, e, n) {
|
|
123
|
-
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 });
|
|
124
120
|
}
|
|
125
121
|
client;
|
|
126
122
|
toStandard(t) {
|
|
127
|
-
for (let e = 0; e < t.length; e++)
|
|
123
|
+
for (let e = 0; e < t.length; e++) {
|
|
128
124
|
if (t[e].role == "assistant" && t[e].tool_calls)
|
|
129
125
|
t[e].content ? delete t[e].tool_calls : (t.splice(e, 1), e--);
|
|
130
126
|
else if (t[e].role == "tool") {
|
|
131
127
|
const n = t[e].content.startsWith('{"error":');
|
|
132
|
-
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 };
|
|
133
129
|
}
|
|
130
|
+
t[e]?.timestamp || (t[e].timestamp = Date.now());
|
|
131
|
+
}
|
|
134
132
|
return t;
|
|
135
133
|
}
|
|
136
134
|
fromStandard(t) {
|
|
137
|
-
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 });
|
|
138
136
|
}
|
|
139
137
|
ask(t, e = {}) {
|
|
140
|
-
const n = new AbortController(),
|
|
141
|
-
let c = e.system || this.ai.options.system,
|
|
142
|
-
|
|
143
|
-
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 = {
|
|
144
142
|
model: e.model || this.model,
|
|
145
|
-
messages:
|
|
143
|
+
messages: d,
|
|
146
144
|
stream: !!e.stream,
|
|
147
145
|
signal: n.signal,
|
|
148
146
|
options: {
|
|
149
147
|
temperature: e.temperature || this.ai.options.temperature || 0.7,
|
|
150
148
|
num_predict: e.max_tokens || this.ai.options.max_tokens || 4096
|
|
151
149
|
},
|
|
152
|
-
tools: (e.tools || this.ai.options.tools || []).map((
|
|
150
|
+
tools: (e.tools || this.ai.options.tools || []).map((s) => ({
|
|
153
151
|
type: "function",
|
|
154
152
|
function: {
|
|
155
|
-
name:
|
|
156
|
-
description:
|
|
153
|
+
name: s.name,
|
|
154
|
+
description: s.description,
|
|
157
155
|
parameters: {
|
|
158
156
|
type: "object",
|
|
159
|
-
properties:
|
|
160
|
-
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]) : []
|
|
161
159
|
}
|
|
162
160
|
}
|
|
163
161
|
}))
|
|
164
162
|
};
|
|
165
|
-
let
|
|
163
|
+
let r;
|
|
164
|
+
const w = [];
|
|
166
165
|
do {
|
|
167
|
-
if (
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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;
|
|
171
172
|
}
|
|
172
|
-
if (
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
if (!
|
|
177
|
-
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;
|
|
178
179
|
try {
|
|
179
|
-
const
|
|
180
|
-
return { role: "tool", tool_name:
|
|
181
|
-
} catch (
|
|
182
|
-
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() };
|
|
183
184
|
}
|
|
184
185
|
}));
|
|
185
|
-
|
|
186
|
+
d.push(...s), w.push(...s), i.messages = d;
|
|
186
187
|
}
|
|
187
|
-
} while (!n.signal.aborted &&
|
|
188
|
-
|
|
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() }]));
|
|
189
193
|
});
|
|
190
|
-
return Object.assign(
|
|
194
|
+
return Object.assign(o, { abort: () => n.abort() });
|
|
191
195
|
}
|
|
192
196
|
}
|
|
193
|
-
class J extends
|
|
197
|
+
class J extends S {
|
|
194
198
|
constructor(t, e, n) {
|
|
195
|
-
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 });
|
|
196
200
|
}
|
|
197
201
|
client;
|
|
198
202
|
toStandard(t) {
|
|
199
203
|
for (let e = 0; e < t.length; e++) {
|
|
200
204
|
const n = t[e];
|
|
201
205
|
if (n.role === "assistant" && n.tool_calls) {
|
|
202
|
-
const
|
|
206
|
+
const o = n.tool_calls.map((m) => ({
|
|
203
207
|
role: "tool",
|
|
204
|
-
id:
|
|
205
|
-
name:
|
|
206
|
-
args:
|
|
208
|
+
id: m.id,
|
|
209
|
+
name: m.function.name,
|
|
210
|
+
args: b(m.function.arguments, {}),
|
|
211
|
+
timestamp: n.timestamp
|
|
207
212
|
}));
|
|
208
|
-
t.splice(e, 1, ...
|
|
213
|
+
t.splice(e, 1, ...o), e += o.length - 1;
|
|
209
214
|
} else if (n.role === "tool" && n.content) {
|
|
210
|
-
const
|
|
211
|
-
|
|
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--;
|
|
212
217
|
}
|
|
218
|
+
t[e]?.timestamp || (t[e].timestamp = Date.now());
|
|
213
219
|
}
|
|
214
220
|
return t;
|
|
215
221
|
}
|
|
@@ -219,69 +225,78 @@ class J extends k {
|
|
|
219
225
|
content: null,
|
|
220
226
|
tool_calls: [{ id: n.id, type: "function", function: { name: n.name, arguments: JSON.stringify(n.args) } }],
|
|
221
227
|
refusal: null,
|
|
222
|
-
annotations: []
|
|
228
|
+
annotations: [],
|
|
229
|
+
timestamp: n.timestamp
|
|
223
230
|
}, {
|
|
224
231
|
role: "tool",
|
|
225
232
|
tool_call_id: n.id,
|
|
226
|
-
content: n.error || n.content
|
|
233
|
+
content: n.error || n.content,
|
|
234
|
+
timestamp: Date.now()
|
|
227
235
|
}) : e.push(n), e), []);
|
|
228
236
|
}
|
|
229
237
|
ask(t, e = {}) {
|
|
230
|
-
const n = new AbortController(),
|
|
231
|
-
let c = this.fromStandard([...e.history || [], { role: "user", content: t }]);
|
|
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() }]);
|
|
232
240
|
e.compress && (c = await this.ai.llm.compress(c, e.compress.max, e.compress.min, e));
|
|
233
|
-
const
|
|
241
|
+
const d = {
|
|
234
242
|
model: e.model || this.model,
|
|
235
243
|
messages: c,
|
|
236
244
|
stream: !!e.stream,
|
|
237
245
|
max_tokens: e.max_tokens || this.ai.options.max_tokens || 4096,
|
|
238
246
|
temperature: e.temperature || this.ai.options.temperature || 0.7,
|
|
239
|
-
tools: (e.tools || this.ai.options.tools || []).map((
|
|
247
|
+
tools: (e.tools || this.ai.options.tools || []).map((a) => ({
|
|
240
248
|
type: "function",
|
|
241
249
|
function: {
|
|
242
|
-
name:
|
|
243
|
-
description:
|
|
250
|
+
name: a.name,
|
|
251
|
+
description: a.description,
|
|
244
252
|
parameters: {
|
|
245
253
|
type: "object",
|
|
246
|
-
properties:
|
|
247
|
-
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]) : []
|
|
248
256
|
}
|
|
249
257
|
}
|
|
250
258
|
}))
|
|
251
259
|
};
|
|
252
|
-
let
|
|
260
|
+
let i;
|
|
261
|
+
const r = [];
|
|
253
262
|
do {
|
|
254
|
-
if (
|
|
255
|
-
|
|
256
|
-
|
|
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) {
|
|
257
268
|
if (n.signal.aborted) break;
|
|
258
|
-
|
|
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);
|
|
259
270
|
}
|
|
260
271
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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() };
|
|
267
279
|
try {
|
|
268
|
-
const
|
|
269
|
-
return { role: "tool", tool_call_id:
|
|
270
|
-
} catch (
|
|
271
|
-
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() };
|
|
272
284
|
}
|
|
273
285
|
}));
|
|
274
|
-
c.push(...
|
|
286
|
+
c.push(...s), r.push(...s), d.messages = c;
|
|
275
287
|
}
|
|
276
|
-
} while (!n.signal.aborted &&
|
|
277
|
-
|
|
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() }]));
|
|
278
293
|
});
|
|
279
|
-
return Object.assign(
|
|
294
|
+
return Object.assign(o, { abort: () => n.abort() });
|
|
280
295
|
}
|
|
281
296
|
}
|
|
282
297
|
class W {
|
|
283
298
|
constructor(t, e) {
|
|
284
|
-
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));
|
|
285
300
|
}
|
|
286
301
|
providers = {};
|
|
287
302
|
/**
|
|
@@ -303,17 +318,17 @@ class W {
|
|
|
303
318
|
* @param {LLMRequest} options LLM options
|
|
304
319
|
* @returns {Promise<LLMMessage[]>} New chat history will summary at index 0
|
|
305
320
|
*/
|
|
306
|
-
async compress(t, e, n,
|
|
321
|
+
async compress(t, e, n, o) {
|
|
307
322
|
if (this.estimateTokens(t) < e) return t;
|
|
308
|
-
let
|
|
309
|
-
for (let
|
|
310
|
-
if (
|
|
323
|
+
let m = 0, u = 0;
|
|
324
|
+
for (let r of t.toReversed())
|
|
325
|
+
if (u += this.estimateTokens(r.content), u < n) m++;
|
|
311
326
|
else break;
|
|
312
|
-
if (t.length <=
|
|
313
|
-
const c =
|
|
314
|
-
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(`
|
|
315
330
|
|
|
316
|
-
`), 250,
|
|
331
|
+
`), 250, o)}`, timestamp: Date.now() }, ...c];
|
|
317
332
|
}
|
|
318
333
|
/**
|
|
319
334
|
* Estimate variable as tokens
|
|
@@ -335,7 +350,7 @@ class W {
|
|
|
335
350
|
system: "Respond using a JSON blob",
|
|
336
351
|
...e
|
|
337
352
|
});
|
|
338
|
-
return n?.[0]?.content ?
|
|
353
|
+
return n?.[0]?.content ? b(new RegExp("{[sS]*}").exec(n[0].content), {}) : {};
|
|
339
354
|
}
|
|
340
355
|
/**
|
|
341
356
|
* Create a summary of some text
|
|
@@ -345,10 +360,10 @@ class W {
|
|
|
345
360
|
* @returns {Promise<string>} Summary
|
|
346
361
|
*/
|
|
347
362
|
summarize(t, e, n) {
|
|
348
|
-
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);
|
|
349
364
|
}
|
|
350
365
|
}
|
|
351
|
-
class
|
|
366
|
+
class Z {
|
|
352
367
|
constructor(t) {
|
|
353
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());
|
|
354
369
|
}
|
|
@@ -366,12 +381,12 @@ class X {
|
|
|
366
381
|
if (!this.options.whisper?.binary) throw new Error("Whisper not configured");
|
|
367
382
|
let n = () => {
|
|
368
383
|
};
|
|
369
|
-
return { response: new Promise((
|
|
384
|
+
return { response: new Promise((m, u) => {
|
|
370
385
|
this.downloadAsrModel(e).then((c) => {
|
|
371
|
-
let
|
|
372
|
-
const
|
|
373
|
-
n = () =>
|
|
374
|
-
|
|
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}`));
|
|
375
390
|
});
|
|
376
391
|
});
|
|
377
392
|
}), abort: n };
|
|
@@ -386,7 +401,7 @@ class X {
|
|
|
386
401
|
if (!this.options.whisper?.binary) throw new Error("Whisper not configured");
|
|
387
402
|
t.endsWith(".bin") || (t += ".bin");
|
|
388
403
|
const e = O.join(this.options.whisper.path, t);
|
|
389
|
-
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]);
|
|
390
405
|
}
|
|
391
406
|
/**
|
|
392
407
|
* Convert image to text using Optical Character Recognition
|
|
@@ -400,9 +415,9 @@ class X {
|
|
|
400
415
|
e?.terminate();
|
|
401
416
|
},
|
|
402
417
|
response: new Promise(async (n) => {
|
|
403
|
-
e = await
|
|
404
|
-
const { data:
|
|
405
|
-
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);
|
|
406
421
|
})
|
|
407
422
|
};
|
|
408
423
|
}
|
|
@@ -414,46 +429,46 @@ class X {
|
|
|
414
429
|
*/
|
|
415
430
|
semanticSimilarity(t, ...e) {
|
|
416
431
|
if (e.length < 2) throw new Error("Requires at least 2 strings to compare");
|
|
417
|
-
const n = (c,
|
|
418
|
-
if (c.length !==
|
|
419
|
-
const
|
|
420
|
-
return
|
|
421
|
-
},
|
|
422
|
-
return { avg:
|
|
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 };
|
|
423
438
|
}
|
|
424
439
|
}
|
|
425
|
-
const
|
|
440
|
+
const N = {
|
|
426
441
|
name: "cli",
|
|
427
442
|
description: "Use the command line interface, returns any output",
|
|
428
443
|
args: { command: { type: "string", description: "Command to run", required: !0 } },
|
|
429
|
-
fn: (
|
|
430
|
-
},
|
|
444
|
+
fn: (p) => $`${p.command}`
|
|
445
|
+
}, ee = {
|
|
431
446
|
name: "get_datetime",
|
|
432
447
|
description: "Get current date and time",
|
|
433
448
|
args: {},
|
|
434
449
|
fn: async () => (/* @__PURE__ */ new Date()).toISOString()
|
|
435
|
-
},
|
|
450
|
+
}, te = {
|
|
436
451
|
name: "exec",
|
|
437
452
|
description: "Run code/scripts",
|
|
438
453
|
args: {
|
|
439
454
|
language: { type: "string", description: "Execution language", enum: ["cli", "node", "python"], required: !0 },
|
|
440
455
|
code: { type: "string", description: "Code to execute", required: !0 }
|
|
441
456
|
},
|
|
442
|
-
fn: async (
|
|
457
|
+
fn: async (p, t) => {
|
|
443
458
|
try {
|
|
444
|
-
switch (
|
|
459
|
+
switch (p.type) {
|
|
445
460
|
case "bash":
|
|
446
|
-
return await
|
|
461
|
+
return await N.fn({ command: p.code }, t);
|
|
447
462
|
case "node":
|
|
448
|
-
return await
|
|
463
|
+
return await z.fn({ code: p.code }, t);
|
|
449
464
|
case "python":
|
|
450
|
-
return await
|
|
465
|
+
return await G.fn({ code: p.code }, t);
|
|
451
466
|
}
|
|
452
467
|
} catch (e) {
|
|
453
468
|
return { error: e?.message || e.toString() };
|
|
454
469
|
}
|
|
455
470
|
}
|
|
456
|
-
},
|
|
471
|
+
}, ne = {
|
|
457
472
|
name: "fetch",
|
|
458
473
|
description: "Make HTTP request to URL",
|
|
459
474
|
args: {
|
|
@@ -462,54 +477,54 @@ const I = {
|
|
|
462
477
|
headers: { type: "object", description: "HTTP headers to send", default: {} },
|
|
463
478
|
body: { type: "object", description: "HTTP body to send" }
|
|
464
479
|
},
|
|
465
|
-
fn: (
|
|
466
|
-
},
|
|
480
|
+
fn: (p) => new T({ url: p.url, headers: p.headers }).request({ method: p.method || "GET", body: p.body })
|
|
481
|
+
}, z = {
|
|
467
482
|
name: "exec_javascript",
|
|
468
483
|
description: "Execute commonjs javascript",
|
|
469
484
|
args: {
|
|
470
485
|
code: { type: "string", description: "CommonJS javascript", required: !0 }
|
|
471
486
|
},
|
|
472
|
-
fn: async (
|
|
473
|
-
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));
|
|
474
489
|
return { ...t.output, return: e, stdout: void 0, stderr: void 0 };
|
|
475
490
|
}
|
|
476
|
-
},
|
|
491
|
+
}, G = {
|
|
477
492
|
name: "exec_javascript",
|
|
478
493
|
description: "Execute commonjs javascript",
|
|
479
494
|
args: {
|
|
480
495
|
code: { type: "string", description: "CommonJS javascript", required: !0 }
|
|
481
496
|
},
|
|
482
|
-
fn: async (
|
|
483
|
-
},
|
|
497
|
+
fn: async (p) => ({ result: L`python -c "${p.code}"` })
|
|
498
|
+
}, se = {
|
|
484
499
|
name: "search",
|
|
485
500
|
description: "Use a search engine to find relevant URLs, should be changed with fetch to scrape sources",
|
|
486
501
|
args: {
|
|
487
502
|
query: { type: "string", description: "Search string", required: !0 },
|
|
488
503
|
length: { type: "string", description: "Number of results to return", default: 5 }
|
|
489
504
|
},
|
|
490
|
-
fn: async (
|
|
491
|
-
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)}`, {
|
|
492
507
|
headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Accept-Language": "en-US,en;q=0.9" }
|
|
493
|
-
}).then((
|
|
508
|
+
}).then((m) => m.text());
|
|
494
509
|
let e, n = /<a .*?href="(.+?)".+?<\/a>/g;
|
|
495
|
-
const
|
|
510
|
+
const o = new P();
|
|
496
511
|
for (; (e = n.exec(t)) !== null; ) {
|
|
497
|
-
let
|
|
498
|
-
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;
|
|
499
514
|
}
|
|
500
|
-
return
|
|
515
|
+
return o;
|
|
501
516
|
}
|
|
502
517
|
};
|
|
503
518
|
export {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
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,
|
|
511
526
|
W as LLM,
|
|
512
|
-
|
|
513
|
-
|
|
527
|
+
G as PythonTool,
|
|
528
|
+
se as SearchTool
|
|
514
529
|
};
|
|
515
530
|
//# sourceMappingURL=index.mjs.map
|