Skip to content

Commit 5f2900d

Browse files
committed
refactor(api): unify completePrompt abort signal to use metadata.abortSignal
1 parent 3943a95 commit 5f2900d

55 files changed

Lines changed: 135 additions & 131 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/api/index.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,17 @@ import {
4040
} from "./providers"
4141
import { NativeOllamaHandler } from "./providers/native-ollama"
4242

43-
export interface CompletePromptOptions {
44-
/** Abort signal for cancelling the request mid-flight */
45-
signal?: AbortSignal
43+
/**
44+
* Options for completePrompt — unified with ApiHandlerCreateMessageMetadata.
45+
* Uses abortSignal (not signal) to match the metadata pattern used in stream path.
46+
*/
47+
export interface CompletePromptOptions extends Pick<ApiHandlerCreateMessageMetadata, "abortSignal"> {
4648
/** Optional timeout override (ms) — falls back to provider default if omitted */
4749
timeoutMs?: number
4850
}
4951

5052
export interface SingleCompletionHandler {
51-
completePrompt(prompt: string, options?: CompletePromptOptions): Promise<string>
53+
completePrompt(prompt: string, metadata?: CompletePromptOptions): Promise<string>
5254
}
5355

5456
export interface ApiHandlerCreateMessageMetadata {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ describe("VertexHandler", () => {
913913
})
914914
;(handler["client"].messages as any).create = mockCreate
915915

916-
await handler.completePrompt("test prompt", { signal: controller.signal })
916+
await handler.completePrompt("test prompt", { abortSignal: controller.signal })
917917
expect(mockCreate).toHaveBeenCalledWith(expect.objectContaining({ model: expect.any(String) }), {
918918
signal: controller.signal,
919919
})
@@ -943,7 +943,7 @@ describe("VertexHandler", () => {
943943
})
944944
;(handler["client"].messages as any).create = mockCreate
945945

946-
await handler.completePrompt("test prompt", { signal: controller.signal, timeoutMs: 5000 })
946+
await handler.completePrompt("test prompt", { abortSignal: controller.signal, timeoutMs: 5000 })
947947
expect(mockCreate).toHaveBeenCalledWith(
948948
expect.objectContaining({ model: expect.any(String) }),
949949
{ signal: controller.signal }, // only signal is passed, not timeoutMs

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ describe("AnthropicHandler", () => {
471471
it("should pass abort signal through to client", async () => {
472472
const controller = new AbortController()
473473
mockCreate.mockResolvedValueOnce({ content: [{ type: "text", text: "response" }] })
474-
await handler.completePrompt("test prompt", { signal: controller.signal })
474+
await handler.completePrompt("test prompt", { abortSignal: controller.signal })
475475
expect(mockCreate).toHaveBeenCalledWith(
476476
{
477477
model: mockOptions.apiModelId,
@@ -505,7 +505,7 @@ describe("AnthropicHandler", () => {
505505
it("should merge signal and timeout together", async () => {
506506
const controller = new AbortController()
507507
mockCreate.mockResolvedValueOnce({ content: [{ type: "text", text: "response" }] })
508-
await handler.completePrompt("test prompt", { signal: controller.signal, timeoutMs: 10000 })
508+
await handler.completePrompt("test prompt", { abortSignal: controller.signal, timeoutMs: 10000 })
509509
expect(mockCreate).toHaveBeenCalledWith(
510510
{
511511
model: mockOptions.apiModelId,
@@ -535,9 +535,11 @@ describe("AnthropicHandler", () => {
535535

536536
const controller = new AbortController()
537537
let timeoutTriggered = false
538-
handlerTimeout.completePrompt("test prompt", { signal: controller.signal, timeoutMs: 50 }).catch(() => {
539-
timeoutTriggered = true
540-
})
538+
handlerTimeout
539+
.completePrompt("test prompt", { abortSignal: controller.signal, timeoutMs: 50 })
540+
.catch(() => {
541+
timeoutTriggered = true
542+
})
541543

542544
// Wait for timeout to trigger (50ms timeout + buffer)
543545
await new Promise((resolve) => setTimeout(resolve, 150))
@@ -551,7 +553,7 @@ describe("AnthropicHandler", () => {
551553
it("should pass the same signal instance", async () => {
552554
const controller = new AbortController()
553555
mockCreate.mockResolvedValueOnce({ content: [{ type: "text", text: "response" }] })
554-
await handler.completePrompt("test prompt", { signal: controller.signal })
556+
await handler.completePrompt("test prompt", { abortSignal: controller.signal })
555557
expect(mockCreate).toHaveBeenCalledWith(
556558
expect.any(Object),
557559
expect.objectContaining({ signal: controller.signal }),

src/api/providers/__tests__/base-openai-compatible-provider-timeout.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ describe("BaseOpenAiCompatibleProvider Timeout Configuration", () => {
126126
})
127127
handler["client"].chat.completions.create = mockCreate
128128

129-
await handler.completePrompt("test prompt", { signal: controller.signal, timeoutMs: 5000 })
129+
await handler.completePrompt("test prompt", { abortSignal: controller.signal, timeoutMs: 5000 })
130130
expect(mockCreate).toHaveBeenCalledWith(
131131
expect.objectContaining({ model: "test-model" }),
132132
expect.objectContaining({ signal: expect.any(AbortSignal), timeout: 5000 }),

src/api/providers/__tests__/bedrock.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1597,7 +1597,7 @@ describe("AwsBedrockHandler", () => {
15971597
output: { message: { content: [{ type: "text", text: "response" }] }, stopReason: null },
15981598
})
15991599

1600-
await handler.completePrompt("test prompt", { signal: controller.signal })
1600+
await handler.completePrompt("test prompt", { abortSignal: controller.signal })
16011601

16021602
expect(mockSend).toHaveBeenCalledWith(expect.any(Object), { abortSignal: controller.signal })
16031603
})

src/api/providers/__tests__/complete-prompt-options.spec.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,27 @@ import { describe, it, expect } from "vitest"
33
import type { CompletePromptOptions } from "../../index"
44

55
describe("CompletePromptOptions", () => {
6-
it("should allow signal property", () => {
6+
it("should allow abortSignal property", () => {
77
const controller = new AbortController()
8-
const options: CompletePromptOptions = { signal: controller.signal }
9-
expect(options.signal).toBe(controller.signal)
8+
const options: CompletePromptOptions = { abortSignal: controller.signal }
9+
expect(options.abortSignal).toBe(controller.signal)
1010
})
1111

1212
it("should allow timeoutMs property", () => {
1313
const options: CompletePromptOptions = { timeoutMs: 5000 }
1414
expect(options.timeoutMs).toBe(5000)
1515
})
1616

17-
it("should allow both signal and timeoutMs together", () => {
17+
it("should allow both abortSignal and timeoutMs together", () => {
1818
const controller = new AbortController()
19-
const options: CompletePromptOptions = { signal: controller.signal, timeoutMs: 10000 }
20-
expect(options.signal).toBe(controller.signal)
19+
const options: CompletePromptOptions = { abortSignal: controller.signal, timeoutMs: 10000 }
20+
expect(options.abortSignal).toBe(controller.signal)
2121
expect(options.timeoutMs).toBe(10000)
2222
})
2323

2424
it("should allow empty options object", () => {
2525
const options: CompletePromptOptions = {}
26-
expect(options.signal).toBeUndefined()
26+
expect(options.abortSignal).toBeUndefined()
2727
expect(options.timeoutMs).toBeUndefined()
2828
})
2929
})

src/api/providers/__tests__/deepseek.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ describe("DeepSeekHandler", () => {
725725
mockCreate.mockResolvedValueOnce({
726726
choices: [{ message: { content: "response" } }],
727727
})
728-
await handler.completePrompt("test prompt", { signal: controller.signal })
728+
await handler.completePrompt("test prompt", { abortSignal: controller.signal })
729729
expect(mockCreate).toHaveBeenCalledWith(
730730
expect.objectContaining({ model: expect.any(String) }),
731731
expect.objectContaining({ signal: controller.signal }),

src/api/providers/__tests__/fireworks.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ describe("FireworksHandler", () => {
612612
it("completePrompt should pass abort signal through to client", async () => {
613613
const controller = new AbortController()
614614
mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: "response" } }] })
615-
await handler.completePrompt("test prompt", { signal: controller.signal })
615+
await handler.completePrompt("test prompt", { abortSignal: controller.signal })
616616
expect(mockCreate).toHaveBeenCalledWith(
617617
expect.objectContaining({ model: expect.any(String) }),
618618
expect.objectContaining({ signal: controller.signal }),
@@ -631,7 +631,7 @@ describe("FireworksHandler", () => {
631631
it("completePrompt should merge signal and timeoutMs together", async () => {
632632
const controller = new AbortController()
633633
mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: "response" } }] })
634-
await handler.completePrompt("test prompt", { signal: controller.signal, timeoutMs: 10000 })
634+
await handler.completePrompt("test prompt", { abortSignal: controller.signal, timeoutMs: 10000 })
635635
expect(mockCreate).toHaveBeenCalledWith(
636636
expect.objectContaining({ model: expect.any(String) }),
637637
expect.objectContaining({ signal: controller.signal, timeout: 10000 }),

src/api/providers/__tests__/gemini-handler.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ describe("GeminiHandler backend support", () => {
6767
const stub = vi.fn().mockResolvedValue({ text: "response" })
6868
handler["client"].models.generateContent = stub
6969

70-
await handler.completePrompt("test prompt", { signal: controller.signal })
70+
await handler.completePrompt("test prompt", { abortSignal: controller.signal })
7171

7272
expect(stub).toHaveBeenCalledWith(
7373
expect.objectContaining({

src/api/providers/__tests__/gemini.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ describe("GeminiHandler", () => {
160160
it("should pass abort signal through to client via httpOptions", async () => {
161161
const controller = new AbortController()
162162
;(handler["client"].models.generateContent as any).mockResolvedValue({ text: "response" })
163-
await handler.completePrompt("test prompt", { signal: controller.signal })
163+
await handler.completePrompt("test prompt", { abortSignal: controller.signal })
164164
expect(handler["client"].models.generateContent).toHaveBeenCalledWith({
165165
model: GEMINI_MODEL_NAME,
166166
contents: [{ role: "user", parts: [{ text: "test prompt" }] }],
@@ -188,7 +188,7 @@ describe("GeminiHandler", () => {
188188
it("should pass timeoutMs through to client via httpOptions", async () => {
189189
const controller = new AbortController()
190190
;(handler["client"].models.generateContent as any).mockResolvedValue({ text: "response" })
191-
await handler.completePrompt("test prompt", { signal: controller.signal, timeoutMs: 10000 })
191+
await handler.completePrompt("test prompt", { abortSignal: controller.signal, timeoutMs: 10000 })
192192
expect(handler["client"].models.generateContent).toHaveBeenCalledWith({
193193
model: GEMINI_MODEL_NAME,
194194
contents: [{ role: "user", parts: [{ text: "test prompt" }] }],

0 commit comments

Comments
 (0)