@swifty.js/swifty 0.0.22 → 0.0.23

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.
Files changed (35) hide show
  1. package/dist/{agent-5T7KNC7V.js → agent-RABW3Z3R.js} +1 -1
  2. package/dist/anthropic-V22T6E6E.js +4 -0
  3. package/dist/{checker-OJFS2MZY.js → checker-3RWAYF2U.js} +1 -1
  4. package/dist/{chunk-HJIGA37J.js → chunk-5KXBVL2A.js} +1 -1
  5. package/dist/{chunk-NLNH3IRT.js → chunk-CV7OKXYC.js} +1 -1
  6. package/dist/chunk-MJR2C7S7.js +130 -0
  7. package/dist/{chunk-GUXBLUNR.js → chunk-NR62AA5K.js} +1 -1
  8. package/dist/{chunk-NEAR6YPZ.js → chunk-OCQ6TYLT.js} +21 -20
  9. package/dist/chunk-QN27QEFS.js +4 -0
  10. package/dist/{chunk-LX2LK3TF.js → chunk-SIWLMWHH.js} +12 -11
  11. package/dist/chunk-Y43POSIW.js +389 -0
  12. package/dist/lib/agent-GHXYOARN.js +9 -0
  13. package/dist/lib/{anthropic-GFWP3ORB.js → anthropic-7YEN2QTU.js} +6 -6
  14. package/dist/lib/{checker-IIXJXQCB.js → checker-6BW4222R.js} +3 -3
  15. package/dist/lib/{chunk-LUEP4JMF.js → chunk-7IZEK7X5.js} +8 -12
  16. package/dist/lib/{chunk-C7IHCJZ3.js → chunk-BN4Q54G2.js} +259 -12
  17. package/dist/lib/{chunk-RR2CZ6CY.js → chunk-BO76JDFZ.js} +94 -75
  18. package/dist/lib/{chunk-6GOWRPYS.js → chunk-CYDNMEBC.js} +2 -2
  19. package/dist/lib/{chunk-EJLGB2EJ.js → chunk-EY7HE52Q.js} +14 -7
  20. package/dist/lib/{chunk-7URDLWQN.js → chunk-GNI7YX6F.js} +2 -2
  21. package/dist/lib/{chunk-UHVO63Y7.js → chunk-MF3YLQDS.js} +69 -38
  22. package/dist/lib/{chunk-UMFNTXKA.js → chunk-OO2CLOEE.js} +38 -38
  23. package/dist/lib/{chunk-GNBXECZN.js → chunk-PZ42NAFA.js} +2 -3
  24. package/dist/lib/index.d.ts +234 -237
  25. package/dist/lib/index.js +212 -224
  26. package/dist/lib/{openai-HXRMPNB7.js → openai-RDHZFJUT.js} +4 -4
  27. package/dist/main.js +203 -465
  28. package/dist/{openai-TVUUHRG7.js → openai-6NWVJ5LI.js} +15 -15
  29. package/dist/{server-ZTLHJWEQ.js → server-KQTLAXC6.js} +16 -16
  30. package/package.json +5 -5
  31. package/dist/anthropic-P2R4GW6F.js +0 -4
  32. package/dist/chunk-L73IHJF4.js +0 -386
  33. package/dist/chunk-YQQVB6VB.js +0 -127
  34. package/dist/chunk-ZZQE743W.js +0 -4
  35. package/dist/lib/agent-2AGRYN3R.js +0 -9
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getMaxOutputTokens,
3
3
  resolveAPIKey
4
- } from "./chunk-6GOWRPYS.js";
4
+ } from "./chunk-CYDNMEBC.js";
5
5
  import {
6
6
  AuthenticationError,
7
7
  ContextTooLongError,
@@ -9,16 +9,15 @@ import {
9
9
  NetworkError,
10
10
  RateLimitError,
11
11
  ensureToolPairing
12
- } from "./chunk-UMFNTXKA.js";
12
+ } from "./chunk-OO2CLOEE.js";
13
13
  import {
14
- DANGEROUSLY_JSON,
15
14
  asRecord,
16
15
  asString,
17
16
  contentToText,
18
17
  createChildLogger,
19
18
  isRecord,
20
19
  strArg
21
- } from "./chunk-EJLGB2EJ.js";
20
+ } from "./chunk-EY7HE52Q.js";
22
21
 
23
22
  // src/llm/openai.ts
24
23
  import OpenAI from "openai";
