fix(look-at): add catch block to prevent TUI crash on unexpected errors

This commit is contained in:
YeonGyu-Kim 2026-03-05 11:11:53 +09:00
parent fc41a389c5
commit c8c99445ea
2 changed files with 94 additions and 0 deletions

View File

@ -456,6 +456,96 @@ describe("look-at tool", () => {
})
})
describe("createLookAt unhandled error resilience", () => {
const createToolContext = (): ToolContext => ({
sessionID: "parent-session",
messageID: "parent-message",
agent: "sisyphus",
directory: "/project",
worktree: "/project",
abort: new AbortController().signal,
metadata: () => {},
ask: async () => {},
})
// given session.create throws (network error, not error response)
// when LookAt tool executed
// then returns error string instead of crashing
test("catches session.create throw and returns error string", async () => {
const mockClient = {
session: {
get: async () => ({ data: { directory: "/project" } }),
create: async () => { throw new Error("ECONNREFUSED: connection refused") },
},
}
const tool = createLookAt({
client: mockClient,
directory: "/project",
} as any)
const result = await tool.execute(
{ file_path: "/test/file.png", goal: "analyze" },
createToolContext(),
)
expect(result).toContain("Error")
expect(result).toContain("ECONNREFUSED")
})
// given session.messages throws unexpectedly
// when LookAt tool executed
// then returns error string instead of crashing
test("catches session.messages throw and returns error string", async () => {
const mockClient = {
app: {
agents: async () => ({ data: [] }),
},
session: {
get: async () => ({ data: { directory: "/project" } }),
create: async () => ({ data: { id: "ses_msg_throw" } }),
prompt: async () => ({}),
messages: async () => { throw new Error("Unexpected server error") },
},
}
const tool = createLookAt({
client: mockClient,
directory: "/project",
} as any)
const result = await tool.execute(
{ file_path: "/test/file.png", goal: "analyze" },
createToolContext(),
)
expect(result).toContain("Error")
expect(result).toContain("Unexpected server error")
})
// given a non-Error object is thrown
// when LookAt tool executed
// then still returns error string
test("handles non-Error thrown objects gracefully", async () => {
const mockClient = {
session: {
get: async () => ({ data: { directory: "/project" } }),
create: async () => { throw "string error thrown" },
},
}
const tool = createLookAt({
client: mockClient,
directory: "/project",
} as any)
const result = await tool.execute(
{ file_path: "/test/file.png", goal: "analyze" },
createToolContext(),
)
expect(result).toContain("Error")
expect(result).toContain("string error thrown")
})
})
describe("createLookAt with image_data", () => {
// given base64 image data is provided
// when LookAt tool executed

View File

@ -217,6 +217,10 @@ Original error: ${createResult.error}`
log(`[look_at] Got response, length: ${responseText.length}`)
return responseText
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error)
log(`[look_at] Unexpected error analyzing ${sourceDescription}:`, error)
return `Error: Failed to analyze ${sourceDescription}: ${errorMessage}`
} finally {
if (tempConversionPath) {
cleanupConvertedImage(tempConversionPath)