fix: resolve ESLint errors and align chromadb types with bundled client
- src/semantic-cache.ts: Replace require('chromadb') with static import and
use proper ChromaClient/Collection types instead of any. Fix camelCase
API parameters (queryEmbeddings, nResults) and wrap single embedding into
Embedding[] for upsert. Fix clearCache to call client.reset() instead of
collection.reset() (matches actual chromadb API).
- src/workflow-engine/workflow-engine.ts: Fix unnecessary escapes in regex,
remove redundant 'as unknown' assertion, handle never type in template
literal, and add type annotations to replace callback to satisfy
no-unsafe-argument and no-base-to-string rules.
- tests/semantic-cache.test.ts: Update mocks to include client.reset() and
adjust clearCache assertions to match new implementation.
This commit is contained in:
+14
-13
@@ -1,13 +1,12 @@
|
||||
// src/semantic-cache.ts
|
||||
|
||||
import { ChromaClient, Collection } from 'chromadb';
|
||||
import { Logger } from './utils';
|
||||
import { CacheConfig } from './types';
|
||||
|
||||
export class SemanticCacheService {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private client: any | null = null;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private collection: any | null = null;
|
||||
private client: ChromaClient | null = null;
|
||||
private collection: Collection | null = null;
|
||||
private config: CacheConfig;
|
||||
private ollamaURL: string;
|
||||
|
||||
@@ -20,8 +19,6 @@ export class SemanticCacheService {
|
||||
if (!this.config.enabled) return;
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { ChromaClient } = require('chromadb');
|
||||
const chromaURL = this.config.chromaURL || 'http://localhost:8000';
|
||||
this.client = new ChromaClient({ path: chromaURL });
|
||||
this.collection = await this.client.getOrCreateCollection({
|
||||
@@ -42,13 +39,17 @@ export class SemanticCacheService {
|
||||
|
||||
try {
|
||||
const results = await this.collection.query({
|
||||
query_embeddings: await this.generateEmbedding(query),
|
||||
n_results: 1,
|
||||
queryEmbeddings: [await this.generateEmbedding(query)],
|
||||
nResults: 1,
|
||||
where: { source: 'ollama' },
|
||||
});
|
||||
|
||||
if (results.ids[0] && results.ids[0].length > 0) {
|
||||
if (results.distances[0] && results.distances[0][0] > this.config.similarityThreshold) {
|
||||
if (
|
||||
results.distances &&
|
||||
results.distances[0] &&
|
||||
results.distances[0][0] > this.config.similarityThreshold
|
||||
) {
|
||||
return results.documents[0][0];
|
||||
}
|
||||
}
|
||||
@@ -76,7 +77,7 @@ export class SemanticCacheService {
|
||||
await this.collection.upsert({
|
||||
ids: [SemanticCacheService.generateId()],
|
||||
documents: [response],
|
||||
embeddings: await this.generateEmbedding(query),
|
||||
embeddings: [await this.generateEmbedding(query)],
|
||||
metadatas: [{ source: 'ollama' }],
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -86,10 +87,10 @@ export class SemanticCacheService {
|
||||
}
|
||||
|
||||
async clearCache(): Promise<void> {
|
||||
if (!this.config.enabled || !this.collection) return;
|
||||
if (!this.config.enabled || !this.client) return;
|
||||
|
||||
try {
|
||||
await this.collection.reset();
|
||||
await this.client.reset();
|
||||
Logger.info('Semantic cache cleared', 'semantic-cache');
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
@@ -113,7 +114,7 @@ export class SemanticCacheService {
|
||||
throw new Error(`Failed to generate embedding: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const data = (await response.json()) as { embedding: number[] };
|
||||
return data.embedding;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,10 +290,10 @@ Rules:
|
||||
|
||||
// Extract JSON from the response (handle markdown code blocks)
|
||||
const jsonMatch =
|
||||
content.match(/\```(?:json)?\s*([\s\S]*?)\```/) ?? content.match(/\{[\s\S]*\}/);
|
||||
content.match(/```(?:json)?\s*([\s\S]*?)```/) ?? content.match(/\{[\s\S]*\}/);
|
||||
const jsonString = jsonMatch ? jsonMatch[1] : content;
|
||||
|
||||
const parsed = safeParseJson(jsonString) as unknown;
|
||||
const parsed = safeParseJson(jsonString);
|
||||
if (!parsed || typeof parsed !== 'object') {
|
||||
Logger.error('Invalid workflow JSON from LLM', 'workflow-engine');
|
||||
return null;
|
||||
@@ -354,7 +354,7 @@ Rules:
|
||||
data = this.executeFormatStep(interpolatedConfig as FormatStepConfig, context);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown step type: ${step.type}`);
|
||||
throw new Error(`Unknown step type: ${String(step.type)}`);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -502,7 +502,7 @@ Rules:
|
||||
* Interpolate variables in a string.
|
||||
*/
|
||||
private interpolateString(input: string, variables: Map<string, unknown>): string {
|
||||
return input.replace(VARIABLE_PATTERN, (_match, variablePath) => {
|
||||
return input.replace(VARIABLE_PATTERN, (_match: string, variablePath: string) => {
|
||||
const value = this.resolveVariable(variablePath, variables);
|
||||
if (value === undefined) {
|
||||
// Keep the original placeholder if variable not found
|
||||
@@ -515,6 +515,18 @@ Rules:
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
if (
|
||||
typeof value === 'string' ||
|
||||
typeof value === 'number' ||
|
||||
typeof value === 'boolean' ||
|
||||
value === null ||
|
||||
value === undefined
|
||||
) {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
// Fallback for symbols, functions, etc.
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||
return String(value);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ jest.mock('chromadb', () => ({
|
||||
reset: jest.fn(),
|
||||
}),
|
||||
deleteCollection: jest.fn(),
|
||||
reset: jest.fn(),
|
||||
};
|
||||
}),
|
||||
IncludeEnum: {
|
||||
@@ -154,13 +155,13 @@ describe('SemanticCacheService', () => {
|
||||
|
||||
await disabledCacheService.clearCache();
|
||||
|
||||
expect(mockCollection.reset).not.toHaveBeenCalled();
|
||||
expect(mockChromaClient.reset).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should clear the cache collection', async () => {
|
||||
it('should clear the cache via the ChromaClient', async () => {
|
||||
await cacheService.clearCache();
|
||||
|
||||
expect(mockCollection.reset).toHaveBeenCalled();
|
||||
expect(mockChromaClient.reset).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user