@earendil-works/pi-durable 1.3.0 → 1.5.0

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 (257) hide show
  1. package/CHANGELOG.md +227 -0
  2. package/README.md +287 -82
  3. package/dist/codemode/codemode.d.ts +4 -4
  4. package/dist/codemode/codemode.d.ts.map +1 -1
  5. package/dist/codemode/codemode.js +21 -16
  6. package/dist/codemode/codemode.js.map +1 -1
  7. package/dist/codemode/models.d.ts.map +1 -1
  8. package/dist/codemode/models.js +6 -4
  9. package/dist/codemode/models.js.map +1 -1
  10. package/dist/documents.d.ts +1 -1
  11. package/dist/documents.d.ts.map +1 -1
  12. package/dist/documents.js.map +1 -1
  13. package/dist/env/index.d.ts +12 -10
  14. package/dist/env/index.d.ts.map +1 -1
  15. package/dist/env/index.js.map +1 -1
  16. package/dist/env/node-watch.d.ts +3 -3
  17. package/dist/env/node-watch.d.ts.map +1 -1
  18. package/dist/env/node-watch.js +18 -16
  19. package/dist/env/node-watch.js.map +1 -1
  20. package/dist/env/node.d.ts +2 -2
  21. package/dist/env/node.d.ts.map +1 -1
  22. package/dist/env/node.js +12 -4
  23. package/dist/env/node.js.map +1 -1
  24. package/dist/errors.d.ts +18 -2
  25. package/dist/errors.d.ts.map +1 -1
  26. package/dist/errors.js +26 -3
  27. package/dist/errors.js.map +1 -1
  28. package/dist/harness/agent.d.ts +13 -2
  29. package/dist/harness/agent.d.ts.map +1 -1
  30. package/dist/harness/agent.js +48 -6
  31. package/dist/harness/agent.js.map +1 -1
  32. package/dist/harness/compaction.d.ts +3 -1
  33. package/dist/harness/compaction.d.ts.map +1 -1
  34. package/dist/harness/compaction.js +38 -6
  35. package/dist/harness/compaction.js.map +1 -1
  36. package/dist/harness/context.d.ts +23 -7
  37. package/dist/harness/context.d.ts.map +1 -1
  38. package/dist/harness/context.js +71 -25
  39. package/dist/harness/context.js.map +1 -1
  40. package/dist/harness/define.d.ts +7 -3
  41. package/dist/harness/define.d.ts.map +1 -1
  42. package/dist/harness/define.js +4 -0
  43. package/dist/harness/define.js.map +1 -1
  44. package/dist/harness/generation.d.ts +38 -5
  45. package/dist/harness/generation.d.ts.map +1 -1
  46. package/dist/harness/generation.js +497 -108
  47. package/dist/harness/generation.js.map +1 -1
  48. package/dist/harness/harness.d.ts +7 -2
  49. package/dist/harness/harness.d.ts.map +1 -1
  50. package/dist/harness/harness.js +147 -57
  51. package/dist/harness/harness.js.map +1 -1
  52. package/dist/harness/inbox.d.ts +7 -3
  53. package/dist/harness/inbox.d.ts.map +1 -1
  54. package/dist/harness/inbox.js +7 -4
  55. package/dist/harness/inbox.js.map +1 -1
  56. package/dist/harness/json.d.ts +20 -4
  57. package/dist/harness/json.d.ts.map +1 -1
  58. package/dist/harness/json.js +23 -5
  59. package/dist/harness/json.js.map +1 -1
  60. package/dist/harness/live.d.ts +122 -16
  61. package/dist/harness/live.d.ts.map +1 -1
  62. package/dist/harness/live.js +93 -12
  63. package/dist/harness/live.js.map +1 -1
  64. package/dist/harness/partial-changes.d.ts +54 -0
  65. package/dist/harness/partial-changes.d.ts.map +1 -0
  66. package/dist/harness/partial-changes.js +162 -0
  67. package/dist/harness/partial-changes.js.map +1 -0
  68. package/dist/harness/prompt.d.ts +1 -1
  69. package/dist/harness/prompt.d.ts.map +1 -1
  70. package/dist/harness/prompt.js +1 -1
  71. package/dist/harness/prompt.js.map +1 -1
  72. package/dist/harness/registry-reader.d.ts +11 -0
  73. package/dist/harness/registry-reader.d.ts.map +1 -0
  74. package/dist/harness/registry-reader.js +25 -0
  75. package/dist/harness/registry-reader.js.map +1 -0
  76. package/dist/harness/scheduler.d.ts +86 -14
  77. package/dist/harness/scheduler.d.ts.map +1 -1
  78. package/dist/harness/scheduler.js +1459 -369
  79. package/dist/harness/scheduler.js.map +1 -1
  80. package/dist/harness/submissions.d.ts +23 -11
  81. package/dist/harness/submissions.d.ts.map +1 -1
  82. package/dist/harness/submissions.js +104 -36
  83. package/dist/harness/submissions.js.map +1 -1
  84. package/dist/harness/task-graph.d.ts +28 -8
  85. package/dist/harness/task-graph.d.ts.map +1 -1
  86. package/dist/harness/task-graph.js +85 -36
  87. package/dist/harness/task-graph.js.map +1 -1
  88. package/dist/harness/telemetry.d.ts +307 -0
  89. package/dist/harness/telemetry.d.ts.map +1 -0
  90. package/dist/harness/telemetry.js +136 -0
  91. package/dist/harness/telemetry.js.map +1 -0
  92. package/dist/harness/tool.d.ts +2 -0
  93. package/dist/harness/tool.d.ts.map +1 -1
  94. package/dist/harness/tool.js +223 -61
  95. package/dist/harness/tool.js.map +1 -1
  96. package/dist/harness/transcript.d.ts +72 -0
  97. package/dist/harness/transcript.d.ts.map +1 -0
  98. package/dist/harness/transcript.js +264 -0
  99. package/dist/harness/transcript.js.map +1 -0
  100. package/dist/harness/types.d.ts +302 -48
  101. package/dist/harness/types.d.ts.map +1 -1
  102. package/dist/harness/types.js.map +1 -1
  103. package/dist/harness/util.d.ts +7 -1
  104. package/dist/harness/util.d.ts.map +1 -1
  105. package/dist/harness/util.js +13 -0
  106. package/dist/harness/util.js.map +1 -1
  107. package/dist/harness/view.d.ts +43 -22
  108. package/dist/harness/view.d.ts.map +1 -1
  109. package/dist/harness/view.js +130 -71
  110. package/dist/harness/view.js.map +1 -1
  111. package/dist/index.d.ts +13 -9
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +7 -5
  114. package/dist/index.js.map +1 -1
  115. package/dist/search.d.ts +19 -3
  116. package/dist/search.d.ts.map +1 -1
  117. package/dist/search.js +107 -44
  118. package/dist/search.js.map +1 -1
  119. package/dist/session/cached-storage.d.ts +71 -0
  120. package/dist/session/cached-storage.d.ts.map +1 -0
  121. package/dist/session/cached-storage.js +269 -0
  122. package/dist/session/cached-storage.js.map +1 -0
  123. package/dist/session/conversation-tails.d.ts +33 -0
  124. package/dist/session/conversation-tails.d.ts.map +1 -0
  125. package/dist/session/conversation-tails.js +101 -0
  126. package/dist/session/conversation-tails.js.map +1 -0
  127. package/dist/session/keys.d.ts +68 -0
  128. package/dist/session/keys.d.ts.map +1 -0
  129. package/dist/session/keys.js +161 -0
  130. package/dist/session/keys.js.map +1 -0
  131. package/dist/session/session.d.ts +181 -29
  132. package/dist/session/session.d.ts.map +1 -1
  133. package/dist/session/session.js +1073 -183
  134. package/dist/session/session.js.map +1 -1
  135. package/dist/session/transaction.d.ts +86 -4
  136. package/dist/session/transaction.d.ts.map +1 -1
  137. package/dist/session/transaction.js +250 -38
  138. package/dist/session/transaction.js.map +1 -1
  139. package/dist/session/writer.d.ts +74 -0
  140. package/dist/session/writer.d.ts.map +1 -0
  141. package/dist/session/writer.js +294 -0
  142. package/dist/session/writer.js.map +1 -0
  143. package/dist/storage/indexeddb.d.ts +68 -0
  144. package/dist/storage/indexeddb.d.ts.map +1 -0
  145. package/dist/storage/indexeddb.js +881 -0
  146. package/dist/storage/indexeddb.js.map +1 -0
  147. package/dist/storage/jsonl/storage.d.ts +30 -2
  148. package/dist/storage/jsonl/storage.d.ts.map +1 -1
  149. package/dist/storage/jsonl/storage.js +88 -24
  150. package/dist/storage/jsonl/storage.js.map +1 -1
  151. package/dist/storage/memory.d.ts +7 -2
  152. package/dist/storage/memory.d.ts.map +1 -1
  153. package/dist/storage/memory.js +29 -3
  154. package/dist/storage/memory.js.map +1 -1
  155. package/dist/storage/sqlite/cloudflare.d.ts +2 -51
  156. package/dist/storage/sqlite/cloudflare.d.ts.map +1 -1
  157. package/dist/storage/sqlite/cloudflare.js +2 -133
  158. package/dist/storage/sqlite/cloudflare.js.map +1 -1
  159. package/dist/storage/sqlite/database.d.ts +1 -36
  160. package/dist/storage/sqlite/database.d.ts.map +1 -1
  161. package/dist/storage/sqlite/database.js.map +1 -1
  162. package/dist/storage/sqlite/index.d.ts +1 -1
  163. package/dist/storage/sqlite/index.d.ts.map +1 -1
  164. package/dist/storage/sqlite/index.js.map +1 -1
  165. package/dist/storage/sqlite/migrations.d.ts +2 -5
  166. package/dist/storage/sqlite/migrations.d.ts.map +1 -1
  167. package/dist/storage/sqlite/migrations.js +28 -28
  168. package/dist/storage/sqlite/migrations.js.map +1 -1
  169. package/dist/storage/sqlite/node.d.ts +2 -37
  170. package/dist/storage/sqlite/node.d.ts.map +1 -1
  171. package/dist/storage/sqlite/node.js +3 -174
  172. package/dist/storage/sqlite/node.js.map +1 -1
  173. package/dist/storage/sqlite/schema.d.ts +1 -3
  174. package/dist/storage/sqlite/schema.d.ts.map +1 -1
  175. package/dist/storage/sqlite/schema.js +2 -9
  176. package/dist/storage/sqlite/schema.js.map +1 -1
  177. package/dist/storage/sqlite/storage.d.ts +15 -3
  178. package/dist/storage/sqlite/storage.d.ts.map +1 -1
  179. package/dist/storage/sqlite/storage.js +110 -36
  180. package/dist/storage/sqlite/storage.js.map +1 -1
  181. package/dist/storage/store/commit.d.ts +33 -0
  182. package/dist/storage/store/commit.d.ts.map +1 -0
  183. package/dist/storage/store/commit.js +286 -0
  184. package/dist/storage/store/commit.js.map +1 -0
  185. package/dist/storage/store/documents.d.ts +43 -0
  186. package/dist/storage/store/documents.d.ts.map +1 -0
  187. package/dist/storage/store/documents.js +102 -0
  188. package/dist/storage/store/documents.js.map +1 -0
  189. package/dist/storage/store/index.d.ts +2 -0
  190. package/dist/storage/store/index.d.ts.map +1 -0
  191. package/dist/storage/store/index.js +2 -0
  192. package/dist/storage/store/index.js.map +1 -0
  193. package/dist/storage/store/queries.d.ts +49 -0
  194. package/dist/storage/store/queries.d.ts.map +1 -0
  195. package/dist/storage/store/queries.js +93 -0
  196. package/dist/storage/store/queries.js.map +1 -0
  197. package/dist/storage/store/storage.d.ts +59 -0
  198. package/dist/storage/store/storage.d.ts.map +1 -0
  199. package/dist/storage/store/storage.js +438 -0
  200. package/dist/storage/store/storage.js.map +1 -0
  201. package/dist/storage/store/tables.d.ts +54 -0
  202. package/dist/storage/store/tables.d.ts.map +1 -0
  203. package/dist/storage/store/tables.js +108 -0
  204. package/dist/storage/store/tables.js.map +1 -0
  205. package/dist/testing/commit-writes.d.ts +5 -0
  206. package/dist/testing/commit-writes.d.ts.map +1 -0
  207. package/dist/testing/commit-writes.js +12 -0
  208. package/dist/testing/commit-writes.js.map +1 -0
  209. package/dist/testing/env-conformance.js +7 -7
  210. package/dist/testing/env-conformance.js.map +1 -1
  211. package/dist/testing/index.d.ts +1 -0
  212. package/dist/testing/index.d.ts.map +1 -1
  213. package/dist/testing/index.js +1 -0
  214. package/dist/testing/index.js.map +1 -1
  215. package/dist/testing/storage-benchmark.d.ts.map +1 -1
  216. package/dist/testing/storage-benchmark.js +18 -17
  217. package/dist/testing/storage-benchmark.js.map +1 -1
  218. package/dist/testing/storage-conformance.d.ts.map +1 -1
  219. package/dist/testing/storage-conformance.js +369 -67
  220. package/dist/testing/storage-conformance.js.map +1 -1
  221. package/dist/timers.d.ts +21 -0
  222. package/dist/timers.d.ts.map +1 -0
  223. package/dist/timers.js +72 -0
  224. package/dist/timers.js.map +1 -0
  225. package/dist/tool-search/tool-search.d.ts +6 -12
  226. package/dist/tool-search/tool-search.d.ts.map +1 -1
  227. package/dist/tool-search/tool-search.js +7 -7
  228. package/dist/tool-search/tool-search.js.map +1 -1
  229. package/dist/tools/bash.d.ts +12 -12
  230. package/dist/tools/bash.d.ts.map +1 -1
  231. package/dist/tools/bash.js +16 -15
  232. package/dist/tools/bash.js.map +1 -1
  233. package/dist/tools/edit.d.ts +7 -7
  234. package/dist/tools/edit.d.ts.map +1 -1
  235. package/dist/tools/edit.js +9 -9
  236. package/dist/tools/edit.js.map +1 -1
  237. package/dist/tools/index.d.ts +32 -32
  238. package/dist/tools/read.d.ts +6 -6
  239. package/dist/tools/read.d.ts.map +1 -1
  240. package/dist/tools/read.js +19 -8
  241. package/dist/tools/read.js.map +1 -1
  242. package/dist/tools/write.d.ts +4 -4
  243. package/dist/tools/write.d.ts.map +1 -1
  244. package/dist/tools/write.js +5 -5
  245. package/dist/tools/write.js.map +1 -1
  246. package/dist/types.d.ts +331 -64
  247. package/dist/types.d.ts.map +1 -1
  248. package/dist/types.js.map +1 -1
  249. package/package.json +27 -10
  250. package/dist/harness/events.d.ts +0 -186
  251. package/dist/harness/events.d.ts.map +0 -1
  252. package/dist/harness/events.js +0 -373
  253. package/dist/harness/events.js.map +0 -1
  254. package/dist/session/observation.d.ts +0 -42
  255. package/dist/session/observation.d.ts.map +0 -1
  256. package/dist/session/observation.js +0 -281
  257. package/dist/session/observation.js.map +0 -1
