@forbocai/browser 0.5.6 → 0.5.8

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.d.mts CHANGED
@@ -5,27 +5,42 @@ declare const createCortex: (config?: CortexConfig) => ICortex;
5
5
 
6
6
  interface IBrowserMemory {
7
7
  store(text: string, type?: string, importance?: number): Promise<MemoryItem>;
8
- recall(query: string, limit?: number): Promise<MemoryItem[]>;
8
+ recall(query: string, limit?: number, threshold?: number): Promise<MemoryItem[]>;
9
+ list(limit?: number, offset?: number): Promise<MemoryItem[]>;
9
10
  clear(): Promise<void>;
11
+ export(): Promise<MemoryItem[]>;
12
+ import(memories: MemoryItem[]): Promise<void>;
10
13
  }
11
14
  declare const createBrowserMemory: (config?: {
12
15
  decay?: "none" | "temporal";
13
16
  maxContextWindow?: number;
14
17
  }) => {
15
18
  store: (text: string, type?: string, importance?: number) => Promise<MemoryItem>;
16
- recall: (query: string, limit?: number) => Promise<MemoryItem[]>;
19
+ recall: (query: string, limit?: number, threshold?: number) => Promise<MemoryItem[]>;
20
+ list: (limit?: number, offset?: number) => Promise<MemoryItem[]>;
17
21
  clear: () => Promise<void>;
22
+ export: () => Promise<MemoryItem[]>;
23
+ import: (memories: MemoryItem[]) => Promise<void>;
18
24
  };
19
25
  declare const createMemory: (config?: {
20
26
  decay?: "none" | "temporal";
21
27
  maxContextWindow?: number;
22
28
  }) => {
23
29
  store: (text: string, type?: string, importance?: number) => Promise<MemoryItem>;
24
- recall: (query: string, limit?: number) => Promise<MemoryItem[]>;
30
+ recall: (query: string, limit?: number, threshold?: number) => Promise<MemoryItem[]>;
31
+ list: (limit?: number, offset?: number) => Promise<MemoryItem[]>;
25
32
  clear: () => Promise<void>;
33
+ export: () => Promise<MemoryItem[]>;
34
+ import: (memories: MemoryItem[]) => Promise<void>;
26
35
  };
27
36
 
37
+ /**
38
+ * Initialize the vector engine.
39
+ */
28
40
  declare const initVectorEngine: () => Promise<void>;
41
+ /**
42
+ * Generate embeddings using Transformers.js.
43
+ */
29
44
  declare const generateEmbedding: (text: string) => Promise<number[]>;
30
45
 
31
46
  export { type IBrowserMemory, createBrowserCortex, createBrowserMemory, createCortex, createMemory, generateEmbedding, initVectorEngine };
package/dist/index.d.ts CHANGED
@@ -5,27 +5,42 @@ declare const createCortex: (config?: CortexConfig) => ICortex;
5
5
 
6
6
  interface IBrowserMemory {
7
7
  store(text: string, type?: string, importance?: number): Promise<MemoryItem>;
8
- recall(query: string, limit?: number): Promise<MemoryItem[]>;
8
+ recall(query: string, limit?: number, threshold?: number): Promise<MemoryItem[]>;
9
+ list(limit?: number, offset?: number): Promise<MemoryItem[]>;
9
10
  clear(): Promise<void>;
11
+ export(): Promise<MemoryItem[]>;
12
+ import(memories: MemoryItem[]): Promise<void>;
10
13
  }
11
14
  declare const createBrowserMemory: (config?: {
12
15
  decay?: "none" | "temporal";
13
16
  maxContextWindow?: number;
14
17
  }) => {
15
18
  store: (text: string, type?: string, importance?: number) => Promise<MemoryItem>;
16
- recall: (query: string, limit?: number) => Promise<MemoryItem[]>;
19
+ recall: (query: string, limit?: number, threshold?: number) => Promise<MemoryItem[]>;
20
+ list: (limit?: number, offset?: number) => Promise<MemoryItem[]>;
17
21
  clear: () => Promise<void>;
22
+ export: () => Promise<MemoryItem[]>;
23
+ import: (memories: MemoryItem[]) => Promise<void>;
18
24
  };
