@ztimson/ai-utils 0.7.2 → 0.7.4

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