@ztimson/ai-utils 0.7.9 → 0.7.10

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
@@ -6,8 +6,8 @@ import { OpenAI as U } from "openai";
6
6
  import { fileURLToPath as z } from "url";
7
7
  import { join as N, dirname as L } from "path";
8
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";
9
+ import { mkdtempSync as J } from "node:fs";
10
+ import k, { rm as W } from "node:fs/promises";
11
11
  import _, { join as x } from "node:path";
12
12
  import { createWorker as D } from "tesseract.js";
13
13
  import * as I from "cheerio";
@@ -21,19 +21,19 @@ class G extends E {
21
21
  client;
22
22
  toStandard(r) {
23
23
  const e = Date.now(), t = [];
24
- for (let l of r)
25
- if (typeof l.content == "string")
26
- t.push({ timestamp: e, ...l });
24
+ for (let m of r)
25
+ if (typeof m.content == "string")
26
+ t.push({ timestamp: e, ...m });
27
27
  else {
28
- const n = l.content?.filter((s) => s.type == "text").map((s) => s.text).join(`
28
+ const n = m.content?.filter((s) => s.type == "text").map((s) => s.text).join(`
29
29
 
30
30
  `);
31
- n && t.push({ timestamp: e, role: l.role, content: n }), l.content.forEach((s) => {
31
+ n && t.push({ timestamp: e, role: m.role, content: n }), m.content.forEach((s) => {
32
32
  if (s.type == "tool_use")
33
33
  t.push({ timestamp: e, role: "tool", id: s.id, name: s.name, args: s.input, content: void 0 });
34
34
  else if (s.type == "tool_result") {
35
- const o = t.findLast((c) => c.id == s.tool_use_id);
36
- o && (o[s.is_error ? "error" : "content"] = s.content);
35
+ const i = t.findLast((l) => l.id == s.tool_use_id);
36
+ i && (i[s.is_error ? "error" : "content"] = s.content);
37
37
  }
38
38
  });
39
39
  }
@@ -54,78 +54,78 @@ class G extends E {
54
54
  }
55
55
  ask(r, e = {}) {
56
56
  const t = new AbortController();
57
- return Object.assign(new Promise(async (l) => {
57
+ return Object.assign(new Promise(async (m) => {
58
58
  let n = this.fromStandard([...e.history || [], { role: "user", content: r, timestamp: Date.now() }]);
59
- const s = e.tools || this.ai.options.llm?.tools || [], o = {
59
+ const s = e.tools || this.ai.options.llm?.tools || [], i = {
60
60
  model: e.model || this.model,
61
61
  max_tokens: e.max_tokens || this.ai.options.llm?.max_tokens || 4096,
62
62
  system: e.system || this.ai.options.llm?.system || "",
63
63
  temperature: e.temperature || this.ai.options.llm?.temperature || 0.7,
64
- tools: s.map((m) => ({
65
- name: m.name,
66
- description: m.description,
64
+ tools: s.map((a) => ({
65
+ name: a.name,
66
+ description: a.description,
67
67
  input_schema: {
68
68
  type: "object",
69
- properties: m.args ? j(m.args, (i, d) => ({ ...d, required: void 0 })) : {},
70
- required: m.args ? Object.entries(m.args).filter((i) => i[1].required).map((i) => i[0]) : []
69
+ properties: a.args ? j(a.args, (o, c) => ({ ...c, required: void 0 })) : {},
70
+ required: a.args ? Object.entries(a.args).filter((o) => o[1].required).map((o) => o[0]) : []
71
71
  },
72
72
  fn: void 0
73
73
  })),
74
74
  messages: n,
75
75
  stream: !!e.stream
76
76
  };
77
- let c, a = !0;
77
+ let l, d = !0;
78
78
  do {
79
- if (c = await this.client.messages.create(o).catch((i) => {
80
- throw i.message += `
79
+ if (l = await this.client.messages.create(i).catch((o) => {
80
+ throw o.message += `
81
81
 
82
82
  Messages:
83
- ${JSON.stringify(n, null, 2)}`, i;
83
+ ${JSON.stringify(n, null, 2)}`, o;
84
84
  }), e.stream) {
85
- a ? a = !1 : e.stream({ text: `
85
+ d ? d = !1 : e.stream({ text: `
86
86
 
87
- ` }), c.content = [];
88
- for await (const i of c) {
87
+ ` }), l.content = [];
88
+ for await (const o of l) {
89
89
  if (t.signal.aborted) break;
90
- if (i.type === "content_block_start")
91
- 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: "" });
92
- else if (i.type === "content_block_delta")
93
- if (i.delta.type === "text_delta") {
94
- const d = i.delta.text;
95
- c.content.at(-1).text += d, e.stream({ text: d });
96
- } else i.delta.type === "input_json_delta" && (c.content.at(-1).input += i.delta.partial_json);
97
- else if (i.type === "content_block_stop") {
98
- const d = c.content.at(-1);
99
- d.input != null && (d.input = d.input ? w(d.input, {}) : {});
100
- } else if (i.type === "message_stop")
90
+ if (o.type === "content_block_start")
91
+ o.content_block.type === "text" ? l.content.push({ type: "text", text: "" }) : o.content_block.type === "tool_use" && l.content.push({ type: "tool_use", id: o.content_block.id, name: o.content_block.name, input: "" });
92
+ else if (o.type === "content_block_delta")
93
+ if (o.delta.type === "text_delta") {
94
+ const c = o.delta.text;
95
+ l.content.at(-1).text += c, e.stream({ text: c });
96
+ } else o.delta.type === "input_json_delta" && (l.content.at(-1).input += o.delta.partial_json);
97
+ else if (o.type === "content_block_stop") {
98
+ const c = l.content.at(-1);
99
+ c.input != null && (c.input = c.input ? w(c.input, {}) : {});
100
+ } else if (o.type === "message_stop")
101
101
  break;
102
102
  }
103
103
  }
104
- const m = c.content.filter((i) => i.type === "tool_use");
105
- if (m.length && !t.signal.aborted) {
106
- n.push({ role: "assistant", content: c.content });
107
- const i = await Promise.all(m.map(async (d) => {
108
- const p = s.find(T("name", d.name));
109
- if (e.stream && e.stream({ tool: d.name }), !p) return { tool_use_id: d.id, is_error: !0, content: "Tool not found" };
104
+ const a = l.content.filter((o) => o.type === "tool_use");
105
+ if (a.length && !t.signal.aborted) {
106
+ n.push({ role: "assistant", content: l.content });
107
+ const o = await Promise.all(a.map(async (c) => {
108
+ const p = s.find(T("name", c.name));
109
+ if (e.stream && e.stream({ tool: c.name }), !p) return { tool_use_id: c.id, is_error: !0, content: "Tool not found" };
110
110
  try {
111
- const u = await p.fn(d.input, e?.stream, this.ai);
112
- return { type: "tool_result", tool_use_id: d.id, content: b(u) };
111
+ const u = await p.fn(c.input, e?.stream, this.ai);
112
+ return { type: "tool_result", tool_use_id: c.id, content: b(u) };
113
113
  } catch (u) {
114
- return { type: "tool_result", tool_use_id: d.id, is_error: !0, content: u?.message || u?.toString() || "Unknown" };
114
+ return { type: "tool_result", tool_use_id: c.id, is_error: !0, content: u?.message || u?.toString() || "Unknown" };
115
115
  }
116
116
  }));
117
- n.push({ role: "user", content: i }), o.messages = n;
117
+ n.push({ role: "user", content: o }), i.messages = n;
118
118
  }
119
- } while (!t.signal.aborted && c.content.some((m) => m.type === "tool_use"));
120
- n.push({ role: "assistant", content: c.content.filter((m) => m.type == "text").map((m) => m.text).join(`
119
+ } while (!t.signal.aborted && l.content.some((a) => a.type === "tool_use"));
120
+ n.push({ role: "assistant", content: l.content.filter((a) => a.type == "text").map((a) => a.text).join(`
121
121
 
122
- `) }), 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);
122
+ `) }), n = this.toStandard(n), e.stream && e.stream({ done: !0 }), e.history && e.history.splice(0, e.history.length, ...n), m(n.at(-1)?.content);
123
123
  }), { abort: () => t.abort() });
124
124
  }
125
125
  }
126
126
  class S extends E {
127
- constructor(r, e, t, l) {
128
- super(), this.ai = r, this.host = e, this.token = t, this.model = l, this.client = new U(M({
127
+ constructor(r, e, t, m) {
128
+ super(), this.ai = r, this.host = e, this.token = t, this.model = m, this.client = new U(M({
129
129
  baseURL: e,
130
130
  apiKey: t
131
131
  }));
@@ -135,17 +135,17 @@ class S extends E {
135
135
  for (let e = 0; e < r.length; e++) {
136
136
  const t = r[e];
137
137
  if (t.role === "assistant" && t.tool_calls) {
138
- const l = t.tool_calls.map((n) => ({
138
+ const m = t.tool_calls.map((n) => ({
139
139
  role: "tool",
140
140
  id: n.id,
141
141
  name: n.function.name,
142
142
  args: w(n.function.arguments, {}),
143
143
  timestamp: t.timestamp
144
144
  }));
145
- r.splice(e, 1, ...l), e += l.length - 1;
145
+ r.splice(e, 1, ...m), e += m.length - 1;
146
146
  } else if (t.role === "tool" && t.content) {
147
- const l = r.find((n) => t.tool_call_id == n.id);
148
- l && (t.content.includes('"error":') ? l.error = t.content : l.content = t.content), r.splice(e, 1), e--;
147
+ const m = r.find((n) => t.tool_call_id == n.id);
148
+ m && (t.content.includes('"error":') ? m.error = t.content : m.content = t.content), r.splice(e, 1), e--;
149
149
  }
150
150
  r[e]?.timestamp || (r[e].timestamp = Date.now());
151
151
  }
@@ -166,7 +166,7 @@ class S extends E {
166
166
  content: t.error || t.content
167
167
  });
168
168
  else {
169
- const { timestamp: l, ...n } = t;
169
+ const { timestamp: m, ...n } = t;
170
170
  e.push(n);
171
171
  }
172
172
  return e;
@@ -174,49 +174,49 @@ class S extends E {
174
174
  }
175
175
  ask(r, e = {}) {
176
176
  const t = new AbortController();
177
- return Object.assign(new Promise(async (l, n) => {
177
+ return Object.assign(new Promise(async (m, n) => {
178
178
  e.system && e.history?.[0]?.role != "system" && e.history?.splice(0, 0, { role: "system", content: e.system, timestamp: Date.now() });
179
179
  let s = this.fromStandard([...e.history || [], { role: "user", content: r, timestamp: Date.now() }]);
180
- const o = e.tools || this.ai.options.llm?.tools || [], c = {
180
+ const i = e.tools || this.ai.options.llm?.tools || [], l = {
181
181
  model: e.model || this.model,
182
182
  messages: s,
183
183
  stream: !!e.stream,
184
184
  max_tokens: e.max_tokens || this.ai.options.llm?.max_tokens || 4096,
185
185
  temperature: e.temperature || this.ai.options.llm?.temperature || 0.7,
186
- tools: o.map((i) => ({
186
+ tools: i.map((o) => ({
187
187
  type: "function",
188
188
  function: {
189
- name: i.name,
190
- description: i.description,
189
+ name: o.name,
190
+ description: o.description,
191
191
  parameters: {
192
192
  type: "object",
193
- properties: i.args ? j(i.args, (d, p) => ({ ...p, required: void 0 })) : {},
194
- required: i.args ? Object.entries(i.args).filter((d) => d[1].required).map((d) => d[0]) : []
193
+ properties: o.args ? j(o.args, (c, p) => ({ ...p, required: void 0 })) : {},
194
+ required: o.args ? Object.entries(o.args).filter((c) => c[1].required).map((c) => c[0]) : []
195
195
  }
196
196
  }
197
197
  }))
198
198
  };
199
- let a, m = !0;
199
+ let d, a = !0;
200
200
  do {
201
- if (a = await this.client.chat.completions.create(c).catch((d) => {
202
- throw d.message += `
201
+ if (d = await this.client.chat.completions.create(l).catch((c) => {
202
+ throw c.message += `
203
203
 
204
204
  Messages:
205
- ${JSON.stringify(s, null, 2)}`, d;
205
+ ${JSON.stringify(s, null, 2)}`, c;
206
206
  }), e.stream) {
207
- m ? m = !1 : e.stream({ text: `
207
+ a ? a = !1 : e.stream({ text: `
208
208
 
209
- ` }), a.choices = [{ message: { content: "", tool_calls: [] } }];
210
- for await (const d of a) {
209
+ ` }), d.choices = [{ message: { content: "", tool_calls: [] } }];
210
+ for await (const c of d) {
211
211
  if (t.signal.aborted) break;
212
- d.choices[0].delta.content && (a.choices[0].message.content += d.choices[0].delta.content, e.stream({ text: d.choices[0].delta.content })), d.choices[0].delta.tool_calls && (a.choices[0].message.tool_calls = d.choices[0].delta.tool_calls);
212
+ c.choices[0].delta.content && (d.choices[0].message.content += c.choices[0].delta.content, e.stream({ text: c.choices[0].delta.content })), c.choices[0].delta.tool_calls && (d.choices[0].message.tool_calls = c.choices[0].delta.tool_calls);
213
213
  }
214
214
  }
215
- const i = a.choices[0].message.tool_calls || [];
216
- if (i.length && !t.signal.aborted) {
217
- s.push(a.choices[0].message);
218
- const d = await Promise.all(i.map(async (p) => {
219
- const u = o?.find(T("name", p.function.name));
215
+ const o = d.choices[0].message.tool_calls || [];
216
+ if (o.length && !t.signal.aborted) {
217
+ s.push(d.choices[0].message);
218
+ const c = await Promise.all(o.map(async (p) => {
219
+ const u = i?.find(T("name", p.function.name));
220
220
  if (e.stream && e.stream({ tool: p.function.name }), !u) return { role: "tool", tool_call_id: p.id, content: '{"error": "Tool not found"}' };
221
221
  try {
222
222
  const f = w(p.function.arguments, {}), y = await u.fn(f, e.stream, this.ai);
@@ -225,10 +225,10 @@ ${JSON.stringify(s, null, 2)}`, d;
225
225
  return { role: "tool", tool_call_id: p.id, content: b({ error: f?.message || f?.toString() || "Unknown" }) };
226
226
  }
227
227
  }));
228
- s.push(...d), c.messages = s;
228
+ s.push(...c), l.messages = s;
229
229
  }
230
- } while (!t.signal.aborted && a.choices?.[0]?.message?.tool_calls?.length);
231
- 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
+ } while (!t.signal.aborted && d.choices?.[0]?.message?.tool_calls?.length);
231
+ s.push({ role: "assistant", content: d.choices[0].message.content || "" }), s = this.toStandard(s), e.stream && e.stream({ done: !0 }), e.history && e.history.splice(0, e.history.length, ...s), m(s.at(-1)?.content);
232
232
  }), { abort: () => t.abort() });