19
25
  declare const createMemory: (config?: {
20
26
  decay?: "none" | "temporal";
21
27
  maxContextWindow?: number;
22
28
  }) => {
23
29
  store: (text: string, type?: string, importance?: number) => Promise<MemoryItem>;
24
- recall: (query: string, limit?: number) => Promise<MemoryItem[]>;
30
+ recall: (query: string, limit?: number, threshold?: number) => Promise<MemoryItem[]>;
31
+ list: (limit?: number, offset?: number) => Promise<MemoryItem[]>;
25
32
  clear: () => Promise<void>;
33
+ export: () => Promise<MemoryItem[]>;
34
+ import: (memories: MemoryItem[]) => Promise<void>;
26
35
  };
27
36
 
37
+ /**
38
+ * Initialize the vector engine.
39
+ */
28
40
  declare const initVectorEngine: () => Promise<void>;
41
+ /**
42
+ * Generate embeddings using Transformers.js.
43
+ */
29
44
  declare const generateEmbedding: (text: string) => Promise<number[]>;
30
45
 
31
46
  export { type IBrowserMemory, createBrowserCortex, createBrowserMemory, createCortex, createMemory, generateEmbedding, initVectorEngine };
package/dist/index.js CHANGED
@@ -40,7 +40,6 @@ __export(index_exports, {
40
40
  module.exports = __toCommonJS(index_exports);
41
41
 
42
42
  // src/cortex.ts
43
- var import_web_llm = require("@mlc-ai/web-llm");
44
43
  var import_meta = {};
45
44
  var DEFAULT_MODEL = "smollm2-135m";
46
45
  var MODEL_ALIASES = {
@@ -50,39 +49,57 @@ var MODEL_ALIASES = {
50
49
  "llama3-8b": "Llama-3.1-8B-Instruct-q4f16_1-MLC"
51
50
  };
52
51
  var resolveModelId = (alias) => MODEL_ALIASES[alias] ?? alias;
52
+ var yieldTokens = async function* (iterator) {
53
+ const { value, done } = await iterator.next();
54
+ if (done) return;
55
+ const content = value.choices[0]?.delta?.content || "";
56
+ if (content) yield content;
57
+ yield* yieldTokens(iterator);
58
+ };
53
59
  var createBrowserCortex = (config = {}) => {
54
60
  const friendlyModel = config.model || DEFAULT_MODEL;
55
- let engine = null;
56
- let status = {
57
- id: "browser-init",
58
- model: friendlyModel,
59
- ready: false,
60
- engine: "web-llm"
61
+ const modelId = resolveModelId(friendlyModel);
62
+ let _state = {
63
+ engine: null,
64
+ status: {
65
+ id: "browser-init",
66
+ model: friendlyModel,
67
+ ready: false,
68
+ engine: "web-llm"
69
+ }
61
70
  };
62
71
  const init = async (onProgress) => {
63
- if (status.ready) return status;
72
+ if (_state.status.ready) return _state.status;
73
+ if (typeof window === "undefined") {
74
+ throw new Error("BrowserCortex requires a browser environment");
75
+ }
76
+ const { CreateWebWorkerMLCEngine } = await import("@mlc-ai/web-llm");
64
77
  const initProgressCallback = (report) => {
65
78
  const match = report.text?.match(/(\d+)%/);
66
- if (onProgress && match) {
67
- onProgress(parseInt(match[1], 10));
68
- }
79
+ if (onProgress && match) onProgress(parseInt(match[1], 10));
69
80
  };
70
- const modelId = resolveModelId(friendlyModel);
71
- engine = await (0, import_web_llm.CreateWebWorkerMLCEngine)(
81
+ const engine = await CreateWebWorkerMLCEngine(
72
82
  new Worker(new URL("./worker.js", import_meta.url), { type: "module" }),
73
83
  modelId,
74
84
  { initProgressCallback }
75
85
  );
76
- status = {
77
- id: `ctx_web_${Date.now()}`,
78
- model: modelId,
79
- ready: true,
80
- engine: "web-llm"
86
+ _state = {
87
+ engine,
88
+ status: {
89
+ id: `ctx_web_${Date.now()}`,
90
+ model: modelId,
91
+ ready: true,
92
+ engine: "web-llm"
93
+ }
81
94
  };
82
- return status;
95
+ return _state.status;
96
+ };
97
+ const ensureReady = async () => {
98
+ if (!_state.status.ready) await init();
99
+ return _state;
83
100
  };
84
101
  const complete = async (prompt, options = {}) => {
85
- if (!status.ready) await init();
102
+ const { engine } = await ensureReady();
86
103
  const reply = await engine.chat.completions.create({
87
104
  messages: [{ role: "user", content: prompt }],
88
105
  max_gen_len: options.maxTokens,
@@ -91,43 +108,37 @@ var createBrowserCortex = (config = {}) => {
91
108
  return reply.choices[0].message.content || "";
92
109
  };
93
110
  const completeStream = async function* (prompt, options = {}) {
94
- if (!status.ready) await init();
111
+ const { engine } = await ensureReady();
95
112
  const chunks = await engine.chat.completions.create({
96
113
  messages: [{ role: "user", content: prompt }],
97
114
  max_gen_len: options.maxTokens,
98
115
  temperature: options.temperature,
99
116
  stream: true
100
117
  });
101
- for await (const chunk of chunks) {
102
- const content = chunk.choices[0]?.delta?.content || "";
103
- if (content) yield content;
104
- }
105
- };
106
- return {
107
- init,
108
- complete,
109
- completeStream
118
+ yield* yieldTokens(chunks[Symbol.asyncIterator]());
110
119
  };
120
+ return { init, complete, completeStream };
111
121
  };
112
122
  var createCortex = (config = {}) => createBrowserCortex(config);
113
123
 
114
124
  // src/memory.ts
115
- var import_orama = require("@orama/orama");
125
+ var import_core2 = require("@forbocai/core");
116
126
 
117
127
  // src/vector.ts
118
- var embedder = null;
119
- var initVectorEngine = async () => {
120
- if (embedder) return;
121
- try {
122
- const { pipeline } = await import("@huggingface/transformers");
123
- embedder = await pipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2");
124
- } catch (e) {
125
- console.error("Failed to init Browser Vector Engine:", e);
128
+ var import_core = require("@forbocai/core");
129
+ var getEmbedder = (0, import_core.memoiseAsync)(async () => {
130
+ if (typeof window === "undefined") {
131
+ throw new Error("BrowserVectorEngine requires a browser environment");
126
132
  }
133
+ const { pipeline } = await import("@huggingface/transformers");
134
+ return pipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2");
135
+ });
136
+ var initVectorEngine = async () => {
137
+ await getEmbedder();
127
138
  };
128
139
  var generateEmbedding = async (text) => {
129
- if (!embedder) await initVectorEngine();
130
140
  try {
141
+ const embedder = await getEmbedder();
131
142
  const result = await embedder(text, { pooling: "mean", normalize: true });
132
143
  return Array.from(result.data);
133
144
  } catch (e) {
@@ -138,10 +149,12 @@ var generateEmbedding = async (text) => {
138
149
 
139
150
  // src/memory.ts
140
151
  var createBrowserMemory = (config = {}) => {
141
- let db = null;
142
- const init = async () => {
143
- if (db) return db;
144
- db = await (0, import_orama.create)({
152
+ const getDb = (0, import_core2.memoiseAsync)(async () => {
153
+ if (typeof window === "undefined") {
154
+ throw new Error("BrowserMemory requires a browser environment");
155
+ }
156
+ const { create } = await import("@orama/orama");
157
+ return create({
145
158
  schema: {
146
159
  id: "string",
147
160
  text: "string",
@@ -149,13 +162,11 @@ var createBrowserMemory = (config = {}) => {
149
162
  type: "string",
150
163
  importance: "number",
151
164
  embedding: "vector[384]"
152
- // all-MiniLM-L6-v2
153
165
  }
154
166
  });
155
- return db;
156
- };
167
+ });
157
168
  const store = async (text, type = "observation", importance = 0.5) => {
158
- const instance = await init();
169
+ const instance = await getDb();
159
170
  const item = {
160
171
  id: `mem_br_${Date.now()}_${Math.random().toString(36).substring(7)}`,
161
172
  text,
@@ -164,30 +175,35 @@ var createBrowserMemory = (config = {}) => {
164
175
  importance
165
176
  };
166
177
  const embedding = await generateEmbedding(text);
167
- await (0, import_orama.insert)(instance, {
168
- ...item,
169
- embedding
170
- });
178
+ const { insert } = await import("@orama/orama");
179
+ await insert(instance, { ...item, embedding });
171
180
  return item;
172
181
  };
173
- const recall = async (query, limit = 5) => {
174
- const instance = await init();
182
+ const recall = async (query, limit = 5, threshold) => {
183
+ const instance = await getDb();
175
184
  const embedding = await generateEmbedding(query);
176
- const results = await (0, import_orama.search)(instance, {
185
+ const { search } = await import("@orama/orama");
186
+ const results = await search(instance, {
177
187
  mode: "vector",
178
- vector: {
179
- value: embedding,
180
- property: "embedding"
181
- },
182
- similarity: 0.5,
188
+ vector: { value: embedding, property: "embedding" },
189
+ similarity: threshold ?? 0.5,
183
190
  limit
184
191
  });
185
192
  return results.hits.map((hit) => hit.document);
186
193
  };
194
+ const list = async (limit = 50, offset = 0) => {
195
+ const instance = await getDb();
196
+ const { search } = await import("@orama/orama");
197
+ const results = await search(instance, { term: "", limit: limit + offset });
198
+ return results.hits.slice(offset).map((hit) => hit.document);
199
+ };
187
200
  const clear = async () => {
188
- db = null;
189
201
  };
190
- return { store, recall, clear };
202
+ const exportMemories = async () => list(1e4);
203
+ const importMemories = async (memories) => {
204
+ await Promise.all(memories.map((m) => store(m.text, m.type, m.importance)));
205
+ };
206
+ return { store, recall, list, clear, export: exportMemories, import: importMemories };
191
207
  };
192
208
  var createMemory = (config = {}) => createBrowserMemory(config);
193
209
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  // src/cortex.ts
2
- import { CreateWebWorkerMLCEngine } from "@mlc-ai/web-llm";
3
2
  var DEFAULT_MODEL = "smollm2-135m";
4
3
  var MODEL_ALIASES = {
5
4
  "smollm2-135m": "SmolLM2-135M-Instruct-q0f16-MLC",
@@ -8,39 +7,57 @@ var MODEL_ALIASES = {
8
7
  "llama3-8b": "Llama-3.1-8B-Instruct-q4f16_1-MLC"
9
8
  };
10
9
  var resolveModelId = (alias) => MODEL_ALIASES[alias] ?? alias;
10
+ var yieldTokens = async function* (iterator) {
11
+ const { value, done } = await iterator.next();
12
+ if (done) return;
13
+ const content = value.choices[0]?.delta?.content || "";
14
+ if (content) yield content;
15
+ yield* yieldTokens(iterator);
16
+ };
11
17
  var createBrowserCortex = (config = {}) => {
12
18
  const friendlyModel = config.model || DEFAULT_MODEL;
13
- let engine = null;
14
- let status = {
15
- id: "browser-init",
16
- model: friendlyModel,
17
- ready: false,
18
- engine: "web-llm"
19
+ const modelId = resolveModelId(friendlyModel);
20
+ let _state = {
21
+ engine: null,
22
+ status: {
23
+ id: "browser-init",
24
+ model: friendlyModel,
25
+ ready: false,
26
+ engine: "web-llm"
27
+ }
19
28
  };
20
29
  const init = async (onProgress) => {
21
- if (status.ready) return status;
30
+ if (_state.status.ready) return _state.status;
31
+ if (typeof window === "undefined") {
32
+ throw new Error("BrowserCortex requires a browser environment");
33
+ }
34
+ const { CreateWebWorkerMLCEngine } = await import("@mlc-ai/web-llm");
22
35
  const initProgressCallback = (report) => {
23
36
  const match = report.text?.match(/(\d+)%/);
24
- if (onProgress && match) {
25
- onProgress(parseInt(match[1], 10));
26
- }
37
+ if (onProgress && match) onProgress(parseInt(match[1], 10));
27
38
  };
28
- const modelId = resolveModelId(friendlyModel);
29
- engine = await CreateWebWorkerMLCEngine(
39
+ const engine = await CreateWebWorkerMLCEngine(
30
40
  new Worker(new URL("./worker.js", import.meta.url), { type: "module" }),
31
41
  modelId,
32
42
  { initProgressCallback }
33
43
  );
34
- status = {
35
- id: `ctx_web_${Date.now()}`,
36
- model: modelId,
37
- ready: true,
38
- engine: "web-llm"
44
+ _state = {
45
+ engine,
46
+ status: {
47
+ id: `ctx_web_${Date.now()}`,
48
+ model: modelId,
49
+ ready: true,
50
+ engine: "web-llm"
51
+ }
39
52
  };
40
- return status;
53
+ return _state.status;
54
+ };
55
+ const ensureReady = async () => {
56
+ if (!_state.status.ready) await init();
57
+ return _state;
41
58
  };
42
59
  const complete = async (prompt, options = {}) => {
43
- if (!status.ready) await init();
60
+ const { engine } = await ensureReady();
44
61
  const reply = await engine.chat.completions.create({
45
62
  messages: [{ role: "user", content: prompt }],
46
63
  max_gen_len: options.maxTokens,
@@ -49,43 +66,37 @@ var createBrowserCortex = (config = {}) => {
49
66
  return reply.choices[0].message.content || "";
50
67
  };
51
68
  const completeStream = async function* (prompt, options = {}) {
52
- if (!status.ready) await init();
69
+ const { engine } = await ensureReady();
53
70
  const chunks = await engine.chat.completions.create({
54
71
  messages: [{ role: "user", content: prompt }],
55
72
  max_gen_len: options.maxTokens,
56
73
  temperature: options.temperature,
57
74
  stream: true
58
75
  });
59
- for await (const chunk of chunks) {
60
- const content = chunk.choices[0]?.delta?.content || "";
61
- if (content) yield content;
62
- }
63
- };
64
- return {
65
- init,
66
- complete,
67
- completeStream
76
+ yield* yieldTokens(chunks[Symbol.asyncIterator]());
68
77
  };
78
+ return { init, complete, completeStream };
69
79
  };
70
80
  var createCortex = (config = {}) => createBrowserCortex(config);
71
81
 
72
82
  // src/memory.ts
73
- import { create, insert, search } from "@orama/orama";
83
+ import { memoiseAsync as memoiseAsync2 } from "@forbocai/core";
74
84
 
75
85
  // src/vector.ts
76
- var embedder = null;
77
- var initVectorEngine = async () => {
78
- if (embedder) return;
79
- try {
80
- const { pipeline } = await import("@huggingface/transformers");
81
- embedder = await pipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2");
82
- } catch (e) {
83
- console.error("Failed to init Browser Vector Engine:", e);
86
+ import { memoiseAsync } from "@forbocai/core";
87
+ var getEmbedder = memoiseAsync(async () => {
88
+ if (typeof window === "undefined") {
89
+ throw new Error("BrowserVectorEngine requires a browser environment");
84
90
  }
91
+ const { pipeline } = await import("@huggingface/transformers");
92
+ return pipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2");
93
+ });
94
+ var initVectorEngine = async () => {
95
+ await getEmbedder();
85
96
  };
86
97
  var generateEmbedding = async (text) => {
87
- if (!embedder) await initVectorEngine();
88
98
  try {
99
+ const embedder = await getEmbedder();
89
100
  const result = await embedder(text, { pooling: "mean", normalize: true });
90
101
  return Array.from(result.data);
91
102
  } catch (e) {
@@ -96,10 +107,12 @@ var generateEmbedding = async (text) => {
96
107
 
97
108
  // src/memory.ts
98
109
  var createBrowserMemory = (config = {}) => {
99
- let db = null;
100
- const init = async () => {
101
- if (db) return db;
102
- db = await create({
110
+ const getDb = memoiseAsync2(async () => {
111
+ if (typeof window === "undefined") {
112
+ throw new Error("BrowserMemory requires a browser environment");
113
+ }
114
+ const { create } = await import("@orama/orama");
115
+ return create({
103
116
  schema: {
104
117
  id: "string",
105
118
  text: "string",
@@ -107,13 +120,11 @@ var createBrowserMemory = (config = {}) => {
107
120
  type: "string",
108
121
  importance: "number",
109
122
  embedding: "vector[384]"
110
- // all-MiniLM-L6-v2
111
123
  }
112
124
  });
113
- return db;
114
- };
125
+ });
115
126
  const store = async (text, type = "observation", importance = 0.5) => {
116
- const instance = await init();
127
+ const instance = await getDb();
117
128
  const item = {
118
129
  id: `mem_br_${Date.now()}_${Math.random().toString(36).substring(7)}`,
119
130
  text,
@@ -122,30 +133,35 @@ var createBrowserMemory = (config = {}) => {
122
133
  importance
123
134
  };
124
135
  const embedding = await generateEmbedding(text);
125
- await insert(instance, {
126
- ...item,
127
- embedding
128
- });
136
+ const { insert } = await import("@orama/orama");
137
+ await insert(instance, { ...item, embedding });
129
138
  return item;
130
139
  };
131
- const recall = async (query, limit = 5) => {
132
- const instance = await init();
140
+ const recall = async (query, limit = 5, threshold) => {
141
+ const instance = await getDb();
133
142
  const embedding = await generateEmbedding(query);
143
+ const { search } = await import("@orama/orama");
134
144
  const results = await search(instance, {
135
145
  mode: "vector",
136
- vector: {
137
- value: embedding,
138
- property: "embedding"
139
- },
140
- similarity: 0.5,
146
+ vector: { value: embedding, property: "embedding" },
147
+ similarity: threshold ?? 0.5,
141
148
  limit
142
149
  });
143
150
  return results.hits.map((hit) => hit.document);
144
151
  };
152
+ const list = async (limit = 50, offset = 0) => {
153
+ const instance = await getDb();
154
+ const { search } = await import("@orama/orama");
155
+ const results = await search(instance, { term: "", limit: limit + offset });
156
+ return results.hits.slice(offset).map((hit) => hit.document);
157
+ };
145
158
  const clear = async () => {
146
- db = null;
147
159
  };
148
- return { store, recall, clear };
160
+ const exportMemories = async () => list(1e4);
161
+ const importMemories = async (memories) => {
162
+ await Promise.all(memories.map((m) => store(m.text, m.type, m.importance)));
163
+ };
164
+ return { store, recall, list, clear, export: exportMemories, import: importMemories };
149
165
  };
150
166
  var createMemory = (config = {}) => createBrowserMemory(config);
151
167
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forbocai/browser",
3
- "version": "0.5.6",
3
+ "version": "0.5.8",
4
4
  "license": "UNLICENSED",
5
5
  "description": "Web Browser implementation for ForbocAI SDK",
6
6
  "main": "dist/index.js",
@@ -12,7 +12,7 @@
12
12
  "test": "vitest"
13
13
  },
14
14
  "dependencies": {
15
- "@forbocai/core": "^0.5.6",
15
+ "@forbocai/core": "^0.5.8",
16
16
  "@mlc-ai/web-llm": "^0.2.46",
17
17
  "@orama/orama": "^2.0.26",
18
18
  "@huggingface/transformers": "^3.0.0"