@ztimson/ai-utils 0.2.4 → 0.2.6

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