diff --git a/package-lock.json b/package-lock.json index cb2cd06..9888e9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "lb4-llm-chat-component", - "version": "1.18.0", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lb4-llm-chat-component", - "version": "1.18.0", + "version": "2.0.0", "license": "MIT", "dependencies": { "@langchain/community": "^0.3.50", @@ -152,40 +152,6 @@ "license": "MIT", "peer": true }, - "node_modules/@aws-crypto/crc32": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", - "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/crc32/node_modules/@aws-crypto/util": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", - "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/crc32/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD", - "optional": true, - "peer": true - }, "node_modules/@aws-crypto/crc32c": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz", @@ -1945,17 +1911,6 @@ } } }, - "node_modules/@aws-sdk/util-utf8-browser": { - "version": "3.259.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", - "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.3.1" - } - }, "node_modules/@aws-sdk/xml-builder": { "version": "3.972.2", "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.2.tgz", @@ -4943,17 +4898,6 @@ "make-plural": "^7.0.0" } }, - "node_modules/@mongodb-js/saslprep": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.5.tgz", - "integrity": "sha512-k64Lbyb7ycCSXHSLzxVdb2xsKGPMvYZfCICXvDsI8Z65CeWQzTEKS4YmGbnqw+U9RBvLPTsB6UCmwkgsDTGWIw==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "sparse-bitfield": "^3.0.3" - } - }, "node_modules/@noble/hashes": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", @@ -6160,48 +6104,6 @@ "node": ">=18.0.0" } }, - "node_modules/@smithy/eventstream-codec": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.2.0.tgz", - "integrity": "sha512-8janZoJw85nJmQZc4L8TuePp2pk1nxLgkxIR0TUjKJ5Dkj5oelB9WtiSSGXCQvNsJl0VSTvK/2ueMXxvpa9GVw==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "@aws-crypto/crc32": "3.0.0", - "@smithy/types": "^2.12.0", - "@smithy/util-hex-encoding": "^2.2.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/eventstream-codec/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/eventstream-codec/node_modules/@smithy/util-hex-encoding": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.2.0.tgz", - "integrity": "sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@smithy/eventstream-serde-browser": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.8.tgz", @@ -6618,35 +6520,6 @@ "node": ">=18.0.0" } }, - "node_modules/@smithy/protocol-http": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", - "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/protocol-http/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@smithy/querystring-builder": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.8.tgz", @@ -6699,83 +6572,6 @@ "node": ">=18.0.0" } }, - "node_modules/@smithy/signature-v4": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.3.0.tgz", - "integrity": "sha512-ui/NlpILU+6HAQBfJX8BBsDXuKSNrjTSuOYArRblcrErwKFutjrCNb/OExfVRyj9+26F9J+ZmfWT+fKWuDrH3Q==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "@smithy/types": "^2.12.0", - "@smithy/util-hex-encoding": "^2.2.0", - "@smithy/util-middleware": "^2.2.0", - "@smithy/util-uri-escape": "^2.2.0", - "@smithy/util-utf8": "^2.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/signature-v4/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/signature-v4/node_modules/@smithy/util-hex-encoding": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.2.0.tgz", - "integrity": "sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/signature-v4/node_modules/@smithy/util-middleware": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.2.0.tgz", - "integrity": "sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/signature-v4/node_modules/@smithy/util-uri-escape": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.2.0.tgz", - "integrity": "sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@smithy/smithy-client": { "version": "4.11.1", "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.11.1.tgz", @@ -7653,25 +7449,6 @@ "license": "MIT", "optional": true }, - "node_modules/@types/webidl-conversions": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/@types/whatwg-url": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", - "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@types/webidl-conversions": "*" - } - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", @@ -8635,17 +8412,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/bson": { - "version": "6.10.4", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz", - "integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "engines": { - "node": ">=16.20.1" - } - }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -17578,106 +17344,6 @@ "node": "*" } }, - "node_modules/mongodb": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.21.0.tgz", - "integrity": "sha512-URyb/VXMjJ4da46OeSXg+puO39XH9DeQpWCslifrRn9JWugy0D+DvvBvkm2WxmHe61O/H19JM66p1z7RHVkZ6A==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "@mongodb-js/saslprep": "^1.3.0", - "bson": "^6.10.4", - "mongodb-connection-string-url": "^3.0.2" - }, - "engines": { - "node": ">=16.20.1" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", - "gcp-metadata": "^5.2.0", - "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", - "snappy": "^7.3.2", - "socks": "^2.7.1" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, - "node_modules/mongodb-connection-string-url": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", - "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "@types/whatwg-url": "^11.0.2", - "whatwg-url": "^14.1.0 || ^13.0.0" - } - }, - "node_modules/mongodb-connection-string-url/node_modules/tr46": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tr46": "^5.1.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/mongodb-uri": { "version": "0.9.7", "resolved": "https://registry.npmjs.org/mongodb-uri/-/mongodb-uri-0.9.7.tgz", diff --git a/src/__tests__/db-query/unit/nodes/semantic-validator.node.unit.ts b/src/__tests__/db-query/unit/nodes/semantic-validator.node.unit.ts index 7c2716c..5df193a 100644 --- a/src/__tests__/db-query/unit/nodes/semantic-validator.node.unit.ts +++ b/src/__tests__/db-query/unit/nodes/semantic-validator.node.unit.ts @@ -4,12 +4,16 @@ import { EvaluationResult, SemanticValidatorNode, } from '../../../../components'; -import {DbSchemaHelperService} from '../../../../components/db-query/services'; +import { + DbSchemaHelperService, + TableSearchService, +} from '../../../../components/db-query/services'; import {LLMProvider} from '../../../../types'; describe('SemanticValidatorNode Unit', function () { let node: SemanticValidatorNode; let llmStub: sinon.SinonStub; + let tableSearchStub: sinon.SinonStubbedInstance; beforeEach(() => { llmStub = sinon.stub(); @@ -17,8 +21,16 @@ describe('SemanticValidatorNode Unit', function () { const schemaHelper = { asString: sinon.stub().returns(''), } as unknown as DbSchemaHelperService; + tableSearchStub = sinon.createStubInstance(TableSearchService); + tableSearchStub.getTables.resolves([]); - node = new SemanticValidatorNode(llm, llm, {models: []}, schemaHelper); + node = new SemanticValidatorNode( + llm, + llm, + {models: []}, + tableSearchStub, + schemaHelper, + ); }); afterEach(() => { @@ -64,6 +76,7 @@ describe('SemanticValidatorNode Unit', function () { }); it('should return QueryError if the query is invalid', async () => { + tableSearchStub.getTables.resolves(['users', 'orders']); const state = { prompt: 'Get all users', sql: 'SELECT * FROM invalid_table', @@ -154,4 +167,71 @@ describe('SemanticValidatorNode Unit', function () { const prompt = llmStub.firstCall.args[0]; expect(prompt.value).to.containEql('the previous query was wrong'); }); + + it('should pass all accessible tables from tableSearchService into available-tables so LLM can flag missing ones', async () => { + const searchedTables = [ + 'public.users', + 'public.orders', + 'public.payments', + 'analytics.reports', + ]; + tableSearchStub = sinon.createStubInstance(TableSearchService); + tableSearchStub.getTables.resolves(searchedTables); + + const schemaHelper = { + asString: sinon.stub().returns(''), + } as unknown as DbSchemaHelperService; + + const nodeWithTables = new SemanticValidatorNode( + llmStub as unknown as LLMProvider, + llmStub as unknown as LLMProvider, + {models: []}, + tableSearchStub, + schemaHelper, + ); + + const state = { + prompt: 'Get revenue per user', + sql: 'SELECT u.name, SUM(p.amount) FROM users u JOIN payments p ON u.id = p.user_id GROUP BY u.name', + schema: {tables: {}, relations: []}, + status: EvaluationResult.Pass, + id: 'test-id', + feedbacks: [], + replyToUser: '', + datasetId: 'test-dataset-id', + done: false, + sampleSqlPrompt: '', + sampleSql: '', + fromCache: false, + resultArray: undefined, + directCall: false, + description: undefined, + syntacticStatus: undefined, + syntacticFeedback: undefined, + semanticStatus: undefined, + semanticFeedback: undefined, + syntacticErrorTables: undefined, + semanticErrorTables: undefined, + fromTemplate: undefined, + templateId: undefined, + validationChecklist: '1. Revenue grouped by user', + changeType: undefined, + }; + + llmStub.resolves({content: ''}); + + await nodeWithTables.execute(state, {}); + + sinon.assert.calledOnce(tableSearchStub.getTables); + expect(tableSearchStub.getTables.firstCall.args[0]).to.equal( + 'Get revenue per user', + ); + + sinon.assert.calledOnce(llmStub); + const prompt = llmStub.firstCall.args[0]; + expect(prompt.value).to.containEql(''); + expect(prompt.value).to.containEql( + 'public.users, public.orders, public.payments, analytics.reports', + ); + }); }); diff --git a/src/components/db-query/models/index.ts b/src/components/db-query/models/index.ts index a556f88..dcb793e 100644 --- a/src/components/db-query/models/index.ts +++ b/src/components/db-query/models/index.ts @@ -1,4 +1,4 @@ -export * from './dataset.model'; export * from './dataset-action.model'; export * from './dataset-update-dto.model'; +export * from './dataset.model'; export * from './query-template-dto.model'; diff --git a/src/components/db-query/nodes/semantic-validator.node.ts b/src/components/db-query/nodes/semantic-validator.node.ts index 0a1a7f9..80aa625 100644 --- a/src/components/db-query/nodes/semantic-validator.node.ts +++ b/src/components/db-query/nodes/semantic-validator.node.ts @@ -9,7 +9,11 @@ import {LLMProvider} from '../../../types'; import {stripThinkingTokens} from '../../../utils'; import {DbQueryAIExtensionBindings} from '../keys'; import {DbQueryNodes} from '../nodes.enum'; -import {DbSchemaHelperService} from '../services'; +import { + DbSchemaHelperService, + PermissionHelper, + TableSearchService, +} from '../services'; import {DbQueryState} from '../state'; import {DbQueryConfig, EvaluationResult} from '../types'; @@ -22,8 +26,12 @@ export class SemanticValidatorNode implements IGraphNode { private readonly cheapllm: LLMProvider, @inject(DbQueryAIExtensionBindings.Config) private readonly config: DbQueryConfig, + @service(TableSearchService) + private readonly tableSearchService: TableSearchService, @service(DbSchemaHelperService) private readonly schemaHelper: DbSchemaHelperService, + @service(PermissionHelper) + private readonly permissionHelper?: PermissionHelper, ) {} prompt = PromptTemplate.fromTemplate(` @@ -103,13 +111,15 @@ Keep these feedbacks in mind while validating the new query. const useSmartLLM = this.config.nodes?.semanticValidatorNode?.useSmartLLM ?? false; const llm = useSmartLLM ? this.smartllm : this.cheapllm; - const tableNames = Object.keys(state.schema?.tables ?? {}); + const tableList = + (await this.tableSearchService.getTables(state.prompt)) ?? []; + const accessibleTables = this._filterByPermissions(tableList); const chain = RunnableSequence.from([this.prompt, llm]); const output = await chain.invoke({ userPrompt: state.prompt, query: state.sql, schema: this.schemaHelper.asString(state.schema), - tableNames: tableNames.join(', '), + tableNames: accessibleTables.join(', '), checklist: state.validationChecklist ?? 'No checklist provided.', feedbacks: await this.getFeedbacks(state), }); @@ -153,4 +163,15 @@ Keep these feedbacks in mind while validating the new query. } return ''; } + + private _filterByPermissions(tables: string[]): string[] { + const permHelper = this.permissionHelper; + if (!permHelper) { + return tables; + } + return tables.filter(t => { + const name = t.toLowerCase().slice(t.indexOf('.') + 1); + return permHelper.findMissingPermissions([name]).length === 0; + }); + } } diff --git a/src/components/db-query/nodes/verify-checklist.node.ts b/src/components/db-query/nodes/verify-checklist.node.ts index b1016a1..2965229 100644 --- a/src/components/db-query/nodes/verify-checklist.node.ts +++ b/src/components/db-query/nodes/verify-checklist.node.ts @@ -1,3 +1,4 @@ +import {AIMessage} from '@langchain/core/messages'; import {PromptTemplate} from '@langchain/core/prompts'; import {RunnableSequence} from '@langchain/core/runnables'; import {LangGraphRunnableConfig} from '@langchain/langgraph'; @@ -7,7 +8,6 @@ import {IGraphNode, LLMStreamEventType} from '../../../graphs'; import {AiIntegrationBindings} from '../../../keys'; import {LLMProvider} from '../../../types'; import {stripThinkingTokens} from '../../../utils'; -import {AIMessage} from '@langchain/core/messages'; import {DbQueryAIExtensionBindings} from '../keys'; import {DbQueryNodes} from '../nodes.enum'; import {DbSchemaHelperService} from '../services'; @@ -43,7 +43,7 @@ A rule is relevant if: - It is a dependency of another relevant rule (e.g. if rule 3 requires a currency conversion, and rule 5 defines how currency conversion works, both must be included). - It applies to any of the selected tables or their relationships. -After selecting relevant rules, review your selection and ensure: +Ensure: - Any rule that is referenced by, or is a prerequisite for, another selected rule is also included. - Do not include rules that are completely unrelated to the question, schema, or selected tables. @@ -82,8 +82,8 @@ If no rules are relevant: none `; simpleOutputInstructions = ` -Return only a comma-separated list of the relevant rule indexes inside a result tag. -Do not include any other text, explanation, or formatting. +Return ONLY the comma-separated list of relevant rule indexes inside a result tag. +Do NOT include any reasoning, analysis, or explanation — only the result tag. Example: 1,3,5 If no rules are relevant: @@ -96,7 +96,7 @@ If no rules are relevant: ): Promise { const empty = {} as DbQueryState; - if (this.config.nodes?.generateChecklistNode?.enabled === false) { + if (this.config.nodes?.verifyChecklistNode?.enabled === false) { return empty; } diff --git a/src/components/db-query/services/knowledge-graph/db-knowledge-graph.service.ts b/src/components/db-query/services/knowledge-graph/db-knowledge-graph.service.ts index 123a43c..8fae90f 100644 --- a/src/components/db-query/services/knowledge-graph/db-knowledge-graph.service.ts +++ b/src/components/db-query/services/knowledge-graph/db-knowledge-graph.service.ts @@ -53,7 +53,7 @@ export class DbKnowledgeGraphService implements KnowledgeGraph< config.knowledgeGraph?.maxClusterSize ?? MAX_CLUSTER_SIZE; // Default max cluster size } - async find(query: string, topK: number): Promise { + async find(query: string, topK = 10): Promise { debug(`Selecting tables for query: "${query}"`); // Step 1: Generate query embedding diff --git a/src/components/db-query/services/knowledge-graph/types.ts b/src/components/db-query/services/knowledge-graph/types.ts index f7f5902..adbf299 100644 --- a/src/components/db-query/services/knowledge-graph/types.ts +++ b/src/components/db-query/services/knowledge-graph/types.ts @@ -46,7 +46,7 @@ export interface Graph { export interface KnowledgeGraph extends Graph { toJSON(): string; fromJSON(json: string): void; - find(query: string, count: number): Promise; + find(query: string, count?: number): Promise; seed(data: S): Promise; } diff --git a/src/components/db-query/services/search/table-search.service.ts b/src/components/db-query/services/search/table-search.service.ts index 37b21e7..5353f41 100644 --- a/src/components/db-query/services/search/table-search.service.ts +++ b/src/components/db-query/services/search/table-search.service.ts @@ -31,7 +31,7 @@ export class TableSearchService { private readonly dbSchemaHelper: DbSchemaHelperService, ) {} - async getTables(prompt: string, count: number): Promise { + async getTables(prompt: string, count?: number): Promise { if (this.config.noKnowledgeGraph) { return this._tables; } diff --git a/src/components/db-query/types.ts b/src/components/db-query/types.ts index 16076b4..54624d5 100644 --- a/src/components/db-query/types.ts +++ b/src/components/db-query/types.ts @@ -134,6 +134,7 @@ export type DbQueryConfig = { parallelism?: number; }; verifyChecklistNode?: { + enabled?: boolean; evaluation?: boolean; }; };