@morphllm/morphsdk 0.2.57 → 0.2.58
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/dist/anthropic-CaFUHxBW.d.ts +89 -0
- package/dist/{chunk-6X5UOY7B.js → chunk-2CASO3ZO.js} +46 -79
- package/dist/chunk-2CASO3ZO.js.map +1 -0
- package/dist/chunk-374N3GIA.js +118 -0
- package/dist/chunk-374N3GIA.js.map +1 -0
- package/dist/chunk-3IQIT6MC.js +65 -0
- package/dist/chunk-3IQIT6MC.js.map +1 -0
- package/dist/chunk-4VGOBA2J.js +57 -0
- package/dist/chunk-4VGOBA2J.js.map +1 -0
- package/dist/chunk-527P5X2E.js +98 -0
- package/dist/chunk-527P5X2E.js.map +1 -0
- package/dist/chunk-6N6ZYZYD.js +74 -0
- package/dist/chunk-6N6ZYZYD.js.map +1 -0
- package/dist/chunk-6Y5JB4JC.js +195 -0
- package/dist/chunk-6Y5JB4JC.js.map +1 -0
- package/dist/{chunk-QFIHUCTF.js → chunk-7EIHYJSG.js} +18 -18
- package/dist/chunk-7EIHYJSG.js.map +1 -0
- package/dist/{chunk-TICMYDII.js → chunk-APP75CBN.js} +33 -16
- package/dist/chunk-APP75CBN.js.map +1 -0
- package/dist/chunk-ILJ3J5IA.js +72 -0
- package/dist/chunk-ILJ3J5IA.js.map +1 -0
- package/dist/chunk-ISWL67SF.js +1 -0
- package/dist/chunk-KW7OEGZK.js +9 -0
- package/dist/chunk-KW7OEGZK.js.map +1 -0
- package/dist/chunk-Q5AHGIQO.js +205 -0
- package/dist/chunk-Q5AHGIQO.js.map +1 -0
- package/dist/{chunk-TJIUA27P.js → chunk-XT5ZO6ES.js} +9 -5
- package/dist/chunk-XT5ZO6ES.js.map +1 -0
- package/dist/{chunk-LVPVVLTI.js → chunk-YV75OQTE.js} +105 -17
- package/dist/chunk-YV75OQTE.js.map +1 -0
- package/dist/{chunk-ZJIIICRA.js → chunk-ZO4PPFCZ.js} +60 -29
- package/dist/chunk-ZO4PPFCZ.js.map +1 -0
- package/dist/{client-CFoR--IU.d.ts → client-CextMMm9.d.ts} +10 -15
- package/dist/client.cjs +687 -341
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.ts +3 -2
- package/dist/client.js +14 -14
- package/dist/finish-kXAcUJyB.d.ts +33 -0
- package/dist/gemini-CE80Pbdy.d.ts +117 -0
- package/dist/index.cjs +700 -341
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +16 -15
- package/dist/openai-Fvpqln7F.d.ts +89 -0
- package/dist/tools/warp_grep/agent/config.cjs +8 -4
- package/dist/tools/warp_grep/agent/config.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/config.d.ts +7 -2
- package/dist/tools/warp_grep/agent/config.js +1 -1
- package/dist/tools/warp_grep/agent/formatter.cjs +32 -15
- package/dist/tools/warp_grep/agent/formatter.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/formatter.d.ts +1 -1
- package/dist/tools/warp_grep/agent/formatter.js +1 -1
- package/dist/tools/warp_grep/agent/parser.cjs +104 -17
- package/dist/tools/warp_grep/agent/parser.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/parser.d.ts +3 -5
- package/dist/tools/warp_grep/agent/parser.js +1 -3
- package/dist/tools/warp_grep/agent/prompt.cjs +132 -56
- package/dist/tools/warp_grep/agent/prompt.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/prompt.d.ts +1 -1
- package/dist/tools/warp_grep/agent/prompt.js +1 -1
- package/dist/tools/warp_grep/agent/runner.cjs +459 -192
- package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/runner.d.ts +1 -0
- package/dist/tools/warp_grep/agent/runner.js +6 -8
- package/dist/tools/warp_grep/agent/types.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/types.d.ts +9 -2
- package/dist/tools/warp_grep/anthropic.cjs +650 -260
- package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
- package/dist/tools/warp_grep/anthropic.d.ts +4 -74
- package/dist/tools/warp_grep/anthropic.js +13 -15
- package/dist/tools/warp_grep/client.cjs +1593 -0
- package/dist/tools/warp_grep/client.cjs.map +1 -0
- package/dist/tools/warp_grep/client.d.ts +87 -0
- package/dist/tools/warp_grep/client.js +26 -0
- package/dist/tools/warp_grep/gemini.cjs +1587 -0
- package/dist/tools/warp_grep/gemini.cjs.map +1 -0
- package/dist/tools/warp_grep/gemini.d.ts +7 -0
- package/dist/tools/warp_grep/gemini.js +34 -0
- package/dist/tools/warp_grep/harness.cjs +556 -220
- package/dist/tools/warp_grep/harness.cjs.map +1 -1
- package/dist/tools/warp_grep/harness.d.ts +50 -119
- package/dist/tools/warp_grep/harness.js +33 -41
- package/dist/tools/warp_grep/harness.js.map +1 -1
- package/dist/tools/warp_grep/index.cjs +812 -346
- package/dist/tools/warp_grep/index.cjs.map +1 -1
- package/dist/tools/warp_grep/index.d.ts +11 -6
- package/dist/tools/warp_grep/index.js +43 -22
- package/dist/tools/warp_grep/openai.cjs +650 -258
- package/dist/tools/warp_grep/openai.cjs.map +1 -1
- package/dist/tools/warp_grep/openai.d.ts +4 -74
- package/dist/tools/warp_grep/openai.js +13 -13
- package/dist/tools/warp_grep/providers/local.cjs +66 -27
- package/dist/tools/warp_grep/providers/local.cjs.map +1 -1
- package/dist/tools/warp_grep/providers/local.d.ts +4 -9
- package/dist/tools/warp_grep/providers/local.js +2 -2
- package/dist/tools/warp_grep/providers/remote.cjs +211 -0
- package/dist/tools/warp_grep/providers/remote.cjs.map +1 -0
- package/dist/tools/warp_grep/providers/remote.d.ts +67 -0
- package/dist/tools/warp_grep/providers/remote.js +9 -0
- package/dist/tools/warp_grep/providers/types.cjs.map +1 -1
- package/dist/tools/warp_grep/providers/types.d.ts +7 -15
- package/dist/tools/warp_grep/vercel.cjs +662 -277
- package/dist/tools/warp_grep/vercel.cjs.map +1 -1
- package/dist/tools/warp_grep/vercel.d.ts +4 -51
- package/dist/tools/warp_grep/vercel.js +16 -14
- package/dist/types-a_hxdPI6.d.ts +144 -0
- package/dist/vercel-3yjvfmVB.d.ts +66 -0
- package/package.json +12 -2
- package/dist/chunk-6X5UOY7B.js.map +0 -1
- package/dist/chunk-73RQWOQC.js +0 -16
- package/dist/chunk-73RQWOQC.js.map +0 -1
- package/dist/chunk-7OQOOB3R.js +0 -1
- package/dist/chunk-CFF636UC.js +0 -70
- package/dist/chunk-CFF636UC.js.map +0 -1
- package/dist/chunk-EK7OQPWD.js +0 -44
- package/dist/chunk-EK7OQPWD.js.map +0 -1
- package/dist/chunk-GJ5TYNRD.js +0 -107
- package/dist/chunk-GJ5TYNRD.js.map +0 -1
- package/dist/chunk-HQO45BAJ.js +0 -14
- package/dist/chunk-HQO45BAJ.js.map +0 -1
- package/dist/chunk-IMYQOKFO.js +0 -83
- package/dist/chunk-IMYQOKFO.js.map +0 -1
- package/dist/chunk-KBQWGT5L.js +0 -77
- package/dist/chunk-KBQWGT5L.js.map +0 -1
- package/dist/chunk-LVPVVLTI.js.map +0 -1
- package/dist/chunk-QFIHUCTF.js.map +0 -1
- package/dist/chunk-TICMYDII.js.map +0 -1
- package/dist/chunk-TJIUA27P.js.map +0 -1
- package/dist/chunk-WETRQJGU.js +0 -129
- package/dist/chunk-WETRQJGU.js.map +0 -1
- package/dist/chunk-ZJIIICRA.js.map +0 -1
- package/dist/core-CpkYEi_T.d.ts +0 -158
- package/dist/tools/warp_grep/tools/analyse.cjs +0 -40
- package/dist/tools/warp_grep/tools/analyse.cjs.map +0 -1
- package/dist/tools/warp_grep/tools/analyse.d.ts +0 -10
- package/dist/tools/warp_grep/tools/analyse.js +0 -8
- package/dist/tools/warp_grep/tools/finish.cjs +0 -69
- package/dist/tools/warp_grep/tools/finish.cjs.map +0 -1
- package/dist/tools/warp_grep/tools/finish.d.ts +0 -10
- package/dist/tools/warp_grep/tools/finish.js +0 -10
- package/dist/tools/warp_grep/tools/grep.cjs +0 -38
- package/dist/tools/warp_grep/tools/grep.cjs.map +0 -1
- package/dist/tools/warp_grep/tools/grep.d.ts +0 -8
- package/dist/tools/warp_grep/tools/grep.js +0 -15
- package/dist/tools/warp_grep/tools/grep.js.map +0 -1
- package/dist/tools/warp_grep/tools/read.cjs +0 -38
- package/dist/tools/warp_grep/tools/read.cjs.map +0 -1
- package/dist/tools/warp_grep/tools/read.d.ts +0 -9
- package/dist/tools/warp_grep/tools/read.js +0 -8
- package/dist/tools/warp_grep/utils/format.cjs +0 -42
- package/dist/tools/warp_grep/utils/format.cjs.map +0 -1
- package/dist/tools/warp_grep/utils/format.d.ts +0 -4
- package/dist/tools/warp_grep/utils/format.js +0 -18
- package/dist/tools/warp_grep/utils/format.js.map +0 -1
- /package/dist/{chunk-7OQOOB3R.js.map → chunk-ISWL67SF.js.map} +0 -0
- /package/dist/tools/warp_grep/{tools/analyse.js.map → client.js.map} +0 -0
- /package/dist/tools/warp_grep/{tools/finish.js.map → gemini.js.map} +0 -0
- /package/dist/tools/warp_grep/{tools/read.js.map → providers/remote.js.map} +0 -0
|
@@ -31,25 +31,37 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var warp_grep_exports = {};
|
|
32
32
|
__export(warp_grep_exports, {
|
|
33
33
|
LocalRipgrepProvider: () => LocalRipgrepProvider,
|
|
34
|
+
RemoteCommandsProvider: () => RemoteCommandsProvider,
|
|
34
35
|
WARP_GREP_DESCRIPTION: () => WARP_GREP_DESCRIPTION,
|
|
35
36
|
WARP_GREP_SYSTEM_PROMPT: () => SYSTEM_PROMPT,
|
|
36
37
|
WARP_GREP_TOOL_NAME: () => WARP_GREP_TOOL_NAME,
|
|
37
38
|
WarpGrepClient: () => WarpGrepClient,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
createVercelWarpGrepTool: () => createMorphWarpGrepTool3,
|
|
39
|
+
anthropic: () => anthropic_exports,
|
|
40
|
+
executeToolCall: () => executeToolCall,
|
|
41
41
|
executeWarpGrep: () => executeWarpGrep,
|
|
42
42
|
formatResult: () => formatResult,
|
|
43
|
+
gemini: () => gemini_exports,
|
|
43
44
|
getSystemPrompt: () => getSystemPrompt,
|
|
44
|
-
|
|
45
|
+
normalizeFinishFiles: () => normalizeFinishFiles,
|
|
46
|
+
openai: () => openai_exports,
|
|
47
|
+
readFinishFiles: () => readFinishFiles,
|
|
48
|
+
runWarpGrep: () => runWarpGrep,
|
|
49
|
+
toolGrep: () => toolGrep,
|
|
50
|
+
toolListDirectory: () => toolListDirectory,
|
|
51
|
+
toolRead: () => toolRead,
|
|
52
|
+
vercel: () => vercel_exports
|
|
45
53
|
});
|
|
46
54
|
module.exports = __toCommonJS(warp_grep_exports);
|
|
47
55
|
|
|
48
56
|
// tools/warp_grep/agent/config.ts
|
|
49
57
|
var AGENT_CONFIG = {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
MAX_TURNS: 4,
|
|
59
|
+
TIMEOUT_MS: 3e4,
|
|
60
|
+
MAX_CONTEXT_CHARS: 54e4,
|
|
61
|
+
MAX_OUTPUT_LINES: 200,
|
|
62
|
+
MAX_READ_LINES: 800,
|
|
63
|
+
MAX_LIST_DEPTH: 3,
|
|
64
|
+
LIST_TIMEOUT_MS: 2e3
|
|
53
65
|
};
|
|
54
66
|
var BUILTIN_EXCLUDES = [
|
|
55
67
|
// Version control
|
|
@@ -131,113 +143,191 @@ var BUILTIN_EXCLUDES = [
|
|
|
131
143
|
".*"
|
|
132
144
|
];
|
|
133
145
|
var DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || "").split(",").map((s) => s.trim()).filter(Boolean).concat(BUILTIN_EXCLUDES);
|
|
134
|
-
var DEFAULT_MODEL = "morph-warp-grep";
|
|
146
|
+
var DEFAULT_MODEL = "morph-warp-grep-v1";
|
|
135
147
|
|
|
136
148
|
// tools/warp_grep/agent/prompt.ts
|
|
137
|
-
var SYSTEM_PROMPT = `You are a code search agent. Your task is to find all relevant code for a given
|
|
149
|
+
var SYSTEM_PROMPT = `You are a code search agent. Your task is to find all relevant code for a given search_string.
|
|
138
150
|
|
|
139
|
-
|
|
151
|
+
### workflow
|
|
140
152
|
You have exactly 4 turns. The 4th turn MUST be a \`finish\` call. Each turn allows up to 8 parallel tool calls.
|
|
141
153
|
|
|
142
|
-
- Turn 1: Map the territory OR dive deep (based on
|
|
154
|
+
- Turn 1: Map the territory OR dive deep (based on search_string specificity)
|
|
143
155
|
- Turn 2-3: Refine based on findings
|
|
144
156
|
- Turn 4: MUST call \`finish\` with all relevant code locations
|
|
145
157
|
- You MAY call \`finish\` early if confident\u2014but never before at least 1 search turn.
|
|
158
|
+
- The user strongly prefers if you can call the finish tool early, but you must be correct
|
|
146
159
|
|
|
147
|
-
Remember, if the task feels easy to you, it is strongly desirable to call
|
|
148
|
-
</workflow>
|
|
160
|
+
Remember, if the task feels easy to you, it is strongly desirable to call 'finish' early using fewer turns, but quality over speed
|
|
149
161
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
162
|
+
### tools
|
|
163
|
+
Tool calls use nested XML elements:
|
|
164
|
+
\`\`\`xml
|
|
165
|
+
<tool_name>
|
|
166
|
+
<parameter>value</parameter>
|
|
167
|
+
</tool_name>
|
|
168
|
+
\`\`\`
|
|
169
|
+
|
|
170
|
+
### \`list_directory\`
|
|
171
|
+
Directory tree view. Shows structure of a path, optionally filtered by regex pattern.
|
|
172
|
+
|
|
173
|
+
Elements:
|
|
174
|
+
- \`<path>\` (required): Directory path to list (use \`.\` for repo root)
|
|
175
|
+
- \`<pattern>\` (optional): Regex to filter results
|
|
155
176
|
|
|
156
177
|
Examples:
|
|
157
178
|
\`\`\`
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
179
|
+
<list_directory>
|
|
180
|
+
<path>src/services</path>
|
|
181
|
+
</list_directory>
|
|
182
|
+
|
|
183
|
+
<list_directory>
|
|
184
|
+
<path>lib/utils</path>
|
|
185
|
+
<pattern>.*\\.(ts|js)$</pattern>
|
|
186
|
+
</list_directory>
|
|
162
187
|
\`\`\`
|
|
163
188
|
|
|
164
|
-
### \`read
|
|
165
|
-
Read file contents.
|
|
189
|
+
### \`read\`
|
|
190
|
+
Read file contents. Supports multiple line ranges.
|
|
166
191
|
- Returns numbered lines for easy reference
|
|
167
|
-
-
|
|
192
|
+
- ALWAYS include import statements (usually lines 1-20). Better to over-include than miss context.
|
|
193
|
+
|
|
194
|
+
Elements:
|
|
195
|
+
- \`<path>\` (required): File path to read
|
|
196
|
+
- \`<lines>\` (optional): Line ranges like "1-50,75-80,100-120" (omit to read entire file)
|
|
168
197
|
|
|
169
198
|
Examples:
|
|
170
199
|
\`\`\`
|
|
171
|
-
read
|
|
172
|
-
|
|
173
|
-
read
|
|
200
|
+
<read>
|
|
201
|
+
<path>src/main.py</path>
|
|
202
|
+
</read>
|
|
203
|
+
|
|
204
|
+
<read>
|
|
205
|
+
<path>src/auth.py</path>
|
|
206
|
+
<lines>1-20,45-80,150-200</lines>
|
|
207
|
+
</read>
|
|
174
208
|
\`\`\`
|
|
175
209
|
|
|
176
|
-
### \`grep
|
|
177
|
-
|
|
178
|
-
-
|
|
179
|
-
-
|
|
210
|
+
### \`grep\`
|
|
211
|
+
Search for pattern matches across files. Returns matches with 1 line of context above and below.
|
|
212
|
+
- Match lines use \`:\` separator \u2192 \`filepath:linenum:content\`
|
|
213
|
+
- Context lines use \`-\` separator \u2192 \`filepath-linenum-content\`
|
|
214
|
+
|
|
215
|
+
Elements:
|
|
216
|
+
- \`<pattern>\` (required): Search pattern (regex). Use \`(a|b)\` for OR patterns.
|
|
217
|
+
- \`<sub_dir>\` (optional): Subdirectory to search in (defaults to \`.\`)
|
|
218
|
+
- \`<glob>\` (optional): File pattern filter like \`*.py\` or \`*.{ts,tsx}\`
|
|
180
219
|
|
|
181
220
|
Examples:
|
|
182
221
|
\`\`\`
|
|
183
|
-
grep
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
grep
|
|
222
|
+
<grep>
|
|
223
|
+
<pattern>(authenticate|authorize|login)</pattern>
|
|
224
|
+
<sub_dir>src/auth/</sub_dir>
|
|
225
|
+
</grep>
|
|
226
|
+
|
|
227
|
+
<grep>
|
|
228
|
+
<pattern>class.*(Service|Controller)</pattern>
|
|
229
|
+
<glob>*.{ts,js}</glob>
|
|
230
|
+
</grep>
|
|
231
|
+
|
|
232
|
+
<grep>
|
|
233
|
+
<pattern>(DB_HOST|DATABASE_URL|connection)</pattern>
|
|
234
|
+
<glob>*.{py,yaml,env}</glob>
|
|
235
|
+
<sub_dir>lib/</sub_dir>
|
|
236
|
+
</grep>
|
|
187
237
|
\`\`\`
|
|
188
238
|
|
|
189
|
-
### \`finish
|
|
190
|
-
Submit final answer with all relevant code locations.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
-
|
|
194
|
-
-
|
|
195
|
-
|
|
239
|
+
### \`finish\`
|
|
240
|
+
Submit final answer with all relevant code locations. Uses nested \`<file>\` elements.
|
|
241
|
+
|
|
242
|
+
File elements:
|
|
243
|
+
- \`<path>\` (required): File path
|
|
244
|
+
- \`<lines>\` (optional): Line ranges like "1-50,75-80" (\`*\` for entire file)
|
|
245
|
+
|
|
246
|
+
ALWAYS include import statements (usually lines 1-20). Better to over-include than miss context.
|
|
196
247
|
|
|
197
248
|
Examples:
|
|
198
249
|
\`\`\`
|
|
199
|
-
finish
|
|
200
|
-
|
|
250
|
+
<finish>
|
|
251
|
+
<file>
|
|
252
|
+
<path>src/auth.py</path>
|
|
253
|
+
<lines>1-15,25-50,75-80</lines>
|
|
254
|
+
</file>
|
|
255
|
+
<file>
|
|
256
|
+
<path>src/models/user.py</path>
|
|
257
|
+
<lines>*</lines>
|
|
258
|
+
</file>
|
|
259
|
+
</finish>
|
|
201
260
|
\`\`\`
|
|
202
261
|
</tools>
|
|
203
262
|
|
|
204
263
|
<strategy>
|
|
205
|
-
**Before your first tool call, classify the
|
|
264
|
+
**Before your first tool call, classify the search_string:**
|
|
206
265
|
|
|
207
|
-
|
|
|
208
|
-
|
|
209
|
-
| **Specific** (function name, error string, unique identifier) | 8 parallel greps on likely paths | Often by
|
|
210
|
-
| **Conceptual** (how does X work, where is Y handled) |
|
|
211
|
-
| **Exploratory** (find all tests, list API endpoints) |
|
|
266
|
+
| Search_string Type | Round 1 Strategy | Early Finish? |
|
|
267
|
+
|------------|------------------|---------------|
|
|
268
|
+
| **Specific** (function name, error string, unique identifier) | 8 parallel greps on likely paths | Often by round 2 |
|
|
269
|
+
| **Conceptual** (how does X work, where is Y handled) | list_directory + 2-3 broad greps | Rarely early |
|
|
270
|
+
| **Exploratory** (find all tests, list API endpoints) | list_directory at multiple depths | Usually needs 3 rounds |
|
|
212
271
|
|
|
213
272
|
**Parallel call patterns:**
|
|
214
273
|
- **Shotgun grep**: Same pattern, 8 different directories\u2014fast coverage
|
|
215
274
|
- **Variant grep**: 8 pattern variations (synonyms, naming conventions)\u2014catches inconsistent codebases
|
|
216
|
-
- **Funnel**: 1
|
|
275
|
+
- **Funnel**: 1 list_directory + 7 greps\u2014orient and search simultaneously
|
|
217
276
|
- **Deep read**: 8 reads on files you already identified\u2014gather full context fast
|
|
277
|
+
|
|
278
|
+
**Tool call expectations:**
|
|
279
|
+
- Low quality tool calls are ones that give back sparse information. This either means they are not well thought out and are not educated guesses OR, they are too broad and give back too many results.
|
|
280
|
+
- High quality tool calls strike a balance between complexity in the tool call to exclude results we know we don't want, and how wide the search space is so that we don't miss anything. It is ok to start off with wider search spaces, but is imperative that you use your intuition from there on out and seek high quality tool calls only.
|
|
281
|
+
- You are not starting blind, you have some information about root level repo structure going in, so use that to prevent making trivial repo wide queries.
|
|
282
|
+
- The grep tool shows you which file path and line numbers the pattern was found in, use this information smartly when trying to read the file.
|
|
218
283
|
</strategy>
|
|
219
284
|
|
|
220
285
|
<output_format>
|
|
221
286
|
EVERY response MUST follow this exact format:
|
|
222
287
|
|
|
223
288
|
1. First, wrap your reasoning in \`<think>...</think>\` tags containing:
|
|
224
|
-
-
|
|
225
|
-
- Confidence estimate (can I finish in 1-2
|
|
226
|
-
- This
|
|
289
|
+
- Search_string classification (specific/conceptual/exploratory)
|
|
290
|
+
- Confidence estimate (can I finish in 1-2 rounds?)
|
|
291
|
+
- This round's parallel strategy
|
|
227
292
|
- What signals would let me finish early?
|
|
228
293
|
|
|
229
|
-
2. Then, output
|
|
294
|
+
2. Then, output up to 8 tool calls using nested XML elements.
|
|
230
295
|
|
|
231
296
|
Example:
|
|
232
297
|
\`\`\`
|
|
233
298
|
<think>
|
|
234
|
-
This is a specific
|
|
235
|
-
High confidence I can finish in 2
|
|
299
|
+
This is a specific search_string about authentication. I'll grep for auth-related patterns.
|
|
300
|
+
High confidence I can finish in 2 rounds if I find the auth module. I have already been shown the repo's structure at root
|
|
236
301
|
Strategy: Shotgun grep across likely directories.
|
|
237
302
|
</think>
|
|
238
|
-
<
|
|
239
|
-
<
|
|
240
|
-
<
|
|
303
|
+
<grep>
|
|
304
|
+
<pattern>(authenticate|login|session)</pattern>
|
|
305
|
+
<sub_dir>src/auth/</sub_dir>
|
|
306
|
+
</grep>
|
|
307
|
+
<grep>
|
|
308
|
+
<pattern>(middleware|interceptor)</pattern>
|
|
309
|
+
<glob>*.{ts,js}</glob>
|
|
310
|
+
</grep>
|
|
311
|
+
<list_directory>
|
|
312
|
+
<path>src/auth</path>
|
|
313
|
+
</list_directory>
|
|
314
|
+
\`\`\`
|
|
315
|
+
|
|
316
|
+
Finishing example:
|
|
317
|
+
\`\`\`
|
|
318
|
+
<think>
|
|
319
|
+
I think I have a rough idea, but this is my last turn so I must call the finish tool regardless.
|
|
320
|
+
</think>
|
|
321
|
+
<finish>
|
|
322
|
+
<file>
|
|
323
|
+
<path>src/auth/login.py</path>
|
|
324
|
+
<lines>1-50</lines>
|
|
325
|
+
</file>
|
|
326
|
+
<file>
|
|
327
|
+
<path>src/middleware/session.py</path>
|
|
328
|
+
<lines>10-80</lines>
|
|
329
|
+
</file>
|
|
330
|
+
</finish>
|
|
241
331
|
\`\`\`
|
|
242
332
|
|
|
243
333
|
No commentary outside \`<think>\`. No explanations after tool calls.
|
|
@@ -250,17 +340,111 @@ When calling \`finish\`:
|
|
|
250
340
|
- Include any type definitions, interfaces, or constants used
|
|
251
341
|
- Better to over-include than leave the user missing context
|
|
252
342
|
- If unsure about boundaries, include more rather than less
|
|
253
|
-
</finishing_requirements
|
|
254
|
-
|
|
255
|
-
Begin your exploration now to find code relevant to the query.`;
|
|
343
|
+
</finishing_requirements>`;
|
|
256
344
|
function getSystemPrompt() {
|
|
257
345
|
return SYSTEM_PROMPT;
|
|
258
346
|
}
|
|
259
347
|
|
|
260
348
|
// tools/warp_grep/agent/parser.ts
|
|
261
|
-
var VALID_COMMANDS = ["
|
|
349
|
+
var VALID_COMMANDS = ["list_directory", "grep", "read", "finish"];
|
|
350
|
+
function isValidCommand(name) {
|
|
351
|
+
return VALID_COMMANDS.includes(name);
|
|
352
|
+
}
|
|
353
|
+
function getXmlElementText(xml, tagName) {
|
|
354
|
+
const regex = new RegExp(`<${tagName}>([\\s\\S]*?)</${tagName}>`, "i");
|
|
355
|
+
const match = xml.match(regex);
|
|
356
|
+
return match ? match[1].trim() : null;
|
|
357
|
+
}
|
|
358
|
+
function parseNestedXmlTools(text) {
|
|
359
|
+
const tools = [];
|
|
360
|
+
const toolRegex = /<([a-z_][a-z0-9_]*)>([\s\S]*?)<\/\1>/gi;
|
|
361
|
+
let match;
|
|
362
|
+
while ((match = toolRegex.exec(text)) !== null) {
|
|
363
|
+
const rawToolName = match[1].toLowerCase();
|
|
364
|
+
const content = match[2];
|
|
365
|
+
if (!isValidCommand(rawToolName)) continue;
|
|
366
|
+
const toolName = rawToolName;
|
|
367
|
+
if (toolName === "list_directory") {
|
|
368
|
+
const path5 = getXmlElementText(content, "path");
|
|
369
|
+
const pattern = getXmlElementText(content, "pattern");
|
|
370
|
+
if (path5) {
|
|
371
|
+
tools.push({ name: "list_directory", arguments: { path: path5, pattern } });
|
|
372
|
+
}
|
|
373
|
+
} else if (toolName === "grep") {
|
|
374
|
+
const pattern = getXmlElementText(content, "pattern");
|
|
375
|
+
const subDir = getXmlElementText(content, "sub_dir");
|
|
376
|
+
const glob = getXmlElementText(content, "glob");
|
|
377
|
+
if (pattern) {
|
|
378
|
+
tools.push({
|
|
379
|
+
name: "grep",
|
|
380
|
+
arguments: {
|
|
381
|
+
pattern,
|
|
382
|
+
path: subDir || ".",
|
|
383
|
+
...glob && { glob }
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
} else if (toolName === "read") {
|
|
388
|
+
const path5 = getXmlElementText(content, "path");
|
|
389
|
+
const linesStr = getXmlElementText(content, "lines");
|
|
390
|
+
if (path5) {
|
|
391
|
+
const args = { path: path5 };
|
|
392
|
+
if (linesStr) {
|
|
393
|
+
const ranges = [];
|
|
394
|
+
for (const rangeStr of linesStr.split(",")) {
|
|
395
|
+
const trimmed = rangeStr.trim();
|
|
396
|
+
if (!trimmed) continue;
|
|
397
|
+
const [s, e] = trimmed.split("-").map((v) => parseInt(v.trim(), 10));
|
|
398
|
+
if (Number.isFinite(s) && Number.isFinite(e)) {
|
|
399
|
+
ranges.push([s, e]);
|
|
400
|
+
} else if (Number.isFinite(s)) {
|
|
401
|
+
ranges.push([s, s]);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (ranges.length === 1) {
|
|
405
|
+
args.start = ranges[0][0];
|
|
406
|
+
args.end = ranges[0][1];
|
|
407
|
+
} else if (ranges.length > 1) {
|
|
408
|
+
args.lines = ranges;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
tools.push({ name: "read", arguments: args });
|
|
412
|
+
}
|
|
413
|
+
} else if (toolName === "finish") {
|
|
414
|
+
const fileRegex = /<file>([\s\S]*?)<\/file>/gi;
|
|
415
|
+
const files = [];
|
|
416
|
+
let fileMatch;
|
|
417
|
+
while ((fileMatch = fileRegex.exec(content)) !== null) {
|
|
418
|
+
const fileContent = fileMatch[1];
|
|
419
|
+
const filePath = getXmlElementText(fileContent, "path");
|
|
420
|
+
const linesStr = getXmlElementText(fileContent, "lines");
|
|
421
|
+
if (filePath && linesStr) {
|
|
422
|
+
const ranges = [];
|
|
423
|
+
for (const rangeStr of linesStr.split(",")) {
|
|
424
|
+
if (rangeStr.trim() === "*") {
|
|
425
|
+
ranges.push([1, 999999]);
|
|
426
|
+
} else {
|
|
427
|
+
const [s, e] = rangeStr.split("-").map((v) => parseInt(v.trim(), 10));
|
|
428
|
+
if (Number.isFinite(s) && Number.isFinite(e)) {
|
|
429
|
+
ranges.push([s, e]);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
if (ranges.length > 0) {
|
|
434
|
+
files.push({ path: filePath, lines: ranges });
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if (files.length > 0) {
|
|
439
|
+
tools.push({ name: "finish", arguments: { files } });
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return tools;
|
|
444
|
+
}
|
|
262
445
|
function preprocessText(text) {
|
|
263
446
|
let processed = text.replace(/<think>[\s\S]*?<\/think>/gi, "");
|
|
447
|
+
const nestedTools = parseNestedXmlTools(processed);
|
|
264
448
|
const openingTagRegex = /<tool_call>|<tool>/gi;
|
|
265
449
|
const closingTagRegex = /<\/tool_call>|<\/tool>/gi;
|
|
266
450
|
const openingMatches = processed.match(openingTagRegex) || [];
|
|
@@ -297,7 +481,7 @@ function preprocessText(text) {
|
|
|
297
481
|
}
|
|
298
482
|
}
|
|
299
483
|
}
|
|
300
|
-
return toolCallLines;
|
|
484
|
+
return { lines: toolCallLines, nestedTools };
|
|
301
485
|
}
|
|
302
486
|
var LLMResponseParser = class {
|
|
303
487
|
finishSpecSplitRe = /,(?=[^,\s]+:)/;
|
|
@@ -305,8 +489,8 @@ var LLMResponseParser = class {
|
|
|
305
489
|
if (typeof text !== "string") {
|
|
306
490
|
throw new TypeError("Command text must be a string.");
|
|
307
491
|
}
|
|
308
|
-
const lines = preprocessText(text);
|
|
309
|
-
const commands = [];
|
|
492
|
+
const { lines, nestedTools } = preprocessText(text);
|
|
493
|
+
const commands = [...nestedTools];
|
|
310
494
|
let finishAccumulator = null;
|
|
311
495
|
lines.forEach((line) => {
|
|
312
496
|
if (!line || line.startsWith("#")) return;
|
|
@@ -314,8 +498,8 @@ var LLMResponseParser = class {
|
|
|
314
498
|
if (parts.length === 0) return;
|
|
315
499
|
const cmd = parts[0];
|
|
316
500
|
switch (cmd) {
|
|
317
|
-
case "
|
|
318
|
-
this.
|
|
501
|
+
case "list_directory":
|
|
502
|
+
this.handleListDirectory(parts, line, commands);
|
|
319
503
|
break;
|
|
320
504
|
case "grep":
|
|
321
505
|
this.handleGrep(parts, line, commands);
|
|
@@ -333,8 +517,8 @@ var LLMResponseParser = class {
|
|
|
333
517
|
if (finishAccumulator) {
|
|
334
518
|
const map = finishAccumulator;
|
|
335
519
|
const entries = [...map.entries()];
|
|
336
|
-
const filesPayload = entries.map(([
|
|
337
|
-
path:
|
|
520
|
+
const filesPayload = entries.map(([path5, ranges]) => ({
|
|
521
|
+
path: path5,
|
|
338
522
|
lines: [...ranges].sort((a, b) => a[0] - b[0])
|
|
339
523
|
}));
|
|
340
524
|
commands.push({ name: "finish", arguments: { files: filesPayload } });
|
|
@@ -366,18 +550,17 @@ var LLMResponseParser = class {
|
|
|
366
550
|
skip(message) {
|
|
367
551
|
return { name: "_skip", arguments: { message } };
|
|
368
552
|
}
|
|
369
|
-
|
|
553
|
+
handleListDirectory(parts, rawLine, commands) {
|
|
370
554
|
if (parts.length < 2) {
|
|
371
555
|
commands.push(this.skip(
|
|
372
|
-
`[SKIPPED] Your command "${rawLine}" is missing a path. Correct format:
|
|
556
|
+
`[SKIPPED] Your command "${rawLine}" is missing a path. Correct format: list_directory <path> [pattern]. Example: list_directory src/`
|
|
373
557
|
));
|
|
374
558
|
return;
|
|
375
559
|
}
|
|
376
|
-
const
|
|
560
|
+
const path5 = parts[1];
|
|
377
561
|
const pattern = parts[2]?.replace(/^"|"$/g, "") ?? null;
|
|
378
|
-
commands.push({ name: "
|
|
562
|
+
commands.push({ name: "list_directory", arguments: { path: path5, pattern } });
|
|
379
563
|
}
|
|
380
|
-
// no glob tool in MCP
|
|
381
564
|
handleGrep(parts, rawLine, commands) {
|
|
382
565
|
if (parts.length < 3) {
|
|
383
566
|
commands.push(this.skip(
|
|
@@ -448,8 +631,30 @@ var LLMResponseParser = class {
|
|
|
448
631
|
}
|
|
449
632
|
};
|
|
450
633
|
|
|
451
|
-
// tools/warp_grep/tools/
|
|
634
|
+
// tools/warp_grep/agent/tools/grep.ts
|
|
635
|
+
async function toolGrep(provider, args) {
|
|
636
|
+
const res = await provider.grep(args);
|
|
637
|
+
if (res.error) {
|
|
638
|
+
return { output: res.error };
|
|
639
|
+
}
|
|
640
|
+
if (!res.lines.length) {
|
|
641
|
+
return { output: "no matches" };
|
|
642
|
+
}
|
|
643
|
+
return { output: res.lines.join("\n") };
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// tools/warp_grep/agent/tools/read.ts
|
|
452
647
|
async function toolRead(provider, args) {
|
|
648
|
+
if (args.lines && args.lines.length > 0) {
|
|
649
|
+
const chunks = [];
|
|
650
|
+
for (const [start, end] of args.lines) {
|
|
651
|
+
const res2 = await provider.read({ path: args.path, start, end });
|
|
652
|
+
if (res2.error) return res2.error;
|
|
653
|
+
chunks.push(res2.lines.join("\n"));
|
|
654
|
+
}
|
|
655
|
+
if (chunks.every((c) => c === "")) return "(empty file)";
|
|
656
|
+
return chunks.join("\n...\n");
|
|
657
|
+
}
|
|
453
658
|
const res = await provider.read({ path: args.path, start: args.start, end: args.end });
|
|
454
659
|
if (res.error) {
|
|
455
660
|
return res.error;
|
|
@@ -458,16 +663,62 @@ async function toolRead(provider, args) {
|
|
|
458
663
|
return res.lines.join("\n");
|
|
459
664
|
}
|
|
460
665
|
|
|
461
|
-
// tools/warp_grep/tools/
|
|
462
|
-
async function
|
|
463
|
-
const list = await provider.
|
|
666
|
+
// tools/warp_grep/agent/tools/list_directory.ts
|
|
667
|
+
async function toolListDirectory(provider, args) {
|
|
668
|
+
const list = await provider.listDirectory({
|
|
464
669
|
path: args.path,
|
|
465
670
|
pattern: args.pattern ?? null,
|
|
466
|
-
maxResults: args.maxResults ??
|
|
467
|
-
maxDepth: args.maxDepth ??
|
|
671
|
+
maxResults: args.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES,
|
|
672
|
+
maxDepth: args.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH
|
|
468
673
|
});
|
|
469
674
|
if (!list.length) return "empty";
|
|
470
|
-
|
|
675
|
+
if (list.length >= AGENT_CONFIG.MAX_OUTPUT_LINES) {
|
|
676
|
+
return "query not specific enough, tool called tried to return too much context and failed";
|
|
677
|
+
}
|
|
678
|
+
return list.map((e) => {
|
|
679
|
+
const indent = " ".repeat(e.depth);
|
|
680
|
+
const name = e.type === "dir" ? `${e.name}/` : e.name;
|
|
681
|
+
return `${indent}${name}`;
|
|
682
|
+
}).join("\n");
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// tools/warp_grep/agent/tools/finish.ts
|
|
686
|
+
function normalizeFinishFiles(files) {
|
|
687
|
+
return files.map((f) => {
|
|
688
|
+
const merged = mergeRanges(f.lines);
|
|
689
|
+
return { path: f.path, lines: merged };
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
async function readFinishFiles(repoRoot, files, reader) {
|
|
693
|
+
const out = [];
|
|
694
|
+
for (const f of files) {
|
|
695
|
+
const ranges = mergeRanges(f.lines);
|
|
696
|
+
const chunks = [];
|
|
697
|
+
for (const [s, e] of ranges) {
|
|
698
|
+
const lines = await reader(f.path, s, e);
|
|
699
|
+
chunks.push(lines.join("\n"));
|
|
700
|
+
}
|
|
701
|
+
out.push({ path: f.path, ranges, content: chunks.join("\n") });
|
|
702
|
+
}
|
|
703
|
+
return out;
|
|
704
|
+
}
|
|
705
|
+
function mergeRanges(ranges) {
|
|
706
|
+
if (!ranges.length) return [];
|
|
707
|
+
const sorted = [...ranges].sort((a, b) => a[0] - b[0]);
|
|
708
|
+
const merged = [];
|
|
709
|
+
let [cs, ce] = sorted[0];
|
|
710
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
711
|
+
const [s, e] = sorted[i];
|
|
712
|
+
if (s <= ce + 1) {
|
|
713
|
+
ce = Math.max(ce, e);
|
|
714
|
+
} else {
|
|
715
|
+
merged.push([cs, ce]);
|
|
716
|
+
cs = s;
|
|
717
|
+
ce = e;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
merged.push([cs, ce]);
|
|
721
|
+
return merged;
|
|
471
722
|
}
|
|
472
723
|
|
|
473
724
|
// tools/utils/resilience.ts
|
|
@@ -560,8 +811,8 @@ var ToolOutputFormatter = class {
|
|
|
560
811
|
switch (name) {
|
|
561
812
|
case "read":
|
|
562
813
|
return this.formatRead(safeArgs, payload, isError);
|
|
563
|
-
case "
|
|
564
|
-
return this.
|
|
814
|
+
case "list_directory":
|
|
815
|
+
return this.formatListDirectory(safeArgs, payload, isError);
|
|
565
816
|
case "grep":
|
|
566
817
|
return this.formatGrep(safeArgs, payload, isError);
|
|
567
818
|
default:
|
|
@@ -574,39 +825,56 @@ ${payload}
|
|
|
574
825
|
if (isError) {
|
|
575
826
|
return payload;
|
|
576
827
|
}
|
|
577
|
-
const
|
|
578
|
-
|
|
828
|
+
const path5 = this.asString(args.path) || "...";
|
|
829
|
+
const start = args.start;
|
|
830
|
+
const end = args.end;
|
|
831
|
+
const linesArray = args.lines;
|
|
832
|
+
const attributes = [`path="${path5}"`];
|
|
833
|
+
if (linesArray && linesArray.length > 0) {
|
|
834
|
+
const rangeStr = linesArray.map(([s, e]) => `${s}-${e}`).join(",");
|
|
835
|
+
attributes.push(`lines="${rangeStr}"`);
|
|
836
|
+
} else if (start !== void 0 && end !== void 0) {
|
|
837
|
+
attributes.push(`lines="${start}-${end}"`);
|
|
838
|
+
}
|
|
839
|
+
return `<read ${attributes.join(" ")}>
|
|
579
840
|
${payload}
|
|
580
|
-
</
|
|
841
|
+
</read>`;
|
|
581
842
|
}
|
|
582
|
-
|
|
583
|
-
const
|
|
843
|
+
formatListDirectory(args, payload, isError) {
|
|
844
|
+
const path5 = this.asString(args.path) || ".";
|
|
845
|
+
const pattern = this.asString(args.pattern);
|
|
846
|
+
const attributes = [`path="${path5}"`];
|
|
847
|
+
if (pattern) {
|
|
848
|
+
attributes.push(`pattern="${pattern}"`);
|
|
849
|
+
}
|
|
584
850
|
if (isError) {
|
|
585
|
-
|
|
586
|
-
${payload}
|
|
587
|
-
</analyse_results>`;
|
|
851
|
+
attributes.push('status="error"');
|
|
588
852
|
}
|
|
589
|
-
return `<
|
|
853
|
+
return `<list_directory ${attributes.join(" ")}>
|
|
590
854
|
${payload}
|
|
591
|
-
</
|
|
855
|
+
</list_directory>`;
|
|
592
856
|
}
|
|
593
857
|
formatGrep(args, payload, isError) {
|
|
594
858
|
const pattern = this.asString(args.pattern);
|
|
595
|
-
const
|
|
859
|
+
const subDir = this.asString(args.path);
|
|
860
|
+
const glob = this.asString(args.glob);
|
|
596
861
|
const attributes = [];
|
|
597
862
|
if (pattern !== void 0) {
|
|
598
863
|
attributes.push(`pattern="${pattern}"`);
|
|
599
864
|
}
|
|
600
|
-
if (
|
|
601
|
-
attributes.push(`
|
|
865
|
+
if (subDir !== void 0) {
|
|
866
|
+
attributes.push(`sub_dir="${subDir}"`);
|
|
867
|
+
}
|
|
868
|
+
if (glob !== void 0) {
|
|
869
|
+
attributes.push(`glob="${glob}"`);
|
|
602
870
|
}
|
|
603
871
|
if (isError) {
|
|
604
872
|
attributes.push('status="error"');
|
|
605
873
|
}
|
|
606
874
|
const attrText = attributes.length ? ` ${attributes.join(" ")}` : "";
|
|
607
|
-
return `<
|
|
875
|
+
return `<grep${attrText}>
|
|
608
876
|
${payload}
|
|
609
|
-
</
|
|
877
|
+
</grep>`;
|
|
610
878
|
}
|
|
611
879
|
asString(value) {
|
|
612
880
|
if (value === null || value === void 0) {
|
|
@@ -620,66 +888,100 @@ function formatAgentToolOutput(toolName, args, output, options = {}) {
|
|
|
620
888
|
return sharedFormatter.format(toolName, args, output, options);
|
|
621
889
|
}
|
|
622
890
|
|
|
623
|
-
// tools/warp_grep/
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
chunks.push(lines.join("\n"));
|
|
632
|
-
}
|
|
633
|
-
out.push({ path: f.path, ranges, content: chunks.join("\n") });
|
|
891
|
+
// tools/warp_grep/agent/helpers.ts
|
|
892
|
+
var import_path = __toESM(require("path"), 1);
|
|
893
|
+
var TRUNCATED_MARKER = "[truncated for context limit]";
|
|
894
|
+
function formatTurnMessage(turnsUsed, maxTurns) {
|
|
895
|
+
const turnsRemaining = maxTurns - turnsUsed;
|
|
896
|
+
if (turnsRemaining === 1) {
|
|
897
|
+
return `
|
|
898
|
+
You have used ${turnsUsed} turns, you only have 1 turn remaining. You have run out of turns to explore the code base and MUST call the finish tool now`;
|
|
634
899
|
}
|
|
635
|
-
return
|
|
900
|
+
return `
|
|
901
|
+
You have used ${turnsUsed} turn${turnsUsed === 1 ? "" : "s"} and have ${turnsRemaining} remaining`;
|
|
636
902
|
}
|
|
637
|
-
function
|
|
638
|
-
|
|
639
|
-
const
|
|
640
|
-
const
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
if (s <= ce + 1) {
|
|
645
|
-
ce = Math.max(ce, e);
|
|
646
|
-
} else {
|
|
647
|
-
merged.push([cs, ce]);
|
|
648
|
-
cs = s;
|
|
649
|
-
ce = e;
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
merged.push([cs, ce]);
|
|
653
|
-
return merged;
|
|
903
|
+
function calculateContextBudget(messages) {
|
|
904
|
+
const totalChars = messages.reduce((sum, m) => sum + m.content.length, 0);
|
|
905
|
+
const maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS;
|
|
906
|
+
const percent = Math.round(totalChars / maxChars * 100);
|
|
907
|
+
const usedK = Math.round(totalChars / 1e3);
|
|
908
|
+
const maxK = Math.round(maxChars / 1e3);
|
|
909
|
+
return `<context_budget>${percent}% (${usedK}K/${maxK}K chars)</context_budget>`;
|
|
654
910
|
}
|
|
655
|
-
|
|
656
|
-
// tools/warp_grep/agent/runner.ts
|
|
657
|
-
var import_path = __toESM(require("path"), 1);
|
|
658
|
-
var parser = new LLMResponseParser();
|
|
659
911
|
async function buildInitialState(repoRoot, query, provider) {
|
|
660
912
|
try {
|
|
661
|
-
const entries = await provider.
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
913
|
+
const entries = await provider.listDirectory({
|
|
914
|
+
path: ".",
|
|
915
|
+
maxResults: AGENT_CONFIG.MAX_OUTPUT_LINES,
|
|
916
|
+
maxDepth: 2
|
|
917
|
+
});
|
|
918
|
+
const treeLines = entries.map((e) => {
|
|
919
|
+
const indent = " ".repeat(e.depth);
|
|
920
|
+
const name = e.type === "dir" ? `${e.name}/` : e.name;
|
|
921
|
+
return `${indent}${name}`;
|
|
922
|
+
});
|
|
923
|
+
const repoName = import_path.default.basename(repoRoot);
|
|
924
|
+
const treeOutput = treeLines.length > 0 ? `${repoName}/
|
|
925
|
+
${treeLines.join("\n")}` : `${repoName}/`;
|
|
926
|
+
return `<repo_structure>
|
|
927
|
+
${treeOutput}
|
|
928
|
+
</repo_structure>
|
|
929
|
+
|
|
930
|
+
<search_string>
|
|
931
|
+
${query}
|
|
932
|
+
</search_string>`;
|
|
670
933
|
} catch {
|
|
671
|
-
|
|
934
|
+
const repoName = import_path.default.basename(repoRoot);
|
|
935
|
+
return `<repo_structure>
|
|
936
|
+
${repoName}/
|
|
937
|
+
</repo_structure>
|
|
938
|
+
|
|
939
|
+
<search_string>
|
|
940
|
+
${query}
|
|
941
|
+
</search_string>`;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
function enforceContextLimit(messages, maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS) {
|
|
945
|
+
const getTotalChars = () => messages.reduce((sum, m) => sum + m.content.length, 0);
|
|
946
|
+
if (getTotalChars() <= maxChars) {
|
|
947
|
+
return messages;
|
|
948
|
+
}
|
|
949
|
+
const userIndices = [];
|
|
950
|
+
let firstUserSkipped = false;
|
|
951
|
+
for (let i = 0; i < messages.length; i++) {
|
|
952
|
+
if (messages[i].role === "user") {
|
|
953
|
+
if (!firstUserSkipped) {
|
|
954
|
+
firstUserSkipped = true;
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
957
|
+
userIndices.push(i);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
for (const idx of userIndices) {
|
|
961
|
+
if (getTotalChars() <= maxChars) {
|
|
962
|
+
break;
|
|
963
|
+
}
|
|
964
|
+
if (messages[idx].content !== TRUNCATED_MARKER) {
|
|
965
|
+
messages[idx] = { role: "user", content: TRUNCATED_MARKER };
|
|
966
|
+
}
|
|
672
967
|
}
|
|
968
|
+
return messages;
|
|
673
969
|
}
|
|
674
|
-
|
|
675
|
-
|
|
970
|
+
|
|
971
|
+
// tools/warp_grep/agent/runner.ts
|
|
972
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
973
|
+
var parser = new LLMResponseParser();
|
|
974
|
+
var DEFAULT_API_URL = "https://api.morphllm.com";
|
|
975
|
+
async function callModel(messages, model, options = {}) {
|
|
976
|
+
const baseUrl = DEFAULT_API_URL;
|
|
977
|
+
const apiKey = options.morphApiKey || process.env.MORPH_API_KEY || "";
|
|
676
978
|
const fetchPromise = fetchWithRetry(
|
|
677
|
-
|
|
979
|
+
`${baseUrl}/v1/chat/completions`,
|
|
678
980
|
{
|
|
679
981
|
method: "POST",
|
|
680
982
|
headers: {
|
|
681
983
|
"Content-Type": "application/json",
|
|
682
|
-
Authorization: `Bearer ${apiKey
|
|
984
|
+
Authorization: `Bearer ${apiKey}`
|
|
683
985
|
},
|
|
684
986
|
body: JSON.stringify({
|
|
685
987
|
model,
|
|
@@ -688,10 +990,15 @@ async function callModel(messages, model, apiKey) {
|
|
|
688
990
|
messages
|
|
689
991
|
})
|
|
690
992
|
},
|
|
691
|
-
|
|
993
|
+
options.retryConfig
|
|
692
994
|
);
|
|
693
995
|
const resp = await withTimeout(fetchPromise, AGENT_CONFIG.TIMEOUT_MS, "morph-warp-grep request timed out");
|
|
694
996
|
if (!resp.ok) {
|
|
997
|
+
if (resp.status === 404) {
|
|
998
|
+
throw new Error(
|
|
999
|
+
"The endpoint you are trying to call is likely deprecated. Please update with: npm cache clean --force && npx -y @morphllm/morphmcp@latest or visit: https://morphllm.com/mcp"
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
695
1002
|
const t = await resp.text();
|
|
696
1003
|
throw new Error(`morph-warp-grep error ${resp.status}: ${t}`);
|
|
697
1004
|
}
|
|
@@ -703,22 +1010,24 @@ async function callModel(messages, model, apiKey) {
|
|
|
703
1010
|
return content;
|
|
704
1011
|
}
|
|
705
1012
|
async function runWarpGrep(config) {
|
|
706
|
-
const repoRoot =
|
|
1013
|
+
const repoRoot = import_path2.default.resolve(config.repoRoot || process.cwd());
|
|
707
1014
|
const messages = [];
|
|
708
|
-
|
|
709
|
-
messages.push(systemMessage);
|
|
710
|
-
const queryContent = `<query>${config.query}</query>`;
|
|
711
|
-
messages.push({ role: "user", content: queryContent });
|
|
1015
|
+
messages.push({ role: "system", content: getSystemPrompt() });
|
|
712
1016
|
const initialState = await buildInitialState(repoRoot, config.query, config.provider);
|
|
713
1017
|
messages.push({ role: "user", content: initialState });
|
|
714
|
-
const
|
|
1018
|
+
const maxTurns = AGENT_CONFIG.MAX_TURNS;
|
|
715
1019
|
const model = config.model || DEFAULT_MODEL;
|
|
716
1020
|
const provider = config.provider;
|
|
717
1021
|
const errors = [];
|
|
718
1022
|
let finishMeta;
|
|
719
1023
|
let terminationReason = "terminated";
|
|
720
|
-
for (let
|
|
721
|
-
|
|
1024
|
+
for (let turn = 1; turn <= maxTurns; turn += 1) {
|
|
1025
|
+
enforceContextLimit(messages);
|
|
1026
|
+
const assistantContent = await callModel(messages, model, {
|
|
1027
|
+
morphApiKey: config.morphApiKey,
|
|
1028
|
+
morphApiUrl: config.morphApiUrl,
|
|
1029
|
+
retryConfig: config.retryConfig
|
|
1030
|
+
}).catch((e) => {
|
|
722
1031
|
errors.push({ message: e instanceof Error ? e.message : String(e) });
|
|
723
1032
|
return "";
|
|
724
1033
|
});
|
|
@@ -726,13 +1035,13 @@ async function runWarpGrep(config) {
|
|
|
726
1035
|
messages.push({ role: "assistant", content: assistantContent });
|
|
727
1036
|
const toolCalls = parser.parse(assistantContent);
|
|
728
1037
|
if (toolCalls.length === 0) {
|
|
729
|
-
errors.push({ message: "No tool calls produced by the model." });
|
|
1038
|
+
errors.push({ message: "No tool calls produced by the model. Your MCP is likely out of date! Update it by running: npm cache clean --force && npx -y @morphllm/morphmcp@latest" });
|
|
730
1039
|
terminationReason = "terminated";
|
|
731
1040
|
break;
|
|
732
1041
|
}
|
|
733
1042
|
const finishCalls = toolCalls.filter((c) => c.name === "finish");
|
|
734
1043
|
const grepCalls = toolCalls.filter((c) => c.name === "grep");
|
|
735
|
-
const
|
|
1044
|
+
const listDirCalls = toolCalls.filter((c) => c.name === "list_directory");
|
|
736
1045
|
const readCalls = toolCalls.filter((c) => c.name === "read");
|
|
737
1046
|
const skipCalls = toolCalls.filter((c) => c.name === "_skip");
|
|
738
1047
|
const formatted = [];
|
|
@@ -744,24 +1053,18 @@ async function runWarpGrep(config) {
|
|
|
744
1053
|
for (const c of grepCalls) {
|
|
745
1054
|
const args = c.arguments ?? {};
|
|
746
1055
|
allPromises.push(
|
|
747
|
-
provider
|
|
748
|
-
(
|
|
749
|
-
if (grepRes.error) {
|
|
750
|
-
return { terminate: true, error: grepRes.error };
|
|
751
|
-
}
|
|
752
|
-
const output = grepRes.lines.join("\n") || "no matches";
|
|
753
|
-
return formatAgentToolOutput("grep", args, output, { isError: false });
|
|
754
|
-
},
|
|
1056
|
+
toolGrep(provider, args).then(
|
|
1057
|
+
({ output }) => formatAgentToolOutput("grep", args, output, { isError: false }),
|
|
755
1058
|
(err) => formatAgentToolOutput("grep", args, String(err), { isError: true })
|
|
756
1059
|
)
|
|
757
1060
|
);
|
|
758
1061
|
}
|
|
759
|
-
for (const c of
|
|
1062
|
+
for (const c of listDirCalls) {
|
|
760
1063
|
const args = c.arguments ?? {};
|
|
761
1064
|
allPromises.push(
|
|
762
|
-
|
|
763
|
-
(p) => formatAgentToolOutput("
|
|
764
|
-
(err) => formatAgentToolOutput("
|
|
1065
|
+
toolListDirectory(provider, args).then(
|
|
1066
|
+
(p) => formatAgentToolOutput("list_directory", args, p, { isError: false }),
|
|
1067
|
+
(err) => formatAgentToolOutput("list_directory", args, String(err), { isError: true })
|
|
765
1068
|
)
|
|
766
1069
|
);
|
|
767
1070
|
}
|
|
@@ -776,34 +1079,12 @@ async function runWarpGrep(config) {
|
|
|
776
1079
|
}
|
|
777
1080
|
const allResults = await Promise.all(allPromises);
|
|
778
1081
|
for (const result of allResults) {
|
|
779
|
-
if (typeof result === "object" && "terminate" in result) {
|
|
780
|
-
errors.push({ message: result.error });
|
|
781
|
-
return {
|
|
782
|
-
terminationReason: "terminated",
|
|
783
|
-
messages,
|
|
784
|
-
errors
|
|
785
|
-
};
|
|
786
|
-
}
|
|
787
1082
|
formatted.push(result);
|
|
788
1083
|
}
|
|
789
1084
|
if (formatted.length > 0) {
|
|
790
|
-
const
|
|
791
|
-
const
|
|
792
|
-
|
|
793
|
-
if (turnsRemaining === 0) {
|
|
794
|
-
turnMessage = `
|
|
795
|
-
|
|
796
|
-
[Turn ${turnsUsed}/4] This is your LAST turn. You MUST call the finish tool now.`;
|
|
797
|
-
} else if (turnsRemaining === 1) {
|
|
798
|
-
turnMessage = `
|
|
799
|
-
|
|
800
|
-
[Turn ${turnsUsed}/4] You have 1 turn remaining. Next turn you MUST call the finish tool.`;
|
|
801
|
-
} else {
|
|
802
|
-
turnMessage = `
|
|
803
|
-
|
|
804
|
-
[Turn ${turnsUsed}/4] You have ${turnsRemaining} turns remaining.`;
|
|
805
|
-
}
|
|
806
|
-
messages.push({ role: "user", content: formatted.join("\n") + turnMessage });
|
|
1085
|
+
const turnMessage = formatTurnMessage(turn, maxTurns);
|
|
1086
|
+
const contextBudget = calculateContextBudget(messages);
|
|
1087
|
+
messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
|
|
807
1088
|
}
|
|
808
1089
|
if (finishCalls.length) {
|
|
809
1090
|
const fc = finishCalls[0];
|
|
@@ -853,7 +1134,7 @@ async function runWarpGrep(config) {
|
|
|
853
1134
|
|
|
854
1135
|
// tools/warp_grep/providers/local.ts
|
|
855
1136
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
856
|
-
var
|
|
1137
|
+
var import_path4 = __toESM(require("path"), 1);
|
|
857
1138
|
|
|
858
1139
|
// tools/warp_grep/utils/ripgrep.ts
|
|
859
1140
|
var import_child_process = require("child_process");
|
|
@@ -918,21 +1199,21 @@ async function runRipgrep(args, opts) {
|
|
|
918
1199
|
|
|
919
1200
|
// tools/warp_grep/utils/paths.ts
|
|
920
1201
|
var import_fs = __toESM(require("fs"), 1);
|
|
921
|
-
var
|
|
1202
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
922
1203
|
function resolveUnderRepo(repoRoot, targetPath) {
|
|
923
|
-
const absRoot =
|
|
924
|
-
const resolved =
|
|
1204
|
+
const absRoot = import_path3.default.resolve(repoRoot);
|
|
1205
|
+
const resolved = import_path3.default.resolve(absRoot, targetPath);
|
|
925
1206
|
ensureWithinRepo(absRoot, resolved);
|
|
926
1207
|
return resolved;
|
|
927
1208
|
}
|
|
928
1209
|
function ensureWithinRepo(repoRoot, absTarget) {
|
|
929
|
-
const rel =
|
|
930
|
-
if (rel.startsWith("..") ||
|
|
1210
|
+
const rel = import_path3.default.relative(import_path3.default.resolve(repoRoot), import_path3.default.resolve(absTarget));
|
|
1211
|
+
if (rel.startsWith("..") || import_path3.default.isAbsolute(rel)) {
|
|
931
1212
|
throw new Error(`Path outside repository root: ${absTarget}`);
|
|
932
1213
|
}
|
|
933
1214
|
}
|
|
934
1215
|
function toRepoRelative(repoRoot, absPath) {
|
|
935
|
-
return
|
|
1216
|
+
return import_path3.default.relative(import_path3.default.resolve(repoRoot), import_path3.default.resolve(absPath));
|
|
936
1217
|
}
|
|
937
1218
|
function isSymlink(p) {
|
|
938
1219
|
try {
|
|
@@ -975,10 +1256,18 @@ var LocalRipgrepProvider = class {
|
|
|
975
1256
|
this.excludes = excludes;
|
|
976
1257
|
}
|
|
977
1258
|
async grep(params) {
|
|
978
|
-
|
|
1259
|
+
let abs;
|
|
1260
|
+
try {
|
|
1261
|
+
abs = resolveUnderRepo(this.repoRoot, params.path);
|
|
1262
|
+
} catch (err) {
|
|
1263
|
+
return {
|
|
1264
|
+
lines: [],
|
|
1265
|
+
error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
979
1268
|
const stat = await import_promises2.default.stat(abs).catch(() => null);
|
|
980
1269
|
if (!stat) return { lines: [] };
|
|
981
|
-
const targetArg = abs ===
|
|
1270
|
+
const targetArg = abs === import_path4.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
|
|
982
1271
|
const args = [
|
|
983
1272
|
"--no-config",
|
|
984
1273
|
"--no-heading",
|
|
@@ -987,6 +1276,9 @@ var LocalRipgrepProvider = class {
|
|
|
987
1276
|
"--color=never",
|
|
988
1277
|
"--trim",
|
|
989
1278
|
"--max-columns=400",
|
|
1279
|
+
"-C",
|
|
1280
|
+
"1",
|
|
1281
|
+
...params.glob ? ["--glob", params.glob] : [],
|
|
990
1282
|
...this.excludes.flatMap((e) => ["-g", `!${e}`]),
|
|
991
1283
|
params.pattern,
|
|
992
1284
|
targetArg || "."
|
|
@@ -1011,29 +1303,24 @@ Details: ${res.stderr}` : ""}`
|
|
|
1011
1303
|
};
|
|
1012
1304
|
}
|
|
1013
1305
|
const lines = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
const args = [
|
|
1020
|
-
"--no-config",
|
|
1021
|
-
"--files",
|
|
1022
|
-
"-g",
|
|
1023
|
-
params.pattern,
|
|
1024
|
-
...this.excludes.flatMap((e) => ["-g", `!${e}`]),
|
|
1025
|
-
targetArg || "."
|
|
1026
|
-
];
|
|
1027
|
-
const res = await runRipgrep(args, { cwd: this.repoRoot });
|
|
1028
|
-
if (res.exitCode === -1) {
|
|
1029
|
-
console.warn(`[warp_grep] ripgrep not available for glob: ${res.stderr || "execution failed"}`);
|
|
1030
|
-
return { files: [] };
|
|
1306
|
+
if (lines.length > AGENT_CONFIG.MAX_OUTPUT_LINES) {
|
|
1307
|
+
return {
|
|
1308
|
+
lines: [],
|
|
1309
|
+
error: "query not specific enough, tool tried to return too much context and failed"
|
|
1310
|
+
};
|
|
1031
1311
|
}
|
|
1032
|
-
|
|
1033
|
-
return { files };
|
|
1312
|
+
return { lines };
|
|
1034
1313
|
}
|
|
1035
1314
|
async read(params) {
|
|
1036
|
-
|
|
1315
|
+
let abs;
|
|
1316
|
+
try {
|
|
1317
|
+
abs = resolveUnderRepo(this.repoRoot, params.path);
|
|
1318
|
+
} catch (err) {
|
|
1319
|
+
return {
|
|
1320
|
+
lines: [],
|
|
1321
|
+
error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1037
1324
|
const stat = await import_promises2.default.stat(abs).catch(() => null);
|
|
1038
1325
|
if (!stat || !stat.isFile()) {
|
|
1039
1326
|
return {
|
|
@@ -1053,7 +1340,15 @@ Details: ${res.stderr}` : ""}`
|
|
|
1053
1340
|
error: `[UNREADABLE FILE] You tried to read "${params.path}" but this file is either too large or not a text file, so it cannot be read. Try a different file.`
|
|
1054
1341
|
};
|
|
1055
1342
|
}
|
|
1056
|
-
|
|
1343
|
+
let lines;
|
|
1344
|
+
try {
|
|
1345
|
+
lines = await readAllLines(abs);
|
|
1346
|
+
} catch (err) {
|
|
1347
|
+
return {
|
|
1348
|
+
lines: [],
|
|
1349
|
+
error: `[READ ERROR] Failed to read "${params.path}": ${err instanceof Error ? err.message : String(err)}`
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1057
1352
|
const total = lines.length;
|
|
1058
1353
|
let s = params.start ?? 1;
|
|
1059
1354
|
let e = Math.min(params.end ?? total, total);
|
|
@@ -1066,30 +1361,46 @@ Details: ${res.stderr}` : ""}`
|
|
|
1066
1361
|
const content = lines[i - 1] ?? "";
|
|
1067
1362
|
out.push(`${i}|${content}`);
|
|
1068
1363
|
}
|
|
1364
|
+
if (out.length > AGENT_CONFIG.MAX_READ_LINES) {
|
|
1365
|
+
const truncated = out.slice(0, AGENT_CONFIG.MAX_READ_LINES);
|
|
1366
|
+
truncated.push(`... [truncated: showing ${AGENT_CONFIG.MAX_READ_LINES} of ${out.length} lines]`);
|
|
1367
|
+
return { lines: truncated };
|
|
1368
|
+
}
|
|
1069
1369
|
return { lines: out };
|
|
1070
1370
|
}
|
|
1071
|
-
async
|
|
1072
|
-
|
|
1371
|
+
async listDirectory(params) {
|
|
1372
|
+
let abs;
|
|
1373
|
+
try {
|
|
1374
|
+
abs = resolveUnderRepo(this.repoRoot, params.path);
|
|
1375
|
+
} catch {
|
|
1376
|
+
return [];
|
|
1377
|
+
}
|
|
1073
1378
|
const stat = await import_promises2.default.stat(abs).catch(() => null);
|
|
1074
1379
|
if (!stat || !stat.isDirectory()) {
|
|
1075
1380
|
return [];
|
|
1076
1381
|
}
|
|
1077
|
-
const maxResults = params.maxResults ??
|
|
1078
|
-
const maxDepth = params.maxDepth ??
|
|
1382
|
+
const maxResults = params.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;
|
|
1383
|
+
const maxDepth = params.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
|
|
1079
1384
|
const regex = params.pattern ? new RegExp(params.pattern) : null;
|
|
1080
1385
|
const results = [];
|
|
1386
|
+
let timedOut = false;
|
|
1387
|
+
const startTime = Date.now();
|
|
1081
1388
|
async function walk(dir, depth) {
|
|
1389
|
+
if (Date.now() - startTime > AGENT_CONFIG.LIST_TIMEOUT_MS) {
|
|
1390
|
+
timedOut = true;
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1082
1393
|
if (depth > maxDepth || results.length >= maxResults) return;
|
|
1083
1394
|
const entries = await import_promises2.default.readdir(dir, { withFileTypes: true });
|
|
1084
1395
|
for (const entry of entries) {
|
|
1085
|
-
|
|
1396
|
+
if (timedOut || results.length >= maxResults) break;
|
|
1397
|
+
const full = import_path4.default.join(dir, entry.name);
|
|
1086
1398
|
const rel = toRepoRelative(abs, full).replace(/^[.][/\\]?/, "");
|
|
1087
|
-
if (DEFAULT_EXCLUDES.some((ex) => rel.split(
|
|
1399
|
+
if (DEFAULT_EXCLUDES.some((ex) => rel.split(import_path4.default.sep).includes(ex))) continue;
|
|
1088
1400
|
if (regex && !regex.test(entry.name)) continue;
|
|
1089
|
-
if (results.length >= maxResults) break;
|
|
1090
1401
|
results.push({
|
|
1091
1402
|
name: entry.name,
|
|
1092
|
-
path: toRepoRelative(
|
|
1403
|
+
path: toRepoRelative(import_path4.default.resolve(""), full),
|
|
1093
1404
|
// relative display
|
|
1094
1405
|
type: entry.isDirectory() ? "dir" : "file",
|
|
1095
1406
|
depth
|
|
@@ -1104,12 +1415,103 @@ Details: ${res.stderr}` : ""}`
|
|
|
1104
1415
|
}
|
|
1105
1416
|
};
|
|
1106
1417
|
|
|
1107
|
-
// tools/warp_grep/
|
|
1418
|
+
// tools/warp_grep/providers/remote.ts
|
|
1419
|
+
var RemoteCommandsProvider = class {
|
|
1420
|
+
constructor(repoRoot, commands) {
|
|
1421
|
+
this.repoRoot = repoRoot;
|
|
1422
|
+
this.commands = commands;
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* Run grep command and parse ripgrep output
|
|
1426
|
+
*/
|
|
1427
|
+
async grep(params) {
|
|
1428
|
+
try {
|
|
1429
|
+
const stdout = await this.commands.grep(params.pattern, params.path, params.glob);
|
|
1430
|
+
const lines = (stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
|
|
1431
|
+
if (lines.length > AGENT_CONFIG.MAX_OUTPUT_LINES) {
|
|
1432
|
+
return {
|
|
1433
|
+
lines: [],
|
|
1434
|
+
error: "Query not specific enough - too many results returned. Try a more specific pattern."
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
return { lines };
|
|
1438
|
+
} catch (error) {
|
|
1439
|
+
return {
|
|
1440
|
+
lines: [],
|
|
1441
|
+
error: `[GREP ERROR] ${error instanceof Error ? error.message : String(error)}`
|
|
1442
|
+
};
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
/**
|
|
1446
|
+
* Read file and add line numbers
|
|
1447
|
+
*/
|
|
1448
|
+
async read(params) {
|
|
1449
|
+
const start = params.start ?? 1;
|
|
1450
|
+
const end = params.end ?? 1e6;
|
|
1451
|
+
try {
|
|
1452
|
+
const stdout = await this.commands.read(params.path, start, end);
|
|
1453
|
+
const contentLines = (stdout || "").split("\n");
|
|
1454
|
+
if (contentLines.length > 0 && contentLines[contentLines.length - 1] === "") {
|
|
1455
|
+
contentLines.pop();
|
|
1456
|
+
}
|
|
1457
|
+
const lines = contentLines.map((content, idx) => `${start + idx}|${content}`);
|
|
1458
|
+
if (lines.length > AGENT_CONFIG.MAX_READ_LINES) {
|
|
1459
|
+
const truncated = lines.slice(0, AGENT_CONFIG.MAX_READ_LINES);
|
|
1460
|
+
truncated.push(`... [truncated: showing ${AGENT_CONFIG.MAX_READ_LINES} of ${lines.length} lines]`);
|
|
1461
|
+
return { lines: truncated };
|
|
1462
|
+
}
|
|
1463
|
+
return { lines };
|
|
1464
|
+
} catch (error) {
|
|
1465
|
+
return {
|
|
1466
|
+
lines: [],
|
|
1467
|
+
error: `[READ ERROR] ${error instanceof Error ? error.message : String(error)}`
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
/**
|
|
1472
|
+
* List directory and parse find output
|
|
1473
|
+
*/
|
|
1474
|
+
async listDirectory(params) {
|
|
1475
|
+
const maxDepth = params.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
|
|
1476
|
+
const maxResults = params.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;
|
|
1477
|
+
try {
|
|
1478
|
+
const stdout = await this.commands.listDir(params.path, maxDepth);
|
|
1479
|
+
const paths = (stdout || "").trim().split(/\r?\n/).filter((p) => p.length > 0);
|
|
1480
|
+
const regex = params.pattern ? new RegExp(params.pattern) : null;
|
|
1481
|
+
const entries = [];
|
|
1482
|
+
for (const fullPath of paths) {
|
|
1483
|
+
if (fullPath === params.path || fullPath === this.repoRoot) continue;
|
|
1484
|
+
const name = fullPath.split("/").pop() || "";
|
|
1485
|
+
if (regex && !regex.test(name)) continue;
|
|
1486
|
+
let relativePath = fullPath;
|
|
1487
|
+
if (fullPath.startsWith(this.repoRoot)) {
|
|
1488
|
+
relativePath = fullPath.slice(this.repoRoot.length).replace(/^\//, "");
|
|
1489
|
+
}
|
|
1490
|
+
const depth = relativePath.split("/").filter(Boolean).length - 1;
|
|
1491
|
+
const hasExtension = name.includes(".") && !name.startsWith(".");
|
|
1492
|
+
const type = hasExtension ? "file" : "dir";
|
|
1493
|
+
entries.push({
|
|
1494
|
+
name,
|
|
1495
|
+
path: relativePath,
|
|
1496
|
+
type,
|
|
1497
|
+
depth: Math.max(0, depth)
|
|
1498
|
+
});
|
|
1499
|
+
if (entries.length >= maxResults) break;
|
|
1500
|
+
}
|
|
1501
|
+
return entries;
|
|
1502
|
+
} catch (error) {
|
|
1503
|
+
return [];
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
};
|
|
1507
|
+
|
|
1508
|
+
// tools/warp_grep/client.ts
|
|
1108
1509
|
var WarpGrepClient = class {
|
|
1109
1510
|
config;
|
|
1110
1511
|
constructor(config = {}) {
|
|
1111
1512
|
this.config = {
|
|
1112
|
-
|
|
1513
|
+
morphApiKey: config.morphApiKey,
|
|
1514
|
+
morphApiUrl: config.morphApiUrl,
|
|
1113
1515
|
debug: config.debug,
|
|
1114
1516
|
timeout: config.timeout,
|
|
1115
1517
|
retryConfig: config.retryConfig
|
|
@@ -1137,38 +1539,50 @@ var WarpGrepClient = class {
|
|
|
1137
1539
|
* ```
|
|
1138
1540
|
*/
|
|
1139
1541
|
async execute(input) {
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
error: "Search did not complete"
|
|
1155
|
-
};
|
|
1156
|
-
}
|
|
1157
|
-
const contexts = (finish.resolved ?? []).map((r) => ({
|
|
1158
|
-
file: r.path,
|
|
1159
|
-
content: r.content
|
|
1160
|
-
}));
|
|
1161
|
-
return {
|
|
1162
|
-
success: true,
|
|
1163
|
-
contexts,
|
|
1164
|
-
summary: finish.payload
|
|
1165
|
-
};
|
|
1542
|
+
return executeToolCall(
|
|
1543
|
+
{ query: input.query },
|
|
1544
|
+
{
|
|
1545
|
+
repoRoot: input.repoRoot,
|
|
1546
|
+
remoteCommands: input.remoteCommands,
|
|
1547
|
+
provider: input.provider,
|
|
1548
|
+
excludes: input.excludes,
|
|
1549
|
+
includes: input.includes,
|
|
1550
|
+
debug: input.debug ?? this.config.debug,
|
|
1551
|
+
morphApiKey: this.config.morphApiKey,
|
|
1552
|
+
morphApiUrl: this.config.morphApiUrl,
|
|
1553
|
+
retryConfig: this.config.retryConfig
|
|
1554
|
+
}
|
|
1555
|
+
);
|
|
1166
1556
|
}
|
|
1167
1557
|
};
|
|
1168
1558
|
async function executeWarpGrep(input, config) {
|
|
1169
1559
|
const client = new WarpGrepClient(config);
|
|
1170
1560
|
return client.execute(input);
|
|
1171
1561
|
}
|
|
1562
|
+
async function executeToolCall(input, config) {
|
|
1563
|
+
const parsed = typeof input === "string" ? JSON.parse(input) : input;
|
|
1564
|
+
const provider = config.remoteCommands ? new RemoteCommandsProvider(config.repoRoot, config.remoteCommands) : config.provider ?? new LocalRipgrepProvider(config.repoRoot, config.excludes);
|
|
1565
|
+
const result = await runWarpGrep({
|
|
1566
|
+
query: parsed.query,
|
|
1567
|
+
repoRoot: config.repoRoot,
|
|
1568
|
+
provider,
|
|
1569
|
+
excludes: config.excludes,
|
|
1570
|
+
includes: config.includes,
|
|
1571
|
+
debug: config.debug ?? false,
|
|
1572
|
+
morphApiKey: config.morphApiKey,
|
|
1573
|
+
morphApiUrl: config.morphApiUrl,
|
|
1574
|
+
retryConfig: config.retryConfig
|
|
1575
|
+
});
|
|
1576
|
+
const finish = result.finish;
|
|
1577
|
+
if (result.terminationReason !== "completed" || !finish?.metadata) {
|
|
1578
|
+
return { success: false, error: "Search did not complete" };
|
|
1579
|
+
}
|
|
1580
|
+
const contexts = (finish.resolved ?? []).map((r) => ({
|
|
1581
|
+
file: r.path,
|
|
1582
|
+
content: r.content
|
|
1583
|
+
}));
|
|
1584
|
+
return { success: true, contexts, summary: finish.payload };
|
|
1585
|
+
}
|
|
1172
1586
|
function formatResult(result) {
|
|
1173
1587
|
if (!result.success) {
|
|
1174
1588
|
return `Search failed: ${result.error}`;
|
|
@@ -1196,48 +1610,39 @@ function formatResult(result) {
|
|
|
1196
1610
|
var WARP_GREP_TOOL_NAME = "warpgrep_codebase_search";
|
|
1197
1611
|
var WARP_GREP_DESCRIPTION = 'IMPORTANT: If you need to explore the codebase to gather context, and the task does not involve a single file or function which is provided by name, you should ALWAYS use the warpgrep codebase search tool first instead of running search commands. When the task requires exploration beyond a single known file, invoke warpgrep first with a natural-language query describing the target functionality, bug, or architectural concern. Warp Grep is a fast and accurate tool that can search for all relevant context in a codebase. Keep queries action-oriented (e.g., "Find where billing invoices are generated and emailed"), and after reviewing the summarized results, you may verify important findings with other search tools or direct file reads to ensure completeness. Warp Grep can be used for query types like: find function responsible for <small feature>; find code that does <description>; find code path for <big feature>; Where does <minimal error message> come from?; or any query of that type. When a task requires exploration beyond a single known file, ALWAYS default to warpgrep codebase search before other search mechanisms.';
|
|
1198
1612
|
|
|
1199
|
-
// tools/warp_grep/
|
|
1200
|
-
var
|
|
1613
|
+
// tools/warp_grep/anthropic.ts
|
|
1614
|
+
var anthropic_exports = {};
|
|
1615
|
+
__export(anthropic_exports, {
|
|
1616
|
+
createWarpGrepTool: () => createWarpGrepTool,
|
|
1617
|
+
execute: () => execute,
|
|
1618
|
+
formatResult: () => formatResult,
|
|
1619
|
+
getSystemPrompt: () => getSystemPrompt,
|
|
1620
|
+
warpGrepTool: () => warpGrepTool
|
|
1621
|
+
});
|
|
1622
|
+
var INPUT_SCHEMA = {
|
|
1201
1623
|
type: "object",
|
|
1202
1624
|
properties: {
|
|
1203
1625
|
query: { type: "string", description: "Free-form repository question" }
|
|
1204
1626
|
},
|
|
1205
1627
|
required: ["query"]
|
|
1206
1628
|
};
|
|
1629
|
+
var warpGrepTool = {
|
|
1630
|
+
name: WARP_GREP_TOOL_NAME,
|
|
1631
|
+
description: WARP_GREP_DESCRIPTION,
|
|
1632
|
+
input_schema: INPUT_SCHEMA
|
|
1633
|
+
};
|
|
1207
1634
|
async function execute(input, config) {
|
|
1208
|
-
|
|
1209
|
-
const provider = config.provider ?? new LocalRipgrepProvider(config.repoRoot, config.excludes);
|
|
1210
|
-
const result = await runWarpGrep({
|
|
1211
|
-
query: parsed.query,
|
|
1212
|
-
repoRoot: config.repoRoot,
|
|
1213
|
-
provider,
|
|
1214
|
-
excludes: config.excludes,
|
|
1215
|
-
includes: config.includes,
|
|
1216
|
-
debug: config.debug ?? false,
|
|
1217
|
-
apiKey: config.apiKey
|
|
1218
|
-
});
|
|
1219
|
-
const finish = result.finish;
|
|
1220
|
-
if (result.terminationReason !== "completed" || !finish?.metadata) {
|
|
1221
|
-
return { success: false, error: "Search did not complete" };
|
|
1222
|
-
}
|
|
1223
|
-
const contexts = (finish.resolved ?? []).map((r) => ({
|
|
1224
|
-
file: r.path,
|
|
1225
|
-
content: r.content
|
|
1226
|
-
}));
|
|
1227
|
-
return { success: true, contexts, summary: finish.payload };
|
|
1635
|
+
return executeToolCall(input, config);
|
|
1228
1636
|
}
|
|
1229
|
-
function
|
|
1637
|
+
function createWarpGrepTool(config) {
|
|
1230
1638
|
const tool2 = {
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
description: config.description ?? WARP_GREP_DESCRIPTION,
|
|
1235
|
-
parameters: TOOL_PARAMETERS
|
|
1236
|
-
}
|
|
1639
|
+
name: config.name ?? WARP_GREP_TOOL_NAME,
|
|
1640
|
+
description: config.description ?? WARP_GREP_DESCRIPTION,
|
|
1641
|
+
input_schema: INPUT_SCHEMA
|
|
1237
1642
|
};
|
|
1238
1643
|
return Object.assign(tool2, {
|
|
1239
1644
|
execute: async (input) => {
|
|
1240
|
-
return
|
|
1645
|
+
return executeToolCall(input, config);
|
|
1241
1646
|
},
|
|
1242
1647
|
formatResult: (result) => {
|
|
1243
1648
|
return formatResult(result);
|
|
@@ -1248,45 +1653,46 @@ function createMorphWarpGrepTool(config) {
|
|
|
1248
1653
|
});
|
|
1249
1654
|
}
|
|
1250
1655
|
|
|
1251
|
-
// tools/warp_grep/
|
|
1252
|
-
var
|
|
1656
|
+
// tools/warp_grep/openai.ts
|
|
1657
|
+
var openai_exports = {};
|
|
1658
|
+
__export(openai_exports, {
|
|
1659
|
+
createWarpGrepTool: () => createWarpGrepTool2,
|
|
1660
|
+
default: () => openai_default,
|
|
1661
|
+
execute: () => execute2,
|
|
1662
|
+
formatResult: () => formatResult,
|
|
1663
|
+
getSystemPrompt: () => getSystemPrompt,
|
|
1664
|
+
warpGrepTool: () => warpGrepTool2
|
|
1665
|
+
});
|
|
1666
|
+
var TOOL_PARAMETERS = {
|
|
1253
1667
|
type: "object",
|
|
1254
1668
|
properties: {
|
|
1255
1669
|
query: { type: "string", description: "Free-form repository question" }
|
|
1256
1670
|
},
|
|
1257
1671
|
required: ["query"]
|
|
1258
1672
|
};
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
provider,
|
|
1266
|
-
excludes: config.excludes,
|
|
1267
|
-
includes: config.includes,
|
|
1268
|
-
debug: config.debug ?? false,
|
|
1269
|
-
apiKey: config.apiKey
|
|
1270
|
-
});
|
|
1271
|
-
const finish = result.finish;
|
|
1272
|
-
if (result.terminationReason !== "completed" || !finish?.metadata) {
|
|
1273
|
-
return { success: false, error: "Search did not complete" };
|
|
1673
|
+
var warpGrepTool2 = {
|
|
1674
|
+
type: "function",
|
|
1675
|
+
function: {
|
|
1676
|
+
name: WARP_GREP_TOOL_NAME,
|
|
1677
|
+
description: WARP_GREP_DESCRIPTION,
|
|
1678
|
+
parameters: TOOL_PARAMETERS
|
|
1274
1679
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
}));
|
|
1279
|
-
return { success: true, contexts, summary: finish.payload };
|
|
1680
|
+
};
|
|
1681
|
+
async function execute2(input, config) {
|
|
1682
|
+
return executeToolCall(input, config);
|
|
1280
1683
|
}
|
|
1281
|
-
function
|
|
1684
|
+
function createWarpGrepTool2(config) {
|
|
1282
1685
|
const tool2 = {
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1686
|
+
type: "function",
|
|
1687
|
+
function: {
|
|
1688
|
+
name: config.name ?? WARP_GREP_TOOL_NAME,
|
|
1689
|
+
description: config.description ?? WARP_GREP_DESCRIPTION,
|
|
1690
|
+
parameters: TOOL_PARAMETERS
|
|
1691
|
+
}
|
|
1286
1692
|
};
|
|
1287
1693
|
return Object.assign(tool2, {
|
|
1288
1694
|
execute: async (input) => {
|
|
1289
|
-
return
|
|
1695
|
+
return executeToolCall(input, config);
|
|
1290
1696
|
},
|
|
1291
1697
|
formatResult: (result) => {
|
|
1292
1698
|
return formatResult(result);
|
|
@@ -1296,53 +1702,113 @@ function createMorphWarpGrepTool2(config) {
|
|
|
1296
1702
|
}
|
|
1297
1703
|
});
|
|
1298
1704
|
}
|
|
1705
|
+
var openai_default = warpGrepTool2;
|
|
1299
1706
|
|
|
1300
1707
|
// tools/warp_grep/vercel.ts
|
|
1708
|
+
var vercel_exports = {};
|
|
1709
|
+
__export(vercel_exports, {
|
|
1710
|
+
createWarpGrepTool: () => createWarpGrepTool3,
|
|
1711
|
+
default: () => vercel_default,
|
|
1712
|
+
execute: () => execute3,
|
|
1713
|
+
formatResult: () => formatResult,
|
|
1714
|
+
getSystemPrompt: () => getSystemPrompt
|
|
1715
|
+
});
|
|
1301
1716
|
var import_ai = require("ai");
|
|
1302
1717
|
var import_zod = require("zod");
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
}
|
|
1306
|
-
function
|
|
1718
|
+
async function execute3(input, config) {
|
|
1719
|
+
return executeToolCall(input, config);
|
|
1720
|
+
}
|
|
1721
|
+
function createWarpGrepTool3(config) {
|
|
1722
|
+
const schema = import_zod.z.object({
|
|
1723
|
+
query: import_zod.z.string().describe("Free-form repository question")
|
|
1724
|
+
});
|
|
1307
1725
|
return (0, import_ai.tool)({
|
|
1308
1726
|
description: config.description ?? WARP_GREP_DESCRIPTION,
|
|
1309
|
-
inputSchema:
|
|
1727
|
+
inputSchema: schema,
|
|
1310
1728
|
execute: async (params) => {
|
|
1311
|
-
const
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
repoRoot: config.repoRoot,
|
|
1315
|
-
provider,
|
|
1316
|
-
excludes: config.excludes,
|
|
1317
|
-
includes: config.includes,
|
|
1318
|
-
debug: config.debug ?? false,
|
|
1319
|
-
apiKey: config.apiKey
|
|
1320
|
-
});
|
|
1321
|
-
const finish = result.finish;
|
|
1322
|
-
if (result.terminationReason !== "completed" || !finish?.metadata) {
|
|
1323
|
-
return { success: false, error: "Search did not complete" };
|
|
1729
|
+
const result = await executeToolCall(params, config);
|
|
1730
|
+
if (!result.success) {
|
|
1731
|
+
throw new Error(`Failed to search codebase: ${result.error}`);
|
|
1324
1732
|
}
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1733
|
+
return {
|
|
1734
|
+
success: true,
|
|
1735
|
+
contexts: result.contexts,
|
|
1736
|
+
summary: result.summary
|
|
1737
|
+
};
|
|
1738
|
+
}
|
|
1739
|
+
});
|
|
1740
|
+
}
|
|
1741
|
+
var vercel_default = createWarpGrepTool3;
|
|
1742
|
+
|
|
1743
|
+
// tools/warp_grep/gemini.ts
|
|
1744
|
+
var gemini_exports = {};
|
|
1745
|
+
__export(gemini_exports, {
|
|
1746
|
+
createMorphWarpGrepTool: () => createMorphWarpGrepTool,
|
|
1747
|
+
default: () => gemini_default,
|
|
1748
|
+
execute: () => execute4,
|
|
1749
|
+
formatResult: () => formatResult,
|
|
1750
|
+
getSystemPrompt: () => getSystemPrompt,
|
|
1751
|
+
warpGrepFunctionDeclaration: () => warpGrepFunctionDeclaration
|
|
1752
|
+
});
|
|
1753
|
+
var import_generative_ai = require("@google/generative-ai");
|
|
1754
|
+
var TOOL_PARAMETERS2 = {
|
|
1755
|
+
type: import_generative_ai.SchemaType.OBJECT,
|
|
1756
|
+
properties: {
|
|
1757
|
+
query: {
|
|
1758
|
+
type: import_generative_ai.SchemaType.STRING,
|
|
1759
|
+
description: "Free-form repository question"
|
|
1760
|
+
}
|
|
1761
|
+
},
|
|
1762
|
+
required: ["query"]
|
|
1763
|
+
};
|
|
1764
|
+
var warpGrepFunctionDeclaration = {
|
|
1765
|
+
name: WARP_GREP_TOOL_NAME,
|
|
1766
|
+
description: WARP_GREP_DESCRIPTION,
|
|
1767
|
+
parameters: TOOL_PARAMETERS2
|
|
1768
|
+
};
|
|
1769
|
+
async function execute4(input, config) {
|
|
1770
|
+
return executeToolCall(input, config);
|
|
1771
|
+
}
|
|
1772
|
+
function createMorphWarpGrepTool(config) {
|
|
1773
|
+
const declaration = {
|
|
1774
|
+
name: config.name ?? WARP_GREP_TOOL_NAME,
|
|
1775
|
+
description: config.description ?? WARP_GREP_DESCRIPTION,
|
|
1776
|
+
parameters: TOOL_PARAMETERS2
|
|
1777
|
+
};
|
|
1778
|
+
return Object.assign(declaration, {
|
|
1779
|
+
execute: async (input) => {
|
|
1780
|
+
return executeToolCall(input, config);
|
|
1781
|
+
},
|
|
1782
|
+
formatResult: (result) => {
|
|
1783
|
+
return formatResult(result);
|
|
1784
|
+
},
|
|
1785
|
+
getSystemPrompt: () => {
|
|
1786
|
+
return getSystemPrompt();
|
|
1330
1787
|
}
|
|
1331
1788
|
});
|
|
1332
1789
|
}
|
|
1790
|
+
var gemini_default = warpGrepFunctionDeclaration;
|
|
1333
1791
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1334
1792
|
0 && (module.exports = {
|
|
1335
1793
|
LocalRipgrepProvider,
|
|
1794
|
+
RemoteCommandsProvider,
|
|
1336
1795
|
WARP_GREP_DESCRIPTION,
|
|
1337
1796
|
WARP_GREP_SYSTEM_PROMPT,
|
|
1338
1797
|
WARP_GREP_TOOL_NAME,
|
|
1339
1798
|
WarpGrepClient,
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
createVercelWarpGrepTool,
|
|
1799
|
+
anthropic,
|
|
1800
|
+
executeToolCall,
|
|
1343
1801
|
executeWarpGrep,
|
|
1344
1802
|
formatResult,
|
|
1803
|
+
gemini,
|
|
1345
1804
|
getSystemPrompt,
|
|
1346
|
-
|
|
1805
|
+
normalizeFinishFiles,
|
|
1806
|
+
openai,
|
|
1807
|
+
readFinishFiles,
|
|
1808
|
+
runWarpGrep,
|
|
1809
|
+
toolGrep,
|
|
1810
|
+
toolListDirectory,
|
|
1811
|
+
toolRead,
|
|
1812
|
+
vercel
|
|
1347
1813
|
});
|
|
1348
1814
|
//# sourceMappingURL=index.cjs.map
|