Skip to content

Commit 6d188d7

Browse files
authored
chore: update langchain dependencies and refactor SimilarityModel (#500)
Signed-off-by: Gordon Smith <GordonJSmith@gmail.com>
1 parent dc69c4b commit 6d188d7

10 files changed

Lines changed: 10559 additions & 10397 deletions

File tree

package-lock.json

Lines changed: 10275 additions & 10366 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -52,49 +52,50 @@
5252
"update": "npx npm-check-updates -u -t minor"
5353
},
5454
"dependencies": {
55-
"@vscode/prompt-tsx": "0.4.0-alpha.6",
55+
"@vscode/prompt-tsx": "0.4.0-alpha.7",
5656
"exceljs": "4.4.0",
5757
"html-to-text": "9.0.5"
5858
},
5959
"devDependencies": {
6060
"@eslint/js": "9.39.2",
61-
"@fluentui/react": "8.125.3",
61+
"@fluentui/react": "8.125.4",
6262
"@fluentui/react-hooks": "8.10.2",
63-
"@hpcc-js/api": "3.4.6",
64-
"@hpcc-js/common": "3.6.2",
65-
"@hpcc-js/comms": "3.14.1",
66-
"@hpcc-js/dgrid": "3.5.6",
67-
"@hpcc-js/dgrid-shim": "3.3.2",
68-
"@hpcc-js/esbuild-plugins": "1.8.1",
63+
"@hpcc-js/api": "3.4.9",
64+
"@hpcc-js/common": "3.6.5",
65+
"@hpcc-js/comms": "3.14.4",
66+
"@hpcc-js/dgrid": "3.5.9",
67+
"@hpcc-js/dgrid-shim": "3.3.3",
68+
"@hpcc-js/esbuild-plugins": "1.8.3",
6969
"@hpcc-js/observable-shim": "3.1.0",
70-
"@hpcc-js/observablehq-compiler": "3.7.2",
71-
"@hpcc-js/util": "3.4.5",
72-
"@hpcc-js/wasm-expat": "1.12.0",
70+
"@hpcc-js/observablehq-compiler": "3.7.4",
71+
"@hpcc-js/util": "3.4.8",
72+
"@hpcc-js/wasm-expat": "1.13.0",
7373
"@hpcc-js/wasm-llama": "1.0.0",
74-
"@hpcc-js/wasm-zstd": "1.11.0",
75-
"@langchain/community": "0.3.59",
76-
"@langchain/core": "0.3.80",
77-
"@langchain/ollama": "0.2.4",
74+
"@hpcc-js/wasm-zstd": "1.12.0",
75+
"@langchain/community": "1.1.15",
76+
"@langchain/core": "1.1.24",
77+
"@langchain/classic": "1.0.17",
78+
"@langchain/ollama": "1.2.2",
7879
"@observablehq/inspector": "5.0.1",
7980
"@observablehq/parser": "6.1.0",
8081
"@observablehq/runtime": "6.0.0",
8182
"@observablehq/stdlib": "5.8.8",
8283
"@octokit/rest": "22.0.1",
8384
"@types/mocha": "10.0.10",
84-
"@types/node": "24.10.9",
85-
"@types/react": "18.3.27",
85+
"@types/node": "24.10.13",
86+
"@types/react": "18.3.28",
8687
"@types/react-dom": "18.3.7",
8788
"@types/tmp": "0.2.6",
8889
"@types/vscode": "1.105.0",
8990
"@types/vscode-notebook-renderer": "1.72.4",
9091
"@vscode/test-cli": "0.0.12",
9192
"@vscode/test-electron": "2.5.2",
92-
"@typescript-eslint/parser": "8.53.1",
93+
"@typescript-eslint/parser": "8.55.0",
9394
"@vitest/coverage-v8": "4.0.18",
9495
"@vitest/ui": "4.0.18",
9596
"@vscode/debugadapter": "1.68.0",
9697
"@vscode/debugprotocol": "1.68.0",
97-
"@vscode/extension-telemetry": "1.4.0",
98+
"@vscode/extension-telemetry": "1.5.0",
9899
"@vscode/vsce": "3.7.1",
99100
"adm-zip": "0.5.16",
100101
"antlr4": "4.13.2",
@@ -103,22 +104,22 @@
103104
"copyfiles": "2.4.1",
104105
"csv-writer": "1.6.0",
105106
"diff": "8.0.3",
106-
"esbuild": "0.27.2",
107+
"esbuild": "0.27.3",
107108
"esbuild-copy-static-files": "0.1.0",
108109
"esbuild-plugin-text-replace": "1.3.0",
109110
"esbuild-plugin-umd-wrapper": "3.0.0",
110111
"eslint": "9.39.2",
111112
"eslint-plugin-react-hooks": "7.0.1",
112-
"jsdom": "27.4.0",
113-
"langchain": "0.3.37",
113+
"jsdom": "28.0.0",
114+
"langchain": "1.2.23",
114115
"npm-run-all": "4.1.5",
115116
"react": "18.3.1",
116117
"react-dom": "18.3.1",
117118
"rimraf": "6.1.2",
118119
"run-script-os": "1.1.6",
119120
"tslib": "2.8.1",
120121
"typescript": "5.9.3",
121-
"typescript-eslint": "8.53.1",
122+
"typescript-eslint": "8.55.0",
122123
"use-resize-observer": "9.1.0",
123124
"uuid": "13.0.0",
124125
"vitest": "4.0.18",

src/ecl/docs/SimilarityModel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as vscode from "vscode";
22
import { Llama } from "@hpcc-js/wasm-llama";
33
import { Zstd } from "@hpcc-js/wasm-zstd";
44
import { Embeddings } from "@langchain/core/embeddings";
5-
import { MemoryVectorStore } from "langchain/vectorstores/memory";
5+
import { MemoryVectorStore } from "@langchain/classic/vectorstores/memory";
66

77
class LlamaEmbeddings extends Embeddings {
88

test/SimilarityModel.test.ts

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import { describe, it, expect, beforeEach, vi } from "vitest";
2+
import * as vscode from "vscode";
3+
import { loadStore } from "../src/ecl/docs/SimilarityModel";
4+
import { MemoryVectorStore } from "@langchain/classic/vectorstores/memory";
5+
6+
// Mock vscode module
7+
vi.mock("vscode", () => ({
8+
workspace: {
9+
fs: {
10+
readFile: vi.fn()
11+
}
12+
},
13+
Uri: {
14+
file: (path: string) => ({ fsPath: path, path })
15+
}
16+
}));
17+
18+
// Mock @hpcc-js/wasm-llama
19+
vi.mock("@hpcc-js/wasm-llama", () => ({
20+
Llama: {
21+
load: vi.fn(() => Promise.resolve({
22+
embedding: vi.fn((text: string, modelData: Uint8Array) => {
23+
// Return mock embeddings based on text length
24+
return [[text.length / 100, (text.length * 2) / 100, (text.length * 3) / 100]];
25+
})
26+
})),
27+
unload: vi.fn()
28+
}
29+
}));
30+
31+
// Mock @hpcc-js/wasm-zstd
32+
vi.mock("@hpcc-js/wasm-zstd", () => ({
33+
Zstd: {
34+
load: vi.fn(() => Promise.resolve({
35+
decompress: vi.fn((data: Uint8Array) => {
36+
// Mock decompression - just return a stringified JSON
37+
const mockData = {
38+
vectors: [
39+
{
40+
content: "test document 1",
41+
embedding: [0.1, 0.2, 0.3],
42+
metadata: { source: "doc1" }
43+
},
44+
{
45+
content: "test document 2",
46+
embedding: [0.4, 0.5, 0.6],
47+
metadata: { source: "doc2" }
48+
}
49+
]
50+
};
51+
const jsonStr = JSON.stringify(mockData);
52+
return new TextEncoder().encode(jsonStr);
53+
})
54+
}))
55+
}
56+
}));
57+
58+
describe("SimilarityModel loadStore", () => {
59+
beforeEach(() => {
60+
vi.clearAllMocks();
61+
});
62+
63+
it("should load and return a MemoryVectorStore instance", async () => {
64+
// Mock file reading
65+
const mockModelData = new Uint8Array([1, 2, 3, 4]);
66+
const mockDocsData = new Uint8Array([5, 6, 7, 8]);
67+
68+
vi.mocked(vscode.workspace.fs.readFile)
69+
.mockResolvedValueOnce(mockModelData)
70+
.mockResolvedValueOnce(mockDocsData);
71+
72+
const modelPath = Promise.resolve(vscode.Uri.file("/path/to/model.bin"));
73+
const docsPath = vscode.Uri.file("/path/to/docs.vecdb");
74+
75+
const store = await loadStore(modelPath, docsPath);
76+
77+
expect(store).toBeDefined();
78+
expect(store).toBeInstanceOf(MemoryVectorStore);
79+
});
80+
81+
it("should read the model and docs files", async () => {
82+
const mockModelData = new Uint8Array([1, 2, 3, 4]);
83+
const mockDocsData = new Uint8Array([5, 6, 7, 8]);
84+
85+
vi.mocked(vscode.workspace.fs.readFile)
86+
.mockResolvedValueOnce(mockModelData)
87+
.mockResolvedValueOnce(mockDocsData);
88+
89+
const modelPath = Promise.resolve(vscode.Uri.file("/path/to/model.bin"));
90+
const docsPath = vscode.Uri.file("/path/to/docs.vecdb");
91+
92+
await loadStore(modelPath, docsPath);
93+
94+
expect(vscode.workspace.fs.readFile).toHaveBeenCalledTimes(2);
95+
});
96+
97+
it("should decompress the docs file using Zstd", async () => {
98+
const { Zstd } = await import("@hpcc-js/wasm-zstd");
99+
100+
const mockModelData = new Uint8Array([1, 2, 3, 4]);
101+
const mockDocsData = new Uint8Array([5, 6, 7, 8]);
102+
103+
vi.mocked(vscode.workspace.fs.readFile)
104+
.mockResolvedValueOnce(mockModelData)
105+
.mockResolvedValueOnce(mockDocsData);
106+
107+
const modelPath = Promise.resolve(vscode.Uri.file("/path/to/model.bin"));
108+
const docsPath = vscode.Uri.file("/path/to/docs.vecdb");
109+
110+
await loadStore(modelPath, docsPath);
111+
112+
expect(Zstd.load).toHaveBeenCalled();
113+
});
114+
115+
it("should populate memoryVectors with decompressed data", async () => {
116+
const mockModelData = new Uint8Array([1, 2, 3, 4]);
117+
const mockDocsData = new Uint8Array([5, 6, 7, 8]);
118+
119+
vi.mocked(vscode.workspace.fs.readFile)
120+
.mockResolvedValueOnce(mockModelData)
121+
.mockResolvedValueOnce(mockDocsData);
122+
123+
const modelPath = Promise.resolve(vscode.Uri.file("/path/to/model.bin"));
124+
const docsPath = vscode.Uri.file("/path/to/docs.vecdb");
125+
126+
const store = await loadStore(modelPath, docsPath);
127+
128+
expect(store.memoryVectors).toBeDefined();
129+
expect(Array.isArray(store.memoryVectors)).toBe(true);
130+
expect(store.memoryVectors.length).toBe(2);
131+
});
132+
133+
it("should return a store with the correct vector data structure", async () => {
134+
const mockModelData = new Uint8Array([1, 2, 3, 4]);
135+
const mockDocsData = new Uint8Array([5, 6, 7, 8]);
136+
137+
vi.mocked(vscode.workspace.fs.readFile)
138+
.mockResolvedValueOnce(mockModelData)
139+
.mockResolvedValueOnce(mockDocsData);
140+
141+
const modelPath = Promise.resolve(vscode.Uri.file("/path/to/model.bin"));
142+
const docsPath = vscode.Uri.file("/path/to/docs.vecdb");
143+
144+
const store = await loadStore(modelPath, docsPath);
145+
146+
expect(store.memoryVectors.length).toBe(2);
147+
expect(store.memoryVectors[0]).toHaveProperty("content");
148+
expect(store.memoryVectors[0]).toHaveProperty("embedding");
149+
expect(store.memoryVectors[0]).toHaveProperty("metadata");
150+
});
151+
152+
it("should handle errors when model file cannot be read", async () => {
153+
vi.mocked(vscode.workspace.fs.readFile)
154+
.mockRejectedValueOnce(new Error("Model file not found"));
155+
156+
const modelPath = Promise.resolve(vscode.Uri.file("/invalid/model.bin"));
157+
const docsPath = vscode.Uri.file("/path/to/docs.vecdb");
158+
159+
await expect(loadStore(modelPath, docsPath)).rejects.toThrow("Model file not found");
160+
});
161+
162+
it("should handle errors when docs file cannot be read", async () => {
163+
vi.mocked(vscode.workspace.fs.readFile)
164+
.mockRejectedValueOnce(new Error("Docs file not found"));
165+
166+
const modelPath = Promise.resolve(vscode.Uri.file("/path/to/model.bin"));
167+
const docsPath = vscode.Uri.file("/invalid/docs.vecdb");
168+
169+
await expect(loadStore(modelPath, docsPath)).rejects.toThrow("Docs file not found");
170+
});
171+
172+
it("should handle invalid JSON in decompressed data", async () => {
173+
const { Zstd } = await import("@hpcc-js/wasm-zstd");
174+
175+
// Mock Zstd to return invalid JSON
176+
vi.mocked(Zstd.load).mockResolvedValueOnce({
177+
decompress: vi.fn(() => new TextEncoder().encode("invalid json"))
178+
} as any);
179+
180+
const mockModelData = new Uint8Array([1, 2, 3, 4]);
181+
const mockDocsData = new Uint8Array([5, 6, 7, 8]);
182+
183+
vi.mocked(vscode.workspace.fs.readFile)
184+
.mockResolvedValueOnce(mockModelData)
185+
.mockResolvedValueOnce(mockDocsData);
186+
187+
const modelPath = Promise.resolve(vscode.Uri.file("/path/to/model.bin"));
188+
const docsPath = vscode.Uri.file("/path/to/docs.vecdb");
189+
190+
await expect(loadStore(modelPath, docsPath)).rejects.toThrow();
191+
});
192+
});

test/__mocks__/vscode.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Mock vscode module for vitest tests
2+
export const workspace = {
3+
fs: {
4+
readFile: () => Promise.resolve(new Uint8Array())
5+
}
6+
};
7+
8+
export const Uri = {
9+
file: (path: string) => ({ fsPath: path, path })
10+
};
11+
12+
// Add other vscode APIs as needed for tests
13+
export default {
14+
workspace,
15+
Uri
16+
};

test/integration/runTest.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import * as path from 'path';
22
import { runTests, downloadAndUnzipVSCode } from '@vscode/test-electron';
3+
import * as cp from 'child_process';
4+
import * as os from 'os';
35

46
async function main() {
57
try {
@@ -11,7 +13,32 @@ async function main() {
1113
const extensionTestsPath = path.resolve(__dirname, './suite/index');
1214

1315
// Ensure VS Code is downloaded (cache will be reused)
14-
await downloadAndUnzipVSCode('stable');
16+
const vscodeExecutablePath = await downloadAndUnzipVSCode('stable');
17+
18+
// Install the required extension dependency before running tests
19+
// Determine the CLI path based on the platform
20+
const platform = os.platform();
21+
let cliPath: string;
22+
23+
if (platform === 'darwin') {
24+
cliPath = path.join(vscodeExecutablePath, 'Contents', 'Resources', 'app', 'bin', 'code');
25+
} else if (platform === 'win32') {
26+
cliPath = path.join(path.dirname(vscodeExecutablePath), 'bin', 'code.cmd');
27+
} else {
28+
cliPath = path.join(path.dirname(vscodeExecutablePath), 'bin', 'code');
29+
}
30+
31+
console.log('Installing GordonSmith.observable-js extension...');
32+
try {
33+
cp.spawnSync(cliPath, ['--install-extension', 'GordonSmith.observable-js', '--force'], {
34+
encoding: 'utf-8',
35+
stdio: 'inherit'
36+
});
37+
console.log('Extension installation completed.');
38+
} catch (installErr) {
39+
console.warn('Warning: Failed to install GordonSmith.observable-js extension:', installErr);
40+
console.warn('Tests requiring this extension will be skipped.');
41+
}
1542

1643
await runTests({
1744
extensionDevelopmentPath,

test/integration/types.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ declare module '@vscode/test-electron' {
55
launchArgs?: string[];
66
}
77
export function runTests(options: RunTestsOptions): Promise<void>;
8-
export function downloadAndUnzipVSCode(version?: string): Promise<void>;
8+
export function downloadAndUnzipVSCode(version?: string): Promise<string>;
99
}

test/sample.test.ts

Lines changed: 0 additions & 2 deletions
This file was deleted.

test/vitest-setup.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* Vitest global setup file
3+
*
4+
* This file runs before vitest tests. Since vitest tests run in jsdom environment
5+
* (not a full VS Code instance), we don't install actual extensions here.
6+
* Instead, we ensure mocks are properly configured.
7+
*/
8+
9+
// Any global test setup can go here
10+
// For example, setting up global test utilities, polyfills, etc.
11+
12+
console.log('Vitest setup complete');

0 commit comments

Comments
 (0)