@ztimson/ai-utils 0.6.5 → 0.6.7

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