zidane 3.1.0 → 3.1.1

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.
@@ -1,5 +1,5 @@
1
1
  import { Hookable } from 'hookable';
2
- import { b as ExecutionContext, c as ExecutionHandle } from './types-BpvTmawk.js';
2
+ import { b as ExecutionContext, c as ExecutionHandle } from './types-vA1a_ZX7.js';
3
3
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
4
4
 
5
5
  /**
@@ -451,8 +451,24 @@ interface AgentRunOptions {
451
451
  */
452
452
  depth?: number;
453
453
  }
454
- /** Reason the provider gave for stopping the turn */
455
- type TurnFinishReason = 'stop' | 'tool-calls' | 'length' | 'content-filter' | 'error' | 'other';
454
+ /**
455
+ * Reason the provider gave for stopping the turn.
456
+ *
457
+ * - `'stop'` — natural turn end (`end_turn` / `stop_sequence`).
458
+ * - `'tool-calls'` — model emitted tool_use blocks.
459
+ * - `'length'` — `max_tokens` reached, or (Anthropic 4.6+) the response bumped
460
+ * against the model's context window mid-stream
461
+ * (`model_context_window_exceeded`). The partial response is preserved; the
462
+ * loop emits this reason so consumers can prune/retry.
463
+ * - `'content-filter'` — model refused.
464
+ * - `'pause'` — Anthropic `pause_turn`: a server-side mid-turn pause for very
465
+ * long thinking. The loop continues with a synthetic "Please continue."
466
+ * user message rather than terminating; consumers see the pause via this
467
+ * finish reason on the prior assistant turn.
468
+ * - `'error'` — provider classified the turn as failed.
469
+ * - `'other'` — unknown / unmapped.
470
+ */
471
+ type TurnFinishReason = 'stop' | 'tool-calls' | 'length' | 'content-filter' | 'pause' | 'error' | 'other';
456
472
  interface TurnUsage {
457
473
  input: number;
458
474
  output: number;
@@ -221,11 +221,14 @@ function mapStopReason(stopReason) {
221
221
  case "tool_use":
222
222
  return "tool-calls";
223
223
  case "max_tokens":
224
+ case "model_context_window_exceeded":
224
225
  return "length";
225
226
  case "refusal":
226
227
  return "content-filter";
228
+ // 4.6+: server-side mid-turn pause for long thinking. The loop
229
+ // continues with a synthetic continue message rather than terminating.
227
230
  case "pause_turn":
228
- return "other";
231
+ return "pause";
229
232
  default:
230
233
  return "other";
231
234
  }
@@ -485,11 +488,12 @@ function anthropic(anthropicParams) {
485
488
  const response = await s.finalMessage();
486
489
  const toolCalls = response.content.filter((b) => b.type === "tool_use").map((b) => ({ id: b.id, name: b.name, input: b.input }));
487
490
  const finishReason = mapStopReason(response.stop_reason);
491
+ const isPause = response.stop_reason === "pause_turn";
488
492
  return {
489
493
  assistantMessage: fromAnthropic({ role: "assistant", content: response.content }),
490
494
  text,
491
495
  toolCalls,
492
- done: response.stop_reason === "end_turn" || toolCalls.length === 0,
496
+ done: !isPause && (response.stop_reason === "end_turn" || toolCalls.length === 0),
493
497
  usage: {
494
498
  input: response.usage.input_tokens,
495
499
  output: response.usage.output_tokens,
@@ -6,7 +6,7 @@ import {
6
6
  shell,
7
7
  spawn,
8
8
  writeFile
9
- } from "./chunk-PYLYK3K7.js";
9
+ } from "./chunk-EBSFBIP3.js";
10
10
 
11
11
  // src/presets/basic.ts
12
12
  var basicTools = { shell, readFile, writeFile, listFiles, edit, multiEdit };
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-TPXPVEH6.js";
9
9
  import {
10
10
  createProcessContext
11
- } from "./chunk-2EQT4EHD.js";
11
+ } from "./chunk-IUBBVF53.js";
12
12
  import {
13
13
  connectMcpServers
14
14
  } from "./chunk-R74LQKAM.js";
@@ -36,6 +36,154 @@ function countExactMatches(haystack, needle) {
36
36
  }
37
37
  return count;
38
38
  }
39
+ var LEFT_SINGLE_CURLY_QUOTE = "\u2018";
40
+ var RIGHT_SINGLE_CURLY_QUOTE = "\u2019";
41
+ var LEFT_DOUBLE_CURLY_QUOTE = "\u201C";
42
+ var RIGHT_DOUBLE_CURLY_QUOTE = "\u201D";
43
+ function normalizeQuotes(str) {
44
+ return str.replaceAll(LEFT_SINGLE_CURLY_QUOTE, "'").replaceAll(RIGHT_SINGLE_CURLY_QUOTE, "'").replaceAll(LEFT_DOUBLE_CURLY_QUOTE, '"').replaceAll(RIGHT_DOUBLE_CURLY_QUOTE, '"');
45
+ }
46
+ var DESANITIZATIONS = [
47
+ ["<fnr>", "<function_results>"],
48
+ ["<n>", "<name>"],
49
+ ["</n>", "</name>"],
50
+ ["<o>", "<output>"],
51
+ ["</o>", "</output>"],
52
+ ["<e>", "<error>"],
53
+ ["</e>", "</error>"],
54
+ ["<s>", "<system>"],
55
+ ["</s>", "</system>"],
56
+ ["<r>", "<result>"],
57
+ ["</r>", "</result>"],
58
+ ["< META_START >", "<META_START>"],
59
+ ["< META_END >", "<META_END>"],
60
+ ["< EOT >", "<EOT>"],
61
+ ["< META >", "<META>"],
62
+ ["< SOS >", "<SOS>"],
63
+ ["\n\nH:", "\n\nHuman:"],
64
+ ["\n\nA:", "\n\nAssistant:"]
65
+ ];
66
+ function desanitize(s) {
67
+ let out = s;
68
+ for (const [from, to] of DESANITIZATIONS)
69
+ out = out.replaceAll(from, to);
70
+ return out;
71
+ }
72
+ function resolveOldString(haystack, needle) {
73
+ const exact = countExactMatches(haystack, needle);
74
+ if (exact > 0)
75
+ return { actual: needle, occurrences: exact, via: "exact" };
76
+ const normNeedle = normalizeQuotes(needle);
77
+ const normFile = normalizeQuotes(haystack);
78
+ if (normNeedle !== needle || normFile !== haystack) {
79
+ const idx = normFile.indexOf(normNeedle);
80
+ if (idx !== -1) {
81
+ const actual = haystack.slice(idx, idx + normNeedle.length);
82
+ let occ = 0;
83
+ let cursor = 0;
84
+ while (true) {
85
+ const next = normFile.indexOf(normNeedle, cursor);
86
+ if (next === -1)
87
+ break;
88
+ occ++;
89
+ cursor = next + normNeedle.length;
90
+ }
91
+ return { actual, occurrences: occ, via: "quotes" };
92
+ }
93
+ }
94
+ const desan = desanitize(needle);
95
+ if (desan !== needle) {
96
+ const desanCount = countExactMatches(haystack, desan);
97
+ if (desanCount > 0)
98
+ return { actual: desan, occurrences: desanCount, via: "desanitize" };
99
+ }
100
+ const combo = desanitize(normNeedle);
101
+ if (combo !== needle) {
102
+ const idx = normFile.indexOf(combo);
103
+ if (idx !== -1) {
104
+ const actual = haystack.slice(idx, idx + combo.length);
105
+ let occ = 0;
106
+ let cursor = 0;
107
+ while (true) {
108
+ const next = normFile.indexOf(combo, cursor);
109
+ if (next === -1)
110
+ break;
111
+ occ++;
112
+ cursor = next + combo.length;
113
+ }
114
+ return { actual, occurrences: occ, via: "quotes+desanitize" };
115
+ }
116
+ }
117
+ return null;
118
+ }
119
+ function preserveQuoteStyle(actual, replacement) {
120
+ const hasDouble = actual.includes(LEFT_DOUBLE_CURLY_QUOTE) || actual.includes(RIGHT_DOUBLE_CURLY_QUOTE);
121
+ const hasSingle = actual.includes(LEFT_SINGLE_CURLY_QUOTE) || actual.includes(RIGHT_SINGLE_CURLY_QUOTE);
122
+ if (!hasDouble && !hasSingle)
123
+ return replacement;
124
+ let out = replacement;
125
+ if (hasDouble)
126
+ out = applyCurly(out, '"', LEFT_DOUBLE_CURLY_QUOTE, RIGHT_DOUBLE_CURLY_QUOTE, false);
127
+ if (hasSingle)
128
+ out = applyCurly(out, "'", LEFT_SINGLE_CURLY_QUOTE, RIGHT_SINGLE_CURLY_QUOTE, true);
129
+ return out;
130
+ }
131
+ function applyCurly(s, straight, left, right, contractionAware) {
132
+ const chars = [...s];
133
+ const result = [];
134
+ for (let i = 0; i < chars.length; i++) {
135
+ if (chars[i] !== straight) {
136
+ result.push(chars[i]);
137
+ continue;
138
+ }
139
+ if (contractionAware) {
140
+ const prev = i > 0 ? chars[i - 1] : "";
141
+ const next = i < chars.length - 1 ? chars[i + 1] : "";
142
+ if (/\p{L}/u.test(prev) && /\p{L}/u.test(next)) {
143
+ result.push(right);
144
+ continue;
145
+ }
146
+ }
147
+ result.push(isOpeningContext(chars, i) ? left : right);
148
+ }
149
+ return result.join("");
150
+ }
151
+ function isOpeningContext(chars, i) {
152
+ if (i === 0)
153
+ return true;
154
+ const prev = chars[i - 1];
155
+ return prev === " " || prev === " " || prev === "\n" || prev === "\r" || prev === "(" || prev === "[" || prev === "{" || prev === "\u2014" || prev === "\u2013";
156
+ }
157
+
158
+ // src/tools/path-suggest.ts
159
+ async function findSimilarFile(execution, handle, path) {
160
+ const slash = path.lastIndexOf("/");
161
+ const dir = slash === -1 ? "." : path.slice(0, slash) || "/";
162
+ const target = slash === -1 ? path : path.slice(slash + 1);
163
+ const dot = target.lastIndexOf(".");
164
+ const targetBase = dot === -1 ? target : target.slice(0, dot);
165
+ if (targetBase.length === 0)
166
+ return null;
167
+ let entries;
168
+ try {
169
+ entries = await execution.listFiles(handle, dir);
170
+ } catch {
171
+ return null;
172
+ }
173
+ for (const entry of entries) {
174
+ if (entry === target)
175
+ continue;
176
+ const entryDot = entry.lastIndexOf(".");
177
+ const entryBase = entryDot === -1 ? entry : entry.slice(0, entryDot);
178
+ if (entryBase === targetBase)
179
+ return entry;
180
+ }
181
+ return null;
182
+ }
183
+ async function suggestionFor(execution, handle, path) {
184
+ const sibling = await findSimilarFile(execution, handle, path);
185
+ return sibling ? ` Did you mean ${sibling}?` : "";
186
+ }
39
187
 
40
188
  // src/tools/read-state.ts
41
189
  var STATE = /* @__PURE__ */ new WeakMap();
@@ -87,7 +235,8 @@ var edit = {
87
235
  try {
88
236
  original = await ctx.execution.readFile(ctx.handle, target);
89
237
  } catch {
90
- return `Edit error: file not found: ${target}`;
238
+ const hint = await suggestionFor(ctx.execution, ctx.handle, target);
239
+ return `Edit error: file not found: ${target}.${hint}`;
91
240
  }
92
241
  if (ctx.behavior?.requireReadBeforeEdit && ctx.session) {
93
242
  const readState = getReadState(ctx.session);
@@ -98,14 +247,18 @@ var edit = {
98
247
  if (prior.contentHash !== hashContent(original))
99
248
  return `Edit error: ${target} has changed on disk since the last read. Re-read the file before editing.`;
100
249
  }
101
- const occurrences = countExactMatches(original, find);
102
- if (occurrences === 0) {
250
+ const match = resolveOldString(original, find);
251
+ if (!match) {
103
252
  const preview = nearestMatchPreview(original, find);
104
253
  return preview ? `Edit error: old_string not found in ${target}. Closest match in the file: ${preview}` : `Edit error: old_string not found in ${target}.`;
105
254
  }
255
+ const { actual, occurrences, via } = match;
106
256
  if (occurrences > 1 && !replaceAll)
107
257
  return `Edit error: old_string appears ${occurrences} times in ${target}. Pass replace_all=true or expand old_string for uniqueness.`;
108
- const updated = replaceAll ? original.split(find).join(replacement) : original.replace(find, replacement);
258
+ let styledReplacement = via === "desanitize" || via === "quotes+desanitize" ? desanitize(replacement) : replacement;
259
+ if (via === "quotes" || via === "quotes+desanitize")
260
+ styledReplacement = preserveQuoteStyle(actual, styledReplacement);
261
+ const updated = replaceAll ? original.split(actual).join(styledReplacement) : original.replace(actual, styledReplacement);
109
262
  if (updated === original)
110
263
  return `Edit error: replacement produced no change in ${target}.`;
111
264
  await ctx.execution.writeFile(ctx.handle, target, updated);
@@ -479,7 +632,8 @@ var multiEdit = {
479
632
  try {
480
633
  current = await ctx.execution.readFile(ctx.handle, target);
481
634
  } catch {
482
- return `multi_edit error: file not found: ${target}`;
635
+ const hint = await suggestionFor(ctx.execution, ctx.handle, target);
636
+ return `multi_edit error: file not found: ${target}.${hint}`;
483
637
  }
484
638
  if (ctx.behavior?.requireReadBeforeEdit && ctx.session) {
485
639
  const readState = getReadState(ctx.session);
@@ -502,12 +656,16 @@ var multiEdit = {
502
656
  return `multi_edit error: edit #${i + 1} has empty old_string. Use write_file to fully replace a file.`;
503
657
  if (find === replacement)
504
658
  return `multi_edit error: edit #${i + 1} old_string and new_string are identical.`;
505
- const occurrences = countExactMatches(current, find);
506
- if (occurrences === 0)
659
+ const match = resolveOldString(current, find);
660
+ if (!match)
507
661
  return `multi_edit error: edit #${i + 1} old_string not found in ${target}.`;
662
+ const { actual, occurrences, via } = match;
508
663
  if (occurrences > 1 && !replaceAll)
509
664
  return `multi_edit error: edit #${i + 1} old_string appears ${occurrences} times. Pass replace_all=true on this edit or expand old_string for uniqueness.`;
510
- current = replaceAll ? current.split(find).join(replacement) : current.replace(find, replacement);
665
+ let styledReplacement = via === "desanitize" || via === "quotes+desanitize" ? desanitize(replacement) : replacement;
666
+ if (via === "quotes" || via === "quotes+desanitize")
667
+ styledReplacement = preserveQuoteStyle(actual, styledReplacement);
668
+ current = replaceAll ? current.split(actual).join(styledReplacement) : current.replace(actual, styledReplacement);
511
669
  applied += occurrences;
512
670
  }
513
671
  await ctx.execution.writeFile(ctx.handle, target, current);
@@ -524,10 +682,51 @@ var multiEdit = {
524
682
  };
525
683
 
526
684
  // src/tools/read-file.ts
685
+ import { Buffer as Buffer2 } from "buffer";
686
+
687
+ // src/tools/binary-read.ts
527
688
  import { Buffer } from "buffer";
689
+ function imageMediaTypeFor(path) {
690
+ const dot = path.lastIndexOf(".");
691
+ if (dot === -1)
692
+ return void 0;
693
+ const ext = path.slice(dot + 1).toLowerCase();
694
+ switch (ext) {
695
+ case "png":
696
+ return "image/png";
697
+ case "jpg":
698
+ case "jpeg":
699
+ return "image/jpeg";
700
+ case "gif":
701
+ return "image/gif";
702
+ case "webp":
703
+ return "image/webp";
704
+ default:
705
+ return void 0;
706
+ }
707
+ }
708
+ async function readFileAsBase64(execution, handle, path) {
709
+ if (execution.readFileBinary) {
710
+ const bytes = await execution.readFileBinary(handle, path);
711
+ const b642 = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
712
+ return { base64: b642, byteLength: bytes.byteLength };
713
+ }
714
+ const cmd = `base64 < ${shellQuote2(path)}`;
715
+ const result = await execution.exec(handle, cmd);
716
+ if (result.exitCode !== 0)
717
+ throw new Error(`base64 read failed: ${result.stderr || `exit ${result.exitCode}`}`);
718
+ const b64 = result.stdout.replace(/\s+/g, "");
719
+ return { base64: b64, byteLength: Math.floor(b64.length * 3 / 4) };
720
+ }
721
+ function shellQuote2(s) {
722
+ return `'${s.replace(/'/g, "'\\''")}'`;
723
+ }
724
+
725
+ // src/tools/read-file.ts
528
726
  var DEFAULT_LINE_LIMIT = 2e3;
529
727
  var DEFAULT_BYTE_CAP = 65536;
530
728
  var BINARY_PROBE_BYTES = 8e3;
729
+ var DEFAULT_IMAGE_BYTE_CAP = 5 * 1024 * 1024;
531
730
  var readFile = {
532
731
  spec: {
533
732
  name: "read_file",
@@ -544,13 +743,33 @@ var readFile = {
544
743
  }
545
744
  },
546
745
  async execute({ path, offset, limit, maxBytes }, ctx) {
746
+ const imgMedia = imageMediaTypeFor(path);
747
+ if (imgMedia) {
748
+ const sizeCap = maxBytes !== void 0 ? normalizeInteger(maxBytes, DEFAULT_IMAGE_BYTE_CAP) : DEFAULT_IMAGE_BYTE_CAP;
749
+ try {
750
+ const { base64, byteLength } = await readFileAsBase64(ctx.execution, ctx.handle, path);
751
+ if (sizeCap > 0 && byteLength > sizeCap) {
752
+ return `[image too large to inline: ${path}, ${byteLength} bytes (cap ${sizeCap}). Raise maxBytes, or use shell to inspect.]`;
753
+ }
754
+ const content = [
755
+ { type: "text", text: `Image: ${path} (${byteLength} bytes, ${imgMedia})` },
756
+ { type: "image", mediaType: imgMedia, data: base64 }
757
+ ];
758
+ return content;
759
+ } catch (err) {
760
+ const msg = err instanceof Error ? err.message : String(err);
761
+ const hint = await suggestionFor(ctx.execution, ctx.handle, path);
762
+ return `Image read failed: ${path} \u2014 ${msg}.${hint}`;
763
+ }
764
+ }
547
765
  let raw;
548
766
  try {
549
767
  raw = await ctx.execution.readFile(ctx.handle, path);
550
768
  } catch {
551
- return `File not found: ${path}`;
769
+ const hint = await suggestionFor(ctx.execution, ctx.handle, path);
770
+ return `File not found: ${path}.${hint}`;
552
771
  }
553
- const totalBytes = Buffer.byteLength(raw);
772
+ const totalBytes = Buffer2.byteLength(raw);
554
773
  const dedupEnabled = ctx.behavior?.dedupReads !== false;
555
774
  const readState = dedupEnabled ? getReadState(ctx.session) : void 0;
556
775
  const absKey = `${ctx.handle.cwd}::${path}`;
@@ -580,7 +799,7 @@ var readFile = {
580
799
  if (maxBytesN > 0) {
581
800
  const truncatedSlice = [];
582
801
  for (const line of slice) {
583
- const lineBytes = Buffer.byteLength(line) + 1;
802
+ const lineBytes = Buffer2.byteLength(line) + 1;
584
803
  if (bytesUsed + lineBytes > maxBytesN && truncatedSlice.length > 0) {
585
804
  bytesCut = true;
586
805
  break;
@@ -597,14 +816,14 @@ var readFile = {
597
816
  }
598
817
  let midLineCut = false;
599
818
  if (maxBytesN > 0 && slice.length > 0) {
600
- const bodyBytes = Buffer.byteLength(slice.join("\n"));
819
+ const bodyBytes = Buffer2.byteLength(slice.join("\n"));
601
820
  if (bodyBytes > maxBytesN) {
602
821
  const lastIdx = slice.length - 1;
603
822
  const lastLine = slice[lastIdx];
604
- const otherBytes = lastIdx > 0 ? Buffer.byteLength(slice.slice(0, lastIdx).join("\n")) + 1 : 0;
823
+ const otherBytes = lastIdx > 0 ? Buffer2.byteLength(slice.slice(0, lastIdx).join("\n")) + 1 : 0;
605
824
  const budgetForLast = Math.max(0, maxBytesN - otherBytes);
606
825
  let cut = Math.min(lastLine.length, budgetForLast);
607
- while (cut > 0 && Buffer.byteLength(lastLine.slice(0, cut)) > budgetForLast)
826
+ while (cut > 0 && Buffer2.byteLength(lastLine.slice(0, cut)) > budgetForLast)
608
827
  cut--;
609
828
  slice[lastIdx] = lastLine.slice(0, cut);
610
829
  midLineCut = true;
@@ -666,7 +885,38 @@ function looksBinary(text) {
666
885
  }
667
886
 
668
887
  // src/tools/shell.ts
669
- import { Buffer as Buffer2 } from "buffer";
888
+ import { Buffer as Buffer3 } from "buffer";
889
+
890
+ // src/tools/shell-semantics.ts
891
+ var DEFAULT_SEMANTIC = (exitCode) => ({
892
+ isError: exitCode !== 0,
893
+ message: exitCode !== 0 ? `Command failed with exit code ${exitCode}` : void 0
894
+ });
895
+ var COMMAND_SEMANTICS = /* @__PURE__ */ new Map([
896
+ // grep / ripgrep: 0 = matches, 1 = no matches, ≥2 = error.
897
+ ["grep", (exit) => ({ isError: exit >= 2, message: exit === 1 ? "No matches found" : void 0 })],
898
+ ["rg", (exit) => ({ isError: exit >= 2, message: exit === 1 ? "No matches found" : void 0 })],
899
+ // diff: 0 = identical, 1 = differ, ≥2 = error.
900
+ ["diff", (exit) => ({ isError: exit >= 2, message: exit === 1 ? "Files differ" : void 0 })],
901
+ // find: 0 = ok, 1 = some dirs inaccessible (warning), ≥2 = error.
902
+ ["find", (exit) => ({ isError: exit >= 2, message: exit === 1 ? "Some directories were inaccessible" : void 0 })],
903
+ // test / [: 0 = condition true, 1 = condition false, ≥2 = error.
904
+ ["test", (exit) => ({ isError: exit >= 2, message: exit === 1 ? "Condition is false" : void 0 })],
905
+ ["[", (exit) => ({ isError: exit >= 2, message: exit === 1 ? "Condition is false" : void 0 })]
906
+ ]);
907
+ function interpretShellResult(command, exitCode) {
908
+ const base = extractTrailingCommand(command);
909
+ const semantic = COMMAND_SEMANTICS.get(base) ?? DEFAULT_SEMANTIC;
910
+ return semantic(exitCode);
911
+ }
912
+ function extractTrailingCommand(command) {
913
+ const segments = command.split(/\|\||&&|[;|\n]/);
914
+ const last = segments[segments.length - 1]?.trim() ?? command;
915
+ const tokens = last.split(/\s+/).filter((t) => !/^[A-Z_]\w*=/i.test(t));
916
+ return tokens[0] ?? "";
917
+ }
918
+
919
+ // src/tools/shell.ts
670
920
  var DEFAULT_MAX_OUTPUT_BYTES = 8192;
671
921
  var shell = {
672
922
  spec: {
@@ -686,10 +936,19 @@ var shell = {
686
936
  const execOpts = {};
687
937
  if (typeof timeout === "number" && Number.isFinite(timeout) && timeout > 0)
688
938
  execOpts.timeout = Math.max(1, Math.ceil(timeout / 1e3));
689
- const result = await ctx.execution.exec(ctx.handle, command, execOpts);
939
+ const cmd = command;
940
+ const result = await ctx.execution.exec(ctx.handle, cmd, execOpts);
690
941
  const cap = normalizeCap(maxOutputBytes);
942
+ const semantic = interpretShellResult(cmd, result.exitCode);
691
943
  if (result.exitCode === 0)
692
944
  return truncateTail(result.stdout || "(no output)", cap);
945
+ if (!semantic.isError) {
946
+ const body = (result.stdout || result.stderr || "").trim();
947
+ const tail = truncateTail(body, cap);
948
+ const footer = semantic.message ? `
949
+ (${semantic.message})` : "";
950
+ return tail.length > 0 ? `${tail}${footer}` : semantic.message ?? "(no output)";
951
+ }
693
952
  const combined = `${result.stdout}
694
953
  ${result.stderr}`.trim();
695
954
  return `Exit code ${result.exitCode}
@@ -706,21 +965,21 @@ function normalizeCap(value) {
706
965
  function truncateTail(text, cap) {
707
966
  if (cap === 0)
708
967
  return text;
709
- const totalBytes = Buffer2.byteLength(text);
968
+ const totalBytes = Buffer3.byteLength(text);
710
969
  if (totalBytes <= cap)
711
970
  return text;
712
971
  let bytes = 0;
713
972
  let charIdx = text.length;
714
973
  while (charIdx > 0) {
715
974
  const ch = text[charIdx - 1];
716
- const chBytes = Buffer2.byteLength(ch);
975
+ const chBytes = Buffer3.byteLength(ch);
717
976
  if (bytes + chBytes > cap)
718
977
  break;
719
978
  bytes += chBytes;
720
979
  charIdx--;
721
980
  }
722
981
  const tail = text.slice(charIdx);
723
- const droppedBytes = totalBytes - Buffer2.byteLength(tail);
982
+ const droppedBytes = totalBytes - Buffer3.byteLength(tail);
724
983
  return `\u2026(${droppedBytes} bytes truncated from head)\u2026
725
984
  ${tail}`;
726
985
  }
@@ -1456,6 +1715,17 @@ async function executeTurn(ctx, turn) {
1456
1715
  }
1457
1716
  return { ended: true, turnId, usage: result.usage };
1458
1717
  }
1718
+ if (canonicalToolCalls.length === 0 && result.usage.finishReason === "pause") {
1719
+ const continueMsg = ctx.provider.userMessage("Please continue.");
1720
+ ctx.turns.push({
1721
+ id: await ctx.generateTurnId(),
1722
+ runId: ctx.runId,
1723
+ role: continueMsg.role,
1724
+ content: continueMsg.content,
1725
+ createdAt: Date.now()
1726
+ });
1727
+ return { ended: false, turnId, usage: result.usage };
1728
+ }
1459
1729
  const toolResults = ctx.toolExecution === "parallel" ? await executeToolsParallel(ctx, canonicalToolCalls, turnId) : await executeToolsSequential(ctx, canonicalToolCalls, turnId);
1460
1730
  const toolResultMsg = ctx.provider.toolResultsMessage(toolResults);
1461
1731
  ctx.turns.push({
@@ -2519,7 +2789,7 @@ function createSpawnTool(options = {}) {
2519
2789
  var spawn = createSpawnTool();
2520
2790
 
2521
2791
  // src/tools/write-file.ts
2522
- import { Buffer as Buffer3 } from "buffer";
2792
+ import { Buffer as Buffer4 } from "buffer";
2523
2793
  var writeFile = {
2524
2794
  spec: {
2525
2795
  name: "write_file",
@@ -2541,7 +2811,7 @@ var writeFile = {
2541
2811
  existing = await ctx.execution.readFile(ctx.handle, targetPath);
2542
2812
  } catch {
2543
2813
  }
2544
- const bytes = Buffer3.byteLength(targetContent);
2814
+ const bytes = Buffer4.byteLength(targetContent);
2545
2815
  if (existing === targetContent)
2546
2816
  return `No change needed: ${targetPath} already at target state (${bytes} bytes).`;
2547
2817
  await ctx.execution.writeFile(ctx.handle, targetPath, targetContent);
@@ -176,6 +176,10 @@ function createProcessContext(config) {
176
176
  async readFile(handle, path) {
177
177
  return readFile(resolve(handle.cwd, path), "utf-8");
178
178
  },
179
+ async readFileBinary(handle, path) {
180
+ const buf = await readFile(resolve(handle.cwd, path));
181
+ return new Uint8Array(buf);
182
+ },
179
183
  async writeFile(handle, path, content) {
180
184
  const fullPath = resolve(handle.cwd, path);
181
185
  await mkdir(dirname(fullPath), { recursive: true });
@@ -1,6 +1,6 @@
1
- import { S as SpawnConfig, b as ExecutionContext } from './types-BpvTmawk.js';
2
- export { C as ContextCapabilities, a as ContextType, E as ExecResult, c as ExecutionHandle } from './types-BpvTmawk.js';
3
- export { S as SandboxProvider, c as createSandboxContext } from './sandbox-CW72eLDP.js';
1
+ import { S as SpawnConfig, b as ExecutionContext } from './types-vA1a_ZX7.js';
2
+ export { C as ContextCapabilities, a as ContextType, E as ExecResult, c as ExecutionHandle } from './types-vA1a_ZX7.js';
3
+ export { S as SandboxProvider, c as createSandboxContext } from './sandbox-CLghrTLi.js';
4
4
 
5
5
  /**
6
6
  * Docker execution context.
package/dist/contexts.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  createDockerContext,
3
3
  createProcessContext,
4
4
  createSandboxContext
5
- } from "./chunk-2EQT4EHD.js";
5
+ } from "./chunk-IUBBVF53.js";
6
6
  export {
7
7
  createDockerContext,
8
8
  createProcessContext,
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- import { d as AgentHooks } from './agent-O5SmWixc.js';
2
- export { ac as ActivationVia, ad as ActiveSkill, A as Agent, a as AgentAbortedError, b as AgentBehavior, c as AgentContextExceededError, e as AgentOptions, f as AgentProviderError, g as AgentRunOptions, h as AgentStats, i as AgentToolNotAllowedError, j as AnthropicParams, C as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, k as CerebrasParams, m as ClassifiedError, n as ClassifiedErrorKind, o as CreateSessionOptions, ae as DeactivationReason, af as FileMapAdapter, ag as FileMapStoreOptions, I as ImageContent, M as McpConnection, p as McpServerConfig, q as McpToolHookContext, O as OAuthRefreshHookContext, ah as OpenAICompatAuthHeader, ai as OpenAICompatHttpError, aj as OpenAICompatParams, r as OpenAIParams, s as OpenRouterParams, P as PromptDocumentPart, t as PromptImagePart, u as PromptPart, v as PromptTextPart, w as Provider, x as ProviderCapabilities, R as RemoteStoreOptions, y as RunHookMap, S as Session, z as SessionContentBlock, B as SessionData, D as SessionEndStatus, E as SessionHookContext, F as SessionMessage, G as SessionRun, H as SessionStore, J as SessionTurn, ak as SkillActivationState, al as SkillActivationStateOptions, K as SkillConfig, am as SkillDiagnostic, L as SkillResource, an as SkillSource, N as SkillsConfig, Q as SpawnHookContext, T as StreamCallbacks, U as StreamHookContext, V as StreamOptions, W as ThinkingLevel, X as ToolCall, Y as ToolContext, Z as ToolDef, _ as ToolExecutionMode, $ as ToolHookContext, a0 as ToolMap, a1 as ToolResult, a2 as ToolResultContent, a3 as ToolResultImageContent, a4 as ToolResultTextContent, a5 as ToolSpec, a6 as TurnFinishReason, a7 as TurnResult, a8 as TurnUsage, ao as anthropic, ap as autoDetectAndConvert, aq as cerebras, ar as classifyOpenAICompatError, as as connectMcpServers, at as createAgent, au as createFileMapStore, av as createMemoryStore, aw as createRemoteStore, ax as createSession, ay as createSkillActivationState, az as fromAnthropic, aA as fromOpenAI, aB as loadSession, aC as mapOAIFinishReason, a9 as matchesContextExceeded, aD as normalizeMcpBlocks, aE as normalizeMcpServers, aF as openai, aG as openaiCompat, aH as openrouter, aI as resultToString, aJ as toAnthropic, aK as toOpenAI, aL as toTypedError, aa as toolOutputByteLength, ab as toolResultToText } from './agent-O5SmWixc.js';
1
+ import { d as AgentHooks } from './agent-Cq009tbG.js';
2
+ export { ac as ActivationVia, ad as ActiveSkill, A as Agent, a as AgentAbortedError, b as AgentBehavior, c as AgentContextExceededError, e as AgentOptions, f as AgentProviderError, g as AgentRunOptions, h as AgentStats, i as AgentToolNotAllowedError, j as AnthropicParams, C as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, k as CerebrasParams, m as ClassifiedError, n as ClassifiedErrorKind, o as CreateSessionOptions, ae as DeactivationReason, af as FileMapAdapter, ag as FileMapStoreOptions, I as ImageContent, M as McpConnection, p as McpServerConfig, q as McpToolHookContext, O as OAuthRefreshHookContext, ah as OpenAICompatAuthHeader, ai as OpenAICompatHttpError, aj as OpenAICompatParams, r as OpenAIParams, s as OpenRouterParams, P as PromptDocumentPart, t as PromptImagePart, u as PromptPart, v as PromptTextPart, w as Provider, x as ProviderCapabilities, R as RemoteStoreOptions, y as RunHookMap, S as Session, z as SessionContentBlock, B as SessionData, D as SessionEndStatus, E as SessionHookContext, F as SessionMessage, G as SessionRun, H as SessionStore, J as SessionTurn, ak as SkillActivationState, al as SkillActivationStateOptions, K as SkillConfig, am as SkillDiagnostic, L as SkillResource, an as SkillSource, N as SkillsConfig, Q as SpawnHookContext, T as StreamCallbacks, U as StreamHookContext, V as StreamOptions, W as ThinkingLevel, X as ToolCall, Y as ToolContext, Z as ToolDef, _ as ToolExecutionMode, $ as ToolHookContext, a0 as ToolMap, a1 as ToolResult, a2 as ToolResultContent, a3 as ToolResultImageContent, a4 as ToolResultTextContent, a5 as ToolSpec, a6 as TurnFinishReason, a7 as TurnResult, a8 as TurnUsage, ao as anthropic, ap as autoDetectAndConvert, aq as cerebras, ar as classifyOpenAICompatError, as as connectMcpServers, at as createAgent, au as createFileMapStore, av as createMemoryStore, aw as createRemoteStore, ax as createSession, ay as createSkillActivationState, az as fromAnthropic, aA as fromOpenAI, aB as loadSession, aC as mapOAIFinishReason, a9 as matchesContextExceeded, aD as normalizeMcpBlocks, aE as normalizeMcpServers, aF as openai, aG as openaiCompat, aH as openrouter, aI as resultToString, aJ as toAnthropic, aK as toOpenAI, aL as toTypedError, aa as toolOutputByteLength, ab as toolResultToText } from './agent-Cq009tbG.js';
3
3
  export { createDockerContext, createProcessContext } from './contexts.js';
4
- export { S as SandboxProvider, c as createSandboxContext } from './sandbox-CW72eLDP.js';
5
- export { C as ContextCapabilities, a as ContextType, E as ExecResult, b as ExecutionContext, c as ExecutionHandle, S as SpawnConfig } from './types-BpvTmawk.js';
4
+ export { S as SandboxProvider, c as createSandboxContext } from './sandbox-CLghrTLi.js';
5
+ export { C as ContextCapabilities, a as ContextType, E as ExecResult, b as ExecutionContext, c as ExecutionHandle, S as SpawnConfig } from './types-vA1a_ZX7.js';
6
6
  export { Preset, basic, basicTools, definePreset } from './presets.js';
7
7
  export { IMPLICITLY_ALLOWED_SKILL_TOOLS, SkillValidationIssue, SkillValidationResult, SourcedScanPath, buildCatalog, defineSkill, discoverSkills, installAllowedToolsGate, interpolateShellCommands, isToolAllowedByUnion, matchesAllowedTool, parseAllowedToolPattern, parseSkillFile, resolveSkills, validateResourcePath, validateSkillForWrite, validateSkillName, writeSkillToDisk, writeSkillsToDisk } from './skills.js';
8
- export { S as SkillsReadToolOptions, a as SkillsRunScriptToolOptions, b as SkillsUseToolOptions, c as createSkillsReadTool, d as createSkillsRunScriptTool, e as createSkillsUseTool, f as edit, g as glob, h as grep, m as multiEdit } from './skills-use-DJKUctM5.js';
9
- export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, V as ValidationResult, c as createInteractionTool, b as createSpawnTool, s as spawn, v as validateToolArgs } from './validation-DE4g5Cez.js';
8
+ export { S as SkillsReadToolOptions, a as SkillsRunScriptToolOptions, b as SkillsUseToolOptions, c as createSkillsReadTool, d as createSkillsRunScriptTool, e as createSkillsUseTool, f as edit, g as glob, h as grep, m as multiEdit } from './skills-use-Bi6Dklye.js';
9
+ export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, V as ValidationResult, c as createInteractionTool, b as createSpawnTool, s as spawn, v as validateToolArgs } from './validation-BeQD94ft.js';
10
10
  import { Hookable } from 'hookable';
11
11
  import '@modelcontextprotocol/sdk/client/index.js';
12
12
 
package/dist/index.js CHANGED
@@ -6,12 +6,12 @@ import {
6
6
  cerebras,
7
7
  openai,
8
8
  openrouter
9
- } from "./chunk-FEAOZ5DB.js";
9
+ } from "./chunk-3DUWP7YU.js";
10
10
  import {
11
11
  basicTools,
12
12
  basic_default,
13
13
  definePreset
14
- } from "./chunk-SARMZCEL.js";
14
+ } from "./chunk-ATMVSCGJ.js";
15
15
  import {
16
16
  createAgent,
17
17
  createInteractionTool,
@@ -25,7 +25,7 @@ import {
25
25
  multiEdit,
26
26
  spawn,
27
27
  validateToolArgs
28
- } from "./chunk-PYLYK3K7.js";
28
+ } from "./chunk-EBSFBIP3.js";
29
29
  import {
30
30
  IMPLICITLY_ALLOWED_SKILL_TOOLS,
31
31
  buildCatalog,
@@ -48,7 +48,7 @@ import {
48
48
  createDockerContext,
49
49
  createProcessContext,
50
50
  createSandboxContext
51
- } from "./chunk-2EQT4EHD.js";
51
+ } from "./chunk-IUBBVF53.js";
52
52
  import {
53
53
  connectMcpServers,
54
54
  normalizeMcpBlocks,
package/dist/mcp.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import 'hookable';
2
- export { M as McpConnection, p as McpServerConfig, as as connectMcpServers, aD as normalizeMcpBlocks, aE as normalizeMcpServers, aI as resultToString } from './agent-O5SmWixc.js';
2
+ export { M as McpConnection, p as McpServerConfig, as as connectMcpServers, aD as normalizeMcpBlocks, aE as normalizeMcpServers, aI as resultToString } from './agent-Cq009tbG.js';
3
3
  import '@modelcontextprotocol/sdk/client/index.js';
4
- import './types-BpvTmawk.js';
4
+ import './types-vA1a_ZX7.js';
package/dist/presets.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { Z as ToolDef, e as AgentOptions } from './agent-O5SmWixc.js';
1
+ import { Z as ToolDef, e as AgentOptions } from './agent-Cq009tbG.js';
2
2
  import 'hookable';
3
- import './types-BpvTmawk.js';
3
+ import './types-vA1a_ZX7.js';
4
4
  import '@modelcontextprotocol/sdk/client/index.js';
5
5
 
6
6
  /**
package/dist/presets.js CHANGED
@@ -2,10 +2,10 @@ import {
2
2
  basicTools,
3
3
  basic_default,
4
4
  definePreset
5
- } from "./chunk-SARMZCEL.js";
6
- import "./chunk-PYLYK3K7.js";
5
+ } from "./chunk-ATMVSCGJ.js";
6
+ import "./chunk-EBSFBIP3.js";
7
7
  import "./chunk-TPXPVEH6.js";
8
- import "./chunk-2EQT4EHD.js";
8
+ import "./chunk-IUBBVF53.js";
9
9
  import "./chunk-R74LQKAM.js";
10
10
  import "./chunk-JH6IAAFA.js";
11
11
  import "./chunk-LNN5UTS2.js";
@@ -1,4 +1,4 @@
1
- export { j as AnthropicParams, k as CerebrasParams, ah as OpenAICompatAuthHeader, ai as OpenAICompatHttpError, aj as OpenAICompatParams, r as OpenAIParams, s as OpenRouterParams, w as Provider, x as ProviderCapabilities, T as StreamCallbacks, V as StreamOptions, X as ToolCall, a1 as ToolResult, a5 as ToolSpec, a7 as TurnResult, ao as anthropic, aq as cerebras, ar as classifyOpenAICompatError, aC as mapOAIFinishReason, aF as openai, aG as openaiCompat, aH as openrouter } from './agent-O5SmWixc.js';
1
+ export { j as AnthropicParams, k as CerebrasParams, ah as OpenAICompatAuthHeader, ai as OpenAICompatHttpError, aj as OpenAICompatParams, r as OpenAIParams, s as OpenRouterParams, w as Provider, x as ProviderCapabilities, T as StreamCallbacks, V as StreamOptions, X as ToolCall, a1 as ToolResult, a5 as ToolSpec, a7 as TurnResult, ao as anthropic, aq as cerebras, ar as classifyOpenAICompatError, aC as mapOAIFinishReason, aF as openai, aG as openaiCompat, aH as openrouter } from './agent-Cq009tbG.js';
2
2
  import 'hookable';
3
- import './types-BpvTmawk.js';
3
+ import './types-vA1a_ZX7.js';
4
4
  import '@modelcontextprotocol/sdk/client/index.js';
package/dist/providers.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  cerebras,
4
4
  openai,
5
5
  openrouter
6
- } from "./chunk-FEAOZ5DB.js";
6
+ } from "./chunk-3DUWP7YU.js";
7
7
  import {
8
8
  OpenAICompatHttpError,
9
9
  classifyOpenAICompatError,
@@ -1,4 +1,4 @@
1
- import { S as SpawnConfig, E as ExecResult, b as ExecutionContext } from './types-BpvTmawk.js';
1
+ import { S as SpawnConfig, E as ExecResult, b as ExecutionContext } from './types-vA1a_ZX7.js';
2
2
 
3
3
  /**
4
4
  * Remote sandbox execution context.
@@ -1,6 +1,6 @@
1
- import { H as SessionStore } from '../agent-O5SmWixc.js';
1
+ import { H as SessionStore } from '../agent-Cq009tbG.js';
2
2
  import 'hookable';
3
- import '../types-BpvTmawk.js';
3
+ import '../types-vA1a_ZX7.js';
4
4
  import '@modelcontextprotocol/sdk/client/index.js';
5
5
 
6
6
  /**
package/dist/session.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { o as CreateSessionOptions, af as FileMapAdapter, ag as FileMapStoreOptions, R as RemoteStoreOptions, S as Session, z as SessionContentBlock, B as SessionData, F as SessionMessage, G as SessionRun, H as SessionStore, J as SessionTurn, ap as autoDetectAndConvert, au as createFileMapStore, av as createMemoryStore, aw as createRemoteStore, ax as createSession, az as fromAnthropic, aA as fromOpenAI, aB as loadSession, aJ as toAnthropic, aK as toOpenAI } from './agent-O5SmWixc.js';
1
+ export { o as CreateSessionOptions, af as FileMapAdapter, ag as FileMapStoreOptions, R as RemoteStoreOptions, S as Session, z as SessionContentBlock, B as SessionData, F as SessionMessage, G as SessionRun, H as SessionStore, J as SessionTurn, ap as autoDetectAndConvert, au as createFileMapStore, av as createMemoryStore, aw as createRemoteStore, ax as createSession, az as fromAnthropic, aA as fromOpenAI, aB as loadSession, aJ as toAnthropic, aK as toOpenAI } from './agent-Cq009tbG.js';
2
2
  import 'hookable';
3
- import './types-BpvTmawk.js';
3
+ import './types-vA1a_ZX7.js';
4
4
  import '@modelcontextprotocol/sdk/client/index.js';
@@ -1,4 +1,4 @@
1
- import { Z as ToolDef, K as SkillConfig, ak as SkillActivationState, d as AgentHooks } from './agent-O5SmWixc.js';
1
+ import { Z as ToolDef, K as SkillConfig, ak as SkillActivationState, d as AgentHooks } from './agent-Cq009tbG.js';
2
2
  import { Hookable } from 'hookable';
3
3
 
4
4
  /**
package/dist/skills.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { d as AgentHooks, ak as SkillActivationState, K as SkillConfig, an as SkillSource, am as SkillDiagnostic, N as SkillsConfig } from './agent-O5SmWixc.js';
2
- export { ac as ActivationVia, ad as ActiveSkill, ae as DeactivationReason, al as SkillActivationStateOptions, L as SkillResource, ay as createSkillActivationState } from './agent-O5SmWixc.js';
1
+ import { d as AgentHooks, ak as SkillActivationState, K as SkillConfig, an as SkillSource, am as SkillDiagnostic, N as SkillsConfig } from './agent-Cq009tbG.js';
2
+ export { ac as ActivationVia, ad as ActiveSkill, ae as DeactivationReason, al as SkillActivationStateOptions, L as SkillResource, ay as createSkillActivationState } from './agent-Cq009tbG.js';
3
3
  import { Hookable } from 'hookable';
4
- import { b as ExecutionContext, c as ExecutionHandle } from './types-BpvTmawk.js';
4
+ import { b as ExecutionContext, c as ExecutionHandle } from './types-vA1a_ZX7.js';
5
5
  import '@modelcontextprotocol/sdk/client/index.js';
6
6
 
7
7
  /**
package/dist/tools.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- export { S as SkillsReadToolOptions, a as SkillsRunScriptToolOptions, b as SkillsUseToolOptions, c as createSkillsReadTool, d as createSkillsRunScriptTool, e as createSkillsUseTool, f as edit, g as glob, h as grep, m as multiEdit } from './skills-use-DJKUctM5.js';
2
- export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, V as ValidationResult, c as createInteractionTool, b as createSpawnTool, s as spawn, v as validateToolArgs } from './validation-DE4g5Cez.js';
3
- import { Z as ToolDef } from './agent-O5SmWixc.js';
4
- export { Y as ToolContext, a0 as ToolMap } from './agent-O5SmWixc.js';
1
+ export { S as SkillsReadToolOptions, a as SkillsRunScriptToolOptions, b as SkillsUseToolOptions, c as createSkillsReadTool, d as createSkillsRunScriptTool, e as createSkillsUseTool, f as edit, g as glob, h as grep, m as multiEdit } from './skills-use-Bi6Dklye.js';
2
+ export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, V as ValidationResult, c as createInteractionTool, b as createSpawnTool, s as spawn, v as validateToolArgs } from './validation-BeQD94ft.js';
3
+ import { Z as ToolDef } from './agent-Cq009tbG.js';
4
+ export { Y as ToolContext, a0 as ToolMap } from './agent-Cq009tbG.js';
5
5
  import 'hookable';
6
6
  import './presets.js';
7
- import './types-BpvTmawk.js';
7
+ import './types-vA1a_ZX7.js';
8
8
  import '@modelcontextprotocol/sdk/client/index.js';
9
9
 
10
10
  declare const listFiles: ToolDef;
package/dist/tools.js CHANGED
@@ -14,9 +14,9 @@ import {
14
14
  spawn,
15
15
  validateToolArgs,
16
16
  writeFile
17
- } from "./chunk-PYLYK3K7.js";
17
+ } from "./chunk-EBSFBIP3.js";
18
18
  import "./chunk-TPXPVEH6.js";
19
- import "./chunk-2EQT4EHD.js";
19
+ import "./chunk-IUBBVF53.js";
20
20
  import "./chunk-R74LQKAM.js";
21
21
  import "./chunk-JH6IAAFA.js";
22
22
  import "./chunk-LNN5UTS2.js";
@@ -67,6 +67,17 @@ interface ExecutionContext {
67
67
  }) => Promise<ExecResult>;
68
68
  /** Read a file from the context's filesystem */
69
69
  readFile: (handle: ExecutionHandle, path: string) => Promise<string>;
70
+ /**
71
+ * Read a file from the context's filesystem as raw bytes.
72
+ *
73
+ * Used by `read_file` to dispatch image / binary files into the multimodal
74
+ * `ToolResultContent[]` route. Optional — when not implemented, the tool
75
+ * falls back to `base64 < path` via the `exec` seam, which works in any
76
+ * shell-capable context. Implementations that already have a native
77
+ * binary read (in-process `fs.readFile` without encoding, container API,
78
+ * sandbox SDK) should override for the latency win.
79
+ */
80
+ readFileBinary?: (handle: ExecutionHandle, path: string) => Promise<Uint8Array>;
70
81
  /** Write a file to the context's filesystem */
71
82
  writeFile: (handle: ExecutionHandle, path: string, content: string) => Promise<void>;
72
83
  /** List files in a directory */
package/dist/types.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- export { A as Agent, a as AgentAbortedError, b as AgentBehavior, c as AgentContextExceededError, d as AgentHooks, e as AgentOptions, f as AgentProviderError, g as AgentRunOptions, h as AgentStats, i as AgentToolNotAllowedError, j as AnthropicParams, C as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, k as CerebrasParams, l as ChildRunStats, m as ClassifiedError, n as ClassifiedErrorKind, o as CreateSessionOptions, I as ImageContent, M as McpConnection, p as McpServerConfig, q as McpToolHookContext, O as OAuthRefreshHookContext, r as OpenAIParams, s as OpenRouterParams, P as PromptDocumentPart, t as PromptImagePart, u as PromptPart, v as PromptTextPart, w as Provider, x as ProviderCapabilities, R as RemoteStoreOptions, y as RunHookMap, S as Session, z as SessionContentBlock, B as SessionData, D as SessionEndStatus, E as SessionHookContext, F as SessionMessage, G as SessionRun, H as SessionStore, J as SessionTurn, K as SkillConfig, L as SkillResource, N as SkillsConfig, Q as SpawnHookContext, T as StreamCallbacks, U as StreamHookContext, V as StreamOptions, W as ThinkingLevel, X as ToolCall, Y as ToolContext, Z as ToolDef, _ as ToolExecutionMode, $ as ToolHookContext, a0 as ToolMap, a1 as ToolResult, a2 as ToolResultContent, a3 as ToolResultImageContent, a4 as ToolResultTextContent, a5 as ToolSpec, a6 as TurnFinishReason, a7 as TurnResult, a8 as TurnUsage, a9 as matchesContextExceeded, aa as toolOutputByteLength, ab as toolResultToText } from './agent-O5SmWixc.js';
2
- export { C as ContextCapabilities, a as ContextType, E as ExecResult, b as ExecutionContext, c as ExecutionHandle, S as SpawnConfig } from './types-BpvTmawk.js';
3
- export { S as SandboxProvider } from './sandbox-CW72eLDP.js';
1
+ export { A as Agent, a as AgentAbortedError, b as AgentBehavior, c as AgentContextExceededError, d as AgentHooks, e as AgentOptions, f as AgentProviderError, g as AgentRunOptions, h as AgentStats, i as AgentToolNotAllowedError, j as AnthropicParams, C as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, k as CerebrasParams, l as ChildRunStats, m as ClassifiedError, n as ClassifiedErrorKind, o as CreateSessionOptions, I as ImageContent, M as McpConnection, p as McpServerConfig, q as McpToolHookContext, O as OAuthRefreshHookContext, r as OpenAIParams, s as OpenRouterParams, P as PromptDocumentPart, t as PromptImagePart, u as PromptPart, v as PromptTextPart, w as Provider, x as ProviderCapabilities, R as RemoteStoreOptions, y as RunHookMap, S as Session, z as SessionContentBlock, B as SessionData, D as SessionEndStatus, E as SessionHookContext, F as SessionMessage, G as SessionRun, H as SessionStore, J as SessionTurn, K as SkillConfig, L as SkillResource, N as SkillsConfig, Q as SpawnHookContext, T as StreamCallbacks, U as StreamHookContext, V as StreamOptions, W as ThinkingLevel, X as ToolCall, Y as ToolContext, Z as ToolDef, _ as ToolExecutionMode, $ as ToolHookContext, a0 as ToolMap, a1 as ToolResult, a2 as ToolResultContent, a3 as ToolResultImageContent, a4 as ToolResultTextContent, a5 as ToolSpec, a6 as TurnFinishReason, a7 as TurnResult, a8 as TurnUsage, a9 as matchesContextExceeded, aa as toolOutputByteLength, ab as toolResultToText } from './agent-Cq009tbG.js';
2
+ export { C as ContextCapabilities, a as ContextType, E as ExecResult, b as ExecutionContext, c as ExecutionHandle, S as SpawnConfig } from './types-vA1a_ZX7.js';
3
+ export { S as SandboxProvider } from './sandbox-CLghrTLi.js';
4
4
  export { Preset } from './presets.js';
5
- export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, V as ValidationResult } from './validation-DE4g5Cez.js';
5
+ export { C as ChildAgent, I as InteractionToolOptions, S as SpawnToolOptions, a as SpawnToolState, V as ValidationResult } from './validation-BeQD94ft.js';
6
6
  import 'hookable';
7
7
  import '@modelcontextprotocol/sdk/client/index.js';
@@ -1,4 +1,4 @@
1
- import { Y as ToolContext, Z as ToolDef, h as AgentStats, l as ChildRunStats } from './agent-O5SmWixc.js';
1
+ import { Y as ToolContext, Z as ToolDef, h as AgentStats, l as ChildRunStats } from './agent-Cq009tbG.js';
2
2
  import { Preset } from './presets.js';
3
3
 
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zidane",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "an agent that goes straight to the goal",
5
5
  "type": "module",
6
6
  "private": false,