@@ -0,0 +1,21 @@
1
+ import type { SetTimer } from "./types.ts";
2
+ /**
3
+ * The default `HarnessOptions.setTimer`: `setTimeout`, waiting out delays beyond its limit in steps. A background timer
4
+ * is unreferenced, so it never keeps the process alive. It is declined in Cloudflare Workers and wherever timers cannot
5
+ * be unreferenced.
6
+ */
7
+ export declare const nativeTimer: SetTimer;
8
+ /** Timers the Session and Harness arm through the host's `setTimer`. */
9
+ export type Timers = {
10
+ /** A timer that paces or resumes work; when the host throws or declines it, `setTimeout` arms it instead. */
11
+ foreground(callback: () => void, delayMs: number): () => void;
12
+ /** A timer that only frees memory; `undefined` when the host declines it. */
13
+ background(callback: () => void, delayMs: number): (() => void) | undefined;
14
+ };
15
+ /**
16
+ * Wrap a host `setTimer`. A foreground timer must fire, or work stalls: one the host throws on or declines is armed
17
+ * with `setTimeout`, and the first such failure is reported. A background one the host throws on is reported and
18
+ * declined.
19
+ */
20
+ export declare function hostTimers(setTimer: SetTimer | undefined, report: (error: unknown) => void): Timers;
21
+ //# sourceMappingURL=timers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timers.d.ts","sourceRoot":"","sources":["../src/timers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAW3C;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,QAmBzB,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,MAAM,GAAG;IACpB,6GAA6G;IAC7G,UAAU,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,IAAI,CAAC;IAC9D,6EAA6E;IAC7E,UAAU,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CAC5E,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,CA4BnG"}
package/dist/timers.js ADDED
@@ -0,0 +1,72 @@
1
+ /** Longest delay `setTimeout` supports; a longer one is waited for in several steps. */
2
+ const MAX_TIMER_DELAY = 2_147_483_647;
3
+ /**
4
+ * Cloudflare Workers: a pending timer keeps a Durable Object from hibernating or being evicted, even an unreferenced
5
+ * one (`nodejs_compat` gives timers an `unref()` that changes nothing).
6
+ */
7
+ const inWorkers = typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers";
8
+ /**
9
+ * The default `HarnessOptions.setTimer`: `setTimeout`, waiting out delays beyond its limit in steps. A background timer
10
+ * is unreferenced, so it never keeps the process alive. It is declined in Cloudflare Workers and wherever timers cannot
11
+ * be unreferenced.
12
+ */
13
+ export const nativeTimer = (callback, delayMs, options) => {
14
+ if (options.background && inWorkers)
15
+ return undefined;
16
+ const arm = (remaining) => {
17
+ const next = setTimeout(() => {
18
+ if (remaining > MAX_TIMER_DELAY)
19
+ handle = arm(remaining - MAX_TIMER_DELAY);
20
+ else
21
+ callback();
22
+ }, Math.min(remaining, MAX_TIMER_DELAY));
23
+ if (options.background)
24
+ next.unref?.();
25
+ return next;
26
+ };
27
+ let handle = arm(Math.max(0, delayMs));
28
+ if (options.background && typeof handle.unref !== "function") {
29
+ clearTimeout(handle);
30
+ return undefined;
31
+ }
32
+ return () => clearTimeout(handle);
33
+ };
34
+ /**
35
+ * Wrap a host `setTimer`. A foreground timer must fire, or work stalls: one the host throws on or declines is armed
36
+ * with `setTimeout`, and the first such failure is reported. A background one the host throws on is reported and
37
+ * declined.
38
+ */
39
+ export function hostTimers(setTimer, report) {
40
+ const arm = setTimer ?? nativeTimer;
41
+ let reported = false;
42
+ const fallBack = (error) => {
43
+ if (reported)
44
+ return;
45
+ reported = true;
46
+ report(error);
47
+ };
48
+ return {
49
+ foreground: (callback, delayMs) => {
50
+ try {
51
+ const disarm = arm(callback, delayMs, { background: false });
52
+ if (disarm !== undefined)
53
+ return disarm;
54
+ fallBack(new Error("HarnessOptions.setTimer declined a timer that paces work; using setTimeout"));
55
+ }
56
+ catch (error) {
57
+ fallBack(error);
58
+ }
59
+ return nativeTimer(callback, delayMs, { background: false });
60
+ },
61
+ background: (callback, delayMs) => {
62
+ try {
63
+ return arm(callback, delayMs, { background: true });
64
+ }
65
+ catch (error) {
66
+ report(error);
67
+ return undefined;
68
+ }
69
+ },
70
+ };
71
+ }
72
+ //# sourceMappingURL=timers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timers.js","sourceRoot":"","sources":["../src/timers.ts"],"names":[],"mappings":"AAEA,wFAAwF;AACxF,MAAM,eAAe,GAAG,aAAa,CAAC;AAEtC;;;GAGG;AACH,MAAM,SAAS,GAAG,OAAO,SAAS,KAAK,WAAW,IAAI,SAAS,CAAC,SAAS,KAAK,oBAAoB,CAAC;AAEnG;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;IACnE,IAAI,OAAO,CAAC,UAAU,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IACtD,MAAM,GAAG,GAAG,CAAC,SAAiB,EAAiC,EAAE;QAChE,MAAM,IAAI,GAAG,UAAU,CACtB,GAAG,EAAE;YACJ,IAAI,SAAS,GAAG,eAAe;gBAAE,MAAM,GAAG,GAAG,CAAC,SAAS,GAAG,eAAe,CAAC,CAAC;;gBACtE,QAAQ,EAAE,CAAC;QACjB,CAAC,EACD,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,eAAe,CAAC,CACpC,CAAC;QACF,IAAI,OAAO,CAAC,UAAU;YAAG,IAA+B,CAAC,KAAK,EAAE,EAAE,CAAC;QACnE,OAAO,IAAI,CAAC;IACb,CAAC,CAAC;IACF,IAAI,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IACvC,IAAI,OAAO,CAAC,UAAU,IAAI,OAAQ,MAA8B,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;QACvF,YAAY,CAAC,MAAM,CAAC,CAAC;QACrB,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC,CAAC;AAUF;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,QAA8B,EAAE,MAAgC;IAC1F,MAAM,GAAG,GAAG,QAAQ,IAAI,WAAW,CAAC;IACpC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAQ,EAAE;QACzC,IAAI,QAAQ;YAAE,OAAO;QACrB,QAAQ,GAAG,IAAI,CAAC;QAChB,MAAM,CAAC,KAAK,CAAC,CAAC;IACf,CAAC,CAAC;IACF,OAAO;QACN,UAAU,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE;YACjC,IAAI,CAAC;gBACJ,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC7D,IAAI,MAAM,KAAK,SAAS;oBAAE,OAAO,MAAM,CAAC;gBACxC,QAAQ,CAAC,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC,CAAC;YACnG,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,QAAQ,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC;YACD,OAAO,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAE,CAAC;QAC/D,CAAC;QACD,UAAU,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE;YACjC,IAAI,CAAC;gBACJ,OAAO,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;YACrD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,MAAM,CAAC,KAAK,CAAC,CAAC;gBACd,OAAO,SAAS,CAAC;YAClB,CAAC;QACF,CAAC;KACD,CAAC;AACH,CAAC","sourcesContent":["import type { SetTimer } from \"./types.ts\";\n\n/** Longest delay `setTimeout` supports; a longer one is waited for in several steps. */\nconst MAX_TIMER_DELAY = 2_147_483_647;\n\n/**\n * Cloudflare Workers: a pending timer keeps a Durable Object from hibernating or being evicted, even an unreferenced\n * one (`nodejs_compat` gives timers an `unref()` that changes nothing).\n */\nconst inWorkers = typeof navigator !== \"undefined\" && navigator.userAgent === \"Cloudflare-Workers\";\n\n/**\n * The default `HarnessOptions.setTimer`: `setTimeout`, waiting out delays beyond its limit in steps. A background timer\n * is unreferenced, so it never keeps the process alive. It is declined in Cloudflare Workers and wherever timers cannot\n * be unreferenced.\n */\nexport const nativeTimer: SetTimer = (callback, delayMs, options) => {\n\tif (options.background && inWorkers) return undefined;\n\tconst arm = (remaining: number): ReturnType<typeof setTimeout> => {\n\t\tconst next = setTimeout(\n\t\t\t() => {\n\t\t\t\tif (remaining > MAX_TIMER_DELAY) handle = arm(remaining - MAX_TIMER_DELAY);\n\t\t\t\telse callback();\n\t\t\t},\n\t\t\tMath.min(remaining, MAX_TIMER_DELAY),\n\t\t);\n\t\tif (options.background) (next as { unref?: () => void }).unref?.();\n\t\treturn next;\n\t};\n\tlet handle = arm(Math.max(0, delayMs));\n\tif (options.background && typeof (handle as { unref?: unknown }).unref !== \"function\") {\n\t\tclearTimeout(handle);\n\t\treturn undefined;\n\t}\n\treturn () => clearTimeout(handle);\n};\n\n/** Timers the Session and Harness arm through the host's `setTimer`. */\nexport type Timers = {\n\t/** A timer that paces or resumes work; when the host throws or declines it, `setTimeout` arms it instead. */\n\tforeground(callback: () => void, delayMs: number): () => void;\n\t/** A timer that only frees memory; `undefined` when the host declines it. */\n\tbackground(callback: () => void, delayMs: number): (() => void) | undefined;\n};\n\n/**\n * Wrap a host `setTimer`. A foreground timer must fire, or work stalls: one the host throws on or declines is armed\n * with `setTimeout`, and the first such failure is reported. A background one the host throws on is reported and\n * declined.\n */\nexport function hostTimers(setTimer: SetTimer | undefined, report: (error: unknown) => void): Timers {\n\tconst arm = setTimer ?? nativeTimer;\n\tlet reported = false;\n\tconst fallBack = (error: unknown): void => {\n\t\tif (reported) return;\n\t\treported = true;\n\t\treport(error);\n\t};\n\treturn {\n\t\tforeground: (callback, delayMs) => {\n\t\t\ttry {\n\t\t\t\tconst disarm = arm(callback, delayMs, { background: false });\n\t\t\t\tif (disarm !== undefined) return disarm;\n\t\t\t\tfallBack(new Error(\"HarnessOptions.setTimer declined a timer that paces work; using setTimeout\"));\n\t\t\t} catch (error) {\n\t\t\t\tfallBack(error);\n\t\t\t}\n\t\t\treturn nativeTimer(callback, delayMs, { background: false })!;\n\t\t},\n\t\tbackground: (callback, delayMs) => {\n\t\t\ttry {\n\t\t\t\treturn arm(callback, delayMs, { background: true });\n\t\t\t} catch (error) {\n\t\t\t\treport(error);\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t},\n\t};\n}\n"]}
@@ -1,9 +1,3 @@
1
- /**
2
- * The `tool_search` tool, a copy of the coding agent's: the model searches the deferred tools it is not offered yet,
3
- * and the matches are loaded with `control.addTools`, so the next request offers them. Loading writes the
4
- * conversation's `modelTools` (its `add`), so loaded tools stay offered on that branch, also after a compaction.
5
- */
6
- import { Type } from "@earendil-works/pi-ai";
7
1
  import type { ToolRegistration } from "../harness/types.ts";
