@squadbase/connectors 0.0.1 → 0.0.3

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/index.js CHANGED
@@ -1,3 +1,14 @@
1
+ // src/connector-setup.ts
2
+ var ConnectorSetup = class {
3
+ prompts;
4
+ constructor(prompts) {
5
+ this.prompts = prompts;
6
+ }
7
+ getPrompt(language) {
8
+ return this.prompts[language];
9
+ }
10
+ };
11
+
1
12
  // src/parameter-definition.ts
2
13
  var ParameterDefinition = class {
3
14
  slug;
@@ -17,10 +28,12 @@ var ParameterDefinition = class {
17
28
  this.required = config.required;
18
29
  }
19
30
  /**
20
- * Resolve a parameter value from a connection object (agent environment).
31
+ * Get the parameter value from a ConnectorConnectionObject.
21
32
  */
22
- resolve(connection) {
23
- const param = connection.parameters.find((p) => p.slug === this.slug);
33
+ getValue(connection) {
34
+ const param = connection.parameters.find(
35
+ (p) => p.parameterSlug === this.slug
36
+ );
24
37
  if (!param || param.value == null) {
25
38
  throw new Error(
26
39
  `Parameter "${this.slug}" not found or has no value in connection "${connection.id}"`
@@ -29,22 +42,14 @@ var ParameterDefinition = class {
29
42
  return param.value;
30
43
  }
31
44
  /**
32
- * Resolve the value of a connection parameter from environment variables (vite-server).
45
+ * Try to get the parameter value. Returns undefined if not found (for optional params).
33
46
  */
34
- resolveEnvVar(entry, connectionId) {
35
- const envVarName = entry.envVars[this.slug];
36
- if (!envVarName) {
37
- throw new Error(
38
- `No env var mapping for parameter "${this.slug}" in connection "${connectionId}"`
39
- );
40
- }
41
- const value = process.env[envVarName];
42
- if (!value) {
43
- throw new Error(
44
- `Environment variable "${envVarName}" is not set (connection "${connectionId}", parameter "${this.slug}")`
45
- );
46
- }
47
- return value;
47
+ tryGetValue(connection) {
48
+ const param = connection.parameters.find(
49
+ (p) => p.parameterSlug === this.slug
50
+ );
51
+ if (!param || param.value == null) return void 0;
52
+ return param.value;
48
53
  }
49
54
  };
50
55
 
@@ -73,35 +78,58 @@ var ConnectorTool = class {
73
78
  };
74
79
 
75
80
  // src/connector-plugin.ts
76
- var ConnectorPlugin = class {
81
+ var ConnectorPlugin = class _ConnectorPlugin {
77
82
  slug;
78
83
  authType;
79
84
  name;
80
85
  description;
81
86
  iconUrl;
82
- order;
83
87
  parameters;
84
88
  releaseFlag;
85
89
  proxyPolicy;
90
+ experimentalAttributes;
91
+ setup;
86
92
  systemPrompt;
87
93
  tools;
88
- createClient;
94
+ query;
89
95
  constructor(config) {
90
96
  this.slug = config.slug;
91
97
  this.authType = config.authType;
92
98
  this.name = config.name;
93
99
  this.description = config.description;
94
100
  this.iconUrl = config.iconUrl;
95
- this.order = config.order;
96
101
  this.parameters = config.parameters;
97
102
  this.releaseFlag = config.releaseFlag;
98
103
  this.proxyPolicy = config.proxyPolicy;
104
+ this.experimentalAttributes = config.experimentalAttributes;
105
+ this.setup = config.setup;
99
106
  this.systemPrompt = config.systemPrompt;
100
107
  this.tools = config.tools;
101
- this.createClient = config.createClient;
108
+ this.query = config.query;
102
109
  }
103
110
  get connectorKey() {
104
- return this.authType ? `${this.slug}-${this.authType}` : this.slug;
111
+ return _ConnectorPlugin.deriveKey(this.slug, this.authType);
112
+ }
113
+ /**
114
+ * Create tools for connections that belong to this connector.
115
+ * Filters connections by connectorKey internally.
116
+ * Returns tools keyed as `${connectorKey}_${toolName}`.
117
+ */
118
+ createTools(connections, config) {
119
+ const myConnections = connections.filter(
120
+ (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
121
+ );
122
+ const result = {};
123
+ for (const t of Object.values(this.tools)) {
124
+ result[`${this.connectorKey}_${t.name}`] = t.createTool(
125
+ myConnections,
126
+ config
127
+ );
128
+ }
129
+ return result;
130
+ }
131
+ static deriveKey(slug, authType) {
132
+ return authType ? `${slug}-${authType}` : slug;
105
133
  }
106
134
  };
107
135
 
@@ -114,7 +142,126 @@ var AUTH_TYPES = {
114
142
  PAT: "pat"
115
143
  };
116
144
 
117
- // src/connectors/snowflake-pat/parameters.ts
145
+ // src/lib/query-utils.ts
146
+ function replaceLiteralParams(sql, namedParams) {
147
+ if (!namedParams) return sql;
148
+ return sql.replace(/\{\{(\w+)\}\}/g, (_match, name) => {
149
+ const value = namedParams[name];
150
+ if (value === null || value === void 0) return "NULL";
151
+ if (typeof value === "string") return `'${value.replace(/'/g, "''")}'`;
152
+ return String(value);
153
+ });
154
+ }
155
+ function buildPositionalParams(sql, namedParams) {
156
+ if (!namedParams) return { text: sql, values: [] };
157
+ const values = [];
158
+ const nameToIndex = /* @__PURE__ */ new Map();
159
+ const text = sql.replace(/\{\{(\w+)\}\}/g, (_match, name) => {
160
+ if (!nameToIndex.has(name)) {
161
+ values.push(namedParams[name] ?? null);
162
+ nameToIndex.set(name, values.length);
163
+ }
164
+ return `$${nameToIndex.get(name)}`;
165
+ });
166
+ return { text, values };
167
+ }
168
+ function buildQuestionmarkParams(sql, namedParams) {
169
+ if (!namedParams) return { text: sql, values: [] };
170
+ const values = [];
171
+ const text = sql.replace(/\{\{(\w+)\}\}/g, (_match, name) => {
172
+ values.push(namedParams[name] ?? null);
173
+ return "?";
174
+ });
175
+ return { text, values };
176
+ }
177
+
178
+ // src/connectors/snowflake/setup.ts
179
+ var snowflakeSetup = new ConnectorSetup({
180
+ ja: `## Snowflake \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u624B\u9806
181
+
182
+ \u4EE5\u4E0B\u306E\u624B\u9806\u3067Snowflake\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
183
+
184
+ ### \u624B\u9806
185
+
186
+ #### \u30B9\u30C6\u30C3\u30D71: \u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u9078\u629E
187
+ 1. \`SHOW DATABASES\` \u3092\u5B9F\u884C\u3057\u3066\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
188
+ 2. \u7D50\u679C\u306B\u5FDC\u3058\u3066\u5206\u5C90:
189
+ - **\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u304C2\u3064\u4EE5\u4E0A**: \`askUserQuestion\`\uFF08multiSelect: true\uFF09\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u63D0\u793A\u3057\u3001\u4F7F\u7528\u3059\u308B\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u9078\u629E\u3055\u305B\u308B
190
+ - **\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u304C1\u3064\u3060\u3051**: askUserQuestion \u306F\u4F7F\u308F\u305A\u81EA\u52D5\u63A1\u7528\u3002\u300C\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9 X \u3092\u81EA\u52D5\u9078\u629E\u3057\u307E\u3057\u305F\u300D\u30681\u6587\u3060\u3051\u66F8\u304F
191
+
192
+ #### \u30B9\u30C6\u30C3\u30D72: \u30B9\u30AD\u30FC\u30DE\u9078\u629E\uFF08\u30C6\u30FC\u30D6\u30EB\u7BC4\u56F2\u306E\u6307\u5B9A\u3092\u542B\u3080\uFF09
193
+ 3. \u9078\u629E\u3055\u308C\u305F\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306B\u5BFE\u3057\u3066 \`SHOW SCHEMAS IN DATABASE {database}\` \u3092\u5B9F\u884C\u3057\u3066\u30B9\u30AD\u30FC\u30DE\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B\uFF08\u8907\u6570\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u5834\u5408\u306F\u305D\u308C\u305E\u308C\u5B9F\u884C\uFF09
194
+ 4. INFORMATION_SCHEMA \u306A\u3069\u5185\u90E8\u30B9\u30AD\u30FC\u30DE\u306F\u9664\u5916\u3059\u308B
195
+ 5. \u5404\u30B9\u30AD\u30FC\u30DE\u306B\u3064\u3044\u3066 **2\u3064\u306E\u9078\u629E\u80A2** \u3092\u751F\u6210\u3057\u3001\`askUserQuestion\`\uFF08multiSelect: true\uFF09\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u63D0\u793A\u3059\u308B:
196
+ - \`{schema}\uFF08\u5168\u30C6\u30FC\u30D6\u30EB\uFF09\` \u2014 description: "{database}.{schema} \u5185\u306E\u5168\u30C6\u30FC\u30D6\u30EB\u3092\u4F7F\u7528"
197
+ - \`{schema}\uFF08\u7279\u5B9A\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u629E\uFF09\` \u2014 description: "{database}.{schema} \u5185\u306E\u7279\u5B9A\u30C6\u30FC\u30D6\u30EB\u306E\u307F\u4F7F\u7528"
198
+ - \u30B9\u30AD\u30FC\u30DE\u304C1\u3064\u3060\u3051\u306E\u5834\u5408\u3082\u3001\u300C\u5168\u30C6\u30FC\u30D6\u30EB\u300D\u3068\u300C\u7279\u5B9A\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u629E\u300D\u306E2\u3064\u306E\u9078\u629E\u80A2\u3092\u63D0\u793A\u3059\u308B\u3053\u3068
199
+
200
+ #### \u30B9\u30C6\u30C3\u30D73: \u30C6\u30FC\u30D6\u30EB\u9078\u629E\uFF08\u300C\u7279\u5B9A\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u629E\u300D\u304C\u9078\u3070\u308C\u305F\u30B9\u30AD\u30FC\u30DE\u306E\u307F\uFF09
201
+ 6. \u300C\u5168\u30C6\u30FC\u30D6\u30EB\u300D\u304C\u9078\u3070\u308C\u305F\u30B9\u30AD\u30FC\u30DE\u306F\u30C6\u30FC\u30D6\u30EB\u9078\u629E\u3092\u30B9\u30AD\u30C3\u30D7\u3057\u3001\u5168\u30C6\u30FC\u30D6\u30EB\u3092\u5BFE\u8C61\u3068\u3059\u308B
202
+ 7. \u300C\u7279\u5B9A\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u629E\u300D\u304C\u9078\u3070\u308C\u305F\u30B9\u30AD\u30FC\u30DE\u306B\u5BFE\u3057\u3066\u306E\u307F \`SHOW TABLES IN SCHEMA {database}.{schema}\` \u3092\u5B9F\u884C\u3057\u3066\u30C6\u30FC\u30D6\u30EB\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
203
+ 8. \u7D50\u679C\u306B\u5FDC\u3058\u3066\u5206\u5C90:
204
+ - **\u30C6\u30FC\u30D6\u30EB\u304C2\u3064\u4EE5\u4E0A**: \`askUserQuestion\`\uFF08multiSelect: true\uFF09\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u63D0\u793A\u3057\u3001\u4F7F\u7528\u3059\u308B\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u629E\u3055\u305B\u308B\u3002description \u306B\u306F\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u540D.\u30B9\u30AD\u30FC\u30DE\u540D\u3092\u8A18\u8F09\u3059\u308B
205
+ - **\u30C6\u30FC\u30D6\u30EB\u304C1\u3064\u3060\u3051**: askUserQuestion \u306F\u4F7F\u308F\u305A\u81EA\u52D5\u63A1\u7528
206
+
207
+ #### \u30B9\u30C6\u30C3\u30D74: \u4FDD\u5B58
208
+ 9. \`updateConnectionContext\` \u3067\u4EE5\u4E0B\u3092\u4FDD\u5B58\u3059\u308B:
209
+ - \`database\`: \u9078\u629E\u3055\u308C\u305F\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u540D\uFF08\u8907\u6570\u306E\u5834\u5408\u306F\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09
210
+ - \`schema\`: \u9078\u629E\u3055\u308C\u305F\u30B9\u30AD\u30FC\u30DE\u540D\uFF08\u8907\u6570\u306E\u5834\u5408\u306F\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09
211
+ - \`tables\`: \u9078\u629E\u3055\u308C\u305F\u30C6\u30FC\u30D6\u30EB\u540D\uFF08\u5B8C\u5168\u4FEE\u98FE\u540D database.schema.table\u3001\u8907\u6570\u306E\u5834\u5408\u306F\u30AB\u30F3\u30DE\u533A\u5207\u308A\u3002\u300C\u5168\u30C6\u30FC\u30D6\u30EB\u300D\u306E\u5834\u5408\u306F "{database}.{schema}.*"\uFF09
212
+ - \`note\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5185\u5BB9\u306E\u7C21\u5358\u306A\u8AAC\u660E
213
+
214
+ ### \u91CD\u8981\u306A\u5236\u7D04
215
+ - askUserQuestion \u306E options \u306B\u306F\u6700\u4F4E2\u4EF6\u5FC5\u8981\u30021\u4EF6\u3057\u304B\u306A\u3044\u5834\u5408\u306F askUserQuestion \u3092\u547C\u3070\u305A\u6B21\u306E\u30B9\u30C6\u30C3\u30D7\u306B\u9032\u3080\u3053\u3068
216
+ - **\u30C6\u30FC\u30D6\u30EB\u306E\u884C\u30C7\u30FC\u30BF\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3053\u3068**\u3002\u5B9F\u884C\u3057\u3066\u3088\u3044\u306E\u306F\u4E0A\u8A18\u624B\u9806\u3067\u6307\u5B9A\u3055\u308C\u305F\u30E1\u30BF\u30C7\u30FC\u30BF\u53D6\u5F97\u30AF\u30A8\u30EA\u306E\u307F\u3002\u305D\u308C\u4EE5\u5916\u306E\u30AF\u30A8\u30EA\u306F\u5B9F\u884C\u7981\u6B62
217
+
218
+ ### \u5B9F\u884C\u65B9\u91DD
219
+ - \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057
220
+ - \u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
221
+ en: `## Snowflake Setup Instructions
222
+
223
+ Follow these steps to set up the Snowflake connection.
224
+
225
+ ### Steps
226
+
227
+ #### Step 1: Database Selection
228
+ 1. Run \`SHOW DATABASES\` to get the list of databases
229
+ 2. Branch based on results:
230
+ - **2 or more databases**: Present them to the user via \`askUserQuestion\` (multiSelect: true) and let them select which databases to use
231
+ - **Exactly 1 database**: Do NOT call askUserQuestion. Auto-select it. Just write "Auto-selected database X" in one sentence
232
+
233
+ #### Step 2: Schema Selection (including table scope)
234
+ 3. For the selected database(s), run \`SHOW SCHEMAS IN DATABASE {database}\` to get the schema list (run separately for each database if multiple)
235
+ 4. Exclude internal schemas such as INFORMATION_SCHEMA
236
+ 5. For each schema, generate **two options** and present them via \`askUserQuestion\` (multiSelect: true):
237
+ - \`{schema} (all tables)\` \u2014 description: "Use all tables in {database}.{schema}"
238
+ - \`{schema} (select specific tables)\` \u2014 description: "Use only specific tables in {database}.{schema}"
239
+ - Even if there is only 1 schema, present both "all tables" and "select specific tables" options
240
+
241
+ #### Step 3: Table Selection (only for schemas where "select specific tables" was chosen)
242
+ 6. For schemas where "all tables" was chosen, skip table selection and include all tables
243
+ 7. For schemas where "select specific tables" was chosen, run \`SHOW TABLES IN SCHEMA {database}.{schema}\` to get the table list
244
+ 8. Branch based on results:
245
+ - **2 or more tables**: Present them to the user via \`askUserQuestion\` (multiSelect: true) and let them select which tables to use. Include database.schema in the description
246
+ - **Exactly 1 table**: Do NOT call askUserQuestion. Auto-select it
247
+
248
+ #### Step 4: Save
249
+ 9. Call \`updateConnectionContext\` to save:
250
+ - \`database\`: Selected database name(s) (comma-separated if multiple)
251
+ - \`schema\`: Selected schema name(s) (comma-separated if multiple)
252
+ - \`tables\`: Selected table names (fully qualified database.schema.table, comma-separated if multiple. Use "{database}.{schema}.*" for "all tables" schemas)
253
+ - \`note\`: Brief description of the setup
254
+
255
+ ### Important Constraint
256
+ - askUserQuestion options requires at least 2 items. If there is only 1 item, do NOT call askUserQuestion \u2014 proceed to the next step directly
257
+ - **Do NOT read table row data**. Only the metadata queries specified in the steps above are allowed. All other queries are forbidden
258
+
259
+ ### Execution Policy
260
+ - Write only 1 sentence between tool calls, then immediately call the next tool
261
+ - Skip unnecessary explanations and proceed efficiently`
262
+ });
263
+
264
+ // src/connectors/snowflake/parameters.ts
118
265
  var parameters = {
119
266
  account: new ParameterDefinition({
120
267
  slug: "account",
@@ -152,18 +299,18 @@ var parameters = {
152
299
  secret: false,
153
300
  required: true
154
301
  }),
155
- pat: new ParameterDefinition({
156
- slug: "pat",
157
- name: "Personal Access Token",
158
- description: "Snowflake Personal Access Token (PAT) for authentication.",
159
- envVarBaseKey: "SNOWFLAKE_PASSWORD",
160
- type: "text",
302
+ privateKeyBase64: new ParameterDefinition({
303
+ slug: "private-key-base64",
304
+ name: "Snowflake Private Key",
305
+ description: "The private key for key-pair authentication.",
306
+ envVarBaseKey: "SNOWFLAKE_PRIVATE_KEY_BASE64",
307
+ type: "base64EncodedText",
161
308
  secret: true,
162
309
  required: true
163
310
  })
164
311
  };
165
312
 
166
- // src/connectors/snowflake-pat/tools/execute-query/tool.ts
313
+ // src/connectors/snowflake/tools/execute-query.ts
167
314
  import { z } from "zod";
168
315
  var MAX_ROWS = 500;
169
316
  var QUERY_TIMEOUT_MS = 6e4;
@@ -181,7 +328,7 @@ var outputSchema = z.discriminatedUnion("success", [
181
328
  success: z.literal(true),
182
329
  rowCount: z.number(),
183
330
  truncated: z.boolean(),
184
- rows: z.array(z.record(z.unknown()))
331
+ rows: z.array(z.record(z.string(), z.unknown()))
185
332
  }),
186
333
  z.object({
187
334
  success: z.literal(false),
@@ -204,22 +351,26 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
204
351
  };
205
352
  }
206
353
  console.log(
207
- `[connector-query] snowflake-pat/${connection.name}: ${sql}`
354
+ `[connector-query] snowflake/${connection.name}: ${sql}`
208
355
  );
209
356
  try {
210
357
  const snowflake = (await import("snowflake-sdk")).default;
211
358
  snowflake.configure({ logLevel: "ERROR" });
212
- const account = parameters.account.resolve(connection);
213
- const user = parameters.user.resolve(connection);
214
- const role = parameters.role.resolve(connection);
215
- const warehouse = parameters.warehouse.resolve(connection);
216
- const password = parameters.pat.resolve(connection);
359
+ const account = parameters.account.getValue(connection);
360
+ const user = parameters.user.getValue(connection);
361
+ const role = parameters.role.getValue(connection);
362
+ const warehouse = parameters.warehouse.getValue(connection);
363
+ const privateKeyBase64 = parameters.privateKeyBase64.getValue(connection);
364
+ const privateKey = Buffer.from(privateKeyBase64, "base64").toString(
365
+ "utf-8"
366
+ );
217
367
  const conn = snowflake.createConnection({
218
368
  account,
219
369
  username: user,
220
370
  role,
221
371
  warehouse,
222
- password
372
+ authenticator: "SNOWFLAKE_JWT",
373
+ privateKey
223
374
  });
224
375
  await new Promise((resolve, reject) => {
225
376
  conn.connect((err) => {
@@ -268,17 +419,231 @@ Avoid loading large amounts of data; always include LIMIT in queries.`,
268
419
  }
269
420
  });
270
421
 
422
+ // src/connectors/snowflake/index.ts
423
+ var tools = { executeQuery: executeQueryTool };
424
+ var snowflakeConnector = new ConnectorPlugin({
425
+ slug: "snowflake",
426
+ authType: null,
427
+ name: "Snowflake",
428
+ description: "Connect to Snowflake for cloud data warehousing and analytics.",
429
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6oyVtAcP3pMlXaOrts9unk/b7a9dc25d15c388b66e983041b855447/snowflake.svg",
430
+ parameters,
431
+ releaseFlag: { dev1: true, dev2: true, prod: true },
432
+ setup: snowflakeSetup,
433
+ systemPrompt: `## Snowflake SQL Notes
434
+ - Use fully qualified names DB.SCHEMA.TABLE for table references
435
+ - Schema exploration commands:
436
+ - List databases: \`SHOW DATABASES\`
437
+ - List schemas: \`SHOW SCHEMAS IN DATABASE db_name\`
438
+ - List tables: \`SHOW TABLES IN SCHEMA db_name.schema_name\`
439
+ - List columns: \`DESCRIBE TABLE db_name.schema_name.table_name\`
440
+ - INFORMATION_SCHEMA is also available: \`SELECT * FROM db_name.INFORMATION_SCHEMA.TABLES\``,
441
+ tools,
442
+ async query(params, sql, namedParams) {
443
+ const resolvedSql = replaceLiteralParams(sql, namedParams);
444
+ const snowflake = (await import("snowflake-sdk")).default;
445
+ snowflake.configure({ logLevel: "ERROR" });
446
+ const privateKey = Buffer.from(
447
+ params[parameters.privateKeyBase64.slug],
448
+ "base64"
449
+ ).toString("utf-8");
450
+ const conn = snowflake.createConnection({
451
+ account: params[parameters.account.slug],
452
+ username: params[parameters.user.slug],
453
+ role: params[parameters.role.slug],
454
+ warehouse: params[parameters.warehouse.slug],
455
+ authenticator: "SNOWFLAKE_JWT",
456
+ privateKey
457
+ });
458
+ await new Promise((resolve, reject) => {
459
+ conn.connect((err) => {
460
+ if (err) reject(new Error(`Snowflake connect failed: ${err.message}`));
461
+ else resolve();
462
+ });
463
+ });
464
+ const rows = await new Promise(
465
+ (resolve, reject) => {
466
+ conn.execute({
467
+ sqlText: resolvedSql,
468
+ complete: (err, _stmt, rows2) => {
469
+ if (err) reject(new Error(`Snowflake query failed: ${err.message}`));
470
+ else resolve(rows2 ?? []);
471
+ }
472
+ });
473
+ }
474
+ );
475
+ conn.destroy((err) => {
476
+ if (err) console.warn(`[connector-client] Snowflake destroy error: ${err.message}`);
477
+ });
478
+ return { rows };
479
+ }
480
+ });
481
+
482
+ // src/connectors/snowflake-pat/parameters.ts
483
+ var parameters2 = {
484
+ account: new ParameterDefinition({
485
+ slug: "account",
486
+ name: "Snowflake Account",
487
+ description: "The Snowflake account identifier (e.g., xy12345.us-east-1).",
488
+ envVarBaseKey: "SNOWFLAKE_ACCOUNT",
489
+ type: "text",
490
+ secret: false,
491
+ required: true
492
+ }),
493
+ user: new ParameterDefinition({
494
+ slug: "user",
495
+ name: "Snowflake User",
496
+ description: "The username for Snowflake authentication.",
497
+ envVarBaseKey: "SNOWFLAKE_USER",
498
+ type: "text",
499
+ secret: false,
500
+ required: true
501
+ }),
502
+ role: new ParameterDefinition({
503
+ slug: "role",
504
+ name: "Snowflake Role",
505
+ description: "The role to use when connecting to Snowflake.",
506
+ envVarBaseKey: "SNOWFLAKE_ROLE",
507
+ type: "text",
508
+ secret: false,
509
+ required: true
510
+ }),
511
+ warehouse: new ParameterDefinition({
512
+ slug: "warehouse",
513
+ name: "Snowflake Warehouse",
514
+ description: "The warehouse to use for executing queries.",
515
+ envVarBaseKey: "SNOWFLAKE_WAREHOUSE",
516
+ type: "text",
517
+ secret: false,
518
+ required: true
519
+ }),
520
+ pat: new ParameterDefinition({
521
+ slug: "pat",
522
+ name: "Personal Access Token",
523
+ description: "Snowflake Personal Access Token (PAT) for authentication.",
524
+ envVarBaseKey: "SNOWFLAKE_PASSWORD",
525
+ type: "text",
526
+ secret: true,
527
+ required: true
528
+ })
529
+ };
530
+
531
+ // src/connectors/snowflake-pat/tools/execute-query.ts
532
+ import { z as z2 } from "zod";
533
+ var MAX_ROWS2 = 500;
534
+ var QUERY_TIMEOUT_MS2 = 6e4;
535
+ var inputSchema2 = z2.object({
536
+ toolUseIntent: z2.string().optional().describe(
537
+ "Brief description of what you intend to accomplish with this tool call"
538
+ ),
539
+ connectionId: z2.string().describe("ID of the Snowflake connection to use"),
540
+ sql: z2.string().describe(
541
+ "Snowflake SQL query. Use fully qualified names DB.SCHEMA.TABLE for table references."
542
+ )
543
+ });
544
+ var outputSchema2 = z2.discriminatedUnion("success", [
545
+ z2.object({
546
+ success: z2.literal(true),
547
+ rowCount: z2.number(),
548
+ truncated: z2.boolean(),
549
+ rows: z2.array(z2.record(z2.string(), z2.unknown()))
550
+ }),
551
+ z2.object({
552
+ success: z2.literal(false),
553
+ error: z2.string()
554
+ })
555
+ ]);
556
+ var executeQueryTool2 = new ConnectorTool({
557
+ name: "executeQuery",
558
+ description: `Execute SQL against Snowflake. Returns up to ${MAX_ROWS2} rows.
559
+ Use for: schema exploration (SHOW DATABASES/SCHEMAS/TABLES, DESCRIBE TABLE, INFORMATION_SCHEMA), data sampling, analytical queries.
560
+ Avoid loading large amounts of data; always include LIMIT in queries.`,
561
+ inputSchema: inputSchema2,
562
+ outputSchema: outputSchema2,
563
+ async execute({ connectionId, sql }, connections) {
564
+ const connection = connections.find((c) => c.id === connectionId);
565
+ if (!connection) {
566
+ return {
567
+ success: false,
568
+ error: `Connection ${connectionId} not found`
569
+ };
570
+ }
571
+ console.log(
572
+ `[connector-query] snowflake-pat/${connection.name}: ${sql}`
573
+ );
574
+ try {
575
+ const snowflake = (await import("snowflake-sdk")).default;
576
+ snowflake.configure({ logLevel: "ERROR" });
577
+ const account = parameters2.account.getValue(connection);
578
+ const user = parameters2.user.getValue(connection);
579
+ const role = parameters2.role.getValue(connection);
580
+ const warehouse = parameters2.warehouse.getValue(connection);
581
+ const password = parameters2.pat.getValue(connection);
582
+ const conn = snowflake.createConnection({
583
+ account,
584
+ username: user,
585
+ role,
586
+ warehouse,
587
+ password
588
+ });
589
+ await new Promise((resolve, reject) => {
590
+ conn.connect((err) => {
591
+ if (err)
592
+ reject(new Error(`Snowflake connect failed: ${err.message}`));
593
+ else resolve();
594
+ });
595
+ });
596
+ const allRows = await new Promise(
597
+ (resolve, reject) => {
598
+ const timeoutId = setTimeout(() => {
599
+ reject(
600
+ new Error(
601
+ "Snowflake query timeout: query exceeded 60 seconds"
602
+ )
603
+ );
604
+ }, QUERY_TIMEOUT_MS2);
605
+ conn.execute({
606
+ sqlText: sql,
607
+ complete: (err, _stmt, rows) => {
608
+ clearTimeout(timeoutId);
609
+ if (err)
610
+ reject(new Error(`Snowflake query failed: ${err.message}`));
611
+ else resolve(rows ?? []);
612
+ }
613
+ });
614
+ }
615
+ );
616
+ conn.destroy((err) => {
617
+ if (err)
618
+ console.warn(
619
+ `[connector-query] Snowflake destroy error: ${err.message}`
620
+ );
621
+ });
622
+ const truncated = allRows.length > MAX_ROWS2;
623
+ return {
624
+ success: true,
625
+ rowCount: Math.min(allRows.length, MAX_ROWS2),
626
+ truncated,
627
+ rows: allRows.slice(0, MAX_ROWS2)
628
+ };
629
+ } catch (err) {
630
+ const msg = err instanceof Error ? err.message : String(err);
631
+ return { success: false, error: msg };
632
+ }
633
+ }
634
+ });
635
+
271
636
  // src/connectors/snowflake-pat/index.ts
272
- var tools = [executeQueryTool];
637
+ var tools2 = { executeQuery: executeQueryTool2 };
273
638
  var snowflakePatConnector = new ConnectorPlugin({
274
639
  slug: "snowflake",
275
640
  authType: AUTH_TYPES.PAT,
276
641
  name: "Snowflake (PAT)",
277
642
  description: "Connect to Snowflake using a Personal Access Token (PAT).",
278
643
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6oyVtAcP3pMlXaOrts9unk/b7a9dc25d15c388b66e983041b855447/snowflake.svg",
279
- order: 11,
280
- parameters: Object.values(parameters),
644
+ parameters: parameters2,
281
645
  releaseFlag: { dev1: true, dev2: false, prod: false },
646
+ setup: snowflakeSetup,
282
647
  systemPrompt: `## Snowflake SQL Notes
283
648
  - Use fully qualified names DB.SCHEMA.TABLE for table references
284
649
  - Schema exploration commands:
@@ -287,66 +652,2555 @@ var snowflakePatConnector = new ConnectorPlugin({
287
652
  - List tables: \`SHOW TABLES IN SCHEMA db_name.schema_name\`
288
653
  - List columns: \`DESCRIBE TABLE db_name.schema_name.table_name\`
289
654
  - INFORMATION_SCHEMA is also available: \`SELECT * FROM db_name.INFORMATION_SCHEMA.TABLES\``,
290
- tools,
291
- createClient(entry, connectionId) {
292
- const account = parameters.account.resolveEnvVar(entry, connectionId);
293
- const user = parameters.user.resolveEnvVar(entry, connectionId);
294
- const role = parameters.role.resolveEnvVar(entry, connectionId);
295
- const warehouse = parameters.warehouse.resolveEnvVar(entry, connectionId);
296
- const password = parameters.pat.resolveEnvVar(entry, connectionId);
297
- return {
298
- async query(sql) {
299
- const snowflake = (await import("snowflake-sdk")).default;
300
- snowflake.configure({ logLevel: "ERROR" });
301
- const conn = snowflake.createConnection({
302
- account,
303
- username: user,
304
- role,
305
- warehouse,
306
- password
307
- });
308
- await new Promise((resolve, reject) => {
309
- conn.connect((err) => {
655
+ tools: tools2,
656
+ async query(params, sql, namedParams) {
657
+ const resolvedSql = replaceLiteralParams(sql, namedParams);
658
+ const snowflake = (await import("snowflake-sdk")).default;
659
+ snowflake.configure({ logLevel: "ERROR" });
660
+ const conn = snowflake.createConnection({
661
+ account: params[parameters2.account.slug],
662
+ username: params[parameters2.user.slug],
663
+ role: params[parameters2.role.slug],
664
+ warehouse: params[parameters2.warehouse.slug],
665
+ password: params[parameters2.pat.slug]
666
+ });
667
+ await new Promise((resolve, reject) => {
668
+ conn.connect((err) => {
669
+ if (err)
670
+ reject(new Error(`Snowflake connect failed: ${err.message}`));
671
+ else resolve();
672
+ });
673
+ });
674
+ const rows = await new Promise(
675
+ (resolve, reject) => {
676
+ conn.execute({
677
+ sqlText: resolvedSql,
678
+ complete: (err, _stmt, rows2) => {
310
679
  if (err)
311
- reject(new Error(`Snowflake connect failed: ${err.message}`));
312
- else resolve();
313
- });
314
- });
315
- const rows = await new Promise(
316
- (resolve, reject) => {
317
- conn.execute({
318
- sqlText: sql,
319
- complete: (err, _stmt, rows2) => {
320
- if (err)
321
- reject(
322
- new Error(`Snowflake query failed: ${err.message}`)
323
- );
324
- else resolve(rows2 ?? []);
325
- }
326
- });
680
+ reject(new Error(`Snowflake query failed: ${err.message}`));
681
+ else resolve(rows2 ?? []);
327
682
  }
328
- );
329
- conn.destroy((err) => {
330
- if (err)
331
- console.warn(
332
- `[connector-client] Snowflake destroy error: ${err.message}`
333
- );
334
683
  });
335
- return { rows };
336
684
  }
337
- };
685
+ );
686
+ conn.destroy((err) => {
687
+ if (err)
688
+ console.warn(
689
+ `[connector-client] Snowflake destroy error: ${err.message}`
690
+ );
691
+ });
692
+ return { rows };
338
693
  }
339
694
  });
340
695
 
341
- // src/connectors/registry.ts
342
- var connectors = [
343
- snowflakePatConnector
344
- ];
696
+ // src/connectors/postgresql/parameters.ts
697
+ var parameters3 = {
698
+ connectionUrl: new ParameterDefinition({
699
+ slug: "connection-url",
700
+ name: "PostgreSQL Connection URL",
701
+ description: "The PostgreSQL connection URL (e.g., postgresql://user:password@host:5432/database).",
702
+ envVarBaseKey: "POSTGRES_URL",
703
+ type: "text",
704
+ secret: true,
705
+ required: true
706
+ })
707
+ };
708
+
709
+ // src/connectors/postgresql/tools/execute-query.ts
710
+ import { z as z3 } from "zod";
711
+ var MAX_ROWS3 = 500;
712
+ var CONNECT_TIMEOUT_MS = 1e4;
713
+ var STATEMENT_TIMEOUT_MS = 6e4;
714
+ var inputSchema3 = z3.object({
715
+ toolUseIntent: z3.string().optional().describe(
716
+ "Brief description of what you intend to accomplish with this tool call"
717
+ ),
718
+ connectionId: z3.string().describe("ID of the PostgreSQL connection to use"),
719
+ sql: z3.string().describe("PostgreSQL SQL query. Always include LIMIT in queries.")
720
+ });
721
+ var outputSchema3 = z3.discriminatedUnion("success", [
722
+ z3.object({
723
+ success: z3.literal(true),
724
+ rowCount: z3.number(),
725
+ truncated: z3.boolean(),
726
+ rows: z3.array(z3.record(z3.string(), z3.unknown()))
727
+ }),
728
+ z3.object({
729
+ success: z3.literal(false),
730
+ error: z3.string()
731
+ })
732
+ ]);
733
+ var executeQueryTool3 = new ConnectorTool({
734
+ name: "executeQuery",
735
+ description: `Execute SQL against PostgreSQL. Returns up to ${MAX_ROWS3} rows.
736
+ Use for: schema exploration (information_schema), data sampling, analytical queries.
737
+ Avoid loading large amounts of data; always include LIMIT in queries.`,
738
+ inputSchema: inputSchema3,
739
+ outputSchema: outputSchema3,
740
+ async execute({ connectionId, sql }, connections) {
741
+ const connection = connections.find((c) => c.id === connectionId);
742
+ if (!connection) {
743
+ return {
744
+ success: false,
745
+ error: `Connection ${connectionId} not found`
746
+ };
747
+ }
748
+ console.log(
749
+ `[connector-query] postgresql/${connection.name}: ${sql}`
750
+ );
751
+ let connectionUrl;
752
+ try {
753
+ const { Pool } = await import("pg");
754
+ connectionUrl = parameters3.connectionUrl.getValue(connection);
755
+ const pool = new Pool({
756
+ connectionString: connectionUrl,
757
+ ssl: { rejectUnauthorized: false },
758
+ connectionTimeoutMillis: CONNECT_TIMEOUT_MS,
759
+ statement_timeout: STATEMENT_TIMEOUT_MS
760
+ });
761
+ try {
762
+ const result = await pool.query(sql);
763
+ const rows = result.rows;
764
+ const truncated = rows.length > MAX_ROWS3;
765
+ return {
766
+ success: true,
767
+ rowCount: Math.min(rows.length, MAX_ROWS3),
768
+ truncated,
769
+ rows: rows.slice(0, MAX_ROWS3)
770
+ };
771
+ } finally {
772
+ await pool.end();
773
+ }
774
+ } catch (err) {
775
+ let msg = err instanceof Error ? err.message : String(err);
776
+ if (connectionUrl) {
777
+ msg = msg.replaceAll(connectionUrl, "***");
778
+ }
779
+ return { success: false, error: msg };
780
+ }
781
+ }
782
+ });
783
+
784
+ // src/connectors/postgresql/index.ts
785
+ var tools3 = { executeQuery: executeQueryTool3 };
786
+ var postgresqlConnector = new ConnectorPlugin({
787
+ slug: "postgresql",
788
+ authType: null,
789
+ name: "PostgreSQL",
790
+ description: "Connect to PostgreSQL databases for relational data storage and querying.",
791
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/42AHi2uqteUn65MyqdN6V7/a0f68f12af6aac96bbcda5980f43de07/elephant.png",
792
+ parameters: parameters3,
793
+ releaseFlag: { dev1: true, dev2: true, prod: true },
794
+ systemPrompt: `## PostgreSQL SQL Notes
795
+ - Schema exploration:
796
+ - List tables: \`SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'\`
797
+ - List columns: \`SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'xxx'\`
798
+ - Always include LIMIT in queries`,
799
+ tools: tools3,
800
+ async query(params, sql, namedParams) {
801
+ const { Pool } = await import("pg");
802
+ const { text, values } = buildPositionalParams(sql, namedParams);
803
+ const pool = new Pool({
804
+ connectionString: params[parameters3.connectionUrl.slug],
805
+ ssl: { rejectUnauthorized: false },
806
+ connectionTimeoutMillis: 1e4,
807
+ statement_timeout: 6e4
808
+ });
809
+ try {
810
+ const result = await pool.query(text, values);
811
+ return { rows: result.rows };
812
+ } finally {
813
+ await pool.end();
814
+ }
815
+ }
816
+ });
817
+
818
+ // src/connectors/mysql/parameters.ts
819
+ var parameters4 = {
820
+ connectionUrl: new ParameterDefinition({
821
+ slug: "connection-url",
822
+ name: "MySQL Connection URL",
823
+ description: "The MySQL connection URL (e.g., mysql://user:password@host:3306/database).",
824
+ envVarBaseKey: "MYSQL_URL",
825
+ type: "text",
826
+ secret: true,
827
+ required: true
828
+ })
829
+ };
830
+
831
+ // src/connectors/mysql/tools/execute-query.ts
832
+ import { z as z4 } from "zod";
833
+ var MAX_ROWS4 = 500;
834
+ var CONNECT_TIMEOUT_MS2 = 1e4;
835
+ var QUERY_TIMEOUT_MS3 = 6e4;
836
+ var inputSchema4 = z4.object({
837
+ toolUseIntent: z4.string().optional().describe(
838
+ "Brief description of what you intend to accomplish with this tool call"
839
+ ),
840
+ connectionId: z4.string().describe("ID of the MySQL connection to use"),
841
+ sql: z4.string().describe("MySQL SQL query. Always include LIMIT in queries.")
842
+ });
843
+ var outputSchema4 = z4.discriminatedUnion("success", [
844
+ z4.object({
845
+ success: z4.literal(true),
846
+ rowCount: z4.number(),
847
+ truncated: z4.boolean(),
848
+ rows: z4.array(z4.record(z4.string(), z4.unknown()))
849
+ }),
850
+ z4.object({
851
+ success: z4.literal(false),
852
+ error: z4.string()
853
+ })
854
+ ]);
855
+ var executeQueryTool4 = new ConnectorTool({
856
+ name: "executeQuery",
857
+ description: `Execute SQL against MySQL. Returns up to ${MAX_ROWS4} rows.
858
+ Use for: schema exploration (information_schema), data sampling, analytical queries.
859
+ Avoid loading large amounts of data; always include LIMIT in queries.`,
860
+ inputSchema: inputSchema4,
861
+ outputSchema: outputSchema4,
862
+ async execute({ connectionId, sql }, connections) {
863
+ const connection = connections.find((c) => c.id === connectionId);
864
+ if (!connection) {
865
+ return {
866
+ success: false,
867
+ error: `Connection ${connectionId} not found`
868
+ };
869
+ }
870
+ console.log(
871
+ `[connector-query] mysql/${connection.name}: ${sql}`
872
+ );
873
+ let connectionUrl;
874
+ try {
875
+ const mysql = await import("mysql2/promise");
876
+ connectionUrl = parameters4.connectionUrl.getValue(connection);
877
+ const pool = mysql.createPool({
878
+ uri: connectionUrl,
879
+ connectTimeout: CONNECT_TIMEOUT_MS2
880
+ });
881
+ try {
882
+ const queryPromise = pool.query(sql);
883
+ const timeoutPromise = new Promise(
884
+ (_, reject) => setTimeout(() => reject(new Error("Query timed out after 60 seconds")), QUERY_TIMEOUT_MS3)
885
+ );
886
+ const [rows] = await Promise.race([queryPromise, timeoutPromise]);
887
+ const resultRows = Array.isArray(rows) ? rows : [];
888
+ const truncated = resultRows.length > MAX_ROWS4;
889
+ return {
890
+ success: true,
891
+ rowCount: Math.min(resultRows.length, MAX_ROWS4),
892
+ truncated,
893
+ rows: resultRows.slice(0, MAX_ROWS4)
894
+ };
895
+ } finally {
896
+ await pool.end();
897
+ }
898
+ } catch (err) {
899
+ let msg = err instanceof Error ? err.message : String(err);
900
+ if (connectionUrl) {
901
+ msg = msg.replaceAll(connectionUrl, "***");
902
+ }
903
+ return { success: false, error: msg };
904
+ }
905
+ }
906
+ });
907
+
908
+ // src/connectors/mysql/index.ts
909
+ var tools4 = { executeQuery: executeQueryTool4 };
910
+ var mysqlConnector = new ConnectorPlugin({
911
+ slug: "mysql",
912
+ authType: null,
913
+ name: "MySQL",
914
+ description: "Connect to MySQL databases for relational data storage and querying.",
915
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6ghPFeGgl7uBs5NHH1a4L/512c9433beec5b595caa41f04921c1f9/logo-mysql-170x115.png",
916
+ parameters: parameters4,
917
+ releaseFlag: { dev1: true, dev2: true, prod: true },
918
+ systemPrompt: `## MySQL SQL Notes
919
+ - Schema exploration:
920
+ - List tables: \`SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE()\`
921
+ - List columns: \`SELECT COLUMN_NAME, DATA_TYPE FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'xxx'\`
922
+ - Always include LIMIT in queries`,
923
+ tools: tools4,
924
+ async query(params, sql, namedParams) {
925
+ const mysql = await import("mysql2/promise");
926
+ const { text, values } = buildQuestionmarkParams(sql, namedParams);
927
+ const pool = mysql.createPool({
928
+ uri: params[parameters4.connectionUrl.slug],
929
+ connectTimeout: 1e4
930
+ });
931
+ try {
932
+ const queryPromise = pool.query(text, values);
933
+ const timeoutPromise = new Promise(
934
+ (_, reject) => setTimeout(() => reject(new Error("Query timed out after 60 seconds")), 6e4)
935
+ );
936
+ const [rows] = await Promise.race([queryPromise, timeoutPromise]);
937
+ const resultRows = Array.isArray(rows) ? rows : [];
938
+ return { rows: resultRows };
939
+ } finally {
940
+ await pool.end();
941
+ }
942
+ }
943
+ });
944
+
945
+ // src/connectors/bigquery/setup.ts
946
+ var bigquerySetup = new ConnectorSetup({
947
+ ja: `## BigQuery \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u624B\u9806
948
+
949
+ \u4EE5\u4E0B\u306E\u624B\u9806\u3067BigQuery\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
950
+
951
+ ### \u624B\u9806
952
+
953
+ #### \u30B9\u30C6\u30C3\u30D70: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u9078\u629E
954
+ 1. \`listProjects\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u304C\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306AGCP\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
955
+ 2. \u7D50\u679C\u306B\u5FDC\u3058\u3066\u5206\u5C90:
956
+ - **\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u304C2\u3064\u4EE5\u4E0A**: \`askUserQuestion\`\uFF08multiSelect: false\uFF09\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u63D0\u793A\u3057\u3001\u4F7F\u7528\u3059\u308B\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u629E\u3055\u305B\u308B\u3002\u9078\u629E\u80A2\u306E label \u306F \`\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D (id: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID)\` \u306E\u5F62\u5F0F\u306B\u3059\u308B
957
+ - **\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u304C1\u3064\u3060\u3051**: askUserQuestion \u306F\u4F7F\u308F\u305A\u81EA\u52D5\u63A1\u7528\u3002\u300C\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 X \u3092\u81EA\u52D5\u9078\u629E\u3057\u307E\u3057\u305F\u300D\u30681\u6587\u3060\u3051\u66F8\u304F
958
+ 3. \`updateConnectionParameters\` \u3067\u9078\u629E\u3055\u308C\u305F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u4FDD\u5B58\u3059\u308B:
959
+ - \`parameterSlug\`: \`"project-id"\`
960
+ - \`value\`: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID
961
+ - \`displayValue\`: \`"\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D (id: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID)"\`
962
+ 4. \u7D9A\u884C\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u53D7\u3051\u53D6\u3063\u305F\u3089\u3001\u30B9\u30C6\u30C3\u30D71\u306B\u9032\u3080
963
+
964
+ #### \u30B9\u30C6\u30C3\u30D71: \u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u9078\u629E
965
+ 1. \`SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA\` \u3092\u5B9F\u884C\u3057\u3066\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
966
+ 2. \u7D50\u679C\u306B\u5FDC\u3058\u3066\u5206\u5C90:
967
+ - **\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u304C2\u3064\u4EE5\u4E0A**: \`askUserQuestion\`\uFF08multiSelect: true\uFF09\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u63D0\u793A\u3057\u3001\u4F7F\u7528\u3059\u308B\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u3092\u9078\u629E\u3055\u305B\u308B
968
+ - **\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u304C1\u3064\u3060\u3051**: askUserQuestion \u306F\u4F7F\u308F\u305A\u81EA\u52D5\u63A1\u7528\u3002\u300C\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8 X \u3092\u81EA\u52D5\u9078\u629E\u3057\u307E\u3057\u305F\u300D\u30681\u6587\u3060\u3051\u66F8\u304F
969
+
970
+ #### \u30B9\u30C6\u30C3\u30D72: \u30C6\u30FC\u30D6\u30EB\u9078\u629E
971
+ 3. \u9078\u629E\u3055\u308C\u305F\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u306B\u5BFE\u3057\u3066 \`SELECT table_name FROM \\\`{project}.{dataset}.INFORMATION_SCHEMA.TABLES\\\`\` \u3092\u5B9F\u884C\u3057\u3066\u30C6\u30FC\u30D6\u30EB\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B\uFF08\u8907\u6570\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u306E\u5834\u5408\u306F UNION ALL \u3067\u4E00\u62EC\u53D6\u5F97\uFF09
972
+ 4. \u7D50\u679C\u306B\u5FDC\u3058\u3066\u5206\u5C90:
973
+ - **\u30C6\u30FC\u30D6\u30EB\u304C2\u3064\u4EE5\u4E0A**: \`askUserQuestion\`\uFF08multiSelect: true\uFF09\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u63D0\u793A\u3057\u3001\u4F7F\u7528\u3059\u308B\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u629E\u3055\u305B\u308B\u3002description \u306B\u306F\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u540D\u3092\u8A18\u8F09\u3059\u308B
974
+ - **\u30C6\u30FC\u30D6\u30EB\u304C1\u3064\u3060\u3051**: askUserQuestion \u306F\u4F7F\u308F\u305A\u81EA\u52D5\u63A1\u7528
975
+
976
+ #### \u30B9\u30C6\u30C3\u30D73: \u4FDD\u5B58
977
+ 5. \`updateConnectionContext\` \u3067\u4EE5\u4E0B\u3092\u4FDD\u5B58\u3059\u308B:
978
+ - \`project\`: BigQuery\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID
979
+ - \`dataset\`: \u9078\u629E\u3055\u308C\u305F\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u540D\uFF08\u8907\u6570\u306E\u5834\u5408\u306F\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09
980
+ - \`tables\`: \u9078\u629E\u3055\u308C\u305F\u30C6\u30FC\u30D6\u30EB\u540D\uFF08\u8907\u6570\u306E\u5834\u5408\u306F\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09
981
+ - \`note\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5185\u5BB9\u306E\u7C21\u5358\u306A\u8AAC\u660E
982
+
983
+ ### \u91CD\u8981\u306A\u5236\u7D04
984
+ - askUserQuestion \u306E options \u306B\u306F\u6700\u4F4E2\u4EF6\u5FC5\u8981\u30021\u4EF6\u3057\u304B\u306A\u3044\u5834\u5408\u306F askUserQuestion \u3092\u547C\u3070\u305A\u6B21\u306E\u30B9\u30C6\u30C3\u30D7\u306B\u9032\u3080\u3053\u3068
985
+ - **\u30C6\u30FC\u30D6\u30EB\u306E\u884C\u30C7\u30FC\u30BF\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3053\u3068**\u3002\u5B9F\u884C\u3057\u3066\u3088\u3044\u306E\u306F\u4E0A\u8A18\u624B\u9806\u3067\u6307\u5B9A\u3055\u308C\u305F\u30E1\u30BF\u30C7\u30FC\u30BF\u53D6\u5F97\u30AF\u30A8\u30EA\u306E\u307F\u3002\u305D\u308C\u4EE5\u5916\u306E\u30AF\u30A8\u30EA\u306F\u5B9F\u884C\u7981\u6B62
986
+
987
+ ### \u5B9F\u884C\u65B9\u91DD
988
+ - \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057
989
+ - \u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
990
+ en: `## BigQuery Setup Instructions
991
+
992
+ Follow these steps to set up the BigQuery connection.
993
+
994
+ ### Steps
995
+
996
+ #### Step 0: Project Selection
997
+ 1. Call \`listProjects\` to get the list of GCP projects accessible with the service account credentials
998
+ 2. Branch based on results:
999
+ - **2 or more projects**: Present them to the user via \`askUserQuestion\` (multiSelect: false) and let them select a project. Format option labels as \`Project Name (id: project-id)\`
1000
+ - **Exactly 1 project**: Do NOT call askUserQuestion. Auto-select it. Just write "Auto-selected project X" in one sentence
1001
+ 3. Call \`updateConnectionParameters\` to save the selected project:
1002
+ - \`parameterSlug\`: \`"project-id"\`
1003
+ - \`value\`: the project ID
1004
+ - \`displayValue\`: \`"Project Name (id: project-id)"\`
1005
+ 4. After receiving the continuation message, proceed to Step 1
1006
+
1007
+ #### Step 1: Dataset Selection
1008
+ 1. Run \`SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA\` to get the list of datasets
1009
+ 2. Branch based on results:
1010
+ - **2 or more datasets**: Present them to the user via \`askUserQuestion\` (multiSelect: true) and let them select which datasets to use
1011
+ - **Exactly 1 dataset**: Do NOT call askUserQuestion. Auto-select it. Just write "Auto-selected dataset X" in one sentence
1012
+
1013
+ #### Step 2: Table Selection
1014
+ 3. For the selected dataset(s), run \`SELECT table_name FROM \\\`{project}.{dataset}.INFORMATION_SCHEMA.TABLES\\\`\` to get the table list (use UNION ALL for multiple datasets)
1015
+ 4. Branch based on results:
1016
+ - **2 or more tables**: Present them to the user via \`askUserQuestion\` (multiSelect: true) and let them select which tables to use. Include the dataset name in the description
1017
+ - **Exactly 1 table**: Do NOT call askUserQuestion. Auto-select it
1018
+
1019
+ #### Step 3: Save
1020
+ 5. Call \`updateConnectionContext\` to save:
1021
+ - \`project\`: BigQuery project ID
1022
+ - \`dataset\`: Selected dataset name(s) (comma-separated if multiple)
1023
+ - \`tables\`: Selected table name(s) (comma-separated if multiple)
1024
+ - \`note\`: Brief description of the setup
1025
+
1026
+ ### Important Constraints
1027
+ - askUserQuestion options requires at least 2 items. If there is only 1 item, do NOT call askUserQuestion \u2014 proceed to the next step directly
1028
+ - **Do NOT read table row data**. Only the metadata queries specified in the steps above are allowed. All other queries are forbidden
1029
+
1030
+ ### Execution Policy
1031
+ - Write only 1 sentence between tool calls, then immediately call the next tool
1032
+ - Skip unnecessary explanations and proceed efficiently`
1033
+ });
1034
+
1035
+ // src/connectors/bigquery/parameters.ts
1036
+ var parameters5 = {
1037
+ serviceAccountKeyJsonBase64: new ParameterDefinition({
1038
+ slug: "service-account-key-json-base64",
1039
+ name: "Google Cloud Service Account JSON",
1040
+ description: "The service account JSON key used to authenticate with Google Cloud Platform. Ensure that the service account has the necessary permissions to access the required resources.",
1041
+ envVarBaseKey: "BIGQUERY_SERVICE_ACCOUNT_JSON_BASE64",
1042
+ type: "base64EncodedJson",
1043
+ secret: true,
1044
+ required: true
1045
+ }),
1046
+ projectId: new ParameterDefinition({
1047
+ slug: "project-id",
1048
+ name: "Google Cloud Project ID",
1049
+ description: "The ID of the Google Cloud project where resources will be managed.",
1050
+ envVarBaseKey: "BIGQUERY_PROJECT_ID",
1051
+ type: "text",
1052
+ secret: false,
1053
+ required: false
1054
+ })
1055
+ };
1056
+
1057
+ // src/connectors/bigquery/tools/execute-query.ts
1058
+ import { z as z5 } from "zod";
1059
+ var MAX_ROWS5 = 500;
1060
+ var inputSchema5 = z5.object({
1061
+ toolUseIntent: z5.string().optional().describe(
1062
+ "Brief description of what you intend to accomplish with this tool call"
1063
+ ),
1064
+ connectionId: z5.string().describe("ID of the BigQuery connection to use"),
1065
+ sql: z5.string().describe(
1066
+ "BigQuery SQL (GoogleSQL) query. Use backtick-quoted fully qualified names `project.dataset.table` for table references."
1067
+ )
1068
+ });
1069
+ var outputSchema5 = z5.discriminatedUnion("success", [
1070
+ z5.object({
1071
+ success: z5.literal(true),
1072
+ rowCount: z5.number(),
1073
+ truncated: z5.boolean(),
1074
+ rows: z5.array(z5.record(z5.string(), z5.unknown()))
1075
+ }),
1076
+ z5.object({
1077
+ success: z5.literal(false),
1078
+ error: z5.string()
1079
+ })
1080
+ ]);
1081
+ var executeQueryTool5 = new ConnectorTool({
1082
+ name: "executeQuery",
1083
+ description: `Execute SQL against BigQuery. Returns up to ${MAX_ROWS5} rows.
1084
+ Use for: schema exploration (INFORMATION_SCHEMA), data sampling, analytical queries.
1085
+ Avoid loading large amounts of data; always include LIMIT in queries.`,
1086
+ inputSchema: inputSchema5,
1087
+ outputSchema: outputSchema5,
1088
+ async execute({ connectionId, sql }, connections) {
1089
+ const connection = connections.find((c) => c.id === connectionId);
1090
+ if (!connection) {
1091
+ return {
1092
+ success: false,
1093
+ error: `Connection ${connectionId} not found`
1094
+ };
1095
+ }
1096
+ console.log(
1097
+ `[connector-query] bigquery/${connection.name}: ${sql}`
1098
+ );
1099
+ try {
1100
+ const { BigQuery } = await import("@google-cloud/bigquery");
1101
+ const projectId = parameters5.projectId.getValue(connection);
1102
+ const serviceAccountJsonBase64 = parameters5.serviceAccountKeyJsonBase64.getValue(connection);
1103
+ const credentials = JSON.parse(
1104
+ Buffer.from(serviceAccountJsonBase64, "base64").toString("utf-8")
1105
+ );
1106
+ const bq = new BigQuery({ projectId, credentials });
1107
+ const [job] = await bq.createQueryJob({ query: sql });
1108
+ const [rows] = await job.getQueryResults();
1109
+ const allRows = rows;
1110
+ const truncated = allRows.length > MAX_ROWS5;
1111
+ return {
1112
+ success: true,
1113
+ rowCount: Math.min(allRows.length, MAX_ROWS5),
1114
+ truncated,
1115
+ rows: allRows.slice(0, MAX_ROWS5)
1116
+ };
1117
+ } catch (err) {
1118
+ const msg = err instanceof Error ? err.message : String(err);
1119
+ return { success: false, error: msg };
1120
+ }
1121
+ }
1122
+ });
1123
+
1124
+ // src/connectors/bigquery/tools/list-projects.ts
1125
+ import { z as z6 } from "zod";
1126
+ var inputSchema6 = z6.object({
1127
+ toolUseIntent: z6.string().optional().describe(
1128
+ "Brief description of what you intend to accomplish with this tool call"
1129
+ ),
1130
+ connectionId: z6.string().describe("ID of the BigQuery connection to use")
1131
+ });
1132
+ var outputSchema6 = z6.discriminatedUnion("success", [
1133
+ z6.object({
1134
+ success: z6.literal(true),
1135
+ projects: z6.array(
1136
+ z6.object({
1137
+ projectId: z6.string(),
1138
+ friendlyName: z6.string()
1139
+ })
1140
+ )
1141
+ }),
1142
+ z6.object({
1143
+ success: z6.literal(false),
1144
+ error: z6.string()
1145
+ })
1146
+ ]);
1147
+ var listProjectsTool = new ConnectorTool({
1148
+ name: "listProjects",
1149
+ description: `List GCP projects accessible with the service account credentials. Returns project IDs and friendly names.`,
1150
+ inputSchema: inputSchema6,
1151
+ outputSchema: outputSchema6,
1152
+ async execute({ connectionId }, connections) {
1153
+ const connection = connections.find((c) => c.id === connectionId);
1154
+ if (!connection) {
1155
+ return {
1156
+ success: false,
1157
+ error: `Connection ${connectionId} not found`
1158
+ };
1159
+ }
1160
+ try {
1161
+ const serviceAccountJsonBase64 = parameters5.serviceAccountKeyJsonBase64.getValue(connection);
1162
+ const credentials = JSON.parse(
1163
+ Buffer.from(serviceAccountJsonBase64, "base64").toString("utf-8")
1164
+ );
1165
+ const { GoogleAuth } = await import("google-auth-library");
1166
+ const auth = new GoogleAuth({
1167
+ credentials,
1168
+ scopes: ["https://www.googleapis.com/auth/bigquery"]
1169
+ });
1170
+ const client = await auth.getClient();
1171
+ const res = await client.request({
1172
+ url: "https://bigquery.googleapis.com/bigquery/v2/projects"
1173
+ });
1174
+ const projects = (res.data.projects ?? []).map((p) => ({
1175
+ projectId: p.projectReference?.projectId ?? "",
1176
+ friendlyName: p.friendlyName ?? p.projectReference?.projectId ?? ""
1177
+ })).filter((p) => p.projectId !== "");
1178
+ return { success: true, projects };
1179
+ } catch (err) {
1180
+ const msg = err instanceof Error ? err.message : String(err);
1181
+ return { success: false, error: msg };
1182
+ }
1183
+ }
1184
+ });
1185
+
1186
+ // src/connectors/bigquery/index.ts
1187
+ var tools5 = { executeQuery: executeQueryTool5, listProjects: listProjectsTool };
1188
+ var bigqueryConnector = new ConnectorPlugin({
1189
+ slug: "bigquery",
1190
+ authType: null,
1191
+ name: "BigQuery",
1192
+ description: "Connect to Google BigQuery for data warehouse and analytics.",
1193
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6nlehQyOmdbktG5hOYkYMr/6ca559140d5ddc7dadc5eac88858a563/bigquery.svg",
1194
+ parameters: parameters5,
1195
+ releaseFlag: { dev1: true, dev2: true, prod: true },
1196
+ setup: bigquerySetup,
1197
+ systemPrompt: `## BigQuery SQL Notes
1198
+ - Use backtick-quoted fully qualified names \`project.dataset.table\` for table references
1199
+ - Use INFORMATION_SCHEMA for schema exploration
1200
+ - List datasets: \`SELECT schema_name FROM \\\`project_id\\\`.INFORMATION_SCHEMA.SCHEMATA\`
1201
+ - List tables: \`SELECT table_name FROM \\\`project_id.dataset\\\`.INFORMATION_SCHEMA.TABLES\`
1202
+ - List columns: \`SELECT column_name, data_type FROM \\\`project_id.dataset\\\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'xxx'\`
1203
+ - Always specify project_id explicitly in queries`,
1204
+ tools: tools5,
1205
+ async query(params, sql, namedParams) {
1206
+ const { BigQuery } = await import("@google-cloud/bigquery");
1207
+ const resolvedSql = replaceLiteralParams(sql, namedParams);
1208
+ const credentials = JSON.parse(
1209
+ Buffer.from(params[parameters5.serviceAccountKeyJsonBase64.slug], "base64").toString("utf-8")
1210
+ );
1211
+ const bq = new BigQuery({
1212
+ projectId: params[parameters5.projectId.slug],
1213
+ credentials
1214
+ });
1215
+ const [job] = await bq.createQueryJob({ query: resolvedSql });
1216
+ const [rows] = await job.getQueryResults();
1217
+ return { rows };
1218
+ }
1219
+ });
1220
+
1221
+ // src/connectors/bigquery-oauth/setup.ts
1222
+ var bigquerySetup2 = new ConnectorSetup({
1223
+ ja: `## BigQuery \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u624B\u9806
1224
+
1225
+ \u4EE5\u4E0B\u306E\u624B\u9806\u3067BigQuery\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
1226
+
1227
+ ### \u624B\u9806
1228
+
1229
+ #### \u30B9\u30C6\u30C3\u30D70: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u9078\u629E
1230
+ 1. \`listProjects\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001OAuth\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306AGCP\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
1231
+ 2. \u7D50\u679C\u306B\u5FDC\u3058\u3066\u5206\u5C90:
1232
+ - **\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u304C2\u3064\u4EE5\u4E0A**: \`askUserQuestion\`\uFF08multiSelect: false\uFF09\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u63D0\u793A\u3057\u3001\u4F7F\u7528\u3059\u308B\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u629E\u3055\u305B\u308B\u3002\u9078\u629E\u80A2\u306E label \u306F \`\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D (id: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID)\` \u306E\u5F62\u5F0F\u306B\u3059\u308B
1233
+ - **\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u304C1\u3064\u3060\u3051**: askUserQuestion \u306F\u4F7F\u308F\u305A\u81EA\u52D5\u63A1\u7528\u3002\u300C\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 X \u3092\u81EA\u52D5\u9078\u629E\u3057\u307E\u3057\u305F\u300D\u30681\u6587\u3060\u3051\u66F8\u304F
1234
+ 3. \`updateConnectionParameters\` \u3067\u9078\u629E\u3055\u308C\u305F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u4FDD\u5B58\u3059\u308B:
1235
+ - \`parameterSlug\`: \`"project-id"\`
1236
+ - \`value\`: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID
1237
+ - \`displayValue\`: \`"\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D (id: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID)"\`
1238
+ 4. \u7D9A\u884C\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u53D7\u3051\u53D6\u3063\u305F\u3089\u3001\u30B9\u30C6\u30C3\u30D71\u306B\u9032\u3080
1239
+
1240
+ #### \u30B9\u30C6\u30C3\u30D71: \u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u9078\u629E
1241
+ 1. \`SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA\` \u3092\u5B9F\u884C\u3057\u3066\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B
1242
+ 2. \u7D50\u679C\u306B\u5FDC\u3058\u3066\u5206\u5C90:
1243
+ - **\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u304C2\u3064\u4EE5\u4E0A**: \`askUserQuestion\`\uFF08multiSelect: true\uFF09\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u63D0\u793A\u3057\u3001\u4F7F\u7528\u3059\u308B\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u3092\u9078\u629E\u3055\u305B\u308B
1244
+ - **\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u304C1\u3064\u3060\u3051**: askUserQuestion \u306F\u4F7F\u308F\u305A\u81EA\u52D5\u63A1\u7528\u3002\u300C\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8 X \u3092\u81EA\u52D5\u9078\u629E\u3057\u307E\u3057\u305F\u300D\u30681\u6587\u3060\u3051\u66F8\u304F
1245
+
1246
+ #### \u30B9\u30C6\u30C3\u30D72: \u30C6\u30FC\u30D6\u30EB\u9078\u629E
1247
+ 3. \u9078\u629E\u3055\u308C\u305F\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u306B\u5BFE\u3057\u3066 \`SELECT table_name FROM \\\`{project}.{dataset}.INFORMATION_SCHEMA.TABLES\\\`\` \u3092\u5B9F\u884C\u3057\u3066\u30C6\u30FC\u30D6\u30EB\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B\uFF08\u8907\u6570\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u306E\u5834\u5408\u306F UNION ALL \u3067\u4E00\u62EC\u53D6\u5F97\uFF09
1248
+ 4. \u7D50\u679C\u306B\u5FDC\u3058\u3066\u5206\u5C90:
1249
+ - **\u30C6\u30FC\u30D6\u30EB\u304C2\u3064\u4EE5\u4E0A**: \`askUserQuestion\`\uFF08multiSelect: true\uFF09\u3067\u30E6\u30FC\u30B6\u30FC\u306B\u63D0\u793A\u3057\u3001\u4F7F\u7528\u3059\u308B\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u629E\u3055\u305B\u308B\u3002description \u306B\u306F\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u540D\u3092\u8A18\u8F09\u3059\u308B
1250
+ - **\u30C6\u30FC\u30D6\u30EB\u304C1\u3064\u3060\u3051**: askUserQuestion \u306F\u4F7F\u308F\u305A\u81EA\u52D5\u63A1\u7528
1251
+
1252
+ #### \u30B9\u30C6\u30C3\u30D73: \u4FDD\u5B58
1253
+ 5. \`updateConnectionContext\` \u3067\u4EE5\u4E0B\u3092\u4FDD\u5B58\u3059\u308B:
1254
+ - \`project\`: BigQuery\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8ID
1255
+ - \`dataset\`: \u9078\u629E\u3055\u308C\u305F\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u540D\uFF08\u8907\u6570\u306E\u5834\u5408\u306F\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09
1256
+ - \`tables\`: \u9078\u629E\u3055\u308C\u305F\u30C6\u30FC\u30D6\u30EB\u540D\uFF08\u8907\u6570\u306E\u5834\u5408\u306F\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09
1257
+ - \`note\`: \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5185\u5BB9\u306E\u7C21\u5358\u306A\u8AAC\u660E
1258
+
1259
+ ### \u91CD\u8981\u306A\u5236\u7D04
1260
+ - askUserQuestion \u306E options \u306B\u306F\u6700\u4F4E2\u4EF6\u5FC5\u8981\u30021\u4EF6\u3057\u304B\u306A\u3044\u5834\u5408\u306F askUserQuestion \u3092\u547C\u3070\u305A\u6B21\u306E\u30B9\u30C6\u30C3\u30D7\u306B\u9032\u3080\u3053\u3068
1261
+ - **\u30C6\u30FC\u30D6\u30EB\u306E\u884C\u30C7\u30FC\u30BF\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3053\u3068**\u3002\u5B9F\u884C\u3057\u3066\u3088\u3044\u306E\u306F\u4E0A\u8A18\u624B\u9806\u3067\u6307\u5B9A\u3055\u308C\u305F\u30E1\u30BF\u30C7\u30FC\u30BF\u53D6\u5F97\u30AF\u30A8\u30EA\u306E\u307F\u3002\u305D\u308C\u4EE5\u5916\u306E\u30AF\u30A8\u30EA\u306F\u5B9F\u884C\u7981\u6B62
1262
+
1263
+ ### \u5B9F\u884C\u65B9\u91DD
1264
+ - \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057
1265
+ - \u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
1266
+ en: `## BigQuery Setup Instructions
1267
+
1268
+ Follow these steps to set up the BigQuery connection.
1269
+
1270
+ ### Steps
1271
+
1272
+ #### Step 0: Project Selection
1273
+ 1. Call \`listProjects\` to get the list of GCP projects accessible with the OAuth credentials
1274
+ 2. Branch based on results:
1275
+ - **2 or more projects**: Present them to the user via \`askUserQuestion\` (multiSelect: false) and let them select a project. Format option labels as \`Project Name (id: project-id)\`
1276
+ - **Exactly 1 project**: Do NOT call askUserQuestion. Auto-select it. Just write "Auto-selected project X" in one sentence
1277
+ 3. Call \`updateConnectionParameters\` to save the selected project:
1278
+ - \`parameterSlug\`: \`"project-id"\`
1279
+ - \`value\`: the project ID
1280
+ - \`displayValue\`: \`"Project Name (id: project-id)"\`
1281
+ 4. After receiving the continuation message, proceed to Step 1
1282
+
1283
+ #### Step 1: Dataset Selection
1284
+ 1. Run \`SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA\` to get the list of datasets
1285
+ 2. Branch based on results:
1286
+ - **2 or more datasets**: Present them to the user via \`askUserQuestion\` (multiSelect: true) and let them select which datasets to use
1287
+ - **Exactly 1 dataset**: Do NOT call askUserQuestion. Auto-select it. Just write "Auto-selected dataset X" in one sentence
1288
+
1289
+ #### Step 2: Table Selection
1290
+ 3. For the selected dataset(s), run \`SELECT table_name FROM \\\`{project}.{dataset}.INFORMATION_SCHEMA.TABLES\\\`\` to get the table list (use UNION ALL for multiple datasets)
1291
+ 4. Branch based on results:
1292
+ - **2 or more tables**: Present them to the user via \`askUserQuestion\` (multiSelect: true) and let them select which tables to use. Include the dataset name in the description
1293
+ - **Exactly 1 table**: Do NOT call askUserQuestion. Auto-select it
1294
+
1295
+ #### Step 3: Save
1296
+ 5. Call \`updateConnectionContext\` to save:
1297
+ - \`project\`: BigQuery project ID
1298
+ - \`dataset\`: Selected dataset name(s) (comma-separated if multiple)
1299
+ - \`tables\`: Selected table name(s) (comma-separated if multiple)
1300
+ - \`note\`: Brief description of the setup
1301
+
1302
+ ### Important Constraints
1303
+ - askUserQuestion options requires at least 2 items. If there is only 1 item, do NOT call askUserQuestion \u2014 proceed to the next step directly
1304
+ - **Do NOT read table row data**. Only the metadata queries specified in the steps above are allowed. All other queries are forbidden
1305
+
1306
+ ### Execution Policy
1307
+ - Write only 1 sentence between tool calls, then immediately call the next tool
1308
+ - Skip unnecessary explanations and proceed efficiently`
1309
+ });
1310
+
1311
+ // src/connectors/bigquery-oauth/parameters.ts
1312
+ var parameters6 = {
1313
+ projectId: new ParameterDefinition({
1314
+ slug: "project-id",
1315
+ name: "Google Cloud Project ID",
1316
+ description: "The ID of the Google Cloud project where resources will be managed.",
1317
+ envVarBaseKey: "BIGQUERY_OAUTH_PROJECT_ID",
1318
+ type: "text",
1319
+ secret: false,
1320
+ required: false
1321
+ })
1322
+ };
1323
+
1324
+ // src/connectors/bigquery-oauth/tools/execute-query.ts
1325
+ import { z as z7 } from "zod";
1326
+ var MAX_ROWS6 = 500;
1327
+ var REQUEST_TIMEOUT_MS = 6e4;
1328
+ var cachedToken = null;
1329
+ async function getProxyToken(config) {
1330
+ if (cachedToken && cachedToken.expiresAt > Date.now() + 6e4) {
1331
+ return cachedToken.token;
1332
+ }
1333
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
1334
+ const res = await fetch(url, {
1335
+ method: "POST",
1336
+ headers: {
1337
+ "Content-Type": "application/json",
1338
+ "x-api-key": config.appApiKey,
1339
+ "project-id": config.projectId
1340
+ },
1341
+ body: JSON.stringify({
1342
+ sandboxId: config.sandboxId,
1343
+ issuedBy: "coding-agent"
1344
+ })
1345
+ });
1346
+ if (!res.ok) {
1347
+ const errorText = await res.text().catch(() => res.statusText);
1348
+ throw new Error(`Failed to get proxy token: HTTP ${res.status} ${errorText}`);
1349
+ }
1350
+ const data = await res.json();
1351
+ cachedToken = {
1352
+ token: data.token,
1353
+ expiresAt: new Date(data.expiresAt).getTime()
1354
+ };
1355
+ return data.token;
1356
+ }
1357
+ var inputSchema7 = z7.object({
1358
+ toolUseIntent: z7.string().optional().describe(
1359
+ "Brief description of what you intend to accomplish with this tool call"
1360
+ ),
1361
+ connectionId: z7.string().describe("ID of the BigQuery OAuth connection to use"),
1362
+ sql: z7.string().describe(
1363
+ "BigQuery SQL (GoogleSQL) query. Use backtick-quoted fully qualified names `project.dataset.table` for table references."
1364
+ )
1365
+ });
1366
+ var outputSchema7 = z7.discriminatedUnion("success", [
1367
+ z7.object({
1368
+ success: z7.literal(true),
1369
+ rowCount: z7.number(),
1370
+ truncated: z7.boolean(),
1371
+ rows: z7.array(z7.record(z7.string(), z7.unknown()))
1372
+ }),
1373
+ z7.object({
1374
+ success: z7.literal(false),
1375
+ error: z7.string()
1376
+ })
1377
+ ]);
1378
+ function parseQueryResponse(data) {
1379
+ const schema = data.schema;
1380
+ const rawRows = data.rows;
1381
+ if (!schema?.fields || !rawRows) return [];
1382
+ const fields = schema.fields;
1383
+ return rawRows.map((row) => {
1384
+ const obj = {};
1385
+ row.f?.forEach((cell, i) => {
1386
+ obj[fields[i].name] = cell.v;
1387
+ });
1388
+ return obj;
1389
+ });
1390
+ }
1391
+ var executeQueryTool6 = new ConnectorTool({
1392
+ name: "executeQuery",
1393
+ description: `Execute SQL against BigQuery via OAuth. Returns up to ${MAX_ROWS6} rows.
1394
+ Use for: schema exploration (INFORMATION_SCHEMA), data sampling, analytical queries.
1395
+ Avoid loading large amounts of data; always include LIMIT in queries.`,
1396
+ inputSchema: inputSchema7,
1397
+ outputSchema: outputSchema7,
1398
+ async execute({ connectionId, sql }, connections, config) {
1399
+ const connection = connections.find((c) => c.id === connectionId);
1400
+ if (!connection) {
1401
+ return {
1402
+ success: false,
1403
+ error: `Connection ${connectionId} not found`
1404
+ };
1405
+ }
1406
+ const gcpProjectId = parameters6.projectId.getValue(connection);
1407
+ console.log(
1408
+ `[connector-query] bigquery-oauth/${connection.name}: ${sql}`
1409
+ );
1410
+ try {
1411
+ const token = await getProxyToken(config.oauthProxy);
1412
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
1413
+ const queryUrl = `https://bigquery.googleapis.com/bigquery/v2/projects/${gcpProjectId}/queries`;
1414
+ const controller = new AbortController();
1415
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
1416
+ try {
1417
+ const response = await fetch(proxyUrl, {
1418
+ method: "POST",
1419
+ headers: {
1420
+ "Content-Type": "application/json",
1421
+ Authorization: `Bearer ${token}`
1422
+ },
1423
+ body: JSON.stringify({
1424
+ url: queryUrl,
1425
+ method: "POST",
1426
+ body: { query: sql, useLegacySql: false, maxResults: MAX_ROWS6 }
1427
+ }),
1428
+ signal: controller.signal
1429
+ });
1430
+ const data = await response.json();
1431
+ if (!response.ok) {
1432
+ const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
1433
+ return { success: false, error: errorMessage };
1434
+ }
1435
+ const rows = parseQueryResponse(data);
1436
+ const truncated = rows.length > MAX_ROWS6;
1437
+ return {
1438
+ success: true,
1439
+ rowCount: Math.min(rows.length, MAX_ROWS6),
1440
+ truncated,
1441
+ rows: rows.slice(0, MAX_ROWS6)
1442
+ };
1443
+ } finally {
1444
+ clearTimeout(timeout);
1445
+ }
1446
+ } catch (err) {
1447
+ const msg = err instanceof Error ? err.message : String(err);
1448
+ return { success: false, error: msg };
1449
+ }
1450
+ }
1451
+ });
1452
+
1453
+ // src/connectors/bigquery-oauth/tools/list-projects.ts
1454
+ import { z as z8 } from "zod";
1455
+ var REQUEST_TIMEOUT_MS2 = 6e4;
1456
+ var cachedToken2 = null;
1457
+ async function getProxyToken2(config) {
1458
+ if (cachedToken2 && cachedToken2.expiresAt > Date.now() + 6e4) {
1459
+ return cachedToken2.token;
1460
+ }
1461
+ const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
1462
+ const res = await fetch(url, {
1463
+ method: "POST",
1464
+ headers: {
1465
+ "Content-Type": "application/json",
1466
+ "x-api-key": config.appApiKey,
1467
+ "project-id": config.projectId
1468
+ },
1469
+ body: JSON.stringify({
1470
+ sandboxId: config.sandboxId,
1471
+ issuedBy: "coding-agent"
1472
+ })
1473
+ });
1474
+ if (!res.ok) {
1475
+ const errorText = await res.text().catch(() => res.statusText);
1476
+ throw new Error(`Failed to get proxy token: HTTP ${res.status} ${errorText}`);
1477
+ }
1478
+ const data = await res.json();
1479
+ cachedToken2 = {
1480
+ token: data.token,
1481
+ expiresAt: new Date(data.expiresAt).getTime()
1482
+ };
1483
+ return data.token;
1484
+ }
1485
+ var inputSchema8 = z8.object({
1486
+ toolUseIntent: z8.string().optional().describe(
1487
+ "Brief description of what you intend to accomplish with this tool call"
1488
+ ),
1489
+ connectionId: z8.string().describe("ID of the BigQuery OAuth connection to use")
1490
+ });
1491
+ var outputSchema8 = z8.discriminatedUnion("success", [
1492
+ z8.object({
1493
+ success: z8.literal(true),
1494
+ projects: z8.array(
1495
+ z8.object({
1496
+ projectId: z8.string(),
1497
+ friendlyName: z8.string()
1498
+ })
1499
+ )
1500
+ }),
1501
+ z8.object({
1502
+ success: z8.literal(false),
1503
+ error: z8.string()
1504
+ })
1505
+ ]);
1506
+ var listProjectsTool2 = new ConnectorTool({
1507
+ name: "listProjects",
1508
+ description: `List GCP projects accessible with the current OAuth credentials. Returns project IDs and friendly names.`,
1509
+ inputSchema: inputSchema8,
1510
+ outputSchema: outputSchema8,
1511
+ async execute({ connectionId }, connections, config) {
1512
+ const connection = connections.find((c) => c.id === connectionId);
1513
+ if (!connection) {
1514
+ return {
1515
+ success: false,
1516
+ error: `Connection ${connectionId} not found`
1517
+ };
1518
+ }
1519
+ console.log(
1520
+ `[connector-query] bigquery-oauth/${connection.name}: listProjects`
1521
+ );
1522
+ try {
1523
+ const token = await getProxyToken2(config.oauthProxy);
1524
+ const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
1525
+ const controller = new AbortController();
1526
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
1527
+ try {
1528
+ const response = await fetch(proxyUrl, {
1529
+ method: "POST",
1530
+ headers: {
1531
+ "Content-Type": "application/json",
1532
+ Authorization: `Bearer ${token}`
1533
+ },
1534
+ body: JSON.stringify({
1535
+ url: "https://bigquery.googleapis.com/bigquery/v2/projects",
1536
+ method: "GET"
1537
+ }),
1538
+ signal: controller.signal
1539
+ });
1540
+ const data = await response.json();
1541
+ if (!response.ok) {
1542
+ const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
1543
+ return { success: false, error: errorMessage };
1544
+ }
1545
+ const projects = (data.projects ?? []).map((p) => ({
1546
+ projectId: p.projectReference?.projectId ?? "",
1547
+ friendlyName: p.friendlyName ?? p.projectReference?.projectId ?? ""
1548
+ })).filter((p) => p.projectId !== "");
1549
+ return { success: true, projects };
1550
+ } finally {
1551
+ clearTimeout(timeout);
1552
+ }
1553
+ } catch (err) {
1554
+ const msg = err instanceof Error ? err.message : String(err);
1555
+ return { success: false, error: msg };
1556
+ }
1557
+ }
1558
+ });
1559
+
1560
+ // src/connectors/bigquery-oauth/index.ts
1561
+ var tools6 = { executeQuery: executeQueryTool6, listProjects: listProjectsTool2 };
1562
+ function parseQueryResponse2(data) {
1563
+ const schema = data.schema;
1564
+ const rawRows = data.rows;
1565
+ if (!schema?.fields || !rawRows) return [];
1566
+ return rawRows.map((row) => {
1567
+ const obj = {};
1568
+ row.f?.forEach((cell, i) => {
1569
+ obj[schema.fields[i].name] = cell.v;
1570
+ });
1571
+ return obj;
1572
+ });
1573
+ }
1574
+ var bigqueryOauthConnector = new ConnectorPlugin({
1575
+ slug: "bigquery",
1576
+ authType: AUTH_TYPES.OAUTH,
1577
+ name: "BigQuery (OAuth)",
1578
+ description: "Connect to Google BigQuery for data warehouse and analytics using OAuth.",
1579
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6nlehQyOmdbktG5hOYkYMr/6ca559140d5ddc7dadc5eac88858a563/bigquery.svg",
1580
+ parameters: parameters6,
1581
+ releaseFlag: { dev1: true, dev2: false, prod: false },
1582
+ setup: bigquerySetup2,
1583
+ proxyPolicy: {
1584
+ allowlist: [
1585
+ { host: "bigquery.googleapis.com", methods: ["GET", "POST", "PUT", "PATCH", "DELETE"] },
1586
+ { host: "www.googleapis.com", pathPrefix: "/bigquery/v2", methods: ["GET", "POST"] }
1587
+ ]
1588
+ },
1589
+ systemPrompt: `## BigQuery SQL Notes (OAuth)
1590
+ - Use backtick-quoted fully qualified names \`project.dataset.table\` for table references
1591
+ - Use INFORMATION_SCHEMA for schema exploration
1592
+ - List datasets: \`SELECT schema_name FROM \\\`project_id\\\`.INFORMATION_SCHEMA.SCHEMATA\`
1593
+ - List tables: \`SELECT table_name FROM \\\`project_id.dataset\\\`.INFORMATION_SCHEMA.TABLES\`
1594
+ - List columns: \`SELECT column_name, data_type FROM \\\`project_id.dataset\\\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'xxx'\`
1595
+ - Always specify project_id explicitly in queries`,
1596
+ tools: tools6,
1597
+ async query(params, sql, namedParams, context) {
1598
+ const { proxyFetch } = context;
1599
+ const projectId = params[parameters6.projectId.slug];
1600
+ const resolvedSql = replaceLiteralParams(sql, namedParams);
1601
+ const url = `https://bigquery.googleapis.com/bigquery/v2/projects/${projectId}/queries`;
1602
+ const res = await proxyFetch(url, {
1603
+ method: "POST",
1604
+ headers: { "Content-Type": "application/json" },
1605
+ body: JSON.stringify({ query: resolvedSql, useLegacySql: false })
1606
+ });
1607
+ if (!res.ok) {
1608
+ const errorText = await res.text().catch(() => res.statusText);
1609
+ throw new Error(`BigQuery query failed: HTTP ${res.status} ${errorText}`);
1610
+ }
1611
+ const data = await res.json();
1612
+ return { rows: parseQueryResponse2(data) };
1613
+ }
1614
+ });
1615
+
1616
+ // src/connectors/aws-athena/parameters.ts
1617
+ var parameters7 = {
1618
+ awsAccessKeyId: new ParameterDefinition({
1619
+ slug: "aws-access-key-id",
1620
+ name: "AWS Access Key ID",
1621
+ description: "The AWS Access Key ID for authentication.",
1622
+ envVarBaseKey: "ATHENA_AWS_ACCESS_KEY_ID",
1623
+ type: "text",
1624
+ secret: true,
1625
+ required: true
1626
+ }),
1627
+ awsSecretAccessKey: new ParameterDefinition({
1628
+ slug: "aws-secret-access-key",
1629
+ name: "AWS Secret Access Key",
1630
+ description: "The AWS Secret Access Key for authentication.",
1631
+ envVarBaseKey: "ATHENA_AWS_SECRET_ACCESS_KEY",
1632
+ type: "text",
1633
+ secret: true,
1634
+ required: true
1635
+ }),
1636
+ awsRegion: new ParameterDefinition({
1637
+ slug: "aws-region",
1638
+ name: "AWS Region",
1639
+ description: "The AWS region where your Athena workgroup is located (e.g., us-east-1).",
1640
+ envVarBaseKey: "ATHENA_AWS_REGION",
1641
+ type: "text",
1642
+ secret: false,
1643
+ required: true
1644
+ }),
1645
+ workgroup: new ParameterDefinition({
1646
+ slug: "workgroup",
1647
+ name: "Athena Workgroup",
1648
+ description: "The Athena workgroup to use for queries. Either workgroup or output-location is required.",
1649
+ envVarBaseKey: "ATHENA_WORKGROUP",
1650
+ type: "text",
1651
+ secret: false,
1652
+ required: false
1653
+ }),
1654
+ outputLocation: new ParameterDefinition({
1655
+ slug: "output-location",
1656
+ name: "S3 Output Location",
1657
+ description: "The S3 location for query results (e.g., s3://bucket-name/path/). Either workgroup or output-location is required.",
1658
+ envVarBaseKey: "ATHENA_OUTPUT_LOCATION",
1659
+ type: "text",
1660
+ secret: false,
1661
+ required: false
1662
+ })
1663
+ };
1664
+
1665
+ // src/connectors/aws-athena/tools/execute-query.ts
1666
+ import { z as z9 } from "zod";
1667
+ var MAX_ROWS7 = 500;
1668
+ var POLL_INTERVAL_MS = 1e3;
1669
+ var POLL_TIMEOUT_MS = 12e4;
1670
+ var inputSchema9 = z9.object({
1671
+ toolUseIntent: z9.string().optional().describe(
1672
+ "Brief description of what you intend to accomplish with this tool call"
1673
+ ),
1674
+ connectionId: z9.string().describe("ID of the AWS Athena connection to use"),
1675
+ sql: z9.string().describe("Athena SQL query (Presto/Trino based)")
1676
+ });
1677
+ var outputSchema9 = z9.discriminatedUnion("success", [
1678
+ z9.object({
1679
+ success: z9.literal(true),
1680
+ rowCount: z9.number(),
1681
+ truncated: z9.boolean(),
1682
+ rows: z9.array(z9.record(z9.string(), z9.unknown()))
1683
+ }),
1684
+ z9.object({
1685
+ success: z9.literal(false),
1686
+ error: z9.string()
1687
+ })
1688
+ ]);
1689
+ var executeQueryTool7 = new ConnectorTool({
1690
+ name: "executeQuery",
1691
+ description: `Execute SQL against AWS Athena. Returns up to ${MAX_ROWS7} rows.
1692
+ Use for: schema exploration (SHOW DATABASES/TABLES, DESCRIBE TABLE), data sampling, analytical queries on S3 data.
1693
+ Avoid loading large amounts of data; always include LIMIT in queries.`,
1694
+ inputSchema: inputSchema9,
1695
+ outputSchema: outputSchema9,
1696
+ async execute({ connectionId, sql }, connections) {
1697
+ const connection = connections.find((c) => c.id === connectionId);
1698
+ if (!connection) {
1699
+ return {
1700
+ success: false,
1701
+ error: `Connection ${connectionId} not found`
1702
+ };
1703
+ }
1704
+ console.log(
1705
+ `[connector-query] aws-athena/${connection.name}: ${sql}`
1706
+ );
1707
+ try {
1708
+ const {
1709
+ AthenaClient,
1710
+ StartQueryExecutionCommand,
1711
+ GetQueryExecutionCommand,
1712
+ GetQueryResultsCommand
1713
+ } = await import("@aws-sdk/client-athena");
1714
+ const workgroup = parameters7.workgroup.tryGetValue(connection);
1715
+ const outputLocation = parameters7.outputLocation.tryGetValue(connection);
1716
+ if (!workgroup && !outputLocation) {
1717
+ return {
1718
+ success: false,
1719
+ error: "Either workgroup or output-location is required"
1720
+ };
1721
+ }
1722
+ const client = new AthenaClient({
1723
+ region: parameters7.awsRegion.getValue(connection),
1724
+ credentials: {
1725
+ accessKeyId: parameters7.awsAccessKeyId.getValue(connection),
1726
+ secretAccessKey: parameters7.awsSecretAccessKey.getValue(connection)
1727
+ }
1728
+ });
1729
+ const startParams = { QueryString: sql };
1730
+ if (workgroup) startParams.WorkGroup = workgroup;
1731
+ if (outputLocation) {
1732
+ startParams.ResultConfiguration = {
1733
+ OutputLocation: outputLocation
1734
+ };
1735
+ }
1736
+ const { QueryExecutionId } = await client.send(
1737
+ new StartQueryExecutionCommand(startParams)
1738
+ );
1739
+ const startTime = Date.now();
1740
+ while (true) {
1741
+ const exec = await client.send(
1742
+ new GetQueryExecutionCommand({ QueryExecutionId })
1743
+ );
1744
+ const state = exec.QueryExecution?.Status?.State;
1745
+ if (state === "SUCCEEDED") break;
1746
+ if (state === "FAILED" || state === "CANCELLED") {
1747
+ throw new Error(
1748
+ exec.QueryExecution?.Status?.StateChangeReason || `Query ${state}`
1749
+ );
1750
+ }
1751
+ if (Date.now() - startTime > POLL_TIMEOUT_MS) {
1752
+ throw new Error("Query timed out after 120 seconds");
1753
+ }
1754
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
1755
+ }
1756
+ const result = await client.send(
1757
+ new GetQueryResultsCommand({ QueryExecutionId })
1758
+ );
1759
+ const resultRows = result.ResultSet?.Rows ?? [];
1760
+ const headers = resultRows[0]?.Data?.map((d) => d.VarCharValue ?? "") ?? [];
1761
+ const dataRows = resultRows.slice(1).map((row) => {
1762
+ const obj = {};
1763
+ row.Data?.forEach((d, i) => {
1764
+ obj[headers[i]] = d.VarCharValue ?? null;
1765
+ });
1766
+ return obj;
1767
+ });
1768
+ const truncated = dataRows.length > MAX_ROWS7;
1769
+ return {
1770
+ success: true,
1771
+ rowCount: Math.min(dataRows.length, MAX_ROWS7),
1772
+ truncated,
1773
+ rows: dataRows.slice(0, MAX_ROWS7)
1774
+ };
1775
+ } catch (err) {
1776
+ const msg = err instanceof Error ? err.message : String(err);
1777
+ return { success: false, error: msg };
1778
+ }
1779
+ }
1780
+ });
1781
+
1782
+ // src/connectors/aws-athena/index.ts
1783
+ var tools7 = { executeQuery: executeQueryTool7 };
1784
+ var awsAthenaConnector = new ConnectorPlugin({
1785
+ slug: "aws-athena",
1786
+ authType: null,
1787
+ name: "AWS Athena",
1788
+ description: "Connect to AWS Athena for serverless SQL queries on S3 data.",
1789
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/5x0vIHtUHfJJMZUv4RFOYZ/5059bac389f0169542f39cdb4b387d2c/Athena.svg",
1790
+ parameters: parameters7,
1791
+ releaseFlag: { dev1: true, dev2: true, prod: true },
1792
+ systemPrompt: `## AWS Athena SQL Notes
1793
+ - Uses Presto/Trino based SQL syntax
1794
+ - Schema exploration:
1795
+ - List databases: \`SHOW DATABASES\`
1796
+ - List tables: \`SHOW TABLES\` or \`SHOW TABLES IN database_name\`
1797
+ - List columns: \`DESCRIBE table_name\`
1798
+ - Always include LIMIT in queries
1799
+ - Query execution is asynchronous and results may take time to retrieve`,
1800
+ tools: tools7,
1801
+ async query(params, sql, namedParams) {
1802
+ const {
1803
+ AthenaClient,
1804
+ StartQueryExecutionCommand,
1805
+ GetQueryExecutionCommand,
1806
+ GetQueryResultsCommand
1807
+ } = await import("@aws-sdk/client-athena");
1808
+ const resolvedSql = replaceLiteralParams(sql, namedParams);
1809
+ const workgroup = params[parameters7.workgroup.slug];
1810
+ const outputLocation = params[parameters7.outputLocation.slug];
1811
+ if (!workgroup && !outputLocation) {
1812
+ throw new Error("Either workgroup or output-location is required");
1813
+ }
1814
+ const client = new AthenaClient({
1815
+ region: params[parameters7.awsRegion.slug],
1816
+ credentials: {
1817
+ accessKeyId: params[parameters7.awsAccessKeyId.slug],
1818
+ secretAccessKey: params[parameters7.awsSecretAccessKey.slug]
1819
+ }
1820
+ });
1821
+ const startParams = { QueryString: resolvedSql };
1822
+ if (workgroup) startParams.WorkGroup = workgroup;
1823
+ if (outputLocation) {
1824
+ startParams.ResultConfiguration = { OutputLocation: outputLocation };
1825
+ }
1826
+ const { QueryExecutionId } = await client.send(
1827
+ new StartQueryExecutionCommand(startParams)
1828
+ );
1829
+ const startTime = Date.now();
1830
+ while (true) {
1831
+ const exec = await client.send(
1832
+ new GetQueryExecutionCommand({ QueryExecutionId })
1833
+ );
1834
+ const state = exec.QueryExecution?.Status?.State;
1835
+ if (state === "SUCCEEDED") break;
1836
+ if (state === "FAILED" || state === "CANCELLED") {
1837
+ throw new Error(
1838
+ exec.QueryExecution?.Status?.StateChangeReason || `Query ${state}`
1839
+ );
1840
+ }
1841
+ if (Date.now() - startTime > 12e4) {
1842
+ throw new Error("Query timed out after 120 seconds");
1843
+ }
1844
+ await new Promise((r) => setTimeout(r, 1e3));
1845
+ }
1846
+ const result = await client.send(
1847
+ new GetQueryResultsCommand({ QueryExecutionId })
1848
+ );
1849
+ const resultRows = result.ResultSet?.Rows ?? [];
1850
+ const headers = resultRows[0]?.Data?.map((d) => d.VarCharValue ?? "") ?? [];
1851
+ const rows = resultRows.slice(1).map((row) => {
1852
+ const obj = {};
1853
+ row.Data?.forEach((d, i) => {
1854
+ obj[headers[i]] = d.VarCharValue ?? null;
1855
+ });
1856
+ return obj;
1857
+ });
1858
+ return { rows };
1859
+ }
1860
+ });
1861
+
1862
+ // src/connectors/redshift/parameters.ts
1863
+ var parameters8 = {
1864
+ awsAccessKeyId: new ParameterDefinition({
1865
+ slug: "aws-access-key-id",
1866
+ name: "AWS Access Key ID",
1867
+ description: "The AWS Access Key ID for authentication.",
1868
+ envVarBaseKey: "REDSHIFT_AWS_ACCESS_KEY_ID",
1869
+ type: "text",
1870
+ secret: true,
1871
+ required: true
1872
+ }),
1873
+ awsSecretAccessKey: new ParameterDefinition({
1874
+ slug: "aws-secret-access-key",
1875
+ name: "AWS Secret Access Key",
1876
+ description: "The AWS Secret Access Key for authentication.",
1877
+ envVarBaseKey: "REDSHIFT_AWS_SECRET_ACCESS_KEY",
1878
+ type: "text",
1879
+ secret: true,
1880
+ required: true
1881
+ }),
1882
+ awsRegion: new ParameterDefinition({
1883
+ slug: "aws-region",
1884
+ name: "AWS Region",
1885
+ description: "The AWS region where your Redshift cluster is located (e.g., us-east-1).",
1886
+ envVarBaseKey: "REDSHIFT_AWS_REGION",
1887
+ type: "text",
1888
+ secret: false,
1889
+ required: true
1890
+ }),
1891
+ database: new ParameterDefinition({
1892
+ slug: "database",
1893
+ name: "Database Name",
1894
+ description: "The name of the database to connect to.",
1895
+ envVarBaseKey: "REDSHIFT_DATABASE",
1896
+ type: "text",
1897
+ secret: false,
1898
+ required: true
1899
+ }),
1900
+ clusterIdentifier: new ParameterDefinition({
1901
+ slug: "cluster-identifier",
1902
+ name: "Cluster Identifier",
1903
+ description: "The Redshift cluster identifier. Required for Provisioned Cluster (use either cluster-identifier or workgroup-name).",
1904
+ envVarBaseKey: "REDSHIFT_CLUSTER_IDENTIFIER",
1905
+ type: "text",
1906
+ secret: false,
1907
+ required: false
1908
+ }),
1909
+ workgroupName: new ParameterDefinition({
1910
+ slug: "workgroup-name",
1911
+ name: "Workgroup Name",
1912
+ description: "The Redshift Serverless workgroup name. Required for Serverless (use either cluster-identifier or workgroup-name).",
1913
+ envVarBaseKey: "REDSHIFT_WORKGROUP_NAME",
1914
+ type: "text",
1915
+ secret: false,
1916
+ required: false
1917
+ }),
1918
+ secretArn: new ParameterDefinition({
1919
+ slug: "secret-arn",
1920
+ name: "Secrets Manager ARN",
1921
+ description: "The ARN of the secret in AWS Secrets Manager for database credentials. Optional for both Provisioned Cluster and Serverless.",
1922
+ envVarBaseKey: "REDSHIFT_SECRET_ARN",
1923
+ type: "text",
1924
+ secret: true,
1925
+ required: false
1926
+ }),
1927
+ dbUser: new ParameterDefinition({
1928
+ slug: "db-user",
1929
+ name: "Database User",
1930
+ description: "The database user for IAM authentication. Required for Provisioned Cluster if secret-arn is not set.",
1931
+ envVarBaseKey: "REDSHIFT_DB_USER",
1932
+ type: "text",
1933
+ secret: false,
1934
+ required: false
1935
+ })
1936
+ };
1937
+
1938
+ // src/connectors/redshift/tools/execute-query.ts
1939
+ import { z as z10 } from "zod";
1940
+ var MAX_ROWS8 = 500;
1941
+ var POLL_INTERVAL_MS2 = 1e3;
1942
+ var POLL_TIMEOUT_MS2 = 12e4;
1943
+ var inputSchema10 = z10.object({
1944
+ toolUseIntent: z10.string().optional().describe(
1945
+ "Brief description of what you intend to accomplish with this tool call"
1946
+ ),
1947
+ connectionId: z10.string().describe("ID of the Redshift connection to use"),
1948
+ sql: z10.string().describe(
1949
+ "SQL query to execute against Amazon Redshift."
1950
+ )
1951
+ });
1952
+ var outputSchema10 = z10.discriminatedUnion("success", [
1953
+ z10.object({
1954
+ success: z10.literal(true),
1955
+ rowCount: z10.number(),
1956
+ truncated: z10.boolean(),
1957
+ rows: z10.array(z10.record(z10.string(), z10.unknown()))
1958
+ }),
1959
+ z10.object({
1960
+ success: z10.literal(false),
1961
+ error: z10.string()
1962
+ })
1963
+ ]);
1964
+ var executeQueryTool8 = new ConnectorTool({
1965
+ name: "executeQuery",
1966
+ description: `Execute SQL against Amazon Redshift. Returns up to ${MAX_ROWS8} rows.
1967
+ Use for: schema exploration, data sampling, analytical queries.
1968
+ Avoid loading large amounts of data; always include LIMIT in queries.`,
1969
+ inputSchema: inputSchema10,
1970
+ outputSchema: outputSchema10,
1971
+ async execute({ connectionId, sql }, connections) {
1972
+ const connection = connections.find((c) => c.id === connectionId);
1973
+ if (!connection) {
1974
+ return {
1975
+ success: false,
1976
+ error: `Connection ${connectionId} not found`
1977
+ };
1978
+ }
1979
+ console.log(
1980
+ `[connector-query] redshift/${connection.name}: ${sql}`
1981
+ );
1982
+ try {
1983
+ const {
1984
+ RedshiftDataClient,
1985
+ ExecuteStatementCommand,
1986
+ DescribeStatementCommand,
1987
+ GetStatementResultCommand
1988
+ } = await import("@aws-sdk/client-redshift-data");
1989
+ const awsAccessKeyId = parameters8.awsAccessKeyId.getValue(connection);
1990
+ const awsSecretAccessKey = parameters8.awsSecretAccessKey.getValue(connection);
1991
+ const awsRegion = parameters8.awsRegion.getValue(connection);
1992
+ const database = parameters8.database.getValue(connection);
1993
+ const clusterIdentifier = parameters8.clusterIdentifier.tryGetValue(connection);
1994
+ const workgroupName = parameters8.workgroupName.tryGetValue(connection);
1995
+ const secretArn = parameters8.secretArn.tryGetValue(connection);
1996
+ const dbUser = parameters8.dbUser.tryGetValue(connection);
1997
+ if (!clusterIdentifier && !workgroupName) {
1998
+ return {
1999
+ success: false,
2000
+ error: "Either cluster-identifier or workgroup-name is required"
2001
+ };
2002
+ }
2003
+ const client = new RedshiftDataClient({
2004
+ region: awsRegion,
2005
+ credentials: {
2006
+ accessKeyId: awsAccessKeyId,
2007
+ secretAccessKey: awsSecretAccessKey
2008
+ }
2009
+ });
2010
+ const { Id: statementId } = await client.send(
2011
+ new ExecuteStatementCommand({
2012
+ Database: database,
2013
+ Sql: sql,
2014
+ ...clusterIdentifier && { ClusterIdentifier: clusterIdentifier },
2015
+ ...workgroupName && { WorkgroupName: workgroupName },
2016
+ ...secretArn && { SecretArn: secretArn },
2017
+ ...dbUser && { DbUser: dbUser }
2018
+ })
2019
+ );
2020
+ const startTime = Date.now();
2021
+ while (true) {
2022
+ const desc = await client.send(
2023
+ new DescribeStatementCommand({ Id: statementId })
2024
+ );
2025
+ if (desc.Status === "FINISHED") break;
2026
+ if (desc.Status === "FAILED" || desc.Status === "ABORTED") {
2027
+ throw new Error(desc.Error || `Statement ${desc.Status}`);
2028
+ }
2029
+ if (Date.now() - startTime > POLL_TIMEOUT_MS2) {
2030
+ throw new Error(`Query timed out after ${POLL_TIMEOUT_MS2 / 1e3} seconds`);
2031
+ }
2032
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS2));
2033
+ }
2034
+ const result = await client.send(
2035
+ new GetStatementResultCommand({ Id: statementId })
2036
+ );
2037
+ const columnNames = (result.ColumnMetadata ?? []).map((c) => c.name ?? "");
2038
+ const allRows = (result.Records ?? []).map((record) => {
2039
+ const row = {};
2040
+ record.forEach((field, i) => {
2041
+ row[columnNames[i]] = field.stringValue ?? field.longValue ?? field.doubleValue ?? field.booleanValue ?? (field.isNull ? null : void 0);
2042
+ });
2043
+ return row;
2044
+ });
2045
+ const truncated = allRows.length > MAX_ROWS8;
2046
+ return {
2047
+ success: true,
2048
+ rowCount: Math.min(allRows.length, MAX_ROWS8),
2049
+ truncated,
2050
+ rows: allRows.slice(0, MAX_ROWS8)
2051
+ };
2052
+ } catch (err) {
2053
+ const msg = err instanceof Error ? err.message : String(err);
2054
+ return { success: false, error: msg };
2055
+ }
2056
+ }
2057
+ });
2058
+
2059
+ // src/connectors/redshift/index.ts
2060
+ var tools8 = { executeQuery: executeQueryTool8 };
2061
+ var redshiftConnector = new ConnectorPlugin({
2062
+ slug: "redshift",
2063
+ authType: null,
2064
+ name: "Redshift",
2065
+ description: "Connect to Amazon Redshift for data warehouse analytics.",
2066
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/AEwW2psmrnZ7htTVsgA9t/a637e31707c5d760be73ce1d8ec75580/aws-redshift-logo.svg",
2067
+ parameters: parameters8,
2068
+ releaseFlag: { dev1: true, dev2: true, prod: true },
2069
+ systemPrompt: `## Redshift SQL Notes
2070
+ - Uses PostgreSQL based SQL syntax
2071
+ - Schema exploration:
2072
+ - List schemas: \`SELECT DISTINCT schemaname FROM pg_tables\`
2073
+ - List tables: \`SELECT tablename FROM pg_tables WHERE schemaname = 'public'\`
2074
+ - List columns: \`SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'xxx'\`
2075
+ - Always include LIMIT in queries
2076
+ - Query execution is asynchronous and results may take time to retrieve`,
2077
+ tools: tools8,
2078
+ async query(params, sql, namedParams) {
2079
+ const {
2080
+ RedshiftDataClient,
2081
+ ExecuteStatementCommand,
2082
+ DescribeStatementCommand,
2083
+ GetStatementResultCommand
2084
+ } = await import("@aws-sdk/client-redshift-data");
2085
+ const resolvedSql = replaceLiteralParams(sql, namedParams);
2086
+ const clusterIdentifier = params[parameters8.clusterIdentifier.slug];
2087
+ const workgroupName = params[parameters8.workgroupName.slug];
2088
+ const secretArn = params[parameters8.secretArn.slug];
2089
+ const dbUser = params[parameters8.dbUser.slug];
2090
+ if (!clusterIdentifier && !workgroupName) {
2091
+ throw new Error("Either cluster-identifier or workgroup-name is required");
2092
+ }
2093
+ const client = new RedshiftDataClient({
2094
+ region: params[parameters8.awsRegion.slug],
2095
+ credentials: {
2096
+ accessKeyId: params[parameters8.awsAccessKeyId.slug],
2097
+ secretAccessKey: params[parameters8.awsSecretAccessKey.slug]
2098
+ }
2099
+ });
2100
+ const { Id: statementId } = await client.send(
2101
+ new ExecuteStatementCommand({
2102
+ Database: params[parameters8.database.slug],
2103
+ Sql: resolvedSql,
2104
+ ...clusterIdentifier && { ClusterIdentifier: clusterIdentifier },
2105
+ ...workgroupName && { WorkgroupName: workgroupName },
2106
+ ...secretArn && { SecretArn: secretArn },
2107
+ ...dbUser && { DbUser: dbUser }
2108
+ })
2109
+ );
2110
+ const startTime = Date.now();
2111
+ while (true) {
2112
+ const desc = await client.send(
2113
+ new DescribeStatementCommand({ Id: statementId })
2114
+ );
2115
+ if (desc.Status === "FINISHED") break;
2116
+ if (desc.Status === "FAILED" || desc.Status === "ABORTED") {
2117
+ throw new Error(desc.Error || `Statement ${desc.Status}`);
2118
+ }
2119
+ if (Date.now() - startTime > 12e4) {
2120
+ throw new Error("Query timed out after 120 seconds");
2121
+ }
2122
+ await new Promise((r) => setTimeout(r, 1e3));
2123
+ }
2124
+ const result = await client.send(
2125
+ new GetStatementResultCommand({ Id: statementId })
2126
+ );
2127
+ const columnNames = (result.ColumnMetadata ?? []).map((c) => c.name ?? "");
2128
+ const rows = (result.Records ?? []).map((record) => {
2129
+ const row = {};
2130
+ record.forEach((field, i) => {
2131
+ row[columnNames[i]] = field.stringValue ?? field.longValue ?? field.doubleValue ?? field.booleanValue ?? (field.isNull ? null : void 0);
2132
+ });
2133
+ return row;
2134
+ });
2135
+ return { rows };
2136
+ }
2137
+ });
2138
+
2139
+ // src/connectors/databricks/parameters.ts
2140
+ var parameters9 = {
2141
+ host: new ParameterDefinition({
2142
+ slug: "host",
2143
+ name: "Databricks Workspace Host",
2144
+ description: "The Databricks workspace host (e.g., your-workspace.cloud.databricks.com).",
2145
+ envVarBaseKey: "DATABRICKS_HOST",
2146
+ type: "text",
2147
+ secret: false,
2148
+ required: true
2149
+ }),
2150
+ token: new ParameterDefinition({
2151
+ slug: "token",
2152
+ name: "Databricks Access Token",
2153
+ description: "The personal access token for Databricks authentication.",
2154
+ envVarBaseKey: "DATABRICKS_TOKEN",
2155
+ type: "text",
2156
+ secret: true,
2157
+ required: true
2158
+ }),
2159
+ httpPath: new ParameterDefinition({
2160
+ slug: "http-path",
2161
+ name: "SQL Warehouse HTTP Path",
2162
+ description: "The HTTP path for the SQL warehouse (e.g., /sql/1.0/warehouses/abc123).",
2163
+ envVarBaseKey: "DATABRICKS_HTTP_PATH",
2164
+ type: "text",
2165
+ secret: false,
2166
+ required: true
2167
+ })
2168
+ };
2169
+
2170
+ // src/connectors/databricks/tools/execute-query.ts
2171
+ import { z as z11 } from "zod";
2172
+ var MAX_ROWS9 = 500;
2173
+ var inputSchema11 = z11.object({
2174
+ toolUseIntent: z11.string().optional().describe(
2175
+ "Brief description of what you intend to accomplish with this tool call"
2176
+ ),
2177
+ connectionId: z11.string().describe("ID of the Databricks connection to use"),
2178
+ sql: z11.string().describe("Databricks SQL query (Spark SQL based)")
2179
+ });
2180
+ var outputSchema11 = z11.discriminatedUnion("success", [
2181
+ z11.object({
2182
+ success: z11.literal(true),
2183
+ rowCount: z11.number(),
2184
+ truncated: z11.boolean(),
2185
+ rows: z11.array(z11.record(z11.string(), z11.unknown()))
2186
+ }),
2187
+ z11.object({
2188
+ success: z11.literal(false),
2189
+ error: z11.string()
2190
+ })
2191
+ ]);
2192
+ var executeQueryTool9 = new ConnectorTool({
2193
+ name: "executeQuery",
2194
+ description: `Execute SQL against Databricks. Returns up to ${MAX_ROWS9} rows.
2195
+ Use for: schema exploration (SHOW CATALOGS/DATABASES/TABLES, DESCRIBE TABLE), data sampling, analytical queries.
2196
+ Avoid loading large amounts of data; always include LIMIT in queries.`,
2197
+ inputSchema: inputSchema11,
2198
+ outputSchema: outputSchema11,
2199
+ async execute({ connectionId, sql }, connections) {
2200
+ const connection = connections.find((c) => c.id === connectionId);
2201
+ if (!connection) {
2202
+ return {
2203
+ success: false,
2204
+ error: `Connection ${connectionId} not found`
2205
+ };
2206
+ }
2207
+ console.log(
2208
+ `[connector-query] databricks/${connection.name}: ${sql}`
2209
+ );
2210
+ try {
2211
+ const { DBSQLClient } = await import("@databricks/sql");
2212
+ const host = parameters9.host.getValue(connection);
2213
+ const token = parameters9.token.getValue(connection);
2214
+ const httpPath = parameters9.httpPath.getValue(connection);
2215
+ const client = new DBSQLClient();
2216
+ await client.connect({ host, path: httpPath, token });
2217
+ let session;
2218
+ let operation;
2219
+ try {
2220
+ session = await client.openSession();
2221
+ operation = await session.executeStatement(sql, {
2222
+ runAsync: true
2223
+ });
2224
+ const allRows = await operation.fetchAll();
2225
+ const truncated = allRows.length > MAX_ROWS9;
2226
+ return {
2227
+ success: true,
2228
+ rowCount: Math.min(allRows.length, MAX_ROWS9),
2229
+ truncated,
2230
+ rows: allRows.slice(0, MAX_ROWS9)
2231
+ };
2232
+ } finally {
2233
+ if (operation) await operation.close().catch(() => {
2234
+ });
2235
+ if (session) await session.close().catch(() => {
2236
+ });
2237
+ await client.close().catch(() => {
2238
+ });
2239
+ }
2240
+ } catch (err) {
2241
+ const msg = err instanceof Error ? err.message : String(err);
2242
+ return { success: false, error: msg };
2243
+ }
2244
+ }
2245
+ });
2246
+
2247
+ // src/connectors/databricks/index.ts
2248
+ var tools9 = { executeQuery: executeQueryTool9 };
2249
+ var databricksConnector = new ConnectorPlugin({
2250
+ slug: "databricks",
2251
+ authType: null,
2252
+ name: "Databricks",
2253
+ description: "Connect to Databricks for data lakehouse and SQL analytics.",
2254
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6QgcrfpQOKg18P7DdgKerd/af55bf0d871339049824dd167b97a29f/databricks-icon.svg",
2255
+ parameters: parameters9,
2256
+ releaseFlag: { dev1: true, dev2: true, prod: true },
2257
+ systemPrompt: `## Databricks SQL Notes
2258
+ - Uses Spark SQL / Databricks SQL syntax
2259
+ - Schema exploration:
2260
+ - List catalogs: \`SHOW CATALOGS\`
2261
+ - List databases: \`SHOW DATABASES\` or \`SHOW SCHEMAS\`
2262
+ - List tables: \`SHOW TABLES\` or \`SHOW TABLES IN database_name\`
2263
+ - List columns: \`DESCRIBE TABLE table_name\`
2264
+ - Always include LIMIT in queries`,
2265
+ tools: tools9,
2266
+ async query(params, sql, namedParams) {
2267
+ const { DBSQLClient } = await import("@databricks/sql");
2268
+ const resolvedSql = replaceLiteralParams(sql, namedParams);
2269
+ const client = new DBSQLClient();
2270
+ await client.connect({
2271
+ host: params[parameters9.host.slug],
2272
+ path: params[parameters9.httpPath.slug],
2273
+ token: params[parameters9.token.slug]
2274
+ });
2275
+ let session;
2276
+ let operation;
2277
+ try {
2278
+ session = await client.openSession();
2279
+ operation = await session.executeStatement(resolvedSql, {
2280
+ runAsync: true
2281
+ });
2282
+ const rows = await operation.fetchAll();
2283
+ return { rows };
2284
+ } finally {
2285
+ if (operation) await operation.close().catch(() => {
2286
+ });
2287
+ if (session) await session.close().catch(() => {
2288
+ });
2289
+ await client.close().catch(() => {
2290
+ });
2291
+ }
2292
+ }
2293
+ });
2294
+
2295
+ // src/connectors/airtable/parameters.ts
2296
+ var parameters10 = {
2297
+ baseId: new ParameterDefinition({
2298
+ slug: "base-id",
2299
+ name: "Airtable Base ID",
2300
+ description: "The Airtable Base ID (e.g., appXXXXXXXXXXXXXX).",
2301
+ envVarBaseKey: "AIRTABLE_BASE_ID",
2302
+ type: "text",
2303
+ secret: false,
2304
+ required: true
2305
+ }),
2306
+ apiKey: new ParameterDefinition({
2307
+ slug: "api-key",
2308
+ name: "Airtable API Key",
2309
+ description: "The Airtable API key or Personal Access Token for authentication. Required scopes: schema.bases:read, data.records:read.",
2310
+ envVarBaseKey: "AIRTABLE_API_KEY",
2311
+ type: "text",
2312
+ secret: true,
2313
+ required: true
2314
+ })
2315
+ };
2316
+
2317
+ // src/connectors/airtable/tools/request.ts
2318
+ import { z as z12 } from "zod";
2319
+ var BASE_URL = "https://api.airtable.com/v0/";
2320
+ var REQUEST_TIMEOUT_MS3 = 6e4;
2321
+ var inputSchema12 = z12.object({
2322
+ toolUseIntent: z12.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
2323
+ connectionId: z12.string().describe("ID of the Airtable connection to use"),
2324
+ method: z12.enum(["GET", "POST", "PATCH", "DELETE"]).describe("HTTP method"),
2325
+ path: z12.string().describe("API path (e.g., '{baseId}/{tableIdOrName}', 'meta/bases/{baseId}/tables'). {baseId} is automatically replaced."),
2326
+ body: z12.record(z12.string(), z12.unknown()).optional().describe("Request body (JSON)")
2327
+ });
2328
+ var outputSchema12 = z12.discriminatedUnion("success", [
2329
+ z12.object({
2330
+ success: z12.literal(true),
2331
+ status: z12.number(),
2332
+ data: z12.record(z12.string(), z12.unknown())
2333
+ }),
2334
+ z12.object({
2335
+ success: z12.literal(false),
2336
+ error: z12.string()
2337
+ })
2338
+ ]);
2339
+ var requestTool = new ConnectorTool({
2340
+ name: "request",
2341
+ description: `Send authenticated requests to the Airtable API.
2342
+ Authentication is handled automatically using the API Key.
2343
+ {baseId} in the path is automatically replaced with the connection's base-id.`,
2344
+ inputSchema: inputSchema12,
2345
+ outputSchema: outputSchema12,
2346
+ async execute({ connectionId, method, path, body }, connections) {
2347
+ const connection = connections.find((c) => c.id === connectionId);
2348
+ if (!connection) {
2349
+ return { success: false, error: `Connection ${connectionId} not found` };
2350
+ }
2351
+ console.log(`[connector-request] airtable/${connection.name}: ${method} ${path}`);
2352
+ try {
2353
+ const apiKey = parameters10.apiKey.getValue(connection);
2354
+ const baseId = parameters10.baseId.getValue(connection);
2355
+ const resolvedPath = path.replace(/\{baseId\}/g, baseId);
2356
+ const url = `${BASE_URL}${resolvedPath}`;
2357
+ const controller = new AbortController();
2358
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS3);
2359
+ try {
2360
+ const response = await fetch(url, {
2361
+ method,
2362
+ headers: {
2363
+ Authorization: `Bearer ${apiKey}`,
2364
+ "Content-Type": "application/json"
2365
+ },
2366
+ body: body ? JSON.stringify(body) : void 0,
2367
+ signal: controller.signal
2368
+ });
2369
+ const data = await response.json();
2370
+ if (!response.ok) {
2371
+ const errorObj = data?.error;
2372
+ return {
2373
+ success: false,
2374
+ error: errorObj?.message ?? `HTTP ${response.status} ${response.statusText}`
2375
+ };
2376
+ }
2377
+ return { success: true, status: response.status, data };
2378
+ } finally {
2379
+ clearTimeout(timeout);
2380
+ }
2381
+ } catch (err) {
2382
+ const msg = err instanceof Error ? err.message : String(err);
2383
+ return { success: false, error: msg };
2384
+ }
2385
+ }
2386
+ });
2387
+
2388
+ // src/connectors/airtable/index.ts
2389
+ var tools10 = { request: requestTool };
2390
+ var airtableConnector = new ConnectorPlugin({
2391
+ slug: "airtable",
2392
+ authType: null,
2393
+ name: "Airtable",
2394
+ description: "Connect to Airtable for spreadsheet-database hybrid data management.",
2395
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/19JUphfOZjyjTK6Zg4NGCf/8c56227b088cada52d3a2d9385a3be97/airtable.svg",
2396
+ parameters: parameters10,
2397
+ releaseFlag: { dev1: true, dev2: true, prod: true },
2398
+ systemPrompt: `## Airtable API
2399
+ - Call the Airtable REST API using the authenticated request tool
2400
+ - {baseId} in the path is automatically replaced
2401
+
2402
+ ### List Tables (Schema Exploration)
2403
+ - GET meta/bases/{baseId}/tables
2404
+
2405
+ ### Get Records
2406
+ - GET {baseId}/{tableIdOrName}
2407
+ - Query parameter examples: ?maxRecords=100&filterByFormula={formula}&sort[0][field]=Name&sort[0][direction]=asc
2408
+ - Filter columns with fields[]: ?fields[]=Name&fields[]=Email
2409
+
2410
+ ### Create Record
2411
+ - POST {baseId}/{tableIdOrName}
2412
+ - Body: { "records": [{ "fields": { "Name": "value", ... } }] }
2413
+
2414
+ ### Pagination
2415
+ - If the response contains an offset, fetch the next page by appending ?offset={offset} to the next request`,
2416
+ tools: tools10
2417
+ });
2418
+
2419
+ // src/connectors/google-analytics/parameters.ts
2420
+ var parameters11 = {
2421
+ serviceAccountKeyJsonBase64: new ParameterDefinition({
2422
+ slug: "service-account-key-json-base64",
2423
+ name: "Google Cloud Service Account JSON",
2424
+ description: "The service account JSON key used to authenticate with Google Cloud Platform. Ensure that the service account has the necessary permissions to access Google Analytics.",
2425
+ envVarBaseKey: "GA_SERVICE_ACCOUNT_JSON_BASE64",
2426
+ type: "base64EncodedJson",
2427
+ secret: true,
2428
+ required: true
2429
+ }),
2430
+ propertyId: new ParameterDefinition({
2431
+ slug: "property-id",
2432
+ name: "Google Analytics Property ID",
2433
+ description: "The Google Analytics 4 property ID (e.g., 123456789).",
2434
+ envVarBaseKey: "GA_PROPERTY_ID",
2435
+ type: "text",
2436
+ secret: false,
2437
+ required: true
2438
+ })
2439
+ };
2440
+
2441
+ // src/connectors/google-analytics/tools/request.ts
2442
+ import { z as z13 } from "zod";
2443
+ var BASE_URL2 = "https://analyticsdata.googleapis.com/v1beta/";
2444
+ var REQUEST_TIMEOUT_MS4 = 6e4;
2445
+ var inputSchema13 = z13.object({
2446
+ toolUseIntent: z13.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
2447
+ connectionId: z13.string().describe("ID of the Google Analytics connection to use"),
2448
+ method: z13.enum(["GET", "POST"]).describe("HTTP method"),
2449
+ path: z13.string().describe("API path (e.g., 'properties/{propertyId}:runReport'). {propertyId} is automatically replaced."),
2450
+ body: z13.record(z13.string(), z13.unknown()).optional().describe("POST request body (JSON)")
2451
+ });
2452
+ var outputSchema13 = z13.discriminatedUnion("success", [
2453
+ z13.object({
2454
+ success: z13.literal(true),
2455
+ status: z13.number(),
2456
+ data: z13.record(z13.string(), z13.unknown())
2457
+ }),
2458
+ z13.object({
2459
+ success: z13.literal(false),
2460
+ error: z13.string()
2461
+ })
2462
+ ]);
2463
+ var requestTool2 = new ConnectorTool({
2464
+ name: "request",
2465
+ description: `Send authenticated requests to the Google Analytics Data API.
2466
+ Authentication is handled automatically using a service account.
2467
+ {propertyId} in the path is automatically replaced with the connection's property-id.`,
2468
+ inputSchema: inputSchema13,
2469
+ outputSchema: outputSchema13,
2470
+ async execute({ connectionId, method, path, body }, connections) {
2471
+ const connection = connections.find((c) => c.id === connectionId);
2472
+ if (!connection) {
2473
+ return { success: false, error: `Connection ${connectionId} not found` };
2474
+ }
2475
+ console.log(`[connector-request] google-analytics/${connection.name}: ${method} ${path}`);
2476
+ try {
2477
+ const { GoogleAuth } = await import("google-auth-library");
2478
+ const keyJsonBase64 = parameters11.serviceAccountKeyJsonBase64.getValue(connection);
2479
+ const propertyId = parameters11.propertyId.getValue(connection);
2480
+ const credentials = JSON.parse(
2481
+ Buffer.from(keyJsonBase64, "base64").toString("utf-8")
2482
+ );
2483
+ const auth = new GoogleAuth({
2484
+ credentials,
2485
+ scopes: ["https://www.googleapis.com/auth/analytics.readonly"]
2486
+ });
2487
+ const token = await auth.getAccessToken();
2488
+ if (!token) {
2489
+ return { success: false, error: "Failed to obtain access token" };
2490
+ }
2491
+ const resolvedPath = path.replace(/\{propertyId\}/g, propertyId);
2492
+ const url = `${BASE_URL2}${resolvedPath}`;
2493
+ const controller = new AbortController();
2494
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS4);
2495
+ try {
2496
+ const response = await fetch(url, {
2497
+ method,
2498
+ headers: {
2499
+ Authorization: `Bearer ${token}`,
2500
+ "Content-Type": "application/json"
2501
+ },
2502
+ body: method === "POST" && body ? JSON.stringify(body) : void 0,
2503
+ signal: controller.signal
2504
+ });
2505
+ const data = await response.json();
2506
+ if (!response.ok) {
2507
+ const errorObj = data?.error;
2508
+ return {
2509
+ success: false,
2510
+ error: errorObj?.message ?? `HTTP ${response.status} ${response.statusText}`
2511
+ };
2512
+ }
2513
+ return { success: true, status: response.status, data };
2514
+ } finally {
2515
+ clearTimeout(timeout);
2516
+ }
2517
+ } catch (err) {
2518
+ const msg = err instanceof Error ? err.message : String(err);
2519
+ return { success: false, error: msg };
2520
+ }
2521
+ }
2522
+ });
2523
+
2524
+ // src/connectors/google-analytics/index.ts
2525
+ var tools11 = { request: requestTool2 };
2526
+ var googleAnalyticsConnector = new ConnectorPlugin({
2527
+ slug: "google-analytics",
2528
+ authType: null,
2529
+ name: "Google Analytics",
2530
+ description: "Connect to Google Analytics for web analytics and reporting.",
2531
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/7fs0ipzxuD9mACDzBATtxX/3c53ed90d15c96483e4f78cb29dab5e9/google-analytics.svg",
2532
+ parameters: parameters11,
2533
+ releaseFlag: { dev1: true, dev2: true, prod: true },
2534
+ systemPrompt: `## Google Analytics Data API
2535
+ - Call the GA4 Data API using the authenticated request tool
2536
+ - {propertyId} in the path is automatically replaced
2537
+
2538
+ ### Get Metadata (Check available dimensions and metrics)
2539
+ - GET properties/{propertyId}/metadata
2540
+
2541
+ ### Get Report
2542
+ - POST properties/{propertyId}:runReport
2543
+ - Body example:
2544
+ {
2545
+ "dateRanges": [{"startDate": "7daysAgo", "endDate": "today"}],
2546
+ "dimensions": [{"name": "date"}],
2547
+ "metrics": [{"name": "activeUsers"}],
2548
+ "limit": 100
2549
+ }
2550
+
2551
+ ### Common Dimensions
2552
+ date, country, city, deviceCategory, browser, pagePath, pageTitle,
2553
+ sessionSource, sessionMedium, eventName
2554
+
2555
+ ### Common Metrics
2556
+ activeUsers, sessions, screenPageViews, bounceRate,
2557
+ averageSessionDuration, conversions, totalRevenue
2558
+
2559
+ ### Date Specification
2560
+ - Absolute: "2024-01-01"
2561
+ - Relative: "today", "yesterday", "7daysAgo", "30daysAgo"`,
2562
+ tools: tools11
2563
+ });
2564
+
2565
+ // src/connectors/kintone/parameters.ts
2566
+ var parameters12 = {
2567
+ baseUrl: new ParameterDefinition({
2568
+ slug: "base-url",
2569
+ name: "kintone Base URL",
2570
+ description: "The base URL of your kintone environment (e.g., https://example.cybozu.com).",
2571
+ envVarBaseKey: "KINTONE_BASE_URL",
2572
+ type: "text",
2573
+ secret: false,
2574
+ required: true
2575
+ }),
2576
+ username: new ParameterDefinition({
2577
+ slug: "username",
2578
+ name: "kintone Username",
2579
+ description: "The username (login name) for kintone authentication.",
2580
+ envVarBaseKey: "KINTONE_USERNAME",
2581
+ type: "text",
2582
+ secret: false,
2583
+ required: true
2584
+ }),
2585
+ password: new ParameterDefinition({
2586
+ slug: "password",
2587
+ name: "kintone Password",
2588
+ description: "The password for kintone authentication.",
2589
+ envVarBaseKey: "KINTONE_PASSWORD",
2590
+ type: "text",
2591
+ secret: true,
2592
+ required: true
2593
+ })
2594
+ };
2595
+
2596
+ // src/connectors/kintone/tools/request.ts
2597
+ import { z as z14 } from "zod";
2598
+ var REQUEST_TIMEOUT_MS5 = 6e4;
2599
+ var inputSchema14 = z14.object({
2600
+ toolUseIntent: z14.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
2601
+ connectionId: z14.string().describe("ID of the kintone connection to use"),
2602
+ method: z14.enum(["GET", "POST", "PUT", "DELETE"]).describe("HTTP method"),
2603
+ path: z14.string().describe("API path (e.g., 'apps.json', 'records.json?app=1&query=...')"),
2604
+ body: z14.record(z14.string(), z14.unknown()).optional().describe("Request body (JSON)")
2605
+ });
2606
+ var outputSchema14 = z14.discriminatedUnion("success", [
2607
+ z14.object({
2608
+ success: z14.literal(true),
2609
+ status: z14.number(),
2610
+ data: z14.record(z14.string(), z14.unknown())
2611
+ }),
2612
+ z14.object({
2613
+ success: z14.literal(false),
2614
+ error: z14.string()
2615
+ })
2616
+ ]);
2617
+ var requestTool3 = new ConnectorTool({
2618
+ name: "request",
2619
+ description: `Send authenticated requests to the kintone REST API.
2620
+ Authentication is handled automatically using username and password.`,
2621
+ inputSchema: inputSchema14,
2622
+ outputSchema: outputSchema14,
2623
+ async execute({ connectionId, method, path, body }, connections) {
2624
+ const connection = connections.find((c) => c.id === connectionId);
2625
+ if (!connection) {
2626
+ return { success: false, error: `Connection ${connectionId} not found` };
2627
+ }
2628
+ console.log(`[connector-request] kintone/${connection.name}: ${method} ${path}`);
2629
+ try {
2630
+ const baseUrl = parameters12.baseUrl.getValue(connection);
2631
+ const username = parameters12.username.getValue(connection);
2632
+ const password = parameters12.password.getValue(connection);
2633
+ const authToken = Buffer.from(`${username}:${password}`).toString("base64");
2634
+ const url = `${baseUrl.replace(/\/+$/, "")}/k/v1/${path}`;
2635
+ const controller = new AbortController();
2636
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS5);
2637
+ try {
2638
+ const response = await fetch(url, {
2639
+ method,
2640
+ headers: {
2641
+ "X-Cybozu-Authorization": authToken,
2642
+ "Content-Type": "application/json"
2643
+ },
2644
+ body: body ? JSON.stringify(body) : void 0,
2645
+ signal: controller.signal
2646
+ });
2647
+ const data = await response.json();
2648
+ if (!response.ok) {
2649
+ return {
2650
+ success: false,
2651
+ error: data?.message ?? `HTTP ${response.status} ${response.statusText}`
2652
+ };
2653
+ }
2654
+ return { success: true, status: response.status, data };
2655
+ } finally {
2656
+ clearTimeout(timeout);
2657
+ }
2658
+ } catch (err) {
2659
+ const msg = err instanceof Error ? err.message : String(err);
2660
+ return { success: false, error: msg };
2661
+ }
2662
+ }
2663
+ });
2664
+
2665
+ // src/connectors/kintone/index.ts
2666
+ var tools12 = { request: requestTool3 };
2667
+ var kintoneConnector = new ConnectorPlugin({
2668
+ slug: "kintone",
2669
+ authType: null,
2670
+ name: "kintone",
2671
+ description: "Connect to kintone for business application data retrieval and analytics.",
2672
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/76nPGMJFZkMFE3UQNo2JFy/e71dc5f5d5cec1306ce0e17aafbfd9f0/kintone.png",
2673
+ parameters: parameters12,
2674
+ releaseFlag: { dev1: true, dev2: true, prod: true },
2675
+ systemPrompt: `## kintone REST API
2676
+ - Call the kintone REST API using the authenticated request tool
2677
+ - The base URL (e.g., https://example.cybozu.com) is automatically resolved
2678
+
2679
+ ### List Apps
2680
+ - GET apps.json
2681
+
2682
+ ### Get Field Definitions
2683
+ - GET app/form/fields.json?app={appId}
2684
+
2685
+ ### Get Records
2686
+ - GET records.json?app={appId}&query={query}
2687
+ - Query example: records.json?app=1&query=updatedTime > "2024-01-01" order by recordNumber asc limit 100
2688
+
2689
+ ### Add Record
2690
+ - POST record.json
2691
+ - Body: { "app": 1, "record": { "fieldName": { "value": "value" } } }
2692
+
2693
+ ### kintone Query Syntax
2694
+ - Comparison: fieldName = "value", fieldName > 100
2695
+ - Operators: and, or, not
2696
+ - Sort: order by fieldName asc/desc
2697
+ - Limit: limit 100 offset 0
2698
+ - String: like "partial match"`,
2699
+ tools: tools12
2700
+ });
2701
+
2702
+ // src/connectors/wix-store/parameters.ts
2703
+ var parameters13 = {
2704
+ accountId: new ParameterDefinition({
2705
+ slug: "account-id",
2706
+ name: "Account ID",
2707
+ description: "Account ID",
2708
+ envVarBaseKey: "WIX_ACCOUNT_ID",
2709
+ type: "text",
2710
+ secret: false,
2711
+ required: true
2712
+ }),
2713
+ siteId: new ParameterDefinition({
2714
+ slug: "site-id",
2715
+ name: "Site ID",
2716
+ description: "Site ID for Wix Store Project",
2717
+ envVarBaseKey: "WIX_SITE_ID",
2718
+ type: "text",
2719
+ secret: false,
2720
+ required: true
2721
+ }),
2722
+ apiKey: new ParameterDefinition({
2723
+ slug: "api-key",
2724
+ name: "API Key",
2725
+ description: "API Key to access the Wix store project",
2726
+ envVarBaseKey: "WIX_API_KEY",
2727
+ type: "text",
2728
+ secret: true,
2729
+ required: true
2730
+ })
2731
+ };
2732
+
2733
+ // src/connectors/wix-store/tools/request.ts
2734
+ import { z as z15 } from "zod";
2735
+ var BASE_URL3 = "https://www.wixapis.com/";
2736
+ var REQUEST_TIMEOUT_MS6 = 6e4;
2737
+ var inputSchema15 = z15.object({
2738
+ toolUseIntent: z15.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
2739
+ connectionId: z15.string().describe("ID of the Wix Store connection to use"),
2740
+ method: z15.enum(["GET", "POST"]).describe("HTTP method"),
2741
+ path: z15.string().describe("API path (e.g., 'stores/v1/products/query', 'stores/v2/orders/query')"),
2742
+ body: z15.record(z15.string(), z15.unknown()).optional().describe("Request body (JSON)")
2743
+ });
2744
+ var outputSchema15 = z15.discriminatedUnion("success", [
2745
+ z15.object({
2746
+ success: z15.literal(true),
2747
+ status: z15.number(),
2748
+ data: z15.record(z15.string(), z15.unknown())
2749
+ }),
2750
+ z15.object({
2751
+ success: z15.literal(false),
2752
+ error: z15.string()
2753
+ })
2754
+ ]);
2755
+ var requestTool4 = new ConnectorTool({
2756
+ name: "request",
2757
+ description: `Send authenticated requests to the Wix Store API.
2758
+ Authentication is handled automatically using the API Key and Site ID.`,
2759
+ inputSchema: inputSchema15,
2760
+ outputSchema: outputSchema15,
2761
+ async execute({ connectionId, method, path, body }, connections) {
2762
+ const connection = connections.find((c) => c.id === connectionId);
2763
+ if (!connection) {
2764
+ return { success: false, error: `Connection ${connectionId} not found` };
2765
+ }
2766
+ console.log(`[connector-request] wix-store/${connection.name}: ${method} ${path}`);
2767
+ try {
2768
+ const apiKey = parameters13.apiKey.getValue(connection);
2769
+ const siteId = parameters13.siteId.getValue(connection);
2770
+ const url = `${BASE_URL3}${path}`;
2771
+ const controller = new AbortController();
2772
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS6);
2773
+ try {
2774
+ const response = await fetch(url, {
2775
+ method,
2776
+ headers: {
2777
+ Authorization: apiKey,
2778
+ "wix-site-id": siteId,
2779
+ "Content-Type": "application/json"
2780
+ },
2781
+ body: body ? JSON.stringify(body) : void 0,
2782
+ signal: controller.signal
2783
+ });
2784
+ const data = await response.json();
2785
+ if (!response.ok) {
2786
+ const errorObj = data?.message;
2787
+ return {
2788
+ success: false,
2789
+ error: errorObj ?? `HTTP ${response.status} ${response.statusText}`
2790
+ };
2791
+ }
2792
+ return { success: true, status: response.status, data };
2793
+ } finally {
2794
+ clearTimeout(timeout);
2795
+ }
2796
+ } catch (err) {
2797
+ const msg = err instanceof Error ? err.message : String(err);
2798
+ return { success: false, error: msg };
2799
+ }
2800
+ }
2801
+ });
2802
+
2803
+ // src/connectors/wix-store/index.ts
2804
+ var tools13 = { request: requestTool4 };
2805
+ var wixStoreConnector = new ConnectorPlugin({
2806
+ slug: "wix-store",
2807
+ authType: null,
2808
+ name: "Wix Store",
2809
+ description: "Connect to Wix Store.",
2810
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/YyFxclQFzROIYpFam6vRK/e7e75d3feac49a1cc5e433c147216d23/Wix_logo_black.svg",
2811
+ parameters: parameters13,
2812
+ releaseFlag: { dev1: true, dev2: true, prod: true },
2813
+ systemPrompt: `## Wix Store API
2814
+ - Call the Wix Store REST API using the authenticated request tool
2815
+ - Authentication (API Key, Site ID) is automatically configured
2816
+ - Wix API uses POST for query endpoints as well
2817
+
2818
+ ### List Products
2819
+ - POST stores/v1/products/query
2820
+ - Body: { "query": { "paging": { "limit": 50, "offset": 0 } } }
2821
+
2822
+ ### Search Products (with filter)
2823
+ - POST stores/v1/products/query
2824
+ - Body: { "query": { "filter": { "name": { "$contains": "keyword" } }, "paging": { "limit": 50 } } }
2825
+
2826
+ ### List Orders
2827
+ - POST stores/v2/orders/query
2828
+ - Body: { "query": { "paging": { "limit": 50 } } }
2829
+
2830
+ ### List Collections (Categories)
2831
+ - POST stores/v1/collections/query
2832
+ - Body: { "query": { "paging": { "limit": 50 } } }`,
2833
+ tools: tools13
2834
+ });
2835
+
2836
+ // src/connectors/dbt/parameters.ts
2837
+ var parameters14 = {
2838
+ host: new ParameterDefinition({
2839
+ slug: "host",
2840
+ name: "dbt Cloud Host",
2841
+ description: "The dbt Cloud host URL (e.g., cloud.getdbt.com).",
2842
+ envVarBaseKey: "DBT_HOST",
2843
+ type: "text",
2844
+ secret: false,
2845
+ required: true
2846
+ }),
2847
+ accountId: new ParameterDefinition({
2848
+ slug: "account-id",
2849
+ name: "dbt Account ID",
2850
+ description: "The dbt Cloud account ID.",
2851
+ envVarBaseKey: "DBT_ACCOUNT_ID",
2852
+ type: "text",
2853
+ secret: false,
2854
+ required: true
2855
+ }),
2856
+ prodEnvId: new ParameterDefinition({
2857
+ slug: "prod-env-id",
2858
+ name: "dbt Production Environment ID",
2859
+ description: "The dbt Cloud production environment ID.",
2860
+ envVarBaseKey: "DBT_PROD_ENV_ID",
2861
+ type: "text",
2862
+ secret: false,
2863
+ required: true
2864
+ }),
2865
+ token: new ParameterDefinition({
2866
+ slug: "token",
2867
+ name: "dbt API Token",
2868
+ description: "The API token for authenticating with dbt Cloud.",
2869
+ envVarBaseKey: "DBT_TOKEN",
2870
+ type: "text",
2871
+ secret: true,
2872
+ required: true
2873
+ })
2874
+ };
2875
+
2876
+ // src/connectors/dbt/tools/request.ts
2877
+ import { z as z16 } from "zod";
2878
+ var REQUEST_TIMEOUT_MS7 = 6e4;
2879
+ function resolveGraphqlEndpoint(host) {
2880
+ if (host.includes("emea")) return "https://metadata.emea.dbt.com/graphql";
2881
+ if (host.includes(".au.")) return "https://metadata.au.dbt.com/graphql";
2882
+ return "https://metadata.cloud.getdbt.com/graphql";
2883
+ }
2884
+ var inputSchema16 = z16.object({
2885
+ toolUseIntent: z16.string().optional().describe("Brief description of what you intend to accomplish with this tool call"),
2886
+ connectionId: z16.string().describe("ID of the dbt Cloud connection to use"),
2887
+ query: z16.string().describe("GraphQL query"),
2888
+ variables: z16.record(z16.string(), z16.unknown()).optional().describe("GraphQL variables (JSON)")
2889
+ });
2890
+ var outputSchema16 = z16.discriminatedUnion("success", [
2891
+ z16.object({
2892
+ success: z16.literal(true),
2893
+ data: z16.record(z16.string(), z16.unknown())
2894
+ }),
2895
+ z16.object({
2896
+ success: z16.literal(false),
2897
+ error: z16.string()
2898
+ })
2899
+ ]);
2900
+ var requestTool5 = new ConnectorTool({
2901
+ name: "request",
2902
+ description: `Send authenticated requests to the dbt Cloud Discovery API (GraphQL).
2903
+ Authentication is handled automatically using the API token.
2904
+ {environmentId} in GraphQL variables is automatically replaced with the prod-env-id.`,
2905
+ inputSchema: inputSchema16,
2906
+ outputSchema: outputSchema16,
2907
+ async execute({ connectionId, query, variables }, connections) {
2908
+ const connection = connections.find((c) => c.id === connectionId);
2909
+ if (!connection) {
2910
+ return { success: false, error: `Connection ${connectionId} not found` };
2911
+ }
2912
+ console.log(`[connector-request] dbt/${connection.name}: GraphQL query`);
2913
+ try {
2914
+ const host = parameters14.host.getValue(connection);
2915
+ const token = parameters14.token.getValue(connection);
2916
+ const environmentId = parameters14.prodEnvId.getValue(connection);
2917
+ const resolvedVariables = variables ? JSON.parse(
2918
+ JSON.stringify(variables).replace(/\{environmentId\}/g, environmentId)
2919
+ ) : void 0;
2920
+ const endpoint = resolveGraphqlEndpoint(host);
2921
+ const controller = new AbortController();
2922
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS7);
2923
+ try {
2924
+ const response = await fetch(endpoint, {
2925
+ method: "POST",
2926
+ headers: {
2927
+ Authorization: `Bearer ${token}`,
2928
+ "Content-Type": "application/json"
2929
+ },
2930
+ body: JSON.stringify({ query, variables: resolvedVariables }),
2931
+ signal: controller.signal
2932
+ });
2933
+ const data = await response.json();
2934
+ if (!response.ok) {
2935
+ return {
2936
+ success: false,
2937
+ error: data?.message ?? `HTTP ${response.status} ${response.statusText}`
2938
+ };
2939
+ }
2940
+ if (Array.isArray(data?.errors) && data.errors.length > 0) {
2941
+ const errors = data.errors;
2942
+ return {
2943
+ success: false,
2944
+ error: errors.map((e) => e.message).join("; ")
2945
+ };
2946
+ }
2947
+ return { success: true, data };
2948
+ } finally {
2949
+ clearTimeout(timeout);
2950
+ }
2951
+ } catch (err) {
2952
+ const msg = err instanceof Error ? err.message : String(err);
2953
+ return { success: false, error: msg };
2954
+ }
2955
+ }
2956
+ });
2957
+
2958
+ // src/connectors/dbt/index.ts
2959
+ var tools14 = { request: requestTool5 };
2960
+ var dbtConnector = new ConnectorPlugin({
2961
+ slug: "dbt",
2962
+ authType: null,
2963
+ name: "dbt",
2964
+ description: "Connect to dbt Cloud for data transformation and analytics engineering.",
2965
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4iT6ncXtdtHdkXexU0WgfZ/0367a38d245f2568eab5eb511f9ee692/dbt.png",
2966
+ parameters: parameters14,
2967
+ releaseFlag: { dev1: true, dev2: true, prod: true },
2968
+ systemPrompt: `## dbt Cloud Discovery API (GraphQL)
2969
+ - Call the dbt Cloud Discovery API using the authenticated request tool
2970
+ - {environmentId} in GraphQL variables is automatically replaced with the prod-env-id
2971
+
2972
+ ### List Models
2973
+ query:
2974
+ query($environmentId: BigInt!) {
2975
+ environment(id: $environmentId) {
2976
+ applied {
2977
+ models(first: 100) {
2978
+ edges {
2979
+ node { uniqueId name description database schema alias materializedType }
2980
+ }
2981
+ }
2982
+ }
2983
+ }
2984
+ }
2985
+ variables: { "environmentId": "{environmentId}" }
2986
+
2987
+ ### List Sources
2988
+ query:
2989
+ query($environmentId: BigInt!) {
2990
+ environment(id: $environmentId) {
2991
+ applied {
2992
+ sources(first: 100) {
2993
+ edges {
2994
+ node { uniqueId name description database schema identifier }
2995
+ }
2996
+ }
2997
+ }
2998
+ }
2999
+ }
3000
+ variables: { "environmentId": "{environmentId}" }
3001
+
3002
+ ### Model Column Information
3003
+ query:
3004
+ query($environmentId: BigInt!, $uniqueId: String!) {
3005
+ environment(id: $environmentId) {
3006
+ applied {
3007
+ models(filter: { uniqueId: { eq: $uniqueId } }) {
3008
+ edges {
3009
+ node { uniqueId name columns { name description type } }
3010
+ }
3011
+ }
3012
+ }
3013
+ }
3014
+ }
3015
+
3016
+ ### Lineage (Dependencies)
3017
+ - Traverse relationships using ancestors / children fields
3018
+ - Get ancestors { uniqueId name } or children { uniqueId name } within node`,
3019
+ tools: tools14
3020
+ });
3021
+
3022
+ // src/connectors/squadbase-db/parameters.ts
3023
+ var parameters15 = {
3024
+ connectionUrl: new ParameterDefinition({
3025
+ slug: "connection-url",
3026
+ name: "Connection URL",
3027
+ description: "PostgreSQL connection URL for Squadbase DB.",
3028
+ envVarBaseKey: "SQUADBASE_DB_CONNECTION_URL",
3029
+ type: "text",
3030
+ secret: true,
3031
+ required: true
3032
+ })
3033
+ };
3034
+
3035
+ // src/connectors/squadbase-db/tools/execute-query.ts
3036
+ import { z as z17 } from "zod";
3037
+ var MAX_ROWS10 = 500;
3038
+ var CONNECT_TIMEOUT_MS3 = 1e4;
3039
+ var STATEMENT_TIMEOUT_MS2 = 6e4;
3040
+ var inputSchema17 = z17.object({
3041
+ toolUseIntent: z17.string().optional().describe(
3042
+ "Brief description of what you intend to accomplish with this tool call"
3043
+ ),
3044
+ connectionId: z17.string().describe("ID of the Squadbase DB connection to use"),
3045
+ sql: z17.string().describe("PostgreSQL SQL query. Always include LIMIT in queries.")
3046
+ });
3047
+ var outputSchema17 = z17.discriminatedUnion("success", [
3048
+ z17.object({
3049
+ success: z17.literal(true),
3050
+ rowCount: z17.number(),
3051
+ truncated: z17.boolean(),
3052
+ rows: z17.array(z17.record(z17.string(), z17.unknown()))
3053
+ }),
3054
+ z17.object({
3055
+ success: z17.literal(false),
3056
+ error: z17.string()
3057
+ })
3058
+ ]);
3059
+ var executeQueryTool10 = new ConnectorTool({
3060
+ name: "executeQuery",
3061
+ description: `Execute SQL against Squadbase DB (PostgreSQL). Returns up to ${MAX_ROWS10} rows.
3062
+ Use for: schema exploration (information_schema), data sampling, analytical queries.
3063
+ Avoid loading large amounts of data; always include LIMIT in queries.`,
3064
+ inputSchema: inputSchema17,
3065
+ outputSchema: outputSchema17,
3066
+ async execute({ connectionId, sql }, connections) {
3067
+ const connection = connections.find((c) => c.id === connectionId);
3068
+ if (!connection) {
3069
+ return {
3070
+ success: false,
3071
+ error: `Connection ${connectionId} not found`
3072
+ };
3073
+ }
3074
+ console.log(
3075
+ `[connector-query] squadbase-db/${connection.name}: ${sql}`
3076
+ );
3077
+ let connectionUrl;
3078
+ try {
3079
+ const { Pool } = await import("pg");
3080
+ connectionUrl = parameters15.connectionUrl.getValue(connection);
3081
+ const pool = new Pool({
3082
+ connectionString: connectionUrl,
3083
+ ssl: { rejectUnauthorized: false },
3084
+ connectionTimeoutMillis: CONNECT_TIMEOUT_MS3,
3085
+ statement_timeout: STATEMENT_TIMEOUT_MS2
3086
+ });
3087
+ try {
3088
+ const result = await pool.query(sql);
3089
+ const rows = result.rows;
3090
+ const truncated = rows.length > MAX_ROWS10;
3091
+ return {
3092
+ success: true,
3093
+ rowCount: Math.min(rows.length, MAX_ROWS10),
3094
+ truncated,
3095
+ rows: rows.slice(0, MAX_ROWS10)
3096
+ };
3097
+ } finally {
3098
+ await pool.end();
3099
+ }
3100
+ } catch (err) {
3101
+ let msg = err instanceof Error ? err.message : String(err);
3102
+ if (connectionUrl) {
3103
+ msg = msg.replaceAll(connectionUrl, "***");
3104
+ }
3105
+ return { success: false, error: msg };
3106
+ }
3107
+ }
3108
+ });
3109
+
3110
+ // src/connectors/squadbase-db/index.ts
3111
+ var tools15 = { executeQuery: executeQueryTool10 };
3112
+ var squadbaseDbConnector = new ConnectorPlugin({
3113
+ slug: "squadbase-db",
3114
+ authType: null,
3115
+ name: "Squadbase DB",
3116
+ description: "Connect to Squadbase DB (PostgreSQL).",
3117
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/25y0XqMxIufeD3egWH3bEl/659b4ade405890654cfaf91c03a4b458/icon.svg",
3118
+ parameters: parameters15,
3119
+ releaseFlag: { dev1: true, dev2: true, prod: true },
3120
+ systemPrompt: `## Squadbase DB SQL Notes
3121
+ - Uses PostgreSQL based SQL syntax
3122
+ - Schema exploration:
3123
+ - List tables: \`SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'\`
3124
+ - List columns: \`SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'xxx'\`
3125
+ - Always include LIMIT in queries`,
3126
+ tools: tools15,
3127
+ async query(params, sql, namedParams) {
3128
+ const { Pool } = await import("pg");
3129
+ const { text, values } = buildPositionalParams(sql, namedParams);
3130
+ const pool = new Pool({
3131
+ connectionString: params[parameters15.connectionUrl.slug],
3132
+ ssl: { rejectUnauthorized: false },
3133
+ connectionTimeoutMillis: 1e4,
3134
+ statement_timeout: 6e4
3135
+ });
3136
+ try {
3137
+ const result = await pool.query(text, values);
3138
+ return { rows: result.rows };
3139
+ } finally {
3140
+ await pool.end();
3141
+ }
3142
+ }
3143
+ });
3144
+
3145
+ // src/connectors/registry.ts
3146
+ var plugins = {
3147
+ snowflake: snowflakeConnector,
3148
+ snowflakePat: snowflakePatConnector,
3149
+ bigquery: bigqueryConnector,
3150
+ bigqueryOauth: bigqueryOauthConnector,
3151
+ databricks: databricksConnector,
3152
+ redshift: redshiftConnector,
3153
+ dbt: dbtConnector,
3154
+ awsAthena: awsAthenaConnector,
3155
+ postgresql: postgresqlConnector,
3156
+ mysql: mysqlConnector,
3157
+ googleAnalytics: googleAnalyticsConnector,
3158
+ airtable: airtableConnector,
3159
+ squadbaseDb: squadbaseDbConnector,
3160
+ kintone: kintoneConnector,
3161
+ wixStore: wixStoreConnector
3162
+ };
3163
+ var connectors = {
3164
+ ...plugins,
3165
+ /**
3166
+ * Return plugins that have at least one matching connection.
3167
+ */
3168
+ pluginsFor(connections) {
3169
+ const keys = new Set(
3170
+ connections.map(
3171
+ (c) => ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType)
3172
+ )
3173
+ );
3174
+ return Object.values(plugins).filter((p) => keys.has(p.connectorKey));
3175
+ },
3176
+ /**
3177
+ * Find a plugin by slug and authType.
3178
+ */
3179
+ findByKey(slug, authType) {
3180
+ const key = ConnectorPlugin.deriveKey(slug, authType);
3181
+ return Object.values(plugins).find((p) => p.connectorKey === key);
3182
+ }
3183
+ };
345
3184
  export {
346
3185
  AUTH_TYPES,
347
3186
  ConnectorPlugin,
3187
+ ConnectorSetup,
348
3188
  ConnectorTool,
349
3189
  ParameterDefinition,
3190
+ airtableConnector,
3191
+ awsAthenaConnector,
3192
+ bigqueryConnector,
3193
+ bigqueryOauthConnector,
350
3194
  connectors,
351
- snowflakePatConnector
3195
+ databricksConnector,
3196
+ dbtConnector,
3197
+ googleAnalyticsConnector,
3198
+ kintoneConnector,
3199
+ mysqlConnector,
3200
+ postgresqlConnector,
3201
+ redshiftConnector,
3202
+ snowflakeConnector,
3203
+ snowflakePatConnector,
3204
+ squadbaseDbConnector,
3205
+ wixStoreConnector
352
3206
  };