Skip to content

Commit a66aab1

Browse files
committed
fix(friendli): thread abortSignal, split params type, add test assertions
- completePrompt: accept CompletePromptOptions, pass abortSignal to SDK - split FriendliChatCompletionParams into streaming/non-streaming variants so completePrompt no longer needs 'as any' on a streaming-required type - remove unused modelInfo destructuring in completePrompt - add include_reasoning assertions to none/disable/completePrompt tests Address @edelauna review on Zoo-Code-Org#886.
1 parent 5f154ce commit a66aab1

2 files changed

Lines changed: 34 additions & 10 deletions

File tree

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,7 @@ describe("FriendliHandler — Friendli-specific reasoning params", () => {
485485
expect(callArgs.reasoning_effort).toBeUndefined()
486486
expect(callArgs.chat_template_kwargs).toEqual({ enable_thinking: false })
487487
expect(callArgs.parse_reasoning).toBeUndefined()
488+
expect(callArgs.include_reasoning).toBeUndefined()
488489
})
489490

490491
it("should send enable_thinking: false when reasoningEffort is disable on controllable model", async () => {
@@ -509,6 +510,7 @@ describe("FriendliHandler — Friendli-specific reasoning params", () => {
509510
expect(callArgs.reasoning_effort).toBeUndefined()
510511
expect(callArgs.chat_template_kwargs).toEqual({ enable_thinking: false })
511512
expect(callArgs.parse_reasoning).toBeUndefined()
513+
expect(callArgs.include_reasoning).toBeUndefined()
512514
})
513515

514516
it("should use model default reasoningEffort when no explicit settings are provided", async () => {
@@ -612,5 +614,6 @@ describe("FriendliHandler — Friendli-specific reasoning params", () => {
612614
expect(callArgs.reasoning_effort).toBe("medium")
613615
expect(callArgs.chat_template_kwargs).toEqual({ enable_thinking: true })
614616
expect(callArgs.parse_reasoning).toBe(true)
617+
expect(callArgs.include_reasoning).toBe(true)
615618
})
616619
})

src/api/providers/friendli.ts

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { getModelParams } from "../transform/model-params"
1111

1212
import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider"
1313
import { handleOpenAIError } from "./utils/error-handler"
14-
import type { ApiHandlerCreateMessageMetadata } from "../index"
14+
import type { ApiHandlerCreateMessageMetadata, CompletePromptOptions } from "../index"
1515

1616
/**
1717
* Friendli extends the OpenAI Chat Completions API with these non-standard fields:
@@ -20,8 +20,12 @@ import type { ApiHandlerCreateMessageMetadata } from "../index"
2020
* - parse_reasoning / include_reasoning: when true, Friendli streams reasoning via
2121
* delta.reasoning_content (which extractReasoningFromDelta already handles)
2222
* - reasoning_budget: integer token budget (not currently surfaced in settings UI)
23+
*
24+
* The reasoning fields are shared across streaming and non-streaming requests; the base
25+
* `ChatCompletionCreateParams` (non-streaming) variant is used for `completePrompt` while the
26+
* `ChatCompletionCreateParamsStreaming` variant is used for `createStream`.
2327
*/
24-
type FriendliChatCompletionParams = OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming & {
28+
type FriendliReasoningParams = {
2529
chat_template_kwargs?: { enable_thinking: boolean }
2630
parse_reasoning?: boolean
2731
include_reasoning?: boolean
@@ -33,6 +37,18 @@ type FriendliChatCompletionParams = OpenAI.Chat.Completions.ChatCompletionCreate
3337
| "max"
3438
}
3539

40+
type FriendliChatCompletionParams = Omit<
41+
OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming,
42+
"reasoning_effort"
43+
> &
44+
FriendliReasoningParams
45+
46+
type FriendliChatCompletionNonStreamingParams = Omit<
47+
OpenAI.Chat.Completions.ChatCompletionCreateParams,
48+
"reasoning_effort"
49+
> &
50+
FriendliReasoningParams
51+
3652
/**
3753
* Handler for the Friendli Model APIs (OpenAI-compatible).
3854
* Routes chat completions to `https://api.friendli.ai/serverless/v1`.
@@ -85,9 +101,9 @@ export class FriendliHandler extends BaseOpenAiCompatibleProvider<FriendliModelI
85101
* - Non-reasoning models (DeepSeek-V3.2, MiniMax-M2.5): no extra params
86102
* (reasoning_effort silently ignored).
87103
*/
88-
private buildFriendliReasoningParams(): Partial<FriendliChatCompletionParams> {
104+
private buildFriendliReasoningParams(): Partial<FriendliReasoningParams> {
89105
const { info: modelInfo, reasoningEffort } = this.getModel()
90-
const extra: Partial<FriendliChatCompletionParams> = {}
106+
const extra: Partial<FriendliReasoningParams> = {}
91107

92108
const isControllableReasoning = Array.isArray(modelInfo.supportsReasoningEffort)
93109

@@ -114,7 +130,7 @@ export class FriendliHandler extends BaseOpenAiCompatibleProvider<FriendliModelI
114130
extra.chat_template_kwargs = { enable_thinking: true }
115131

116132
if (reasoningEffort) {
117-
extra.reasoning_effort = reasoningEffort as FriendliChatCompletionParams["reasoning_effort"]
133+
extra.reasoning_effort = reasoningEffort as FriendliReasoningParams["reasoning_effort"]
118134
}
119135

120136
return extra
@@ -169,19 +185,24 @@ export class FriendliHandler extends BaseOpenAiCompatibleProvider<FriendliModelI
169185
}
170186
}
171187

172-
override async completePrompt(prompt: string): Promise<string> {
173-
const { id: modelId, info: modelInfo } = this.getModel()
188+
override async completePrompt(prompt: string, options?: CompletePromptOptions): Promise<string> {
189+
const { id: modelId } = this.getModel()
174190
const friendliExtra = this.buildFriendliReasoningParams()
175191

176-
const params: OpenAI.Chat.Completions.ChatCompletionCreateParams & Partial<FriendliChatCompletionParams> = {
192+
const params: FriendliChatCompletionNonStreamingParams = {
177193
model: modelId,
178194
messages: [{ role: "user", content: prompt }],
179195
...friendliExtra,
180196
}
181197

182198
try {
183-
const response = await this.client.chat.completions.create(params as any)
184-
199+
const requestOptions: OpenAI.RequestOptions | undefined = options?.abortSignal
200+
? { signal: options.abortSignal }
201+
: undefined
202+
const response = (await this.client.chat.completions.create(
203+
params as OpenAI.Chat.Completions.ChatCompletionCreateParams,
204+
requestOptions,
205+
)) as OpenAI.Chat.Completions.ChatCompletion
185206
return response.choices?.[0]?.message.content || ""
186207
} catch (error) {
187208
throw handleOpenAIError(error, this.providerName)

0 commit comments

Comments
 (0)