memq-ai-memory
Version:
Memory SDK with Vercel AI SDK integration
394 lines • 13.8 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MemoryClient = void 0;
const axios_1 = __importDefault(require("axios"));
const uuid_1 = require("uuid");
const crypto = __importStar(require("crypto"));
class MemoryClient {
constructor(config) {
this.config = {
baseUrl: 'http://localhost:8000',
timeout: 30000,
retryAttempts: 3,
retryDelay: 1000,
enableLogging: false,
...config
};
this.sessionId = (0, uuid_1.v4)();
// Derive user_id from API key (like mem0 client does)
this.derivedUserId = crypto.createHash('md5').update(this.config.apiKey).digest('hex');
this.client = axios_1.default.create({
baseURL: this.config.baseUrl,
timeout: this.config.timeout,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.config.apiKey}`,
'X-Session-ID': this.sessionId,
// Provide API key via header expected by backend API key auth
'x-api-key': this.config.apiKey
}
});
// Add request interceptor for logging
if (this.config.enableLogging) {
this.client.interceptors.request.use((config) => {
console.log(`[MemorySDK] Request: ${config.method?.toUpperCase()} ${config.url}`);
return config;
}, (error) => {
console.error('[MemorySDK] Request Error:', error);
return Promise.reject(error);
});
this.client.interceptors.response.use((response) => {
console.log(`[MemorySDK] Response: ${response.status} ${response.config.url}`);
return response;
}, (error) => {
console.error('[MemorySDK] Response Error:', error.response?.status, error.response?.data);
return Promise.reject(error);
});
}
}
/**
* Validate the API key by making a test request
*/
async validateApiKey() {
try {
const response = await this.client.get('/health');
return response.status === 200;
}
catch (error) {
return false;
}
}
/**
* Create a new memory (automatically uses derived user_id)
*/
async createMemory(memory) {
try {
const response = await this.client.post('/memory/smart', {
...memory,
user_id: memory.user_id || this.actualUserId || this.derivedUserId, // Prefer actual user id over derived
session_id: memory.session_id || this.sessionId
});
return response.data;
}
catch (error) {
throw this.handleError(error, 'Failed to create memory');
}
}
/**
* Get all memories (automatically uses derived user_id)
*/
async getAllMemories(userId, limit = 50) {
try {
const actualUserId = userId || this.actualUserId || this.derivedUserId;
const response = await this.client.get(`/memories/${encodeURIComponent(actualUserId)}?limit=${limit}`);
return response.data;
}
catch (error) {
throw this.handleError(error, 'Failed to get memories');
}
}
/**
* Search memories (automatically uses derived user_id)
*/
async searchMemories(request) {
try {
const params = new URLSearchParams();
const userId = request.user_id || this.actualUserId || this.derivedUserId;
if (userId) {
params.append('user_id', userId);
}
const response = await this.client.post(`/query/smart?${params.toString()}`, {
prompt: request.query,
limit: request.limit || 10,
...request.filters
});
return response.data;
}
catch (error) {
throw this.handleError(error, 'Failed to search memories');
}
}
/**
* Get workflow memories for a user
*/
async getWorkflowMemories(userId, limit = 50) {
try {
const response = await this.client.get(`/workflow-memories/${encodeURIComponent(userId)}?limit=${limit}`);
return response.data;
}
catch (error) {
throw this.handleError(error, 'Failed to get workflow memories');
}
}
/**
* Get user facts (automatically uses derived user_id if not provided)
*/
async getUserFacts(userId, category, limit = 20) {
try {
const actualUserId = userId || this.actualUserId || this.derivedUserId;
const categoryParam = category ? `&category=${encodeURIComponent(category)}` : '';
const response = await this.client.get(`/facts/${actualUserId}?limit=${limit}${categoryParam}`);
return response.data;
}
catch (error) {
throw this.handleError(error, 'Failed to get user facts');
}
}
/**
* Get user prompt structures (automatically uses derived user_id if not provided)
*/
async getUserPromptStructures(userId, isComplete, limit = 20) {
try {
const actualUserId = userId || this.actualUserId || this.derivedUserId;
const completeParam = isComplete !== undefined ? `&is_complete=${isComplete}` : '';
const response = await this.client.get(`/prompt/structures/user/${actualUserId}?limit=${limit}${completeParam}`);
return response.data;
}
catch (error) {
throw this.handleError(error, 'Failed to get prompt structures');
}
}
/**
* Delete a memory
*/
async deleteMemory(memoryId) {
try {
const response = await this.client.delete(`/memory/${memoryId}`);
return response.data;
}
catch (error) {
throw this.handleError(error, 'Failed to delete memory');
}
}
/**
* Get collection statistics
*/
async getStats() {
try {
const response = await this.client.get('/stats');
return response.data;
}
catch (error) {
throw this.handleError(error, 'Failed to get stats');
}
}
/**
* Health check
*/
async healthCheck() {
try {
const response = await this.client.get('/health');
return response.data;
}
catch (error) {
throw this.handleError(error, 'Failed to perform health check');
}
}
/**
* Get recent activity for a user (automatically uses derived user_id if not provided)
*/
async getRecentActivity(userId, limit = 10) {
try {
const actualUserId = userId || this.derivedUserId;
const [memories, facts, structures] = await Promise.all([
this.searchMemories({ query: 'recent activity', user_id: actualUserId, limit }),
this.getUserFacts(actualUserId, undefined, limit),
this.getUserPromptStructures(actualUserId, undefined, limit)
]);
return {
memories: memories.memories,
facts: facts.facts,
prompt_structures: structures.structures
};
}
catch (error) {
throw this.handleError(error, 'Failed to get recent activity');
}
}
/**
* Create a new API key
*/
async createApiKey(request) {
try {
const response = await this.client.post('/api-keys', request);
return response.data;
}
catch (error) {
throw this.handleError(error, 'Failed to create API key');
}
}
/**
* Get user's API keys
*/
async getApiKeys() {
try {
const response = await this.client.get('/api-keys');
return response.data;
}
catch (error) {
throw this.handleError(error, 'Failed to get API keys');
}
}
/**
* Revoke an API key
*/
async revokeApiKey(keyId) {
try {
const response = await this.client.delete(`/api-keys/${keyId}`);
return response.data;
}
catch (error) {
throw this.handleError(error, 'Failed to revoke API key');
}
}
/**
* Update API key details
*/
async updateApiKey(keyId, updates) {
try {
const response = await this.client.put(`/api-keys/${keyId}`, updates);
return response.data;
}
catch (error) {
throw this.handleError(error, 'Failed to update API key');
}
}
/**
* Get the current session ID
*/
getSessionId() {
return this.sessionId;
}
/**
* Set a new session ID
*/
setSessionId(sessionId) {
this.sessionId = sessionId;
this.client.defaults.headers['X-Session-ID'] = sessionId;
}
/**
* Get derived user_id
*/
getDerivedUserId() {
return this.derivedUserId;
}
/**
* Get actual user_id resolved from API key, if available
*/
getActualUserId() {
return this.actualUserId;
}
/**
* Initialize actual user_id by validating API key against backend
* Uses /api-keys/test/protected which returns user_id when x-api-key is valid
*/
async initializeUserFromApiKey() {
try {
if (this.config.enableLogging) {
console.log('[MemorySDK] Attempting to resolve actual user ID from API key...');
}
const response = await this.client.get('/api-keys/test/protected');
if (this.config.enableLogging) {
console.log('[MemorySDK] API key validation response:', response.data);
}
const userId = (response.data && (response.data.user_id || response.data.userId));
if (userId) {
this.actualUserId = userId;
if (this.config.enableLogging) {
console.log(`[MemorySDK] Successfully resolved actual user ID: ${userId}`);
}
}
else {
if (this.config.enableLogging) {
console.log('[MemorySDK] No user_id found in API key validation response');
}
}
}
catch (error) {
if (this.config.enableLogging) {
console.log('[MemorySDK] Failed to resolve actual user ID from API key:', error);
}
// Silently ignore and fall back to derived user id
}
}
/**
* Handle API errors
*/
handleError(error, defaultMessage) {
if (error.response) {
const errorData = error.response.data;
const message = errorData?.detail || errorData?.error || defaultMessage;
const customError = new Error(message);
customError.status = error.response.status;
customError.data = errorData;
return customError;
}
else if (error.request) {
return new Error('Network error: No response received');
}
else {
return new Error(`Request error: ${error.message}`);
}
}
/**
* Retry a request with exponential backoff
*/
async retryRequest(requestFn, attempts = this.config.retryAttempts || 3) {
let lastError;
for (let i = 0; i < attempts; i++) {
try {
return await requestFn();
}
catch (error) {
lastError = error;
// Don't retry on client errors (4xx)
if (error.status && error.status >= 400 && error.status < 500) {
throw error;
}
if (i < attempts - 1) {
const delay = (this.config.retryDelay || 1000) * Math.pow(2, i);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
throw lastError;
}
}
exports.MemoryClient = MemoryClient;
//# sourceMappingURL=MemoryClient.js.map