@ztimson/ai-utils 0.1.22 → 0.2.1

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,18 +1,18 @@
1
- import { createWorker as j } from "tesseract.js";
2
- import { deepCopy as T, objectMap as b, JSONAttemptParse as _, findByProp as k, JSONSanitize as y, Http as q, consoleInterceptor as v, fn as P, ASet as A } from "@ztimson/utils";
3
- import { Anthropic as E } from "@anthropic-ai/sdk";
4
- import { Ollama as M } from "ollama";
5
- import { OpenAI as O } from "openai";
6
- import S from "node:fs/promises";
7
- import U from "node:path";
8
- import * as w from "@tensorflow/tfjs";
9
- import { spawn as $ } from "node:child_process";
1
+ import { pipeline as S } from "@xenova/transformers";
2
+ import { deepCopy as T, objectMap as y, JSONAttemptParse as w, findByProp as b, JSONSanitize as _, Http as j, consoleInterceptor as M, fn as q, ASet as A } from "@ztimson/utils";
3
+ import { Anthropic as P } from "@anthropic-ai/sdk";
4
+ import { Ollama as E } from "ollama";
5
+ import { OpenAI as $ } from "openai";
6
+ import { spawn as v } from "node:child_process";
7
+ import x from "node:fs/promises";
8
+ import O from "node:path";
9
+ import { createWorker as U } from "tesseract.js";
10
10
  import { $ as L, $Sync as R } from "@ztimson/node-utils";
