@mindstudio-ai/agent 0.1.33 → 0.1.35

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
@@ -37,13 +37,23 @@ async function requestWithRetry(config, method, url, body, attempt) {
37
37
  return requestWithRetry(config, method, url, body, attempt + 1);
38
38
  }
39
39
  if (!res.ok) {
40
- const errorBody = await res.json().catch(() => ({}));
41
- throw new MindStudioError(
42
- errorBody.message || `${res.status} ${res.statusText}`,
43
- errorBody.code || "api_error",
44
- res.status,
45
- errorBody
46
- );
40
+ let message = `${res.status} ${res.statusText}`;
41
+ let code = "api_error";
42
+ let details;
43
+ try {
44
+ const text = await res.text();
45
+ try {
46
+ const body2 = JSON.parse(text);
47
+ details = body2;
48
+ const errMsg = body2.error ?? body2.message ?? body2.details;
49
+ if (errMsg) message = errMsg;
50
+ if (body2.code) code = body2.code;
51
+ } catch {
52
+ if (text && text.length < 500) message = text;
53
+ }
54
+ } catch {
55
+ }
56
+ throw new MindStudioError(message, code, res.status, details);
47
57
  }
48
58
  const data = await res.json();
49
59
  return { data, headers: res.headers };
@@ -1248,6 +1258,9 @@ var Table = class {
1248
1258
  const items = (isArray ? data : [data]).map(
1249
1259
  (item) => this._config.defaults ? { ...this._config.defaults, ...item } : item
1250
1260
  );
1261
+ for (const item of items) {
1262
+ this._checkManagedColumns(item);
1263
+ }
1251
1264
  const queries = items.map(
1252
1265
  (item) => buildInsert(
1253
1266
  this._config.tableName,
@@ -1265,7 +1278,13 @@ var Table = class {
1265
1278
  }
1266
1279
  return void 0;
1267
1280
  });
1268
- return isArray ? rows : rows[0];
1281
+ const result = isArray ? rows : rows[0];
1282
+ this._syncRolesIfNeeded(
1283
+ items,
1284
+ result,
1285
+ isArray
1286
+ );
1287
+ return result;
1269
1288
  });
1270
1289
  }
1271
1290
  /**
@@ -1273,20 +1292,25 @@ var Table = class {
1273
1292
  * Returns the updated row via `UPDATE ... RETURNING *`.
1274
1293
  */
1275
1294
  update(id, data) {
1295
+ this._checkManagedColumns(data);
1276
1296
  const query = buildUpdate(
1277
1297
  this._config.tableName,
1278
1298
  id,
1279
1299
  data,
1280
1300
  this._config.columns
1281
1301
  );
1282
- return new Mutation(
1283
- this._config,
1284
- [query],
1285
- (results) => deserializeRow(
1302
+ return new Mutation(this._config, [query], (results) => {
1303
+ const result = deserializeRow(
1286
1304
  results[0].rows[0],
1287
1305
  this._config.columns
1288
- )
1289
- );
1306
+ );
1307
+ this._syncRolesIfNeeded(
1308
+ [data],
1309
+ result,
1310
+ false
1311
+ );
1312
+ return result;
1313
+ });
1290
1314
  }
