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