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