diff --git a/src/ollama-client.ts b/src/ollama-client.ts index b80b8d1..03a0fe2 100644 --- a/src/ollama-client.ts +++ b/src/ollama-client.ts @@ -196,7 +196,9 @@ export class OllamaClient { } if (parsed.error) { - throw new Error(`Ollama error: ${parsed.error}`); + const errorMsg = + typeof parsed.error === 'string' ? parsed.error : JSON.stringify(parsed.error); + throw new Error(`Ollama error: ${errorMsg}`); } yield this.normalizeMessage(parsed.message); @@ -216,7 +218,9 @@ export class OllamaClient { } if (parsed?.error) { - throw new Error(`Ollama error: ${parsed.error}`); + const errorMsg = + typeof parsed.error === 'string' ? parsed.error : JSON.stringify(parsed.error); + throw new Error(`Ollama error: ${errorMsg}`); } if (parsed?.message) { @@ -226,7 +230,10 @@ export class OllamaClient { } catch (error) { if (retryCount < this.maxRetries && this.isRetryableError(error, controller)) { const errorMessage = error instanceof Error ? error.message : String(error); - Logger.warn(`Retrying after error (attempt ${retryCount + 1}): ${errorMessage}`, 'ollama-client'); + Logger.warn( + `Retrying after error (attempt ${retryCount + 1}): ${errorMessage}`, + 'ollama-client' + ); await new Promise((resolve) => setTimeout(resolve, 10 * Math.pow(2, retryCount))); yield* this.streamChatWithRetry(messages, tools, retryCount + 1); } else { @@ -267,7 +274,7 @@ export class OllamaClient { throw new ApiError(`Ollama API error: ${response.status}`, response.status); } - const data = await response.json() as unknown; + const data = (await response.json()) as unknown; if (!this.isChatResponse(data)) { return this.normalizeMessage(); } @@ -275,7 +282,10 @@ export class OllamaClient { } catch (error) { if (retryCount < this.maxRetries && this.isRetryableError(error, controller)) { const errorMessage = error instanceof Error ? error.message : String(error); - Logger.warn(`Retrying after error (attempt ${retryCount + 1}): ${errorMessage}`, 'ollama-client'); + Logger.warn( + `Retrying after error (attempt ${retryCount + 1}): ${errorMessage}`, + 'ollama-client' + ); await new Promise((resolve) => setTimeout(resolve, 10 * Math.pow(2, retryCount))); return this.chatWithRetry(messages, tools, retryCount + 1); } else { diff --git a/src/semantic-cache.ts b/src/semantic-cache.ts index 108f09c..3e7b61a 100644 --- a/src/semantic-cache.ts +++ b/src/semantic-cache.ts @@ -62,12 +62,20 @@ export class SemanticCacheService { } } + private static generateId(): string { + if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { + return crypto.randomUUID(); + } + // Fallback for environments without crypto.randomUUID + return 'cache_' + Date.now() + '_' + Math.random().toString(36).substring(2, 11); + } + async setCache(query: string, response: string): Promise { if (!this.config.enabled || !this.collection) return; try { - await this.collection.add({ - ids: [crypto.randomUUID()], + await this.collection.upsert({ + ids: [SemanticCacheService.generateId()], documents: [response], embeddings: await this.generateEmbedding(query), metadatas: [{ source: 'ollama' }], diff --git a/tests/semantic-cache.test.ts b/tests/semantic-cache.test.ts index 3d12f69..a148c01 100644 --- a/tests/semantic-cache.test.ts +++ b/tests/semantic-cache.test.ts @@ -10,6 +10,7 @@ jest.mock('chromadb', () => ({ getOrCreateCollection: jest.fn().mockResolvedValue({ query: jest.fn(), add: jest.fn(), + upsert: jest.fn(), reset: jest.fn(), }), deleteCollection: jest.fn(), @@ -135,13 +136,13 @@ describe('SemanticCacheService', () => { await disabledCacheService.setCache('test query', 'test response'); - expect(mockCollection.add).not.toHaveBeenCalled(); + expect(mockCollection.upsert).not.toHaveBeenCalled(); }); it('should add content to cache', async () => { await cacheService.setCache('test query', 'test response'); - expect(mockCollection.add).toHaveBeenCalled(); + expect(mockCollection.upsert).toHaveBeenCalled(); }); });