11
- class x {
11
+ class k {
12
12
  }
13
- class D extends x {
13
+ class D extends k {
14
14
  constructor(t, e, n) {
15
- super(), this.ai = t, this.apiToken = e, this.model = n, this.client = new E({ apiKey: e });
15
+ super(), this.ai = t, this.apiToken = e, this.model = n, this.client = new P({ apiKey: e });
16
16
  }
17
17
  client;
18
18
  toStandard(t) {
@@ -45,74 +45,74 @@ class D extends x {
45
45
  ask(t, e = {}) {
46
46
  const n = new AbortController(), a = new Promise(async (c, f) => {
47
47
  let i = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]);
48
- const l = T(i);
49
- e.compress && (i = await this.ai.llm.compress(i, e.compress.max, e.compress.min, e));
50
- const m = {
48
+ const p = T(i);
49
+ e.compress && (i = await this.ai.language.compressHistory(i, e.compress.max, e.compress.min, e));
50
+ const l = {
51
51
  model: e.model || this.model,
52
52
  max_tokens: e.max_tokens || this.ai.options.max_tokens || 4096,
53
53
  system: e.system || this.ai.options.system || "",
54
54
  temperature: e.temperature || this.ai.options.temperature || 0.7,
55
- tools: (e.tools || this.ai.options.tools || []).map((o) => ({
56
- name: o.name,
57
- description: o.description,
55
+ tools: (e.tools || this.ai.options.tools || []).map((s) => ({
56
+ name: s.name,
57
+ description: s.description,
58
58
  input_schema: {
59
59
  type: "object",
60
- properties: o.args ? b(o.args, (r, u) => ({ ...u, required: void 0 })) : {},
61
- required: o.args ? Object.entries(o.args).filter((r) => r[1].required).map((r) => r[0]) : []
60
+ properties: s.args ? y(s.args, (r, d) => ({ ...d, required: void 0 })) : {},
61
+ required: s.args ? Object.entries(s.args).filter((r) => r[1].required).map((r) => r[0]) : []
62
62
  },
63
63
  fn: void 0
64
64
  })),
65
65
  messages: i,
66
66
  stream: !!e.stream
67
67
  };
68
- let s, p = !0;
68
+ let o, m = !0;
69
69
  do {
70
- if (s = await this.client.messages.create(m), e.stream) {
71
- p ? p = !1 : e.stream({ text: `
70
+ if (o = await this.client.messages.create(l), e.stream) {
71
+ m ? m = !1 : e.stream({ text: `
72
72
 
73
- ` }), s.content = [];
74
- for await (const r of s) {
73
+ ` }), o.content = [];
74
+ for await (const r of o) {
75
75
  if (n.signal.aborted) break;
76
76
  if (r.type === "content_block_start")
77
- r.content_block.type === "text" ? s.content.push({ type: "text", text: "" }) : r.content_block.type === "tool_use" && s.content.push({ type: "tool_use", id: r.content_block.id, name: r.content_block.name, input: "" });
77
+ r.content_block.type === "text" ? o.content.push({ type: "text", text: "" }) : r.content_block.type === "tool_use" && o.content.push({ type: "tool_use", id: r.content_block.id, name: r.content_block.name, input: "" });
78
78
  else if (r.type === "content_block_delta")
79
79
  if (r.delta.type === "text_delta") {
80
- const u = r.delta.text;
81
- s.content.at(-1).text += u, e.stream({ text: u });
82
- } else r.delta.type === "input_json_delta" && (s.content.at(-1).input += r.delta.partial_json);
80
+ const d = r.delta.text;
81
+ o.content.at(-1).text += d, e.stream({ text: d });
82
+ } else r.delta.type === "input_json_delta" && (o.content.at(-1).input += r.delta.partial_json);
83
83
  else if (r.type === "content_block_stop") {
84
- const u = s.content.at(-1);
85
- u.input != null && (u.input = u.input ? _(u.input, {}) : {});
84
+ const d = o.content.at(-1);
85
+ d.input != null && (d.input = d.input ? w(d.input, {}) : {});
86
86
  } else if (r.type === "message_stop")
87
87
  break;
88
88
  }
89
89
  }
90
- const o = s.content.filter((r) => r.type === "tool_use");
91
- if (o.length && !n.signal.aborted) {
92
- i.push({ role: "assistant", content: s.content }), l.push({ role: "assistant", content: s.content });
93
- const r = await Promise.all(o.map(async (u) => {
94
- const h = e.tools?.find(k("name", u.name));
95
- if (!h) return { tool_use_id: u.id, is_error: !0, content: "Tool not found" };
90
+ const s = o.content.filter((r) => r.type === "tool_use");
91
+ if (s.length && !n.signal.aborted) {
92
+ i.push({ role: "assistant", content: o.content }), p.push({ role: "assistant", content: o.content });
93
+ const r = await Promise.all(s.map(async (d) => {
94
+ const h = e.tools?.find(b("name", d.name));
95
+ if (!h) return { tool_use_id: d.id, is_error: !0, content: "Tool not found" };
96
96
  try {
97
- const g = await h.fn(u.input, this.ai);
98
- return { type: "tool_result", tool_use_id: u.id, content: y(g) };
97
+ const g = await h.fn(d.input, this.ai);
98
+ return { type: "tool_result", tool_use_id: d.id, content: _(g) };
99
99
  } catch (g) {
100
- return { type: "tool_result", tool_use_id: u.id, is_error: !0, content: g?.message || g?.toString() || "Unknown" };
100
+ return { type: "tool_result", tool_use_id: d.id, is_error: !0, content: g?.message || g?.toString() || "Unknown" };
101
101
  }
102
102
  }));
103
- i.push({ role: "user", content: r }), m.messages = i;
103
+ i.push({ role: "user", content: r }), l.messages = i;
104
104
  }
105
- } while (!n.signal.aborted && s.content.some((o) => o.type === "tool_use"));
106
- e.stream && e.stream({ done: !0 }), c(this.toStandard([...i, { role: "assistant", content: s.content.filter((o) => o.type == "text").map((o) => o.text).join(`
105
+ } while (!n.signal.aborted && o.content.some((s) => s.type === "tool_use"));
106
+ e.stream && e.stream({ done: !0 }), c(this.toStandard([...i, { role: "assistant", content: o.content.filter((s) => s.type == "text").map((s) => s.text).join(`
107
107
 
108
108
  `) }]));
109
109
  });
110
110
  return Object.assign(a, { abort: () => n.abort() });
111
111
  }
112
112
  }
113
- class I extends x {
113
+ class z extends k {
114
114
  constructor(t, e, n) {
115
- super(), this.ai = t, this.host = e, this.model = n, this.client = new M({ host: e });
115
+ super(), this.ai = t, this.host = e, this.model = n, this.client = new E({ host: e });
116
116
  }
117
117
  client;
118
118
  toStandard(t) {
@@ -135,63 +135,63 @@ class I extends x {
135
135
  }
136
136
  ask(t, e = {}) {
137
137
  const n = new AbortController(), a = new Promise(async (c, f) => {
138
- let i = e.system || this.ai.options.system, l = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]);
139
- l[0].roll == "system" && (i ? l.shift() : i = l.shift()), e.compress && (l = await this.ai.llm.compress(l, e.compress.max, e.compress.min)), e.system && l.unshift({ role: "system", content: i });
140
- const m = {
138
+ let i = e.system || this.ai.options.system, p = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]);
139
+ p[0].roll == "system" && (i ? p.shift() : i = p.shift()), e.compress && (p = await this.ai.language.compressHistory(p, e.compress.max, e.compress.min)), e.system && p.unshift({ role: "system", content: i });
140
+ const l = {
141
141
  model: e.model || this.model,
142
- messages: l,
142
+ messages: p,
143
143
  stream: !!e.stream,
144
144
  signal: n.signal,
145
145
  options: {
146
146
  temperature: e.temperature || this.ai.options.temperature || 0.7,
147
147
  num_predict: e.max_tokens || this.ai.options.max_tokens || 4096
148
148
  },
149
- tools: (e.tools || this.ai.options.tools || []).map((o) => ({
149
+ tools: (e.tools || this.ai.options.tools || []).map((s) => ({
150
150
  type: "function",
151
151
  function: {
152
- name: o.name,
153
- description: o.description,
152
+ name: s.name,
153
+ description: s.description,
154
154
  parameters: {
155
155
  type: "object",
156
- properties: o.args ? b(o.args, (r, u) => ({ ...u, required: void 0 })) : {},
157
- required: o.args ? Object.entries(o.args).filter((r) => r[1].required).map((r) => r[0]) : []
156
+ properties: s.args ? y(s.args, (r, d) => ({ ...d, required: void 0 })) : {},
157
+ required: s.args ? Object.entries(s.args).filter((r) => r[1].required).map((r) => r[0]) : []
158
158
  }
159
159
  }
160
160
  }))
161
161
  };
162
- let s, p = !0;
162
+ let o, m = !0;
163
163
  do {
164
- if (s = await this.client.chat(m), e.stream) {
165
- p ? p = !1 : e.stream({ text: `
164
+ if (o = await this.client.chat(l), e.stream) {
165
+ m ? m = !1 : e.stream({ text: `
166
166
 
167
- ` }), s.message = { role: "assistant", content: "", tool_calls: [] };
168
- for await (const o of s)
169
- if (n.signal.aborted || (o.message?.content && (s.message.content += o.message.content, e.stream({ text: o.message.content })), o.message?.tool_calls && (s.message.tool_calls = o.message.tool_calls), o.done)) break;
167
+ ` }), o.message = { role: "assistant", content: "", tool_calls: [] };
168
+ for await (const s of o)
169
+ if (n.signal.aborted || (s.message?.content && (o.message.content += s.message.content, e.stream({ text: s.message.content })), s.message?.tool_calls && (o.message.tool_calls = s.message.tool_calls), s.done)) break;
170
170
  }
171
- if (s.message?.tool_calls?.length && !n.signal.aborted) {
172
- l.push(s.message);
173
- const o = await Promise.all(s.message.tool_calls.map(async (r) => {
174
- const u = (e.tools || this.ai.options.tools)?.find(k("name", r.function.name));
175
- if (!u) return { role: "tool", tool_name: r.function.name, content: '{"error": "Tool not found"}' };
176
- const h = typeof r.function.arguments == "string" ? _(r.function.arguments, {}) : r.function.arguments;
171
+ if (o.message?.tool_calls?.length && !n.signal.aborted) {
172
+ p.push(o.message);
173
+ const s = await Promise.all(o.message.tool_calls.map(async (r) => {
174
+ const d = (e.tools || this.ai.options.tools)?.find(b("name", r.function.name));
175
+ if (!d) return { role: "tool", tool_name: r.function.name, content: '{"error": "Tool not found"}' };
176
+ const h = typeof r.function.arguments == "string" ? w(r.function.arguments, {}) : r.function.arguments;
177
177
  try {
178
- const g = await u.fn(h, this.ai);
179
- return { role: "tool", tool_name: r.function.name, args: h, content: y(g) };
178
+ const g = await d.fn(h, this.ai);
179
+ return { role: "tool", tool_name: r.function.name, args: h, content: _(g) };
180
180
  } catch (g) {
181
- return { role: "tool", tool_name: r.function.name, args: h, content: y({ error: g?.message || g?.toString() || "Unknown" }) };
181
+ return { role: "tool", tool_name: r.function.name, args: h, content: _({ error: g?.message || g?.toString() || "Unknown" }) };
182
182
  }
183
183
  }));
184
- l.push(...o), m.messages = l;
184
+ p.push(...s), l.messages = p;
185
185
  }
186
- } while (!n.signal.aborted && s.message?.tool_calls?.length);
187
- e.stream && e.stream({ done: !0 }), c(this.toStandard([...l, { role: "assistant", content: s.message?.content }]));
186
+ } while (!n.signal.aborted && o.message?.tool_calls?.length);
187
+ e.stream && e.stream({ done: !0 }), c(this.toStandard([...p, { role: "assistant", content: o.message?.content }]));
188
188
  });
189
189
  return Object.assign(a, { abort: () => n.abort() });
190
190
  }
191
191
  }
192
- class J extends x {
192
+ class H extends k {
193
193
  constructor(t, e, n) {
194
- super(), this.ai = t, this.apiToken = e, this.model = n, this.client = new O({ apiKey: e });
194
+ super(), this.ai = t, this.apiToken = e, this.model = n, this.client = new $({ apiKey: e });
195
195
  }
196
196
  client;
197
197
  toStandard(t) {
@@ -202,7 +202,7 @@ class J extends x {
202
202
  role: "tool",
203
203
  id: c.id,
204
204
  name: c.function.name,
205
- args: _(c.function.arguments, {}),
205
+ args: w(c.function.arguments, {}),
206
206
  timestamp: n.timestamp
207
207
  }));
208
208
  t.splice(e, 1, ...a), e += a.length - 1;
@@ -238,62 +238,63 @@ class J extends x {
238
238
  ask(t, e = {}) {
239
239
  const n = new AbortController(), a = new Promise(async (c, f) => {
240
240
  let i = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]);
241
- e.compress && (i = await this.ai.llm.compress(i, e.compress.max, e.compress.min, e));
242
- const l = {
241
+ e.compress && (i = await this.ai.language.compressHistory(i, e.compress.max, e.compress.min, e));
242
+ const p = {
243
243
  model: e.model || this.model,
244
244
  messages: i,
245
245
  stream: !!e.stream,
246
246
  max_tokens: e.max_tokens || this.ai.options.max_tokens || 4096,
247
247
  temperature: e.temperature || this.ai.options.temperature || 0.7,
248
- tools: (e.tools || this.ai.options.tools || []).map((p) => ({
248
+ tools: (e.tools || this.ai.options.tools || []).map((m) => ({
249
249
  type: "function",
250
250
  function: {
251
- name: p.name,
252
- description: p.description,
251
+ name: m.name,
252
+ description: m.description,
253
253
  parameters: {
254
254
  type: "object",
255
- properties: p.args ? b(p.args, (o, r) => ({ ...r, required: void 0 })) : {},
256
- required: p.args ? Object.entries(p.args).filter((o) => o[1].required).map((o) => o[0]) : []
255
+ properties: m.args ? y(m.args, (s, r) => ({ ...r, required: void 0 })) : {},
256
+ required: m.args ? Object.entries(m.args).filter((s) => s[1].required).map((s) => s[0]) : []
257
257
  }
258
258
  }
259
259
  }))
260
260
  };
261
- let m, s = !0;
261
+ let l, o = !0;
262
262
  do {
263
- if (m = await this.client.chat.completions.create(l), e.stream) {
264
- s ? s = !1 : e.stream({ text: `
263
+ if (l = await this.client.chat.completions.create(p), e.stream) {
264
+ o ? o = !1 : e.stream({ text: `
265
265
 
266
- ` }), m.choices = [{ message: { content: "", tool_calls: [] } }];
267
- for await (const o of m) {
266
+ ` }), l.choices = [{ message: { content: "", tool_calls: [] } }];
267
+ for await (const s of l) {
268
268
  if (n.signal.aborted) break;
269
- o.choices[0].delta.content && (m.choices[0].message.content += o.choices[0].delta.content, e.stream({ text: o.choices[0].delta.content })), o.choices[0].delta.tool_calls && (m.choices[0].message.tool_calls = o.choices[0].delta.tool_calls);
269
+ s.choices[0].delta.content && (l.choices[0].message.content += s.choices[0].delta.content, e.stream({ text: s.choices[0].delta.content })), s.choices[0].delta.tool_calls && (l.choices[0].message.tool_calls = s.choices[0].delta.tool_calls);
270
270
  }
271
271
  }
272
- const p = m.choices[0].message.tool_calls || [];
273
- if (p.length && !n.signal.aborted) {
274
- i.push(m.choices[0].message);
275
- const o = await Promise.all(p.map(async (r) => {
276
- const u = e.tools?.find(k("name", r.function.name));
277
- if (!u) return { role: "tool", tool_call_id: r.id, content: '{"error": "Tool not found"}' };
272
+ const m = l.choices[0].message.tool_calls || [];
273
+ if (m.length && !n.signal.aborted) {
274
+ i.push(l.choices[0].message);
275
+ const s = await Promise.all(m.map(async (r) => {
276
+ const d = e.tools?.find(b("name", r.function.name));
277
+ if (!d) return { role: "tool", tool_call_id: r.id, content: '{"error": "Tool not found"}' };
278
278
  try {
279
- const h = _(r.function.arguments, {}), g = await u.fn(h, this.ai);
280
- return { role: "tool", tool_call_id: r.id, content: y(g) };
279
+ const h = w(r.function.arguments, {}), g = await d.fn(h, this.ai);
280
+ return { role: "tool", tool_call_id: r.id, content: _(g) };
281
281
  } catch (h) {
282
- return { role: "tool", tool_call_id: r.id, content: y({ error: h?.message || h?.toString() || "Unknown" }) };
282
+ return { role: "tool", tool_call_id: r.id, content: _({ error: h?.message || h?.toString() || "Unknown" }) };
283
283
  }
284
284
  }));
285
- i.push(...o), l.messages = i;
285
+ i.push(...s), p.messages = i;
286
286
  }
287
- } while (!n.signal.aborted && m.choices?.[0]?.message?.tool_calls?.length);
288
- e.stream && e.stream({ done: !0 }), c(this.toStandard([...i, { role: "assistant", content: m.choices[0].message.content || "" }]));
287
+ } while (!n.signal.aborted && l.choices?.[0]?.message?.tool_calls?.length);
288
+ e.stream && e.stream({ done: !0 }), c(this.toStandard([...i, { role: "assistant", content: l.choices[0].message.content || "" }]));
289
289
  });
290
290
  return Object.assign(a, { abort: () => n.abort() });
291
291
  }
292
292
  }
293
- class W {
294
- constructor(t, e) {
295
- this.ai = t, this.options = e, e.anthropic?.token && (this.providers.anthropic = new D(this.ai, e.anthropic.token, e.anthropic.model)), e.ollama?.host && (this.providers.ollama = new I(this.ai, e.ollama.host, e.ollama.model)), e.openAi?.token && (this.providers.openAi = new J(this.ai, e.openAi.token, e.openAi.model));
293
+ class N {
294
+ constructor(t) {
295
+ this.ai = t, this.embedModel = S("feature-extraction", "Xenova/all-MiniLM-L6-v2"), t.options.anthropic?.token && (this.providers.anthropic = new D(this.ai, t.options.anthropic.token, t.options.anthropic.model)), t.options.ollama?.host && (this.providers.ollama = new z(this.ai, t.options.ollama.host, t.options.ollama.model)), t.options.openAi?.token && (this.providers.openAi = new H(this.ai, t.options.openAi.token, t.options.openAi.model));
296
296
  }
297
+ embedModel;
297
298
  providers = {};
298
299
  /**
299
300
  * Chat with LLM
@@ -303,7 +304,7 @@ class W {
303
304
  */
304
305
  ask(t, e = {}) {
305
306
  let n = [null, null];
306
- if (e.model && (typeof e.model == "object" ? n = e.model : n = [e.model, this.options[e.model]?.model]), (!e.model || n[1] == null) && (typeof this.options.model == "object" ? n = this.options.model : n = [this.options.model, this.options[this.options.model]?.model]), !n[0] || !n[1]) throw new Error(`Unknown LLM provider or model: ${n[0]} / ${n[1]}`);
307
+ if (e.model && (typeof e.model == "object" ? n = e.model : n = [e.model, this.ai.options[e.model]?.model]), (!e.model || n[1] == null) && (typeof this.ai.options.model == "object" ? n = this.ai.options.model : n = [this.ai.options.model, this.ai.options[this.ai.options.model]?.model]), !n[0] || !n[1]) throw new Error(`Unknown LLM provider or model: ${n[0]} / ${n[1]}`);
307
308
  return this.providers[n[0]].ask(t, { ...e, model: n[1] });
308
309
  }
309
310
  /**
@@ -314,18 +315,58 @@ class W {
314
315
  * @param {LLMRequest} options LLM options
315
316
  * @returns {Promise<LLMMessage[]>} New chat history will summary at index 0
316
317
  */
317
- async compress(t, e, n, a) {
318
+ async compressHistory(t, e, n, a) {
318
319
  if (this.estimateTokens(t) < e) return t;
319
320
  let c = 0, f = 0;
320
- for (let s of t.toReversed())
321
- if (f += this.estimateTokens(s.content), f < n) c++;
321
+ for (let o of t.toReversed())
322
+ if (f += this.estimateTokens(o.content), f < n) c++;
322
323
  else break;
323
324
  if (t.length <= c) return t;
324
- const i = c == 0 ? [] : t.slice(-c), l = (c == 0 ? t : t.slice(0, -c)).filter((s) => s.role === "assistant" || s.role === "user");
325
- return [{ role: "assistant", content: `Conversation Summary: ${await this.summarize(l.map((s) => `${s.role}: ${s.content}`).join(`
325
+ const i = c == 0 ? [] : t.slice(-c), p = (c == 0 ? t : t.slice(0, -c)).filter((o) => o.role === "assistant" || o.role === "user");
326
+ return [{ role: "assistant", content: `Conversation Summary: ${await this.summarize(p.map((o) => `${o.role}: ${o.content}`).join(`
326
327
 
327
328
  `), 250, a)}`, timestamp: Date.now() }, ...i];
328
329
  }
330
+ cosineSimilarity(t, e) {
331
+ if (t.length !== e.length) throw new Error("Vectors must be same length");
332
+ let n = 0, a = 0, c = 0;
333
+ for (let i = 0; i < t.length; i++)
334
+ n += t[i] * e[i], a += t[i] * t[i], c += e[i] * e[i];
335
+ const f = Math.sqrt(a) * Math.sqrt(c);
336
+ return f === 0 ? 0 : n / f;
337
+ }
338
+ embedding(t, e = 500, n = 50) {
339
+ const a = (o, m = "") => o == null ? [] : Object.entries(o).flatMap(([s, r]) => {
340
+ const d = m ? `${m}${isNaN(+s) ? `.${s}` : `[${s}]`}` : s;
341
+ if (typeof r == "object" && r !== null && !Array.isArray(r)) return a(r, d);
342
+ const h = Array.isArray(r) ? r.join(", ") : String(r);
343
+ return `${d}: ${h}`;
344
+ }), c = async (o) => {
345
+ const s = await (await this.embedModel)(o, { pooling: "mean", normalize: !0 });
346
+ return Array.from(s.data);
347
+ }, i = (typeof t == "object" ? a(t) : t.split(`
348
+ `)).flatMap((o) => [...o.split(/\s+/).filter((m) => m.trim()), `
349
+ `]), p = [];
350
+ let l = 0;
351
+ for (; l < i.length; ) {
352
+ let o = l, m = "";
353
+ for (; o < i.length; ) {
354
+ const r = i[o], d = m + (m ? " " : "") + r;
355
+ if (this.estimateTokens(d.replace(/\s*\n\s*/g, `
356
+ `)) > e && m) break;
357
+ m = d, o++;
358
+ }
359
+ const s = m.replace(/\s*\n\s*/g, `
360
+ `).trim();
361
+ s && p.push(s), l = o - n, l <= o - i.length + o && (l = o);
362
+ }
363
+ return Promise.all(p.map(async (o, m) => ({
364
+ index: m,
365
+ embedding: await c(o),
366
+ text: o,
367
+ tokens: this.estimateTokens(o)
368
+ })));
369
+ }
329
370
  /**
330
371
  * Estimate variable as tokens
331
372
  * @param history Object to size
@@ -335,6 +376,17 @@ class W {
335
376
  const e = JSON.stringify(t);
336
377
  return Math.ceil(e.length / 4 * 1.2);
337
378
  }
379
+ /**
380
+ * Compare the difference between two strings using tensor math
381
+ * @param target Text that will checked
382
+ * @param {string} searchTerms Multiple search terms to check against target
383
+ * @returns {{avg: number, max: number, similarities: number[]}} Similarity values 0-1: 0 = unique, 1 = identical
384
+ */
385
+ fuzzyMatch(t, ...e) {
386
+ if (e.length < 2) throw new Error("Requires at least 2 strings to compare");
387
+ const n = (f, i = 10) => f.toLowerCase().split("").map((p, l) => p.charCodeAt(0) * (l + 1) % i / i).slice(0, i), a = n(t), c = e.map((f) => n(f)).map((f) => this.cosineSimilarity(a, f));
388
+ return { avg: c.reduce((f, i) => f + i, 0) / c.length, max: Math.max(...c), similarities: c };
389
+ }
338
390
  /**
339
391
  * Ask a question with JSON response
340
392
  * @param {string} message Question
@@ -346,7 +398,7 @@ class W {
346
398
  system: "Respond using a JSON blob",
347
399
  ...e
348
400
  });
349
- return n?.[0]?.content ? _(new RegExp("{[sS]*}").exec(n[0].content), {}) : {};
401
+ return n?.[0]?.content ? w(new RegExp("{[sS]*}").exec(n[0].content), {}) : {};
350
402
  }
351
403
  /**
352
404
  * Create a summary of some text
@@ -359,14 +411,12 @@ class W {
359
411
  return this.ask(t, { system: `Generate a brief summary <= ${e} tokens. Output nothing else`, temperature: 0.3, ...n }).then((a) => a.pop()?.content || null);
360
412
  }
361
413
  }
362
- class Z {
414
+ class I {
363
415
  constructor(t) {
364
- this.options = t, this.llm = new W(this, t), this.options.whisper?.binary && (this.whisperModel = this.options.whisper?.model.endsWith(".bin") ? this.options.whisper?.model : this.options.whisper?.model + ".bin", this.downloadAsrModel());
416
+ this.ai = t, t.options.whisper?.binary && (this.whisperModel = t.options.whisper?.model.endsWith(".bin") ? t.options.whisper?.model : t.options.whisper?.model + ".bin", this.downloadAsrModel());
365
417
  }
366
418
  downloads = {};
367
419
  whisperModel;
368
- /** Large Language Models */
369
- llm;
370
420
  /**
371
421
  * Convert audio to text using Auditory Speech Recognition
372
422
  * @param {string} path Path to audio
@@ -374,15 +424,15 @@ class Z {
374
424
  * @returns {Promise<any>} Extracted text
375
425
  */
376
426
  asr(t, e = this.whisperModel) {
377
- if (!this.options.whisper?.binary) throw new Error("Whisper not configured");
427
+ if (!this.ai.options.whisper?.binary) throw new Error("Whisper not configured");
378
428
  let n = () => {
379
429
  };
380
430
  return { response: new Promise((c, f) => {
381
431
  this.downloadAsrModel(e).then((i) => {
382
- let l = "";
383
- const m = $(this.options.whisper?.binary, ["-nt", "-np", "-m", i, "-f", t], { stdio: ["ignore", "pipe", "ignore"] });
384
- n = () => m.kill("SIGTERM"), m.on("error", (s) => f(s)), m.stdout.on("data", (s) => l += s.toString()), m.on("close", (s) => {
385
- s === 0 ? c(l.trim() || null) : f(new Error(`Exit code ${s}`));
432
+ let p = "";
433
+ const l = v(this.ai.options.whisper?.binary, ["-nt", "-np", "-m", i, "-f", t], { stdio: ["ignore", "pipe", "ignore"] });
434
+ n = () => l.kill("SIGTERM"), l.on("error", (o) => f(o)), l.stdout.on("data", (o) => p += o.toString()), l.on("close", (o) => {
435
+ o === 0 ? c(p.trim() || null) : f(new Error(`Exit code ${o}`));
386
436
  });
387
437
  });
388
438
  }), abort: n };
@@ -394,10 +444,15 @@ class Z {
394
444
  * @return {Promise<string>} Absolute path to model file, resolves once downloaded
395
445
  */
396
446
  async downloadAsrModel(t = this.whisperModel) {
397
- if (!this.options.whisper?.binary) throw new Error("Whisper not configured");
447
+ if (!this.ai.options.whisper?.binary) throw new Error("Whisper not configured");
398
448
  t.endsWith(".bin") || (t += ".bin");
399
- const e = U.join(this.options.whisper.path, t);
400
- return await S.stat(e).then(() => !0).catch(() => !1) ? e : this.downloads[t] ? this.downloads[t] : (this.downloads[t] = fetch(`https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${t}`).then((n) => n.arrayBuffer()).then((n) => Buffer.from(n)).then(async (n) => (await S.writeFile(e, n), delete this.downloads[t], e)), this.downloads[t]);
449
+ const e = O.join(this.ai.options.whisper.path, t);
450
+ return await x.stat(e).then(() => !0).catch(() => !1) ? e : this.downloads[t] ? this.downloads[t] : (this.downloads[t] = fetch(`https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${t}`).then((n) => n.arrayBuffer()).then((n) => Buffer.from(n)).then(async (n) => (await x.writeFile(e, n), delete this.downloads[t], e)), this.downloads[t]);
451
+ }
452
+ }
453
+ class J {
454
+ constructor(t) {
455
+ this.ai = t;
401
456
  }
402
457
  /**
403
458
  * Convert image to text using Optical Character Recognition
@@ -411,60 +466,58 @@ class Z {
411
466
  e?.terminate();
412
467
  },
413
468
  response: new Promise(async (n) => {
414
- e = await j("eng");
469
+ e = await U("eng");
415
470
  const { data: a } = await e.recognize(t);
416
471
  await e.terminate(), n(a.text.trim() || null);
417
472
  })
418
473
  };
419
474
  }
420
- /**
421
- * Compare the difference between two strings using tensor math
422
- * @param target Text that will checked
423
- * @param {string} searchTerms Multiple search terms to check against target
424
- * @returns {{avg: number, max: number, similarities: number[]}} Similarity values 0-1: 0 = unique, 1 = identical
425
- */
426
- semanticSimilarity(t, ...e) {
427
- if (e.length < 2) throw new Error("Requires at least 2 strings to compare");
428
- const n = (i, l = 10) => i.toLowerCase().split("").map((m, s) => m.charCodeAt(0) * (s + 1) % l / l).slice(0, l), a = (i, l) => {
429
- if (i.length !== l.length) throw new Error("Vectors must be same length");
430
- const m = w.tensor1d(i), s = w.tensor1d(l), p = w.dot(m, s), o = w.norm(m), r = w.norm(s);
431
- return o.dataSync()[0] === 0 || r.dataSync()[0] === 0 ? 0 : p.dataSync()[0] / (o.dataSync()[0] * r.dataSync()[0]);
432
- }, c = n(t), f = e.map((i) => n(i)).map((i) => a(c, i));
433
- return { avg: f.reduce((i, l) => i + l, 0) / f.length, max: Math.max(...f), similarities: f };
475
+ }
476
+ class ne {
477
+ constructor(t) {
478
+ this.options = t, this.audio = new I(this), this.language = new N(this), this.vision = new J(this);
434
479
  }
480
+ downloads = {};
481
+ whisperModel;
482
+ /** Audio processing AI */
483
+ audio;
484
+ /** Language processing AI */
485
+ language;
486
+ /** Vision processing AI */
487
+ vision;
435
488
  }
436
- const N = {
489
+ const W = {
437
490
  name: "cli",
438
491
  description: "Use the command line interface, returns any output",
439
492
  args: { command: { type: "string", description: "Command to run", required: !0 } },
440
- fn: (d) => L`${d.command}`
441
- }, ee = {
493
+ fn: (u) => L`${u.command}`
494
+ }, oe = {
442
495
  name: "get_datetime",
443
496
  description: "Get current date and time",
444
497
  args: {},
445
498
  fn: async () => (/* @__PURE__ */ new Date()).toISOString()
446
- }, te = {
499
+ }, se = {
447
500
  name: "exec",
448
501
  description: "Run code/scripts",
449
502
  args: {
450
503
  language: { type: "string", description: "Execution language", enum: ["cli", "node", "python"], required: !0 },
451
504
  code: { type: "string", description: "Code to execute", required: !0 }
452
505
  },
453
- fn: async (d, t) => {
506
+ fn: async (u, t) => {
454
507
  try {
455
- switch (d.type) {
508
+ switch (u.type) {
456
509
  case "bash":
457
- return await N.fn({ command: d.code }, t);
510
+ return await W.fn({ command: u.code }, t);
458
511
  case "node":
459
- return await z.fn({ code: d.code }, t);
512
+ return await G.fn({ code: u.code }, t);
460
513
  case "python":
461
- return await G.fn({ code: d.code }, t);
514
+ return await F.fn({ code: u.code }, t);
462
515
  }
463
516
  } catch (e) {
464
517
  return { error: e?.message || e.toString() };
465
518
  }
466
519
  }
467
- }, ne = {
520
+ }, re = {
468
521
  name: "fetch",
469
522
  description: "Make HTTP request to URL",
470
523
  args: {
@@ -473,54 +526,54 @@ const N = {
473
526
  headers: { type: "object", description: "HTTP headers to send", default: {} },
474
527
  body: { type: "object", description: "HTTP body to send" }
475
528
  },
476
- fn: (d) => new q({ url: d.url, headers: d.headers }).request({ method: d.method || "GET", body: d.body })
477
- }, z = {
529
+ fn: (u) => new j({ url: u.url, headers: u.headers }).request({ method: u.method || "GET", body: u.body })
530
+ }, G = {
478
531
  name: "exec_javascript",
479
532
  description: "Execute commonjs javascript",
480
533
  args: {
481
534
  code: { type: "string", description: "CommonJS javascript", required: !0 }
482
535
  },
483
- fn: async (d) => {
484
- const t = v(null), e = await P({ console: t }, d.code, !0).catch((n) => t.output.error.push(n));
536
+ fn: async (u) => {
537
+ const t = M(null), e = await q({ console: t }, u.code, !0).catch((n) => t.output.error.push(n));
485
538
  return { ...t.output, return: e, stdout: void 0, stderr: void 0 };
486
539
  }
487
- }, G = {
540
+ }, F = {
488
541
  name: "exec_javascript",
489
542
  description: "Execute commonjs javascript",
490
543
  args: {
491
544
  code: { type: "string", description: "CommonJS javascript", required: !0 }
492
545
  },
493
- fn: async (d) => ({ result: R`python -c "${d.code}"` })
494
- }, se = {
546
+ fn: async (u) => ({ result: R`python -c "${u.code}"` })
547
+ }, ae = {
495
548
  name: "search",
496
549
  description: "Use a search engine to find relevant URLs, should be changed with fetch to scrape sources",
497
550
  args: {
498
551
  query: { type: "string", description: "Search string", required: !0 },
499
552
  length: { type: "string", description: "Number of results to return", default: 5 }
500
553
  },
501
- fn: async (d) => {
502
- const t = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(d.query)}`, {
554
+ fn: async (u) => {
555
+ const t = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(u.query)}`, {
503
556
  headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Accept-Language": "en-US,en;q=0.9" }
504
557
  }).then((c) => c.text());
505
558
  let e, n = /<a .*?href="(.+?)".+?<\/a>/g;
506
559
  const a = new A();
507
560
  for (; (e = n.exec(t)) !== null; ) {
508
561
  let c = /uddg=(.+)&amp?/.exec(decodeURIComponent(e[1]))?.[1];
509
- if (c && (c = decodeURIComponent(c)), c && a.add(c), a.size >= (d.length || 5)) break;
562
+ if (c && (c = decodeURIComponent(c)), c && a.add(c), a.size >= (u.length || 5)) break;
510
563
  }
511
564
  return a;
512
565
  }
513
566
  };
514
567
  export {
515
- Z as Ai,
568
+ ne as Ai,
516
569
  D as Anthropic,
517
- N as CliTool,
518
- ee as DateTimeTool,
519
- te as ExecTool,
520
- ne as FetchTool,
521
- z as JSTool,
522
- W as LLM,
523
- G as PythonTool,
524
- se as SearchTool
570
+ W as CliTool,
571
+ oe as DateTimeTool,
572
+ se as ExecTool,
573
+ re as FetchTool,
574
+ G as JSTool,
575
+ N as LLM,
576
+ F as PythonTool,
577
+ ae as SearchTool
525
578
  };
526
579
  //# sourceMappingURL=index.mjs.map