@mindstudio-ai/agent 0.1.140 → 0.1.142

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
@@ -273,7 +273,6 @@ function getOrOpen(url, token) {
273
273
  pending: /* @__PURE__ */ new Map(),
274
274
  chunked: false,
275
275
  inbound: /* @__PURE__ */ new Map(),
276
- acksSeen: false,
277
276
  retired: false
278
277
  };
279
278
  const c = self;
@@ -297,7 +296,6 @@ function getOrOpen(url, token) {
297
296
  return;
298
297
  }
299
298
  if (msg.t === "db-ack") {
300
- c.acksSeen = true;
301
299
  const p = c.pending.get(msg.id);
302
300
  if (p && !p.acked) {
303
301
  p.acked = true;
@@ -373,15 +371,11 @@ async function executeDbBatchOverWs(url, token, databaseId, queries) {
373
371
  }
374
372
  return await new Promise((resolve, reject) => {
375
373
  const pending = { resolve, reject, timer: null, acked: false };
376
- if (self.acksSeen) {
377
- pending.timer = setTimeout(() => {
378
- forget(self, id);
379
- retire(self, "a request went unacknowledged");
380
- reject(new DbWsTransportError("ws ack timed out", true));
381
- }, WS_ACK_TIMEOUT_MS);
382
- } else {
383
- armIdleTimer(self, id, pending);
384
- }
374
+ pending.timer = setTimeout(() => {
375
+ forget(self, id);
376
+ retire(self, "a request went unacknowledged");
377
+ reject(new DbWsTransportError("ws ack timed out", true));
378
+ }, WS_ACK_TIMEOUT_MS);
385
379
  self.pending.set(id, pending);
386
380
  let started = false;
387
381
  let complete = false;
@@ -3410,7 +3404,15 @@ var DataSource = class {
3410
3404
  * as the new one is registered, before its build lands; a search in that
3411
3405
  * window sees neither. **Throws `mapper_skipped`** (HTTP 422) when the
3412
3406
  * mapper skipped the object — a specific thing it refused, which the caller
3413
- * should see — and `mapper_error` when the mapper threw.
3407
+ * should see — and `mapper_error` when the mapper threw, or when none of
3408
+ * its documents passed validation. A document that fails is left out and
3409
+ * reported in {@link AddResult.invalid}; the rest are registered.
3410
+ *
3411
+ * An object that maps to more than a thousand documents (a large export,
3412
+ * streamed out of the mapper as it parses) registers its first thousand
3413
+ * here and returns {@link AddResult.job}, a job that registers and builds
3414
+ * the rest; `documentCount` says how many there are in all. Another job on
3415
+ * the source refuses it with `data_source_busy`.
3414
3416
  */
3415
3417
  async add(content, options) {
3416
3418
  const bytes = typeof content === "string" ? Buffer.from(content) : Buffer.from(content);
@@ -3420,6 +3422,7 @@ var DataSource = class {
3420
3422
  ...options.contentType ? { contentType: options.contentType } : {},
3421
3423
  ...options.metadata !== void 0 ? { metadata: options.metadata } : {},
3422
3424
  ...options.entities !== void 0 ? { entities: options.entities } : {},
3425
+ ...options.budgetDollars !== void 0 ? { budgetDollars: options.budgetDollars } : {},
3423
3426
  body: bytes.toString("base64")
3424
3427
  });
3425
3428
  }
@@ -3631,6 +3634,15 @@ var DataSource = class {
3631
3634
  ...name ? { name } : {}
3632
3635
  });
3633
3636
  }
3637
+ /**
3638
+ * @internal A mapper frame's grant to store the next part of its spill: how
3639
+ * `defineMapper`'s executor hands the platform an object's documents a part
3640
+ * at a time once they outgrow the frame's record. Only a mapper frame's
3641
+ * token is granted one.
3642
+ */
3643
+ async _mapSpillGrant(spillId) {
3644
+ return this._call("map/spill", { slug: this._slug, spillId });
3645
+ }
3634
3646
  /**
3635
3647
  * @internal Content hash of some bytes, matching what the server computes.
3636
3648
  * Exposed for callers that want to check whether they already added a file.
@@ -3781,7 +3793,7 @@ function createEvents(call) {
3781
3793
  };
3782
3794
  }
3783
3795
 
3784
- // src/task/index.ts
3796
+ // src/task/local.ts
3785
3797
  import { randomUUID as randomUUID2 } from "crypto";
3786
3798
 
3787
3799
  // src/generated/metadata.ts
@@ -4926,6 +4938,51 @@ var stepMetadata = {
4926
4938
  }
4927
4939
  };
4928
4940
 
4941
+ // src/task/index.ts
4942
+ function resolveStepType(name) {
4943
+ const meta = stepMetadata[name];
4944
+ return meta ? meta.stepType : name;
4945
+ }
4946
+ function mapTools(tools) {
4947
+ return tools.map((t) => {
4948
+ if (typeof t === "object" && "execute" in t) {
4949
+ return {
4950
+ name: t.name,
4951
+ description: t.description,
4952
+ inputSchema: t.inputSchema ?? { type: "object", properties: {} }
4953
+ };
4954
+ }
4955
+ if (typeof t === "object" && "appMethod" in t) {
4956
+ return {
4957
+ appMethod: t.appMethod,
4958
+ ...t.description ? { description: t.description } : {},
4959
+ ...t.defaults ? { defaults: t.defaults } : {}
4960
+ };
4961
+ }
4962
+ const method = typeof t === "string" ? t : t.method;
4963
+ const stepType = resolveStepType(method);
4964
+ const defaults = typeof t === "object" ? t.defaults : void 0;
4965
+ return defaults ? { stepType, defaults } : { stepType };
4966
+ });
4967
+ }
4968
+ function sleep2(ms) {
4969
+ return new Promise((resolve) => setTimeout(resolve, ms));
4970
+ }
4971
+ function isDevMode() {
4972
+ return !!(process.env.CALLBACK_TOKEN || getRequestContext()?.callbackToken);
4973
+ }
4974
+ function logTaskResult(result) {
4975
+ if (!isDevMode()) {
4976
+ return;
4977
+ }
4978
+ const toolSummary = result.toolCalls.map(
4979
+ (tc) => `${tc.name} (${tc.durationMs}ms) ${tc.success ? "\u2713" : "\u2717"}` + (tc.truncated ? " \u26A0 result cut" : "")
4980
+ ).join(", ");
4981
+ console.log(
4982
+ `[task] ${result.turns} turn${result.turns === 1 ? "" : "s"}` + (toolSummary ? `: ${toolSummary}` : "") + (result.hitMaxTurns ? " | \u26A0 ran out of turns" : "") + (result.stopReason === "max_tokens" ? " | \u26A0 answer cut at the output limit" : "") + ` | ${result.parsedSuccessfully ? "output OK" : "\u26A0 output not valid JSON"} | cost: ${result.usage.totalBillingCost} | trace: ${result.traceId}`
4983
+ );
4984
+ }
4985
+
4929
4986
  // src/task/schema.ts
4930
4987
  function describe(value) {
4931
4988
  if (value === void 0) {
@@ -5066,38 +5123,6 @@ function assertSupportedNode(schema, path) {
5066
5123
  assertSupportedNode(schema.items, `${path}[]`);
5067
5124
  }
5068
5125
  }
5069
- function buildExampleFromSchema(schema) {
5070
- if (schema.const !== void 0) {
5071
- return schema.const;
5072
- }
5073
- if (schema.enum !== void 0 && schema.enum.length > 0) {
5074
- return schema.enum[0];
5075
- }
5076
- const names = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
5077
- const name = names.find((n) => n !== "null") ?? names[0];
5078
- switch (name) {
5079
- case "object": {
5080
- const example = {};
5081
- for (const [key, propSchema] of Object.entries(schema.properties ?? {})) {
5082
- example[key] = buildExampleFromSchema(propSchema);
5083
- }
5084
- return example;
5085
- }
5086
- case "array":
5087
- return schema.items ? [buildExampleFromSchema(schema.items)] : [];
5088
- case "string":
5089
- return "...";
5090
- case "number":
5091
- case "integer":
5092
- return 0;
5093
- case "boolean":
5094
- return true;
5095
- case "null":
5096
- return null;
5097
- default:
5098
- return null;
5099
- }
5100
- }
5101
5126
  function stripCodeFences(text) {
5102
5127
  const match = /^```[a-zA-Z]*[ \t]*\r?\n([\s\S]*?)\r?\n?```$/.exec(
5103
5128
  text.trim()
@@ -5105,262 +5130,7 @@ function stripCodeFences(text) {
5105
5130
  return match ? match[1] : text;
5106
5131
  }
5107
5132
 
5108
- // src/task/index.ts
5109
- function resolveStepType(name) {
5110
- const meta = stepMetadata[name];
5111
- return meta ? meta.stepType : name;
5112
- }
5113
- function mapTools(tools) {
5114
- return tools.map((t) => {
5115
- if (typeof t === "object" && "execute" in t) {
5116
- return {
5117
- name: t.name,
5118
- description: t.description,
5119
- inputSchema: t.inputSchema ?? { type: "object", properties: {} }
5120
- };
5121
- }
5122
- if (typeof t === "object" && "appMethod" in t) {
5123
- return {
5124
- appMethod: t.appMethod,
5125
- ...t.description ? { description: t.description } : {},
5126
- ...t.defaults ? { defaults: t.defaults } : {}
5127
- };
5128
- }
5129
- const method = typeof t === "string" ? t : t.method;
5130
- const stepType = resolveStepType(method);
5131
- const defaults = typeof t === "object" ? t.defaults : void 0;
5132
- return defaults ? { stepType, defaults } : { stepType };
5133
- });
5134
- }
5135
- function buildTaskRequestBody(options) {
5136
- return {
5137
- prompt: options.prompt,
5138
- input: options.input,
5139
- tools: mapTools(options.tools),
5140
- // The legacy whole-task route requires structuredOutputExample and
5141
- // composes its own prompt server-side, so in schema mode we synthesize a
5142
- // skeleton example from the schema. Validation still happens client-side
5143
- // after the result comes back (see _runTaskInner).
5144
- structuredOutputExample: options.outputSchema ? JSON.stringify(buildExampleFromSchema(options.outputSchema)) : typeof options.structuredOutputExample === "string" ? options.structuredOutputExample : JSON.stringify(options.structuredOutputExample),
5145
- model: options.model,
5146
- ...options.maxTurns != null && { maxTurns: options.maxTurns },
5147
- ...options.appId != null && { appId: options.appId },
5148
- ...options.threadId != null && { threadId: options.threadId }
5149
- };
5150
- }
5151
- function sleep2(ms) {
5152
- return new Promise((resolve) => setTimeout(resolve, ms));
5153
- }
5154
- function isDevMode() {
5155
- return !!(process.env.CALLBACK_TOKEN || getRequestContext()?.callbackToken);
5156
- }
5157
- function logTaskResult(result) {
5158
- if (!isDevMode()) {
5159
- return;
5160
- }
5161
- const toolSummary = result.toolCalls.map((tc) => `${tc.name} (${tc.durationMs}ms) ${tc.success ? "\u2713" : "\u2717"}`).join(", ");
5162
- console.log(
5163
- `[task] ${result.turns} turn${result.turns === 1 ? "" : "s"}` + (toolSummary ? `: ${toolSummary}` : "") + ` | ${result.parsedSuccessfully ? "output OK" : "\u26A0 output not valid JSON"} | cost: ${result.usage.totalBillingCost} | trace: ${result.traceId}`
5164
- );
5165
- }
5166
- async function runTaskPoll(httpConfig, body) {
5167
- const traceId = randomUUID2();
5168
- const { data } = await request(
5169
- httpConfig,
5170
- "POST",
5171
- "/task",
5172
- body
5173
- );
5174
- const pollUrl = `${httpConfig.baseUrl}/developer/v2/task/poll/${data.taskToken}`;
5175
- let pollDelay = 300;
5176
- while (true) {
5177
- await sleep2(pollDelay);
5178
- pollDelay = Math.min(pollDelay * 1.5, 3e3);
5179
- const res = await fetch(pollUrl, {
5180
- headers: { "User-Agent": "@mindstudio-ai/agent" }
5181
- });
5182
- if (res.status === 502 || res.status === 503 || res.status === 504) {
5183
- continue;
5184
- }
5185
- if (res.status === 404) {
5186
- throw new MindStudioError(
5187
- "Task poll token not found or expired.",
5188
- "poll_token_expired",
5189
- 404
5190
- );
5191
- }
5192
- if (!res.ok) {
5193
- const errorBody = await res.json().catch(() => ({}));
5194
- throw new MindStudioError(
5195
- errorBody.message ?? errorBody.error ?? `Task poll failed: ${res.status} ${res.statusText}`,
5196
- errorCodeFrom(errorBody, "poll_error"),
5197
- res.status,
5198
- errorBody
5199
- );
5200
- }
5201
- const poll = await res.json();
5202
- if (poll.status === "pending") {
5203
- if (isDevMode() && poll.currentTurn != null) {
5204
- console.log(
5205
- `[task] running... turn ${poll.currentTurn}/${poll.maxTurns ?? "?"}`
5206
- );
5207
- }
5208
- continue;
5209
- }
5210
- if (poll.status === "error") {
5211
- throw new MindStudioError(
5212
- poll.error ?? "Task execution failed.",
5213
- "task_execution_error",
5214
- 500
5215
- );
5216
- }
5217
- const result = {
5218
- output: poll.output,
5219
- outputRaw: poll.outputRaw ?? "",
5220
- parsedSuccessfully: poll.parsedSuccessfully ?? true,
5221
- turns: poll.turns ?? 0,
5222
- usage: poll.usage ?? {
5223
- inputTokens: 0,
5224
- outputTokens: 0,
5225
- totalBillingCost: 0
5226
- },
5227
- toolCalls: poll.toolCalls ?? [],
5228
- traceId
5229
- };
5230
- logTaskResult(result);
5231
- return result;
5232
- }
5233
- }
5234
- async function runTaskStream(httpConfig, body, onEvent) {
5235
- const traceId = randomUUID2();
5236
- const url = `${httpConfig.baseUrl}/developer/v2/task`;
5237
- const res = await fetch(url, {
5238
- method: "POST",
5239
- headers: {
5240
- Authorization: `Bearer ${httpConfig.token}`,
5241
- "Content-Type": "application/json",
5242
- "User-Agent": "@mindstudio-ai/agent",
5243
- Accept: "text/event-stream"
5244
- },
5245
- body: JSON.stringify(body)
5246
- });
5247
- if (!res.ok) {
5248
- let message = `${res.status} ${res.statusText}`;
5249
- let code = "api_error";
5250
- let details;
5251
- try {
5252
- const text = await res.text();
5253
- try {
5254
- const errBody = JSON.parse(text);
5255
- details = errBody;
5256
- const errMsg = (typeof errBody.error === "string" ? errBody.error : void 0) ?? (typeof errBody.message === "string" ? errBody.message : void 0);
5257
- if (errMsg) {
5258
- message = errMsg;
5259
- }
5260
- code = errorCodeFrom(errBody, code);
5261
- } catch {
5262
- const stripped = text.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
5263
- if (stripped) {
5264
- message = stripped.slice(0, 200);
5265
- }
5266
- }
5267
- } catch {
5268
- }
5269
- throw new MindStudioError(`[task] ${message}`, code, res.status, details);
5270
- }
5271
- const reader = res.body.getReader();
5272
- const decoder = new TextDecoder();
5273
- let buffer = "";
5274
- let result = null;
5275
- while (true) {
5276
- const { done, value } = await reader.read();
5277
- if (done) {
5278
- break;
5279
- }
5280
- buffer += decoder.decode(value, { stream: true });
5281
- const lines = buffer.split("\n");
5282
- buffer = lines.pop() ?? "";
5283
- for (const line of lines) {
5284
- if (!line.startsWith("data: ")) {
5285
- continue;
5286
- }
5287
- try {
5288
- const event = JSON.parse(line.slice(6));
5289
- onEvent(event);
5290
- if (event.type === "error") {
5291
- throw new MindStudioError(
5292
- event.error ?? "Task execution failed.",
5293
- "task_execution_error",
5294
- 500
5295
- );
5296
- }
5297
- if (event.type === "done") {
5298
- result = {
5299
- output: event.output,
5300
- outputRaw: event.outputRaw ?? "",
5301
- parsedSuccessfully: event.parsedSuccessfully ?? true,
5302
- turns: event.turns ?? 0,
5303
- usage: event.usage ?? {
5304
- inputTokens: 0,
5305
- outputTokens: 0,
5306
- totalBillingCost: 0
5307
- },
5308
- toolCalls: event.toolCalls ?? [],
5309
- traceId
5310
- };
5311
- }
5312
- } catch (err) {
5313
- if (err instanceof MindStudioError) {
5314
- throw err;
5315
- }
5316
- }
5317
- }
5318
- }
5319
- if (buffer.startsWith("data: ")) {
5320
- try {
5321
- const event = JSON.parse(buffer.slice(6));
5322
- onEvent(event);
5323
- if (event.type === "error") {
5324
- throw new MindStudioError(
5325
- event.error ?? "Task execution failed.",
5326
- "task_execution_error",
5327
- 500
5328
- );
5329
- }
5330
- if (event.type === "done") {
5331
- result = {
5332
- output: event.output,
5333
- outputRaw: event.outputRaw ?? "",
5334
- parsedSuccessfully: event.parsedSuccessfully ?? true,
5335
- turns: event.turns ?? 0,
5336
- usage: event.usage ?? {
5337
- inputTokens: 0,
5338
- outputTokens: 0,
5339
- totalBillingCost: 0
5340
- },
5341
- toolCalls: event.toolCalls ?? [],
5342
- traceId
5343
- };
5344
- }
5345
- } catch (err) {
5346
- if (err instanceof MindStudioError) {
5347
- throw err;
5348
- }
5349
- }
5350
- }
5351
- if (!result) {
5352
- throw new MindStudioError(
5353
- "[task] Stream ended without a done event. The task execution may have been interrupted.",
5354
- "stream_error",
5355
- 500
5356
- );
5357
- }
5358
- logTaskResult(result);
5359
- return result;
5360
- }
5361
-
5362
5133
  // src/task/local.ts
5363
- import { randomUUID as randomUUID3 } from "crypto";
5364
5134
  var DEFAULT_MAX_TURNS = 20;
5365
5135
  var MAX_TURNS_LIMIT = 100;
5366
5136
  var MAX_SCHEMA_REPAIR_ATTEMPTS = 3;
@@ -5368,7 +5138,6 @@ var MAX_TOOL_OUTPUT_CHARS = 5e4;
5368
5138
  var MAX_TURN_ATTEMPTS = 5;
5369
5139
  var INITIAL_BACKOFF_MS = 1e3;
5370
5140
  var STALL_TIMEOUT_MS = 3e5;
5371
- var TURN_UNAVAILABLE_CODE = "task_turn_unavailable";
5372
5141
  var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
5373
5142
  function isPlainObject(value) {
5374
5143
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
@@ -5388,9 +5157,20 @@ function mergeToolInput(modelInput, defaults) {
5388
5157
  }
5389
5158
  return merged;
5390
5159
  }
5391
- function truncateToolOutput(output) {
5160
+ function truncateToolOutput(output, maxChars) {
5392
5161
  const serialized = JSON.stringify(output);
5393
- return serialized && serialized.length > MAX_TOOL_OUTPUT_CHARS ? serialized.slice(0, MAX_TOOL_OUTPUT_CHARS) + "... [truncated]" : output;
5162
+ if (!serialized || serialized.length <= maxChars) {
5163
+ return { output, truncated: false };
5164
+ }
5165
+ return {
5166
+ output: {
5167
+ truncated: true,
5168
+ totalChars: serialized.length,
5169
+ shownChars: maxChars,
5170
+ content: serialized.slice(0, maxChars)
5171
+ },
5172
+ truncated: true
5173
+ };
5394
5174
  }
5395
5175
  var TurnError = class extends Error {
5396
5176
  constructor(message, retryable, phase, status, errorCode) {
@@ -5614,7 +5394,8 @@ ${structuredOutputExample}
5614
5394
  Math.max(options.maxTurns || DEFAULT_MAX_TURNS, 1),
5615
5395
  MAX_TURNS_LIMIT
5616
5396
  );
5617
- const traceId = randomUUID3();
5397
+ const maxToolOutputChars = options.maxToolOutputChars ?? MAX_TOOL_OUTPUT_CHARS;
5398
+ const traceId = randomUUID2();
5618
5399
  const messages = [
5619
5400
  { role: "user", content: JSON.stringify(options.input) }
5620
5401
  ];
@@ -5628,11 +5409,13 @@ ${structuredOutputExample}
5628
5409
  cacheReadTokens: 0,
5629
5410
  totalBillingCost: 0
5630
5411
  };
5631
- const buildResult = (output2, outputRaw, parsedSuccessfully2, turns) => ({
5412
+ const buildResult = (output2, outputRaw, parsedSuccessfully2, turns, stopReason, hitMaxTurns = false) => ({
5632
5413
  output: output2,
5633
5414
  outputRaw,
5634
5415
  parsedSuccessfully: parsedSuccessfully2,
5635
5416
  turns,
5417
+ hitMaxTurns,
5418
+ stopReason,
5636
5419
  usage: totalUsage,
5637
5420
  toolCalls: toolCallLog,
5638
5421
  traceId
@@ -5690,7 +5473,7 @@ ${structuredOutputExample}
5690
5473
  }
5691
5474
  );
5692
5475
  }
5693
- return finish(buildResult(null, "", false, loopCount));
5476
+ return finish(buildResult(null, "", false, loopCount, null));
5694
5477
  }
5695
5478
  if (err instanceof TurnError) {
5696
5479
  throw new MindStudioError(
@@ -5714,13 +5497,6 @@ ${structuredOutputExample}
5714
5497
  traceId
5715
5498
  });
5716
5499
  } catch (err) {
5717
- if (loopCount === 1 && err instanceof TurnError && err.status === 404 && err.errorCode === "not_found") {
5718
- throw new MindStudioError(
5719
- "Task turn endpoint unavailable.",
5720
- TURN_UNAVAILABLE_CODE,
5721
- 404
5722
- );
5723
- }
5724
5500
  return turnFailure(err);
5725
5501
  }
5726
5502
  accumulate(turn);
@@ -5744,11 +5520,11 @@ ${structuredOutputExample}
5744
5520
  let result;
5745
5521
  if (kind === "function") {
5746
5522
  try {
5747
- const output3 = await functionTools.get(toolCall.name)(
5523
+ const output4 = await functionTools.get(toolCall.name)(
5748
5524
  mergedInput
5749
5525
  );
5750
5526
  result = {
5751
- output: output3 ?? null,
5527
+ output: output4 ?? null,
5752
5528
  billingCost: 0,
5753
5529
  isError: false
5754
5530
  };
@@ -5769,29 +5545,40 @@ ${structuredOutputExample}
5769
5545
  } else {
5770
5546
  result = await deps.executeStepTool(toolCall.name, mergedInput);
5771
5547
  }
5548
+ const { output: output3, truncated } = truncateToolOutput(
5549
+ result.output,
5550
+ maxToolOutputChars
5551
+ );
5772
5552
  toolCallLog.push({
5773
5553
  name: toolCall.name,
5774
5554
  success: !result.isError,
5775
- durationMs: Date.now() - startTime
5555
+ durationMs: Date.now() - startTime,
5556
+ truncated
5776
5557
  });
5777
- return { toolCall, ...result };
5558
+ return { toolCall, ...result, output: output3, truncated };
5778
5559
  })
5779
5560
  );
5780
- for (const { toolCall, output: output3, billingCost, isError } of results) {
5561
+ for (const {
5562
+ toolCall,
5563
+ output: output3,
5564
+ truncated,
5565
+ billingCost,
5566
+ isError
5567
+ } of results) {
5781
5568
  if (billingCost) {
5782
5569
  totalUsage.totalBillingCost += billingCost;
5783
5570
  }
5784
- const truncated = truncateToolOutput(output3);
5785
5571
  messages.push({
5786
5572
  role: "user",
5787
- content: JSON.stringify(truncated),
5573
+ content: JSON.stringify(output3),
5788
5574
  toolCallId: toolCall.id,
5789
5575
  ...isError && { isToolError: true }
5790
5576
  });
5791
5577
  onEvent?.({
5792
5578
  type: "tool_call_result",
5793
5579
  id: toolCall.id,
5794
- output: truncated
5580
+ output: output3,
5581
+ ...truncated && { truncated: true }
5795
5582
  });
5796
5583
  }
5797
5584
  if (isDevMode()) {
@@ -5811,11 +5598,15 @@ ${structuredOutputExample}
5811
5598
  }
5812
5599
  if (parseOk) {
5813
5600
  if (!outputSchema) {
5814
- return finish(buildResult(output2, turn.text, true, loopCount));
5601
+ return finish(
5602
+ buildResult(output2, turn.text, true, loopCount, turn.stopReason)
5603
+ );
5815
5604
  }
5816
5605
  const errors = validateAgainstSchema(output2, outputSchema);
5817
5606
  if (errors.length === 0) {
5818
- return finish(buildResult(output2, turn.text, true, loopCount));
5607
+ return finish(
5608
+ buildResult(output2, turn.text, true, loopCount, turn.stopReason)
5609
+ );
5819
5610
  }
5820
5611
  if (loopCount < maxTurns && schemaRepairCount < MAX_SCHEMA_REPAIR_ATTEMPTS) {
5821
5612
  schemaRepairCount++;
@@ -5840,13 +5631,16 @@ ${formatValidationErrors(errors)}`
5840
5631
  { path: "$", message: "output was not valid JSON" }
5841
5632
  ]);
5842
5633
  }
5843
- return finish(buildResult(turn.text, turn.text, false, loopCount));
5634
+ return finish(
5635
+ buildResult(turn.text, turn.text, false, loopCount, turn.stopReason)
5636
+ );
5844
5637
  }
5845
5638
  messages.push({
5846
5639
  role: "user",
5847
5640
  content: "You have reached the maximum number of turns. Please provide your final output now as JSON."
5848
5641
  });
5849
5642
  let finalText = "";
5643
+ let finalStopReason = null;
5850
5644
  try {
5851
5645
  const turn = await runTurnWithRetry(httpConfig, {
5852
5646
  model: options.model,
@@ -5857,6 +5651,7 @@ ${formatValidationErrors(errors)}`
5857
5651
  });
5858
5652
  accumulate(turn);
5859
5653
  finalText = turn.text;
5654
+ finalStopReason = turn.stopReason;
5860
5655
  } catch (err) {
5861
5656
  if (err instanceof TurnError && err.phase === "model") {
5862
5657
  if (isDevMode()) {
@@ -5886,7 +5681,14 @@ ${formatValidationErrors(errors)}`
5886
5681
  }
5887
5682
  }
5888
5683
  return finish(
5889
- buildResult(output, finalText, parsedSuccessfully, loopCount + 1)
5684
+ buildResult(
5685
+ output,
5686
+ finalText,
5687
+ parsedSuccessfully,
5688
+ loopCount + 1,
5689
+ finalStopReason,
5690
+ true
5691
+ )
5890
5692
  );
5891
5693
  }
5892
5694
 
@@ -6945,108 +6747,75 @@ var MindStudioAgent = class {
6945
6747
  }
6946
6748
  async _runTaskInner(options) {
6947
6749
  const httpConfig = this._currentHttpConfig;
6948
- try {
6949
- return await runTaskLocal(
6950
- {
6951
- httpConfig,
6952
- executeStepTool: async (stepType, input) => {
6953
- try {
6954
- const result = await this.executeStep(stepType, input, {
6955
- requestSource: "v2-task"
6956
- });
6957
- const output = {};
6958
- let billingCost = 0;
6959
- for (const [key, value] of Object.entries(
6960
- result
6961
- )) {
6962
- if (key === "$billingCost" && typeof value === "number") {
6963
- billingCost = value;
6964
- }
6965
- if (!key.startsWith("$")) {
6966
- output[key] = value;
6967
- }
6750
+ return runTaskLocal(
6751
+ {
6752
+ httpConfig,
6753
+ executeStepTool: async (stepType, input) => {
6754
+ try {
6755
+ const result = await this.executeStep(stepType, input, {
6756
+ requestSource: "v2-task"
6757
+ });
6758
+ const output = {};
6759
+ let billingCost = 0;
6760
+ for (const [key, value] of Object.entries(
6761
+ result
6762
+ )) {
6763
+ if (key === "$billingCost" && typeof value === "number") {
6764
+ billingCost = value;
6968
6765
  }
6969
- return { output, billingCost, isError: false };
6970
- } catch (err) {
6971
- return {
6972
- output: {
6973
- error: err instanceof Error ? err.message : "Step execution failed"
6974
- },
6975
- billingCost: 0,
6976
- isError: true
6977
- };
6978
- }
6979
- },
6980
- executeMethodTool: async (methodId, input, call) => {
6981
- try {
6982
- const { data } = await request(
6983
- { ...httpConfig, maxRetries: 0 },
6984
- "POST",
6985
- "/task/invoke-method",
6986
- {
6987
- methodId,
6988
- input,
6989
- traceId: call.traceId,
6990
- toolCallId: call.toolCallId
6991
- }
6992
- );
6993
- if (data.error) {
6994
- return {
6995
- output: { error: data.error },
6996
- billingCost: 0,
6997
- isError: true
6998
- };
6766
+ if (!key.startsWith("$")) {
6767
+ output[key] = value;
6999
6768
  }
7000
- return {
7001
- output: data.output ?? null,
7002
- billingCost: 0,
7003
- isError: false
7004
- };
7005
- } catch (err) {
7006
- return {
7007
- output: {
7008
- error: err instanceof Error ? err.message : "Method execution failed"
7009
- },
7010
- billingCost: 0,
7011
- isError: true
7012
- };
7013
6769
  }
6770
+ return { output, billingCost, isError: false };
6771
+ } catch (err) {
6772
+ return {
6773
+ output: {
6774
+ error: err instanceof Error ? err.message : "Step execution failed"
6775
+ },
6776
+ billingCost: 0,
6777
+ isError: true
6778
+ };
7014
6779
  }
7015
6780
  },
7016
- options
7017
- );
7018
- } catch (err) {
7019
- if (err instanceof MindStudioError && err.code === TURN_UNAVAILABLE_CODE) {
7020
- if (options.tools.some((t) => typeof t === "object" && "execute" in t)) {
7021
- throw new MindStudioError(
7022
- "[task] This server does not support the per-turn task endpoint required for function tools.",
7023
- "task_function_tools_unsupported",
7024
- 404
7025
- );
7026
- }
7027
- const body = buildTaskRequestBody(options);
7028
- const result = options.onEvent ? await runTaskStream(httpConfig, body, options.onEvent) : await runTaskPoll(httpConfig, body);
7029
- if (options.outputSchema) {
7030
- const errors = result.parsedSuccessfully ? validateAgainstSchema(result.output, options.outputSchema) : [{ path: "$", message: "output was not valid JSON" }];
7031
- if (errors.length > 0) {
7032
- throw new MindStudioError(
7033
- "[task] Output did not conform to outputSchema (legacy task route, no repair turns).",
7034
- "task_output_schema_mismatch",
7035
- 422,
6781
+ executeMethodTool: async (methodId, input, call) => {
6782
+ try {
6783
+ const { data } = await request(
6784
+ { ...httpConfig, maxRetries: 0 },
6785
+ "POST",
6786
+ "/task/invoke-method",
7036
6787
  {
7037
- outputRaw: result.outputRaw,
7038
- errors,
7039
- turns: result.turns,
7040
- usage: result.usage,
7041
- toolCalls: result.toolCalls
6788
+ methodId,
6789
+ input,
6790
+ traceId: call.traceId,
6791
+ toolCallId: call.toolCallId
7042
6792
  }
7043
6793
  );
6794
+ if (data.error) {
6795
+ return {
6796
+ output: { error: data.error },
6797
+ billingCost: 0,
6798
+ isError: true
6799
+ };
6800
+ }
6801
+ return {
6802
+ output: data.output ?? null,
6803
+ billingCost: 0,
6804
+ isError: false
6805
+ };
6806
+ } catch (err) {
6807
+ return {
6808
+ output: {
6809
+ error: err instanceof Error ? err.message : "Method execution failed"
6810
+ },
6811
+ billingCost: 0,
6812
+ isError: true
6813
+ };
7044
6814
  }
7045
6815
  }
7046
- return result;
7047
- }
7048
- throw err;
7049
- }
6816
+ },
6817
+ options
6818
+ );
7050
6819
  }
7051
6820
  /**
7052
6821
  * Get the authenticated user's identity and organization info.
@@ -8419,8 +8188,18 @@ function defineJewel(method, config) {
8419
8188
  }
8420
8189
 
8421
8190
  // src/mapper/index.ts
8191
+ import { gzipSync } from "zlib";
8422
8192
  function documents(list) {
8423
- return { kind: "documents", documents: Array.isArray(list) ? list : [list] };
8193
+ return {
8194
+ kind: "documents",
8195
+ documents: isIterable(list) || isAsyncIterable(list) ? list : [list]
8196
+ };
8197
+ }
8198
+ function isIterable(value) {
8199
+ return value !== null && typeof value === "object" && typeof value[Symbol.iterator] === "function";
8200
+ }
8201
+ function isAsyncIterable(value) {
8202
+ return value !== null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
8424
8203
  }
8425
8204
  function passthrough(options) {
8426
8205
  return {
@@ -8440,6 +8219,8 @@ function deletes(externalIds) {
8440
8219
  }
8441
8220
  var DEFAULT_TIMEOUT_MS = 3e4;
8442
8221
  var DEFAULT_CONCURRENCY2 = 4;
8222
+ var PART_DOCUMENTS = 1e3;
8223
+ var PART_BYTES = 8 * 1024 * 1024;
8443
8224
  function errorInfo2(e) {
8444
8225
  if (e instanceof Error) {
8445
8226
  return { message: e.message, stack: e.stack };
@@ -8471,7 +8252,7 @@ function objectFor(input) {
8471
8252
  etag: input.etag,
8472
8253
  lastModified: input.lastModified,
8473
8254
  metadata: input.metadata,
8474
- entities: input.entities ?? null,
8255
+ entities: input.entities,
8475
8256
  bytes,
8476
8257
  text: async () => new TextDecoder("utf-8").decode(await bytes()),
8477
8258
  json: async () => JSON.parse(new TextDecoder("utf-8").decode(await bytes()))
@@ -8480,13 +8261,17 @@ function objectFor(input) {
8480
8261
  var OUTCOME_KINDS = /* @__PURE__ */ new Set(["documents", "passthrough", "skip", "deletes"]);
8481
8262
  function normalizeOutcome(value) {
8482
8263
  const outcome = value;
8264
+ const invalid = () => ({
8265
+ kind: "error",
8266
+ error: {
8267
+ message: `map returned an invalid outcome: ${JSON.stringify(value)?.slice(0, 200)}. Return documents(), passthrough(), skip() or deletes().`
8268
+ }
8269
+ });
8483
8270
  if (!outcome || typeof outcome !== "object" || !OUTCOME_KINDS.has(outcome.kind)) {
8484
- return {
8485
- kind: "error",
8486
- error: {
8487
- message: `map returned an invalid outcome: ${JSON.stringify(value)?.slice(0, 200)}. Return documents(), passthrough(), skip() or deletes().`
8488
- }
8489
- };
8271
+ return invalid();
8272
+ }
8273
+ if (outcome.kind === "documents" && !isIterable(outcome.documents) && !isAsyncIterable(outcome.documents)) {
8274
+ return invalid();
8490
8275
  }
8491
8276
  return outcome;
8492
8277
  }
@@ -8508,13 +8293,107 @@ async function withTimeout(work, timeoutMs, key) {
8508
8293
  }
8509
8294
  }
8510
8295
  }
