@ridit/lens 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.tsx CHANGED
@@ -7,6 +7,9 @@ import { ReviewCommand } from "./commands/review";
7
7
  import { TaskCommand } from "./commands/task";
8
8
  import { ChatCommand } from "./commands/chat";
9
9
  import { TimelineCommand } from "./commands/timeline";
10
+ import { registerBuiltins } from "./utils/tools/builtins";
11
+
12
+ registerBuiltins();
10
13
 
11
14
  const program = new Command();
12
15
 
@@ -3,63 +3,19 @@ import type { ImportantFile } from "../types/repo";
3
3
  export function buildSystemPrompt(
4
4
  files: ImportantFile[],
5
5
  memorySummary = "",
6
+ toolsSection?: string,
6
7
  ): string {
7
8
  const fileList = files
8
9
  .map((f) => `### ${f.path}\n\`\`\`\n${f.content.slice(0, 2000)}\n\`\`\``)
9
10
  .join("\n\n");
10
11
 
11
- return `You are an expert software engineer assistant with access to the user's codebase and tools.
12
-
13
- ## TOOLS
14
-
15
- You have exactly thirteen tools. To use a tool you MUST wrap it in the exact XML tags shown below — no other format will work.
16
-
17
- ### 1. fetch — load a URL
18
- <fetch>https://example.com</fetch>
12
+ // If a toolsSection is supplied (e.g. from the plugin registry), use it.
13
+ // Otherwise fall back to the static built-in section.
14
+ const tools = toolsSection ?? BUILTIN_TOOLS_SECTION;
19
15
 
20
- ### 2. shell run a terminal command
21
- <shell>node -v</shell>
22
-
23
- ### 3. read-file — read a file from the repo
24
- <read-file>src/foo.ts</read-file>
25
-
26
- ### 4. read-folder — list contents of a folder (files + subfolders, one level deep)
27
- <read-folder>src/components</read-folder>
28
-
29
- ### 5. grep — search for a pattern across files in the repo (cross-platform, no shell needed)
30
- <grep>
31
- {"pattern": "ChatRunner", "glob": "src/**/*.tsx"}
32
- </grep>
33
-
34
- ### 6. write-file — create or overwrite a file
35
- <write-file>
36
- {"path": "data/output.csv", "content": "col1,col2\nval1,val2"}
37
- </write-file>
38
-
39
- ### 7. delete-file — permanently delete a single file
40
- <delete-file>src/old-component.tsx</delete-file>
41
-
42
- ### 8. delete-folder — permanently delete a folder and all its contents
43
- <delete-folder>src/legacy</delete-folder>
44
-
45
- ### 9. open-url — open a URL in the user's default browser
46
- <open-url>https://github.com/owner/repo</open-url>
47
-
48
- ### 10. generate-pdf — generate a PDF file from markdown-style content
49
- <generate-pdf>
50
- {"path": "output/report.pdf", "content": "# Title\n\nSome body text.\n\n## Section\n\nMore content."}
51
- </generate-pdf>
52
-
53
- ### 11. search — search the internet for anything you are unsure about
54
- <search>how to use React useEffect cleanup function</search>
55
-
56
- ### 12. clone — clone a GitHub repo so you can explore and discuss it
57
- <clone>https://github.com/owner/repo</clone>
16
+ return `You are an expert software engineer assistant with access to the user's codebase and tools.
58
17
 
59
- ### 13. changes — propose code edits (shown as a diff for user approval)
60
- <changes>
61
- {"summary": "what changed and why", "patches": [{"path": "src/foo.ts", "content": "COMPLETE file content", "isNew": false}]}
62
- </changes>
18
+ ${tools}
63
19
 
64
20
  ## MEMORY OPERATIONS
65
21
 
@@ -109,9 +65,26 @@ You may emit multiple memory operations in a single response alongside normal co
109
65
  22. When scaffolding a multi-file project, after each write-file succeeds, immediately proceed to writing the NEXT file — NEVER rewrite a file you already wrote in this session. Each file is written ONCE and ONLY ONCE.
110
66
  23. For JSX/TSX files always use \`.tsx\` extension and include \`/** @jsxImportSource react */\` or ensure tsconfig has jsx set — bun needs this to parse JSX
111
67
  24. When explaining how to use a tool in text, use [tag] bracket notation or a fenced code block — NEVER emit a real XML tool tag as part of an explanation or example
112
- 25. NEVER chain tool calls unless the user's request explicitly requires multiple steps
113
- 26. NEVER read files, list folders, or run tools that were not asked for in the current user message
114
- 27. NEVER use markdown formatting in plain text responses — no **bold**, no *italics*, no # headings, no bullet points with -, *, or +, no numbered lists, no backtick inline code. Write in plain prose. Only use fenced \`\`\` code blocks when showing actual code.
68
+ 25. NEVER read files, list folders, or run tools that were not asked for in the current user message
69
+ 26. NEVER use markdown formatting in plain text responses — no **bold**, no *italics*, no # headings, no bullet points with -, *, or +, no numbered lists, no backtick inline code. Write in plain prose. Only use fenced \`\`\` code blocks when showing actual code.
70
+
71
+ ## SCAFFOLDING — CHAINING WRITE-FILE CALLS
72
+
73
+ When creating multiple files (e.g. scaffolding a project or creating 10 files), emit ALL of them
74
+ in a single response by chaining the tags back-to-back with no text between them:
75
+
76
+ <write-file>
77
+ {"path": "test/file1.txt", "content": "File 1 content"}
78
+ </write-file>
79
+ <write-file>
80
+ {"path": "test/file2.txt", "content": "File 2 content"}
81
+ </write-file>
82
+ <write-file>
83
+ {"path": "test/file3.txt", "content": "File 3 content"}
84
+ </write-file>
85
+
86
+ The system processes each tag sequentially and automatically continues to the next one.
87
+ Do NOT wait for a user message between files — emit all tags at once.
115
88
 
116
89
  ## CRITICAL: READ BEFORE YOU WRITE
117
90
 
@@ -133,58 +106,62 @@ These rules are mandatory whenever you plan to edit or create a file:
133
106
  - NEVER produce a file that is shorter than the original unless you are explicitly asked to delete things
134
107
  - If you catch yourself rewriting a file from scratch, STOP — go back and read the original first
135
108
 
136
- ## WHEN TO USE read-folder:
137
- - Before editing files in an unfamiliar directory — list it first to understand the structure
138
- - When a feature spans multiple files and you are not sure what exists
139
- - When the user asks you to explore or explain a part of the codebase
140
-
141
- ## SCAFFOLDING A NEW PROJECT (follow this exactly)
142
-
143
- When the user asks to create a new CLI/app in a subfolder (e.g. "make a todo app called list"):
144
- 1. Create all files first using write-file with paths like \`list/package.json\`, \`list/src/index.tsx\`
145
- 2. Then run \`cd list && bun install\` (or npm/pnpm) in one shell command
146
- 3. Then run the project with \`cd list && bun run index.ts\` or whatever the entry point is
147
- 4. NEVER run \`bun init\` — it is interactive and will hang. Create package.json manually with write-file instead
148
- 5. TSX files need either tsconfig.json with \`"jsx": "react-jsx"\` or \`/** @jsxImportSource react */\` at the top
149
-
150
- ## FETCH → WRITE FLOW (follow this exactly when saving fetched data)
151
-
152
- 1. fetch the URL
153
- 2. Analyze the result — count the rows, identify columns, check completeness
154
- 3. Tell the user what you found: "Found X rows with columns: A, B, C. Writing now."
155
- 4. emit write-file with correctly structured, complete content
156
- 5. After write-file confirms success, emit read-file to verify
157
- 6. Only after read-file confirms content is correct, tell the user it is done
158
-
159
- ## WHEN TO USE TOOLS
160
-
161
- - User shares any URL → fetch it immediately
162
- - User asks to run anything → shell it immediately
163
- - User asks to open a link, open a URL, or visit a website → open-url it immediately, do NOT use fetch
164
- - User asks to delete a file → delete-file it immediately (requires approval)
165
- - User asks to delete a folder or directory → delete-folder it immediately (requires approval)
166
- - User asks to search for a pattern in files, find usages, find where something is defined → grep it immediately, NEVER use shell grep/findstr/Select-String
167
- - User asks to read a file → read-file it immediately, NEVER use shell cat/type
168
- - User asks what files are in a folder, or to explore/list a directory → read-folder it immediately, NEVER use shell ls/dir/find/git ls-files
169
- - User asks to explore a folder or directory → read-folder it immediately
170
- - User asks to save/create/write a file → write-file it immediately, then read-file to verify
171
- - User asks to modify/edit/add to an existing file → read-file it FIRST, then emit changes
172
- - User shares a GitHub URL and wants to clone/explore/discuss it → use clone immediately, NEVER use shell git clone
173
- - After clone succeeds, you will see context about the clone in the conversation. Wait for the user to ask a specific question before using any tools. Do NOT auto-read files, do NOT emit any tool tags until the user asks.
174
- - You are unsure about an API, library, error, concept, or piece of code → search it immediately
175
- - User asks about something recent or that you might not know → search it immediately
176
- - You are about to say "I'm not sure" or "I don't know" → search instead of guessing
177
-
178
- ## shell IS ONLY FOR:
179
- - Running code: \`node script.js\`, \`bun run dev\`, \`python main.py\`
180
- - Installing packages: \`npm install\`, \`pip install\`
181
- - Building/testing: \`npm run build\`, \`bun test\`
182
- - Git operations other than clone: \`git status\`, \`git log\`, \`git diff\`
183
- - Anything that EXECUTES — not reads or lists
184
-
185
109
  ## CODEBASE
186
110
 
187
111
  ${fileList.length > 0 ? fileList : "(no files indexed)"}
188
112
 
189
113
  ${memorySummary}`;
190
114
  }
