@mindstudio-ai/agent 0.1.32 → 0.1.34

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
@@ -1999,1135 +1999,6 @@ function applyStepMethods(AgentClass) {
1999
1999
  };
2000
2000
  }
2001
2001
 
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
2002
  // src/generated/metadata.ts
3132
2003
  var stepMetadata = {
3133
2004
  "activeCampaignAddNote": {
@@ -4289,6 +3160,1139 @@ var stepMetadata = {
4289
3160
  }
4290
3161
  };
4291
3162
 
3163
+ // src/client.ts
3164
+ var DEFAULT_BASE_URL = "https://v1.mindstudio-api.com";
3165
+ var DEFAULT_MAX_RETRIES = 3;
3166
+ var MindStudioAgent = class {
3167
+ /** @internal */
3168
+ _httpConfig;
3169
+ /** @internal */
3170
+ _reuseThreadId;
3171
+ /** @internal */
3172
+ _threadId;
3173
+ /** @internal Stream ID for SSE token streaming. Set by sandbox via STREAM_ID env var. */
3174
+ _streamId;
3175
+ // ---- App context (db + auth) ----
3176
+ /**
3177
+ * @internal App ID for context resolution. Resolved from:
3178
+ * constructor appId → MINDSTUDIO_APP_ID env → sandbox globals →
3179
+ * auto-detected from first executeStep response header.
3180
+ */
3181
+ _appId;
3182
+ /**
3183
+ * @internal Cached app context (auth + databases). Populated by
3184
+ * ensureContext() and cached for the lifetime of the instance.
3185
+ */
3186
+ _context;
3187
+ /**
3188
+ * @internal Deduplication promise for ensureContext(). Ensures only one
3189
+ * context fetch is in-flight at a time, even if multiple db/auth
3190
+ * operations trigger it concurrently.
3191
+ */
3192
+ _contextPromise;
3193
+ /** @internal Cached AuthContext instance, created during context hydration. */
3194
+ _auth;
3195
+ /** @internal Cached Db namespace instance, created during context hydration. */
3196
+ _db;
3197
+ /** @internal Auth type — 'internal' for CALLBACK_TOKEN (managed mode), 'apiKey' otherwise. */
3198
+ _authType;
3199
+ /**
3200
+ * @internal Resolve the current auth token. For internal (CALLBACK_TOKEN)
3201
+ * auth, re-reads the env var each time so that long-lived singleton
3202
+ * instances pick up token rotations from the host process.
3203
+ */
3204
+ get _token() {
3205
+ if (this._authType === "internal" && process.env.CALLBACK_TOKEN) {
3206
+ return process.env.CALLBACK_TOKEN;
3207
+ }
3208
+ return this._httpConfig.token;
3209
+ }
3210
+ constructor(options = {}) {
3211
+ const config = loadConfig();
3212
+ const { token, authType } = resolveToken(options.apiKey, config);
3213
+ const baseUrl = options.baseUrl ?? process.env.MINDSTUDIO_BASE_URL ?? process.env.REMOTE_HOSTNAME ?? config.baseUrl ?? DEFAULT_BASE_URL;
3214
+ this._reuseThreadId = options.reuseThreadId ?? /^(true|1)$/i.test(process.env.MINDSTUDIO_REUSE_THREAD_ID ?? "");
3215
+ this._appId = options.appId ?? process.env.MINDSTUDIO_APP_ID ?? void 0;
3216
+ this._authType = authType;
3217
+ this._httpConfig = {
3218
+ baseUrl,
3219
+ token,
3220
+ rateLimiter: new RateLimiter(authType),
3221
+ maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES
3222
+ };
3223
+ if (authType === "internal") {
3224
+ this._trySandboxHydration();
3225
+ }
3226
+ this._streamId = process.env.STREAM_ID ?? void 0;
3227
+ }
3228
+ /**
3229
+ * Execute any step by its type name. This is the low-level method that all
3230
+ * typed step methods delegate to. Use it as an escape hatch for step types
3231
+ * not yet covered by the generated methods.
3232
+ *
3233
+ * ```ts
3234
+ * const result = await agent.executeStep("generateImage", { prompt: "hello", mode: "background" });
3235
+ * ```
3236
+ */
3237
+ async executeStep(stepType, step, options) {
3238
+ if (options?.onLog) {
3239
+ return this._executeStepStreaming(
3240
+ stepType,
3241
+ step,
3242
+ options
3243
+ );
3244
+ }
3245
+ const threadId = options?.threadId ?? (this._reuseThreadId ? this._threadId : void 0);
3246
+ const { data, headers } = await request(this._httpConfig, "POST", `/steps/${stepType}/execute`, {
3247
+ step,
3248
+ ...options?.appId != null && { appId: options.appId },
3249
+ ...threadId != null && { threadId },
3250
+ ...this._streamId != null && { streamId: this._streamId }
3251
+ });
3252
+ let output;
3253
+ if (data.output != null) {
3254
+ output = data.output;
3255
+ } else if (data.outputUrl) {
3256
+ const res = await fetch(data.outputUrl);
3257
+ if (!res.ok) {
3258
+ throw new MindStudioError(
3259
+ `Failed to fetch output from S3: ${res.status} ${res.statusText}`,
3260
+ "output_fetch_error",
3261
+ res.status
3262
+ );
3263
+ }
3264
+ const envelope = await res.json();
3265
+ output = envelope.value;
3266
+ } else {
3267
+ output = void 0;
3268
+ }
3269
+ const returnedThreadId = headers.get("x-mindstudio-thread-id") ?? "";
3270
+ if (this._reuseThreadId && returnedThreadId) {
3271
+ this._threadId = returnedThreadId;
3272
+ }
3273
+ const returnedAppId = headers.get("x-mindstudio-app-id");
3274
+ if (!this._appId && returnedAppId) {
3275
+ this._appId = returnedAppId;
3276
+ }
3277
+ const remaining = headers.get("x-ratelimit-remaining");
3278
+ const billingCost = headers.get("x-mindstudio-billing-cost");
3279
+ const billingEvents = headers.get("x-mindstudio-billing-events");
3280
+ return {
3281
+ ...output,
3282
+ $appId: headers.get("x-mindstudio-app-id") ?? "",
3283
+ $threadId: returnedThreadId,
3284
+ $rateLimitRemaining: remaining != null ? parseInt(remaining, 10) : void 0,
3285
+ $billingCost: billingCost != null ? parseFloat(billingCost) : void 0,
3286
+ $billingEvents: billingEvents != null ? JSON.parse(billingEvents) : void 0
3287
+ };
3288
+ }
3289
+ /**
3290
+ * @internal Streaming step execution — sends `Accept: text/event-stream`
3291
+ * and parses SSE events for real-time debug logs.
3292
+ */
3293
+ async _executeStepStreaming(stepType, step, options) {
3294
+ const threadId = options.threadId ?? (this._reuseThreadId ? this._threadId : void 0);
3295
+ const url = `${this._httpConfig.baseUrl}/developer/v2/steps/${stepType}/execute`;
3296
+ const body = {
3297
+ step,
3298
+ ...options.appId != null && { appId: options.appId },
3299
+ ...threadId != null && { threadId },
3300
+ ...this._streamId != null && { streamId: this._streamId }
3301
+ };
3302
+ await this._httpConfig.rateLimiter.acquire();
3303
+ let res;
3304
+ try {
3305
+ res = await fetch(url, {
3306
+ method: "POST",
3307
+ headers: {
3308
+ Authorization: `Bearer ${this._token}`,
3309
+ "Content-Type": "application/json",
3310
+ "User-Agent": "@mindstudio-ai/agent",
3311
+ Accept: "text/event-stream"
3312
+ },
3313
+ body: JSON.stringify(body)
3314
+ });
3315
+ } catch (err) {
3316
+ this._httpConfig.rateLimiter.release();
3317
+ throw err;
3318
+ }
3319
+ this._httpConfig.rateLimiter.updateFromHeaders(res.headers);
3320
+ if (!res.ok) {
3321
+ this._httpConfig.rateLimiter.release();
3322
+ const errorBody = await res.json().catch(() => ({}));
3323
+ throw new MindStudioError(
3324
+ errorBody.message || `${res.status} ${res.statusText}`,
3325
+ errorBody.code || "api_error",
3326
+ res.status,
3327
+ errorBody
3328
+ );
3329
+ }
3330
+ const headers = res.headers;
3331
+ try {
3332
+ const reader = res.body.getReader();
3333
+ const decoder = new TextDecoder();
3334
+ let buffer = "";
3335
+ let doneEvent = null;
3336
+ while (true) {
3337
+ const { done, value } = await reader.read();
3338
+ if (done) break;
3339
+ buffer += decoder.decode(value, { stream: true });
3340
+ const lines = buffer.split("\n");
3341
+ buffer = lines.pop() ?? "";
3342
+ for (const line of lines) {
3343
+ if (!line.startsWith("data: ")) continue;
3344
+ try {
3345
+ const event = JSON.parse(line.slice(6));
3346
+ if (event.type === "log") {
3347
+ options.onLog({
3348
+ value: event.value,
3349
+ tag: event.tag,
3350
+ ts: event.ts
3351
+ });
3352
+ } else if (event.type === "done") {
3353
+ doneEvent = {
3354
+ output: event.output,
3355
+ outputUrl: event.outputUrl,
3356
+ billingCost: event.billingCost,
3357
+ billingEvents: event.billingEvents
3358
+ };
3359
+ } else if (event.type === "error") {
3360
+ throw new MindStudioError(
3361
+ event.error || "Step execution failed",
3362
+ "step_error",
3363
+ 500
3364
+ );
3365
+ }
3366
+ } catch (err) {
3367
+ if (err instanceof MindStudioError) throw err;
3368
+ }
3369
+ }
3370
+ }
3371
+ if (buffer.startsWith("data: ")) {
3372
+ try {
3373
+ const event = JSON.parse(buffer.slice(6));
3374
+ if (event.type === "done") {
3375
+ doneEvent = {
3376
+ output: event.output,
3377
+ outputUrl: event.outputUrl,
3378
+ billingCost: event.billingCost,
3379
+ billingEvents: event.billingEvents
3380
+ };
3381
+ } else if (event.type === "error") {
3382
+ throw new MindStudioError(
3383
+ event.error || "Step execution failed",
3384
+ "step_error",
3385
+ 500
3386
+ );
3387
+ } else if (event.type === "log") {
3388
+ options.onLog({
3389
+ value: event.value,
3390
+ tag: event.tag,
3391
+ ts: event.ts
3392
+ });
3393
+ }
3394
+ } catch (err) {
3395
+ if (err instanceof MindStudioError) throw err;
3396
+ }
3397
+ }
3398
+ if (!doneEvent) {
3399
+ throw new MindStudioError(
3400
+ "Stream ended without a done event",
3401
+ "stream_error",
3402
+ 500
3403
+ );
3404
+ }
3405
+ let output;
3406
+ if (doneEvent.output != null) {
3407
+ output = doneEvent.output;
3408
+ } else if (doneEvent.outputUrl) {
3409
+ const s3Res = await fetch(doneEvent.outputUrl);
3410
+ if (!s3Res.ok) {
3411
+ throw new MindStudioError(
3412
+ `Failed to fetch output from S3: ${s3Res.status} ${s3Res.statusText}`,
3413
+ "output_fetch_error",
3414
+ s3Res.status
3415
+ );
3416
+ }
3417
+ const envelope = await s3Res.json();
3418
+ output = envelope.value;
3419
+ } else {
3420
+ output = void 0;
3421
+ }
3422
+ const returnedThreadId = headers.get("x-mindstudio-thread-id") ?? "";
3423
+ if (this._reuseThreadId && returnedThreadId) {
3424
+ this._threadId = returnedThreadId;
3425
+ }
3426
+ const returnedAppId = headers.get("x-mindstudio-app-id");
3427
+ if (!this._appId && returnedAppId) {
3428
+ this._appId = returnedAppId;
3429
+ }
3430
+ const remaining = headers.get("x-ratelimit-remaining");
3431
+ return {
3432
+ ...output,
3433
+ $appId: headers.get("x-mindstudio-app-id") ?? "",
3434
+ $threadId: returnedThreadId,
3435
+ $rateLimitRemaining: remaining != null ? parseInt(remaining, 10) : void 0,
3436
+ $billingCost: doneEvent.billingCost,
3437
+ $billingEvents: doneEvent.billingEvents
3438
+ };
3439
+ } finally {
3440
+ this._httpConfig.rateLimiter.release();
3441
+ }
3442
+ }
3443
+ /**
3444
+ * Execute multiple steps in parallel in a single request.
3445
+ *
3446
+ * All steps run in parallel on the server. Results are returned in the same
3447
+ * order as the input. Individual step failures do not affect other steps —
3448
+ * partial success is possible.
3449
+ *
3450
+ * ```ts
3451
+ * const { results } = await agent.executeStepBatch([
3452
+ * { stepType: 'generateImage', step: { prompt: 'a sunset' } },
3453
+ * { stepType: 'textToSpeech', step: { text: 'Hello world' } },
3454
+ * ]);
3455
+ * ```
3456
+ */
3457
+ async executeStepBatch(steps, options) {
3458
+ const threadId = options?.threadId ?? (this._reuseThreadId ? this._threadId : void 0);
3459
+ const { data } = await request(this._httpConfig, "POST", "/steps/execute-batch", {
3460
+ steps: steps.map((s) => ({ ...s, stepType: resolveStepType(s.stepType) })),
3461
+ ...options?.appId != null && { appId: options.appId },
3462
+ ...threadId != null && { threadId }
3463
+ });
3464
+ const results = await Promise.all(
3465
+ data.results.map(async (r) => {
3466
+ if (r.output != null) {
3467
+ return {
3468
+ stepType: r.stepType,
3469
+ output: r.output,
3470
+ billingCost: r.billingCost,
3471
+ error: r.error
3472
+ };
3473
+ }
3474
+ if (r.outputUrl) {
3475
+ const res = await fetch(r.outputUrl);
3476
+ if (!res.ok) {
3477
+ return {
3478
+ stepType: r.stepType,
3479
+ error: `Failed to fetch output from S3: ${res.status} ${res.statusText}`
3480
+ };
3481
+ }
3482
+ const envelope = await res.json();
3483
+ return {
3484
+ stepType: r.stepType,
3485
+ output: envelope.value,
3486
+ billingCost: r.billingCost
3487
+ };
3488
+ }
3489
+ return {
3490
+ stepType: r.stepType,
3491
+ billingCost: r.billingCost,
3492
+ error: r.error
3493
+ };
3494
+ })
3495
+ );
3496
+ if (this._reuseThreadId && data.threadId) {
3497
+ this._threadId = data.threadId;
3498
+ }
3499
+ return {
3500
+ results,
3501
+ totalBillingCost: data.totalBillingCost,
3502
+ appId: data.appId,
3503
+ threadId: data.threadId
3504
+ };
3505
+ }
3506
+ /**
3507
+ * Get the authenticated user's identity and organization info.
3508
+ *
3509
+ * ```ts
3510
+ * const info = await agent.getUserInfo();
3511
+ * console.log(info.displayName, info.organizationName);
3512
+ * ```
3513
+ */
3514
+ async getUserInfo() {
3515
+ const { data } = await request(
3516
+ this._httpConfig,
3517
+ "GET",
3518
+ "/account/userinfo"
3519
+ );
3520
+ return data;
3521
+ }
3522
+ /**
3523
+ * List all pre-built agents in the organization.
3524
+ *
3525
+ * ```ts
3526
+ * const { apps } = await agent.listAgents();
3527
+ * for (const app of apps) console.log(app.name, app.id);
3528
+ * ```
3529
+ */
3530
+ async listAgents() {
3531
+ const { data } = await request(
3532
+ this._httpConfig,
3533
+ "GET",
3534
+ "/agents/load"
3535
+ );
3536
+ return data;
3537
+ }
3538
+ /**
3539
+ * Run a pre-built agent and wait for the result.
3540
+ *
3541
+ * Uses async polling internally — the request returns immediately with a
3542
+ * callback token, then polls until the run completes or fails.
3543
+ *
3544
+ * ```ts
3545
+ * const result = await agent.runAgent({
3546
+ * appId: 'your-agent-id',
3547
+ * variables: { query: 'hello' },
3548
+ * });
3549
+ * console.log(result.result);
3550
+ * ```
3551
+ */
3552
+ async runAgent(options) {
3553
+ const pollInterval = options.pollIntervalMs ?? 1e3;
3554
+ const { data } = await request(this._httpConfig, "POST", "/agents/run", {
3555
+ appId: options.appId,
3556
+ async: true,
3557
+ ...options.variables != null && { variables: options.variables },
3558
+ ...options.workflow != null && { workflow: options.workflow },
3559
+ ...options.version != null && { version: options.version },
3560
+ ...options.includeBillingCost != null && {
3561
+ includeBillingCost: options.includeBillingCost
3562
+ },
3563
+ ...options.metadata != null && { metadata: options.metadata }
3564
+ });
3565
+ const token = data.callbackToken;
3566
+ const pollUrl = `${this._httpConfig.baseUrl}/developer/v2/agents/run/poll/${token}`;
3567
+ while (true) {
3568
+ await sleep2(pollInterval);
3569
+ const res = await fetch(pollUrl, {
3570
+ headers: { "User-Agent": "@mindstudio-ai/agent" }
3571
+ });
3572
+ if (res.status === 404) {
3573
+ throw new MindStudioError(
3574
+ "Poll token not found or expired.",
3575
+ "poll_token_expired",
3576
+ 404
3577
+ );
3578
+ }
3579
+ if (!res.ok) {
3580
+ const errorBody = await res.json().catch(() => ({}));
3581
+ throw new MindStudioError(
3582
+ errorBody.message ?? errorBody.error ?? `Poll request failed: ${res.status} ${res.statusText}`,
3583
+ errorBody.code ?? "poll_error",
3584
+ res.status,
3585
+ errorBody
3586
+ );
3587
+ }
3588
+ const poll = await res.json();
3589
+ if (poll.status === "pending") continue;
3590
+ if (poll.status === "error") {
3591
+ throw new MindStudioError(
3592
+ poll.error ?? "Agent run failed.",
3593
+ "agent_run_error",
3594
+ 500
3595
+ );
3596
+ }
3597
+ return poll.result;
3598
+ }
3599
+ }
3600
+ /** @internal Used by generated action methods. */
3601
+ _request(method, path, body) {
3602
+ return request(this._httpConfig, method, path, body);
3603
+ }
3604
+ // -------------------------------------------------------------------------
3605
+ // Helper methods — models
3606
+ // -------------------------------------------------------------------------
3607
+ /** List all available AI models. */
3608
+ async listModels() {
3609
+ const { data } = await request(
3610
+ this._httpConfig,
3611
+ "GET",
3612
+ "/helpers/models"
3613
+ );
3614
+ return data;
3615
+ }
3616
+ /** List AI models filtered by type. */
3617
+ async listModelsByType(modelType) {
3618
+ const { data } = await request(
3619
+ this._httpConfig,
3620
+ "GET",
3621
+ `/helpers/models/${modelType}`
3622
+ );
3623
+ return data;
3624
+ }
3625
+ /** List all available AI models (summary). Returns only id, name, type, and tags. */
3626
+ async listModelsSummary() {
3627
+ const { data } = await request(
3628
+ this._httpConfig,
3629
+ "GET",
3630
+ "/helpers/models-summary"
3631
+ );
3632
+ return data;
3633
+ }
3634
+ /** List AI models (summary) filtered by type. */
3635
+ async listModelsSummaryByType(modelType) {
3636
+ const { data } = await request(
3637
+ this._httpConfig,
3638
+ "GET",
3639
+ `/helpers/models-summary/${modelType}`
3640
+ );
3641
+ return data;
3642
+ }
3643
+ // -------------------------------------------------------------------------
3644
+ // Helper methods — OAuth connectors & connections
3645
+ // -------------------------------------------------------------------------
3646
+ /**
3647
+ * List available OAuth connector services (Slack, Google, HubSpot, etc.).
3648
+ *
3649
+ * These are third-party integrations from the MindStudio Connector Registry.
3650
+ * For most tasks, use actions directly instead.
3651
+ */
3652
+ async listConnectors() {
3653
+ const { data } = await request(
3654
+ this._httpConfig,
3655
+ "GET",
3656
+ "/helpers/connectors"
3657
+ );
3658
+ return data;
3659
+ }
3660
+ /** Get details for a single OAuth connector service. */
3661
+ async getConnector(serviceId) {
3662
+ const { data } = await request(
3663
+ this._httpConfig,
3664
+ "GET",
3665
+ `/helpers/connectors/${serviceId}`
3666
+ );
3667
+ return data;
3668
+ }
3669
+ /** Get the full configuration for an OAuth connector action, including input fields. */
3670
+ async getConnectorAction(serviceId, actionId) {
3671
+ const { data } = await request(
3672
+ this._httpConfig,
3673
+ "GET",
3674
+ `/helpers/connectors/${serviceId}/${actionId}`
3675
+ );
3676
+ return data;
3677
+ }
3678
+ /** List OAuth connections for the organization. These are authenticated third-party service links. */
3679
+ async listConnections() {
3680
+ const { data } = await request(
3681
+ this._httpConfig,
3682
+ "GET",
3683
+ "/helpers/connections"
3684
+ );
3685
+ return data;
3686
+ }
3687
+ // -------------------------------------------------------------------------
3688
+ // Helper methods — cost estimation
3689
+ // -------------------------------------------------------------------------
3690
+ /** Estimate the cost of executing an action before running it. */
3691
+ async estimateStepCost(stepType, step, options) {
3692
+ const { data } = await request(this._httpConfig, "POST", "/helpers/step-cost-estimate", {
3693
+ step: { type: resolveStepType(stepType), ...step },
3694
+ ...options
3695
+ });
3696
+ return data;
3697
+ }
3698
+ // -------------------------------------------------------------------------
3699
+ // Streaming
3700
+ // -------------------------------------------------------------------------
3701
+ /**
3702
+ * Send a stream chunk to the caller via SSE.
3703
+ *
3704
+ * When invoked from a method that was called with `stream: true`, chunks
3705
+ * are delivered in real-time as Server-Sent Events. When there is no active
3706
+ * stream (no `STREAM_ID`), calls are silently ignored — so it's safe to
3707
+ * call unconditionally.
3708
+ *
3709
+ * Accepts strings (sent as `type: 'token'`) or structured data (sent as
3710
+ * `type: 'data'`). The caller receives each chunk as an SSE event.
3711
+ *
3712
+ * @example
3713
+ * ```ts
3714
+ * // Stream text tokens
3715
+ * await agent.stream('Processing item 1...');
3716
+ *
3717
+ * // Stream structured data
3718
+ * await agent.stream({ progress: 50, currentItem: 'abc' });
3719
+ * ```
3720
+ */
3721
+ stream = async (data) => {
3722
+ if (!this._streamId) return;
3723
+ const url = `${this._httpConfig.baseUrl}/_internal/v2/stream-chunk`;
3724
+ const body = typeof data === "string" ? { streamId: this._streamId, type: "token", text: data } : { streamId: this._streamId, type: "data", data };
3725
+ const res = await fetch(url, {
3726
+ method: "POST",
3727
+ headers: {
3728
+ "Content-Type": "application/json",
3729
+ Authorization: this._token
3730
+ },
3731
+ body: JSON.stringify(body)
3732
+ });
3733
+ if (!res.ok) {
3734
+ const text = await res.text().catch(() => "");
3735
+ console.warn(`[mindstudio] stream chunk failed: ${res.status} ${text}`);
3736
+ }
3737
+ };
3738
+ // -------------------------------------------------------------------------
3739
+ // db + auth namespaces
3740
+ // -------------------------------------------------------------------------
3741
+ /**
3742
+ * The `auth` namespace — synchronous role-based access control.
3743
+ *
3744
+ * Provides the current user's identity and roles. All methods are
3745
+ * synchronous since the role map is preloaded during context hydration.
3746
+ *
3747
+ * **Important**: Context must be hydrated before accessing `auth`.
3748
+ * - Inside the MindStudio sandbox: automatic (populated from globals)
3749
+ * - Outside the sandbox: call `await agent.ensureContext()` first,
3750
+ * or access `auth` after any `db` operation (which auto-hydrates)
3751
+ *
3752
+ * @throws {MindStudioError} if context has not been hydrated yet
3753
+ *
3754
+ * @example
3755
+ * ```ts
3756
+ * await agent.ensureContext();
3757
+ * agent.auth.requireRole(Roles.admin);
3758
+ * const admins = agent.auth.getUsersByRole(Roles.admin);
3759
+ * ```
3760
+ */
3761
+ get auth() {
3762
+ if (!this._auth) {
3763
+ this._trySandboxHydration();
3764
+ }
3765
+ if (!this._auth) {
3766
+ throw new MindStudioError(
3767
+ "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.",
3768
+ "context_not_loaded",
3769
+ 400
3770
+ );
3771
+ }
3772
+ return this._auth;
3773
+ }
3774
+ /**
3775
+ * The `db` namespace — chainable collection API over managed databases.
3776
+ *
3777
+ * Use `db.defineTable<T>(name)` to get a typed Table<T>, then call
3778
+ * collection methods (filter, sortBy, push, update, etc.) on it.
3779
+ *
3780
+ * Context is auto-hydrated on first query execution — you can safely
3781
+ * call `defineTable()` at module scope without triggering any HTTP.
3782
+ *
3783
+ * @example
3784
+ * ```ts
3785
+ * const Orders = agent.db.defineTable<Order>('orders');
3786
+ * const active = await Orders.filter(o => o.status === 'active').take(10);
3787
+ * ```
3788
+ */
3789
+ get db() {
3790
+ if (!this._db) {
3791
+ this._trySandboxHydration();
3792
+ }
3793
+ if (this._db) return this._db;
3794
+ return this._createLazyDb();
3795
+ }
3796
+ /**
3797
+ * Hydrate the app context (auth + database metadata). This must be
3798
+ * called before using `auth` synchronously. For `db`, hydration happens
3799
+ * automatically on first query.
3800
+ *
3801
+ * Context is fetched once and cached for the instance's lifetime.
3802
+ * Calling `ensureContext()` multiple times is safe (no-op after first).
3803
+ *
3804
+ * Context sources (checked in order):
3805
+ * 1. Sandbox globals (`globalThis.ai.auth`, `globalThis.ai.databases`)
3806
+ * 2. HTTP: `GET /developer/v2/helpers/app-context?appId={appId}`
3807
+ *
3808
+ * @throws {MindStudioError} if no `appId` is available
3809
+ *
3810
+ * @example
3811
+ * ```ts
3812
+ * await agent.ensureContext();
3813
+ * // auth is now available synchronously
3814
+ * agent.auth.requireRole(Roles.admin);
3815
+ * ```
3816
+ */
3817
+ async ensureContext() {
3818
+ if (this._context) return;
3819
+ if (!this._contextPromise) {
3820
+ this._contextPromise = this._hydrateContext();
3821
+ }
3822
+ await this._contextPromise;
3823
+ }
3824
+ /**
3825
+ * @internal Fetch and cache app context, then create auth + db instances.
3826
+ *
3827
+ * In managed mode (CALLBACK_TOKEN), the platform resolves the app from
3828
+ * the token — no appId needed. With an API key, appId is required.
3829
+ */
3830
+ async _hydrateContext() {
3831
+ if (!this._appId && this._authType !== "internal") {
3832
+ throw new MindStudioError(
3833
+ "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).",
3834
+ "missing_app_id",
3835
+ 400
3836
+ );
3837
+ }
3838
+ const context = await this.getAppContext(this._appId);
3839
+ this._applyContext(context);
3840
+ }
3841
+ /**
3842
+ * @internal Apply a resolved context object — creates AuthContext and Db.
3843
+ * Used by both the HTTP path and sandbox hydration.
3844
+ */
3845
+ _applyContext(context) {
3846
+ this._context = context;
3847
+ this._auth = new AuthContext(context.auth);
3848
+ this._db = createDb(
3849
+ context.databases,
3850
+ this._executeDbBatch.bind(this)
3851
+ );
3852
+ }
3853
+ /**
3854
+ * @internal Try to hydrate context synchronously from sandbox globals.
3855
+ * Called in the constructor when CALLBACK_TOKEN auth is detected.
3856
+ *
3857
+ * The MindStudio sandbox pre-populates `globalThis.ai` with:
3858
+ * - `ai.auth`: { userId, roleAssignments[] }
3859
+ * - `ai.databases`: [{ id, name, tables[] }]
3860
+ */
3861
+ _trySandboxHydration() {
3862
+ const ai = globalThis.ai;
3863
+ if (ai?.auth && ai?.databases) {
3864
+ this._applyContext({
3865
+ auth: ai.auth,
3866
+ databases: ai.databases
3867
+ });
3868
+ }
3869
+ }
3870
+ /**
3871
+ * @internal Execute a batch of SQL queries against a managed database.
3872
+ * Used as the `executeBatch` callback for Table/Query instances.
3873
+ *
3874
+ * Calls `POST /_internal/v2/db/query` directly with the hook token
3875
+ * (raw, no Bearer prefix). All queries run on a single SQLite connection,
3876
+ * enabling RETURNING clauses and multi-statement batches.
3877
+ */
3878
+ async _executeDbBatch(databaseId, queries) {
3879
+ const url = `${this._httpConfig.baseUrl}/_internal/v2/db/query`;
3880
+ const res = await fetch(url, {
3881
+ method: "POST",
3882
+ headers: {
3883
+ "Content-Type": "application/json",
3884
+ Authorization: this._token
3885
+ },
3886
+ body: JSON.stringify({ databaseId, queries })
3887
+ });
3888
+ if (!res.ok) {
3889
+ let message = `Database query failed: ${res.status} ${res.statusText}`;
3890
+ let code = "db_query_error";
3891
+ try {
3892
+ const text = await res.text();
3893
+ try {
3894
+ const body = JSON.parse(text);
3895
+ const errMsg = body.error ?? body.message ?? body.details;
3896
+ if (errMsg) message = errMsg;
3897
+ if (body.code) code = body.code;
3898
+ } catch {
3899
+ if (text && text.length < 500) message = text;
3900
+ }
3901
+ } catch {
3902
+ }
3903
+ throw new MindStudioError(
3904
+ `[db] ${message}`,
3905
+ code,
3906
+ res.status
3907
+ );
3908
+ }
3909
+ const data = await res.json();
3910
+ return data.results;
3911
+ }
3912
+ /**
3913
+ * @internal Create a lazy Db proxy that auto-hydrates context.
3914
+ *
3915
+ * defineTable() returns Table instances immediately (no async needed).
3916
+ * But the Table's executeBatch callback is wrapped to call ensureContext()
3917
+ * before the first query, so context is fetched lazily.
3918
+ */
3919
+ _createLazyDb() {
3920
+ const agent = this;
3921
+ return {
3922
+ defineTable(name, options) {
3923
+ const databaseHint = options?.database;
3924
+ return new Table({
3925
+ databaseId: "",
3926
+ tableName: name,
3927
+ columns: [],
3928
+ unique: options?.unique,
3929
+ defaults: options?.defaults,
3930
+ executeBatch: async (queries) => {
3931
+ await agent.ensureContext();
3932
+ const databases = agent._context.databases;
3933
+ let targetDb;
3934
+ if (databaseHint) {
3935
+ targetDb = databases.find(
3936
+ (d) => d.id === databaseHint || d.name === databaseHint
3937
+ );
3938
+ } else {
3939
+ targetDb = databases.find(
3940
+ (d) => d.tables.some((t) => t.name === name)
3941
+ );
3942
+ }
3943
+ const databaseId = targetDb?.id ?? databases[0]?.id ?? "";
3944
+ return agent._executeDbBatch(databaseId, queries);
3945
+ }
3946
+ });
3947
+ },
3948
+ // Time helpers work without context
3949
+ now: () => Date.now(),
3950
+ days: (n) => n * 864e5,
3951
+ hours: (n) => n * 36e5,
3952
+ minutes: (n) => n * 6e4,
3953
+ ago: (ms) => Date.now() - ms,
3954
+ fromNow: (ms) => Date.now() + ms,
3955
+ // Batch needs context — hydrate first, then delegate to real db
3956
+ batch: ((...queries) => {
3957
+ return (async () => {
3958
+ await agent.ensureContext();
3959
+ return agent._db.batch(...queries);
3960
+ })();
3961
+ })
3962
+ };
3963
+ }
3964
+ // -------------------------------------------------------------------------
3965
+ // Helper methods — user resolution
3966
+ // -------------------------------------------------------------------------
3967
+ /**
3968
+ * Resolve a single user ID to display info (name, email, profile picture).
3969
+ *
3970
+ * Use this when you have a `User`-typed field value and need the person's
3971
+ * display name, email, or avatar. Returns null if the user ID is not found.
3972
+ *
3973
+ * Also available as a top-level import:
3974
+ * ```ts
3975
+ * import { resolveUser } from '@mindstudio-ai/agent';
3976
+ * ```
3977
+ *
3978
+ * @param userId - The user ID to resolve (a `User` branded string or plain UUID)
3979
+ * @returns Resolved user info, or null if not found
3980
+ *
3981
+ * @example
3982
+ * ```ts
3983
+ * const user = await agent.resolveUser(order.requestedBy);
3984
+ * if (user) {
3985
+ * console.log(user.name); // "Jane Smith"
3986
+ * console.log(user.email); // "jane@example.com"
3987
+ * console.log(user.profilePictureUrl); // "https://..." or null
3988
+ * }
3989
+ * ```
3990
+ */
3991
+ async resolveUser(userId) {
3992
+ const { users } = await this.resolveUsers([userId]);
3993
+ return users[0] ?? null;
3994
+ }
3995
+ /**
3996
+ * Resolve multiple user IDs to display info in a single request.
3997
+ * Maximum 100 user IDs per request.
3998
+ *
3999
+ * Use this for batch resolution when you have multiple user references
4000
+ * to display (e.g. all approvers on a purchase order, all team members).
4001
+ *
4002
+ * @param userIds - Array of user IDs to resolve (max 100)
4003
+ * @returns Object with `users` array of resolved user info
4004
+ *
4005
+ * @example
4006
+ * ```ts
4007
+ * // Resolve all approvers at once
4008
+ * const approverIds = approvals.map(a => a.assignedTo);
4009
+ * const { users } = await agent.resolveUsers(approverIds);
4010
+ *
4011
+ * for (const u of users) {
4012
+ * console.log(`${u.name} (${u.email})`);
4013
+ * }
4014
+ * ```
4015
+ */
4016
+ async resolveUsers(userIds) {
4017
+ const { data } = await request(
4018
+ this._httpConfig,
4019
+ "POST",
4020
+ "/helpers/resolve-users",
4021
+ { userIds }
4022
+ );
4023
+ return data;
4024
+ }
4025
+ // -------------------------------------------------------------------------
4026
+ // App context
4027
+ // -------------------------------------------------------------------------
4028
+ /**
4029
+ * Get auth and database context for an app.
4030
+ *
4031
+ * Returns role assignments and managed database schemas. Useful for
4032
+ * hydrating `auth` and `db` namespaces when running outside the sandbox.
4033
+ *
4034
+ * When called with a CALLBACK_TOKEN (managed mode), `appId` is optional —
4035
+ * the platform resolves the app from the token. With an API key, `appId`
4036
+ * is required.
4037
+ *
4038
+ * ```ts
4039
+ * const ctx = await agent.getAppContext('your-app-id');
4040
+ * console.log(ctx.auth.roleAssignments, ctx.databases);
4041
+ * ```
4042
+ */
4043
+ async getAppContext(appId) {
4044
+ const query = appId ? `?appId=${encodeURIComponent(appId)}` : "";
4045
+ const { data } = await request(
4046
+ this._httpConfig,
4047
+ "GET",
4048
+ `/helpers/app-context${query}`
4049
+ );
4050
+ return data;
4051
+ }
4052
+ // -------------------------------------------------------------------------
4053
+ // Account methods
4054
+ // -------------------------------------------------------------------------
4055
+ /** Update the display name of the authenticated user/agent. */
4056
+ async changeName(displayName) {
4057
+ await request(this._httpConfig, "POST", "/account/change-name", {
4058
+ name: displayName
4059
+ });
4060
+ }
4061
+ /** Update the profile picture of the authenticated user/agent. */
4062
+ async changeProfilePicture(url) {
4063
+ await request(this._httpConfig, "POST", "/account/change-profile-picture", {
4064
+ url
4065
+ });
4066
+ }
4067
+ /**
4068
+ * Upload a file to the MindStudio CDN.
4069
+ *
4070
+ * Gets a signed upload URL, PUTs the file content, and returns the
4071
+ * permanent public URL.
4072
+ */
4073
+ async uploadFile(content, options) {
4074
+ const { data } = await request(
4075
+ this._httpConfig,
4076
+ "POST",
4077
+ "/account/upload",
4078
+ {
4079
+ extension: options.extension,
4080
+ ...options.type != null && { type: options.type }
4081
+ }
4082
+ );
4083
+ const buf = content.buffer.slice(
4084
+ content.byteOffset,
4085
+ content.byteOffset + content.byteLength
4086
+ );
4087
+ const res = await fetch(data.uploadUrl, {
4088
+ method: "PUT",
4089
+ body: buf,
4090
+ headers: options.type ? { "Content-Type": options.type } : {}
4091
+ });
4092
+ if (!res.ok) {
4093
+ const errorBody = await res.json().catch(() => ({}));
4094
+ throw new MindStudioError(
4095
+ errorBody.message ?? errorBody.error ?? `Upload failed: ${res.status} ${res.statusText}`,
4096
+ errorBody.code ?? "upload_error",
4097
+ res.status,
4098
+ errorBody
4099
+ );
4100
+ }
4101
+ return { url: data.url };
4102
+ }
4103
+ };
4104
+ function sleep2(ms) {
4105
+ return new Promise((resolve) => setTimeout(resolve, ms));
4106
+ }
4107
+ applyStepMethods(MindStudioAgent);
4108
+ function resolveStepType(name) {
4109
+ const meta = stepMetadata[name];
4110
+ return meta ? meta.stepType : name;
4111
+ }
4112
+ function resolveToken(provided, config) {
4113
+ if (process.env.CALLBACK_TOKEN)
4114
+ return { token: process.env.CALLBACK_TOKEN, authType: "internal" };
4115
+ if (provided) return { token: provided, authType: "apiKey" };
4116
+ if (process.env.MINDSTUDIO_API_KEY)
4117
+ return { token: process.env.MINDSTUDIO_API_KEY, authType: "apiKey" };
4118
+ if (config?.apiKey)
4119
+ return { token: config.apiKey, authType: "apiKey" };
4120
+ throw new MindStudioError(
4121
+ "No API key provided. Run `mindstudio login`, pass `apiKey` to the constructor, or set the MINDSTUDIO_API_KEY environment variable.",
4122
+ "missing_api_key",
4123
+ 401
4124
+ );
4125
+ }
4126
+
4127
+ // src/generated/snippets.ts
4128
+ var monacoSnippets = {
4129
+ "activeCampaignAddNote": { fields: [["contactId", "string"], ["note", "string"]], outputKeys: [] },
4130
+ "activeCampaignCreateContact": { fields: [["email", "string"], ["firstName", "string"], ["lastName", "string"], ["phone", "string"], ["accountId", "string"], ["customFields", "object"]], outputKeys: ["contactId"] },
4131
+ "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"] },
4132
+ "airtableCreateUpdateRecord": { fields: [["baseId", "string"], ["tableId", "string"], ["fields", "string"], ["recordData", "object"]], outputKeys: ["recordId"] },
4133
+ "airtableDeleteRecord": { fields: [["baseId", "string"], ["tableId", "string"], ["recordId", "string"]], outputKeys: ["deleted"] },
4134
+ "airtableGetRecord": { fields: [["baseId", "string"], ["tableId", "string"], ["recordId", "string"]], outputKeys: ["record"] },
4135
+ "airtableGetTableRecords": { fields: [["baseId", "string"], ["tableId", "string"]], outputKeys: ["records"] },
4136
+ "analyzeImage": { fields: [["prompt", "string"], ["imageUrl", "string"]], outputKeys: ["analysis"] },
4137
+ "analyzeVideo": { fields: [["prompt", "string"], ["videoUrl", "string"]], outputKeys: ["analysis"] },
4138
+ "captureThumbnail": { fields: [["videoUrl", "string"], ["at", "string"]], outputKeys: ["thumbnailUrl"] },
4139
+ "checkAppRole": { fields: [["roleName", "string"]], outputKeys: ["hasRole", "userRoles"] },
4140
+ "codaCreateUpdatePage": { fields: [["pageData", "object"]], outputKeys: ["pageId"] },
4141
+ "codaCreateUpdateRow": { fields: [["docId", "string"], ["tableId", "string"], ["rowData", "object"]], outputKeys: ["rowId"] },
4142
+ "codaFindRow": { fields: [["docId", "string"], ["tableId", "string"], ["rowData", "object"]], outputKeys: ["row"] },
4143
+ "codaGetPage": { fields: [["docId", "string"], ["pageId", "string"]], outputKeys: ["content"] },
4144
+ "codaGetTableRows": { fields: [["docId", "string"], ["tableId", "string"]], outputKeys: ["rows"] },
4145
+ "convertPdfToImages": { fields: [["pdfUrl", "string"]], outputKeys: ["imageUrls"] },
4146
+ "createDataSource": { fields: [["name", "string"]], outputKeys: [] },
4147
+ "createGmailDraft": { fields: [["to", "string"], ["subject", "string"], ["message", "string"], ["messageType", ["plain", "html", "markdown"]]], outputKeys: ["draftId"] },
4148
+ "createGoogleCalendarEvent": { fields: [["summary", "string"], ["startDateTime", "string"], ["endDateTime", "string"]], outputKeys: ["eventId", "htmlLink"] },
4149
+ "createGoogleDoc": { fields: [["title", "string"], ["text", "string"], ["textType", ["plain", "html", "markdown"]]], outputKeys: ["documentUrl"] },
4150
+ "createGoogleSheet": { fields: [["title", "string"], ["text", "string"]], outputKeys: ["spreadsheetUrl"] },
4151
+ "deleteDataSource": { fields: [["dataSourceId", "string"]], outputKeys: [] },
4152
+ "deleteDataSourceDocument": { fields: [["dataSourceId", "string"], ["documentId", "string"]], outputKeys: [] },
4153
+ "deleteGmailEmail": { fields: [["messageId", "string"]], outputKeys: [] },
4154
+ "deleteGoogleCalendarEvent": { fields: [["eventId", "string"]], outputKeys: [] },
4155
+ "deleteGoogleSheetRows": { fields: [["documentId", "string"], ["startRow", "string"], ["endRow", "string"]], outputKeys: [] },
4156
+ "detectChanges": { fields: [["mode", ["ai", "comparison"]], ["input", "string"]], outputKeys: ["hasChanged", "currentValue", "previousValue", "isFirstRun"] },
4157
+ "detectPII": { fields: [["input", "string"], ["language", "string"], ["entities", "array"]], outputKeys: ["detected", "detections"] },
4158
+ "discordEditMessage": { fields: [["botToken", "string"], ["channelId", "string"], ["messageId", "string"], ["text", "string"]], outputKeys: [] },
4159
+ "discordSendFollowUp": { fields: [["applicationId", "string"], ["interactionToken", "string"], ["text", "string"]], outputKeys: ["messageId"] },
4160
+ "discordSendMessage": { fields: [["mode", ["edit", "send"]], ["text", "string"]], outputKeys: [] },
4161
+ "downloadVideo": { fields: [["videoUrl", "string"], ["format", ["mp4", "mp3"]]], outputKeys: ["videoUrl"] },
4162
+ "enhanceImageGenerationPrompt": { fields: [["initialPrompt", "string"], ["includeNegativePrompt", "boolean"], ["systemPrompt", "string"]], outputKeys: ["prompt"] },
4163
+ "enhanceVideoGenerationPrompt": { fields: [["initialPrompt", "string"], ["includeNegativePrompt", "boolean"], ["systemPrompt", "string"]], outputKeys: ["prompt"] },
4164
+ "enrichPerson": { fields: [["params", "object"]], outputKeys: ["data"] },
4165
+ "extractAudioFromVideo": { fields: [["videoUrl", "string"]], outputKeys: ["audioUrl"] },
4166
+ "extractText": { fields: [["url", "string"]], outputKeys: ["text"] },
4167
+ "fetchDataSourceDocument": { fields: [["dataSourceId", "string"], ["documentId", "string"]], outputKeys: [] },
4168
+ "fetchGoogleDoc": { fields: [["documentId", "string"], ["exportType", ["html", "markdown", "json", "plain"]]], outputKeys: ["content"] },
4169
+ "fetchGoogleSheet": { fields: [["spreadsheetId", "string"], ["range", "string"], ["exportType", ["csv", "json"]]], outputKeys: ["content"] },
4170
+ "fetchSlackChannelHistory": { fields: [["channelId", "string"]], outputKeys: ["messages"] },
4171
+ "fetchYoutubeCaptions": { fields: [["videoUrl", "string"], ["exportType", ["text", "json"]], ["language", "string"]], outputKeys: ["transcripts"] },
4172
+ "fetchYoutubeChannel": { fields: [["channelUrl", "string"]], outputKeys: [] },
4173
+ "fetchYoutubeComments": { fields: [["videoUrl", "string"], ["exportType", ["text", "json"]], ["limitPages", "string"]], outputKeys: ["comments"] },
4174
+ "fetchYoutubeVideo": { fields: [["videoUrl", "string"]], outputKeys: [] },
4175
+ "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"] },
4176
+ "generateChart": { fields: [["chart", "object"]], outputKeys: ["chartUrl"] },
4177
+ "generateImage": { fields: [["prompt", "string"]], outputKeys: ["imageUrl"] },
4178
+ "generateLipsync": { fields: [], outputKeys: [] },
4179
+ "generateMusic": { fields: [["text", "string"]], outputKeys: [] },
4180
+ "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"] },
4181
+ "generateStaticVideoFromImage": { fields: [["imageUrl", "string"], ["duration", "string"]], outputKeys: ["videoUrl"] },
4182
+ "generateText": { fields: [["message", "string"]], outputKeys: ["content"] },
4183
+ "generateVideo": { fields: [["prompt", "string"]], outputKeys: ["videoUrl"] },
4184
+ "getGmailAttachments": { fields: [["messageId", "string"]], outputKeys: [] },
4185
+ "getGmailDraft": { fields: [["draftId", "string"]], outputKeys: ["draftId", "messageId", "subject", "to", "from", "body"] },
4186
+ "getGmailEmail": { fields: [["messageId", "string"]], outputKeys: ["messageId", "subject", "from", "to", "date", "body", "labels"] },
4187
+ "getGmailUnreadCount": { fields: [], outputKeys: [] },
4188
+ "getGoogleCalendarEvent": { fields: [["eventId", "string"], ["exportType", ["json", "text"]]], outputKeys: ["event"] },
4189
+ "getGoogleDriveFile": { fields: [["fileId", "string"]], outputKeys: ["url", "name", "mimeType", "size"] },
4190
+ "getGoogleSheetInfo": { fields: [["documentId", "string"]], outputKeys: ["title", "sheets"] },
4191
+ "getMediaMetadata": { fields: [["mediaUrl", "string"]], outputKeys: ["metadata"] },
4192
+ "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"] },
4193
+ "hubspotCreateCompany": { fields: [["company", "object"], ["enabledProperties", "array"]], outputKeys: ["companyId"] },
4194
+ "hubspotCreateContact": { fields: [["contact", "object"], ["enabledProperties", "array"], ["companyDomain", "string"]], outputKeys: ["contactId"] },
4195
+ "hubspotGetCompany": { fields: [["searchBy", ["domain", "id"]], ["companyDomain", "string"], ["companyId", "string"], ["additionalProperties", "array"]], outputKeys: ["company"] },
4196
+ "hubspotGetContact": { fields: [["searchBy", ["email", "id"]], ["contactEmail", "string"], ["contactId", "string"], ["additionalProperties", "array"]], outputKeys: ["contact"] },
4197
+ "hunterApiCompanyEnrichment": { fields: [["domain", "string"]], outputKeys: ["data"] },
4198
+ "hunterApiDomainSearch": { fields: [["domain", "string"]], outputKeys: ["data"] },
4199
+ "hunterApiEmailFinder": { fields: [["domain", "string"], ["firstName", "string"], ["lastName", "string"]], outputKeys: ["data"] },
4200
+ "hunterApiEmailVerification": { fields: [["email", "string"]], outputKeys: ["data"] },
4201
+ "hunterApiPersonEnrichment": { fields: [["email", "string"]], outputKeys: ["data"] },
4202
+ "imageFaceSwap": { fields: [["imageUrl", "string"], ["faceImageUrl", "string"], ["engine", "string"]], outputKeys: ["imageUrl"] },
4203
+ "imageRemoveWatermark": { fields: [["imageUrl", "string"], ["engine", "string"]], outputKeys: ["imageUrl"] },
4204
+ "insertVideoClips": { fields: [["baseVideoUrl", "string"], ["overlayVideos", "array"]], outputKeys: ["videoUrl"] },
4205
+ "listDataSources": { fields: [], outputKeys: [] },
4206
+ "listGmailDrafts": { fields: [["exportType", ["json", "text"]]], outputKeys: ["drafts"] },
4207
+ "listGmailLabels": { fields: [], outputKeys: [] },
4208
+ "listGoogleCalendarEvents": { fields: [["limit", "number"], ["exportType", ["json", "text"]]], outputKeys: ["events"] },
4209
+ "listGoogleDriveFiles": { fields: [["exportType", ["json", "text"]]], outputKeys: ["files"] },
4210
+ "listRecentGmailEmails": { fields: [["exportType", ["json", "text"]], ["limit", "string"]], outputKeys: [] },
4211
+ "logic": { fields: [["context", "string"], ["cases", "array"]], outputKeys: ["selectedCase"] },
4212
+ "makeDotComRunScenario": { fields: [["webhookUrl", "string"], ["input", "object"]], outputKeys: ["data"] },
4213
+ "mergeAudio": { fields: [["mp3Urls", "array"]], outputKeys: ["audioUrl"] },
4214
+ "mergeVideos": { fields: [["videoUrls", "array"]], outputKeys: ["videoUrl"] },
4215
+ "mixAudioIntoVideo": { fields: [["videoUrl", "string"], ["audioUrl", "string"], ["options", "object"]], outputKeys: ["videoUrl"] },
4216
+ "muteVideo": { fields: [["videoUrl", "string"]], outputKeys: ["videoUrl"] },
4217
+ "n8nRunNode": { fields: [["method", "string"], ["authentication", ["none", "basic", "string"]], ["user", "string"], ["password", "string"], ["webhookUrl", "string"], ["input", "object"]], outputKeys: ["data"] },
4218
+ "notionCreatePage": { fields: [["pageId", "string"], ["content", "string"], ["title", "string"]], outputKeys: ["pageId", "pageUrl"] },
4219
+ "notionUpdatePage": { fields: [["pageId", "string"], ["content", "string"], ["mode", ["append", "overwrite"]]], outputKeys: ["pageId", "pageUrl"] },
4220
+ "peopleSearch": { fields: [["smartQuery", "string"], ["enrichPeople", "boolean"], ["enrichOrganizations", "boolean"], ["limit", "string"], ["page", "string"], ["params", "object"]], outputKeys: ["results"] },
4221
+ "postToLinkedIn": { fields: [["message", "string"], ["visibility", ["PUBLIC", "CONNECTIONS"]]], outputKeys: [] },
4222
+ "postToSlackChannel": { fields: [["channelId", "string"], ["messageType", ["string", "blocks"]], ["message", "string"]], outputKeys: [] },
4223
+ "postToX": { fields: [["text", "string"]], outputKeys: [] },
4224
+ "postToZapier": { fields: [["webhookUrl", "string"], ["input", "object"]], outputKeys: ["data"] },
4225
+ "queryAppDatabase": { fields: [["databaseId", "string"], ["sql", "string"]], outputKeys: ["rows", "changes"] },
4226
+ "queryDataSource": { fields: [["dataSourceId", "string"], ["query", "string"], ["maxResults", "number"]], outputKeys: ["text", "chunks", "query", "citations", "latencyMs"] },
4227
+ "queryExternalDatabase": { fields: [["query", "string"], ["outputFormat", ["json", "csv"]]], outputKeys: ["data"] },
4228
+ "redactPII": { fields: [["input", "string"], ["language", "string"], ["entities", "array"]], outputKeys: ["text"] },
4229
+ "removeBackgroundFromImage": { fields: [["imageUrl", "string"]], outputKeys: ["imageUrl"] },
4230
+ "replyToGmailEmail": { fields: [["messageId", "string"], ["message", "string"], ["messageType", ["plain", "html", "markdown"]]], outputKeys: ["messageId"] },
4231
+ "resizeVideo": { fields: [["videoUrl", "string"], ["mode", ["fit", "exact"]]], outputKeys: ["videoUrl"] },
4232
+ "runFromConnectorRegistry": { fields: [["actionId", "string"], ["displayName", "string"], ["icon", "string"], ["configurationValues", "object"]], outputKeys: ["data"] },
4233
+ "runPackagedWorkflow": { fields: [["appId", "string"], ["workflowId", "string"], ["inputVariables", "object"], ["outputVariables", "object"], ["name", "string"]], outputKeys: ["data"] },
4234
+ "scrapeFacebookPage": { fields: [["pageUrl", "string"]], outputKeys: ["data"] },
4235
+ "scrapeFacebookPosts": { fields: [["pageUrl", "string"]], outputKeys: ["data"] },
4236
+ "scrapeInstagramComments": { fields: [["postUrl", "string"], ["resultsLimit", "string"]], outputKeys: ["data"] },
4237
+ "scrapeInstagramMentions": { fields: [["profileUrl", "string"], ["resultsLimit", "string"]], outputKeys: ["data"] },
4238
+ "scrapeInstagramPosts": { fields: [["profileUrl", "string"], ["resultsLimit", "string"], ["onlyPostsNewerThan", "string"]], outputKeys: ["data"] },
4239
+ "scrapeInstagramProfile": { fields: [["profileUrl", "string"]], outputKeys: ["data"] },
4240
+ "scrapeInstagramReels": { fields: [["profileUrl", "string"], ["resultsLimit", "string"]], outputKeys: ["data"] },
4241
+ "scrapeLinkedInCompany": { fields: [["url", "string"]], outputKeys: ["company"] },
4242
+ "scrapeLinkedInProfile": { fields: [["url", "string"]], outputKeys: ["profile"] },
4243
+ "scrapeMetaThreadsProfile": { fields: [["profileUrl", "string"]], outputKeys: ["data"] },
4244
+ "scrapeUrl": { fields: [["url", "string"]], outputKeys: ["content"] },
4245
+ "scrapeXPost": { fields: [["url", "string"]], outputKeys: ["post"] },
4246
+ "scrapeXProfile": { fields: [["url", "string"]], outputKeys: ["profile"] },
4247
+ "screenshotUrl": { fields: [["url", "string"]], outputKeys: ["screenshotUrl"] },
4248
+ "searchGmailEmails": { fields: [["query", "string"], ["exportType", ["json", "text"]], ["limit", "string"]], outputKeys: ["emails"] },
4249
+ "searchGoogle": { fields: [["query", "string"], ["exportType", ["text", "json"]]], outputKeys: ["results"] },
4250
+ "searchGoogleCalendarEvents": { fields: [["exportType", ["json", "text"]]], outputKeys: ["events"] },
4251
+ "searchGoogleDrive": { fields: [["query", "string"], ["exportType", ["json", "text"]]], outputKeys: ["files"] },
4252
+ "searchGoogleImages": { fields: [["query", "string"], ["exportType", ["text", "json"]]], outputKeys: ["images"] },
4253
+ "searchGoogleNews": { fields: [["text", "string"], ["exportType", ["text", "json"]]], outputKeys: ["articles"] },
4254
+ "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"] },
4255
+ "searchPerplexity": { fields: [["query", "string"], ["exportType", ["text", "json"]]], outputKeys: ["results"] },
4256
+ "searchXPosts": { fields: [["query", "string"], ["scope", ["recent", "all"]], ["options", "object"]], outputKeys: ["posts"] },
4257
+ "searchYoutube": { fields: [["query", "string"], ["limitPages", "string"], ["filter", "string"], ["filterType", "string"]], outputKeys: ["results"] },
4258
+ "searchYoutubeTrends": { fields: [["bp", ["now", "music", "gaming", "films"]], ["hl", "string"], ["gl", "string"]], outputKeys: [] },
4259
+ "sendEmail": { fields: [["subject", "string"], ["body", "string"]], outputKeys: ["recipients"] },
4260
+ "sendGmailDraft": { fields: [["draftId", "string"]], outputKeys: [] },
4261
+ "sendGmailMessage": { fields: [["to", "string"], ["subject", "string"], ["message", "string"], ["messageType", ["plain", "html", "markdown"]]], outputKeys: ["messageId"] },
4262
+ "sendSMS": { fields: [["body", "string"]], outputKeys: [] },
4263
+ "setGmailReadStatus": { fields: [["messageIds", "string"], ["markAsRead", "boolean"]], outputKeys: [] },
4264
+ "setRunTitle": { fields: [["title", "string"]], outputKeys: [] },
4265
+ "setVariable": { fields: [["value", "string"]], outputKeys: [] },
4266
+ "telegramEditMessage": { fields: [["botToken", "string"], ["chatId", "string"], ["messageId", "string"], ["text", "string"]], outputKeys: [] },
4267
+ "telegramReplyToMessage": { fields: [["botToken", "string"], ["chatId", "string"], ["replyToMessageId", "string"], ["text", "string"]], outputKeys: ["messageId"] },
4268
+ "telegramSendAudio": { fields: [["botToken", "string"], ["chatId", "string"], ["audioUrl", "string"], ["mode", ["audio", "voice"]]], outputKeys: [] },
4269
+ "telegramSendFile": { fields: [["botToken", "string"], ["chatId", "string"], ["fileUrl", "string"]], outputKeys: [] },
4270
+ "telegramSendImage": { fields: [["botToken", "string"], ["chatId", "string"], ["imageUrl", "string"]], outputKeys: [] },
4271
+ "telegramSendMessage": { fields: [["botToken", "string"], ["chatId", "string"], ["text", "string"]], outputKeys: ["messageId"] },
4272
+ "telegramSendVideo": { fields: [["botToken", "string"], ["chatId", "string"], ["videoUrl", "string"]], outputKeys: [] },
4273
+ "telegramSetTyping": { fields: [["botToken", "string"], ["chatId", "string"]], outputKeys: [] },
4274
+ "textToSpeech": { fields: [["text", "string"]], outputKeys: ["audioUrl"] },
4275
+ "transcribeAudio": { fields: [["audioUrl", "string"], ["prompt", "string"]], outputKeys: ["text"] },
4276
+ "trimMedia": { fields: [["inputUrl", "string"]], outputKeys: ["mediaUrl"] },
4277
+ "updateGmailLabels": { fields: [["query", "string"], ["messageIds", "string"], ["addLabelIds", "string"], ["removeLabelIds", "string"]], outputKeys: ["updatedMessageIds"] },
4278
+ "updateGoogleCalendarEvent": { fields: [["eventId", "string"]], outputKeys: ["eventId", "htmlLink"] },
4279
+ "updateGoogleDoc": { fields: [["documentId", "string"], ["text", "string"], ["textType", ["plain", "html", "markdown"]], ["operationType", ["addToTop", "addToBottom", "overwrite"]]], outputKeys: ["documentUrl"] },
4280
+ "updateGoogleSheet": { fields: [["text", "string"], ["spreadsheetId", "string"], ["range", "string"], ["operationType", ["addToBottom", "overwrite", "range"]]], outputKeys: ["spreadsheetUrl"] },
4281
+ "uploadDataSourceDocument": { fields: [["dataSourceId", "string"], ["file", "string"], ["fileName", "string"]], outputKeys: [] },
4282
+ "upscaleImage": { fields: [["imageUrl", "string"], ["targetResolution", ["2k", "4k", "8k"]], ["engine", ["standard", "pro"]]], outputKeys: ["imageUrl"] },
4283
+ "upscaleVideo": { fields: [["videoUrl", "string"], ["targetResolution", ["720p", "1080p", "2K", "4K"]], ["engine", ["standard", "pro", "ultimate", "flashvsr", "seedance", "seedvr2", "runwayml/upscale-v1"]]], outputKeys: ["videoUrl"] },
4284
+ "userMessage": { fields: [["message", "string"]], outputKeys: ["content"] },
4285
+ "videoFaceSwap": { fields: [["videoUrl", "string"], ["faceImageUrl", "string"], ["targetIndex", "number"], ["engine", "string"]], outputKeys: ["videoUrl"] },
4286
+ "videoRemoveBackground": { fields: [["videoUrl", "string"], ["newBackground", ["transparent", "image"]], ["engine", "string"]], outputKeys: ["videoUrl"] },
4287
+ "videoRemoveWatermark": { fields: [["videoUrl", "string"], ["engine", "string"]], outputKeys: ["videoUrl"] },
4288
+ "watermarkImage": { fields: [["imageUrl", "string"], ["watermarkImageUrl", "string"], ["corner", ["top-left", "top-right", "bottom-left", "bottom-right"]], ["paddingPx", "number"], ["widthPx", "number"]], outputKeys: ["imageUrl"] },
4289
+ "watermarkVideo": { fields: [["videoUrl", "string"], ["imageUrl", "string"], ["corner", ["top-left", "top-right", "bottom-left", "bottom-right"]], ["paddingPx", "number"], ["widthPx", "number"]], outputKeys: ["videoUrl"] }
4290
+ };
4291
+ var blockTypeAliases = {
4292
+ "userMessage": "generateText",
4293
+ "generatePdf": "generateAsset"
4294
+ };
4295
+
4292
4296
  // src/index.ts
4293
4297
  var MindStudioAgent2 = MindStudioAgent;
4294
4298
  var _default;