@mindstudio-ai/agent 0.1.46 → 0.1.48

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.
@@ -1242,9 +1242,9 @@ async function requestWithRetry(config, method, url, body, attempt) {
1242
1242
  body: body != null ? JSON.stringify(body) : void 0
1243
1243
  });
1244
1244
  config.rateLimiter.updateFromHeaders(res.headers);
1245
- if (res.status === 429 && attempt < config.maxRetries) {
1245
+ if (attempt < config.maxRetries && (res.status === 429 || res.status === 502 || res.status === 503 || res.status === 504)) {
1246
1246
  const retryAfter = res.headers.get("retry-after");
1247
- const waitMs = retryAfter ? parseFloat(retryAfter) * 1e3 : 1e3;
1247
+ const waitMs = retryAfter ? parseFloat(retryAfter) * 1e3 : Math.min(1e3 * Math.pow(2, attempt), 1e4);
1248
1248
  await sleep(waitMs);
1249
1249
  return requestWithRetry(config, method, url, body, attempt + 1);
1250
1250
  }
@@ -2776,15 +2776,16 @@ var init_table = __esm({
2776
2776
  // -------------------------------------------------------------------------
2777
2777
  // Internal helpers
2778
2778
  // -------------------------------------------------------------------------
2779
- /** @internal Throw if data includes a platform-managed email/phone column. */
2779
+ /** @internal Throw if data includes a platform-managed read-only column. */
2780
2780
  _checkManagedColumns(data) {
2781
2781
  const mc = this._config.managedColumns;
2782
2782
  if (!mc) return;
2783
2783
  const keys = Object.keys(data);
2784
2784
  for (const key of keys) {
2785
- if (mc.email && key === mc.email || mc.phone && key === mc.phone) {
2785
+ if (mc.email && key === mc.email || mc.phone && key === mc.phone || mc.apiKey && key === mc.apiKey) {
2786
+ const friendly = key === mc.email ? "email" : key === mc.phone ? "phone" : "API key";
2786
2787
  throw new MindStudioError(
2787
- `Cannot write to "${key}" \u2014 this column is managed by auth. Use the auth API to change a user's ${key === mc.email ? "email" : "phone"}.`,
2788
+ `Cannot write to "${key}" \u2014 this column is managed by auth. Use the auth API to change a user's ${friendly}.`,
2788
2789
  "managed_column_write",
2789
2790
  400
2790
2791
  );
@@ -3006,7 +3007,7 @@ function buildTaskRequestBody(options) {
3006
3007
  prompt: options.prompt,
3007
3008
  input: options.input,
3008
3009
  tools: mapTools(options.tools),
3009
- structuredOutputExample: options.structuredOutputExample,
3010
+ structuredOutputExample: typeof options.structuredOutputExample === "string" ? options.structuredOutputExample : JSON.stringify(options.structuredOutputExample),
3010
3011
  model: options.model,
3011
3012
  ...options.maxTurns != null && { maxTurns: options.maxTurns },
3012
3013
  ...options.appId != null && { appId: options.appId },
@@ -3016,6 +3017,16 @@ function buildTaskRequestBody(options) {
3016
3017
  function sleep2(ms) {
3017
3018
  return new Promise((resolve) => setTimeout(resolve, ms));
3018
3019
  }
3020
+ function isDevMode() {
3021
+ return !!(process.env.CALLBACK_TOKEN || getRequestContext()?.callbackToken);
3022
+ }
3023
+ function logTaskResult(result) {
3024
+ if (!isDevMode()) return;
3025
+ const toolSummary = result.toolCalls.map((tc) => `${tc.name} (${tc.durationMs}ms) ${tc.success ? "\u2713" : "\u2717"}`).join(", ");
3026
+ console.log(
3027
+ `[task] ${result.turns} turn${result.turns === 1 ? "" : "s"}` + (toolSummary ? `: ${toolSummary}` : "") + ` | ${result.parsedSuccessfully ? "output OK" : "\u26A0 output not valid JSON"} | cost: ${result.usage.totalBillingCost}`
3028
+ );
3029
+ }
3019
3030
  async function runTaskPoll(httpConfig, body) {
3020
3031
  const { data } = await request(
3021
3032
  httpConfig,
@@ -3031,6 +3042,7 @@ async function runTaskPoll(httpConfig, body) {
3031
3042
  const res = await fetch(pollUrl, {
3032
3043
  headers: { "User-Agent": "@mindstudio-ai/agent" }
3033
3044
  });
3045
+ if (res.status === 502 || res.status === 503 || res.status === 504) continue;
3034
3046
  if (res.status === 404) {
3035
3047
  throw new MindStudioError(
3036
3048
  "Task poll token not found or expired.",
@@ -3048,7 +3060,12 @@ async function runTaskPoll(httpConfig, body) {
3048
3060
  );
3049
3061
  }
3050
3062
  const poll = await res.json();
3051
- if (poll.status === "pending") continue;
3063
+ if (poll.status === "pending") {
3064
+ if (isDevMode() && poll.currentTurn != null) {
3065
+ console.log(`[task] running... turn ${poll.currentTurn}/${poll.maxTurns ?? "?"}`);
3066
+ }
3067
+ continue;
3068
+ }
3052
3069
  if (poll.status === "error") {
3053
3070
  throw new MindStudioError(
3054
3071
  poll.error ?? "Task execution failed.",
@@ -3056,11 +3073,16 @@ async function runTaskPoll(httpConfig, body) {
3056
3073
  500
3057
3074
  );
3058
3075
  }
3059
- return {
3076
+ const result = {
3060
3077
  output: poll.output,
3078
+ outputRaw: poll.outputRaw ?? "",
3079
+ parsedSuccessfully: poll.parsedSuccessfully ?? true,
3061
3080
  turns: poll.turns ?? 0,
3062
- usage: poll.usage ?? { inputTokens: 0, outputTokens: 0, totalBillingCost: 0 }
3081
+ usage: poll.usage ?? { inputTokens: 0, outputTokens: 0, totalBillingCost: 0 },
3082
+ toolCalls: poll.toolCalls ?? []
3063
3083
  };
3084
+ logTaskResult(result);
3085
+ return result;
3064
3086
  }
3065
3087
  }
3066
3088
  async function runTaskStream(httpConfig, body, onEvent) {
@@ -3120,12 +3142,15 @@ async function runTaskStream(httpConfig, body, onEvent) {
3120
3142
  if (event.type === "done") {
3121
3143
  result = {
3122
3144
  output: event.output,
3145
+ outputRaw: event.outputRaw ?? "",
3146
+ parsedSuccessfully: event.parsedSuccessfully ?? true,
3123
3147
  turns: event.turns ?? 0,
3124
3148
  usage: event.usage ?? {
3125
3149
  inputTokens: 0,
3126
3150
  outputTokens: 0,
3127
3151
  totalBillingCost: 0
3128
- }
3152
+ },
3153
+ toolCalls: event.toolCalls ?? []
3129
3154
  };
3130
3155
  }
3131
3156
  } catch (err) {
@@ -3147,12 +3172,15 @@ async function runTaskStream(httpConfig, body, onEvent) {
3147
3172
  if (event.type === "done") {
3148
3173
  result = {
3149
3174
  output: event.output,
3175
+ outputRaw: event.outputRaw ?? "",
3176
+ parsedSuccessfully: event.parsedSuccessfully ?? true,
3150
3177
  turns: event.turns ?? 0,
3151
3178
  usage: event.usage ?? {
3152
3179
  inputTokens: 0,
3153
3180
  outputTokens: 0,
3154
3181
  totalBillingCost: 0
3155
- }
3182
+ },
3183
+ toolCalls: event.toolCalls ?? []
3156
3184
  };
3157
3185
  }
3158
3186
  } catch (err) {
@@ -3166,6 +3194,7 @@ async function runTaskStream(httpConfig, body, onEvent) {
3166
3194
  500
3167
3195
  );
3168
3196
  }
3197
+ logTaskResult(result);
3169
3198
  return result;
3170
3199
  }
3171
3200
  var init_task = __esm({
@@ -3173,6 +3202,7 @@ var init_task = __esm({
3173
3202
  "use strict";
3174
3203
  init_http();
3175
3204
  init_errors();
3205
+ init_context();
3176
3206
  init_metadata();
3177
3207
  }
3178
3208
  });
@@ -3825,48 +3855,80 @@ var init_client = __esm({
3825
3855
  );
3826
3856
  }
3827
3857
  const threadId = options?.threadId ?? (this._reuseThreadId && !getRequestContext() ? this._threadId : void 0);
3828
- const { data, headers } = await request(this._httpConfig, "POST", `/steps/${stepType}/execute`, {
3858
+ const { data: asyncData, headers } = await request(this._currentHttpConfig, "POST", `/steps/${stepType}/execute-async`, {
3829
3859
  step,
3830
3860
  ...options?.appId != null && { appId: options.appId },
3831
3861
  ...threadId != null && { threadId },
3832
3862
  ...this._currentStreamId != null && { streamId: this._currentStreamId }
3833
3863
  });
3834
- let output;
3835
- if (data.output != null) {
3836
- output = data.output;
3837
- } else if (data.outputUrl) {
3838
- const res = await fetch(data.outputUrl);
3864
+ const remaining = headers.get("x-ratelimit-remaining");
3865
+ const returnedThreadId = asyncData.threadId ?? "";
3866
+ if (this._reuseThreadId && returnedThreadId && !getRequestContext()) {
3867
+ this._threadId = returnedThreadId;
3868
+ }
3869
+ if (!this._appId && asyncData.appId && !getRequestContext()) {
3870
+ this._appId = asyncData.appId;
3871
+ }
3872
+ const pollUrl = `${this._currentHttpConfig.baseUrl}/developer/v2/steps/${stepType}/execute-async/poll/${asyncData.executionToken}`;
3873
+ let pollDelay = 100;
3874
+ while (true) {
3875
+ await sleep3(pollDelay);
3876
+ pollDelay = Math.min(pollDelay * 2, 5e3);
3877
+ const res = await fetch(pollUrl, {
3878
+ headers: { "User-Agent": "@mindstudio-ai/agent" }
3879
+ });
3880
+ if (res.status === 502 || res.status === 503 || res.status === 504) continue;
3881
+ if (res.status === 404) {
3882
+ throw new MindStudioError(
3883
+ `[${stepType}] Execution token expired.`,
3884
+ "poll_token_expired",
3885
+ 404
3886
+ );
3887
+ }
3839
3888
  if (!res.ok) {
3889
+ const errorBody = await res.json().catch(() => ({}));
3840
3890
  throw new MindStudioError(
3841
- `Failed to fetch ${stepType} output from S3: ${res.status} ${res.statusText}`,
3842
- "output_fetch_error",
3843
- res.status
3891
+ errorBody.message ?? errorBody.error ?? `[${stepType}] Poll failed: ${res.status} ${res.statusText}`,
3892
+ errorBody.code ?? "poll_error",
3893
+ res.status,
3894
+ errorBody
3844
3895
  );
3845
3896
  }
3846
- const envelope = await res.json();
3847
- output = envelope.value;
3848
- } else {
3849
- output = void 0;
3850
- }
3851
- const returnedThreadId = headers.get("x-mindstudio-thread-id") ?? "";
3852
- if (this._reuseThreadId && returnedThreadId && !getRequestContext()) {
3853
- this._threadId = returnedThreadId;
3854
- }
3855
- const returnedAppId = headers.get("x-mindstudio-app-id");
3856
- if (!this._appId && returnedAppId && !getRequestContext()) {
3857
- this._appId = returnedAppId;
3897
+ const poll = await res.json();
3898
+ if (poll.status === "pending") continue;
3899
+ if (poll.status === "error") {
3900
+ throw new MindStudioError(
3901
+ `[${stepType}] ${poll.error ?? "Step execution failed."}`,
3902
+ "step_error",
3903
+ 500
3904
+ );
3905
+ }
3906
+ let output;
3907
+ if (poll.output != null) {
3908
+ output = poll.output;
3909
+ } else if (poll.outputUrl) {
3910
+ const s3Res = await fetch(poll.outputUrl);
3911
+ if (!s3Res.ok) {
3912
+ throw new MindStudioError(
3913
+ `Failed to fetch ${stepType} output from S3: ${s3Res.status} ${s3Res.statusText}`,
3914
+ "output_fetch_error",
3915
+ s3Res.status
3916
+ );
3917
+ }
3918
+ const envelope = await s3Res.json();
3919
+ output = envelope.value;
3920
+ } else {
3921
+ output = void 0;
3922
+ }
3923
+ return {
3924
+ ...output,
3925
+ $appId: poll.appId ?? asyncData.appId ?? "",
3926
+ $threadId: poll.threadId ?? returnedThreadId,
3927
+ $rateLimitRemaining: remaining != null ? parseInt(remaining, 10) : void 0,
3928
+ $billingCost: poll.billingCost,
3929
+ $billingEvents: poll.billingEvents
3930
+ };
3858
3931
  }
3859
- const remaining = headers.get("x-ratelimit-remaining");
3860
- const billingCost = headers.get("x-mindstudio-billing-cost");
3861
- const billingEvents = headers.get("x-mindstudio-billing-events");
3862
- return {
3863
- ...output,
3864
- $appId: headers.get("x-mindstudio-app-id") ?? "",
3865
- $threadId: returnedThreadId,
3866
- $rateLimitRemaining: remaining != null ? parseInt(remaining, 10) : void 0,
3867
- $billingCost: billingCost != null ? parseFloat(billingCost) : void 0,
3868
- $billingEvents: billingEvents != null ? JSON.parse(billingEvents) : void 0
3869
- };
3870
3932
  }
3871
3933
  /**
3872
3934
  * @internal Streaming step execution — sends `Accept: text/event-stream`
@@ -4065,6 +4127,7 @@ var init_client = __esm({
4065
4127
  const res = await fetch(pollUrl, {
4066
4128
  headers: { "User-Agent": "@mindstudio-ai/agent" }
4067
4129
  });
4130
+ if (res.status === 502 || res.status === 503 || res.status === 504) continue;
4068
4131
  if (res.status === 404) {
4069
4132
  throw new MindStudioError(
4070
4133
  "Batch poll token not found or expired.",
@@ -4228,6 +4291,7 @@ var init_client = __esm({
4228
4291
  const res = await fetch(pollUrl, {
4229
4292
  headers: { "User-Agent": "@mindstudio-ai/agent" }
4230
4293
  });
4294
+ if (res.status === 502 || res.status === 503 || res.status === 504) continue;
4231
4295
  if (res.status === 404) {
4232
4296
  throw new MindStudioError(
4233
4297
  "Poll token not found or expired.",
@@ -5494,7 +5558,7 @@ async function startMcpServer(options) {
5494
5558
  capabilities: { tools: {} },
5495
5559
  serverInfo: {
5496
5560
  name: "mindstudio-agent",
5497
- version: "0.1.46"
5561
+ version: "0.1.48"
5498
5562
  },
5499
5563
  instructions: 'Welcome to MindStudio \u2014 a platform with 200+ AI models, 850+ third-party integrations, and pre-built agents.\n\nGetting started:\n1. Call `ask` with any question about the SDK \u2014 it knows every action, model, and connector and returns working code with real model IDs and config options. Examples: ask("generate an image with FLUX"), ask("what models support vision?"), ask("how do I send a Slack message?").\n2. Call `changeName` to set your display name \u2014 use your name or whatever your user calls you. This is how you\'ll appear in MindStudio request logs.\n3. If you have a profile picture or icon, call `uploadFile` to upload it, then `changeProfilePicture` with the returned URL.\n4. For manual browsing, call `listActions` to discover all available actions.\n\nThen use the tools to generate text, images, video, audio, search the web, work with data sources, run agents, and more.\n\nImportant:\n- AI-powered actions (text generation, image generation, video, audio, etc.) cost money. Before running these, call `estimateActionCost` and confirm with the user before proceeding \u2014 unless they\'ve explicitly told you to go ahead.\n- Not all agents from `listAgents` are configured for API use. Do not try to run an agent just because it appears in the list \u2014 it will likely fail. Only run agents the user specifically asks you to run.'
5500
5564
  });
@@ -6355,7 +6419,7 @@ function isNewerVersion(current, latest) {
6355
6419
  return false;
6356
6420
  }
6357
6421
  async function checkForUpdate() {
6358
- const currentVersion = "0.1.46";
6422
+ const currentVersion = "0.1.48";
6359
6423
  if (!currentVersion) return null;
6360
6424
  try {
6361
6425
  const { loadConfig: loadConfig2, saveConfig: saveConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
@@ -6384,7 +6448,7 @@ async function checkForUpdate() {
6384
6448
  }
6385
6449
  }
6386
6450
  function printUpdateNotice(latestVersion) {
6387
- const currentVersion = "0.1.46";
6451
+ const currentVersion = "0.1.48";
6388
6452
  process.stderr.write(
6389
6453
  `
6390
6454
  ${ansi2.cyanBright("Update available")} ${ansi2.gray(currentVersion + " \u2192")} ${ansi2.cyanBold(latestVersion)}
@@ -6397,7 +6461,7 @@ function isStandaloneBinary() {
6397
6461
  return !argv1.includes("node_modules");
6398
6462
  }
6399
6463
  async function cmdUpdate() {
6400
- const currentVersion = "0.1.46";
6464
+ const currentVersion = "0.1.48";
6401
6465
  process.stderr.write(
6402
6466
  ` ${ansi2.gray("Current version:")} ${currentVersion}
6403
6467
  `
@@ -6512,7 +6576,7 @@ async function cmdLogin(options) {
6512
6576
  process.stderr.write("\n");
6513
6577
  printLogo();
6514
6578
  process.stderr.write("\n");
6515
- const ver = "0.1.46";
6579
+ const ver = "0.1.48";
6516
6580
  process.stderr.write(
6517
6581
  ` ${ansi2.bold("MindStudio Agent")} ${ver ? " " + ansi2.gray("v" + ver) : ""}
6518
6582
  `
@@ -6823,7 +6887,7 @@ async function main() {
6823
6887
  try {
6824
6888
  if (command === "version" || command === "-v") {
6825
6889
  process.stdout.write(
6826
- "0.1.46\n"
6890
+ "0.1.48\n"
6827
6891
  );
6828
6892
  return;
6829
6893
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/agent",
3
- "version": "0.1.46",
3
+ "version": "0.1.48",
4
4
  "description": "TypeScript SDK for MindStudio direct step execution",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",