@morphllm/morphsdk 0.2.145 → 0.2.146
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-HBIW2XV2.js → chunk-4PBUB77N.js} +2 -2
- package/dist/{chunk-SUE4GYA2.js → chunk-BDHKL3MT.js} +2 -2
- package/dist/{chunk-S54SPKX3.js → chunk-BIQ7234U.js} +2 -2
- package/dist/{chunk-I3J46TSB.js → chunk-DKODF3YG.js} +4 -5
- package/dist/chunk-DKODF3YG.js.map +1 -0
- package/dist/{chunk-MRPASJBX.js → chunk-E45FW5EK.js} +2 -2
- package/dist/{chunk-BXRJYLRS.js → chunk-E4YKEKGW.js} +2 -2
- package/dist/{chunk-G23BI5CQ.js → chunk-EU7OLX4Z.js} +2 -2
- package/dist/chunk-EUHNJMWL.js +409 -0
- package/dist/chunk-EUHNJMWL.js.map +1 -0
- package/dist/{chunk-HE7K2QNQ.js → chunk-FBOJJ3UY.js} +17 -17
- package/dist/{chunk-HYRHI2UL.js → chunk-FIVYDIHX.js} +1 -1
- package/dist/{chunk-GXM3G7Z4.js → chunk-FYO46OT6.js} +2 -2
- package/dist/{chunk-GHPQYSSF.js → chunk-GJUB3ECP.js} +2 -2
- package/dist/{chunk-4Y2NM6JD.js → chunk-HZOTLGJH.js} +2 -42
- package/dist/chunk-HZOTLGJH.js.map +1 -0
- package/dist/{chunk-MTJ3PR4M.js → chunk-I7SFRYTX.js} +2 -2
- package/dist/{chunk-PX7ODEML.js → chunk-J2HIK4GB.js} +2 -2
- package/dist/{chunk-RZXS4ADX.js → chunk-JSWNBCGS.js} +2 -2
- package/dist/{chunk-GXCWKYGU.js → chunk-KYKRRF7E.js} +2 -2
- package/dist/{chunk-N7TTZIBK.js → chunk-MMBQKN4G.js} +2 -2
- package/dist/{chunk-B3AKP3RA.js → chunk-NF2QWJDY.js} +2 -31
- package/dist/chunk-NF2QWJDY.js.map +1 -0
- package/dist/{chunk-JMUAQQJU.js → chunk-NKUSUSVI.js} +3 -3
- package/dist/{chunk-VRV5UYTN.js → chunk-OV57JBMB.js} +2 -2
- package/dist/{chunk-EPIOAODF.js → chunk-Q36MNOFA.js} +2 -2
- package/dist/{chunk-JRBU4UNP.js → chunk-QRSWXP4K.js} +2 -2
- package/dist/{chunk-KELRCMA6.js → chunk-SJYAKVSS.js} +2 -2
- package/dist/{chunk-KELRCMA6.js.map → chunk-SJYAKVSS.js.map} +1 -1
- package/dist/{chunk-IRWHN55G.js → chunk-T564HFSH.js} +1 -1
- package/dist/{chunk-6CFKWZK3.js → chunk-UVNENJ6H.js} +3 -3
- package/dist/{chunk-5FCXLQJU.js → chunk-UYPWKQKV.js} +2 -2
- package/dist/{chunk-BAF33L6C.js → chunk-V73GO5AJ.js} +2 -2
- package/dist/chunk-VCKJ22DX.js +131 -0
- package/dist/chunk-VCKJ22DX.js.map +1 -0
- package/dist/{chunk-XL7R3XN5.js → chunk-VZ6VYRQB.js} +2 -2
- package/dist/{chunk-4LWMPKSB.js → chunk-YIETFYCL.js} +44 -71
- package/dist/chunk-YIETFYCL.js.map +1 -0
- package/dist/client.cjs +438 -426
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +27 -26
- package/dist/edge.cjs +1 -1
- package/dist/edge.cjs.map +1 -1
- package/dist/edge.js +4 -4
- package/dist/{finish-Ddj1MPGt.d.ts → finish-DBKuo8yj.d.ts} +1 -1
- package/dist/index.cjs +438 -445
- 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 +434 -422
- package/dist/subagents/anthropic.cjs.map +1 -1
- package/dist/subagents/anthropic.js +9 -8
- package/dist/subagents/vercel.cjs +434 -422
- package/dist/subagents/vercel.cjs.map +1 -1
- package/dist/subagents/vercel.js +9 -8
- 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 +3 -4
- package/dist/tools/warp_grep/agent/config.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/config.d.ts +1 -2
- package/dist/tools/warp_grep/agent/config.js +1 -1
- package/dist/tools/warp_grep/agent/parser.cjs +121 -52
- package/dist/tools/warp_grep/agent/parser.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/parser.d.ts +5 -12
- package/dist/tools/warp_grep/agent/parser.js +3 -7
- package/dist/tools/warp_grep/agent/runner.cjs +416 -335
- package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/runner.d.ts +3 -6
- package/dist/tools/warp_grep/agent/runner.js +6 -5
- package/dist/tools/warp_grep/agent/types.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/types.d.ts +3 -22
- package/dist/tools/warp_grep/anthropic.cjs +434 -422
- package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
- package/dist/tools/warp_grep/anthropic.js +9 -8
- package/dist/tools/warp_grep/client.cjs +434 -422
- package/dist/tools/warp_grep/client.cjs.map +1 -1
- package/dist/tools/warp_grep/client.js +8 -7
- package/dist/tools/warp_grep/gemini.cjs +434 -422
- package/dist/tools/warp_grep/gemini.cjs.map +1 -1
- package/dist/tools/warp_grep/gemini.js +8 -7
- package/dist/tools/warp_grep/gemini.js.map +1 -1
- package/dist/tools/warp_grep/harness.cjs +176 -164
- package/dist/tools/warp_grep/harness.cjs.map +1 -1
- package/dist/tools/warp_grep/harness.d.ts +38 -17
- package/dist/tools/warp_grep/harness.js +14 -15
- package/dist/tools/warp_grep/harness.js.map +1 -1
- package/dist/tools/warp_grep/index.cjs +434 -441
- 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 +434 -422
- package/dist/tools/warp_grep/openai.cjs.map +1 -1
- package/dist/tools/warp_grep/openai.js +9 -8
- package/dist/tools/warp_grep/providers/local.cjs +2 -43
- package/dist/tools/warp_grep/providers/local.cjs.map +1 -1
- package/dist/tools/warp_grep/providers/local.d.ts +1 -5
- package/dist/tools/warp_grep/providers/local.js +2 -2
- package/dist/tools/warp_grep/providers/remote.cjs +2 -32
- package/dist/tools/warp_grep/providers/remote.cjs.map +1 -1
- package/dist/tools/warp_grep/providers/remote.d.ts +1 -9
- 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 +1 -14
- package/dist/tools/warp_grep/vercel.cjs +434 -422
- package/dist/tools/warp_grep/vercel.cjs.map +1 -1
- package/dist/tools/warp_grep/vercel.js +9 -8
- 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-4LWMPKSB.js.map +0 -1
- package/dist/chunk-4Y2NM6JD.js.map +0 -1
- package/dist/chunk-B3AKP3RA.js.map +0 -1
- package/dist/chunk-CMSHXALI.js +0 -60
- package/dist/chunk-CMSHXALI.js.map +0 -1
- package/dist/chunk-I3J46TSB.js.map +0 -1
- package/dist/chunk-OPEQQGST.js +0 -396
- package/dist/chunk-OPEQQGST.js.map +0 -1
- /package/dist/{chunk-HBIW2XV2.js.map → chunk-4PBUB77N.js.map} +0 -0
- /package/dist/{chunk-SUE4GYA2.js.map → chunk-BDHKL3MT.js.map} +0 -0
- /package/dist/{chunk-S54SPKX3.js.map → chunk-BIQ7234U.js.map} +0 -0
- /package/dist/{chunk-MRPASJBX.js.map → chunk-E45FW5EK.js.map} +0 -0
- /package/dist/{chunk-BXRJYLRS.js.map → chunk-E4YKEKGW.js.map} +0 -0
- /package/dist/{chunk-G23BI5CQ.js.map → chunk-EU7OLX4Z.js.map} +0 -0
- /package/dist/{chunk-HE7K2QNQ.js.map → chunk-FBOJJ3UY.js.map} +0 -0
- /package/dist/{chunk-HYRHI2UL.js.map → chunk-FIVYDIHX.js.map} +0 -0
- /package/dist/{chunk-GXM3G7Z4.js.map → chunk-FYO46OT6.js.map} +0 -0
- /package/dist/{chunk-GHPQYSSF.js.map → chunk-GJUB3ECP.js.map} +0 -0
- /package/dist/{chunk-MTJ3PR4M.js.map → chunk-I7SFRYTX.js.map} +0 -0
- /package/dist/{chunk-PX7ODEML.js.map → chunk-J2HIK4GB.js.map} +0 -0
- /package/dist/{chunk-RZXS4ADX.js.map → chunk-JSWNBCGS.js.map} +0 -0
- /package/dist/{chunk-GXCWKYGU.js.map → chunk-KYKRRF7E.js.map} +0 -0
- /package/dist/{chunk-N7TTZIBK.js.map → chunk-MMBQKN4G.js.map} +0 -0
- /package/dist/{chunk-JMUAQQJU.js.map → chunk-NKUSUSVI.js.map} +0 -0
- /package/dist/{chunk-VRV5UYTN.js.map → chunk-OV57JBMB.js.map} +0 -0
- /package/dist/{chunk-EPIOAODF.js.map → chunk-Q36MNOFA.js.map} +0 -0
- /package/dist/{chunk-JRBU4UNP.js.map → chunk-QRSWXP4K.js.map} +0 -0
- /package/dist/{chunk-IRWHN55G.js.map → chunk-T564HFSH.js.map} +0 -0
- /package/dist/{chunk-6CFKWZK3.js.map → chunk-UVNENJ6H.js.map} +0 -0
- /package/dist/{chunk-5FCXLQJU.js.map → chunk-UYPWKQKV.js.map} +0 -0
- /package/dist/{chunk-BAF33L6C.js.map → chunk-V73GO5AJ.js.map} +0 -0
- /package/dist/{chunk-XL7R3XN5.js.map → chunk-VZ6VYRQB.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,7 @@ var init_package = __esm({
|
|
|
36
36
|
"package.json"() {
|
|
37
37
|
package_default = {
|
|
38
38
|
name: "@morphllm/morphsdk",
|
|
39
|
-
version: "0.2.
|
|
39
|
+
version: "0.2.146",
|
|
40
40
|
description: "TypeScript SDK and CLI for Morph Fast Apply integration",
|
|
41
41
|
type: "module",
|
|
42
42
|
main: "./dist/index.cjs",
|
|
@@ -416,12 +416,11 @@ var init_config = __esm({
|
|
|
416
416
|
return isNaN(parsed) || parsed <= 0 ? defaultMs : parsed;
|
|
417
417
|
};
|
|
418
418
|
AGENT_CONFIG = {
|
|
419
|
-
MAX_TURNS:
|
|
419
|
+
MAX_TURNS: 4,
|
|
420
420
|
/** Default timeout for model calls. Can be overridden via MORPH_WARP_GREP_TIMEOUT env var (in ms) */
|
|
421
421
|
TIMEOUT_MS: parseEnvTimeout(process.env.MORPH_WARP_GREP_TIMEOUT, 3e4),
|
|
422
|
-
MAX_CONTEXT_CHARS:
|
|
422
|
+
MAX_CONTEXT_CHARS: 54e4,
|
|
423
423
|
MAX_OUTPUT_LINES: 200,
|
|
424
|
-
MAX_LIST_RESULTS: 500,
|
|
425
424
|
MAX_READ_LINES: 800,
|
|
426
425
|
MAX_LIST_DEPTH: 3,
|
|
427
426
|
LIST_TIMEOUT_MS: 2e3
|
|
@@ -506,7 +505,7 @@ var init_config = __esm({
|
|
|
506
505
|
".*"
|
|
507
506
|
];
|
|
508
507
|
DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || "").split(",").map((s) => s.trim()).filter(Boolean).concat(BUILTIN_EXCLUDES);
|
|
509
|
-
DEFAULT_MODEL = "morph-warp-grep-v2
|
|
508
|
+
DEFAULT_MODEL = "morph-warp-grep-v2";
|
|
510
509
|
}
|
|
511
510
|
});
|
|
512
511
|
|
|
@@ -579,19 +578,19 @@ var init_ripgrep = __esm({
|
|
|
579
578
|
|
|
580
579
|
// tools/warp_grep/utils/paths.ts
|
|
581
580
|
function resolveUnderRepo(repoRoot, targetPath) {
|
|
582
|
-
const absRoot =
|
|
583
|
-
const resolved =
|
|
581
|
+
const absRoot = import_path4.default.resolve(repoRoot);
|
|
582
|
+
const resolved = import_path4.default.resolve(absRoot, targetPath);
|
|
584
583
|
ensureWithinRepo(absRoot, resolved);
|
|
585
584
|
return resolved;
|
|
586
585
|
}
|
|
587
586
|
function ensureWithinRepo(repoRoot, absTarget) {
|
|
588
|
-
const rel =
|
|
589
|
-
if (rel.startsWith("..") ||
|
|
587
|
+
const rel = import_path4.default.relative(import_path4.default.resolve(repoRoot), import_path4.default.resolve(absTarget));
|
|
588
|
+
if (rel.startsWith("..") || import_path4.default.isAbsolute(rel)) {
|
|
590
589
|
throw new Error(`Path outside repository root: ${absTarget}`);
|
|
591
590
|
}
|
|
592
591
|
}
|
|
593
592
|
function toRepoRelative(repoRoot, absPath) {
|
|
594
|
-
return
|
|
593
|
+
return import_path4.default.relative(import_path4.default.resolve(repoRoot), import_path4.default.resolve(absPath));
|
|
595
594
|
}
|
|
596
595
|
function isSymlink(p) {
|
|
597
596
|
try {
|
|
@@ -602,7 +601,7 @@ function isSymlink(p) {
|
|
|
602
601
|
}
|
|
603
602
|
}
|
|
604
603
|
function fixPathRepetition(fullPath) {
|
|
605
|
-
const segments = fullPath.split(
|
|
604
|
+
const segments = fullPath.split(import_path4.default.sep).filter(Boolean);
|
|
606
605
|
if (segments.length < 2) return null;
|
|
607
606
|
for (let len = Math.floor(segments.length / 2); len >= 1; len--) {
|
|
608
607
|
for (let i = 0; i <= segments.length - 2 * len; i++) {
|
|
@@ -610,7 +609,7 @@ function fixPathRepetition(fullPath) {
|
|
|
610
609
|
const second = segments.slice(i + len, i + 2 * len);
|
|
611
610
|
if (first.every((seg, idx) => seg === second[idx])) {
|
|
612
611
|
const fixed = [...segments.slice(0, i), ...segments.slice(i + len)];
|
|
613
|
-
return
|
|
612
|
+
return import_path4.default.sep + fixed.join(import_path4.default.sep);
|
|
614
613
|
}
|
|
615
614
|
}
|
|
616
615
|
}
|
|
@@ -634,12 +633,12 @@ function isTextualFile(filePath, maxBytes = 2e6) {
|
|
|
634
633
|
return false;
|
|
635
634
|
}
|
|
636
635
|
}
|
|
637
|
-
var import_fs,
|
|
636
|
+
var import_fs, import_path4;
|
|
638
637
|
var init_paths = __esm({
|
|
639
638
|
"tools/warp_grep/utils/paths.ts"() {
|
|
640
639
|
"use strict";
|
|
641
640
|
import_fs = __toESM(require("fs"), 1);
|
|
642
|
-
|
|
641
|
+
import_path4 = __toESM(require("path"), 1);
|
|
643
642
|
}
|
|
644
643
|
});
|
|
645
644
|
|
|
@@ -670,12 +669,12 @@ function shouldSkip2(name, allowNames) {
|
|
|
670
669
|
}
|
|
671
670
|
return false;
|
|
672
671
|
}
|
|
673
|
-
var import_promises2,
|
|
672
|
+
var import_promises2, import_path5, SKIP_NAMES2, SKIP_EXTENSIONS2, LocalRipgrepProvider;
|
|
674
673
|
var init_local = __esm({
|
|
675
674
|
"tools/warp_grep/providers/local.ts"() {
|
|
676
675
|
"use strict";
|
|
677
676
|
import_promises2 = __toESM(require("fs/promises"), 1);
|
|
678
|
-
|
|
677
|
+
import_path5 = __toESM(require("path"), 1);
|
|
679
678
|
init_ripgrep();
|
|
680
679
|
init_paths();
|
|
681
680
|
init_files();
|
|
@@ -777,7 +776,7 @@ var init_local = __esm({
|
|
|
777
776
|
}
|
|
778
777
|
const stat = await import_promises2.default.stat(abs).catch(() => null);
|
|
779
778
|
if (!stat) return { lines: [] };
|
|
780
|
-
const targetArg = abs ===
|
|
779
|
+
const targetArg = abs === import_path5.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
|
|
781
780
|
const contextLines = params.context_lines !== void 0 ? String(params.context_lines) : "1";
|
|
782
781
|
const args = [
|
|
783
782
|
"--no-config",
|
|
@@ -932,7 +931,7 @@ Details: ${res.stderr}` : ""}`
|
|
|
932
931
|
if (timedOut || results.length >= maxResults) break;
|
|
933
932
|
if (shouldSkip2(entry.name, allowNames)) continue;
|
|
934
933
|
if (regex && !regex.test(entry.name)) continue;
|
|
935
|
-
const full =
|
|
934
|
+
const full = import_path5.default.join(dir, entry.name);
|
|
936
935
|
const isDir = entry.isDirectory();
|
|
937
936
|
results.push({
|
|
938
937
|
name: entry.name,
|
|
@@ -948,46 +947,6 @@ Details: ${res.stderr}` : ""}`
|
|
|
948
947
|
await walk(abs, 0);
|
|
949
948
|
return results;
|
|
950
949
|
}
|
|
951
|
-
async glob(params) {
|
|
952
|
-
let abs;
|
|
953
|
-
try {
|
|
954
|
-
abs = params.path ? resolveUnderRepo(this.repoRoot, params.path) : this.repoRoot;
|
|
955
|
-
} catch (err) {
|
|
956
|
-
return { files: [], searchDir: this.repoRoot, totalFound: 0, error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}` };
|
|
957
|
-
}
|
|
958
|
-
const stat = await import_promises2.default.stat(abs).catch(() => null);
|
|
959
|
-
if (!stat || !stat.isDirectory()) {
|
|
960
|
-
return { files: [], searchDir: abs, totalFound: 0, error: `[PATH ERROR] Directory not found: ${params.path || "."}` };
|
|
961
|
-
}
|
|
962
|
-
const targetArg = abs === import_path6.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
|
|
963
|
-
const args = [
|
|
964
|
-
"--no-config",
|
|
965
|
-
"--files",
|
|
966
|
-
"--color=never",
|
|
967
|
-
"-g",
|
|
968
|
-
params.pattern,
|
|
969
|
-
...this.excludes.filter((e) => !this.allowNames?.has(e)).flatMap((e) => ["-g", `!${e}`]),
|
|
970
|
-
targetArg || "."
|
|
971
|
-
];
|
|
972
|
-
const res = await runRipgrep(args, { cwd: this.repoRoot });
|
|
973
|
-
if (res.exitCode === -1) {
|
|
974
|
-
return { files: [], searchDir: abs, totalFound: 0, error: `[RIPGREP NOT AVAILABLE] ripgrep (rg) is required for glob search.` };
|
|
975
|
-
}
|
|
976
|
-
if (res.exitCode !== 0 && res.exitCode !== 1) {
|
|
977
|
-
return { files: [], searchDir: abs, totalFound: 0, error: `[GLOB ERROR] glob failed with exit code ${res.exitCode}${res.stderr ? `: ${res.stderr}` : ""}` };
|
|
978
|
-
}
|
|
979
|
-
const absRoot = import_path6.default.resolve(this.repoRoot);
|
|
980
|
-
const relFiles = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
|
|
981
|
-
const absFiles = relFiles.map((f) => import_path6.default.resolve(absRoot, f));
|
|
982
|
-
const withMtime = [];
|
|
983
|
-
for (const f of absFiles) {
|
|
984
|
-
const s = await import_promises2.default.stat(f).catch(() => null);
|
|
985
|
-
withMtime.push({ file: f, mtime: s?.mtimeMs ?? 0 });
|
|
986
|
-
}
|
|
987
|
-
withMtime.sort((a, b) => b.mtime - a.mtime);
|
|
988
|
-
const totalFound = withMtime.length;
|
|
989
|
-
return { files: withMtime.slice(0, 100).map((f) => f.file), searchDir: abs, totalFound };
|
|
990
|
-
}
|
|
991
950
|
};
|
|
992
951
|
}
|
|
993
952
|
});
|
|
@@ -2556,58 +2515,131 @@ async function checkHealth(config = {}) {
|
|
|
2556
2515
|
init_config();
|
|
2557
2516
|
|
|
2558
2517
|
// tools/warp_grep/agent/parser.ts
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
const trimmed = rangeStr.trim();
|
|
2563
|
-
if (!trimmed) continue;
|
|
2564
|
-
const parts = trimmed.split("-").map((v) => parseInt(v.trim(), 10));
|
|
2565
|
-
if (parts.length >= 2 && Number.isFinite(parts[0]) && Number.isFinite(parts[1])) {
|
|
2566
|
-
ranges.push([parts[0], parts[1]]);
|
|
2567
|
-
} else if (Number.isFinite(parts[0])) {
|
|
2568
|
-
ranges.push([parts[0], parts[0]]);
|
|
2569
|
-
}
|
|
2570
|
-
}
|
|
2571
|
-
if (ranges.length === 1) return { start: ranges[0][0], end: ranges[0][1] };
|
|
2572
|
-
if (ranges.length > 1) return { lines: ranges };
|
|
2573
|
-
return {};
|
|
2518
|
+
var VALID_COMMANDS = ["list_directory", "ripgrep", "read", "finish"];
|
|
2519
|
+
function isValidCommand(name) {
|
|
2520
|
+
return VALID_COMMANDS.includes(name);
|
|
2574
2521
|
}
|
|
2575
|
-
function
|
|
2576
|
-
const
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
const
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
}
|
|
2599
|
-
|
|
2522
|
+
function parseQwen3ToolCalls(text) {
|
|
2523
|
+
const tools = [];
|
|
2524
|
+
const toolCallRegex = /<tool_call>\s*<function=([a-z_][a-z0-9_]*)>([\s\S]*?)<\/function>\s*<\/tool_call>/gi;
|
|
2525
|
+
let match;
|
|
2526
|
+
while ((match = toolCallRegex.exec(text)) !== null) {
|
|
2527
|
+
const funcName = match[1].toLowerCase();
|
|
2528
|
+
const body = match[2];
|
|
2529
|
+
if (!isValidCommand(funcName)) continue;
|
|
2530
|
+
const params = {};
|
|
2531
|
+
const paramRegex = /<parameter=([a-z_][a-z0-9_]*)>([\s\S]*?)<\/parameter>/gi;
|
|
2532
|
+
let paramMatch;
|
|
2533
|
+
while ((paramMatch = paramRegex.exec(body)) !== null) {
|
|
2534
|
+
params[paramMatch[1].toLowerCase()] = paramMatch[2].trim();
|
|
2535
|
+
}
|
|
2536
|
+
if (funcName === "ripgrep") {
|
|
2537
|
+
const pattern = params.pattern;
|
|
2538
|
+
if (!pattern) continue;
|
|
2539
|
+
const args = {
|
|
2540
|
+
pattern,
|
|
2541
|
+
path: params.path || ".",
|
|
2542
|
+
...params.glob && { glob: params.glob },
|
|
2543
|
+
...params.context_lines && { context_lines: parseInt(params.context_lines, 10) },
|
|
2544
|
+
...params.case_sensitive && { case_sensitive: params.case_sensitive === "true" }
|
|
2545
|
+
};
|
|
2546
|
+
tools.push({ name: "grep", arguments: args });
|
|
2547
|
+
} else if (funcName === "list_directory") {
|
|
2548
|
+
const command = params.command;
|
|
2549
|
+
const directPath = params.path;
|
|
2550
|
+
let dirPath = directPath || ".";
|
|
2551
|
+
if (!directPath && command) {
|
|
2552
|
+
const tokens = command.trim().split(/\s+/);
|
|
2553
|
+
const pathTokens = tokens.slice(1).filter((t) => !t.startsWith("-") && !t.startsWith("|") && !t.startsWith("\\("));
|
|
2554
|
+
if (pathTokens.length > 0) {
|
|
2555
|
+
dirPath = pathTokens[0];
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
tools.push({ name: "list_directory", arguments: { path: dirPath, pattern: params.pattern || null } });
|
|
2559
|
+
} else if (funcName === "read") {
|
|
2560
|
+
const filePath = params.path;
|
|
2561
|
+
if (!filePath) continue;
|
|
2562
|
+
const args = { path: filePath };
|
|
2563
|
+
const linesStr = params.lines;
|
|
2564
|
+
if (linesStr) {
|
|
2565
|
+
const ranges = [];
|
|
2566
|
+
for (const rangeStr of linesStr.split(",")) {
|
|
2567
|
+
const trimmed = rangeStr.trim();
|
|
2568
|
+
if (!trimmed) continue;
|
|
2569
|
+
const [s, e] = trimmed.split("-").map((v) => parseInt(v.trim(), 10));
|
|
2570
|
+
if (Number.isFinite(s) && Number.isFinite(e)) {
|
|
2571
|
+
ranges.push([s, e]);
|
|
2572
|
+
} else if (Number.isFinite(s)) {
|
|
2573
|
+
ranges.push([s, s]);
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
if (ranges.length === 1) {
|
|
2577
|
+
args.start = ranges[0][0];
|
|
2578
|
+
args.end = ranges[0][1];
|
|
2579
|
+
} else if (ranges.length > 1) {
|
|
2580
|
+
args.lines = ranges;
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
tools.push({ name: "read", arguments: args });
|
|
2584
|
+
} else if (funcName === "finish") {
|
|
2585
|
+
if (params.result && !params.files) {
|
|
2586
|
+
tools.push({ name: "finish", arguments: { files: [], textResult: params.result } });
|
|
2587
|
+
continue;
|
|
2588
|
+
}
|
|
2589
|
+
const filesStr = params.files;
|
|
2590
|
+
if (!filesStr) {
|
|
2591
|
+
tools.push({ name: "finish", arguments: { files: [], textResult: "No relevant code found." } });
|
|
2592
|
+
continue;
|
|
2593
|
+
}
|
|
2594
|
+
const files = [];
|
|
2595
|
+
for (const line of filesStr.split("\n")) {
|
|
2596
|
+
const trimmed = line.trim();
|
|
2597
|
+
if (!trimmed) continue;
|
|
2598
|
+
const colonIdx = trimmed.indexOf(":");
|
|
2599
|
+
if (colonIdx === -1) {
|
|
2600
|
+
files.push({ path: trimmed, lines: "*" });
|
|
2601
|
+
} else {
|
|
2602
|
+
const filePath = trimmed.slice(0, colonIdx);
|
|
2603
|
+
const rangesPart = trimmed.slice(colonIdx + 1);
|
|
2604
|
+
const ranges = [];
|
|
2605
|
+
for (const rangeStr of rangesPart.split(",")) {
|
|
2606
|
+
const rt = rangeStr.trim();
|
|
2607
|
+
if (!rt || rt === "*") {
|
|
2608
|
+
files.push({ path: filePath, lines: "*" });
|
|
2609
|
+
break;
|
|
2610
|
+
}
|
|
2611
|
+
const [s, e] = rt.split("-").map((v) => parseInt(v.trim(), 10));
|
|
2612
|
+
if (Number.isFinite(s) && Number.isFinite(e)) {
|
|
2613
|
+
ranges.push([s, e]);
|
|
2614
|
+
} else if (Number.isFinite(s)) {
|
|
2615
|
+
ranges.push([s, s]);
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
if (ranges.length > 0) {
|
|
2619
|
+
files.push({ path: filePath, lines: ranges });
|
|
2620
|
+
} else if (!files.some((f) => f.path === filePath)) {
|
|
2621
|
+
files.push({ path: filePath, lines: "*" });
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
if (files.length > 0) {
|
|
2626
|
+
tools.push({ name: "finish", arguments: { files } });
|
|
2627
|
+
} else {
|
|
2628
|
+
tools.push({ name: "finish", arguments: { files: [], textResult: filesStr } });
|
|
2600
2629
|
}
|
|
2601
2630
|
}
|
|
2602
|
-
files.push({ path: filePath, lines: ranges.length > 0 ? ranges : "*" });
|
|
2603
2631
|
}
|
|
2604
|
-
return
|
|
2605
|
-
}
|
|
2606
|
-
function extractPathFromCommand(command) {
|
|
2607
|
-
const tokens = command.trim().split(/\s+/);
|
|
2608
|
-
const pathTokens = tokens.slice(1).filter((t) => !t.startsWith("-") && !t.startsWith("|") && !t.startsWith("\\("));
|
|
2609
|
-
return pathTokens[0] || ".";
|
|
2632
|
+
return tools;
|
|
2610
2633
|
}
|
|
2634
|
+
var LLMResponseParser = class {
|
|
2635
|
+
parse(text) {
|
|
2636
|
+
if (typeof text !== "string") {
|
|
2637
|
+
throw new TypeError("Command text must be a string.");
|
|
2638
|
+
}
|
|
2639
|
+
const withoutThink = text.replace(/<think>[\s\S]*?<\/think>/gi, "");
|
|
2640
|
+
return parseQwen3ToolCalls(withoutThink);
|
|
2641
|
+
}
|
|
2642
|
+
};
|
|
2611
2643
|
|
|
2612
2644
|
// tools/warp_grep/agent/tools/grep.ts
|
|
2613
2645
|
async function toolGrep(provider, args) {
|
|
@@ -2658,42 +2690,29 @@ async function toolRead(provider, args) {
|
|
|
2658
2690
|
|
|
2659
2691
|
// tools/warp_grep/agent/tools/list_directory.ts
|
|
2660
2692
|
init_config();
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
const
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
}
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
return res.error;
|
|
2685
|
-
}
|
|
2686
|
-
if (!res.files.length) {
|
|
2687
|
-
return "no matches";
|
|
2688
|
-
}
|
|
2689
|
-
const header = `Found ${res.totalFound} file(s) matching "${args.pattern}" within ${res.searchDir}, sorted by modification time (newest first):`;
|
|
2690
|
-
const body = res.files.join("\n");
|
|
2691
|
-
const truncated = res.totalFound > res.files.length ? `
|
|
2692
|
-
[${res.totalFound - res.files.length} files truncated]` : "";
|
|
2693
|
-
return `${header}
|
|
2694
|
-
---
|
|
2695
|
-
${body}
|
|
2696
|
-
---${truncated}`;
|
|
2693
|
+
async function toolListDirectory(provider, args) {
|
|
2694
|
+
const maxResults = args.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;
|
|
2695
|
+
const initialDepth = args.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
|
|
2696
|
+
async function getListRecursive(currentDepth) {
|
|
2697
|
+
const entries = await provider.listDirectory({
|
|
2698
|
+
path: args.path,
|
|
2699
|
+
pattern: args.pattern ?? null,
|
|
2700
|
+
maxResults,
|
|
2701
|
+
maxDepth: currentDepth
|
|
2702
|
+
});
|
|
2703
|
+
if (entries.length >= maxResults && currentDepth > 0) {
|
|
2704
|
+
return getListRecursive(currentDepth - 1);
|
|
2705
|
+
}
|
|
2706
|
+
return { entries };
|
|
2707
|
+
}
|
|
2708
|
+
const { entries: list } = await getListRecursive(initialDepth);
|
|
2709
|
+
if (!list.length) return "empty";
|
|
2710
|
+
const tree = list.map((e) => {
|
|
2711
|
+
const indent = " ".repeat(e.depth);
|
|
2712
|
+
const name = e.type === "dir" ? `${e.name}/` : e.name;
|
|
2713
|
+
return `${indent}${name}`;
|
|
2714
|
+
}).join("\n");
|
|
2715
|
+
return tree;
|
|
2697
2716
|
}
|
|
2698
2717
|
|
|
2699
2718
|
// tools/warp_grep/agent/tools/finish.ts
|
|
@@ -2754,21 +2773,32 @@ function mergeRanges(ranges) {
|
|
|
2754
2773
|
return merged;
|
|
2755
2774
|
}
|
|
2756
2775
|
|
|
2757
|
-
// tools/warp_grep/agent/
|
|
2758
|
-
var
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2776
|
+
// tools/warp_grep/agent/formatter.ts
|
|
2777
|
+
var ToolOutputFormatter = class {
|
|
2778
|
+
format(toolName, _args, output, options = {}) {
|
|
2779
|
+
const name = (toolName ?? "").trim();
|
|
2780
|
+
if (!name) {
|
|
2781
|
+
return "";
|
|
2782
|
+
}
|
|
2783
|
+
const payload = output?.toString?.()?.trim?.() ?? "";
|
|
2784
|
+
const isError = Boolean(options.isError);
|
|
2785
|
+
if (!payload && !isError) {
|
|
2786
|
+
return "";
|
|
2767
2787
|
}
|
|
2768
|
-
return
|
|
2788
|
+
return `<tool_response>
|
|
2789
|
+
${payload}
|
|
2790
|
+
</tool_response>`;
|
|
2769
2791
|
}
|
|
2770
|
-
|
|
2792
|
+
};
|
|
2793
|
+
var sharedFormatter = new ToolOutputFormatter();
|
|
2794
|
+
function formatAgentToolOutput(toolName, args, output, options = {}) {
|
|
2795
|
+
return sharedFormatter.format(toolName, args, output, options);
|
|
2771
2796
|
}
|
|
2797
|
+
|
|
2798
|
+
// tools/warp_grep/agent/helpers.ts
|
|
2799
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
2800
|
+
init_config();
|
|
2801
|
+
var TRUNCATED_MARKER = "[truncated for context limit]";
|
|
2772
2802
|
function formatTurnMessage(turnsUsed, maxTurns) {
|
|
2773
2803
|
const turnsRemaining = maxTurns - turnsUsed;
|
|
2774
2804
|
if (turnsRemaining === 1) {
|
|
@@ -2779,7 +2809,7 @@ You have used ${turnsUsed} turns, you only have 1 turn remaining. You have run o
|
|
|
2779
2809
|
You have used ${turnsUsed} turn${turnsUsed === 1 ? "" : "s"} and have ${turnsRemaining} remaining`;
|
|
2780
2810
|
}
|
|
2781
2811
|
function calculateContextBudget(messages) {
|
|
2782
|
-
const totalChars = messages.reduce((sum, m) => sum +
|
|
2812
|
+
const totalChars = messages.reduce((sum, m) => sum + m.content.length, 0);
|
|
2783
2813
|
const maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS;
|
|
2784
2814
|
const percent = Math.round(totalChars / maxChars * 100);
|
|
2785
2815
|
const usedK = Math.round(totalChars / 1e3);
|
|
@@ -2788,21 +2818,24 @@ function calculateContextBudget(messages) {
|
|
|
2788
2818
|
}
|
|
2789
2819
|
async function buildInitialState(repoRoot, searchTerm, provider, options) {
|
|
2790
2820
|
const budget = calculateContextBudget([]);
|
|
2791
|
-
const turnTag = `
|
|
2821
|
+
const turnTag = `Turn 0/${AGENT_CONFIG.MAX_TURNS}`;
|
|
2792
2822
|
const treeDepth = options?.search_type === "node_modules" ? 1 : 2;
|
|
2793
|
-
const absRoot = import_path3.default.resolve(repoRoot);
|
|
2794
2823
|
try {
|
|
2795
2824
|
const entries = await provider.listDirectory({
|
|
2796
2825
|
path: ".",
|
|
2797
2826
|
maxResults: AGENT_CONFIG.MAX_OUTPUT_LINES,
|
|
2798
2827
|
maxDepth: treeDepth
|
|
2799
2828
|
});
|
|
2800
|
-
const
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2829
|
+
const treeLines = entries.map((e) => {
|
|
2830
|
+
const indent = " ".repeat(e.depth);
|
|
2831
|
+
const name = e.type === "dir" ? `${e.name}/` : e.name;
|
|
2832
|
+
return `${indent}${name}`;
|
|
2833
|
+
});
|
|
2834
|
+
const repoName = import_path2.default.basename(repoRoot);
|
|
2835
|
+
const treeOutput = treeLines.length > 0 ? `${repoName}/
|
|
2836
|
+
${treeLines.join("\n")}` : `${repoName}/`;
|
|
2804
2837
|
return `<repo_structure>
|
|
2805
|
-
${
|
|
2838
|
+
${treeOutput}
|
|
2806
2839
|
</repo_structure>
|
|
2807
2840
|
|
|
2808
2841
|
<search_string>
|
|
@@ -2811,8 +2844,9 @@ ${searchTerm}
|
|
|
2811
2844
|
${budget}
|
|
2812
2845
|
${turnTag}`;
|
|
2813
2846
|
} catch {
|
|
2847
|
+
const repoName = import_path2.default.basename(repoRoot);
|
|
2814
2848
|
return `<repo_structure>
|
|
2815
|
-
${
|
|
2849
|
+
${repoName}/
|
|
2816
2850
|
</repo_structure>
|
|
2817
2851
|
|
|
2818
2852
|
<search_string>
|
|
@@ -2823,32 +2857,26 @@ ${turnTag}`;
|
|
|
2823
2857
|
}
|
|
2824
2858
|
}
|
|
2825
2859
|
function enforceContextLimit(messages, maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS) {
|
|
2826
|
-
const getTotalChars = () => messages.reduce((sum, m) => sum +
|
|
2860
|
+
const getTotalChars = () => messages.reduce((sum, m) => sum + m.content.length, 0);
|
|
2827
2861
|
if (getTotalChars() <= maxChars) {
|
|
2828
2862
|
return messages;
|
|
2829
2863
|
}
|
|
2830
|
-
const
|
|
2864
|
+
const userIndices = [];
|
|
2831
2865
|
let firstUserSkipped = false;
|
|
2832
2866
|
for (let i = 0; i < messages.length; i++) {
|
|
2833
|
-
|
|
2834
|
-
if (m.role === "tool") {
|
|
2835
|
-
truncatableIndices.push(i);
|
|
2836
|
-
} else if (m.role === "user") {
|
|
2867
|
+
if (messages[i].role === "user") {
|
|
2837
2868
|
if (!firstUserSkipped) {
|
|
2838
2869
|
firstUserSkipped = true;
|
|
2839
2870
|
continue;
|
|
2840
2871
|
}
|
|
2841
|
-
|
|
2872
|
+
userIndices.push(i);
|
|
2842
2873
|
}
|
|
2843
2874
|
}
|
|
2844
|
-
for (const idx of
|
|
2875
|
+
for (const idx of userIndices) {
|
|
2845
2876
|
if (getTotalChars() <= maxChars) {
|
|
2846
2877
|
break;
|
|
2847
2878
|
}
|
|
2848
|
-
|
|
2849
|
-
if (m.role === "tool" && m.content !== TRUNCATED_MARKER) {
|
|
2850
|
-
messages[idx] = { role: "tool", tool_call_id: m.tool_call_id, content: TRUNCATED_MARKER };
|
|
2851
|
-
} else if (m.role === "user" && m.content !== TRUNCATED_MARKER) {
|
|
2879
|
+
if (messages[idx].content !== TRUNCATED_MARKER) {
|
|
2852
2880
|
messages[idx] = { role: "user", content: TRUNCATED_MARKER };
|
|
2853
2881
|
}
|
|
2854
2882
|
}
|
|
@@ -2858,115 +2886,9 @@ function enforceContextLimit(messages, maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS
|
|
|
2858
2886
|
// tools/warp_grep/agent/runner.ts
|
|
2859
2887
|
var import_openai2 = __toESM(require("openai"), 1);
|
|
2860
2888
|
init_version();
|
|
2861
|
-
var
|
|
2889
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
2890
|
+
var parser = new LLMResponseParser();
|
|
2862
2891
|
var DEFAULT_API_URL3 = "https://api.morphllm.com";
|
|
2863
|
-
var TOOL_SPECS = [
|
|
2864
|
-
{
|
|
2865
|
-
type: "function",
|
|
2866
|
-
function: {
|
|
2867
|
-
name: "list_directory",
|
|
2868
|
-
description: "Execute ls or find commands to explore directory structure. Max 500 results. Common junk directories are excluded automatically.",
|
|
2869
|
-
parameters: {
|
|
2870
|
-
type: "object",
|
|
2871
|
-
properties: {
|
|
2872
|
-
command: {
|
|
2873
|
-
type: "string",
|
|
2874
|
-
description: "Full ls or find command (e.g. ls -la src/, find . -maxdepth 2 -type f -name '*.py', find . -type d, ls -d */)."
|
|
2875
|
-
}
|
|
2876
|
-
},
|
|
2877
|
-
required: ["command"]
|
|
2878
|
-
}
|
|
2879
|
-
}
|
|
2880
|
-
},
|
|
2881
|
-
{
|
|
2882
|
-
type: "function",
|
|
2883
|
-
function: {
|
|
2884
|
-
name: "grep_search",
|
|
2885
|
-
description: "Search for a regex pattern in file contents. Returns matching lines with file paths and line numbers. Case-insensitive. Respects .gitignore.",
|
|
2886
|
-
parameters: {
|
|
2887
|
-
type: "object",
|
|
2888
|
-
properties: {
|
|
2889
|
-
pattern: {
|
|
2890
|
-
type: "string",
|
|
2891
|
-
description: "Regex pattern to search for in file contents (e.g. 'class\\s+\\w+Error', 'import|require|from', 'def (get|set|update)_user')."
|
|
2892
|
-
},
|
|
2893
|
-
path: {
|
|
2894
|
-
type: "string",
|
|
2895
|
-
description: "File or directory to search in. Defaults to current working directory."
|
|
2896
|
-
},
|
|
2897
|
-
glob: {
|
|
2898
|
-
type: "string",
|
|
2899
|
-
description: "Glob pattern to filter files (e.g. '*.py', '*.{ts,tsx,js,jsx,py,go}', 'src/**/*.go', '!*.test.*')."
|
|
2900
|
-
},
|
|
2901
|
-
limit: {
|
|
2902
|
-
type: "integer",
|
|
2903
|
-
description: "Limit output to first N matching lines. Shows all matches if not specified."
|
|
2904
|
-
}
|
|
2905
|
-
},
|
|
2906
|
-
required: ["pattern"]
|
|
2907
|
-
}
|
|
2908
|
-
}
|
|
2909
|
-
},
|
|
2910
|
-
{
|
|
2911
|
-
type: "function",
|
|
2912
|
-
function: {
|
|
2913
|
-
name: "glob",
|
|
2914
|
-
description: "Find files by name/extension using glob patterns. Returns absolute paths sorted by modification time (newest first). Respects .gitignore. Max 100 results.",
|
|
2915
|
-
parameters: {
|
|
2916
|
-
type: "object",
|
|
2917
|
-
properties: {
|
|
2918
|
-
pattern: {
|
|
2919
|
-
type: "string",
|
|
2920
|
-
description: "Glob pattern to match files (e.g. '*.py', 'src/**/*.js', '*.{ts,tsx}', 'test_*.py')."
|
|
2921
|
-
},
|
|
2922
|
-
path: {
|
|
2923
|
-
type: "string",
|
|
2924
|
-
description: "Directory to search in. Defaults to repository root."
|
|
2925
|
-
}
|
|
2926
|
-
},
|
|
2927
|
-
required: ["pattern"]
|
|
2928
|
-
}
|
|
2929
|
-
}
|
|
2930
|
-
},
|
|
2931
|
-
{
|
|
2932
|
-
type: "function",
|
|
2933
|
-
function: {
|
|
2934
|
-
name: "read",
|
|
2935
|
-
description: "Read entire files or specific line ranges using absolute paths.",
|
|
2936
|
-
parameters: {
|
|
2937
|
-
type: "object",
|
|
2938
|
-
properties: {
|
|
2939
|
-
path: {
|
|
2940
|
-
type: "string",
|
|
2941
|
-
description: "File path to read, using absolute path (e.g. '/home/ubuntu/repo/src/main.py' or windows path)."
|
|
2942
|
-
},
|
|
2943
|
-
lines: {
|
|
2944
|
-
type: "string",
|
|
2945
|
-
description: "Optional line range (e.g. '1-50' or '1-20,45-80'). Omit to read entire file."
|
|
2946
|
-
}
|
|
2947
|
-
},
|
|
2948
|
-
required: ["path"]
|
|
2949
|
-
}
|
|
2950
|
-
}
|
|
2951
|
-
},
|
|
2952
|
-
{
|
|
2953
|
-
type: "function",
|
|
2954
|
-
function: {
|
|
2955
|
-
name: "finish",
|
|
2956
|
-
description: "Submit final answer with all relevant code locations. Include imports and over-include rather than miss context.",
|
|
2957
|
-
parameters: {
|
|
2958
|
-
type: "object",
|
|
2959
|
-
properties: {
|
|
2960
|
-
files: {
|
|
2961
|
-
type: "string",
|
|
2962
|
-
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."
|
|
2963
|
-
}
|
|
2964
|
-
},
|
|
2965
|
-
required: ["files"]
|
|
2966
|
-
}
|
|
2967
|
-
}
|
|
2968
|
-
}
|
|
2969
|
-
];
|
|
2970
2892
|
async function callModel(messages, model, options = {}) {
|
|
2971
2893
|
const baseUrl = options.morphApiUrl || DEFAULT_API_URL3;
|
|
2972
2894
|
const apiKey = options.morphApiKey || process.env.MORPH_API_KEY || "";
|
|
@@ -2987,9 +2909,8 @@ async function callModel(messages, model, options = {}) {
|
|
|
2987
2909
|
data = await client.chat.completions.create({
|
|
2988
2910
|
model,
|
|
2989
2911
|
temperature: 0,
|
|
2990
|
-
max_tokens:
|
|
2912
|
+
max_tokens: 1024,
|
|
2991
2913
|
messages,
|
|
2992
|
-
tools: TOOL_SPECS,
|
|
2993
2914
|
...options.search_type ? { search_type: options.search_type } : {}
|
|
2994
2915
|
});
|
|
2995
2916
|
} catch (error) {
|
|
@@ -3001,87 +2922,187 @@ async function callModel(messages, model, options = {}) {
|
|
|
3001
2922
|
throw error;
|
|
3002
2923
|
}
|
|
3003
2924
|
const choice = data?.choices?.[0];
|
|
3004
|
-
const
|
|
3005
|
-
if (
|
|
3006
|
-
|
|
3007
|
-
throw new Error("Invalid response from model: no message in response");
|
|
3008
|
-
}
|
|
3009
|
-
await new Promise((resolve2) => setTimeout(resolve2, 200));
|
|
3010
|
-
continue;
|
|
3011
|
-
}
|
|
3012
|
-
const toolCalls = (message.tool_calls || []).map((tc) => ({
|
|
3013
|
-
id: tc.id,
|
|
3014
|
-
type: "function",
|
|
3015
|
-
function: { name: tc.function.name, arguments: tc.function.arguments }
|
|
3016
|
-
}));
|
|
3017
|
-
if (message.content || toolCalls.length > 0) {
|
|
3018
|
-
return { content: message.content ?? null, tool_calls: toolCalls };
|
|
2925
|
+
const content = choice?.message?.content;
|
|
2926
|
+
if (content && typeof content === "string") {
|
|
2927
|
+
return content;
|
|
3019
2928
|
}
|
|
3020
2929
|
if (attempt === MAX_EMPTY_RETRIES) {
|
|
3021
2930
|
const finishReason = choice?.finish_reason ?? "unknown";
|
|
2931
|
+
const hasToolCalls = Array.isArray(choice?.message?.tool_calls) && choice.message.tool_calls.length > 0;
|
|
2932
|
+
const choicesLen = data?.choices?.length ?? 0;
|
|
2933
|
+
const contentType = content === null ? "null" : content === void 0 ? "undefined" : typeof content;
|
|
3022
2934
|
throw new Error(
|
|
3023
|
-
`Invalid response from model:
|
|
2935
|
+
`Invalid response from model: content=${contentType}, finish_reason=${finishReason}, has_tool_calls=${hasToolCalls}, choices_length=${choicesLen}`
|
|
3024
2936
|
);
|
|
3025
2937
|
}
|
|
3026
2938
|
await new Promise((resolve2) => setTimeout(resolve2, 200));
|
|
3027
2939
|
}
|
|
3028
2940
|
throw new Error("Invalid response from model");
|
|
3029
2941
|
}
|
|
3030
|
-
function
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
2942
|
+
async function runWarpGrep(config) {
|
|
2943
|
+
const totalStart = Date.now();
|
|
2944
|
+
const timeoutMs = config.timeout ?? AGENT_CONFIG.TIMEOUT_MS;
|
|
2945
|
+
const timings = { turns: [], timeout_ms: timeoutMs };
|
|
2946
|
+
const repoRoot = import_path3.default.resolve(config.repoRoot || process.cwd());
|
|
2947
|
+
const model = config.model || DEFAULT_MODEL;
|
|
2948
|
+
const messages = [];
|
|
2949
|
+
const maxTurns = AGENT_CONFIG.MAX_TURNS;
|
|
2950
|
+
const initialStateStart = Date.now();
|
|
2951
|
+
const initialState = await buildInitialState(repoRoot, config.searchTerm, config.provider, { search_type: config.search_type });
|
|
2952
|
+
timings.initial_state_ms = Date.now() - initialStateStart;
|
|
2953
|
+
messages.push({ role: "user", content: initialState });
|
|
2954
|
+
const provider = config.provider;
|
|
2955
|
+
const errors = [];
|
|
2956
|
+
let finishMeta;
|
|
2957
|
+
let terminationReason = "terminated";
|
|
2958
|
+
for (let turn = 1; turn <= maxTurns; turn += 1) {
|
|
2959
|
+
const turnMetrics = { turn, morph_api_ms: 0, local_tools_ms: 0 };
|
|
2960
|
+
enforceContextLimit(messages);
|
|
2961
|
+
const modelCallStart = Date.now();
|
|
2962
|
+
const assistantContent = await callModel(messages, model, {
|
|
2963
|
+
morphApiKey: config.morphApiKey,
|
|
2964
|
+
morphApiUrl: config.morphApiUrl,
|
|
2965
|
+
retryConfig: config.retryConfig,
|
|
2966
|
+
timeout: timeoutMs,
|
|
2967
|
+
search_type: config.search_type
|
|
2968
|
+
}).catch((e) => {
|
|
2969
|
+
const errMsg = e instanceof Error ? e.message : String(e);
|
|
2970
|
+
console.error(`[warp_grep] Morph API call failed on turn ${turn}:`, errMsg);
|
|
2971
|
+
errors.push({ message: errMsg });
|
|
2972
|
+
return "";
|
|
2973
|
+
});
|
|
2974
|
+
turnMetrics.morph_api_ms = Date.now() - modelCallStart;
|
|
2975
|
+
if (!assistantContent) {
|
|
2976
|
+
console.error(`[warp_grep] Empty response from Morph API on turn ${turn}. Errors so far:`, errors);
|
|
2977
|
+
timings.turns.push(turnMetrics);
|
|
2978
|
+
break;
|
|
3056
2979
|
}
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
});
|
|
2980
|
+
messages.push({ role: "assistant", content: assistantContent });
|
|
2981
|
+
const toolCalls = parser.parse(assistantContent);
|
|
2982
|
+
if (toolCalls.length === 0) {
|
|
2983
|
+
console.error(`[warp_grep] No tool calls parsed on turn ${turn}. Assistant content (first 500 chars):`, assistantContent.slice(0, 500));
|
|
2984
|
+
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" });
|
|
2985
|
+
terminationReason = "terminated";
|
|
2986
|
+
timings.turns.push(turnMetrics);
|
|
2987
|
+
break;
|
|
3062
2988
|
}
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
2989
|
+
const finishCalls = toolCalls.filter((c) => c.name === "finish");
|
|
2990
|
+
const grepCalls = toolCalls.filter((c) => c.name === "grep");
|
|
2991
|
+
const listDirCalls = toolCalls.filter((c) => c.name === "list_directory");
|
|
2992
|
+
const readCalls = toolCalls.filter((c) => c.name === "read");
|
|
2993
|
+
const skipCalls = toolCalls.filter((c) => c.name === "_skip");
|
|
2994
|
+
const formatted = [];
|
|
2995
|
+
for (const c of skipCalls) {
|
|
2996
|
+
const msg = c.arguments?.message || "Command skipped due to parsing error";
|
|
2997
|
+
formatted.push(msg);
|
|
2998
|
+
}
|
|
2999
|
+
const allPromises = [];
|
|
3000
|
+
for (const c of grepCalls) {
|
|
3001
|
+
const args = c.arguments ?? {};
|
|
3002
|
+
allPromises.push(
|
|
3003
|
+
toolGrep(provider, args).then(
|
|
3004
|
+
({ output }) => formatAgentToolOutput("grep", args, output),
|
|
3005
|
+
(err) => formatAgentToolOutput("grep", args, String(err), { isError: true })
|
|
3006
|
+
)
|
|
3007
|
+
);
|
|
3066
3008
|
}
|
|
3067
|
-
|
|
3068
|
-
const
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3009
|
+
for (const c of listDirCalls) {
|
|
3010
|
+
const args = c.arguments ?? {};
|
|
3011
|
+
allPromises.push(
|
|
3012
|
+
toolListDirectory(provider, args).then(
|
|
3013
|
+
(p) => formatAgentToolOutput("list_directory", args, p),
|
|
3014
|
+
(err) => formatAgentToolOutput("list_directory", args, String(err), { isError: true })
|
|
3015
|
+
)
|
|
3016
|
+
);
|
|
3017
|
+
}
|
|
3018
|
+
for (const c of readCalls) {
|
|
3019
|
+
const args = c.arguments ?? {};
|
|
3020
|
+
allPromises.push(
|
|
3021
|
+
toolRead(provider, args).then(
|
|
3022
|
+
(p) => formatAgentToolOutput("read", args, p),
|
|
3023
|
+
(err) => formatAgentToolOutput("read", args, String(err), { isError: true })
|
|
3024
|
+
)
|
|
3025
|
+
);
|
|
3026
|
+
}
|
|
3027
|
+
const toolExecStart = Date.now();
|
|
3028
|
+
const allResults = await Promise.all(allPromises);
|
|
3029
|
+
turnMetrics.local_tools_ms = Date.now() - toolExecStart;
|
|
3030
|
+
for (const result of allResults) {
|
|
3031
|
+
formatted.push(result);
|
|
3032
|
+
}
|
|
3033
|
+
if (formatted.length > 0) {
|
|
3034
|
+
const turnMessage = formatTurnMessage(turn, maxTurns);
|
|
3035
|
+
const contextBudget = calculateContextBudget(messages);
|
|
3036
|
+
messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
|
|
3037
|
+
}
|
|
3038
|
+
timings.turns.push(turnMetrics);
|
|
3039
|
+
if (finishCalls.length) {
|
|
3040
|
+
const fc = finishCalls[0];
|
|
3041
|
+
const files = fc.arguments?.files ?? [];
|
|
3042
|
+
const textResult = fc.arguments?.textResult;
|
|
3043
|
+
finishMeta = { files };
|
|
3044
|
+
terminationReason = "completed";
|
|
3045
|
+
if (files.length === 0) {
|
|
3046
|
+
const payload2 = textResult || "No relevant code found.";
|
|
3047
|
+
timings.turns.push(turnMetrics);
|
|
3048
|
+
timings.total_ms = Date.now() - totalStart;
|
|
3049
|
+
return {
|
|
3050
|
+
terminationReason: "completed",
|
|
3051
|
+
messages,
|
|
3052
|
+
finish: { payload: payload2, metadata: finishMeta },
|
|
3053
|
+
timings
|
|
3054
|
+
};
|
|
3073
3055
|
}
|
|
3074
|
-
|
|
3056
|
+
break;
|
|
3075
3057
|
}
|
|
3076
|
-
default:
|
|
3077
|
-
return `Unknown tool: ${name}`;
|
|
3078
3058
|
}
|
|
3059
|
+
if (terminationReason !== "completed" || !finishMeta) {
|
|
3060
|
+
timings.total_ms = Date.now() - totalStart;
|
|
3061
|
+
return { terminationReason, messages, errors, timings };
|
|
3062
|
+
}
|
|
3063
|
+
const parts = ["Relevant context found:"];
|
|
3064
|
+
for (const f of finishMeta.files) {
|
|
3065
|
+
const ranges = f.lines === "*" ? "*" : Array.isArray(f.lines) ? f.lines.map(([s, e]) => `${s}-${e}`).join(", ") : "*";
|
|
3066
|
+
parts.push(`- ${f.path}: ${ranges}`);
|
|
3067
|
+
}
|
|
3068
|
+
const payload = parts.join("\n");
|
|
3069
|
+
const finishResolutionStart = Date.now();
|
|
3070
|
+
const fileReadErrors = [];
|
|
3071
|
+
const resolved = await readFinishFiles(
|
|
3072
|
+
repoRoot,
|
|
3073
|
+
finishMeta.files,
|
|
3074
|
+
async (p, s, e) => {
|
|
3075
|
+
try {
|
|
3076
|
+
const rr = await provider.read({ path: p, start: s, end: e });
|
|
3077
|
+
return rr.lines.map((l) => {
|
|
3078
|
+
const idx = l.indexOf("|");
|
|
3079
|
+
return idx >= 0 ? l.slice(idx + 1) : l;
|
|
3080
|
+
});
|
|
3081
|
+
} catch (err) {
|
|
3082
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
3083
|
+
fileReadErrors.push({ path: p, error: errorMsg });
|
|
3084
|
+
console.error(`[warp_grep] Failed to read file: ${p} - ${errorMsg}`);
|
|
3085
|
+
return [`[couldn't find: ${p}]`];
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
);
|
|
3089
|
+
timings.finish_resolution_ms = Date.now() - finishResolutionStart;
|
|
3090
|
+
if (fileReadErrors.length > 0) {
|
|
3091
|
+
errors.push(...fileReadErrors.map((e) => ({ message: `File read error: ${e.path} - ${e.error}` })));
|
|
3092
|
+
}
|
|
3093
|
+
timings.total_ms = Date.now() - totalStart;
|
|
3094
|
+
return {
|
|
3095
|
+
terminationReason: "completed",
|
|
3096
|
+
messages,
|
|
3097
|
+
finish: { payload, metadata: finishMeta, resolved },
|
|
3098
|
+
timings
|
|
3099
|
+
};
|
|
3079
3100
|
}
|
|
3080
3101
|
async function* runWarpGrepStreaming(config) {
|
|
3081
3102
|
const totalStart = Date.now();
|
|
3082
3103
|
const timeoutMs = config.timeout ?? AGENT_CONFIG.TIMEOUT_MS;
|
|
3083
3104
|
const timings = { turns: [], timeout_ms: timeoutMs };
|
|
3084
|
-
const repoRoot =
|
|
3105
|
+
const repoRoot = import_path3.default.resolve(config.repoRoot || process.cwd());
|
|
3085
3106
|
const model = config.model || DEFAULT_MODEL;
|
|
3086
3107
|
const messages = [];
|
|
3087
3108
|
const maxTurns = AGENT_CONFIG.MAX_TURNS;
|
|
@@ -3097,7 +3118,7 @@ async function* runWarpGrepStreaming(config) {
|
|
|
3097
3118
|
const turnMetrics = { turn, morph_api_ms: 0, local_tools_ms: 0 };
|
|
3098
3119
|
enforceContextLimit(messages);
|
|
3099
3120
|
const modelCallStart = Date.now();
|
|
3100
|
-
const
|
|
3121
|
+
const assistantContent = await callModel(messages, model, {
|
|
3101
3122
|
morphApiKey: config.morphApiKey,
|
|
3102
3123
|
morphApiUrl: config.morphApiUrl,
|
|
3103
3124
|
retryConfig: config.retryConfig,
|
|
@@ -3105,45 +3126,90 @@ async function* runWarpGrepStreaming(config) {
|
|
|
3105
3126
|
search_type: config.search_type
|
|
3106
3127
|
}).catch((e) => {
|
|
3107
3128
|
const errMsg = e instanceof Error ? e.message : String(e);
|
|
3108
|
-
console.error(`[warp_grep] Morph API call failed on turn ${turn}:`, errMsg);
|
|
3129
|
+
console.error(`[warp_grep:stream] Morph API call failed on turn ${turn}:`, errMsg);
|
|
3109
3130
|
errors.push({ message: errMsg });
|
|
3110
|
-
return
|
|
3131
|
+
return "";
|
|
3111
3132
|
});
|
|
3112
3133
|
turnMetrics.morph_api_ms = Date.now() - modelCallStart;
|
|
3113
|
-
if (!
|
|
3134
|
+
if (!assistantContent) {
|
|
3135
|
+
console.error(`[warp_grep:stream] Empty response from Morph API on turn ${turn}. Errors so far:`, errors);
|
|
3114
3136
|
timings.turns.push(turnMetrics);
|
|
3115
3137
|
break;
|
|
3116
3138
|
}
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
role: "assistant",
|
|
3120
|
-
content: response.content,
|
|
3121
|
-
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
|
|
3122
|
-
});
|
|
3139
|
+
messages.push({ role: "assistant", content: assistantContent });
|
|
3140
|
+
const toolCalls = parser.parse(assistantContent);
|
|
3123
3141
|
if (toolCalls.length === 0) {
|
|
3124
|
-
console.error(`[warp_grep] No tool calls on turn ${turn}.
|
|
3125
|
-
errors.push({ message: "No tool calls produced by the model." });
|
|
3142
|
+
console.error(`[warp_grep:stream] No tool calls parsed on turn ${turn}. Assistant content (first 500 chars):`, assistantContent.slice(0, 500));
|
|
3143
|
+
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" });
|
|
3126
3144
|
terminationReason = "terminated";
|
|
3127
3145
|
timings.turns.push(turnMetrics);
|
|
3128
3146
|
break;
|
|
3129
3147
|
}
|
|
3130
3148
|
yield {
|
|
3131
3149
|
turn,
|
|
3132
|
-
toolCalls: toolCalls.map((
|
|
3133
|
-
name:
|
|
3134
|
-
arguments:
|
|
3150
|
+
toolCalls: toolCalls.map((c) => ({
|
|
3151
|
+
name: c.name,
|
|
3152
|
+
arguments: c.arguments ?? {}
|
|
3135
3153
|
}))
|
|
3136
3154
|
};
|
|
3137
|
-
const
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3155
|
+
const finishCalls = toolCalls.filter((c) => c.name === "finish");
|
|
3156
|
+
const grepCalls = toolCalls.filter((c) => c.name === "grep");
|
|
3157
|
+
const listDirCalls = toolCalls.filter((c) => c.name === "list_directory");
|
|
3158
|
+
const readCalls = toolCalls.filter((c) => c.name === "read");
|
|
3159
|
+
const skipCalls = toolCalls.filter((c) => c.name === "_skip");
|
|
3160
|
+
const formatted = [];
|
|
3161
|
+
for (const c of skipCalls) {
|
|
3162
|
+
const msg = c.arguments?.message || "Command skipped due to parsing error";
|
|
3163
|
+
formatted.push(msg);
|
|
3164
|
+
}
|
|
3165
|
+
const allPromises = [];
|
|
3166
|
+
for (const c of grepCalls) {
|
|
3167
|
+
const args = c.arguments ?? {};
|
|
3168
|
+
allPromises.push(
|
|
3169
|
+
toolGrep(provider, args).then(
|
|
3170
|
+
({ output }) => formatAgentToolOutput("grep", args, output),
|
|
3171
|
+
(err) => formatAgentToolOutput("grep", args, String(err), { isError: true })
|
|
3172
|
+
)
|
|
3173
|
+
);
|
|
3174
|
+
}
|
|
3175
|
+
for (const c of listDirCalls) {
|
|
3176
|
+
const args = c.arguments ?? {};
|
|
3177
|
+
allPromises.push(
|
|
3178
|
+
toolListDirectory(provider, args).then(
|
|
3179
|
+
(p) => formatAgentToolOutput("list_directory", args, p),
|
|
3180
|
+
(err) => formatAgentToolOutput("list_directory", args, String(err), { isError: true })
|
|
3181
|
+
)
|
|
3182
|
+
);
|
|
3183
|
+
}
|
|
3184
|
+
for (const c of readCalls) {
|
|
3185
|
+
const args = c.arguments ?? {};
|
|
3186
|
+
allPromises.push(
|
|
3187
|
+
toolRead(provider, args).then(
|
|
3188
|
+
(p) => formatAgentToolOutput("read", args, p),
|
|
3189
|
+
(err) => formatAgentToolOutput("read", args, String(err), { isError: true })
|
|
3190
|
+
)
|
|
3191
|
+
);
|
|
3192
|
+
}
|
|
3193
|
+
const toolExecStart = Date.now();
|
|
3194
|
+
const allResults = await Promise.all(allPromises);
|
|
3195
|
+
turnMetrics.local_tools_ms = Date.now() - toolExecStart;
|
|
3196
|
+
for (const result of allResults) {
|
|
3197
|
+
formatted.push(result);
|
|
3198
|
+
}
|
|
3199
|
+
if (formatted.length > 0) {
|
|
3200
|
+
const turnMessage = formatTurnMessage(turn, maxTurns);
|
|
3201
|
+
const contextBudget = calculateContextBudget(messages);
|
|
3202
|
+
messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
|
|
3203
|
+
}
|
|
3204
|
+
timings.turns.push(turnMetrics);
|
|
3205
|
+
if (finishCalls.length) {
|
|
3206
|
+
const fc = finishCalls[0];
|
|
3207
|
+
const files = fc.arguments?.files ?? [];
|
|
3208
|
+
const textResult = fc.arguments?.textResult;
|
|
3142
3209
|
finishMeta = { files };
|
|
3143
3210
|
terminationReason = "completed";
|
|
3144
3211
|
if (files.length === 0) {
|
|
3145
|
-
const payload2 =
|
|
3146
|
-
timings.turns.push(turnMetrics);
|
|
3212
|
+
const payload2 = textResult || "No relevant code found.";
|
|
3147
3213
|
timings.total_ms = Date.now() - totalStart;
|
|
3148
3214
|
return {
|
|
3149
3215
|
terminationReason: "completed",
|
|
@@ -3152,25 +3218,8 @@ async function* runWarpGrepStreaming(config) {
|
|
|
3152
3218
|
timings
|
|
3153
3219
|
};
|
|
3154
3220
|
}
|
|
3155
|
-
timings.turns.push(turnMetrics);
|
|
3156
3221
|
break;
|
|
3157
3222
|
}
|
|
3158
|
-
const toolExecStart = Date.now();
|
|
3159
|
-
const results = await Promise.all(
|
|
3160
|
-
toolCalls.map(async (tc) => {
|
|
3161
|
-
const args = safeParseJSON(tc.function.arguments);
|
|
3162
|
-
const output = await executeTool(provider, tc.function.name, args, repoRoot).catch((err) => String(err));
|
|
3163
|
-
return { tool_call_id: tc.id, content: output };
|
|
3164
|
-
})
|
|
3165
|
-
);
|
|
3166
|
-
turnMetrics.local_tools_ms = Date.now() - toolExecStart;
|
|
3167
|
-
for (const result of results) {
|
|
3168
|
-
messages.push({ role: "tool", tool_call_id: result.tool_call_id, content: result.content });
|
|
3169
|
-
}
|
|
3170
|
-
const turnMsg = formatTurnMessage(turn, maxTurns);
|
|
3171
|
-
const budget = calculateContextBudget(messages);
|
|
3172
|
-
messages.push({ role: "user", content: turnMsg + "\n" + budget });
|
|
3173
|
-
timings.turns.push(turnMetrics);
|
|
3174
3223
|
}
|
|
3175
3224
|
if (terminationReason !== "completed" || !finishMeta) {
|
|
3176
3225
|
timings.total_ms = Date.now() - totalStart;
|
|
@@ -3214,14 +3263,6 @@ async function* runWarpGrepStreaming(config) {
|
|
|
3214
3263
|
timings
|
|
3215
3264
|
};
|
|
3216
3265
|
}
|
|
3217
|
-
async function runWarpGrep(config) {
|
|
3218
|
-
const gen = runWarpGrepStreaming(config);
|
|
3219
|
-
let result = await gen.next();
|
|
3220
|
-
while (!result.done) {
|
|
3221
|
-
result = await gen.next();
|
|
3222
|
-
}
|
|
3223
|
-
return result.value;
|
|
3224
|
-
}
|
|
3225
3266
|
|
|
3226
3267
|
// tools/warp_grep/providers/remote.ts
|
|
3227
3268
|
init_config();
|
|
@@ -3401,35 +3442,6 @@ var RemoteCommandsProvider = class {
|
|
|
3401
3442
|
return [];
|
|
3402
3443
|
}
|
|
3403
3444
|
}
|
|
3404
|
-
/**
|
|
3405
|
-
* Glob search - finds files matching a pattern.
|
|
3406
|
-
* Falls back to a grep --files approach via the listDir command.
|
|
3407
|
-
*/
|
|
3408
|
-
async glob(params) {
|
|
3409
|
-
const searchPath = params.path || this.repoRoot;
|
|
3410
|
-
try {
|
|
3411
|
-
const stdout = await this.commands.listDir(searchPath, 10);
|
|
3412
|
-
const allPaths = (stdout || "").trim().split(/\r?\n/).filter((p) => p.length > 0);
|
|
3413
|
-
const globToRegex = (glob) => {
|
|
3414
|
-
const escaped = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
3415
|
-
return new RegExp(escaped);
|
|
3416
|
-
};
|
|
3417
|
-
const regex = globToRegex(params.pattern);
|
|
3418
|
-
const matched = allPaths.filter((p) => {
|
|
3419
|
-
const name = p.split("/").pop() || "";
|
|
3420
|
-
return regex.test(name) && !shouldSkip(name);
|
|
3421
|
-
});
|
|
3422
|
-
const totalFound = matched.length;
|
|
3423
|
-
return { files: matched.slice(0, 100), searchDir: searchPath, totalFound };
|
|
3424
|
-
} catch (error) {
|
|
3425
|
-
return {
|
|
3426
|
-
files: [],
|
|
3427
|
-
searchDir: searchPath,
|
|
3428
|
-
totalFound: 0,
|
|
3429
|
-
error: `[GLOB ERROR] ${error instanceof Error ? error.message : String(error)}`
|
|
3430
|
-
};
|
|
3431
|
-
}
|
|
3432
|
-
}
|
|
3433
3445
|
};
|
|
3434
3446
|
|
|
3435
3447
|
// tools/warp_grep/providers/code_storage_http.ts
|
|
@@ -3456,9 +3468,9 @@ function createCodeStorageHttpCommands(config) {
|
|
|
3456
3468
|
const { baseUrl, repoId, branch } = config;
|
|
3457
3469
|
const encodedRepoId = encodeURIComponent(repoId);
|
|
3458
3470
|
return {
|
|
3459
|
-
grep: (pattern,
|
|
3460
|
-
read: (
|
|
3461
|
-
listDir: (
|
|
3471
|
+
grep: (pattern, path5, glob) => post(`${baseUrl}/api/code-search/${encodedRepoId}/grep`, { pattern, path: path5, glob, branch }, "grep"),
|
|
3472
|
+
read: (path5, start, end) => post(`${baseUrl}/api/code-search/${encodedRepoId}/read`, { path: path5, start, end, branch }, "read"),
|
|
3473
|
+
listDir: (path5, maxDepth) => post(`${baseUrl}/api/code-search/${encodedRepoId}/list`, { path: path5, maxDepth, branch }, "list")
|
|
3462
3474
|
};
|
|
3463
3475
|
}
|
|
3464
3476
|
|
|
@@ -3841,10 +3853,10 @@ var GitHubClient = class {
|
|
|
3841
3853
|
/**
|
|
3842
3854
|
* Make an authenticated API request
|
|
3843
3855
|
*/
|
|
3844
|
-
async request(method,
|
|
3845
|
-
const url = `${this.baseUrl}${
|
|
3856
|
+
async request(method, path5, body) {
|
|
3857
|
+
const url = `${this.baseUrl}${path5}`;
|
|
3846
3858
|
if (this.debug) {
|
|
3847
|
-
console.log(`[GitHub SDK] ${method} ${
|
|
3859
|
+
console.log(`[GitHub SDK] ${method} ${path5}`, body || "");
|
|
3848
3860
|
}
|
|
3849
3861
|
const controller = new AbortController();
|
|
3850
3862
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
@@ -6412,25 +6424,6 @@ init_paths();
|
|
|
6412
6424
|
// tools/warp_grep/agent/index.ts
|
|
6413
6425
|
init_config();
|
|
6414
6426
|
|
|
6415
|
-
// tools/warp_grep/agent/formatter.ts
|
|
6416
|
-
var ToolOutputFormatter = class {
|
|
6417
|
-
format(toolName, _args, output, options = {}) {
|
|
6418
|
-
const name = (toolName ?? "").trim();
|
|
6419
|
-
if (!name) {
|
|
6420
|
-
return "";
|
|
6421
|
-
}
|
|
6422
|
-
const payload = output?.toString?.()?.trim?.() ?? "";
|
|
6423
|
-
const isError = Boolean(options.isError);
|
|
6424
|
-
if (!payload && !isError) {
|
|
6425
|
-
return "";
|
|
6426
|
-
}
|
|
6427
|
-
return `<tool_response>
|
|
6428
|
-
${payload}
|
|
6429
|
-
</tool_response>`;
|
|
6430
|
-
}
|
|
6431
|
-
};
|
|
6432
|
-
var sharedFormatter = new ToolOutputFormatter();
|
|
6433
|
-
|
|
6434
6427
|
// tools/warp_grep/index.ts
|
|
6435
6428
|
var warpGrepInputSchema = import_zod5.z.object({
|
|
6436
6429
|
search_term: import_zod5.z.string().describe("Search problem statement that this subagent is supposed to research for")
|