@morphllm/morphsdk 0.2.146 → 0.2.148
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/{chunk-FYO46OT6.js → chunk-33CVSDM6.js} +2 -2
- package/dist/{chunk-SJYAKVSS.js → chunk-44WJK4MN.js} +2 -2
- package/dist/{chunk-SJYAKVSS.js.map → chunk-44WJK4MN.js.map} +1 -1
- package/dist/{chunk-GJUB3ECP.js → chunk-4FLNLA2D.js} +2 -2
- package/dist/{chunk-E4YKEKGW.js → chunk-4K36ATXI.js} +2 -2
- package/dist/{chunk-V73GO5AJ.js → chunk-4ZA4INTU.js} +2 -2
- package/dist/{chunk-T564HFSH.js → chunk-5R5FVUAL.js} +1 -1
- package/dist/{chunk-FBOJJ3UY.js → chunk-6MVJ5J6H.js} +17 -17
- package/dist/{chunk-UVNENJ6H.js → chunk-7PZKCKIH.js} +3 -3
- package/dist/{chunk-NF2QWJDY.js → chunk-B3AKP3RA.js} +31 -2
- package/dist/chunk-B3AKP3RA.js.map +1 -0
- package/dist/chunk-CMSHXALI.js +60 -0
- package/dist/chunk-CMSHXALI.js.map +1 -0
- package/dist/{chunk-I7SFRYTX.js → chunk-DMYFFSLS.js} +2 -2
- package/dist/{chunk-Q36MNOFA.js → chunk-E5K4VHMA.js} +2 -2
- package/dist/{chunk-OV57JBMB.js → chunk-EGUJNHMV.js} +2 -2
- package/dist/{chunk-E45FW5EK.js → chunk-ELU34VFH.js} +2 -2
- package/dist/{chunk-BDHKL3MT.js → chunk-F6OUFO25.js} +2 -2
- package/dist/{chunk-QRSWXP4K.js → chunk-H6TH3F4V.js} +2 -2
- package/dist/{chunk-FIVYDIHX.js → chunk-HYRHI2UL.js} +1 -1
- package/dist/{chunk-DKODF3YG.js → chunk-I3J46TSB.js} +5 -4
- package/dist/chunk-I3J46TSB.js.map +1 -0
- package/dist/{chunk-J2HIK4GB.js → chunk-IL7OLRJP.js} +2 -2
- package/dist/{chunk-JSWNBCGS.js → chunk-LJM3R7UZ.js} +2 -2
- package/dist/{chunk-NKUSUSVI.js → chunk-N67TYW2Z.js} +3 -3
- package/dist/chunk-OBXWT7NJ.js +401 -0
- package/dist/chunk-OBXWT7NJ.js.map +1 -0
- package/dist/{chunk-MMBQKN4G.js → chunk-OHYA6SUF.js} +2 -2
- package/dist/{chunk-EU7OLX4Z.js → chunk-RH2JB76E.js} +2 -2
- package/dist/{chunk-KYKRRF7E.js → chunk-SID7EXWK.js} +2 -2
- package/dist/{chunk-YIETFYCL.js → chunk-T7HF2TDQ.js} +75 -48
- package/dist/chunk-T7HF2TDQ.js.map +1 -0
- package/dist/{chunk-VZ6VYRQB.js → chunk-TSUTRT4Q.js} +2 -2
- package/dist/{chunk-UYPWKQKV.js → chunk-TVUYMM4J.js} +2 -2
- package/dist/{chunk-HZOTLGJH.js → chunk-XNBQJSLI.js} +42 -2
- package/dist/chunk-XNBQJSLI.js.map +1 -0
- package/dist/{chunk-BIQ7234U.js → chunk-XT7JQAXV.js} +2 -2
- package/dist/{chunk-4PBUB77N.js → chunk-YWJHOYEM.js} +2 -2
- package/dist/client.cjs +439 -446
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +26 -27
- package/dist/edge.cjs +1 -1
- package/dist/edge.cjs.map +1 -1
- package/dist/edge.js +4 -4
- package/dist/{finish-DBKuo8yj.d.ts → finish-Ddj1MPGt.d.ts} +1 -1
- package/dist/index.cjs +458 -446
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +29 -29
- package/dist/modelrouter/core.cjs +1 -1
- package/dist/modelrouter/core.cjs.map +1 -1
- package/dist/modelrouter/core.js +3 -3
- package/dist/modelrouter/index.cjs +1 -1
- package/dist/modelrouter/index.cjs.map +1 -1
- package/dist/modelrouter/index.js +3 -3
- package/dist/subagents/anthropic.cjs +435 -442
- package/dist/subagents/anthropic.cjs.map +1 -1
- package/dist/subagents/anthropic.js +8 -9
- package/dist/subagents/vercel.cjs +435 -442
- package/dist/subagents/vercel.cjs.map +1 -1
- package/dist/subagents/vercel.js +8 -9
- package/dist/tools/browser/anthropic.cjs +1 -1
- package/dist/tools/browser/anthropic.cjs.map +1 -1
- package/dist/tools/browser/anthropic.js +5 -5
- package/dist/tools/browser/core.cjs +1 -1
- package/dist/tools/browser/core.cjs.map +1 -1
- package/dist/tools/browser/core.js +4 -4
- package/dist/tools/browser/index.cjs +1 -1
- package/dist/tools/browser/index.cjs.map +1 -1
- package/dist/tools/browser/index.js +7 -7
- package/dist/tools/browser/openai.cjs +1 -1
- package/dist/tools/browser/openai.cjs.map +1 -1
- package/dist/tools/browser/openai.js +5 -5
- package/dist/tools/browser/profiles/core.cjs +1 -1
- package/dist/tools/browser/profiles/core.cjs.map +1 -1
- package/dist/tools/browser/profiles/core.js +3 -3
- package/dist/tools/browser/profiles/index.cjs +1 -1
- package/dist/tools/browser/profiles/index.cjs.map +1 -1
- package/dist/tools/browser/profiles/index.js +3 -3
- package/dist/tools/browser/vercel.cjs +1 -1
- package/dist/tools/browser/vercel.cjs.map +1 -1
- package/dist/tools/browser/vercel.js +5 -5
- package/dist/tools/codebase_search/anthropic.cjs +1 -1
- package/dist/tools/codebase_search/anthropic.cjs.map +1 -1
- package/dist/tools/codebase_search/anthropic.js +4 -4
- package/dist/tools/codebase_search/core.cjs +1 -1
- package/dist/tools/codebase_search/core.cjs.map +1 -1
- package/dist/tools/codebase_search/core.js +3 -3
- package/dist/tools/codebase_search/index.cjs +1 -1
- package/dist/tools/codebase_search/index.cjs.map +1 -1
- package/dist/tools/codebase_search/index.js +6 -6
- package/dist/tools/codebase_search/openai.cjs +1 -1
- package/dist/tools/codebase_search/openai.cjs.map +1 -1
- package/dist/tools/codebase_search/openai.js +4 -4
- package/dist/tools/codebase_search/vercel.cjs +1 -1
- package/dist/tools/codebase_search/vercel.cjs.map +1 -1
- package/dist/tools/codebase_search/vercel.js +4 -4
- package/dist/tools/fastapply/anthropic.cjs +1 -1
- package/dist/tools/fastapply/anthropic.cjs.map +1 -1
- package/dist/tools/fastapply/anthropic.js +4 -4
- package/dist/tools/fastapply/apply.cjs +1 -1
- package/dist/tools/fastapply/apply.cjs.map +1 -1
- package/dist/tools/fastapply/apply.js +2 -2
- package/dist/tools/fastapply/core.cjs +1 -1
- package/dist/tools/fastapply/core.cjs.map +1 -1
- package/dist/tools/fastapply/core.js +3 -3
- package/dist/tools/fastapply/index.cjs +1 -1
- package/dist/tools/fastapply/index.cjs.map +1 -1
- package/dist/tools/fastapply/index.js +6 -6
- package/dist/tools/fastapply/openai.cjs +1 -1
- package/dist/tools/fastapply/openai.cjs.map +1 -1
- package/dist/tools/fastapply/openai.js +4 -4
- package/dist/tools/fastapply/vercel.cjs +1 -1
- package/dist/tools/fastapply/vercel.cjs.map +1 -1
- package/dist/tools/fastapply/vercel.js +4 -4
- package/dist/tools/index.cjs +1 -1
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.js +6 -6
- package/dist/tools/utils/resilience.cjs +1 -1
- package/dist/tools/utils/resilience.cjs.map +1 -1
- package/dist/tools/utils/resilience.js +2 -2
- package/dist/tools/warp_grep/agent/config.cjs +4 -3
- package/dist/tools/warp_grep/agent/config.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/config.d.ts +2 -1
- package/dist/tools/warp_grep/agent/config.js +1 -1
- package/dist/tools/warp_grep/agent/parser.cjs +52 -121
- package/dist/tools/warp_grep/agent/parser.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/parser.d.ts +12 -5
- package/dist/tools/warp_grep/agent/parser.js +7 -3
- package/dist/tools/warp_grep/agent/runner.cjs +348 -424
- package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/runner.d.ts +6 -3
- package/dist/tools/warp_grep/agent/runner.js +5 -6
- package/dist/tools/warp_grep/agent/types.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/types.d.ts +22 -3
- package/dist/tools/warp_grep/anthropic.cjs +435 -442
- package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
- package/dist/tools/warp_grep/anthropic.js +8 -9
- package/dist/tools/warp_grep/client.cjs +435 -442
- package/dist/tools/warp_grep/client.cjs.map +1 -1
- package/dist/tools/warp_grep/client.js +7 -8
- package/dist/tools/warp_grep/gemini.cjs +435 -442
- package/dist/tools/warp_grep/gemini.cjs.map +1 -1
- package/dist/tools/warp_grep/gemini.js +7 -8
- package/dist/tools/warp_grep/gemini.js.map +1 -1
- package/dist/tools/warp_grep/harness.cjs +168 -180
- package/dist/tools/warp_grep/harness.cjs.map +1 -1
- package/dist/tools/warp_grep/harness.d.ts +17 -38
- package/dist/tools/warp_grep/harness.js +15 -14
- package/dist/tools/warp_grep/harness.js.map +1 -1
- package/dist/tools/warp_grep/index.cjs +454 -442
- package/dist/tools/warp_grep/index.cjs.map +1 -1
- package/dist/tools/warp_grep/index.d.ts +1 -1
- package/dist/tools/warp_grep/index.js +10 -10
- package/dist/tools/warp_grep/openai.cjs +435 -442
- package/dist/tools/warp_grep/openai.cjs.map +1 -1
- package/dist/tools/warp_grep/openai.js +8 -9
- package/dist/tools/warp_grep/providers/local.cjs +43 -2
- package/dist/tools/warp_grep/providers/local.cjs.map +1 -1
- package/dist/tools/warp_grep/providers/local.d.ts +5 -1
- package/dist/tools/warp_grep/providers/local.js +2 -2
- package/dist/tools/warp_grep/providers/remote.cjs +32 -2
- package/dist/tools/warp_grep/providers/remote.cjs.map +1 -1
- package/dist/tools/warp_grep/providers/remote.d.ts +9 -1
- package/dist/tools/warp_grep/providers/remote.js +2 -2
- package/dist/tools/warp_grep/providers/types.cjs.map +1 -1
- package/dist/tools/warp_grep/providers/types.d.ts +14 -1
- package/dist/tools/warp_grep/vercel.cjs +435 -442
- package/dist/tools/warp_grep/vercel.cjs.map +1 -1
- package/dist/tools/warp_grep/vercel.js +8 -9
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-DKODF3YG.js.map +0 -1
- package/dist/chunk-EUHNJMWL.js +0 -409
- package/dist/chunk-EUHNJMWL.js.map +0 -1
- package/dist/chunk-HZOTLGJH.js.map +0 -1
- package/dist/chunk-NF2QWJDY.js.map +0 -1
- package/dist/chunk-VCKJ22DX.js +0 -131
- package/dist/chunk-VCKJ22DX.js.map +0 -1
- package/dist/chunk-YIETFYCL.js.map +0 -1
- /package/dist/{chunk-FYO46OT6.js.map → chunk-33CVSDM6.js.map} +0 -0
- /package/dist/{chunk-GJUB3ECP.js.map → chunk-4FLNLA2D.js.map} +0 -0
- /package/dist/{chunk-E4YKEKGW.js.map → chunk-4K36ATXI.js.map} +0 -0
- /package/dist/{chunk-V73GO5AJ.js.map → chunk-4ZA4INTU.js.map} +0 -0
- /package/dist/{chunk-T564HFSH.js.map → chunk-5R5FVUAL.js.map} +0 -0
- /package/dist/{chunk-FBOJJ3UY.js.map → chunk-6MVJ5J6H.js.map} +0 -0
- /package/dist/{chunk-UVNENJ6H.js.map → chunk-7PZKCKIH.js.map} +0 -0
- /package/dist/{chunk-I7SFRYTX.js.map → chunk-DMYFFSLS.js.map} +0 -0
- /package/dist/{chunk-Q36MNOFA.js.map → chunk-E5K4VHMA.js.map} +0 -0
- /package/dist/{chunk-OV57JBMB.js.map → chunk-EGUJNHMV.js.map} +0 -0
- /package/dist/{chunk-E45FW5EK.js.map → chunk-ELU34VFH.js.map} +0 -0
- /package/dist/{chunk-BDHKL3MT.js.map → chunk-F6OUFO25.js.map} +0 -0
- /package/dist/{chunk-QRSWXP4K.js.map → chunk-H6TH3F4V.js.map} +0 -0
- /package/dist/{chunk-FIVYDIHX.js.map → chunk-HYRHI2UL.js.map} +0 -0
- /package/dist/{chunk-J2HIK4GB.js.map → chunk-IL7OLRJP.js.map} +0 -0
- /package/dist/{chunk-JSWNBCGS.js.map → chunk-LJM3R7UZ.js.map} +0 -0
- /package/dist/{chunk-NKUSUSVI.js.map → chunk-N67TYW2Z.js.map} +0 -0
- /package/dist/{chunk-MMBQKN4G.js.map → chunk-OHYA6SUF.js.map} +0 -0
- /package/dist/{chunk-EU7OLX4Z.js.map → chunk-RH2JB76E.js.map} +0 -0
- /package/dist/{chunk-KYKRRF7E.js.map → chunk-SID7EXWK.js.map} +0 -0
- /package/dist/{chunk-VZ6VYRQB.js.map → chunk-TSUTRT4Q.js.map} +0 -0
- /package/dist/{chunk-UYPWKQKV.js.map → chunk-TVUYMM4J.js.map} +0 -0
- /package/dist/{chunk-BIQ7234U.js.map → chunk-XT7JQAXV.js.map} +0 -0
- /package/dist/{chunk-4PBUB77N.js.map → chunk-YWJHOYEM.js.map} +0 -0
|
@@ -42,11 +42,12 @@ var parseEnvTimeout = (envValue, defaultMs) => {
|
|
|
42
42
|
return isNaN(parsed) || parsed <= 0 ? defaultMs : parsed;
|
|
43
43
|
};
|
|
44
44
|
var AGENT_CONFIG = {
|
|
45
|
-
MAX_TURNS:
|
|
45
|
+
MAX_TURNS: 6,
|
|
46
46
|
/** Default timeout for model calls. Can be overridden via MORPH_WARP_GREP_TIMEOUT env var (in ms) */
|
|
47
47
|
TIMEOUT_MS: parseEnvTimeout(process.env.MORPH_WARP_GREP_TIMEOUT, 3e4),
|
|
48
|
-
MAX_CONTEXT_CHARS:
|
|
48
|
+
MAX_CONTEXT_CHARS: 321600,
|
|
49
49
|
MAX_OUTPUT_LINES: 200,
|
|
50
|
+
MAX_LIST_RESULTS: 500,
|
|
50
51
|
MAX_READ_LINES: 800,
|
|
51
52
|
MAX_LIST_DEPTH: 3,
|
|
52
53
|
LIST_TIMEOUT_MS: 2e3
|
|
@@ -131,134 +132,61 @@ var BUILTIN_EXCLUDES = [
|
|
|
131
132
|
".*"
|
|
132
133
|
];
|
|
133
134
|
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-v2";
|
|
135
|
+
var DEFAULT_MODEL = "morph-warp-grep-v2.1";
|
|
135
136
|
|
|
136
137
|
// tools/warp_grep/agent/parser.ts
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
function parseReadLines(linesStr) {
|
|
139
|
+
const ranges = [];
|
|
140
|
+
for (const rangeStr of linesStr.split(",")) {
|
|
141
|
+
const trimmed = rangeStr.trim();
|
|
142
|
+
if (!trimmed) continue;
|
|
143
|
+
const parts = trimmed.split("-").map((v) => parseInt(v.trim(), 10));
|
|
144
|
+
if (parts.length >= 2 && Number.isFinite(parts[0]) && Number.isFinite(parts[1])) {
|
|
145
|
+
ranges.push([parts[0], parts[1]]);
|
|
146
|
+
} else if (Number.isFinite(parts[0])) {
|
|
147
|
+
ranges.push([parts[0], parts[0]]);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (ranges.length === 1) return { start: ranges[0][0], end: ranges[0][1] };
|
|
151
|
+
if (ranges.length > 1) return { lines: ranges };
|
|
152
|
+
return {};
|
|
140
153
|
}
|
|
141
|
-
function
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const paramRegex = /<parameter=([a-z_][a-z0-9_]*)>([\s\S]*?)<\/parameter>/gi;
|
|
151
|
-
let paramMatch;
|
|
152
|
-
while ((paramMatch = paramRegex.exec(body)) !== null) {
|
|
153
|
-
params[paramMatch[1].toLowerCase()] = paramMatch[2].trim();
|
|
154
|
+
function parseFinishFiles(filesStr) {
|
|
155
|
+
const files = [];
|
|
156
|
+
for (const line of filesStr.trim().split(/\s+/)) {
|
|
157
|
+
const trimmed = line.trim();
|
|
158
|
+
if (!trimmed) continue;
|
|
159
|
+
const colonIdx = trimmed.indexOf(":");
|
|
160
|
+
if (colonIdx === -1) {
|
|
161
|
+
files.push({ path: trimmed, lines: "*" });
|
|
162
|
+
continue;
|
|
154
163
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (!directPath && command) {
|
|
171
|
-
const tokens = command.trim().split(/\s+/);
|
|
172
|
-
const pathTokens = tokens.slice(1).filter((t) => !t.startsWith("-") && !t.startsWith("|") && !t.startsWith("\\("));
|
|
173
|
-
if (pathTokens.length > 0) {
|
|
174
|
-
dirPath = pathTokens[0];
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
tools.push({ name: "list_directory", arguments: { path: dirPath, pattern: params.pattern || null } });
|
|
178
|
-
} else if (funcName === "read") {
|
|
179
|
-
const filePath = params.path;
|
|
180
|
-
if (!filePath) continue;
|
|
181
|
-
const args = { path: filePath };
|
|
182
|
-
const linesStr = params.lines;
|
|
183
|
-
if (linesStr) {
|
|
184
|
-
const ranges = [];
|
|
185
|
-
for (const rangeStr of linesStr.split(",")) {
|
|
186
|
-
const trimmed = rangeStr.trim();
|
|
187
|
-
if (!trimmed) continue;
|
|
188
|
-
const [s, e] = trimmed.split("-").map((v) => parseInt(v.trim(), 10));
|
|
189
|
-
if (Number.isFinite(s) && Number.isFinite(e)) {
|
|
190
|
-
ranges.push([s, e]);
|
|
191
|
-
} else if (Number.isFinite(s)) {
|
|
192
|
-
ranges.push([s, s]);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
if (ranges.length === 1) {
|
|
196
|
-
args.start = ranges[0][0];
|
|
197
|
-
args.end = ranges[0][1];
|
|
198
|
-
} else if (ranges.length > 1) {
|
|
199
|
-
args.lines = ranges;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
tools.push({ name: "read", arguments: args });
|
|
203
|
-
} else if (funcName === "finish") {
|
|
204
|
-
if (params.result && !params.files) {
|
|
205
|
-
tools.push({ name: "finish", arguments: { files: [], textResult: params.result } });
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
const filesStr = params.files;
|
|
209
|
-
if (!filesStr) {
|
|
210
|
-
tools.push({ name: "finish", arguments: { files: [], textResult: "No relevant code found." } });
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
const files = [];
|
|
214
|
-
for (const line of filesStr.split("\n")) {
|
|
215
|
-
const trimmed = line.trim();
|
|
216
|
-
if (!trimmed) continue;
|
|
217
|
-
const colonIdx = trimmed.indexOf(":");
|
|
218
|
-
if (colonIdx === -1) {
|
|
219
|
-
files.push({ path: trimmed, lines: "*" });
|
|
220
|
-
} else {
|
|
221
|
-
const filePath = trimmed.slice(0, colonIdx);
|
|
222
|
-
const rangesPart = trimmed.slice(colonIdx + 1);
|
|
223
|
-
const ranges = [];
|
|
224
|
-
for (const rangeStr of rangesPart.split(",")) {
|
|
225
|
-
const rt = rangeStr.trim();
|
|
226
|
-
if (!rt || rt === "*") {
|
|
227
|
-
files.push({ path: filePath, lines: "*" });
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
const [s, e] = rt.split("-").map((v) => parseInt(v.trim(), 10));
|
|
231
|
-
if (Number.isFinite(s) && Number.isFinite(e)) {
|
|
232
|
-
ranges.push([s, e]);
|
|
233
|
-
} else if (Number.isFinite(s)) {
|
|
234
|
-
ranges.push([s, s]);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
if (ranges.length > 0) {
|
|
238
|
-
files.push({ path: filePath, lines: ranges });
|
|
239
|
-
} else if (!files.some((f) => f.path === filePath)) {
|
|
240
|
-
files.push({ path: filePath, lines: "*" });
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
if (files.length > 0) {
|
|
245
|
-
tools.push({ name: "finish", arguments: { files } });
|
|
246
|
-
} else {
|
|
247
|
-
tools.push({ name: "finish", arguments: { files: [], textResult: filesStr } });
|
|
164
|
+
const filePath = trimmed.slice(0, colonIdx);
|
|
165
|
+
const rangesPart = trimmed.slice(colonIdx + 1);
|
|
166
|
+
if (!rangesPart.trim() || rangesPart.trim() === "*") {
|
|
167
|
+
files.push({ path: filePath, lines: "*" });
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const ranges = [];
|
|
171
|
+
for (const rangeStr of rangesPart.split(",")) {
|
|
172
|
+
const rt = rangeStr.trim();
|
|
173
|
+
if (!rt) continue;
|
|
174
|
+
const parts = rt.split("-").map((v) => parseInt(v.trim(), 10));
|
|
175
|
+
if (parts.length >= 2 && Number.isFinite(parts[0]) && Number.isFinite(parts[1])) {
|
|
176
|
+
ranges.push([parts[0], parts[1]]);
|
|
177
|
+
} else if (Number.isFinite(parts[0])) {
|
|
178
|
+
ranges.push([parts[0], parts[0]]);
|
|
248
179
|
}
|
|
249
180
|
}
|
|
181
|
+
files.push({ path: filePath, lines: ranges.length > 0 ? ranges : "*" });
|
|
250
182
|
}
|
|
251
|
-
return
|
|
183
|
+
return files;
|
|
184
|
+
}
|
|
185
|
+
function extractPathFromCommand(command) {
|
|
186
|
+
const tokens = command.trim().split(/\s+/);
|
|
187
|
+
const pathTokens = tokens.slice(1).filter((t) => !t.startsWith("-") && !t.startsWith("|") && !t.startsWith("\\("));
|
|
188
|
+
return pathTokens[0] || ".";
|
|
252
189
|
}
|
|
253
|
-
var LLMResponseParser = class {
|
|
254
|
-
parse(text) {
|
|
255
|
-
if (typeof text !== "string") {
|
|
256
|
-
throw new TypeError("Command text must be a string.");
|
|
257
|
-
}
|
|
258
|
-
const withoutThink = text.replace(/<think>[\s\S]*?<\/think>/gi, "");
|
|
259
|
-
return parseQwen3ToolCalls(withoutThink);
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
190
|
|
|
263
191
|
// tools/warp_grep/agent/tools/grep.ts
|
|
264
192
|
async function toolGrep(provider, args) {
|
|
@@ -308,29 +236,42 @@ async function toolRead(provider, args) {
|
|
|
308
236
|
}
|
|
309
237
|
|
|
310
238
|
// tools/warp_grep/agent/tools/list_directory.ts
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
239
|
+
var import_path = __toESM(require("path"), 1);
|
|
240
|
+
async function toolListDirectory(provider, args, repoRoot) {
|
|
241
|
+
const maxResults = args.maxResults ?? AGENT_CONFIG.MAX_LIST_RESULTS;
|
|
242
|
+
const maxDepth = args.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
|
|
243
|
+
const entries = await provider.listDirectory({
|
|
244
|
+
path: args.path,
|
|
245
|
+
pattern: args.pattern ?? null,
|
|
246
|
+
maxResults,
|
|
247
|
+
maxDepth
|
|
248
|
+
});
|
|
249
|
+
if (!entries.length) return "empty";
|
|
250
|
+
if (repoRoot) {
|
|
251
|
+
const absRoot = import_path.default.resolve(repoRoot);
|
|
252
|
+
const lines = entries.map((e) => import_path.default.join(absRoot, e.path));
|
|
253
|
+
return lines.join("\n");
|
|
325
254
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
255
|
+
return entries.map((e) => e.path).join("\n");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// tools/warp_grep/agent/tools/glob.ts
|
|
259
|
+
async function toolGlob(provider, args) {
|
|
260
|
+
const res = await provider.glob(args);
|
|
261
|
+
if (res.error) {
|
|
262
|
+
return res.error;
|
|
263
|
+
}
|
|
264
|
+
if (!res.files.length) {
|
|
265
|
+
return "no matches";
|
|
266
|
+
}
|
|
267
|
+
const header = `Found ${res.totalFound} file(s) matching "${args.pattern}" within ${res.searchDir}, sorted by modification time (newest first):`;
|
|
268
|
+
const body = res.files.join("\n");
|
|
269
|
+
const truncated = res.totalFound > res.files.length ? `
|
|
270
|
+
[${res.totalFound - res.files.length} files truncated]` : "";
|
|
271
|
+
return `${header}
|
|
272
|
+
---
|
|
273
|
+
${body}
|
|
274
|
+
---${truncated}`;
|
|
334
275
|
}
|
|
335
276
|
|
|
336
277
|
// tools/warp_grep/agent/tools/finish.ts
|
|
@@ -391,31 +332,20 @@ function mergeRanges(ranges) {
|
|
|
391
332
|
return merged;
|
|
392
333
|
}
|
|
393
334
|
|
|
394
|
-
// tools/warp_grep/agent/
|
|
395
|
-
var
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
if (!payload && !isError) {
|
|
404
|
-
return "";
|
|
335
|
+
// tools/warp_grep/agent/helpers.ts
|
|
336
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
337
|
+
var TRUNCATED_MARKER = "[truncated for context limit]";
|
|
338
|
+
function getMessageSize(m) {
|
|
339
|
+
if (m.role === "tool") return m.content.length;
|
|
340
|
+
if (m.role === "assistant") {
|
|
341
|
+
let size = typeof m.content === "string" ? m.content.length : 0;
|
|
342
|
+
if (m.tool_calls) {
|
|
343
|
+
size += m.tool_calls.reduce((s, tc) => s + tc.function.name.length + tc.function.arguments.length, 0);
|
|
405
344
|
}
|
|
406
|
-
return
|
|
407
|
-
${payload}
|
|
408
|
-
</tool_response>`;
|
|
345
|
+
return size;
|
|
409
346
|
}
|
|
410
|
-
|
|
411
|
-
var sharedFormatter = new ToolOutputFormatter();
|
|
412
|
-
function formatAgentToolOutput(toolName, args, output, options = {}) {
|
|
413
|
-
return sharedFormatter.format(toolName, args, output, options);
|
|
347
|
+
return m.content.length;
|
|
414
348
|
}
|
|
415
|
-
|
|
416
|
-
// tools/warp_grep/agent/helpers.ts
|
|
417
|
-
var import_path = __toESM(require("path"), 1);
|
|
418
|
-
var TRUNCATED_MARKER = "[truncated for context limit]";
|
|
419
349
|
function formatTurnMessage(turnsUsed, maxTurns) {
|
|
420
350
|
const turnsRemaining = maxTurns - turnsUsed;
|
|
421
351
|
if (turnsRemaining === 1) {
|
|
@@ -426,33 +356,30 @@ You have used ${turnsUsed} turns, you only have 1 turn remaining. You have run o
|
|
|
426
356
|
You have used ${turnsUsed} turn${turnsUsed === 1 ? "" : "s"} and have ${turnsRemaining} remaining`;
|
|
427
357
|
}
|
|
428
358
|
function calculateContextBudget(messages) {
|
|
429
|
-
const totalChars = messages.reduce((sum, m) => sum + m
|
|
359
|
+
const totalChars = messages.reduce((sum, m) => sum + getMessageSize(m), 0);
|
|
430
360
|
const maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS;
|
|
431
|
-
const percent = Math.
|
|
432
|
-
const usedK = Math.
|
|
433
|
-
const maxK = Math.
|
|
434
|
-
return `<context_budget>${percent}% (${usedK}K/${maxK}K chars
|
|
361
|
+
const percent = Math.floor(totalChars / maxChars * 100);
|
|
362
|
+
const usedK = Math.floor(totalChars / 1e3);
|
|
363
|
+
const maxK = Math.floor(maxChars / 1e3);
|
|
364
|
+
return `<context_budget>${percent}% (${usedK}K/${maxK}K chars)</context_budget>`;
|
|
435
365
|
}
|
|
436
366
|
async function buildInitialState(repoRoot, searchTerm, provider, options) {
|
|
437
367
|
const budget = calculateContextBudget([]);
|
|
438
|
-
const turnTag = `
|
|
368
|
+
const turnTag = `You have used 0 turns and have ${AGENT_CONFIG.MAX_TURNS} remaining`;
|
|
439
369
|
const treeDepth = options?.search_type === "node_modules" ? 1 : 2;
|
|
370
|
+
const absRoot = import_path2.default.resolve(repoRoot);
|
|
440
371
|
try {
|
|
441
372
|
const entries = await provider.listDirectory({
|
|
442
373
|
path: ".",
|
|
443
374
|
maxResults: AGENT_CONFIG.MAX_OUTPUT_LINES,
|
|
444
375
|
maxDepth: treeDepth
|
|
445
376
|
});
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
});
|
|
451
|
-
const repoName = import_path.default.basename(repoRoot);
|
|
452
|
-
const treeOutput = treeLines.length > 0 ? `${repoName}/
|
|
453
|
-
${treeLines.join("\n")}` : `${repoName}/`;
|
|
377
|
+
const lines = [absRoot];
|
|
378
|
+
for (const e of entries) {
|
|
379
|
+
lines.push(import_path2.default.join(absRoot, e.path));
|
|
380
|
+
}
|
|
454
381
|
return `<repo_structure>
|
|
455
|
-
${
|
|
382
|
+
${lines.join("\n")}
|
|
456
383
|
</repo_structure>
|
|
457
384
|
|
|
458
385
|
<search_string>
|
|
@@ -461,9 +388,8 @@ ${searchTerm}
|
|
|
461
388
|
${budget}
|
|
462
389
|
${turnTag}`;
|
|
463
390
|
} catch {
|
|
464
|
-
const repoName = import_path.default.basename(repoRoot);
|
|
465
391
|
return `<repo_structure>
|
|
466
|
-
${
|
|
392
|
+
${absRoot}
|
|
467
393
|
</repo_structure>
|
|
468
394
|
|
|
469
395
|
<search_string>
|
|
@@ -474,26 +400,32 @@ ${turnTag}`;
|
|
|
474
400
|
}
|
|
475
401
|
}
|
|
476
402
|
function enforceContextLimit(messages, maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS) {
|
|
477
|
-
const getTotalChars = () => messages.reduce((sum, m) => sum + m
|
|
403
|
+
const getTotalChars = () => messages.reduce((sum, m) => sum + getMessageSize(m), 0);
|
|
478
404
|
if (getTotalChars() <= maxChars) {
|
|
479
405
|
return messages;
|
|
480
406
|
}
|
|
481
|
-
const
|
|
407
|
+
const truncatableIndices = [];
|
|
482
408
|
let firstUserSkipped = false;
|
|
483
409
|
for (let i = 0; i < messages.length; i++) {
|
|
484
|
-
|
|
410
|
+
const m = messages[i];
|
|
411
|
+
if (m.role === "tool") {
|
|
412
|
+
truncatableIndices.push(i);
|
|
413
|
+
} else if (m.role === "user") {
|
|
485
414
|
if (!firstUserSkipped) {
|
|
486
415
|
firstUserSkipped = true;
|
|
487
416
|
continue;
|
|
488
417
|
}
|
|
489
|
-
|
|
418
|
+
truncatableIndices.push(i);
|
|
490
419
|
}
|
|
491
420
|
}
|
|
492
|
-
for (const idx of
|
|
421
|
+
for (const idx of truncatableIndices) {
|
|
493
422
|
if (getTotalChars() <= maxChars) {
|
|
494
423
|
break;
|
|
495
424
|
}
|
|
496
|
-
|
|
425
|
+
const m = messages[idx];
|
|
426
|
+
if (m.role === "tool" && m.content !== TRUNCATED_MARKER) {
|
|
427
|
+
messages[idx] = { role: "tool", tool_call_id: m.tool_call_id, content: TRUNCATED_MARKER };
|
|
428
|
+
} else if (m.role === "user" && m.content !== TRUNCATED_MARKER) {
|
|
497
429
|
messages[idx] = { role: "user", content: TRUNCATED_MARKER };
|
|
498
430
|
}
|
|
499
431
|
}
|
|
@@ -506,7 +438,7 @@ var import_openai = __toESM(require("openai"), 1);
|
|
|
506
438
|
// package.json
|
|
507
439
|
var package_default = {
|
|
508
440
|
name: "@morphllm/morphsdk",
|
|
509
|
-
version: "0.2.
|
|
441
|
+
version: "0.2.148",
|
|
510
442
|
description: "TypeScript SDK and CLI for Morph Fast Apply integration",
|
|
511
443
|
type: "module",
|
|
512
444
|
main: "./dist/index.cjs",
|
|
@@ -745,9 +677,115 @@ var package_default = {
|
|
|
745
677
|
var SDK_VERSION = package_default.version;
|
|
746
678
|
|
|
747
679
|
// tools/warp_grep/agent/runner.ts
|
|
748
|
-
var
|
|
749
|
-
var parser = new LLMResponseParser();
|
|
680
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
750
681
|
var DEFAULT_API_URL = "https://api.morphllm.com";
|
|
682
|
+
var TOOL_SPECS = [
|
|
683
|
+
{
|
|
684
|
+
type: "function",
|
|
685
|
+
function: {
|
|
686
|
+
name: "list_directory",
|
|
687
|
+
description: "Execute ls or find commands to explore directory structure. Max 500 results. Common junk directories are excluded automatically.",
|
|
688
|
+
parameters: {
|
|
689
|
+
type: "object",
|
|
690
|
+
properties: {
|
|
691
|
+
command: {
|
|
692
|
+
type: "string",
|
|
693
|
+
description: "Full ls or find command (e.g. ls -la src/, find . -maxdepth 2 -type f -name '*.py', find . -type d, ls -d */)."
|
|
694
|
+
}
|
|
695
|
+
},
|
|
696
|
+
required: ["command"]
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
type: "function",
|
|
702
|
+
function: {
|
|
703
|
+
name: "grep_search",
|
|
704
|
+
description: "Search for a regex pattern in file contents. Returns matching lines with file paths and line numbers. Case-insensitive. Respects .gitignore.",
|
|
705
|
+
parameters: {
|
|
706
|
+
type: "object",
|
|
707
|
+
properties: {
|
|
708
|
+
pattern: {
|
|
709
|
+
type: "string",
|
|
710
|
+
description: "Regex pattern to search for in file contents (e.g. 'class\\s+\\w+Error', 'import|require|from', 'def (get|set|update)_user')."
|
|
711
|
+
},
|
|
712
|
+
path: {
|
|
713
|
+
type: "string",
|
|
714
|
+
description: "File or directory to search in. Defaults to current working directory."
|
|
715
|
+
},
|
|
716
|
+
glob: {
|
|
717
|
+
type: "string",
|
|
718
|
+
description: "Glob pattern to filter files (e.g. '*.py', '*.{ts,tsx,js,jsx,py,go}', 'src/**/*.go', '!*.test.*')."
|
|
719
|
+
},
|
|
720
|
+
limit: {
|
|
721
|
+
type: "integer",
|
|
722
|
+
description: "Limit output to first N matching lines. Shows all matches if not specified."
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
required: ["pattern"]
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
},
|
|
729
|
+
{
|
|
730
|
+
type: "function",
|
|
731
|
+
function: {
|
|
732
|
+
name: "glob",
|
|
733
|
+
description: "Find files by name/extension using glob patterns. Returns absolute paths sorted by modification time (newest first). Respects .gitignore. Max 100 results.",
|
|
734
|
+
parameters: {
|
|
735
|
+
type: "object",
|
|
736
|
+
properties: {
|
|
737
|
+
pattern: {
|
|
738
|
+
type: "string",
|
|
739
|
+
description: "Glob pattern to match files (e.g. '*.py', 'src/**/*.js', '*.{ts,tsx}', 'test_*.py')."
|
|
740
|
+
},
|
|
741
|
+
path: {
|
|
742
|
+
type: "string",
|
|
743
|
+
description: "Directory to search in. Defaults to repository root."
|
|
744
|
+
}
|
|
745
|
+
},
|
|
746
|
+
required: ["pattern"]
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
type: "function",
|
|
752
|
+
function: {
|
|
753
|
+
name: "read",
|
|
754
|
+
description: "Read entire files or specific line ranges using absolute paths.",
|
|
755
|
+
parameters: {
|
|
756
|
+
type: "object",
|
|
757
|
+
properties: {
|
|
758
|
+
path: {
|
|
759
|
+
type: "string",
|
|
760
|
+
description: "File path to read, using absolute path (e.g. '/home/ubuntu/repo/src/main.py' or windows path)."
|
|
761
|
+
},
|
|
762
|
+
lines: {
|
|
763
|
+
type: "string",
|
|
764
|
+
description: "Optional line range (e.g. '1-50' or '1-20,45-80'). Omit to read entire file."
|
|
765
|
+
}
|
|
766
|
+
},
|
|
767
|
+
required: ["path"]
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
type: "function",
|
|
773
|
+
function: {
|
|
774
|
+
name: "finish",
|
|
775
|
+
description: "Submit final answer with all relevant code locations. Include imports and over-include rather than miss context.",
|
|
776
|
+
parameters: {
|
|
777
|
+
type: "object",
|
|
778
|
+
properties: {
|
|
779
|
+
files: {
|
|
780
|
+
type: "string",
|
|
781
|
+
description: "One file per line as path:lines (e.g. 'src/auth.py:1-15,25-50\\nsrc/user.py'). Omit line range to include entire file."
|
|
782
|
+
}
|
|
783
|
+
},
|
|
784
|
+
required: ["files"]
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
];
|
|
751
789
|
async function callModel(messages, model, options = {}) {
|
|
752
790
|
const baseUrl = options.morphApiUrl || DEFAULT_API_URL;
|
|
753
791
|
const apiKey = options.morphApiKey || process.env.MORPH_API_KEY || "";
|
|
@@ -768,8 +806,9 @@ async function callModel(messages, model, options = {}) {
|
|
|
768
806
|
data = await client.chat.completions.create({
|
|
769
807
|
model,
|
|
770
808
|
temperature: 0,
|
|
771
|
-
max_tokens:
|
|
809
|
+
max_tokens: 2048,
|
|
772
810
|
messages,
|
|
811
|
+
tools: TOOL_SPECS,
|
|
773
812
|
...options.search_type ? { search_type: options.search_type } : {}
|
|
774
813
|
});
|
|
775
814
|
} catch (error) {
|
|
@@ -781,187 +820,87 @@ async function callModel(messages, model, options = {}) {
|
|
|
781
820
|
throw error;
|
|
782
821
|
}
|
|
783
822
|
const choice = data?.choices?.[0];
|
|
784
|
-
const
|
|
785
|
-
if (
|
|
786
|
-
|
|
823
|
+
const message = choice?.message;
|
|
824
|
+
if (!message) {
|
|
825
|
+
if (attempt === MAX_EMPTY_RETRIES) {
|
|
826
|
+
throw new Error("Invalid response from model: no message in response");
|
|
827
|
+
}
|
|
828
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
const toolCalls = (message.tool_calls || []).map((tc) => ({
|
|
832
|
+
id: tc.id,
|
|
833
|
+
type: "function",
|
|
834
|
+
function: { name: tc.function.name, arguments: tc.function.arguments }
|
|
835
|
+
}));
|
|
836
|
+
if (message.content || toolCalls.length > 0) {
|
|
837
|
+
return { content: message.content ?? null, tool_calls: toolCalls };
|
|
787
838
|
}
|
|
788
839
|
if (attempt === MAX_EMPTY_RETRIES) {
|
|
789
840
|
const finishReason = choice?.finish_reason ?? "unknown";
|
|
790
|
-
const hasToolCalls = Array.isArray(choice?.message?.tool_calls) && choice.message.tool_calls.length > 0;
|
|
791
|
-
const choicesLen = data?.choices?.length ?? 0;
|
|
792
|
-
const contentType = content === null ? "null" : content === void 0 ? "undefined" : typeof content;
|
|
793
841
|
throw new Error(
|
|
794
|
-
`Invalid response from model: content
|
|
842
|
+
`Invalid response from model: no content and no tool_calls, finish_reason=${finishReason}`
|
|
795
843
|
);
|
|
796
844
|
}
|
|
797
845
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
798
846
|
}
|
|
799
847
|
throw new Error("Invalid response from model");
|
|
800
848
|
}
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
}).catch((e) => {
|
|
828
|
-
const errMsg = e instanceof Error ? e.message : String(e);
|
|
829
|
-
console.error(`[warp_grep] Morph API call failed on turn ${turn}:`, errMsg);
|
|
830
|
-
errors.push({ message: errMsg });
|
|
831
|
-
return "";
|
|
832
|
-
});
|
|
833
|
-
turnMetrics.morph_api_ms = Date.now() - modelCallStart;
|
|
834
|
-
if (!assistantContent) {
|
|
835
|
-
console.error(`[warp_grep] Empty response from Morph API on turn ${turn}. Errors so far:`, errors);
|
|
836
|
-
timings.turns.push(turnMetrics);
|
|
837
|
-
break;
|
|
838
|
-
}
|
|
839
|
-
messages.push({ role: "assistant", content: assistantContent });
|
|
840
|
-
const toolCalls = parser.parse(assistantContent);
|
|
841
|
-
if (toolCalls.length === 0) {
|
|
842
|
-
console.error(`[warp_grep] No tool calls parsed on turn ${turn}. Assistant content (first 500 chars):`, assistantContent.slice(0, 500));
|
|
843
|
-
errors.push({ message: "No tool calls produced by the model. Your MCP is likely out of date! Update it by running: rm -rf ~/.npm/_npx && npm cache clean --force && npx -y @morphllm/morphmcp@latest" });
|
|
844
|
-
terminationReason = "terminated";
|
|
845
|
-
timings.turns.push(turnMetrics);
|
|
846
|
-
break;
|
|
847
|
-
}
|
|
848
|
-
const finishCalls = toolCalls.filter((c) => c.name === "finish");
|
|
849
|
-
const grepCalls = toolCalls.filter((c) => c.name === "grep");
|
|
850
|
-
const listDirCalls = toolCalls.filter((c) => c.name === "list_directory");
|
|
851
|
-
const readCalls = toolCalls.filter((c) => c.name === "read");
|
|
852
|
-
const skipCalls = toolCalls.filter((c) => c.name === "_skip");
|
|
853
|
-
const formatted = [];
|
|
854
|
-
for (const c of skipCalls) {
|
|
855
|
-
const msg = c.arguments?.message || "Command skipped due to parsing error";
|
|
856
|
-
formatted.push(msg);
|
|
857
|
-
}
|
|
858
|
-
const allPromises = [];
|
|
859
|
-
for (const c of grepCalls) {
|
|
860
|
-
const args = c.arguments ?? {};
|
|
861
|
-
allPromises.push(
|
|
862
|
-
toolGrep(provider, args).then(
|
|
863
|
-
({ output }) => formatAgentToolOutput("grep", args, output),
|
|
864
|
-
(err) => formatAgentToolOutput("grep", args, String(err), { isError: true })
|
|
865
|
-
)
|
|
866
|
-
);
|
|
867
|
-
}
|
|
868
|
-
for (const c of listDirCalls) {
|
|
869
|
-
const args = c.arguments ?? {};
|
|
870
|
-
allPromises.push(
|
|
871
|
-
toolListDirectory(provider, args).then(
|
|
872
|
-
(p) => formatAgentToolOutput("list_directory", args, p),
|
|
873
|
-
(err) => formatAgentToolOutput("list_directory", args, String(err), { isError: true })
|
|
874
|
-
)
|
|
875
|
-
);
|
|
876
|
-
}
|
|
877
|
-
for (const c of readCalls) {
|
|
878
|
-
const args = c.arguments ?? {};
|
|
879
|
-
allPromises.push(
|
|
880
|
-
toolRead(provider, args).then(
|
|
881
|
-
(p) => formatAgentToolOutput("read", args, p),
|
|
882
|
-
(err) => formatAgentToolOutput("read", args, String(err), { isError: true })
|
|
883
|
-
)
|
|
884
|
-
);
|
|
849
|
+
function safeParseJSON(s) {
|
|
850
|
+
try {
|
|
851
|
+
return JSON.parse(s);
|
|
852
|
+
} catch {
|
|
853
|
+
return {};
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
async function executeTool(provider, name, args, repoRoot) {
|
|
857
|
+
switch (name) {
|
|
858
|
+
case "grep_search": {
|
|
859
|
+
const grepArgs = {
|
|
860
|
+
pattern: args.pattern,
|
|
861
|
+
path: args.path || "."
|
|
862
|
+
};
|
|
863
|
+
if (args.glob) grepArgs.glob = args.glob;
|
|
864
|
+
if (args.case_sensitive !== void 0) grepArgs.case_sensitive = args.case_sensitive;
|
|
865
|
+
const result = await toolGrep(provider, grepArgs);
|
|
866
|
+
let output = result.output;
|
|
867
|
+
if (args.limit && typeof args.limit === "number") {
|
|
868
|
+
const lines = output.split("\n");
|
|
869
|
+
if (lines.length > args.limit) {
|
|
870
|
+
output = lines.slice(0, args.limit).join("\n") + `
|
|
871
|
+
... (truncated at ${args.limit} lines)`;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
return output;
|
|
885
875
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
876
|
+
case "glob": {
|
|
877
|
+
return toolGlob(provider, {
|
|
878
|
+
pattern: args.pattern,
|
|
879
|
+
path: args.path
|
|
880
|
+
});
|
|
891
881
|
}
|
|
892
|
-
|
|
893
|
-
const
|
|
894
|
-
|
|
895
|
-
messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
|
|
882
|
+
case "list_directory": {
|
|
883
|
+
const dirPath = extractPathFromCommand(args.command || ".");
|
|
884
|
+
return toolListDirectory(provider, { path: dirPath }, repoRoot);
|
|
896
885
|
}
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
terminationReason = "completed";
|
|
904
|
-
if (files.length === 0) {
|
|
905
|
-
const payload2 = textResult || "No relevant code found.";
|
|
906
|
-
timings.turns.push(turnMetrics);
|
|
907
|
-
timings.total_ms = Date.now() - totalStart;
|
|
908
|
-
return {
|
|
909
|
-
terminationReason: "completed",
|
|
910
|
-
messages,
|
|
911
|
-
finish: { payload: payload2, metadata: finishMeta },
|
|
912
|
-
timings
|
|
913
|
-
};
|
|
914
|
-
}
|
|
915
|
-
break;
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
if (terminationReason !== "completed" || !finishMeta) {
|
|
919
|
-
timings.total_ms = Date.now() - totalStart;
|
|
920
|
-
return { terminationReason, messages, errors, timings };
|
|
921
|
-
}
|
|
922
|
-
const parts = ["Relevant context found:"];
|
|
923
|
-
for (const f of finishMeta.files) {
|
|
924
|
-
const ranges = f.lines === "*" ? "*" : Array.isArray(f.lines) ? f.lines.map(([s, e]) => `${s}-${e}`).join(", ") : "*";
|
|
925
|
-
parts.push(`- ${f.path}: ${ranges}`);
|
|
926
|
-
}
|
|
927
|
-
const payload = parts.join("\n");
|
|
928
|
-
const finishResolutionStart = Date.now();
|
|
929
|
-
const fileReadErrors = [];
|
|
930
|
-
const resolved = await readFinishFiles(
|
|
931
|
-
repoRoot,
|
|
932
|
-
finishMeta.files,
|
|
933
|
-
async (p, s, e) => {
|
|
934
|
-
try {
|
|
935
|
-
const rr = await provider.read({ path: p, start: s, end: e });
|
|
936
|
-
return rr.lines.map((l) => {
|
|
937
|
-
const idx = l.indexOf("|");
|
|
938
|
-
return idx >= 0 ? l.slice(idx + 1) : l;
|
|
939
|
-
});
|
|
940
|
-
} catch (err) {
|
|
941
|
-
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
942
|
-
fileReadErrors.push({ path: p, error: errorMsg });
|
|
943
|
-
console.error(`[warp_grep] Failed to read file: ${p} - ${errorMsg}`);
|
|
944
|
-
return [`[couldn't find: ${p}]`];
|
|
886
|
+
case "read": {
|
|
887
|
+
const readArgs = {
|
|
888
|
+
path: args.path
|
|
889
|
+
};
|
|
890
|
+
if (args.lines && typeof args.lines === "string") {
|
|
891
|
+
Object.assign(readArgs, parseReadLines(args.lines));
|
|
945
892
|
}
|
|
893
|
+
return toolRead(provider, readArgs);
|
|
946
894
|
}
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
if (fileReadErrors.length > 0) {
|
|
950
|
-
errors.push(...fileReadErrors.map((e) => ({ message: `File read error: ${e.path} - ${e.error}` })));
|
|
895
|
+
default:
|
|
896
|
+
return `Unknown tool: ${name}`;
|
|
951
897
|
}
|
|
952
|
-
timings.total_ms = Date.now() - totalStart;
|
|
953
|
-
return {
|
|
954
|
-
terminationReason: "completed",
|
|
955
|
-
messages,
|
|
956
|
-
finish: { payload, metadata: finishMeta, resolved },
|
|
957
|
-
timings
|
|
958
|
-
};
|
|
959
898
|
}
|
|
960
899
|
async function* runWarpGrepStreaming(config) {
|
|
961
900
|
const totalStart = Date.now();
|
|
962
901
|
const timeoutMs = config.timeout ?? AGENT_CONFIG.TIMEOUT_MS;
|
|
963
902
|
const timings = { turns: [], timeout_ms: timeoutMs };
|
|
964
|
-
const repoRoot =
|
|
903
|
+
const repoRoot = import_path3.default.resolve(config.repoRoot || process.cwd());
|
|
965
904
|
const model = config.model || DEFAULT_MODEL;
|
|
966
905
|
const messages = [];
|
|
967
906
|
const maxTurns = AGENT_CONFIG.MAX_TURNS;
|
|
@@ -977,7 +916,7 @@ async function* runWarpGrepStreaming(config) {
|
|
|
977
916
|
const turnMetrics = { turn, morph_api_ms: 0, local_tools_ms: 0 };
|
|
978
917
|
enforceContextLimit(messages);
|
|
979
918
|
const modelCallStart = Date.now();
|
|
980
|
-
const
|
|
919
|
+
const response = await callModel(messages, model, {
|
|
981
920
|
morphApiKey: config.morphApiKey,
|
|
982
921
|
morphApiUrl: config.morphApiUrl,
|
|
983
922
|
retryConfig: config.retryConfig,
|
|
@@ -985,90 +924,45 @@ async function* runWarpGrepStreaming(config) {
|
|
|
985
924
|
search_type: config.search_type
|
|
986
925
|
}).catch((e) => {
|
|
987
926
|
const errMsg = e instanceof Error ? e.message : String(e);
|
|
988
|
-
console.error(`[warp_grep
|
|
927
|
+
console.error(`[warp_grep] Morph API call failed on turn ${turn}:`, errMsg);
|
|
989
928
|
errors.push({ message: errMsg });
|
|
990
|
-
return
|
|
929
|
+
return null;
|
|
991
930
|
});
|
|
992
931
|
turnMetrics.morph_api_ms = Date.now() - modelCallStart;
|
|
993
|
-
if (!
|
|
994
|
-
console.error(`[warp_grep:stream] Empty response from Morph API on turn ${turn}. Errors so far:`, errors);
|
|
932
|
+
if (!response) {
|
|
995
933
|
timings.turns.push(turnMetrics);
|
|
996
934
|
break;
|
|
997
935
|
}
|
|
998
|
-
|
|
999
|
-
|
|
936
|
+
const toolCalls = response.tool_calls;
|
|
937
|
+
messages.push({
|
|
938
|
+
role: "assistant",
|
|
939
|
+
content: response.content,
|
|
940
|
+
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
|
|
941
|
+
});
|
|
1000
942
|
if (toolCalls.length === 0) {
|
|
1001
|
-
console.error(`[warp_grep
|
|
1002
|
-
errors.push({ message: "No tool calls produced by the model.
|
|
943
|
+
console.error(`[warp_grep] No tool calls on turn ${turn}. Content: ${(response.content || "").slice(0, 500)}`);
|
|
944
|
+
errors.push({ message: "No tool calls produced by the model." });
|
|
1003
945
|
terminationReason = "terminated";
|
|
1004
946
|
timings.turns.push(turnMetrics);
|
|
1005
947
|
break;
|
|
1006
948
|
}
|
|
1007
949
|
yield {
|
|
1008
950
|
turn,
|
|
1009
|
-
toolCalls: toolCalls.map((
|
|
1010
|
-
name:
|
|
1011
|
-
arguments:
|
|
951
|
+
toolCalls: toolCalls.map((tc) => ({
|
|
952
|
+
name: tc.function.name,
|
|
953
|
+
arguments: safeParseJSON(tc.function.arguments)
|
|
1012
954
|
}))
|
|
1013
955
|
};
|
|
1014
|
-
const
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
const formatted = [];
|
|
1020
|
-
for (const c of skipCalls) {
|
|
1021
|
-
const msg = c.arguments?.message || "Command skipped due to parsing error";
|
|
1022
|
-
formatted.push(msg);
|
|
1023
|
-
}
|
|
1024
|
-
const allPromises = [];
|
|
1025
|
-
for (const c of grepCalls) {
|
|
1026
|
-
const args = c.arguments ?? {};
|
|
1027
|
-
allPromises.push(
|
|
1028
|
-
toolGrep(provider, args).then(
|
|
1029
|
-
({ output }) => formatAgentToolOutput("grep", args, output),
|
|
1030
|
-
(err) => formatAgentToolOutput("grep", args, String(err), { isError: true })
|
|
1031
|
-
)
|
|
1032
|
-
);
|
|
1033
|
-
}
|
|
1034
|
-
for (const c of listDirCalls) {
|
|
1035
|
-
const args = c.arguments ?? {};
|
|
1036
|
-
allPromises.push(
|
|
1037
|
-
toolListDirectory(provider, args).then(
|
|
1038
|
-
(p) => formatAgentToolOutput("list_directory", args, p),
|
|
1039
|
-
(err) => formatAgentToolOutput("list_directory", args, String(err), { isError: true })
|
|
1040
|
-
)
|
|
1041
|
-
);
|
|
1042
|
-
}
|
|
1043
|
-
for (const c of readCalls) {
|
|
1044
|
-
const args = c.arguments ?? {};
|
|
1045
|
-
allPromises.push(
|
|
1046
|
-
toolRead(provider, args).then(
|
|
1047
|
-
(p) => formatAgentToolOutput("read", args, p),
|
|
1048
|
-
(err) => formatAgentToolOutput("read", args, String(err), { isError: true })
|
|
1049
|
-
)
|
|
1050
|
-
);
|
|
1051
|
-
}
|
|
1052
|
-
const toolExecStart = Date.now();
|
|
1053
|
-
const allResults = await Promise.all(allPromises);
|
|
1054
|
-
turnMetrics.local_tools_ms = Date.now() - toolExecStart;
|
|
1055
|
-
for (const result of allResults) {
|
|
1056
|
-
formatted.push(result);
|
|
1057
|
-
}
|
|
1058
|
-
if (formatted.length > 0) {
|
|
1059
|
-
const turnMessage = formatTurnMessage(turn, maxTurns);
|
|
1060
|
-
const contextBudget = calculateContextBudget(messages);
|
|
1061
|
-
messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
|
|
1062
|
-
}
|
|
1063
|
-
timings.turns.push(turnMetrics);
|
|
1064
|
-
if (finishCalls.length) {
|
|
1065
|
-
const fc = finishCalls[0];
|
|
1066
|
-
const files = fc.arguments?.files ?? [];
|
|
1067
|
-
const textResult = fc.arguments?.textResult;
|
|
956
|
+
const finishCall = toolCalls.find((tc) => tc.function.name === "finish");
|
|
957
|
+
if (finishCall) {
|
|
958
|
+
const args = safeParseJSON(finishCall.function.arguments);
|
|
959
|
+
const filesStr = args.files || "";
|
|
960
|
+
const files = parseFinishFiles(filesStr);
|
|
1068
961
|
finishMeta = { files };
|
|
1069
962
|
terminationReason = "completed";
|
|
1070
963
|
if (files.length === 0) {
|
|
1071
|
-
const payload2 =
|
|
964
|
+
const payload2 = filesStr || "No relevant code found.";
|
|
965
|
+
timings.turns.push(turnMetrics);
|
|
1072
966
|
timings.total_ms = Date.now() - totalStart;
|
|
1073
967
|
return {
|
|
1074
968
|
terminationReason: "completed",
|
|
@@ -1077,8 +971,25 @@ async function* runWarpGrepStreaming(config) {
|
|
|
1077
971
|
timings
|
|
1078
972
|
};
|
|
1079
973
|
}
|
|
974
|
+
timings.turns.push(turnMetrics);
|
|
1080
975
|
break;
|
|
1081
976
|
}
|
|
977
|
+
const toolExecStart = Date.now();
|
|
978
|
+
const results = await Promise.all(
|
|
979
|
+
toolCalls.map(async (tc) => {
|
|
980
|
+
const args = safeParseJSON(tc.function.arguments);
|
|
981
|
+
const output = await executeTool(provider, tc.function.name, args, repoRoot).catch((err) => String(err));
|
|
982
|
+
return { tool_call_id: tc.id, content: output };
|
|
983
|
+
})
|
|
984
|
+
);
|
|
985
|
+
turnMetrics.local_tools_ms = Date.now() - toolExecStart;
|
|
986
|
+
for (const result of results) {
|
|
987
|
+
messages.push({ role: "tool", tool_call_id: result.tool_call_id, content: result.content });
|
|
988
|
+
}
|
|
989
|
+
const turnMsg = formatTurnMessage(turn, maxTurns);
|
|
990
|
+
const budget = calculateContextBudget(messages);
|
|
991
|
+
messages.push({ role: "user", content: turnMsg + "\n" + budget });
|
|
992
|
+
timings.turns.push(turnMetrics);
|
|
1082
993
|
}
|
|
1083
994
|
if (terminationReason !== "completed" || !finishMeta) {
|
|
1084
995
|
timings.total_ms = Date.now() - totalStart;
|
|
@@ -1096,17 +1007,22 @@ async function* runWarpGrepStreaming(config) {
|
|
|
1096
1007
|
repoRoot,
|
|
1097
1008
|
finishMeta.files,
|
|
1098
1009
|
async (p, s, e) => {
|
|
1010
|
+
let resolvedPath = p;
|
|
1011
|
+
if (!p.startsWith(repoRoot)) {
|
|
1012
|
+
const relative = p.startsWith("/") ? p.slice(1) : p;
|
|
1013
|
+
resolvedPath = import_path3.default.join(repoRoot, relative);
|
|
1014
|
+
}
|
|
1099
1015
|
try {
|
|
1100
|
-
const rr = await provider.read({ path:
|
|
1016
|
+
const rr = await provider.read({ path: resolvedPath, start: s, end: e });
|
|
1101
1017
|
return rr.lines.map((l) => {
|
|
1102
1018
|
const idx = l.indexOf("|");
|
|
1103
1019
|
return idx >= 0 ? l.slice(idx + 1) : l;
|
|
1104
1020
|
});
|
|
1105
1021
|
} catch (err) {
|
|
1106
1022
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
1107
|
-
fileReadErrors.push({ path:
|
|
1108
|
-
console.error(`[warp_grep] Failed to read file: ${
|
|
1109
|
-
return [`[couldn't find: ${
|
|
1023
|
+
fileReadErrors.push({ path: resolvedPath, error: errorMsg });
|
|
1024
|
+
console.error(`[warp_grep] Failed to read file: ${resolvedPath} - ${errorMsg}`);
|
|
1025
|
+
return [`[couldn't find: ${resolvedPath}]`];
|
|
1110
1026
|
}
|
|
1111
1027
|
}
|
|
1112
1028
|
);
|
|
@@ -1122,6 +1038,14 @@ async function* runWarpGrepStreaming(config) {
|
|
|
1122
1038
|
timings
|
|
1123
1039
|
};
|
|
1124
1040
|
}
|
|
1041
|
+
async function runWarpGrep(config) {
|
|
1042
|
+
const gen = runWarpGrepStreaming(config);
|
|
1043
|
+
let result = await gen.next();
|
|
1044
|
+
while (!result.done) {
|
|
1045
|
+
result = await gen.next();
|
|
1046
|
+
}
|
|
1047
|
+
return result.value;
|
|
1048
|
+
}
|
|
1125
1049
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1126
1050
|
0 && (module.exports = {
|
|
1127
1051
|
runWarpGrep,
|