233
233
  }
234
234
  }
@@ -249,22 +249,22 @@ class B {
249
249
  ask(r, e = {}) {
250
250
  const t = e.model || this.defaultModel;
251
251
  if (!this.models[t]) throw new Error(`Model does not exist: ${t}`);
252
- let l = () => {
252
+ let m = () => {
253
253
  };
254
254
  return Object.assign(new Promise(async (n) => {
255
255
  if (e.history || (e.history = []), e.memory) {
256
256
  e.system = (e.system || "") + `
257
257
  You have passive persistent memory never make any mention of your memory capabilities and what you can/cannot remember
258
258
  `;
259
- const o = async (a, m, i = 50) => {
260
- const [d, p] = await Promise.all([
261
- m ? this.embedding(m) : Promise.resolve(null),
262
- a ? this.embedding(a) : Promise.resolve(null)
259
+ const i = async (d, a, o = 50) => {
260
+ const [c, p] = await Promise.all([
261
+ a ? this.embedding(a) : Promise.resolve(null),
262
+ d ? this.embedding(d) : Promise.resolve(null)
263
263
  ]);
264
- 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);
265
- }, c = await o(r);
266
- c.length && e.history.push({ role: "assistant", content: `Things I remembered:
267
- ` + c.map((a) => `${a.owner}: ${a.fact}`).join(`
264
+ return (e.memory || []).map((u) => ({ ...u, score: c ? this.cosineSimilarity(u.embeddings[0], c[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, o);
265
+ }, l = await i(r);
266
+ l.length && e.history.push({ role: "assistant", content: `Things I remembered:
267
+ ` + l.map((d) => `${d.owner}: ${d.fact}`).join(`
268
268
  `) }), e.tools = [...e.tools || [], {
269
269
  name: "read_memory",
270
270
  description: "Check your long-term memory for more information",
@@ -273,32 +273,32 @@ You have passive persistent memory never make any mention of your memory capabil
273
273
  query: { type: "string", description: "Search memory based on a query, can be used with or without subject argument" },
274
274
  limit: { type: "number", description: "Result limit, default 5" }
275
275
  },
276
- fn: (a) => {
277
- if (!a.subject && !a.query) throw new Error("Either a subject or query argument is required");
278
- return o(a.query, a.subject, a.limit || 5);
276
+ fn: (d) => {
277
+ if (!d.subject && !d.query) throw new Error("Either a subject or query argument is required");
278
+ return i(d.query, d.subject, d.limit || 5);
279
279
  }
280
280
  }];
281
281
  }
282
282
  const s = await this.models[t].ask(r, e);
283
283
  if (e.memory) {
284
- const o = e.history?.findIndex((c) => c.role == "assistant" && c.content.startsWith("Things I remembered:"));
285
- o != null && o >= 0 && e.history?.splice(o, 1);
284
+ const i = e.history?.findIndex((l) => l.role == "assistant" && l.content.startsWith("Things I remembered:"));
285
+ i != null && i >= 0 && e.history?.splice(i, 1);
286
286
  }
287
287
  if (e.compress || e.memory) {
288
- let o = null;
288
+ let i = null;
289
289
  if (e.compress)
290
- o = await this.ai.language.compressHistory(e.history, e.compress.max, e.compress.min, e), e.history.splice(0, e.history.length, ...o.history);
290
+ i = await this.ai.language.compressHistory(e.history, e.compress.max, e.compress.min, e), e.history.splice(0, e.history.length, ...i.history);
291
291
  else {
292
- const c = e.history?.findLastIndex((a) => a.role == "user") ?? -1;
293
- o = await this.ai.language.compressHistory(c != -1 ? e.history.slice(c) : e.history, 0, 0, e);
292
+ const l = e.history?.findLastIndex((d) => d.role == "user") ?? -1;
293
+ i = await this.ai.language.compressHistory(l != -1 ? e.history.slice(l) : e.history, 0, 0, e);
294
294
  }
295
295
  if (e.memory) {
296
- const c = e.memory.filter((a) => !o.memory.some((m) => this.cosineSimilarity(a.embeddings[1], m.embeddings[1]) > 0.8)).concat(o.memory);
297
- e.memory.splice(0, e.memory.length, ...c);
296
+ const l = e.memory.filter((d) => !i.memory.some((a) => this.cosineSimilarity(d.embeddings[1], a.embeddings[1]) > 0.8)).concat(i.memory);
297
+ e.memory.splice(0, e.memory.length, ...l);
298
298
  }
299
299
  }
300
300
  return n(s);
301
- }), { abort: l });
301
+ }), { abort: m });
302
302
  }
303
303
  /**
304
304
  * Compress chat history to reduce context size
@@ -308,24 +308,24 @@ You have passive persistent memory never make any mention of your memory capabil
308
308
  * @param {LLMRequest} options LLM options
309
309
  * @returns {Promise<LLMMessage[]>} New chat history will summary at index 0
310
310
  */
311
- async compressHistory(r, e, t, l) {
311
+ async compressHistory(r, e, t, m) {
312
312
  if (this.estimateTokens(r) < e) return { history: r, memory: [] };
313
313
  let n = 0, s = 0;
314
314
  for (let u of r.toReversed())
315
315
  if (s += this.estimateTokens(u.content), s < t) n++;
316
316
  else break;
317
317
  if (r.length <= n) return { history: r, memory: [] };
318
- 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(`
318
+ const i = r[0].role == "system" ? r[0] : null, l = n == 0 ? [] : r.slice(-n), d = (n == 0 ? r : r.slice(0, -n)).filter((u) => u.role === "assistant" || u.role === "user"), a = await this.json(d.map((u) => `${u.role}: ${u.content}`).join(`
319
319
 
320
320
  `), "{summary: string, facts: [[subject, fact]]}", {
321
321
  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.",
322
- model: l?.model,
323
- temperature: l?.temperature || 0.3
324
- }), i = /* @__PURE__ */ new Date(), d = await Promise.all((m?.facts || [])?.map(async ([u, f]) => {
322
+ model: m?.model,
323
+ temperature: m?.temperature || 0.3
324
+ }), o = /* @__PURE__ */ new Date(), c = await Promise.all((a?.facts || [])?.map(async ([u, f]) => {
325
325
  const y = await Promise.all([this.embedding(u), this.embedding(`${u}: ${f}`)]);
326
- return { owner: u, fact: f, embeddings: [y[0][0].embedding, y[1][0].embedding], timestamp: i };
327
- })), p = [{ role: "assistant", content: `Conversation Summary: ${m?.summary}`, timestamp: Date.now() }, ...c];
328
- return o && p.splice(0, 0, o), { history: p, memory: d };
326
+ return { owner: u, fact: f, embeddings: [y[0][0].embedding, y[1][0].embedding], timestamp: o };
327
+ })), p = [{ role: "assistant", content: `Conversation Summary: ${a?.summary}`, timestamp: Date.now() }, ...l];
328
+ return i && p.splice(0, 0, i), { history: p, memory: c };
329
329
  }
330
330
  /**
331
331
  * Compare the difference between embeddings (calculates the angle between two vectors)
@@ -335,10 +335,10 @@ You have passive persistent memory never make any mention of your memory capabil
335
335
  */
336
336
  cosineSimilarity(r, e) {
337
337
  if (r.length !== e.length) throw new Error("Vectors must be same length");
338
- let t = 0, l = 0, n = 0;
339
- for (let o = 0; o < r.length; o++)
340
- t += r[o] * e[o], l += r[o] * r[o], n += e[o] * e[o];
341
- const s = Math.sqrt(l) * Math.sqrt(n);
338
+ let t = 0, m = 0, n = 0;
339
+ for (let i = 0; i < r.length; i++)
340
+ t += r[i] * e[i], m += r[i] * r[i], n += e[i] * e[i];
341
+ const s = Math.sqrt(m) * Math.sqrt(n);
342
342
  return s === 0 ? 0 : t / s;
343
343
  }
344
344
  /**
@@ -349,25 +349,25 @@ You have passive persistent memory never make any mention of your memory capabil
349
349
  * @returns {string[]} Chunked strings
350
350
  */
351
351
  chunk(r, e = 500, t = 50) {
352
- const l = (c, a = "") => c ? Object.entries(c).flatMap(([m, i]) => {
353
- const d = a ? `${a}${isNaN(+m) ? `.${m}` : `[${m}]`}` : m;
354
- return typeof i == "object" && !Array.isArray(i) ? l(i, d) : `${d}: ${Array.isArray(i) ? i.join(", ") : i}`;
355
- }) : [], s = (typeof r == "object" ? l(r) : r.split(`
356
- `)).flatMap((c) => [...c.split(/\s+/).filter(Boolean), `
357
- `]), o = [];
358
- for (let c = 0; c < s.length; ) {
359
- let a = "", m = c;
360
- for (; m < s.length; ) {
361
- const d = a + (a ? " " : "") + s[m];
362
- if (this.estimateTokens(d.replace(/\s*\n\s*/g, `
363
- `)) > e && a) break;
364
- a = d, m++;
352
+ const m = (l, d = "") => l ? Object.entries(l).flatMap(([a, o]) => {
353
+ const c = d ? `${d}${isNaN(+a) ? `.${a}` : `[${a}]`}` : a;
354
+ return typeof o == "object" && !Array.isArray(o) ? m(o, c) : `${c}: ${Array.isArray(o) ? o.join(", ") : o}`;
355
+ }) : [], s = (typeof r == "object" ? m(r) : r.split(`
356
+ `)).flatMap((l) => [...l.split(/\s+/).filter(Boolean), `
357
+ `]), i = [];
358
+ for (let l = 0; l < s.length; ) {
359
+ let d = "", a = l;
360
+ for (; a < s.length; ) {
361
+ const c = d + (d ? " " : "") + s[a];
362
+ if (this.estimateTokens(c.replace(/\s*\n\s*/g, `
363
+ `)) > e && d) break;
364
+ d = c, a++;
365
365
  }
366
- const i = a.replace(/\s*\n\s*/g, `
366
+ const o = d.replace(/\s*\n\s*/g, `
367
367
  `).trim();
368
- i && o.push(i), c = Math.max(m - t, m === c ? c + 1 : m);
368
+ o && i.push(o), l = Math.max(a - t, a === l ? l + 1 : a);
369
369
  }
370
- return o;
370
+ return i;
371
371
  }
372
372
  /**
373
373
  * Create a vector representation of a string
@@ -376,39 +376,39 @@ You have passive persistent memory never make any mention of your memory capabil
376
376
  * @returns {Promise<Awaited<{index: number, embedding: number[], text: string, tokens: number}>[]>} Chunked embeddings
377
377
  */
378
378
  embedding(r, e = {}) {
379
- let { maxTokens: t = 500, overlapTokens: l = 50 } = e, n = !1;
379
+ let { maxTokens: t = 500, overlapTokens: m = 50 } = e, n = !1;
380
380
  const s = () => {
381
381
  n = !0;
382
- }, o = (a) => new Promise((m, i) => {
383
- if (n) return i(new Error("Aborted"));
384
- const d = [
382
+ }, i = (d) => new Promise((a, o) => {
383
+ if (n) return o(new Error("Aborted"));
384
+ const c = [
385
385
  N(L(z(import.meta.url)), "embedder.js"),
386
386
  this.ai.options.path,
387
387
  this.ai.options?.embedder || "bge-small-en-v1.5"
388
- ], p = g("node", d, { stdio: ["pipe", "pipe", "ignore"] });
389
- p.stdin.write(a), p.stdin.end();
388
+ ], p = g("node", c, { stdio: ["pipe", "pipe", "ignore"] });
389
+ p.stdin.write(d), p.stdin.end();
390
390
  let u = "";
391
391
  p.stdout.on("data", (f) => u += f.toString()), p.on("close", (f) => {
392
- if (n) return i(new Error("Aborted"));
392
+ if (n) return o(new Error("Aborted"));
393
393
  if (f === 0)
394
394
  try {
395
395
  const y = JSON.parse(u);
396
- m(y.embedding);
396
+ a(y.embedding);
397
397
  } catch {
398
- i(new Error("Failed to parse embedding output"));
398
+ o(new Error("Failed to parse embedding output"));
399
399
  }
400
400
  else
401
- i(new Error(`Embedder process exited with code ${f}`));
402
- }), p.on("error", i);
403
- }), c = (async () => {
404
- const a = this.chunk(r, t, l), m = [];
405
- for (let i = 0; i < a.length && !n; i++) {
406
- const d = a[i], p = await o(d);
407
- m.push({ index: i, embedding: p, text: d, tokens: this.estimateTokens(d) });
401
+ o(new Error(`Embedder process exited with code ${f}`));
402
+ }), p.on("error", o);
403
+ }), l = (async () => {
404
+ const d = this.chunk(r, t, m), a = [];
405
+ for (let o = 0; o < d.length && !n; o++) {
406
+ const c = d[o], p = await i(c);
407
+ a.push({ index: o, embedding: p, text: c, tokens: this.estimateTokens(c) });
408
408
  }
409
- return m;
409
+ return a;
410
410
  })();
411
- return Object.assign(c, { abort: s });
411
+ return Object.assign(l, { abort: s });
412
412
  }
413
413
  /**
414
414
  * Estimate variable as tokens
@@ -427,8 +427,8 @@ You have passive persistent memory never make any mention of your memory capabil
427
427
  */
428
428
  fuzzyMatch(r, ...e) {
429
429
  if (e.length < 2) throw new Error("Requires at least 2 strings to compare");
430
- 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));
431
- return { avg: n.reduce((s, o) => s + o, 0) / n.length, max: Math.max(...n), similarities: n };
430
+ const t = (s, i = 10) => s.toLowerCase().split("").map((l, d) => l.charCodeAt(0) * (d + 1) % i / i).slice(0, i), m = t(r), n = e.map((s) => t(s)).map((s) => this.cosineSimilarity(m, s));
431
+ return { avg: n.reduce((s, i) => s + i, 0) / n.length, max: Math.max(...n), similarities: n };
432
432
  }
433
433
  /**
434
434
  * Ask a question with JSON response
@@ -438,13 +438,13 @@ You have passive persistent memory never make any mention of your memory capabil
438
438
  * @returns {Promise<{} | {} | RegExpExecArray | null>}
439
439
  */
440
440
  async json(r, e, t) {
441
- let l = await this.ask(r, { ...t, system: (t?.system ? `${t.system}
441
+ let m = await this.ask(r, { ...t, system: (t?.system ? `${t.system}
442
442
  ` : "") + `Only respond using a JSON code block matching this schema:
443
443
  \`\`\`json
444
444
  ${e}
445
445
  \`\`\`` });
446
- if (!l) return {};
447
- const n = /```(?:.+)?\s*([\s\S]*?)```/.exec(l), s = n ? n[1].trim() : l;
446
+ if (!m) return {};
447
+ const n = /```(?:.+)?\s*([\s\S]*?)```/.exec(m), s = n ? n[1].trim() : m;
448
448
  return w(s, {});
449
449
  }
450
450
  /**
@@ -482,96 +482,98 @@ print(json.dumps(segments))
482
482
  whisperModel;
483
483
  runAsr(r, e = {}) {
484
484
  let t;
485
- const l = new Promise((n, s) => {
486
- this.downloadAsrModel(e.model).then((o) => {
487
- let c = "";
488
- const a = [e.diarization ? "-owts" : "-nt", "-m", o, "-f", r];
489
- 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) => {
490
- if (m === 0)
485
+ const m = new Promise((n, s) => {
486
+ this.downloadAsrModel(e.model).then((i) => {
487
+ let l = "";
488
+ const d = [e.diarization ? "-owts" : "-nt", "-m", i, "-f", r];
489
+ console.log(this.ai.options.whisper + " " + d.join(" ")), t = g(this.ai.options.whisper, d, { stdio: ["ignore", "pipe", "ignore"] }), t.on("error", (a) => s(a)), t.stdout.on("data", (a) => l += a.toString()), t.on("close", (a) => {
490
+ if (a === 0)
491
491
  if (e.diarization)
492
492
  try {
493
- n(JSON.parse(c));
493
+ n(JSON.parse(l));
494
494
  } catch {
495
495
  s(new Error("Failed to parse whisper JSON"));
496
496
  }
497
497
  else
498
- n(c.trim() || null);
498
+ n(l.trim() || null);
499
499
  else
500
- s(new Error(`Exit code ${m}`));
500
+ s(new Error(`Exit code ${a}`));
501
501
  });
502
502
  });
503
503
  });
504
- return Object.assign(l, { abort: () => t?.kill("SIGTERM") });
504
+ return Object.assign(m, { abort: () => t?.kill("SIGTERM") });
505
505
  }
506
506
  runDiarization(r) {
507
507
  let e = !1, t = () => {
508
508
  e = !0;
509
509
  };
510
- const l = (s) => new Promise((o) => {
511
- const c = g(s, ["-c", "import pyannote.audio"]);
512
- c.on("close", (a) => o(a === 0)), c.on("error", () => o(!1));
510
+ const m = (s) => new Promise((i) => {
511
+ const l = g(s, ["-c", "import pyannote.audio"]);
512
+ l.on("close", (d) => i(d === 0)), l.on("error", () => i(!1));
513
513
  }), n = Promise.all([
514
- l("python"),
515
- l("python3")
516
- ]).then((async ([s, o]) => {
514
+ m("python"),
515
+ m("python3")
516
+ ]).then((async ([s, i]) => {
517
517
  if (e) return;
518
- if (!s && !o) throw new Error("Pyannote is not installed: pip install pyannote.audio");
519
- const c = o ? "python3" : "python";
520
- let a = null;
521
- return new Promise((m, i) => {
522
- if (a = x(J(x(P(), "audio-")), "converted.wav"), C(`ffmpeg -i "${r}" -ar 16000 -ac 1 -f wav "${a}"`, { stdio: "ignore" }), e) return;
523
- let d = "";
524
- const p = g(c, ["-c", this.pyannote, a]);
525
- p.stdout.on("data", (u) => d += u.toString()), p.stderr.on("data", (u) => console.error(u.toString())), p.on("close", (u) => {
526
- if (u === 0)
518
+ if (!s && !i) throw new Error("Pyannote is not installed: pip install pyannote.audio");
519
+ const l = i ? "python3" : "python";
520
+ return new Promise((d, a) => {
521
+ if (e) return;
522
+ let o = "";
523
+ const c = g(l, ["-c", this.pyannote, r]);
524
+ c.stdout.on("data", (p) => o += p.toString()), c.stderr.on("data", (p) => console.error(p.toString())), c.on("close", (p) => {
525
+ if (p === 0)
527
526
  try {
528
- m(JSON.parse(d));
527
+ d(JSON.parse(o));
529
528
  } catch {
530
- i(new Error("Failed to parse diarization output"));
529
+ a(new Error("Failed to parse diarization output"));
531
530
  }
532
531
  else
533
- i(new Error(`Python process exited with code ${u}`));
534
- }), p.on("error", i), t = () => p.kill("SIGTERM");
535
- }).finally(() => {
536
- a && W(_.dirname(a), { recursive: !0, force: !0 });
532
+ a(new Error(`Python process exited with code ${p}`));
533
+ }), c.on("error", a), t = () => c.kill("SIGTERM");
537
534
  });
538
535
  }));
539
536
  return Object.assign(n, { abort: t });
540
537
  }
541
538
  combineSpeakerTranscript(r, e) {
542
539
  const t = /* @__PURE__ */ new Map();
543
- let l = 0;
544
- e.forEach((c) => {
545
- t.has(c.speaker) || t.set(c.speaker, ++l);
540
+ let m = 0;
541
+ e.forEach((l) => {
542
+ t.has(l.speaker) || t.set(l.speaker, ++m);
546
543
  });
547
544
  const n = [];
548
- let s = -1, o = "";
549
- return r.transcription.forEach((c) => {
550
- const a = c.offsets.from / 1e3, m = e.find((d) => a >= d.start && a <= d.end), i = m ? t.get(m.speaker) : 1;
551
- i !== s ? (o && n.push(`[Speaker ${s}]: ${o.trim()}`), s = i, o = c.text) : o += " " + c.text;
552
- }), o && n.push(`[Speaker ${s}]: ${o.trim()}`), n.join(`
545
+ let s = -1, i = "";
546
+ return r.transcription.forEach((l) => {
547
+ const d = l.offsets.from / 1e3, a = e.find((c) => d >= c.start && d <= c.end), o = a ? t.get(a.speaker) : 1;
548
+ o !== s ? (i && n.push(`[Speaker ${s}]: ${i.trim()}`), s = o, i = l.text) : i += " " + l.text;
549
+ }), i && n.push(`[Speaker ${s}]: ${i.trim()}`), n.join(`
553
550
  `);
554
551
  }
555
552
  asr(r, e = {}) {
556
553
  if (!this.ai.options.whisper) throw new Error("Whisper not configured");
557
- const t = this.runAsr(r, { model: e.model, diarization: !!e.diarization }), l = e.diarization ? this.runDiarization(r) : Promise.resolve(null), n = () => {
558
- t.abort(), l?.abort?.();
559
- }, s = Promise.all([t, l]).then(async ([o, c]) => {
560
- if (!e.diarization) return o;
561
- if (o = this.combineSpeakerTranscript(o, c), e.diarization === "id") {
554
+ const t = x(J(x(P(), "audio-")), "converted.wav");
555
+ C(`ffmpeg -i "${r}" -ar 16000 -ac 1 -f wav "${t}"`, { stdio: "ignore" });
556
+ const m = () => W(_.dirname(t), { recursive: !0, force: !0 }).catch(() => {
557
+ }), n = this.runAsr(t, { model: e.model, diarization: !!e.diarization }), s = e.diarization ? this.runDiarization(t) : Promise.resolve(null);
558
+ let i = !1, l = () => {
559
+ i = !0, n.abort(), s?.abort?.(), m();
560
+ };
561
+ const d = Promise.all([n, s]).then(async ([a, o]) => {
562
+ if (i || !e.diarization) return a;
563
+ if (a = this.combineSpeakerTranscript(a, o), !i && e.diarization === "id") {
562
564
  if (!this.ai.language.defaultModel) throw new Error("Configure an LLM for advanced ASR speaker detection");
563
- let a = this.ai.language.chunk(o, 500, 0);
564
- a.length > 4 && (a = [...a.slice(0, 3), a.at(-1)]);
565
- const m = await this.ai.language.json(a.join(`
565
+ let c = this.ai.language.chunk(a, 500, 0);
566
+ c.length > 4 && (c = [...c.slice(0, 3), c.at(-1)]);
567
+ const p = await this.ai.language.json(c.join(`
566
568
  `), '{1: "Detected Name", 2: "Second Name"}', {
567
569
  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",
568
570
  temperature: 0.1
569
571
  });
570
- Object.entries(m).forEach(([i, d]) => o = o.replaceAll(`[Speaker ${i}]`, `[${d}]`));
572
+ Object.entries(p).forEach(([u, f]) => a = a.replaceAll(`[Speaker ${u}]`, `[${f}]`));
571
573
  }
572
- return o;
573
- });
574
- return Object.assign(s, { abort: n });
574
+ return a;
575
+ }).finally(() => m());
576
+ return Object.assign(d, { abort: l });
575
577
  }
576
578
  async downloadAsrModel(r = this.whisperModel) {
577
579
  if (!this.ai.options.whisper) throw new Error("Whisper not configured");
@@ -591,10 +593,10 @@ class V {
591
593
  */
592
594
  ocr(r) {
593
595
  let e;
594
- const t = new Promise(async (l) => {
596
+ const t = new Promise(async (m) => {
595
597
  e = await D(this.ai.options.ocr || "eng", 2, { cachePath: this.ai.options.path });
596
598
  const { data: n } = await e.recognize(r);
597
- await e.terminate(), l(n.text.trim() || null);
599
+ await e.terminate(), m(n.text.trim() || null);
598
600
  });
599
601
  return Object.assign(t, { abort: () => e?.terminate() });
600
602
  }
@@ -684,16 +686,16 @@ const Y = {
684
686
  title: e('meta[property="og:title"]').attr("content") || e("title").text() || "",
685
687
  description: e('meta[name="description"]').attr("content") || e('meta[property="og:description"]').attr("content") || ""
686
688
  };
687
- let l = "";
689
+ let m = "";
688
690
  const n = ["article", "main", '[role="main"]', ".content", ".post", ".entry", "body"];
689
691
  for (const s of n) {
690
- const o = e(s).first();
691
- if (o.length && o.text().trim().length > 200) {
692
- l = o.text();
692
+ const i = e(s).first();
693
+ if (i.length && i.text().trim().length > 200) {
694
+ m = i.text();
693
695
  break;
694
696
  }
695
697
  }
696
- 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 };
698
+ return m || (m = e("body").text()), m = m.replace(/\s+/g, " ").trim().slice(0, 8e3), { url: h.url, title: t.title.trim(), description: t.description.trim(), content: m, focus: h.focus };
697
699
  }
698
700
  }, ye = {
699
701
  name: "web_search",
@@ -707,12 +709,12 @@ const Y = {
707
709
  headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Accept-Language": "en-US,en;q=0.9" }
708
710
  }).then((n) => n.text());
709
711
  let e, t = /<a .*?href="(.+?)".+?<\/a>/g;
710
- const l = new v();
712
+ const m = new v();
711
713
  for (; (e = t.exec(r)) !== null; ) {
712
714
  let n = /uddg=(.+)&amp?/.exec(decodeURIComponent(e[1]))?.[1];
713
- if (n && (n = decodeURIComponent(n)), n && l.add(n), l.size >= (h.length || 5)) break;
715
+ if (n && (n = decodeURIComponent(n)), n && m.add(n), m.size >= (h.length || 5)) break;
714
716
  }
715
- return l;
717
+ return m;
716
718
  }
717
719
  };
718
720
  export {