8
2
  export declare const TOOL_SEARCH_TOOL_NAME = "tool_search";
9
3
  export declare const DEFAULT_TOOL_SEARCH_LIMIT = 8;
@@ -11,13 +5,13 @@ export declare const DEFAULT_TOOL_SEARCH_LIMIT = 8;
11
5
  export type ToolSearchToolDetails = {
12
6
  loaded: string[];
13
7
  };
14
- export declare function createToolSearchTool(): ToolRegistration<Type.TObject<{
15
- query: Type.TString;
16
- limit: Type.TOptional<Type.TNumber>;
8
+ export declare function createToolSearchTool(): ToolRegistration<import("@earendil-works/pi-schema").Schema<{
9
+ query: string;
10
+ limit?: number | undefined;
17
11
  }>, import("@earendil-works/chord").JsonValue>;
18
12
  /** The `tool_search` extension: install it and select it where the model should find deferred tools. */
19
- export declare function createToolSearchExtension(): import("../harness/types.ts").Extension<ToolRegistration<Type.TObject<{
20
- query: Type.TString;
21
- limit: Type.TOptional<Type.TNumber>;
13
+ export declare function createToolSearchExtension(): import("../harness/types.ts").Extension<ToolRegistration<import("@earendil-works/pi-schema").Schema<{
14
+ query: string;
15
+ limit?: number | undefined;
22
16
  }>, import("@earendil-works/chord").JsonValue>>;
23
17
  //# sourceMappingURL=tool-search.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tool-search.d.ts","sourceRoot":"","sources":["../../src/tool-search/tool-search.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAE7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAG5D,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AACnD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAY3C,yDAAyD;AACzD,MAAM,MAAM,qBAAqB,GAAG;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AA8BzD,wBAAgB,oBAAoB;;;+CAgCnC;AAED,wGAAwG;AACxG,wBAAgB,yBAAyB;;;gDAExC"}
1
+ {"version":3,"file":"tool-search.d.ts","sourceRoot":"","sources":["../../src/tool-search/tool-search.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAG5D,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AACnD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAa3C,yDAAyD;AACzD,MAAM,MAAM,qBAAqB,GAAG;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AA8BzD,wBAAgB,oBAAoB;;;+CAgCnC;AAED,wGAAwG;AACxG,wBAAgB,yBAAyB;;;gDAExC"}
@@ -3,17 +3,17 @@
3
3
  * and the matches are loaded with `control.addTools`, so the next request offers them. Loading writes the
4
4
  * conversation's `modelTools` (its `add`), so loaded tools stay offered on that branch, also after a compaction.
5
5
  */
6
- import { Type } from "@earendil-works/pi-ai";
6
+ import { num, obj, opt, str } from "@earendil-works/pi-schema";
7
7
  import { defineExtension, defineTool } from "../harness/define.js";
8
8
  import { rankDocuments } from "../search.js";
9
9
  export const TOOL_SEARCH_TOOL_NAME = "tool_search";
10
10
  export const DEFAULT_TOOL_SEARCH_LIMIT = 8;
11
11
  /** Fixed, so it does not change while deferred tools are registered, for example as MCP servers connect. */
12
12
  const TOOL_SEARCH_DESCRIPTION = `# Tool discovery\n\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.\n\nSome of the tools, such as tools of MCP servers, may not have been provided to you upfront, and you should use this tool (\`${TOOL_SEARCH_TOOL_NAME}\`) to search for the required tools. For MCP tool discovery, always use \`${TOOL_SEARCH_TOOL_NAME}\`.`;
13
- const toolSearchSchema = Type.Object({
14
- query: Type.String({ description: "Search query for deferred tools." }),
15
- limit: Type.Optional(Type.Number({ description: `Maximum number of tools to return. Defaults to ${DEFAULT_TOOL_SEARCH_LIMIT}.` })),
16
- });
13
+ const toolSearchSchema = obj({
14
+ query: str({ description: "Search query for deferred tools." }),
15
+ limit: opt(num({ description: `Maximum number of tools to return. Defaults to ${DEFAULT_TOOL_SEARCH_LIMIT}.` })),
16
+ }, { open: true });
17
17
  function isObject(value) {
18
18
  return typeof value === "object" && value !== null && !Array.isArray(value);
19
19
  }
@@ -37,9 +37,9 @@ function schemaText(schema, parts) {
37
37
  schemaText(variant, parts);
38
38
  }
39
39
  }
40
- /** Search text of a tool: its name, the name with `_` as spaces, its description, and its parameters' text. */
40
+ /** Search text of a tool: its description and its parameters' names and descriptions; the ranker reads the name. */
41
41
  function searchText(tool) {
42
- const parts = [tool.name, tool.name.replaceAll("_", " "), tool.description];
42
+ const parts = [tool.description];
43
43
  schemaText(tool.parameters, parts);
44
44
  return parts.filter((part) => part.trim() !== "").join(" ");
45
45
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tool-search.js","sourceRoot":"","sources":["../../src/tool-search/tool-search.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The `tool_search` tool, a copy of the coding agent's: the model searches the deferred tools it is not offered yet,\n * and the matches are loaded with `control.addTools`, so the next request offers them. Loading writes the\n * conversation's `modelTools` (its `add`), so loaded tools stay offered on that branch, also after a compaction.\n */\nimport { Type } from \"@earendil-works/pi-ai\";\nimport { defineExtension, defineTool } from \"../harness/define.ts\";\nimport type { ToolRegistration } from \"../harness/types.ts\";\nimport { rankDocuments } from \"../search.ts\";\n\nexport const TOOL_SEARCH_TOOL_NAME = \"tool_search\";\nexport const DEFAULT_TOOL_SEARCH_LIMIT = 8;\n\n/** Fixed, so it does not change while deferred tools are registered, for example as MCP servers connect. */\nconst TOOL_SEARCH_DESCRIPTION = `# Tool discovery\\n\\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.\\n\\nSome of the tools, such as tools of MCP servers, may not have been provided to you upfront, and you should use this tool (\\`${TOOL_SEARCH_TOOL_NAME}\\`) to search for the required tools. For MCP tool discovery, always use \\`${TOOL_SEARCH_TOOL_NAME}\\`.`;\n\nconst toolSearchSchema = Type.Object({\n\tquery: Type.String({ description: \"Search query for deferred tools.\" }),\n\tlimit: Type.Optional(\n\t\tType.Number({ description: `Maximum number of tools to return. Defaults to ${DEFAULT_TOOL_SEARCH_LIMIT}.` }),\n\t),\n});\n\n/** `tool_search` result details: the tools it loaded. */\nexport type ToolSearchToolDetails = { loaded: string[] };\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Schema descriptions and property names, recursively. */\nfunction schemaText(schema: unknown, parts: string[]): void {\n\tif (!isObject(schema)) return;\n\tif (typeof schema.description === \"string\") parts.push(schema.description);\n\tif (isObject(schema.properties)) {\n\t\tfor (const [name, property] of Object.entries(schema.properties)) {\n\t\t\tparts.push(name);\n\t\t\tschemaText(property, parts);\n\t\t}\n\t}\n\tschemaText(schema.items, parts);\n\tfor (const key of [\"anyOf\", \"oneOf\", \"allOf\"]) {\n\t\tconst variants = schema[key];\n\t\tif (Array.isArray(variants)) for (const variant of variants) schemaText(variant, parts);\n\t}\n}\n\n/** Search text of a tool: its name, the name with `_` as spaces, its description, and its parameters' text. */\nfunction searchText(tool: ToolRegistration): string {\n\tconst parts = [tool.name, tool.name.replaceAll(\"_\", \" \"), tool.description];\n\tschemaText(tool.parameters, parts);\n\treturn parts.filter((part) => part.trim() !== \"\").join(\" \");\n}\n\nexport function createToolSearchTool() {\n\treturn defineTool({\n\t\tname: TOOL_SEARCH_TOOL_NAME,\n\t\tdescription: TOOL_SEARCH_DESCRIPTION,\n\t\tparameters: toolSearchSchema,\n\t\t// Searching changes what the model is offered; scripts have their own `searchTools()`.\n\t\tcallers: [\"model\"],\n\t\treplay: \"safe\",\n\t\tasync execute({ query, limit }, api, context) {\n\t\t\tif (query.trim() === \"\") throw new Error(\"query must not be empty\");\n\t\t\tconst max = limit ?? DEFAULT_TOOL_SEARCH_LIMIT;\n\t\t\tif (!Number.isInteger(max) || max <= 0) throw new Error(\"limit must be a positive integer\");\n\t\t\tconst candidates = (await api.agent(context)).deferred;\n\t\t\tconst documents = candidates.map((tool) => ({ name: tool.name, text: searchText(tool) }));\n\t\t\tconst loaded = rankDocuments(query, documents, max);\n\t\t\tconst text =\n\t\t\t\tloaded.length === 0\n\t\t\t\t\t? \"No matching tools found.\"\n\t\t\t\t\t: `Loaded ${loaded.length} tool${loaded.length === 1 ? \"\" : \"s\"}. They are available from your next call:\\n${loaded\n\t\t\t\t\t\t\t.map((name) => {\n\t\t\t\t\t\t\t\tconst description = candidates.find((tool) => tool.name === name)?.description ?? \"\";\n\t\t\t\t\t\t\t\treturn `- ${name}: ${description.trim().split(/\\r?\\n/)[0]}`;\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.join(\"\\n\")}`;\n\t\t\tconst details: ToolSearchToolDetails = { loaded };\n\t\t\treturn {\n\t\t\t\toutput: [{ type: \"text\", text }],\n\t\t\t\tdetails,\n\t\t\t\t...(loaded.length === 0 ? {} : { control: { addTools: loaded } }),\n\t\t\t};\n\t\t},\n\t});\n}\n\n/** The `tool_search` extension: install it and select it where the model should find deferred tools. */\nexport function createToolSearchExtension() {\n\treturn defineExtension({ name: \"tool-search\", tools: [createToolSearchTool()] });\n}\n"]}
1
+ {"version":3,"file":"tool-search.js","sourceRoot":"","sources":["../../src/tool-search/tool-search.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The `tool_search` tool, a copy of the coding agent's: the model searches the deferred tools it is not offered yet,\n * and the matches are loaded with `control.addTools`, so the next request offers them. Loading writes the\n * conversation's `modelTools` (its `add`), so loaded tools stay offered on that branch, also after a compaction.\n */\nimport { num, obj, opt, str } from \"@earendil-works/pi-schema\";\nimport { defineExtension, defineTool } from \"../harness/define.ts\";\nimport type { ToolRegistration } from \"../harness/types.ts\";\nimport { rankDocuments } from \"../search.ts\";\n\nexport const TOOL_SEARCH_TOOL_NAME = \"tool_search\";\nexport const DEFAULT_TOOL_SEARCH_LIMIT = 8;\n\n/** Fixed, so it does not change while deferred tools are registered, for example as MCP servers connect. */\nconst TOOL_SEARCH_DESCRIPTION = `# Tool discovery\\n\\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.\\n\\nSome of the tools, such as tools of MCP servers, may not have been provided to you upfront, and you should use this tool (\\`${TOOL_SEARCH_TOOL_NAME}\\`) to search for the required tools. For MCP tool discovery, always use \\`${TOOL_SEARCH_TOOL_NAME}\\`.`;\n\nconst toolSearchSchema = obj(\n\t{\n\t\tquery: str({ description: \"Search query for deferred tools.\" }),\n\t\tlimit: opt(num({ description: `Maximum number of tools to return. Defaults to ${DEFAULT_TOOL_SEARCH_LIMIT}.` })),\n\t},\n\t{ open: true },\n);\n\n/** `tool_search` result details: the tools it loaded. */\nexport type ToolSearchToolDetails = { loaded: string[] };\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Schema descriptions and property names, recursively. */\nfunction schemaText(schema: unknown, parts: string[]): void {\n\tif (!isObject(schema)) return;\n\tif (typeof schema.description === \"string\") parts.push(schema.description);\n\tif (isObject(schema.properties)) {\n\t\tfor (const [name, property] of Object.entries(schema.properties)) {\n\t\t\tparts.push(name);\n\t\t\tschemaText(property, parts);\n\t\t}\n\t}\n\tschemaText(schema.items, parts);\n\tfor (const key of [\"anyOf\", \"oneOf\", \"allOf\"]) {\n\t\tconst variants = schema[key];\n\t\tif (Array.isArray(variants)) for (const variant of variants) schemaText(variant, parts);\n\t}\n}\n\n/** Search text of a tool: its description and its parameters' names and descriptions; the ranker reads the name. */\nfunction searchText(tool: ToolRegistration): string {\n\tconst parts = [tool.description];\n\tschemaText(tool.parameters, parts);\n\treturn parts.filter((part) => part.trim() !== \"\").join(\" \");\n}\n\nexport function createToolSearchTool() {\n\treturn defineTool({\n\t\tname: TOOL_SEARCH_TOOL_NAME,\n\t\tdescription: TOOL_SEARCH_DESCRIPTION,\n\t\tparameters: toolSearchSchema,\n\t\t// Searching changes what the model is offered; scripts have their own `searchTools()`.\n\t\tcallers: [\"model\"],\n\t\treplay: \"safe\",\n\t\tasync execute({ query, limit }, api, context) {\n\t\t\tif (query.trim() === \"\") throw new Error(\"query must not be empty\");\n\t\t\tconst max = limit ?? DEFAULT_TOOL_SEARCH_LIMIT;\n\t\t\tif (!Number.isInteger(max) || max <= 0) throw new Error(\"limit must be a positive integer\");\n\t\t\tconst candidates = (await api.agent(context)).deferred;\n\t\t\tconst documents = candidates.map((tool) => ({ name: tool.name, text: searchText(tool) }));\n\t\t\tconst loaded = rankDocuments(query, documents, max);\n\t\t\tconst text =\n\t\t\t\tloaded.length === 0\n\t\t\t\t\t? \"No matching tools found.\"\n\t\t\t\t\t: `Loaded ${loaded.length} tool${loaded.length === 1 ? \"\" : \"s\"}. They are available from your next call:\\n${loaded\n\t\t\t\t\t\t\t.map((name) => {\n\t\t\t\t\t\t\t\tconst description = candidates.find((tool) => tool.name === name)?.description ?? \"\";\n\t\t\t\t\t\t\t\treturn `- ${name}: ${description.trim().split(/\\r?\\n/)[0]}`;\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.join(\"\\n\")}`;\n\t\t\tconst details: ToolSearchToolDetails = { loaded };\n\t\t\treturn {\n\t\t\t\toutput: [{ type: \"text\", text }],\n\t\t\t\tdetails,\n\t\t\t\t...(loaded.length === 0 ? {} : { control: { addTools: loaded } }),\n\t\t\t};\n\t\t},\n\t});\n}\n\n/** The `tool_search` extension: install it and select it where the model should find deferred tools. */\nexport function createToolSearchExtension() {\n\treturn defineExtension({ name: \"tool-search\", tools: [createToolSearchTool()] });\n}\n"]}
@@ -1,20 +1,20 @@
1
1
  import type { Context } from "@earendil-works/chord";
2
- import { type Static, Type } from "typebox";
2
+ import { type Static } from "@earendil-works/pi-schema";
3
3
  import type { ToolExecutionApi, ToolRegistration } from "../harness/types.ts";
4
- declare const bashSchema: Type.TObject<{
5
- command: Type.TString;
6
- timeout: Type.TOptional<Type.TNumber>;
4
+ declare const bashSchema: import("@earendil-works/pi-schema").Schema<{
5
+ command: string;
6
+ timeout?: number | undefined;
7
7
  }>;
8
- declare const powershellSchema: Type.TObject<{
9
- command: Type.TString;
10
- timeout: Type.TOptional<Type.TNumber>;
8
+ declare const powershellSchema: import("@earendil-works/pi-schema").Schema<{
9
+ command: string;
10
+ timeout?: number | undefined;
11
11
  }>;
12
12
  /** What a program that calls `bash` or `powershell` receives. */
13
- declare const shellStructuredOutputSchema: Type.TObject<{
14
- output: Type.TString;
15
- truncated: Type.TBoolean;
16
- fullOutputPath: Type.TOptional<Type.TString>;
17
- exitCode: Type.TNumber;
13
+ declare const shellStructuredOutputSchema: import("@earendil-works/pi-schema").Schema<{
14
+ output: string;
15
+ truncated: boolean;
16
+ fullOutputPath?: string | undefined;
17
+ exitCode: number;
18
18
  }>;
19
19
  export type BashToolInput = Static<typeof bashSchema>;
20
20
  export type PowerShellToolInput = Static<typeof powershellSchema>;
@@ -1 +1 @@
1
- {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,gBAAgB,EAAuB,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAMnG,QAAA,MAAM,UAAU;;;EAGd,CAAC;AAEH,QAAA,MAAM,gBAAgB;;;EAGpB,CAAC;AAEH,iEAAiE;AACjE,QAAA,MAAM,2BAA2B;;;;;EAK/B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AACtD,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAClE,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAE/E,6GAA6G;AAC7G,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,UAAU,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEtH,MAAM,WAAW,eAAe;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACrC,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,sHAAsH;IACtH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAqFD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,gBAAgB,CAAC,OAAO,UAAU,CAAC,CAa7F;AAMD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,gBAAgB,CAAC,OAAO,gBAAgB,CAAC,CAgB/G"}
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAuB,KAAK,MAAM,EAAO,MAAM,2BAA2B,CAAC;AAElF,OAAO,KAAK,EAAE,gBAAgB,EAAuB,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAOnG,QAAA,MAAM,UAAU;;;EAMf,CAAC;AAEF,QAAA,MAAM,gBAAgB;;;EAMrB,CAAC;AAEF,iEAAiE;AACjE,QAAA,MAAM,2BAA2B;;;;;EAQhC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AACtD,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAClE,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAE/E,6GAA6G;AAC7G,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,UAAU,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEtH,MAAM,WAAW,eAAe;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACrC,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,sHAAsH;IACtH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAqFD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,gBAAgB,CAAC,OAAO,UAAU,CAAC,CAa7F;AAMD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,gBAAgB,CAAC,OAAO,gBAAgB,CAAC,CAgB/G"}
@@ -1,23 +1,24 @@
1
- import { Type } from "typebox";
1
+ import { bool, num, obj, opt, str } from "@earendil-works/pi-schema";
2
2
  import { defineTool } from "../harness/define.js";
3
3
  import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES } from "../truncate.js";
4
4
  import { requireEnv } from "./env.js";
5
5
  const MAX_TIMEOUT_SECONDS = 2_147_483_647 / 1000;
6
- const bashSchema = Type.Object({
7
- command: Type.String({ description: "Bash command to execute" }),
8
- timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" })),
9
- });
10
- const powershellSchema = Type.Object({
11
- command: Type.String({ description: "PowerShell command to execute" }),
12
- timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" })),
13
- });
6
+ // Open objects, as the tools accepted extra arguments when their schemas were TypeBox's.
7
+ const bashSchema = obj({
8
+ command: str({ description: "Bash command to execute" }),
9
+ timeout: opt(num({ description: "Timeout in seconds (optional, no default timeout)" })),
10
+ }, { open: true });
11
+ const powershellSchema = obj({
12
+ command: str({ description: "PowerShell command to execute" }),
13
+ timeout: opt(num({ description: "Timeout in seconds (optional, no default timeout)" })),
14
+ }, { open: true });
14
15
  /** What a program that calls `bash` or `powershell` receives. */
15
- const shellStructuredOutputSchema = Type.Object({
16
- output: Type.String({ description: "Combined stdout and stderr: the retained tail, as the model sees it" }),
17
- truncated: Type.Boolean({ description: "Whether earlier output was dropped" }),
18
- fullOutputPath: Type.Optional(Type.String({ description: "File with the complete output, when it was spilled" })),
19
- exitCode: Type.Number(),
20
- });
16
+ const shellStructuredOutputSchema = obj({
17
+ output: str({ description: "Combined stdout and stderr: the retained tail, as the model sees it" }),
18
+ truncated: bool({ description: "Whether earlier output was dropped" }),
19
+ fullOutputPath: opt(str({ description: "File with the complete output, when it was spilled" })),
20
+ exitCode: num(),
21
+ }, { open: true });
21
22
  function validateTimeout(timeout) {
22
23
  if (timeout === undefined)
23
24
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from \"@earendil-works/chord\";\nimport { type Static, Type } from \"typebox\";\nimport { defineTool } from \"../harness/define.ts\";\nimport type { ToolExecutionApi, ToolExecutionResult, ToolRegistration } from \"../harness/types.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES } from \"../truncate.ts\";\nimport { requireEnv } from \"./env.ts\";\n\nconst MAX_TIMEOUT_SECONDS = 2_147_483_647 / 1000;\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Bash command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\nconst powershellSchema = Type.Object({\n\tcommand: Type.String({ description: \"PowerShell command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\n/** What a program that calls `bash` or `powershell` receives. */\nconst shellStructuredOutputSchema = Type.Object({\n\toutput: Type.String({ description: \"Combined stdout and stderr: the retained tail, as the model sees it\" }),\n\ttruncated: Type.Boolean({ description: \"Whether earlier output was dropped\" }),\n\tfullOutputPath: Type.Optional(Type.String({ description: \"File with the complete output, when it was spilled\" })),\n\texitCode: Type.Number(),\n});\n\nexport type BashToolInput = Static<typeof bashSchema>;\nexport type PowerShellToolInput = Static<typeof powershellSchema>;\nexport type ShellStructuredOutput = Static<typeof shellStructuredOutputSchema>;\n\n/** A command about to run, which `prepare` may change: the script, its working directory and environment. */\nexport interface BashExecution {\n\tcommand: string;\n\tcwd: string;\n\tenv: Record<string, string>;\n\tinheritEnv: boolean;\n}\n\nexport type BashPrepare = (execution: BashExecution, api: ToolExecutionApi, context: Context) => void | Promise<void>;\n\nexport interface BashToolOptions {\n\tcommandPrefix?: string;\n\tprepare?: BashPrepare;\n}\n\nexport interface PowerShellToolOptions {\n\t/** Lines run before each command. */\n\tcommandPrefix?: string;\n\tprepare?: BashPrepare;\n\t/** PowerShell programs to try in order; default `pwsh`, then `powershell`. A program that cannot start is skipped. */\n\tprograms?: readonly string[];\n}\n\nfunction validateTimeout(timeout: number | undefined): void {\n\tif (timeout === undefined) return;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\tif (timeout > MAX_TIMEOUT_SECONDS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n}\n\n/** The execution of one call: the command with its prefix, in the environment's working directory, then `prepare`. */\nasync function prepareExecution(\n\tcommand: string,\n\toptions: { commandPrefix?: string; prepare?: BashPrepare } | undefined,\n\tapi: ToolExecutionApi,\n\tcontext: Context,\n): Promise<BashExecution> {\n\tconst execution: BashExecution = {\n\t\tcommand: options?.commandPrefix ? `${options.commandPrefix}\\n${command}` : command,\n\t\tcwd: requireEnv(api).cwd,\n\t\tenv: {},\n\t\tinheritEnv: true,\n\t};\n\tawait options?.prepare?.(execution, api, context);\n\treturn execution;\n}\n\n/**\n * Run each command form in turn until one starts, streaming output to `api.output()` within the retained window, and\n * turn the result into the tool's result: a spill diagnostic, an error result for a nonzero exit, and a thrown error for\n * a failure such as a timeout. The structured output repeats the retained output with the exit code.\n */\nasync function runCommand(\n\tcommands: readonly (string | readonly string[])[],\n\texecution: BashExecution,\n\ttimeout: number | undefined,\n\tapi: ToolExecutionApi,\n\tcontext: Context,\n): Promise<ToolExecutionResult> {\n\tconst env = requireEnv(api);\n\tlet result: Awaited<ReturnType<typeof env.exec>> | undefined;\n\tfor (const command of commands) {\n\t\tresult = await env.exec(\n\t\t\tcommand,\n\t\t\t{\n\t\t\t\tcwd: execution.cwd,\n\t\t\t\tenv: execution.env,\n\t\t\t\tinheritEnv: execution.inheritEnv,\n\t\t\t\t...(timeout === undefined ? {} : { timeout }),\n\t\t\t\tonOutput: (text, _context, info) => api.output(text, info.skipped),\n\t\t\t\tspill: { afterBytes: DEFAULT_MAX_BYTES, afterLines: DEFAULT_MAX_LINES },\n\t\t\t\t// An environment may then omit output outside the retained tail and report the omission.\n\t\t\t\t...(api.outputWindow === undefined ? {} : { window: api.outputWindow }),\n\t\t\t},\n\t\t\tcontext,\n\t\t);\n\t\t// A program that could not start produced no output; the next form may.\n\t\tif (result.ok || result.error.code !== \"spawn_error\") break;\n\t}\n\tif (result === undefined) throw new Error(\"No command to run\");\n\tconst spillPath = result.ok ? result.value.spillPath : result.error.spillPath;\n\tif (spillPath !== undefined) {\n\t\tapi.diagnostic({ severity: \"info\", code: \"full_output\", message: `Full output: ${spillPath}` });\n\t}\n\tif (!result.ok) {\n\t\tif (result.error.code === \"aborted\" && context.abortSignal?.aborted) throw result.error;\n\t\tif (result.error.code === \"timeout\") throw new Error(`Command timed out after ${timeout} seconds`);\n\t\tif (result.error.code === \"aborted\") throw new Error(\"Command aborted\");\n\t\tthrow result.error;\n\t}\n\tconst exitCode = result.value.exitCode;\n\tconst retained = api.retainedOutput();\n\tconst structuredOutput: ShellStructuredOutput = {\n\t\toutput: retained.text,\n\t\ttruncated: retained.truncated,\n\t\t...(spillPath === undefined ? {} : { fullOutputPath: spillPath }),\n\t\texitCode,\n\t};\n\tif (exitCode === 0) return { structuredOutput };\n\tconst exited = { severity: \"error\", code: \"exit_code\", message: `Command exited with code ${exitCode}` } as const;\n\treturn { structuredOutput, isError: true, diagnostics: [exited] };\n}\n\n/**\n * Runs a command through the environment's shell. Its output streams to `api.output()`, where the Harness keeps the\n * tail within the default limits; the result content is that retained output. The retained window goes to the\n * environment, which may omit output outside it and report how much it omitted, so dropped counts stay exact. Output\n * beyond the limits is spilled to a file whose path is reported as a diagnostic. A nonzero exit is an error result with\n * the exit code; a timeout throws, which makes an error result that still carries the output and diagnostics.\n */\nexport function createBashTool(options?: BashToolOptions): ToolRegistration<typeof bashSchema> {\n\treturn defineTool({\n\t\tname: \"bash\",\n\t\tdescription: `Execute a bash command in the current working directory. Returns combined stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tparameters: bashSchema,\n\t\tstructuredOutputSchema: shellStructuredOutputSchema,\n\t\toutputLimits: { retain: \"tail\" },\n\t\tasync execute(args, api, context) {\n\t\t\tvalidateTimeout(args.timeout);\n\t\t\tconst execution = await prepareExecution(args.command, options, api, context);\n\t\t\treturn runCommand([execution.command], execution, args.timeout, api, context);\n\t\t},\n\t});\n}\n\n/** Output in UTF-8 whatever the console's code page, as the coding agent's `powershell` tool does. */\nconst UTF8_OUTPUT = \"try { [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 } catch {}\";\nconst POWERSHELL_ARGS = [\"-NoProfile\", \"-NonInteractive\", \"-ExecutionPolicy\", \"Bypass\", \"-Command\"] as const;\n\n/**\n * Runs a PowerShell command, like `bash` but through PowerShell instead of the environment's shell: `pwsh` (PowerShell\n * 7), else Windows PowerShell, started directly with the command as an argument, so no other shell parses it.\n */\nexport function createPowerShellTool(options?: PowerShellToolOptions): ToolRegistration<typeof powershellSchema> {\n\tconst programs = options?.programs ?? [\"pwsh\", \"powershell\"];\n\treturn defineTool({\n\t\tname: \"powershell\",\n\t\tdescription: `Execute a PowerShell command in the current working directory. Returns combined stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tparameters: powershellSchema,\n\t\tstructuredOutputSchema: shellStructuredOutputSchema,\n\t\toutputLimits: { retain: \"tail\" },\n\t\tasync execute(args, api, context) {\n\t\t\tvalidateTimeout(args.timeout);\n\t\t\tconst execution = await prepareExecution(args.command, options, api, context);\n\t\t\tconst script = `${UTF8_OUTPUT}\\n${execution.command}`;\n\t\t\tconst commands = programs.map((program) => [program, ...POWERSHELL_ARGS, script]);\n\t\t\treturn runCommand(commands, execution, args.timeout, api, context);\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from \"@earendil-works/chord\";\nimport { bool, num, obj, opt, type Static, str } from \"@earendil-works/pi-schema\";\nimport { defineTool } from \"../harness/define.ts\";\nimport type { ToolExecutionApi, ToolExecutionResult, ToolRegistration } from \"../harness/types.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES } from \"../truncate.ts\";\nimport { requireEnv } from \"./env.ts\";\n\nconst MAX_TIMEOUT_SECONDS = 2_147_483_647 / 1000;\n\n// Open objects, as the tools accepted extra arguments when their schemas were TypeBox's.\nconst bashSchema = obj(\n\t{\n\t\tcommand: str({ description: \"Bash command to execute\" }),\n\t\ttimeout: opt(num({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n\t},\n\t{ open: true },\n);\n\nconst powershellSchema = obj(\n\t{\n\t\tcommand: str({ description: \"PowerShell command to execute\" }),\n\t\ttimeout: opt(num({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n\t},\n\t{ open: true },\n);\n\n/** What a program that calls `bash` or `powershell` receives. */\nconst shellStructuredOutputSchema = obj(\n\t{\n\t\toutput: str({ description: \"Combined stdout and stderr: the retained tail, as the model sees it\" }),\n\t\ttruncated: bool({ description: \"Whether earlier output was dropped\" }),\n\t\tfullOutputPath: opt(str({ description: \"File with the complete output, when it was spilled\" })),\n\t\texitCode: num(),\n\t},\n\t{ open: true },\n);\n\nexport type BashToolInput = Static<typeof bashSchema>;\nexport type PowerShellToolInput = Static<typeof powershellSchema>;\nexport type ShellStructuredOutput = Static<typeof shellStructuredOutputSchema>;\n\n/** A command about to run, which `prepare` may change: the script, its working directory and environment. */\nexport interface BashExecution {\n\tcommand: string;\n\tcwd: string;\n\tenv: Record<string, string>;\n\tinheritEnv: boolean;\n}\n\nexport type BashPrepare = (execution: BashExecution, api: ToolExecutionApi, context: Context) => void | Promise<void>;\n\nexport interface BashToolOptions {\n\tcommandPrefix?: string;\n\tprepare?: BashPrepare;\n}\n\nexport interface PowerShellToolOptions {\n\t/** Lines run before each command. */\n\tcommandPrefix?: string;\n\tprepare?: BashPrepare;\n\t/** PowerShell programs to try in order; default `pwsh`, then `powershell`. A program that cannot start is skipped. */\n\tprograms?: readonly string[];\n}\n\nfunction validateTimeout(timeout: number | undefined): void {\n\tif (timeout === undefined) return;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\tif (timeout > MAX_TIMEOUT_SECONDS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n}\n\n/** The execution of one call: the command with its prefix, in the environment's working directory, then `prepare`. */\nasync function prepareExecution(\n\tcommand: string,\n\toptions: { commandPrefix?: string; prepare?: BashPrepare } | undefined,\n\tapi: ToolExecutionApi,\n\tcontext: Context,\n): Promise<BashExecution> {\n\tconst execution: BashExecution = {\n\t\tcommand: options?.commandPrefix ? `${options.commandPrefix}\\n${command}` : command,\n\t\tcwd: requireEnv(api).cwd,\n\t\tenv: {},\n\t\tinheritEnv: true,\n\t};\n\tawait options?.prepare?.(execution, api, context);\n\treturn execution;\n}\n\n/**\n * Run each command form in turn until one starts, streaming output to `api.output()` within the retained window, and\n * turn the result into the tool's result: a spill diagnostic, an error result for a nonzero exit, and a thrown error for\n * a failure such as a timeout. The structured output repeats the retained output with the exit code.\n */\nasync function runCommand(\n\tcommands: readonly (string | readonly string[])[],\n\texecution: BashExecution,\n\ttimeout: number | undefined,\n\tapi: ToolExecutionApi,\n\tcontext: Context,\n): Promise<ToolExecutionResult> {\n\tconst env = requireEnv(api);\n\tlet result: Awaited<ReturnType<typeof env.exec>> | undefined;\n\tfor (const command of commands) {\n\t\tresult = await env.exec(\n\t\t\tcommand,\n\t\t\t{\n\t\t\t\tcwd: execution.cwd,\n\t\t\t\tenv: execution.env,\n\t\t\t\tinheritEnv: execution.inheritEnv,\n\t\t\t\t...(timeout === undefined ? {} : { timeout }),\n\t\t\t\tonOutput: (text, _context, info) => api.output(text, info.skipped),\n\t\t\t\tspill: { afterBytes: DEFAULT_MAX_BYTES, afterLines: DEFAULT_MAX_LINES },\n\t\t\t\t// An environment may then omit output outside the retained tail and report the omission.\n\t\t\t\t...(api.outputWindow === undefined ? {} : { window: api.outputWindow }),\n\t\t\t},\n\t\t\tcontext,\n\t\t);\n\t\t// A program that could not start produced no output; the next form may.\n\t\tif (result.ok || result.error.code !== \"spawn_error\") break;\n\t}\n\tif (result === undefined) throw new Error(\"No command to run\");\n\tconst spillPath = result.ok ? result.value.spillPath : result.error.spillPath;\n\tif (spillPath !== undefined) {\n\t\tapi.diagnostic({ severity: \"info\", code: \"full_output\", message: `Full output: ${spillPath}` });\n\t}\n\tif (!result.ok) {\n\t\tif (result.error.code === \"aborted\" && context.abortSignal?.aborted) throw result.error;\n\t\tif (result.error.code === \"timeout\") throw new Error(`Command timed out after ${timeout} seconds`);\n\t\tif (result.error.code === \"aborted\") throw new Error(\"Command aborted\");\n\t\tthrow result.error;\n\t}\n\tconst exitCode = result.value.exitCode;\n\tconst retained = api.retainedOutput();\n\tconst structuredOutput: ShellStructuredOutput = {\n\t\toutput: retained.text,\n\t\ttruncated: retained.truncated,\n\t\t...(spillPath === undefined ? {} : { fullOutputPath: spillPath }),\n\t\texitCode,\n\t};\n\tif (exitCode === 0) return { structuredOutput };\n\tconst exited = { severity: \"error\", code: \"exit_code\", message: `Command exited with code ${exitCode}` } as const;\n\treturn { structuredOutput, isError: true, diagnostics: [exited] };\n}\n\n/**\n * Runs a command through the environment's shell. Its output streams to `api.output()`, where the Harness keeps the\n * tail within the default limits; the result content is that retained output. The retained window goes to the\n * environment, which may omit output outside it and report how much it omitted, so dropped counts stay exact. Output\n * beyond the limits is spilled to a file whose path is reported as a diagnostic. A nonzero exit is an error result with\n * the exit code; a timeout throws, which makes an error result that still carries the output and diagnostics.\n */\nexport function createBashTool(options?: BashToolOptions): ToolRegistration<typeof bashSchema> {\n\treturn defineTool({\n\t\tname: \"bash\",\n\t\tdescription: `Execute a bash command in the current working directory. Returns combined stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tparameters: bashSchema,\n\t\tstructuredOutputSchema: shellStructuredOutputSchema,\n\t\toutputLimits: { retain: \"tail\" },\n\t\tasync execute(args, api, context) {\n\t\t\tvalidateTimeout(args.timeout);\n\t\t\tconst execution = await prepareExecution(args.command, options, api, context);\n\t\t\treturn runCommand([execution.command], execution, args.timeout, api, context);\n\t\t},\n\t});\n}\n\n/** Output in UTF-8 whatever the console's code page, as the coding agent's `powershell` tool does. */\nconst UTF8_OUTPUT = \"try { [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 } catch {}\";\nconst POWERSHELL_ARGS = [\"-NoProfile\", \"-NonInteractive\", \"-ExecutionPolicy\", \"Bypass\", \"-Command\"] as const;\n\n/**\n * Runs a PowerShell command, like `bash` but through PowerShell instead of the environment's shell: `pwsh` (PowerShell\n * 7), else Windows PowerShell, started directly with the command as an argument, so no other shell parses it.\n */\nexport function createPowerShellTool(options?: PowerShellToolOptions): ToolRegistration<typeof powershellSchema> {\n\tconst programs = options?.programs ?? [\"pwsh\", \"powershell\"];\n\treturn defineTool({\n\t\tname: \"powershell\",\n\t\tdescription: `Execute a PowerShell command in the current working directory. Returns combined stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tparameters: powershellSchema,\n\t\tstructuredOutputSchema: shellStructuredOutputSchema,\n\t\toutputLimits: { retain: \"tail\" },\n\t\tasync execute(args, api, context) {\n\t\t\tvalidateTimeout(args.timeout);\n\t\t\tconst execution = await prepareExecution(args.command, options, api, context);\n\t\t\tconst script = `${UTF8_OUTPUT}\\n${execution.command}`;\n\t\t\tconst commands = programs.map((program) => [program, ...POWERSHELL_ARGS, script]);\n\t\t\treturn runCommand(commands, execution, args.timeout, api, context);\n\t\t},\n\t});\n}\n"]}
@@ -1,11 +1,11 @@
1
- import { type Static, Type } from "typebox";
1
+ import { type Static } from "@earendil-works/pi-schema";
2
2
  import type { ToolRegistration } from "../harness/types.ts";
3
- declare const editSchema: Type.TObject<{
4
- path: Type.TString;
5
- edits: Type.TArray<Type.TObject<{
6
- oldText: Type.TString;
7
- newText: Type.TString;
8
- }>>;
3
+ declare const editSchema: import("@earendil-works/pi-schema").Schema<{
4
+ path: string;
5
+ edits: {
6
+ oldText: string;
7
+ newText: string;
8
+ }[];
9
9
  }>;
10
10
  export type EditToolInput = Static<typeof editSchema>;
11
11
  export type EditToolDetails = {
@@ -1 +1 @@
1
- {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAuB5D,QAAA,MAAM,UAAU;;;;;;EAMd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAsCtD,MAAM,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAaF,wBAAgB,cAAc,IAAI,gBAAgB,CAAC,OAAO,UAAU,EAAE,eAAe,CAAC,CAsDrF"}
1
+ {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,MAAM,EAAO,MAAM,2BAA2B,CAAC;AAGvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AA0B5D,QAAA,MAAM,UAAU;;;;;;EASf,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAsCtD,MAAM,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAaF,wBAAgB,cAAc,IAAI,gBAAgB,CAAC,OAAO,UAAU,EAAE,eAAe,CAAC,CAsDrF"}
@@ -1,21 +1,21 @@
1
- import { Type } from "typebox";
1
+ import { arr, obj, str } from "@earendil-works/pi-schema";
2
2
  import { defineTool } from "../harness/define.js";
3
3
  import { applyEditsToNormalizedContent, detectLineEnding, generateDiffString, generateUnifiedPatch, normalizeToLF, restoreLineEndings, stripBom, } from "./edit-diff.js";
4
4
  import { requireEnv } from "./env.js";
5
5
  import { withFileMutationQueue } from "./file-mutation-queue.js";
6
6
  import { resolveToolPath } from "./path-utils.js";
7
- const replaceEditSchema = Type.Object({
8
- oldText: Type.String({
7
+ const replaceEditSchema = obj({
8
+ oldText: str({
9
9
  description: "Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call.",
10
10
  }),
11
- newText: Type.String({ description: "Replacement text for this targeted edit." }),
12
- });
13
- const editSchema = Type.Object({
14
- path: Type.String({ description: "Path to the file to edit (relative or absolute)" }),
15
- edits: Type.Array(replaceEditSchema, {
11
+ newText: str({ description: "Replacement text for this targeted edit." }),
12
+ }, { open: true });
13
+ const editSchema = obj({
14
+ path: str({ description: "Path to the file to edit (relative or absolute)" }),
15
+ edits: arr(replaceEditSchema, {
16
16
  description: "One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead.",
17
17
  }),
18
- });
18
+ }, { open: true });
19
19
  function isSingleEditInput(value) {
20
20
  if (!value || typeof value !== "object" || Array.isArray(value))
21
21
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport type { FileError } from \"../env/index.ts\";\nimport { defineTool } from \"../harness/define.ts\";\nimport type { ToolRegistration } from \"../harness/types.ts\";\nimport {\n\tapplyEditsToNormalizedContent,\n\tdetectLineEnding,\n\ttype Edit,\n\tgenerateDiffString,\n\tgenerateUnifiedPatch,\n\tnormalizeToLF,\n\trestoreLineEndings,\n\tstripBom,\n} from \"./edit-diff.ts\";\nimport { requireEnv } from \"./env.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { resolveToolPath } from \"./path-utils.ts\";\n\nconst replaceEditSchema = Type.Object({\n\toldText: Type.String({\n\t\tdescription:\n\t\t\t\"Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call.\",\n\t}),\n\tnewText: Type.String({ description: \"Replacement text for this targeted edit.\" }),\n});\n\nconst editSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to edit (relative or absolute)\" }),\n\tedits: Type.Array(replaceEditSchema, {\n\t\tdescription:\n\t\t\t\"One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead.\",\n\t}),\n});\n\nexport type EditToolInput = Static<typeof editSchema>;\ntype LegacyEditToolInput = EditToolInput & { oldText?: unknown; newText?: unknown };\ntype SingleEditInput = { oldText: string; newText: string };\n\nfunction isSingleEditInput(value: unknown): value is SingleEditInput {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst edit = value as Record<string, unknown>;\n\treturn typeof edit.oldText === \"string\" && typeof edit.newText === \"string\";\n}\n\n/**\n * Repair shapes models commonly send: `edits` as a JSON string or as a single edit object, and a top-level\n * `oldText`/`newText` pair. Works on a copy; the call's arguments stay unchanged.\n */\nfunction prepareEditArguments(input: unknown): EditToolInput {\n\tif (!input || typeof input !== \"object\" || Array.isArray(input)) return input as EditToolInput;\n\tconst args: Record<string, unknown> = { ...input };\n\tif (typeof args.edits === \"string\") {\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(args.edits);\n\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\targs.edits = parsed;\n\t\t\t} else if (isSingleEditInput(parsed)) {\n\t\t\t\targs.edits = [parsed];\n\t\t\t}\n\t\t} catch {}\n\t} else if (isSingleEditInput(args.edits)) {\n\t\targs.edits = [args.edits];\n\t}\n\n\tconst legacy = args as LegacyEditToolInput;\n\tif (typeof legacy.oldText !== \"string\" || typeof legacy.newText !== \"string\") return legacy;\n\tconst edits = Array.isArray(legacy.edits) ? [...legacy.edits] : [];\n\tedits.push({ oldText: legacy.oldText, newText: legacy.newText });\n\tconst { oldText: _oldText, newText: _newText, ...rest } = legacy;\n\treturn { ...rest, edits };\n}\n\nexport type EditToolDetails = {\n\tdiff: string;\n\tpatch: string;\n\tfirstChangedLine?: number;\n};\n\nfunction validateEditInput(input: EditToolInput): { path: string; edits: Edit[] } {\n\tif (!Array.isArray(input.edits) || input.edits.length === 0) {\n\t\tthrow new Error(\"Edit tool input is invalid. edits must contain at least one replacement.\");\n\t}\n\treturn { path: input.path, edits: input.edits };\n}\n\nfunction editAccessError(path: string, error: FileError): Error {\n\treturn new Error(`Could not edit file: ${path}. Error code: ${error.code}.`, { cause: error });\n}\n\nexport function createEditTool(): ToolRegistration<typeof editSchema, EditToolDetails> {\n\treturn defineTool({\n\t\tname: \"edit\",\n\t\tdescription:\n\t\t\t\"Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.\",\n\t\tparameters: editSchema,\n\t\tprepareArguments: prepareEditArguments,\n\t\tasync execute(args, api, context) {\n\t\t\tconst { path, edits } = validateEditInput(args);\n\t\t\tconst env = requireEnv(api);\n\t\t\tconst absolutePath = await resolveToolPath(env, path, context);\n\t\t\treturn withFileMutationQueue(\n\t\t\t\tenv,\n\t\t\t\tabsolutePath,\n\t\t\t\tasync () => {\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\t\tconst info = await env.fileInfo(absolutePath, context);\n\t\t\t\t\tif (!info.ok) throw editAccessError(path, info.error);\n\t\t\t\t\tif (info.value.kind !== \"file\" && info.value.kind !== \"symlink\") {\n\t\t\t\t\t\tthrow new Error(`Could not edit file: ${path}. Path is not a file.`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst readResult = await env.readTextFile(absolutePath, context);\n\t\t\t\t\tif (!readResult.ok) throw editAccessError(path, readResult.error);\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\t\tconst { bom, text: content } = stripBom(readResult.value);\n\t\t\t\t\tconst originalEnding = detectLineEnding(content);\n\t\t\t\t\tconst normalizedContent = normalizeToLF(content);\n\t\t\t\t\tconst { baseContent, newContent } = applyEditsToNormalizedContent(normalizedContent, edits, path);\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\t\tconst finalContent = bom + restoreLineEndings(newContent, originalEnding);\n\t\t\t\t\tconst writeResult = await env.writeFile(absolutePath, finalContent, context);\n\t\t\t\t\tif (!writeResult.ok) throw editAccessError(path, writeResult.error);\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\t\tconst diffResult = generateDiffString(baseContent, newContent);\n\t\t\t\t\tconst details: EditToolDetails = {\n\t\t\t\t\t\tdiff: diffResult.diff,\n\t\t\t\t\t\tpatch: generateUnifiedPatch(path, baseContent, newContent),\n\t\t\t\t\t\t...(diffResult.firstChangedLine === undefined\n\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t: { firstChangedLine: diffResult.firstChangedLine }),\n\t\t\t\t\t};\n\t\t\t\t\treturn {\n\t\t\t\t\t\toutput: [{ type: \"text\", text: `Successfully replaced ${edits.length} block(s) in ${path}.` }],\n\t\t\t\t\t\tdetails,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tcontext,\n\t\t\t);\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import { arr, obj, type Static, str } from \"@earendil-works/pi-schema\";\nimport type { FileError } from \"../env/index.ts\";\nimport { defineTool } from \"../harness/define.ts\";\nimport type { ToolRegistration } from \"../harness/types.ts\";\nimport {\n\tapplyEditsToNormalizedContent,\n\tdetectLineEnding,\n\ttype Edit,\n\tgenerateDiffString,\n\tgenerateUnifiedPatch,\n\tnormalizeToLF,\n\trestoreLineEndings,\n\tstripBom,\n} from \"./edit-diff.ts\";\nimport { requireEnv } from \"./env.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { resolveToolPath } from \"./path-utils.ts\";\n\nconst replaceEditSchema = obj(\n\t{\n\t\toldText: str({\n\t\t\tdescription:\n\t\t\t\t\"Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call.\",\n\t\t}),\n\t\tnewText: str({ description: \"Replacement text for this targeted edit.\" }),\n\t},\n\t{ open: true },\n);\n\nconst editSchema = obj(\n\t{\n\t\tpath: str({ description: \"Path to the file to edit (relative or absolute)\" }),\n\t\tedits: arr(replaceEditSchema, {\n\t\t\tdescription:\n\t\t\t\t\"One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead.\",\n\t\t}),\n\t},\n\t{ open: true },\n);\n\nexport type EditToolInput = Static<typeof editSchema>;\ntype LegacyEditToolInput = EditToolInput & { oldText?: unknown; newText?: unknown };\ntype SingleEditInput = { oldText: string; newText: string };\n\nfunction isSingleEditInput(value: unknown): value is SingleEditInput {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst edit = value as Record<string, unknown>;\n\treturn typeof edit.oldText === \"string\" && typeof edit.newText === \"string\";\n}\n\n/**\n * Repair shapes models commonly send: `edits` as a JSON string or as a single edit object, and a top-level\n * `oldText`/`newText` pair. Works on a copy; the call's arguments stay unchanged.\n */\nfunction prepareEditArguments(input: unknown): EditToolInput {\n\tif (!input || typeof input !== \"object\" || Array.isArray(input)) return input as EditToolInput;\n\tconst args: Record<string, unknown> = { ...input };\n\tif (typeof args.edits === \"string\") {\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(args.edits);\n\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\targs.edits = parsed;\n\t\t\t} else if (isSingleEditInput(parsed)) {\n\t\t\t\targs.edits = [parsed];\n\t\t\t}\n\t\t} catch {}\n\t} else if (isSingleEditInput(args.edits)) {\n\t\targs.edits = [args.edits];\n\t}\n\n\tconst legacy = args as LegacyEditToolInput;\n\tif (typeof legacy.oldText !== \"string\" || typeof legacy.newText !== \"string\") return legacy;\n\tconst edits = Array.isArray(legacy.edits) ? [...legacy.edits] : [];\n\tedits.push({ oldText: legacy.oldText, newText: legacy.newText });\n\tconst { oldText: _oldText, newText: _newText, ...rest } = legacy;\n\treturn { ...rest, edits };\n}\n\nexport type EditToolDetails = {\n\tdiff: string;\n\tpatch: string;\n\tfirstChangedLine?: number;\n};\n\nfunction validateEditInput(input: EditToolInput): { path: string; edits: Edit[] } {\n\tif (!Array.isArray(input.edits) || input.edits.length === 0) {\n\t\tthrow new Error(\"Edit tool input is invalid. edits must contain at least one replacement.\");\n\t}\n\treturn { path: input.path, edits: input.edits };\n}\n\nfunction editAccessError(path: string, error: FileError): Error {\n\treturn new Error(`Could not edit file: ${path}. Error code: ${error.code}.`, { cause: error });\n}\n\nexport function createEditTool(): ToolRegistration<typeof editSchema, EditToolDetails> {\n\treturn defineTool({\n\t\tname: \"edit\",\n\t\tdescription:\n\t\t\t\"Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.\",\n\t\tparameters: editSchema,\n\t\tprepareArguments: prepareEditArguments,\n\t\tasync execute(args, api, context) {\n\t\t\tconst { path, edits } = validateEditInput(args);\n\t\t\tconst env = requireEnv(api);\n\t\t\tconst absolutePath = await resolveToolPath(env, path, context);\n\t\t\treturn withFileMutationQueue(\n\t\t\t\tenv,\n\t\t\t\tabsolutePath,\n\t\t\t\tasync () => {\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\t\tconst info = await env.fileInfo(absolutePath, context);\n\t\t\t\t\tif (!info.ok) throw editAccessError(path, info.error);\n\t\t\t\t\tif (info.value.kind !== \"file\" && info.value.kind !== \"symlink\") {\n\t\t\t\t\t\tthrow new Error(`Could not edit file: ${path}. Path is not a file.`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst readResult = await env.readTextFile(absolutePath, context);\n\t\t\t\t\tif (!readResult.ok) throw editAccessError(path, readResult.error);\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\t\tconst { bom, text: content } = stripBom(readResult.value);\n\t\t\t\t\tconst originalEnding = detectLineEnding(content);\n\t\t\t\t\tconst normalizedContent = normalizeToLF(content);\n\t\t\t\t\tconst { baseContent, newContent } = applyEditsToNormalizedContent(normalizedContent, edits, path);\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\t\tconst finalContent = bom + restoreLineEndings(newContent, originalEnding);\n\t\t\t\t\tconst writeResult = await env.writeFile(absolutePath, finalContent, context);\n\t\t\t\t\tif (!writeResult.ok) throw editAccessError(path, writeResult.error);\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\t\tconst diffResult = generateDiffString(baseContent, newContent);\n\t\t\t\t\tconst details: EditToolDetails = {\n\t\t\t\t\t\tdiff: diffResult.diff,\n\t\t\t\t\t\tpatch: generateUnifiedPatch(path, baseContent, newContent),\n\t\t\t\t\t\t...(diffResult.firstChangedLine === undefined\n\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t: { firstChangedLine: diffResult.firstChangedLine }),\n\t\t\t\t\t};\n\t\t\t\t\treturn {\n\t\t\t\t\t\toutput: [{ type: \"text\", text: `Successfully replaced ${edits.length} block(s) in ${path}.` }],\n\t\t\t\t\t\tdetails,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tcontext,\n\t\t\t);\n\t\t},\n\t});\n}\n"]}
@@ -8,39 +8,39 @@ export { createWriteTool, type WriteToolInput } from "./write.ts";
8
8
  * The `coding-tools` extension: `read`, `write`, `edit`, and `bash`; nothing installs it automatically.
9
9
  * `createPowerShellTool()` adds `powershell`. `images` prepares the images `read` returns (see `ReadToolOptions`).
10
10
  */
11
- export declare function createCodingTools(options?: ReadToolOptions): import("../index.ts").Extension<import("../index.ts").ToolRegistration<import("typebox").TObject<{
12
- command: import("typebox").TString;
13
- timeout: import("typebox").TOptional<import("typebox").TNumber>;
14
- }>> | import("../index.ts").ToolRegistration<import("typebox").TObject<{
15
- path: import("typebox").TString;
16
- content: import("typebox").TString;
17
- }>> | import("../index.ts").ToolRegistration<import("typebox").TObject<{
18
- path: import("typebox").TString;
19
- edits: import("typebox").TArray<import("typebox").TObject<{
20
- oldText: import("typebox").TString;
21
- newText: import("typebox").TString;
22
- }>>;
23
- }>, import("./edit.ts").EditToolDetails> | import("../index.ts").ToolRegistration<import("typebox").TObject<{
24
- path: import("typebox").TString;
25
- offset: import("typebox").TOptional<import("typebox").TNumber>;
26
- limit: import("typebox").TOptional<import("typebox").TNumber>;
11
+ export declare function createCodingTools(options?: ReadToolOptions): import("../index.ts").Extension<import("../index.ts").ToolRegistration<import("@earendil-works/pi-schema").Schema<{
12
+ command: string;
13
+ timeout?: number | undefined;
14
+ }>> | import("../index.ts").ToolRegistration<import("@earendil-works/pi-schema").Schema<{
15
+ path: string;
16
+ content: string;
17
+ }>> | import("../index.ts").ToolRegistration<import("@earendil-works/pi-schema").Schema<{
18
+ path: string;
19
+ edits: {
20
+ oldText: string;
21
+ newText: string;
22
+ }[];
23
+ }>, import("./edit.ts").EditToolDetails> | import("../index.ts").ToolRegistration<import("@earendil-works/pi-schema").Schema<{
24
+ path: string;
25
+ offset?: number | undefined;
26
+ limit?: number | undefined;
27
27
  }>, import("./read.ts").ReadToolDetails>>;
28
28
  /** `createCodingTools()` without an image processor. */
29
- export declare const CodingTools: import("../index.ts").Extension<import("../index.ts").ToolRegistration<import("typebox").TObject<{
30
- command: import("typebox").TString;
31
- timeout: import("typebox").TOptional<import("typebox").TNumber>;
32
- }>> | import("../index.ts").ToolRegistration<import("typebox").TObject<{
33
- path: import("typebox").TString;
34
- content: import("typebox").TString;
35
- }>> | import("../index.ts").ToolRegistration<import("typebox").TObject<{
36
- path: import("typebox").TString;
37
- edits: import("typebox").TArray<import("typebox").TObject<{
38
- oldText: import("typebox").TString;
39
- newText: import("typebox").TString;
40
- }>>;
41
- }>, import("./edit.ts").EditToolDetails> | import("../index.ts").ToolRegistration<import("typebox").TObject<{
42
- path: import("typebox").TString;
43
- offset: import("typebox").TOptional<import("typebox").TNumber>;
44
- limit: import("typebox").TOptional<import("typebox").TNumber>;
29
+ export declare const CodingTools: import("../index.ts").Extension<import("../index.ts").ToolRegistration<import("@earendil-works/pi-schema").Schema<{
30
+ command: string;
31
+ timeout?: number | undefined;
32
+ }>> | import("../index.ts").ToolRegistration<import("@earendil-works/pi-schema").Schema<{
33
+ path: string;
34
+ content: string;
35
+ }>> | import("../index.ts").ToolRegistration<import("@earendil-works/pi-schema").Schema<{
36
+ path: string;
37
+ edits: {
38
+ oldText: string;
39
+ newText: string;
40
+ }[];
41
+ }>, import("./edit.ts").EditToolDetails> | import("../index.ts").ToolRegistration<import("@earendil-works/pi-schema").Schema<{
42
+ path: string;
43
+ offset?: number | undefined;
44
+ limit?: number | undefined;
45
45
  }>, import("./read.ts").ReadToolDetails>>;
46
46
  //# sourceMappingURL=index.d.ts.map
@@ -1,11 +1,11 @@
1
- import { type Static, Type } from "typebox";
1
+ import { type Static } from "@earendil-works/pi-schema";
2
2
  import type { ToolRegistration } from "../harness/types.ts";
3
3
  import { type TruncationResult } from "../truncate.ts";
4
4
  import { type ImageProcessor } from "./image-processor.ts";
5
- declare const readSchema: Type.TObject<{
6
- path: Type.TString;
7
- offset: Type.TOptional<Type.TNumber>;
8
- limit: Type.TOptional<Type.TNumber>;
5
+ declare const readSchema: import("@earendil-works/pi-schema").Schema<{
6
+ path: string;
7
+ offset?: number | undefined;
8
+ limit?: number | undefined;
9
9
  }>;
10
10
  export type ReadToolInput = Static<typeof readSchema>;
11
11
  export type ReadToolDetails = {
@@ -18,7 +18,7 @@ export type ReadToolOptions = {
18
18
  };
19
19
  /**
20
20
  * Reads text files and images. Remarks about truncation, continuation, and image processing are diagnostics; the content
21
- * is only file text, or one image, which programs get as its `ImageContent`.
21
+ * is only file text, or one image. Programs get the text, or the image's `ImageContent`.
22
22
  */
23
23
  export declare function createReadTool(options?: ReadToolOptions): ToolRegistration<typeof readSchema, ReadToolDetails>;
24
24
  export {};