@ztimson/ai-utils 0.7.6 → 0.7.8

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