salmon-loop 0.2.3 → 0.2.16

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 (234) hide show
  1. package/dist/cli/argv/headless-detection.js +27 -0
  2. package/dist/cli/chat-flow.js +11 -0
  3. package/dist/cli/chat.js +161 -24
  4. package/dist/cli/commands/chat.js +30 -24
  5. package/dist/cli/commands/context.js +15 -3
  6. package/dist/cli/commands/flow-mode.js +63 -0
  7. package/dist/cli/commands/help-format.js +12 -0
  8. package/dist/cli/commands/registry.js +6 -7
  9. package/dist/cli/commands/run/benchmark-artifacts.js +41 -0
  10. package/dist/cli/commands/run/config-resolution.js +30 -24
  11. package/dist/cli/commands/run/early-errors.js +23 -0
  12. package/dist/cli/commands/run/handler.js +131 -44
  13. package/dist/cli/commands/run/headless-error-writer.js +8 -0
  14. package/dist/cli/commands/run/loop-params.js +3 -0
  15. package/dist/cli/commands/run/mode.js +2 -5
  16. package/dist/cli/commands/run/parse-options.js +18 -2
  17. package/dist/cli/commands/run/persist-session.js +10 -1
  18. package/dist/cli/commands/run/preflight.js +10 -0
  19. package/dist/cli/commands/run/reporter-factory.js +4 -0
  20. package/dist/cli/commands/run/runtime-llm.js +38 -11
  21. package/dist/cli/commands/run/runtime-options.js +2 -2
  22. package/dist/cli/commands/run/validate-options.js +0 -5
  23. package/dist/cli/commands/run/verbose.js +2 -7
  24. package/dist/cli/commands/serve.js +117 -90
  25. package/dist/cli/commands/tool-names.js +78 -78
  26. package/dist/cli/headless/anthropic-stream-normalized-encoder.js +6 -1
  27. package/dist/cli/headless/json-protocol.js +37 -0
  28. package/dist/cli/headless/native-stream-normalized-encoder.js +6 -1
  29. package/dist/cli/headless/protocol-metadata.js +22 -0
  30. package/dist/cli/headless/stream-json-protocol.js +34 -1
  31. package/dist/cli/index.js +6 -4
  32. package/dist/cli/locales/en.js +32 -6
  33. package/dist/cli/program-bootstrap.js +14 -4
  34. package/dist/cli/program-commands.js +9 -1
  35. package/dist/cli/program-options.js +1 -0
  36. package/dist/cli/reporters/anthropic-stream.js +7 -1
  37. package/dist/cli/reporters/json.js +4 -0
  38. package/dist/cli/reporters/stream-json.js +17 -2
  39. package/dist/cli/run-cli.js +5 -3
  40. package/dist/cli/slash/runtime.js +30 -15
  41. package/dist/cli/ui/components/CommandInput.js +7 -3
  42. package/dist/cli/ui/components/CommandSuggestionList.js +1 -1
  43. package/dist/cli/utils/command-option-source.js +13 -0
  44. package/dist/cli/utils/output-format.js +6 -0
  45. package/dist/cli/utils/resolve-cli-config.js +98 -0
  46. package/dist/cli/utils/verbose-level.js +8 -0
  47. package/dist/cli/utils/verify-resolver.js +8 -4
  48. package/dist/cli/utils/worktree-prepare-resolver.js +7 -3
  49. package/dist/core/adapters/fs/file-adapter.js +6 -0
  50. package/dist/core/adapters/fs/filesystem.js +2 -1
  51. package/dist/core/adapters/git/git-adapter.js +78 -1
  52. package/dist/core/benchmark/patch-artifact.js +124 -0
  53. package/dist/core/benchmark/swe-bench.js +25 -0
  54. package/dist/core/config/load.js +39 -18
  55. package/dist/core/config/merge.js +27 -0
  56. package/dist/core/config/paths.js +24 -5
  57. package/dist/core/config/resolve-llm.js +12 -0
  58. package/dist/core/config/resolve.js +7 -5
  59. package/dist/core/config/resolvers/server.js +0 -6
  60. package/dist/core/config/validate.js +94 -21
  61. package/dist/core/context/gatherers/metadata-gatherer.js +1 -0
  62. package/dist/core/context/gatherers/ripgrep-gatherer.js +84 -2
  63. package/dist/core/context/keywords.js +18 -4
  64. package/dist/core/context/service-deps.js +2 -2
  65. package/dist/core/context/service.js +8 -0
  66. package/dist/core/context/steps/context-gather.js +38 -0
  67. package/dist/core/context/summarization/summarizer.js +55 -12
  68. package/dist/core/context/targeting/target-resolver.js +4 -4
  69. package/dist/core/extensions/index.js +23 -5
  70. package/dist/core/extensions/paths.js +31 -0
  71. package/dist/core/extensions/schemas.js +8 -5
  72. package/dist/core/facades/cli-chat.js +6 -2
  73. package/dist/core/facades/cli-command-chat.js +2 -1
  74. package/dist/core/facades/cli-command-tool-names.js +2 -0
  75. package/dist/core/facades/cli-context.js +1 -0
  76. package/dist/core/facades/cli-observability.js +1 -1
  77. package/dist/core/facades/cli-run-handler.js +4 -2
  78. package/dist/core/facades/cli-run-persist-session.js +1 -0
  79. package/dist/core/facades/cli-serve.js +2 -4
  80. package/dist/core/facades/cli-utils-worktree.js +1 -1
  81. package/dist/core/failure/diagnostics.js +53 -1
  82. package/dist/core/grizzco/dsl/llm-strategy.js +4 -1
  83. package/dist/core/grizzco/engine/outcome/loop-result-mapper.js +67 -9
  84. package/dist/core/grizzco/engine/pipeline/pipeline.js +6 -2
  85. package/dist/core/grizzco/engine/transaction/attempt-failure.js +90 -15
  86. package/dist/core/grizzco/engine/transaction/report-mapper.js +17 -3
  87. package/dist/core/grizzco/engine/transaction/transaction-runner.js +173 -7
  88. package/dist/core/grizzco/flows/AutopilotFlow.js +18 -0
  89. package/dist/core/grizzco/flows/flow-dispatch.js +11 -0
  90. package/dist/core/grizzco/steps/answer.js +13 -14
  91. package/dist/core/grizzco/steps/autopilot.js +396 -0
  92. package/dist/core/grizzco/steps/cache-sharing.js +29 -0
  93. package/dist/core/grizzco/steps/explore.js +37 -21
  94. package/dist/core/grizzco/steps/generateReview.js +2 -5
  95. package/dist/core/grizzco/steps/patch/apply-check.js +10 -0
  96. package/dist/core/grizzco/steps/patch/diff-normalization.js +70 -0
  97. package/dist/core/grizzco/steps/patch/diff-salvage.js +46 -0
  98. package/dist/core/grizzco/steps/patch/prompt-input.js +42 -0
  99. package/dist/core/grizzco/steps/patch.js +105 -146
  100. package/dist/core/grizzco/steps/plan.js +101 -25
  101. package/dist/core/grizzco/steps/preflight.js +5 -3
  102. package/dist/core/grizzco/steps/request-assembly.js +78 -0
  103. package/dist/core/grizzco/steps/research.js +39 -36
  104. package/dist/core/grizzco/steps/tool-runtime.js +47 -0
  105. package/dist/core/grizzco/steps/verify-shared.js +23 -0
  106. package/dist/core/grizzco/steps/verify.js +13 -21
  107. package/dist/core/intent/chat-intent.js +0 -4
  108. package/dist/core/llm/ai-sdk/chat-executor.js +2 -0
  109. package/dist/core/llm/ai-sdk/high-level-phase-specs.js +63 -0
  110. package/dist/core/llm/ai-sdk/message-mapper.js +40 -10
  111. package/dist/core/llm/ai-sdk/provider-factory.js +14 -0
  112. package/dist/core/llm/ai-sdk/request-params.js +74 -1
  113. package/dist/core/llm/ai-sdk/result-mapper.js +16 -0
  114. package/dist/core/llm/ai-sdk.js +112 -27
  115. package/dist/core/llm/capabilities.js +12 -0
  116. package/dist/core/llm/contracts/repair.js +36 -30
  117. package/dist/core/llm/errors.js +83 -2
  118. package/dist/core/llm/message-composition.js +7 -22
  119. package/dist/core/llm/phase-router.js +29 -10
  120. package/dist/core/llm/redact.js +28 -3
  121. package/dist/core/llm/registry.js +2 -0
  122. package/dist/core/llm/request-augmentation.js +55 -0
  123. package/dist/core/llm/request-envelope.js +334 -0
  124. package/dist/core/llm/shared-request-assembly.js +35 -0
  125. package/dist/core/llm/stream-utils.js +13 -4
  126. package/dist/core/llm/utils.js +18 -29
  127. package/dist/core/memory/relevant-retrieval.js +144 -0
  128. package/dist/core/observability/logger.js +11 -2
  129. package/dist/core/patch/diff.js +1 -0
  130. package/dist/core/prompts/registry.js +39 -2
  131. package/dist/core/prompts/runtime.js +50 -12
  132. package/dist/core/prompts/templates/phases/patch_user.hbs +2 -5
  133. package/dist/core/prompts/templates/phases/research_user.hbs +11 -0
  134. package/dist/core/prompts/templates/phases/review_user.hbs +3 -0
  135. package/dist/core/prompts/templates/system/answer_system.hbs +5 -0
  136. package/dist/core/prompts/templates/system/autopilot_system.hbs +11 -0
  137. package/dist/core/prompts/templates/system/explore_system.hbs +14 -23
  138. package/dist/core/prompts/templates/system/main_system.hbs +4 -16
  139. package/dist/core/prompts/templates/system/patch_system.hbs +39 -8
  140. package/dist/core/prompts/templates/system/plan_system.hbs +86 -1
  141. package/dist/core/prompts/templates/system/research_system.hbs +2 -0
  142. package/dist/core/protocols/a2a/agent-card.js +3 -2
  143. package/dist/core/protocols/a2a/sdk/executor.js +8 -6
  144. package/dist/core/protocols/a2a/sdk/server.js +0 -1
  145. package/dist/core/protocols/acp/formal-agent.js +221 -55
  146. package/dist/core/protocols/acp/handlers.js +5 -1
  147. package/dist/core/protocols/acp/permission-provider.js +21 -1
  148. package/dist/core/protocols/shared/execution-request.js +24 -0
  149. package/dist/core/protocols/shared/flow-mode-mapping.js +23 -0
  150. package/dist/core/public-capabilities/flow-mode-metadata.js +39 -0
  151. package/dist/core/public-capabilities/projections.js +29 -0
  152. package/dist/core/public-capabilities/registry.js +26 -0
  153. package/dist/core/public-capabilities/types.js +2 -0
  154. package/dist/core/runtime/agent-server-runtime.js +47 -43
  155. package/dist/core/runtime/execution-profile.js +67 -0
  156. package/dist/core/session/artifact-state.js +160 -0
  157. package/dist/core/session/compaction/index.js +183 -0
  158. package/dist/core/session/compaction/microcompact.js +78 -0
  159. package/dist/core/session/compaction/tracking.js +48 -0
  160. package/dist/core/session/compaction/types.js +11 -0
  161. package/dist/core/session/compression.js +12 -4
  162. package/dist/core/session/manager.js +247 -10
  163. package/dist/core/session/pruning-strategy.js +55 -9
  164. package/dist/core/session/replacement-preview-provider.js +24 -0
  165. package/dist/core/session/replacement-state.js +131 -0
  166. package/dist/core/session/resume-repair/pipeline.js +79 -0
  167. package/dist/core/session/resume-repair/stages/load-raw-archive-state.js +40 -0
  168. package/dist/core/session/resume-repair/stages/reattach-runtime-state.js +8 -0
  169. package/dist/core/session/resume-repair/stages/recover-orphaned-branches.js +10 -0
  170. package/dist/core/session/resume-repair/stages/relink-boundary-and-tail.js +36 -0
  171. package/dist/core/session/resume-repair/stages/replay-startup-hooks.js +23 -0
  172. package/dist/core/session/resume-repair/stages/rescue-stale-metadata.js +17 -0
  173. package/dist/core/session/resume-repair/types.js +2 -0
  174. package/dist/core/session/summary-sync.js +164 -13
  175. package/dist/core/session/token-tracker.js +6 -0
  176. package/dist/core/skills/audit.js +34 -0
  177. package/dist/core/skills/bridge.js +84 -7
  178. package/dist/core/skills/discovery.js +94 -0
  179. package/dist/core/skills/feature-flags.js +52 -0
  180. package/dist/core/skills/index.js +1 -1
  181. package/dist/core/skills/loader.js +195 -20
  182. package/dist/core/skills/parser.js +296 -24
  183. package/dist/core/skills/permissions.js +117 -0
  184. package/dist/core/skills/runtime/MicroTaskRunner.js +10 -4
  185. package/dist/core/skills/runtime/SkillRunner.js +240 -61
  186. package/dist/core/strata/layers/shadow-driver/shadow-driver.js +37 -7
  187. package/dist/core/strata/layers/worktree.js +70 -13
  188. package/dist/core/strata/runtime/synchronizer.js +29 -2
  189. package/dist/core/streaming/stream-assembler.js +75 -31
  190. package/dist/core/sub-agent/context-snapshot.js +156 -0
  191. package/dist/core/sub-agent/core/loop.js +1 -1
  192. package/dist/core/sub-agent/core/manager.js +119 -20
  193. package/dist/core/sub-agent/dispatch-policy.js +29 -0
  194. package/dist/core/sub-agent/prefix-consistency.js +48 -0
  195. package/dist/core/sub-agent/registry-defaults.js +4 -0
  196. package/dist/core/sub-agent/tools/task-spawn.js +79 -2
  197. package/dist/core/sub-agent/types.js +134 -5
  198. package/dist/core/tools/audit.js +13 -4
  199. package/dist/core/tools/builtin/ast-grep.js +1 -1
  200. package/dist/core/tools/builtin/ast.js +1 -1
  201. package/dist/core/tools/builtin/benchmark.js +360 -0
  202. package/dist/core/tools/builtin/code-search/backends/rg.js +2 -1
  203. package/dist/core/tools/builtin/code-search/executor.js +6 -1
  204. package/dist/core/tools/builtin/code-search/spec.js +26 -2
  205. package/dist/core/tools/builtin/fs.js +256 -23
  206. package/dist/core/tools/builtin/git.js +2 -2
  207. package/dist/core/tools/builtin/index.js +51 -2
  208. package/dist/core/tools/builtin/interaction.js +8 -1
  209. package/dist/core/tools/builtin/plan.js +37 -15
  210. package/dist/core/tools/builtin/shell.js +1 -1
  211. package/dist/core/tools/loader.js +39 -16
  212. package/dist/core/tools/mapper.js +17 -3
  213. package/dist/core/tools/parallel/scheduler.js +35 -4
  214. package/dist/core/tools/permissions/permission-rules.js +5 -10
  215. package/dist/core/tools/policy.js +6 -1
  216. package/dist/core/tools/recoverable-tool-errors.js +10 -0
  217. package/dist/core/tools/router.js +24 -6
  218. package/dist/core/tools/session.js +458 -48
  219. package/dist/core/tools/tool-visibility.js +62 -0
  220. package/dist/core/tools/types.js +9 -1
  221. package/dist/core/types/execution.js +4 -0
  222. package/dist/core/types/flow-mode.js +8 -0
  223. package/dist/core/utils/path.js +52 -0
  224. package/dist/core/verification/runner.js +4 -1
  225. package/dist/interfaces/cli/task-runner.js +4 -3
  226. package/dist/languages/typescript/index.js +4 -1
  227. package/dist/locales/en.js +87 -2
  228. package/dist/utils/eol.js +1 -1
  229. package/package.json +15 -8
  230. package/scripts/fix-es-abstract-compat.js +77 -0
  231. package/dist/core/runtime/fastify-server-bundle.js +0 -26
  232. package/dist/core/runtime/sidecar-fastify-plugin.js +0 -35
  233. package/dist/core/runtime/sidecar-paths.js +0 -47
  234. package/dist/core/runtime/sidecar-route-catalog.js +0 -103
