Skip to content

Commit cb153ec

Browse files
committed
refactor(api): adopt RequestConfigBuilder in feat/abort-r1-openai-native-compat abort wiring
1 parent 176a0fa commit cb153ec

4 files changed

Lines changed: 54 additions & 4 deletions

File tree

‎src/api/providers/__tests__/request-config-builder.spec.ts‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,4 +505,35 @@ describe("RequestConfigBuilder", () => {
505505
expect(config.maxTokens).toBe(2000)
506506
})
507507
})
508+
509+
describe("static merge helpers (canonical abort-signal entry points)", () => {
510+
it("returns undefined from mergeAbortSignalAndTimeout when no external signal and no valid timeout", () => {
511+
expect(RequestConfigBuilder.mergeAbortSignalAndTimeout(undefined, undefined)).toBeUndefined()
512+
expect(RequestConfigBuilder.mergeAbortSignalAndTimeout(undefined, 0)).toBeUndefined()
513+
expect(RequestConfigBuilder.mergeAbortSignalAndTimeout(undefined, -5)).toBeUndefined()
514+
})
515+
516+
it("returns the external signal directly when no timeout is merged", () => {
517+
const controller = new AbortController()
518+
expect(RequestConfigBuilder.mergeAbortSignalAndTimeout(controller.signal, undefined)).toBe(
519+
controller.signal,
520+
)
521+
expect(RequestConfigBuilder.mergeAbortSignalAndTimeout(controller.signal, 0)).toBe(controller.signal)
522+
})
523+
524+
it("returns the primary signal directly from mergeAbortSignals when there is no secondary", () => {
525+
const controller = new AbortController()
526+
expect(RequestConfigBuilder.mergeAbortSignals(controller.signal)).toBe(controller.signal)
527+
expect(RequestConfigBuilder.mergeAbortSignals(controller.signal, undefined)).toBe(controller.signal)
528+
})
529+
530+
it("delegates to AbortSignal.any when two distinct signals are merged", () => {
531+
const a = new AbortController()
532+
const b = new AbortController()
533+
const merged = RequestConfigBuilder.mergeAbortSignals(a.signal, b.signal)
534+
expect(merged.aborted).toBe(false)
535+
b.abort()
536+
expect(merged.aborted).toBe(true)
537+
})
538+
})
508539
})

‎src/api/providers/config-builder/request-config-builder.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,19 @@ export class RequestConfigBuilder<TOptions extends RequestConfigOptionsBase = Re
163163
builder.setAbortSignal(metadata)
164164
return builder.build()
165165
}
166+
167+
/**
168+
* Static canonical entry points for merging abort signals, mirroring the API
169+
* surface providers used before the builder existed. Delegate to the shared
170+
* utils in ../utils/abort-signal so timeout semantics (timeoutMs <= 0 disables
171+
* the timeout; native AbortSignal.timeout self-manages its timer) stay
172+
* single-sourced.
173+
*/
174+
static mergeAbortSignalAndTimeout(externalSignal?: AbortSignal, timeoutMs?: number): AbortSignal | undefined {
175+
return mergeAbortSignalAndTimeout(externalSignal, timeoutMs)
176+
}
177+
178+
static mergeAbortSignals(primarySignal: AbortSignal, secondarySignal?: AbortSignal): AbortSignal {
179+
return mergeAbortSignals(primarySignal, secondarySignal)
180+
}
166181
}

‎src/api/providers/openai-compatible.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { ApiStream, ApiStreamUsageChunk } from "../transform/stream"
1818
import { DEFAULT_HEADERS } from "./constants"
1919
import { BaseProvider } from "./base-provider"
2020
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata, CompletePromptOptions } from "../index"
21-
import { mergeAbortSignalAndTimeout } from "./utils/abort-signal"
21+
import { RequestConfigBuilder } from "./config-builder/request-config-builder"
2222

2323
/**
2424
* Configuration options for creating an OpenAI-compatible provider.
@@ -214,7 +214,10 @@ export abstract class OpenAICompatibleHandler extends BaseProvider implements Si
214214
temperature: this.config.temperature ?? 0,
215215
}
216216

217-
const mergedAbortSignal = mergeAbortSignalAndTimeout(options?.abortSignal, options?.timeoutMs)
217+
const mergedAbortSignal = RequestConfigBuilder.mergeAbortSignalAndTimeout(
218+
options?.abortSignal,
219+
options?.timeoutMs,
220+
)
218221
if (mergedAbortSignal) {
219222
generateOptions.abortSignal = mergedAbortSignal
220223
}

‎src/api/providers/openai-native.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import { NOT_PROVIDED } from "./constants"
3232
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata, CompletePromptOptions } from "../index"
3333
import { isMcpTool } from "../../utils/mcp-name"
3434
import { sanitizeOpenAiCallId } from "../../utils/tool-id"
35-
import { mergeAbortSignalAndTimeout } from "./utils/abort-signal"
35+
import { RequestConfigBuilder } from "./config-builder/request-config-builder"
3636

3737
export type OpenAiNativeModel = ReturnType<OpenAiNativeHandler["getModel"]>
3838

@@ -1552,7 +1552,8 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
15521552
// Request-local abort signal: merges the external abort signal with an optional
15531553
// timeout without touching this.abortController (owned by streaming requests).
15541554
const requestSignal =
1555-
mergeAbortSignalAndTimeout(options?.abortSignal, options?.timeoutMs) ?? new AbortController().signal
1555+
RequestConfigBuilder.mergeAbortSignalAndTimeout(options?.abortSignal, options?.timeoutMs) ??
1556+
new AbortController().signal
15561557

15571558
try {
15581559
const model = this.getModel()

0 commit comments

Comments
 (0)