Skip to content

Commit 698ad37

Browse files
authored
Merge pull request #8254 from continuedev/pe/tool-call-errors
fix: log correct tool call error from gui
2 parents 48a918c + 2d861bf commit 698ad37

File tree

14 files changed

+75
-17
lines changed

14 files changed

+75
-17
lines changed

core/protocol/core.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,11 @@ export type ToCoreFromIdeOrWebviewProtocol = {
307307
"auth/getAuthUrl": [{ useOnboarding: boolean }, { url: string }];
308308
"tools/call": [
309309
{ toolCall: ToolCall },
310-
{ contextItems: ContextItem[]; errorMessage?: string },
310+
{
311+
contextItems: ContextItem[];
312+
errorMessage?: string;
313+
errorReason?: ContinueErrorReason;
314+
},
311315
];
312316
"tools/evaluatePolicy": [
313317
{ toolName: string; basePolicy: ToolPolicy; args: Record<string, unknown> },

core/tools/callTool.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types.js";
22
import { ContextItem, Tool, ToolCall, ToolExtras } from "..";
33
import { MCPManagerSingleton } from "../context/mcp/MCPManagerSingleton";
4+
import { ContinueError, ContinueErrorReason } from "../util/errors";
45
import { canParseUrl } from "../util/url";
56
import { BuiltInToolNames } from "./builtIn";
67

@@ -197,6 +198,7 @@ export async function callTool(
197198
): Promise<{
198199
contextItems: ContextItem[];
199200
errorMessage: string | undefined;
201+
errorReason?: ContinueErrorReason;
200202
}> {
201203
try {
202204
const args = safeParseToolCallArgs(toolCall);
@@ -214,12 +216,19 @@ export async function callTool(
214216
};
215217
} catch (e) {
216218
let errorMessage = `${e}`;
217-
if (e instanceof Error) {
219+
let errorReason: ContinueErrorReason | undefined;
220+
221+
if (e instanceof ContinueError) {
222+
errorMessage = e.message;
223+
errorReason = e.reason;
224+
} else if (e instanceof Error) {
218225
errorMessage = e.message;
219226
}
227+
220228
return {
221229
contextItems: [],
222230
errorMessage,
231+
errorReason,
223232
};
224233
}
225234
}

core/tools/implementations/createNewFile.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { inferResolvedUriFromRelativePath } from "../../util/ideUtils";
33
import { ToolImpl } from ".";
44
import { getCleanUriPath, getUriPathBasename } from "../../util/uri";
55
import { getStringArg } from "../parseArgs";
6+
import { ContinueError, ContinueErrorReason } from "../../util/errors";
67

78
export const createNewFileImpl: ToolImpl = async (args, extras) => {
89
const filepath = getStringArg(args, "filepath");
@@ -15,7 +16,8 @@ export const createNewFileImpl: ToolImpl = async (args, extras) => {
1516
if (resolvedFileUri) {
1617
const exists = await extras.ide.fileExists(resolvedFileUri);
1718
if (exists) {
18-
throw new Error(
19+
throw new ContinueError(
20+
ContinueErrorReason.FileAlreadyExists,
1921
`File ${filepath} already exists. Use the edit tool to edit this file`,
2022
);
2123
}
@@ -37,6 +39,9 @@ export const createNewFileImpl: ToolImpl = async (args, extras) => {
3739
},
3840
];
3941
} else {
40-
throw new Error("Failed to resolve path");
42+
throw new ContinueError(
43+
ContinueErrorReason.PathResolutionFailed,
44+
"Failed to resolve path",
45+
);
4146
}
4247
};

core/tools/implementations/grepSearch.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ToolImpl } from ".";
22
import { ContextItem } from "../..";
3+
import { ContinueError, ContinueErrorReason } from "../../util/errors";
34
import { formatGrepSearchResults } from "../../util/grepSearch";
45
import { prepareQueryForRipgrep } from "../../util/regexValidator";
56
import { getStringArg } from "../parseArgs";
@@ -63,7 +64,10 @@ export const grepSearchImpl: ToolImpl = async (args, extras) => {
6364
];
6465
}
6566

66-
throw error;
67+
throw new ContinueError(
68+
ContinueErrorReason.SearchExecutionFailed,
69+
errorMessage,
70+
);
6771
}
6872

6973
const { formatted, numResults, truncated } = formatGrepSearchResults(

core/tools/implementations/lsTool.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import ignore from "ignore";
33
import { ToolImpl } from ".";
44
import { walkDir } from "../../indexing/walkDir";
55
import { resolveRelativePathInDir } from "../../util/ideUtils";
6+
import { ContinueError, ContinueErrorReason } from "../../util/errors";
67

78
export function resolveLsToolDirPath(dirPath: string | undefined) {
89
if (!dirPath || dirPath === ".") {
@@ -20,7 +21,8 @@ export const lsToolImpl: ToolImpl = async (args, extras) => {
2021
const dirPath = resolveLsToolDirPath(args?.dirPath);
2122
const uri = await resolveRelativePathInDir(dirPath, extras.ide);
2223
if (!uri) {
23-
throw new Error(
24+
throw new ContinueError(
25+
ContinueErrorReason.DirectoryNotFound,
2426
`Directory ${args.dirPath} not found. Make sure to use forward-slash paths`,
2527
);
2628
}

core/tools/implementations/readFile.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ import { ToolImpl } from ".";
55
import { throwIfFileIsSecurityConcern } from "../../indexing/ignore";
66
import { getStringArg } from "../parseArgs";
77
import { throwIfFileExceedsHalfOfContext } from "./readFileLimit";
8+
import { ContinueError, ContinueErrorReason } from "../../util/errors";
89

910
export const readFileImpl: ToolImpl = async (args, extras) => {
1011
const filepath = getStringArg(args, "filepath");
1112
throwIfFileIsSecurityConcern(filepath);
1213

1314
const firstUriMatch = await resolveRelativePathInDir(filepath, extras.ide);
1415
if (!firstUriMatch) {
15-
throw new Error(
16+
throw new ContinueError(
17+
ContinueErrorReason.FileNotFound,
1618
`File "${filepath}" does not exist. You might want to check the path and try again.`,
1719
);
1820
}

core/tools/implementations/readFileLimit.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ILLM } from "../..";
22
import { countTokensAsync } from "../../llm/countTokens";
3+
import { ContinueError, ContinueErrorReason } from "../../util/errors";
34

45
export async function throwIfFileExceedsHalfOfContext(
56
filepath: string,
@@ -10,7 +11,8 @@ export async function throwIfFileExceedsHalfOfContext(
1011
const tokens = await countTokensAsync(content, model.title);
1112
const tokenLimit = model.contextLength / 2;
1213
if (tokens > tokenLimit) {
13-
throw new Error(
14+
throw new ContinueError(
15+
ContinueErrorReason.FileTooLarge,
1416
`File ${filepath} is too large (${tokens} tokens vs ${tokenLimit} token limit). Try another approach`,
1517
);
1618
}

core/tools/implementations/readFileRange.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { getUriPathBasename } from "../../util/uri";
44
import { ToolImpl } from ".";
55
import { getNumberArg, getStringArg } from "../parseArgs";
66
import { throwIfFileExceedsHalfOfContext } from "./readFileLimit";
7+
import { ContinueError, ContinueErrorReason } from "../../util/errors";
78

89
export const readFileRangeImpl: ToolImpl = async (args, extras) => {
910
const filepath = getStringArg(args, "filepath");
@@ -12,24 +13,28 @@ export const readFileRangeImpl: ToolImpl = async (args, extras) => {
1213

1314
// Validate that line numbers are positive integers
1415
if (startLine < 1) {
15-
throw new Error(
16+
throw new ContinueError(
17+
ContinueErrorReason.InvalidLineNumber,
1618
"startLine must be 1 or greater. Negative line numbers are not supported - use the terminal tool with 'tail' command for reading from file end.",
1719
);
1820
}
1921
if (endLine < 1) {
20-
throw new Error(
22+
throw new ContinueError(
23+
ContinueErrorReason.InvalidLineNumber,
2124
"endLine must be 1 or greater. Negative line numbers are not supported - use the terminal tool with 'tail' command for reading from file end.",
2225
);
2326
}
2427
if (endLine < startLine) {
25-
throw new Error(
28+
throw new ContinueError(
29+
ContinueErrorReason.InvalidLineNumber,
2630
`endLine (${endLine}) must be greater than or equal to startLine (${startLine})`,
2731
);
2832
}
2933

3034
const firstUriMatch = await resolveRelativePathInDir(filepath, extras.ide);
3135
if (!firstUriMatch) {
32-
throw new Error(
36+
throw new ContinueError(
37+
ContinueErrorReason.FileNotFound,
3338
`File "${filepath}" does not exist. You might want to check the path and try again.`,
3439
);
3540
}

core/tools/implementations/requestRule.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ToolImpl } from ".";
2+
import { ContinueError, ContinueErrorReason } from "../../util/errors";
23
import { getStringArg } from "../parseArgs";
34

45
export const requestRuleImpl: ToolImpl = async (args, extras) => {
@@ -8,7 +9,10 @@ export const requestRuleImpl: ToolImpl = async (args, extras) => {
89
const rule = extras.config.rules.find((r) => r.name === name);
910

1011
if (!rule || !rule.sourceFile) {
11-
throw new Error(`Rule with name "${name}" not found or has no file path`);
12+
throw new ContinueError(
13+
ContinueErrorReason.RuleNotFound,
14+
`Rule with name "${name}" not found or has no file path`,
15+
);
1216
}
1317

1418
return [

core/tools/implementations/runTerminalCommand.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import iconv from "iconv-lite";
22
import childProcess from "node:child_process";
33
import os from "node:os";
44
import util from "node:util";
5+
import { ContinueError, ContinueErrorReason } from "../../util/errors";
56
// Automatically decode the buffer according to the platform to avoid garbled Chinese
67
function getDecodedOutput(data: Buffer): string {
78
if (process.platform === "win32") {
@@ -337,7 +338,8 @@ export const runTerminalCommandImpl: ToolImpl = async (args, extras) => {
337338
if (code === 0) {
338339
resolve({ stdout, stderr });
339340
} else {
340-
const error = new Error(
341+
const error = new ContinueError(
342+
ContinueErrorReason.CommandExecutionFailed,
341343
`Command failed with exit code ${code}`,
342344
);
343345
(error as any).stderr = stderr;

0 commit comments

Comments
 (0)