@ztimson/ai-utils 0.4.1 → 0.5.2
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/ai.d.ts +3 -1
- package/dist/antrhopic.d.ts +2 -2
- package/dist/embedder.js +1 -1
- package/dist/embedder.js.map +1 -1
- package/dist/embedder.mjs +6 -6
- package/dist/embedder.mjs.map +1 -1
- package/dist/index.js +18 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +326 -256
- package/dist/index.mjs.map +1 -1
- package/dist/llm.d.ts +45 -8
- package/dist/open-ai.d.ts +2 -2
- package/dist/provider.d.ts +2 -2
- package/dist/tools.d.ts +2 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,239 +1,237 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import { objectMap as k, JSONAttemptParse as
|
|
1
|
+
import * as S from "node:os";
|
|
2
|
+
import { objectMap as k, JSONAttemptParse as y, findByProp as x, JSONSanitize as b, clean as T, Http as M, consoleInterceptor as q, fn as P, ASet as E } from "@ztimson/utils";
|
|
3
3
|
import { Anthropic as $ } from "@anthropic-ai/sdk";
|
|
4
|
-
import { OpenAI as
|
|
5
|
-
import { Worker as
|
|
6
|
-
import { fileURLToPath as
|
|
7
|
-
import { join as
|
|
8
|
-
import { spawn as
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import { createWorker as
|
|
4
|
+
import { OpenAI as A } from "openai";
|
|
5
|
+
import { Worker as v } from "worker_threads";
|
|
6
|
+
import { fileURLToPath as O } from "url";
|
|
7
|
+
import { join as R, dirname as U } from "path";
|
|
8
|
+
import { spawn as W } from "node:child_process";
|
|
9
|
+
import w from "node:fs/promises";
|
|
10
|
+
import L from "node:path";
|
|
11
|
+
import { createWorker as I } from "tesseract.js";
|
|
12
12
|
import "./embedder.mjs";
|
|
13
|
-
import * as
|
|
13
|
+
import * as N from "cheerio";
|
|
14
14
|
import { $ as C, $Sync as D } from "@ztimson/node-utils";
|
|
15
|
-
class
|
|
15
|
+
class j {
|
|
16
16
|
}
|
|
17
|
-
class
|
|
18
|
-
constructor(t, e,
|
|
19
|
-
super(), this.ai = t, this.apiToken = e, this.model =
|
|
17
|
+
class J extends j {
|
|
18
|
+
constructor(t, e, s) {
|
|
19
|
+
super(), this.ai = t, this.apiToken = e, this.model = s, this.client = new $({ apiKey: e });
|
|
20
20
|
}
|
|
21
21
|
client;
|
|
22
22
|
toStandard(t) {
|
|
23
23
|
for (let e = 0; e < t.length; e++) {
|
|
24
|
-
const
|
|
25
|
-
typeof t[
|
|
26
|
-
|
|
27
|
-
}) : t[
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
}), t[
|
|
24
|
+
const s = e;
|
|
25
|
+
typeof t[s].content != "string" && (t[s].role == "assistant" ? t[s].content.filter((r) => r.type == "tool_use").forEach((r) => {
|
|
26
|
+
t.splice(e + 1, 0, { role: "tool", id: r.id, name: r.name, args: r.input, timestamp: Date.now() });
|
|
27
|
+
}) : t[s].role == "user" && t[s].content.filter((r) => r.type == "tool_result").forEach((r) => {
|
|
28
|
+
const c = t.find((o) => o.id == r.tool_use_id);
|
|
29
|
+
c[r.is_error ? "error" : "content"] = r.content;
|
|
30
|
+
}), t[s].content = t[s].content.filter((r) => r.type == "text").map((r) => r.text).join(`
|
|
31
31
|
|
|
32
|
-
`)), t[
|
|
32
|
+
`), t[s].content || t.splice(s, 1)), t[s].timestamp || (t[s].timestamp = Date.now());
|
|
33
33
|
}
|
|
34
34
|
return t.filter((e) => !!e.content);
|
|
35
35
|
}
|
|
36
36
|
fromStandard(t) {
|
|
37
37
|
for (let e = 0; e < t.length; e++)
|
|
38
38
|
if (t[e].role == "tool") {
|
|
39
|
-
const
|
|
39
|
+
const s = t[e];
|
|
40
40
|
t.splice(
|
|
41
41
|
e,
|
|
42
42
|
1,
|
|
43
|
-
{ role: "assistant", content: [{ type: "tool_use", id:
|
|
44
|
-
{ role: "user", content: [{ type: "tool_result", tool_use_id:
|
|
43
|
+
{ role: "assistant", content: [{ type: "tool_use", id: s.id, name: s.name, input: s.args }] },
|
|
44
|
+
{ role: "user", content: [{ type: "tool_result", tool_use_id: s.id, is_error: !!s.error, content: s.error || s.content }] }
|
|
45
45
|
), e++;
|
|
46
46
|
}
|
|
47
|
-
return t.map(({ timestamp: e, ...
|
|
47
|
+
return t.map(({ timestamp: e, ...s }) => s);
|
|
48
48
|
}
|
|
49
49
|
ask(t, e = {}) {
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
e.
|
|
53
|
-
const d = e.tools || this.ai.options.llm?.tools || [], u = {
|
|
50
|
+
const s = new AbortController();
|
|
51
|
+
return Object.assign(new Promise(async (r, c) => {
|
|
52
|
+
const o = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]), a = e.tools || this.ai.options.llm?.tools || [], m = {
|
|
54
53
|
model: e.model || this.model,
|
|
55
54
|
max_tokens: e.max_tokens || this.ai.options.llm?.max_tokens || 4096,
|
|
56
55
|
system: e.system || this.ai.options.llm?.system || "",
|
|
57
56
|
temperature: e.temperature || this.ai.options.llm?.temperature || 0.7,
|
|
58
|
-
tools:
|
|
57
|
+
tools: a.map((l) => ({
|
|
59
58
|
name: l.name,
|
|
60
59
|
description: l.description,
|
|
61
60
|
input_schema: {
|
|
62
61
|
type: "object",
|
|
63
|
-
properties: l.args ? k(l.args, (
|
|
64
|
-
required: l.args ? Object.entries(l.args).filter((
|
|
62
|
+
properties: l.args ? k(l.args, (i, u) => ({ ...u, required: void 0 })) : {},
|
|
63
|
+
required: l.args ? Object.entries(l.args).filter((i) => i[1].required).map((i) => i[0]) : []
|
|
65
64
|
},
|
|
66
65
|
fn: void 0
|
|
67
66
|
})),
|
|
68
|
-
messages:
|
|
67
|
+
messages: o,
|
|
69
68
|
stream: !!e.stream
|
|
70
69
|
};
|
|
71
|
-
let
|
|
70
|
+
let n, d = !0;
|
|
72
71
|
do {
|
|
73
|
-
if (
|
|
74
|
-
throw
|
|
72
|
+
if (n = await this.client.messages.create(m).catch((i) => {
|
|
73
|
+
throw i.message += `
|
|
75
74
|
|
|
76
75
|
Messages:
|
|
77
|
-
${JSON.stringify(
|
|
76
|
+
${JSON.stringify(o, null, 2)}`, i;
|
|
78
77
|
}), e.stream) {
|
|
79
|
-
|
|
78
|
+
d ? d = !1 : e.stream({ text: `
|
|
80
79
|
|
|
81
|
-
` }),
|
|
82
|
-
for await (const
|
|
83
|
-
if (
|
|
84
|
-
if (
|
|
85
|
-
|
|
86
|
-
else if (
|
|
87
|
-
if (
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
} else
|
|
91
|
-
else if (
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
} else if (
|
|
80
|
+
` }), n.content = [];
|
|
81
|
+
for await (const i of n) {
|
|
82
|
+
if (s.signal.aborted) break;
|
|
83
|
+
if (i.type === "content_block_start")
|
|
84
|
+
i.content_block.type === "text" ? n.content.push({ type: "text", text: "" }) : i.content_block.type === "tool_use" && n.content.push({ type: "tool_use", id: i.content_block.id, name: i.content_block.name, input: "" });
|
|
85
|
+
else if (i.type === "content_block_delta")
|
|
86
|
+
if (i.delta.type === "text_delta") {
|
|
87
|
+
const u = i.delta.text;
|
|
88
|
+
n.content.at(-1).text += u, e.stream({ text: u });
|
|
89
|
+
} else i.delta.type === "input_json_delta" && (n.content.at(-1).input += i.delta.partial_json);
|
|
90
|
+
else if (i.type === "content_block_stop") {
|
|
91
|
+
const u = n.content.at(-1);
|
|
92
|
+
u.input != null && (u.input = u.input ? y(u.input, {}) : {});
|
|
93
|
+
} else if (i.type === "message_stop")
|
|
95
94
|
break;
|
|
96
95
|
}
|
|
97
96
|
}
|
|
98
|
-
const l =
|
|
99
|
-
if (l.length && !
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
if (e.stream && e.stream({ tool:
|
|
97
|
+
const l = n.content.filter((i) => i.type === "tool_use");
|
|
98
|
+
if (l.length && !s.signal.aborted) {
|
|
99
|
+
o.push({ role: "assistant", content: n.content });
|
|
100
|
+
const i = await Promise.all(l.map(async (u) => {
|
|
101
|
+
const h = a.find(x("name", u.name));
|
|
102
|
+
if (e.stream && e.stream({ tool: u.name }), !h) return { tool_use_id: u.id, is_error: !0, content: "Tool not found" };
|
|
104
103
|
try {
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
console.log(typeof h.fn);
|
|
105
|
+
const f = await h.fn(u.input, e?.stream, this.ai);
|
|
106
|
+
return { type: "tool_result", tool_use_id: u.id, content: b(f) };
|
|
107
107
|
} catch (f) {
|
|
108
|
-
return { type: "tool_result", tool_use_id:
|
|
108
|
+
return { type: "tool_result", tool_use_id: u.id, is_error: !0, content: f?.message || f?.toString() || "Unknown" };
|
|
109
109
|
}
|
|
110
110
|
}));
|
|
111
|
-
|
|
111
|
+
o.push({ role: "user", content: i }), m.messages = o;
|
|
112
112
|
}
|
|
113
|
-
} while (!
|
|
114
|
-
|
|
113
|
+
} while (!s.signal.aborted && n.content.some((l) => l.type === "tool_use"));
|
|
114
|
+
o.push({ role: "assistant", content: n.content.filter((l) => l.type == "text").map((l) => l.text).join(`
|
|
115
115
|
|
|
116
|
-
`) }
|
|
117
|
-
});
|
|
118
|
-
return Object.assign(o, { abort: () => n.abort() });
|
|
116
|
+
`) }), this.toStandard(o), e.stream && e.stream({ done: !0 }), e.history && e.history.splice(0, e.history.length, ...o), r(o.at(-1)?.content);
|
|
117
|
+
}), { abort: () => s.abort() });
|
|
119
118
|
}
|
|
120
119
|
}
|
|
121
|
-
class _ extends
|
|
122
|
-
constructor(t, e,
|
|
123
|
-
super(), this.ai = t, this.host = e, this.token =
|
|
120
|
+
class _ extends j {
|
|
121
|
+
constructor(t, e, s, r) {
|
|
122
|
+
super(), this.ai = t, this.host = e, this.token = s, this.model = r, this.client = new A(T({
|
|
124
123
|
baseURL: e,
|
|
125
|
-
apiKey:
|
|
124
|
+
apiKey: s
|
|
126
125
|
}));
|
|
127
126
|
}
|
|
128
127
|
client;
|
|
129
128
|
toStandard(t) {
|
|
130
129
|
for (let e = 0; e < t.length; e++) {
|
|
131
|
-
const
|
|
132
|
-
if (
|
|
133
|
-
const
|
|
130
|
+
const s = t[e];
|
|
131
|
+
if (s.role === "assistant" && s.tool_calls) {
|
|
132
|
+
const r = s.tool_calls.map((c) => ({
|
|
134
133
|
role: "tool",
|
|
135
|
-
id:
|
|
136
|
-
name:
|
|
137
|
-
args:
|
|
138
|
-
timestamp:
|
|
134
|
+
id: c.id,
|
|
135
|
+
name: c.function.name,
|
|
136
|
+
args: y(c.function.arguments, {}),
|
|
137
|
+
timestamp: s.timestamp
|
|
139
138
|
}));
|
|
140
|
-
t.splice(e, 1, ...
|
|
141
|
-
} else if (
|
|
142
|
-
const
|
|
143
|
-
|
|
139
|
+
t.splice(e, 1, ...r), e += r.length - 1;
|
|
140
|
+
} else if (s.role === "tool" && s.content) {
|
|
141
|
+
const r = t.find((c) => s.tool_call_id == c.id);
|
|
142
|
+
r && (s.content.includes('"error":') ? r.error = s.content : r.content = s.content), t.splice(e, 1), e--;
|
|
144
143
|
}
|
|
145
144
|
t[e]?.timestamp || (t[e].timestamp = Date.now());
|
|
146
145
|
}
|
|
147
146
|
return t;
|
|
148
147
|
}
|
|
149
148
|
fromStandard(t) {
|
|
150
|
-
return t.reduce((e,
|
|
151
|
-
if (
|
|
149
|
+
return t.reduce((e, s) => {
|
|
150
|
+
if (s.role === "tool")
|
|
152
151
|
e.push({
|
|
153
152
|
role: "assistant",
|
|
154
153
|
content: null,
|
|
155
|
-
tool_calls: [{ id:
|
|
154
|
+
tool_calls: [{ id: s.id, type: "function", function: { name: s.name, arguments: JSON.stringify(s.args) } }],
|
|
156
155
|
refusal: null,
|
|
157
156
|
annotations: []
|
|
158
157
|
}, {
|
|
159
158
|
role: "tool",
|
|
160
|
-
tool_call_id:
|
|
161
|
-
content:
|
|
159
|
+
tool_call_id: s.id,
|
|
160
|
+
content: s.error || s.content
|
|
162
161
|
});
|
|
163
162
|
else {
|
|
164
|
-
const { timestamp:
|
|
165
|
-
e.push(
|
|
163
|
+
const { timestamp: r, ...c } = s;
|
|
164
|
+
e.push(c);
|
|
166
165
|
}
|
|
167
166
|
return e;
|
|
168
167
|
}, []);
|
|
169
168
|
}
|
|
170
169
|
ask(t, e = {}) {
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
e.
|
|
174
|
-
const
|
|
170
|
+
const s = new AbortController();
|
|
171
|
+
return Object.assign(new Promise(async (r, c) => {
|
|
172
|
+
e.system && e.history?.[0]?.role != "system" && e.history?.splice(0, 0, { role: "system", content: e.system, timestamp: Date.now() });
|
|
173
|
+
const o = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]), a = e.tools || this.ai.options.llm?.tools || [], m = {
|
|
175
174
|
model: e.model || this.model,
|
|
176
|
-
messages:
|
|
175
|
+
messages: o,
|
|
177
176
|
stream: !!e.stream,
|
|
178
177
|
max_tokens: e.max_tokens || this.ai.options.llm?.max_tokens || 4096,
|
|
179
178
|
temperature: e.temperature || this.ai.options.llm?.temperature || 0.7,
|
|
180
|
-
tools:
|
|
179
|
+
tools: a.map((l) => ({
|
|
181
180
|
type: "function",
|
|
182
181
|
function: {
|
|
183
182
|
name: l.name,
|
|
184
183
|
description: l.description,
|
|
185
184
|
parameters: {
|
|
186
185
|
type: "object",
|
|
187
|
-
properties: l.args ? k(l.args, (
|
|
188
|
-
required: l.args ? Object.entries(l.args).filter((
|
|
186
|
+
properties: l.args ? k(l.args, (i, u) => ({ ...u, required: void 0 })) : {},
|
|
187
|
+
required: l.args ? Object.entries(l.args).filter((i) => i[1].required).map((i) => i[0]) : []
|
|
189
188
|
}
|
|
190
189
|
}
|
|
191
190
|
}))
|
|
192
191
|
};
|
|
193
|
-
let
|
|
192
|
+
let n, d = !0;
|
|
194
193
|
do {
|
|
195
|
-
if (
|
|
196
|
-
throw
|
|
194
|
+
if (n = await this.client.chat.completions.create(m).catch((i) => {
|
|
195
|
+
throw i.message += `
|
|
197
196
|
|
|
198
197
|
Messages:
|
|
199
|
-
${JSON.stringify(
|
|
198
|
+
${JSON.stringify(o, null, 2)}`, i;
|
|
200
199
|
}), e.stream) {
|
|
201
|
-
|
|
200
|
+
d ? d = !1 : e.stream({ text: `
|
|
202
201
|
|
|
203
|
-
` }),
|
|
204
|
-
for await (const
|
|
205
|
-
if (
|
|
206
|
-
|
|
202
|
+
` }), n.choices = [{ message: { content: "", tool_calls: [] } }];
|
|
203
|
+
for await (const i of n) {
|
|
204
|
+
if (s.signal.aborted) break;
|
|
205
|
+
i.choices[0].delta.content && (n.choices[0].message.content += i.choices[0].delta.content, e.stream({ text: i.choices[0].delta.content })), i.choices[0].delta.tool_calls && (n.choices[0].message.tool_calls = i.choices[0].delta.tool_calls);
|
|
207
206
|
}
|
|
208
207
|
}
|
|
209
|
-
const l =
|
|
210
|
-
if (l.length && !
|
|
211
|
-
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
if (e.stream && e.stream({ tool:
|
|
208
|
+
const l = n.choices[0].message.tool_calls || [];
|
|
209
|
+
if (l.length && !s.signal.aborted) {
|
|
210
|
+
o.push(n.choices[0].message);
|
|
211
|
+
const i = await Promise.all(l.map(async (u) => {
|
|
212
|
+
const h = a?.find(x("name", u.function.name));
|
|
213
|
+
if (e.stream && e.stream({ tool: u.function.name }), !h) return { role: "tool", tool_call_id: u.id, content: '{"error": "Tool not found"}' };
|
|
215
214
|
try {
|
|
216
|
-
const f =
|
|
217
|
-
return { role: "tool", tool_call_id:
|
|
215
|
+
const f = y(u.function.arguments, {}), g = await h.fn(f, e.stream, this.ai);
|
|
216
|
+
return { role: "tool", tool_call_id: u.id, content: b(g) };
|
|
218
217
|
} catch (f) {
|
|
219
|
-
return { role: "tool", tool_call_id:
|
|
218
|
+
return { role: "tool", tool_call_id: u.id, content: b({ error: f?.message || f?.toString() || "Unknown" }) };
|
|
220
219
|
}
|
|
221
220
|
}));
|
|
222
|
-
|
|
221
|
+
o.push(...i), m.messages = o;
|
|
223
222
|
}
|
|
224
|
-
} while (!
|
|
225
|
-
e.stream && e.stream({ done: !0 }),
|
|
226
|
-
});
|
|
227
|
-
return Object.assign(o, { abort: () => n.abort() });
|
|
223
|
+
} while (!s.signal.aborted && n.choices?.[0]?.message?.tool_calls?.length);
|
|
224
|
+
o.push({ role: "assistant", content: n.choices[0].message.content || "" }), this.toStandard(o), e.stream && e.stream({ done: !0 }), e.history && e.history.splice(0, e.history.length, ...o), r(o.at(-1)?.content);
|
|
225
|
+
}), { abort: () => s.abort() });
|
|
228
226
|
}
|
|
229
227
|
}
|
|
230
|
-
class
|
|
228
|
+
class H {
|
|
231
229
|
constructor(t) {
|
|
232
|
-
this.ai = t, this.embedWorker = new R(
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
}), t.options.llm?.models && Object.entries(t.options.llm.models).forEach(([e,
|
|
236
|
-
this.defaultModel || (this.defaultModel = e),
|
|
230
|
+
this.ai = t, this.embedWorker = new v(R(U(O(import.meta.url)), "embedder.js")), this.embedWorker.on("message", ({ id: e, embedding: s }) => {
|
|
231
|
+
const r = this.embedQueue.get(e);
|
|
232
|
+
r && (r.resolve(s), this.embedQueue.delete(e));
|
|
233
|
+
}), t.options.llm?.models && Object.entries(t.options.llm.models).forEach(([e, s]) => {
|
|
234
|
+
this.defaultModel || (this.defaultModel = e), s.proto == "anthropic" ? this.models[e] = new J(this.ai, s.token, e) : s.proto == "ollama" ? this.models[e] = new _(this.ai, s.host, "not-needed", e) : s.proto == "openai" && (this.models[e] = new _(this.ai, s.host || null, s.token, e));
|
|
237
235
|
});
|
|
238
236
|
}
|
|
239
237
|
embedWorker = null;
|
|
@@ -245,72 +243,146 @@ class I {
|
|
|
245
243
|
* Chat with LLM
|
|
246
244
|
* @param {string} message Question
|
|
247
245
|
* @param {LLMRequest} options Configuration options and chat history
|
|
248
|
-
* @returns {{abort: () => void, response: Promise<
|
|
246
|
+
* @returns {{abort: () => void, response: Promise<string>}} Function to abort response and chat history
|
|
249
247
|
*/
|
|
250
248
|
ask(t, e = {}) {
|
|
251
|
-
const
|
|
252
|
-
if (!this.models[
|
|
253
|
-
|
|
249
|
+
const s = e.model || this.defaultModel;
|
|
250
|
+
if (!this.models[s]) throw new Error(`Model does not exist: ${s}`);
|
|
251
|
+
let r = () => {
|
|
252
|
+
};
|
|
253
|
+
return Object.assign(new Promise(async (c) => {
|
|
254
|
+
if (e.history || (e.history = []), e.memory) {
|
|
255
|
+
e.system = (e.system || "") + `
|
|
256
|
+
You have passive persistent memory never make any mention of your memory capabilities and what you can/cannot remember
|
|
257
|
+
`;
|
|
258
|
+
const a = async (n, d, l = 50) => {
|
|
259
|
+
const [i, u] = await Promise.all([
|
|
260
|
+
d ? this.embedding(d) : Promise.resolve(null),
|
|
261
|
+
n ? this.embedding(n) : Promise.resolve(null)
|
|
262
|
+
]);
|
|
263
|
+
return (e.memory || []).map((h) => ({ ...h, score: i ? this.cosineSimilarity(h.embeddings[0], i[0].embedding) : 1 })).filter((h) => h.score >= 0.8).map((h) => ({ ...h, score: u ? this.cosineSimilarity(h.embeddings[1], u[0].embedding) : h.score })).filter((h) => h.score >= 0.2).toSorted((h, f) => h.score - f.score).slice(0, l);
|
|
264
|
+
}, m = await a(t);
|
|
265
|
+
m.length && e.history.push({ role: "assistant", content: `Things I remembered:
|
|
266
|
+
` + m.map((n) => `${n.owner}: ${n.fact}`).join(`
|
|
267
|
+
`) }), e.tools = [...e.tools || [], {
|
|
268
|
+
name: "read_memory",
|
|
269
|
+
description: "Check your long-term memory for more information",
|
|
270
|
+
args: {
|
|
271
|
+
subject: { type: "string", description: "Find information by a subject topic, can be used with or without query argument" },
|
|
272
|
+
query: { type: "string", description: "Search memory based on a query, can be used with or without subject argument" },
|
|
273
|
+
limit: { type: "number", description: "Result limit, default 5" }
|
|
274
|
+
},
|
|
275
|
+
fn: (n) => {
|
|
276
|
+
if (!n.subject && !n.query) throw new Error("Either a subject or query argument is required");
|
|
277
|
+
return a(n.query, n.subject, n.limit || 5);
|
|
278
|
+
}
|
|
279
|
+
}];
|
|
280
|
+
}
|
|
281
|
+
const o = await this.models[s].ask(t, e);
|
|
282
|
+
if (e.memory) {
|
|
283
|
+
const a = e.history?.findIndex((m) => m.role == "assistant" && m.content.startsWith("Things I remembered:"));
|
|
284
|
+
a != null && a >= 0 && e.history?.splice(a, 1);
|
|
285
|
+
}
|
|
286
|
+
if (e.compress || e.memory) {
|
|
287
|
+
let a = null;
|
|
288
|
+
if (e.compress)
|
|
289
|
+
a = await this.ai.language.compressHistory(e.history, e.compress.max, e.compress.min, e), e.history.splice(0, e.history.length, ...a.history);
|
|
290
|
+
else {
|
|
291
|
+
const m = e.history?.findLastIndex((n) => n.role == "user") ?? -1;
|
|
292
|
+
a = await this.ai.language.compressHistory(m != -1 ? e.history.slice(m) : e.history, 0, 0, e);
|
|
293
|
+
}
|
|
294
|
+
if (e.memory) {
|
|
295
|
+
const m = e.memory.filter((n) => !a.memory.some((d) => this.cosineSimilarity(n.embeddings[1], d.embeddings[1]) > 0.8)).concat(a.memory);
|
|
296
|
+
e.memory.splice(0, e.memory.length, ...m);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return c(o);
|
|
300
|
+
}), { abort: r });
|
|
254
301
|
}
|
|
255
302
|
/**
|
|
256
303
|
* Compress chat history to reduce context size
|
|
257
304
|
* @param {LLMMessage[]} history Chatlog that will be compressed
|
|
258
305
|
* @param max Trigger compression once context is larger than max
|
|
259
|
-
* @param min
|
|
306
|
+
* @param min Leave messages less than the token minimum, summarize the rest
|
|
260
307
|
* @param {LLMRequest} options LLM options
|
|
261
308
|
* @returns {Promise<LLMMessage[]>} New chat history will summary at index 0
|
|
262
309
|
*/
|
|
263
|
-
async compressHistory(t, e,
|
|
264
|
-
if (this.estimateTokens(t) < e) return t;
|
|
265
|
-
let
|
|
266
|
-
for (let
|
|
267
|
-
if (
|
|
310
|
+
async compressHistory(t, e, s, r) {
|
|
311
|
+
if (this.estimateTokens(t) < e) return { history: t, memory: [] };
|
|
312
|
+
let c = 0, o = 0;
|
|
313
|
+
for (let h of t.toReversed())
|
|
314
|
+
if (o += this.estimateTokens(h.content), o < s) c++;
|
|
268
315
|
else break;
|
|
269
|
-
if (t.length <=
|
|
270
|
-
const
|
|
271
|
-
return [{ role: "assistant", content: `Conversation Summary: ${await this.summarize(d.map((r) => `${r.role}: ${r.content}`).join(`
|
|
316
|
+
if (t.length <= c) return { history: t, memory: [] };
|
|
317
|
+
const a = t[0].role == "system" ? t[0] : null, m = c == 0 ? [] : t.slice(-c), n = (c == 0 ? t : t.slice(0, -c)).filter((h) => h.role === "assistant" || h.role === "user"), d = await this.json(`Create the smallest summary possible, no more than 500 tokens. Create a list of NEW facts (split by subject [pro]noun and fact) about what you learned from this conversation that you didn't already know or get from a tool call or system prompt. Focus only on new information about people, topics, or facts. Avoid generating facts about the AI. Match this format: {summary: string, facts: [[subject, fact]]}
|
|
272
318
|
|
|
273
|
-
|
|
319
|
+
${n.map((h) => `${h.role}: ${h.content}`).join(`
|
|
320
|
+
|
|
321
|
+
`)}`, { model: r?.model, temperature: r?.temperature || 0.3 }), l = /* @__PURE__ */ new Date(), i = await Promise.all((d?.facts || [])?.map(async ([h, f]) => {
|
|
322
|
+
const g = await Promise.all([this.embedding(h), this.embedding(`${h}: ${f}`)]);
|
|
323
|
+
return { owner: h, fact: f, embeddings: [g[0][0].embedding, g[1][0].embedding], timestamp: l };
|
|
324
|
+
})), u = [{ role: "assistant", content: `Conversation Summary: ${d?.summary}`, timestamp: Date.now() }, ...m];
|
|
325
|
+
return a && u.splice(0, 0, a), { history: u, memory: i };
|
|
274
326
|
}
|
|
327
|
+
/**
|
|
328
|
+
* Compare the difference between embeddings (calculates the angle between two vectors)
|
|
329
|
+
* @param {number[]} v1 First embedding / vector comparison
|
|
330
|
+
* @param {number[]} v2 Second embedding / vector for comparison
|
|
331
|
+
* @returns {number} Similarity values 0-1: 0 = unique, 1 = identical
|
|
332
|
+
*/
|
|
275
333
|
cosineSimilarity(t, e) {
|
|
276
334
|
if (t.length !== e.length) throw new Error("Vectors must be same length");
|
|
277
|
-
let
|
|
278
|
-
for (let
|
|
279
|
-
|
|
280
|
-
const
|
|
281
|
-
return
|
|
335
|
+
let s = 0, r = 0, c = 0;
|
|
336
|
+
for (let a = 0; a < t.length; a++)
|
|
337
|
+
s += t[a] * e[a], r += t[a] * t[a], c += e[a] * e[a];
|
|
338
|
+
const o = Math.sqrt(r) * Math.sqrt(c);
|
|
339
|
+
return o === 0 ? 0 : s / o;
|
|
282
340
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
`))
|
|
296
|
-
|
|
341
|
+
/**
|
|
342
|
+
* Chunk text into parts for AI digestion
|
|
343
|
+
* @param {object | string} target Item that will be chunked (objects get converted)
|
|
344
|
+
* @param {number} maxTokens Chunking size. More = better context, less = more specific (Search by paragraphs or lines)
|
|
345
|
+
* @param {number} overlapTokens Includes previous X tokens to provide continuity to AI (In addition to max tokens)
|
|
346
|
+
* @returns {string[]} Chunked strings
|
|
347
|
+
*/
|
|
348
|
+
chunk(t, e = 500, s = 50) {
|
|
349
|
+
const r = (m, n = "") => m ? Object.entries(m).flatMap(([d, l]) => {
|
|
350
|
+
const i = n ? `${n}${isNaN(+d) ? `.${d}` : `[${d}]`}` : d;
|
|
351
|
+
return typeof l == "object" && !Array.isArray(l) ? r(l, i) : `${i}: ${Array.isArray(l) ? l.join(", ") : l}`;
|
|
352
|
+
}) : [], o = (typeof t == "object" ? r(t) : t.split(`
|
|
353
|
+
`)).flatMap((m) => [...m.split(/\s+/).filter(Boolean), `
|
|
354
|
+
`]), a = [];
|
|
355
|
+
for (let m = 0; m < o.length; ) {
|
|
356
|
+
let n = "", d = m;
|
|
357
|
+
for (; d < o.length; ) {
|
|
358
|
+
const i = n + (n ? " " : "") + o[d];
|
|
359
|
+
if (this.estimateTokens(i.replace(/\s*\n\s*/g, `
|
|
360
|
+
`)) > e && n) break;
|
|
361
|
+
n = i, d++;
|
|
297
362
|
}
|
|
298
|
-
const
|
|
363
|
+
const l = n.replace(/\s*\n\s*/g, `
|
|
299
364
|
`).trim();
|
|
300
|
-
|
|
365
|
+
l && a.push(l), m = Math.max(d - s, d === m ? m + 1 : d);
|
|
301
366
|
}
|
|
302
|
-
return
|
|
367
|
+
return a;
|
|
303
368
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
369
|
+
/**
|
|
370
|
+
* Create a vector representation of a string
|
|
371
|
+
* @param {object | string} target Item that will be embedded (objects get converted)
|
|
372
|
+
* @param {number} maxTokens Chunking size. More = better context, less = more specific (Search by paragraphs or lines)
|
|
373
|
+
* @param {number} overlapTokens Includes previous X tokens to provide continuity to AI (In addition to max tokens)
|
|
374
|
+
* @returns {Promise<Awaited<{index: number, embedding: number[], text: string, tokens: number}>[]>} Chunked embeddings
|
|
375
|
+
*/
|
|
376
|
+
embedding(t, e = 500, s = 50) {
|
|
377
|
+
const r = (o) => new Promise((a, m) => {
|
|
378
|
+
const n = this.embedId++;
|
|
379
|
+
this.embedQueue.set(n, { resolve: a, reject: m }), this.embedWorker?.postMessage({ id: n, text: o, model: this.ai.options?.embedder || "bge-small-en-v1.5" });
|
|
380
|
+
}), c = this.chunk(t, e, s);
|
|
381
|
+
return Promise.all(c.map(async (o, a) => ({
|
|
382
|
+
index: a,
|
|
383
|
+
embedding: await r(o),
|
|
384
|
+
text: o,
|
|
385
|
+
tokens: this.estimateTokens(o)
|
|
314
386
|
})));
|
|
315
387
|
}
|
|
316
388
|
/**
|
|
@@ -324,14 +396,14 @@ class I {
|
|
|
324
396
|
}
|
|
325
397
|
/**
|
|
326
398
|
* Compare the difference between two strings using tensor math
|
|
327
|
-
* @param target Text that will checked
|
|
399
|
+
* @param target Text that will be checked
|
|
328
400
|
* @param {string} searchTerms Multiple search terms to check against target
|
|
329
401
|
* @returns {{avg: number, max: number, similarities: number[]}} Similarity values 0-1: 0 = unique, 1 = identical
|
|
330
402
|
*/
|
|
331
403
|
fuzzyMatch(t, ...e) {
|
|
332
404
|
if (e.length < 2) throw new Error("Requires at least 2 strings to compare");
|
|
333
|
-
const
|
|
334
|
-
return { avg:
|
|
405
|
+
const s = (o, a = 10) => o.toLowerCase().split("").map((m, n) => m.charCodeAt(0) * (n + 1) % a / a).slice(0, a), r = s(t), c = e.map((o) => s(o)).map((o) => this.cosineSimilarity(r, o));
|
|
406
|
+
return { avg: c.reduce((o, a) => o + a, 0) / c.length, max: Math.max(...c), similarities: c };
|
|
335
407
|
}
|
|
336
408
|
/**
|
|
337
409
|
* Ask a question with JSON response
|
|
@@ -340,11 +412,10 @@ class I {
|
|
|
340
412
|
* @returns {Promise<{} | {} | RegExpExecArray | null>}
|
|
341
413
|
*/
|
|
342
414
|
async json(t, e) {
|
|
343
|
-
let
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
});
|
|
347
|
-
return n?.[0]?.content ? w(new RegExp("{[sS]*}").exec(n[0].content), {}) : {};
|
|
415
|
+
let s = await this.ask(t, { system: "Respond using a JSON blob matching any provided examples", ...e });
|
|
416
|
+
if (!s) return {};
|
|
417
|
+
const r = /```(?:.+)?\s*([\s\S]*?)```/.exec(s), c = r ? r[1].trim() : s;
|
|
418
|
+
return y(c, {});
|
|
348
419
|
}
|
|
349
420
|
/**
|
|
350
421
|
* Create a summary of some text
|
|
@@ -353,11 +424,11 @@ class I {
|
|
|
353
424
|
* @param options LLM request options
|
|
354
425
|
* @returns {Promise<string>} Summary
|
|
355
426
|
*/
|
|
356
|
-
summarize(t, e,
|
|
357
|
-
return this.ask(t, { system: `Generate a brief summary <= ${e} tokens. Output nothing else`, temperature: 0.3, ...
|
|
427
|
+
summarize(t, e, s) {
|
|
428
|
+
return this.ask(t, { system: `Generate a brief summary <= ${e} tokens. Output nothing else`, temperature: 0.3, ...s });
|
|
358
429
|
}
|
|
359
430
|
}
|
|
360
|
-
class
|
|
431
|
+
class z {
|
|
361
432
|
constructor(t) {
|
|
362
433
|
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());
|
|
363
434
|
}
|
|
@@ -365,26 +436,26 @@ class F {
|
|
|
365
436
|
whisperModel;
|
|
366
437
|
asr(t, e = this.whisperModel) {
|
|
367
438
|
if (!this.ai.options.whisper?.binary) throw new Error("Whisper not configured");
|
|
368
|
-
let
|
|
439
|
+
let s = () => {
|
|
369
440
|
};
|
|
370
|
-
const
|
|
371
|
-
const
|
|
372
|
-
let
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
441
|
+
const r = new Promise(async (c, o) => {
|
|
442
|
+
const a = await this.downloadAsrModel(e);
|
|
443
|
+
let m = "";
|
|
444
|
+
const n = W(this.ai.options.whisper?.binary, ["-nt", "-np", "-m", a, "-f", t], { stdio: ["ignore", "pipe", "ignore"] });
|
|
445
|
+
s = () => n.kill("SIGTERM"), n.on("error", (d) => o(d)), n.stdout.on("data", (d) => m += d.toString()), n.on("close", (d) => {
|
|
446
|
+
d === 0 ? c(m.trim() || null) : o(new Error(`Exit code ${d}`));
|
|
376
447
|
});
|
|
377
448
|
});
|
|
378
|
-
return Object.assign(
|
|
449
|
+
return Object.assign(r, { abort: s });
|
|
379
450
|
}
|
|
380
451
|
async downloadAsrModel(t = this.whisperModel) {
|
|
381
452
|
if (!this.ai.options.whisper?.binary) throw new Error("Whisper not configured");
|
|
382
453
|
t.endsWith(".bin") || (t += ".bin");
|
|
383
|
-
const e =
|
|
384
|
-
return await
|
|
454
|
+
const e = L.join(this.ai.options.path, t);
|
|
455
|
+
return await w.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 w.writeFile(e, s), delete this.downloads[t], e)), this.downloads[t]);
|
|
385
456
|
}
|
|
386
457
|
}
|
|
387
|
-
class
|
|
458
|
+
class F {
|
|
388
459
|
constructor(t) {
|
|
389
460
|
this.ai = t;
|
|
390
461
|
}
|
|
@@ -395,17 +466,17 @@ class G {
|
|
|
395
466
|
*/
|
|
396
467
|
ocr(t) {
|
|
397
468
|
let e;
|
|
398
|
-
const
|
|
399
|
-
e = await
|
|
400
|
-
const { data:
|
|
401
|
-
await e.terminate(),
|
|
469
|
+
const s = new Promise(async (r) => {
|
|
470
|
+
e = await I(this.ai.options.tesseract?.model || "eng", 2, { cachePath: this.ai.options.path });
|
|
471
|
+
const { data: c } = await e.recognize(t);
|
|
472
|
+
await e.terminate(), r(c.text.trim() || null);
|
|
402
473
|
});
|
|
403
|
-
return Object.assign(
|
|
474
|
+
return Object.assign(s, { abort: () => e?.terminate() });
|
|
404
475
|
}
|
|
405
476
|
}
|
|
406
|
-
class
|
|
477
|
+
class ae {
|
|
407
478
|
constructor(t) {
|
|
408
|
-
this.options = t, t.path || (t.path =
|
|
479
|
+
this.options = t, t.path || (t.path = S.tmpdir()), process.env.TRANSFORMERS_CACHE = t.path, this.audio = new z(this), this.language = new H(this), this.vision = new F(this);
|
|
409
480
|
}
|
|
410
481
|
/** Audio processing AI */
|
|
411
482
|
audio;
|
|
@@ -418,34 +489,34 @@ const B = {
|
|
|
418
489
|
name: "cli",
|
|
419
490
|
description: "Use the command line interface, returns any output",
|
|
420
491
|
args: { command: { type: "string", description: "Command to run", required: !0 } },
|
|
421
|
-
fn: (
|
|
422
|
-
},
|
|
492
|
+
fn: (p) => C`${p.command}`
|
|
493
|
+
}, ce = {
|
|
423
494
|
name: "get_datetime",
|
|
424
495
|
description: "Get current UTC date / time",
|
|
425
496
|
args: {},
|
|
426
497
|
fn: async () => (/* @__PURE__ */ new Date()).toUTCString()
|
|
427
|
-
},
|
|
498
|
+
}, le = {
|
|
428
499
|
name: "exec",
|
|
429
500
|
description: "Run code/scripts",
|
|
430
501
|
args: {
|
|
431
502
|
language: { type: "string", description: "Execution language", enum: ["cli", "node", "python"], required: !0 },
|
|
432
503
|
code: { type: "string", description: "Code to execute", required: !0 }
|
|
433
504
|
},
|
|
434
|
-
fn: async (
|
|
505
|
+
fn: async (p, t, e) => {
|
|
435
506
|
try {
|
|
436
|
-
switch (
|
|
507
|
+
switch (p.type) {
|
|
437
508
|
case "bash":
|
|
438
|
-
return await B.fn({ command:
|
|
509
|
+
return await B.fn({ command: p.code }, t, e);
|
|
439
510
|
case "node":
|
|
440
|
-
return await
|
|
511
|
+
return await G.fn({ code: p.code }, t, e);
|
|
441
512
|
case "python":
|
|
442
|
-
return await
|
|
513
|
+
return await Q.fn({ code: p.code }, t, e);
|
|
443
514
|
}
|
|
444
|
-
} catch (
|
|
445
|
-
return { error:
|
|
515
|
+
} catch (s) {
|
|
516
|
+
return { error: s?.message || s.toString() };
|
|
446
517
|
}
|
|
447
518
|
}
|
|
448
|
-
},
|
|
519
|
+
}, me = {
|
|
449
520
|
name: "fetch",
|
|
450
521
|
description: "Make HTTP request to URL",
|
|
451
522
|
args: {
|
|
@@ -454,86 +525,85 @@ const B = {
|
|
|
454
525
|
headers: { type: "object", description: "HTTP headers to send", default: {} },
|
|
455
526
|
body: { type: "object", description: "HTTP body to send" }
|
|
456
527
|
},
|
|
457
|
-
fn: (
|
|
458
|
-
},
|
|
528
|
+
fn: (p) => new M({ url: p.url, headers: p.headers }).request({ method: p.method || "GET", body: p.body })
|
|
529
|
+
}, G = {
|
|
459
530
|
name: "exec_javascript",
|
|
460
531
|
description: "Execute commonjs javascript",
|
|
461
532
|
args: {
|
|
462
533
|
code: { type: "string", description: "CommonJS javascript", required: !0 }
|
|
463
534
|
},
|
|
464
|
-
fn: async (
|
|
465
|
-
const t = q(null), e = await
|
|
535
|
+
fn: async (p) => {
|
|
536
|
+
const t = q(null), e = await P({ console: t }, p.code, !0).catch((s) => t.output.error.push(s));
|
|
466
537
|
return { ...t.output, return: e, stdout: void 0, stderr: void 0 };
|
|
467
538
|
}
|
|
468
|
-
},
|
|
539
|
+
}, Q = {
|
|
469
540
|
name: "exec_javascript",
|
|
470
541
|
description: "Execute commonjs javascript",
|
|
471
542
|
args: {
|
|
472
543
|
code: { type: "string", description: "CommonJS javascript", required: !0 }
|
|
473
544
|
},
|
|
474
|
-
fn: async (
|
|
475
|
-
},
|
|
545
|
+
fn: async (p) => ({ result: D`python -c "${p.code}"` })
|
|
546
|
+
}, de = {
|
|
476
547
|
name: "read_webpage",
|
|
477
548
|
description: "Extract clean, structured content from a webpage. Use after web_search to read specific URLs",
|
|
478
549
|
args: {
|
|
479
550
|
url: { type: "string", description: "URL to extract content from", required: !0 },
|
|
480
551
|
focus: { type: "string", description: 'Optional: What aspect to focus on (e.g., "pricing", "features", "contact info")' }
|
|
481
552
|
},
|
|
482
|
-
fn: async (
|
|
483
|
-
const t = await fetch(
|
|
484
|
-
throw new Error(`Failed to fetch: ${
|
|
485
|
-
}), e =
|
|
553
|
+
fn: async (p) => {
|
|
554
|
+
const t = await fetch(p.url, { headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" } }).then((o) => o.text()).catch((o) => {
|
|
555
|
+
throw new Error(`Failed to fetch: ${o.message}`);
|
|
556
|
+
}), e = N.load(t);
|
|
486
557
|
e('script, style, nav, footer, header, aside, iframe, noscript, [role="navigation"], [role="banner"], .ad, .ads, .cookie, .popup').remove();
|
|
487
|
-
const
|
|
558
|
+
const s = {
|
|
488
559
|
title: e('meta[property="og:title"]').attr("content") || e("title").text() || "",
|
|
489
560
|
description: e('meta[name="description"]').attr("content") || e('meta[property="og:description"]').attr("content") || ""
|
|
490
561
|
};
|
|
491
|
-
let
|
|
492
|
-
const
|
|
493
|
-
for (const
|
|
494
|
-
const
|
|
495
|
-
if (
|
|
496
|
-
|
|
562
|
+
let r = "";
|
|
563
|
+
const c = ["article", "main", '[role="main"]', ".content", ".post", ".entry", "body"];
|
|
564
|
+
for (const o of c) {
|
|
565
|
+
const a = e(o).first();
|
|
566
|
+
if (a.length && a.text().trim().length > 200) {
|
|
567
|
+
r = a.text();
|
|
497
568
|
break;
|
|
498
569
|
}
|
|
499
570
|
}
|
|
500
|
-
return
|
|
571
|
+
return r || (r = e("body").text()), r = r.replace(/\s+/g, " ").trim().slice(0, 8e3), { url: p.url, title: s.title.trim(), description: s.description.trim(), content: r, focus: p.focus };
|
|
501
572
|
}
|
|
502
|
-
},
|
|
573
|
+
}, ue = {
|
|
503
574
|
name: "web_search",
|
|
504
575
|
description: "Use duckduckgo (anonymous) to find find relevant online resources. Returns a list of URLs that works great with the `read_webpage` tool",
|
|
505
576
|
args: {
|
|
506
577
|
query: { type: "string", description: "Search string", required: !0 },
|
|
507
578
|
length: { type: "string", description: "Number of results to return", default: 5 }
|
|
508
579
|
},
|
|
509
|
-
fn: async (
|
|
510
|
-
const t = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(
|
|
580
|
+
fn: async (p) => {
|
|
581
|
+
const t = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(p.query)}`, {
|
|
511
582
|
headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Accept-Language": "en-US,en;q=0.9" }
|
|
512
|
-
}).then((
|
|
513
|
-
let e,
|
|
514
|
-
const
|
|
515
|
-
for (; (e =
|
|
516
|
-
let
|
|
517
|
-
if (
|
|
583
|
+
}).then((c) => c.text());
|
|
584
|
+
let e, s = /<a .*?href="(.+?)".+?<\/a>/g;
|
|
585
|
+
const r = new E();
|
|
586
|
+
for (; (e = s.exec(t)) !== null; ) {
|
|
587
|
+
let c = /uddg=(.+)&?/.exec(decodeURIComponent(e[1]))?.[1];
|
|
588
|
+
if (c && (c = decodeURIComponent(c)), c && r.add(c), r.size >= (p.length || 5)) break;
|
|
518
589
|
}
|
|
519
|
-
return
|
|
590
|
+
return r;
|
|
520
591
|
}
|
|
521
592
|
};
|
|
522
593
|
export {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
594
|
+
ae as Ai,
|
|
595
|
+
J as Anthropic,
|
|
596
|
+
z as Audio,
|
|
526
597
|
B as CliTool,
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
S as LLMProvider,
|
|
598
|
+
ce as DateTimeTool,
|
|
599
|
+
le as ExecTool,
|
|
600
|
+
me as FetchTool,
|
|
601
|
+
G as JSTool,
|
|
602
|
+
j as LLMProvider,
|
|
533
603
|
_ as OpenAi,
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
604
|
+
Q as PythonTool,
|
|
605
|
+
de as ReadWebpageTool,
|
|
606
|
+
F as Vision,
|
|
607
|
+
ue as WebSearchTool
|
|
538
608
|
};
|
|
539
609
|
//# sourceMappingURL=index.mjs.map
|