@morphllm/morphsdk 0.2.144 → 0.2.145
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-YIETFYCL.js → chunk-4LWMPKSB.js} +71 -44
- package/dist/chunk-4LWMPKSB.js.map +1 -0
- package/dist/{chunk-HZOTLGJH.js → chunk-4Y2NM6JD.js} +42 -2
- package/dist/chunk-4Y2NM6JD.js.map +1 -0
- package/dist/{chunk-BVVINERL.js → chunk-5FCXLQJU.js} +2 -2
- package/dist/{chunk-CZ53BD6B.js → chunk-6CFKWZK3.js} +3 -3
- package/dist/{chunk-NF2QWJDY.js → chunk-B3AKP3RA.js} +31 -2
- package/dist/chunk-B3AKP3RA.js.map +1 -0
- package/dist/{chunk-RDISKUTQ.js → chunk-BAF33L6C.js} +2 -2
- package/dist/{chunk-IBYOMW76.js → chunk-BXRJYLRS.js} +2 -2
- package/dist/chunk-CMSHXALI.js +60 -0
- package/dist/chunk-CMSHXALI.js.map +1 -0
- package/dist/{chunk-A5BCEQSU.js → chunk-EPIOAODF.js} +2 -2
- package/dist/{chunk-XX22ZYNY.js → chunk-G23BI5CQ.js} +2 -2
- package/dist/{chunk-OHCUVHG6.js → chunk-GHPQYSSF.js} +2 -2
- package/dist/{chunk-GFVUXQEC.js → chunk-GXCWKYGU.js} +2 -2
- package/dist/{chunk-U7VQWPYU.js → chunk-GXM3G7Z4.js} +2 -2
- package/dist/{chunk-W72JUWQY.js → chunk-HBIW2XV2.js} +2 -2
- package/dist/{chunk-4YSNUXSF.js → chunk-HE7K2QNQ.js} +25 -25
- package/dist/{chunk-FIVYDIHX.js → chunk-HYRHI2UL.js} +1 -1
- package/dist/{chunk-DKODF3YG.js → chunk-I3J46TSB.js} +5 -4
- package/dist/chunk-I3J46TSB.js.map +1 -0
- package/dist/{chunk-Z5PGIDOK.js → chunk-IRWHN55G.js} +1 -1
- package/dist/{chunk-YS2HX2AS.js → chunk-JMUAQQJU.js} +3 -3
- package/dist/{chunk-BS3APHNI.js → chunk-JRBU4UNP.js} +2 -2
- package/dist/{chunk-ZCUQX5PA.js → chunk-KELRCMA6.js} +2 -2
- package/dist/{chunk-ZCUQX5PA.js.map → chunk-KELRCMA6.js.map} +1 -1
- package/dist/{chunk-PFAYHEUS.js → chunk-MRPASJBX.js} +2 -2
- package/dist/{chunk-UPU7DO2Y.js → chunk-MTJ3PR4M.js} +2 -2
- package/dist/{chunk-TX7VXDUV.js → chunk-N7TTZIBK.js} +2 -2
- package/dist/chunk-OPEQQGST.js +396 -0
- package/dist/chunk-OPEQQGST.js.map +1 -0
- package/dist/{chunk-KGGPSPYH.js → chunk-PX7ODEML.js} +2 -2
- package/dist/{chunk-DHT77R7E.js → chunk-RZXS4ADX.js} +2 -2
- package/dist/{chunk-HYHHHNJK.js → chunk-S54SPKX3.js} +2 -2
- package/dist/{chunk-F6HIFE6U.js → chunk-SUE4GYA2.js} +2 -2
- package/dist/{chunk-EOUG4EY4.js → chunk-VRV5UYTN.js} +2 -2
- package/dist/{chunk-H73WKT7O.js → chunk-XL7R3XN5.js} +2 -2
- package/dist/client.cjs +426 -438
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +28 -29
- package/dist/edge.cjs +1 -1
- package/dist/edge.cjs.map +1 -1
- package/dist/edge.js +4 -4
- package/dist/{finish-DBKuo8yj.d.ts → finish-Ddj1MPGt.d.ts} +1 -1
- package/dist/index.cjs +445 -438
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +35 -35
- 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 +422 -434
- package/dist/subagents/anthropic.cjs.map +1 -1
- package/dist/subagents/anthropic.js +8 -9
- package/dist/subagents/vercel.cjs +422 -434
- package/dist/subagents/vercel.cjs.map +1 -1
- package/dist/subagents/vercel.js +8 -9
- package/dist/tools/browser/anthropic.cjs +1 -1
- package/dist/tools/browser/anthropic.cjs.map +1 -1
- package/dist/tools/browser/anthropic.js +5 -5
- package/dist/tools/browser/core.cjs +1 -1
- package/dist/tools/browser/core.cjs.map +1 -1
- package/dist/tools/browser/core.js +4 -4
- package/dist/tools/browser/index.cjs +1 -1
- package/dist/tools/browser/index.cjs.map +1 -1
- package/dist/tools/browser/index.js +7 -7
- package/dist/tools/browser/openai.cjs +1 -1
- package/dist/tools/browser/openai.cjs.map +1 -1
- package/dist/tools/browser/openai.js +5 -5
- package/dist/tools/browser/profiles/core.cjs +1 -1
- package/dist/tools/browser/profiles/core.cjs.map +1 -1
- package/dist/tools/browser/profiles/core.js +3 -3
- package/dist/tools/browser/profiles/index.cjs +1 -1
- package/dist/tools/browser/profiles/index.cjs.map +1 -1
- package/dist/tools/browser/profiles/index.js +3 -3
- package/dist/tools/browser/vercel.cjs +1 -1
- package/dist/tools/browser/vercel.cjs.map +1 -1
- package/dist/tools/browser/vercel.js +5 -5
- package/dist/tools/codebase_search/anthropic.cjs +1 -1
- package/dist/tools/codebase_search/anthropic.cjs.map +1 -1
- package/dist/tools/codebase_search/anthropic.js +4 -4
- package/dist/tools/codebase_search/core.cjs +1 -1
- package/dist/tools/codebase_search/core.cjs.map +1 -1
- package/dist/tools/codebase_search/core.js +3 -3
- package/dist/tools/codebase_search/index.cjs +1 -1
- package/dist/tools/codebase_search/index.cjs.map +1 -1
- package/dist/tools/codebase_search/index.js +8 -8
- package/dist/tools/codebase_search/openai.cjs +1 -1
- package/dist/tools/codebase_search/openai.cjs.map +1 -1
- package/dist/tools/codebase_search/openai.js +4 -4
- package/dist/tools/codebase_search/vercel.cjs +1 -1
- package/dist/tools/codebase_search/vercel.cjs.map +1 -1
- package/dist/tools/codebase_search/vercel.js +4 -4
- package/dist/tools/fastapply/anthropic.cjs +1 -1
- package/dist/tools/fastapply/anthropic.cjs.map +1 -1
- package/dist/tools/fastapply/anthropic.js +4 -4
- package/dist/tools/fastapply/apply.cjs +1 -1
- package/dist/tools/fastapply/apply.cjs.map +1 -1
- package/dist/tools/fastapply/apply.js +2 -2
- package/dist/tools/fastapply/core.cjs +1 -1
- package/dist/tools/fastapply/core.cjs.map +1 -1
- package/dist/tools/fastapply/core.js +3 -3
- package/dist/tools/fastapply/index.cjs +1 -1
- package/dist/tools/fastapply/index.cjs.map +1 -1
- package/dist/tools/fastapply/index.js +6 -6
- package/dist/tools/fastapply/openai.cjs +1 -1
- package/dist/tools/fastapply/openai.cjs.map +1 -1
- package/dist/tools/fastapply/openai.js +4 -4
- package/dist/tools/fastapply/vercel.cjs +1 -1
- package/dist/tools/fastapply/vercel.cjs.map +1 -1
- package/dist/tools/fastapply/vercel.js +4 -4
- package/dist/tools/index.cjs +1 -1
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.js +6 -6
- package/dist/tools/utils/resilience.cjs +1 -1
- package/dist/tools/utils/resilience.cjs.map +1 -1
- package/dist/tools/utils/resilience.js +2 -2
- package/dist/tools/warp_grep/agent/config.cjs +4 -3
- package/dist/tools/warp_grep/agent/config.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/config.d.ts +2 -1
- package/dist/tools/warp_grep/agent/config.js +1 -1
- package/dist/tools/warp_grep/agent/parser.cjs +52 -121
- package/dist/tools/warp_grep/agent/parser.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/parser.d.ts +12 -5
- package/dist/tools/warp_grep/agent/parser.js +7 -3
- package/dist/tools/warp_grep/agent/runner.cjs +335 -416
- package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/runner.d.ts +6 -3
- package/dist/tools/warp_grep/agent/runner.js +5 -6
- package/dist/tools/warp_grep/agent/types.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/types.d.ts +22 -3
- package/dist/tools/warp_grep/anthropic.cjs +422 -434
- package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
- package/dist/tools/warp_grep/anthropic.js +8 -9
- package/dist/tools/warp_grep/client.cjs +422 -434
- package/dist/tools/warp_grep/client.cjs.map +1 -1
- package/dist/tools/warp_grep/client.js +7 -8
- package/dist/tools/warp_grep/gemini.cjs +422 -434
- package/dist/tools/warp_grep/gemini.cjs.map +1 -1
- package/dist/tools/warp_grep/gemini.js +7 -8
- package/dist/tools/warp_grep/gemini.js.map +1 -1
- package/dist/tools/warp_grep/harness.cjs +164 -176
- package/dist/tools/warp_grep/harness.cjs.map +1 -1
- package/dist/tools/warp_grep/harness.d.ts +17 -38
- package/dist/tools/warp_grep/harness.js +15 -14
- package/dist/tools/warp_grep/harness.js.map +1 -1
- package/dist/tools/warp_grep/index.cjs +441 -434
- 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 +422 -434
- package/dist/tools/warp_grep/openai.cjs.map +1 -1
- package/dist/tools/warp_grep/openai.js +8 -9
- package/dist/tools/warp_grep/providers/local.cjs +43 -2
- package/dist/tools/warp_grep/providers/local.cjs.map +1 -1
- package/dist/tools/warp_grep/providers/local.d.ts +5 -1
- package/dist/tools/warp_grep/providers/local.js +2 -2
- package/dist/tools/warp_grep/providers/remote.cjs +32 -2
- package/dist/tools/warp_grep/providers/remote.cjs.map +1 -1
- package/dist/tools/warp_grep/providers/remote.d.ts +9 -1
- package/dist/tools/warp_grep/providers/remote.js +2 -2
- package/dist/tools/warp_grep/providers/types.cjs.map +1 -1
- package/dist/tools/warp_grep/providers/types.d.ts +14 -1
- package/dist/tools/warp_grep/vercel.cjs +422 -434
- package/dist/tools/warp_grep/vercel.cjs.map +1 -1
- package/dist/tools/warp_grep/vercel.js +8 -9
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-DKODF3YG.js.map +0 -1
- package/dist/chunk-GNROKGNS.js +0 -409
- package/dist/chunk-GNROKGNS.js.map +0 -1
- package/dist/chunk-HZOTLGJH.js.map +0 -1
- package/dist/chunk-NF2QWJDY.js.map +0 -1
- package/dist/chunk-VCKJ22DX.js +0 -131
- package/dist/chunk-VCKJ22DX.js.map +0 -1
- package/dist/chunk-YIETFYCL.js.map +0 -1
- /package/dist/{chunk-BVVINERL.js.map → chunk-5FCXLQJU.js.map} +0 -0
- /package/dist/{chunk-CZ53BD6B.js.map → chunk-6CFKWZK3.js.map} +0 -0
- /package/dist/{chunk-RDISKUTQ.js.map → chunk-BAF33L6C.js.map} +0 -0
- /package/dist/{chunk-IBYOMW76.js.map → chunk-BXRJYLRS.js.map} +0 -0
- /package/dist/{chunk-A5BCEQSU.js.map → chunk-EPIOAODF.js.map} +0 -0
- /package/dist/{chunk-XX22ZYNY.js.map → chunk-G23BI5CQ.js.map} +0 -0
- /package/dist/{chunk-OHCUVHG6.js.map → chunk-GHPQYSSF.js.map} +0 -0
- /package/dist/{chunk-GFVUXQEC.js.map → chunk-GXCWKYGU.js.map} +0 -0
- /package/dist/{chunk-U7VQWPYU.js.map → chunk-GXM3G7Z4.js.map} +0 -0
- /package/dist/{chunk-W72JUWQY.js.map → chunk-HBIW2XV2.js.map} +0 -0
- /package/dist/{chunk-4YSNUXSF.js.map → chunk-HE7K2QNQ.js.map} +0 -0
- /package/dist/{chunk-FIVYDIHX.js.map → chunk-HYRHI2UL.js.map} +0 -0
- /package/dist/{chunk-Z5PGIDOK.js.map → chunk-IRWHN55G.js.map} +0 -0
- /package/dist/{chunk-YS2HX2AS.js.map → chunk-JMUAQQJU.js.map} +0 -0
- /package/dist/{chunk-BS3APHNI.js.map → chunk-JRBU4UNP.js.map} +0 -0
- /package/dist/{chunk-PFAYHEUS.js.map → chunk-MRPASJBX.js.map} +0 -0
- /package/dist/{chunk-UPU7DO2Y.js.map → chunk-MTJ3PR4M.js.map} +0 -0
- /package/dist/{chunk-TX7VXDUV.js.map → chunk-N7TTZIBK.js.map} +0 -0
- /package/dist/{chunk-KGGPSPYH.js.map → chunk-PX7ODEML.js.map} +0 -0
- /package/dist/{chunk-DHT77R7E.js.map → chunk-RZXS4ADX.js.map} +0 -0
- /package/dist/{chunk-HYHHHNJK.js.map → chunk-S54SPKX3.js.map} +0 -0
- /package/dist/{chunk-F6HIFE6U.js.map → chunk-SUE4GYA2.js.map} +0 -0
- /package/dist/{chunk-EOUG4EY4.js.map → chunk-VRV5UYTN.js.map} +0 -0
- /package/dist/{chunk-H73WKT7O.js.map → chunk-XL7R3XN5.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.145",
|
|
40
40
|
description: "TypeScript SDK and CLI for Morph Fast Apply integration",
|
|
41
41
|
type: "module",
|
|
42
42
|
main: "./dist/index.cjs",
|
|
@@ -416,11 +416,12 @@ 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: 6,
|
|
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: 321600,
|
|
423
423
|
MAX_OUTPUT_LINES: 200,
|
|
424
|
+
MAX_LIST_RESULTS: 500,
|
|
424
425
|
MAX_READ_LINES: 800,
|
|
425
426
|
MAX_LIST_DEPTH: 3,
|
|
426
427
|
LIST_TIMEOUT_MS: 2e3
|
|
@@ -505,7 +506,7 @@ var init_config = __esm({
|
|
|
505
506
|
".*"
|
|
506
507
|
];
|
|
507
508
|
DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || "").split(",").map((s) => s.trim()).filter(Boolean).concat(BUILTIN_EXCLUDES);
|
|
508
|
-
DEFAULT_MODEL = "morph-warp-grep-v2";
|
|
509
|
+
DEFAULT_MODEL = "morph-warp-grep-v2.1";
|
|
509
510
|
}
|
|
510
511
|
});
|
|
511
512
|
|
|
@@ -578,19 +579,19 @@ var init_ripgrep = __esm({
|
|
|
578
579
|
|
|
579
580
|
// tools/warp_grep/utils/paths.ts
|
|
580
581
|
function resolveUnderRepo(repoRoot, targetPath) {
|
|
581
|
-
const absRoot =
|
|
582
|
-
const resolved =
|
|
582
|
+
const absRoot = import_path5.default.resolve(repoRoot);
|
|
583
|
+
const resolved = import_path5.default.resolve(absRoot, targetPath);
|
|
583
584
|
ensureWithinRepo(absRoot, resolved);
|
|
584
585
|
return resolved;
|
|
585
586
|
}
|
|
586
587
|
function ensureWithinRepo(repoRoot, absTarget) {
|
|
587
|
-
const rel =
|
|
588
|
-
if (rel.startsWith("..") ||
|
|
588
|
+
const rel = import_path5.default.relative(import_path5.default.resolve(repoRoot), import_path5.default.resolve(absTarget));
|
|
589
|
+
if (rel.startsWith("..") || import_path5.default.isAbsolute(rel)) {
|
|
589
590
|
throw new Error(`Path outside repository root: ${absTarget}`);
|
|
590
591
|
}
|
|
591
592
|
}
|
|
592
593
|
function toRepoRelative(repoRoot, absPath) {
|
|
593
|
-
return
|
|
594
|
+
return import_path5.default.relative(import_path5.default.resolve(repoRoot), import_path5.default.resolve(absPath));
|
|
594
595
|
}
|
|
595
596
|
function isSymlink(p) {
|
|
596
597
|
try {
|
|
@@ -601,7 +602,7 @@ function isSymlink(p) {
|
|
|
601
602
|
}
|
|
602
603
|
}
|
|
603
604
|
function fixPathRepetition(fullPath) {
|
|
604
|
-
const segments = fullPath.split(
|
|
605
|
+
const segments = fullPath.split(import_path5.default.sep).filter(Boolean);
|
|
605
606
|
if (segments.length < 2) return null;
|
|
606
607
|
for (let len = Math.floor(segments.length / 2); len >= 1; len--) {
|
|
607
608
|
for (let i = 0; i <= segments.length - 2 * len; i++) {
|
|
@@ -609,7 +610,7 @@ function fixPathRepetition(fullPath) {
|
|
|
609
610
|
const second = segments.slice(i + len, i + 2 * len);
|
|
610
611
|
if (first.every((seg, idx) => seg === second[idx])) {
|
|
611
612
|
const fixed = [...segments.slice(0, i), ...segments.slice(i + len)];
|
|
612
|
-
return
|
|
613
|
+
return import_path5.default.sep + fixed.join(import_path5.default.sep);
|
|
613
614
|
}
|
|
614
615
|
}
|
|
615
616
|
}
|
|
@@ -633,12 +634,12 @@ function isTextualFile(filePath, maxBytes = 2e6) {
|
|
|
633
634
|
return false;
|
|
634
635
|
}
|
|
635
636
|
}
|
|
636
|
-
var import_fs,
|
|
637
|
+
var import_fs, import_path5;
|
|
637
638
|
var init_paths = __esm({
|
|
638
639
|
"tools/warp_grep/utils/paths.ts"() {
|
|
639
640
|
"use strict";
|
|
640
641
|
import_fs = __toESM(require("fs"), 1);
|
|
641
|
-
|
|
642
|
+
import_path5 = __toESM(require("path"), 1);
|
|
642
643
|
}
|
|
643
644
|
});
|
|
644
645
|
|
|
@@ -669,12 +670,12 @@ function shouldSkip2(name, allowNames) {
|
|
|
669
670
|
}
|
|
670
671
|
return false;
|
|
671
672
|
}
|
|
672
|
-
var import_promises2,
|
|
673
|
+
var import_promises2, import_path6, SKIP_NAMES2, SKIP_EXTENSIONS2, LocalRipgrepProvider;
|
|
673
674
|
var init_local = __esm({
|
|
674
675
|
"tools/warp_grep/providers/local.ts"() {
|
|
675
676
|
"use strict";
|
|
676
677
|
import_promises2 = __toESM(require("fs/promises"), 1);
|
|
677
|
-
|
|
678
|
+
import_path6 = __toESM(require("path"), 1);
|
|
678
679
|
init_ripgrep();
|
|
679
680
|
init_paths();
|
|
680
681
|
init_files();
|
|
@@ -776,7 +777,7 @@ var init_local = __esm({
|
|
|
776
777
|
}
|
|
777
778
|
const stat = await import_promises2.default.stat(abs).catch(() => null);
|
|
778
779
|
if (!stat) return { lines: [] };
|
|
779
|
-
const targetArg = abs ===
|
|
780
|
+
const targetArg = abs === import_path6.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
|
|
780
781
|
const contextLines = params.context_lines !== void 0 ? String(params.context_lines) : "1";
|
|
781
782
|
const args = [
|
|
782
783
|
"--no-config",
|
|
@@ -931,7 +932,7 @@ Details: ${res.stderr}` : ""}`
|
|
|
931
932
|
if (timedOut || results.length >= maxResults) break;
|
|
932
933
|
if (shouldSkip2(entry.name, allowNames)) continue;
|
|
933
934
|
if (regex && !regex.test(entry.name)) continue;
|
|
934
|
-
const full =
|
|
935
|
+
const full = import_path6.default.join(dir, entry.name);
|
|
935
936
|
const isDir = entry.isDirectory();
|
|
936
937
|
results.push({
|
|
937
938
|
name: entry.name,
|
|
@@ -947,6 +948,46 @@ Details: ${res.stderr}` : ""}`
|
|
|
947
948
|
await walk(abs, 0);
|
|
948
949
|
return results;
|
|
949
950
|
}
|
|
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
|
+
}
|
|
950
991
|
};
|
|
951
992
|
}
|
|
952
993
|
});
|
|
@@ -2515,131 +2556,58 @@ async function checkHealth(config = {}) {
|
|
|
2515
2556
|
init_config();
|
|
2516
2557
|
|
|
2517
2558
|
// tools/warp_grep/agent/parser.ts
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2559
|
+
function parseReadLines(linesStr) {
|
|
2560
|
+
const ranges = [];
|
|
2561
|
+
for (const rangeStr of linesStr.split(",")) {
|
|
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 {};
|
|
2521
2574
|
}
|
|
2522
|
-
function
|
|
2523
|
-
const
|
|
2524
|
-
const
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
const
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
}
|
|
2546
|
-
|
|
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 } });
|
|
2575
|
+
function parseFinishFiles(filesStr) {
|
|
2576
|
+
const files = [];
|
|
2577
|
+
for (const line of filesStr.trim().split(/\s+/)) {
|
|
2578
|
+
const trimmed = line.trim();
|
|
2579
|
+
if (!trimmed) continue;
|
|
2580
|
+
const colonIdx = trimmed.indexOf(":");
|
|
2581
|
+
if (colonIdx === -1) {
|
|
2582
|
+
files.push({ path: trimmed, lines: "*" });
|
|
2583
|
+
continue;
|
|
2584
|
+
}
|
|
2585
|
+
const filePath = trimmed.slice(0, colonIdx);
|
|
2586
|
+
const rangesPart = trimmed.slice(colonIdx + 1);
|
|
2587
|
+
if (!rangesPart.trim() || rangesPart.trim() === "*") {
|
|
2588
|
+
files.push({ path: filePath, lines: "*" });
|
|
2589
|
+
continue;
|
|
2590
|
+
}
|
|
2591
|
+
const ranges = [];
|
|
2592
|
+
for (const rangeStr of rangesPart.split(",")) {
|
|
2593
|
+
const rt = rangeStr.trim();
|
|
2594
|
+
if (!rt) continue;
|
|
2595
|
+
const parts = rt.split("-").map((v) => parseInt(v.trim(), 10));
|
|
2596
|
+
if (parts.length >= 2 && Number.isFinite(parts[0]) && Number.isFinite(parts[1])) {
|
|
2597
|
+
ranges.push([parts[0], parts[1]]);
|
|
2598
|
+
} else if (Number.isFinite(parts[0])) {
|
|
2599
|
+
ranges.push([parts[0], parts[0]]);
|
|
2629
2600
|
}
|
|
2630
2601
|
}
|
|
2602
|
+
files.push({ path: filePath, lines: ranges.length > 0 ? ranges : "*" });
|
|
2631
2603
|
}
|
|
2632
|
-
return
|
|
2604
|
+
return files;
|
|
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] || ".";
|
|
2633
2610
|
}
|
|
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
|
-
};
|
|
2643
2611
|
|
|
2644
2612
|
// tools/warp_grep/agent/tools/grep.ts
|
|
2645
2613
|
async function toolGrep(provider, args) {
|
|
@@ -2690,29 +2658,42 @@ async function toolRead(provider, args) {
|
|
|
2690
2658
|
|
|
2691
2659
|
// tools/warp_grep/agent/tools/list_directory.ts
|
|
2692
2660
|
init_config();
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
const
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2661
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
2662
|
+
async function toolListDirectory(provider, args, repoRoot) {
|
|
2663
|
+
const maxResults = args.maxResults ?? AGENT_CONFIG.MAX_LIST_RESULTS;
|
|
2664
|
+
const maxDepth = args.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
|
|
2665
|
+
const entries = await provider.listDirectory({
|
|
2666
|
+
path: args.path,
|
|
2667
|
+
pattern: args.pattern ?? null,
|
|
2668
|
+
maxResults,
|
|
2669
|
+
maxDepth
|
|
2670
|
+
});
|
|
2671
|
+
if (!entries.length) return "empty";
|
|
2672
|
+
if (repoRoot) {
|
|
2673
|
+
const absRoot = import_path2.default.resolve(repoRoot);
|
|
2674
|
+
const lines = entries.map((e) => import_path2.default.join(absRoot, e.path));
|
|
2675
|
+
return lines.join("\n");
|
|
2676
|
+
}
|
|
2677
|
+
return entries.map((e) => e.path).join("\n");
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
// tools/warp_grep/agent/tools/glob.ts
|
|
2681
|
+
async function toolGlob(provider, args) {
|
|
2682
|
+
const res = await provider.glob(args);
|
|
2683
|
+
if (res.error) {
|
|
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}`;
|
|
2716
2697
|
}
|
|
2717
2698
|
|
|
2718
2699
|
// tools/warp_grep/agent/tools/finish.ts
|
|
@@ -2773,32 +2754,21 @@ function mergeRanges(ranges) {
|
|
|
2773
2754
|
return merged;
|
|
2774
2755
|
}
|
|
2775
2756
|
|
|
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 "";
|
|
2787
|
-
}
|
|
2788
|
-
return `<tool_response>
|
|
2789
|
-
${payload}
|
|
2790
|
-
</tool_response>`;
|
|
2791
|
-
}
|
|
2792
|
-
};
|
|
2793
|
-
var sharedFormatter = new ToolOutputFormatter();
|
|
2794
|
-
function formatAgentToolOutput(toolName, args, output, options = {}) {
|
|
2795
|
-
return sharedFormatter.format(toolName, args, output, options);
|
|
2796
|
-
}
|
|
2797
|
-
|
|
2798
2757
|
// tools/warp_grep/agent/helpers.ts
|
|
2799
|
-
var
|
|
2758
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
2800
2759
|
init_config();
|
|
2801
2760
|
var TRUNCATED_MARKER = "[truncated for context limit]";
|
|
2761
|
+
function getMessageSize(m) {
|
|
2762
|
+
if (m.role === "tool") return m.content.length;
|
|
2763
|
+
if (m.role === "assistant") {
|
|
2764
|
+
let size = typeof m.content === "string" ? m.content.length : 0;
|
|
2765
|
+
if (m.tool_calls) {
|
|
2766
|
+
size += m.tool_calls.reduce((s, tc) => s + tc.function.name.length + tc.function.arguments.length, 0);
|
|
2767
|
+
}
|
|
2768
|
+
return size;
|
|
2769
|
+
}
|
|
2770
|
+
return m.content.length;
|
|
2771
|
+
}
|
|
2802
2772
|
function formatTurnMessage(turnsUsed, maxTurns) {
|
|
2803
2773
|
const turnsRemaining = maxTurns - turnsUsed;
|
|
2804
2774
|
if (turnsRemaining === 1) {
|
|
@@ -2809,7 +2779,7 @@ You have used ${turnsUsed} turns, you only have 1 turn remaining. You have run o
|
|
|
2809
2779
|
You have used ${turnsUsed} turn${turnsUsed === 1 ? "" : "s"} and have ${turnsRemaining} remaining`;
|
|
2810
2780
|
}
|
|
2811
2781
|
function calculateContextBudget(messages) {
|
|
2812
|
-
const totalChars = messages.reduce((sum, m) => sum + m
|
|
2782
|
+
const totalChars = messages.reduce((sum, m) => sum + getMessageSize(m), 0);
|
|
2813
2783
|
const maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS;
|
|
2814
2784
|
const percent = Math.round(totalChars / maxChars * 100);
|
|
2815
2785
|
const usedK = Math.round(totalChars / 1e3);
|
|
@@ -2818,24 +2788,21 @@ function calculateContextBudget(messages) {
|
|
|
2818
2788
|
}
|
|
2819
2789
|
async function buildInitialState(repoRoot, searchTerm, provider, options) {
|
|
2820
2790
|
const budget = calculateContextBudget([]);
|
|
2821
|
-
const turnTag = `
|
|
2791
|
+
const turnTag = `You have used 0 turns and have ${AGENT_CONFIG.MAX_TURNS} remaining`;
|
|
2822
2792
|
const treeDepth = options?.search_type === "node_modules" ? 1 : 2;
|
|
2793
|
+
const absRoot = import_path3.default.resolve(repoRoot);
|
|
2823
2794
|
try {
|
|
2824
2795
|
const entries = await provider.listDirectory({
|
|
2825
2796
|
path: ".",
|
|
2826
2797
|
maxResults: AGENT_CONFIG.MAX_OUTPUT_LINES,
|
|
2827
2798
|
maxDepth: treeDepth
|
|
2828
2799
|
});
|
|
2829
|
-
const
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
});
|
|
2834
|
-
const repoName = import_path2.default.basename(repoRoot);
|
|
2835
|
-
const treeOutput = treeLines.length > 0 ? `${repoName}/
|
|
2836
|
-
${treeLines.join("\n")}` : `${repoName}/`;
|
|
2800
|
+
const lines = [absRoot];
|
|
2801
|
+
for (const e of entries) {
|
|
2802
|
+
lines.push(import_path3.default.join(absRoot, e.path));
|
|
2803
|
+
}
|
|
2837
2804
|
return `<repo_structure>
|
|
2838
|
-
${
|
|
2805
|
+
${lines.join("\n")}
|
|
2839
2806
|
</repo_structure>
|
|
2840
2807
|
|
|
2841
2808
|
<search_string>
|
|
@@ -2844,9 +2811,8 @@ ${searchTerm}
|
|
|
2844
2811
|
${budget}
|
|
2845
2812
|
${turnTag}`;
|
|
2846
2813
|
} catch {
|
|
2847
|
-
const repoName = import_path2.default.basename(repoRoot);
|
|
2848
2814
|
return `<repo_structure>
|
|
2849
|
-
${
|
|
2815
|
+
${absRoot}
|
|
2850
2816
|
</repo_structure>
|
|
2851
2817
|
|
|
2852
2818
|
<search_string>
|
|
@@ -2857,26 +2823,32 @@ ${turnTag}`;
|
|
|
2857
2823
|
}
|
|
2858
2824
|
}
|
|
2859
2825
|
function enforceContextLimit(messages, maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS) {
|
|
2860
|
-
const getTotalChars = () => messages.reduce((sum, m) => sum + m
|
|
2826
|
+
const getTotalChars = () => messages.reduce((sum, m) => sum + getMessageSize(m), 0);
|
|
2861
2827
|
if (getTotalChars() <= maxChars) {
|
|
2862
2828
|
return messages;
|
|
2863
2829
|
}
|
|
2864
|
-
const
|
|
2830
|
+
const truncatableIndices = [];
|
|
2865
2831
|
let firstUserSkipped = false;
|
|
2866
2832
|
for (let i = 0; i < messages.length; i++) {
|
|
2867
|
-
|
|
2833
|
+
const m = messages[i];
|
|
2834
|
+
if (m.role === "tool") {
|
|
2835
|
+
truncatableIndices.push(i);
|
|
2836
|
+
} else if (m.role === "user") {
|
|
2868
2837
|
if (!firstUserSkipped) {
|
|
2869
2838
|
firstUserSkipped = true;
|
|
2870
2839
|
continue;
|
|
2871
2840
|
}
|
|
2872
|
-
|
|
2841
|
+
truncatableIndices.push(i);
|
|
2873
2842
|
}
|
|
2874
2843
|
}
|
|
2875
|
-
for (const idx of
|
|
2844
|
+
for (const idx of truncatableIndices) {
|
|
2876
2845
|
if (getTotalChars() <= maxChars) {
|
|
2877
2846
|
break;
|
|
2878
2847
|
}
|
|
2879
|
-
|
|
2848
|
+
const m = messages[idx];
|
|
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) {
|
|
2880
2852
|
messages[idx] = { role: "user", content: TRUNCATED_MARKER };
|
|
2881
2853
|
}
|
|
2882
2854
|
}
|
|
@@ -2886,9 +2858,115 @@ function enforceContextLimit(messages, maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS
|
|
|
2886
2858
|
// tools/warp_grep/agent/runner.ts
|
|
2887
2859
|
var import_openai2 = __toESM(require("openai"), 1);
|
|
2888
2860
|
init_version();
|
|
2889
|
-
var
|
|
2890
|
-
var parser = new LLMResponseParser();
|
|
2861
|
+
var import_path4 = __toESM(require("path"), 1);
|
|
2891
2862
|
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
|
+
];
|
|
2892
2970
|
async function callModel(messages, model, options = {}) {
|
|
2893
2971
|
const baseUrl = options.morphApiUrl || DEFAULT_API_URL3;
|
|
2894
2972
|
const apiKey = options.morphApiKey || process.env.MORPH_API_KEY || "";
|
|
@@ -2909,8 +2987,9 @@ async function callModel(messages, model, options = {}) {
|
|
|
2909
2987
|
data = await client.chat.completions.create({
|
|
2910
2988
|
model,
|
|
2911
2989
|
temperature: 0,
|
|
2912
|
-
max_tokens:
|
|
2990
|
+
max_tokens: 2048,
|
|
2913
2991
|
messages,
|
|
2992
|
+
tools: TOOL_SPECS,
|
|
2914
2993
|
...options.search_type ? { search_type: options.search_type } : {}
|
|
2915
2994
|
});
|
|
2916
2995
|
} catch (error) {
|
|
@@ -2922,187 +3001,87 @@ async function callModel(messages, model, options = {}) {
|
|
|
2922
3001
|
throw error;
|
|
2923
3002
|
}
|
|
2924
3003
|
const choice = data?.choices?.[0];
|
|
2925
|
-
const
|
|
2926
|
-
if (
|
|
2927
|
-
|
|
3004
|
+
const message = choice?.message;
|
|
3005
|
+
if (!message) {
|
|
3006
|
+
if (attempt === MAX_EMPTY_RETRIES) {
|
|
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 };
|
|
2928
3019
|
}
|
|
2929
3020
|
if (attempt === MAX_EMPTY_RETRIES) {
|
|
2930
3021
|
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;
|
|
2934
3022
|
throw new Error(
|
|
2935
|
-
`Invalid response from model: content
|
|
3023
|
+
`Invalid response from model: no content and no tool_calls, finish_reason=${finishReason}`
|
|
2936
3024
|
);
|
|
2937
3025
|
}
|
|
2938
3026
|
await new Promise((resolve2) => setTimeout(resolve2, 200));
|
|
2939
3027
|
}
|
|
2940
3028
|
throw new Error("Invalid response from model");
|
|
2941
3029
|
}
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
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;
|
|
2979
|
-
}
|
|
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;
|
|
2988
|
-
}
|
|
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
|
-
);
|
|
3008
|
-
}
|
|
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);
|
|
3030
|
+
function safeParseJSON(s) {
|
|
3031
|
+
try {
|
|
3032
|
+
return JSON.parse(s);
|
|
3033
|
+
} catch {
|
|
3034
|
+
return {};
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
async function executeTool(provider, name, args, repoRoot) {
|
|
3038
|
+
switch (name) {
|
|
3039
|
+
case "grep_search": {
|
|
3040
|
+
const grepArgs = {
|
|
3041
|
+
pattern: args.pattern,
|
|
3042
|
+
path: args.path || "."
|
|
3043
|
+
};
|
|
3044
|
+
if (args.glob) grepArgs.glob = args.glob;
|
|
3045
|
+
if (args.case_sensitive !== void 0) grepArgs.case_sensitive = args.case_sensitive;
|
|
3046
|
+
const result = await toolGrep(provider, grepArgs);
|
|
3047
|
+
let output = result.output;
|
|
3048
|
+
if (args.limit && typeof args.limit === "number") {
|
|
3049
|
+
const lines = output.split("\n");
|
|
3050
|
+
if (lines.length > args.limit) {
|
|
3051
|
+
output = lines.slice(0, args.limit).join("\n") + `
|
|
3052
|
+
... (truncated at ${args.limit} lines)`;
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
return output;
|
|
3032
3056
|
}
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3057
|
+
case "glob": {
|
|
3058
|
+
return toolGlob(provider, {
|
|
3059
|
+
pattern: args.pattern,
|
|
3060
|
+
path: args.path
|
|
3061
|
+
});
|
|
3037
3062
|
}
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
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
|
-
};
|
|
3055
|
-
}
|
|
3056
|
-
break;
|
|
3063
|
+
case "list_directory": {
|
|
3064
|
+
const dirPath = extractPathFromCommand(args.command || ".");
|
|
3065
|
+
return toolListDirectory(provider, { path: dirPath }, repoRoot);
|
|
3057
3066
|
}
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
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}]`];
|
|
3067
|
+
case "read": {
|
|
3068
|
+
const readArgs = {
|
|
3069
|
+
path: args.path
|
|
3070
|
+
};
|
|
3071
|
+
if (args.lines && typeof args.lines === "string") {
|
|
3072
|
+
Object.assign(readArgs, parseReadLines(args.lines));
|
|
3086
3073
|
}
|
|
3074
|
+
return toolRead(provider, readArgs);
|
|
3087
3075
|
}
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
if (fileReadErrors.length > 0) {
|
|
3091
|
-
errors.push(...fileReadErrors.map((e) => ({ message: `File read error: ${e.path} - ${e.error}` })));
|
|
3076
|
+
default:
|
|
3077
|
+
return `Unknown tool: ${name}`;
|
|
3092
3078
|
}
|
|
3093
|
-
timings.total_ms = Date.now() - totalStart;
|
|
3094
|
-
return {
|
|
3095
|
-
terminationReason: "completed",
|
|
3096
|
-
messages,
|
|
3097
|
-
finish: { payload, metadata: finishMeta, resolved },
|
|
3098
|
-
timings
|
|
3099
|
-
};
|
|
3100
3079
|
}
|
|
3101
3080
|
async function* runWarpGrepStreaming(config) {
|
|
3102
3081
|
const totalStart = Date.now();
|
|
3103
3082
|
const timeoutMs = config.timeout ?? AGENT_CONFIG.TIMEOUT_MS;
|
|
3104
3083
|
const timings = { turns: [], timeout_ms: timeoutMs };
|
|
3105
|
-
const repoRoot =
|
|
3084
|
+
const repoRoot = import_path4.default.resolve(config.repoRoot || process.cwd());
|
|
3106
3085
|
const model = config.model || DEFAULT_MODEL;
|
|
3107
3086
|
const messages = [];
|
|
3108
3087
|
const maxTurns = AGENT_CONFIG.MAX_TURNS;
|
|
@@ -3118,7 +3097,7 @@ async function* runWarpGrepStreaming(config) {
|
|
|
3118
3097
|
const turnMetrics = { turn, morph_api_ms: 0, local_tools_ms: 0 };
|
|
3119
3098
|
enforceContextLimit(messages);
|
|
3120
3099
|
const modelCallStart = Date.now();
|
|
3121
|
-
const
|
|
3100
|
+
const response = await callModel(messages, model, {
|
|
3122
3101
|
morphApiKey: config.morphApiKey,
|
|
3123
3102
|
morphApiUrl: config.morphApiUrl,
|
|
3124
3103
|
retryConfig: config.retryConfig,
|
|
@@ -3126,90 +3105,45 @@ async function* runWarpGrepStreaming(config) {
|
|
|
3126
3105
|
search_type: config.search_type
|
|
3127
3106
|
}).catch((e) => {
|
|
3128
3107
|
const errMsg = e instanceof Error ? e.message : String(e);
|
|
3129
|
-
console.error(`[warp_grep
|
|
3108
|
+
console.error(`[warp_grep] Morph API call failed on turn ${turn}:`, errMsg);
|
|
3130
3109
|
errors.push({ message: errMsg });
|
|
3131
|
-
return
|
|
3110
|
+
return null;
|
|
3132
3111
|
});
|
|
3133
3112
|
turnMetrics.morph_api_ms = Date.now() - modelCallStart;
|
|
3134
|
-
if (!
|
|
3135
|
-
console.error(`[warp_grep:stream] Empty response from Morph API on turn ${turn}. Errors so far:`, errors);
|
|
3113
|
+
if (!response) {
|
|
3136
3114
|
timings.turns.push(turnMetrics);
|
|
3137
3115
|
break;
|
|
3138
3116
|
}
|
|
3139
|
-
|
|
3140
|
-
|
|
3117
|
+
const toolCalls = response.tool_calls;
|
|
3118
|
+
messages.push({
|
|
3119
|
+
role: "assistant",
|
|
3120
|
+
content: response.content,
|
|
3121
|
+
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
|
|
3122
|
+
});
|
|
3141
3123
|
if (toolCalls.length === 0) {
|
|
3142
|
-
console.error(`[warp_grep
|
|
3143
|
-
errors.push({ message: "No tool calls produced by the model.
|
|
3124
|
+
console.error(`[warp_grep] No tool calls on turn ${turn}. Content: ${(response.content || "").slice(0, 500)}`);
|
|
3125
|
+
errors.push({ message: "No tool calls produced by the model." });
|
|
3144
3126
|
terminationReason = "terminated";
|
|
3145
3127
|
timings.turns.push(turnMetrics);
|
|
3146
3128
|
break;
|
|
3147
3129
|
}
|
|
3148
3130
|
yield {
|
|
3149
3131
|
turn,
|
|
3150
|
-
toolCalls: toolCalls.map((
|
|
3151
|
-
name:
|
|
3152
|
-
arguments:
|
|
3132
|
+
toolCalls: toolCalls.map((tc) => ({
|
|
3133
|
+
name: tc.function.name,
|
|
3134
|
+
arguments: safeParseJSON(tc.function.arguments)
|
|
3153
3135
|
}))
|
|
3154
3136
|
};
|
|
3155
|
-
const
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
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;
|
|
3137
|
+
const finishCall = toolCalls.find((tc) => tc.function.name === "finish");
|
|
3138
|
+
if (finishCall) {
|
|
3139
|
+
const args = safeParseJSON(finishCall.function.arguments);
|
|
3140
|
+
const filesStr = args.files || "";
|
|
3141
|
+
const files = parseFinishFiles(filesStr);
|
|
3209
3142
|
finishMeta = { files };
|
|
3210
3143
|
terminationReason = "completed";
|
|
3211
3144
|
if (files.length === 0) {
|
|
3212
|
-
const payload2 =
|
|
3145
|
+
const payload2 = filesStr || "No relevant code found.";
|
|
3146
|
+
timings.turns.push(turnMetrics);
|
|
3213
3147
|
timings.total_ms = Date.now() - totalStart;
|
|
3214
3148
|
return {
|
|
3215
3149
|
terminationReason: "completed",
|
|
@@ -3218,8 +3152,25 @@ async function* runWarpGrepStreaming(config) {
|
|
|
3218
3152
|
timings
|
|
3219
3153
|
};
|
|
3220
3154
|
}
|
|
3155
|
+
timings.turns.push(turnMetrics);
|
|
3221
3156
|
break;
|
|
3222
3157
|
}
|
|
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);
|
|
3223
3174
|
}
|
|
3224
3175
|
if (terminationReason !== "completed" || !finishMeta) {
|
|
3225
3176
|
timings.total_ms = Date.now() - totalStart;
|
|
@@ -3263,6 +3214,14 @@ async function* runWarpGrepStreaming(config) {
|
|
|
3263
3214
|
timings
|
|
3264
3215
|
};
|
|
3265
3216
|
}
|
|
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
|
+
}
|
|
3266
3225
|
|
|
3267
3226
|
// tools/warp_grep/providers/remote.ts
|
|
3268
3227
|
init_config();
|
|
@@ -3442,6 +3401,35 @@ var RemoteCommandsProvider = class {
|
|
|
3442
3401
|
return [];
|
|
3443
3402
|
}
|
|
3444
3403
|
}
|
|
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
|
+
}
|
|
3445
3433
|
};
|
|
3446
3434
|
|
|
3447
3435
|
// tools/warp_grep/providers/code_storage_http.ts
|
|
@@ -3468,9 +3456,9 @@ function createCodeStorageHttpCommands(config) {
|
|
|
3468
3456
|
const { baseUrl, repoId, branch } = config;
|
|
3469
3457
|
const encodedRepoId = encodeURIComponent(repoId);
|
|
3470
3458
|
return {
|
|
3471
|
-
grep: (pattern,
|
|
3472
|
-
read: (
|
|
3473
|
-
listDir: (
|
|
3459
|
+
grep: (pattern, path6, glob) => post(`${baseUrl}/api/code-search/${encodedRepoId}/grep`, { pattern, path: path6, glob, branch }, "grep"),
|
|
3460
|
+
read: (path6, start, end) => post(`${baseUrl}/api/code-search/${encodedRepoId}/read`, { path: path6, start, end, branch }, "read"),
|
|
3461
|
+
listDir: (path6, maxDepth) => post(`${baseUrl}/api/code-search/${encodedRepoId}/list`, { path: path6, maxDepth, branch }, "list")
|
|
3474
3462
|
};
|
|
3475
3463
|
}
|
|
3476
3464
|
|
|
@@ -3853,10 +3841,10 @@ var GitHubClient = class {
|
|
|
3853
3841
|
/**
|
|
3854
3842
|
* Make an authenticated API request
|
|
3855
3843
|
*/
|
|
3856
|
-
async request(method,
|
|
3857
|
-
const url = `${this.baseUrl}${
|
|
3844
|
+
async request(method, path6, body) {
|
|
3845
|
+
const url = `${this.baseUrl}${path6}`;
|
|
3858
3846
|
if (this.debug) {
|
|
3859
|
-
console.log(`[GitHub SDK] ${method} ${
|
|
3847
|
+
console.log(`[GitHub SDK] ${method} ${path6}`, body || "");
|
|
3860
3848
|
}
|
|
3861
3849
|
const controller = new AbortController();
|
|
3862
3850
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
@@ -6424,6 +6412,25 @@ init_paths();
|
|
|
6424
6412
|
// tools/warp_grep/agent/index.ts
|
|
6425
6413
|
init_config();
|
|
6426
6414
|
|
|
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
|
+
|
|
6427
6434
|
// tools/warp_grep/index.ts
|
|
6428
6435
|
var warpGrepInputSchema = import_zod5.z.object({
|
|
6429
6436
|
search_term: import_zod5.z.string().describe("Search problem statement that this subagent is supposed to research for")
|