@ztimson/ai-utils 0.6.4 → 0.6.5

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,23 +1,23 @@
1
- import * as j from "node:os";
2
- import { objectMap as _, JSONAttemptParse as g, findByProp as x, JSONSanitize as b, clean as T, Http as P, consoleInterceptor as q, fn as $, ASet as M } from "@ztimson/utils";
3
- import { Anthropic as E } from "@anthropic-ai/sdk";
4
- import { OpenAI as O } from "openai";
5
- import { Worker as v } from "worker_threads";
6
- import { fileURLToPath as A } from "url";
7
- import { join as R, dirname as U } from "path";
8
- import { spawn as w } from "node:child_process";
9
- import { pipeline as z } from "@xenova/transformers";
10
- import * as D from "node:fs";
11
- import * as L from "wavefile";
12
- import { createWorker as N } from "tesseract.js";
1
+ import * as P from "node:os";
2
+ import { objectMap as x, JSONAttemptParse as b, findByProp as S, JSONSanitize as w, clean as q, Http as $, consoleInterceptor as M, fn as E, ASet as A } from "@ztimson/utils";
3
+ import { Anthropic as O } from "@anthropic-ai/sdk";
4
+ import { OpenAI as v } from "openai";
5
+ import { Worker as R } from "worker_threads";
6
+ import { fileURLToPath as U } from "url";
7
+ import { join as z, dirname as L } from "path";
8
+ import { spawn as k } from "node:child_process";
9
+ import { pipeline as N } from "@xenova/transformers";
10
+ import * as W from "node:fs";
11
+ import C from "wavefile";
12
+ import { createWorker as D } from "tesseract.js";
13
13
  import "./embedder.mjs";
