@forbocai/node 0.4.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.
@@ -0,0 +1,107 @@
1
+ import { CortexConfig, ICortex, MemoryType, MemoryItem, MemoryConfig } from '@forbocai/core';
2
+
3
+ declare const createCortex: (config: CortexConfig) => ICortex & {
4
+ embed: (text: string) => Promise<number[]>;
5
+ };
6
+
7
+ /**
8
+ * Interface definition for Memory operations.
9
+ */
10
+ interface IMemory {
11
+ /**
12
+ * Stores a text memory.
13
+ * @param text - The content of the memory.
14
+ * @param type - The type of memory (e.g., 'observation').
15
+ * @param importance - The importance score (0-1).
16
+ * @returns A promise resolving to the stored MemoryItem.
17
+ */
18
+ store(text: string, type?: MemoryType, importance?: number): Promise<MemoryItem>;
19
+ /**
20
+ * Recalls memories relevant to a query.
21
+ * @param query - The query string.
22
+ * @param limit - Maximum number of memories to return.
23
+ * @returns A promise resolving to an array of relevant MemoryItems.
24
+ */
25
+ recall(query: string, limit?: number): Promise<MemoryItem[]>;
26
+ /**
27
+ * Lists recent memories.
28
+ * @param limit - Maximum number of memories to list.
29
+ * @param offset - Offset for pagination.
30
+ * @returns A promise resolving to an array of MemoryItems.
31
+ */
32
+ list(limit?: number, offset?: number): Promise<MemoryItem[]>;
33
+ /**
34
+ * Exports all memories (for Soul portability/backup).
35
+ * @returns A promise resolving to an array of all MemoryItems.
36
+ */
37
+ export(): Promise<MemoryItem[]>;
38
+ /**
39
+ * Imports memories (for Soul hydration/restore).
40
+ * @param memories - Array of MemoryItems to import.
41
+ */
42
+ import(memories: MemoryItem[]): Promise<void>;
43
+ /**
44
+ * Clears all stored memories.
45
+ */
46
+ clear(): Promise<void>;
47
+ }
48
+ /**
49
+ * Configuration for the Memory module.
50
+ */
51
+ interface MemoryModuleConfig extends MemoryConfig {
52
+ /** Key to use for storage/table name. */
53
+ storageKey?: string;
54
+ /** Optional API URL for remote operations. */
55
+ apiUrl?: string;
56
+ /** ID of the agent owning this memory. */
57
+ agentId?: string;
58
+ }
59
+ /**
60
+ * Helper to create a standard MemoryItem object.
61
+ * @param text - The memory content.
62
+ * @param type - The type of memory.
63
+ * @param importance - Importance score (0-1).
64
+ * @returns A formatted MemoryItem.
65
+ */
66
+ declare const createMemoryItem: (text: string, type?: MemoryType, importance?: number) => MemoryItem;
67
+ /**
68
+ * Factory function to create a Memory module instance (LanceDB backed).
69
+ * @param config - Configuration for the memory module.
70
+ * @returns An instance of IMemory.
71
+ */
72
+ declare const createMemory: (config?: MemoryModuleConfig) => IMemory;
73
+
74
+ /**
75
+ * Status of the Vector Engine.
76
+ */
77
+ interface VectorStatus {
78
+ ready: boolean;
79
+ backend: 'lancedb' | 'memory';
80
+ }
81
+ /**
82
+ * Initializes the vector engine (Transformers + LanceDB).
83
+ */
84
+ declare const initVectorEngine: () => Promise<void>;
85
+ /**
86
+ * Generates an embedding vector for the given text.
87
+ * @param text - The text to embed.
88
+ * @returns A promise resolving to the embedding vector (number array).
89
+ */
90
+ declare const generateEmbedding: (text: string) => Promise<number[]>;
91
+ /**
92
+ * Retrieves or creates a table in LanceDB.
93
+ * @param dbPath - Path to the LanceDB directory.
94
+ * @param tableName - Name of the table.
95
+ * @returns The table object or null if not found/created.
96
+ */
97
+ declare const getVectorTable: (dbPath: string, tableName?: string) => Promise<any>;
98
+ /**
99
+ * Creates a new table in LanceDB.
100
+ * @param dbPath - Path to the LanceDB directory.
101
+ * @param tableName - Name of the table.
102
+ * @param data - Initial data to populate the table.
103
+ * @returns The created table object.
104
+ */
105
+ declare const createTable: (dbPath: string, tableName: string, data: any[]) => Promise<any>;
106
+
107
+ export { type IMemory, type MemoryModuleConfig, type VectorStatus, createCortex, createMemory, createMemoryItem, createTable, generateEmbedding, getVectorTable, initVectorEngine };
@@ -0,0 +1,107 @@
1
+ import { CortexConfig, ICortex, MemoryType, MemoryItem, MemoryConfig } from '@forbocai/core';
2
+
3
+ declare const createCortex: (config: CortexConfig) => ICortex & {
4
+ embed: (text: string) => Promise<number[]>;
5
+ };
6
+
7
+ /**
8
+ * Interface definition for Memory operations.
9
+ */
10
+ interface IMemory {
11
+ /**
12
+ * Stores a text memory.
13
+ * @param text - The content of the memory.
14
+ * @param type - The type of memory (e.g., 'observation').
15
+ * @param importance - The importance score (0-1).
16
+ * @returns A promise resolving to the stored MemoryItem.
17
+ */
18
+ store(text: string, type?: MemoryType, importance?: number): Promise<MemoryItem>;
19
+ /**
20
+ * Recalls memories relevant to a query.
21
+ * @param query - The query string.
22
+ * @param limit - Maximum number of memories to return.
23
+ * @returns A promise resolving to an array of relevant MemoryItems.
24
+ */
25
+ recall(query: string, limit?: number): Promise<MemoryItem[]>;
26
+ /**
27
+ * Lists recent memories.
28
+ * @param limit - Maximum number of memories to list.
29
+ * @param offset - Offset for pagination.
30
+ * @returns A promise resolving to an array of MemoryItems.
31
+ */
32
+ list(limit?: number, offset?: number): Promise<MemoryItem[]>;
33
+ /**
34
+ * Exports all memories (for Soul portability/backup).
35
+ * @returns A promise resolving to an array of all MemoryItems.
36
+ */
37
+ export(): Promise<MemoryItem[]>;
38
+ /**
39
+ * Imports memories (for Soul hydration/restore).
40
+ * @param memories - Array of MemoryItems to import.
41
+ */
42
+ import(memories: MemoryItem[]): Promise<void>;
43
+ /**
44
+ * Clears all stored memories.
45
+ */
46
+ clear(): Promise<void>;
47
+ }
48
+ /**
49
+ * Configuration for the Memory module.
50
+ */
51
+ interface MemoryModuleConfig extends MemoryConfig {
52
+ /** Key to use for storage/table name. */
53
+ storageKey?: string;
54
+ /** Optional API URL for remote operations. */
55
+ apiUrl?: string;
56
+ /** ID of the agent owning this memory. */
57
+ agentId?: string;
58
+ }
59
+ /**
60
+ * Helper to create a standard MemoryItem object.
61
+ * @param text - The memory content.
62
+ * @param type - The type of memory.
63
+ * @param importance - Importance score (0-1).
64
+ * @returns A formatted MemoryItem.
65
+ */
66
+ declare const createMemoryItem: (text: string, type?: MemoryType, importance?: number) => MemoryItem;
67
+ /**
68
+ * Factory function to create a Memory module instance (LanceDB backed).
69
+ * @param config - Configuration for the memory module.
70
+ * @returns An instance of IMemory.
71
+ */
72
+ declare const createMemory: (config?: MemoryModuleConfig) => IMemory;
73
+
74
+ /**
75
+ * Status of the Vector Engine.
76
+ */
77
+ interface VectorStatus {
78
+ ready: boolean;
79
+ backend: 'lancedb' | 'memory';
80
+ }
81
+ /**
82
+ * Initializes the vector engine (Transformers + LanceDB).
83
+ */
84
+ declare const initVectorEngine: () => Promise<void>;
85
+ /**
86
+ * Generates an embedding vector for the given text.
87
+ * @param text - The text to embed.
88
+ * @returns A promise resolving to the embedding vector (number array).
89
+ */
90
+ declare const generateEmbedding: (text: string) => Promise<number[]>;
91
+ /**
92
+ * Retrieves or creates a table in LanceDB.
93
+ * @param dbPath - Path to the LanceDB directory.
94
+ * @param tableName - Name of the table.
95
+ * @returns The table object or null if not found/created.
96
+ */
97
+ declare const getVectorTable: (dbPath: string, tableName?: string) => Promise<any>;
98
+ /**
99
+ * Creates a new table in LanceDB.
100
+ * @param dbPath - Path to the LanceDB directory.
101
+ * @param tableName - Name of the table.
102
+ * @param data - Initial data to populate the table.
103
+ * @returns The created table object.
104
+ */
105
+ declare const createTable: (dbPath: string, tableName: string, data: any[]) => Promise<any>;
106
+
107
+ export { type IMemory, type MemoryModuleConfig, type VectorStatus, createCortex, createMemory, createMemoryItem, createTable, generateEmbedding, getVectorTable, initVectorEngine };
package/dist/index.js ADDED
@@ -0,0 +1,380 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ createCortex: () => createCortex,
34
+ createMemory: () => createMemory,
35
+ createMemoryItem: () => createMemoryItem,
36
+ createTable: () => createTable,
37
+ generateEmbedding: () => generateEmbedding,
38
+ getVectorTable: () => getVectorTable,
39
+ initVectorEngine: () => initVectorEngine
40
+ });
41
+ module.exports = __toCommonJS(index_exports);
42
+
43
+ // src/cortex.ts
44
+ var fs = __toESM(require("fs"));
45
+ var path = __toESM(require("path"));
46
+ var https = __toESM(require("https"));
47
+ var isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
48
+ if (!isNode) {
49
+ throw new Error("ForbocAI SDK requires Node.js environment - browser support has been removed");
50
+ }
51
+ var MODEL_URLS = {
52
+ "smollm2-135m": "https://huggingface.co/bartowski/SmolLM2-135M-Instruct-GGUF/resolve/main/SmolLM2-135M-Instruct-Q4_K_M.gguf",
53
+ "llama3-8b": "https://huggingface.co/lmstudio-community/Meta-Llama-3-8B-Instruct-GGUF/resolve/main/Meta-Llama-3-8B-Instruct-Q4_K_M.gguf"
54
+ };
55
+ var DEFAULT_MODEL = "smollm2-135m";
56
+ var downloadFile = (url, destPath) => {
57
+ return new Promise((resolve, reject) => {
58
+ const file = fs.createWriteStream(destPath);
59
+ https.get(url, (response) => {
60
+ if (response.statusCode === 302 || response.statusCode === 301) {
61
+ downloadFile(response.headers.location, destPath).then(resolve).catch(reject);
62
+ return;
63
+ }
64
+ if (response.statusCode !== 200) {
65
+ reject(new Error(`Failed to download: ${response.statusCode}`));
66
+ return;
67
+ }
68
+ response.pipe(file);
69
+ file.on("finish", () => {
70
+ file.close();
71
+ resolve();
72
+ });
73
+ }).on("error", (err) => {
74
+ fs.unlink(destPath, () => {
75
+ });
76
+ reject(err);
77
+ });
78
+ });
79
+ };
80
+ var createNativeCortex = (config) => {
81
+ let status = {
82
+ id: "native-init",
83
+ model: config.model || DEFAULT_MODEL,
84
+ ready: false,
85
+ engine: "node-llama-cpp"
86
+ };
87
+ let llama;
88
+ let model;
89
+ let context;
90
+ let session;
91
+ let featureExtraction = null;
92
+ const MODELS_DIR = path.join(process.cwd(), "local_infrastructure", "models");
93
+ const init = async () => {
94
+ if (status.ready) return status;
95
+ try {
96
+ console.log("> Initializing Native Cortex...");
97
+ console.log("> Loading Embedding Model (all-MiniLM-L6-v2)...");
98
+ const { pipeline: pipeline2 } = await import("@xenova/transformers");
99
+ featureExtraction = await pipeline2("feature-extraction", "Xenova/all-MiniLM-L6-v2");
100
+ const ensureDirectoryExists = (dirPath) => {
101
+ if (!fs.existsSync(dirPath)) fs.mkdirSync(dirPath, { recursive: true });
102
+ };
103
+ ensureDirectoryExists(MODELS_DIR);
104
+ const modelKey = config.model || DEFAULT_MODEL;
105
+ const modelUrl = MODEL_URLS[modelKey] || MODEL_URLS[DEFAULT_MODEL];
106
+ const modelFileName = path.basename(modelUrl);
107
+ const modelPath = path.join(MODELS_DIR, modelFileName);
108
+ if (!fs.existsSync(modelPath)) {
109
+ console.log(`> Downloading SLM: ${modelKey}...`);
110
+ await downloadFile(modelUrl, modelPath);
111
+ console.log(`> Download complete.`);
112
+ }
113
+ const { getLlama, LlamaChatSession } = await import("node-llama-cpp");
114
+ llama = await getLlama();
115
+ console.log("> Loading SLM into memory...");
116
+ model = await llama.loadModel({
117
+ modelPath,
118
+ gpuLayers: config.gpu ? 99 : 0
119
+ });
120
+ context = await model.createContext();
121
+ session = new LlamaChatSession({
122
+ contextSequence: context.getSequence()
123
+ });
124
+ status = {
125
+ id: `ctx_${Date.now()}`,
126
+ model: modelKey,
127
+ ready: true,
128
+ engine: "node-llama-cpp"
129
+ };
130
+ console.log("> Cortex Ready.");
131
+ return status;
132
+ } catch (e) {
133
+ console.error("Failed to initialize Native Cortex:", e);
134
+ throw e;
135
+ }
136
+ };
137
+ const complete = async (prompt, options = {}) => {
138
+ if (!status.ready) await init();
139
+ return await session.prompt(prompt, {
140
+ maxTokens: options.maxTokens,
141
+ temperature: options.temperature
142
+ });
143
+ };
144
+ const completeStream = async function* (prompt, options = {}) {
145
+ if (!status.ready) await init();
146
+ const tokenQueue = [];
147
+ let resolveToken = null;
148
+ let done = false;
149
+ session.prompt(prompt, {
150
+ maxTokens: options.maxTokens,
151
+ temperature: options.temperature,
152
+ onToken: (token) => {
153
+ tokenQueue.push(token);
154
+ if (resolveToken) {
155
+ resolveToken();
156
+ resolveToken = null;
157
+ }
158
+ }
159
+ }).then(() => {
160
+ done = true;
161
+ if (resolveToken) {
162
+ resolveToken();
163
+ resolveToken = null;
164
+ }
165
+ }).catch((e) => {
166
+ console.error("Stream failed:", e);
167
+ done = true;
168
+ if (resolveToken) {
169
+ resolveToken();
170
+ resolveToken = null;
171
+ }
172
+ });
173
+ while (!done || tokenQueue.length > 0) {
174
+ if (tokenQueue.length === 0) {
175
+ await new Promise((resolve) => {
176
+ resolveToken = resolve;
177
+ });
178
+ }
179
+ while (tokenQueue.length > 0) {
180
+ yield tokenQueue.shift();
181
+ }
182
+ }
183
+ };
184
+ const embed = async (text) => {
185
+ if (!status.ready) await init();
186
+ try {
187
+ const output = await featureExtraction(text, { pooling: "mean", normalize: true });
188
+ return Array.from(output.data);
189
+ } catch (e) {
190
+ console.error("Embedding failed:", e);
191
+ return new Array(384).fill(0);
192
+ }
193
+ };
194
+ return {
195
+ init,
196
+ complete,
197
+ completeStream,
198
+ embed
199
+ };
200
+ };
201
+ var createCortex = (config) => createNativeCortex(config);
202
+
203
+ // src/memory.ts
204
+ var path3 = __toESM(require("path"));
205
+
206
+ // src/vector.ts
207
+ var path2 = __toESM(require("path"));
208
+ var fs2 = __toESM(require("fs"));
209
+ var pipeline;
210
+ var lancedb;
211
+ var initVectorEngine = async () => {
212
+ if (pipeline) return;
213
+ try {
214
+ console.log("> Initializing Vector Engine (Transformers)...");
215
+ const transformers = await import("@xenova/transformers");
216
+ transformers.env.cacheDir = path2.join(process.env.HOME || ".", ".forbocai", "cache");
217
+ pipeline = await transformers.pipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2");
218
+ console.log("> Initializing LanceDB...");
219
+ lancedb = await import("@lancedb/lancedb");
220
+ } catch (e) {
221
+ console.error("Failed to init Vector Engine:", e);
222
+ }
223
+ };
224
+ var generateEmbedding = async (text) => {
225
+ try {
226
+ if (!pipeline) await initVectorEngine();
227
+ const output = await pipeline(text, { pooling: "mean", normalize: true });
228
+ return Array.from(output.data);
229
+ } catch (e) {
230
+ console.warn("Transformers embedding failed, falling back to Cortex:", e);
231
+ const cortexConfig = {
232
+ model: "smollm2-135m",
233
+ temperature: 0.7,
234
+ maxTokens: 128,
235
+ gpu: true
236
+ };
237
+ const cortex = createCortex(cortexConfig);
238
+ try {
239
+ await cortex.init();
240
+ return await cortex.embed(text);
241
+ } catch (cortexError) {
242
+ console.error("All embedding methods failed:", cortexError);
243
+ return new Array(384).fill(0);
244
+ }
245
+ }
246
+ };
247
+ var getVectorTable = async (dbPath, tableName = "memories") => {
248
+ if (!lancedb) await initVectorEngine();
249
+ if (!fs2.existsSync(dbPath)) fs2.mkdirSync(dbPath, { recursive: true });
250
+ const db = await lancedb.connect(dbPath);
251
+ const tables = await db.tableNames();
252
+ if (tables.includes(tableName)) {
253
+ return await db.openTable(tableName);
254
+ } else {
255
+ return null;
256
+ }
257
+ };
258
+ var createTable = async (dbPath, tableName, data) => {
259
+ if (!lancedb) await initVectorEngine();
260
+ const db = await lancedb.connect(dbPath);
261
+ return await db.createTable(tableName, data);
262
+ };
263
+
264
+ // src/memory.ts
265
+ var createMemoryItem = (text, type = "observation", importance = 0.5) => ({
266
+ id: `mem_${Date.now()}_${Math.random().toString(36).substring(7)}`,
267
+ text,
268
+ timestamp: Date.now(),
269
+ type,
270
+ importance: Math.min(1, Math.max(0, importance))
271
+ });
272
+ var createLanceDBMemory = (config) => {
273
+ const dbName = config.storageKey || "forbocai_vectors";
274
+ const dbPath = path3.join(process.cwd(), "local_infrastructure", "vectors", dbName + ".lance");
275
+ const tableName = "memories";
276
+ let _table = null;
277
+ const getTable = async () => {
278
+ if (_table) return _table;
279
+ _table = await getVectorTable(dbPath, tableName);
280
+ return _table;
281
+ };
282
+ const store = async (text, type = "observation", importance = 0.5) => {
283
+ const item = createMemoryItem(text, type, importance);
284
+ const vector = await generateEmbedding(text);
285
+ const record = {
286
+ ...item,
287
+ vector
288
+ };
289
+ const existingTable = await getTable();
290
+ if (existingTable) {
291
+ await existingTable.add([record]);
292
+ } else {
293
+ _table = await createTable(dbPath, tableName, [record]);
294
+ }
295
+ return item;
296
+ };
297
+ const recall = async (query, limit = 5) => {
298
+ const table = await getTable();
299
+ if (!table) return [];
300
+ const queryVec = await generateEmbedding(query);
301
+ const results = await table.search(queryVec).limit(limit).execute();
302
+ return results.map((r) => ({
303
+ id: r.id,
304
+ text: r.text,
305
+ timestamp: r.timestamp,
306
+ type: r.type,
307
+ importance: r.importance
308
+ }));
309
+ };
310
+ const list = async (limit = 50, offset = 0) => {
311
+ const table = await getTable();
312
+ if (!table) return [];
313
+ const results = await table.query().limit(limit + offset).execute();
314
+ return results.slice(offset).map((r) => ({
315
+ id: r.id,
316
+ text: r.text,
317
+ timestamp: r.timestamp,
318
+ type: r.type,
319
+ importance: r.importance
320
+ }));
321
+ };
322
+ const exportMemories = async () => {
323
+ const table = await getTable();
324
+ if (!table) return [];
325
+ const results = await table.query().execute();
326
+ return results.map((r) => ({
327
+ id: r.id,
328
+ text: r.text,
329
+ timestamp: r.timestamp,
330
+ type: r.type,
331
+ importance: r.importance
332
+ }));
333
+ };
334
+ const importMemories = async (memories) => {
335
+ if (memories.length === 0) return;
336
+ const records = [];
337
+ for (const mem of memories) {
338
+ const vector = await generateEmbedding(mem.text);
339
+ records.push({
340
+ ...mem,
341
+ vector
342
+ });
343
+ }
344
+ const existingTable = await getTable();
345
+ if (existingTable) {
346
+ await existingTable.add(records);
347
+ } else {
348
+ _table = await createTable(dbPath, tableName, records);
349
+ }
350
+ };
351
+ const clear = async () => {
352
+ const tablePath = path3.join(dbPath, tableName + ".lance");
353
+ try {
354
+ const fs3 = await import("fs");
355
+ if (fs3.existsSync(tablePath)) {
356
+ fs3.rmSync(tablePath, { recursive: true, force: true });
357
+ }
358
+ if (fs3.existsSync(dbPath)) {
359
+ fs3.rmSync(dbPath, { recursive: true, force: true });
360
+ }
361
+ _table = null;
362
+ console.log("> Memory cleared successfully");
363
+ } catch (e) {
364
+ console.error("Failed to clear memory:", e);
365
+ throw e;
366
+ }
367
+ };
368
+ return { store, recall, list, export: exportMemories, import: importMemories, clear };
369
+ };
370
+ var createMemory = (config = {}) => createLanceDBMemory(config);
371
+ // Annotate the CommonJS export names for ESM import in node:
372
+ 0 && (module.exports = {
373
+ createCortex,
374
+ createMemory,
375
+ createMemoryItem,
376
+ createTable,
377
+ generateEmbedding,
378
+ getVectorTable,
379
+ initVectorEngine
380
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,337 @@
1
+ // src/cortex.ts
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import * as https from "https";
5
+ var isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
6
+ if (!isNode) {
7
+ throw new Error("ForbocAI SDK requires Node.js environment - browser support has been removed");
8
+ }
9
+ var MODEL_URLS = {
10
+ "smollm2-135m": "https://huggingface.co/bartowski/SmolLM2-135M-Instruct-GGUF/resolve/main/SmolLM2-135M-Instruct-Q4_K_M.gguf",
11
+ "llama3-8b": "https://huggingface.co/lmstudio-community/Meta-Llama-3-8B-Instruct-GGUF/resolve/main/Meta-Llama-3-8B-Instruct-Q4_K_M.gguf"
12
+ };
13
+ var DEFAULT_MODEL = "smollm2-135m";
14
+ var downloadFile = (url, destPath) => {
15
+ return new Promise((resolve, reject) => {
16
+ const file = fs.createWriteStream(destPath);
17
+ https.get(url, (response) => {
18
+ if (response.statusCode === 302 || response.statusCode === 301) {
19
+ downloadFile(response.headers.location, destPath).then(resolve).catch(reject);
20
+ return;
21
+ }
22
+ if (response.statusCode !== 200) {
23
+ reject(new Error(`Failed to download: ${response.statusCode}`));
24
+ return;
25
+ }
26
+ response.pipe(file);
27
+ file.on("finish", () => {
28
+ file.close();
29
+ resolve();
30
+ });
31
+ }).on("error", (err) => {
32
+ fs.unlink(destPath, () => {
33
+ });
34
+ reject(err);
35
+ });
36
+ });
37
+ };
38
+ var createNativeCortex = (config) => {
39
+ let status = {
40
+ id: "native-init",
41
+ model: config.model || DEFAULT_MODEL,
42
+ ready: false,
43
+ engine: "node-llama-cpp"
44
+ };
45
+ let llama;
46
+ let model;
47
+ let context;
48
+ let session;
49
+ let featureExtraction = null;
50
+ const MODELS_DIR = path.join(process.cwd(), "local_infrastructure", "models");
51
+ const init = async () => {
52
+ if (status.ready) return status;
53
+ try {
54
+ console.log("> Initializing Native Cortex...");
55
+ console.log("> Loading Embedding Model (all-MiniLM-L6-v2)...");
56
+ const { pipeline: pipeline2 } = await import("@xenova/transformers");
57
+ featureExtraction = await pipeline2("feature-extraction", "Xenova/all-MiniLM-L6-v2");
58
+ const ensureDirectoryExists = (dirPath) => {
59
+ if (!fs.existsSync(dirPath)) fs.mkdirSync(dirPath, { recursive: true });
60
+ };
61
+ ensureDirectoryExists(MODELS_DIR);
62
+ const modelKey = config.model || DEFAULT_MODEL;
63
+ const modelUrl = MODEL_URLS[modelKey] || MODEL_URLS[DEFAULT_MODEL];
64
+ const modelFileName = path.basename(modelUrl);
65
+ const modelPath = path.join(MODELS_DIR, modelFileName);
66
+ if (!fs.existsSync(modelPath)) {
67
+ console.log(`> Downloading SLM: ${modelKey}...`);
68
+ await downloadFile(modelUrl, modelPath);
69
+ console.log(`> Download complete.`);
70
+ }
71
+ const { getLlama, LlamaChatSession } = await import("node-llama-cpp");
72
+ llama = await getLlama();
73
+ console.log("> Loading SLM into memory...");
74
+ model = await llama.loadModel({
75
+ modelPath,
76
+ gpuLayers: config.gpu ? 99 : 0
77
+ });
78
+ context = await model.createContext();
79
+ session = new LlamaChatSession({
80
+ contextSequence: context.getSequence()
81
+ });
82
+ status = {
83
+ id: `ctx_${Date.now()}`,
84
+ model: modelKey,
85
+ ready: true,
86
+ engine: "node-llama-cpp"
87
+ };
88
+ console.log("> Cortex Ready.");
89
+ return status;
90
+ } catch (e) {
91
+ console.error("Failed to initialize Native Cortex:", e);
92
+ throw e;
93
+ }
94
+ };
95
+ const complete = async (prompt, options = {}) => {
96
+ if (!status.ready) await init();
97
+ return await session.prompt(prompt, {
98
+ maxTokens: options.maxTokens,
99
+ temperature: options.temperature
100
+ });
101
+ };
102
+ const completeStream = async function* (prompt, options = {}) {
103
+ if (!status.ready) await init();
104
+ const tokenQueue = [];
105
+ let resolveToken = null;
106
+ let done = false;
107
+ session.prompt(prompt, {
108
+ maxTokens: options.maxTokens,
109
+ temperature: options.temperature,
110
+ onToken: (token) => {
111
+ tokenQueue.push(token);
112
+ if (resolveToken) {
113
+ resolveToken();
114
+ resolveToken = null;
115
+ }
116
+ }
117
+ }).then(() => {
118
+ done = true;
119
+ if (resolveToken) {
120
+ resolveToken();
121
+ resolveToken = null;
122
+ }
123
+ }).catch((e) => {
124
+ console.error("Stream failed:", e);
125
+ done = true;
126
+ if (resolveToken) {
127
+ resolveToken();
128
+ resolveToken = null;
129
+ }
130
+ });
131
+ while (!done || tokenQueue.length > 0) {
132
+ if (tokenQueue.length === 0) {
133
+ await new Promise((resolve) => {
134
+ resolveToken = resolve;
135
+ });
136
+ }
137
+ while (tokenQueue.length > 0) {
138
+ yield tokenQueue.shift();
139
+ }
140
+ }
141
+ };
142
+ const embed = async (text) => {
143
+ if (!status.ready) await init();
144
+ try {
145
+ const output = await featureExtraction(text, { pooling: "mean", normalize: true });
146
+ return Array.from(output.data);
147
+ } catch (e) {
148
+ console.error("Embedding failed:", e);
149
+ return new Array(384).fill(0);
150
+ }
151
+ };
152
+ return {
153
+ init,
154
+ complete,
155
+ completeStream,
156
+ embed
157
+ };
158
+ };
159
+ var createCortex = (config) => createNativeCortex(config);
160
+
161
+ // src/memory.ts
162
+ import * as path3 from "path";
163
+
164
+ // src/vector.ts
165
+ import * as path2 from "path";
166
+ import * as fs2 from "fs";
167
+ var pipeline;
168
+ var lancedb;
169
+ var initVectorEngine = async () => {
170
+ if (pipeline) return;
171
+ try {
172
+ console.log("> Initializing Vector Engine (Transformers)...");
173
+ const transformers = await import("@xenova/transformers");
174
+ transformers.env.cacheDir = path2.join(process.env.HOME || ".", ".forbocai", "cache");
175
+ pipeline = await transformers.pipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2");
176
+ console.log("> Initializing LanceDB...");
177
+ lancedb = await import("@lancedb/lancedb");
178
+ } catch (e) {
179
+ console.error("Failed to init Vector Engine:", e);
180
+ }
181
+ };
182
+ var generateEmbedding = async (text) => {
183
+ try {
184
+ if (!pipeline) await initVectorEngine();
185
+ const output = await pipeline(text, { pooling: "mean", normalize: true });
186
+ return Array.from(output.data);
187
+ } catch (e) {
188
+ console.warn("Transformers embedding failed, falling back to Cortex:", e);
189
+ const cortexConfig = {
190
+ model: "smollm2-135m",
191
+ temperature: 0.7,
192
+ maxTokens: 128,
193
+ gpu: true
194
+ };
195
+ const cortex = createCortex(cortexConfig);
196
+ try {
197
+ await cortex.init();
198
+ return await cortex.embed(text);
199
+ } catch (cortexError) {
200
+ console.error("All embedding methods failed:", cortexError);
201
+ return new Array(384).fill(0);
202
+ }
203
+ }
204
+ };
205
+ var getVectorTable = async (dbPath, tableName = "memories") => {
206
+ if (!lancedb) await initVectorEngine();
207
+ if (!fs2.existsSync(dbPath)) fs2.mkdirSync(dbPath, { recursive: true });
208
+ const db = await lancedb.connect(dbPath);
209
+ const tables = await db.tableNames();
210
+ if (tables.includes(tableName)) {
211
+ return await db.openTable(tableName);
212
+ } else {
213
+ return null;
214
+ }
215
+ };
216
+ var createTable = async (dbPath, tableName, data) => {
217
+ if (!lancedb) await initVectorEngine();
218
+ const db = await lancedb.connect(dbPath);
219
+ return await db.createTable(tableName, data);
220
+ };
221
+
222
+ // src/memory.ts
223
+ var createMemoryItem = (text, type = "observation", importance = 0.5) => ({
224
+ id: `mem_${Date.now()}_${Math.random().toString(36).substring(7)}`,
225
+ text,
226
+ timestamp: Date.now(),
227
+ type,
228
+ importance: Math.min(1, Math.max(0, importance))
229
+ });
230
+ var createLanceDBMemory = (config) => {
231
+ const dbName = config.storageKey || "forbocai_vectors";
232
+ const dbPath = path3.join(process.cwd(), "local_infrastructure", "vectors", dbName + ".lance");
233
+ const tableName = "memories";
234
+ let _table = null;
235
+ const getTable = async () => {
236
+ if (_table) return _table;
237
+ _table = await getVectorTable(dbPath, tableName);
238
+ return _table;
239
+ };
240
+ const store = async (text, type = "observation", importance = 0.5) => {
241
+ const item = createMemoryItem(text, type, importance);
242
+ const vector = await generateEmbedding(text);
243
+ const record = {
244
+ ...item,
245
+ vector
246
+ };
247
+ const existingTable = await getTable();
248
+ if (existingTable) {
249
+ await existingTable.add([record]);
250
+ } else {
251
+ _table = await createTable(dbPath, tableName, [record]);
252
+ }
253
+ return item;
254
+ };
255
+ const recall = async (query, limit = 5) => {
256
+ const table = await getTable();
257
+ if (!table) return [];
258
+ const queryVec = await generateEmbedding(query);
259
+ const results = await table.search(queryVec).limit(limit).execute();
260
+ return results.map((r) => ({
261
+ id: r.id,
262
+ text: r.text,
263
+ timestamp: r.timestamp,
264
+ type: r.type,
265
+ importance: r.importance
266
+ }));
267
+ };
268
+ const list = async (limit = 50, offset = 0) => {
269
+ const table = await getTable();
270
+ if (!table) return [];
271
+ const results = await table.query().limit(limit + offset).execute();
272
+ return results.slice(offset).map((r) => ({
273
+ id: r.id,
274
+ text: r.text,
275
+ timestamp: r.timestamp,
276
+ type: r.type,
277
+ importance: r.importance
278
+ }));
279
+ };
280
+ const exportMemories = async () => {
281
+ const table = await getTable();
282
+ if (!table) return [];
283
+ const results = await table.query().execute();
284
+ return results.map((r) => ({
285
+ id: r.id,
286
+ text: r.text,
287
+ timestamp: r.timestamp,
288
+ type: r.type,
289
+ importance: r.importance
290
+ }));
291
+ };
292
+ const importMemories = async (memories) => {
293
+ if (memories.length === 0) return;
294
+ const records = [];
295
+ for (const mem of memories) {
296
+ const vector = await generateEmbedding(mem.text);
297
+ records.push({
298
+ ...mem,
299
+ vector
300
+ });
301
+ }
302
+ const existingTable = await getTable();
303
+ if (existingTable) {
304
+ await existingTable.add(records);
305
+ } else {
306
+ _table = await createTable(dbPath, tableName, records);
307
+ }
308
+ };
309
+ const clear = async () => {
310
+ const tablePath = path3.join(dbPath, tableName + ".lance");
311
+ try {
312
+ const fs3 = await import("fs");
313
+ if (fs3.existsSync(tablePath)) {
314
+ fs3.rmSync(tablePath, { recursive: true, force: true });
315
+ }
316
+ if (fs3.existsSync(dbPath)) {
317
+ fs3.rmSync(dbPath, { recursive: true, force: true });
318
+ }
319
+ _table = null;
320
+ console.log("> Memory cleared successfully");
321
+ } catch (e) {
322
+ console.error("Failed to clear memory:", e);
323
+ throw e;
324
+ }
325
+ };
326
+ return { store, recall, list, export: exportMemories, import: importMemories, clear };
327
+ };
328
+ var createMemory = (config = {}) => createLanceDBMemory(config);
329
+ export {
330
+ createCortex,
331
+ createMemory,
332
+ createMemoryItem,
333
+ createTable,
334
+ generateEmbedding,
335
+ getVectorTable,
336
+ initVectorEngine
337
+ };
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@forbocai/node",
3
+ "version": "0.4.4",
4
+ "license": "UNLICENSED",
5
+ "description": "Node.js native implementation for ForbocAI SDK",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.mjs",
8
+ "types": "dist/index.d.ts",
9
+ "scripts": {
10
+ "build": "tsup src/index.ts --format cjs,esm --dts",
11
+ "dev": "tsup src/index.ts --watch",
12
+ "test": "vitest"
13
+ },
14
+ "dependencies": {
15
+ "@forbocai/core": "*",
16
+ "@lancedb/lancedb": "^0.23.0",
17
+ "@xenova/transformers": "^2.17.2",
18
+ "apache-arrow": "^18.1.0",
19
+ "node-llama-cpp": "^3.15.1",
20
+ "onnxruntime-node": "^1.23.2"
21
+ },
22
+ "devDependencies": {
23
+ "tsup": "^8.5.1",
24
+ "typescript": "^5.9.3",
25
+ "vitest": "^1.0.0"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "package.json"
30
+ ]
31
+ }