UNPKG

@oliverlessa/gemini-agent-lib

Version:

Uma biblioteca NodeJS para criar agentes de IA com Gemini LLM

197 lines (186 loc) 8.35 kB
const SummaryMemory = require('./summary-memory'); const sqlite3 = require('sqlite3').verbose(); const debug = require('../debug').create('gemini-agent-lib:memory:summary'); /** * Adaptador de memória de resumos que utiliza SQLite para persistência. * Implementa a interface SummaryMemory. */ class SQLiteSummaryMemoryAdapter extends SummaryMemory { /** * Construtor para o adaptador de memória de resumos SQLite. * @param {Object} options - Opções de configuração. * @param {Object} options.dbConfig - Configuração do banco de dados SQLite. * @param {string} options.dbConfig.dbPath - Caminho para o arquivo do banco de dados SQLite. */ constructor(options) { // Remover desestruturação debug('Inicializando adaptador com opções: %o', options); // Verificar diretamente o objeto options if (!options || !options.dbConfig || !options.dbConfig.dbPath) { console.error("[SQLiteSummaryMemoryAdapter] Opções recebidas:", options); // Log para depuração throw new Error("SQLiteSummaryMemoryAdapter requer 'options.dbConfig.dbPath'."); } const dbConfig = options.dbConfig; // Extrair dbConfig super({ dbType: 'sqlite', dbConfig: dbConfig }); // Passar dbConfig explicitamente this.dbPath = dbConfig.dbPath; this.db = new sqlite3.Database(this.dbPath); this._initializeDatabase(); } /** * Inicializa o banco de dados, criando a tabela de resumos se necessário. * @private */ _initializeDatabase() { debug('Inicializando banco de dados SQLite em: %s', this.dbPath); this.db.serialize(() => { this.db.run(` CREATE TABLE IF NOT EXISTS summaries ( summary_id INTEGER PRIMARY KEY AUTOINCREMENT, context_id TEXT NOT NULL, summary_content TEXT NOT NULL, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP ); `, (err) => { if (err) { console.error('Erro ao criar tabela summaries:', err); } else { debug('Tabela summaries verificada/criada com sucesso'); } }); this.db.run(` CREATE INDEX IF NOT EXISTS idx_summaries_context_timestamp ON summaries (context_id, timestamp DESC); `, (err) => { if (err) { console.error('Erro ao criar índice idx_summaries_context_timestamp:', err); } else { debug('Índice idx_summaries_context_timestamp verificado/criado com sucesso'); } }); }); } /** * Adiciona um novo resumo para um contexto específico. * @param {string} contextId - Identificador único do contexto. * @param {string} summaryContent - O conteúdo do resumo. * @param {Date} [timestamp=new Date()] - O timestamp associado ao resumo. * @returns {Promise<void>} */ async addSummary(contextId, summaryContent, timestamp = new Date()) { debug('Adicionando resumo para contextId: %s', contextId); return new Promise((resolve, reject) => { // Converte timestamp para formato compatível com SQLite (ISO 8601 string) const isoTimestamp = timestamp.toISOString(); this.db.run(` INSERT INTO summaries (context_id, summary_content, timestamp) VALUES (?, ?, ?) `, [contextId, summaryContent, isoTimestamp], function(err) { if (err) { console.error("[SQLiteSummaryMemoryAdapter] Erro ao adicionar resumo:", err); reject(err); } else { debug('Resumo adicionado com sucesso para contextId: %s, ID: %d', contextId, this.lastID); resolve(); } }); }); } /** * Recupera o resumo mais recente para um contexto específico. * @param {string} contextId - Identificador único do contexto. * @returns {Promise<string|null>} - O conteúdo do resumo mais recente, ou null se nenhum resumo for encontrado. */ async getLatestSummary(contextId) { debug('Obtendo resumo mais recente para contextId: %s', contextId); return new Promise((resolve, reject) => { this.db.get(` SELECT summary_content FROM summaries WHERE context_id = ? ORDER BY timestamp DESC LIMIT 1 `, [contextId], (err, row) => { if (err) { console.error("[SQLiteSummaryMemoryAdapter] Erro ao obter último resumo:", err); reject(err); } else { const found = !!row; debug('Resumo mais recente %s para contextId: %s', found ? 'encontrado' : 'não encontrado', contextId); resolve(row ? row.summary_content : null); } }); }); } /** * Recupera todos os resumos para um contexto específico, ordenados do mais recente para o mais antigo. * @param {string} contextId - Identificador único do contexto. * @param {number} [limit] - Número máximo de resumos a serem retornados. * @returns {Promise<Array<{ summaryContent: string, timestamp: Date }>>} - Um array de objetos de resumo. */ async getAllSummaries(contextId, limit) { debug('Obtendo todos os resumos para contextId: %s, limit: %s', contextId, limit || 'sem limite'); return new Promise((resolve, reject) => { let query = ` SELECT summary_content, timestamp FROM summaries WHERE context_id = ? ORDER BY timestamp DESC `; const params = [contextId]; if (limit && typeof limit === 'number' && limit > 0) { query += ` LIMIT ?`; params.push(limit); } this.db.all(query, params, (err, rows) => { if (err) { console.error("[SQLiteSummaryMemoryAdapter] Erro ao obter todos os resumos:", err); reject(err); } else { // Converte timestamp de string ISO para objeto Date const summaries = rows.map(row => ({ summaryContent: row.summary_content, timestamp: new Date(row.timestamp) })); debug('Recuperados %d resumos para contextId: %s', summaries.length, contextId); resolve(summaries); } }); }); } /** * Deleta todos os resumos para um contexto específico. * @param {string} contextId - Identificador único do contexto. * @returns {Promise<void>} */ async deleteAllSummaries(contextId) { debug('Deletando todos os resumos para contextId: %s', contextId); return new Promise((resolve, reject) => { this.db.run(` DELETE FROM summaries WHERE context_id = ? `, [contextId], function(err) { if (err) { console.error("[SQLiteSummaryMemoryAdapter] Erro ao deletar resumos:", err); reject(err); } else { debug('Todos os resumos deletados para contextId: %s, registros afetados: %d', contextId, this.changes); resolve(); } }); }); } /** * Fecha a conexão com o banco de dados SQLite. * @returns {Promise<void>} */ async close() { debug('Fechando conexão com o banco de dados SQLite'); return new Promise((resolve, reject) => { this.db.close((err) => { if (err) { console.error("[SQLiteSummaryMemoryAdapter] Erro ao fechar conexão:", err); reject(err); return; } debug('Conexão com o banco de dados SQLite fechada com sucesso'); resolve(); }); }); } } module.exports = SQLiteSummaryMemoryAdapter;