@ztimson/ai-utils 0.8.15 → 0.9.0
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 +66 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +510 -410
- package/dist/index.mjs.map +1 -1
- package/dist/tools.d.ts +2 -0
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import { tmpdir as
|
|
3
|
-
import { Anthropic as
|
|
4
|
-
import { objectMap as
|
|
5
|
-
import { OpenAI as
|
|
6
|
-
import { fileURLToPath as
|
|
7
|
-
import { join as
|
|
8
|
-
import { spawn as
|
|
9
|
-
import { mkdtempSync as
|
|
10
|
-
import
|
|
11
|
-
import * as
|
|
12
|
-
import
|
|
13
|
-
import { createWorker as
|
|
14
|
-
import * as
|
|
1
|
+
import * as R from "node:os";
|
|
2
|
+
import { tmpdir as W } from "node:os";
|
|
3
|
+
import { Anthropic as C } from "@anthropic-ai/sdk";
|
|
4
|
+
import { objectMap as O, JSONAttemptParse as $, findByProp as U, JSONSanitize as T, clean as J, Http as F, consoleInterceptor as B, fn as I, decodeHtml as D, ASet as H } from "@ztimson/utils";
|
|
5
|
+
import { OpenAI as G } from "openai";
|
|
6
|
+
import { fileURLToPath as K } from "url";
|
|
7
|
+
import { join as Y, dirname as V } from "path";
|
|
8
|
+
import { spawn as k, execSync as Z } from "node:child_process";
|
|
9
|
+
import { mkdtempSync as Q } from "node:fs";
|
|
10
|
+
import x from "node:fs/promises";
|
|
11
|
+
import * as q from "node:path";
|
|
12
|
+
import M, { join as A } from "node:path";
|
|
13
|
+
import { createWorker as X } from "tesseract.js";
|
|
14
|
+
import * as ee from "cheerio";
|
|
15
15
|
import { $Sync as j } from "@ztimson/node-utils";
|
|
16
16
|
class L {
|
|
17
17
|
}
|
|
18
|
-
class
|
|
18
|
+
class te extends L {
|
|
19
19
|
constructor(r, e, t) {
|
|
20
|
-
super(), this.ai = r, this.apiToken = e, this.model = t, this.client = new
|
|
20
|
+
super(), this.ai = r, this.apiToken = e, this.model = t, this.client = new C({ apiKey: e });
|
|
21
21
|
}
|
|
22
22
|
client;
|
|
23
23
|
toStandard(r) {
|
|
24
24
|
const e = Date.now(), t = [];
|
|
25
|
-
for (let
|
|
26
|
-
if (typeof
|
|
27
|
-
t.push({ timestamp: e, ...
|
|
25
|
+
for (let l of r)
|
|
26
|
+
if (typeof l.content == "string")
|
|
27
|
+
t.push({ timestamp: e, ...l });
|
|
28
28
|
else {
|
|
29
|
-
const
|
|
29
|
+
const n = l.content?.filter((s) => s.type == "text").map((s) => s.text).join(`
|
|
30
30
|
|
|
31
31
|
`);
|
|
32
|
-
|
|
33
|
-
if (
|
|
34
|
-
t.push({ timestamp: e, role: "tool", id:
|
|
35
|
-
else if (
|
|
36
|
-
const
|
|
37
|
-
|
|
32
|
+
n && t.push({ timestamp: e, role: l.role, content: n }), l.content.forEach((s) => {
|
|
33
|
+
if (s.type == "tool_use")
|
|
34
|
+
t.push({ timestamp: e, role: "tool", id: s.id, name: s.name, args: s.input, content: void 0 });
|
|
35
|
+
else if (s.type == "tool_result") {
|
|
36
|
+
const o = t.findLast((u) => u.id == s.tool_use_id);
|
|
37
|
+
o && (o[s.is_error ? "error" : "content"] = s.content);
|
|
38
38
|
}
|
|
39
39
|
});
|
|
40
40
|
}
|
|
@@ -55,78 +55,78 @@ class Q extends L {
|
|
|
55
55
|
}
|
|
56
56
|
ask(r, e = {}) {
|
|
57
57
|
const t = new AbortController();
|
|
58
|
-
return Object.assign(new Promise(async (
|
|
59
|
-
let
|
|
60
|
-
const
|
|
58
|
+
return Object.assign(new Promise(async (l) => {
|
|
59
|
+
let n = this.fromStandard([...e.history || [], { role: "user", content: r, timestamp: Date.now() }]);
|
|
60
|
+
const s = e.tools || this.ai.options.llm?.tools || [], o = {
|
|
61
61
|
model: e.model || this.model,
|
|
62
62
|
max_tokens: e.max_tokens || this.ai.options.llm?.max_tokens || 4096,
|
|
63
63
|
system: e.system || this.ai.options.llm?.system || "",
|
|
64
64
|
temperature: e.temperature || this.ai.options.llm?.temperature || 0.7,
|
|
65
|
-
tools:
|
|
66
|
-
name:
|
|
67
|
-
description:
|
|
65
|
+
tools: s.map((m) => ({
|
|
66
|
+
name: m.name,
|
|
67
|
+
description: m.description,
|
|
68
68
|
input_schema: {
|
|
69
69
|
type: "object",
|
|
70
|
-
properties:
|
|
71
|
-
required:
|
|
70
|
+
properties: m.args ? O(m.args, (i, p) => ({ ...p, required: void 0 })) : {},
|
|
71
|
+
required: m.args ? Object.entries(m.args).filter((i) => i[1].required).map((i) => i[0]) : []
|
|
72
72
|
},
|
|
73
73
|
fn: void 0
|
|
74
74
|
})),
|
|
75
|
-
messages:
|
|
75
|
+
messages: n,
|
|
76
76
|
stream: !!e.stream
|
|
77
77
|
};
|
|
78
|
-
let
|
|
78
|
+
let u, a = !0;
|
|
79
79
|
do {
|
|
80
|
-
if (
|
|
81
|
-
throw
|
|
80
|
+
if (u = await this.client.messages.create(o).catch((i) => {
|
|
81
|
+
throw i.message += `
|
|
82
82
|
|
|
83
83
|
Messages:
|
|
84
|
-
${JSON.stringify(
|
|
84
|
+
${JSON.stringify(n, null, 2)}`, i;
|
|
85
85
|
}), e.stream) {
|
|
86
|
-
|
|
86
|
+
a ? a = !1 : e.stream({ text: `
|
|
87
87
|
|
|
88
|
-
` }),
|
|
89
|
-
for await (const
|
|
88
|
+
` }), u.content = [];
|
|
89
|
+
for await (const i of u) {
|
|
90
90
|
if (t.signal.aborted) break;
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
-
else if (
|
|
94
|
-
if (
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
} else
|
|
98
|
-
else if (
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
} else if (
|
|
91
|
+
if (i.type === "content_block_start")
|
|
92
|
+
i.content_block.type === "text" ? u.content.push({ type: "text", text: "" }) : i.content_block.type === "tool_use" && u.content.push({ type: "tool_use", id: i.content_block.id, name: i.content_block.name, input: "" });
|
|
93
|
+
else if (i.type === "content_block_delta")
|
|
94
|
+
if (i.delta.type === "text_delta") {
|
|
95
|
+
const p = i.delta.text;
|
|
96
|
+
u.content.at(-1).text += p, e.stream({ text: p });
|
|
97
|
+
} else i.delta.type === "input_json_delta" && (u.content.at(-1).input += i.delta.partial_json);
|
|
98
|
+
else if (i.type === "content_block_stop") {
|
|
99
|
+
const p = u.content.at(-1);
|
|
100
|
+
p.input != null && (p.input = p.input ? $(p.input, {}) : {});
|
|
101
|
+
} else if (i.type === "message_stop")
|
|
102
102
|
break;
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
|
-
const
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
const d =
|
|
110
|
-
if (e.stream && e.stream({ tool:
|
|
105
|
+
const m = u.content.filter((i) => i.type === "tool_use");
|
|
106
|
+
if (m.length && !t.signal.aborted) {
|
|
107
|
+
n.push({ role: "assistant", content: u.content });
|
|
108
|
+
const i = await Promise.all(m.map(async (p) => {
|
|
109
|
+
const d = s.find(U("name", p.name));
|
|
110
|
+
if (e.stream && e.stream({ tool: p.name }), !d) return { tool_use_id: p.id, is_error: !0, content: "Tool not found" };
|
|
111
111
|
try {
|
|
112
|
-
const
|
|
113
|
-
return { type: "tool_result", tool_use_id:
|
|
114
|
-
} catch (
|
|
115
|
-
return { type: "tool_result", tool_use_id:
|
|
112
|
+
const c = await d.fn(p.input, e?.stream, this.ai);
|
|
113
|
+
return { type: "tool_result", tool_use_id: p.id, content: typeof c == "object" ? T(c) : c };
|
|
114
|
+
} catch (c) {
|
|
115
|
+
return { type: "tool_result", tool_use_id: p.id, is_error: !0, content: c?.message || c?.toString() || "Unknown" };
|
|
116
116
|
}
|
|
117
117
|
}));
|
|
118
|
-
|
|
118
|
+
n.push({ role: "user", content: i }), o.messages = n;
|
|
119
119
|
}
|
|
120
|
-
} while (!t.signal.aborted &&
|
|
121
|
-
|
|
120
|
+
} while (!t.signal.aborted && u.content.some((m) => m.type === "tool_use"));
|
|
121
|
+
n.push({ role: "assistant", content: u.content.filter((m) => m.type == "text").map((m) => m.text).join(`
|
|
122
122
|
|
|
123
|
-
`) }),
|
|
123
|
+
`) }), n = this.toStandard(n), e.stream && e.stream({ done: !0 }), e.history && e.history.splice(0, e.history.length, ...n), l(n.at(-1)?.content);
|
|
124
124
|
}), { abort: () => t.abort() });
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
class P extends L {
|
|
128
|
-
constructor(r, e, t,
|
|
129
|
-
super(), this.ai = r, this.host = e, this.token = t, this.model =
|
|
128
|
+
constructor(r, e, t, l) {
|
|
129
|
+
super(), this.ai = r, this.host = e, this.token = t, this.model = l, this.client = new G(J({
|
|
130
130
|
baseURL: e,
|
|
131
131
|
apiKey: t || e ? "ignored" : void 0
|
|
132
132
|
}));
|
|
@@ -136,17 +136,17 @@ class P extends L {
|
|
|
136
136
|
for (let e = 0; e < r.length; e++) {
|
|
137
137
|
const t = r[e];
|
|
138
138
|
if (t.role === "assistant" && t.tool_calls) {
|
|
139
|
-
const
|
|
139
|
+
const l = t.tool_calls.map((n) => ({
|
|
140
140
|
role: "tool",
|
|
141
|
-
id:
|
|
142
|
-
name:
|
|
143
|
-
args:
|
|
141
|
+
id: n.id,
|
|
142
|
+
name: n.function.name,
|
|
143
|
+
args: $(n.function.arguments, {}),
|
|
144
144
|
timestamp: t.timestamp
|
|
145
145
|
}));
|
|
146
|
-
r.splice(e, 1, ...
|
|
146
|
+
r.splice(e, 1, ...l), e += l.length - 1;
|
|
147
147
|
} else if (t.role === "tool" && t.content) {
|
|
148
|
-
const
|
|
149
|
-
|
|
148
|
+
const l = r.find((n) => t.tool_call_id == n.id);
|
|
149
|
+
l && (t.content.includes('"error":') ? l.error = t.content : l.content = t.content), r.splice(e, 1), e--;
|
|
150
150
|
}
|
|
151
151
|
r[e]?.timestamp || (r[e].timestamp = Date.now());
|
|
152
152
|
}
|
|
@@ -167,53 +167,53 @@ class P extends L {
|
|
|
167
167
|
content: t.error || t.content
|
|
168
168
|
});
|
|
169
169
|
else {
|
|
170
|
-
const { timestamp:
|
|
171
|
-
e.push(
|
|
170
|
+
const { timestamp: l, ...n } = t;
|
|
171
|
+
e.push(n);
|
|
172
172
|
}
|
|
173
173
|
return e;
|
|
174
174
|
}, []);
|
|
175
175
|
}
|
|
176
176
|
ask(r, e = {}) {
|
|
177
177
|
const t = new AbortController();
|
|
178
|
-
return Object.assign(new Promise(async (
|
|
178
|
+
return Object.assign(new Promise(async (l, n) => {
|
|
179
179
|
e.system && (e.history?.[0]?.role != "system" ? e.history?.splice(0, 0, { role: "system", content: e.system, timestamp: Date.now() }) : e.history[0].content = e.system);
|
|
180
|
-
let
|
|
181
|
-
const
|
|
180
|
+
let s = this.fromStandard([...e.history || [], { role: "user", content: r, timestamp: Date.now() }]);
|
|
181
|
+
const o = e.tools || this.ai.options.llm?.tools || [], u = {
|
|
182
182
|
model: e.model || this.model,
|
|
183
|
-
messages:
|
|
183
|
+
messages: s,
|
|
184
184
|
stream: !!e.stream,
|
|
185
185
|
max_tokens: e.max_tokens || this.ai.options.llm?.max_tokens || 4096,
|
|
186
186
|
temperature: e.temperature || this.ai.options.llm?.temperature || 0.7,
|
|
187
|
-
tools:
|
|
187
|
+
tools: o.map((i) => ({
|
|
188
188
|
type: "function",
|
|
189
189
|
function: {
|
|
190
|
-
name:
|
|
191
|
-
description:
|
|
190
|
+
name: i.name,
|
|
191
|
+
description: i.description,
|
|
192
192
|
parameters: {
|
|
193
193
|
type: "object",
|
|
194
|
-
properties:
|
|
195
|
-
required:
|
|
194
|
+
properties: i.args ? O(i.args, (p, d) => ({ ...d, required: void 0 })) : {},
|
|
195
|
+
required: i.args ? Object.entries(i.args).filter((p) => p[1].required).map((p) => p[0]) : []
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
}))
|
|
199
199
|
};
|
|
200
|
-
let
|
|
200
|
+
let a, m = !0;
|
|
201
201
|
do {
|
|
202
|
-
if (
|
|
203
|
-
throw
|
|
202
|
+
if (a = await this.client.chat.completions.create(u).catch((p) => {
|
|
203
|
+
throw p.message += `
|
|
204
204
|
|
|
205
205
|
Messages:
|
|
206
|
-
${JSON.stringify(
|
|
206
|
+
${JSON.stringify(s, null, 2)}`, p;
|
|
207
207
|
}), e.stream) {
|
|
208
|
-
|
|
208
|
+
m ? m = !1 : e.stream({ text: `
|
|
209
209
|
|
|
210
|
-
` }),
|
|
211
|
-
for await (const
|
|
210
|
+
` }), a.choices = [{ message: { role: "assistant", content: "", tool_calls: [] } }];
|
|
211
|
+
for await (const p of a) {
|
|
212
212
|
if (t.signal.aborted) break;
|
|
213
|
-
if (
|
|
214
|
-
for (const d of
|
|
215
|
-
const
|
|
216
|
-
|
|
213
|
+
if (p.choices[0].delta.content && (a.choices[0].message.content += p.choices[0].delta.content, e.stream({ text: p.choices[0].delta.content })), p.choices[0].delta.tool_calls)
|
|
214
|
+
for (const d of p.choices[0].delta.tool_calls) {
|
|
215
|
+
const c = a.choices[0].message.tool_calls.find((f) => f.index === d.index);
|
|
216
|
+
c ? (d.id && (c.id = d.id), d.type && (c.type = d.type), d.function && (c.function || (c.function = {}), d.function.name && (c.function.name = d.function.name), d.function.arguments && (c.function.arguments = (c.function.arguments || "") + d.function.arguments))) : a.choices[0].message.tool_calls.push({
|
|
217
217
|
index: d.index,
|
|
218
218
|
id: d.id || "",
|
|
219
219
|
type: d.type || "function",
|
|
@@ -225,30 +225,30 @@ ${JSON.stringify(n, null, 2)}`, c;
|
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
|
-
const
|
|
229
|
-
if (
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
const
|
|
233
|
-
if (e.stream && e.stream({ tool: d.function.name }), !
|
|
228
|
+
const i = a.choices[0].message.tool_calls || [];
|
|
229
|
+
if (i.length && !t.signal.aborted) {
|
|
230
|
+
s.push(a.choices[0].message);
|
|
231
|
+
const p = await Promise.all(i.map(async (d) => {
|
|
232
|
+
const c = o?.find(U("name", d.function.name));
|
|
233
|
+
if (e.stream && e.stream({ tool: d.function.name }), !c) return { role: "tool", tool_call_id: d.id, content: '{"error": "Tool not found"}' };
|
|
234
234
|
try {
|
|
235
|
-
const f =
|
|
236
|
-
return { role: "tool", tool_call_id: d.id, content:
|
|
235
|
+
const f = $(d.function.arguments, {}), g = await c.fn(f, e.stream, this.ai);
|
|
236
|
+
return { role: "tool", tool_call_id: d.id, content: typeof g == "object" ? T(g) : g };
|
|
237
237
|
} catch (f) {
|
|
238
|
-
return { role: "tool", tool_call_id: d.id, content:
|
|
238
|
+
return { role: "tool", tool_call_id: d.id, content: T({ error: f?.message || f?.toString() || "Unknown" }) };
|
|
239
239
|
}
|
|
240
240
|
}));
|
|
241
|
-
|
|
241
|
+
s.push(...p), u.messages = s;
|
|
242
242
|
}
|
|
243
|
-
} while (!t.signal.aborted &&
|
|
244
|
-
|
|
243
|
+
} while (!t.signal.aborted && a.choices?.[0]?.message?.tool_calls?.length);
|
|
244
|
+
s.push({ role: "assistant", content: a.choices[0].message.content || "" }), s = this.toStandard(s), e.stream && e.stream({ done: !0 }), e.history && e.history.splice(0, e.history.length, ...s), l(s.at(-1)?.content);
|
|
245
245
|
}), { abort: () => t.abort() });
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
|
-
class
|
|
248
|
+
class re {
|
|
249
249
|
constructor(r) {
|
|
250
250
|
this.ai = r, r.options.llm?.models && Object.entries(r.options.llm.models).forEach(([e, t]) => {
|
|
251
|
-
this.defaultModel || (this.defaultModel = e), t.proto == "anthropic" ? this.models[e] = new
|
|
251
|
+
this.defaultModel || (this.defaultModel = e), t.proto == "anthropic" ? this.models[e] = new te(this.ai, t.token, e) : t.proto == "ollama" ? this.models[e] = new P(this.ai, t.host, "not-needed", e) : t.proto == "openai" && (this.models[e] = new P(this.ai, t.host || null, t.token, e));
|
|
252
252
|
});
|
|
253
253
|
}
|
|
254
254
|
defaultModel;
|
|
@@ -270,27 +270,27 @@ class X {
|
|
|
270
270
|
};
|
|
271
271
|
const t = e.model || this.defaultModel;
|
|
272
272
|
if (!this.models[t]) throw new Error(`Model does not exist: ${t}`);
|
|
273
|
-
let
|
|
273
|
+
let l = () => {
|
|
274
274
|
};
|
|
275
|
-
return Object.assign(new Promise(async (
|
|
275
|
+
return Object.assign(new Promise(async (n) => {
|
|
276
276
|
if (e.history || (e.history = []), e.memory) {
|
|
277
|
-
const
|
|
278
|
-
const [
|
|
279
|
-
|
|
280
|
-
|
|
277
|
+
const o = async (a, m, i = 10) => {
|
|
278
|
+
const [p, d] = await Promise.all([
|
|
279
|
+
m ? this.embedding(m) : Promise.resolve(null),
|
|
280
|
+
a ? this.embedding(a) : Promise.resolve(null)
|
|
281
281
|
]);
|
|
282
|
-
return (e.memory || []).map((
|
|
283
|
-
const f = (
|
|
284
|
-
return { ...
|
|
285
|
-
}).toSorted((
|
|
282
|
+
return (e.memory || []).map((c) => {
|
|
283
|
+
const f = (p ? this.cosineSimilarity(c.embeddings[0], p[0].embedding) : 0) + (d ? this.cosineSimilarity(c.embeddings[1], d[0].embedding) : 0);
|
|
284
|
+
return { ...c, score: f };
|
|
285
|
+
}).toSorted((c, f) => c.score - f.score).slice(0, i).map((c) => `- ${c.owner}: ${c.fact}`).join(`
|
|
286
286
|
`);
|
|
287
287
|
};
|
|
288
288
|
e.system += `
|
|
289
289
|
You have RAG memory and will be given the top_k closest memories regarding the users query. Save anything new you have learned worth remembering from the user message using the remember tool and feel free to recall memories manually.
|
|
290
290
|
`;
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
${
|
|
291
|
+
const u = await o(r);
|
|
292
|
+
u.length && e.history.push({ role: "tool", name: "recall", id: "auto_recall_" + Math.random().toString(), args: {}, content: `Things I remembered:
|
|
293
|
+
${u}` }), e.tools = [{
|
|
294
294
|
name: "recall",
|
|
295
295
|
description: "Recall the closest memories you have regarding a query using RAG",
|
|
296
296
|
args: {
|
|
@@ -298,9 +298,9 @@ ${l}` }), e.tools = [{
|
|
|
298
298
|
query: { type: "string", description: "Search memory based on a query, can be used with or without subject argument" },
|
|
299
299
|
topK: { type: "number", description: "Result limit, default 5" }
|
|
300
300
|
},
|
|
301
|
-
fn: (
|
|
302
|
-
if (!
|
|
303
|
-
return
|
|
301
|
+
fn: (a) => {
|
|
302
|
+
if (!a.subject && !a.query) throw new Error("Either a subject or query argument is required");
|
|
303
|
+
return o(a.query, a.subject, a.topK);
|
|
304
304
|
}
|
|
305
305
|
}, {
|
|
306
306
|
name: "remember",
|
|
@@ -309,31 +309,31 @@ ${l}` }), e.tools = [{
|
|
|
309
309
|
owner: { type: "string", description: "Subject/person this fact is about" },
|
|
310
310
|
fact: { type: "string", description: "The information to remember" }
|
|
311
311
|
},
|
|
312
|
-
fn: async (
|
|
312
|
+
fn: async (a) => {
|
|
313
313
|
if (!e.memory) return;
|
|
314
|
-
const
|
|
315
|
-
this.embedding(
|
|
316
|
-
this.embedding(`${
|
|
317
|
-
]),
|
|
318
|
-
return e.memory.splice(0, e.memory.length, ...e.memory.filter((
|
|
314
|
+
const m = await Promise.all([
|
|
315
|
+
this.embedding(a.owner),
|
|
316
|
+
this.embedding(`${a.owner}: ${a.fact}`)
|
|
317
|
+
]), i = { owner: a.owner, fact: a.fact, embeddings: [m[0][0].embedding, m[1][0].embedding] };
|
|
318
|
+
return e.memory.splice(0, e.memory.length, ...e.memory.filter((p) => !(this.cosineSimilarity(i.embeddings[0], p.embeddings[0]) >= 0.9 && this.cosineSimilarity(i.embeddings[1], p.embeddings[1]) >= 0.8)), i), "Remembered!";
|
|
319
319
|
}
|
|
320
320
|
}, ...e.tools || []];
|
|
321
321
|
}
|
|
322
|
-
const
|
|
323
|
-
if (e.memory && e.history.splice(0, e.history.length, ...e.history.filter((
|
|
324
|
-
const
|
|
325
|
-
e.history.splice(0, e.history.length, ...
|
|
322
|
+
const s = await this.models[t].ask(r, e);
|
|
323
|
+
if (e.memory && e.history.splice(0, e.history.length, ...e.history.filter((o) => o.role != "tool" || o.name != "recall" && o.name != "remember")), e.compress) {
|
|
324
|
+
const o = await this.ai.language.compressHistory(e.history, e.compress.max, e.compress.min, e);
|
|
325
|
+
e.history.splice(0, e.history.length, ...o);
|
|
326
326
|
}
|
|
327
|
-
return
|
|
328
|
-
}), { abort:
|
|
327
|
+
return n(s);
|
|
328
|
+
}), { abort: l });
|
|
329
329
|
}
|
|
330
330
|
async code(r, e) {
|
|
331
331
|
const t = await this.ask(r, { ...e, system: [
|
|
332
332
|
e?.system,
|
|
333
333
|
"Return your response in a code block"
|
|
334
|
-
].filter((
|
|
335
|
-
`) }),
|
|
336
|
-
return
|
|
334
|
+
].filter((n) => !!n).join(`
|
|
335
|
+
`) }), l = /```(?:.+)?\s*([\s\S]*?)```/.exec(t);
|
|
336
|
+
return l ? l[1].trim() : null;
|
|
337
337
|
}
|
|
338
338
|
/**
|
|
339
339
|
* Compress chat history to reduce context size
|
|
@@ -343,17 +343,17 @@ ${l}` }), e.tools = [{
|
|
|
343
343
|
* @param {LLMRequest} options LLM options
|
|
344
344
|
* @returns {Promise<LLMMessage[]>} New chat history will summary at index 0
|
|
345
345
|
*/
|
|
346
|
-
async compressHistory(r, e, t,
|
|
346
|
+
async compressHistory(r, e, t, l) {
|
|
347
347
|
if (this.estimateTokens(r) < e) return r;
|
|
348
|
-
let
|
|
348
|
+
let n = 0, s = 0;
|
|
349
349
|
for (let d of r.toReversed())
|
|
350
|
-
if (
|
|
350
|
+
if (s += this.estimateTokens(d.content), s < t) n++;
|
|
351
351
|
else break;
|
|
352
|
-
if (r.length <=
|
|
353
|
-
const
|
|
352
|
+
if (r.length <= n) return r;
|
|
353
|
+
const o = r[0].role == "system" ? r[0] : null, u = n == 0 ? [] : r.slice(-n), a = (n == 0 ? r : r.slice(0, -n)).filter((d) => d.role === "assistant" || d.role === "user"), m = await this.summarize(a.map((d) => `[${d.role}]: ${d.content}`).join(`
|
|
354
354
|
|
|
355
|
-
`), 500,
|
|
356
|
-
return
|
|
355
|
+
`), 500, l), i = Date.now(), p = [{ role: "tool", name: "summary", id: "summary_" + i, args: {}, content: `Conversation Summary: ${m?.summary}`, timestamp: i }, ...u];
|
|
356
|
+
return o && p.splice(0, 0, o), p;
|
|
357
357
|
}
|
|
358
358
|
/**
|
|
359
359
|
* Compare the difference between embeddings (calculates the angle between two vectors)
|
|
@@ -363,11 +363,11 @@ ${l}` }), e.tools = [{
|
|
|
363
363
|
*/
|
|
364
364
|
cosineSimilarity(r, e) {
|
|
365
365
|
if (r.length !== e.length) throw new Error("Vectors must be same length");
|
|
366
|
-
let t = 0,
|
|
367
|
-
for (let
|
|
368
|
-
t += r[
|
|
369
|
-
const
|
|
370
|
-
return
|
|
366
|
+
let t = 0, l = 0, n = 0;
|
|
367
|
+
for (let o = 0; o < r.length; o++)
|
|
368
|
+
t += r[o] * e[o], l += r[o] * r[o], n += e[o] * e[o];
|
|
369
|
+
const s = Math.sqrt(l) * Math.sqrt(n);
|
|
370
|
+
return s === 0 ? 0 : t / s;
|
|
371
371
|
}
|
|
372
372
|
/**
|
|
373
373
|
* Chunk text into parts for AI digestion
|
|
@@ -377,25 +377,25 @@ ${l}` }), e.tools = [{
|
|
|
377
377
|
* @returns {string[]} Chunked strings
|
|
378
378
|
*/
|
|
379
379
|
chunk(r, e = 500, t = 50) {
|
|
380
|
-
const
|
|
381
|
-
const
|
|
382
|
-
return typeof
|
|
383
|
-
}) : [],
|
|
384
|
-
`)).flatMap((
|
|
385
|
-
`]),
|
|
386
|
-
for (let
|
|
387
|
-
let
|
|
388
|
-
for (;
|
|
389
|
-
const
|
|
390
|
-
if (this.estimateTokens(
|
|
391
|
-
`)) > e &&
|
|
392
|
-
|
|
380
|
+
const l = (u, a = "") => u ? Object.entries(u).flatMap(([m, i]) => {
|
|
381
|
+
const p = a ? `${a}${isNaN(+m) ? `.${m}` : `[${m}]`}` : m;
|
|
382
|
+
return typeof i == "object" && !Array.isArray(i) ? l(i, p) : `${p}: ${Array.isArray(i) ? i.join(", ") : i}`;
|
|
383
|
+
}) : [], s = (typeof r == "object" ? l(r) : r.toString().split(`
|
|
384
|
+
`)).flatMap((u) => [...u.split(/\s+/).filter(Boolean), `
|
|
385
|
+
`]), o = [];
|
|
386
|
+
for (let u = 0; u < s.length; ) {
|
|
387
|
+
let a = "", m = u;
|
|
388
|
+
for (; m < s.length; ) {
|
|
389
|
+
const p = a + (a ? " " : "") + s[m];
|
|
390
|
+
if (this.estimateTokens(p.replace(/\s*\n\s*/g, `
|
|
391
|
+
`)) > e && a) break;
|
|
392
|
+
a = p, m++;
|
|
393
393
|
}
|
|
394
|
-
const
|
|
394
|
+
const i = a.replace(/\s*\n\s*/g, `
|
|
395
395
|
`).trim();
|
|
396
|
-
|
|
396
|
+
i && o.push(i), u = Math.max(m - t, m === u ? u + 1 : m);
|
|
397
397
|
}
|
|
398
|
-
return
|
|
398
|
+
return o;
|
|
399
399
|
}
|
|
400
400
|
/**
|
|
401
401
|
* Create a vector representation of a string
|
|
@@ -404,39 +404,39 @@ ${l}` }), e.tools = [{
|
|
|
404
404
|
* @returns {Promise<Awaited<{index: number, embedding: number[], text: string, tokens: number}>[]>} Chunked embeddings
|
|
405
405
|
*/
|
|
406
406
|
embedding(r, e = {}) {
|
|
407
|
-
let { maxTokens: t = 500, overlapTokens:
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
},
|
|
411
|
-
if (
|
|
412
|
-
const
|
|
413
|
-
|
|
407
|
+
let { maxTokens: t = 500, overlapTokens: l = 50 } = e, n = !1;
|
|
408
|
+
const s = () => {
|
|
409
|
+
n = !0;
|
|
410
|
+
}, o = (a) => new Promise((m, i) => {
|
|
411
|
+
if (n) return i(new Error("Aborted"));
|
|
412
|
+
const p = [
|
|
413
|
+
Y(V(K(import.meta.url)), "embedder.js"),
|
|
414
414
|
this.ai.options.path,
|
|
415
415
|
this.ai.options?.embedder || "bge-small-en-v1.5"
|
|
416
|
-
], d =
|
|
417
|
-
d.stdin.write(
|
|
418
|
-
let
|
|
419
|
-
d.stdout.on("data", (f) =>
|
|
420
|
-
if (
|
|
416
|
+
], d = k("node", p, { stdio: ["pipe", "pipe", "ignore"] });
|
|
417
|
+
d.stdin.write(a), d.stdin.end();
|
|
418
|
+
let c = "";
|
|
419
|
+
d.stdout.on("data", (f) => c += f.toString()), d.on("close", (f) => {
|
|
420
|
+
if (n) return i(new Error("Aborted"));
|
|
421
421
|
if (f === 0)
|
|
422
422
|
try {
|
|
423
|
-
const g = JSON.parse(
|
|
424
|
-
|
|
423
|
+
const g = JSON.parse(c);
|
|
424
|
+
m(g.embedding);
|
|
425
425
|
} catch {
|
|
426
|
-
|
|
426
|
+
i(new Error("Failed to parse embedding output"));
|
|
427
427
|
}
|
|
428
428
|
else
|
|
429
|
-
|
|
430
|
-
}), d.on("error",
|
|
431
|
-
}),
|
|
432
|
-
const
|
|
433
|
-
for (let
|
|
434
|
-
const
|
|
435
|
-
|
|
429
|
+
i(new Error(`Embedder process exited with code ${f}`));
|
|
430
|
+
}), d.on("error", i);
|
|
431
|
+
}), u = (async () => {
|
|
432
|
+
const a = this.chunk(r, t, l), m = [];
|
|
433
|
+
for (let i = 0; i < a.length && !n; i++) {
|
|
434
|
+
const p = a[i], d = await o(p);
|
|
435
|
+
m.push({ index: i, embedding: d, text: p, tokens: this.estimateTokens(p) });
|
|
436
436
|
}
|
|
437
|
-
return
|
|
437
|
+
return m;
|
|
438
438
|
})();
|
|
439
|
-
return Object.assign(
|
|
439
|
+
return Object.assign(u, { abort: s });
|
|
440
440
|
}
|
|
441
441
|
/**
|
|
442
442
|
* Estimate variable as tokens
|
|
@@ -455,8 +455,8 @@ ${l}` }), e.tools = [{
|
|
|
455
455
|
*/
|
|
456
456
|
fuzzyMatch(r, ...e) {
|
|
457
457
|
if (e.length < 2) throw new Error("Requires at least 2 strings to compare");
|
|
458
|
-
const t = (
|
|
459
|
-
return { avg:
|
|
458
|
+
const t = (s, o = 10) => s.toLowerCase().split("").map((u, a) => u.charCodeAt(0) * (a + 1) % o / o).slice(0, o), l = t(r), n = e.map((s) => t(s)).map((s) => this.cosineSimilarity(l, s));
|
|
459
|
+
return { avg: n.reduce((s, o) => s + o, 0) / n.length, max: Math.max(...n), similarities: n };
|
|
460
460
|
}
|
|
461
461
|
/**
|
|
462
462
|
* Ask a question with JSON response
|
|
@@ -466,28 +466,28 @@ ${l}` }), e.tools = [{
|
|
|
466
466
|
* @returns {Promise<{} | {} | RegExpExecArray | null>}
|
|
467
467
|
*/
|
|
468
468
|
async json(r, e, t) {
|
|
469
|
-
let
|
|
469
|
+
let l = `Your job is to convert input to JSON using tool calls. Call the \`submit\` tool at least once with JSON matching this schema:
|
|
470
470
|
\`\`\`json
|
|
471
471
|
${e}
|
|
472
472
|
\`\`\`
|
|
473
473
|
|
|
474
474
|
Responses are ignored`;
|
|
475
|
-
return t?.system && (
|
|
475
|
+
return t?.system && (l += `
|
|
476
476
|
|
|
477
|
-
` + t.system), new Promise(async (
|
|
478
|
-
let
|
|
479
|
-
const
|
|
477
|
+
` + t.system), new Promise(async (n, s) => {
|
|
478
|
+
let o = !1;
|
|
479
|
+
const u = await this.ask(r, {
|
|
480
480
|
temperature: 0.3,
|
|
481
481
|
...t,
|
|
482
|
-
system:
|
|
482
|
+
system: l,
|
|
483
483
|
tools: [{
|
|
484
484
|
name: "submit",
|
|
485
485
|
description: "Submit JSON",
|
|
486
486
|
args: { json: { type: "string", description: "Javascript parsable JSON string", required: !0 } },
|
|
487
|
-
fn: (
|
|
487
|
+
fn: (a) => {
|
|
488
488
|
try {
|
|
489
|
-
const
|
|
490
|
-
|
|
489
|
+
const m = JSON.parse(a.json);
|
|
490
|
+
n(m), o = !0;
|
|
491
491
|
} catch {
|
|
492
492
|
return "Invalid JSON";
|
|
493
493
|
}
|
|
@@ -495,8 +495,8 @@ Responses are ignored`;
|
|
|
495
495
|
}
|
|
496
496
|
}, ...t?.tools || []]
|
|
497
497
|
});
|
|
498
|
-
|
|
499
|
-
${
|
|
498
|
+
o || s(`AI failed to create JSON:
|
|
499
|
+
${u}`);
|
|
500
500
|
});
|
|
501
501
|
}
|
|
502
502
|
/**
|
|
@@ -507,28 +507,28 @@ ${l}`);
|
|
|
507
507
|
* @returns {Promise<string>} Summary
|
|
508
508
|
*/
|
|
509
509
|
async summarize(r, e = 500, t) {
|
|
510
|
-
let
|
|
511
|
-
return t?.system && (
|
|
510
|
+
let l = `Your job is to summarize the users message using tool calls. Call the \`submit\` tool at least once with the shortest summary possible that's <= ${e} words. The tool call will respond with the token count. Responses are ignored`;
|
|
511
|
+
return t?.system && (l += `
|
|
512
512
|
|
|
513
|
-
` + t.system), new Promise(async (
|
|
514
|
-
let
|
|
515
|
-
const
|
|
513
|
+
` + t.system), new Promise(async (n, s) => {
|
|
514
|
+
let o = !1;
|
|
515
|
+
const u = await this.ask(r, {
|
|
516
516
|
temperature: 0.3,
|
|
517
517
|
...t,
|
|
518
|
-
system:
|
|
518
|
+
system: l,
|
|
519
519
|
tools: [{
|
|
520
520
|
name: "submit",
|
|
521
521
|
description: "Submit summary",
|
|
522
522
|
args: { summary: { type: "string", description: "Text summarization", required: !0 } },
|
|
523
|
-
fn: (
|
|
523
|
+
fn: (a) => a.summary ? a.summary.split(" ").length > e ? `Too long: ${e} words` : (o = !0, n(a.summary || null), `Saved: ${e} words`) : "No summary provided"
|
|
524
524
|
}, ...t?.tools || []]
|
|
525
525
|
});
|
|
526
|
-
|
|
527
|
-
${
|
|
526
|
+
o || s(`AI failed to create summary:
|
|
527
|
+
${u}`);
|
|
528
528
|
});
|
|
529
529
|
}
|
|
530
530
|
}
|
|
531
|
-
class
|
|
531
|
+
class ne {
|
|
532
532
|
constructor(r) {
|
|
533
533
|
this.ai = r, r.options.whisper && (this.whisperModel = r.options.asr || "ggml-base.en.bin", this.downloadAsrModel()), this.pyannote = `
|
|
534
534
|
import sys
|
|
@@ -551,21 +551,21 @@ print(json.dumps(segments))
|
|
|
551
551
|
pyannote;
|
|
552
552
|
whisperModel;
|
|
553
553
|
async addPunctuation(r, e, t = 150) {
|
|
554
|
-
const
|
|
555
|
-
if (
|
|
556
|
-
const
|
|
557
|
-
let
|
|
558
|
-
return
|
|
554
|
+
const l = (s) => {
|
|
555
|
+
if (s = s.toLowerCase().replace(/[^a-z]/g, ""), s.length <= 3) return 1;
|
|
556
|
+
const o = s.match(/[aeiouy]+/g);
|
|
557
|
+
let u = o ? o.length : 1;
|
|
558
|
+
return s.endsWith("e") && u--, Math.max(1, u);
|
|
559
559
|
};
|
|
560
|
-
let
|
|
561
|
-
return r.transcription.filter((
|
|
562
|
-
let
|
|
563
|
-
const
|
|
564
|
-
return !
|
|
565
|
-
}).forEach((
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
}), e ? this.ai.language.ask(
|
|
560
|
+
let n = "";
|
|
561
|
+
return r.transcription.filter((s, o) => {
|
|
562
|
+
let u = !1;
|
|
563
|
+
const a = r.transcription[o - 1], m = r.transcription[o + 1];
|
|
564
|
+
return !s.text && m ? (m.offsets.from = s.offsets.from, m.timestamps.from = s.offsets.from) : s.text && s.text[0] != " " && a && (a.offsets.to = s.offsets.to, a.timestamps.to = s.timestamps.to, a.text += s.text, u = !0), !!s.text && !u;
|
|
565
|
+
}).forEach((s) => {
|
|
566
|
+
const o = /^[A-Z]/.test(s.text.trim()), u = s.offsets.to - s.offsets.from, m = l(s.text.trim()) * t;
|
|
567
|
+
o && u > m * 2 && s.text[0] == " " && (n += "."), n += s.text;
|
|
568
|
+
}), e ? this.ai.language.ask(n, {
|
|
569
569
|
system: "Remove any misplaced punctuation from the following ASR transcript using the replace tool. Avoid modifying words unless there is an obvious typo",
|
|
570
570
|
temperature: 0.1,
|
|
571
571
|
tools: [{
|
|
@@ -575,141 +575,141 @@ print(json.dumps(segments))
|
|
|
575
575
|
find: { type: "string", description: "Text to find", required: !0 },
|
|
576
576
|
replace: { type: "string", description: "Text to replace", required: !0 }
|
|
577
577
|
},
|
|
578
|
-
fn: (
|
|
578
|
+
fn: (s) => n = n.replace(s.find, s.replace)
|
|
579
579
|
}]
|
|
580
|
-
}).then(() =>
|
|
580
|
+
}).then(() => n) : n.trim();
|
|
581
581
|
}
|
|
582
582
|
async diarizeTranscript(r, e, t) {
|
|
583
|
-
const
|
|
584
|
-
let
|
|
585
|
-
e.forEach((
|
|
586
|
-
|
|
583
|
+
const l = /* @__PURE__ */ new Map();
|
|
584
|
+
let n = 0;
|
|
585
|
+
e.forEach((c) => {
|
|
586
|
+
l.has(c.speaker) || l.set(c.speaker, ++n);
|
|
587
587
|
});
|
|
588
|
-
const
|
|
589
|
-
if (
|
|
590
|
-
const f =
|
|
591
|
-
f.forEach((
|
|
592
|
-
const
|
|
593
|
-
if (!
|
|
594
|
-
const
|
|
595
|
-
if (
|
|
596
|
-
const
|
|
597
|
-
g.set(
|
|
588
|
+
const s = await this.addPunctuation(r, t), o = s.match(/[^.!?]+[.!?]+/g) || [s], u = r.transcription.filter((c) => c.text.trim()), a = o.map((c) => {
|
|
589
|
+
if (c = c.trim(), !c) return null;
|
|
590
|
+
const f = c.toLowerCase().replace(/[^\w\s]/g, "").split(/\s+/), g = /* @__PURE__ */ new Map();
|
|
591
|
+
f.forEach((y) => {
|
|
592
|
+
const _ = u.find((w) => y === w.text.trim().toLowerCase().replace(/[^\w]/g, ""));
|
|
593
|
+
if (!_) return;
|
|
594
|
+
const v = _.offsets.from / 1e3, E = e.find((w) => v >= w.start && v <= w.end);
|
|
595
|
+
if (E) {
|
|
596
|
+
const w = l.get(E.speaker);
|
|
597
|
+
g.set(w, (g.get(w) || 0) + 1);
|
|
598
598
|
}
|
|
599
599
|
});
|
|
600
|
-
let
|
|
601
|
-
return g.forEach((
|
|
602
|
-
|
|
603
|
-
}), { speaker:
|
|
604
|
-
}).filter((
|
|
605
|
-
|
|
606
|
-
const f =
|
|
607
|
-
f && f.speaker ===
|
|
600
|
+
let b = 1, S = 0;
|
|
601
|
+
return g.forEach((y, _) => {
|
|
602
|
+
y > S && (S = y, b = _);
|
|
603
|
+
}), { speaker: b, text: c };
|
|
604
|
+
}).filter((c) => c !== null), m = [];
|
|
605
|
+
a.forEach((c) => {
|
|
606
|
+
const f = m[m.length - 1];
|
|
607
|
+
f && f.speaker === c.speaker ? f.text += " " + c.text : m.push({ ...c });
|
|
608
608
|
});
|
|
609
|
-
let
|
|
609
|
+
let i = m.map((c) => `[Speaker ${c.speaker}]: ${c.text}`).join(`
|
|
610
610
|
`).trim();
|
|
611
|
-
if (!t) return
|
|
612
|
-
let
|
|
613
|
-
|
|
614
|
-
const d = await this.ai.language.json(
|
|
611
|
+
if (!t) return i;
|
|
612
|
+
let p = this.ai.language.chunk(i, 500, 0);
|
|
613
|
+
p.length > 4 && (p = [...p.slice(0, 3), p.at(-1)]);
|
|
614
|
+
const d = await this.ai.language.json(p.join(`
|
|
615
615
|
`), '{1: "Detected Name", 2: "Second Name"}', {
|
|
616
616
|
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",
|
|
617
617
|
temperature: 0.1
|
|
618
618
|
});
|
|
619
|
-
return Object.entries(d).forEach(([
|
|
619
|
+
return Object.entries(d).forEach(([c, f]) => i = i.replaceAll(`[Speaker ${c}]`, `[${f}]`)), i;
|
|
620
620
|
}
|
|
621
621
|
runAsr(r, e = {}) {
|
|
622
622
|
let t;
|
|
623
|
-
const
|
|
624
|
-
this.downloadAsrModel(e.model).then((
|
|
623
|
+
const l = new Promise((n, s) => {
|
|
624
|
+
this.downloadAsrModel(e.model).then((o) => {
|
|
625
625
|
if (e.diarization) {
|
|
626
|
-
let
|
|
627
|
-
t =
|
|
626
|
+
let u = q.join(q.dirname(r), "transcript");
|
|
627
|
+
t = k(
|
|
628
628
|
this.ai.options.whisper,
|
|
629
|
-
["-m",
|
|
629
|
+
["-m", o, "-f", r, "-np", "-ml", "1", "-oj", "-of", u],
|
|
630
630
|
{ stdio: ["ignore", "ignore", "pipe"] }
|
|
631
|
-
), t.on("error", (
|
|
632
|
-
if (
|
|
633
|
-
|
|
631
|
+
), t.on("error", (a) => s(a)), t.on("close", async (a) => {
|
|
632
|
+
if (a === 0) {
|
|
633
|
+
u = await x.readFile(u + ".json", "utf-8"), x.rm(u + ".json").catch(() => {
|
|
634
634
|
});
|
|
635
635
|
try {
|
|
636
|
-
|
|
636
|
+
n(JSON.parse(u));
|
|
637
637
|
} catch {
|
|
638
|
-
|
|
638
|
+
s(new Error("Failed to parse whisper JSON"));
|
|
639
639
|
}
|
|
640
640
|
} else
|
|
641
|
-
|
|
641
|
+
s(new Error(`Exit code ${a}`));
|
|
642
642
|
});
|
|
643
643
|
} else {
|
|
644
|
-
let
|
|
645
|
-
t =
|
|
646
|
-
|
|
644
|
+
let u = "";
|
|
645
|
+
t = k(this.ai.options.whisper, ["-m", o, "-f", r, "-np", "-nt"]), t.on("error", (a) => s(a)), t.stdout.on("data", (a) => u += a.toString()), t.on("close", async (a) => {
|
|
646
|
+
a === 0 ? n(u.trim() || null) : s(new Error(`Exit code ${a}`));
|
|
647
647
|
});
|
|
648
648
|
}
|
|
649
649
|
});
|
|
650
650
|
});
|
|
651
|
-
return Object.assign(
|
|
651
|
+
return Object.assign(l, { abort: () => t?.kill("SIGTERM") });
|
|
652
652
|
}
|
|
653
653
|
runDiarization(r) {
|
|
654
654
|
let e = !1, t = () => {
|
|
655
655
|
e = !0;
|
|
656
656
|
};
|
|
657
|
-
const
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
}),
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
]).then((async ([
|
|
657
|
+
const l = (s) => new Promise((o) => {
|
|
658
|
+
const u = k(s, ["-W", "ignore", "-c", "import pyannote.audio"]);
|
|
659
|
+
u.on("close", (a) => o(a === 0)), u.on("error", () => o(!1));
|
|
660
|
+
}), n = Promise.all([
|
|
661
|
+
l("python"),
|
|
662
|
+
l("python3")
|
|
663
|
+
]).then((async ([s, o]) => {
|
|
664
664
|
if (e) return;
|
|
665
|
-
if (!
|
|
666
|
-
const
|
|
667
|
-
return new Promise((
|
|
665
|
+
if (!s && !o) throw new Error("Pyannote is not installed: pip install pyannote.audio");
|
|
666
|
+
const u = o ? "python3" : "python";
|
|
667
|
+
return new Promise((a, m) => {
|
|
668
668
|
if (e) return;
|
|
669
|
-
let
|
|
670
|
-
const
|
|
671
|
-
|
|
669
|
+
let i = "";
|
|
670
|
+
const p = k(u, ["-W", "ignore", "-c", this.pyannote, r]);
|
|
671
|
+
p.stdout.on("data", (d) => i += d.toString()), p.stderr.on("data", (d) => console.error(d.toString())), p.on("close", (d) => {
|
|
672
672
|
if (d === 0)
|
|
673
673
|
try {
|
|
674
|
-
|
|
674
|
+
a(JSON.parse(i));
|
|
675
675
|
} catch {
|
|
676
|
-
|
|
676
|
+
m(new Error("Failed to parse diarization output"));
|
|
677
677
|
}
|
|
678
678
|
else
|
|
679
|
-
|
|
680
|
-
}),
|
|
679
|
+
m(new Error(`Python process exited with code ${d}`));
|
|
680
|
+
}), p.on("error", m), t = () => p.kill("SIGTERM");
|
|
681
681
|
});
|
|
682
682
|
}));
|
|
683
|
-
return Object.assign(
|
|
683
|
+
return Object.assign(n, { abort: t });
|
|
684
684
|
}
|
|
685
685
|
asr(r, e = {}) {
|
|
686
686
|
if (!this.ai.options.whisper) throw new Error("Whisper not configured");
|
|
687
|
-
const t = A(
|
|
688
|
-
|
|
689
|
-
const
|
|
687
|
+
const t = A(Q(A(W(), "audio-")), "converted.wav");
|
|
688
|
+
Z(`ffmpeg -i "${r}" -ar 16000 -ac 1 -f wav "${t}"`, { stdio: "ignore" });
|
|
689
|
+
const l = () => x.rm(M.dirname(t), { recursive: !0, force: !0 }).catch(() => {
|
|
690
690
|
});
|
|
691
691
|
if (!e.diarization) return this.runAsr(t, { model: e.model });
|
|
692
|
-
const
|
|
693
|
-
let
|
|
694
|
-
|
|
692
|
+
const n = this.runAsr(t, { model: e.model, diarization: !0 }), s = this.runDiarization(t);
|
|
693
|
+
let o = !1, u = () => {
|
|
694
|
+
o = !0, n.abort(), s.abort(), l();
|
|
695
695
|
};
|
|
696
|
-
const
|
|
697
|
-
if (
|
|
698
|
-
` +
|
|
699
|
-
if (
|
|
700
|
-
` +
|
|
701
|
-
return
|
|
702
|
-
}).finally(() =>
|
|
703
|
-
return Object.assign(
|
|
696
|
+
const a = Promise.allSettled([n, s]).then(async ([m, i]) => {
|
|
697
|
+
if (m.status == "rejected") throw new Error(`Whisper.cpp timestamps:
|
|
698
|
+
` + m.reason);
|
|
699
|
+
if (i.status == "rejected") throw new Error(`Pyannote:
|
|
700
|
+
` + i.reason);
|
|
701
|
+
return o || !e.diarization ? m.value : this.diarizeTranscript(m.value, i.value, e.diarization == "llm");
|
|
702
|
+
}).finally(() => l());
|
|
703
|
+
return Object.assign(a, { abort: u });
|
|
704
704
|
}
|
|
705
705
|
async downloadAsrModel(r = this.whisperModel) {
|
|
706
706
|
if (!this.ai.options.whisper) throw new Error("Whisper not configured");
|
|
707
707
|
r.endsWith(".bin") || (r += ".bin");
|
|
708
|
-
const e =
|
|
709
|
-
return await
|
|
708
|
+
const e = M.join(this.ai.options.path, r);
|
|
709
|
+
return await x.stat(e).then(() => !0).catch(() => !1) ? e : this.downloads[r] ? this.downloads[r] : (this.downloads[r] = fetch(`https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${r}`).then((t) => t.arrayBuffer()).then((t) => Buffer.from(t)).then(async (t) => (await x.writeFile(e, t), delete this.downloads[r], e)), this.downloads[r]);
|
|
710
710
|
}
|
|
711
711
|
}
|
|
712
|
-
class
|
|
712
|
+
class se {
|
|
713
713
|
constructor(r) {
|
|
714
714
|
this.ai = r;
|
|
715
715
|
}
|
|
@@ -720,17 +720,17 @@ class te {
|
|
|
720
720
|
*/
|
|
721
721
|
ocr(r) {
|
|
722
722
|
let e;
|
|
723
|
-
const t = new Promise(async (
|
|
724
|
-
e = await
|
|
725
|
-
const { data:
|
|
726
|
-
await e.terminate(),
|
|
723
|
+
const t = new Promise(async (l) => {
|
|
724
|
+
e = await X(this.ai.options.ocr || "eng", 2, { cachePath: this.ai.options.path });
|
|
725
|
+
const { data: n } = await e.recognize(r);
|
|
726
|
+
await e.terminate(), l(n.text.trim() || null);
|
|
727
727
|
});
|
|
728
728
|
return Object.assign(t, { abort: () => e?.terminate() });
|
|
729
729
|
}
|
|
730
730
|
}
|
|
731
|
-
class
|
|
731
|
+
class ke {
|
|
732
732
|
constructor(r) {
|
|
733
|
-
this.options = r, r.path || (r.path =
|
|
733
|
+
this.options = r, r.path || (r.path = R.tmpdir()), process.env.TRANSFORMERS_CACHE = r.path, this.audio = new ne(this), this.language = new re(this), this.vision = new se(this);
|
|
734
734
|
}
|
|
735
735
|
/** Audio processing AI */
|
|
736
736
|
audio;
|
|
@@ -739,37 +739,37 @@ class be {
|
|
|
739
739
|
/** Vision processing AI */
|
|
740
740
|
vision;
|
|
741
741
|
}
|
|
742
|
-
const
|
|
742
|
+
const z = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", oe = () => R.platform() == "win32" ? "cmd" : j`echo $SHELL`?.split("/").pop() || "bash", ie = {
|
|
743
743
|
name: "cli",
|
|
744
744
|
description: "Use the command line interface, returns any output",
|
|
745
745
|
args: { command: { type: "string", description: "Command to run", required: !0 } },
|
|
746
746
|
fn: (h) => j`${h.command}`
|
|
747
|
-
},
|
|
747
|
+
}, Se = {
|
|
748
748
|
name: "get_datetime",
|
|
749
749
|
description: "Get local date / time",
|
|
750
750
|
args: {},
|
|
751
751
|
fn: async () => (/* @__PURE__ */ new Date()).toString()
|
|
752
|
-
},
|
|
752
|
+
}, _e = {
|
|
753
753
|
name: "get_datetime_utc",
|
|
754
754
|
description: "Get current UTC date / time",
|
|
755
755
|
args: {},
|
|
756
756
|
fn: async () => (/* @__PURE__ */ new Date()).toUTCString()
|
|
757
|
-
},
|
|
757
|
+
}, $e = {
|
|
758
758
|
name: "exec",
|
|
759
759
|
description: "Run code/scripts",
|
|
760
760
|
args: {
|
|
761
|
-
language: { type: "string", description: `Execution language (CLI: ${
|
|
761
|
+
language: { type: "string", description: `Execution language (CLI: ${oe()})`, enum: ["cli", "node", "python"], required: !0 },
|
|
762
762
|
code: { type: "string", description: "Code to execute", required: !0 }
|
|
763
763
|
},
|
|
764
764
|
fn: async (h, r, e) => {
|
|
765
765
|
try {
|
|
766
766
|
switch (h.language) {
|
|
767
767
|
case "cli":
|
|
768
|
-
return await
|
|
768
|
+
return await ie.fn({ command: h.code }, r, e);
|
|
769
769
|
case "node":
|
|
770
|
-
return await
|
|
770
|
+
return await ae.fn({ code: h.code }, r, e);
|
|
771
771
|
case "python":
|
|
772
|
-
return await
|
|
772
|
+
return await ce.fn({ code: h.code }, r, e);
|
|
773
773
|
default:
|
|
774
774
|
throw new Error(`Unsupported language: ${h.language}`);
|
|
775
775
|
}
|
|
@@ -777,7 +777,7 @@ const re = () => O.platform() == "win32" ? "cmd" : j`echo $SHELL`?.split("/").po
|
|
|
777
777
|
return { error: t?.message || t.toString() };
|
|
778
778
|
}
|
|
779
779
|
}
|
|
780
|
-
},
|
|
780
|
+
}, Te = {
|
|
781
781
|
name: "fetch",
|
|
782
782
|
description: "Make HTTP request to URL",
|
|
783
783
|
args: {
|
|
@@ -786,100 +786,122 @@ const re = () => O.platform() == "win32" ? "cmd" : j`echo $SHELL`?.split("/").po
|
|
|
786
786
|
headers: { type: "object", description: "HTTP headers to send", default: {} },
|
|
787
787
|
body: { type: "object", description: "HTTP body to send" }
|
|
788
788
|
},
|
|
789
|
-
fn: (h) => new
|
|
790
|
-
},
|
|
789
|
+
fn: (h) => new F({ url: h.url, headers: h.headers }).request({ method: h.method || "GET", body: h.body })
|
|
790
|
+
}, ae = {
|
|
791
791
|
name: "exec_javascript",
|
|
792
792
|
description: "Execute commonjs javascript",
|
|
793
793
|
args: {
|
|
794
794
|
code: { type: "string", description: "CommonJS javascript", required: !0 }
|
|
795
795
|
},
|
|
796
796
|
fn: async (h) => {
|
|
797
|
-
const r =
|
|
797
|
+
const r = B(null), e = await I({ console: r }, h.code, !0).catch((t) => r.output.error.push(t));
|
|
798
798
|
return { ...r.output, return: e, stdout: void 0, stderr: void 0 };
|
|
799
799
|
}
|
|
800
|
-
},
|
|
800
|
+
}, ce = {
|
|
801
801
|
name: "exec_javascript",
|
|
802
802
|
description: "Execute commonjs javascript",
|
|
803
803
|
args: {
|
|
804
804
|
code: { type: "string", description: "CommonJS javascript", required: !0 }
|
|
805
805
|
},
|
|
806
806
|
fn: async (h) => ({ result: j`python -c "${h.code}"` })
|
|
807
|
-
},
|
|
807
|
+
}, je = {
|
|
808
808
|
name: "read_webpage",
|
|
809
|
-
description: "Extract clean
|
|
809
|
+
description: "Extract clean content from webpages, or convert media/documents to accessible formats",
|
|
810
810
|
args: {
|
|
811
|
-
url: { type: "string", description: "URL to
|
|
812
|
-
mimeRegex: { type: "string", description: 'Optional
|
|
813
|
-
maxSize: { type: "number", description: "Optional: Max file size in bytes for binary content (default: 10MB)" }
|
|
811
|
+
url: { type: "string", description: "URL to read", required: !0 },
|
|
812
|
+
mimeRegex: { type: "string", description: 'Optional regex to filter MIME types (e.g., "^image/", "text/")' }
|
|
814
813
|
},
|
|
815
814
|
fn: async (h) => {
|
|
816
|
-
const
|
|
815
|
+
const t = await fetch(h.url, {
|
|
817
816
|
headers: {
|
|
818
|
-
"User-Agent": "
|
|
817
|
+
"User-Agent": "AiTools-Webpage/1.0",
|
|
819
818
|
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
|
820
819
|
"Accept-Language": "en-US,en;q=0.5"
|
|
821
820
|
},
|
|
822
821
|
redirect: "follow"
|
|
823
|
-
}).catch((
|
|
824
|
-
throw new Error(`Failed to fetch: ${
|
|
825
|
-
}),
|
|
826
|
-
if (
|
|
827
|
-
return
|
|
828
|
-
if (
|
|
829
|
-
const
|
|
830
|
-
if (
|
|
831
|
-
return
|
|
832
|
-
|
|
833
|
-
|
|
822
|
+
}).catch((c) => {
|
|
823
|
+
throw new Error(`Failed to fetch: ${c.message}`);
|
|
824
|
+
}), n = (t.headers.get("content-type") || "").split(";")[0].trim().toLowerCase();
|
|
825
|
+
if (h.mimeRegex && !new RegExp(h.mimeRegex, "i").test(n))
|
|
826
|
+
return `❌ MIME type rejected: ${n} (filter: ${h.mimeRegex})`;
|
|
827
|
+
if (n.match(/^(image|audio|video)\//)) {
|
|
828
|
+
const c = await t.arrayBuffer();
|
|
829
|
+
if (c.byteLength > 10485760)
|
|
830
|
+
return `❌ File too large: ${(c.byteLength / 1024 / 1024).toFixed(1)}MB (max 10MB)
|
|
831
|
+
Type: ${n}`;
|
|
832
|
+
const f = Buffer.from(c).toString("base64");
|
|
833
|
+
return `## Media File
|
|
834
|
+
**Type:** ${n}
|
|
835
|
+
**Size:** ${(c.byteLength / 1024).toFixed(1)}KB
|
|
836
|
+
**Data URL:** \`data:${n};base64,${f.slice(0, 100)}...\``;
|
|
834
837
|
}
|
|
835
|
-
if (
|
|
836
|
-
const
|
|
837
|
-
return
|
|
838
|
+
if (n.match(/^text\/(plain|csv|xml)/) || h.url.match(/\.(txt|csv|xml|md|yaml|yml)$/i)) {
|
|
839
|
+
const c = await t.text(), f = c.length > 5e4 ? c.slice(0, 5e4) : c;
|
|
840
|
+
return `## Text File
|
|
841
|
+
**Type:** ${n}
|
|
842
|
+
**URL:** ${h.url}
|
|
843
|
+
|
|
844
|
+
${f}`;
|
|
838
845
|
}
|
|
839
|
-
if (
|
|
840
|
-
const
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
846
|
+
if (n.match(/application\/(json|xml|csv)/)) {
|
|
847
|
+
const c = await t.text(), f = c.length > 5e4 ? c.slice(0, 5e4) : c;
|
|
848
|
+
return `## Structured Data
|
|
849
|
+
**Type:** ${n}
|
|
850
|
+
**URL:** ${h.url}
|
|
851
|
+
|
|
852
|
+
\`\`\`
|
|
853
|
+
${f}
|
|
854
|
+
\`\`\``;
|
|
845
855
|
}
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
856
|
+
if (n === "application/pdf" || n.startsWith("application/") && !n.includes("html")) {
|
|
857
|
+
const c = await t.arrayBuffer();
|
|
858
|
+
if (c.byteLength > 10485760)
|
|
859
|
+
return `❌ File too large: ${(c.byteLength / 1024 / 1024).toFixed(1)}MB (max 10MB)
|
|
860
|
+
Type: ${n}`;
|
|
861
|
+
const f = Buffer.from(c).toString("base64");
|
|
862
|
+
return `## Binary File
|
|
863
|
+
**Type:** ${n}
|
|
864
|
+
**Size:** ${(c.byteLength / 1024).toFixed(1)}KB
|
|
865
|
+
**Data URL:** \`data:${n};base64,${f.slice(0, 100)}...\``;
|
|
866
|
+
}
|
|
867
|
+
const s = await t.text(), o = ee.load(s);
|
|
868
|
+
o("script, style, nav, footer, header, aside, iframe, noscript, svg").remove(), o('[role="navigation"], [role="banner"], [role="complementary"]').remove(), o('[aria-hidden="true"], [hidden], .visually-hidden, .sr-only, .screen-reader-text').remove(), o(".ad, .ads, .advertisement, .cookie, .popup, .modal, .sidebar, .related, .comments, .social-share").remove(), o('button, [class*="share"], [class*="follow"], [class*="social"]').remove();
|
|
869
|
+
const u = o('meta[property="og:title"]').attr("content") || o("title").text().trim() || "", a = o('meta[name="description"]').attr("content") || o('meta[property="og:description"]').attr("content") || "", m = o('meta[name="author"]').attr("content") || "";
|
|
870
|
+
let i = "";
|
|
871
|
+
const p = ["article", "main", '[role="main"]', ".content", ".post-content", ".entry-content", ".article-content"];
|
|
872
|
+
for (const c of p) {
|
|
873
|
+
const f = o(c).first();
|
|
874
|
+
if (f.length && f.text().trim().length > 200) {
|
|
875
|
+
const g = [];
|
|
876
|
+
if (f.find("p").each((b, S) => {
|
|
877
|
+
const y = o(S).text().trim();
|
|
878
|
+
y.length > 80 && g.push(y);
|
|
879
|
+
}), g.length > 2) {
|
|
880
|
+
i = g.join(`
|
|
881
|
+
|
|
882
|
+
`);
|
|
883
|
+
break;
|
|
884
|
+
}
|
|
862
885
|
}
|
|
863
886
|
}
|
|
864
|
-
|
|
887
|
+
if (!i) {
|
|
888
|
+
const c = [];
|
|
889
|
+
o("body p").each((f, g) => {
|
|
890
|
+
const b = o(g).text().trim();
|
|
891
|
+
b.length > 80 && c.push(b);
|
|
892
|
+
}), i = c.slice(0, 30).join(`
|
|
865
893
|
|
|
866
|
-
`)
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
description: m.description.trim(),
|
|
876
|
-
author: m.author.trim(),
|
|
877
|
-
published: m.published,
|
|
878
|
-
content: l,
|
|
879
|
-
links: u.length ? u : void 0
|
|
880
|
-
};
|
|
894
|
+
`);
|
|
895
|
+
}
|
|
896
|
+
const d = [`## ${u || "Webpage"}`];
|
|
897
|
+
return a && d.push(`_${a}_`), m && d.push(`👤 ${m}`), d.push(`🔗 ${h.url}
|
|
898
|
+
`), d.push(i), D(d.join(`
|
|
899
|
+
|
|
900
|
+
`).replaceAll(/\n{3,}/g, `
|
|
901
|
+
|
|
902
|
+
`));
|
|
881
903
|
}
|
|
882
|
-
},
|
|
904
|
+
}, ve = {
|
|
883
905
|
name: "web_search",
|
|
884
906
|
description: "Use duckduckgo (anonymous) to find find relevant online resources. Returns a list of URLs that works great with the `read_webpage` tool",
|
|
885
907
|
args: {
|
|
@@ -888,32 +910,110 @@ const re = () => O.platform() == "win32" ? "cmd" : j`echo $SHELL`?.split("/").po
|
|
|
888
910
|
},
|
|
889
911
|
fn: async (h) => {
|
|
890
912
|
const r = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(h.query)}`, {
|
|
891
|
-
headers: { "User-Agent":
|
|
892
|
-
}).then((
|
|
913
|
+
headers: { "User-Agent": z, "Accept-Language": "en-US,en;q=0.9" }
|
|
914
|
+
}).then((n) => n.text());
|
|
893
915
|
let e, t = /<a .*?href="(.+?)".+?<\/a>/g;
|
|
894
|
-
const
|
|
916
|
+
const l = new H();
|
|
895
917
|
for (; (e = t.exec(r)) !== null; ) {
|
|
896
|
-
let
|
|
897
|
-
if (
|
|
918
|
+
let n = /uddg=(.+)&?/.exec(decodeURIComponent(e[1]))?.[1];
|
|
919
|
+
if (n && (n = decodeURIComponent(n)), n && l.add(n), l.size >= (h.length || 5)) break;
|
|
898
920
|
}
|
|
899
|
-
return
|
|
921
|
+
return l;
|
|
900
922
|
}
|
|
901
923
|
};
|
|
924
|
+
class N {
|
|
925
|
+
async get(r) {
|
|
926
|
+
return (await fetch(r, { headers: { "User-Agent": z } })).json();
|
|
927
|
+
}
|
|
928
|
+
api(r) {
|
|
929
|
+
const e = new URLSearchParams({ ...r, format: "json", utf8: "1" }).toString();
|
|
930
|
+
return this.get(`https://en.wikipedia.org/w/api.php?${e}`);
|
|
931
|
+
}
|
|
932
|
+
clean(r) {
|
|
933
|
+
return r.replace(/\n{3,}/g, `
|
|
934
|
+
|
|
935
|
+
`).replace(/ {2,}/g, " ").replace(/\[\d+\]/g, "").trim();
|
|
936
|
+
}
|
|
937
|
+
truncate(r, e) {
|
|
938
|
+
if (r.length <= e) return r;
|
|
939
|
+
const t = r.slice(0, e), l = t.lastIndexOf(`
|
|
940
|
+
|
|
941
|
+
`);
|
|
942
|
+
return l > e * 0.7 ? t.slice(0, l) : t;
|
|
943
|
+
}
|
|
944
|
+
async searchTitles(r, e = 6) {
|
|
945
|
+
return (await this.api({ action: "query", list: "search", srsearch: r, srlimit: e, srprop: "snippet" })).query?.search || [];
|
|
946
|
+
}
|
|
947
|
+
async fetchExtract(r, e = !1) {
|
|
948
|
+
const t = { action: "query", prop: "extracts", titles: r, explaintext: 1, redirects: 1 };
|
|
949
|
+
e && (t.exintro = 1);
|
|
950
|
+
const l = await this.api(t), n = Object.values(l.query?.pages || {})[0];
|
|
951
|
+
return this.clean(n?.extract || "");
|
|
952
|
+
}
|
|
953
|
+
pageUrl(r) {
|
|
954
|
+
return `https://en.wikipedia.org/wiki/${encodeURIComponent(r.replace(/ /g, "_"))}`;
|
|
955
|
+
}
|
|
956
|
+
stripHtml(r) {
|
|
957
|
+
return r.replace(/<[^>]+>/g, "");
|
|
958
|
+
}
|
|
959
|
+
async lookup(r, e = "intro") {
|
|
960
|
+
const t = await this.searchTitles(r, 6);
|
|
961
|
+
if (!t.length) return `❌ No Wikipedia articles found for "${r}"`;
|
|
962
|
+
const l = t[0].title, n = this.pageUrl(l), s = await this.fetchExtract(l, e === "intro"), o = this.truncate(s, e === "intro" ? 2e3 : 8e3);
|
|
963
|
+
return `## ${l}
|
|
964
|
+
🔗 ${n}
|
|
965
|
+
|
|
966
|
+
${o}`;
|
|
967
|
+
}
|
|
968
|
+
async search(r) {
|
|
969
|
+
const e = await this.searchTitles(r, 8);
|
|
970
|
+
if (!e.length) return `❌ No results for "${r}"`;
|
|
971
|
+
const t = [`### Search results for "${r}"
|
|
972
|
+
`];
|
|
973
|
+
for (let l = 0; l < e.length; l++) {
|
|
974
|
+
const n = e[l], s = this.truncate(this.stripHtml(n.snippet || ""), 150);
|
|
975
|
+
t.push(`**${l + 1}. ${n.title}**
|
|
976
|
+
${s}
|
|
977
|
+
${this.pageUrl(n.title)}`);
|
|
978
|
+
}
|
|
979
|
+
return t.join(`
|
|
980
|
+
|
|
981
|
+
`);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
const Ee = {
|
|
985
|
+
name: "wikipedia_lookup",
|
|
986
|
+
description: "Get Wikipedia article content",
|
|
987
|
+
args: {
|
|
988
|
+
query: { type: "string", description: "Topic or article title", required: !0 },
|
|
989
|
+
detail: { type: "string", description: 'Content level: "intro" (summary, default) or "full" (complete article)', enum: ["intro", "full"], default: "intro" }
|
|
990
|
+
},
|
|
991
|
+
fn: async (h) => new N().lookup(h.query, h.detail || "intro")
|
|
992
|
+
}, qe = {
|
|
993
|
+
name: "wikipedia_search",
|
|
994
|
+
description: "Search Wikipedia for matching articles",
|
|
995
|
+
args: {
|
|
996
|
+
query: { type: "string", description: "Search terms", required: !0 }
|
|
997
|
+
},
|
|
998
|
+
fn: async (h) => new N().search(h.query)
|
|
999
|
+
};
|
|
902
1000
|
export {
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
1001
|
+
ke as Ai,
|
|
1002
|
+
te as Anthropic,
|
|
1003
|
+
ne as Audio,
|
|
1004
|
+
ie as CliTool,
|
|
1005
|
+
Se as DateTimeTool,
|
|
1006
|
+
_e as DateTimeUTCTool,
|
|
1007
|
+
$e as ExecTool,
|
|
1008
|
+
Te as FetchTool,
|
|
1009
|
+
ae as JSTool,
|
|
912
1010
|
L as LLMProvider,
|
|
913
1011
|
P as OpenAi,
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1012
|
+
ce as PythonTool,
|
|
1013
|
+
je as ReadWebpageTool,
|
|
1014
|
+
se as Vision,
|
|
1015
|
+
ve as WebSearchTool,
|
|
1016
|
+
Ee as WikipediaLookupTool,
|
|
1017
|
+
qe as WikipediaSearchTool
|
|
918
1018
|
};
|
|
919
1019
|
//# sourceMappingURL=index.mjs.map
|