115
+
116
+ // ── Static fallback tools section (used when registry is not available) ───────
117
+
118
+ const BUILTIN_TOOLS_SECTION = `## TOOLS
119
+
120
+ You have exactly thirteen tools. To use a tool you MUST wrap it in the exact XML tags shown below — no other format will work.
121
+
122
+ ### 1. fetch — load a URL
123
+ <fetch>https://example.com</fetch>
124
+
125
+ ### 2. shell — run a terminal command
126
+ <shell>node -v</shell>
127
+
128
+ ### 3. read-file — read a file from the repo
129
+ <read-file>src/foo.ts</read-file>
130
+
131
+ ### 4. read-folder — list contents of a folder (files + subfolders, one level deep)
132
+ <read-folder>src/components</read-folder>
133
+
134
+ ### 5. grep — search for a pattern across files in the repo (cross-platform, no shell needed)
135
+ <grep>
136
+ {"pattern": "ChatRunner", "glob": "src/**/*.tsx"}
137
+ </grep>
138
+
139
+ ### 6. write-file — create or overwrite a file
140
+ <write-file>
141
+ {"path": "data/output.csv", "content": "col1,col2\\nval1,val2"}
142
+ </write-file>
143
+
144
+ ### 7. delete-file — permanently delete a single file
145
+ <delete-file>src/old-component.tsx</delete-file>
146
+
147
+ ### 8. delete-folder — permanently delete a folder and all its contents
148
+ <delete-folder>src/legacy</delete-folder>
149
+
150
+ ### 9. open-url — open a URL in the user's default browser
151
+ <open-url>https://github.com/owner/repo</open-url>
152
+
153
+ ### 10. generate-pdf — generate a PDF file from markdown-style content
154
+ <generate-pdf>
155
+ {"path": "output/report.pdf", "content": "# Title\\n\\nSome body text.\\n\\n## Section\\n\\nMore content."}
156
+ </generate-pdf>
157
+
158
+ ### 11. search — search the internet for anything you are unsure about
159
+ <search>how to use React useEffect cleanup function</search>
160
+
161
+ ### 12. clone — clone a GitHub repo so you can explore and discuss it
162
+ <clone>https://github.com/owner/repo</clone>
163
+
164
+ ### 13. changes — propose code edits (shown as a diff for user approval)
165
+ <changes>
166
+ {"summary": "what changed and why", "patches": [{"path": "src/foo.ts", "content": "COMPLETE file content", "isNew": false}]}
167
+ </changes>`;
package/src/utils/chat.ts CHANGED
@@ -1,3 +1,9 @@
1
+ // ── chat.ts ───────────────────────────────────────────────────────────────────
2
+ //
3
+ // Response parsing and API calls.
4
+ // Tool parsing is now fully driven by the ToolRegistry — adding a new tool
5
+ // to the registry automatically makes it parseable here.
6
+
1
7
  export {
2
8
  walkDir,
3
9
  applyPatches,
@@ -13,104 +19,87 @@ export { fetchUrl, searchWeb } from "../tools/web";
13
19
  export { generatePdf } from "../tools/pdf";
14
20
  export { buildSystemPrompt, FEW_SHOT_MESSAGES } from "../prompts";
15
21
 
16
- import type { FilePatch } from "../components/repo/DiffViewer";
17
22
  import type { Message } from "../types/chat";
18
23
  import type { Provider } from "../types/config";
19
24
  import { FEW_SHOT_MESSAGES } from "../prompts";
20
-
21
- // ── Response parser ───────────────────────────────────────────────────────────
25
+ import { registry } from "./tools/registry";
26
+ import type { FilePatch } from "../components/repo/DiffViewer";
22
27
 
23
28
  export type ParsedResponse =
24
- | { kind: "text"; content: string }
25
- | { kind: "changes"; content: string; patches: FilePatch[] }
26
- | { kind: "shell"; content: string; command: string }
27
- | { kind: "fetch"; content: string; url: string }
28
- | { kind: "read-file"; content: string; filePath: string }
29
- | { kind: "read-folder"; content: string; folderPath: string }
30
- | { kind: "grep"; content: string; pattern: string; glob: string }
31
- | { kind: "delete-file"; content: string; filePath: string }
32
- | { kind: "delete-folder"; content: string; folderPath: string }
33
- | { kind: "open-url"; content: string; url: string }
29
+ | { kind: "text"; content: string; remainder?: string }
34
30
  | {
35
- kind: "generate-pdf";
31
+ kind: "changes";
36
32
  content: string;
37
- filePath: string;
38
- pdfContent: string;
33
+ patches: FilePatch[];
34
+ remainder?: string;
39
35
  }
36
+ | { kind: "clone"; content: string; repoUrl: string; remainder?: string }
40
37
  | {
41
- kind: "write-file";
38
+ kind: "tool";
39
+ toolName: string;
40
+ input: unknown;
41
+ rawInput: string;
42
42
  content: string;
43
- filePath: string;
44
- fileContent: string;
45
- }
46
- | { kind: "search"; content: string; query: string }
47
- | { kind: "clone"; content: string; repoUrl: string };
43
+ remainder?: string;
44
+ };
48
45
 
