@ztimson/ai-utils 0.1.21 → 0.2.0

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