@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/client.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
|
});
|
|
@@ -2534,58 +2493,131 @@ async function checkHealth(config = {}) {
|
|
|
2534
2493
|
init_config();
|
|
2535
2494
|
|
|
2536
2495
|
// tools/warp_grep/agent/parser.ts
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
const trimmed = rangeStr.trim();
|
|
2541
|
-
if (!trimmed) continue;
|
|
2542
|
-
const parts = trimmed.split("-").map((v) => parseInt(v.trim(), 10));
|
|
2543
|
-
if (parts.length >= 2 && Number.isFinite(parts[0]) && Number.isFinite(parts[1])) {
|
|
2544
|
-
ranges.push([parts[0], parts[1]]);
|
|
2545
|
-
} else if (Number.isFinite(parts[0])) {
|
|
2546
|
-
ranges.push([parts[0], parts[0]]);
|
|
2547
|
-
}
|
|
2548
|
-
}
|
|
2549
|
-
if (ranges.length === 1) return { start: ranges[0][0], end: ranges[0][1] };
|
|
2550
|
-
if (ranges.length > 1) return { lines: ranges };
|
|
2551
|
-
return {};
|
|
2496
|
+
var VALID_COMMANDS = ["list_directory", "ripgrep", "read", "finish"];
|
|
2497
|
+
function isValidCommand(name) {
|
|
2498
|
+
return VALID_COMMANDS.includes(name);
|
|
2552
2499
|
}
|
|
2553
|
-
function
|
|
2554
|
-
const
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
const
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
}
|
|
2577
|
-
|
|
2500
|
+
function parseQwen3ToolCalls(text) {
|
|
2501
|
+
const tools = [];
|
|
2502
|
+
const toolCallRegex = /<tool_call>\s*<function=([a-z_][a-z0-9_]*)>([\s\S]*?)<\/function>\s*<\/tool_call>/gi;
|
|
2503
|
+
let match;
|
|
2504
|
+
while ((match = toolCallRegex.exec(text)) !== null) {
|
|
2505
|
+
const funcName = match[1].toLowerCase();
|
|
2506
|
+
const body = match[2];
|
|
2507
|
+
if (!isValidCommand(funcName)) continue;
|
|
2508
|
+
const params = {};
|
|
2509
|
+
const paramRegex = /<parameter=([a-z_][a-z0-9_]*)>([\s\S]*?)<\/parameter>/gi;
|
|
2510
|
+
let paramMatch;
|
|
2511
|
+
while ((paramMatch = paramRegex.exec(body)) !== null) {
|
|
2512
|
+
params[paramMatch[1].toLowerCase()] = paramMatch[2].trim();
|
|
2513
|
+
}
|
|
2514
|
+
if (funcName === "ripgrep") {
|
|
2515
|
+
const pattern = params.pattern;
|
|
2516
|
+
if (!pattern) continue;
|
|
2517
|
+
const args = {
|
|
2518
|
+
pattern,
|
|
2519
|
+
path: params.path || ".",
|
|
2520
|
+
...params.glob && { glob: params.glob },
|
|
2521
|
+
...params.context_lines && { context_lines: parseInt(params.context_lines, 10) },
|
|
2522
|
+
...params.case_sensitive && { case_sensitive: params.case_sensitive === "true" }
|
|
2523
|
+
};
|
|
2524
|
+
tools.push({ name: "grep", arguments: args });
|
|
2525
|
+
} else if (funcName === "list_directory") {
|
|
2526
|
+
const command = params.command;
|
|
2527
|
+
const directPath = params.path;
|
|
2528
|
+
let dirPath = directPath || ".";
|
|
2529
|
+
if (!directPath && command) {
|
|
2530
|
+
const tokens = command.trim().split(/\s+/);
|
|
2531
|
+
const pathTokens = tokens.slice(1).filter((t) => !t.startsWith("-") && !t.startsWith("|") && !t.startsWith("\\("));
|
|
2532
|
+
if (pathTokens.length > 0) {
|
|
2533
|
+
dirPath = pathTokens[0];
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
tools.push({ name: "list_directory", arguments: { path: dirPath, pattern: params.pattern || null } });
|
|
2537
|
+
} else if (funcName === "read") {
|
|
2538
|
+
const filePath = params.path;
|
|
2539
|
+
if (!filePath) continue;
|
|
2540
|
+
const args = { path: filePath };
|
|
2541
|
+
const linesStr = params.lines;
|
|
2542
|
+
if (linesStr) {
|
|
2543
|
+
const ranges = [];
|
|
2544
|
+
for (const rangeStr of linesStr.split(",")) {
|
|
2545
|
+
const trimmed = rangeStr.trim();
|
|
2546
|
+
if (!trimmed) continue;
|
|
2547
|
+
const [s, e] = trimmed.split("-").map((v) => parseInt(v.trim(), 10));
|
|
2548
|
+
if (Number.isFinite(s) && Number.isFinite(e)) {
|
|
2549
|
+
ranges.push([s, e]);
|
|
2550
|
+
} else if (Number.isFinite(s)) {
|
|
2551
|
+
ranges.push([s, s]);
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
if (ranges.length === 1) {
|
|
2555
|
+
args.start = ranges[0][0];
|
|
2556
|
+
args.end = ranges[0][1];
|
|
2557
|
+
} else if (ranges.length > 1) {
|
|
2558
|
+
args.lines = ranges;
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
tools.push({ name: "read", arguments: args });
|
|
2562
|
+
} else if (funcName === "finish") {
|
|
2563
|
+
if (params.result && !params.files) {
|
|
2564
|
+
tools.push({ name: "finish", arguments: { files: [], textResult: params.result } });
|
|
2565
|
+
continue;
|
|
2566
|
+
}
|
|
2567
|
+
const filesStr = params.files;
|
|
2568
|
+
if (!filesStr) {
|
|
2569
|
+
tools.push({ name: "finish", arguments: { files: [], textResult: "No relevant code found." } });
|
|
2570
|
+
continue;
|
|
2571
|
+
}
|
|
2572
|
+
const files = [];
|
|
2573
|
+
for (const line of filesStr.split("\n")) {
|
|
2574
|
+
const trimmed = line.trim();
|
|
2575
|
+
if (!trimmed) continue;
|
|
2576
|
+
const colonIdx = trimmed.indexOf(":");
|
|
2577
|
+
if (colonIdx === -1) {
|
|
2578
|
+
files.push({ path: trimmed, lines: "*" });
|
|
2579
|
+
} else {
|
|
2580
|
+
const filePath = trimmed.slice(0, colonIdx);
|
|
2581
|
+
const rangesPart = trimmed.slice(colonIdx + 1);
|
|
2582
|
+
const ranges = [];
|
|
2583
|
+
for (const rangeStr of rangesPart.split(",")) {
|
|
2584
|
+
const rt = rangeStr.trim();
|
|
2585
|
+
if (!rt || rt === "*") {
|
|
2586
|
+
files.push({ path: filePath, lines: "*" });
|
|
2587
|
+
break;
|
|
2588
|
+
}
|
|
2589
|
+
const [s, e] = rt.split("-").map((v) => parseInt(v.trim(), 10));
|
|
2590
|
+
if (Number.isFinite(s) && Number.isFinite(e)) {
|
|
2591
|
+
ranges.push([s, e]);
|
|
2592
|
+
} else if (Number.isFinite(s)) {
|
|
2593
|
+
ranges.push([s, s]);
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
if (ranges.length > 0) {
|
|
2597
|
+
files.push({ path: filePath, lines: ranges });
|
|
2598
|
+
} else if (!files.some((f) => f.path === filePath)) {
|
|
2599
|
+
files.push({ path: filePath, lines: "*" });
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
if (files.length > 0) {
|
|
2604
|
+
tools.push({ name: "finish", arguments: { files } });
|
|
2605
|
+
} else {
|
|
2606
|
+
tools.push({ name: "finish", arguments: { files: [], textResult: filesStr } });
|
|
2578
2607
|
}
|
|
2579
2608
|
}
|
|
2580
|
-
files.push({ path: filePath, lines: ranges.length > 0 ? ranges : "*" });
|
|
2581
2609
|
}
|
|
2582
|
-
return
|
|
2583
|
-
}
|
|
2584
|
-
function extractPathFromCommand(command) {
|
|
2585
|
-
const tokens = command.trim().split(/\s+/);
|
|
2586
|
-
const pathTokens = tokens.slice(1).filter((t) => !t.startsWith("-") && !t.startsWith("|") && !t.startsWith("\\("));
|
|
2587
|
-
return pathTokens[0] || ".";
|
|
2610
|
+
return tools;
|
|
2588
2611
|
}
|
|
2612
|
+
var LLMResponseParser = class {
|
|
2613
|
+
parse(text) {
|
|
2614
|
+
if (typeof text !== "string") {
|
|
2615
|
+
throw new TypeError("Command text must be a string.");
|
|
2616
|
+
}
|
|
2617
|
+
const withoutThink = text.replace(/<think>[\s\S]*?<\/think>/gi, "");
|
|
2618
|
+
return parseQwen3ToolCalls(withoutThink);
|
|
2619
|
+
}
|
|
2620
|
+
};
|
|
2589
2621
|
|
|
2590
2622
|
// tools/warp_grep/agent/tools/grep.ts
|
|
2591
2623
|
async function toolGrep(provider, args) {
|
|
@@ -2636,42 +2668,29 @@ async function toolRead(provider, args) {
|
|
|
2636
2668
|
|
|
2637
2669
|
// tools/warp_grep/agent/tools/list_directory.ts
|
|
2638
2670
|
init_config();
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
const
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
}
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
return res.error;
|
|
2663
|
-
}
|
|
2664
|
-
if (!res.files.length) {
|
|
2665
|
-
return "no matches";
|
|
2666
|
-
}
|
|
2667
|
-
const header = `Found ${res.totalFound} file(s) matching "${args.pattern}" within ${res.searchDir}, sorted by modification time (newest first):`;
|
|
2668
|
-
const body = res.files.join("\n");
|
|
2669
|
-
const truncated = res.totalFound > res.files.length ? `
|
|
2670
|
-
[${res.totalFound - res.files.length} files truncated]` : "";
|
|
2671
|
-
return `${header}
|
|
2672
|
-
---
|
|
2673
|
-
${body}
|
|
2674
|
-
---${truncated}`;
|
|
2671
|
+
async function toolListDirectory(provider, args) {
|
|
2672
|
+
const maxResults = args.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;
|
|
2673
|
+
const initialDepth = args.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
|
|
2674
|
+
async function getListRecursive(currentDepth) {
|
|
2675
|
+
const entries = await provider.listDirectory({
|
|
2676
|
+
path: args.path,
|
|
2677
|
+
pattern: args.pattern ?? null,
|
|
2678
|
+
maxResults,
|
|
2679
|
+
maxDepth: currentDepth
|
|
2680
|
+
});
|
|
2681
|
+
if (entries.length >= maxResults && currentDepth > 0) {
|
|
2682
|
+
return getListRecursive(currentDepth - 1);
|
|
2683
|
+
}
|
|
2684
|
+
return { entries };
|
|
2685
|
+
}
|
|
2686
|
+
const { entries: list } = await getListRecursive(initialDepth);
|
|
2687
|
+
if (!list.length) return "empty";
|
|
2688
|
+
const tree = list.map((e) => {
|
|
2689
|
+
const indent = " ".repeat(e.depth);
|
|
2690
|
+
const name = e.type === "dir" ? `${e.name}/` : e.name;
|
|
2691
|
+
return `${indent}${name}`;
|
|
2692
|
+
}).join("\n");
|
|
2693
|
+
return tree;
|
|
2675
2694
|
}
|
|
2676
2695
|
|
|
2677
2696
|
// tools/warp_grep/agent/tools/finish.ts
|
|
@@ -2732,21 +2751,32 @@ function mergeRanges(ranges) {
|
|
|
2732
2751
|
return merged;
|
|
2733
2752
|
}
|
|
2734
2753
|
|
|
2754
|
+
// tools/warp_grep/agent/formatter.ts
|
|
2755
|
+
var ToolOutputFormatter = class {
|
|
2756
|
+
format(toolName, _args, output, options = {}) {
|
|
2757
|
+
const name = (toolName ?? "").trim();
|
|
2758
|
+
if (!name) {
|
|
2759
|
+
return "";
|
|
2760
|
+
}
|
|
2761
|
+
const payload = output?.toString?.()?.trim?.() ?? "";
|
|
2762
|
+
const isError = Boolean(options.isError);
|
|
2763
|
+
if (!payload && !isError) {
|
|
2764
|
+
return "";
|
|
2765
|
+
}
|
|
2766
|
+
return `<tool_response>
|
|
2767
|
+
${payload}
|
|
2768
|
+
</tool_response>`;
|
|
2769
|
+
}
|
|
2770
|
+
};
|
|
2771
|
+
var sharedFormatter = new ToolOutputFormatter();
|
|
2772
|
+
function formatAgentToolOutput(toolName, args, output, options = {}) {
|
|
2773
|
+
return sharedFormatter.format(toolName, args, output, options);
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2735
2776
|
// tools/warp_grep/agent/helpers.ts
|
|
2736
|
-
var
|
|
2777
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
2737
2778
|
init_config();
|
|
2738
2779
|
var TRUNCATED_MARKER = "[truncated for context limit]";
|
|
2739
|
-
function getMessageSize(m) {
|
|
2740
|
-
if (m.role === "tool") return m.content.length;
|
|
2741
|
-
if (m.role === "assistant") {
|
|
2742
|
-
let size = typeof m.content === "string" ? m.content.length : 0;
|
|
2743
|
-
if (m.tool_calls) {
|
|
2744
|
-
size += m.tool_calls.reduce((s, tc) => s + tc.function.name.length + tc.function.arguments.length, 0);
|
|
2745
|
-
}
|
|
2746
|
-
return size;
|
|
2747
|
-
}
|
|
2748
|
-
return m.content.length;
|
|
2749
|
-
}
|
|
2750
2780
|
function formatTurnMessage(turnsUsed, maxTurns) {
|
|
2751
2781
|
const turnsRemaining = maxTurns - turnsUsed;
|
|
2752
2782
|
if (turnsRemaining === 1) {
|
|
@@ -2757,7 +2787,7 @@ You have used ${turnsUsed} turns, you only have 1 turn remaining. You have run o
|
|
|
2757
2787
|
You have used ${turnsUsed} turn${turnsUsed === 1 ? "" : "s"} and have ${turnsRemaining} remaining`;
|
|
2758
2788
|
}
|
|
2759
2789
|
function calculateContextBudget(messages) {
|
|
2760
|
-
const totalChars = messages.reduce((sum, m) => sum +
|
|
2790
|
+
const totalChars = messages.reduce((sum, m) => sum + m.content.length, 0);
|
|
2761
2791
|
const maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS;
|
|
2762
2792
|
const percent = Math.round(totalChars / maxChars * 100);
|
|
2763
2793
|
const usedK = Math.round(totalChars / 1e3);
|
|
@@ -2766,21 +2796,24 @@ function calculateContextBudget(messages) {
|
|
|
2766
2796
|
}
|
|
2767
2797
|
async function buildInitialState(repoRoot, searchTerm, provider, options) {
|
|
2768
2798
|
const budget = calculateContextBudget([]);
|
|
2769
|
-
const turnTag = `
|
|
2799
|
+
const turnTag = `Turn 0/${AGENT_CONFIG.MAX_TURNS}`;
|
|
2770
2800
|
const treeDepth = options?.search_type === "node_modules" ? 1 : 2;
|
|
2771
|
-
const absRoot = import_path3.default.resolve(repoRoot);
|
|
2772
2801
|
try {
|
|
2773
2802
|
const entries = await provider.listDirectory({
|
|
2774
2803
|
path: ".",
|
|
2775
2804
|
maxResults: AGENT_CONFIG.MAX_OUTPUT_LINES,
|
|
2776
2805
|
maxDepth: treeDepth
|
|
2777
2806
|
});
|
|
2778
|
-
const
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2807
|
+
const treeLines = entries.map((e) => {
|
|
2808
|
+
const indent = " ".repeat(e.depth);
|
|
2809
|
+
const name = e.type === "dir" ? `${e.name}/` : e.name;
|
|
2810
|
+
return `${indent}${name}`;
|
|
2811
|
+
});
|
|
2812
|
+
const repoName = import_path2.default.basename(repoRoot);
|
|
2813
|
+
const treeOutput = treeLines.length > 0 ? `${repoName}/
|
|
2814
|
+
${treeLines.join("\n")}` : `${repoName}/`;
|
|
2782
2815
|
return `<repo_structure>
|
|
2783
|
-
${
|
|
2816
|
+
${treeOutput}
|
|
2784
2817
|
</repo_structure>
|
|
2785
2818
|
|
|
2786
2819
|
<search_string>
|
|
@@ -2789,8 +2822,9 @@ ${searchTerm}
|
|
|
2789
2822
|
${budget}
|
|
2790
2823
|
${turnTag}`;
|
|
2791
2824
|
} catch {
|
|
2825
|
+
const repoName = import_path2.default.basename(repoRoot);
|
|
2792
2826
|
return `<repo_structure>
|
|
2793
|
-
${
|
|
2827
|
+
${repoName}/
|
|
2794
2828
|
</repo_structure>
|
|
2795
2829
|
|
|
2796
2830
|
<search_string>
|
|
@@ -2801,32 +2835,26 @@ ${turnTag}`;
|
|
|
2801
2835
|
}
|
|
2802
2836
|
}
|
|
2803
2837
|
function enforceContextLimit(messages, maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS) {
|
|
2804
|
-
const getTotalChars = () => messages.reduce((sum, m) => sum +
|
|
2838
|
+
const getTotalChars = () => messages.reduce((sum, m) => sum + m.content.length, 0);
|
|
2805
2839
|
if (getTotalChars() <= maxChars) {
|
|
2806
2840
|
return messages;
|
|
2807
2841
|
}
|
|
2808
|
-
const
|
|
2842
|
+
const userIndices = [];
|
|
2809
2843
|
let firstUserSkipped = false;
|
|
2810
2844
|
for (let i = 0; i < messages.length; i++) {
|
|
2811
|
-
|
|
2812
|
-
if (m.role === "tool") {
|
|
2813
|
-
truncatableIndices.push(i);
|
|
2814
|
-
} else if (m.role === "user") {
|
|
2845
|
+
if (messages[i].role === "user") {
|
|
2815
2846
|
if (!firstUserSkipped) {
|
|
2816
2847
|
firstUserSkipped = true;
|
|
2817
2848
|
continue;
|
|
2818
2849
|
}
|
|
2819
|
-
|
|
2850
|
+
userIndices.push(i);
|
|
2820
2851
|
}
|
|
2821
2852
|
}
|
|
2822
|
-
for (const idx of
|
|
2853
|
+
for (const idx of userIndices) {
|
|
2823
2854
|
if (getTotalChars() <= maxChars) {
|
|
2824
2855
|
break;
|
|
2825
2856
|
}
|
|
2826
|
-
|
|
2827
|
-
if (m.role === "tool" && m.content !== TRUNCATED_MARKER) {
|
|
2828
|
-
messages[idx] = { role: "tool", tool_call_id: m.tool_call_id, content: TRUNCATED_MARKER };
|
|
2829
|
-
} else if (m.role === "user" && m.content !== TRUNCATED_MARKER) {
|
|
2857
|
+
if (messages[idx].content !== TRUNCATED_MARKER) {
|
|
2830
2858
|
messages[idx] = { role: "user", content: TRUNCATED_MARKER };
|
|
2831
2859
|
}
|
|
2832
2860
|
}
|
|
@@ -2836,115 +2864,9 @@ function enforceContextLimit(messages, maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS
|
|
|
2836
2864
|
// tools/warp_grep/agent/runner.ts
|
|
2837
2865
|
var import_openai2 = __toESM(require("openai"), 1);
|
|
2838
2866
|
init_version();
|
|
2839
|
-
var
|
|
2867
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
2868
|
+
var parser = new LLMResponseParser();
|
|
2840
2869
|
var DEFAULT_API_URL3 = "https://api.morphllm.com";
|
|
2841
|
-
var TOOL_SPECS = [
|
|
2842
|
-
{
|
|
2843
|
-
type: "function",
|
|
2844
|
-
function: {
|
|
2845
|
-
name: "list_directory",
|
|
2846
|
-
description: "Execute ls or find commands to explore directory structure. Max 500 results. Common junk directories are excluded automatically.",
|
|
2847
|
-
parameters: {
|
|
2848
|
-
type: "object",
|
|
2849
|
-
properties: {
|
|
2850
|
-
command: {
|
|
2851
|
-
type: "string",
|
|
2852
|
-
description: "Full ls or find command (e.g. ls -la src/, find . -maxdepth 2 -type f -name '*.py', find . -type d, ls -d */)."
|
|
2853
|
-
}
|
|
2854
|
-
},
|
|
2855
|
-
required: ["command"]
|
|
2856
|
-
}
|
|
2857
|
-
}
|
|
2858
|
-
},
|
|
2859
|
-
{
|
|
2860
|
-
type: "function",
|
|
2861
|
-
function: {
|
|
2862
|
-
name: "grep_search",
|
|
2863
|
-
description: "Search for a regex pattern in file contents. Returns matching lines with file paths and line numbers. Case-insensitive. Respects .gitignore.",
|
|
2864
|
-
parameters: {
|
|
2865
|
-
type: "object",
|
|
2866
|
-
properties: {
|
|
2867
|
-
pattern: {
|
|
2868
|
-
type: "string",
|
|
2869
|
-
description: "Regex pattern to search for in file contents (e.g. 'class\\s+\\w+Error', 'import|require|from', 'def (get|set|update)_user')."
|
|
2870
|
-
},
|
|
2871
|
-
path: {
|
|
2872
|
-
type: "string",
|
|
2873
|
-
description: "File or directory to search in. Defaults to current working directory."
|
|
2874
|
-
},
|
|
2875
|
-
glob: {
|
|
2876
|
-
type: "string",
|
|
2877
|
-
description: "Glob pattern to filter files (e.g. '*.py', '*.{ts,tsx,js,jsx,py,go}', 'src/**/*.go', '!*.test.*')."
|
|
2878
|
-
},
|
|
2879
|
-
limit: {
|
|
2880
|
-
type: "integer",
|
|
2881
|
-
description: "Limit output to first N matching lines. Shows all matches if not specified."
|
|
2882
|
-
}
|
|
2883
|
-
},
|
|
2884
|
-
required: ["pattern"]
|
|
2885
|
-
}
|
|
2886
|
-
}
|
|
2887
|
-
},
|
|
2888
|
-
{
|
|
2889
|
-
type: "function",
|
|
2890
|
-
function: {
|
|
2891
|
-
name: "glob",
|
|
2892
|
-
description: "Find files by name/extension using glob patterns. Returns absolute paths sorted by modification time (newest first). Respects .gitignore. Max 100 results.",
|
|
2893
|
-
parameters: {
|
|
2894
|
-
type: "object",
|
|
2895
|
-
properties: {
|
|
2896
|
-
pattern: {
|
|
2897
|
-
type: "string",
|
|
2898
|
-
description: "Glob pattern to match files (e.g. '*.py', 'src/**/*.js', '*.{ts,tsx}', 'test_*.py')."
|
|
2899
|
-
},
|
|
2900
|
-
path: {
|
|
2901
|
-
type: "string",
|
|
2902
|
-
description: "Directory to search in. Defaults to repository root."
|
|
2903
|
-
}
|
|
2904
|
-
},
|
|
2905
|
-
required: ["pattern"]
|
|
2906
|
-
}
|
|
2907
|
-
}
|
|
2908
|
-
},
|
|
2909
|
-
{
|
|
2910
|
-
type: "function",
|
|
2911
|
-
function: {
|
|
2912
|
-
name: "read",
|
|
2913
|
-
description: "Read entire files or specific line ranges using absolute paths.",
|
|
2914
|
-
parameters: {
|
|
2915
|
-
type: "object",
|
|
2916
|
-
properties: {
|
|
2917
|
-
path: {
|
|
2918
|
-
type: "string",
|
|
2919
|
-
description: "File path to read, using absolute path (e.g. '/home/ubuntu/repo/src/main.py' or windows path)."
|
|
2920
|
-
},
|
|
2921
|
-
lines: {
|
|
2922
|
-
type: "string",
|
|
2923
|
-
description: "Optional line range (e.g. '1-50' or '1-20,45-80'). Omit to read entire file."
|
|
2924
|
-
}
|
|
2925
|
-
},
|
|
2926
|
-
required: ["path"]
|
|
2927
|
-
}
|
|
2928
|
-
}
|
|
2929
|
-
},
|
|
2930
|
-
{
|
|
2931
|
-
type: "function",
|
|
2932
|
-
function: {
|
|
2933
|
-
name: "finish",
|
|
2934
|
-
description: "Submit final answer with all relevant code locations. Include imports and over-include rather than miss context.",
|
|
2935
|
-
parameters: {
|
|
2936
|
-
type: "object",
|
|
2937
|
-
properties: {
|
|
2938
|
-
files: {
|
|
2939
|
-
type: "string",
|
|
2940
|
-
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."
|
|
2941
|
-
}
|
|
2942
|
-
},
|
|
2943
|
-
required: ["files"]
|
|
2944
|
-
}
|
|
2945
|
-
}
|
|
2946
|
-
}
|
|
2947
|
-
];
|
|
2948
2870
|
async function callModel(messages, model, options = {}) {
|
|
2949
2871
|
const baseUrl = options.morphApiUrl || DEFAULT_API_URL3;
|
|
2950
2872
|
const apiKey = options.morphApiKey || process.env.MORPH_API_KEY || "";
|
|
@@ -2965,9 +2887,8 @@ async function callModel(messages, model, options = {}) {
|
|
|
2965
2887
|
data = await client.chat.completions.create({
|
|
2966
2888
|
model,
|
|
2967
2889
|
temperature: 0,
|
|
2968
|
-
max_tokens:
|
|
2890
|
+
max_tokens: 1024,
|
|
2969
2891
|
messages,
|
|
2970
|
-
tools: TOOL_SPECS,
|
|
2971
2892
|
...options.search_type ? { search_type: options.search_type } : {}
|
|
2972
2893
|
});
|
|
2973
2894
|
} catch (error) {
|
|
@@ -2979,87 +2900,187 @@ async function callModel(messages, model, options = {}) {
|
|
|
2979
2900
|
throw error;
|
|
2980
2901
|
}
|
|
2981
2902
|
const choice = data?.choices?.[0];
|
|
2982
|
-
const
|
|
2983
|
-
if (
|
|
2984
|
-
|
|
2985
|
-
throw new Error("Invalid response from model: no message in response");
|
|
2986
|
-
}
|
|
2987
|
-
await new Promise((resolve2) => setTimeout(resolve2, 200));
|
|
2988
|
-
continue;
|
|
2989
|
-
}
|
|
2990
|
-
const toolCalls = (message.tool_calls || []).map((tc) => ({
|
|
2991
|
-
id: tc.id,
|
|
2992
|
-
type: "function",
|
|
2993
|
-
function: { name: tc.function.name, arguments: tc.function.arguments }
|
|
2994
|
-
}));
|
|
2995
|
-
if (message.content || toolCalls.length > 0) {
|
|
2996
|
-
return { content: message.content ?? null, tool_calls: toolCalls };
|
|
2903
|
+
const content = choice?.message?.content;
|
|
2904
|
+
if (content && typeof content === "string") {
|
|
2905
|
+
return content;
|
|
2997
2906
|
}
|
|
2998
2907
|
if (attempt === MAX_EMPTY_RETRIES) {
|
|
2999
2908
|
const finishReason = choice?.finish_reason ?? "unknown";
|
|
2909
|
+
const hasToolCalls = Array.isArray(choice?.message?.tool_calls) && choice.message.tool_calls.length > 0;
|
|
2910
|
+
const choicesLen = data?.choices?.length ?? 0;
|
|
2911
|
+
const contentType = content === null ? "null" : content === void 0 ? "undefined" : typeof content;
|
|
3000
2912
|
throw new Error(
|
|
3001
|
-
`Invalid response from model:
|
|
2913
|
+
`Invalid response from model: content=${contentType}, finish_reason=${finishReason}, has_tool_calls=${hasToolCalls}, choices_length=${choicesLen}`
|
|
3002
2914
|
);
|
|
3003
2915
|
}
|
|
3004
2916
|
await new Promise((resolve2) => setTimeout(resolve2, 200));
|
|
3005
2917
|
}
|
|
3006
2918
|
throw new Error("Invalid response from model");
|
|
3007
2919
|
}
|
|
3008
|
-
function
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
2920
|
+
async function runWarpGrep(config) {
|
|
2921
|
+
const totalStart = Date.now();
|
|
2922
|
+
const timeoutMs = config.timeout ?? AGENT_CONFIG.TIMEOUT_MS;
|
|
2923
|
+
const timings = { turns: [], timeout_ms: timeoutMs };
|
|
2924
|
+
const repoRoot = import_path3.default.resolve(config.repoRoot || process.cwd());
|
|
2925
|
+
const model = config.model || DEFAULT_MODEL;
|
|
2926
|
+
const messages = [];
|
|
2927
|
+
const maxTurns = AGENT_CONFIG.MAX_TURNS;
|
|
2928
|
+
const initialStateStart = Date.now();
|
|
2929
|
+
const initialState = await buildInitialState(repoRoot, config.searchTerm, config.provider, { search_type: config.search_type });
|
|
2930
|
+
timings.initial_state_ms = Date.now() - initialStateStart;
|
|
2931
|
+
messages.push({ role: "user", content: initialState });
|
|
2932
|
+
const provider = config.provider;
|
|
2933
|
+
const errors = [];
|
|
2934
|
+
let finishMeta;
|
|
2935
|
+
let terminationReason = "terminated";
|
|
2936
|
+
for (let turn = 1; turn <= maxTurns; turn += 1) {
|
|
2937
|
+
const turnMetrics = { turn, morph_api_ms: 0, local_tools_ms: 0 };
|
|
2938
|
+
enforceContextLimit(messages);
|
|
2939
|
+
const modelCallStart = Date.now();
|
|
2940
|
+
const assistantContent = await callModel(messages, model, {
|
|
2941
|
+
morphApiKey: config.morphApiKey,
|
|
2942
|
+
morphApiUrl: config.morphApiUrl,
|
|
2943
|
+
retryConfig: config.retryConfig,
|
|
2944
|
+
timeout: timeoutMs,
|
|
2945
|
+
search_type: config.search_type
|
|
2946
|
+
}).catch((e) => {
|
|
2947
|
+
const errMsg = e instanceof Error ? e.message : String(e);
|
|
2948
|
+
console.error(`[warp_grep] Morph API call failed on turn ${turn}:`, errMsg);
|
|
2949
|
+
errors.push({ message: errMsg });
|
|
2950
|
+
return "";
|
|
2951
|
+
});
|
|
2952
|
+
turnMetrics.morph_api_ms = Date.now() - modelCallStart;
|
|
2953
|
+
if (!assistantContent) {
|
|
2954
|
+
console.error(`[warp_grep] Empty response from Morph API on turn ${turn}. Errors so far:`, errors);
|
|
2955
|
+
timings.turns.push(turnMetrics);
|
|
2956
|
+
break;
|
|
3034
2957
|
}
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
});
|
|
2958
|
+
messages.push({ role: "assistant", content: assistantContent });
|
|
2959
|
+
const toolCalls = parser.parse(assistantContent);
|
|
2960
|
+
if (toolCalls.length === 0) {
|
|
2961
|
+
console.error(`[warp_grep] No tool calls parsed on turn ${turn}. Assistant content (first 500 chars):`, assistantContent.slice(0, 500));
|
|
2962
|
+
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" });
|
|
2963
|
+
terminationReason = "terminated";
|
|
2964
|
+
timings.turns.push(turnMetrics);
|
|
2965
|
+
break;
|
|
3040
2966
|
}
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
2967
|
+
const finishCalls = toolCalls.filter((c) => c.name === "finish");
|
|
2968
|
+
const grepCalls = toolCalls.filter((c) => c.name === "grep");
|
|
2969
|
+
const listDirCalls = toolCalls.filter((c) => c.name === "list_directory");
|
|
2970
|
+
const readCalls = toolCalls.filter((c) => c.name === "read");
|
|
2971
|
+
const skipCalls = toolCalls.filter((c) => c.name === "_skip");
|
|
2972
|
+
const formatted = [];
|
|
2973
|
+
for (const c of skipCalls) {
|
|
2974
|
+
const msg = c.arguments?.message || "Command skipped due to parsing error";
|
|
2975
|
+
formatted.push(msg);
|
|
2976
|
+
}
|
|
2977
|
+
const allPromises = [];
|
|
2978
|
+
for (const c of grepCalls) {
|
|
2979
|
+
const args = c.arguments ?? {};
|
|
2980
|
+
allPromises.push(
|
|
2981
|
+
toolGrep(provider, args).then(
|
|
2982
|
+
({ output }) => formatAgentToolOutput("grep", args, output),
|
|
2983
|
+
(err) => formatAgentToolOutput("grep", args, String(err), { isError: true })
|
|
2984
|
+
)
|
|
2985
|
+
);
|
|
3044
2986
|
}
|
|
3045
|
-
|
|
3046
|
-
const
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
2987
|
+
for (const c of listDirCalls) {
|
|
2988
|
+
const args = c.arguments ?? {};
|
|
2989
|
+
allPromises.push(
|
|
2990
|
+
toolListDirectory(provider, args).then(
|
|
2991
|
+
(p) => formatAgentToolOutput("list_directory", args, p),
|
|
2992
|
+
(err) => formatAgentToolOutput("list_directory", args, String(err), { isError: true })
|
|
2993
|
+
)
|
|
2994
|
+
);
|
|
2995
|
+
}
|
|
2996
|
+
for (const c of readCalls) {
|
|
2997
|
+
const args = c.arguments ?? {};
|
|
2998
|
+
allPromises.push(
|
|
2999
|
+
toolRead(provider, args).then(
|
|
3000
|
+
(p) => formatAgentToolOutput("read", args, p),
|
|
3001
|
+
(err) => formatAgentToolOutput("read", args, String(err), { isError: true })
|
|
3002
|
+
)
|
|
3003
|
+
);
|
|
3004
|
+
}
|
|
3005
|
+
const toolExecStart = Date.now();
|
|
3006
|
+
const allResults = await Promise.all(allPromises);
|
|
3007
|
+
turnMetrics.local_tools_ms = Date.now() - toolExecStart;
|
|
3008
|
+
for (const result of allResults) {
|
|
3009
|
+
formatted.push(result);
|
|
3010
|
+
}
|
|
3011
|
+
if (formatted.length > 0) {
|
|
3012
|
+
const turnMessage = formatTurnMessage(turn, maxTurns);
|
|
3013
|
+
const contextBudget = calculateContextBudget(messages);
|
|
3014
|
+
messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
|
|
3015
|
+
}
|
|
3016
|
+
timings.turns.push(turnMetrics);
|
|
3017
|
+
if (finishCalls.length) {
|
|
3018
|
+
const fc = finishCalls[0];
|
|
3019
|
+
const files = fc.arguments?.files ?? [];
|
|
3020
|
+
const textResult = fc.arguments?.textResult;
|
|
3021
|
+
finishMeta = { files };
|
|
3022
|
+
terminationReason = "completed";
|
|
3023
|
+
if (files.length === 0) {
|
|
3024
|
+
const payload2 = textResult || "No relevant code found.";
|
|
3025
|
+
timings.turns.push(turnMetrics);
|
|
3026
|
+
timings.total_ms = Date.now() - totalStart;
|
|
3027
|
+
return {
|
|
3028
|
+
terminationReason: "completed",
|
|
3029
|
+
messages,
|
|
3030
|
+
finish: { payload: payload2, metadata: finishMeta },
|
|
3031
|
+
timings
|
|
3032
|
+
};
|
|
3051
3033
|
}
|
|
3052
|
-
|
|
3034
|
+
break;
|
|
3053
3035
|
}
|
|
3054
|
-
default:
|
|
3055
|
-
return `Unknown tool: ${name}`;
|
|
3056
3036
|
}
|
|
3037
|
+
if (terminationReason !== "completed" || !finishMeta) {
|
|
3038
|
+
timings.total_ms = Date.now() - totalStart;
|
|
3039
|
+
return { terminationReason, messages, errors, timings };
|
|
3040
|
+
}
|
|
3041
|
+
const parts = ["Relevant context found:"];
|
|
3042
|
+
for (const f of finishMeta.files) {
|
|
3043
|
+
const ranges = f.lines === "*" ? "*" : Array.isArray(f.lines) ? f.lines.map(([s, e]) => `${s}-${e}`).join(", ") : "*";
|
|
3044
|
+
parts.push(`- ${f.path}: ${ranges}`);
|
|
3045
|
+
}
|
|
3046
|
+
const payload = parts.join("\n");
|
|
3047
|
+
const finishResolutionStart = Date.now();
|
|
3048
|
+
const fileReadErrors = [];
|
|
3049
|
+
const resolved = await readFinishFiles(
|
|
3050
|
+
repoRoot,
|
|
3051
|
+
finishMeta.files,
|
|
3052
|
+
async (p, s, e) => {
|
|
3053
|
+
try {
|
|
3054
|
+
const rr = await provider.read({ path: p, start: s, end: e });
|
|
3055
|
+
return rr.lines.map((l) => {
|
|
3056
|
+
const idx = l.indexOf("|");
|
|
3057
|
+
return idx >= 0 ? l.slice(idx + 1) : l;
|
|
3058
|
+
});
|
|
3059
|
+
} catch (err) {
|
|
3060
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
3061
|
+
fileReadErrors.push({ path: p, error: errorMsg });
|
|
3062
|
+
console.error(`[warp_grep] Failed to read file: ${p} - ${errorMsg}`);
|
|
3063
|
+
return [`[couldn't find: ${p}]`];
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
);
|
|
3067
|
+
timings.finish_resolution_ms = Date.now() - finishResolutionStart;
|
|
3068
|
+
if (fileReadErrors.length > 0) {
|
|
3069
|
+
errors.push(...fileReadErrors.map((e) => ({ message: `File read error: ${e.path} - ${e.error}` })));
|
|
3070
|
+
}
|
|
3071
|
+
timings.total_ms = Date.now() - totalStart;
|
|
3072
|
+
return {
|
|
3073
|
+
terminationReason: "completed",
|
|
3074
|
+
messages,
|
|
3075
|
+
finish: { payload, metadata: finishMeta, resolved },
|
|
3076
|
+
timings
|
|
3077
|
+
};
|
|
3057
3078
|
}
|
|
3058
3079
|
async function* runWarpGrepStreaming(config) {
|
|
3059
3080
|
const totalStart = Date.now();
|
|
3060
3081
|
const timeoutMs = config.timeout ?? AGENT_CONFIG.TIMEOUT_MS;
|
|
3061
3082
|
const timings = { turns: [], timeout_ms: timeoutMs };
|
|
3062
|
-
const repoRoot =
|
|
3083
|
+
const repoRoot = import_path3.default.resolve(config.repoRoot || process.cwd());
|
|
3063
3084
|
const model = config.model || DEFAULT_MODEL;
|
|
3064
3085
|
const messages = [];
|
|
3065
3086
|
const maxTurns = AGENT_CONFIG.MAX_TURNS;
|
|
@@ -3075,7 +3096,7 @@ async function* runWarpGrepStreaming(config) {
|
|
|
3075
3096
|
const turnMetrics = { turn, morph_api_ms: 0, local_tools_ms: 0 };
|
|
3076
3097
|
enforceContextLimit(messages);
|
|
3077
3098
|
const modelCallStart = Date.now();
|
|
3078
|
-
const
|
|
3099
|
+
const assistantContent = await callModel(messages, model, {
|
|
3079
3100
|
morphApiKey: config.morphApiKey,
|
|
3080
3101
|
morphApiUrl: config.morphApiUrl,
|
|
3081
3102
|
retryConfig: config.retryConfig,
|
|
@@ -3083,45 +3104,90 @@ async function* runWarpGrepStreaming(config) {
|
|
|
3083
3104
|
search_type: config.search_type
|
|
3084
3105
|
}).catch((e) => {
|
|
3085
3106
|
const errMsg = e instanceof Error ? e.message : String(e);
|
|
3086
|
-
console.error(`[warp_grep] Morph API call failed on turn ${turn}:`, errMsg);
|
|
3107
|
+
console.error(`[warp_grep:stream] Morph API call failed on turn ${turn}:`, errMsg);
|
|
3087
3108
|
errors.push({ message: errMsg });
|
|
3088
|
-
return
|
|
3109
|
+
return "";
|
|
3089
3110
|
});
|
|
3090
3111
|
turnMetrics.morph_api_ms = Date.now() - modelCallStart;
|
|
3091
|
-
if (!
|
|
3112
|
+
if (!assistantContent) {
|
|
3113
|
+
console.error(`[warp_grep:stream] Empty response from Morph API on turn ${turn}. Errors so far:`, errors);
|
|
3092
3114
|
timings.turns.push(turnMetrics);
|
|
3093
3115
|
break;
|
|
3094
3116
|
}
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
role: "assistant",
|
|
3098
|
-
content: response.content,
|
|
3099
|
-
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
|
|
3100
|
-
});
|
|
3117
|
+
messages.push({ role: "assistant", content: assistantContent });
|
|
3118
|
+
const toolCalls = parser.parse(assistantContent);
|
|
3101
3119
|
if (toolCalls.length === 0) {
|
|
3102
|
-
console.error(`[warp_grep] No tool calls on turn ${turn}.
|
|
3103
|
-
errors.push({ message: "No tool calls produced by the model." });
|
|
3120
|
+
console.error(`[warp_grep:stream] No tool calls parsed on turn ${turn}. Assistant content (first 500 chars):`, assistantContent.slice(0, 500));
|
|
3121
|
+
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" });
|
|
3104
3122
|
terminationReason = "terminated";
|
|
3105
3123
|
timings.turns.push(turnMetrics);
|
|
3106
3124
|
break;
|
|
3107
3125
|
}
|
|
3108
3126
|
yield {
|
|
3109
3127
|
turn,
|
|
3110
|
-
toolCalls: toolCalls.map((
|
|
3111
|
-
name:
|
|
3112
|
-
arguments:
|
|
3128
|
+
toolCalls: toolCalls.map((c) => ({
|
|
3129
|
+
name: c.name,
|
|
3130
|
+
arguments: c.arguments ?? {}
|
|
3113
3131
|
}))
|
|
3114
3132
|
};
|
|
3115
|
-
const
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3133
|
+
const finishCalls = toolCalls.filter((c) => c.name === "finish");
|
|
3134
|
+
const grepCalls = toolCalls.filter((c) => c.name === "grep");
|
|
3135
|
+
const listDirCalls = toolCalls.filter((c) => c.name === "list_directory");
|
|
3136
|
+
const readCalls = toolCalls.filter((c) => c.name === "read");
|
|
3137
|
+
const skipCalls = toolCalls.filter((c) => c.name === "_skip");
|
|
3138
|
+
const formatted = [];
|
|
3139
|
+
for (const c of skipCalls) {
|
|
3140
|
+
const msg = c.arguments?.message || "Command skipped due to parsing error";
|
|
3141
|
+
formatted.push(msg);
|
|
3142
|
+
}
|
|
3143
|
+
const allPromises = [];
|
|
3144
|
+
for (const c of grepCalls) {
|
|
3145
|
+
const args = c.arguments ?? {};
|
|
3146
|
+
allPromises.push(
|
|
3147
|
+
toolGrep(provider, args).then(
|
|
3148
|
+
({ output }) => formatAgentToolOutput("grep", args, output),
|
|
3149
|
+
(err) => formatAgentToolOutput("grep", args, String(err), { isError: true })
|
|
3150
|
+
)
|
|
3151
|
+
);
|
|
3152
|
+
}
|
|
3153
|
+
for (const c of listDirCalls) {
|
|
3154
|
+
const args = c.arguments ?? {};
|
|
3155
|
+
allPromises.push(
|
|
3156
|
+
toolListDirectory(provider, args).then(
|
|
3157
|
+
(p) => formatAgentToolOutput("list_directory", args, p),
|
|
3158
|
+
(err) => formatAgentToolOutput("list_directory", args, String(err), { isError: true })
|
|
3159
|
+
)
|
|
3160
|
+
);
|
|
3161
|
+
}
|
|
3162
|
+
for (const c of readCalls) {
|
|
3163
|
+
const args = c.arguments ?? {};
|
|
3164
|
+
allPromises.push(
|
|
3165
|
+
toolRead(provider, args).then(
|
|
3166
|
+
(p) => formatAgentToolOutput("read", args, p),
|
|
3167
|
+
(err) => formatAgentToolOutput("read", args, String(err), { isError: true })
|
|
3168
|
+
)
|
|
3169
|
+
);
|
|
3170
|
+
}
|
|
3171
|
+
const toolExecStart = Date.now();
|
|
3172
|
+
const allResults = await Promise.all(allPromises);
|
|
3173
|
+
turnMetrics.local_tools_ms = Date.now() - toolExecStart;
|
|
3174
|
+
for (const result of allResults) {
|
|
3175
|
+
formatted.push(result);
|
|
3176
|
+
}
|
|
3177
|
+
if (formatted.length > 0) {
|
|
3178
|
+
const turnMessage = formatTurnMessage(turn, maxTurns);
|
|
3179
|
+
const contextBudget = calculateContextBudget(messages);
|
|
3180
|
+
messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
|
|
3181
|
+
}
|
|
3182
|
+
timings.turns.push(turnMetrics);
|
|
3183
|
+
if (finishCalls.length) {
|
|
3184
|
+
const fc = finishCalls[0];
|
|
3185
|
+
const files = fc.arguments?.files ?? [];
|
|
3186
|
+
const textResult = fc.arguments?.textResult;
|
|
3120
3187
|
finishMeta = { files };
|
|
3121
3188
|
terminationReason = "completed";
|
|
3122
3189
|
if (files.length === 0) {
|
|
3123
|
-
const payload2 =
|
|
3124
|
-
timings.turns.push(turnMetrics);
|
|
3190
|
+
const payload2 = textResult || "No relevant code found.";
|
|
3125
3191
|
timings.total_ms = Date.now() - totalStart;
|
|
3126
3192
|
return {
|
|
3127
3193
|
terminationReason: "completed",
|
|
@@ -3130,25 +3196,8 @@ async function* runWarpGrepStreaming(config) {
|
|
|
3130
3196
|
timings
|
|
3131
3197
|
};
|
|
3132
3198
|
}
|
|
3133
|
-
timings.turns.push(turnMetrics);
|
|
3134
3199
|
break;
|
|
3135
3200
|
}
|
|
3136
|
-
const toolExecStart = Date.now();
|
|
3137
|
-
const results = await Promise.all(
|
|
3138
|
-
toolCalls.map(async (tc) => {
|
|
3139
|
-
const args = safeParseJSON(tc.function.arguments);
|
|
3140
|
-
const output = await executeTool(provider, tc.function.name, args, repoRoot).catch((err) => String(err));
|
|
3141
|
-
return { tool_call_id: tc.id, content: output };
|
|
3142
|
-
})
|
|
3143
|
-
);
|
|
3144
|
-
turnMetrics.local_tools_ms = Date.now() - toolExecStart;
|
|
3145
|
-
for (const result of results) {
|
|
3146
|
-
messages.push({ role: "tool", tool_call_id: result.tool_call_id, content: result.content });
|
|
3147
|
-
}
|
|
3148
|
-
const turnMsg = formatTurnMessage(turn, maxTurns);
|
|
3149
|
-
const budget = calculateContextBudget(messages);
|
|
3150
|
-
messages.push({ role: "user", content: turnMsg + "\n" + budget });
|
|
3151
|
-
timings.turns.push(turnMetrics);
|
|
3152
3201
|
}
|
|
3153
3202
|
if (terminationReason !== "completed" || !finishMeta) {
|
|
3154
3203
|
timings.total_ms = Date.now() - totalStart;
|
|
@@ -3192,14 +3241,6 @@ async function* runWarpGrepStreaming(config) {
|
|
|
3192
3241
|
timings
|
|
3193
3242
|
};
|
|
3194
3243
|
}
|
|
3195
|
-
async function runWarpGrep(config) {
|
|
3196
|
-
const gen = runWarpGrepStreaming(config);
|
|
3197
|
-
let result = await gen.next();
|
|
3198
|
-
while (!result.done) {
|
|
3199
|
-
result = await gen.next();
|
|
3200
|
-
}
|
|
3201
|
-
return result.value;
|
|
3202
|
-
}
|
|
3203
3244
|
|
|
3204
3245
|
// tools/warp_grep/providers/remote.ts
|
|
3205
3246
|
init_config();
|
|
@@ -3379,35 +3420,6 @@ var RemoteCommandsProvider = class {
|
|
|
3379
3420
|
return [];
|
|
3380
3421
|
}
|
|
3381
3422
|
}
|
|
3382
|
-
/**
|
|
3383
|
-
* Glob search - finds files matching a pattern.
|
|
3384
|
-
* Falls back to a grep --files approach via the listDir command.
|
|
3385
|
-
*/
|
|
3386
|
-
async glob(params) {
|
|
3387
|
-
const searchPath = params.path || this.repoRoot;
|
|
3388
|
-
try {
|
|
3389
|
-
const stdout = await this.commands.listDir(searchPath, 10);
|
|
3390
|
-
const allPaths = (stdout || "").trim().split(/\r?\n/).filter((p) => p.length > 0);
|
|
3391
|
-
const globToRegex = (glob) => {
|
|
3392
|
-
const escaped = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
3393
|
-
return new RegExp(escaped);
|
|
3394
|
-
};
|
|
3395
|
-
const regex = globToRegex(params.pattern);
|
|
3396
|
-
const matched = allPaths.filter((p) => {
|
|
3397
|
-
const name = p.split("/").pop() || "";
|
|
3398
|
-
return regex.test(name) && !shouldSkip(name);
|
|
3399
|
-
});
|
|
3400
|
-
const totalFound = matched.length;
|
|
3401
|
-
return { files: matched.slice(0, 100), searchDir: searchPath, totalFound };
|
|
3402
|
-
} catch (error) {
|
|
3403
|
-
return {
|
|
3404
|
-
files: [],
|
|
3405
|
-
searchDir: searchPath,
|
|
3406
|
-
totalFound: 0,
|
|
3407
|
-
error: `[GLOB ERROR] ${error instanceof Error ? error.message : String(error)}`
|
|
3408
|
-
};
|
|
3409
|
-
}
|
|
3410
|
-
}
|
|
3411
3423
|
};
|
|
3412
3424
|
|
|
3413
3425
|
// tools/warp_grep/providers/code_storage_http.ts
|
|
@@ -3434,9 +3446,9 @@ function createCodeStorageHttpCommands(config) {
|
|
|
3434
3446
|
const { baseUrl, repoId, branch } = config;
|
|
3435
3447
|
const encodedRepoId = encodeURIComponent(repoId);
|
|
3436
3448
|
return {
|
|
3437
|
-
grep: (pattern,
|
|
3438
|
-
read: (
|
|
3439
|
-
listDir: (
|
|
3449
|
+
grep: (pattern, path5, glob) => post(`${baseUrl}/api/code-search/${encodedRepoId}/grep`, { pattern, path: path5, glob, branch }, "grep"),
|
|
3450
|
+
read: (path5, start, end) => post(`${baseUrl}/api/code-search/${encodedRepoId}/read`, { path: path5, start, end, branch }, "read"),
|
|
3451
|
+
listDir: (path5, maxDepth) => post(`${baseUrl}/api/code-search/${encodedRepoId}/list`, { path: path5, maxDepth, branch }, "list")
|
|
3440
3452
|
};
|
|
3441
3453
|
}
|
|
3442
3454
|
|
|
@@ -3819,10 +3831,10 @@ var GitHubClient = class {
|
|
|
3819
3831
|
/**
|
|
3820
3832
|
* Make an authenticated API request
|
|
3821
3833
|
*/
|
|
3822
|
-
async request(method,
|
|
3823
|
-
const url = `${this.baseUrl}${
|
|
3834
|
+
async request(method, path5, body) {
|
|
3835
|
+
const url = `${this.baseUrl}${path5}`;
|
|
3824
3836
|
if (this.debug) {
|
|
3825
|
-
console.log(`[GitHub SDK] ${method} ${
|
|
3837
|
+
console.log(`[GitHub SDK] ${method} ${path5}`, body || "");
|
|
3826
3838
|
}
|
|
3827
3839
|
const controller = new AbortController();
|
|
3828
3840
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|