8296
+ var PartWriter = class {
8297
+ constructor(source, spillId) {
8298
+ this.source = source;
8299
+ this.spillId = spillId;
8300
+ }
8301
+ source;
8302
+ spillId;
8303
+ parts = [];
8304
+ /** Objects whose documents did not all store, with why. */
8305
+ failed = /* @__PURE__ */ new Map();
8306
+ lines = [];
8307
+ objects = /* @__PURE__ */ new Set();
8308
+ bytes = 0;
8309
+ uploading = Promise.resolve();
8310
+ async write(o, i, d) {
8311
+ const line = JSON.stringify({ o, i, d });
8312
+ this.lines.push(line);
8313
+ this.objects.add(o);
8314
+ this.bytes += line.length;
8315
+ if (this.lines.length >= PART_DOCUMENTS || this.bytes >= PART_BYTES) {
8316
+ await this.flush();
8317
+ }
8318
+ }
8319
+ /** Store what the buffer holds; resolves once every upload so far is done. */
8320
+ async flush() {
8321
+ if (this.lines.length > 0) {
8322
+ const lines = this.lines;
8323
+ const objects = this.objects;
8324
+ this.lines = [];
8325
+ this.objects = /* @__PURE__ */ new Set();
8326
+ this.bytes = 0;
8327
+ this.uploading = this.uploading.then(() => this.store(lines, objects));
8328
+ }
8329
+ await this.uploading;
8330
+ }
8331
+ async store(lines, objects) {
8332
+ try {
8333
+ const grant = await this.source._mapSpillGrant(this.spillId);
8334
+ const form = new FormData();
8335
+ for (const [k, v] of Object.entries(grant.uploadFields)) {
8336
+ form.append(k, v);
8337
+ }
8338
+ form.append(
8339
+ "file",
8340
+ new Blob(
8341
+ [new Uint8Array(gzipSync(Buffer.from(lines.join("\n") + "\n")))],
8342
+ { type: "application/gzip" }
8343
+ ),
8344
+ `${grant.part}.ndjson.gz`
8345
+ );
8346
+ const response = await fetch(grant.uploadUrl, {
8347
+ method: "POST",
8348
+ body: form
8349
+ });
8350
+ if (!response.ok) {
8351
+ throw new Error(
8352
+ `Could not store part ${grant.part} of the documents: HTTP ${response.status}`
8353
+ );
8354
+ }
8355
+ this.parts.push({ part: grant.part, count: lines.length });
8356
+ } catch (e) {
8357
+ const err = e instanceof Error ? e : new Error(String(e));
8358
+ for (const o of objects) {
8359
+ if (!this.failed.has(o)) {
8360
+ this.failed.set(o, err);
8361
+ }
8362
+ }
8363
+ }
8364
+ }
8365
+ };
8366
+ async function writeDocuments(list, ctx) {
8367
+ const iterator = isAsyncIterable(list) ? list[Symbol.asyncIterator]() : list[Symbol.iterator]();
8368
+ let count = 0;
8369
+ try {
8370
+ while (true) {
8371
+ const step = await withTimeout(
8372
+ Promise.resolve(iterator.next()),
8373
+ ctx.timeoutMs,
8374
+ ctx.key
8375
+ );
8376
+ if (step.done) {
8377
+ return count;
8378
+ }
8379
+ await ctx.writer.write(ctx.o, count, step.value);
8380
+ count += 1;
8381
+ }
8382
+ } catch (e) {
8383
+ await Promise.resolve(iterator.return?.()).catch(() => {
8384
+ });
8385
+ throw e;
8386
+ }
8387
+ }
8511
8388
  function defineMapper(source, config) {
8389
+ const handle = source;
8512
8390
  const run = async (params) => {
8513
8391
  const startedAt = Date.now();
8514
8392
  const timeoutMs = params.timeoutMs ?? DEFAULT_TIMEOUT_MS;
8515
8393
  const concurrency = Math.max(1, params.concurrency ?? DEFAULT_CONCURRENCY2);
8516
8394
  const objects = Array.isArray(params.objects) ? params.objects : [];
8517
8395
  const outcomes = new Array(objects.length);
8396
+ const writer = params.spill?.id && typeof handle._mapSpillGrant === "function" ? new PartWriter(handle, params.spill.id) : null;
8518
8397
  let next = 0;
8519
8398
  const worker = async () => {
8520
8399
  while (true) {
@@ -8526,13 +8405,30 @@ function defineMapper(source, config) {
8526
8405
  const t = Date.now();
8527
8406
  let outcome;
8528
8407
  try {
8529
- outcome = normalizeOutcome(
8408
+ const mapped = normalizeOutcome(
8530
8409
  await withTimeout(
8531
8410
  Promise.resolve().then(() => config.map(objectFor(input))),
8532
8411
  timeoutMs,
8533
8412
  input.key
8534
8413
  )
8535
8414
  );
8415
+ if (mapped.kind !== "documents") {
8416
+ outcome = mapped;
8417
+ } else if (!writer) {
8418
+ throw new Error(
8419
+ "documents() needs the platform to store what it produces, and this frame was given nowhere to store it."
8420
+ );
8421
+ } else {
8422
+ outcome = {
8423
+ kind: "documents",
8424
+ count: await writeDocuments(mapped.documents, {
8425
+ o: index,
8426
+ key: input.key,
8427
+ timeoutMs,
8428
+ writer
8429
+ })
8430
+ };
8431
+ }
8536
8432
  } catch (e) {
8537
8433
  outcome = { kind: "error", error: errorInfo2(e) };
8538
8434
  }
@@ -8546,10 +8442,17 @@ function defineMapper(source, config) {
8546
8442
  await Promise.all(
8547
8443
  Array.from({ length: Math.min(concurrency, objects.length) }, worker)
8548
8444
  );
8445
+ await writer?.flush();
8446
+ for (const [o, err] of writer?.failed ?? []) {
8447
+ if (outcomes[o]?.outcome.kind === "documents") {
8448
+ outcomes[o].outcome = { kind: "error", error: errorInfo2(err) };
8449
+ }
8450
+ }
8549
8451
  return {
8550
8452
  v: 1,
8551
8453
  source: source.name,
8552
8454
  outcomes,
8455
+ parts: writer?.parts ?? [],
8553
8456
  startedAt,
8554
8457
  durationMs: Date.now() - startedAt
8555
8458
  };