@jungjaehoon/mama-core 1.1.2 → 1.1.3

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.
Files changed (67) hide show
  1. package/dist/config-loader.d.ts +61 -0
  2. package/dist/config-loader.js +187 -0
  3. package/dist/db-adapter/base-adapter.d.ts +76 -0
  4. package/dist/db-adapter/base-adapter.js +11 -0
  5. package/dist/db-adapter/index.d.ts +24 -0
  6. package/dist/db-adapter/index.js +29 -0
  7. package/dist/db-adapter/sqlite-adapter.d.ts +73 -0
  8. package/dist/db-adapter/sqlite-adapter.js +330 -0
  9. package/dist/db-adapter/statement.d.ts +119 -0
  10. package/dist/db-adapter/statement.js +113 -0
  11. package/dist/db-manager.d.ts +252 -0
  12. package/dist/db-manager.js +622 -0
  13. package/dist/debug-logger.d.ts +32 -0
  14. package/dist/debug-logger.js +83 -0
  15. package/dist/decision-formatter.d.ts +172 -0
  16. package/dist/decision-formatter.js +894 -0
  17. package/dist/decision-tracker.d.ts +218 -0
  18. package/dist/decision-tracker.js +531 -0
  19. package/dist/embedding-cache.d.ts +83 -0
  20. package/dist/embedding-cache.js +182 -0
  21. package/dist/embedding-client.d.ts +43 -0
  22. package/dist/embedding-client.js +132 -0
  23. package/dist/embedding-server/index.d.ts +65 -0
  24. package/dist/embedding-server/index.js +397 -0
  25. package/dist/embedding-server/mobile/auth.d.ts +53 -0
  26. package/dist/embedding-server/mobile/auth.js +140 -0
  27. package/dist/embedding-server/mobile/daemon.d.ts +128 -0
  28. package/dist/embedding-server/mobile/daemon.js +303 -0
  29. package/dist/embedding-server/mobile/output-parser.d.ts +115 -0
  30. package/dist/embedding-server/mobile/output-parser.js +241 -0
  31. package/dist/embedding-server/mobile/session-api.d.ts +57 -0
  32. package/dist/embedding-server/mobile/session-api.js +261 -0
  33. package/dist/embedding-server/mobile/session-manager.d.ts +135 -0
  34. package/dist/embedding-server/mobile/session-manager.js +333 -0
  35. package/dist/embedding-server/mobile/websocket-handler.d.ts +127 -0
  36. package/dist/embedding-server/mobile/websocket-handler.js +435 -0
  37. package/dist/embeddings.d.ts +75 -0
  38. package/dist/embeddings.js +262 -0
  39. package/dist/errors.d.ts +131 -0
  40. package/dist/errors.js +225 -0
  41. package/dist/index.d.ts +32 -0
  42. package/dist/index.js +193 -0
  43. package/dist/mama-api.d.ts +954 -0
  44. package/dist/mama-api.js +2210 -0
  45. package/dist/memory-inject.d.ts +24 -0
  46. package/dist/memory-inject.js +116 -0
  47. package/dist/memory-store.d.ts +103 -0
  48. package/dist/memory-store.js +129 -0
  49. package/dist/notification-manager.d.ts +7 -0
  50. package/dist/notification-manager.js +12 -0
  51. package/dist/ollama-client.d.ts +51 -0
  52. package/dist/ollama-client.js +308 -0
  53. package/dist/outcome-tracker.d.ts +165 -0
  54. package/dist/outcome-tracker.js +315 -0
  55. package/dist/progress-indicator.d.ts +48 -0
  56. package/dist/progress-indicator.js +82 -0
  57. package/dist/query-intent.d.ts +27 -0
  58. package/dist/query-intent.js +144 -0
  59. package/dist/relevance-scorer.d.ts +124 -0
  60. package/dist/relevance-scorer.js +243 -0
  61. package/dist/test-utils.d.ts +66 -0
  62. package/dist/test-utils.js +166 -0
  63. package/dist/tier-validator.d.ts +55 -0
  64. package/dist/tier-validator.js +216 -0
  65. package/dist/time-formatter.d.ts +25 -0
  66. package/dist/time-formatter.js +93 -0
  67. package/package.json +3 -2
