@morphllm/morphsdk 0.2.125 → 0.2.126
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-BQO3WODX.js → chunk-37ZZ24IX.js} +3 -12
- package/dist/chunk-37ZZ24IX.js.map +1 -0
- package/dist/{chunk-OQGX4RZP.js → chunk-3NLCSADX.js} +2 -2
- package/dist/{chunk-UGSV5LPO.js → chunk-5CIUBER5.js} +2 -2
- package/dist/{chunk-2S7ZQFIB.js → chunk-6722FXFI.js} +2 -2
- package/dist/{chunk-FAZO2LNY.js → chunk-6Y2LHEJJ.js} +2 -2
- package/dist/{chunk-IRNUW2DB.js → chunk-76PPJZWV.js} +3 -12
- package/dist/chunk-76PPJZWV.js.map +1 -0
- package/dist/{chunk-5L3TPS6A.js → chunk-AXYGFPEJ.js} +1 -1
- package/dist/{chunk-5L3TPS6A.js.map → chunk-AXYGFPEJ.js.map} +1 -1
- package/dist/{chunk-TFK4UOUE.js → chunk-C26M3TWM.js} +6 -6
- package/dist/{chunk-TS3E6IRI.js → chunk-CPZKCBED.js} +2 -2
- package/dist/{chunk-33CP5QCC.js → chunk-CYVV5X5K.js} +3 -3
- package/dist/{chunk-33CP5QCC.js.map → chunk-CYVV5X5K.js.map} +1 -1
- package/dist/{chunk-5PNMAWLC.js → chunk-DKODF3YG.js} +2 -2
- package/dist/{chunk-5PNMAWLC.js.map → chunk-DKODF3YG.js.map} +1 -1
- package/dist/{chunk-IB4MEIQG.js → chunk-EB656RG6.js} +2 -2
- package/dist/{chunk-6TH3VNCF.js → chunk-FAH4YGRN.js} +3 -3
- package/dist/{chunk-DGYWACHC.js → chunk-GISRJI5P.js} +2 -2
- package/dist/{chunk-EF7ZYLA2.js → chunk-HZOTLGJH.js} +19 -12
- package/dist/chunk-HZOTLGJH.js.map +1 -0
- package/dist/{chunk-FEQJCZJQ.js → chunk-IYZX6EYC.js} +2 -2
- package/dist/{chunk-3MLWXJTJ.js → chunk-K2FXHDX2.js} +15 -10
- package/dist/chunk-K2FXHDX2.js.map +1 -0
- package/dist/{chunk-F6HNFC2H.js → chunk-K6GLBQBV.js} +2 -2
- package/dist/{chunk-57PXQ6IS.js → chunk-KJVFYRXY.js} +15 -15
- package/dist/{chunk-2MK64KK4.js → chunk-KUABSLVR.js} +2 -2
- package/dist/{chunk-PUGSTXLO.js → chunk-NF2QWJDY.js} +6 -7
- package/dist/chunk-NF2QWJDY.js.map +1 -0
- package/dist/{chunk-7RTJCQWB.js → chunk-QK5RNORE.js} +3 -3
- package/dist/chunk-QK5RNORE.js.map +1 -0
- package/dist/{chunk-V3HLOZK2.js → chunk-QLBRTLEI.js} +1 -1
- package/dist/{chunk-V3HLOZK2.js.map → chunk-QLBRTLEI.js.map} +1 -1
- package/dist/chunk-QRXG5CAZ.js +27 -0
- package/dist/chunk-QRXG5CAZ.js.map +1 -0
- package/dist/{chunk-ACHEU2V3.js → chunk-R74NP2D4.js} +2 -2
- package/dist/{chunk-H6KT7IXW.js → chunk-TREVNTLA.js} +2 -2
- package/dist/{chunk-G5YJDK5S.js → chunk-ULZOJQ2W.js} +2 -2
- package/dist/chunk-VCKJ22DX.js +131 -0
- package/dist/chunk-VCKJ22DX.js.map +1 -0
- package/dist/{chunk-WZAZFW77.js → chunk-VYJUGQUR.js} +1 -1
- package/dist/{chunk-OFQRY3RM.js → chunk-W7WUZMKZ.js} +18 -23
- package/dist/chunk-W7WUZMKZ.js.map +1 -0
- package/dist/{chunk-BGL35LL6.js → chunk-YHZRHPJI.js} +2 -2
- package/dist/{client-JHPwle1Z.d.ts → client-s3_iDem0.d.ts} +0 -4
- package/dist/client.cjs +145 -572
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.ts +1 -2
- package/dist/client.js +27 -28
- package/dist/edge.cjs +2 -2
- package/dist/edge.cjs.map +1 -1
- package/dist/edge.js +4 -4
- package/dist/{finish-pPJfB0uO.d.ts → finish-DBKuo8yj.d.ts} +2 -0
- package/dist/index.cjs +145 -572
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +29 -30
- package/dist/modelrouter/core.cjs +2 -2
- package/dist/modelrouter/core.cjs.map +1 -1
- package/dist/modelrouter/core.js +3 -3
- package/dist/modelrouter/index.cjs +2 -2
- package/dist/modelrouter/index.cjs.map +1 -1
- package/dist/modelrouter/index.js +3 -3
- package/dist/tools/browser/anthropic.cjs +2 -2
- package/dist/tools/browser/anthropic.cjs.map +1 -1
- package/dist/tools/browser/anthropic.js +5 -5
- package/dist/tools/browser/core.cjs +2 -2
- package/dist/tools/browser/core.cjs.map +1 -1
- package/dist/tools/browser/core.js +4 -4
- package/dist/tools/browser/index.cjs +2 -2
- package/dist/tools/browser/index.cjs.map +1 -1
- package/dist/tools/browser/index.js +7 -7
- package/dist/tools/browser/openai.cjs +2 -2
- package/dist/tools/browser/openai.cjs.map +1 -1
- package/dist/tools/browser/openai.js +5 -5
- package/dist/tools/browser/profiles/core.cjs +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/tools/browser/vercel.cjs.map +1 -1
- package/dist/tools/browser/vercel.js +5 -5
- package/dist/tools/codebase_search/anthropic.cjs +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/tools/fastapply/anthropic.cjs.map +1 -1
- package/dist/tools/fastapply/anthropic.js +4 -4
- package/dist/tools/fastapply/apply.cjs +2 -2
- package/dist/tools/fastapply/apply.cjs.map +1 -1
- package/dist/tools/fastapply/apply.js +2 -2
- package/dist/tools/fastapply/core.cjs +2 -2
- package/dist/tools/fastapply/core.cjs.map +1 -1
- package/dist/tools/fastapply/core.js +3 -3
- package/dist/tools/fastapply/index.cjs +2 -2
- package/dist/tools/fastapply/index.cjs.map +1 -1
- package/dist/tools/fastapply/index.js +6 -6
- package/dist/tools/fastapply/openai.cjs +2 -2
- package/dist/tools/fastapply/openai.cjs.map +1 -1
- package/dist/tools/fastapply/openai.js +4 -4
- package/dist/tools/fastapply/vercel.cjs +2 -2
- package/dist/tools/fastapply/vercel.cjs.map +1 -1
- package/dist/tools/fastapply/vercel.js +4 -4
- package/dist/tools/index.cjs +2 -2
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.js +6 -6
- package/dist/tools/utils/resilience.cjs +2 -2
- 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 +1 -1
- package/dist/tools/warp_grep/agent/config.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/config.d.ts +1 -1
- package/dist/tools/warp_grep/agent/config.js +1 -1
- package/dist/tools/warp_grep/agent/formatter.cjs +3 -74
- package/dist/tools/warp_grep/agent/formatter.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/formatter.d.ts +1 -5
- package/dist/tools/warp_grep/agent/formatter.js +1 -1
- package/dist/tools/warp_grep/agent/parser.cjs +91 -242
- package/dist/tools/warp_grep/agent/parser.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/parser.d.ts +0 -8
- package/dist/tools/warp_grep/agent/parser.js +1 -1
- package/dist/tools/warp_grep/agent/runner.cjs +122 -543
- package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/runner.js +6 -7
- package/dist/tools/warp_grep/agent/types.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/types.d.ts +2 -0
- package/dist/tools/warp_grep/anthropic.cjs +143 -566
- package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
- package/dist/tools/warp_grep/anthropic.d.ts +0 -3
- package/dist/tools/warp_grep/anthropic.js +11 -15
- package/dist/tools/warp_grep/client.cjs +143 -558
- package/dist/tools/warp_grep/client.cjs.map +1 -1
- package/dist/tools/warp_grep/client.js +9 -10
- package/dist/tools/warp_grep/gemini.cjs +143 -566
- package/dist/tools/warp_grep/gemini.cjs.map +1 -1
- package/dist/tools/warp_grep/gemini.d.ts +0 -3
- package/dist/tools/warp_grep/gemini.js +10 -20
- package/dist/tools/warp_grep/gemini.js.map +1 -1
- package/dist/tools/warp_grep/harness.cjs +124 -540
- package/dist/tools/warp_grep/harness.cjs.map +1 -1
- package/dist/tools/warp_grep/harness.d.ts +4 -5
- package/dist/tools/warp_grep/harness.js +5 -11
- package/dist/tools/warp_grep/harness.js.map +1 -1
- package/dist/tools/warp_grep/index.cjs +143 -562
- package/dist/tools/warp_grep/index.cjs.map +1 -1
- package/dist/tools/warp_grep/index.d.ts +1 -2
- package/dist/tools/warp_grep/index.js +14 -20
- package/dist/tools/warp_grep/openai.cjs +143 -566
- package/dist/tools/warp_grep/openai.cjs.map +1 -1
- package/dist/tools/warp_grep/openai.d.ts +0 -3
- package/dist/tools/warp_grep/openai.js +11 -15
- package/dist/tools/warp_grep/providers/local.cjs +17 -10
- package/dist/tools/warp_grep/providers/local.cjs.map +1 -1
- package/dist/tools/warp_grep/providers/local.d.ts +6 -1
- package/dist/tools/warp_grep/providers/local.js +2 -2
- package/dist/tools/warp_grep/providers/remote.cjs +4 -5
- package/dist/tools/warp_grep/providers/remote.cjs.map +1 -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 +2 -0
- package/dist/tools/warp_grep/vercel.cjs +143 -560
- package/dist/tools/warp_grep/vercel.cjs.map +1 -1
- package/dist/tools/warp_grep/vercel.d.ts +0 -1
- package/dist/tools/warp_grep/vercel.js +11 -15
- package/dist/version.cjs +2 -2
- package/dist/version.cjs.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-3MLWXJTJ.js.map +0 -1
- package/dist/chunk-7RTJCQWB.js.map +0 -1
- package/dist/chunk-APP75CBN.js +0 -98
- package/dist/chunk-APP75CBN.js.map +0 -1
- package/dist/chunk-BQO3WODX.js.map +0 -1
- package/dist/chunk-EF7ZYLA2.js.map +0 -1
- package/dist/chunk-FMLHRJDF.js +0 -207
- package/dist/chunk-FMLHRJDF.js.map +0 -1
- package/dist/chunk-GHGJAQSJ.js +0 -282
- package/dist/chunk-GHGJAQSJ.js.map +0 -1
- package/dist/chunk-IRNUW2DB.js.map +0 -1
- package/dist/chunk-OFQRY3RM.js.map +0 -1
- package/dist/chunk-PUGSTXLO.js.map +0 -1
- package/dist/tools/warp_grep/agent/prompt.cjs +0 -232
- package/dist/tools/warp_grep/agent/prompt.cjs.map +0 -1
- package/dist/tools/warp_grep/agent/prompt.d.ts +0 -4
- package/dist/tools/warp_grep/agent/prompt.js +0 -10
- package/dist/tools/warp_grep/agent/prompt.js.map +0 -1
- /package/dist/{chunk-OQGX4RZP.js.map → chunk-3NLCSADX.js.map} +0 -0
- /package/dist/{chunk-UGSV5LPO.js.map → chunk-5CIUBER5.js.map} +0 -0
- /package/dist/{chunk-2S7ZQFIB.js.map → chunk-6722FXFI.js.map} +0 -0
- /package/dist/{chunk-FAZO2LNY.js.map → chunk-6Y2LHEJJ.js.map} +0 -0
- /package/dist/{chunk-TFK4UOUE.js.map → chunk-C26M3TWM.js.map} +0 -0
- /package/dist/{chunk-TS3E6IRI.js.map → chunk-CPZKCBED.js.map} +0 -0
- /package/dist/{chunk-IB4MEIQG.js.map → chunk-EB656RG6.js.map} +0 -0
- /package/dist/{chunk-6TH3VNCF.js.map → chunk-FAH4YGRN.js.map} +0 -0
- /package/dist/{chunk-DGYWACHC.js.map → chunk-GISRJI5P.js.map} +0 -0
- /package/dist/{chunk-FEQJCZJQ.js.map → chunk-IYZX6EYC.js.map} +0 -0
- /package/dist/{chunk-F6HNFC2H.js.map → chunk-K6GLBQBV.js.map} +0 -0
- /package/dist/{chunk-57PXQ6IS.js.map → chunk-KJVFYRXY.js.map} +0 -0
- /package/dist/{chunk-2MK64KK4.js.map → chunk-KUABSLVR.js.map} +0 -0
- /package/dist/{chunk-ACHEU2V3.js.map → chunk-R74NP2D4.js.map} +0 -0
- /package/dist/{chunk-H6KT7IXW.js.map → chunk-TREVNTLA.js.map} +0 -0
- /package/dist/{chunk-G5YJDK5S.js.map → chunk-ULZOJQ2W.js.map} +0 -0
- /package/dist/{chunk-WZAZFW77.js.map → chunk-VYJUGQUR.js.map} +0 -0
- /package/dist/{chunk-BGL35LL6.js.map → chunk-YHZRHPJI.js.map} +0 -0
|
@@ -34,13 +34,11 @@ __export(harness_exports, {
|
|
|
34
34
|
DEFAULT_EXCLUDES: () => DEFAULT_EXCLUDES,
|
|
35
35
|
LLMResponseParser: () => LLMResponseParser,
|
|
36
36
|
LocalRipgrepProvider: () => LocalRipgrepProvider,
|
|
37
|
-
SYSTEM_PROMPT: () => SYSTEM_PROMPT,
|
|
38
37
|
buildInitialState: () => buildInitialState,
|
|
39
38
|
calculateContextBudget: () => calculateContextBudget,
|
|
40
39
|
formatListDirectoryTree: () => formatListDirectoryTree,
|
|
41
40
|
formatToolResult: () => formatAgentToolOutput,
|
|
42
41
|
formatTurnMessage: () => formatTurnMessage,
|
|
43
|
-
getSystemPrompt: () => getSystemPrompt,
|
|
44
42
|
normalizeFinishFiles: () => normalizeFinishFiles,
|
|
45
43
|
parseToolCalls: () => parseToolCalls,
|
|
46
44
|
readFinishFiles: () => readFinishFiles,
|
|
@@ -52,571 +50,147 @@ __export(harness_exports, {
|
|
|
52
50
|
module.exports = __toCommonJS(harness_exports);
|
|
53
51
|
|
|
54
52
|
// tools/warp_grep/agent/parser.ts
|
|
55
|
-
var VALID_COMMANDS = ["list_directory", "
|
|
53
|
+
var VALID_COMMANDS = ["list_directory", "ripgrep", "read", "finish"];
|
|
56
54
|
function isValidCommand(name) {
|
|
57
55
|
return VALID_COMMANDS.includes(name);
|
|
58
56
|
}
|
|
59
|
-
function
|
|
60
|
-
const regex = new RegExp(`<${tagName}>([\\s\\S]*?)</${tagName}>`, "i");
|
|
61
|
-
const match = xml.match(regex);
|
|
62
|
-
return match ? match[1].trim() : null;
|
|
63
|
-
}
|
|
64
|
-
function parseNestedXmlTools(text) {
|
|
57
|
+
function parseQwen3ToolCalls(text) {
|
|
65
58
|
const tools = [];
|
|
66
|
-
const
|
|
59
|
+
const toolCallRegex = /<tool_call>\s*<function=([a-z_][a-z0-9_]*)>([\s\S]*?)<\/function>\s*<\/tool_call>/gi;
|
|
67
60
|
let match;
|
|
68
|
-
while ((match =
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
if (!isValidCommand(
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
61
|
+
while ((match = toolCallRegex.exec(text)) !== null) {
|
|
62
|
+
const funcName = match[1].toLowerCase();
|
|
63
|
+
const body = match[2];
|
|
64
|
+
if (!isValidCommand(funcName)) continue;
|
|
65
|
+
const params = {};
|
|
66
|
+
const paramRegex = /<parameter=([a-z_][a-z0-9_]*)>([\s\S]*?)<\/parameter>/gi;
|
|
67
|
+
let paramMatch;
|
|
68
|
+
while ((paramMatch = paramRegex.exec(body)) !== null) {
|
|
69
|
+
params[paramMatch[1].toLowerCase()] = paramMatch[2].trim();
|
|
70
|
+
}
|
|
71
|
+
if (funcName === "ripgrep") {
|
|
72
|
+
const pattern = params.pattern;
|
|
73
|
+
if (!pattern) continue;
|
|
74
|
+
const args = {
|
|
75
|
+
pattern,
|
|
76
|
+
path: params.path || ".",
|
|
77
|
+
...params.glob && { glob: params.glob },
|
|
78
|
+
...params.context_lines && { context_lines: parseInt(params.context_lines, 10) },
|
|
79
|
+
...params.case_sensitive && { case_sensitive: params.case_sensitive === "true" }
|
|
80
|
+
};
|
|
81
|
+
tools.push({ name: "grep", arguments: args });
|
|
82
|
+
} else if (funcName === "list_directory") {
|
|
83
|
+
const command = params.command;
|
|
84
|
+
const directPath = params.path;
|
|
85
|
+
let dirPath = directPath || ".";
|
|
86
|
+
if (!directPath && command) {
|
|
87
|
+
const tokens = command.trim().split(/\s+/);
|
|
88
|
+
const pathTokens = tokens.slice(1).filter((t) => !t.startsWith("-") && !t.startsWith("|") && !t.startsWith("\\("));
|
|
89
|
+
if (pathTokens.length > 0) {
|
|
90
|
+
dirPath = pathTokens[0];
|
|
91
|
+
}
|
|
78
92
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
tools.push({ name: "list_directory", arguments: { path: dirPath, pattern: params.pattern || null } });
|
|
94
|
+
} else if (funcName === "read") {
|
|
95
|
+
const filePath = params.path;
|
|
96
|
+
if (!filePath) continue;
|
|
97
|
+
const args = { path: filePath };
|
|
98
|
+
const linesStr = params.lines;
|
|
99
|
+
if (linesStr) {
|
|
100
|
+
const ranges = [];
|
|
101
|
+
for (const rangeStr of linesStr.split(",")) {
|
|
102
|
+
const trimmed = rangeStr.trim();
|
|
103
|
+
if (!trimmed) continue;
|
|
104
|
+
const [s, e] = trimmed.split("-").map((v) => parseInt(v.trim(), 10));
|
|
105
|
+
if (Number.isFinite(s) && Number.isFinite(e)) {
|
|
106
|
+
ranges.push([s, e]);
|
|
107
|
+
} else if (Number.isFinite(s)) {
|
|
108
|
+
ranges.push([s, s]);
|
|
90
109
|
}
|
|
91
|
-
}
|
|
110
|
+
}
|
|
111
|
+
if (ranges.length === 1) {
|
|
112
|
+
args.start = ranges[0][0];
|
|
113
|
+
args.end = ranges[0][1];
|
|
114
|
+
} else if (ranges.length > 1) {
|
|
115
|
+
args.lines = ranges;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
tools.push({ name: "read", arguments: args });
|
|
119
|
+
} else if (funcName === "finish") {
|
|
120
|
+
if (params.result && !params.files) {
|
|
121
|
+
tools.push({ name: "finish", arguments: { files: [], textResult: params.result } });
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const filesStr = params.files;
|
|
125
|
+
if (!filesStr) {
|
|
126
|
+
tools.push({ name: "finish", arguments: { files: [], textResult: "No relevant code found." } });
|
|
127
|
+
continue;
|
|
92
128
|
}
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
if (
|
|
129
|
+
const files = [];
|
|
130
|
+
for (const line of filesStr.split("\n")) {
|
|
131
|
+
const trimmed = line.trim();
|
|
132
|
+
if (!trimmed) continue;
|
|
133
|
+
const colonIdx = trimmed.indexOf(":");
|
|
134
|
+
if (colonIdx === -1) {
|
|
135
|
+
files.push({ path: trimmed, lines: "*" });
|
|
136
|
+
} else {
|
|
137
|
+
const filePath = trimmed.slice(0, colonIdx);
|
|
138
|
+
const rangesPart = trimmed.slice(colonIdx + 1);
|
|
99
139
|
const ranges = [];
|
|
100
|
-
for (const rangeStr of
|
|
101
|
-
const
|
|
102
|
-
if (!
|
|
103
|
-
|
|
140
|
+
for (const rangeStr of rangesPart.split(",")) {
|
|
141
|
+
const rt = rangeStr.trim();
|
|
142
|
+
if (!rt || rt === "*") {
|
|
143
|
+
files.push({ path: filePath, lines: "*" });
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
const [s, e] = rt.split("-").map((v) => parseInt(v.trim(), 10));
|
|
104
147
|
if (Number.isFinite(s) && Number.isFinite(e)) {
|
|
105
148
|
ranges.push([s, e]);
|
|
106
149
|
} else if (Number.isFinite(s)) {
|
|
107
150
|
ranges.push([s, s]);
|
|
108
151
|
}
|
|
109
152
|
}
|
|
110
|
-
if (ranges.length
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
} else if (ranges.length > 1) {
|
|
114
|
-
args.lines = ranges;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
tools.push({ name: "read", arguments: args });
|
|
118
|
-
}
|
|
119
|
-
} else if (toolName === "finish") {
|
|
120
|
-
const fileRegex = /<file>([\s\S]*?)<\/file>/gi;
|
|
121
|
-
const files = [];
|
|
122
|
-
let fileMatch;
|
|
123
|
-
while ((fileMatch = fileRegex.exec(content)) !== null) {
|
|
124
|
-
const fileContent = fileMatch[1];
|
|
125
|
-
const filePath = getXmlElementText(fileContent, "path");
|
|
126
|
-
const linesStr = getXmlElementText(fileContent, "lines");
|
|
127
|
-
if (filePath) {
|
|
128
|
-
if (!linesStr || linesStr.trim() === "*") {
|
|
153
|
+
if (ranges.length > 0) {
|
|
154
|
+
files.push({ path: filePath, lines: ranges });
|
|
155
|
+
} else if (!files.some((f) => f.path === filePath)) {
|
|
129
156
|
files.push({ path: filePath, lines: "*" });
|
|
130
|
-
} else {
|
|
131
|
-
const ranges = [];
|
|
132
|
-
for (const rangeStr of linesStr.split(",")) {
|
|
133
|
-
const [s, e] = rangeStr.split("-").map((v) => parseInt(v.trim(), 10));
|
|
134
|
-
if (Number.isFinite(s) && Number.isFinite(e)) {
|
|
135
|
-
ranges.push([s, e]);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (ranges.length > 0) {
|
|
139
|
-
files.push({ path: filePath, lines: ranges });
|
|
140
|
-
} else {
|
|
141
|
-
files.push({ path: filePath, lines: "*" });
|
|
142
|
-
}
|
|
143
157
|
}
|
|
144
158
|
}
|
|
145
159
|
}
|
|
146
160
|
if (files.length > 0) {
|
|
147
161
|
tools.push({ name: "finish", arguments: { files } });
|
|
148
162
|
} else {
|
|
149
|
-
|
|
150
|
-
const textResult = !raw || raw === "*" ? "No relevant code found." : raw;
|
|
151
|
-
tools.push({ name: "finish", arguments: { files: [], textResult } });
|
|
163
|
+
tools.push({ name: "finish", arguments: { files: [], textResult: filesStr } });
|
|
152
164
|
}
|
|
153
165
|
}
|
|
154
166
|
}
|
|
155
|
-
if (tools.length === 0) {
|
|
156
|
-
const fnFinishMatch = text.match(/<function=finish>([\s\S]*?)<\/function>/i);
|
|
157
|
-
if (fnFinishMatch) {
|
|
158
|
-
const inner = fnFinishMatch[1];
|
|
159
|
-
const paramMatch = inner.match(/<parameter=result>([\s\S]*?)<\/parameter>/i);
|
|
160
|
-
const raw = (paramMatch ? paramMatch[1] : inner).trim();
|
|
161
|
-
const textResult = !raw || raw === "*" ? "No relevant code found." : raw;
|
|
162
|
-
tools.push({ name: "finish", arguments: { files: [], textResult } });
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
167
|
return tools;
|
|
166
168
|
}
|
|
167
|
-
function preprocessText(text) {
|
|
168
|
-
const processed = text.replace(/<think>[\s\S]*?<\/think>/gi, "").replace(/<\/?tool_call>/gi, "");
|
|
169
|
-
const nestedTools = parseNestedXmlTools(processed);
|
|
170
|
-
const toolCallLines = [];
|
|
171
|
-
const allLines = processed.split(/\r?\n/).map((l) => l.trim());
|
|
172
|
-
for (const line of allLines) {
|
|
173
|
-
if (!line) continue;
|
|
174
|
-
if (line.startsWith("<")) continue;
|
|
175
|
-
const firstWord = line.split(/\s/)[0];
|
|
176
|
-
if (VALID_COMMANDS.includes(firstWord)) {
|
|
177
|
-
if (!toolCallLines.includes(line)) {
|
|
178
|
-
toolCallLines.push(line);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return { lines: toolCallLines, nestedTools };
|
|
183
|
-
}
|
|
184
169
|
var LLMResponseParser = class {
|
|
185
|
-
finishSpecSplitRe = /,(?=[^,\s]+:)/;
|
|
186
170
|
parse(text) {
|
|
187
171
|
if (typeof text !== "string") {
|
|
188
172
|
throw new TypeError("Command text must be a string.");
|
|
189
173
|
}
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
let finishAccumulator = null;
|
|
193
|
-
lines.forEach((line) => {
|
|
194
|
-
if (!line || line.startsWith("#")) return;
|
|
195
|
-
const parts = this.splitLine(line);
|
|
196
|
-
if (parts.length === 0) return;
|
|
197
|
-
const cmd = parts[0];
|
|
198
|
-
switch (cmd) {
|
|
199
|
-
case "list_directory":
|
|
200
|
-
this.handleListDirectory(parts, line, commands);
|
|
201
|
-
break;
|
|
202
|
-
case "grep":
|
|
203
|
-
this.handleGrep(parts, line, commands);
|
|
204
|
-
break;
|
|
205
|
-
case "read":
|
|
206
|
-
this.handleRead(parts, line, commands);
|
|
207
|
-
break;
|
|
208
|
-
case "finish":
|
|
209
|
-
finishAccumulator = this.handleFinish(parts, line, commands, finishAccumulator);
|
|
210
|
-
break;
|
|
211
|
-
default:
|
|
212
|
-
break;
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
if (finishAccumulator) {
|
|
216
|
-
const map = finishAccumulator;
|
|
217
|
-
const entries = [...map.entries()];
|
|
218
|
-
const filesPayload = entries.map(([path4, ranges]) => ({
|
|
219
|
-
path: path4,
|
|
220
|
-
lines: [...ranges].sort((a, b) => a[0] - b[0])
|
|
221
|
-
}));
|
|
222
|
-
commands.push({ name: "finish", arguments: { files: filesPayload } });
|
|
223
|
-
}
|
|
224
|
-
return commands;
|
|
225
|
-
}
|
|
226
|
-
splitLine(line) {
|
|
227
|
-
const parts = [];
|
|
228
|
-
let current = "";
|
|
229
|
-
let inSingle = false;
|
|
230
|
-
for (let i = 0; i < line.length; i++) {
|
|
231
|
-
const ch = line[i];
|
|
232
|
-
if (ch === "'" && line[i - 1] !== "\\") {
|
|
233
|
-
inSingle = !inSingle;
|
|
234
|
-
current += ch;
|
|
235
|
-
} else if (!inSingle && /\s/.test(ch)) {
|
|
236
|
-
if (current) {
|
|
237
|
-
parts.push(current);
|
|
238
|
-
current = "";
|
|
239
|
-
}
|
|
240
|
-
} else {
|
|
241
|
-
current += ch;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
if (current) parts.push(current);
|
|
245
|
-
return parts;
|
|
246
|
-
}
|
|
247
|
-
/** Helper to create a _skip tool call with an error message */
|
|
248
|
-
skip(message) {
|
|
249
|
-
return { name: "_skip", arguments: { message } };
|
|
250
|
-
}
|
|
251
|
-
handleListDirectory(parts, rawLine, commands) {
|
|
252
|
-
if (parts.length < 2) {
|
|
253
|
-
commands.push(this.skip(
|
|
254
|
-
`[SKIPPED] Your command "${rawLine}" is missing a path. Correct format: list_directory <path> [pattern]. Example: list_directory src/`
|
|
255
|
-
));
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
const path4 = parts[1];
|
|
259
|
-
const pattern = parts[2]?.replace(/^"|"$/g, "") ?? null;
|
|
260
|
-
commands.push({ name: "list_directory", arguments: { path: path4, pattern } });
|
|
261
|
-
}
|
|
262
|
-
handleGrep(parts, rawLine, commands) {
|
|
263
|
-
if (parts.length < 3) {
|
|
264
|
-
commands.push(this.skip(
|
|
265
|
-
`[SKIPPED] Your command "${rawLine}" is missing arguments. Correct format: grep '<pattern>' <path>. Example: grep 'TODO' src/`
|
|
266
|
-
));
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
let pat = parts[1];
|
|
270
|
-
if (pat.startsWith("'") && pat.endsWith("'")) {
|
|
271
|
-
pat = pat.slice(1, -1);
|
|
272
|
-
}
|
|
273
|
-
if (!pat) {
|
|
274
|
-
commands.push(this.skip(
|
|
275
|
-
`[SKIPPED] Your command "${rawLine}" has an empty pattern. Provide a non-empty search pattern. Example: grep 'function' src/`
|
|
276
|
-
));
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
commands.push({ name: "grep", arguments: { pattern: pat, path: parts[2] } });
|
|
280
|
-
}
|
|
281
|
-
handleRead(parts, rawLine, commands) {
|
|
282
|
-
if (parts.length < 2) {
|
|
283
|
-
commands.push(this.skip(
|
|
284
|
-
`[SKIPPED] Your command "${rawLine}" is missing a path. Correct format: read <path> or read <path>:<start>-<end>. Example: read src/index.ts:1-50`
|
|
285
|
-
));
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
const spec = parts[1];
|
|
289
|
-
const rangeIdx = spec.indexOf(":");
|
|
290
|
-
if (rangeIdx === -1) {
|
|
291
|
-
commands.push({ name: "read", arguments: { path: spec } });
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
const filePath = spec.slice(0, rangeIdx);
|
|
295
|
-
const range = spec.slice(rangeIdx + 1);
|
|
296
|
-
const [s, e] = range.split("-").map((v) => parseInt(v, 10));
|
|
297
|
-
if (!Number.isFinite(s) || !Number.isFinite(e)) {
|
|
298
|
-
commands.push({ name: "read", arguments: { path: filePath } });
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
commands.push({ name: "read", arguments: { path: filePath, start: s, end: e } });
|
|
302
|
-
}
|
|
303
|
-
handleFinish(parts, rawLine, commands, acc) {
|
|
304
|
-
const map = acc ?? /* @__PURE__ */ new Map();
|
|
305
|
-
const args = parts.slice(1);
|
|
306
|
-
for (const token of args) {
|
|
307
|
-
const [filePath, rangesText] = token.split(":", 2);
|
|
308
|
-
if (!filePath || !rangesText) {
|
|
309
|
-
commands.push(this.skip(
|
|
310
|
-
`[SKIPPED] Invalid finish token "${token}". Correct format: finish <path>:<start>-<end>. Example: finish src/index.ts:1-50`
|
|
311
|
-
));
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
const rangeSpecs = rangesText.split(",").filter(Boolean);
|
|
315
|
-
for (const spec of rangeSpecs) {
|
|
316
|
-
const [s, e] = spec.split("-").map((v) => parseInt(v, 10));
|
|
317
|
-
if (!Number.isFinite(s) || !Number.isFinite(e) || e < s) {
|
|
318
|
-
commands.push(this.skip(
|
|
319
|
-
`[SKIPPED] Invalid range "${spec}" in "${token}". Ranges must be <start>-<end> where start <= end. Example: 1-50`
|
|
320
|
-
));
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
const arr = map.get(filePath) ?? [];
|
|
324
|
-
arr.push([s, e]);
|
|
325
|
-
map.set(filePath, arr);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
return map;
|
|
174
|
+
const withoutThink = text.replace(/<think>[\s\S]*?<\/think>/gi, "");
|
|
175
|
+
return parseQwen3ToolCalls(withoutThink);
|
|
329
176
|
}
|
|
330
177
|
};
|
|
331
178
|
|
|
332
|
-
// tools/warp_grep/agent/prompt.ts
|
|
333
|
-
var SYSTEM_PROMPT = `You are a code search agent. Your task is to find all relevant code for a given search_string.
|
|
334
|
-
|
|
335
|
-
### workflow
|
|
336
|
-
You have exactly 4 turns. The 4th turn MUST be a \`finish\` call. Each turn allows up to 8 parallel tool calls.
|
|
337
|
-
|
|
338
|
-
- Turn 1: Map the territory OR dive deep (based on search_string specificity)
|
|
339
|
-
- Turn 2-3: Refine based on findings
|
|
340
|
-
- Turn 4: MUST call \`finish\` with all relevant code locations
|
|
341
|
-
- You MAY call \`finish\` early if confident\u2014but never before at least 1 search turn.
|
|
342
|
-
- The user strongly prefers if you can call the finish tool early, but you must be correct
|
|
343
|
-
|
|
344
|
-
Remember, if the task feels easy to you, it is strongly desirable to call 'finish' early using fewer turns, but quality over speed
|
|
345
|
-
|
|
346
|
-
### tools
|
|
347
|
-
Tool calls use nested XML elements:
|
|
348
|
-
\`\`\`xml
|
|
349
|
-
<tool_name>
|
|
350
|
-
<parameter>value</parameter>
|
|
351
|
-
</tool_name>
|
|
352
|
-
\`\`\`
|
|
353
|
-
|
|
354
|
-
### \`list_directory\`
|
|
355
|
-
Directory tree view. Shows structure of a path, optionally filtered by regex pattern.
|
|
356
|
-
|
|
357
|
-
Elements:
|
|
358
|
-
- \`<path>\` (required): Directory path to list (use \`.\` for repo root)
|
|
359
|
-
- \`<pattern>\` (optional): Regex to filter results
|
|
360
|
-
|
|
361
|
-
Examples:
|
|
362
|
-
\`\`\`
|
|
363
|
-
<list_directory>
|
|
364
|
-
<path>src/services</path>
|
|
365
|
-
</list_directory>
|
|
366
|
-
|
|
367
|
-
<list_directory>
|
|
368
|
-
<path>lib/utils</path>
|
|
369
|
-
<pattern>.*\\.(ts|js)$</pattern>
|
|
370
|
-
</list_directory>
|
|
371
|
-
\`\`\`
|
|
372
|
-
|
|
373
|
-
### \`read\`
|
|
374
|
-
Read file contents. Supports multiple line ranges.
|
|
375
|
-
- Returns numbered lines for easy reference
|
|
376
|
-
- ALWAYS include import statements (usually lines 1-20). Better to over-include than miss context.
|
|
377
|
-
|
|
378
|
-
Elements:
|
|
379
|
-
- \`<path>\` (required): File path to read
|
|
380
|
-
- \`<lines>\` (optional): Line ranges like "1-50,75-80,100-120" (omit to read entire file)
|
|
381
|
-
|
|
382
|
-
Examples:
|
|
383
|
-
\`\`\`
|
|
384
|
-
<read>
|
|
385
|
-
<path>src/main.py</path>
|
|
386
|
-
</read>
|
|
387
|
-
|
|
388
|
-
<read>
|
|
389
|
-
<path>src/auth.py</path>
|
|
390
|
-
<lines>1-20,45-80,150-200</lines>
|
|
391
|
-
</read>
|
|
392
|
-
\`\`\`
|
|
393
|
-
|
|
394
|
-
### \`grep\`
|
|
395
|
-
Search for pattern matches across files. Returns matches with 1 line of context above and below.
|
|
396
|
-
- Match lines use \`:\` separator \u2192 \`filepath:linenum:content\`
|
|
397
|
-
- Context lines use \`-\` separator \u2192 \`filepath-linenum-content\`
|
|
398
|
-
|
|
399
|
-
Elements:
|
|
400
|
-
- \`<pattern>\` (required): Search pattern (regex). Use \`(a|b)\` for OR patterns.
|
|
401
|
-
- \`<sub_dir>\` (optional): Subdirectory to search in (defaults to \`.\`)
|
|
402
|
-
- \`<glob>\` (optional): File pattern filter like \`*.py\` or \`*.{ts,tsx}\`
|
|
403
|
-
|
|
404
|
-
Examples:
|
|
405
|
-
\`\`\`
|
|
406
|
-
<grep>
|
|
407
|
-
<pattern>(authenticate|authorize|login)</pattern>
|
|
408
|
-
<sub_dir>src/auth/</sub_dir>
|
|
409
|
-
</grep>
|
|
410
|
-
|
|
411
|
-
<grep>
|
|
412
|
-
<pattern>class.*(Service|Controller)</pattern>
|
|
413
|
-
<glob>*.{ts,js}</glob>
|
|
414
|
-
</grep>
|
|
415
|
-
|
|
416
|
-
<grep>
|
|
417
|
-
<pattern>(DB_HOST|DATABASE_URL|connection)</pattern>
|
|
418
|
-
<glob>*.{py,yaml,env}</glob>
|
|
419
|
-
<sub_dir>lib/</sub_dir>
|
|
420
|
-
</grep>
|
|
421
|
-
\`\`\`
|
|
422
|
-
|
|
423
|
-
### \`finish\`
|
|
424
|
-
Submit final answer with all relevant code locations. Uses nested \`<file>\` elements.
|
|
425
|
-
|
|
426
|
-
File elements:
|
|
427
|
-
- \`<path>\` (required): File path
|
|
428
|
-
- \`<lines>\` (optional): Line ranges like "1-50,75-80" (\`*\` for entire file)
|
|
429
|
-
|
|
430
|
-
ALWAYS include import statements (usually lines 1-20). Better to over-include than miss context.
|
|
431
|
-
|
|
432
|
-
Examples:
|
|
433
|
-
\`\`\`
|
|
434
|
-
<finish>
|
|
435
|
-
<file>
|
|
436
|
-
<path>src/auth.py</path>
|
|
437
|
-
<lines>1-15,25-50,75-80</lines>
|
|
438
|
-
</file>
|
|
439
|
-
<file>
|
|
440
|
-
<path>src/models/user.py</path>
|
|
441
|
-
<lines>*</lines>
|
|
442
|
-
</file>
|
|
443
|
-
</finish>
|
|
444
|
-
\`\`\`
|
|
445
|
-
</tools>
|
|
446
|
-
|
|
447
|
-
<strategy>
|
|
448
|
-
**Before your first tool call, classify the search_string:**
|
|
449
|
-
|
|
450
|
-
| Search_string Type | Round 1 Strategy | Early Finish? |
|
|
451
|
-
|------------|------------------|---------------|
|
|
452
|
-
| **Specific** (function name, error string, unique identifier) | 8 parallel greps on likely paths | Often by round 2 |
|
|
453
|
-
| **Conceptual** (how does X work, where is Y handled) | list_directory + 2-3 broad greps | Rarely early |
|
|
454
|
-
| **Exploratory** (find all tests, list API endpoints) | list_directory at multiple depths | Usually needs 3 rounds |
|
|
455
|
-
|
|
456
|
-
**Parallel call patterns:**
|
|
457
|
-
- **Shotgun grep**: Same pattern, 8 different directories\u2014fast coverage
|
|
458
|
-
- **Variant grep**: 8 pattern variations (synonyms, naming conventions)\u2014catches inconsistent codebases
|
|
459
|
-
- **Funnel**: 1 list_directory + 7 greps\u2014orient and search simultaneously
|
|
460
|
-
- **Deep read**: 8 reads on files you already identified\u2014gather full context fast
|
|
461
|
-
|
|
462
|
-
**Tool call expectations:**
|
|
463
|
-
- Low quality tool calls are ones that give back sparse information. This either means they are not well thought out and are not educated guesses OR, they are too broad and give back too many results.
|
|
464
|
-
- High quality tool calls strike a balance between complexity in the tool call to exclude results we know we don't want, and how wide the search space is so that we don't miss anything. It is ok to start off with wider search spaces, but is imperative that you use your intuition from there on out and seek high quality tool calls only.
|
|
465
|
-
- You are not starting blind, you have some information about root level repo structure going in, so use that to prevent making trivial repo wide queries.
|
|
466
|
-
- The grep tool shows you which file path and line numbers the pattern was found in, use this information smartly when trying to read the file.
|
|
467
|
-
</strategy>
|
|
468
|
-
|
|
469
|
-
<output_format>
|
|
470
|
-
EVERY response MUST follow this exact format:
|
|
471
|
-
|
|
472
|
-
1. First, wrap your reasoning in \`<think>...</think>\` tags containing:
|
|
473
|
-
- Search_string classification (specific/conceptual/exploratory)
|
|
474
|
-
- Confidence estimate (can I finish in 1-2 rounds?)
|
|
475
|
-
- This round's parallel strategy
|
|
476
|
-
- What signals would let me finish early?
|
|
477
|
-
|
|
478
|
-
2. Then, output up to 8 tool calls using nested XML elements.
|
|
479
|
-
|
|
480
|
-
Example:
|
|
481
|
-
\`\`\`
|
|
482
|
-
<think>
|
|
483
|
-
This is a specific search_string about authentication. I'll grep for auth-related patterns.
|
|
484
|
-
High confidence I can finish in 2 rounds if I find the auth module. I have already been shown the repo's structure at root
|
|
485
|
-
Strategy: Shotgun grep across likely directories.
|
|
486
|
-
</think>
|
|
487
|
-
<grep>
|
|
488
|
-
<pattern>(authenticate|login|session)</pattern>
|
|
489
|
-
<sub_dir>src/auth/</sub_dir>
|
|
490
|
-
</grep>
|
|
491
|
-
<grep>
|
|
492
|
-
<pattern>(middleware|interceptor)</pattern>
|
|
493
|
-
<glob>*.{ts,js}</glob>
|
|
494
|
-
</grep>
|
|
495
|
-
<list_directory>
|
|
496
|
-
<path>src/auth</path>
|
|
497
|
-
</list_directory>
|
|
498
|
-
\`\`\`
|
|
499
|
-
|
|
500
|
-
Finishing example:
|
|
501
|
-
\`\`\`
|
|
502
|
-
<think>
|
|
503
|
-
I think I have a rough idea, but this is my last turn so I must call the finish tool regardless.
|
|
504
|
-
</think>
|
|
505
|
-
<finish>
|
|
506
|
-
<file>
|
|
507
|
-
<path>src/auth/login.py</path>
|
|
508
|
-
<lines>1-50</lines>
|
|
509
|
-
</file>
|
|
510
|
-
<file>
|
|
511
|
-
<path>src/middleware/session.py</path>
|
|
512
|
-
<lines>10-80</lines>
|
|
513
|
-
</file>
|
|
514
|
-
</finish>
|
|
515
|
-
\`\`\`
|
|
516
|
-
|
|
517
|
-
No commentary outside \`<think>\`. No explanations after tool calls.
|
|
518
|
-
</output_format>
|
|
519
|
-
|
|
520
|
-
use as all 8 tool calls to be optimal
|
|
521
|
-
|
|
522
|
-
<finishing_requirements>
|
|
523
|
-
When calling \`finish\`:
|
|
524
|
-
- Include the import section (typically lines 1-20) of each file
|
|
525
|
-
- Include all function/class definitions that are relevant
|
|
526
|
-
- Include any type definitions, interfaces, or constants used
|
|
527
|
-
- Better to over-include than leave the user missing context
|
|
528
|
-
- If unsure about boundaries, include more rather than less
|
|
529
|
-
</finishing_requirements>`;
|
|
530
|
-
function getSystemPrompt() {
|
|
531
|
-
return SYSTEM_PROMPT;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
179
|
// tools/warp_grep/agent/formatter.ts
|
|
535
180
|
var ToolOutputFormatter = class {
|
|
536
|
-
format(toolName,
|
|
181
|
+
format(toolName, _args, output, options = {}) {
|
|
537
182
|
const name = (toolName ?? "").trim();
|
|
538
183
|
if (!name) {
|
|
539
184
|
return "";
|
|
540
185
|
}
|
|
541
186
|
const payload = output?.toString?.()?.trim?.() ?? "";
|
|
542
187
|
const isError = Boolean(options.isError);
|
|
543
|
-
const safeArgs = args ?? {};
|
|
544
188
|
if (!payload && !isError) {
|
|
545
189
|
return "";
|
|
546
190
|
}
|
|
547
|
-
|
|
548
|
-
case "read":
|
|
549
|
-
return this.formatRead(safeArgs, payload, isError);
|
|
550
|
-
case "list_directory":
|
|
551
|
-
return this.formatListDirectory(safeArgs, payload, isError);
|
|
552
|
-
case "grep":
|
|
553
|
-
return this.formatGrep(safeArgs, payload, isError);
|
|
554
|
-
default:
|
|
555
|
-
return payload ? `<tool_output>
|
|
556
|
-
${payload}
|
|
557
|
-
</tool_output>` : "";
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
formatRead(args, payload, isError) {
|
|
561
|
-
if (isError) {
|
|
562
|
-
return payload;
|
|
563
|
-
}
|
|
564
|
-
const path4 = this.asString(args.path) || "...";
|
|
565
|
-
const start = args.start;
|
|
566
|
-
const end = args.end;
|
|
567
|
-
const linesArray = args.lines;
|
|
568
|
-
const attributes = [`path="${path4}"`];
|
|
569
|
-
if (linesArray && linesArray.length > 0) {
|
|
570
|
-
const rangeStr = linesArray.map(([s, e]) => `${s}-${e}`).join(",");
|
|
571
|
-
attributes.push(`lines="${rangeStr}"`);
|
|
572
|
-
} else if (start !== void 0 && end !== void 0) {
|
|
573
|
-
attributes.push(`lines="${start}-${end}"`);
|
|
574
|
-
}
|
|
575
|
-
return `<read ${attributes.join(" ")}>
|
|
191
|
+
return `<tool_response>
|
|
576
192
|
${payload}
|
|
577
|
-
</
|
|
578
|
-
}
|
|
579
|
-
formatListDirectory(args, payload, isError) {
|
|
580
|
-
const path4 = this.asString(args.path) || ".";
|
|
581
|
-
const pattern = this.asString(args.pattern);
|
|
582
|
-
const attributes = [`path="${path4}"`];
|
|
583
|
-
if (pattern) {
|
|
584
|
-
attributes.push(`pattern="${pattern}"`);
|
|
585
|
-
}
|
|
586
|
-
if (isError) {
|
|
587
|
-
attributes.push('status="error"');
|
|
588
|
-
}
|
|
589
|
-
return `<list_directory ${attributes.join(" ")}>
|
|
590
|
-
${payload}
|
|
591
|
-
</list_directory>`;
|
|
592
|
-
}
|
|
593
|
-
formatGrep(args, payload, isError) {
|
|
594
|
-
const pattern = this.asString(args.pattern);
|
|
595
|
-
const subDir = this.asString(args.path);
|
|
596
|
-
const glob = this.asString(args.glob);
|
|
597
|
-
const attributes = [];
|
|
598
|
-
if (pattern !== void 0) {
|
|
599
|
-
attributes.push(`pattern="${pattern}"`);
|
|
600
|
-
}
|
|
601
|
-
if (subDir !== void 0) {
|
|
602
|
-
attributes.push(`sub_dir="${subDir}"`);
|
|
603
|
-
}
|
|
604
|
-
if (glob !== void 0) {
|
|
605
|
-
attributes.push(`glob="${glob}"`);
|
|
606
|
-
}
|
|
607
|
-
if (isError) {
|
|
608
|
-
attributes.push('status="error"');
|
|
609
|
-
}
|
|
610
|
-
const attrText = attributes.length ? ` ${attributes.join(" ")}` : "";
|
|
611
|
-
return `<grep${attrText}>
|
|
612
|
-
${payload}
|
|
613
|
-
</grep>`;
|
|
614
|
-
}
|
|
615
|
-
asString(value) {
|
|
616
|
-
if (value === null || value === void 0) {
|
|
617
|
-
return void 0;
|
|
618
|
-
}
|
|
619
|
-
return String(value);
|
|
193
|
+
</tool_response>`;
|
|
620
194
|
}
|
|
621
195
|
};
|
|
622
196
|
var sharedFormatter = new ToolOutputFormatter();
|
|
@@ -742,12 +316,15 @@ function calculateContextBudget(messages) {
|
|
|
742
316
|
const maxK = Math.round(maxChars / 1e3);
|
|
743
317
|
return `<context_budget>${percent}% (${usedK}K/${maxK}K chars)</context_budget>`;
|
|
744
318
|
}
|
|
745
|
-
async function buildInitialState(repoRoot, query, provider) {
|
|
319
|
+
async function buildInitialState(repoRoot, query, provider, options) {
|
|
320
|
+
const budget = calculateContextBudget([]);
|
|
321
|
+
const turnTag = `Turn 0/${AGENT_CONFIG.MAX_TURNS}`;
|
|
322
|
+
const treeDepth = options?.query_type === "node_modules" ? 1 : 2;
|
|
746
323
|
try {
|
|
747
324
|
const entries = await provider.listDirectory({
|
|
748
325
|
path: ".",
|
|
749
326
|
maxResults: AGENT_CONFIG.MAX_OUTPUT_LINES,
|
|
750
|
-
maxDepth:
|
|
327
|
+
maxDepth: treeDepth
|
|
751
328
|
});
|
|
752
329
|
const treeLines = entries.map((e) => {
|
|
753
330
|
const indent = " ".repeat(e.depth);
|
|
@@ -763,7 +340,9 @@ ${treeOutput}
|
|
|
763
340
|
|
|
764
341
|
<search_string>
|
|
765
342
|
${query}
|
|
766
|
-
</search_string
|
|
343
|
+
</search_string>
|
|
344
|
+
${budget}
|
|
345
|
+
${turnTag}`;
|
|
767
346
|
} catch {
|
|
768
347
|
const repoName = import_path.default.basename(repoRoot);
|
|
769
348
|
return `<repo_structure>
|
|
@@ -772,7 +351,9 @@ ${repoName}/
|
|
|
772
351
|
|
|
773
352
|
<search_string>
|
|
774
353
|
${query}
|
|
775
|
-
</search_string
|
|
354
|
+
</search_string>
|
|
355
|
+
${budget}
|
|
356
|
+
${turnTag}`;
|
|
776
357
|
}
|
|
777
358
|
}
|
|
778
359
|
function formatListDirectoryTree(entries) {
|
|
@@ -849,14 +430,12 @@ async function toolListDirectory(provider, args) {
|
|
|
849
430
|
}
|
|
850
431
|
const { entries: list } = await getListRecursive(initialDepth);
|
|
851
432
|
if (!list.length) return "empty";
|
|
852
|
-
|
|
853
|
-
return "query not specific enough, tool called tried to return too much context and failed";
|
|
854
|
-
}
|
|
855
|
-
return list.map((e) => {
|
|
433
|
+
const tree = list.map((e) => {
|
|
856
434
|
const indent = " ".repeat(e.depth);
|
|
857
435
|
const name = e.type === "dir" ? `${e.name}/` : e.name;
|
|
858
436
|
return `${indent}${name}`;
|
|
859
437
|
}).join("\n");
|
|
438
|
+
return tree;
|
|
860
439
|
}
|
|
861
440
|
|
|
862
441
|
// tools/warp_grep/agent/tools/finish.ts
|
|
@@ -1134,7 +713,8 @@ var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
1134
713
|
".map",
|
|
1135
714
|
".js.map"
|
|
1136
715
|
]);
|
|
1137
|
-
function shouldSkip(name) {
|
|
716
|
+
function shouldSkip(name, allowNames) {
|
|
717
|
+
if (allowNames?.has(name)) return false;
|
|
1138
718
|
if (SKIP_NAMES.has(name)) return true;
|
|
1139
719
|
if (name.startsWith(".")) return true;
|
|
1140
720
|
for (const ext of SKIP_EXTENSIONS) {
|
|
@@ -1143,10 +723,14 @@ function shouldSkip(name) {
|
|
|
1143
723
|
return false;
|
|
1144
724
|
}
|
|
1145
725
|
var LocalRipgrepProvider = class {
|
|
1146
|
-
constructor(repoRoot, excludes = DEFAULT_EXCLUDES) {
|
|
726
|
+
constructor(repoRoot, excludes = DEFAULT_EXCLUDES, options) {
|
|
1147
727
|
this.repoRoot = repoRoot;
|
|
1148
728
|
this.excludes = excludes;
|
|
729
|
+
if (options?.allowNames?.length) {
|
|
730
|
+
this.allowNames = new Set(options.allowNames);
|
|
731
|
+
}
|
|
1149
732
|
}
|
|
733
|
+
allowNames;
|
|
1150
734
|
async grep(params) {
|
|
1151
735
|
let abs;
|
|
1152
736
|
try {
|
|
@@ -1160,6 +744,7 @@ var LocalRipgrepProvider = class {
|
|
|
1160
744
|
const stat = await import_promises2.default.stat(abs).catch(() => null);
|
|
1161
745
|
if (!stat) return { lines: [] };
|
|
1162
746
|
const targetArg = abs === import_path3.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
|
|
747
|
+
const contextLines = params.context_lines !== void 0 ? String(params.context_lines) : "1";
|
|
1163
748
|
const args = [
|
|
1164
749
|
"--no-config",
|
|
1165
750
|
"--no-heading",
|
|
@@ -1169,9 +754,10 @@ var LocalRipgrepProvider = class {
|
|
|
1169
754
|
"--trim",
|
|
1170
755
|
"--max-columns=400",
|
|
1171
756
|
"-C",
|
|
1172
|
-
|
|
757
|
+
contextLines,
|
|
758
|
+
...params.case_sensitive === false ? ["--ignore-case"] : [],
|
|
1173
759
|
...params.glob ? ["--glob", params.glob] : [],
|
|
1174
|
-
...this.excludes.flatMap((e) => ["-g", `!${e}`]),
|
|
760
|
+
...this.excludes.filter((e) => !this.allowNames?.has(e)).flatMap((e) => ["-g", `!${e}`]),
|
|
1175
761
|
params.pattern,
|
|
1176
762
|
targetArg || "."
|
|
1177
763
|
];
|
|
@@ -1196,10 +782,9 @@ Details: ${res.stderr}` : ""}`
|
|
|
1196
782
|
}
|
|
1197
783
|
const lines = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
|
|
1198
784
|
if (lines.length > AGENT_CONFIG.MAX_OUTPUT_LINES) {
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
};
|
|
785
|
+
const truncated = lines.slice(0, AGENT_CONFIG.MAX_OUTPUT_LINES);
|
|
786
|
+
truncated.push(`... (output truncated at ${AGENT_CONFIG.MAX_OUTPUT_LINES} of ${lines.length} lines)`);
|
|
787
|
+
return { lines: truncated };
|
|
1203
788
|
}
|
|
1204
789
|
return { lines };
|
|
1205
790
|
}
|
|
@@ -1273,7 +858,7 @@ Details: ${res.stderr}` : ""}`
|
|
|
1273
858
|
}
|
|
1274
859
|
if (out.length > AGENT_CONFIG.MAX_READ_LINES) {
|
|
1275
860
|
const truncated = out.slice(0, AGENT_CONFIG.MAX_READ_LINES);
|
|
1276
|
-
truncated.push(`...
|
|
861
|
+
truncated.push(`... (output truncated at ${AGENT_CONFIG.MAX_READ_LINES} of ${out.length} lines)`);
|
|
1277
862
|
return { lines: truncated };
|
|
1278
863
|
}
|
|
1279
864
|
return { lines: out };
|
|
@@ -1293,6 +878,7 @@ Details: ${res.stderr}` : ""}`
|
|
|
1293
878
|
const maxDepth = params.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
|
|
1294
879
|
const regex = params.pattern ? new RegExp(params.pattern) : null;
|
|
1295
880
|
const repoRoot = this.repoRoot;
|
|
881
|
+
const allowNames = this.allowNames;
|
|
1296
882
|
const results = [];
|
|
1297
883
|
let timedOut = false;
|
|
1298
884
|
const startTime = Date.now();
|
|
@@ -1310,7 +896,7 @@ Details: ${res.stderr}` : ""}`
|
|
|
1310
896
|
}
|
|
1311
897
|
for (const entry of entries) {
|
|
1312
898
|
if (timedOut || results.length >= maxResults) break;
|
|
1313
|
-
if (shouldSkip(entry.name)) continue;
|
|
899
|
+
if (shouldSkip(entry.name, allowNames)) continue;
|
|
1314
900
|
if (regex && !regex.test(entry.name)) continue;
|
|
1315
901
|
const full = import_path3.default.join(dir, entry.name);
|
|
1316
902
|
const isDir = entry.isDirectory();
|
|
@@ -1350,13 +936,11 @@ async function resolveFinishFiles(provider, files) {
|
|
|
1350
936
|
DEFAULT_EXCLUDES,
|
|
1351
937
|
LLMResponseParser,
|
|
1352
938
|
LocalRipgrepProvider,
|
|
1353
|
-
SYSTEM_PROMPT,
|
|
1354
939
|
buildInitialState,
|
|
1355
940
|
calculateContextBudget,
|
|
1356
941
|
formatListDirectoryTree,
|
|
1357
942
|
formatToolResult,
|
|
1358
943
|
formatTurnMessage,
|
|
1359
|
-
getSystemPrompt,
|
|
1360
944
|
normalizeFinishFiles,
|
|
1361
945
|
parseToolCalls,
|
|
1362
946
|
readFinishFiles,
|