@zilliz/claude-context-core 0.1.11 → 0.1.13
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.
- package/README.md +3 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/context.abort.test.d.ts +2 -0
- package/dist/context.abort.test.d.ts.map +1 -0
- package/dist/context.abort.test.js +212 -0
- package/dist/context.abort.test.js.map +1 -0
- package/dist/context.d.ts +25 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/context.ignore-patterns.test.js +145 -14
- package/dist/context.ignore-patterns.test.js.map +1 -1
- package/dist/context.js +126 -32
- package/dist/context.js.map +1 -1
- package/dist/context.splitter.test.d.ts +2 -0
- package/dist/context.splitter.test.d.ts.map +1 -0
- package/dist/context.splitter.test.js +202 -0
- package/dist/context.splitter.test.js.map +1 -0
- package/dist/embedding/gemini-embedding.d.ts +9 -6
- package/dist/embedding/gemini-embedding.d.ts.map +1 -1
- package/dist/embedding/gemini-embedding.js +31 -16
- package/dist/embedding/gemini-embedding.js.map +1 -1
- package/dist/embedding/gemini-embedding.test.d.ts +2 -0
- package/dist/embedding/gemini-embedding.test.d.ts.map +1 -0
- package/dist/embedding/gemini-embedding.test.js +105 -0
- package/dist/embedding/gemini-embedding.test.js.map +1 -0
- package/dist/sync/synchronizer.d.ts +1 -0
- package/dist/sync/synchronizer.d.ts.map +1 -1
- package/dist/sync/synchronizer.js +32 -33
- package/dist/sync/synchronizer.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const fs = __importStar(require("fs/promises"));
|
|
37
|
+
const os = __importStar(require("os"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const context_1 = require("./context");
|
|
40
|
+
const embedding_1 = require("./embedding");
|
|
41
|
+
const synchronizer_1 = require("./sync/synchronizer");
|
|
42
|
+
class TestEmbedding extends embedding_1.Embedding {
|
|
43
|
+
constructor() {
|
|
44
|
+
super(...arguments);
|
|
45
|
+
this.maxTokens = 8192;
|
|
46
|
+
}
|
|
47
|
+
async detectDimension() {
|
|
48
|
+
return 3;
|
|
49
|
+
}
|
|
50
|
+
async embed(text) {
|
|
51
|
+
return { vector: [1, 0, 0], dimension: 3 };
|
|
52
|
+
}
|
|
53
|
+
async embedBatch(texts) {
|
|
54
|
+
return texts.map(() => ({ vector: [1, 0, 0], dimension: 3 }));
|
|
55
|
+
}
|
|
56
|
+
getDimension() {
|
|
57
|
+
return 3;
|
|
58
|
+
}
|
|
59
|
+
getProvider() {
|
|
60
|
+
return 'test';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
class RecordingSplitter {
|
|
64
|
+
constructor(label) {
|
|
65
|
+
this.label = label;
|
|
66
|
+
this.calls = [];
|
|
67
|
+
}
|
|
68
|
+
async split(code, language, filePath) {
|
|
69
|
+
this.calls.push({ code, language, filePath });
|
|
70
|
+
return [{
|
|
71
|
+
content: `${this.label}:${code}`,
|
|
72
|
+
metadata: {
|
|
73
|
+
startLine: 1,
|
|
74
|
+
endLine: code.split('\n').length,
|
|
75
|
+
language,
|
|
76
|
+
filePath,
|
|
77
|
+
},
|
|
78
|
+
}];
|
|
79
|
+
}
|
|
80
|
+
setChunkSize() { }
|
|
81
|
+
setChunkOverlap() { }
|
|
82
|
+
}
|
|
83
|
+
const createVectorDatabase = () => ({
|
|
84
|
+
createCollection: jest.fn().mockResolvedValue(undefined),
|
|
85
|
+
createHybridCollection: jest.fn().mockResolvedValue(undefined),
|
|
86
|
+
dropCollection: jest.fn().mockResolvedValue(undefined),
|
|
87
|
+
hasCollection: jest.fn().mockResolvedValue(false),
|
|
88
|
+
listCollections: jest.fn().mockResolvedValue([]),
|
|
89
|
+
insert: jest.fn().mockResolvedValue(undefined),
|
|
90
|
+
insertHybrid: jest.fn().mockResolvedValue(undefined),
|
|
91
|
+
search: jest.fn().mockResolvedValue([]),
|
|
92
|
+
hybridSearch: jest.fn().mockResolvedValue([]),
|
|
93
|
+
delete: jest.fn().mockResolvedValue(undefined),
|
|
94
|
+
query: jest.fn().mockResolvedValue([]),
|
|
95
|
+
getCollectionDescription: jest.fn().mockResolvedValue(''),
|
|
96
|
+
checkCollectionLimit: jest.fn().mockResolvedValue(true),
|
|
97
|
+
getCollectionRowCount: jest.fn().mockResolvedValue(0),
|
|
98
|
+
});
|
|
99
|
+
describe('Context request-scoped splitters', () => {
|
|
100
|
+
let tempRoot;
|
|
101
|
+
let originalHome;
|
|
102
|
+
let originalHybridMode;
|
|
103
|
+
beforeEach(async () => {
|
|
104
|
+
tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'claude-context-splitter-'));
|
|
105
|
+
const homeDir = path.join(tempRoot, 'home');
|
|
106
|
+
await fs.mkdir(homeDir, { recursive: true });
|
|
107
|
+
originalHome = process.env.HOME;
|
|
108
|
+
originalHybridMode = process.env.HYBRID_MODE;
|
|
109
|
+
process.env.HOME = homeDir;
|
|
110
|
+
process.env.HYBRID_MODE = 'false';
|
|
111
|
+
});
|
|
112
|
+
afterEach(async () => {
|
|
113
|
+
if (originalHome === undefined) {
|
|
114
|
+
delete process.env.HOME;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
process.env.HOME = originalHome;
|
|
118
|
+
}
|
|
119
|
+
if (originalHybridMode === undefined) {
|
|
120
|
+
delete process.env.HYBRID_MODE;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
process.env.HYBRID_MODE = originalHybridMode;
|
|
124
|
+
}
|
|
125
|
+
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
126
|
+
});
|
|
127
|
+
it('uses a request-scoped splitter for indexing without replacing the context splitter', async () => {
|
|
128
|
+
const project = path.join(tempRoot, 'project');
|
|
129
|
+
await fs.mkdir(project);
|
|
130
|
+
await fs.writeFile(path.join(project, 'index.ts'), 'const value = 1;');
|
|
131
|
+
const vectorDatabase = createVectorDatabase();
|
|
132
|
+
const contextSplitter = new RecordingSplitter('context');
|
|
133
|
+
const requestSplitter = new RecordingSplitter('request');
|
|
134
|
+
const context = new context_1.Context({
|
|
135
|
+
embedding: new TestEmbedding(),
|
|
136
|
+
vectorDatabase,
|
|
137
|
+
codeSplitter: contextSplitter,
|
|
138
|
+
});
|
|
139
|
+
await context.indexCodebase(project, undefined, false, [], [], requestSplitter);
|
|
140
|
+
expect(contextSplitter.calls).toHaveLength(0);
|
|
141
|
+
expect(requestSplitter.calls).toHaveLength(1);
|
|
142
|
+
expect(context.getCodeSplitter()).toBe(contextSplitter);
|
|
143
|
+
const insertedDocuments = vectorDatabase.insert.mock.calls
|
|
144
|
+
.flatMap(([, documents]) => documents);
|
|
145
|
+
expect(insertedDocuments).toHaveLength(1);
|
|
146
|
+
expect(insertedDocuments[0].content).toBe('request:const value = 1;');
|
|
147
|
+
});
|
|
148
|
+
it('uses a request-scoped splitter for changed files during sync reindexing', async () => {
|
|
149
|
+
const project = path.join(tempRoot, 'project');
|
|
150
|
+
await fs.mkdir(project);
|
|
151
|
+
const filePath = path.join(project, 'note.md');
|
|
152
|
+
await fs.writeFile(filePath, 'first version');
|
|
153
|
+
const vectorDatabase = createVectorDatabase();
|
|
154
|
+
const contextSplitter = new RecordingSplitter('context');
|
|
155
|
+
const requestSplitter = new RecordingSplitter('request');
|
|
156
|
+
const context = new context_1.Context({
|
|
157
|
+
embedding: new TestEmbedding(),
|
|
158
|
+
vectorDatabase,
|
|
159
|
+
codeSplitter: contextSplitter,
|
|
160
|
+
});
|
|
161
|
+
try {
|
|
162
|
+
const synchronizer = new synchronizer_1.FileSynchronizer(project, await context.getEffectiveIgnorePatterns(project), context.getEffectiveSupportedExtensions());
|
|
163
|
+
await synchronizer.initialize();
|
|
164
|
+
context.setSynchronizer(context.getCollectionName(project), synchronizer);
|
|
165
|
+
await fs.writeFile(filePath, 'second version');
|
|
166
|
+
await context.reindexByChange(project, undefined, [], [], requestSplitter);
|
|
167
|
+
expect(contextSplitter.calls).toHaveLength(0);
|
|
168
|
+
expect(requestSplitter.calls).toHaveLength(1);
|
|
169
|
+
expect(context.getCodeSplitter()).toBe(contextSplitter);
|
|
170
|
+
const insertedDocuments = vectorDatabase.insert.mock.calls
|
|
171
|
+
.flatMap(([, documents]) => documents);
|
|
172
|
+
expect(insertedDocuments).toHaveLength(1);
|
|
173
|
+
expect(insertedDocuments[0].content).toBe('request:second version');
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
await synchronizer_1.FileSynchronizer.deleteSnapshot(project);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
it('indexes Solidity files by default and maps them to the solidity language', async () => {
|
|
180
|
+
const project = path.join(tempRoot, 'project');
|
|
181
|
+
await fs.mkdir(project);
|
|
182
|
+
await fs.writeFile(path.join(project, 'Token.sol'), 'contract Token {}');
|
|
183
|
+
const vectorDatabase = createVectorDatabase();
|
|
184
|
+
const splitter = new RecordingSplitter('context');
|
|
185
|
+
const context = new context_1.Context({
|
|
186
|
+
embedding: new TestEmbedding(),
|
|
187
|
+
vectorDatabase,
|
|
188
|
+
codeSplitter: splitter,
|
|
189
|
+
});
|
|
190
|
+
await context.indexCodebase(project);
|
|
191
|
+
expect(splitter.calls).toHaveLength(1);
|
|
192
|
+
expect(splitter.calls[0]).toMatchObject({
|
|
193
|
+
language: 'solidity',
|
|
194
|
+
filePath: path.join(project, 'Token.sol'),
|
|
195
|
+
});
|
|
196
|
+
const insertedDocuments = vectorDatabase.insert.mock.calls
|
|
197
|
+
.flatMap(([, documents]) => documents);
|
|
198
|
+
expect(insertedDocuments).toHaveLength(1);
|
|
199
|
+
expect(insertedDocuments[0].relativePath).toBe('Token.sol');
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
//# sourceMappingURL=context.splitter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.splitter.test.js","sourceRoot":"","sources":["../src/context.splitter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { GoogleGenAI } from '@google/genai';
|
|
2
2
|
import { Embedding, EmbeddingVector } from './base-embedding';
|
|
3
|
+
type GeminiModelInfo = {
|
|
4
|
+
dimension: number;
|
|
5
|
+
contextLength: number;
|
|
6
|
+
description: string;
|
|
7
|
+
supportedDimensions?: number[];
|
|
8
|
+
};
|
|
3
9
|
export interface GeminiEmbeddingConfig {
|
|
4
10
|
model: string;
|
|
5
11
|
apiKey: string;
|
|
@@ -16,6 +22,7 @@ export declare class GeminiEmbedding extends Embedding {
|
|
|
16
22
|
detectDimension(): Promise<number>;
|
|
17
23
|
embed(text: string): Promise<EmbeddingVector>;
|
|
18
24
|
embedBatch(texts: string[]): Promise<EmbeddingVector[]>;
|
|
25
|
+
private embedProcessedText;
|
|
19
26
|
getDimension(): number;
|
|
20
27
|
getProvider(): string;
|
|
21
28
|
/**
|
|
@@ -35,12 +42,7 @@ export declare class GeminiEmbedding extends Embedding {
|
|
|
35
42
|
/**
|
|
36
43
|
* Get list of supported models
|
|
37
44
|
*/
|
|
38
|
-
static getSupportedModels(): Record<string,
|
|
39
|
-
dimension: number;
|
|
40
|
-
contextLength: number;
|
|
41
|
-
description: string;
|
|
42
|
-
supportedDimensions?: number[];
|
|
43
|
-
}>;
|
|
45
|
+
static getSupportedModels(): Record<string, GeminiModelInfo>;
|
|
44
46
|
/**
|
|
45
47
|
* Get supported dimensions for the current model
|
|
46
48
|
*/
|
|
@@ -50,4 +52,5 @@ export declare class GeminiEmbedding extends Embedding {
|
|
|
50
52
|
*/
|
|
51
53
|
isDimensionSupported(dimension: number): boolean;
|
|
52
54
|
}
|
|
55
|
+
export {};
|
|
53
56
|
//# sourceMappingURL=gemini-embedding.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini-embedding.d.ts","sourceRoot":"","sources":["../../src/embedding/gemini-embedding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE9D,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,qBAAa,eAAgB,SAAQ,SAAS;IAC1C,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,SAAS,CAAgB;IACjC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAQ;gBAEvB,MAAM,EAAE,qBAAqB;IAqBzC,OAAO,CAAC,uBAAuB;IAczB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;IAKlC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"gemini-embedding.d.ts","sourceRoot":"","sources":["../../src/embedding/gemini-embedding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE9D,KAAK,eAAe,GAAG;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC,CAAC;AAEF,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,qBAAa,eAAgB,SAAQ,SAAS;IAC1C,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,SAAS,CAAgB;IACjC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAQ;gBAEvB,MAAM,EAAE,qBAAqB;IAqBzC,OAAO,CAAC,uBAAuB;IAczB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;IAKlC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAW7C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;YAuC/C,kBAAkB;IAmBhC,YAAY,IAAI,MAAM;IAItB,WAAW,IAAI,MAAM;IAIrB;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK7B;;;OAGG;IACH,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKhD;;OAEG;IACH,SAAS,IAAI,WAAW;IAIxB;;OAEG;IACH,MAAM,CAAC,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC;IAiB5D;;OAEG;IACH,sBAAsB,IAAI,MAAM,EAAE;IAKlC;;OAEG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;CAInD"}
|
|
@@ -6,7 +6,7 @@ const base_embedding_1 = require("./base-embedding");
|
|
|
6
6
|
class GeminiEmbedding extends base_embedding_1.Embedding {
|
|
7
7
|
constructor(config) {
|
|
8
8
|
super();
|
|
9
|
-
this.dimension = 3072; // Default dimension for
|
|
9
|
+
this.dimension = 3072; // Default dimension for Gemini embedding models
|
|
10
10
|
this.maxTokens = 2048; // Maximum tokens for Gemini embedding models
|
|
11
11
|
this.config = config;
|
|
12
12
|
this.client = new genai_1.GoogleGenAI({
|
|
@@ -45,26 +45,16 @@ class GeminiEmbedding extends base_embedding_1.Embedding {
|
|
|
45
45
|
const processedText = this.preprocessText(text);
|
|
46
46
|
const model = this.config.model || 'gemini-embedding-001';
|
|
47
47
|
try {
|
|
48
|
-
|
|
49
|
-
model: model,
|
|
50
|
-
contents: processedText,
|
|
51
|
-
config: {
|
|
52
|
-
outputDimensionality: this.config.outputDimensionality || this.dimension,
|
|
53
|
-
},
|
|
54
|
-
});
|
|
55
|
-
if (!response.embeddings || !response.embeddings[0] || !response.embeddings[0].values) {
|
|
56
|
-
throw new Error('Gemini API returned invalid response');
|
|
57
|
-
}
|
|
58
|
-
return {
|
|
59
|
-
vector: response.embeddings[0].values,
|
|
60
|
-
dimension: response.embeddings[0].values.length
|
|
61
|
-
};
|
|
48
|
+
return await this.embedProcessedText(processedText, model);
|
|
62
49
|
}
|
|
63
50
|
catch (error) {
|
|
64
51
|
throw new Error(`Gemini embedding failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
65
52
|
}
|
|
66
53
|
}
|
|
67
54
|
async embedBatch(texts) {
|
|
55
|
+
if (texts.length === 0) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
68
58
|
const processedTexts = this.preprocessTexts(texts);
|
|
69
59
|
const model = this.config.model || 'gemini-embedding-001';
|
|
70
60
|
try {
|
|
@@ -78,6 +68,9 @@ class GeminiEmbedding extends base_embedding_1.Embedding {
|
|
|
78
68
|
if (!response.embeddings) {
|
|
79
69
|
throw new Error('Gemini API returned invalid response');
|
|
80
70
|
}
|
|
71
|
+
if (response.embeddings.length !== processedTexts.length) {
|
|
72
|
+
throw new Error(`Gemini API returned ${response.embeddings.length} embeddings for ${processedTexts.length} inputs`);
|
|
73
|
+
}
|
|
81
74
|
return response.embeddings.map((embedding) => {
|
|
82
75
|
if (!embedding.values) {
|
|
83
76
|
throw new Error('Gemini API returned invalid embedding data');
|
|
@@ -92,6 +85,22 @@ class GeminiEmbedding extends base_embedding_1.Embedding {
|
|
|
92
85
|
throw new Error(`Gemini batch embedding failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
93
86
|
}
|
|
94
87
|
}
|
|
88
|
+
async embedProcessedText(processedText, model) {
|
|
89
|
+
const response = await this.client.models.embedContent({
|
|
90
|
+
model: model,
|
|
91
|
+
contents: processedText,
|
|
92
|
+
config: {
|
|
93
|
+
outputDimensionality: this.config.outputDimensionality || this.dimension,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
if (!response.embeddings || !response.embeddings[0] || !response.embeddings[0].values) {
|
|
97
|
+
throw new Error('Gemini API returned invalid response');
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
vector: response.embeddings[0].values,
|
|
101
|
+
dimension: response.embeddings[0].values.length
|
|
102
|
+
};
|
|
103
|
+
}
|
|
95
104
|
getDimension() {
|
|
96
105
|
return this.dimension;
|
|
97
106
|
}
|
|
@@ -128,8 +137,14 @@ class GeminiEmbedding extends base_embedding_1.Embedding {
|
|
|
128
137
|
'gemini-embedding-001': {
|
|
129
138
|
dimension: 3072,
|
|
130
139
|
contextLength: 2048,
|
|
131
|
-
description: '
|
|
140
|
+
description: 'Gemini embedding model with state-of-the-art performance',
|
|
132
141
|
supportedDimensions: [3072, 1536, 768, 256] // Matryoshka Representation Learning support
|
|
142
|
+
},
|
|
143
|
+
'gemini-embedding-2': {
|
|
144
|
+
dimension: 3072,
|
|
145
|
+
contextLength: 8192,
|
|
146
|
+
description: 'Gemini Embedding 2 model with improved embedding quality and longer context',
|
|
147
|
+
supportedDimensions: [3072, 1536, 768, 256]
|
|
133
148
|
}
|
|
134
149
|
};
|
|
135
150
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini-embedding.js","sourceRoot":"","sources":["../../src/embedding/gemini-embedding.ts"],"names":[],"mappings":";;;AAAA,yCAA4C;AAC5C,qDAA8D;
|
|
1
|
+
{"version":3,"file":"gemini-embedding.js","sourceRoot":"","sources":["../../src/embedding/gemini-embedding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini-embedding.test.d.ts","sourceRoot":"","sources":["../../src/embedding/gemini-embedding.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const genai_1 = require("@google/genai");
|
|
4
|
+
const gemini_embedding_1 = require("./gemini-embedding");
|
|
5
|
+
const mockEmbedContent = jest.fn();
|
|
6
|
+
jest.mock('@google/genai', () => ({
|
|
7
|
+
GoogleGenAI: jest.fn().mockImplementation(() => ({
|
|
8
|
+
models: {
|
|
9
|
+
embedContent: mockEmbedContent
|
|
10
|
+
}
|
|
11
|
+
}))
|
|
12
|
+
}));
|
|
13
|
+
describe('GeminiEmbedding', () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
mockEmbedContent.mockReset();
|
|
16
|
+
genai_1.GoogleGenAI.mockClear();
|
|
17
|
+
});
|
|
18
|
+
it('exposes Gemini Embedding 2 model metadata', () => {
|
|
19
|
+
const supportedModels = gemini_embedding_1.GeminiEmbedding.getSupportedModels();
|
|
20
|
+
expect(supportedModels['gemini-embedding-2']).toMatchObject({
|
|
21
|
+
dimension: 3072,
|
|
22
|
+
contextLength: 8192,
|
|
23
|
+
});
|
|
24
|
+
const embedding = new gemini_embedding_1.GeminiEmbedding({
|
|
25
|
+
apiKey: 'test-api-key',
|
|
26
|
+
model: 'gemini-embedding-2',
|
|
27
|
+
});
|
|
28
|
+
expect(embedding.getDimension()).toBe(3072);
|
|
29
|
+
expect(embedding.getSupportedDimensions()).toContain(3072);
|
|
30
|
+
expect(embedding.getSupportedDimensions()).toContain(768);
|
|
31
|
+
});
|
|
32
|
+
it('keeps batched request behavior for Gemini Embedding 2', async () => {
|
|
33
|
+
mockEmbedContent.mockResolvedValue({
|
|
34
|
+
embeddings: [
|
|
35
|
+
{ values: [1, 0, 0] },
|
|
36
|
+
{ values: [0, 1, 0] },
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
const embedding = new gemini_embedding_1.GeminiEmbedding({
|
|
40
|
+
apiKey: 'test-api-key',
|
|
41
|
+
model: 'gemini-embedding-2',
|
|
42
|
+
});
|
|
43
|
+
const embeddings = await embedding.embedBatch(['first chunk', 'second chunk']);
|
|
44
|
+
expect(embeddings).toEqual([
|
|
45
|
+
{ vector: [1, 0, 0], dimension: 3 },
|
|
46
|
+
{ vector: [0, 1, 0], dimension: 3 },
|
|
47
|
+
]);
|
|
48
|
+
expect(mockEmbedContent).toHaveBeenCalledTimes(1);
|
|
49
|
+
expect(mockEmbedContent).toHaveBeenCalledWith({
|
|
50
|
+
model: 'gemini-embedding-2',
|
|
51
|
+
contents: ['first chunk', 'second chunk'],
|
|
52
|
+
config: {
|
|
53
|
+
outputDimensionality: 3072,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
it('keeps the existing batched request behavior for Gemini Embedding 001', async () => {
|
|
58
|
+
mockEmbedContent.mockResolvedValue({
|
|
59
|
+
embeddings: [
|
|
60
|
+
{ values: [1, 0, 0] },
|
|
61
|
+
{ values: [0, 1, 0] },
|
|
62
|
+
],
|
|
63
|
+
});
|
|
64
|
+
const embedding = new gemini_embedding_1.GeminiEmbedding({
|
|
65
|
+
apiKey: 'test-api-key',
|
|
66
|
+
model: 'gemini-embedding-001',
|
|
67
|
+
});
|
|
68
|
+
const embeddings = await embedding.embedBatch(['first chunk', 'second chunk']);
|
|
69
|
+
expect(embeddings).toEqual([
|
|
70
|
+
{ vector: [1, 0, 0], dimension: 3 },
|
|
71
|
+
{ vector: [0, 1, 0], dimension: 3 },
|
|
72
|
+
]);
|
|
73
|
+
expect(mockEmbedContent).toHaveBeenCalledTimes(1);
|
|
74
|
+
expect(mockEmbedContent).toHaveBeenCalledWith({
|
|
75
|
+
model: 'gemini-embedding-001',
|
|
76
|
+
contents: ['first chunk', 'second chunk'],
|
|
77
|
+
config: {
|
|
78
|
+
outputDimensionality: 3072,
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
it('throws a clear error when a batched response count does not match the inputs', async () => {
|
|
83
|
+
mockEmbedContent.mockResolvedValue({
|
|
84
|
+
embeddings: [
|
|
85
|
+
{ values: [1, 0, 0] },
|
|
86
|
+
],
|
|
87
|
+
});
|
|
88
|
+
const embedding = new gemini_embedding_1.GeminiEmbedding({
|
|
89
|
+
apiKey: 'test-api-key',
|
|
90
|
+
model: 'gemini-embedding-001',
|
|
91
|
+
});
|
|
92
|
+
await expect(embedding.embedBatch(['first chunk', 'second chunk']))
|
|
93
|
+
.rejects
|
|
94
|
+
.toThrow('Gemini API returned 1 embeddings for 2 inputs');
|
|
95
|
+
});
|
|
96
|
+
it('returns an empty batch without calling the Gemini API', async () => {
|
|
97
|
+
const embedding = new gemini_embedding_1.GeminiEmbedding({
|
|
98
|
+
apiKey: 'test-api-key',
|
|
99
|
+
model: 'gemini-embedding-2',
|
|
100
|
+
});
|
|
101
|
+
await expect(embedding.embedBatch([])).resolves.toEqual([]);
|
|
102
|
+
expect(mockEmbedContent).not.toHaveBeenCalled();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
//# sourceMappingURL=gemini-embedding.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini-embedding.test.js","sourceRoot":"","sources":["../../src/embedding/gemini-embedding.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"synchronizer.d.ts","sourceRoot":"","sources":["../../src/sync/synchronizer.ts"],"names":[],"mappings":"AAMA,qBAAa,gBAAgB;IACzB,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,cAAc,CAAW;IACjC,OAAO,CAAC,mBAAmB,CAAW;gBAE1B,OAAO,EAAE,MAAM,EAAE,cAAc,GAAE,MAAM,EAAO,EAAE,mBAAmB,GAAE,MAAM,EAAO;IAS9F,OAAO,CAAC,eAAe;YAUT,QAAQ;YAUR,kBAAkB;IA4DhC,OAAO,CAAC,YAAY;
|
|
1
|
+
{"version":3,"file":"synchronizer.d.ts","sourceRoot":"","sources":["../../src/sync/synchronizer.ts"],"names":[],"mappings":"AAMA,qBAAa,gBAAgB;IACzB,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,cAAc,CAAW;IACjC,OAAO,CAAC,mBAAmB,CAAW;gBAE1B,OAAO,EAAE,MAAM,EAAE,cAAc,GAAE,MAAM,EAAO,EAAE,mBAAmB,GAAE,MAAM,EAAO;IAS9F,OAAO,CAAC,eAAe;YAUT,QAAQ;YAUR,kBAAkB;IA4DhC,OAAO,CAAC,YAAY;IAuCpB,OAAO,CAAC,YAAY;IAoCpB,OAAO,CAAC,uBAAuB;IAc/B,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,cAAc;IAsBT,UAAU;IAOV,eAAe,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IA0BnG,OAAO,CAAC,aAAa;IA0Bd,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;YAI1C,YAAY;YAmBZ,YAAY;IA2B1B;;OAEG;WACU,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAmBnE"}
|
|
@@ -78,7 +78,7 @@ class FileSynchronizer {
|
|
|
78
78
|
const fullPath = path.join(dir, entry.name);
|
|
79
79
|
const relativePath = path.relative(this.rootDir, fullPath);
|
|
80
80
|
// Check if this path should be ignored BEFORE any file system operations
|
|
81
|
-
if (this.shouldIgnore(relativePath
|
|
81
|
+
if (this.shouldIgnore(relativePath)) {
|
|
82
82
|
continue; // Skip completely - no access at all
|
|
83
83
|
}
|
|
84
84
|
// Double-check with fs.stat to be absolutely sure about file type
|
|
@@ -92,7 +92,7 @@ class FileSynchronizer {
|
|
|
92
92
|
}
|
|
93
93
|
if (stat.isDirectory()) {
|
|
94
94
|
// Verify it's really a directory and not ignored
|
|
95
|
-
if (!this.shouldIgnore(relativePath
|
|
95
|
+
if (!this.shouldIgnore(relativePath)) {
|
|
96
96
|
const subHashes = await this.generateFileHashes(fullPath);
|
|
97
97
|
const entries = Array.from(subHashes.entries());
|
|
98
98
|
for (let i = 0; i < entries.length; i++) {
|
|
@@ -103,7 +103,7 @@ class FileSynchronizer {
|
|
|
103
103
|
}
|
|
104
104
|
else if (stat.isFile()) {
|
|
105
105
|
// Verify it's really a file and not ignored
|
|
106
|
-
if (!this.shouldIgnore(relativePath
|
|
106
|
+
if (!this.shouldIgnore(relativePath)) {
|
|
107
107
|
const ext = path.extname(entry.name);
|
|
108
108
|
if (this.supportedExtensions.length > 0 && !this.supportedExtensions.includes(ext)) {
|
|
109
109
|
continue;
|
|
@@ -122,7 +122,7 @@ class FileSynchronizer {
|
|
|
122
122
|
}
|
|
123
123
|
return fileHashes;
|
|
124
124
|
}
|
|
125
|
-
shouldIgnore(relativePath
|
|
125
|
+
shouldIgnore(relativePath) {
|
|
126
126
|
// Always ignore hidden files and directories (starting with .)
|
|
127
127
|
const pathParts = relativePath.split(path.sep);
|
|
128
128
|
if (pathParts.some(part => part.startsWith('.'))) {
|
|
@@ -138,7 +138,7 @@ class FileSynchronizer {
|
|
|
138
138
|
}
|
|
139
139
|
// Check direct pattern matches first
|
|
140
140
|
for (const pattern of this.ignorePatterns) {
|
|
141
|
-
if (this.matchPattern(normalizedPath, pattern
|
|
141
|
+
if (this.matchPattern(normalizedPath, pattern)) {
|
|
142
142
|
return true;
|
|
143
143
|
}
|
|
144
144
|
}
|
|
@@ -147,45 +147,33 @@ class FileSynchronizer {
|
|
|
147
147
|
for (let i = 0; i < normalizedPathParts.length; i++) {
|
|
148
148
|
const partialPath = normalizedPathParts.slice(0, i + 1).join('/');
|
|
149
149
|
for (const pattern of this.ignorePatterns) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const dirPattern = pattern.slice(0, -1);
|
|
153
|
-
if (this.simpleGlobMatch(partialPath, dirPattern) ||
|
|
154
|
-
this.simpleGlobMatch(normalizedPathParts[i], dirPattern)) {
|
|
155
|
-
return true;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
// Check exact path patterns
|
|
159
|
-
else if (pattern.includes('/')) {
|
|
160
|
-
if (this.simpleGlobMatch(partialPath, pattern)) {
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
// Check filename patterns against any path component
|
|
165
|
-
else {
|
|
166
|
-
if (this.simpleGlobMatch(normalizedPathParts[i], pattern)) {
|
|
167
|
-
return true;
|
|
168
|
-
}
|
|
150
|
+
if (this.matchPattern(partialPath, pattern)) {
|
|
151
|
+
return true;
|
|
169
152
|
}
|
|
170
153
|
}
|
|
171
154
|
}
|
|
172
155
|
return false;
|
|
173
156
|
}
|
|
174
|
-
matchPattern(filePath, pattern
|
|
157
|
+
matchPattern(filePath, pattern) {
|
|
175
158
|
// Clean both path and pattern
|
|
176
159
|
const cleanPath = filePath.replace(/^\/+|\/+$/g, '');
|
|
177
|
-
const
|
|
160
|
+
const normalizedPattern = pattern.replace(/\\/g, '/');
|
|
161
|
+
const cleanPattern = normalizedPattern.replace(/^\/+|\/+$/g, '');
|
|
162
|
+
const isRootAnchored = normalizedPattern.startsWith('/');
|
|
163
|
+
const isDirectoryPattern = normalizedPattern.endsWith('/');
|
|
178
164
|
if (!cleanPath || !cleanPattern) {
|
|
179
165
|
return false;
|
|
180
166
|
}
|
|
181
167
|
// Handle directory patterns (ending with /)
|
|
182
|
-
if (
|
|
183
|
-
if (
|
|
184
|
-
return
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return this.
|
|
188
|
-
|
|
168
|
+
if (isDirectoryPattern) {
|
|
169
|
+
if (isRootAnchored) {
|
|
170
|
+
return this.simpleGlobMatch(cleanPath, cleanPattern) ||
|
|
171
|
+
cleanPath.startsWith(`${cleanPattern}/`);
|
|
172
|
+
}
|
|
173
|
+
return this.matchesDirectoryPattern(cleanPath, cleanPattern);
|
|
174
|
+
}
|
|
175
|
+
if (isRootAnchored) {
|
|
176
|
+
return this.simpleGlobMatch(cleanPath, cleanPattern);
|
|
189
177
|
}
|
|
190
178
|
// Handle path patterns (containing /)
|
|
191
179
|
if (cleanPattern.includes('/')) {
|
|
@@ -195,6 +183,17 @@ class FileSynchronizer {
|
|
|
195
183
|
const fileName = path.basename(cleanPath);
|
|
196
184
|
return this.simpleGlobMatch(fileName, cleanPattern);
|
|
197
185
|
}
|
|
186
|
+
matchesDirectoryPattern(filePath, dirPattern) {
|
|
187
|
+
const pathParts = filePath.split('/');
|
|
188
|
+
const dirPartCount = dirPattern.split('/').length;
|
|
189
|
+
for (let i = 0; i <= pathParts.length - dirPartCount; i++) {
|
|
190
|
+
const candidate = pathParts.slice(i, i + dirPartCount).join('/');
|
|
191
|
+
if (this.simpleGlobMatch(candidate, dirPattern)) {
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
198
197
|
simpleGlobMatch(text, pattern) {
|
|
199
198
|
if (!text || !pattern)
|
|
200
199
|
return false;
|