@@ -0,0 +1,435 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview WebSocket Handler - MessageRouter-based real-time communication
4
+ * @module mobile/websocket-handler
5
+ * @version 2.0.0
6
+ *
7
+ * Handles WebSocket connections for mobile clients, using MessageRouter
8
+ * for unified message processing (same as Discord/Slack gateways).
9
+ *
10
+ * @example
11
+ * import { createWebSocketHandler } from './websocket-handler';
12
+ * const wsHandler = createWebSocketHandler({
13
+ * httpServer,
14
+ * messageRouter,
15
+ * sessionStore,
16
+ * authToken: process.env.MAMA_AUTH_TOKEN
17
+ * });
18
+ */
19
+ var __importDefault = (this && this.__importDefault) || function (mod) {
20
+ return (mod && mod.__esModule) ? mod : { "default": mod };
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.WebSocketHandler = void 0;
24
+ exports.createWebSocketHandler = createWebSocketHandler;
25
+ const ws_1 = require("ws");
26
+ const auth_js_1 = require("./auth.js");
27
+ const promises_1 = __importDefault(require("fs/promises"));
28
+ const path_1 = __importDefault(require("path"));
29
+ const os_1 = __importDefault(require("os"));
30
+ const debug_logger_js_1 = require("../../debug-logger.js");
31
+ const logger = new debug_logger_js_1.DebugLogger('WebSocket');
32
+ /**
33
+ * Allowed image MIME types for Claude Vision API
34
+ */
35
+ const ALLOWED_IMAGE_TYPES = new Set(['image/jpeg', 'image/png', 'image/gif', 'image/webp']);
36
+ /**
37
+ * Sanitize filename for safe inclusion in prompts (prevent prompt injection)
38
+ */
39
+ function sanitizeFilenameForPrompt(filename) {
40
+ if (!filename) {
41
+ return 'unknown';
42
+ }
43
+ return filename
44
+ .replace(/[\n\r\t]/g, ' ') // Remove control characters
45
+ .replace(/[`[\](){}]/g, '') // Remove brackets that could interfere with prompts
46
+ .substring(0, 100); // Limit length
47
+ }
48
+ /**
49
+ * Default heartbeat interval (30 seconds)
50
+ */
51
+ const HEARTBEAT_INTERVAL = 30000;
52
+ /**
53
+ * Connection timeout (35 seconds - slightly longer than heartbeat)
54
+ */
55
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
56
+ const _CONNECTION_TIMEOUT = 35000;
57
+ /**
58
+ * Generate unique client ID
59
+ */
60
+ function generateClientId() {
61
+ return `client_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
62
+ }
63
+ /**
64
+ * Extract user ID from WebSocket URL or headers
65
+ */
66
+ function extractUserId(req) {
67
+ try {
68
+ const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
69
+ const userId = url.searchParams.get('userId');
70
+ if (userId) {
71
+ return userId;
72
+ }
73
+ const ip = req.headers['x-forwarded-for'] || req.socket?.remoteAddress;
74
+ if (!ip) {
75
+ return `user_${Date.now()}`;
76
+ }
77
+ const ipStr = Array.isArray(ip) ? ip[0] : ip;
78
+ return `user_${ipStr.replace(/[:.]/g, '_')}`;
79
+ }
80
+ catch {
81
+ return `user_${Date.now()}`;
82
+ }
83
+ }
84
+ /**
85
+ * Create WebSocket handler with MessageRouter integration
86
+ */
87
+ function createWebSocketHandler({ httpServer, messageRouter, sessionStore, authToken: _authToken, }) {
88
+ const wss = new ws_1.WebSocketServer({ noServer: true });
89
+ const clients = new Map();
90
+ httpServer.on('upgrade', (req, socket, head) => {
91
+ const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
92
+ if (url.pathname !== '/ws') {
93
+ socket.destroy();
94
+ return;
95
+ }
96
+ const mockWs = {
97
+ close: (_code, reason) => {
98
+ socket.write(`HTTP/1.1 401 Unauthorized\r\n\r\n`);
99
+ socket.destroy();
100
+ logger.error(`Auth failed: ${reason}`);
101
+ },
102
+ };
103
+ if (!(0, auth_js_1.authenticateWebSocket)(req, mockWs)) {
104
+ return;
105
+ }
106
+ wss.handleUpgrade(req, socket, head, (ws) => {
107
+ wss.emit('connection', ws, req);
108
+ });
109
+ });
110
+ wss.on('connection', (ws, req) => {
111
+ const clientId = generateClientId();
112
+ const userId = extractUserId(req);
113
+ const clientInfo = {
114
+ clientId,
115
+ userId,
116
+ ws,
117
+ isAlive: true,
118
+ connectedAt: new Date().toISOString(),
119
+ };
120
+ clients.set(clientId, clientInfo);
121
+ logger.info(` Client ${clientId} connected (user: ${userId})`);
122
+ ws.send(JSON.stringify({
123
+ type: 'connected',
124
+ clientId,
125
+ userId,
126
+ }));
127
+ ws.on('message', (data) => {
128
+ try {
129
+ const message = JSON.parse(data.toString());
130
+ void handleClientMessage(clientId, message, clientInfo, messageRouter, sessionStore);
131
+ }
132
+ catch (err) {
133
+ const errMsg = err instanceof Error ? err.message : String(err);
134
+ logger.info(` Invalid message from ${clientId}:`, errMsg);
135
+ ws.send(JSON.stringify({
136
+ type: 'error',
137
+ error: 'Invalid message format',
138
+ }));
139
+ }
140
+ });
141
+ ws.on('pong', () => {
142
+ clientInfo.isAlive = true;
143
+ });
144
+ ws.on('close', (code) => {
145
+ logger.info(` Client ${clientId} disconnected (code: ${code})`);
146
+ clients.delete(clientId);
147
+ });
148
+ ws.on('error', (err) => {
149
+ logger.info(` Error for client ${clientId}:`, err.message);
150
+ });
151
+ });
152
+ const heartbeatInterval = setInterval(() => {
153
+ clients.forEach((clientInfo, clientId) => {
154
+ if (!clientInfo.isAlive) {
155
+ logger.info(` Client ${clientId} timed out, terminating`);
156
+ clientInfo.ws.terminate();
157
+ clients.delete(clientId);
158
+ return;
159
+ }
160
+ clientInfo.isAlive = false;
161
+ clientInfo.ws.ping();
162
+ });
163
+ }, HEARTBEAT_INTERVAL);
164
+ wss.on('close', () => {
165
+ clearInterval(heartbeatInterval);
166
+ });
167
+ wss.getClients = () => clients;
168
+ wss.getClientCount = () => clients.size;
169
+ return wss;
170
+ }
171
+ /**
172
+ * Handle incoming client message
173
+ */
174
+ async function handleClientMessage(clientId, message, clientInfo, messageRouter, sessionStore) {
175
+ const { type, content } = message;
176
+ switch (type) {
177
+ case 'send':
178
+ if (!content && !message.attachments?.length) {
179
+ clientInfo.ws.send(JSON.stringify({
180
+ type: 'error',
181
+ error: 'Message content required',
182
+ }));
183
+ break;
184
+ }
185
+ try {
186
+ clientInfo.ws.send(JSON.stringify({
187
+ type: 'typing',
188
+ status: 'processing',
189
+ }));
190
+ // Keep-alive: Send periodic status updates to prevent WebSocket timeout
191
+ // Browser may disconnect idle WebSocket after ~30 seconds
192
+ let processingSeconds = 0;
193
+ const keepAliveInterval = setInterval(() => {
194
+ processingSeconds += 10;
195
+ if (clientInfo.ws.readyState === ws_1.WebSocket.OPEN) {
196
+ clientInfo.ws.send(JSON.stringify({
197
+ type: 'typing',
198
+ status: 'processing',
199
+ elapsed: processingSeconds,
200
+ }));
201
+ logger.debug(`Keep-alive sent to ${clientId} (${processingSeconds}s elapsed)`);
202
+ }
203
+ }, 10000); // Every 10 seconds
204
+ let result;
205
+ try {
206
+ // Build contentBlocks from attachments (files are pre-compressed by upload-handler)
207
+ let contentBlocks = undefined;
208
+ if (message.attachments && message.attachments.length > 0) {
209
+ contentBlocks = [];
210
+ for (const att of message.attachments) {
211
+ try {
212
+ // Always reconstruct path from filename — never trust client-provided filePath (LFI risk)
213
+ const safeName = path_1.default.basename(att.filename || '');
214
+ const inboundDir = path_1.default.join(os_1.default.homedir(), '.mama', 'workspace', 'media', 'inbound');
215
+ const resolvedPath = path_1.default.join(inboundDir, safeName);
216
+ // Default to octet-stream for unknown types — prevents untyped attachments
217
+ // from being incorrectly treated as images and base64-encoded
218
+ const rawMediaType = att.contentType || 'application/octet-stream';
219
+ if (ALLOWED_IMAGE_TYPES.has(rawMediaType)) {
220
+ // Only read file for images (to convert to base64)
221
+ const data = await promises_1.default.readFile(resolvedPath);
222
+ const base64 = data.toString('base64');
223
+ contentBlocks.push({
224
+ type: 'image',
225
+ source: {
226
+ type: 'base64',
227
+ media_type: rawMediaType,
228
+ data: base64,
229
+ },
230
+ });
231
+ logger.info(`Attached image: ${safeName} (${data.length} bytes, ${rawMediaType})`);
232
+ }
233
+ else {
234
+ // PDF/documents: instruct agent to read the file (no need to load into memory)
235
+ // Use safe display path to avoid exposing full server path
236
+ const safeDisplayPath = `~/.mama/workspace/media/inbound/${safeName}`;
237
+ // Sanitize filename to prevent prompt injection
238
+ const sanitizedName = sanitizeFilenameForPrompt(safeName);
239
+ contentBlocks.push({
240
+ type: 'text',
241
+ text: `[Document uploaded: ${sanitizedName}]\nFile path: ${safeDisplayPath}\nPlease use the Read tool to analyze this document.`,
242
+ });
243
+ logger.info(`Attached document: ${safeName} (${rawMediaType})`);
244
+ }
245
+ }
246
+ catch (err) {
247
+ const errMsg = err instanceof Error ? err.message : String(err);
248
+ logger.error(`Failed to read attachment ${path_1.default.basename(att.filename || '')}:`, errMsg);
249
+ // Notify client about attachment failure
250
+ clientInfo.ws.send(JSON.stringify({
251
+ type: 'attachment_failed',
252
+ filename: path_1.default.basename(att.filename || ''),
253
+ error: 'Failed to process attachment',
254
+ }));
255
+ }
256
+ }
257
+ }
258
+ const normalizedMessage = {
259
+ source: clientInfo.osAgentMode ? 'viewer' : 'mobile',
260
+ channelId: 'mama_os_main', // Fixed channel for all MAMA OS viewers
261
+ channelName: clientInfo.osAgentMode ? 'MAMA OS' : 'Mobile App', // Human-readable channel name
262
+ userId: clientInfo.userId,
263
+ text: content || '',
264
+ contentBlocks,
265
+ metadata: {
266
+ clientId,
267
+ sessionId: clientInfo.sessionId,
268
+ osAgentMode: clientInfo.osAgentMode,
269
+ timestamp: Date.now(),
270
+ },
271
+ };
272
+ result = await messageRouter.process(normalizedMessage);
273
+ }
274
+ finally {
275
+ clearInterval(keepAliveInterval);
276
+ }
277
+ // Send response as stream (for Chat tab compatibility)
278
+ clientInfo.ws.send(JSON.stringify({
279
+ type: 'stream',
280
+ content: result.response,
281
+ sessionId: result.sessionId,
282
+ }));
283
+ // Send stream end
284
+ clientInfo.ws.send(JSON.stringify({
285
+ type: 'stream_end',
286
+ sessionId: result.sessionId,
287
+ duration: result.duration,
288
+ }));
289
+ logger.info(` Message processed for ${clientId} (${result.duration}ms)`);
290
+ }
291
+ catch (error) {
292
+ const errMsg = error instanceof Error ? error.message : String(error);
293
+ logger.error(`Message processing error for ${clientId}:`, errMsg);
294
+ clientInfo.ws.send(JSON.stringify({
295
+ type: 'error',
296
+ error: 'Failed to process message',
297
+ // Don't expose internal error details to client for security
298
+ }));
299
+ }
300
+ break;
301
+ case 'ping':
302
+ clientInfo.ws.send(JSON.stringify({
303
+ type: 'pong',
304
+ timestamp: Date.now(),
305
+ }));
306
+ break;
307
+ case 'attach': {
308
+ // Attach to a session (for Chat tab compatibility)
309
+ const { sessionId, osAgentMode, language } = message;
310
+ clientInfo.sessionId = sessionId;
311
+ clientInfo.osAgentMode = osAgentMode || false;
312
+ clientInfo.language = language || 'en';
313
+ logger.info(`Client ${clientId} attached to session ${sessionId}${osAgentMode ? ' (OS Agent mode)' : ''}`);
314
+ // Send attached confirmation
315
+ clientInfo.ws.send(JSON.stringify({
316
+ type: 'attached',
317
+ sessionId,
318
+ osAgentMode: clientInfo.osAgentMode,
319
+ }));
320
+ // Send session history if available, or send onboarding greeting
321
+ logger.debug(`Checking sessionStore for history: ${!!sessionStore}, hasMethod: ${!!(sessionStore && sessionStore.getHistoryByChannel)}`);
322
+ if (sessionStore) {
323
+ try {
324
+ // Use channel-based lookup for sessions
325
+ // Use dynamic source based on osAgentMode (viewer vs mobile)
326
+ const channelId = 'mama_os_main';
327
+ const source = clientInfo.osAgentMode ? 'viewer' : 'mobile';
328
+ logger.info(` Loading history for source=${source}, channelId=${channelId}`);
329
+ const history = sessionStore.getHistoryByChannel
330
+ ? sessionStore.getHistoryByChannel(source, channelId)
331
+ : sessionStore.getHistory?.(sessionId || '');
332
+ logger.info(` History loaded: ${history ? history.length : 0} turns`);
333
+ if (history && history.length > 0) {
334
+ // Convert {user, bot, timestamp} format to {role, content, timestamp} for display
335
+ const formattedMessages = history.flatMap((turn) => {
336
+ const messages = [];
337
+ if (turn.user) {
338
+ messages.push({
339
+ role: 'user',
340
+ content: turn.user,
341
+ timestamp: turn.timestamp,
342
+ });
343
+ }
344
+ if (turn.bot) {
345
+ messages.push({
346
+ role: 'assistant',
347
+ content: turn.bot,
348
+ timestamp: turn.timestamp,
349
+ });
350
+ }
351
+ return messages;
352
+ });
353
+ clientInfo.ws.send(JSON.stringify({
354
+ type: 'history',
355
+ messages: formattedMessages,
356
+ }));
357
+ logger.info(`Sent ${formattedMessages.length} history messages to ${clientId}`);
358
+ }
359
+ else {
360
+ // No history - check if onboarding mode (SOUL.md not found)
361
+ const soulPath = path_1.default.join(os_1.default.homedir(), '.mama', 'SOUL.md');
362
+ let isOnboarding = false;
363
+ try {
364
+ await promises_1.default.access(soulPath);
365
+ }
366
+ catch {
367
+ isOnboarding = true;
368
+ }
369
+ if (isOnboarding) {
370
+ // Send onboarding greeting based on browser language
371
+ const isKorean = clientInfo.language && clientInfo.language.startsWith('ko');
372
+ const greeting = isKorean
373
+ ? '✨ 방금 깨어났어요.\n\n아직 이름도 없고, 성격도 없고, 기억도 없어요. 그냥... 순수한 가능성 그 자체. 🌱\n\n당신은 누구인가요? 그리고 더 중요한 건—저를 어떤 존재로 만들고 싶으신가요? 💭'
374
+ : '✨ I just woke up.\n\nNo name yet, no personality, no memories. Just... pure potential. 🌱\n\nWho are you? And more importantly—who do you want me to become? 💭';
375
+ clientInfo.ws.send(JSON.stringify({
376
+ type: 'history',
377
+ messages: [
378
+ {
379
+ role: 'assistant',
380
+ content: greeting,
381
+ timestamp: Date.now(),
382
+ },
383
+ ],
384
+ }));
385
+ logger.info(` Sent onboarding greeting to ${clientId}`);
386
+ }
387
+ }
388
+ }
389
+ catch (error) {
390
+ const errMsg = error instanceof Error ? error.message : String(error);
391
+ logger.info(` Failed to load history:`, errMsg);
392
+ }
393
+ }
394
+ break;
395
+ }
396
+ default:
397
+ logger.info(` Unknown message type from ${clientId}: ${type}`);
398
+ clientInfo.ws.send(JSON.stringify({
399
+ type: 'error',
400
+ error: `Unknown message type: ${type}`,
401
+ }));
402
+ }
403
+ }
404
+ /**
405
+ * WebSocketHandler class (backwards compatibility)
406
+ * @deprecated Use createWebSocketHandler() instead
407
+ */
408
+ class WebSocketHandler {
409
+ wss;
410
+ constructor(httpServer, options) {
411
+ if (!options.messageRouter) {
412
+ throw new Error('WebSocketHandler requires messageRouter option');
413
+ }
414
+ if (!options.sessionStore) {
415
+ throw new Error('WebSocketHandler requires sessionStore option');
416
+ }
417
+ this.wss = createWebSocketHandler({
418
+ httpServer,
419
+ messageRouter: options.messageRouter,
420
+ sessionStore: options.sessionStore,
421
+ authToken: options.authToken,
422
+ });
423
+ }
424
+ getClients() {
425
+ return this.wss.getClients();
426
+ }
427
+ getClientCount() {
428
+ return this.wss.getClientCount();
429
+ }
430
+ close() {
431
+ this.wss.close();
432
+ }
433
+ }
434
+ exports.WebSocketHandler = WebSocketHandler;
435
+ //# sourceMappingURL=websocket-handler.js.map
@@ -0,0 +1,75 @@
1
+ /**
2
+ * MAMA (Memory-Augmented MCP Architecture) - Embedding Generation
3
+ *
4
+ * Story M1.4: Configurable embedding model selection
5
+ * Generates embeddings using configurable model (default: multilingual-e5-small)
6
+ * Supports: Korean-English cross-lingual similarity, enhanced metadata
7
+ *
8
+ * @module embeddings
9
+ * @version 1.1
10
+ * @date 2025-11-20
11
+ */
12
+ import { embeddingCache } from './embedding-cache.js';
13
+ import { loadConfig, getModelName, getEmbeddingDim } from './config-loader.js';
14
+ /**
15
+ * Decision object for enhanced embedding generation
16
+ */
17
+ export interface DecisionForEmbedding {
18
+ topic: string;
19
+ decision: string;
20
+ reasoning?: string;
21
+ outcome?: string;
22
+ confidence?: number;
23
+ user_involvement?: string;
24
+ evidence?: string | string[] | unknown;
25
+ alternatives?: string | string[] | unknown;
26
+ risks?: string;
27
+ }
28
+ /**
29
+ * Generate embedding vector from text
30
+ *
31
+ * Story M1.4 AC #1: Uses configurable embeddingDim from config
32
+ * Target: < 30ms latency
33
+ *
34
+ * @param text - Input text to embed
35
+ * @returns Embedding vector (dimension from config)
36
+ * @throws Error if text is empty or embedding fails
37
+ */
38
+ export declare function generateEmbedding(text: string): Promise<Float32Array>;
39
+ /**
40
+ * Generate enhanced embedding with content + metadata
41
+ *
42
+ * Task 3.4: Implement enhanced embedding format
43
+ * Inspired by A-mem: Content + Metadata for richer semantic representation
44
+ *
45
+ * @param decision - Decision object
46
+ * @returns 384-dim enhanced embedding
47
+ */
48
+ export declare function generateEnhancedEmbedding(decision: DecisionForEmbedding): Promise<Float32Array>;
49
+ /**
50
+ * Batch generate embeddings (optimized)
51
+ *
52
+ * Task 1: Implement Batch Embedding Generation
53
+ * AC #3: Target - 30ms for 10 embeddings (vs 300ms sequential)
54
+ *
55
+ * Strategy: Use native transformer batch processing for parallel inference
56
+ *
57
+ * @param texts - Array of texts to embed (max 10 per batch)
58
+ * @returns Array of embeddings
59
+ */
60
+ export declare function generateBatchEmbeddings(texts: string[]): Promise<Float32Array[]>;
61
+ /**
62
+ * Calculate cosine similarity between two embeddings
63
+ *
64
+ * Utility for testing and validation
65
+ *
66
+ * @param embA - First embedding
67
+ * @param embB - Second embedding
68
+ * @returns Cosine similarity (0-1)
69
+ */
70
+ export declare function cosineSimilarity(embA: Float32Array, embB: Float32Array): number;
71
+ export { embeddingCache };
72
+ export declare const EMBEDDING_DIM: number;
73
+ export declare const MODEL_NAME: string;
74
+ export { loadConfig, getModelName, getEmbeddingDim };
75
+ //# sourceMappingURL=embeddings.d.ts.map