49
46
  export function parseResponse(text: string): ParsedResponse {
50
47
  const scanText = text.replace(/```[\s\S]*?```/g, (m) => " ".repeat(m.length));
51
48
 
52
49
  type Candidate = {
53
50
  index: number;
54
- kind:
55
- | "changes"
56
- | "shell"
57
- | "fetch"
58
- | "read-file"
59
- | "read-folder"
60
- | "grep"
61
- | "delete-file"
62
- | "delete-folder"
63
- | "open-url"
64
- | "generate-pdf"
65
- | "write-file"
66
- | "search"
67
- | "clone";
51
+ toolName: string;
68
52
  match: RegExpExecArray;
69
53
  };
70
54
  const candidates: Candidate[] = [];
71
55
 
72
- const patterns: { kind: Candidate["kind"]; re: RegExp }[] = [
73
- { kind: "fetch", re: /<fetch>([\s\S]*?)<\/fetch>/g },
74
- { kind: "shell", re: /<shell>([\s\S]*?)<\/shell>/g },
75
- { kind: "read-file", re: /<read-file>([\s\S]*?)<\/read-file>/g },
76
- { kind: "read-folder", re: /<read-folder>([\s\S]*?)<\/read-folder>/g },
77
- { kind: "grep", re: /<grep>([\s\S]*?)<\/grep>/g },
78
- { kind: "delete-file", re: /<delete-file>([\s\S]*?)<\/delete-file>/g },
79
- {
80
- kind: "delete-folder",
81
- re: /<delete-folder>([\s\S]*?)<\/delete-folder>/g,
82
- },
83
- { kind: "open-url", re: /<open-url>([\s\S]*?)<\/open-url>/g },
84
- { kind: "generate-pdf", re: /<generate-pdf>([\s\S]*?)<\/generate-pdf>/g },
85
- { kind: "write-file", re: /<write-file>([\s\S]*?)<\/write-file>/g },
86
- { kind: "search", re: /<search>([\s\S]*?)<\/search>/g },
87
- { kind: "clone", re: /<clone>([\s\S]*?)<\/clone>/g },
88
- { kind: "changes", re: /<changes>([\s\S]*?)<\/changes>/g },
89
- // fenced fallbacks
90
- { kind: "fetch", re: /```fetch\r?\n([\s\S]*?)\r?\n```/g },
91
- { kind: "shell", re: /```shell\r?\n([\s\S]*?)\r?\n```/g },
92
- { kind: "read-file", re: /```read-file\r?\n([\s\S]*?)\r?\n```/g },
93
- { kind: "read-folder", re: /```read-folder\r?\n([\s\S]*?)\r?\n```/g },
94
- { kind: "write-file", re: /```write-file\r?\n([\s\S]*?)\r?\n```/g },
95
- { kind: "search", re: /```search\r?\n([\s\S]*?)\r?\n```/g },
96
- { kind: "changes", re: /```changes\r?\n([\s\S]*?)\r?\n```/g },
97
- ];
56
+ for (const toolName of registry.names()) {
57
+ const escaped = toolName.replace(/[-]/g, "\\-");
58
+
59
+ // XML tag
60
+ const xmlRe = new RegExp(`<${escaped}>([\\s\\S]*?)<\\/${escaped}>`, "g");
61
+ xmlRe.lastIndex = 0;
62
+ const xmlM = xmlRe.exec(scanText);
63
+ if (xmlM) {
64
+ const orig = new RegExp(xmlRe.source);
65
+ const origM = orig.exec(text.slice(xmlM.index));
66
+ if (origM) {
67
+ candidates.push({
68
+ index: xmlM.index,
69
+ toolName,
70
+ match: Object.assign(
71
+ [
72
+ text.slice(xmlM.index, xmlM.index + origM[0].length),
73
+ origM[1],
74
+ ] as unknown as RegExpExecArray,
75
+ { index: xmlM.index, input: text, groups: undefined },
76
+ ),
77
+ });
78
+ }
79
+ }
98
80
 
99
- for (const { kind, re } of patterns) {
100
- re.lastIndex = 0;
101
- const m = re.exec(scanText);
102
- if (m) {
103
- const originalRe = new RegExp(re.source, re.flags.replace("g", ""));
104
- const originalMatch = originalRe.exec(text.slice(m.index));
105
- if (originalMatch) {
106
- const fakeMatch = Object.assign(
107
- [
108
- text.slice(m.index, m.index + originalMatch[0].length),
109
- originalMatch[1],
110
- ] as unknown as RegExpExecArray,
111
- { index: m.index, input: text, groups: undefined },
112
- );
113
- candidates.push({ index: m.index, kind, match: fakeMatch });
81
+ // Fenced code block fallback
82
+ const fencedRe = new RegExp(
83
+ `\`\`\`${escaped}\\r?\\n([\\s\\S]*?)\\r?\\n\`\`\``,
84
+ "g",
85
+ );
86
+ fencedRe.lastIndex = 0;
87
+ const fencedM = fencedRe.exec(scanText);
88
+ if (fencedM) {
89
+ const orig = new RegExp(fencedRe.source);
90
+ const origM = orig.exec(text.slice(fencedM.index));
91
+ if (origM) {
92
+ candidates.push({
93
+ index: fencedM.index,
94
+ toolName,
95
+ match: Object.assign(
96
+ [
97
+ text.slice(fencedM.index, fencedM.index + origM[0].length),
98
+ origM[1],
99
+ ] as unknown as RegExpExecArray,
100
+ { index: fencedM.index, input: text, groups: undefined },
101
+ ),
102
+ });
114
103
  }
115
104
  }
116
105
  }
@@ -118,104 +107,56 @@ export function parseResponse(text: string): ParsedResponse {
118
107
  if (candidates.length === 0) return { kind: "text", content: text.trim() };
119
108
 
120
109
  candidates.sort((a, b) => a.index - b.index);
121
- const { kind, match } = candidates[0]!;
110
+ const { toolName, match } = candidates[0]!;
122
111
 
123
- const before = text
124
- .slice(0, match.index)
125
- .replace(
126
- /<(fetch|shell|read-file|read-folder|write-file|search|clone|changes)[^>]*>[\s\S]*?<\/\1>/g,
127
- "",
128
- )
129
- .trim();
112
+ const before = text.slice(0, match.index).trim();
130
113
  const body = (match[1] ?? "").trim();
114
+ const afterMatch = text.slice(match.index + match[0].length).trim();
115
+ const remainder = afterMatch.length > 0 ? afterMatch : undefined;
131
116
 
132
- if (kind === "changes") {
117
+ // Special UI variants
118
+ if (toolName === "changes") {
133
119
  try {
134
120
  const parsed = JSON.parse(body) as {
135
121
  summary: string;
136
122
  patches: FilePatch[];
137
123
  };
138
124
  const display = [before, parsed.summary].filter(Boolean).join("\n\n");
139
- return { kind: "changes", content: display, patches: parsed.patches };
125
+ return {
126
+ kind: "changes",
127
+ content: display,
128
+ patches: parsed.patches,
129
+ remainder,
130
+ };
140
131
  } catch {
141
- /* fall through */
132
+ return { kind: "text", content: text.trim() };
142
133
  }
143
134
  }
144
135
 
145
- if (kind === "shell")
146
- return { kind: "shell", content: before, command: body };
147
- if (kind === "fetch")
148
- return {
149
- kind: "fetch",
150
- content: before,
151
- url: body.replace(/^<|>$/g, "").trim(),
152
- };
153
- if (kind === "read-file")
154
- return { kind: "read-file", content: before, filePath: body };
155
- if (kind === "read-folder")
156
- return { kind: "read-folder", content: before, folderPath: body };
157
- if (kind === "delete-file")
158
- return { kind: "delete-file", content: before, filePath: body };
159
- if (kind === "delete-folder")
160
- return { kind: "delete-folder", content: before, folderPath: body };
161
- if (kind === "open-url")
162
- return {
163
- kind: "open-url",
164
- content: before,
165
- url: body.replace(/^<|>$/g, "").trim(),
166
- };
167
- if (kind === "search")
168
- return { kind: "search", content: before, query: body };
169
- if (kind === "clone")
136
+ if (toolName === "clone") {
170
137
  return {
171
138
  kind: "clone",
172
139
  content: before,
173
140
  repoUrl: body.replace(/^<|>$/g, "").trim(),
141
+ remainder,
174
142
  };
175
-
176
- if (kind === "generate-pdf") {
177
- try {
178
- const parsed = JSON.parse(body);
179
- return {
180
- kind: "generate-pdf",
181
- content: before,
182
- filePath: parsed.path ?? parsed.filePath ?? "output.pdf",
183
- pdfContent: parsed.content ?? "",
184
- };
185
- } catch {
186
- return { kind: "text", content: text };
187
- }
188
143
  }
189
144
 
190
- if (kind === "grep") {
191
- try {
192
- const parsed = JSON.parse(body) as { pattern: string; glob?: string };
193
- return {
194
- kind: "grep",
195
- content: before,
196
- pattern: parsed.pattern,
197
- glob: parsed.glob ?? "**/*",
198
- };
199
- } catch {
200
- return { kind: "grep", content: before, pattern: body, glob: "**/*" };
201
- }
202
- }
145
+ // Generic tool
146
+ const tool = registry.get(toolName);
147
+ if (!tool) return { kind: "text", content: text.trim() };
203
148
 
204
- if (kind === "write-file") {
205
- try {
206
- const parsed = JSON.parse(body) as { path: string; content: string };
207
- return {
208
- kind: "write-file",
209
- content: before,
210
- filePath: parsed.path,
211
- fileContent: parsed.content,
212
- };
213
- } catch {
214
- /* fall through */
215
- }
216
- }
149
+ const input = tool.parseInput(body);
150
+ if (input === null) return { kind: "text", content: text.trim() };
217
151
 
218
- return { kind: "text", content: text.trim() };
152
+ return {
153
+ kind: "tool",
154
+ toolName,
155
+ input,
156
+ rawInput: body,
157
+ content: before,
158
+ remainder,
159
+ };
219
160
  }
220
161
 
221
162
  // ── Clone tag helper ──────────────────────────────────────────────────────────
@@ -251,31 +192,9 @@ function buildApiMessages(
251
192
  "The tool call was denied by the user. Please respond without using that tool.",
252
193
  };
253
194
  }
254
- const label =
255
- m.toolName === "shell"
256
- ? `shell command \`${m.content}\``
257
- : m.toolName === "fetch"
258
- ? `fetch of ${m.content}`
259
- : m.toolName === "read-file"
260
- ? `read-file of ${m.content}`
261
- : m.toolName === "read-folder"
262
- ? `read-folder of ${m.content}`
263
- : m.toolName === "grep"
264
- ? `grep for "${m.content}"`
265
- : m.toolName === "delete-file"
266
- ? `delete-file of ${m.content}`
267
- : m.toolName === "delete-folder"
268
- ? `delete-folder of ${m.content}`
269
- : m.toolName === "open-url"
270
- ? `open-url ${m.content}`
271
- : m.toolName === "generate-pdf"
272
- ? `generate-pdf to ${m.content}`
273
- : m.toolName === "search"
274
- ? `web search for "${m.content}"`
275
- : `write-file to ${m.content}`;
276
195
  return {
277
196
  role: "user",
278
- content: `Here is the output from the ${label}:\n\n${m.result}\n\nPlease continue your response based on this output.`,
197
+ content: `Here is the output from the ${m.toolName} of ${m.content}:\n\n${m.result}\n\nPlease continue your response based on this output.`,
279
198
  };
280
199
  }
281
200
  return { role: m.role, content: m.content };