14
- import * as W from "cheerio";
15
- import { $ as C, $Sync as I } from "@ztimson/node-utils";
16
- class S {
14
+ import * as I from "cheerio";
15
+ import { $ as F, $Sync as H } from "@ztimson/node-utils";
16
+ class j {
17
17
  }
18
- class H extends S {
18
+ class J extends j {
19
19
  constructor(r, e, t) {
20
- super(), this.ai = r, this.apiToken = e, this.model = t, this.client = new E({ apiKey: e });
20
+ super(), this.ai = r, this.apiToken = e, this.model = t, this.client = new O({ apiKey: e });
21
21
  }
22
22
  client;
23
23
  toStandard(r) {
@@ -26,15 +26,15 @@ class H extends S {
26
26
  if (typeof i.content == "string")
27
27
  t.push({ timestamp: e, ...i });
28
28
  else {
29
- const n = i.content?.filter((s) => s.type == "text").map((s) => s.text).join(`
29
+ const s = i.content?.filter((n) => n.type == "text").map((n) => n.text).join(`
30
30
 
31
31
  `);
32
- n && t.push({ timestamp: e, role: i.role, content: n }), i.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((a) => a.id == s.tool_use_id);
37
- o && (o[s.is_error ? "error" : "content"] = s.content);
32
+ s && t.push({ timestamp: e, role: i.role, content: s }), i.content.forEach((n) => {
33
+ if (n.type == "tool_use")
34
+ t.push({ timestamp: e, role: "tool", id: n.id, name: n.name, args: n.input, content: void 0 });
35
+ else if (n.type == "tool_result") {
36
+ const o = t.findLast((a) => a.id == n.tool_use_id);
37
+ o && (o[n.is_error ? "error" : "content"] = n.content);
38
38
  }
39
39
  });
40
40
  }
@@ -56,34 +56,34 @@ class H extends S {
56
56
  ask(r, e = {}) {
57
57
  const t = new AbortController();
58
58
  return Object.assign(new Promise(async (i) => {
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 = {
59
+ let s = this.fromStandard([...e.history || [], { role: "user", content: r, timestamp: Date.now() }]);
60
+ const n = 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: s.map((d) => ({
65
+ tools: n.map((d) => ({
66
66
  name: d.name,
67
67
  description: d.description,
68
68
  input_schema: {
69
69
  type: "object",
70
- properties: d.args ? _(d.args, (c, m) => ({ ...m, required: void 0 })) : {},
70
+ properties: d.args ? x(d.args, (c, l) => ({ ...l, required: void 0 })) : {},
71
71
  required: d.args ? Object.entries(d.args).filter((c) => c[1].required).map((c) => c[0]) : []
72
72
  },
73
73
  fn: void 0
74
74
  })),
75
- messages: n,
75
+ messages: s,
76
76
  stream: !!e.stream
77
77
  };
78
- let a, l = !0;
78
+ let a, m = !0;
79
79
  do {
80
80
  if (a = await this.client.messages.create(o).catch((c) => {
81
81
  throw c.message += `
82
82
 
83
83
  Messages:
84
- ${JSON.stringify(n, null, 2)}`, c;
84
+ ${JSON.stringify(s, null, 2)}`, c;
85
85
  }), e.stream) {
86
- l ? l = !1 : e.stream({ text: `
86
+ m ? m = !1 : e.stream({ text: `
87
87
 
88
88
  ` }), a.content = [];
89
89
  for await (const c of a) {
@@ -92,41 +92,41 @@ ${JSON.stringify(n, null, 2)}`, c;
92
92
  c.content_block.type === "text" ? a.content.push({ type: "text", text: "" }) : c.content_block.type === "tool_use" && a.content.push({ type: "tool_use", id: c.content_block.id, name: c.content_block.name, input: "" });
93
93
  else if (c.type === "content_block_delta")
94
94
  if (c.delta.type === "text_delta") {
95
- const m = c.delta.text;
96
- a.content.at(-1).text += m, e.stream({ text: m });
95
+ const l = c.delta.text;
96
+ a.content.at(-1).text += l, e.stream({ text: l });
97
97
  } else c.delta.type === "input_json_delta" && (a.content.at(-1).input += c.delta.partial_json);
98
98
  else if (c.type === "content_block_stop") {
99
- const m = a.content.at(-1);
100
- m.input != null && (m.input = m.input ? g(m.input, {}) : {});
99
+ const l = a.content.at(-1);
100
+ l.input != null && (l.input = l.input ? b(l.input, {}) : {});
101
101
  } else if (c.type === "message_stop")
102
102
  break;
103
103
  }
104
104
  }
105
105
  const d = a.content.filter((c) => c.type === "tool_use");
106
106
  if (d.length && !t.signal.aborted) {
107
- n.push({ role: "assistant", content: a.content });
108
- const c = await Promise.all(d.map(async (m) => {
109
- const h = s.find(x("name", m.name));
110
- if (e.stream && e.stream({ tool: m.name }), !h) return { tool_use_id: m.id, is_error: !0, content: "Tool not found" };
107
+ s.push({ role: "assistant", content: a.content });
108
+ const c = await Promise.all(d.map(async (l) => {
109
+ const h = n.find(S("name", l.name));
110
+ if (e.stream && e.stream({ tool: l.name }), !h) return { tool_use_id: l.id, is_error: !0, content: "Tool not found" };
111
111
  try {
112
- const u = await h.fn(m.input, e?.stream, this.ai);
113
- return { type: "tool_result", tool_use_id: m.id, content: b(u) };
112
+ const u = await h.fn(l.input, e?.stream, this.ai);
113
+ return { type: "tool_result", tool_use_id: l.id, content: w(u) };
114
114
  } catch (u) {
115
- return { type: "tool_result", tool_use_id: m.id, is_error: !0, content: u?.message || u?.toString() || "Unknown" };
115
+ return { type: "tool_result", tool_use_id: l.id, is_error: !0, content: u?.message || u?.toString() || "Unknown" };
116
116
  }
117
117
  }));
118
- n.push({ role: "user", content: c }), o.messages = n;
118
+ s.push({ role: "user", content: c }), o.messages = s;
119
119
  }
120
120
  } while (!t.signal.aborted && a.content.some((d) => d.type === "tool_use"));
121
- n.push({ role: "assistant", content: a.content.filter((d) => d.type == "text").map((d) => d.text).join(`
121
+ s.push({ role: "assistant", content: a.content.filter((d) => d.type == "text").map((d) => d.text).join(`
122
122
 
123
- `) }), n = this.toStandard(n), e.stream && e.stream({ done: !0 }), e.history && e.history.splice(0, e.history.length, ...n), i(n.at(-1)?.content);
123
+ `) }), s = this.toStandard(s), e.stream && e.stream({ done: !0 }), e.history && e.history.splice(0, e.history.length, ...s), i(s.at(-1)?.content);
124
124
  }), { abort: () => t.abort() });
125
125
  }
126
126
  }
127
- class k extends S {
127
+ class _ extends j {
128
128
  constructor(r, e, t, i) {
129
- super(), this.ai = r, this.host = e, this.token = t, this.model = i, this.client = new O(T({
129
+ super(), this.ai = r, this.host = e, this.token = t, this.model = i, this.client = new v(q({
130
130
  baseURL: e,
131
131
  apiKey: t
132
132
  }));
@@ -136,16 +136,16 @@ class k extends S {
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 i = t.tool_calls.map((n) => ({
139
+ const i = t.tool_calls.map((s) => ({
140
140
  role: "tool",
141
- id: n.id,
142
- name: n.function.name,
143
- args: g(n.function.arguments, {}),
141
+ id: s.id,
142
+ name: s.function.name,
143
+ args: b(s.function.arguments, {}),
144
144
  timestamp: t.timestamp
145
145
  }));
146
146
  r.splice(e, 1, ...i), e += i.length - 1;
147
147
  } else if (t.role === "tool" && t.content) {
148
- const i = r.find((n) => t.tool_call_id == n.id);
148
+ const i = r.find((s) => t.tool_call_id == s.id);
149
149
  i && (t.content.includes('"error":') ? i.error = t.content : i.content = t.content), r.splice(e, 1), e--;
150
150
  }
151
151
  r[e]?.timestamp || (r[e].timestamp = Date.now());
@@ -167,20 +167,20 @@ class k extends S {
167
167
  content: t.error || t.content
168
168
  });
169
169
  else {
170
- const { timestamp: i, ...n } = t;
171
- e.push(n);
170
+ const { timestamp: i, ...s } = t;
171
+ e.push(s);
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 (i, n) => {
178
+ return Object.assign(new Promise(async (i, s) => {
179
179
  e.system && e.history?.[0]?.role != "system" && e.history?.splice(0, 0, { role: "system", content: e.system, timestamp: Date.now() });
180
- let s = this.fromStandard([...e.history || [], { role: "user", content: r, timestamp: Date.now() }]);
180
+ let n = this.fromStandard([...e.history || [], { role: "user", content: r, timestamp: Date.now() }]);
181
181
  const o = e.tools || this.ai.options.llm?.tools || [], a = {
182
182
  model: e.model || this.model,
183
- messages: s,
183
+ messages: n,
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,
@@ -191,55 +191,55 @@ class k extends S {
191
191
  description: c.description,
192
192
  parameters: {
193
193
  type: "object",
194
- properties: c.args ? _(c.args, (m, h) => ({ ...h, required: void 0 })) : {},
195
- required: c.args ? Object.entries(c.args).filter((m) => m[1].required).map((m) => m[0]) : []
194
+ properties: c.args ? x(c.args, (l, h) => ({ ...h, required: void 0 })) : {},
195
+ required: c.args ? Object.entries(c.args).filter((l) => l[1].required).map((l) => l[0]) : []
196
196
  }
197
197
  }
198
198
  }))
199
199
  };
200
- let l, d = !0;
200
+ let m, d = !0;
201
201
  do {
202
- if (l = await this.client.chat.completions.create(a).catch((m) => {
203
- throw m.message += `
202
+ if (m = await this.client.chat.completions.create(a).catch((l) => {
203
+ throw l.message += `
204
204
 
205
205
  Messages:
206
- ${JSON.stringify(s, null, 2)}`, m;
206
+ ${JSON.stringify(n, null, 2)}`, l;
207
207
  }), e.stream) {
208
208
  d ? d = !1 : e.stream({ text: `
209
209
 
210
- ` }), l.choices = [{ message: { content: "", tool_calls: [] } }];
211
- for await (const m of l) {
210
+ ` }), m.choices = [{ message: { content: "", tool_calls: [] } }];
211
+ for await (const l of m) {
212
212
  if (t.signal.aborted) break;
213
- m.choices[0].delta.content && (l.choices[0].message.content += m.choices[0].delta.content, e.stream({ text: m.choices[0].delta.content })), m.choices[0].delta.tool_calls && (l.choices[0].message.tool_calls = m.choices[0].delta.tool_calls);
213
+ l.choices[0].delta.content && (m.choices[0].message.content += l.choices[0].delta.content, e.stream({ text: l.choices[0].delta.content })), l.choices[0].delta.tool_calls && (m.choices[0].message.tool_calls = l.choices[0].delta.tool_calls);
214
214
  }
215
215
  }
216
- const c = l.choices[0].message.tool_calls || [];
216
+ const c = m.choices[0].message.tool_calls || [];
217
217
  if (c.length && !t.signal.aborted) {
218
- s.push(l.choices[0].message);
219
- const m = await Promise.all(c.map(async (h) => {
220
- const u = o?.find(x("name", h.function.name));
218
+ n.push(m.choices[0].message);
219
+ const l = await Promise.all(c.map(async (h) => {
220
+ const u = o?.find(S("name", h.function.name));
221
221
  if (e.stream && e.stream({ tool: h.function.name }), !u) return { role: "tool", tool_call_id: h.id, content: '{"error": "Tool not found"}' };
222
222
  try {
223
- const f = g(h.function.arguments, {}), y = await u.fn(f, e.stream, this.ai);
224
- return { role: "tool", tool_call_id: h.id, content: b(y) };
223
+ const f = b(h.function.arguments, {}), y = await u.fn(f, e.stream, this.ai);
224
+ return { role: "tool", tool_call_id: h.id, content: w(y) };
225
225
  } catch (f) {
226
- return { role: "tool", tool_call_id: h.id, content: b({ error: f?.message || f?.toString() || "Unknown" }) };
226
+ return { role: "tool", tool_call_id: h.id, content: w({ error: f?.message || f?.toString() || "Unknown" }) };
227
227
  }
228
228
  }));
229
- s.push(...m), a.messages = s;
229
+ n.push(...l), a.messages = n;
230
230
  }
231
- } while (!t.signal.aborted && l.choices?.[0]?.message?.tool_calls?.length);
232
- s.push({ role: "assistant", content: l.choices[0].message.content || "" }), s = this.toStandard(s), e.stream && e.stream({ done: !0 }), e.history && e.history.splice(0, e.history.length, ...s), i(s.at(-1)?.content);
231
+ } while (!t.signal.aborted && m.choices?.[0]?.message?.tool_calls?.length);
232
+ n.push({ role: "assistant", content: m.choices[0].message.content || "" }), n = this.toStandard(n), e.stream && e.stream({ done: !0 }), e.history && e.history.splice(0, e.history.length, ...n), i(n.at(-1)?.content);
233
233
  }), { abort: () => t.abort() });
234
234
  }
235
235
  }
236
- class J {
236
+ class B {
237
237
  constructor(r) {
238
- this.ai = r, this.embedWorker = new v(R(U(A(import.meta.url)), "embedder.js")), this.embedWorker.on("message", ({ id: e, embedding: t }) => {
238
+ this.ai = r, this.embedWorker = new R(z(L(U(import.meta.url)), "embedder.js")), this.embedWorker.on("message", ({ id: e, embedding: t }) => {
239
239
  const i = this.embedQueue.get(e);
240
240
  i && (i.resolve(t), this.embedQueue.delete(e));
241
241
  }), r.options.llm?.models && Object.entries(r.options.llm.models).forEach(([e, t]) => {
242
- this.defaultModel || (this.defaultModel = e), t.proto == "anthropic" ? this.models[e] = new H(this.ai, t.token, e) : t.proto == "ollama" ? this.models[e] = new k(this.ai, t.host, "not-needed", e) : t.proto == "openai" && (this.models[e] = new k(this.ai, t.host || null, t.token, e));
242
+ this.defaultModel || (this.defaultModel = e), t.proto == "anthropic" ? this.models[e] = new J(this.ai, t.token, e) : t.proto == "ollama" ? this.models[e] = new _(this.ai, t.host, "not-needed", e) : t.proto == "openai" && (this.models[e] = new _(this.ai, t.host || null, t.token, e));
243
243
  });
244
244
  }
245
245
  embedWorker = null;
@@ -258,20 +258,20 @@ class J {
258
258
  if (!this.models[t]) throw new Error(`Model does not exist: ${t}`);
259
259
  let i = () => {
260
260
  };
261
- return Object.assign(new Promise(async (n) => {
261
+ return Object.assign(new Promise(async (s) => {
262
262
  if (e.history || (e.history = []), e.memory) {
263
263
  e.system = (e.system || "") + `
264
264
  You have passive persistent memory never make any mention of your memory capabilities and what you can/cannot remember
265
265
  `;
266
- const o = async (l, d, c = 50) => {
267
- const [m, h] = await Promise.all([
266
+ const o = async (m, d, c = 50) => {
267
+ const [l, h] = await Promise.all([
268
268
  d ? this.embedding(d) : Promise.resolve(null),
269
- l ? this.embedding(l) : Promise.resolve(null)
269
+ m ? this.embedding(m) : Promise.resolve(null)
270
270
  ]);
271
- return (e.memory || []).map((u) => ({ ...u, score: m ? this.cosineSimilarity(u.embeddings[0], m[0].embedding) : 1 })).filter((u) => u.score >= 0.8).map((u) => ({ ...u, score: h ? this.cosineSimilarity(u.embeddings[1], h[0].embedding) : u.score })).filter((u) => u.score >= 0.2).toSorted((u, f) => u.score - f.score).slice(0, c);
271
+ return (e.memory || []).map((u) => ({ ...u, score: l ? this.cosineSimilarity(u.embeddings[0], l[0].embedding) : 1 })).filter((u) => u.score >= 0.8).map((u) => ({ ...u, score: h ? this.cosineSimilarity(u.embeddings[1], h[0].embedding) : u.score })).filter((u) => u.score >= 0.2).toSorted((u, f) => u.score - f.score).slice(0, c);
272
272
  }, a = await o(r);
273
273
  a.length && e.history.push({ role: "assistant", content: `Things I remembered:
274
- ` + a.map((l) => `${l.owner}: ${l.fact}`).join(`
274
+ ` + a.map((m) => `${m.owner}: ${m.fact}`).join(`
275
275
  `) }), e.tools = [...e.tools || [], {
276
276
  name: "read_memory",
277
277
  description: "Check your long-term memory for more information",
@@ -280,13 +280,13 @@ You have passive persistent memory never make any mention of your memory capabil
280
280
  query: { type: "string", description: "Search memory based on a query, can be used with or without subject argument" },
281
281
  limit: { type: "number", description: "Result limit, default 5" }
282
282
  },
283
- fn: (l) => {
284
- if (!l.subject && !l.query) throw new Error("Either a subject or query argument is required");
285
- return o(l.query, l.subject, l.limit || 5);
283
+ fn: (m) => {
284
+ if (!m.subject && !m.query) throw new Error("Either a subject or query argument is required");
285
+ return o(m.query, m.subject, m.limit || 5);
286
286
  }
287
287
  }];
288
288
  }
289
- const s = await this.models[t].ask(r, e);
289
+ const n = await this.models[t].ask(r, e);
290
290
  if (e.memory) {
291
291
  const o = e.history?.findIndex((a) => a.role == "assistant" && a.content.startsWith("Things I remembered:"));
292
292
  o != null && o >= 0 && e.history?.splice(o, 1);
@@ -296,15 +296,15 @@ You have passive persistent memory never make any mention of your memory capabil
296
296
  if (e.compress)
297
297
  o = await this.ai.language.compressHistory(e.history, e.compress.max, e.compress.min, e), e.history.splice(0, e.history.length, ...o.history);
298
298
  else {
299
- const a = e.history?.findLastIndex((l) => l.role == "user") ?? -1;
299
+ const a = e.history?.findLastIndex((m) => m.role == "user") ?? -1;
300
300
  o = await this.ai.language.compressHistory(a != -1 ? e.history.slice(a) : e.history, 0, 0, e);
301
301
  }
302
302
  if (e.memory) {
303
- const a = e.memory.filter((l) => !o.memory.some((d) => this.cosineSimilarity(l.embeddings[1], d.embeddings[1]) > 0.8)).concat(o.memory);
303
+ const a = e.memory.filter((m) => !o.memory.some((d) => this.cosineSimilarity(m.embeddings[1], d.embeddings[1]) > 0.8)).concat(o.memory);
304
304
  e.memory.splice(0, e.memory.length, ...a);
305
305
  }
306
306
  }
307
- return n(s);
307
+ return s(n);
308
308
  }), { abort: i });
309
309
  }
310
310
  /**
@@ -317,20 +317,20 @@ You have passive persistent memory never make any mention of your memory capabil
317
317
  */
318
318
  async compressHistory(r, e, t, i) {
319
319
  if (this.estimateTokens(r) < e) return { history: r, memory: [] };
320
- let n = 0, s = 0;
320
+ let s = 0, n = 0;
321
321
  for (let u of r.toReversed())
322
- if (s += this.estimateTokens(u.content), s < t) n++;
322
+ if (n += this.estimateTokens(u.content), n < t) s++;
323
323
  else break;
324
- if (r.length <= n) return { history: r, memory: [] };
325
- const o = r[0].role == "system" ? r[0] : null, a = n == 0 ? [] : r.slice(-n), l = (n == 0 ? r : r.slice(0, -n)).filter((u) => u.role === "assistant" || u.role === "user"), d = await this.json(`Create the smallest summary possible, no more than 500 tokens. Create a list of NEW facts (split by subject [pro]noun and fact) about what you learned from this conversation that you didn't already know or get from a tool call or system prompt. Focus only on new information about people, topics, or facts. Avoid generating facts about the AI. Match this format: {summary: string, facts: [[subject, fact]]}
324
+ if (r.length <= s) return { history: r, memory: [] };
325
+ const o = r[0].role == "system" ? r[0] : null, a = s == 0 ? [] : r.slice(-s), m = (s == 0 ? r : r.slice(0, -s)).filter((u) => u.role === "assistant" || u.role === "user"), d = await this.json(`Create the smallest summary possible, no more than 500 tokens. Create a list of NEW facts (split by subject [pro]noun and fact) about what you learned from this conversation that you didn't already know or get from a tool call or system prompt. Focus only on new information about people, topics, or facts. Avoid generating facts about the AI. Match this format: {summary: string, facts: [[subject, fact]]}
326
326
 
327
- ${l.map((u) => `${u.role}: ${u.content}`).join(`
327
+ ${m.map((u) => `${u.role}: ${u.content}`).join(`
328
328
 
329
- `)}`, { model: i?.model, temperature: i?.temperature || 0.3 }), c = /* @__PURE__ */ new Date(), m = await Promise.all((d?.facts || [])?.map(async ([u, f]) => {
329
+ `)}`, { model: i?.model, temperature: i?.temperature || 0.3 }), c = /* @__PURE__ */ new Date(), l = await Promise.all((d?.facts || [])?.map(async ([u, f]) => {
330
330
  const y = await Promise.all([this.embedding(u), this.embedding(`${u}: ${f}`)]);
331
331
  return { owner: u, fact: f, embeddings: [y[0][0].embedding, y[1][0].embedding], timestamp: c };
332
332
  })), h = [{ role: "assistant", content: `Conversation Summary: ${d?.summary}`, timestamp: Date.now() }, ...a];
333
- return o && h.splice(0, 0, o), { history: h, memory: m };
333
+ return o && h.splice(0, 0, o), { history: h, memory: l };
334
334
  }
335
335
  /**
336
336
  * Compare the difference between embeddings (calculates the angle between two vectors)
@@ -340,11 +340,11 @@ ${l.map((u) => `${u.role}: ${u.content}`).join(`
340
340
  */
341
341
  cosineSimilarity(r, e) {
342
342
  if (r.length !== e.length) throw new Error("Vectors must be same length");
343
- let t = 0, i = 0, n = 0;
343
+ let t = 0, i = 0, s = 0;
344
344
  for (let o = 0; o < r.length; o++)
345
- t += r[o] * e[o], i += r[o] * r[o], n += e[o] * e[o];
346
- const s = Math.sqrt(i) * Math.sqrt(n);
347
- return s === 0 ? 0 : t / s;
345
+ t += r[o] * e[o], i += r[o] * r[o], s += e[o] * e[o];
346
+ const n = Math.sqrt(i) * Math.sqrt(s);
347
+ return n === 0 ? 0 : t / n;
348
348
  }
349
349
  /**
350
350
  * Chunk text into parts for AI digestion
@@ -354,21 +354,21 @@ ${l.map((u) => `${u.role}: ${u.content}`).join(`
354
354
  * @returns {string[]} Chunked strings
355
355
  */
356
356
  chunk(r, e = 500, t = 50) {
357
- const i = (a, l = "") => a ? Object.entries(a).flatMap(([d, c]) => {
358
- const m = l ? `${l}${isNaN(+d) ? `.${d}` : `[${d}]`}` : d;
359
- return typeof c == "object" && !Array.isArray(c) ? i(c, m) : `${m}: ${Array.isArray(c) ? c.join(", ") : c}`;
360
- }) : [], s = (typeof r == "object" ? i(r) : r.split(`
357
+ const i = (a, m = "") => a ? Object.entries(a).flatMap(([d, c]) => {
358
+ const l = m ? `${m}${isNaN(+d) ? `.${d}` : `[${d}]`}` : d;
359
+ return typeof c == "object" && !Array.isArray(c) ? i(c, l) : `${l}: ${Array.isArray(c) ? c.join(", ") : c}`;
360
+ }) : [], n = (typeof r == "object" ? i(r) : r.split(`
361
361
  `)).flatMap((a) => [...a.split(/\s+/).filter(Boolean), `
362
362
  `]), o = [];
363
- for (let a = 0; a < s.length; ) {
364
- let l = "", d = a;
365
- for (; d < s.length; ) {
366
- const m = l + (l ? " " : "") + s[d];
367
- if (this.estimateTokens(m.replace(/\s*\n\s*/g, `
368
- `)) > e && l) break;
369
- l = m, d++;
363
+ for (let a = 0; a < n.length; ) {
364
+ let m = "", d = a;
365
+ for (; d < n.length; ) {
366
+ const l = m + (m ? " " : "") + n[d];
367
+ if (this.estimateTokens(l.replace(/\s*\n\s*/g, `
368
+ `)) > e && m) break;
369
+ m = l, d++;
370
370
  }
371
- const c = l.replace(/\s*\n\s*/g, `
371
+ const c = m.replace(/\s*\n\s*/g, `
372
372
  `).trim();
373
373
  c && o.push(c), a = Math.max(d - t, d === a ? a + 1 : d);
374
374
  }
@@ -382,20 +382,20 @@ ${l.map((u) => `${u.role}: ${u.content}`).join(`
382
382
  * @returns {Promise<Awaited<{index: number, embedding: number[], text: string, tokens: number}>[]>} Chunked embeddings
383
383
  */
384
384
  embedding(r, e = 500, t = 50) {
385
- const i = (s) => new Promise((o, a) => {
386
- const l = this.embedId++;
387
- this.embedQueue.set(l, { resolve: o, reject: a }), this.embedWorker?.postMessage({
388
- id: l,
389
- text: s,
385
+ const i = (n) => new Promise((o, a) => {
386
+ const m = this.embedId++;
387
+ this.embedQueue.set(m, { resolve: o, reject: a }), this.embedWorker?.postMessage({
388
+ id: m,
389
+ text: n,
390
390
  model: this.ai.options?.embedder || "bge-small-en-v1.5",
391
391
  path: this.ai.options.path
392
392
  });
393
- }), n = this.chunk(r, e, t);
394
- return Promise.all(n.map(async (s, o) => ({
393
+ }), s = this.chunk(r, e, t);
394
+ return Promise.all(s.map(async (n, o) => ({
395
395
  index: o,
396
- embedding: await i(s),
397
- text: s,
398
- tokens: this.estimateTokens(s)
396
+ embedding: await i(n),
397
+ text: n,
398
+ tokens: this.estimateTokens(n)
399
399
  })));
400
400
  }
401
401
  /**
@@ -415,8 +415,8 @@ ${l.map((u) => `${u.role}: ${u.content}`).join(`
415
415
  */
416
416
  fuzzyMatch(r, ...e) {
417
417
  if (e.length < 2) throw new Error("Requires at least 2 strings to compare");
418
- const t = (s, o = 10) => s.toLowerCase().split("").map((a, l) => a.charCodeAt(0) * (l + 1) % o / o).slice(0, o), i = t(r), n = e.map((s) => t(s)).map((s) => this.cosineSimilarity(i, s));
419
- return { avg: n.reduce((s, o) => s + o, 0) / n.length, max: Math.max(...n), similarities: n };
418
+ const t = (n, o = 10) => n.toLowerCase().split("").map((a, m) => a.charCodeAt(0) * (m + 1) % o / o).slice(0, o), i = t(r), s = e.map((n) => t(n)).map((n) => this.cosineSimilarity(i, n));
419
+ return { avg: s.reduce((n, o) => n + o, 0) / s.length, max: Math.max(...s), similarities: s };
420
420
  }
421
421
  /**
422
422
  * Ask a question with JSON response
@@ -427,8 +427,8 @@ ${l.map((u) => `${u.role}: ${u.content}`).join(`
427
427
  async json(r, e) {
428
428
  let t = await this.ask(r, { system: "Respond using a JSON blob matching any provided examples", ...e });
429
429
  if (!t) return {};
430
- const i = /```(?:.+)?\s*([\s\S]*?)```/.exec(t), n = i ? i[1].trim() : t;
431
- return g(n, {});
430
+ const i = /```(?:.+)?\s*([\s\S]*?)```/.exec(t), s = i ? i[1].trim() : t;
431
+ return b(s, {});
432
432
  }
433
433
  /**
434
434
  * Create a summary of some text
@@ -441,7 +441,7 @@ ${l.map((u) => `${u.role}: ${u.content}`).join(`
441
441
  return this.ask(r, { system: `Generate a brief summary <= ${e} tokens. Output nothing else`, temperature: 0.3, ...t });
442
442
  }
443
443
  }
444
- class F {
444
+ class G {
445
445
  constructor(r) {
446
446
  this.ai = r;
447
447
  }
@@ -452,17 +452,17 @@ class F {
452
452
  e.forEach((a) => {
453
453
  t.has(a.speaker) || t.set(a.speaker, ++i);
454
454
  });
455
- const n = [];
456
- let s = -1, o = "";
455
+ const s = [];
456
+ let n = -1, o = "";
457
457
  return r.forEach((a) => {
458
- const l = a.timestamp[0], d = e.find((m) => l >= m.start && l <= m.end), c = d ? t.get(d.speaker) : 1;
459
- c !== s ? (o && n.push(`[speaker ${s}]: ${o.trim()}`), s = c, o = a.text) : o += a.text;
460
- }), o && n.push(`[speaker ${s}]: ${o.trim()}`), n.join(`
458
+ const m = a.timestamp[0], d = e.find((l) => m >= l.start && m <= l.end), c = d ? t.get(d.speaker) : 1;
459
+ c !== n ? (o && s.push(`[speaker ${n}]: ${o.trim()}`), n = c, o = a.text) : o += a.text;
460
+ }), o && s.push(`[speaker ${n}]: ${o.trim()}`), s.join(`
461
461
  `);
462
462
  }
463
463
  async canDiarization() {
464
464
  return new Promise((r) => {
465
- const e = w("python3", ["-c", "import pyannote.audio"]);
465
+ const e = k("python3", ["-c", "import pyannote.audio"]);
466
466
  e.on("close", (t) => r(t === 0)), e.on("error", () => r(!1));
467
467
  });
468
468
  }
@@ -488,45 +488,54 @@ for turn, _, speaker in diarization.itertracks(yield_label=True):
488
488
  print(json.dumps(segments))
489
489
  `;
490
490
  return new Promise((t, i) => {
491
- let n = "";
492
- const s = w("python3", ["-c", e, r]);
493
- s.stdout.on("data", (o) => n += o.toString()), s.stderr.on("data", (o) => console.error(o.toString())), s.on("close", (o) => {
491
+ let s = "";
492
+ const n = k("python3", ["-c", e, r]);
493
+ n.stdout.on("data", (o) => s += o.toString()), n.stderr.on("data", (o) => console.error(o.toString())), n.on("close", (o) => {
494
494
  if (o === 0)
495
495
  try {
496
- t(JSON.parse(n));
496
+ t(JSON.parse(s));
497
497
  } catch {
498
498
  i(new Error("Failed to parse diarization output"));
499
499
  }
500
500
  else
501
501
  i(new Error(`Python process exited with code ${o}`));
502
- }), s.on("error", i);
502
+ }), n.on("error", i);
503
503
  });
504
504
  }
505
505
  asr(r, e = {}) {
506
506
  const { model: t = this.ai.options.asr || "whisper-base", speaker: i = !1 } = e;
507
- let n = !1;
508
- const s = () => {
509
- n = !0;
510
- }, o = new Promise(async (a, l) => {
507
+ let s = !1;
508
+ const n = () => {
509
+ s = !0;
510
+ }, o = new Promise(async (a, m) => {
511
511
  try {
512
- if (n || (this.whisperPipeline || (this.whisperPipeline = await z("automatic-speech-recognition", `Xenova/${t}`, { cache_dir: this.ai.options.path, quantized: !0 })), n)) return a(null);
513
- const d = D.readFileSync(r), c = new L.WaveFile(d);
514
- c.toBitDepth("32f"), c.toSampleRate(16e3);
515
- const m = c.getSamples(), h = await this.whisperPipeline(m, { return_timestamps: i ? "word" : !1, chunk_length_s: 30 });
512
+ if (s || (this.whisperPipeline || (this.whisperPipeline = await N("automatic-speech-recognition", `Xenova/${t}`, { cache_dir: this.ai.options.path, quantized: !0 })), s)) return a(null);
513
+ const d = new C.WaveFile(W.readFileSync(r));
514
+ d.toBitDepth("32f"), d.toSampleRate(16e3);
515
+ const c = d.getSamples();
516
+ let l;
517
+ if (Array.isArray(c)) {
518
+ const y = c[0], T = c[1];
519
+ l = new Float32Array(y.length);
520
+ for (let g = 0; g < y.length; g++) l[g] = (y[g] + T[g]) / 2;
521
+ } else
522
+ l = c;
523
+ if (s) return a(null);
524
+ const h = await this.whisperPipeline(l, { return_timestamps: i ? "word" : !1 });
516
525
  if (!i) return a(h.text?.trim() || null);
517
- if (n) return a(null);
526
+ if (s) return a(null);
518
527
  const u = await this.runDiarization(r);
519
- if (n) return a(null);
528
+ if (s) return a(null);
520
529
  const f = this.combineSpeakerTranscript(h.chunks || [], u);
521
530
  a(f);
522
531
  } catch (d) {
523
- l(d);
532
+ m(d);
524
533
  }
525
534
  });
526
- return Object.assign(o, { abort: s });
535
+ return Object.assign(o, { abort: n });
527
536
  }
528
537
  }
529
- class B {
538
+ class Q {
530
539
  constructor(r) {
531
540
  this.ai = r;
532
541
  }
@@ -538,16 +547,16 @@ class B {
538
547
  ocr(r) {
539
548
  let e;
540
549
  const t = new Promise(async (i) => {
541
- e = await N(this.ai.options.ocr || "eng", 2, { cachePath: this.ai.options.path });
542
- const { data: n } = await e.recognize(r);
543
- await e.terminate(), i(n.text.trim() || null);
550
+ e = await D(this.ai.options.ocr || "eng", 2, { cachePath: this.ai.options.path });
551
+ const { data: s } = await e.recognize(r);
552
+ await e.terminate(), i(s.text.trim() || null);
544
553
  });
545
554
  return Object.assign(t, { abort: () => e?.terminate() });
546
555
  }
547
556
  }
548
- class ae {
557
+ class me {
549
558
  constructor(r) {
550
- this.options = r, r.path || (r.path = j.tmpdir()), process.env.TRANSFORMERS_CACHE = r.path, this.audio = new F(this), this.language = new J(this), this.vision = new B(this);
559
+ this.options = r, r.path || (r.path = P.tmpdir()), process.env.TRANSFORMERS_CACHE = r.path, this.audio = new G(this), this.language = new B(this), this.vision = new Q(this);
551
560
  }
552
561
  /** Audio processing AI */
553
562
  audio;
@@ -556,17 +565,17 @@ class ae {
556
565
  /** Vision processing AI */
557
566
  vision;
558
567
  }
559
- const G = {
568
+ const K = {
560
569
  name: "cli",
561
570
  description: "Use the command line interface, returns any output",
562
571
  args: { command: { type: "string", description: "Command to run", required: !0 } },
563
- fn: (p) => C`${p.command}`
564
- }, ce = {
572
+ fn: (p) => F`${p.command}`
573
+ }, de = {
565
574
  name: "get_datetime",
566
575
  description: "Get current UTC date / time",
567
576
  args: {},
568
577
  fn: async () => (/* @__PURE__ */ new Date()).toUTCString()
569
- }, le = {
578
+ }, ue = {
570
579
  name: "exec",
571
580
  description: "Run code/scripts",
572
581
  args: {
@@ -577,17 +586,17 @@ const G = {
577
586
  try {
578
587
  switch (p.type) {
579
588
  case "bash":
580
- return await G.fn({ command: p.code }, r, e);
589
+ return await K.fn({ command: p.code }, r, e);
581
590
  case "node":
582
- return await Q.fn({ code: p.code }, r, e);
591
+ return await V.fn({ code: p.code }, r, e);
583
592
  case "python":
584
- return await K.fn({ code: p.code }, r, e);
593
+ return await X.fn({ code: p.code }, r, e);
585
594
  }
586
595
  } catch (t) {
587
596
  return { error: t?.message || t.toString() };
588
597
  }
589
598
  }
590
- }, me = {
599
+ }, pe = {
591
600
  name: "fetch",
592
601
  description: "Make HTTP request to URL",
593
602
  args: {
@@ -596,25 +605,25 @@ const G = {
596
605
  headers: { type: "object", description: "HTTP headers to send", default: {} },
597
606
  body: { type: "object", description: "HTTP body to send" }
598
607
  },
599
- fn: (p) => new P({ url: p.url, headers: p.headers }).request({ method: p.method || "GET", body: p.body })
600
- }, Q = {
608
+ fn: (p) => new $({ url: p.url, headers: p.headers }).request({ method: p.method || "GET", body: p.body })
609
+ }, V = {
601
610
  name: "exec_javascript",
602
611
  description: "Execute commonjs javascript",
603
612
  args: {
604
613
  code: { type: "string", description: "CommonJS javascript", required: !0 }
605
614
  },
606
615
  fn: async (p) => {
607
- const r = q(null), e = await $({ console: r }, p.code, !0).catch((t) => r.output.error.push(t));
616
+ const r = M(null), e = await E({ console: r }, p.code, !0).catch((t) => r.output.error.push(t));
608
617
  return { ...r.output, return: e, stdout: void 0, stderr: void 0 };
609
618
  }
610
- }, K = {
619
+ }, X = {
611
620
  name: "exec_javascript",
612
621
  description: "Execute commonjs javascript",
613
622
  args: {
614
623
  code: { type: "string", description: "CommonJS javascript", required: !0 }
615
624
  },
616
- fn: async (p) => ({ result: I`python -c "${p.code}"` })
617
- }, de = {
625
+ fn: async (p) => ({ result: H`python -c "${p.code}"` })
626
+ }, he = {
618
627
  name: "read_webpage",
619
628
  description: "Extract clean, structured content from a webpage. Use after web_search to read specific URLs",
620
629
  args: {
@@ -622,18 +631,18 @@ const G = {
622
631
  focus: { type: "string", description: 'Optional: What aspect to focus on (e.g., "pricing", "features", "contact info")' }
623
632
  },
624
633
  fn: async (p) => {
625
- const r = await fetch(p.url, { headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" } }).then((s) => s.text()).catch((s) => {
626
- throw new Error(`Failed to fetch: ${s.message}`);
627
- }), e = W.load(r);
634
+ const r = await fetch(p.url, { headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" } }).then((n) => n.text()).catch((n) => {
635
+ throw new Error(`Failed to fetch: ${n.message}`);
636
+ }), e = I.load(r);
628
637
  e('script, style, nav, footer, header, aside, iframe, noscript, [role="navigation"], [role="banner"], .ad, .ads, .cookie, .popup').remove();
629
638
  const t = {
630
639
  title: e('meta[property="og:title"]').attr("content") || e("title").text() || "",
631
640
  description: e('meta[name="description"]').attr("content") || e('meta[property="og:description"]').attr("content") || ""
632
641
  };
633
642
  let i = "";
634
- const n = ["article", "main", '[role="main"]', ".content", ".post", ".entry", "body"];
635
- for (const s of n) {
636
- const o = e(s).first();
643
+ const s = ["article", "main", '[role="main"]', ".content", ".post", ".entry", "body"];
644
+ for (const n of s) {
645
+ const o = e(n).first();
637
646
  if (o.length && o.text().trim().length > 200) {
638
647
  i = o.text();
639
648
  break;
@@ -641,7 +650,7 @@ const G = {
641
650
  }
642
651
  return i || (i = e("body").text()), i = i.replace(/\s+/g, " ").trim().slice(0, 8e3), { url: p.url, title: t.title.trim(), description: t.description.trim(), content: i, focus: p.focus };
643
652
  }
644
- }, ue = {
653
+ }, fe = {
645
654
  name: "web_search",
646
655
  description: "Use duckduckgo (anonymous) to find find relevant online resources. Returns a list of URLs that works great with the `read_webpage` tool",
647
656
  args: {
@@ -651,30 +660,30 @@ const G = {
651
660
  fn: async (p) => {
652
661
  const r = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(p.query)}`, {
653
662
  headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Accept-Language": "en-US,en;q=0.9" }
654
- }).then((n) => n.text());
663
+ }).then((s) => s.text());
655
664
  let e, t = /<a .*?href="(.+?)".+?<\/a>/g;
656
- const i = new M();
665
+ const i = new A();
657
666
  for (; (e = t.exec(r)) !== null; ) {
658
- let n = /uddg=(.+)&amp?/.exec(decodeURIComponent(e[1]))?.[1];
659
- if (n && (n = decodeURIComponent(n)), n && i.add(n), i.size >= (p.length || 5)) break;
667
+ let s = /uddg=(.+)&amp?/.exec(decodeURIComponent(e[1]))?.[1];
668
+ if (s && (s = decodeURIComponent(s)), s && i.add(s), i.size >= (p.length || 5)) break;
660
669
  }
661
670
  return i;
662
671
  }
663
672
  };
664
673
  export {
665
- ae as Ai,
666
- H as Anthropic,
667
- F as Audio,
668
- G as CliTool,
669
- ce as DateTimeTool,
670
- le as ExecTool,
671
- me as FetchTool,
672
- Q as JSTool,
673
- S as LLMProvider,
674
- k as OpenAi,
675
- K as PythonTool,
676
- de as ReadWebpageTool,
677
- B as Vision,
678
- ue as WebSearchTool
674
+ me as Ai,
675
+ J as Anthropic,
676
+ G as Audio,
677
+ K as CliTool,
678
+ de as DateTimeTool,
679
+ ue as ExecTool,
680
+ pe as FetchTool,
681
+ V as JSTool,
682
+ j as LLMProvider,
683
+ _ as OpenAi,
684
+ X as PythonTool,
685
+ he as ReadWebpageTool,
686
+ Q as Vision,
687
+ fe as WebSearchTool
679
688
  };
680
689
  //# sourceMappingURL=index.mjs.map