@forestadmin/ai-proxy 1.8.0 → 1.10.0
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/dist/forest-integration-client.d.ts +4 -2
- package/dist/forest-integration-client.js +14 -5
- package/dist/integrations/snowflake/tools/cortex-analyst.d.ts +3 -0
- package/dist/integrations/snowflake/tools/cortex-analyst.js +53 -0
- package/dist/integrations/snowflake/tools/cortex-search.d.ts +3 -0
- package/dist/integrations/snowflake/tools/cortex-search.js +55 -0
- package/dist/integrations/snowflake/tools/execute-query.d.ts +4 -0
- package/dist/integrations/snowflake/tools/execute-query.js +49 -0
- package/dist/integrations/snowflake/tools.d.ts +11 -0
- package/dist/integrations/snowflake/tools.js +24 -0
- package/dist/integrations/snowflake/utils.d.ts +14 -0
- package/dist/integrations/snowflake/utils.js +132 -0
- package/package.json +1 -1
|
@@ -2,9 +2,11 @@ import type RemoteTool from './remote-tool';
|
|
|
2
2
|
import type { ToolProvider } from './tool-provider';
|
|
3
3
|
import type { Logger } from '@forestadmin/datasource-toolkit';
|
|
4
4
|
import { type KolarConfig } from './integrations/kolar/tools';
|
|
5
|
+
import { type SnowflakeConfig } from './integrations/snowflake/tools';
|
|
5
6
|
import { type ZendeskConfig } from './integrations/zendesk/tools';
|
|
6
|
-
export type CustomConfig = ZendeskConfig | KolarConfig;
|
|
7
|
-
export
|
|
7
|
+
export type CustomConfig = ZendeskConfig | KolarConfig | SnowflakeConfig;
|
|
8
|
+
export declare const FOREST_INTEGRATION_NAMES: readonly ["Zendesk", "Kolar", "Snowflake"];
|
|
9
|
+
export type ForestIntegrationName = (typeof FOREST_INTEGRATION_NAMES)[number];
|
|
8
10
|
export interface ForestIntegrationConfig {
|
|
9
11
|
integrationName: ForestIntegrationName;
|
|
10
12
|
config: CustomConfig;
|
|
@@ -3,12 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FOREST_INTEGRATION_NAMES = void 0;
|
|
6
7
|
exports.isForestIntegrationConfig = isForestIntegrationConfig;
|
|
7
8
|
const errors_1 = require("./errors");
|
|
8
9
|
const tools_1 = __importDefault(require("./integrations/kolar/tools"));
|
|
9
10
|
const utils_1 = require("./integrations/kolar/utils");
|
|
10
|
-
const tools_2 = __importDefault(require("./integrations/
|
|
11
|
-
const utils_2 = require("./integrations/
|
|
11
|
+
const tools_2 = __importDefault(require("./integrations/snowflake/tools"));
|
|
12
|
+
const utils_2 = require("./integrations/snowflake/utils");
|
|
13
|
+
const tools_3 = __importDefault(require("./integrations/zendesk/tools"));
|
|
14
|
+
const utils_3 = require("./integrations/zendesk/utils");
|
|
15
|
+
exports.FOREST_INTEGRATION_NAMES = ['Zendesk', 'Kolar', 'Snowflake'];
|
|
12
16
|
function isForestIntegrationConfig(config) {
|
|
13
17
|
return ('isForestConnector' in config && config.isForestConnector === true);
|
|
14
18
|
}
|
|
@@ -22,11 +26,14 @@ class ForestIntegrationClient {
|
|
|
22
26
|
this.configs.forEach(({ integrationName, config }) => {
|
|
23
27
|
switch (integrationName) {
|
|
24
28
|
case 'Zendesk':
|
|
25
|
-
tools.push(...(0,
|
|
29
|
+
tools.push(...(0, tools_3.default)(config));
|
|
26
30
|
break;
|
|
27
31
|
case 'Kolar':
|
|
28
32
|
tools.push(...(0, tools_1.default)(config));
|
|
29
33
|
break;
|
|
34
|
+
case 'Snowflake':
|
|
35
|
+
tools.push(...(0, tools_2.default)(config));
|
|
36
|
+
break;
|
|
30
37
|
default:
|
|
31
38
|
this.logger?.('Warn', `Unsupported integration: ${integrationName}`);
|
|
32
39
|
}
|
|
@@ -37,9 +44,11 @@ class ForestIntegrationClient {
|
|
|
37
44
|
await Promise.all(this.configs.map(({ integrationName, config }) => {
|
|
38
45
|
switch (integrationName) {
|
|
39
46
|
case 'Zendesk':
|
|
40
|
-
return (0,
|
|
47
|
+
return (0, utils_3.validateZendeskConfig)(config);
|
|
41
48
|
case 'Kolar':
|
|
42
49
|
return (0, utils_1.validateKolarConfig)(config);
|
|
50
|
+
case 'Snowflake':
|
|
51
|
+
return (0, utils_2.validateSnowflakeConfig)(config);
|
|
43
52
|
default:
|
|
44
53
|
throw new errors_1.AIBadRequestError(`Unsupported integration: ${integrationName}`);
|
|
45
54
|
}
|
|
@@ -51,4 +60,4 @@ class ForestIntegrationClient {
|
|
|
51
60
|
}
|
|
52
61
|
}
|
|
53
62
|
exports.default = ForestIntegrationClient;
|
|
54
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
63
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yZXN0LWludGVncmF0aW9uLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9mb3Jlc3QtaW50ZWdyYXRpb24tY2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQXNCQSw4REFNQztBQXhCRCxxQ0FBNkM7QUFDN0MsdUVBQTZFO0FBQzdFLHNEQUFpRTtBQUNqRSwyRUFBeUY7QUFDekYsMERBQXlFO0FBQ3pFLHlFQUFtRjtBQUNuRix3REFBcUU7QUFHeEQsUUFBQSx3QkFBd0IsR0FBRyxDQUFDLFNBQVMsRUFBRSxPQUFPLEVBQUUsV0FBVyxDQUFVLENBQUM7QUFTbkYsU0FBZ0IseUJBQXlCLENBQ3ZDLE1BQXlEO0lBRXpELE9BQU8sQ0FDTCxtQkFBbUIsSUFBSSxNQUFNLElBQUssTUFBa0MsQ0FBQyxpQkFBaUIsS0FBSyxJQUFJLENBQ2hHLENBQUM7QUFDSixDQUFDO0FBRUQsTUFBcUIsdUJBQXVCO0lBSTFDLFlBQVksT0FBa0MsRUFBRSxNQUFlO1FBQzdELElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO0lBQ3pCLENBQUM7SUFFRCxLQUFLLENBQUMsU0FBUztRQUNiLE1BQU0sS0FBSyxHQUFpQixFQUFFLENBQUM7UUFFL0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFFLGVBQWUsRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFO1lBQ25ELFFBQVEsZUFBZSxFQUFFLENBQUM7Z0JBQ3hCLEtBQUssU0FBUztvQkFDWixLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBQSxlQUFlLEVBQUMsTUFBdUIsQ0FBQyxDQUFDLENBQUM7b0JBQ3hELE1BQU07Z0JBQ1IsS0FBSyxPQUFPO29CQUNWLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFBLGVBQWEsRUFBQyxNQUFxQixDQUFDLENBQUMsQ0FBQztvQkFDcEQsTUFBTTtnQkFDUixLQUFLLFdBQVc7b0JBQ2QsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUEsZUFBaUIsRUFBQyxNQUF5QixDQUFDLENBQUMsQ0FBQztvQkFDNUQsTUFBTTtnQkFDUjtvQkFDRSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsTUFBTSxFQUFFLDRCQUE0QixlQUFlLEVBQUUsQ0FBQyxDQUFDO1lBQ3pFLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUVILE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVELEtBQUssQ0FBQyxlQUFlO1FBQ25CLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FDZixJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsZUFBZSxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUU7WUFDL0MsUUFBUSxlQUFlLEVBQUUsQ0FBQztnQkFDeEIsS0FBSyxTQUFTO29CQUNaLE9BQU8sSUFBQSw2QkFBcUIsRUFBQyxNQUF1QixDQUFDLENBQUM7Z0JBQ3hELEtBQUssT0FBTztvQkFDVixPQUFPLElBQUEsMkJBQW1CLEVBQUMsTUFBcUIsQ0FBQyxDQUFDO2dCQUNwRCxLQUFLLFdBQVc7b0JBQ2QsT0FBTyxJQUFBLCtCQUF1QixFQUFDLE1BQXlCLENBQUMsQ0FBQztnQkFDNUQ7b0JBQ0UsTUFBTSxJQUFJLDBCQUFpQixDQUFDLDRCQUE0QixlQUFlLEVBQUUsQ0FBQyxDQUFDO1lBQy9FLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FDSCxDQUFDO1FBRUYsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsS0FBSyxDQUFDLE9BQU87UUFDWCx3REFBd0Q7SUFDMUQsQ0FBQztDQUNGO0FBckRELDBDQXFEQyJ9
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = createCortexAnalystTool;
|
|
4
|
+
const tools_1 = require("@langchain/core/tools");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const errors_1 = require("../../../errors");
|
|
7
|
+
const utils_1 = require("../utils");
|
|
8
|
+
function createCortexAnalystTool(headers, baseUrl) {
|
|
9
|
+
return new tools_1.DynamicStructuredTool({
|
|
10
|
+
name: 'snowflake_cortex_analyst',
|
|
11
|
+
description: 'Ask a natural-language analytical question against a Snowflake semantic model or ' +
|
|
12
|
+
'semantic view using Cortex Analyst. Returns a generated SQL query and the answer. ' +
|
|
13
|
+
'Exactly one of `semantic_model_file` or `semantic_view` must be provided.',
|
|
14
|
+
schema: zod_1.z.object({
|
|
15
|
+
question: zod_1.z.string().min(1).describe('The natural-language analytical question'),
|
|
16
|
+
semantic_model_file: zod_1.z
|
|
17
|
+
.string()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('Stage path to the YAML semantic model file ' +
|
|
20
|
+
'(e.g. "@my_db.my_schema.my_stage/model.yaml")'),
|
|
21
|
+
semantic_view: zod_1.z
|
|
22
|
+
.string()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('Fully qualified semantic view name (e.g. "my_db.my_schema.my_view")'),
|
|
25
|
+
}),
|
|
26
|
+
func: async ({ question, semantic_model_file, semantic_view }) => {
|
|
27
|
+
if (!semantic_model_file && !semantic_view) {
|
|
28
|
+
throw new errors_1.AIBadRequestError('Either `semantic_model_file` or `semantic_view` must be provided.');
|
|
29
|
+
}
|
|
30
|
+
if (semantic_model_file && semantic_view) {
|
|
31
|
+
throw new errors_1.AIBadRequestError('Provide only one of `semantic_model_file` or `semantic_view`, not both.');
|
|
32
|
+
}
|
|
33
|
+
const body = {
|
|
34
|
+
messages: [
|
|
35
|
+
{
|
|
36
|
+
role: 'user',
|
|
37
|
+
content: [{ type: 'text', text: question }],
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
...(semantic_model_file && { semantic_model_file }),
|
|
41
|
+
...(semantic_view && { semantic_view }),
|
|
42
|
+
};
|
|
43
|
+
const response = await fetch(`${baseUrl}/api/v2/cortex/analyst/message`, {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers,
|
|
46
|
+
body: JSON.stringify(body),
|
|
47
|
+
});
|
|
48
|
+
await (0, utils_1.assertResponseOk)(response, 'cortex analyst');
|
|
49
|
+
return JSON.stringify(await response.json());
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29ydGV4LWFuYWx5c3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvaW50ZWdyYXRpb25zL3Nub3dmbGFrZS90b29scy9jb3J0ZXgtYW5hbHlzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQU1BLDBDQTJEQztBQWpFRCxpREFBOEQ7QUFDOUQsNkJBQXdCO0FBRXhCLDRDQUFvRDtBQUNwRCxvQ0FBNEM7QUFFNUMsU0FBd0IsdUJBQXVCLENBQzdDLE9BQStCLEVBQy9CLE9BQWU7SUFFZixPQUFPLElBQUksNkJBQXFCLENBQUM7UUFDL0IsSUFBSSxFQUFFLDBCQUEwQjtRQUNoQyxXQUFXLEVBQ1QsbUZBQW1GO1lBQ25GLG9GQUFvRjtZQUNwRiwyRUFBMkU7UUFDN0UsTUFBTSxFQUFFLE9BQUMsQ0FBQyxNQUFNLENBQUM7WUFDZixRQUFRLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsMENBQTBDLENBQUM7WUFDaEYsbUJBQW1CLEVBQUUsT0FBQztpQkFDbkIsTUFBTSxFQUFFO2lCQUNSLFFBQVEsRUFBRTtpQkFDVixRQUFRLENBQ1AsNkNBQTZDO2dCQUMzQywrQ0FBK0MsQ0FDbEQ7WUFDSCxhQUFhLEVBQUUsT0FBQztpQkFDYixNQUFNLEVBQUU7aUJBQ1IsUUFBUSxFQUFFO2lCQUNWLFFBQVEsQ0FBQyxxRUFBcUUsQ0FBQztTQUNuRixDQUFDO1FBQ0YsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFLFFBQVEsRUFBRSxtQkFBbUIsRUFBRSxhQUFhLEVBQUUsRUFBRSxFQUFFO1lBQy9ELElBQUksQ0FBQyxtQkFBbUIsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO2dCQUMzQyxNQUFNLElBQUksMEJBQWlCLENBQ3pCLG1FQUFtRSxDQUNwRSxDQUFDO1lBQ0osQ0FBQztZQUVELElBQUksbUJBQW1CLElBQUksYUFBYSxFQUFFLENBQUM7Z0JBQ3pDLE1BQU0sSUFBSSwwQkFBaUIsQ0FDekIseUVBQXlFLENBQzFFLENBQUM7WUFDSixDQUFDO1lBRUQsTUFBTSxJQUFJLEdBQTRCO2dCQUNwQyxRQUFRLEVBQUU7b0JBQ1I7d0JBQ0UsSUFBSSxFQUFFLE1BQU07d0JBQ1osT0FBTyxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQztxQkFDNUM7aUJBQ0Y7Z0JBQ0QsR0FBRyxDQUFDLG1CQUFtQixJQUFJLEVBQUUsbUJBQW1CLEVBQUUsQ0FBQztnQkFDbkQsR0FBRyxDQUFDLGFBQWEsSUFBSSxFQUFFLGFBQWEsRUFBRSxDQUFDO2FBQ3hDLENBQUM7WUFFRixNQUFNLFFBQVEsR0FBRyxNQUFNLEtBQUssQ0FBQyxHQUFHLE9BQU8sZ0NBQWdDLEVBQUU7Z0JBQ3ZFLE1BQU0sRUFBRSxNQUFNO2dCQUNkLE9BQU87Z0JBQ1AsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDO2FBQzNCLENBQUMsQ0FBQztZQUVILE1BQU0sSUFBQSx3QkFBZ0IsRUFBQyxRQUFRLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztZQUVuRCxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUMvQyxDQUFDO0tBQ0YsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyJ9
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = createCortexSearchTool;
|
|
4
|
+
const tools_1 = require("@langchain/core/tools");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
function createCortexSearchTool(headers, baseUrl) {
|
|
8
|
+
return new tools_1.DynamicStructuredTool({
|
|
9
|
+
name: 'snowflake_cortex_search',
|
|
10
|
+
description: 'Search data using a Snowflake Cortex Search service. ' +
|
|
11
|
+
'Returns semantic search results ranked by relevance. ' +
|
|
12
|
+
'The caller must provide the fully qualified service identifier (database, schema, service).',
|
|
13
|
+
schema: zod_1.z.object({
|
|
14
|
+
database: zod_1.z.string().min(1).describe('Name of the database containing the search service'),
|
|
15
|
+
schema: zod_1.z.string().min(1).describe('Name of the schema containing the search service'),
|
|
16
|
+
service: zod_1.z.string().min(1).describe('Name of the Cortex Search service'),
|
|
17
|
+
query: zod_1.z.string().min(1).describe('The natural-language search query'),
|
|
18
|
+
columns: zod_1.z
|
|
19
|
+
.array(zod_1.z.string().min(1))
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Columns to include in the search results'),
|
|
22
|
+
filter: zod_1.z
|
|
23
|
+
.record(zod_1.z.string(), zod_1.z.unknown())
|
|
24
|
+
.optional()
|
|
25
|
+
.describe('Optional filter expression as a JSON object'),
|
|
26
|
+
limit: zod_1.z
|
|
27
|
+
.number()
|
|
28
|
+
.int()
|
|
29
|
+
.positive()
|
|
30
|
+
.max(1000)
|
|
31
|
+
.optional()
|
|
32
|
+
.describe('Maximum number of results to return (default: service-defined)'),
|
|
33
|
+
}),
|
|
34
|
+
func: async ({ database, schema, service, query, columns, filter, limit }) => {
|
|
35
|
+
const url = `${baseUrl}/api/v2/databases/${encodeURIComponent(database)}` +
|
|
36
|
+
`/schemas/${encodeURIComponent(schema)}` +
|
|
37
|
+
`/cortex-search-services/${encodeURIComponent(service)}:query`;
|
|
38
|
+
const body = { query };
|
|
39
|
+
if (columns)
|
|
40
|
+
body.columns = columns;
|
|
41
|
+
if (filter)
|
|
42
|
+
body.filter = filter;
|
|
43
|
+
if (limit !== undefined)
|
|
44
|
+
body.limit = limit;
|
|
45
|
+
const response = await fetch(url, {
|
|
46
|
+
method: 'POST',
|
|
47
|
+
headers,
|
|
48
|
+
body: JSON.stringify(body),
|
|
49
|
+
});
|
|
50
|
+
await (0, utils_1.assertResponseOk)(response, 'cortex search');
|
|
51
|
+
return JSON.stringify(await response.json());
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29ydGV4LXNlYXJjaC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9pbnRlZ3JhdGlvbnMvc25vd2ZsYWtlL3Rvb2xzL2NvcnRleC1zZWFyY2gudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFLQSx5Q0FxREM7QUExREQsaURBQThEO0FBQzlELDZCQUF3QjtBQUV4QixvQ0FBNEM7QUFFNUMsU0FBd0Isc0JBQXNCLENBQzVDLE9BQStCLEVBQy9CLE9BQWU7SUFFZixPQUFPLElBQUksNkJBQXFCLENBQUM7UUFDL0IsSUFBSSxFQUFFLHlCQUF5QjtRQUMvQixXQUFXLEVBQ1QsdURBQXVEO1lBQ3ZELHVEQUF1RDtZQUN2RCw2RkFBNkY7UUFDL0YsTUFBTSxFQUFFLE9BQUMsQ0FBQyxNQUFNLENBQUM7WUFDZixRQUFRLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsb0RBQW9ELENBQUM7WUFDMUYsTUFBTSxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLGtEQUFrRCxDQUFDO1lBQ3RGLE9BQU8sRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxtQ0FBbUMsQ0FBQztZQUN4RSxLQUFLLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsbUNBQW1DLENBQUM7WUFDdEUsT0FBTyxFQUFFLE9BQUM7aUJBQ1AsS0FBSyxDQUFDLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7aUJBQ3hCLFFBQVEsRUFBRTtpQkFDVixRQUFRLENBQUMsMENBQTBDLENBQUM7WUFDdkQsTUFBTSxFQUFFLE9BQUM7aUJBQ04sTUFBTSxDQUFDLE9BQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxPQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7aUJBQy9CLFFBQVEsRUFBRTtpQkFDVixRQUFRLENBQUMsNkNBQTZDLENBQUM7WUFDMUQsS0FBSyxFQUFFLE9BQUM7aUJBQ0wsTUFBTSxFQUFFO2lCQUNSLEdBQUcsRUFBRTtpQkFDTCxRQUFRLEVBQUU7aUJBQ1YsR0FBRyxDQUFDLElBQUksQ0FBQztpQkFDVCxRQUFRLEVBQUU7aUJBQ1YsUUFBUSxDQUFDLGdFQUFnRSxDQUFDO1NBQzlFLENBQUM7UUFDRixJQUFJLEVBQUUsS0FBSyxFQUFFLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRTtZQUMzRSxNQUFNLEdBQUcsR0FDUCxHQUFHLE9BQU8scUJBQXFCLGtCQUFrQixDQUFDLFFBQVEsQ0FBQyxFQUFFO2dCQUM3RCxZQUFZLGtCQUFrQixDQUFDLE1BQU0sQ0FBQyxFQUFFO2dCQUN4QywyQkFBMkIsa0JBQWtCLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQztZQUVqRSxNQUFNLElBQUksR0FBNEIsRUFBRSxLQUFLLEVBQUUsQ0FBQztZQUNoRCxJQUFJLE9BQU87Z0JBQUUsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7WUFDcEMsSUFBSSxNQUFNO2dCQUFFLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1lBQ2pDLElBQUksS0FBSyxLQUFLLFNBQVM7Z0JBQUUsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7WUFFNUMsTUFBTSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsR0FBRyxFQUFFO2dCQUNoQyxNQUFNLEVBQUUsTUFBTTtnQkFDZCxPQUFPO2dCQUNQLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQzthQUMzQixDQUFDLENBQUM7WUFFSCxNQUFNLElBQUEsd0JBQWdCLEVBQUMsUUFBUSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1lBRWxELE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQy9DLENBQUM7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDIn0=
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SnowflakeConfig } from '../tools';
|
|
2
|
+
import { DynamicStructuredTool } from '@langchain/core/tools';
|
|
3
|
+
export default function createExecuteQueryTool(headers: Record<string, string>, baseUrl: string, config: SnowflakeConfig): DynamicStructuredTool;
|
|
4
|
+
//# sourceMappingURL=execute-query.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = createExecuteQueryTool;
|
|
4
|
+
const tools_1 = require("@langchain/core/tools");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
function createExecuteQueryTool(headers, baseUrl, config) {
|
|
8
|
+
return new tools_1.DynamicStructuredTool({
|
|
9
|
+
name: 'snowflake_execute_query',
|
|
10
|
+
description: 'Execute a read-only SQL query on Snowflake and return the results. ' +
|
|
11
|
+
'Only SELECT, SHOW, DESCRIBE, and EXPLAIN statements are allowed. ' +
|
|
12
|
+
'Multiple statements are not permitted.',
|
|
13
|
+
schema: zod_1.z.object({
|
|
14
|
+
statement: zod_1.z.string().min(1).describe('The read-only SQL statement to execute'),
|
|
15
|
+
warehouse: zod_1.z
|
|
16
|
+
.string()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe('Warehouse to use for this query (overrides the default)'),
|
|
19
|
+
database: zod_1.z
|
|
20
|
+
.string()
|
|
21
|
+
.optional()
|
|
22
|
+
.describe('Database to use for this query (overrides the default)'),
|
|
23
|
+
schema: zod_1.z
|
|
24
|
+
.string()
|
|
25
|
+
.optional()
|
|
26
|
+
.describe('Schema to use for this query (overrides the default)'),
|
|
27
|
+
role: zod_1.z.string().optional().describe('Role to use for this query (overrides the default)'),
|
|
28
|
+
}),
|
|
29
|
+
func: async ({ statement, warehouse, database, schema, role }) => {
|
|
30
|
+
(0, utils_1.assertReadOnlySql)(statement);
|
|
31
|
+
const body = {
|
|
32
|
+
statement,
|
|
33
|
+
...(0, utils_1.buildSessionContext)(config),
|
|
34
|
+
...(warehouse && { warehouse }),
|
|
35
|
+
...(database && { database }),
|
|
36
|
+
...(schema && { schema }),
|
|
37
|
+
...(role && { role }),
|
|
38
|
+
};
|
|
39
|
+
const response = await fetch(`${baseUrl}/api/v2/statements`, {
|
|
40
|
+
method: 'POST',
|
|
41
|
+
headers,
|
|
42
|
+
body: JSON.stringify(body),
|
|
43
|
+
});
|
|
44
|
+
await (0, utils_1.assertResponseOk)(response, 'execute query');
|
|
45
|
+
return JSON.stringify(await response.json());
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhlY3V0ZS1xdWVyeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9pbnRlZ3JhdGlvbnMvc25vd2ZsYWtlL3Rvb2xzL2V4ZWN1dGUtcXVlcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFPQSx5Q0FrREM7QUF2REQsaURBQThEO0FBQzlELDZCQUF3QjtBQUV4QixvQ0FBb0Y7QUFFcEYsU0FBd0Isc0JBQXNCLENBQzVDLE9BQStCLEVBQy9CLE9BQWUsRUFDZixNQUF1QjtJQUV2QixPQUFPLElBQUksNkJBQXFCLENBQUM7UUFDL0IsSUFBSSxFQUFFLHlCQUF5QjtRQUMvQixXQUFXLEVBQ1QscUVBQXFFO1lBQ3JFLG1FQUFtRTtZQUNuRSx3Q0FBd0M7UUFDMUMsTUFBTSxFQUFFLE9BQUMsQ0FBQyxNQUFNLENBQUM7WUFDZixTQUFTLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsd0NBQXdDLENBQUM7WUFDL0UsU0FBUyxFQUFFLE9BQUM7aUJBQ1QsTUFBTSxFQUFFO2lCQUNSLFFBQVEsRUFBRTtpQkFDVixRQUFRLENBQUMseURBQXlELENBQUM7WUFDdEUsUUFBUSxFQUFFLE9BQUM7aUJBQ1IsTUFBTSxFQUFFO2lCQUNSLFFBQVEsRUFBRTtpQkFDVixRQUFRLENBQUMsd0RBQXdELENBQUM7WUFDckUsTUFBTSxFQUFFLE9BQUM7aUJBQ04sTUFBTSxFQUFFO2lCQUNSLFFBQVEsRUFBRTtpQkFDVixRQUFRLENBQUMsc0RBQXNELENBQUM7WUFDbkUsSUFBSSxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMsb0RBQW9ELENBQUM7U0FDM0YsQ0FBQztRQUNGLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRTtZQUMvRCxJQUFBLHlCQUFpQixFQUFDLFNBQVMsQ0FBQyxDQUFDO1lBRTdCLE1BQU0sSUFBSSxHQUFHO2dCQUNYLFNBQVM7Z0JBQ1QsR0FBRyxJQUFBLDJCQUFtQixFQUFDLE1BQU0sQ0FBQztnQkFDOUIsR0FBRyxDQUFDLFNBQVMsSUFBSSxFQUFFLFNBQVMsRUFBRSxDQUFDO2dCQUMvQixHQUFHLENBQUMsUUFBUSxJQUFJLEVBQUUsUUFBUSxFQUFFLENBQUM7Z0JBQzdCLEdBQUcsQ0FBQyxNQUFNLElBQUksRUFBRSxNQUFNLEVBQUUsQ0FBQztnQkFDekIsR0FBRyxDQUFDLElBQUksSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDO2FBQ3RCLENBQUM7WUFFRixNQUFNLFFBQVEsR0FBRyxNQUFNLEtBQUssQ0FBQyxHQUFHLE9BQU8sb0JBQW9CLEVBQUU7Z0JBQzNELE1BQU0sRUFBRSxNQUFNO2dCQUNkLE9BQU87Z0JBQ1AsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDO2FBQzNCLENBQUMsQ0FBQztZQUVILE1BQU0sSUFBQSx3QkFBZ0IsRUFBQyxRQUFRLEVBQUUsZUFBZSxDQUFDLENBQUM7WUFFbEQsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFDL0MsQ0FBQztLQUNGLENBQUMsQ0FBQztBQUNMLENBQUMifQ==
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type RemoteTool from '../../remote-tool';
|
|
2
|
+
export interface SnowflakeConfig {
|
|
3
|
+
accountIdentifier: string;
|
|
4
|
+
programmaticAccessToken: string;
|
|
5
|
+
defaultWarehouse?: string;
|
|
6
|
+
defaultDatabase?: string;
|
|
7
|
+
defaultSchema?: string;
|
|
8
|
+
defaultRole?: string;
|
|
9
|
+
}
|
|
10
|
+
export default function getSnowflakeTools(config: SnowflakeConfig): RemoteTool[];
|
|
11
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = getSnowflakeTools;
|
|
7
|
+
const server_remote_tool_1 = __importDefault(require("../../server-remote-tool"));
|
|
8
|
+
const cortex_analyst_1 = __importDefault(require("./tools/cortex-analyst"));
|
|
9
|
+
const cortex_search_1 = __importDefault(require("./tools/cortex-search"));
|
|
10
|
+
const execute_query_1 = __importDefault(require("./tools/execute-query"));
|
|
11
|
+
const utils_1 = require("./utils");
|
|
12
|
+
function getSnowflakeTools(config) {
|
|
13
|
+
const headers = (0, utils_1.getSnowflakeAuthHeaders)(config);
|
|
14
|
+
const baseUrl = (0, utils_1.getSnowflakeBaseUrl)(config.accountIdentifier);
|
|
15
|
+
return [
|
|
16
|
+
(0, cortex_search_1.default)(headers, baseUrl),
|
|
17
|
+
(0, cortex_analyst_1.default)(headers, baseUrl),
|
|
18
|
+
(0, execute_query_1.default)(headers, baseUrl, config),
|
|
19
|
+
].map(tool => new server_remote_tool_1.default({
|
|
20
|
+
sourceId: 'snowflake',
|
|
21
|
+
tool,
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW50ZWdyYXRpb25zL3Nub3dmbGFrZS90b29scy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQWlCQSxvQ0FlQztBQTlCRCxrRkFBd0Q7QUFDeEQsNEVBQTZEO0FBQzdELDBFQUEyRDtBQUMzRCwwRUFBMkQ7QUFDM0QsbUNBQXVFO0FBV3ZFLFNBQXdCLGlCQUFpQixDQUFDLE1BQXVCO0lBQy9ELE1BQU0sT0FBTyxHQUFHLElBQUEsK0JBQXVCLEVBQUMsTUFBTSxDQUFDLENBQUM7SUFDaEQsTUFBTSxPQUFPLEdBQUcsSUFBQSwyQkFBbUIsRUFBQyxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUU5RCxPQUFPO1FBQ0wsSUFBQSx1QkFBc0IsRUFBQyxPQUFPLEVBQUUsT0FBTyxDQUFDO1FBQ3hDLElBQUEsd0JBQXVCLEVBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQztRQUN6QyxJQUFBLHVCQUFzQixFQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxDQUFDO0tBQ2pELENBQUMsR0FBRyxDQUNILElBQUksQ0FBQyxFQUFFLENBQ0wsSUFBSSw0QkFBZ0IsQ0FBQztRQUNuQixRQUFRLEVBQUUsV0FBVztRQUNyQixJQUFJO0tBQ0wsQ0FBQyxDQUNMLENBQUM7QUFDSixDQUFDIn0=
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SnowflakeConfig } from './tools';
|
|
2
|
+
export declare function assertValidAccountIdentifier(accountIdentifier: string): void;
|
|
3
|
+
export declare function getSnowflakeAuthHeaders(config: SnowflakeConfig): Record<string, string>;
|
|
4
|
+
export declare function getSnowflakeBaseUrl(accountIdentifier: string): string;
|
|
5
|
+
export declare function buildSessionContext(config: SnowflakeConfig): {
|
|
6
|
+
role: string;
|
|
7
|
+
schema: string;
|
|
8
|
+
database: string;
|
|
9
|
+
warehouse: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function assertReadOnlySql(statement: string): void;
|
|
12
|
+
export declare function assertResponseOk(response: Response, action: string): Promise<void>;
|
|
13
|
+
export declare function validateSnowflakeConfig(config: SnowflakeConfig): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertValidAccountIdentifier = assertValidAccountIdentifier;
|
|
4
|
+
exports.getSnowflakeAuthHeaders = getSnowflakeAuthHeaders;
|
|
5
|
+
exports.getSnowflakeBaseUrl = getSnowflakeBaseUrl;
|
|
6
|
+
exports.buildSessionContext = buildSessionContext;
|
|
7
|
+
exports.assertReadOnlySql = assertReadOnlySql;
|
|
8
|
+
exports.assertResponseOk = assertResponseOk;
|
|
9
|
+
exports.validateSnowflakeConfig = validateSnowflakeConfig;
|
|
10
|
+
const errors_1 = require("../../errors");
|
|
11
|
+
const READ_ONLY_LEADING_KEYWORD_RE = /^\s*(select|show|describe|desc|explain)\b/i;
|
|
12
|
+
const FORBIDDEN_KEYWORD_RE = /\b(insert|update|delete|merge|drop|create|alter|truncate|rename|undrop|swap|grant|revoke|call|execute|copy|put|get|use|set|unset|begin|commit|rollback|with)\b/i;
|
|
13
|
+
// Snowflake account identifiers are alphanumeric segments optionally separated by `.` or `-`
|
|
14
|
+
// (org-account or locator.region.cloud). Anything else could redirect URL building to an
|
|
15
|
+
// attacker-controlled host (e.g. `attack.com#` makes `#` start the URL fragment).
|
|
16
|
+
const ACCOUNT_IDENTIFIER_RE = /^[A-Za-z0-9_-]{1,128}(\.[A-Za-z0-9_-]{1,128}){0,3}$/;
|
|
17
|
+
function assertValidAccountIdentifier(accountIdentifier) {
|
|
18
|
+
if (typeof accountIdentifier !== 'string' || !ACCOUNT_IDENTIFIER_RE.test(accountIdentifier)) {
|
|
19
|
+
throw new errors_1.AIBadRequestError(`Invalid Snowflake account identifier: ${JSON.stringify(accountIdentifier)}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function getSnowflakeAuthHeaders(config) {
|
|
23
|
+
return {
|
|
24
|
+
Authorization: `Bearer ${config.programmaticAccessToken}`,
|
|
25
|
+
'Content-Type': 'application/json',
|
|
26
|
+
Accept: 'application/json',
|
|
27
|
+
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function getSnowflakeBaseUrl(accountIdentifier) {
|
|
31
|
+
assertValidAccountIdentifier(accountIdentifier);
|
|
32
|
+
return `https://${accountIdentifier}.snowflakecomputing.com`;
|
|
33
|
+
}
|
|
34
|
+
function buildSessionContext(config) {
|
|
35
|
+
return {
|
|
36
|
+
...(config.defaultWarehouse && { warehouse: config.defaultWarehouse }),
|
|
37
|
+
...(config.defaultDatabase && { database: config.defaultDatabase }),
|
|
38
|
+
...(config.defaultSchema && { schema: config.defaultSchema }),
|
|
39
|
+
...(config.defaultRole && { role: config.defaultRole }),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Single-pass lexer: a regex pipeline cannot disambiguate `--` inside a string
|
|
43
|
+
// from a comment containing `'`, so it is unsafe for security checks.
|
|
44
|
+
function normalizeSql(statement) {
|
|
45
|
+
let result = '';
|
|
46
|
+
let i = 0;
|
|
47
|
+
while (i < statement.length) {
|
|
48
|
+
const c = statement[i];
|
|
49
|
+
const next = statement[i + 1];
|
|
50
|
+
if (c === '/' && next === '*') {
|
|
51
|
+
const end = statement.indexOf('*/', i + 2);
|
|
52
|
+
i = end === -1 ? statement.length : end + 2;
|
|
53
|
+
}
|
|
54
|
+
else if (c === '-' && next === '-') {
|
|
55
|
+
const end = statement.indexOf('\n', i + 2);
|
|
56
|
+
i = end === -1 ? statement.length : end;
|
|
57
|
+
}
|
|
58
|
+
else if (c === "'" || c === '"') {
|
|
59
|
+
result += c === "'" ? "''" : '""';
|
|
60
|
+
i += 1;
|
|
61
|
+
while (i < statement.length) {
|
|
62
|
+
if (statement[i] === c && statement[i + 1] === c) {
|
|
63
|
+
i += 2;
|
|
64
|
+
}
|
|
65
|
+
else if (statement[i] === c) {
|
|
66
|
+
i += 1;
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
i += 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
result += c;
|
|
76
|
+
i += 1;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result.trim();
|
|
80
|
+
}
|
|
81
|
+
function assertReadOnlySql(statement) {
|
|
82
|
+
const normalized = normalizeSql(statement);
|
|
83
|
+
if (!normalized) {
|
|
84
|
+
throw new errors_1.AIBadRequestError('SQL statement is empty');
|
|
85
|
+
}
|
|
86
|
+
const withoutTrailingSemicolon = normalized.replace(/;\s*$/, '');
|
|
87
|
+
if (withoutTrailingSemicolon.includes(';')) {
|
|
88
|
+
throw new errors_1.AIBadRequestError('Only a single SQL statement is allowed. Multiple statements are not permitted.');
|
|
89
|
+
}
|
|
90
|
+
if (!READ_ONLY_LEADING_KEYWORD_RE.test(withoutTrailingSemicolon)) {
|
|
91
|
+
throw new errors_1.AIBadRequestError('Only read-only statements (SELECT, SHOW, DESCRIBE, EXPLAIN) are allowed.');
|
|
92
|
+
}
|
|
93
|
+
const forbiddenMatch = withoutTrailingSemicolon.match(FORBIDDEN_KEYWORD_RE);
|
|
94
|
+
if (forbiddenMatch) {
|
|
95
|
+
throw new errors_1.AIBadRequestError(`SQL statement contains a disallowed keyword: ${forbiddenMatch[0].toUpperCase()}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async function extractErrorMessage(response) {
|
|
99
|
+
const fallback = response.statusText || 'Unknown error';
|
|
100
|
+
try {
|
|
101
|
+
const json = await response.json();
|
|
102
|
+
return json.message || json.error || json.code || fallback;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return fallback;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async function assertResponseOk(response, action) {
|
|
109
|
+
if (response.ok)
|
|
110
|
+
return;
|
|
111
|
+
const errorMessage = await extractErrorMessage(response);
|
|
112
|
+
throw new errors_1.AIToolUnprocessableError(`Snowflake ${action} failed (${response.status}): ${errorMessage}`);
|
|
113
|
+
}
|
|
114
|
+
async function validateSnowflakeConfig(config) {
|
|
115
|
+
const baseUrl = getSnowflakeBaseUrl(config.accountIdentifier);
|
|
116
|
+
const headers = getSnowflakeAuthHeaders(config);
|
|
117
|
+
const body = {
|
|
118
|
+
statement: 'SELECT 1',
|
|
119
|
+
...buildSessionContext(config),
|
|
120
|
+
};
|
|
121
|
+
const url = `${baseUrl}/api/v2/statements`;
|
|
122
|
+
const response = await fetch(url, {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
headers,
|
|
125
|
+
body: JSON.stringify(body),
|
|
126
|
+
});
|
|
127
|
+
if (response.ok)
|
|
128
|
+
return;
|
|
129
|
+
const errorMessage = await extractErrorMessage(response);
|
|
130
|
+
throw new errors_1.McpConnectionError(`Failed to validate Snowflake config (HTTP ${response.status} on ${url}): ${errorMessage}`);
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW50ZWdyYXRpb25zL3Nub3dmbGFrZS91dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQVlBLG9FQU1DO0FBRUQsMERBT0M7QUFFRCxrREFJQztBQUVELGtEQU9DO0FBMkNELDhDQTRCQztBQWNELDRDQVFDO0FBRUQsMERBc0JDO0FBN0pELHlDQUErRjtBQUUvRixNQUFNLDRCQUE0QixHQUFHLDRDQUE0QyxDQUFDO0FBQ2xGLE1BQU0sb0JBQW9CLEdBQ3hCLGlLQUFpSyxDQUFDO0FBQ3BLLDZGQUE2RjtBQUM3Rix5RkFBeUY7QUFDekYsa0ZBQWtGO0FBQ2xGLE1BQU0scUJBQXFCLEdBQUcscURBQXFELENBQUM7QUFFcEYsU0FBZ0IsNEJBQTRCLENBQUMsaUJBQXlCO0lBQ3BFLElBQUksT0FBTyxpQkFBaUIsS0FBSyxRQUFRLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUFDO1FBQzVGLE1BQU0sSUFBSSwwQkFBaUIsQ0FDekIseUNBQXlDLElBQUksQ0FBQyxTQUFTLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUM3RSxDQUFDO0lBQ0osQ0FBQztBQUNILENBQUM7QUFFRCxTQUFnQix1QkFBdUIsQ0FBQyxNQUF1QjtJQUM3RCxPQUFPO1FBQ0wsYUFBYSxFQUFFLFVBQVUsTUFBTSxDQUFDLHVCQUF1QixFQUFFO1FBQ3pELGNBQWMsRUFBRSxrQkFBa0I7UUFDbEMsTUFBTSxFQUFFLGtCQUFrQjtRQUMxQixzQ0FBc0MsRUFBRSwyQkFBMkI7S0FDcEUsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFnQixtQkFBbUIsQ0FBQyxpQkFBeUI7SUFDM0QsNEJBQTRCLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUVoRCxPQUFPLFdBQVcsaUJBQWlCLHlCQUF5QixDQUFDO0FBQy9ELENBQUM7QUFFRCxTQUFnQixtQkFBbUIsQ0FBQyxN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
|