1291
1315
  remove(id) {
1292
1316
  const query = buildDelete(this._config.tableName, `id = ?`, [id]);
@@ -1341,24 +1365,65 @@ var Table = class {
1341
1365
  const conflictColumns = Array.isArray(conflictKey) ? conflictKey : [conflictKey];
1342
1366
  this._validateUniqueConstraint(conflictColumns);
1343
1367
  const withDefaults = this._config.defaults ? { ...this._config.defaults, ...data } : data;
1368
+ this._checkManagedColumns(withDefaults);
1344
1369
  const query = buildUpsert(
1345
1370
  this._config.tableName,
1346
1371
  withDefaults,
1347
1372
  conflictColumns,
1348
1373
  this._config.columns
1349
1374
  );
1350
- return new Mutation(
1351
- this._config,
1352
- [query],
1353
- (results) => deserializeRow(
1375
+ return new Mutation(this._config, [query], (results) => {
1376
+ const result = deserializeRow(
1354
1377
  results[0].rows[0],
1355
1378
  this._config.columns
1356
- )
1357
- );
1379
+ );
1380
+ this._syncRolesIfNeeded([withDefaults], result, false);
1381
+ return result;
1382
+ });
1358
1383
  }
1359
1384
  // -------------------------------------------------------------------------
1360
1385
  // Internal helpers
1361
1386
  // -------------------------------------------------------------------------
1387
+ /** @internal Throw if data includes a platform-managed email/phone column. */
1388
+ _checkManagedColumns(data) {
1389
+ const mc = this._config.managedColumns;
1390
+ if (!mc) return;
1391
+ const keys = Object.keys(data);
1392
+ for (const key of keys) {
1393
+ if (mc.email && key === mc.email || mc.phone && key === mc.phone) {
1394
+ throw new MindStudioError(
1395
+ `Cannot write to "${key}" \u2014 this column is managed by auth. Use the auth API to change a user's ${key === mc.email ? "email" : "phone"}.`,
1396
+ "managed_column_write",
1397
+ 400
1398
+ );
1399
+ }
1400
+ }
1401
+ }
1402
+ /**
1403
+ * @internal Fire role sync for rows that wrote to the roles column.
1404
+ * Called inside processResult (runs after SQL execution in both
1405
+ * standalone and batch paths). Fire-and-forget.
1406
+ */
1407
+ _syncRolesIfNeeded(inputItems, result, isArray) {
1408
+ const rolesCol = this._config.managedColumns?.roles;
1409
+ const syncRoles = this._config.syncRoles;
1410
+ if (!rolesCol || !syncRoles) return;
1411
+ if (!inputItems.some((item) => rolesCol in item)) return;
1412
+ if (isArray) {
1413
+ for (const row of result) {
1414
+ if (row?.id) {
1415
+ syncRoles(row.id, row[rolesCol]).catch(() => {
1416
+ });
1417
+ }
1418
+ }
1419
+ } else {
1420
+ const row = result;
1421
+ if (row?.id) {
1422
+ syncRoles(row.id, row[rolesCol]).catch(() => {
1423
+ });
1424
+ }
1425
+ }
1426
+ }
1362
1427
  /** @internal Validate that the given columns match a declared unique constraint. */
1363
1428
  _validateUniqueConstraint(columns) {
1364
1429
  if (!this._config.unique?.length) {
@@ -1383,7 +1448,7 @@ var Table = class {
1383
1448
  };
1384
1449
 
1385
1450
  // src/db/index.ts
1386
- function createDb(databases, executeBatch) {
1451
+ function createDb(databases, executeBatch, authConfig, syncRoles) {
1387
1452
  return {
1388
1453
  defineTable(name, options) {
1389
1454
  const resolved = resolveTable(databases, name, options?.database);
@@ -1393,6 +1458,8 @@ function createDb(databases, executeBatch) {
1393
1458
  columns: resolved.columns,
1394
1459
  unique: options?.unique,
1395
1460
  defaults: options?.defaults,
1461
+ managedColumns: authConfig?.table === name ? authConfig.columns : void 0,
1462
+ syncRoles: authConfig?.table === name && authConfig.columns.roles ? syncRoles : void 0,
1396
1463
  executeBatch: (queries) => executeBatch(resolved.databaseId, queries)
1397
1464
  };
1398
1465
  return new Table(config);
@@ -1999,1135 +2066,6 @@ function applyStepMethods(AgentClass) {
1999
2066
  };
2000
2067
  }
2001
2068
 
2002
- // src/client.ts
2003
- var DEFAULT_BASE_URL = "https://v1.mindstudio-api.com";
2004
- var DEFAULT_MAX_RETRIES = 3;
2005
- var MindStudioAgent = class {
2006
- /** @internal */
2007
- _httpConfig;
2008
- /** @internal */
2009
- _reuseThreadId;
2010
- /** @internal */
2011
- _threadId;
2012
- /** @internal Stream ID for SSE token streaming. Set by sandbox via STREAM_ID env var. */
2013
- _streamId;
2014
- // ---- App context (db + auth) ----
2015
- /**
2016
- * @internal App ID for context resolution. Resolved from:
2017
- * constructor appId → MINDSTUDIO_APP_ID env → sandbox globals →
2018
- * auto-detected from first executeStep response header.
2019
- */
2020
- _appId;
2021
- /**
2022
- * @internal Cached app context (auth + databases). Populated by
2023
- * ensureContext() and cached for the lifetime of the instance.
2024
- */
2025
- _context;
2026
- /**
2027
- * @internal Deduplication promise for ensureContext(). Ensures only one
2028
- * context fetch is in-flight at a time, even if multiple db/auth
2029
- * operations trigger it concurrently.
2030
- */
2031
- _contextPromise;
2032
- /** @internal Cached AuthContext instance, created during context hydration. */
2033
- _auth;
2034
- /** @internal Cached Db namespace instance, created during context hydration. */
2035
- _db;
2036
- /** @internal Auth type — 'internal' for CALLBACK_TOKEN (managed mode), 'apiKey' otherwise. */
2037
- _authType;
2038
- /**
2039
- * @internal Resolve the current auth token. For internal (CALLBACK_TOKEN)
2040
- * auth, re-reads the env var each time so that long-lived singleton
2041
- * instances pick up token rotations from the host process.
2042
- */
2043
- get _token() {
2044
- if (this._authType === "internal" && process.env.CALLBACK_TOKEN) {
2045
- return process.env.CALLBACK_TOKEN;
2046
- }
2047
- return this._httpConfig.token;
2048
- }
2049
- constructor(options = {}) {
2050
- const config = loadConfig();
2051
- const { token, authType } = resolveToken(options.apiKey, config);
2052
- const baseUrl = options.baseUrl ?? process.env.MINDSTUDIO_BASE_URL ?? process.env.REMOTE_HOSTNAME ?? config.baseUrl ?? DEFAULT_BASE_URL;
2053
- this._reuseThreadId = options.reuseThreadId ?? /^(true|1)$/i.test(process.env.MINDSTUDIO_REUSE_THREAD_ID ?? "");
2054
- this._appId = options.appId ?? process.env.MINDSTUDIO_APP_ID ?? void 0;
2055
- this._authType = authType;
2056
- this._httpConfig = {
2057
- baseUrl,
2058
- token,
2059
- rateLimiter: new RateLimiter(authType),
2060
- maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES
2061
- };
2062
- if (authType === "internal") {
2063
- this._trySandboxHydration();
2064
- }
2065
- this._streamId = process.env.STREAM_ID ?? void 0;
2066
- }
2067
- /**
2068
- * Execute any step by its type name. This is the low-level method that all
2069
- * typed step methods delegate to. Use it as an escape hatch for step types
2070
- * not yet covered by the generated methods.
2071
- *
2072
- * ```ts
2073
- * const result = await agent.executeStep("generateImage", { prompt: "hello", mode: "background" });
2074
- * ```
2075
- */
2076
- async executeStep(stepType, step, options) {
2077
- if (options?.onLog) {
2078
- return this._executeStepStreaming(
2079
- stepType,
2080
- step,
2081
- options
2082
- );
2083
- }
2084
- const threadId = options?.threadId ?? (this._reuseThreadId ? this._threadId : void 0);
2085
- const { data, headers } = await request(this._httpConfig, "POST", `/steps/${stepType}/execute`, {
2086
- step,
2087
- ...options?.appId != null && { appId: options.appId },
2088
- ...threadId != null && { threadId },
2089
- ...this._streamId != null && { streamId: this._streamId }
2090
- });
2091
- let output;
2092
- if (data.output != null) {
2093
- output = data.output;
2094
- } else if (data.outputUrl) {
2095
- const res = await fetch(data.outputUrl);
2096
- if (!res.ok) {
2097
- throw new MindStudioError(
2098
- `Failed to fetch output from S3: ${res.status} ${res.statusText}`,
2099
- "output_fetch_error",
2100
- res.status
2101
- );
2102
- }
2103
- const envelope = await res.json();
2104
- output = envelope.value;
2105
- } else {
2106
- output = void 0;
2107
- }
2108
- const returnedThreadId = headers.get("x-mindstudio-thread-id") ?? "";
2109
- if (this._reuseThreadId && returnedThreadId) {
2110
- this._threadId = returnedThreadId;
2111
- }
2112
- const returnedAppId = headers.get("x-mindstudio-app-id");
2113
- if (!this._appId && returnedAppId) {
2114
- this._appId = returnedAppId;
2115
- }
2116
- const remaining = headers.get("x-ratelimit-remaining");
2117
- const billingCost = headers.get("x-mindstudio-billing-cost");
2118
- const billingEvents = headers.get("x-mindstudio-billing-events");
2119
- return {
2120
- ...output,
2121
- $appId: headers.get("x-mindstudio-app-id") ?? "",
2122
- $threadId: returnedThreadId,
2123
- $rateLimitRemaining: remaining != null ? parseInt(remaining, 10) : void 0,
2124
- $billingCost: billingCost != null ? parseFloat(billingCost) : void 0,
2125
- $billingEvents: billingEvents != null ? JSON.parse(billingEvents) : void 0
2126
- };
2127
- }
2128
- /**
2129
- * @internal Streaming step execution — sends `Accept: text/event-stream`
2130
- * and parses SSE events for real-time debug logs.
2131
- */
2132
- async _executeStepStreaming(stepType, step, options) {
2133
- const threadId = options.threadId ?? (this._reuseThreadId ? this._threadId : void 0);
2134
- const url = `${this._httpConfig.baseUrl}/developer/v2/steps/${stepType}/execute`;
2135
- const body = {
2136
- step,
2137
- ...options.appId != null && { appId: options.appId },
2138
- ...threadId != null && { threadId },
2139
- ...this._streamId != null && { streamId: this._streamId }
2140
- };
2141
- await this._httpConfig.rateLimiter.acquire();
2142
- let res;
2143
- try {
2144
- res = await fetch(url, {
2145
- method: "POST",
2146
- headers: {
2147
- Authorization: `Bearer ${this._token}`,
2148
- "Content-Type": "application/json",
2149
- "User-Agent": "@mindstudio-ai/agent",
2150
- Accept: "text/event-stream"
2151
- },
2152
- body: JSON.stringify(body)
2153
- });
2154
- } catch (err) {
2155
- this._httpConfig.rateLimiter.release();
2156
- throw err;
2157
- }
2158
- this._httpConfig.rateLimiter.updateFromHeaders(res.headers);
2159
- if (!res.ok) {
2160
- this._httpConfig.rateLimiter.release();
2161
- const errorBody = await res.json().catch(() => ({}));
2162
- throw new MindStudioError(
2163
- errorBody.message || `${res.status} ${res.statusText}`,
2164
- errorBody.code || "api_error",
2165
- res.status,
2166
- errorBody
2167
- );
2168
- }
2169
- const headers = res.headers;
2170
- try {
2171
- const reader = res.body.getReader();
2172
- const decoder = new TextDecoder();
2173
- let buffer = "";
2174
- let doneEvent = null;
2175
- while (true) {
2176
- const { done, value } = await reader.read();
2177
- if (done) break;
2178
- buffer += decoder.decode(value, { stream: true });
2179
- const lines = buffer.split("\n");
2180
- buffer = lines.pop() ?? "";
2181
- for (const line of lines) {
2182
- if (!line.startsWith("data: ")) continue;
2183
- try {
2184
- const event = JSON.parse(line.slice(6));
2185
- if (event.type === "log") {
2186
- options.onLog({
2187
- value: event.value,
2188
- tag: event.tag,
2189
- ts: event.ts
2190
- });
2191
- } else if (event.type === "done") {
2192
- doneEvent = {
2193
- output: event.output,
2194
- outputUrl: event.outputUrl,
2195
- billingCost: event.billingCost,
2196
- billingEvents: event.billingEvents
2197
- };
2198
- } else if (event.type === "error") {
2199
- throw new MindStudioError(
2200
- event.error || "Step execution failed",
2201
- "step_error",
2202
- 500
2203
- );
2204
- }
2205
- } catch (err) {
2206
- if (err instanceof MindStudioError) throw err;
2207
- }
2208
- }
2209
- }
2210
- if (buffer.startsWith("data: ")) {
2211
- try {
2212
- const event = JSON.parse(buffer.slice(6));
2213
- if (event.type === "done") {
2214
- doneEvent = {
2215
- output: event.output,
2216
- outputUrl: event.outputUrl,
2217
- billingCost: event.billingCost,
2218
- billingEvents: event.billingEvents
2219
- };
2220
- } else if (event.type === "error") {
2221
- throw new MindStudioError(
2222
- event.error || "Step execution failed",
2223
- "step_error",
2224
- 500
2225
- );
2226
- } else if (event.type === "log") {
2227
- options.onLog({
2228
- value: event.value,
2229
- tag: event.tag,
2230
- ts: event.ts
2231
- });
2232
- }
2233
- } catch (err) {
2234
- if (err instanceof MindStudioError) throw err;
2235
- }
2236
- }
2237
- if (!doneEvent) {
2238
- throw new MindStudioError(
2239
- "Stream ended without a done event",
2240
- "stream_error",
2241
- 500
2242
- );
2243
- }
2244
- let output;
2245
- if (doneEvent.output != null) {
2246
- output = doneEvent.output;
2247
- } else if (doneEvent.outputUrl) {
2248
- const s3Res = await fetch(doneEvent.outputUrl);
2249
- if (!s3Res.ok) {
2250
- throw new MindStudioError(
2251
- `Failed to fetch output from S3: ${s3Res.status} ${s3Res.statusText}`,
2252
- "output_fetch_error",
2253
- s3Res.status
2254
- );
2255
- }
2256
- const envelope = await s3Res.json();
2257
- output = envelope.value;
2258
- } else {
2259
- output = void 0;
2260
- }
2261
- const returnedThreadId = headers.get("x-mindstudio-thread-id") ?? "";
2262
- if (this._reuseThreadId && returnedThreadId) {
2263
- this._threadId = returnedThreadId;
2264
- }
2265
- const returnedAppId = headers.get("x-mindstudio-app-id");
2266
- if (!this._appId && returnedAppId) {
2267
- this._appId = returnedAppId;
2268
- }
2269
- const remaining = headers.get("x-ratelimit-remaining");
2270
- return {
2271
- ...output,
2272
- $appId: headers.get("x-mindstudio-app-id") ?? "",
2273
- $threadId: returnedThreadId,
2274
- $rateLimitRemaining: remaining != null ? parseInt(remaining, 10) : void 0,
2275
- $billingCost: doneEvent.billingCost,
2276
- $billingEvents: doneEvent.billingEvents
2277
- };
2278
- } finally {
2279
- this._httpConfig.rateLimiter.release();
2280
- }
2281
- }
2282
- /**
2283
- * Execute multiple steps in parallel in a single request.
2284
- *
2285
- * All steps run in parallel on the server. Results are returned in the same
2286
- * order as the input. Individual step failures do not affect other steps —
2287
- * partial success is possible.
2288
- *
2289
- * ```ts
2290
- * const { results } = await agent.executeStepBatch([
2291
- * { stepType: 'generateImage', step: { prompt: 'a sunset' } },
2292
- * { stepType: 'textToSpeech', step: { text: 'Hello world' } },
2293
- * ]);
2294
- * ```
2295
- */
2296
- async executeStepBatch(steps, options) {
2297
- const threadId = options?.threadId ?? (this._reuseThreadId ? this._threadId : void 0);
2298
- const { data } = await request(this._httpConfig, "POST", "/steps/execute-batch", {
2299
- steps,
2300
- ...options?.appId != null && { appId: options.appId },
2301
- ...threadId != null && { threadId }
2302
- });
2303
- const results = await Promise.all(
2304
- data.results.map(async (r) => {
2305
- if (r.output != null) {
2306
- return {
2307
- stepType: r.stepType,
2308
- output: r.output,
2309
- billingCost: r.billingCost,
2310
- error: r.error
2311
- };
2312
- }
2313
- if (r.outputUrl) {
2314
- const res = await fetch(r.outputUrl);
2315
- if (!res.ok) {
2316
- return {
2317
- stepType: r.stepType,
2318
- error: `Failed to fetch output from S3: ${res.status} ${res.statusText}`
2319
- };
2320
- }
2321
- const envelope = await res.json();
2322
- return {
2323
- stepType: r.stepType,
2324
- output: envelope.value,
2325
- billingCost: r.billingCost
2326
- };
2327
- }
2328
- return {
2329
- stepType: r.stepType,
2330
- billingCost: r.billingCost,
2331
- error: r.error
2332
- };
2333
- })
2334
- );
2335
- if (this._reuseThreadId && data.threadId) {
2336
- this._threadId = data.threadId;
2337
- }
2338
- return {
2339
- results,
2340
- totalBillingCost: data.totalBillingCost,
2341
- appId: data.appId,
2342
- threadId: data.threadId
2343
- };
2344
- }
2345
- /**
2346
- * Get the authenticated user's identity and organization info.
2347
- *
2348
- * ```ts
2349
- * const info = await agent.getUserInfo();
2350
- * console.log(info.displayName, info.organizationName);
2351
- * ```
2352
- */
2353
- async getUserInfo() {
2354
- const { data } = await request(
2355
- this._httpConfig,
2356
- "GET",
2357
- "/account/userinfo"
2358
- );
2359
- return data;
2360
- }
2361
- /**
2362
- * List all pre-built agents in the organization.
2363
- *
2364
- * ```ts
2365
- * const { apps } = await agent.listAgents();
2366
- * for (const app of apps) console.log(app.name, app.id);
2367
- * ```
2368
- */
2369
- async listAgents() {
2370
- const { data } = await request(
2371
- this._httpConfig,
2372
- "GET",
2373
- "/agents/load"
2374
- );
2375
- return data;
2376
- }
2377
- /**
2378
- * Run a pre-built agent and wait for the result.
2379
- *
2380
- * Uses async polling internally — the request returns immediately with a
2381
- * callback token, then polls until the run completes or fails.
2382
- *
2383
- * ```ts
2384
- * const result = await agent.runAgent({
2385
- * appId: 'your-agent-id',
2386
- * variables: { query: 'hello' },
2387
- * });
2388
- * console.log(result.result);
2389
- * ```
2390
- */
2391
- async runAgent(options) {
2392
- const pollInterval = options.pollIntervalMs ?? 1e3;
2393
- const { data } = await request(this._httpConfig, "POST", "/agents/run", {
2394
- appId: options.appId,
2395
- async: true,
2396
- ...options.variables != null && { variables: options.variables },
2397
- ...options.workflow != null && { workflow: options.workflow },
2398
- ...options.version != null && { version: options.version },
2399
- ...options.includeBillingCost != null && {
2400
- includeBillingCost: options.includeBillingCost
2401
- },
2402
- ...options.metadata != null && { metadata: options.metadata }
2403
- });
2404
- const token = data.callbackToken;
2405
- const pollUrl = `${this._httpConfig.baseUrl}/developer/v2/agents/run/poll/${token}`;
2406
- while (true) {
2407
- await sleep2(pollInterval);
2408
- const res = await fetch(pollUrl, {
2409
- headers: { "User-Agent": "@mindstudio-ai/agent" }
2410
- });
2411
- if (res.status === 404) {
2412
- throw new MindStudioError(
2413
- "Poll token not found or expired.",
2414
- "poll_token_expired",
2415
- 404
2416
- );
2417
- }
2418
- if (!res.ok) {
2419
- const errorBody = await res.json().catch(() => ({}));
2420
- throw new MindStudioError(
2421
- errorBody.message ?? errorBody.error ?? `Poll request failed: ${res.status} ${res.statusText}`,
2422
- errorBody.code ?? "poll_error",
2423
- res.status,
2424
- errorBody
2425
- );
2426
- }
2427
- const poll = await res.json();
2428
- if (poll.status === "pending") continue;
2429
- if (poll.status === "error") {
2430
- throw new MindStudioError(
2431
- poll.error ?? "Agent run failed.",
2432
- "agent_run_error",
2433
- 500
2434
- );
2435
- }
2436
- return poll.result;
2437
- }
2438
- }
2439
- /** @internal Used by generated action methods. */
2440
- _request(method, path, body) {
2441
- return request(this._httpConfig, method, path, body);
2442
- }
2443
- // -------------------------------------------------------------------------
2444
- // Helper methods — models
2445
- // -------------------------------------------------------------------------
2446
- /** List all available AI models. */
2447
- async listModels() {
2448
- const { data } = await request(
2449
- this._httpConfig,
2450
- "GET",
2451
- "/helpers/models"
2452
- );
2453
- return data;
2454
- }
2455
- /** List AI models filtered by type. */
2456
- async listModelsByType(modelType) {
2457
- const { data } = await request(
2458
- this._httpConfig,
2459
- "GET",
2460
- `/helpers/models/${modelType}`
2461
- );
2462
- return data;
2463
- }
2464
- /** List all available AI models (summary). Returns only id, name, type, and tags. */
2465
- async listModelsSummary() {
2466
- const { data } = await request(
2467
- this._httpConfig,
2468
- "GET",
2469
- "/helpers/models-summary"
2470
- );
2471
- return data;
2472
- }
2473
- /** List AI models (summary) filtered by type. */
2474
- async listModelsSummaryByType(modelType) {
2475
- const { data } = await request(
2476
- this._httpConfig,
2477
- "GET",
2478
- `/helpers/models-summary/${modelType}`
2479
- );
2480
- return data;
2481
- }
2482
- // -------------------------------------------------------------------------
2483
- // Helper methods — OAuth connectors & connections
2484
- // -------------------------------------------------------------------------
2485
- /**
2486
- * List available OAuth connector services (Slack, Google, HubSpot, etc.).
2487
- *
2488
- * These are third-party integrations from the MindStudio Connector Registry.
2489
- * For most tasks, use actions directly instead.
2490
- */
2491
- async listConnectors() {
2492
- const { data } = await request(
2493
- this._httpConfig,
2494
- "GET",
2495
- "/helpers/connectors"
2496
- );
2497
- return data;
2498
- }
2499
- /** Get details for a single OAuth connector service. */
2500
- async getConnector(serviceId) {
2501
- const { data } = await request(
2502
- this._httpConfig,
2503
- "GET",
2504
- `/helpers/connectors/${serviceId}`
2505
- );
2506
- return data;
2507
- }
2508
- /** Get the full configuration for an OAuth connector action, including input fields. */
2509
- async getConnectorAction(serviceId, actionId) {
2510
- const { data } = await request(
2511
- this._httpConfig,
2512
- "GET",
2513
- `/helpers/connectors/${serviceId}/${actionId}`
2514
- );
2515
- return data;
2516
- }
2517
- /** List OAuth connections for the organization. These are authenticated third-party service links. */
2518
- async listConnections() {
2519
- const { data } = await request(
2520
- this._httpConfig,
2521
- "GET",
2522
- "/helpers/connections"
2523
- );
2524
- return data;
2525
- }
2526
- // -------------------------------------------------------------------------
2527
- // Helper methods — cost estimation
2528
- // -------------------------------------------------------------------------
2529
- /** Estimate the cost of executing an action before running it. */
2530
- async estimateStepCost(stepType, step, options) {
2531
- const { data } = await request(this._httpConfig, "POST", "/helpers/step-cost-estimate", {
2532
- step: { type: stepType, ...step },
2533
- ...options
2534
- });
2535
- return data;
2536
- }
2537
- // -------------------------------------------------------------------------
2538
- // Streaming
2539
- // -------------------------------------------------------------------------
2540
- /**
2541
- * Send a stream chunk to the caller via SSE.
2542
- *
2543
- * When invoked from a method that was called with `stream: true`, chunks
2544
- * are delivered in real-time as Server-Sent Events. When there is no active
2545
- * stream (no `STREAM_ID`), calls are silently ignored — so it's safe to
2546
- * call unconditionally.
2547
- *
2548
- * Accepts strings (sent as `type: 'token'`) or structured data (sent as
2549
- * `type: 'data'`). The caller receives each chunk as an SSE event.
2550
- *
2551
- * @example
2552
- * ```ts
2553
- * // Stream text tokens
2554
- * await agent.stream('Processing item 1...');
2555
- *
2556
- * // Stream structured data
2557
- * await agent.stream({ progress: 50, currentItem: 'abc' });
2558
- * ```
2559
- */
2560
- stream = async (data) => {
2561
- if (!this._streamId) return;
2562
- const url = `${this._httpConfig.baseUrl}/_internal/v2/stream-chunk`;
2563
- const body = typeof data === "string" ? { streamId: this._streamId, type: "token", text: data } : { streamId: this._streamId, type: "data", data };
2564
- const res = await fetch(url, {
2565
- method: "POST",
2566
- headers: {
2567
- "Content-Type": "application/json",
2568
- Authorization: this._token
2569
- },
2570
- body: JSON.stringify(body)
2571
- });
2572
- if (!res.ok) {
2573
- const text = await res.text().catch(() => "");
2574
- console.warn(`[mindstudio] stream chunk failed: ${res.status} ${text}`);
2575
- }
2576
- };
2577
- // -------------------------------------------------------------------------
2578
- // db + auth namespaces
2579
- // -------------------------------------------------------------------------
2580
- /**
2581
- * The `auth` namespace — synchronous role-based access control.
2582
- *
2583
- * Provides the current user's identity and roles. All methods are
2584
- * synchronous since the role map is preloaded during context hydration.
2585
- *
2586
- * **Important**: Context must be hydrated before accessing `auth`.
2587
- * - Inside the MindStudio sandbox: automatic (populated from globals)
2588
- * - Outside the sandbox: call `await agent.ensureContext()` first,
2589
- * or access `auth` after any `db` operation (which auto-hydrates)
2590
- *
2591
- * @throws {MindStudioError} if context has not been hydrated yet
2592
- *
2593
- * @example
2594
- * ```ts
2595
- * await agent.ensureContext();
2596
- * agent.auth.requireRole(Roles.admin);
2597
- * const admins = agent.auth.getUsersByRole(Roles.admin);
2598
- * ```
2599
- */
2600
- get auth() {
2601
- if (!this._auth) {
2602
- this._trySandboxHydration();
2603
- }
2604
- if (!this._auth) {
2605
- throw new MindStudioError(
2606
- "Auth context not yet loaded. Call `await agent.ensureContext()` or perform any db operation first (which auto-hydrates context). Inside the MindStudio sandbox, context is loaded automatically.",
2607
- "context_not_loaded",
2608
- 400
2609
- );
2610
- }
2611
- return this._auth;
2612
- }
2613
- /**
2614
- * The `db` namespace — chainable collection API over managed databases.
2615
- *
2616
- * Use `db.defineTable<T>(name)` to get a typed Table<T>, then call
2617
- * collection methods (filter, sortBy, push, update, etc.) on it.
2618
- *
2619
- * Context is auto-hydrated on first query execution — you can safely
2620
- * call `defineTable()` at module scope without triggering any HTTP.
2621
- *
2622
- * @example
2623
- * ```ts
2624
- * const Orders = agent.db.defineTable<Order>('orders');
2625
- * const active = await Orders.filter(o => o.status === 'active').take(10);
2626
- * ```
2627
- */
2628
- get db() {
2629
- if (!this._db) {
2630
- this._trySandboxHydration();
2631
- }
2632
- if (this._db) return this._db;
2633
- return this._createLazyDb();
2634
- }
2635
- /**
2636
- * Hydrate the app context (auth + database metadata). This must be
2637
- * called before using `auth` synchronously. For `db`, hydration happens
2638
- * automatically on first query.
2639
- *
2640
- * Context is fetched once and cached for the instance's lifetime.
2641
- * Calling `ensureContext()` multiple times is safe (no-op after first).
2642
- *
2643
- * Context sources (checked in order):
2644
- * 1. Sandbox globals (`globalThis.ai.auth`, `globalThis.ai.databases`)
2645
- * 2. HTTP: `GET /developer/v2/helpers/app-context?appId={appId}`
2646
- *
2647
- * @throws {MindStudioError} if no `appId` is available
2648
- *
2649
- * @example
2650
- * ```ts
2651
- * await agent.ensureContext();
2652
- * // auth is now available synchronously
2653
- * agent.auth.requireRole(Roles.admin);
2654
- * ```
2655
- */
2656
- async ensureContext() {
2657
- if (this._context) return;
2658
- if (!this._contextPromise) {
2659
- this._contextPromise = this._hydrateContext();
2660
- }
2661
- await this._contextPromise;
2662
- }
2663
- /**
2664
- * @internal Fetch and cache app context, then create auth + db instances.
2665
- *
2666
- * In managed mode (CALLBACK_TOKEN), the platform resolves the app from
2667
- * the token — no appId needed. With an API key, appId is required.
2668
- */
2669
- async _hydrateContext() {
2670
- if (!this._appId && this._authType !== "internal") {
2671
- throw new MindStudioError(
2672
- "No app ID available for context resolution. Pass `appId` to the constructor, set the MINDSTUDIO_APP_ID environment variable, or make a step execution call first (which auto-detects the app ID).",
2673
- "missing_app_id",
2674
- 400
2675
- );
2676
- }
2677
- const context = await this.getAppContext(this._appId);
2678
- this._applyContext(context);
2679
- }
2680
- /**
2681
- * @internal Apply a resolved context object — creates AuthContext and Db.
2682
- * Used by both the HTTP path and sandbox hydration.
2683
- */
2684
- _applyContext(context) {
2685
- this._context = context;
2686
- this._auth = new AuthContext(context.auth);
2687
- this._db = createDb(
2688
- context.databases,
2689
- this._executeDbBatch.bind(this)
2690
- );
2691
- }
2692
- /**
2693
- * @internal Try to hydrate context synchronously from sandbox globals.
2694
- * Called in the constructor when CALLBACK_TOKEN auth is detected.
2695
- *
2696
- * The MindStudio sandbox pre-populates `globalThis.ai` with:
2697
- * - `ai.auth`: { userId, roleAssignments[] }
2698
- * - `ai.databases`: [{ id, name, tables[] }]
2699
- */
2700
- _trySandboxHydration() {
2701
- const ai = globalThis.ai;
2702
- if (ai?.auth && ai?.databases) {
2703
- this._applyContext({
2704
- auth: ai.auth,
2705
- databases: ai.databases
2706
- });
2707
- }
2708
- }
2709
- /**
2710
- * @internal Execute a batch of SQL queries against a managed database.
2711
- * Used as the `executeBatch` callback for Table/Query instances.
2712
- *
2713
- * Calls `POST /_internal/v2/db/query` directly with the hook token
2714
- * (raw, no Bearer prefix). All queries run on a single SQLite connection,
2715
- * enabling RETURNING clauses and multi-statement batches.
2716
- */
2717
- async _executeDbBatch(databaseId, queries) {
2718
- const url = `${this._httpConfig.baseUrl}/_internal/v2/db/query`;
2719
- const res = await fetch(url, {
2720
- method: "POST",
2721
- headers: {
2722
- "Content-Type": "application/json",
2723
- Authorization: this._token
2724
- },
2725
- body: JSON.stringify({ databaseId, queries })
2726
- });
2727
- if (!res.ok) {
2728
- let message = `Database query failed: ${res.status} ${res.statusText}`;
2729
- let code = "db_query_error";
2730
- try {
2731
- const text = await res.text();
2732
- try {
2733
- const body = JSON.parse(text);
2734
- const errMsg = body.error ?? body.message ?? body.details;
2735
- if (errMsg) message = errMsg;
2736
- if (body.code) code = body.code;
2737
- } catch {
2738
- if (text && text.length < 500) message = text;
2739
- }
2740
- } catch {
2741
- }
2742
- throw new MindStudioError(
2743
- `[db] ${message}`,
2744
- code,
2745
- res.status
2746
- );
2747
- }
2748
- const data = await res.json();
2749
- return data.results;
2750
- }
2751
- /**
2752
- * @internal Create a lazy Db proxy that auto-hydrates context.
2753
- *
2754
- * defineTable() returns Table instances immediately (no async needed).
2755
- * But the Table's executeBatch callback is wrapped to call ensureContext()
2756
- * before the first query, so context is fetched lazily.
2757
- */
2758
- _createLazyDb() {
2759
- const agent = this;
2760
- return {
2761
- defineTable(name, options) {
2762
- const databaseHint = options?.database;
2763
- return new Table({
2764
- databaseId: "",
2765
- tableName: name,
2766
- columns: [],
2767
- unique: options?.unique,
2768
- defaults: options?.defaults,
2769
- executeBatch: async (queries) => {
2770
- await agent.ensureContext();
2771
- const databases = agent._context.databases;
2772
- let targetDb;
2773
- if (databaseHint) {
2774
- targetDb = databases.find(
2775
- (d) => d.id === databaseHint || d.name === databaseHint
2776
- );
2777
- } else {
2778
- targetDb = databases.find(
2779
- (d) => d.tables.some((t) => t.name === name)
2780
- );
2781
- }
2782
- const databaseId = targetDb?.id ?? databases[0]?.id ?? "";
2783
- return agent._executeDbBatch(databaseId, queries);
2784
- }
2785
- });
2786
- },
2787
- // Time helpers work without context
2788
- now: () => Date.now(),
2789
- days: (n) => n * 864e5,
2790
- hours: (n) => n * 36e5,
2791
- minutes: (n) => n * 6e4,
2792
- ago: (ms) => Date.now() - ms,
2793
- fromNow: (ms) => Date.now() + ms,
2794
- // Batch needs context — hydrate first, then delegate to real db
2795
- batch: ((...queries) => {
2796
- return (async () => {
2797
- await agent.ensureContext();
2798
- return agent._db.batch(...queries);
2799
- })();
2800
- })
2801
- };
2802
- }
2803
- // -------------------------------------------------------------------------
2804
- // Helper methods — user resolution
2805
- // -------------------------------------------------------------------------
2806
- /**
2807
- * Resolve a single user ID to display info (name, email, profile picture).
2808
- *
2809
- * Use this when you have a `User`-typed field value and need the person's
2810
- * display name, email, or avatar. Returns null if the user ID is not found.
2811
- *
2812
- * Also available as a top-level import:
2813
- * ```ts
2814
- * import { resolveUser } from '@mindstudio-ai/agent';
2815
- * ```
2816
- *
2817
- * @param userId - The user ID to resolve (a `User` branded string or plain UUID)
2818
- * @returns Resolved user info, or null if not found
2819
- *
2820
- * @example
2821
- * ```ts
2822
- * const user = await agent.resolveUser(order.requestedBy);
2823
- * if (user) {
2824
- * console.log(user.name); // "Jane Smith"
2825
- * console.log(user.email); // "jane@example.com"
2826
- * console.log(user.profilePictureUrl); // "https://..." or null
2827
- * }
2828
- * ```
2829
- */
2830
- async resolveUser(userId) {
2831
- const { users } = await this.resolveUsers([userId]);
2832
- return users[0] ?? null;
2833
- }
2834
- /**
2835
- * Resolve multiple user IDs to display info in a single request.
2836
- * Maximum 100 user IDs per request.
2837
- *
2838
- * Use this for batch resolution when you have multiple user references
2839
- * to display (e.g. all approvers on a purchase order, all team members).
2840
- *
2841
- * @param userIds - Array of user IDs to resolve (max 100)
2842
- * @returns Object with `users` array of resolved user info
2843
- *
2844
- * @example
2845
- * ```ts
2846
- * // Resolve all approvers at once
2847
- * const approverIds = approvals.map(a => a.assignedTo);
2848
- * const { users } = await agent.resolveUsers(approverIds);
2849
- *
2850
- * for (const u of users) {
2851
- * console.log(`${u.name} (${u.email})`);
2852
- * }
2853
- * ```
2854
- */
2855
- async resolveUsers(userIds) {
2856
- const { data } = await request(
2857
- this._httpConfig,
2858
- "POST",
2859
- "/helpers/resolve-users",
2860
- { userIds }
2861
- );
2862
- return data;
2863
- }
2864
- // -------------------------------------------------------------------------
2865
- // App context
2866
- // -------------------------------------------------------------------------
2867
- /**
2868
- * Get auth and database context for an app.
2869
- *
2870
- * Returns role assignments and managed database schemas. Useful for
2871
- * hydrating `auth` and `db` namespaces when running outside the sandbox.
2872
- *
2873
- * When called with a CALLBACK_TOKEN (managed mode), `appId` is optional —
2874
- * the platform resolves the app from the token. With an API key, `appId`
2875
- * is required.
2876
- *
2877
- * ```ts
2878
- * const ctx = await agent.getAppContext('your-app-id');
2879
- * console.log(ctx.auth.roleAssignments, ctx.databases);
2880
- * ```
2881
- */
2882
- async getAppContext(appId) {
2883
- const query = appId ? `?appId=${encodeURIComponent(appId)}` : "";
2884
- const { data } = await request(
2885
- this._httpConfig,
2886
- "GET",
2887
- `/helpers/app-context${query}`
2888
- );
2889
- return data;
2890
- }
2891
- // -------------------------------------------------------------------------
2892
- // Account methods
2893
- // -------------------------------------------------------------------------
2894
- /** Update the display name of the authenticated user/agent. */
2895
- async changeName(displayName) {
2896
- await request(this._httpConfig, "POST", "/account/change-name", {
2897
- name: displayName
2898
- });
2899
- }
2900
- /** Update the profile picture of the authenticated user/agent. */
2901
- async changeProfilePicture(url) {
2902
- await request(this._httpConfig, "POST", "/account/change-profile-picture", {
2903
- url
2904
- });
2905
- }
2906
- /**
2907
- * Upload a file to the MindStudio CDN.
2908
- *
2909
- * Gets a signed upload URL, PUTs the file content, and returns the
2910
- * permanent public URL.
2911
- */
2912
- async uploadFile(content, options) {
2913
- const { data } = await request(
2914
- this._httpConfig,
2915
- "POST",
2916
- "/account/upload",
2917
- {
2918
- extension: options.extension,
2919
- ...options.type != null && { type: options.type }
2920
- }
2921
- );
2922
- const buf = content.buffer.slice(
2923
- content.byteOffset,
2924
- content.byteOffset + content.byteLength
2925
- );
2926
- const res = await fetch(data.uploadUrl, {
2927
- method: "PUT",
2928
- body: buf,
2929
- headers: options.type ? { "Content-Type": options.type } : {}
2930
- });
2931
- if (!res.ok) {
2932
- const errorBody = await res.json().catch(() => ({}));
2933
- throw new MindStudioError(
2934
- errorBody.message ?? errorBody.error ?? `Upload failed: ${res.status} ${res.statusText}`,
2935
- errorBody.code ?? "upload_error",
2936
- res.status,
2937
- errorBody
2938
- );
2939
- }
2940
- return { url: data.url };
2941
- }
2942
- };
2943
- function sleep2(ms) {
2944
- return new Promise((resolve) => setTimeout(resolve, ms));
2945
- }
2946
- applyStepMethods(MindStudioAgent);
2947
- function resolveToken(provided, config) {
2948
- if (process.env.CALLBACK_TOKEN)
2949
- return { token: process.env.CALLBACK_TOKEN, authType: "internal" };
2950
- if (provided) return { token: provided, authType: "apiKey" };
2951
- if (process.env.MINDSTUDIO_API_KEY)
2952
- return { token: process.env.MINDSTUDIO_API_KEY, authType: "apiKey" };
2953
- if (config?.apiKey)
2954
- return { token: config.apiKey, authType: "apiKey" };
2955
- throw new MindStudioError(
2956
- "No API key provided. Run `mindstudio login`, pass `apiKey` to the constructor, or set the MINDSTUDIO_API_KEY environment variable.",
2957
- "missing_api_key",
2958
- 401
2959
- );
2960
- }
2961
-
2962
- // src/generated/snippets.ts
2963
- var monacoSnippets = {
2964
- "activeCampaignAddNote": { fields: [["contactId", "string"], ["note", "string"]], outputKeys: [] },
2965
- "activeCampaignCreateContact": { fields: [["email", "string"], ["firstName", "string"], ["lastName", "string"], ["phone", "string"], ["accountId", "string"], ["customFields", "object"]], outputKeys: ["contactId"] },
2966
- "addSubtitlesToVideo": { fields: [["videoUrl", "string"], ["language", "string"], ["fontName", "string"], ["fontSize", "number"], ["fontWeight", ["normal", "bold", "black"]], ["fontColor", ["white", "black", "red", "green", "blue", "yellow", "orange", "purple", "pink", "brown", "gray", "cyan", "magenta"]], ["highlightColor", ["white", "black", "red", "green", "blue", "yellow", "orange", "purple", "pink", "brown", "gray", "cyan", "magenta"]], ["strokeWidth", "number"], ["strokeColor", ["black", "white", "red", "green", "blue", "yellow", "orange", "purple", "pink", "brown", "gray", "cyan", "magenta"]], ["backgroundColor", ["black", "white", "red", "green", "blue", "yellow", "orange", "purple", "pink", "brown", "gray", "cyan", "magenta", "none"]], ["backgroundOpacity", "number"], ["position", ["top", "center", "bottom"]], ["yOffset", "number"], ["wordsPerSubtitle", "number"], ["enableAnimation", "boolean"]], outputKeys: ["videoUrl"] },
2967
- "airtableCreateUpdateRecord": { fields: [["baseId", "string"], ["tableId", "string"], ["fields", "string"], ["recordData", "object"]], outputKeys: ["recordId"] },
2968
- "airtableDeleteRecord": { fields: [["baseId", "string"], ["tableId", "string"], ["recordId", "string"]], outputKeys: ["deleted"] },
2969
- "airtableGetRecord": { fields: [["baseId", "string"], ["tableId", "string"], ["recordId", "string"]], outputKeys: ["record"] },
2970
- "airtableGetTableRecords": { fields: [["baseId", "string"], ["tableId", "string"]], outputKeys: ["records"] },
2971
- "analyzeImage": { fields: [["prompt", "string"], ["imageUrl", "string"]], outputKeys: ["analysis"] },
2972
- "analyzeVideo": { fields: [["prompt", "string"], ["videoUrl", "string"]], outputKeys: ["analysis"] },
2973
- "captureThumbnail": { fields: [["videoUrl", "string"], ["at", "string"]], outputKeys: ["thumbnailUrl"] },
2974
- "checkAppRole": { fields: [["roleName", "string"]], outputKeys: ["hasRole", "userRoles"] },
2975
- "codaCreateUpdatePage": { fields: [["pageData", "object"]], outputKeys: ["pageId"] },
2976
- "codaCreateUpdateRow": { fields: [["docId", "string"], ["tableId", "string"], ["rowData", "object"]], outputKeys: ["rowId"] },
2977
- "codaFindRow": { fields: [["docId", "string"], ["tableId", "string"], ["rowData", "object"]], outputKeys: ["row"] },
2978
- "codaGetPage": { fields: [["docId", "string"], ["pageId", "string"]], outputKeys: ["content"] },
2979
- "codaGetTableRows": { fields: [["docId", "string"], ["tableId", "string"]], outputKeys: ["rows"] },
2980
- "convertPdfToImages": { fields: [["pdfUrl", "string"]], outputKeys: ["imageUrls"] },
2981
- "createDataSource": { fields: [["name", "string"]], outputKeys: [] },
2982
- "createGmailDraft": { fields: [["to", "string"], ["subject", "string"], ["message", "string"], ["messageType", ["plain", "html", "markdown"]]], outputKeys: ["draftId"] },
2983
- "createGoogleCalendarEvent": { fields: [["summary", "string"], ["startDateTime", "string"], ["endDateTime", "string"]], outputKeys: ["eventId", "htmlLink"] },
2984
- "createGoogleDoc": { fields: [["title", "string"], ["text", "string"], ["textType", ["plain", "html", "markdown"]]], outputKeys: ["documentUrl"] },
2985
- "createGoogleSheet": { fields: [["title", "string"], ["text", "string"]], outputKeys: ["spreadsheetUrl"] },
2986
- "deleteDataSource": { fields: [["dataSourceId", "string"]], outputKeys: [] },
2987
- "deleteDataSourceDocument": { fields: [["dataSourceId", "string"], ["documentId", "string"]], outputKeys: [] },
2988
- "deleteGmailEmail": { fields: [["messageId", "string"]], outputKeys: [] },
2989
- "deleteGoogleCalendarEvent": { fields: [["eventId", "string"]], outputKeys: [] },
2990
- "deleteGoogleSheetRows": { fields: [["documentId", "string"], ["startRow", "string"], ["endRow", "string"]], outputKeys: [] },
2991
- "detectChanges": { fields: [["mode", ["ai", "comparison"]], ["input", "string"]], outputKeys: ["hasChanged", "currentValue", "previousValue", "isFirstRun"] },
2992
- "detectPII": { fields: [["input", "string"], ["language", "string"], ["entities", "array"]], outputKeys: ["detected", "detections"] },
2993
- "discordEditMessage": { fields: [["botToken", "string"], ["channelId", "string"], ["messageId", "string"], ["text", "string"]], outputKeys: [] },
2994
- "discordSendFollowUp": { fields: [["applicationId", "string"], ["interactionToken", "string"], ["text", "string"]], outputKeys: ["messageId"] },
2995
- "discordSendMessage": { fields: [["mode", ["edit", "send"]], ["text", "string"]], outputKeys: [] },
2996
- "downloadVideo": { fields: [["videoUrl", "string"], ["format", ["mp4", "mp3"]]], outputKeys: ["videoUrl"] },
2997
- "enhanceImageGenerationPrompt": { fields: [["initialPrompt", "string"], ["includeNegativePrompt", "boolean"], ["systemPrompt", "string"]], outputKeys: ["prompt"] },
2998
- "enhanceVideoGenerationPrompt": { fields: [["initialPrompt", "string"], ["includeNegativePrompt", "boolean"], ["systemPrompt", "string"]], outputKeys: ["prompt"] },
2999
- "enrichPerson": { fields: [["params", "object"]], outputKeys: ["data"] },
3000
- "extractAudioFromVideo": { fields: [["videoUrl", "string"]], outputKeys: ["audioUrl"] },
3001
- "extractText": { fields: [["url", "string"]], outputKeys: ["text"] },
3002
- "fetchDataSourceDocument": { fields: [["dataSourceId", "string"], ["documentId", "string"]], outputKeys: [] },
3003
- "fetchGoogleDoc": { fields: [["documentId", "string"], ["exportType", ["html", "markdown", "json", "plain"]]], outputKeys: ["content"] },
3004
- "fetchGoogleSheet": { fields: [["spreadsheetId", "string"], ["range", "string"], ["exportType", ["csv", "json"]]], outputKeys: ["content"] },
3005
- "fetchSlackChannelHistory": { fields: [["channelId", "string"]], outputKeys: ["messages"] },
3006
- "fetchYoutubeCaptions": { fields: [["videoUrl", "string"], ["exportType", ["text", "json"]], ["language", "string"]], outputKeys: ["transcripts"] },
3007
- "fetchYoutubeChannel": { fields: [["channelUrl", "string"]], outputKeys: [] },
3008
- "fetchYoutubeComments": { fields: [["videoUrl", "string"], ["exportType", ["text", "json"]], ["limitPages", "string"]], outputKeys: ["comments"] },
3009
- "fetchYoutubeVideo": { fields: [["videoUrl", "string"]], outputKeys: [] },
3010
- "generateAsset": { fields: [["source", "string"], ["sourceType", ["html", "markdown", "spa", "raw", "dynamic", "customInterface"]], ["outputFormat", ["pdf", "png", "html", "mp4", "openGraph"]], ["pageSize", ["full", "letter", "A4", "custom"]], ["testData", "object"]], outputKeys: ["url"] },
3011
- "generateChart": { fields: [["chart", "object"]], outputKeys: ["chartUrl"] },
3012
- "generateImage": { fields: [["prompt", "string"]], outputKeys: ["imageUrl"] },
3013
- "generateLipsync": { fields: [], outputKeys: [] },
3014
- "generateMusic": { fields: [["text", "string"]], outputKeys: [] },
3015
- "generatePdf": { fields: [["source", "string"], ["sourceType", ["html", "markdown", "spa", "raw", "dynamic", "customInterface"]], ["outputFormat", ["pdf", "png", "html", "mp4", "openGraph"]], ["pageSize", ["full", "letter", "A4", "custom"]], ["testData", "object"]], outputKeys: ["url"] },
3016
- "generateStaticVideoFromImage": { fields: [["imageUrl", "string"], ["duration", "string"]], outputKeys: ["videoUrl"] },
3017
- "generateText": { fields: [["message", "string"]], outputKeys: ["content"] },
3018
- "generateVideo": { fields: [["prompt", "string"]], outputKeys: ["videoUrl"] },
3019
- "getGmailAttachments": { fields: [["messageId", "string"]], outputKeys: [] },
3020
- "getGmailDraft": { fields: [["draftId", "string"]], outputKeys: ["draftId", "messageId", "subject", "to", "from", "body"] },
3021
- "getGmailEmail": { fields: [["messageId", "string"]], outputKeys: ["messageId", "subject", "from", "to", "date", "body", "labels"] },
3022
- "getGmailUnreadCount": { fields: [], outputKeys: [] },
3023
- "getGoogleCalendarEvent": { fields: [["eventId", "string"], ["exportType", ["json", "text"]]], outputKeys: ["event"] },
3024
- "getGoogleDriveFile": { fields: [["fileId", "string"]], outputKeys: ["url", "name", "mimeType", "size"] },
3025
- "getGoogleSheetInfo": { fields: [["documentId", "string"]], outputKeys: ["title", "sheets"] },
3026
- "getMediaMetadata": { fields: [["mediaUrl", "string"]], outputKeys: ["metadata"] },
3027
- "httpRequest": { fields: [["url", "string"], ["method", "string"], ["headers", "object"], ["queryParams", "object"], ["body", "string"], ["bodyItems", "object"], ["contentType", ["none", "application/json", "application/x-www-form-urlencoded", "multipart/form-data", "custom"]], ["customContentType", "string"]], outputKeys: ["ok", "status", "statusText", "response"] },
3028
- "hubspotCreateCompany": { fields: [["company", "object"], ["enabledProperties", "array"]], outputKeys: ["companyId"] },
3029
- "hubspotCreateContact": { fields: [["contact", "object"], ["enabledProperties", "array"], ["companyDomain", "string"]], outputKeys: ["contactId"] },
3030
- "hubspotGetCompany": { fields: [["searchBy", ["domain", "id"]], ["companyDomain", "string"], ["companyId", "string"], ["additionalProperties", "array"]], outputKeys: ["company"] },
3031
- "hubspotGetContact": { fields: [["searchBy", ["email", "id"]], ["contactEmail", "string"], ["contactId", "string"], ["additionalProperties", "array"]], outputKeys: ["contact"] },
3032
- "hunterApiCompanyEnrichment": { fields: [["domain", "string"]], outputKeys: ["data"] },
3033
- "hunterApiDomainSearch": { fields: [["domain", "string"]], outputKeys: ["data"] },
3034
- "hunterApiEmailFinder": { fields: [["domain", "string"], ["firstName", "string"], ["lastName", "string"]], outputKeys: ["data"] },
3035
- "hunterApiEmailVerification": { fields: [["email", "string"]], outputKeys: ["data"] },
3036
- "hunterApiPersonEnrichment": { fields: [["email", "string"]], outputKeys: ["data"] },
3037
- "imageFaceSwap": { fields: [["imageUrl", "string"], ["faceImageUrl", "string"], ["engine", "string"]], outputKeys: ["imageUrl"] },
3038
- "imageRemoveWatermark": { fields: [["imageUrl", "string"], ["engine", "string"]], outputKeys: ["imageUrl"] },
3039
- "insertVideoClips": { fields: [["baseVideoUrl", "string"], ["overlayVideos", "array"]], outputKeys: ["videoUrl"] },
3040
- "listDataSources": { fields: [], outputKeys: [] },
3041
- "listGmailDrafts": { fields: [["exportType", ["json", "text"]]], outputKeys: ["drafts"] },
3042
- "listGmailLabels": { fields: [], outputKeys: [] },
3043
- "listGoogleCalendarEvents": { fields: [["limit", "number"], ["exportType", ["json", "text"]]], outputKeys: ["events"] },
3044
- "listGoogleDriveFiles": { fields: [["exportType", ["json", "text"]]], outputKeys: ["files"] },
3045
- "listRecentGmailEmails": { fields: [["exportType", ["json", "text"]], ["limit", "string"]], outputKeys: [] },
3046
- "logic": { fields: [["context", "string"], ["cases", "array"]], outputKeys: ["selectedCase"] },
3047
- "makeDotComRunScenario": { fields: [["webhookUrl", "string"], ["input", "object"]], outputKeys: ["data"] },
3048
- "mergeAudio": { fields: [["mp3Urls", "array"]], outputKeys: ["audioUrl"] },
3049
- "mergeVideos": { fields: [["videoUrls", "array"]], outputKeys: ["videoUrl"] },
3050
- "mixAudioIntoVideo": { fields: [["videoUrl", "string"], ["audioUrl", "string"], ["options", "object"]], outputKeys: ["videoUrl"] },
3051
- "muteVideo": { fields: [["videoUrl", "string"]], outputKeys: ["videoUrl"] },
3052
- "n8nRunNode": { fields: [["method", "string"], ["authentication", ["none", "basic", "string"]], ["user", "string"], ["password", "string"], ["webhookUrl", "string"], ["input", "object"]], outputKeys: ["data"] },
3053
- "notionCreatePage": { fields: [["pageId", "string"], ["content", "string"], ["title", "string"]], outputKeys: ["pageId", "pageUrl"] },
3054
- "notionUpdatePage": { fields: [["pageId", "string"], ["content", "string"], ["mode", ["append", "overwrite"]]], outputKeys: ["pageId", "pageUrl"] },
3055
- "peopleSearch": { fields: [["smartQuery", "string"], ["enrichPeople", "boolean"], ["enrichOrganizations", "boolean"], ["limit", "string"], ["page", "string"], ["params", "object"]], outputKeys: ["results"] },
3056
- "postToLinkedIn": { fields: [["message", "string"], ["visibility", ["PUBLIC", "CONNECTIONS"]]], outputKeys: [] },
3057
- "postToSlackChannel": { fields: [["channelId", "string"], ["messageType", ["string", "blocks"]], ["message", "string"]], outputKeys: [] },
3058
- "postToX": { fields: [["text", "string"]], outputKeys: [] },
3059
- "postToZapier": { fields: [["webhookUrl", "string"], ["input", "object"]], outputKeys: ["data"] },
3060
- "queryAppDatabase": { fields: [["databaseId", "string"], ["sql", "string"]], outputKeys: ["rows", "changes"] },
3061
- "queryDataSource": { fields: [["dataSourceId", "string"], ["query", "string"], ["maxResults", "number"]], outputKeys: ["text", "chunks", "query", "citations", "latencyMs"] },
3062
- "queryExternalDatabase": { fields: [["query", "string"], ["outputFormat", ["json", "csv"]]], outputKeys: ["data"] },
3063
- "redactPII": { fields: [["input", "string"], ["language", "string"], ["entities", "array"]], outputKeys: ["text"] },
3064
- "removeBackgroundFromImage": { fields: [["imageUrl", "string"]], outputKeys: ["imageUrl"] },
3065
- "replyToGmailEmail": { fields: [["messageId", "string"], ["message", "string"], ["messageType", ["plain", "html", "markdown"]]], outputKeys: ["messageId"] },
3066
- "resizeVideo": { fields: [["videoUrl", "string"], ["mode", ["fit", "exact"]]], outputKeys: ["videoUrl"] },
3067
- "runFromConnectorRegistry": { fields: [["actionId", "string"], ["displayName", "string"], ["icon", "string"], ["configurationValues", "object"]], outputKeys: ["data"] },
3068
- "runPackagedWorkflow": { fields: [["appId", "string"], ["workflowId", "string"], ["inputVariables", "object"], ["outputVariables", "object"], ["name", "string"]], outputKeys: ["data"] },
3069
- "scrapeFacebookPage": { fields: [["pageUrl", "string"]], outputKeys: ["data"] },
3070
- "scrapeFacebookPosts": { fields: [["pageUrl", "string"]], outputKeys: ["data"] },
3071
- "scrapeInstagramComments": { fields: [["postUrl", "string"], ["resultsLimit", "string"]], outputKeys: ["data"] },
3072
- "scrapeInstagramMentions": { fields: [["profileUrl", "string"], ["resultsLimit", "string"]], outputKeys: ["data"] },
3073
- "scrapeInstagramPosts": { fields: [["profileUrl", "string"], ["resultsLimit", "string"], ["onlyPostsNewerThan", "string"]], outputKeys: ["data"] },
3074
- "scrapeInstagramProfile": { fields: [["profileUrl", "string"]], outputKeys: ["data"] },
3075
- "scrapeInstagramReels": { fields: [["profileUrl", "string"], ["resultsLimit", "string"]], outputKeys: ["data"] },
3076
- "scrapeLinkedInCompany": { fields: [["url", "string"]], outputKeys: ["company"] },
3077
- "scrapeLinkedInProfile": { fields: [["url", "string"]], outputKeys: ["profile"] },
3078
- "scrapeMetaThreadsProfile": { fields: [["profileUrl", "string"]], outputKeys: ["data"] },
3079
- "scrapeUrl": { fields: [["url", "string"]], outputKeys: ["content"] },
3080
- "scrapeXPost": { fields: [["url", "string"]], outputKeys: ["post"] },
3081
- "scrapeXProfile": { fields: [["url", "string"]], outputKeys: ["profile"] },
3082
- "screenshotUrl": { fields: [["url", "string"]], outputKeys: ["screenshotUrl"] },
3083
- "searchGmailEmails": { fields: [["query", "string"], ["exportType", ["json", "text"]], ["limit", "string"]], outputKeys: ["emails"] },
3084
- "searchGoogle": { fields: [["query", "string"], ["exportType", ["text", "json"]]], outputKeys: ["results"] },
3085
- "searchGoogleCalendarEvents": { fields: [["exportType", ["json", "text"]]], outputKeys: ["events"] },
3086
- "searchGoogleDrive": { fields: [["query", "string"], ["exportType", ["json", "text"]]], outputKeys: ["files"] },
3087
- "searchGoogleImages": { fields: [["query", "string"], ["exportType", ["text", "json"]]], outputKeys: ["images"] },
3088
- "searchGoogleNews": { fields: [["text", "string"], ["exportType", ["text", "json"]]], outputKeys: ["articles"] },
3089
- "searchGoogleTrends": { fields: [["text", "string"], ["hl", "string"], ["geo", "string"], ["data_type", ["TIMESERIES", "GEO_MAP", "GEO_MAP_0", "RELATED_TOPICS", "RELATED_QUERIES"]], ["cat", "string"], ["date", "string"], ["ts", "string"]], outputKeys: ["trends"] },
3090
- "searchPerplexity": { fields: [["query", "string"], ["exportType", ["text", "json"]]], outputKeys: ["results"] },
3091
- "searchXPosts": { fields: [["query", "string"], ["scope", ["recent", "all"]], ["options", "object"]], outputKeys: ["posts"] },
3092
- "searchYoutube": { fields: [["query", "string"], ["limitPages", "string"], ["filter", "string"], ["filterType", "string"]], outputKeys: ["results"] },
3093
- "searchYoutubeTrends": { fields: [["bp", ["now", "music", "gaming", "films"]], ["hl", "string"], ["gl", "string"]], outputKeys: [] },
3094
- "sendEmail": { fields: [["subject", "string"], ["body", "string"]], outputKeys: ["recipients"] },
3095
- "sendGmailDraft": { fields: [["draftId", "string"]], outputKeys: [] },
3096
- "sendGmailMessage": { fields: [["to", "string"], ["subject", "string"], ["message", "string"], ["messageType", ["plain", "html", "markdown"]]], outputKeys: ["messageId"] },
3097
- "sendSMS": { fields: [["body", "string"]], outputKeys: [] },
3098
- "setGmailReadStatus": { fields: [["messageIds", "string"], ["markAsRead", "boolean"]], outputKeys: [] },
3099
- "setRunTitle": { fields: [["title", "string"]], outputKeys: [] },
3100
- "setVariable": { fields: [["value", "string"]], outputKeys: [] },
3101
- "telegramEditMessage": { fields: [["botToken", "string"], ["chatId", "string"], ["messageId", "string"], ["text", "string"]], outputKeys: [] },
3102
- "telegramReplyToMessage": { fields: [["botToken", "string"], ["chatId", "string"], ["replyToMessageId", "string"], ["text", "string"]], outputKeys: ["messageId"] },
3103
- "telegramSendAudio": { fields: [["botToken", "string"], ["chatId", "string"], ["audioUrl", "string"], ["mode", ["audio", "voice"]]], outputKeys: [] },
3104
- "telegramSendFile": { fields: [["botToken", "string"], ["chatId", "string"], ["fileUrl", "string"]], outputKeys: [] },
3105
- "telegramSendImage": { fields: [["botToken", "string"], ["chatId", "string"], ["imageUrl", "string"]], outputKeys: [] },
3106
- "telegramSendMessage": { fields: [["botToken", "string"], ["chatId", "string"], ["text", "string"]], outputKeys: ["messageId"] },
3107
- "telegramSendVideo": { fields: [["botToken", "string"], ["chatId", "string"], ["videoUrl", "string"]], outputKeys: [] },
3108
- "telegramSetTyping": { fields: [["botToken", "string"], ["chatId", "string"]], outputKeys: [] },
3109
- "textToSpeech": { fields: [["text", "string"]], outputKeys: ["audioUrl"] },
3110
- "transcribeAudio": { fields: [["audioUrl", "string"], ["prompt", "string"]], outputKeys: ["text"] },
3111
- "trimMedia": { fields: [["inputUrl", "string"]], outputKeys: ["mediaUrl"] },
3112
- "updateGmailLabels": { fields: [["query", "string"], ["messageIds", "string"], ["addLabelIds", "string"], ["removeLabelIds", "string"]], outputKeys: ["updatedMessageIds"] },
3113
- "updateGoogleCalendarEvent": { fields: [["eventId", "string"]], outputKeys: ["eventId", "htmlLink"] },
3114
- "updateGoogleDoc": { fields: [["documentId", "string"], ["text", "string"], ["textType", ["plain", "html", "markdown"]], ["operationType", ["addToTop", "addToBottom", "overwrite"]]], outputKeys: ["documentUrl"] },
3115
- "updateGoogleSheet": { fields: [["text", "string"], ["spreadsheetId", "string"], ["range", "string"], ["operationType", ["addToBottom", "overwrite", "range"]]], outputKeys: ["spreadsheetUrl"] },
3116
- "uploadDataSourceDocument": { fields: [["dataSourceId", "string"], ["file", "string"], ["fileName", "string"]], outputKeys: [] },
3117
- "upscaleImage": { fields: [["imageUrl", "string"], ["targetResolution", ["2k", "4k", "8k"]], ["engine", ["standard", "pro"]]], outputKeys: ["imageUrl"] },
3118
- "upscaleVideo": { fields: [["videoUrl", "string"], ["targetResolution", ["720p", "1080p", "2K", "4K"]], ["engine", ["standard", "pro", "ultimate", "flashvsr", "seedance", "seedvr2", "runwayml/upscale-v1"]]], outputKeys: ["videoUrl"] },
3119
- "userMessage": { fields: [["message", "string"]], outputKeys: ["content"] },
3120
- "videoFaceSwap": { fields: [["videoUrl", "string"], ["faceImageUrl", "string"], ["targetIndex", "number"], ["engine", "string"]], outputKeys: ["videoUrl"] },
3121
- "videoRemoveBackground": { fields: [["videoUrl", "string"], ["newBackground", ["transparent", "image"]], ["engine", "string"]], outputKeys: ["videoUrl"] },
3122
- "videoRemoveWatermark": { fields: [["videoUrl", "string"], ["engine", "string"]], outputKeys: ["videoUrl"] },
3123
- "watermarkImage": { fields: [["imageUrl", "string"], ["watermarkImageUrl", "string"], ["corner", ["top-left", "top-right", "bottom-left", "bottom-right"]], ["paddingPx", "number"], ["widthPx", "number"]], outputKeys: ["imageUrl"] },
3124
- "watermarkVideo": { fields: [["videoUrl", "string"], ["imageUrl", "string"], ["corner", ["top-left", "top-right", "bottom-left", "bottom-right"]], ["paddingPx", "number"], ["widthPx", "number"]], outputKeys: ["videoUrl"] }
3125
- };
3126
- var blockTypeAliases = {
3127
- "userMessage": "generateText",
3128
- "generatePdf": "generateAsset"
3129
- };
3130
-
3131
2069
  // src/generated/metadata.ts
3132
2070
  var stepMetadata = {
3133
2071
  "activeCampaignAddNote": {
@@ -4289,6 +3227,1183 @@ var stepMetadata = {
4289
3227
  }
4290
3228
  };
4291
3229
 
3230
+ // src/client.ts
3231
+ var DEFAULT_BASE_URL = "https://v1.mindstudio-api.com";
3232
+ var DEFAULT_MAX_RETRIES = 3;
3233
+ var MindStudioAgent = class {
3234
+ /** @internal */
3235
+ _httpConfig;
3236
+ /** @internal */
3237
+ _reuseThreadId;
3238
+ /** @internal */
3239
+ _threadId;
3240
+ /** @internal Stream ID for SSE token streaming. Set by sandbox via STREAM_ID env var. */
3241
+ _streamId;
3242
+ // ---- App context (db + auth) ----
3243
+ /**
3244
+ * @internal App ID for context resolution. Resolved from:
3245
+ * constructor appId → MINDSTUDIO_APP_ID env → sandbox globals →
3246
+ * auto-detected from first executeStep response header.
3247
+ */
3248
+ _appId;
3249
+ /**
3250
+ * @internal Cached app context (auth + databases). Populated by
3251
+ * ensureContext() and cached for the lifetime of the instance.
3252
+ */
3253
+ _context;
3254
+ /**
3255
+ * @internal Deduplication promise for ensureContext(). Ensures only one
3256
+ * context fetch is in-flight at a time, even if multiple db/auth
3257
+ * operations trigger it concurrently.
3258
+ */
3259
+ _contextPromise;
3260
+ /** @internal Cached AuthContext instance, created during context hydration. */
3261
+ _auth;
3262
+ /** @internal Cached Db namespace instance, created during context hydration. */
3263
+ _db;
3264
+ /** @internal Auth type — 'internal' for CALLBACK_TOKEN (managed mode), 'apiKey' otherwise. */
3265
+ _authType;
3266
+ /**
3267
+ * @internal Resolve the current auth token. For internal (CALLBACK_TOKEN)
3268
+ * auth, re-reads the env var each time so that long-lived singleton
3269
+ * instances pick up token rotations from the host process.
3270
+ */
3271
+ get _token() {
3272
+ if (this._authType === "internal" && process.env.CALLBACK_TOKEN) {
3273
+ return process.env.CALLBACK_TOKEN;
3274
+ }
3275
+ return this._httpConfig.token;
3276
+ }
3277
+ constructor(options = {}) {
3278
+ const config = loadConfig();
3279
+ const { token, authType } = resolveToken(options.apiKey, config);
3280
+ const baseUrl = options.baseUrl ?? process.env.MINDSTUDIO_BASE_URL ?? process.env.REMOTE_HOSTNAME ?? config.baseUrl ?? DEFAULT_BASE_URL;
3281
+ this._reuseThreadId = options.reuseThreadId ?? /^(true|1)$/i.test(process.env.MINDSTUDIO_REUSE_THREAD_ID ?? "");
3282
+ this._appId = options.appId ?? process.env.MINDSTUDIO_APP_ID ?? void 0;
3283
+ this._authType = authType;
3284
+ this._httpConfig = {
3285
+ baseUrl,
3286
+ token,
3287
+ rateLimiter: new RateLimiter(authType),
3288
+ maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES
3289
+ };
3290
+ if (authType === "internal") {
3291
+ this._trySandboxHydration();
3292
+ }
3293
+ this._streamId = process.env.STREAM_ID ?? void 0;
3294
+ }
3295
+ /**
3296
+ * Execute any step by its type name. This is the low-level method that all
3297
+ * typed step methods delegate to. Use it as an escape hatch for step types
3298
+ * not yet covered by the generated methods.
3299
+ *
3300
+ * ```ts
3301
+ * const result = await agent.executeStep("generateImage", { prompt: "hello", mode: "background" });
3302
+ * ```
3303
+ */
3304
+ async executeStep(stepType, step, options) {
3305
+ if (options?.onLog) {
3306
+ return this._executeStepStreaming(
3307
+ stepType,
3308
+ step,
3309
+ options
3310
+ );
3311
+ }
3312
+ const threadId = options?.threadId ?? (this._reuseThreadId ? this._threadId : void 0);
3313
+ const { data, headers } = await request(this._httpConfig, "POST", `/steps/${stepType}/execute`, {
3314
+ step,
3315
+ ...options?.appId != null && { appId: options.appId },
3316
+ ...threadId != null && { threadId },
3317
+ ...this._streamId != null && { streamId: this._streamId }
3318
+ });
3319
+ let output;
3320
+ if (data.output != null) {
3321
+ output = data.output;
3322
+ } else if (data.outputUrl) {
3323
+ const res = await fetch(data.outputUrl);
3324
+ if (!res.ok) {
3325
+ throw new MindStudioError(
3326
+ `Failed to fetch output from S3: ${res.status} ${res.statusText}`,
3327
+ "output_fetch_error",
3328
+ res.status
3329
+ );
3330
+ }
3331
+ const envelope = await res.json();
3332
+ output = envelope.value;
3333
+ } else {
3334
+ output = void 0;
3335
+ }
3336
+ const returnedThreadId = headers.get("x-mindstudio-thread-id") ?? "";
3337
+ if (this._reuseThreadId && returnedThreadId) {
3338
+ this._threadId = returnedThreadId;
3339
+ }
3340
+ const returnedAppId = headers.get("x-mindstudio-app-id");
3341
+ if (!this._appId && returnedAppId) {
3342
+ this._appId = returnedAppId;
3343
+ }
3344
+ const remaining = headers.get("x-ratelimit-remaining");
3345
+ const billingCost = headers.get("x-mindstudio-billing-cost");
3346
+ const billingEvents = headers.get("x-mindstudio-billing-events");
3347
+ return {
3348
+ ...output,
3349
+ $appId: headers.get("x-mindstudio-app-id") ?? "",
3350
+ $threadId: returnedThreadId,
3351
+ $rateLimitRemaining: remaining != null ? parseInt(remaining, 10) : void 0,
3352
+ $billingCost: billingCost != null ? parseFloat(billingCost) : void 0,
3353
+ $billingEvents: billingEvents != null ? JSON.parse(billingEvents) : void 0
3354
+ };
3355
+ }
3356
+ /**
3357
+ * @internal Streaming step execution — sends `Accept: text/event-stream`
3358
+ * and parses SSE events for real-time debug logs.
3359
+ */
3360
+ async _executeStepStreaming(stepType, step, options) {
3361
+ const threadId = options.threadId ?? (this._reuseThreadId ? this._threadId : void 0);
3362
+ const url = `${this._httpConfig.baseUrl}/developer/v2/steps/${stepType}/execute`;
3363
+ const body = {
3364
+ step,
3365
+ ...options.appId != null && { appId: options.appId },
3366
+ ...threadId != null && { threadId },
3367
+ ...this._streamId != null && { streamId: this._streamId }
3368
+ };
3369
+ await this._httpConfig.rateLimiter.acquire();
3370
+ let res;
3371
+ try {
3372
+ res = await fetch(url, {
3373
+ method: "POST",
3374
+ headers: {
3375
+ Authorization: `Bearer ${this._token}`,
3376
+ "Content-Type": "application/json",
3377
+ "User-Agent": "@mindstudio-ai/agent",
3378
+ Accept: "text/event-stream"
3379
+ },
3380
+ body: JSON.stringify(body)
3381
+ });
3382
+ } catch (err) {
3383
+ this._httpConfig.rateLimiter.release();
3384
+ throw err;
3385
+ }
3386
+ this._httpConfig.rateLimiter.updateFromHeaders(res.headers);
3387
+ if (!res.ok) {
3388
+ this._httpConfig.rateLimiter.release();
3389
+ const errorBody = await res.json().catch(() => ({}));
3390
+ throw new MindStudioError(
3391
+ errorBody.message || `${res.status} ${res.statusText}`,
3392
+ errorBody.code || "api_error",
3393
+ res.status,
3394
+ errorBody
3395
+ );
3396
+ }
3397
+ const headers = res.headers;
3398
+ try {
3399
+ const reader = res.body.getReader();
3400
+ const decoder = new TextDecoder();
3401
+ let buffer = "";
3402
+ let doneEvent = null;
3403
+ while (true) {
3404
+ const { done, value } = await reader.read();
3405
+ if (done) break;
3406
+ buffer += decoder.decode(value, { stream: true });
3407
+ const lines = buffer.split("\n");
3408
+ buffer = lines.pop() ?? "";
3409
+ for (const line of lines) {
3410
+ if (!line.startsWith("data: ")) continue;
3411
+ try {
3412
+ const event = JSON.parse(line.slice(6));
3413
+ if (event.type === "log") {
3414
+ options.onLog({
3415
+ value: event.value,
3416
+ tag: event.tag,
3417
+ ts: event.ts
3418
+ });
3419
+ } else if (event.type === "done") {
3420
+ doneEvent = {
3421
+ output: event.output,
3422
+ outputUrl: event.outputUrl,
3423
+ billingCost: event.billingCost,
3424
+ billingEvents: event.billingEvents
3425
+ };
3426
+ } else if (event.type === "error") {
3427
+ throw new MindStudioError(
3428
+ event.error || "Step execution failed",
3429
+ "step_error",
3430
+ 500
3431
+ );
3432
+ }
3433
+ } catch (err) {
3434
+ if (err instanceof MindStudioError) throw err;
3435
+ }
3436
+ }
3437
+ }
3438
+ if (buffer.startsWith("data: ")) {
3439
+ try {
3440
+ const event = JSON.parse(buffer.slice(6));
3441
+ if (event.type === "done") {
3442
+ doneEvent = {
3443
+ output: event.output,
3444
+ outputUrl: event.outputUrl,
3445
+ billingCost: event.billingCost,
3446
+ billingEvents: event.billingEvents
3447
+ };
3448
+ } else if (event.type === "error") {
3449
+ throw new MindStudioError(
3450
+ event.error || "Step execution failed",
3451
+ "step_error",
3452
+ 500
3453
+ );
3454
+ } else if (event.type === "log") {
3455
+ options.onLog({
3456
+ value: event.value,
3457
+ tag: event.tag,
3458
+ ts: event.ts
3459
+ });
3460
+ }
3461
+ } catch (err) {
3462
+ if (err instanceof MindStudioError) throw err;
3463
+ }
3464
+ }
3465
+ if (!doneEvent) {
3466
+ throw new MindStudioError(
3467
+ "Stream ended without a done event",
3468
+ "stream_error",
3469
+ 500
3470
+ );
3471
+ }
3472
+ let output;
3473
+ if (doneEvent.output != null) {
3474
+ output = doneEvent.output;
3475
+ } else if (doneEvent.outputUrl) {
3476
+ const s3Res = await fetch(doneEvent.outputUrl);
3477
+ if (!s3Res.ok) {
3478
+ throw new MindStudioError(
3479
+ `Failed to fetch output from S3: ${s3Res.status} ${s3Res.statusText}`,
3480
+ "output_fetch_error",
3481
+ s3Res.status
3482
+ );
3483
+ }
3484
+ const envelope = await s3Res.json();
3485
+ output = envelope.value;
3486
+ } else {
3487
+ output = void 0;
3488
+ }
3489
+ const returnedThreadId = headers.get("x-mindstudio-thread-id") ?? "";
3490
+ if (this._reuseThreadId && returnedThreadId) {
3491
+ this._threadId = returnedThreadId;
3492
+ }
3493
+ const returnedAppId = headers.get("x-mindstudio-app-id");
3494
+ if (!this._appId && returnedAppId) {
3495
+ this._appId = returnedAppId;
3496
+ }
3497
+ const remaining = headers.get("x-ratelimit-remaining");
3498
+ return {
3499
+ ...output,
3500
+ $appId: headers.get("x-mindstudio-app-id") ?? "",
3501
+ $threadId: returnedThreadId,
3502
+ $rateLimitRemaining: remaining != null ? parseInt(remaining, 10) : void 0,
3503
+ $billingCost: doneEvent.billingCost,
3504
+ $billingEvents: doneEvent.billingEvents
3505
+ };
3506
+ } finally {
3507
+ this._httpConfig.rateLimiter.release();
3508
+ }
3509
+ }
3510
+ /**
3511
+ * Execute multiple steps in parallel in a single request.
3512
+ *
3513
+ * All steps run in parallel on the server. Results are returned in the same
3514
+ * order as the input. Individual step failures do not affect other steps —
3515
+ * partial success is possible.
3516
+ *
3517
+ * ```ts
3518
+ * const { results } = await agent.executeStepBatch([
3519
+ * { stepType: 'generateImage', step: { prompt: 'a sunset' } },
3520
+ * { stepType: 'textToSpeech', step: { text: 'Hello world' } },
3521
+ * ]);
3522
+ * ```
3523
+ */
3524
+ async executeStepBatch(steps, options) {
3525
+ const threadId = options?.threadId ?? (this._reuseThreadId ? this._threadId : void 0);
3526
+ const { data } = await request(this._httpConfig, "POST", "/steps/execute-batch", {
3527
+ steps: steps.map((s) => ({ ...s, stepType: resolveStepType(s.stepType) })),
3528
+ ...options?.appId != null && { appId: options.appId },
3529
+ ...threadId != null && { threadId }
3530
+ });
3531
+ const results = await Promise.all(
3532
+ data.results.map(async (r) => {
3533
+ if (r.output != null) {
3534
+ return {
3535
+ stepType: r.stepType,
3536
+ output: r.output,
3537
+ billingCost: r.billingCost,
3538
+ error: r.error
3539
+ };
3540
+ }
3541
+ if (r.outputUrl) {
3542
+ const res = await fetch(r.outputUrl);
3543
+ if (!res.ok) {
3544
+ return {
3545
+ stepType: r.stepType,
3546
+ error: `Failed to fetch output from S3: ${res.status} ${res.statusText}`
3547
+ };
3548
+ }
3549
+ const envelope = await res.json();
3550
+ return {
3551
+ stepType: r.stepType,
3552
+ output: envelope.value,
3553
+ billingCost: r.billingCost
3554
+ };
3555
+ }
3556
+ return {
3557
+ stepType: r.stepType,
3558
+ billingCost: r.billingCost,
3559
+ error: r.error
3560
+ };
3561
+ })
3562
+ );
3563
+ if (this._reuseThreadId && data.threadId) {
3564
+ this._threadId = data.threadId;
3565
+ }
3566
+ return {
3567
+ results,
3568
+ totalBillingCost: data.totalBillingCost,
3569
+ appId: data.appId,
3570
+ threadId: data.threadId
3571
+ };
3572
+ }
3573
+ /**
3574
+ * Get the authenticated user's identity and organization info.
3575
+ *
3576
+ * ```ts
3577
+ * const info = await agent.getUserInfo();
3578
+ * console.log(info.displayName, info.organizationName);
3579
+ * ```
3580
+ */
3581
+ async getUserInfo() {
3582
+ const { data } = await request(
3583
+ this._httpConfig,
3584
+ "GET",
3585
+ "/account/userinfo"
3586
+ );
3587
+ return data;
3588
+ }
3589
+ /**
3590
+ * List all pre-built agents in the organization.
3591
+ *
3592
+ * ```ts
3593
+ * const { apps } = await agent.listAgents();
3594
+ * for (const app of apps) console.log(app.name, app.id);
3595
+ * ```
3596
+ */
3597
+ async listAgents() {
3598
+ const { data } = await request(
3599
+ this._httpConfig,
3600
+ "GET",
3601
+ "/agents/load"
3602
+ );
3603
+ return data;
3604
+ }
3605
+ /**
3606
+ * Run a pre-built agent and wait for the result.
3607
+ *
3608
+ * Uses async polling internally — the request returns immediately with a
3609
+ * callback token, then polls until the run completes or fails.
3610
+ *
3611
+ * ```ts
3612
+ * const result = await agent.runAgent({
3613
+ * appId: 'your-agent-id',
3614
+ * variables: { query: 'hello' },
3615
+ * });
3616
+ * console.log(result.result);
3617
+ * ```
3618
+ */
3619
+ async runAgent(options) {
3620
+ const pollInterval = options.pollIntervalMs ?? 1e3;
3621
+ const { data } = await request(this._httpConfig, "POST", "/agents/run", {
3622
+ appId: options.appId,
3623
+ async: true,
3624
+ ...options.variables != null && { variables: options.variables },
3625
+ ...options.workflow != null && { workflow: options.workflow },
3626
+ ...options.version != null && { version: options.version },
3627
+ ...options.includeBillingCost != null && {
3628
+ includeBillingCost: options.includeBillingCost
3629
+ },
3630
+ ...options.metadata != null && { metadata: options.metadata }
3631
+ });
3632
+ const token = data.callbackToken;
3633
+ const pollUrl = `${this._httpConfig.baseUrl}/developer/v2/agents/run/poll/${token}`;
3634
+ while (true) {
3635
+ await sleep2(pollInterval);
3636
+ const res = await fetch(pollUrl, {
3637
+ headers: { "User-Agent": "@mindstudio-ai/agent" }
3638
+ });
3639
+ if (res.status === 404) {
3640
+ throw new MindStudioError(
3641
+ "Poll token not found or expired.",
3642
+ "poll_token_expired",
3643
+ 404
3644
+ );
3645
+ }
3646
+ if (!res.ok) {
3647
+ const errorBody = await res.json().catch(() => ({}));
3648
+ throw new MindStudioError(
3649
+ errorBody.message ?? errorBody.error ?? `Poll request failed: ${res.status} ${res.statusText}`,
3650
+ errorBody.code ?? "poll_error",
3651
+ res.status,
3652
+ errorBody
3653
+ );
3654
+ }
3655
+ const poll = await res.json();
3656
+ if (poll.status === "pending") continue;
3657
+ if (poll.status === "error") {
3658
+ throw new MindStudioError(
3659
+ poll.error ?? "Agent run failed.",
3660
+ "agent_run_error",
3661
+ 500
3662
+ );
3663
+ }
3664
+ return poll.result;
3665
+ }
3666
+ }
3667
+ /** @internal Used by generated action methods. */
3668
+ _request(method, path, body) {
3669
+ return request(this._httpConfig, method, path, body);
3670
+ }
3671
+ // -------------------------------------------------------------------------
3672
+ // Helper methods — models
3673
+ // -------------------------------------------------------------------------
3674
+ /** List all available AI models. */
3675
+ async listModels() {
3676
+ const { data } = await request(
3677
+ this._httpConfig,
3678
+ "GET",
3679
+ "/helpers/models"
3680
+ );
3681
+ return data;
3682
+ }
3683
+ /** List AI models filtered by type. */
3684
+ async listModelsByType(modelType) {
3685
+ const { data } = await request(
3686
+ this._httpConfig,
3687
+ "GET",
3688
+ `/helpers/models/${modelType}`
3689
+ );
3690
+ return data;
3691
+ }
3692
+ /** List all available AI models (summary). Returns only id, name, type, and tags. */
3693
+ async listModelsSummary() {
3694
+ const { data } = await request(
3695
+ this._httpConfig,
3696
+ "GET",
3697
+ "/helpers/models-summary"
3698
+ );
3699
+ return data;
3700
+ }
3701
+ /** List AI models (summary) filtered by type. */
3702
+ async listModelsSummaryByType(modelType) {
3703
+ const { data } = await request(
3704
+ this._httpConfig,
3705
+ "GET",
3706
+ `/helpers/models-summary/${modelType}`
3707
+ );
3708
+ return data;
3709
+ }
3710
+ // -------------------------------------------------------------------------
3711
+ // Helper methods — OAuth connectors & connections
3712
+ // -------------------------------------------------------------------------
3713
+ /**
3714
+ * List available OAuth connector services (Slack, Google, HubSpot, etc.).
3715
+ *
3716
+ * These are third-party integrations from the MindStudio Connector Registry.
3717
+ * For most tasks, use actions directly instead.
3718
+ */
3719
+ async listConnectors() {
3720
+ const { data } = await request(
3721
+ this._httpConfig,
3722
+ "GET",
3723
+ "/helpers/connectors"
3724
+ );
3725
+ return data;
3726
+ }
3727
+ /** Get details for a single OAuth connector service. */
3728
+ async getConnector(serviceId) {
3729
+ const { data } = await request(
3730
+ this._httpConfig,
3731
+ "GET",
3732
+ `/helpers/connectors/${serviceId}`
3733
+ );
3734
+ return data;
3735
+ }
3736
+ /** Get the full configuration for an OAuth connector action, including input fields. */
3737
+ async getConnectorAction(serviceId, actionId) {
3738
+ const { data } = await request(
3739
+ this._httpConfig,
3740
+ "GET",
3741
+ `/helpers/connectors/${serviceId}/${actionId}`
3742
+ );
3743
+ return data;
3744
+ }
3745
+ /** List OAuth connections for the organization. These are authenticated third-party service links. */
3746
+ async listConnections() {
3747
+ const { data } = await request(
3748
+ this._httpConfig,
3749
+ "GET",
3750
+ "/helpers/connections"
3751
+ );
3752
+ return data;
3753
+ }
3754
+ // -------------------------------------------------------------------------
3755
+ // Helper methods — cost estimation
3756
+ // -------------------------------------------------------------------------
3757
+ /** Estimate the cost of executing an action before running it. */
3758
+ async estimateStepCost(stepType, step, options) {
3759
+ const { data } = await request(this._httpConfig, "POST", "/helpers/step-cost-estimate", {
3760
+ step: { type: resolveStepType(stepType), ...step },
3761
+ ...options
3762
+ });
3763
+ return data;
3764
+ }
3765
+ // -------------------------------------------------------------------------
3766
+ // Streaming
3767
+ // -------------------------------------------------------------------------
3768
+ /**
3769
+ * Send a stream chunk to the caller via SSE.
3770
+ *
3771
+ * When invoked from a method that was called with `stream: true`, chunks
3772
+ * are delivered in real-time as Server-Sent Events. When there is no active
3773
+ * stream (no `STREAM_ID`), calls are silently ignored — so it's safe to
3774
+ * call unconditionally.
3775
+ *
3776
+ * Accepts strings (sent as `type: 'token'`) or structured data (sent as
3777
+ * `type: 'data'`). The caller receives each chunk as an SSE event.
3778
+ *
3779
+ * @example
3780
+ * ```ts
3781
+ * // Stream text tokens
3782
+ * await agent.stream('Processing item 1...');
3783
+ *
3784
+ * // Stream structured data
3785
+ * await agent.stream({ progress: 50, currentItem: 'abc' });
3786
+ * ```
3787
+ */
3788
+ stream = async (data) => {
3789
+ if (!this._streamId) return;
3790
+ const url = `${this._httpConfig.baseUrl}/_internal/v2/stream-chunk`;
3791
+ const body = typeof data === "string" ? { streamId: this._streamId, type: "token", text: data } : { streamId: this._streamId, type: "data", data };
3792
+ const res = await fetch(url, {
3793
+ method: "POST",
3794
+ headers: {
3795
+ "Content-Type": "application/json",
3796
+ Authorization: this._token
3797
+ },
3798
+ body: JSON.stringify(body)
3799
+ });
3800
+ if (!res.ok) {
3801
+ const text = await res.text().catch(() => "");
3802
+ console.warn(`[mindstudio] stream chunk failed: ${res.status} ${text}`);
3803
+ }
3804
+ };
3805
+ // -------------------------------------------------------------------------
3806
+ // db + auth namespaces
3807
+ // -------------------------------------------------------------------------
3808
+ /**
3809
+ * The `auth` namespace — synchronous role-based access control.
3810
+ *
3811
+ * Provides the current user's identity and roles. All methods are
3812
+ * synchronous since the role map is preloaded during context hydration.
3813
+ *
3814
+ * **Important**: Context must be hydrated before accessing `auth`.
3815
+ * - Inside the MindStudio sandbox: automatic (populated from globals)
3816
+ * - Outside the sandbox: call `await agent.ensureContext()` first,
3817
+ * or access `auth` after any `db` operation (which auto-hydrates)
3818
+ *
3819
+ * @throws {MindStudioError} if context has not been hydrated yet
3820
+ *
3821
+ * @example
3822
+ * ```ts
3823
+ * await agent.ensureContext();
3824
+ * agent.auth.requireRole(Roles.admin);
3825
+ * const admins = agent.auth.getUsersByRole(Roles.admin);
3826
+ * ```
3827
+ */
3828
+ get auth() {
3829
+ if (!this._auth) {
3830
+ this._trySandboxHydration();
3831
+ }
3832
+ if (!this._auth) {
3833
+ throw new MindStudioError(
3834
+ "Auth context not yet loaded. Call `await agent.ensureContext()` or perform any db operation first (which auto-hydrates context). Inside the MindStudio sandbox, context is loaded automatically.",
3835
+ "context_not_loaded",
3836
+ 400
3837
+ );
3838
+ }
3839
+ return this._auth;
3840
+ }
3841
+ /**
3842
+ * The `db` namespace — chainable collection API over managed databases.
3843
+ *
3844
+ * Use `db.defineTable<T>(name)` to get a typed Table<T>, then call
3845
+ * collection methods (filter, sortBy, push, update, etc.) on it.
3846
+ *
3847
+ * Context is auto-hydrated on first query execution — you can safely
3848
+ * call `defineTable()` at module scope without triggering any HTTP.
3849
+ *
3850
+ * @example
3851
+ * ```ts
3852
+ * const Orders = agent.db.defineTable<Order>('orders');
3853
+ * const active = await Orders.filter(o => o.status === 'active').take(10);
3854
+ * ```
3855
+ */
3856
+ get db() {
3857
+ if (!this._db) {
3858
+ this._trySandboxHydration();
3859
+ }
3860
+ if (this._db) return this._db;
3861
+ return this._createLazyDb();
3862
+ }
3863
+ /**
3864
+ * Hydrate the app context (auth + database metadata). This must be
3865
+ * called before using `auth` synchronously. For `db`, hydration happens
3866
+ * automatically on first query.
3867
+ *
3868
+ * Context is fetched once and cached for the instance's lifetime.
3869
+ * Calling `ensureContext()` multiple times is safe (no-op after first).
3870
+ *
3871
+ * Context sources (checked in order):
3872
+ * 1. Sandbox globals (`globalThis.ai.auth`, `globalThis.ai.databases`)
3873
+ * 2. HTTP: `GET /developer/v2/helpers/app-context?appId={appId}`
3874
+ *
3875
+ * @throws {MindStudioError} if no `appId` is available
3876
+ *
3877
+ * @example
3878
+ * ```ts
3879
+ * await agent.ensureContext();
3880
+ * // auth is now available synchronously
3881
+ * agent.auth.requireRole(Roles.admin);
3882
+ * ```
3883
+ */
3884
+ async ensureContext() {
3885
+ if (this._context) return;
3886
+ if (!this._contextPromise) {
3887
+ this._contextPromise = this._hydrateContext();
3888
+ }
3889
+ await this._contextPromise;
3890
+ }
3891
+ /**
3892
+ * @internal Fetch and cache app context, then create auth + db instances.
3893
+ *
3894
+ * In managed mode (CALLBACK_TOKEN), the platform resolves the app from
3895
+ * the token — no appId needed. With an API key, appId is required.
3896
+ */
3897
+ async _hydrateContext() {
3898
+ if (!this._appId && this._authType !== "internal") {
3899
+ throw new MindStudioError(
3900
+ "No app ID available for context resolution. Pass `appId` to the constructor, set the MINDSTUDIO_APP_ID environment variable, or make a step execution call first (which auto-detects the app ID).",
3901
+ "missing_app_id",
3902
+ 400
3903
+ );
3904
+ }
3905
+ const context = await this.getAppContext(this._appId);
3906
+ this._applyContext(context);
3907
+ }
3908
+ /**
3909
+ * @internal Apply a resolved context object — creates AuthContext and Db.
3910
+ * Used by both the HTTP path and sandbox hydration.
3911
+ */
3912
+ _applyContext(context) {
3913
+ this._context = context;
3914
+ this._auth = new AuthContext(context.auth);
3915
+ this._db = createDb(
3916
+ context.databases,
3917
+ this._executeDbBatch.bind(this),
3918
+ context.authConfig,
3919
+ this._syncRoles.bind(this)
3920
+ );
3921
+ }
3922
+ /**
3923
+ * @internal Try to hydrate context synchronously from sandbox globals.
3924
+ * Called in the constructor when CALLBACK_TOKEN auth is detected.
3925
+ *
3926
+ * The MindStudio sandbox pre-populates `globalThis.ai` with:
3927
+ * - `ai.auth`: { userId, roleAssignments[] }
3928
+ * - `ai.databases`: [{ id, name, tables[] }]
3929
+ */
3930
+ _trySandboxHydration() {
3931
+ const ai = globalThis.ai;
3932
+ if (ai?.auth && ai?.databases) {
3933
+ this._applyContext({
3934
+ auth: ai.auth,
3935
+ databases: ai.databases,
3936
+ authConfig: ai.authConfig
3937
+ });
3938
+ }
3939
+ }
3940
+ /**
3941
+ * @internal Execute a batch of SQL queries against a managed database.
3942
+ * Used as the `executeBatch` callback for Table/Query instances.
3943
+ *
3944
+ * Calls `POST /_internal/v2/db/query` directly with the hook token
3945
+ * (raw, no Bearer prefix). All queries run on a single SQLite connection,
3946
+ * enabling RETURNING clauses and multi-statement batches.
3947
+ */
3948
+ async _executeDbBatch(databaseId, queries) {
3949
+ const url = `${this._httpConfig.baseUrl}/_internal/v2/db/query`;
3950
+ const res = await fetch(url, {
3951
+ method: "POST",
3952
+ headers: {
3953
+ "Content-Type": "application/json",
3954
+ Authorization: this._token
3955
+ },
3956
+ body: JSON.stringify({ databaseId, queries })
3957
+ });
3958
+ if (!res.ok) {
3959
+ let message = `Database query failed: ${res.status} ${res.statusText}`;
3960
+ let code = "db_query_error";
3961
+ try {
3962
+ const text = await res.text();
3963
+ try {
3964
+ const body = JSON.parse(text);
3965
+ const errMsg = body.error ?? body.message ?? body.details;
3966
+ if (errMsg) message = errMsg;
3967
+ if (body.code) code = body.code;
3968
+ } catch {
3969
+ if (text && text.length < 500) message = text;
3970
+ }
3971
+ } catch {
3972
+ }
3973
+ throw new MindStudioError(
3974
+ `[db] ${message}`,
3975
+ code,
3976
+ res.status
3977
+ );
3978
+ }
3979
+ const data = await res.json();
3980
+ return data.results;
3981
+ }
3982
+ /**
3983
+ * @internal Sync a user's roles to the platform after a successful
3984
+ * auth table write. Calls POST /_internal/v2/auth/sync-user.
3985
+ * Fire-and-forget: errors are caught and logged, never propagated.
3986
+ */
3987
+ async _syncRoles(userId, roles) {
3988
+ try {
3989
+ const url = `${this._httpConfig.baseUrl}/_internal/v2/auth/sync-user`;
3990
+ const res = await fetch(url, {
3991
+ method: "POST",
3992
+ headers: {
3993
+ "Content-Type": "application/json",
3994
+ Authorization: this._token
3995
+ },
3996
+ body: JSON.stringify({
3997
+ appId: this._appId,
3998
+ userId,
3999
+ roles
4000
+ })
4001
+ });
4002
+ if (!res.ok) {
4003
+ const text = await res.text().catch(() => "");
4004
+ console.warn(
4005
+ `[mindstudio] Failed to sync roles for user ${userId}: ${res.status} ${text}`
4006
+ );
4007
+ }
4008
+ } catch (err) {
4009
+ console.warn(
4010
+ `[mindstudio] Failed to sync roles for user ${userId}:`,
4011
+ err
4012
+ );
4013
+ }
4014
+ }
4015
+ /**
4016
+ * @internal Create a lazy Db proxy that auto-hydrates context.
4017
+ *
4018
+ * defineTable() returns Table instances immediately (no async needed).
4019
+ * But the Table's executeBatch callback is wrapped to call ensureContext()
4020
+ * before the first query, so context is fetched lazily.
4021
+ */
4022
+ _createLazyDb() {
4023
+ const agent = this;
4024
+ return {
4025
+ defineTable(name, options) {
4026
+ const databaseHint = options?.database;
4027
+ const tableConfig = {
4028
+ databaseId: "",
4029
+ tableName: name,
4030
+ columns: [],
4031
+ unique: options?.unique,
4032
+ defaults: options?.defaults,
4033
+ executeBatch: async (queries) => {
4034
+ await agent.ensureContext();
4035
+ const ac = agent._context.authConfig;
4036
+ if (ac && ac.table === name && !tableConfig.managedColumns) {
4037
+ tableConfig.managedColumns = ac.columns;
4038
+ if (ac.columns.roles) {
4039
+ tableConfig.syncRoles = agent._syncRoles.bind(agent);
4040
+ }
4041
+ }
4042
+ const databases = agent._context.databases;
4043
+ let targetDb;
4044
+ if (databaseHint) {
4045
+ targetDb = databases.find(
4046
+ (d) => d.id === databaseHint || d.name === databaseHint
4047
+ );
4048
+ } else {
4049
+ targetDb = databases.find(
4050
+ (d) => d.tables.some((t) => t.name === name)
4051
+ );
4052
+ }
4053
+ const databaseId = targetDb?.id ?? databases[0]?.id ?? "";
4054
+ return agent._executeDbBatch(databaseId, queries);
4055
+ }
4056
+ };
4057
+ return new Table(tableConfig);
4058
+ },
4059
+ // Time helpers work without context
4060
+ now: () => Date.now(),
4061
+ days: (n) => n * 864e5,
4062
+ hours: (n) => n * 36e5,
4063
+ minutes: (n) => n * 6e4,
4064
+ ago: (ms) => Date.now() - ms,
4065
+ fromNow: (ms) => Date.now() + ms,
4066
+ // Batch needs context — hydrate first, then delegate to real db
4067
+ batch: ((...queries) => {
4068
+ return (async () => {
4069
+ await agent.ensureContext();
4070
+ return agent._db.batch(...queries);
4071
+ })();
4072
+ })
4073
+ };
4074
+ }
4075
+ // -------------------------------------------------------------------------
4076
+ // Helper methods — user resolution
4077
+ // -------------------------------------------------------------------------
4078
+ /**
4079
+ * Resolve a single user ID to display info (name, email, profile picture).
4080
+ *
4081
+ * Use this when you have a `User`-typed field value and need the person's
4082
+ * display name, email, or avatar. Returns null if the user ID is not found.
4083
+ *
4084
+ * Also available as a top-level import:
4085
+ * ```ts
4086
+ * import { resolveUser } from '@mindstudio-ai/agent';
4087
+ * ```
4088
+ *
4089
+ * @param userId - The user ID to resolve (a `User` branded string or plain UUID)
4090
+ * @returns Resolved user info, or null if not found
4091
+ *
4092
+ * @example
4093
+ * ```ts
4094
+ * const user = await agent.resolveUser(order.requestedBy);
4095
+ * if (user) {
4096
+ * console.log(user.name); // "Jane Smith"
4097
+ * console.log(user.email); // "jane@example.com"
4098
+ * console.log(user.profilePictureUrl); // "https://..." or null
4099
+ * }
4100
+ * ```
4101
+ */
4102
+ async resolveUser(userId) {
4103
+ const { users } = await this.resolveUsers([userId]);
4104
+ return users[0] ?? null;
4105
+ }
4106
+ /**
4107
+ * Resolve multiple user IDs to display info in a single request.
4108
+ * Maximum 100 user IDs per request.
4109
+ *
4110
+ * Use this for batch resolution when you have multiple user references
4111
+ * to display (e.g. all approvers on a purchase order, all team members).
4112
+ *
4113
+ * @param userIds - Array of user IDs to resolve (max 100)
4114
+ * @returns Object with `users` array of resolved user info
4115
+ *
4116
+ * @example
4117
+ * ```ts
4118
+ * // Resolve all approvers at once
4119
+ * const approverIds = approvals.map(a => a.assignedTo);
4120
+ * const { users } = await agent.resolveUsers(approverIds);
4121
+ *
4122
+ * for (const u of users) {
4123
+ * console.log(`${u.name} (${u.email})`);
4124
+ * }
4125
+ * ```
4126
+ */
4127
+ async resolveUsers(userIds) {
4128
+ const { data } = await request(
4129
+ this._httpConfig,
4130
+ "POST",
4131
+ "/helpers/resolve-users",
4132
+ { userIds }
4133
+ );
4134
+ return data;
4135
+ }
4136
+ // -------------------------------------------------------------------------
4137
+ // App context
4138
+ // -------------------------------------------------------------------------
4139
+ /**
4140
+ * Get auth and database context for an app.
4141
+ *
4142
+ * Returns role assignments and managed database schemas. Useful for
4143
+ * hydrating `auth` and `db` namespaces when running outside the sandbox.
4144
+ *
4145
+ * When called with a CALLBACK_TOKEN (managed mode), `appId` is optional —
4146
+ * the platform resolves the app from the token. With an API key, `appId`
4147
+ * is required.
4148
+ *
4149
+ * ```ts
4150
+ * const ctx = await agent.getAppContext('your-app-id');
4151
+ * console.log(ctx.auth.roleAssignments, ctx.databases);
4152
+ * ```
4153
+ */
4154
+ async getAppContext(appId) {
4155
+ const query = appId ? `?appId=${encodeURIComponent(appId)}` : "";
4156
+ const { data } = await request(
4157
+ this._httpConfig,
4158
+ "GET",
4159
+ `/helpers/app-context${query}`
4160
+ );
4161
+ return data;
4162
+ }
4163
+ // -------------------------------------------------------------------------
4164
+ // Account methods
4165
+ // -------------------------------------------------------------------------
4166
+ /** Update the display name of the authenticated user/agent. */
4167
+ async changeName(displayName) {
4168
+ await request(this._httpConfig, "POST", "/account/change-name", {
4169
+ name: displayName
4170
+ });
4171
+ }
4172
+ /** Update the profile picture of the authenticated user/agent. */
4173
+ async changeProfilePicture(url) {
4174
+ await request(this._httpConfig, "POST", "/account/change-profile-picture", {
4175
+ url
4176
+ });
4177
+ }
4178
+ /**
4179
+ * Upload a file to the MindStudio CDN.
4180
+ *
4181
+ * Gets a signed upload URL, PUTs the file content, and returns the
4182
+ * permanent public URL.
4183
+ */
4184
+ async uploadFile(content, options) {
4185
+ const { data } = await request(
4186
+ this._httpConfig,
4187
+ "POST",
4188
+ "/account/upload",
4189
+ {
4190
+ extension: options.extension,
4191
+ ...options.type != null && { type: options.type }
4192
+ }
4193
+ );
4194
+ const buf = content.buffer.slice(
4195
+ content.byteOffset,
4196
+ content.byteOffset + content.byteLength
4197
+ );
4198
+ const res = await fetch(data.uploadUrl, {
4199
+ method: "PUT",
4200
+ body: buf,
4201
+ headers: options.type ? { "Content-Type": options.type } : {}
4202
+ });
4203
+ if (!res.ok) {
4204
+ const errorBody = await res.json().catch(() => ({}));
4205
+ throw new MindStudioError(
4206
+ errorBody.message ?? errorBody.error ?? `Upload failed: ${res.status} ${res.statusText}`,
4207
+ errorBody.code ?? "upload_error",
4208
+ res.status,
4209
+ errorBody
4210
+ );
4211
+ }
4212
+ return { url: data.url };
4213
+ }
4214
+ };
4215
+ function sleep2(ms) {
4216
+ return new Promise((resolve) => setTimeout(resolve, ms));
4217
+ }
4218
+ applyStepMethods(MindStudioAgent);
4219
+ function resolveStepType(name) {
4220
+ const meta = stepMetadata[name];
4221
+ return meta ? meta.stepType : name;
4222
+ }
4223
+ function resolveToken(provided, config) {
4224
+ if (process.env.CALLBACK_TOKEN)
4225
+ return { token: process.env.CALLBACK_TOKEN, authType: "internal" };
4226
+ if (provided) return { token: provided, authType: "apiKey" };
4227
+ if (process.env.MINDSTUDIO_API_KEY)
4228
+ return { token: process.env.MINDSTUDIO_API_KEY, authType: "apiKey" };
4229
+ if (config?.apiKey)
4230
+ return { token: config.apiKey, authType: "apiKey" };
4231
+ throw new MindStudioError(
4232
+ "No API key provided. Run `mindstudio login`, pass `apiKey` to the constructor, or set the MINDSTUDIO_API_KEY environment variable.",
4233
+ "missing_api_key",
4234
+ 401
4235
+ );
4236
+ }
4237
+
4238
+ // src/generated/snippets.ts
4239
+ var monacoSnippets = {
4240
+ "activeCampaignAddNote": { fields: [["contactId", "string"], ["note", "string"]], outputKeys: [] },
4241
+ "activeCampaignCreateContact": { fields: [["email", "string"], ["firstName", "string"], ["lastName", "string"], ["phone", "string"], ["accountId", "string"], ["customFields", "object"]], outputKeys: ["contactId"] },
4242
+ "addSubtitlesToVideo": { fields: [["videoUrl", "string"], ["language", "string"], ["fontName", "string"], ["fontSize", "number"], ["fontWeight", ["normal", "bold", "black"]], ["fontColor", ["white", "black", "red", "green", "blue", "yellow", "orange", "purple", "pink", "brown", "gray", "cyan", "magenta"]], ["highlightColor", ["white", "black", "red", "green", "blue", "yellow", "orange", "purple", "pink", "brown", "gray", "cyan", "magenta"]], ["strokeWidth", "number"], ["strokeColor", ["black", "white", "red", "green", "blue", "yellow", "orange", "purple", "pink", "brown", "gray", "cyan", "magenta"]], ["backgroundColor", ["black", "white", "red", "green", "blue", "yellow", "orange", "purple", "pink", "brown", "gray", "cyan", "magenta", "none"]], ["backgroundOpacity", "number"], ["position", ["top", "center", "bottom"]], ["yOffset", "number"], ["wordsPerSubtitle", "number"], ["enableAnimation", "boolean"]], outputKeys: ["videoUrl"] },
4243
+ "airtableCreateUpdateRecord": { fields: [["baseId", "string"], ["tableId", "string"], ["fields", "string"], ["recordData", "object"]], outputKeys: ["recordId"] },
4244
+ "airtableDeleteRecord": { fields: [["baseId", "string"], ["tableId", "string"], ["recordId", "string"]], outputKeys: ["deleted"] },
4245
+ "airtableGetRecord": { fields: [["baseId", "string"], ["tableId", "string"], ["recordId", "string"]], outputKeys: ["record"] },
4246
+ "airtableGetTableRecords": { fields: [["baseId", "string"], ["tableId", "string"]], outputKeys: ["records"] },
4247
+ "analyzeImage": { fields: [["prompt", "string"], ["imageUrl", "string"]], outputKeys: ["analysis"] },
4248
+ "analyzeVideo": { fields: [["prompt", "string"], ["videoUrl", "string"]], outputKeys: ["analysis"] },
4249
+ "captureThumbnail": { fields: [["videoUrl", "string"], ["at", "string"]], outputKeys: ["thumbnailUrl"] },
4250
+ "checkAppRole": { fields: [["roleName", "string"]], outputKeys: ["hasRole", "userRoles"] },
4251
+ "codaCreateUpdatePage": { fields: [["pageData", "object"]], outputKeys: ["pageId"] },
4252
+ "codaCreateUpdateRow": { fields: [["docId", "string"], ["tableId", "string"], ["rowData", "object"]], outputKeys: ["rowId"] },
4253
+ "codaFindRow": { fields: [["docId", "string"], ["tableId", "string"], ["rowData", "object"]], outputKeys: ["row"] },
4254
+ "codaGetPage": { fields: [["docId", "string"], ["pageId", "string"]], outputKeys: ["content"] },
4255
+ "codaGetTableRows": { fields: [["docId", "string"], ["tableId", "string"]], outputKeys: ["rows"] },
4256
+ "convertPdfToImages": { fields: [["pdfUrl", "string"]], outputKeys: ["imageUrls"] },
4257
+ "createDataSource": { fields: [["name", "string"]], outputKeys: [] },
4258
+ "createGmailDraft": { fields: [["to", "string"], ["subject", "string"], ["message", "string"], ["messageType", ["plain", "html", "markdown"]]], outputKeys: ["draftId"] },
4259
+ "createGoogleCalendarEvent": { fields: [["summary", "string"], ["startDateTime", "string"], ["endDateTime", "string"]], outputKeys: ["eventId", "htmlLink"] },
4260
+ "createGoogleDoc": { fields: [["title", "string"], ["text", "string"], ["textType", ["plain", "html", "markdown"]]], outputKeys: ["documentUrl"] },
4261
+ "createGoogleSheet": { fields: [["title", "string"], ["text", "string"]], outputKeys: ["spreadsheetUrl"] },
4262
+ "deleteDataSource": { fields: [["dataSourceId", "string"]], outputKeys: [] },
4263
+ "deleteDataSourceDocument": { fields: [["dataSourceId", "string"], ["documentId", "string"]], outputKeys: [] },
4264
+ "deleteGmailEmail": { fields: [["messageId", "string"]], outputKeys: [] },
4265
+ "deleteGoogleCalendarEvent": { fields: [["eventId", "string"]], outputKeys: [] },
4266
+ "deleteGoogleSheetRows": { fields: [["documentId", "string"], ["startRow", "string"], ["endRow", "string"]], outputKeys: [] },
4267
+ "detectChanges": { fields: [["mode", ["ai", "comparison"]], ["input", "string"]], outputKeys: ["hasChanged", "currentValue", "previousValue", "isFirstRun"] },
4268
+ "detectPII": { fields: [["input", "string"], ["language", "string"], ["entities", "array"]], outputKeys: ["detected", "detections"] },
4269
+ "discordEditMessage": { fields: [["botToken", "string"], ["channelId", "string"], ["messageId", "string"], ["text", "string"]], outputKeys: [] },
4270
+ "discordSendFollowUp": { fields: [["applicationId", "string"], ["interactionToken", "string"], ["text", "string"]], outputKeys: ["messageId"] },
4271
+ "discordSendMessage": { fields: [["mode", ["edit", "send"]], ["text", "string"]], outputKeys: [] },
4272
+ "downloadVideo": { fields: [["videoUrl", "string"], ["format", ["mp4", "mp3"]]], outputKeys: ["videoUrl"] },
4273
+ "enhanceImageGenerationPrompt": { fields: [["initialPrompt", "string"], ["includeNegativePrompt", "boolean"], ["systemPrompt", "string"]], outputKeys: ["prompt"] },
4274
+ "enhanceVideoGenerationPrompt": { fields: [["initialPrompt", "string"], ["includeNegativePrompt", "boolean"], ["systemPrompt", "string"]], outputKeys: ["prompt"] },
4275
+ "enrichPerson": { fields: [["params", "object"]], outputKeys: ["data"] },
4276
+ "extractAudioFromVideo": { fields: [["videoUrl", "string"]], outputKeys: ["audioUrl"] },
4277
+ "extractText": { fields: [["url", "string"]], outputKeys: ["text"] },
4278
+ "fetchDataSourceDocument": { fields: [["dataSourceId", "string"], ["documentId", "string"]], outputKeys: [] },
4279
+ "fetchGoogleDoc": { fields: [["documentId", "string"], ["exportType", ["html", "markdown", "json", "plain"]]], outputKeys: ["content"] },
4280
+ "fetchGoogleSheet": { fields: [["spreadsheetId", "string"], ["range", "string"], ["exportType", ["csv", "json"]]], outputKeys: ["content"] },
4281
+ "fetchSlackChannelHistory": { fields: [["channelId", "string"]], outputKeys: ["messages"] },
4282
+ "fetchYoutubeCaptions": { fields: [["videoUrl", "string"], ["exportType", ["text", "json"]], ["language", "string"]], outputKeys: ["transcripts"] },
4283
+ "fetchYoutubeChannel": { fields: [["channelUrl", "string"]], outputKeys: [] },
4284
+ "fetchYoutubeComments": { fields: [["videoUrl", "string"], ["exportType", ["text", "json"]], ["limitPages", "string"]], outputKeys: ["comments"] },
4285
+ "fetchYoutubeVideo": { fields: [["videoUrl", "string"]], outputKeys: [] },
4286
+ "generateAsset": { fields: [["source", "string"], ["sourceType", ["html", "markdown", "spa", "raw", "dynamic", "customInterface"]], ["outputFormat", ["pdf", "png", "html", "mp4", "openGraph"]], ["pageSize", ["full", "letter", "A4", "custom"]], ["testData", "object"]], outputKeys: ["url"] },
4287
+ "generateChart": { fields: [["chart", "object"]], outputKeys: ["chartUrl"] },
4288
+ "generateImage": { fields: [["prompt", "string"]], outputKeys: ["imageUrl"] },
4289
+ "generateLipsync": { fields: [], outputKeys: [] },
4290
+ "generateMusic": { fields: [["text", "string"]], outputKeys: [] },
4291
+ "generatePdf": { fields: [["source", "string"], ["sourceType", ["html", "markdown", "spa", "raw", "dynamic", "customInterface"]], ["outputFormat", ["pdf", "png", "html", "mp4", "openGraph"]], ["pageSize", ["full", "letter", "A4", "custom"]], ["testData", "object"]], outputKeys: ["url"] },
4292
+ "generateStaticVideoFromImage": { fields: [["imageUrl", "string"], ["duration", "string"]], outputKeys: ["videoUrl"] },
4293
+ "generateText": { fields: [["message", "string"]], outputKeys: ["content"] },
4294
+ "generateVideo": { fields: [["prompt", "string"]], outputKeys: ["videoUrl"] },
4295
+ "getGmailAttachments": { fields: [["messageId", "string"]], outputKeys: [] },
4296
+ "getGmailDraft": { fields: [["draftId", "string"]], outputKeys: ["draftId", "messageId", "subject", "to", "from", "body"] },
4297
+ "getGmailEmail": { fields: [["messageId", "string"]], outputKeys: ["messageId", "subject", "from", "to", "date", "body", "labels"] },
4298
+ "getGmailUnreadCount": { fields: [], outputKeys: [] },
4299
+ "getGoogleCalendarEvent": { fields: [["eventId", "string"], ["exportType", ["json", "text"]]], outputKeys: ["event"] },
4300
+ "getGoogleDriveFile": { fields: [["fileId", "string"]], outputKeys: ["url", "name", "mimeType", "size"] },
4301
+ "getGoogleSheetInfo": { fields: [["documentId", "string"]], outputKeys: ["title", "sheets"] },
4302
+ "getMediaMetadata": { fields: [["mediaUrl", "string"]], outputKeys: ["metadata"] },
4303
+ "httpRequest": { fields: [["url", "string"], ["method", "string"], ["headers", "object"], ["queryParams", "object"], ["body", "string"], ["bodyItems", "object"], ["contentType", ["none", "application/json", "application/x-www-form-urlencoded", "multipart/form-data", "custom"]], ["customContentType", "string"]], outputKeys: ["ok", "status", "statusText", "response"] },
4304
+ "hubspotCreateCompany": { fields: [["company", "object"], ["enabledProperties", "array"]], outputKeys: ["companyId"] },
4305
+ "hubspotCreateContact": { fields: [["contact", "object"], ["enabledProperties", "array"], ["companyDomain", "string"]], outputKeys: ["contactId"] },
4306
+ "hubspotGetCompany": { fields: [["searchBy", ["domain", "id"]], ["companyDomain", "string"], ["companyId", "string"], ["additionalProperties", "array"]], outputKeys: ["company"] },
4307
+ "hubspotGetContact": { fields: [["searchBy", ["email", "id"]], ["contactEmail", "string"], ["contactId", "string"], ["additionalProperties", "array"]], outputKeys: ["contact"] },
4308
+ "hunterApiCompanyEnrichment": { fields: [["domain", "string"]], outputKeys: ["data"] },
4309
+ "hunterApiDomainSearch": { fields: [["domain", "string"]], outputKeys: ["data"] },
4310
+ "hunterApiEmailFinder": { fields: [["domain", "string"], ["firstName", "string"], ["lastName", "string"]], outputKeys: ["data"] },
4311
+ "hunterApiEmailVerification": { fields: [["email", "string"]], outputKeys: ["data"] },
4312
+ "hunterApiPersonEnrichment": { fields: [["email", "string"]], outputKeys: ["data"] },
4313
+ "imageFaceSwap": { fields: [["imageUrl", "string"], ["faceImageUrl", "string"], ["engine", "string"]], outputKeys: ["imageUrl"] },
4314
+ "imageRemoveWatermark": { fields: [["imageUrl", "string"], ["engine", "string"]], outputKeys: ["imageUrl"] },
4315
+ "insertVideoClips": { fields: [["baseVideoUrl", "string"], ["overlayVideos", "array"]], outputKeys: ["videoUrl"] },
4316
+ "listDataSources": { fields: [], outputKeys: [] },
4317
+ "listGmailDrafts": { fields: [["exportType", ["json", "text"]]], outputKeys: ["drafts"] },
4318
+ "listGmailLabels": { fields: [], outputKeys: [] },
4319
+ "listGoogleCalendarEvents": { fields: [["limit", "number"], ["exportType", ["json", "text"]]], outputKeys: ["events"] },
4320
+ "listGoogleDriveFiles": { fields: [["exportType", ["json", "text"]]], outputKeys: ["files"] },
4321
+ "listRecentGmailEmails": { fields: [["exportType", ["json", "text"]], ["limit", "string"]], outputKeys: [] },
4322
+ "logic": { fields: [["context", "string"], ["cases", "array"]], outputKeys: ["selectedCase"] },
4323
+ "makeDotComRunScenario": { fields: [["webhookUrl", "string"], ["input", "object"]], outputKeys: ["data"] },
4324
+ "mergeAudio": { fields: [["mp3Urls", "array"]], outputKeys: ["audioUrl"] },
4325
+ "mergeVideos": { fields: [["videoUrls", "array"]], outputKeys: ["videoUrl"] },
4326
+ "mixAudioIntoVideo": { fields: [["videoUrl", "string"], ["audioUrl", "string"], ["options", "object"]], outputKeys: ["videoUrl"] },
4327
+ "muteVideo": { fields: [["videoUrl", "string"]], outputKeys: ["videoUrl"] },
4328
+ "n8nRunNode": { fields: [["method", "string"], ["authentication", ["none", "basic", "string"]], ["user", "string"], ["password", "string"], ["webhookUrl", "string"], ["input", "object"]], outputKeys: ["data"] },
4329
+ "notionCreatePage": { fields: [["pageId", "string"], ["content", "string"], ["title", "string"]], outputKeys: ["pageId", "pageUrl"] },
4330
+ "notionUpdatePage": { fields: [["pageId", "string"], ["content", "string"], ["mode", ["append", "overwrite"]]], outputKeys: ["pageId", "pageUrl"] },
4331
+ "peopleSearch": { fields: [["smartQuery", "string"], ["enrichPeople", "boolean"], ["enrichOrganizations", "boolean"], ["limit", "string"], ["page", "string"], ["params", "object"]], outputKeys: ["results"] },
4332
+ "postToLinkedIn": { fields: [["message", "string"], ["visibility", ["PUBLIC", "CONNECTIONS"]]], outputKeys: [] },
4333
+ "postToSlackChannel": { fields: [["channelId", "string"], ["messageType", ["string", "blocks"]], ["message", "string"]], outputKeys: [] },
4334
+ "postToX": { fields: [["text", "string"]], outputKeys: [] },
4335
+ "postToZapier": { fields: [["webhookUrl", "string"], ["input", "object"]], outputKeys: ["data"] },
4336
+ "queryAppDatabase": { fields: [["databaseId", "string"], ["sql", "string"]], outputKeys: ["rows", "changes"] },
4337
+ "queryDataSource": { fields: [["dataSourceId", "string"], ["query", "string"], ["maxResults", "number"]], outputKeys: ["text", "chunks", "query", "citations", "latencyMs"] },
4338
+ "queryExternalDatabase": { fields: [["query", "string"], ["outputFormat", ["json", "csv"]]], outputKeys: ["data"] },
4339
+ "redactPII": { fields: [["input", "string"], ["language", "string"], ["entities", "array"]], outputKeys: ["text"] },
4340
+ "removeBackgroundFromImage": { fields: [["imageUrl", "string"]], outputKeys: ["imageUrl"] },
4341
+ "replyToGmailEmail": { fields: [["messageId", "string"], ["message", "string"], ["messageType", ["plain", "html", "markdown"]]], outputKeys: ["messageId"] },
4342
+ "resizeVideo": { fields: [["videoUrl", "string"], ["mode", ["fit", "exact"]]], outputKeys: ["videoUrl"] },
4343
+ "runFromConnectorRegistry": { fields: [["actionId", "string"], ["displayName", "string"], ["icon", "string"], ["configurationValues", "object"]], outputKeys: ["data"] },
4344
+ "runPackagedWorkflow": { fields: [["appId", "string"], ["workflowId", "string"], ["inputVariables", "object"], ["outputVariables", "object"], ["name", "string"]], outputKeys: ["data"] },
4345
+ "scrapeFacebookPage": { fields: [["pageUrl", "string"]], outputKeys: ["data"] },
4346
+ "scrapeFacebookPosts": { fields: [["pageUrl", "string"]], outputKeys: ["data"] },
4347
+ "scrapeInstagramComments": { fields: [["postUrl", "string"], ["resultsLimit", "string"]], outputKeys: ["data"] },
4348
+ "scrapeInstagramMentions": { fields: [["profileUrl", "string"], ["resultsLimit", "string"]], outputKeys: ["data"] },
4349
+ "scrapeInstagramPosts": { fields: [["profileUrl", "string"], ["resultsLimit", "string"], ["onlyPostsNewerThan", "string"]], outputKeys: ["data"] },
4350
+ "scrapeInstagramProfile": { fields: [["profileUrl", "string"]], outputKeys: ["data"] },
4351
+ "scrapeInstagramReels": { fields: [["profileUrl", "string"], ["resultsLimit", "string"]], outputKeys: ["data"] },
4352
+ "scrapeLinkedInCompany": { fields: [["url", "string"]], outputKeys: ["company"] },
4353
+ "scrapeLinkedInProfile": { fields: [["url", "string"]], outputKeys: ["profile"] },
4354
+ "scrapeMetaThreadsProfile": { fields: [["profileUrl", "string"]], outputKeys: ["data"] },
4355
+ "scrapeUrl": { fields: [["url", "string"]], outputKeys: ["content"] },
4356
+ "scrapeXPost": { fields: [["url", "string"]], outputKeys: ["post"] },
4357
+ "scrapeXProfile": { fields: [["url", "string"]], outputKeys: ["profile"] },
4358
+ "screenshotUrl": { fields: [["url", "string"]], outputKeys: ["screenshotUrl"] },
4359
+ "searchGmailEmails": { fields: [["query", "string"], ["exportType", ["json", "text"]], ["limit", "string"]], outputKeys: ["emails"] },
4360
+ "searchGoogle": { fields: [["query", "string"], ["exportType", ["text", "json"]]], outputKeys: ["results"] },
4361
+ "searchGoogleCalendarEvents": { fields: [["exportType", ["json", "text"]]], outputKeys: ["events"] },
4362
+ "searchGoogleDrive": { fields: [["query", "string"], ["exportType", ["json", "text"]]], outputKeys: ["files"] },
4363
+ "searchGoogleImages": { fields: [["query", "string"], ["exportType", ["text", "json"]]], outputKeys: ["images"] },
4364
+ "searchGoogleNews": { fields: [["text", "string"], ["exportType", ["text", "json"]]], outputKeys: ["articles"] },
4365
+ "searchGoogleTrends": { fields: [["text", "string"], ["hl", "string"], ["geo", "string"], ["data_type", ["TIMESERIES", "GEO_MAP", "GEO_MAP_0", "RELATED_TOPICS", "RELATED_QUERIES"]], ["cat", "string"], ["date", "string"], ["ts", "string"]], outputKeys: ["trends"] },
4366
+ "searchPerplexity": { fields: [["query", "string"], ["exportType", ["text", "json"]]], outputKeys: ["results"] },
4367
+ "searchXPosts": { fields: [["query", "string"], ["scope", ["recent", "all"]], ["options", "object"]], outputKeys: ["posts"] },
4368
+ "searchYoutube": { fields: [["query", "string"], ["limitPages", "string"], ["filter", "string"], ["filterType", "string"]], outputKeys: ["results"] },
4369
+ "searchYoutubeTrends": { fields: [["bp", ["now", "music", "gaming", "films"]], ["hl", "string"], ["gl", "string"]], outputKeys: [] },
4370
+ "sendEmail": { fields: [["subject", "string"], ["body", "string"]], outputKeys: ["recipients"] },
4371
+ "sendGmailDraft": { fields: [["draftId", "string"]], outputKeys: [] },
4372
+ "sendGmailMessage": { fields: [["to", "string"], ["subject", "string"], ["message", "string"], ["messageType", ["plain", "html", "markdown"]]], outputKeys: ["messageId"] },
4373
+ "sendSMS": { fields: [["body", "string"]], outputKeys: [] },
4374
+ "setGmailReadStatus": { fields: [["messageIds", "string"], ["markAsRead", "boolean"]], outputKeys: [] },
4375
+ "setRunTitle": { fields: [["title", "string"]], outputKeys: [] },
4376
+ "setVariable": { fields: [["value", "string"]], outputKeys: [] },
4377
+ "telegramEditMessage": { fields: [["botToken", "string"], ["chatId", "string"], ["messageId", "string"], ["text", "string"]], outputKeys: [] },
4378
+ "telegramReplyToMessage": { fields: [["botToken", "string"], ["chatId", "string"], ["replyToMessageId", "string"], ["text", "string"]], outputKeys: ["messageId"] },
4379
+ "telegramSendAudio": { fields: [["botToken", "string"], ["chatId", "string"], ["audioUrl", "string"], ["mode", ["audio", "voice"]]], outputKeys: [] },
4380
+ "telegramSendFile": { fields: [["botToken", "string"], ["chatId", "string"], ["fileUrl", "string"]], outputKeys: [] },
4381
+ "telegramSendImage": { fields: [["botToken", "string"], ["chatId", "string"], ["imageUrl", "string"]], outputKeys: [] },
4382
+ "telegramSendMessage": { fields: [["botToken", "string"], ["chatId", "string"], ["text", "string"]], outputKeys: ["messageId"] },
4383
+ "telegramSendVideo": { fields: [["botToken", "string"], ["chatId", "string"], ["videoUrl", "string"]], outputKeys: [] },
4384
+ "telegramSetTyping": { fields: [["botToken", "string"], ["chatId", "string"]], outputKeys: [] },
4385
+ "textToSpeech": { fields: [["text", "string"]], outputKeys: ["audioUrl"] },
4386
+ "transcribeAudio": { fields: [["audioUrl", "string"], ["prompt", "string"]], outputKeys: ["text"] },
4387
+ "trimMedia": { fields: [["inputUrl", "string"]], outputKeys: ["mediaUrl"] },
4388
+ "updateGmailLabels": { fields: [["query", "string"], ["messageIds", "string"], ["addLabelIds", "string"], ["removeLabelIds", "string"]], outputKeys: ["updatedMessageIds"] },
4389
+ "updateGoogleCalendarEvent": { fields: [["eventId", "string"]], outputKeys: ["eventId", "htmlLink"] },
4390
+ "updateGoogleDoc": { fields: [["documentId", "string"], ["text", "string"], ["textType", ["plain", "html", "markdown"]], ["operationType", ["addToTop", "addToBottom", "overwrite"]]], outputKeys: ["documentUrl"] },
4391
+ "updateGoogleSheet": { fields: [["text", "string"], ["spreadsheetId", "string"], ["range", "string"], ["operationType", ["addToBottom", "overwrite", "range"]]], outputKeys: ["spreadsheetUrl"] },
4392
+ "uploadDataSourceDocument": { fields: [["dataSourceId", "string"], ["file", "string"], ["fileName", "string"]], outputKeys: [] },
4393
+ "upscaleImage": { fields: [["imageUrl", "string"], ["targetResolution", ["2k", "4k", "8k"]], ["engine", ["standard", "pro"]]], outputKeys: ["imageUrl"] },
4394
+ "upscaleVideo": { fields: [["videoUrl", "string"], ["targetResolution", ["720p", "1080p", "2K", "4K"]], ["engine", ["standard", "pro", "ultimate", "flashvsr", "seedance", "seedvr2", "runwayml/upscale-v1"]]], outputKeys: ["videoUrl"] },
4395
+ "userMessage": { fields: [["message", "string"]], outputKeys: ["content"] },
4396
+ "videoFaceSwap": { fields: [["videoUrl", "string"], ["faceImageUrl", "string"], ["targetIndex", "number"], ["engine", "string"]], outputKeys: ["videoUrl"] },
4397
+ "videoRemoveBackground": { fields: [["videoUrl", "string"], ["newBackground", ["transparent", "image"]], ["engine", "string"]], outputKeys: ["videoUrl"] },
4398
+ "videoRemoveWatermark": { fields: [["videoUrl", "string"], ["engine", "string"]], outputKeys: ["videoUrl"] },
4399
+ "watermarkImage": { fields: [["imageUrl", "string"], ["watermarkImageUrl", "string"], ["corner", ["top-left", "top-right", "bottom-left", "bottom-right"]], ["paddingPx", "number"], ["widthPx", "number"]], outputKeys: ["imageUrl"] },
4400
+ "watermarkVideo": { fields: [["videoUrl", "string"], ["imageUrl", "string"], ["corner", ["top-left", "top-right", "bottom-left", "bottom-right"]], ["paddingPx", "number"], ["widthPx", "number"]], outputKeys: ["videoUrl"] }
4401
+ };
4402
+ var blockTypeAliases = {
4403
+ "userMessage": "generateText",
4404
+ "generatePdf": "generateAsset"
4405
+ };
4406
+
4292
4407
  // src/index.ts
4293
4408
  var MindStudioAgent2 = MindStudioAgent;
4294
4409
  var _default;