@@ -1,8 +1,12 @@
1
+ import { createHash } from 'crypto';
2
+ import { Buffer } from 'node:buffer';
1
3
  import { isAbsolute, relative, resolve } from 'path';
2
4
  import { z } from 'zod';
3
5
  import { text } from '../../../locales/index.js';
4
- import { readFile, readdir, stat } from '../../adapters/fs/node-fs.js';
6
+ import { AtomicFileWriter } from '../../adapters/fs/atomic-file-writer.js';
7
+ import { mkdir, readFile, readdir, stat } from '../../adapters/fs/node-fs.js';
5
8
  import { Phase } from '../../types/runtime.js';
9
+ import { normalizeRepoRelativePath } from '../../utils/path.js';
6
10
  import { pathPrefixResource } from '../parallel/resource-helpers.js';
7
11
  const FsListEntryType = z.enum(['file', 'dir', 'symlink', 'other']);
8
12
  const fsListInputSchema = z.preprocess((raw) => {
@@ -94,6 +98,7 @@ export const fsReadFileSpec = {
94
98
  Phase.CONTEXT,
95
99
  Phase.EXPLORE,
96
100
  Phase.PLAN,
101
+ Phase.AUTOPILOT,
97
102
  Phase.PATCH,
98
103
  Phase.VERIFY,
99
104
  Phase.SHRINK,
@@ -154,11 +159,28 @@ export const fsListSpec = {
154
159
  Phase.CONTEXT,
155
160
  Phase.EXPLORE,
156
161
  Phase.PLAN,
162
+ Phase.AUTOPILOT,
157
163
  Phase.PATCH,
158
164
  Phase.VERIFY,
159
165
  Phase.SHRINK,
160
166
  ],
161
167
  };
168
+ /**
169
+ * Spec for the fs.list_directory tool.
170
+ */
171
+ export const fsListDirectorySpec = {
172
+ ...fsListSpec,
173
+ name: 'fs.list_directory',
174
+ description: text.tools.fsListDirectoryDescription,
175
+ };
176
+ /**
177
+ * Spec for the fs.list_files tool.
178
+ */
179
+ export const fsListFilesSpec = {
180
+ ...fsListSpec,
181
+ name: 'fs.list_files',
182
+ description: text.tools.fsListFilesDescription,
183
+ };
162
184
  function toRepoRelativeChildPath(dir, name) {
163
185
  const normalizedDir = String(dir || '.')
164
186
  .replace(/\\/g, '/')
@@ -166,23 +188,49 @@ function toRepoRelativeChildPath(dir, name) {
166
188
  const base = normalizedDir === '.' ? '' : normalizedDir.replace(/^\.\/+/, '').replace(/\/+$/, '');
167
189
  return base ? `${base}/${name}` : name;
168
190
  }
191
+ function assertNotReservedRepoPrefix(relPath) {
192
+ const normalized = normalizeRepoRelativePath(relPath);
193
+ if (normalized === '.git' || normalized.startsWith('.git/')) {
194
+ throw new Error(text.errors.reservedPathPrefix('.git/'));
195
+ }
196
+ if (normalized === '.salmonloop' || normalized.startsWith('.salmonloop/')) {
197
+ throw new Error(text.errors.reservedPathPrefix('.salmonloop/'));
198
+ }
199
+ }
200
+ function resolveRepoRelativePath(repoRoot, relPath) {
201
+ if (isAbsolute(relPath)) {
202
+ throw new Error(text.errors.pathOutsideRepo);
203
+ }
204
+ assertNotReservedRepoPrefix(relPath);
205
+ const absoluteRoot = resolve(repoRoot);
206
+ const absolutePath = resolve(absoluteRoot, relPath);
207
+ const computedRelPath = relative(absoluteRoot, absolutePath);
208
+ if (computedRelPath.startsWith('..') || isAbsolute(computedRelPath)) {
209
+ throw new Error(text.errors.pathOutsideRepo);
210
+ }
211
+ return { absolutePath };
212
+ }
213
+ function shouldIncludeListedEntry(dir, entryName, includeHidden) {
214
+ if (!includeHidden && entryName.startsWith('.'))
215
+ return false;
216
+ const childPath = toRepoRelativeChildPath(dir, entryName);
217
+ try {
218
+ assertNotReservedRepoPrefix(childPath);
219
+ return true;
220
+ }
221
+ catch {
222
+ return false;
223
+ }
224
+ }
169
225
  /**
170
226
  * Implementation of the fs.list tool.
171
227
  */
172
228
  export async function executeFsList(input, ctx) {
173
229
  const { path: dir, includeHidden, maxEntries } = input;
174
- if (isAbsolute(dir)) {
175
- throw new Error('Access denied: Path is outside of repository root.');
176
- }
177
- const absoluteRoot = resolve(ctx.repoRoot);
178
- const absolutePath = resolve(absoluteRoot, dir);
179
- const relPath = relative(absoluteRoot, absolutePath);
180
- if (relPath.startsWith('..') || isAbsolute(relPath)) {
181
- throw new Error('Access denied: Path is outside of repository root.');
182
- }
230
+ const { absolutePath } = resolveRepoRelativePath(ctx.repoRoot, dir);
183
231
  try {
184
232
  const dirents = await readdir(absolutePath, { withFileTypes: true });
185
- const visible = includeHidden ? dirents : dirents.filter((d) => !d.name.startsWith('.'));
233
+ const visible = dirents.filter((d) => shouldIncludeListedEntry(dir, d.name, includeHidden));
186
234
  const entries = visible
187
235
  .map((d) => {
188
236
  const type = d.isDirectory()
@@ -211,23 +259,208 @@ export async function executeFsList(input, ctx) {
211
259
  throw new Error(`Failed to list directory ${dir}: ${e instanceof Error ? e.message : String(e)}`);
212
260
  }
213
261
  }
262
+ /**
263
+ * Implementation of the fs.list_directory tool.
264
+ */
265
+ export async function executeFsListDirectory(input, ctx) {
266
+ return executeFsList(input, ctx);
267
+ }
268
+ /**
269
+ * Implementation of the fs.list_files tool.
270
+ */
271
+ export async function executeFsListFiles(input, ctx) {
272
+ const { path: dir, includeHidden, maxEntries } = input;
273
+ const { absolutePath } = resolveRepoRelativePath(ctx.repoRoot, dir);
274
+ try {
275
+ const dirents = await readdir(absolutePath, { withFileTypes: true });
276
+ const visible = dirents.filter((d) => shouldIncludeListedEntry(dir, d.name, includeHidden));
277
+ const fileEntries = visible
278
+ .filter((d) => d.isFile())
279
+ .map((d) => ({
280
+ name: d.name,
281
+ path: toRepoRelativeChildPath(dir, d.name),
282
+ type: 'file',
283
+ }))
284
+ .sort((a, b) => a.path.localeCompare(b.path));
285
+ const totalEntries = fileEntries.length;
286
+ const sliced = fileEntries.slice(0, maxEntries);
287
+ return {
288
+ entries: sliced,
289
+ truncated: sliced.length < totalEntries,
290
+ totalEntries,
291
+ };
292
+ }
293
+ catch (e) {
294
+ throw new Error(`Failed to list files in directory ${dir}: ${e instanceof Error ? e.message : String(e)}`);
295
+ }
296
+ }
297
+ const fsWriteFileInputSchema = z.preprocess((raw) => {
298
+ if (typeof raw === 'string') {
299
+ return { file: raw };
300
+ }
301
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
302
+ return raw;
303
+ const input = raw;
304
+ if (typeof input.file === 'string')
305
+ return input;
306
+ const alias = input.path ?? input.file_path ?? input.filePath;
307
+ if (typeof alias !== 'string')
308
+ return input;
309
+ return {
310
+ ...input,
311
+ file: alias,
312
+ };
313
+ }, z.object({
314
+ file: z.string().describe('Relative path to the file from the repository root'),
315
+ content: z.string().describe('UTF-8 text content to write'),
316
+ encoding: z
317
+ .enum(['utf-8'])
318
+ .optional()
319
+ .describe('Text encoding (only utf-8 is supported; default: utf-8)'),
320
+ }));
321
+ /**
322
+ * Spec for the fs.write_file tool.
323
+ */
324
+ export const fsWriteFileSpec = {
325
+ name: 'fs.write_file',
326
+ source: 'builtin',
327
+ intent: 'WRITE',
328
+ description: text.tools.fsWriteFileDescription,
329
+ riskLevel: 'high',
330
+ sideEffects: ['fs_write'],
331
+ concurrency: 'serial_only',
332
+ computeResources: (input, ctx) => [pathPrefixResource(ctx, input.file)],
333
+ allowedPhases: [Phase.SLASH, Phase.AUTOPILOT],
334
+ inputSchema: fsWriteFileInputSchema,
335
+ outputSchema: z.object({
336
+ ok: z.boolean(),
337
+ path: z.string(),
338
+ bytesWritten: z.number().int().nonnegative(),
339
+ }),
340
+ summarizeArgsForAuthorization: async (args) => {
341
+ const encoding = args?.encoding || 'utf-8';
342
+ const content = String(args?.content ?? '');
343
+ const bytes = Buffer.byteLength(content, 'utf8');
344
+ const sha256 = createHash('sha256').update(content, 'utf8').digest('hex');
345
+ return JSON.stringify({
346
+ file: args?.file,
347
+ encoding,
348
+ bytes,
349
+ sha256,
350
+ });
351
+ },
352
+ };
353
+ export async function executeFsWriteFile(input, ctx) {
354
+ if (ctx.dryRun) {
355
+ return { ok: true, path: input.file, bytesWritten: 0 };
356
+ }
357
+ const { absolutePath } = resolveRepoRelativePath(ctx.repoRoot, input.file);
358
+ const writer = new AtomicFileWriter();
359
+ const contentBytes = Buffer.from(input.content, 'utf8');
360
+ await writer.writeAtomic(absolutePath, contentBytes);
361
+ return {
362
+ ok: true,
363
+ path: input.file,
364
+ bytesWritten: contentBytes.length,
365
+ };
366
+ }
367
+ const fsCreateDirectoryInputSchema = z.preprocess((raw) => {
368
+ if (typeof raw === 'string')
369
+ return { path: raw };
370
+ return raw;
371
+ }, z.object({
372
+ path: z.string().describe('Relative directory path to create from the repository root'),
373
+ recursive: z.boolean().default(true).describe('Whether to create parent directories'),
374
+ }));
375
+ /**
376
+ * Spec for the fs.create_directory tool.
377
+ */
378
+ export const fsCreateDirectorySpec = {
379
+ name: 'fs.create_directory',
380
+ source: 'builtin',
381
+ intent: 'WRITE',
382
+ description: text.tools.fsCreateDirectoryDescription,
383
+ riskLevel: 'high',
384
+ sideEffects: ['fs_write'],
385
+ concurrency: 'serial_only',
386
+ computeResources: (input, ctx) => [pathPrefixResource(ctx, input.path)],
387
+ allowedPhases: [Phase.SLASH, Phase.AUTOPILOT],
388
+ inputSchema: fsCreateDirectoryInputSchema,
389
+ outputSchema: z.object({
390
+ ok: z.boolean(),
391
+ path: z.string(),
392
+ }),
393
+ summarizeArgsForAuthorization: async (args) => JSON.stringify({ path: args?.path, recursive: args?.recursive }),
394
+ };
395
+ export async function executeFsCreateDirectory(input, ctx) {
396
+ if (ctx.dryRun) {
397
+ return { ok: true, path: input.path };
398
+ }
399
+ const { absolutePath } = resolveRepoRelativePath(ctx.repoRoot, input.path);
400
+ await mkdir(absolutePath, { recursive: input.recursive });
401
+ return { ok: true, path: input.path };
402
+ }
403
+ const fsDeleteFileInputSchema = z.preprocess((raw) => {
404
+ if (typeof raw === 'string')
405
+ return { file: raw };
406
+ return raw;
407
+ }, z.object({
408
+ file: z.string().describe('Relative path to the file from the repository root'),
409
+ missingOk: z.boolean().default(true).describe('Whether missing files are treated as success'),
410
+ }));
411
+ /**
412
+ * Spec for the fs.delete_file tool.
413
+ */
414
+ export const fsDeleteFileSpec = {
415
+ name: 'fs.delete_file',
416
+ source: 'builtin',
417
+ intent: 'WRITE',
418
+ description: text.tools.fsDeleteFileDescription,
419
+ riskLevel: 'high',
420
+ sideEffects: ['fs_write'],
421
+ concurrency: 'serial_only',
422
+ computeResources: (input, ctx) => [pathPrefixResource(ctx, input.file)],
423
+ allowedPhases: [Phase.SLASH, Phase.AUTOPILOT],
424
+ inputSchema: fsDeleteFileInputSchema,
425
+ outputSchema: z.object({
426
+ ok: z.boolean(),
427
+ path: z.string(),
428
+ deleted: z.boolean(),
429
+ }),
430
+ summarizeArgsForAuthorization: async (args) => JSON.stringify({ file: args?.file, missingOk: args?.missingOk }),
431
+ };
432
+ export async function executeFsDeleteFile(input, ctx) {
433
+ if (ctx.dryRun) {
434
+ return { ok: true, path: input.file, deleted: false };
435
+ }
436
+ const { absolutePath } = resolveRepoRelativePath(ctx.repoRoot, input.file);
437
+ let exists = true;
438
+ try {
439
+ await stat(absolutePath);
440
+ }
441
+ catch (e) {
442
+ const code = e && typeof e === 'object' && 'code' in e ? e.code : undefined;
443
+ if (code === 'ENOENT')
444
+ exists = false;
445
+ else
446
+ throw e;
447
+ }
448
+ if (!exists) {
449
+ if (input.missingOk) {
450
+ return { ok: true, path: input.file, deleted: false };
451
+ }
452
+ throw new Error(text.errors.pathNotFound(input.file));
453
+ }
454
+ const writer = new AtomicFileWriter();
455
+ await writer.deleteAtomic(absolutePath);
456
+ return { ok: true, path: input.file, deleted: true };
457
+ }
214
458
  /**
215
459
  * Implementation of the fs.read tool.
216
460
  */
217
461
  export async function executeFsReadFile(input, ctx) {
218
462
  const { file } = input;
219
- if (isAbsolute(file)) {
220
- throw new Error('Access denied: Path is outside of repository root.');
221
- }
222
- // CRITICAL SAFETY: Path traversal check using relative path resolution
223
- // We resolve to absolute paths to handle '.' and '..' correctly
224
- const absoluteRoot = resolve(ctx.repoRoot);
225
- // use resolve instead of join to handle absolute paths in input correctly
226
- const absolutePath = resolve(absoluteRoot, file);
227
- const relPath = relative(absoluteRoot, absolutePath);
228
- if (relPath.startsWith('..') || isAbsolute(relPath)) {
229
- throw new Error('Access denied: Path is outside of repository root.');
230
- }
463
+ const { absolutePath } = resolveRepoRelativePath(ctx.repoRoot, file);
231
464
  try {
232
465
  const fileStat = await stat(absolutePath);
233
466
  const content = await readFile(absolutePath, 'utf-8');
@@ -22,7 +22,7 @@ export const gitCatSpec = {
22
22
  file: z.string(),
23
23
  ref: z.string(),
24
24
  }),
25
- allowedPhases: [Phase.SLASH, Phase.CONTEXT],
25
+ allowedPhases: [Phase.SLASH, Phase.CONTEXT, Phase.AUTOPILOT],
26
26
  examples: [
27
27
  {
28
28
  description: 'Read a file from HEAD revision',
@@ -86,7 +86,7 @@ export const gitStatusSpec = {
86
86
  outputSchema: z.object({
87
87
  status: z.string(),
88
88
  }),
89
- allowedPhases: [Phase.SLASH, Phase.CONTEXT, Phase.PLAN, Phase.VERIFY],
89
+ allowedPhases: [Phase.SLASH, Phase.CONTEXT, Phase.PLAN, Phase.AUTOPILOT, Phase.VERIFY],
90
90
  };
91
91
  /**
92
92
  * Builtin tool to check git status
@@ -2,9 +2,10 @@ import { subAgentTaskSpec } from '../../sub-agent/tools/task-spawn.js';
2
2
  import { artifactReadSpec, executeArtifactRead } from './artifact.js';
3
3
  import { astGrepSpec, executeAstGrep } from './ast-grep.js';
4
4
  import { astDefsRefsSpec, executeAstDefsRefs } from './ast.js';
5
+ import { benchmarkReportSpec, executeBenchmarkReport, executeGitApplyCheck, executeGitDiffCheck, executeSweBenchGetReport, executeSweBenchLoadInstance, executeSweBenchSubmitPredictions, executeSweBenchWritePrediction, gitApplyCheckSpec, gitDiffCheckSpec, sweBenchGetReportSpec, sweBenchLoadInstanceSpec, sweBenchSubmitPredictionsSpec, sweBenchWritePredictionSpec, } from './benchmark.js';
5
6
  import { codeSearchExecutor } from './code-search/executor.js';
6
7
  import { CodeSearchSpec } from './code-search/spec.js';
7
- import { codeReadSpec, executeFsList, executeFsReadFile, fsListSpec, fsReadFileSpec, } from './fs.js';
8
+ import { codeReadSpec, executeFsCreateDirectory, executeFsList, executeFsListDirectory, executeFsListFiles, executeFsReadFile, executeFsDeleteFile, executeFsWriteFile, fsCreateDirectorySpec, fsDeleteFileSpec, fsListSpec, fsListDirectorySpec, fsListFilesSpec, fsReadFileSpec, fsWriteFileSpec, } from './fs.js';
8
9
  import { gitCatSpec, executeGitCat, gitStatusSpec, executeGitStatus } from './git.js';
9
10
  import { askUserSpec } from './interaction.js';
10
11
  import { updateKnowledgeSpec, executeUpdateKnowledge } from './knowledge.js';
@@ -47,6 +48,34 @@ export function registerAllBuiltins(registry) {
47
48
  ...gitStatusSpec,
48
49
  executor: executeGitStatus,
49
50
  });
51
+ registry.register({
52
+ ...gitDiffCheckSpec,
53
+ executor: executeGitDiffCheck,
54
+ });
55
+ registry.register({
56
+ ...gitApplyCheckSpec,
57
+ executor: executeGitApplyCheck,
58
+ });
59
+ registry.register({
60
+ ...benchmarkReportSpec,
61
+ executor: executeBenchmarkReport,
62
+ });
63
+ registry.register({
64
+ ...sweBenchLoadInstanceSpec,
65
+ executor: executeSweBenchLoadInstance,
66
+ });
67
+ registry.register({
68
+ ...sweBenchWritePredictionSpec,
69
+ executor: executeSweBenchWritePrediction,
70
+ });
71
+ registry.register({
72
+ ...sweBenchSubmitPredictionsSpec,
73
+ executor: executeSweBenchSubmitPredictions,
74
+ });
75
+ registry.register({
76
+ ...sweBenchGetReportSpec,
77
+ executor: executeSweBenchGetReport,
78
+ });
50
79
  registry.register({
51
80
  ...fsReadFileSpec,
52
81
  executor: executeFsReadFile,
@@ -59,6 +88,14 @@ export function registerAllBuiltins(registry) {
59
88
  ...fsListSpec,
60
89
  executor: executeFsList,
61
90
  });
91
+ registry.register({
92
+ ...fsListDirectorySpec,
93
+ executor: executeFsListDirectory,
94
+ });
95
+ registry.register({
96
+ ...fsListFilesSpec,
97
+ executor: executeFsListFiles,
98
+ });
62
99
  registry.register({
63
100
  ...astGrepSpec,
64
101
  executor: executeAstGrep,
@@ -71,10 +108,22 @@ export function registerAllBuiltins(registry) {
71
108
  ...shellExecSpec,
72
109
  executor: executeShellExec,
73
110
  });
111
+ registry.register({
112
+ ...fsWriteFileSpec,
113
+ executor: executeFsWriteFile,
114
+ });
115
+ registry.register({
116
+ ...fsCreateDirectorySpec,
117
+ executor: executeFsCreateDirectory,
118
+ });
119
+ registry.register({
120
+ ...fsDeleteFileSpec,
121
+ executor: executeFsDeleteFile,
122
+ });
74
123
  registry.register(planInitSpec);
75
124
  registry.register(planReadSpec);
76
125
  registry.register(planUpdateSpec);
77
126
  registry.register(askUserSpec);
78
127
  }
79
- export { CodeSearchSpec, codeSearchExecutor, astDefsRefsSpec as codeAstSpec, executeAstDefsRefs as executeCodeAst, gitCatSpec, executeGitCat, gitStatusSpec, executeGitStatus, codeReadSpec, fsListSpec, executeFsList, fsReadFileSpec as fsReadSpec, executeFsReadFile as executeFsRead, updateKnowledgeSpec, executeUpdateKnowledge, astGrepSpec as codeSearchAstSpec, executeAstGrep as executeCodeSearchAst, verifyRunSpec as testRunSpec, executeVerifyRun as executeTestRun, };
128
+ export { CodeSearchSpec, codeSearchExecutor, astDefsRefsSpec as codeAstSpec, executeAstDefsRefs as executeCodeAst, gitCatSpec, executeGitCat, gitStatusSpec, executeGitStatus, codeReadSpec, fsListSpec, executeFsList, fsReadFileSpec as fsReadSpec, executeFsReadFile as executeFsRead, updateKnowledgeSpec, executeUpdateKnowledge, astGrepSpec as codeSearchAstSpec, executeAstGrep as executeCodeSearchAst, verifyRunSpec as testRunSpec, executeVerifyRun as executeTestRun, gitDiffCheckSpec, executeGitDiffCheck, gitApplyCheckSpec, executeGitApplyCheck, benchmarkReportSpec, executeBenchmarkReport, sweBenchLoadInstanceSpec, executeSweBenchLoadInstance, sweBenchWritePredictionSpec, executeSweBenchWritePrediction, sweBenchSubmitPredictionsSpec, executeSweBenchSubmitPredictions, sweBenchGetReportSpec, executeSweBenchGetReport, };
80
129
  //# sourceMappingURL=index.js.map
@@ -63,7 +63,14 @@ export const askUserSpec = {
63
63
  riskLevel: 'low',
64
64
  sideEffects: ['none'],
65
65
  concurrency: 'serial_only',
66
- allowedPhases: [Phase.EXPLORE, Phase.PLAN, Phase.PATCH, Phase.VALIDATE, Phase.AST_VALIDATE],
66
+ allowedPhases: [
67
+ Phase.EXPLORE,
68
+ Phase.PLAN,
69
+ Phase.AUTOPILOT,
70
+ Phase.PATCH,
71
+ Phase.VALIDATE,
72
+ Phase.AST_VALIDATE,
73
+ ],
67
74
  inputSchema: askUserInputSchema,
68
75
  outputSchema: askUserOutputSchema,
69
76
  executor: async (input, ctx) => {
@@ -14,6 +14,17 @@ const stepIdSchema = z
14
14
  .max(128)
15
15
  .regex(/^[a-zA-Z0-9_.:-]+$/)
16
16
  .describe('Stable step ID (from <!-- sl:id=... -->).');
17
+ const planUpdatePatchSchema = z
18
+ .object({
19
+ status: z.enum(['todo', 'active', 'done', 'failed', 'skipped', 'conflict']).optional(),
20
+ checkbox: z.enum(['checked', 'unchecked']).optional(),
21
+ appendSubtasks: z.array(z.string().min(1)).optional(),
22
+ note: z.string().optional(),
23
+ })
24
+ .describe('Patch object for plan.update. Provide a JSON object (not a JSON string). Optional keys: status, checkbox, appendSubtasks, note.');
25
+ const planUpdateConflictCodeSchema = z
26
+ .enum(['BASE_HASH_MISMATCH', 'STEP_NOT_FOUND', 'MALFORMED_METADATA', 'WRITE_DENIED'])
27
+ .describe('Conflict code returned when ok=false.');
17
28
  function planResource(ctx, sessionId) {
18
29
  const repoId = ctx.persistenceRoot ?? ctx.repoRoot;
19
30
  if (!sessionId)
@@ -29,7 +40,14 @@ export const planInitSpec = {
29
40
  sideEffects: ['runtime_write'],
30
41
  concurrency: 'mutex_by_resource',
31
42
  computeResources: (_args, ctx) => planResource(ctx),
32
- allowedPhases: [Phase.EXPLORE, Phase.PLAN, Phase.PATCH, Phase.VERIFY, Phase.SHRINK],
43
+ allowedPhases: [
44
+ Phase.EXPLORE,
45
+ Phase.PLAN,
46
+ Phase.AUTOPILOT,
47
+ Phase.PATCH,
48
+ Phase.VERIFY,
49
+ Phase.SHRINK,
50
+ ],
33
51
  inputSchema: z.object({
34
52
  mission: z.string().min(1),
35
53
  objective: z.string().min(1),
@@ -59,7 +77,14 @@ export const planReadSpec = {
59
77
  sideEffects: ['fs_read'],
60
78
  concurrency: 'parallel_ok',
61
79
  computeResources: (args, ctx) => planResource(ctx, args.sessionId),
62
- allowedPhases: [Phase.EXPLORE, Phase.PLAN, Phase.PATCH, Phase.VERIFY, Phase.SHRINK],
80
+ allowedPhases: [
81
+ Phase.EXPLORE,
82
+ Phase.PLAN,
83
+ Phase.AUTOPILOT,
84
+ Phase.PATCH,
85
+ Phase.VERIFY,
86
+ Phase.SHRINK,
87
+ ],
63
88
  inputSchema: z.object({
64
89
  sessionId: sessionIdSchema,
65
90
  }),
@@ -100,17 +125,19 @@ export const planUpdateSpec = {
100
125
  sideEffects: ['runtime_write'],
101
126
  concurrency: 'mutex_by_resource',
102
127
  computeResources: (args, ctx) => planResource(ctx, args.sessionId),
103
- allowedPhases: [Phase.EXPLORE, Phase.PLAN, Phase.PATCH, Phase.VERIFY, Phase.SHRINK],
128
+ allowedPhases: [
129
+ Phase.EXPLORE,
130
+ Phase.PLAN,
131
+ Phase.AUTOPILOT,
132
+ Phase.PATCH,
133
+ Phase.VERIFY,
134
+ Phase.SHRINK,
135
+ ],
104
136
  inputSchema: z.object({
105
137
  sessionId: sessionIdSchema,
106
138
  baseHash: z.string().min(8),
107
139
  stepId: stepIdSchema,
108
- patch: z.object({
109
- status: z.enum(['todo', 'active', 'done', 'failed', 'skipped', 'conflict']).optional(),
110
- checkbox: z.enum(['checked', 'unchecked']).optional(),
111
- appendSubtasks: z.array(z.string().min(1)).optional(),
112
- note: z.string().optional(),
113
- }),
140
+ patch: planUpdatePatchSchema,
114
141
  }),
115
142
  outputSchema: z.union([
116
143
  z.object({
@@ -124,12 +151,7 @@ export const planUpdateSpec = {
124
151
  sessionId: z.string(),
125
152
  baseHash: z.string(),
126
153
  conflict: z.object({
127
- code: z.enum([
128
- 'BASE_HASH_MISMATCH',
129
- 'STEP_NOT_FOUND',
130
- 'MALFORMED_METADATA',
131
- 'WRITE_DENIED',
132
- ]),
154
+ code: planUpdateConflictCodeSchema,
133
155
  message: z.string(),
134
156
  }),
135
157
  }),
@@ -13,7 +13,7 @@ export const shellExecSpec = {
13
13
  sideEffects: ['process'],
14
14
  concurrency: 'isolated',
15
15
  computeResources: (_input, ctx) => [repoResource(ctx), processResource(ctx)],
16
- allowedPhases: [Phase.SLASH],
16
+ allowedPhases: [Phase.SLASH, Phase.AUTOPILOT],
17
17
  inputSchema: z.object({
18
18
  command: z.string().min(1).describe('Shell command to execute'),
19
19
  }),
@@ -28,21 +28,6 @@ export async function createStandardToolstack(options) {
28
28
  const sanitize = new ToolSanitizer();
29
29
  // 2. Register all builtin tools (rg, git, ast, ast-grep)
30
30
  registerAllBuiltins(registry);
31
- // 3. Load and register Skills as tools
32
- const extensions = options.extensions;
33
- const skillLoader = new SkillLoader({
34
- repoRoot: options.repoRoot,
35
- useDefaults: extensions?.skillDiscovery.useDefaults,
36
- extraPaths: extensions?.skillDiscovery.paths,
37
- });
38
- const skills = await skillLoader.initialize();
39
- for (const skill of skills) {
40
- registry.register(skillToToolSpec(skill));
41
- }
42
- if (extensions) {
43
- await registerMcpTools(registry, extensions.mcpServers);
44
- await registerPluginTools(registry, extensions.toolPlugins);
45
- }
46
31
  const compiledPermissionRules = (() => {
47
32
  if (!options.permissionRules)
48
33
  return undefined;
@@ -53,6 +38,42 @@ export async function createStandardToolstack(options) {
53
38
  }
54
39
  return compiled.compiled;
55
40
  })();
41
+ // 3. Register ALL tools (builtins already done above) into the registry,
42
+ // then apply allowlist/permission filtering, then create the router.
43
+ //
44
+ // The challenge: skill executors need a ToolRouter reference (to call
45
+ // shell.exec through governance), but the router needs the final filtered
46
+ // registry. We break this cycle with a RouterBox — a mutable container
47
+ // whose .router field is filled after the router is constructed.
48
+ //
49
+ // Order:
50
+ // a. Create RouterBox (null initially)
51
+ // b. Load skills → register with RouterBox (executor reads lazily)
52
+ // c. Register MCP + plugin tools
53
+ // d. Apply allowlist/permission filtering → new filtered registry
54
+ // e. Create ToolRouter with filtered registry
55
+ // f. Fill RouterBox.router — skill executors now have a valid reference
56
+ const routerBox = { router: null };
57
+ // 3a. Load skill catalog (Tier 1: lightweight metadata only) and register
58
+ // bridge tool specs with lazy activation. Full skill content is loaded
59
+ // on demand via SkillLoader.activateSkill() (Tier 2) when the executor
60
+ // is actually invoked.
61
+ // @see https://agentskills.io/specification — Progressive disclosure
62
+ const extensions = options.extensions;
63
+ const skillLoader = new SkillLoader({
64
+ repoRoot: options.repoRoot,
65
+ extraPaths: extensions?.skillDiscovery.paths,
66
+ });
67
+ const catalog = await skillLoader.loadCatalog();
68
+ for (const entry of catalog) {
69
+ registry.register(skillToToolSpec({ entry, loader: skillLoader }, routerBox));
70
+ }
71
+ // 3b. Register MCP + plugin tools
72
+ if (extensions) {
73
+ await registerMcpTools(registry, extensions.mcpServers);
74
+ await registerPluginTools(registry, extensions.toolPlugins);
75
+ }
76
+ // 3c. Apply allowlist / permission-rule filtering — skills are now included
56
77
  const allowSets = [];
57
78
  if (Array.isArray(options.allowedToolNames) && options.allowedToolNames.length > 0) {
58
79
  allowSets.push(new Set(options.allowedToolNames));
@@ -76,8 +97,10 @@ export async function createStandardToolstack(options) {
76
97
  }
77
98
  registry = filtered;
78
99
  }
79
- // 4. Create Router (The execution pipeline)
100
+ // 3d. Create Router with the FINAL (filtered) registry — skills included
80
101
  const router = new ToolRouter(registry, policy, budget, audit, sanitize, options.authorizationProvider, { authorizationMode: options.authorizationMode, permissionRules: compiledPermissionRules });
102
+ // 3e. Fill the RouterBox — skill executors can now resolve the router
103
+ routerBox.router = router;
81
104
  // 4. Create Dispatcher (The high-level coordinator for LLM text)
82
105
  const dispatcher = new ToolDispatcher(router, {
83
106
  repoRoot: options.repoRoot,
@@ -1,4 +1,18 @@
1
1
  import { z } from 'zod';
2
+ function formatToolExamplesForDescription(spec) {
3
+ if (!Array.isArray(spec.examples) || spec.examples.length === 0)
4
+ return '';
5
+ const examples = spec.examples
6
+ .map((example) => {
7
+ const input = JSON.stringify(example.input);
8
+ return input ? `- ${example.description}: ${input}` : undefined;
9
+ })
10
+ .filter((line) => Boolean(line));
11
+ return examples.length > 0 ? `\n\nExamples:\n${examples.join('\n')}` : '';
12
+ }
13
+ function toolDescriptionForModel(spec) {
14
+ return `${spec.description}${formatToolExamplesForDescription(spec)}`;
15
+ }
2
16
  function unwrapForSchemaGeneration(schema) {
3
17
  let current = schema;
4
18
  for (let depth = 0; depth < 20; depth++) {
@@ -113,7 +127,7 @@ export function toolToOpenAI(spec) {
113
127
  type: 'function',
114
128
  function: {
115
129
  name: spec.name,
116
- description: spec.description,
130
+ description: toolDescriptionForModel(spec),
117
131
  parameters: zodToOpenApi3(spec.inputSchema),
118
132
  },
119
133
  };
@@ -124,7 +138,7 @@ export function toolToOpenAI(spec) {
124
138
  export function toolToAnthropic(spec) {
125
139
  return {
126
140
  name: spec.name,
127
- description: spec.description,
141
+ description: toolDescriptionForModel(spec),
128
142
  input_schema: zodToOpenApi3(spec.inputSchema),
129
143
  };
130
144
  }
@@ -135,7 +149,7 @@ export function formatToolsForPrompt(specs) {
135
149
  return specs
136
150
  .map((spec) => {
137
151
  const schema = zodToOpenApi3(spec.inputSchema);
138
- return `Tool: ${spec.name}\nDescription: ${spec.description}\nSchema: ${JSON.stringify(schema, null, 2)}`;
152
+ return `Tool: ${spec.name}\nDescription: ${toolDescriptionForModel(spec)}\nSchema: ${JSON.stringify(schema, null, 2)}`;
139
153
  })
140
154
  .join('\n\n---\n\n');
141
155
  }