Skip to content

Commit 1211eaa

Browse files
authored
fix: avoid unsafe array index access in AnthropicVertex completePrompt (#789)
The completePrompt method accessed response.content[0] directly, which could throw a TypeError when the content array is empty, and would return an empty string when the first block is a non-text block (e.g. thinking or tool_use) even when a text block is present later in the array. Use Array.prototype.find() to locate the first text block, matching the pattern already used in anthropic.ts. This safely returns undefined for empty arrays and surfaces the actual text response regardless of its position among content blocks. Add regression tests covering an empty content array and a mixed content array where a thinking block precedes the text block. Signed-off-by: daewoongoh <dw.oh@samsung.com>
1 parent 4e5f601 commit 1211eaa

2 files changed

Lines changed: 40 additions & 7 deletions

File tree

src/api/providers/__tests__/anthropic-vertex.spec.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,41 @@ describe("VertexHandler", () => {
895895
const result = await handler.completePrompt("Test prompt")
896896
expect(result).toBe("")
897897
})
898+
899+
it("should handle empty content array for Claude", async () => {
900+
handler = new AnthropicVertexHandler({
901+
apiModelId: "claude-3-5-sonnet-v2@20241022",
902+
vertexProjectId: "test-project",
903+
vertexRegion: "us-central1",
904+
})
905+
906+
const mockCreate = vitest.fn().mockResolvedValue({
907+
content: [],
908+
})
909+
;(handler["client"].messages as any).create = mockCreate
910+
911+
const result = await handler.completePrompt("Test prompt")
912+
expect(result).toBe("")
913+
})
914+
915+
it("should return text from first text block when mixed content for Claude", async () => {
916+
handler = new AnthropicVertexHandler({
917+
apiModelId: "claude-3-5-sonnet-v2@20241022",
918+
vertexProjectId: "test-project",
919+
vertexRegion: "us-central1",
920+
})
921+
922+
const mockCreate = vitest.fn().mockResolvedValue({
923+
content: [
924+
{ type: "thinking", thinking: "internal reasoning" },
925+
{ type: "text", text: "visible response" },
926+
],
927+
})
928+
;(handler["client"].messages as any).create = mockCreate
929+
930+
const result = await handler.completePrompt("Test prompt")
931+
expect(result).toBe("visible response")
932+
})
898933
})
899934

900935
describe("getModel", () => {
@@ -1342,7 +1377,9 @@ describe("VertexHandler", () => {
13421377
}))
13431378
;(sonnetHandler["client"].messages as any).create = mockCreate
13441379

1345-
await sonnetHandler.createMessage("You are a helpful assistant", [{ role: "user", content: "Hello" }]).next()
1380+
await sonnetHandler
1381+
.createMessage("You are a helpful assistant", [{ role: "user", content: "Hello" }])
1382+
.next()
13461383

13471384
expect(mockCreate).toHaveBeenCalledWith(
13481385
expect.objectContaining({

src/api/providers/anthropic-vertex.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -297,13 +297,9 @@ export class AnthropicVertexHandler extends BaseProvider implements SingleComple
297297
} as Anthropic.Messages.MessageCreateParamsNonStreaming
298298

299299
const response = await this.client.messages.create(params)
300-
const content = response.content[0]
300+
const content = response.content.find(({ type }) => type === "text")
301301

302-
if (content.type === "text") {
303-
return content.text
304-
}
305-
306-
return ""
302+
return content?.type === "text" ? content.text : ""
307303
} catch (error) {
308304
if (error instanceof Error) {
309305
throw new Error(`Vertex completion error: ${error.message}`)

0 commit comments

Comments
 (0)