@@ -124,12 +123,10 @@ var OpenAIClient = class {
124
123
  if (jsonAccumulate) {
125
124
  try {
126
125
  const parsed = JSON.parse(jsonAccumulate);
127
- args = isRecord(parsed) ? asRecord(parsed) : { [DANGEROUSLY_JSON]: jsonAccumulate };
126
+ args = isRecord(parsed) ? asRecord(parsed) : {};
128
127
  } catch (err) {
129
128
  log.error({ err }, "llm operation failed");
130
- args = {
131
- [DANGEROUSLY_JSON]: jsonAccumulate
132
- };
129
+ args = {};
133
130
  }
134
131
  }
135
132
  yield {
@@ -183,72 +180,104 @@ var OpenAIClient = class {
183
180
  }
184
181
  };
185
182
  function imageDataUrl(block) {
186
- if (block.type !== "image") {
183
+ if (!isRecord(block) || block.type !== "image" || !isRecord(block.source)) {
187
184
  return null;
188
185
  }
189
- const source = block.source;
190
- if (!isRecord(source) || source.type !== "base64") {
186
+ if (block.source.type === "url") {
187
+ return strArg(block.source, "url") || null;
188
+ }
189
+ if (block.source.type !== "base64") {
191
190
  return null;
192
191
  }
193
- const mediaType = strArg(source, "media_type");
194
- const data = strArg(source, "data");
195
- if (!mediaType || !data) {
192
+ const mediaType = strArg(block.source, "media_type");
193
+ const data = strArg(block.source, "data");
194
+ return mediaType && data ? `data:${mediaType};base64,${data}` : null;
195
+ }
196
+ function documentForResponses(block) {
197
+ if (!isRecord(block) || block.type !== "document" || !isRecord(block.source)) {
196
198
  return null;
197
199
  }
198
- return `data:${mediaType};base64,${data}`;
200
+ const title = typeof block.title === "string" && block.title ? block.title : "tool-result";
201
+ if (block.source.type === "url") {
202
+ const fileUrl = strArg(block.source, "url");
203
+ return fileUrl ? { type: "input_file", file_url: fileUrl } : null;
204
+ }
205
+ if (block.source.type === "base64") {
206
+ const data = strArg(block.source, "data");
207
+ return data ? { type: "input_file", file_data: data, filename: `${title}.pdf` } : null;
208
+ }
209
+ if (block.source.type === "text") {
210
+ const data = strArg(block.source, "data");
211
+ return data ? {
212
+ type: "input_file",
213
+ file_data: Buffer.from(data, "utf-8").toString("base64"),
214
+ filename: `${title}.txt`
215
+ } : null;
216
+ }
217
+ return null;
199
218
  }
200
- function collectImageContents(tr) {
201
- const { toolUseId, content } = tr;
202
- if (typeof content === "string") {
203
- return [];
219
+ function documentForChat(block) {
220
+ if (!isRecord(block) || block.type !== "document" || !isRecord(block.source)) {
221
+ return null;
204
222
  }
205
- const images = [];
206
- for (const block of content) {
207
- const url = imageDataUrl(block);
208
- if (url) {
209
- images.push({
210
- type: "input_image",
211
- image_url: url,
212
- detail: "auto"
213
- });
214
- }
223
+ const title = typeof block.title === "string" && block.title ? block.title : "tool-result";
224
+ if (block.source.type === "base64") {
225
+ const data = strArg(block.source, "data");
226
+ return data ? { type: "file", file: { file_data: data, filename: `${title}.pdf` } } : null;
215
227
  }
216
- if (images.length === 0) {
217
- return [];
228
+ if (block.source.type === "text") {
229
+ const data = strArg(block.source, "data");
230
+ return data ? {
231
+ type: "file",
232
+ file: {
233
+ file_data: Buffer.from(data, "utf-8").toString("base64"),
234
+ filename: `${title}.txt`
235
+ }
236
+ } : null;
218
237
  }
219
- return [
220
- {
221
- type: "input_text",
222
- text: `[Image(s) returned by tool call ${toolUseId}]`
223
- },
224
- ...images
225
- ];
238
+ return null;
226
239
  }
227
- function collectImageParts(tr) {
228
- const { toolUseId, content } = tr;
229
- if (typeof content === "string") {
240
+ function toolOutputForResponses(tr) {
241
+ if (!tr.contentBlocks?.length) {
242
+ return tr.content;
243
+ }
244
+ const rich = [];
245
+ if (tr.content) {
246
+ rich.push({ type: "input_text", text: tr.content });
247
+ }
248
+ for (const block of tr.contentBlocks) {
249
+ const imageUrl = imageDataUrl(block);
250
+ if (imageUrl) {
251
+ rich.push({ type: "input_image", image_url: imageUrl, detail: "auto" });
252
+ continue;
253
+ }
254
+ const file = documentForResponses(block);
255
+ if (file) {
256
+ rich.push(file);
257
+ }
258
+ }
259
+ return rich.length > 0 ? rich : tr.content;
260
+ }
261
+ function collectRichParts(tr) {
262
+ if (!tr.contentBlocks?.length) {
230
263
  return [];
231
264
  }
232
- const images = [];
233
- for (const block of content) {
234
- const url = imageDataUrl(block);
235
- if (url) {
236
- images.push({
237
- type: "image_url",
238
- image_url: { url }
239
- });
265
+ const rich = [];
266
+ for (const block of tr.contentBlocks) {
267
+ const imageUrl = imageDataUrl(block);
268
+ if (imageUrl) {
269
+ rich.push({ type: "image_url", image_url: { url: imageUrl } });
270
+ continue;
271
+ }
272
+ const file = documentForChat(block);
273
+ if (file) {
274
+ rich.push(file);
240
275
  }
241
276
  }
242
- if (images.length === 0) {
277
+ if (rich.length === 0) {
243
278
  return [];
244
279
  }
245
- return [
246
- {
247
- type: "text",
248
- text: `[Image(s) returned by tool call ${toolUseId}]`
249
- },
250
- ...images
251
- ];
280
+ return [{ type: "text", text: `[Rich content returned by tool call ${tr.toolUseId}]` }, ...rich];
252
281
  }
253
282
  function userContentsFor(content) {
254
283
  if (typeof content === "string") {
@@ -313,19 +342,11 @@ function buildOpenAIInput(messages) {
313
342
  });
314
343
  }
315
344
  } else if (m.toolResults && m.toolResults.length > 0) {
316
- const pendingImageContents = [];
317
345
  for (const tr of m.toolResults) {
318
346
  result.push({
319
347
  type: "function_call_output",
320
348
  call_id: tr.toolUseId,
321
- output: contentToText(tr.content)
322
- });
323
- pendingImageContents.push(...collectImageContents(tr));
324
- }
325
- if (pendingImageContents.length > 0) {
326
- result.push({
327
- role: "user",
328
- content: pendingImageContents
349
+ output: toolOutputForResponses(tr)
329
350
  });
330
351
  }
331
352
  } else if (m.role === "assistant") {
@@ -474,12 +495,10 @@ var OpenAICompatClient = class {
474
495
  if (jsonArgs) {
475
496
  try {
476
497
  const parsed = JSON.parse(jsonArgs);
477
- args = isRecord(parsed) ? asRecord(parsed) : { [DANGEROUSLY_JSON]: jsonArgs };
498
+ args = isRecord(parsed) ? asRecord(parsed) : {};
478
499
  } catch (err) {
479
500
  log.error({ err }, "llm operation failed");
480
- args = {
481
- [DANGEROUSLY_JSON]: jsonArgs
482
- };
501
+ args = {};
483
502
  }
484
503
  yield {
485
504
  type: "tool_call_complete",
@@ -552,19 +571,19 @@ function buildChatCompletionMessages(messages) {
552
571
  }))
553
572
  });
554
573
  } else if (m.toolResults && m.toolResults.length > 0) {
555
- const pendingImageParts = [];
574
+ const pendingRichParts = [];
556
575
  for (const tr of m.toolResults) {
557
576
  params.push({
558
577
  role: "tool",
559
578
  tool_call_id: tr.toolUseId,
560
- content: contentToText(tr.content)
579
+ content: tr.content
561
580
  });
562
- pendingImageParts.push(...collectImageParts(tr));
581
+ pendingRichParts.push(...collectRichParts(tr));
563
582
  }
564
- if (pendingImageParts.length > 0) {
583
+ if (pendingRichParts.length > 0) {
565
584
  params.push({
566
585
  role: "user",
567
- content: pendingImageParts
586
+ content: pendingRichParts
568
587
  });
569
588
  }
570
589
  } else if (m.role === "assistant") {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createChildLogger
3
- } from "./chunk-EJLGB2EJ.js";
3
+ } from "./chunk-EY7HE52Q.js";
4
4
 
5
5
  // src/config/config.ts
6
6
  import { existsSync, readFileSync } from "fs";
@@ -75,7 +75,7 @@ async function getContextWindowAsync(p, fetcher) {
75
75
  let fetched = fetchedWindowCache.get(key);
76
76
  if (fetched === void 0) {
77
77
  try {
78
- const fn = fetcher ?? (await import("./anthropic-GFWP3ORB.js")).fetchModelContextWindow;
78
+ const fn = fetcher ?? (await import("./anthropic-7YEN2QTU.js")).fetchModelContextWindow;
79
79
  fetched = await fn(p);
80
80
  } catch (err) {
81
81
  log.error({ err }, "config operation failed");
@@ -230,7 +230,6 @@ function errSerializer(err) {
230
230
 
231
231
  // src/utils/index.ts
232
232
  var log = createChildLogger({ module: "utils" });
233
- var DANGEROUSLY_JSON = "dangerouslyJson";
234
233
  function contentToText(content) {
235
234
  if (typeof content === "string") {
236
235
  return content;
@@ -238,12 +237,21 @@ function contentToText(content) {
238
237
  const parts = [];
239
238
  for (const block of content) {
240
239
  if (block.type === "text" && typeof block.text === "string") {
241
- const b = block;
242
- parts.push(b.text);
243
- } else if (block.type === "image" && typeof block.source === "object") {
244
- const b = block;
245
- const mediaType = b.source.type === "base64" ? b.source.media_type : "image";
240
+ parts.push(block.text);
241
+ } else if (block.type === "image" && isRecord(block.source)) {
242
+ const mediaType = block.source.type === "base64" && typeof block.source.media_type === "string" ? block.source.media_type : "image";
246
243
  parts.push(`[Image: ${mediaType}]`);
244
+ } else if (block.type === "tool_reference" && typeof block.tool_name === "string") {
245
+ parts.push(`[Tool reference: ${block.tool_name}]`);
246
+ } else if (block.type === "search_result") {
247
+ const title = typeof block.title === "string" ? block.title : "search result";
248
+ const source = typeof block.source === "string" ? ` (${block.source})` : "";
249
+ const nested = Array.isArray(block.content) ? contentToText(block.content.filter(isRecord)) : "";
250
+ parts.push(`${title}${source}${nested ? `
251
+ ${nested}` : ""}`);
252
+ } else if (block.type === "document") {
253
+ const title = typeof block.title === "string" ? block.title : "document";
254
+ parts.push(`[Document: ${title}]`);
247
255
  }
248
256
  }
249
257
  return parts.join("\n");
@@ -359,7 +367,6 @@ export {
359
367
  closeLogger,
360
368
  logger,
361
369
  createChildLogger,
362
- DANGEROUSLY_JSON,
363
370
  contentToText,
364
371
  isRecord,
365
372
  asRecord,
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  mcpCallPermissionContent
3
- } from "./chunk-GNBXECZN.js";
3
+ } from "./chunk-PZ42NAFA.js";
4
4
  import {
5
5
  createChildLogger,
6
6
  strArg
7
- } from "./chunk-EJLGB2EJ.js";
7
+ } from "./chunk-EY7HE52Q.js";
8
8
  import {
9
9
  MCP_CALL_TOOL_NAME
10
10
  } from "./chunk-GHF2PSEW.js";
@@ -6,24 +6,19 @@ import {
6
6
  saveMessage,
7
7
  toolResultsToRecords,
8
8
  toolUsesToRecords
9
- } from "./chunk-C7IHCJZ3.js";
9
+ } from "./chunk-BN4Q54G2.js";
10
10
  import {
11
11
  ContextTooLongError,
12
12
  REJECTED_TOOL_RESULT,
13
13
  RateLimitError
14
- } from "./chunk-UMFNTXKA.js";
14
+ } from "./chunk-OO2CLOEE.js";
15
15
  import {
16
16
  asErrorString,
17
17
  asRecord,
18
- asString,
19
- contentToText,
20
18
  createChildLogger,
21
19
  isObject,
22
20
  strArg
23
- } from "./chunk-EJLGB2EJ.js";
24
-
25
- // src/agent/agent.ts
26
- import { readFile } from "fs/promises";
21
+ } from "./chunk-EY7HE52Q.js";
27
22
 
28
23
  // src/compact/recovery.ts
29
24
  var RECOVERY_FILE_LIMIT = 5;
@@ -48,13 +43,29 @@ function truncateByTokens(s, tokenBudget) {
48
43
  if (maxChars <= 0 || maxChars >= s.length) {
49
44
  return s;
50
45
  }
51
- return s.slice(0, maxChars) + "\n\u2026 (content truncated)";
46
+ const suffix = "\n\u2026 (content truncated)";
47
+ if (maxChars <= suffix.length) {
48
+ return suffix.slice(0, maxChars);
49
+ }
50
+ return s.slice(0, maxChars - suffix.length) + suffix;
52
51
  }
53
52
  var RecoveryState = class {
54
53
  files = /* @__PURE__ */ new Map();
55
54
  skills = /* @__PURE__ */ new Map();
56
55
  recordFileRead(path, content) {
57
- this.files.set(path, { path, content, timestamp: Date.now() });
56
+ this.files.delete(path);
57
+ this.files.set(path, {
58
+ path,
59
+ content: truncateByTokens(content, RECOVERY_TOKENS_PER_FILE),
60
+ timestamp: Date.now()
61
+ });
62
+ while (this.files.size > RECOVERY_FILE_LIMIT) {
63
+ const oldestPath = this.files.keys().next().value;
64
+ if (typeof oldestPath !== "string") {
65
+ break;
66
+ }
67
+ this.files.delete(oldestPath);
68
+ }
58
69
  }
59
70
  recordSkillInvocation(name, body) {
60
71
  this.skills.set(name, { name, body, timestamp: Date.now() });
@@ -465,6 +476,7 @@ import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
465
476
  import { join as join2, resolve as resolve2 } from "path";
466
477
  var log2 = createChildLogger({ module: "tool-result" });
467
478
  var MESSAGE_AGGREGATE_LIMIT = 2e5;
479
+ var TOOL_RESULT_PREVIEW_CHARS = 2e3;
468
480
  function spillDir(workDir, sessionId) {
469
481
  const id = sessionId || "default";
470
482
  return join2(workDir, ".swifty", "sessions", id, "tool-results");
@@ -483,11 +495,26 @@ function writeSpill(workDir, sessionId, toolUseId, content) {
483
495
  }
484
496
  return path;
485
497
  }
486
- var PREVIEW_CHARS = 2e3;
498
+ function toDisplayPreview(content) {
499
+ if (content.length <= TOOL_RESULT_PREVIEW_CHARS) {
500
+ return content;
501
+ }
502
+ return content.slice(0, TOOL_RESULT_PREVIEW_CHARS) + `
503
+ \u2026 ${String(content.length - TOOL_RESULT_PREVIEW_CHARS)} chars omitted from transcript`;
504
+ }
505
+ function replaceToolResultContent(result, content) {
506
+ result.content = content;
507
+ if (result.contentBlocks?.length) {
508
+ result.contentBlocks = [
509
+ { type: "text", text: content },
510
+ ...result.contentBlocks.filter((block) => block.type !== "text")
511
+ ];
512
+ }
513
+ }
487
514
  function buildSpillPreview(content, spillPath) {
488
515
  const sizeKB = Math.floor(content.length / 1024);
489
- const preview = content.slice(0, PREVIEW_CHARS);
490
- const hasMore = content.length > PREVIEW_CHARS;
516
+ const preview = content.slice(0, TOOL_RESULT_PREVIEW_CHARS);
517
+ const hasMore = content.length > TOOL_RESULT_PREVIEW_CHARS;
491
518
  let msg = `<persisted-output>
492
519
  `;
493
520
  msg += `Output too large (${String(sizeKB)}KB). Full content saved to:
@@ -513,17 +540,11 @@ function isSpillReadback(toolName, args, workDir, sessionId) {
513
540
  return resolve2(raw).startsWith(resolve2(spillDir(workDir, sessionId)));
514
541
  }
515
542
  function applyBudget(toolResults, workDir, sessionId, exemptIds) {
516
- const spillable = toolResults.filter((r) => typeof r.content === "string");
517
- let total = spillable.reduce(
518
- (sum, r) => sum + (typeof r.content === "string" ? r.content.length : 0),
519
- 0
520
- );
543
+ let total = toolResults.reduce((sum, result) => sum + result.content.length, 0);
521
544
  if (total <= MESSAGE_AGGREGATE_LIMIT) {
522
545
  return;
523
546
  }
524
- const sorted = spillable.toSorted(
525
- (a, b) => asString(b.content).length - asString(a.content).length
526
- );
547
+ const sorted = toolResults.toSorted((a, b) => b.content.length - a.content.length);
527
548
  for (const r of sorted) {
528
549
  if (total <= MESSAGE_AGGREGATE_LIMIT) {
529
550
  break;
@@ -531,8 +552,8 @@ function applyBudget(toolResults, workDir, sessionId, exemptIds) {
531
552
  if (exemptIds?.has(r.toolUseId)) {
532
553
  continue;
533
554
  }
534
- const content = asString(r.content);
535
- if (content.length <= PREVIEW_CHARS) {
555
+ const content = r.content;
556
+ if (content.length <= TOOL_RESULT_PREVIEW_CHARS) {
536
557
  continue;
537
558
  }
538
559
  let spillPath;
@@ -543,7 +564,7 @@ function applyBudget(toolResults, workDir, sessionId, exemptIds) {
543
564
  }
544
565
  const replacement = buildSpillPreview(content, spillPath);
545
566
  total -= content.length - replacement.length;
546
- r.content = replacement;
567
+ replaceToolResultContent(r, replacement);
547
568
  }
548
569
  }
549
570
  function persistLargeResult(workDir, sessionId, toolUseId, content) {
@@ -959,16 +980,25 @@ var Agent = class {
959
980
  const toolResults = [];
960
981
  for (const r of results) {
961
982
  if (r.type === "tool_result") {
962
- let content = r.output;
963
- if (typeof content === "string" && content.length > MAX_OUTPUT_CHARS && !exemptIds.has(r.toolId)) {
964
- content = persistLargeResult(this.workDir, this.sessionId, r.toolId, content);
965
- exemptIds.add(r.toolId);
966
- }
967
- toolResults.push({
983
+ const toolResult = {
968
984
  toolUseId: r.toolId,
969
- content,
985
+ content: r.output,
986
+ ...r.contentBlocks?.length ? { contentBlocks: r.contentBlocks } : {},
970
987
  isError: r.isError
971
- });
988
+ };
989
+ if (toolResult.content.length > MAX_OUTPUT_CHARS && !exemptIds.has(r.toolId)) {
990
+ const replacement = persistLargeResult(
991
+ this.workDir,
992
+ this.sessionId,
993
+ r.toolId,
994
+ toolResult.content
995
+ );
996
+ if (replacement !== toolResult.content) {
997
+ replaceToolResultContent(toolResult, replacement);
998
+ }
999
+ exemptIds.add(r.toolId);
1000
+ }
1001
+ toolResults.push(toolResult);
972
1002
  }
973
1003
  }
974
1004
  applyBudget(toolResults, this.workDir, this.sessionId, exemptIds);
@@ -1158,14 +1188,11 @@ var Agent = class {
1158
1188
  // processToolResult handles a single executor result: records file-read
1159
1189
  // snapshots, emits the tool_result event, and fires post-tool hooks.
1160
1190
  async processToolResult(r, toolUses, events) {
1161
- if (!r.result.isError && r.toolName === "ReadFile" && typeof r.result.output === "string") {
1191
+ if (!r.result.isError && r.toolName === "ReadFile" && !r.result.contentBlocks?.length) {
1162
1192
  const tu = toolUses.find((t) => t.toolUseId === r.toolId);
1163
1193
  const p = strArg(tu?.arguments ?? {}, "file_path");
1164
1194
  if (p) {
1165
- try {
1166
- this.recoveryState.recordFileRead(p, await readFile(p, "utf-8"));
1167
- } catch {
1168
- }
1195
+ this.recoveryState.recordFileRead(p, r.result.output);
1169
1196
  }
1170
1197
  }
1171
1198
  events.push({
@@ -1173,6 +1200,7 @@ var Agent = class {
1173
1200
  toolName: r.toolName,
1174
1201
  toolId: r.toolId,
1175
1202
  output: r.result.output,
1203
+ ...r.result.contentBlocks?.length ? { contentBlocks: r.result.contentBlocks } : {},
1176
1204
  isError: r.result.isError,
1177
1205
  elapsed: r.elapsed
1178
1206
  });
@@ -1180,7 +1208,7 @@ var Agent = class {
1180
1208
  const hookResults = await this.hookEngine.fire("post_tool_use", {
1181
1209
  event: "post_tool_use",
1182
1210
  toolName: r.toolName,
1183
- message: contentToText(r.result.output)
1211
+ message: r.result.output
1184
1212
  });
1185
1213
  for (const hr of hookResults) {
1186
1214
  if (hr.output) {
@@ -1238,6 +1266,9 @@ export {
1238
1266
  buildPlanModeReminder,
1239
1267
  buildPlanModeExitReminder,
1240
1268
  buildPlanModeReentryReminder,
1269
+ TOOL_RESULT_PREVIEW_CHARS,
1270
+ toDisplayPreview,
1271
+ replaceToolResultContent,
1241
1272
  isSpillReadback,
1242
1273
  applyBudget,
1243
1274
  persistLargeResult,
@@ -1,3 +1,37 @@
1
+ // src/llm/errors.ts
2
+ var LLMError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "LLMError";
6
+ }
7
+ };
8
+ var AuthenticationError = class extends LLMError {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = "AuthenticationError";
12
+ }
13
+ };
14
+ var RateLimitError = class extends LLMError {
15
+ retryAfter;
16
+ constructor(message, retryAfter) {
17
+ super(message);
18
+ this.name = "RateLimitError";
19
+ this.retryAfter = retryAfter;
20
+ }
21
+ };
22
+ var NetworkError = class extends LLMError {
23
+ constructor(message) {
24
+ super(message);
25
+ this.name = "NetworkError";
26
+ }
27
+ };
28
+ var ContextTooLongError = class extends LLMError {
29
+ constructor(message) {
30
+ super(message);
31
+ this.name = "ContextTooLongError";
32
+ }
33
+ };
34
+
1
35
  // src/conversation/pairing.ts
2
36
  var INTERRUPTED_TOOL_RESULT = "Tool execution was interrupted. The tool may or may not have completed; verify before relying on its effects.";
3
37
  var REJECTED_TOOL_RESULT = "The user rejected this tool use. Nothing was changed (for file edits, the new content was NOT written).";
@@ -42,47 +76,13 @@ function ensureToolPairing(messages) {
42
76
  return out;
43
77
  }
44
78
 
45
- // src/llm/errors.ts
46
- var LLMError = class extends Error {
47
- constructor(message) {
48
- super(message);
49
- this.name = "LLMError";
50
- }
51
- };
52
- var AuthenticationError = class extends LLMError {
53
- constructor(message) {
54
- super(message);
55
- this.name = "AuthenticationError";
56
- }
57
- };
58
- var RateLimitError = class extends LLMError {
59
- retryAfter;
60
- constructor(message, retryAfter) {
61
- super(message);
62
- this.name = "RateLimitError";
63
- this.retryAfter = retryAfter;
64
- }
65
- };
66
- var NetworkError = class extends LLMError {
67
- constructor(message) {
68
- super(message);
69
- this.name = "NetworkError";
70
- }
71
- };
72
- var ContextTooLongError = class extends LLMError {
73
- constructor(message) {
74
- super(message);
75
- this.name = "ContextTooLongError";
76
- }
77
- };
78
-
79
79
  export {
80
- INTERRUPTED_TOOL_RESULT,
81
- REJECTED_TOOL_RESULT,
82
- ensureToolPairing,
83
80
  LLMError,
84
81
  AuthenticationError,
85
82
  RateLimitError,
86
83
  NetworkError,
87
- ContextTooLongError
84
+ ContextTooLongError,
85
+ INTERRUPTED_TOOL_RESULT,
86
+ REJECTED_TOOL_RESULT,
87
+ ensureToolPairing
88
88
  };
@@ -3,7 +3,7 @@ import {
3
3
  asRecord,
4
4
  createChildLogger,
5
5
  strArg
6
- } from "./chunk-EJLGB2EJ.js";
6
+ } from "./chunk-EY7HE52Q.js";
7
7
  import {
8
8
  MCP_CALL_TOOL_NAME
9
9
  } from "./chunk-GHF2PSEW.js";
@@ -56,8 +56,7 @@ var MCPToolWrapper = class {
56
56
  }
57
57
  async execute(_ctx, args) {
58
58
  try {
59
- const { output, isError } = await this.client.callTool(this.originalName, args);
60
- return { output, isError };
59
+ return await this.client.callTool(this.originalName, args);
61
60
  } catch (err) {
62
61
  log.error({ err }, "mcp operation failed");
63
62
  return {