Skip to content

feat(friendli): add reasoning params support#886

Open
Lee-Si-Yoon wants to merge 1 commit into
Zoo-Code-Org:mainfrom
Lee-Si-Yoon:feat/friendli-reasoning-params-clean
Open

feat(friendli): add reasoning params support#886
Lee-Si-Yoon wants to merge 1 commit into
Zoo-Code-Org:mainfrom
Lee-Si-Yoon:feat/friendli-reasoning-params-clean

Conversation

@Lee-Si-Yoon

@Lee-Si-Yoon Lee-Si-Yoon commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Add Friendli-specific reasoning parameter support for GLM-5.x and MiniMax-M2.5 models served via Friendli Model APIs.

Friendli extends the OpenAI Chat Completions API with non-standard reasoning fields (reasoning_effort, chat_template_kwargs, parse_reasoning, include_reasoning) that the base BaseOpenAiCompatibleProvider does not handle. This PR overrides createStream and completePrompt in FriendliHandler to inject these parameters.

Ref: https://friendli.ai/docs/guides/reasoning

Changes

Model catalog (packages/types/src/providers/friendli.ts)

  • GLM-5.2 / GLM-5.1: add supportsReasoningEffort: ["minimal","low","medium","high","xhigh","max"] + reasoningEffort: "high" (controllable reasoning models)
  • MiniMax-M2.5: add supportsReasoningBinary: true (always-reasoning model)

Handler (src/api/providers/friendli.ts)

  • Override createStream and completePrompt to inject Friendli reasoning params via buildFriendliReasoningParams()
  • Controllable reasoning models (GLM-5.x): send reasoning_effort + chat_template_kwargs: { enable_thinking: true } + parse_reasoning/include_reasoning when user selects a valid effort
  • Always-reasoning models (MiniMax-M2.5): send parse_reasoning/include_reasoning only
  • Non-reasoning models (DeepSeek-V3.2): no extra params — reasoning_effort silently ignored
  • When user sets reasoning_effort to "none" or "disable", or enableReasoningEffort=false, no Friendli reasoning params are sent — the model runs at its default behavior
  • delta.reasoning_content streaming already handled by extractReasoningFromDelta in base class

Tests (src/api/providers/__tests__/friendli.spec.ts)

  • 8 reasoning-specific tests added (29 total pass):
    • GLM-5.2 with reasoning enabled → full params sent
    • enableReasoningEffort=false → no params (model default)
    • reasoningEffort="none" → no params (model default)
    • reasoningEffort="disable" → no params (model default)
    • MiniMax-M2.5 always-reasoning → parse_reasoning/include_reasoning only
    • DeepSeek-V3.2 non-reasoning → no params
    • delta.reasoning_content stream parsing
    • completePrompt reasoning params

Design decisions

  • No enable_thinking: false: When reasoning is disabled (none/disable), we send nothing rather than explicitly disabling thinking. This lets the model use its default behavior.
  • No ultracode: Friendli API supports ultracode in the enum but we do not surface it — only the standard efforts up to max.
  • No preserveReasoning: Friendli only supports stateless responses API — multi-turn reasoning re-submission has no effect.
  • Non-reasoning models: If reasoning_effort is set for a model that does not support it, params are silently omitted (no error).

Test plan

  • pnpm vitest run api/providers/__tests__/friendli.spec.ts — 29/29 pass
  • pnpm run build — success
  • pnpm run lint (src + packages/types) — clean

Summary by CodeRabbit

  • New Features
    • Added reasoning-effort controls for supported Friendli GLM models, including per-model allowed effort levels and a default “high” setting for GLM-5.1/5.2.
    • Friendli requests now apply reasoning settings consistently for both streaming and non-streaming, including streamed reasoning output when enabled.
  • Bug Fixes
    • Stopped sending reasoning-related parameters to non-reasoning models.
    • Properly disables/omits reasoning fields when reasoning is turned off.
  • Tests
    • Expanded coverage for reasoning parameter inclusion/exclusion and streamed reasoning chunk emission.

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Friendli model metadata now defines reasoning settings for GLM models. The provider applies those settings to streaming and non-streaming requests, and tests cover enabled, disabled, model-specific, and streamed reasoning behavior.

Changes

Friendli reasoning support

Layer / File(s) Summary
Model reasoning capabilities
packages/types/src/providers/friendli.ts
GLM-5.2 and GLM-5.1 declare supported reasoning-effort levels with a default of high.
Reasoning parameter construction
src/api/providers/friendli.ts
Friendli request types, model selection, and capability-aware reasoning parameter construction were added.
Request execution and validation
src/api/providers/friendli.ts, src/api/providers/__tests__/friendli.spec.ts
Streaming and prompt requests include applicable reasoning parameters, while tests validate request fields and streamed reasoning chunks.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant FriendliHandler
  participant FriendliAPI
  participant StreamConsumer
  FriendliHandler->>FriendliAPI: send reasoning parameters and messages
  FriendliAPI-->>FriendliHandler: return response or stream chunks
  FriendliHandler-->>StreamConsumer: emit reasoning and text chunks
Loading

Possibly related PRs

Suggested labels: awaiting-review

Suggested reviewers: navedmerchant

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is thorough, but it omits the required linked GitHub issue section from the template. Add the required "Closes: #" link and include the template's issue-linked section.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: adding Friendli reasoning parameter support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.88889% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/api/providers/friendli.ts 88.88% 1 Missing and 3 partials ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/api/providers/__tests__/friendli.spec.ts`:
- Around line 397-583: The Friendli reasoning tests lack coverage for default
model settings and explicit reasoning disablement. Extend the “Friendli-specific
reasoning params” suite with a GLM-5.2 case omitting both enableReasoningEffort
and reasoningEffort, asserting the model default enables reasoning with the
expected reasoning_effort and chat_template_kwargs, and a disabled-reasoning
case asserting chat_template_kwargs.enable_thinking is explicitly false while
reasoning parameters remain disabled.

In `@src/api/providers/friendli.ts`:
- Around line 87-121: Update buildFriendliReasoningParams so
controllable-reasoning models receive chat_template_kwargs with enable_thinking
false when reasoningEffort is disabled or set to none, including the
early-return path. Preserve the existing empty-params behavior for models
without controllable reasoning support, and keep enable_thinking true for active
reasoning requests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b8feab0f-3a58-41ff-9a11-bee8c5dbdc20

📥 Commits

Reviewing files that changed from the base of the PR and between 9e218a5 and eb3cd4c.

📒 Files selected for processing (3)
  • packages/types/src/providers/friendli.ts
  • src/api/providers/__tests__/friendli.spec.ts
  • src/api/providers/friendli.ts

Comment thread src/api/providers/__tests__/friendli.spec.ts
Comment thread src/api/providers/friendli.ts Outdated
@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 13, 2026

@taltas taltas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. A couple of questons on some of the models I found.

outputPrice: 4.4,
cacheWritesPrice: 0,
cacheReadsPrice: 0.26,
supportsReasoningEffort: ["minimal", "low", "medium", "high", "xhigh", "max"],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does GLM offer a way to disable reasoning effort completely using 'disable' as a key?

@Lee-Si-Yoon Lee-Si-Yoon Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, verified that it throws 422 when disable or none is given

Endpoint: https://api.friendli.ai/serverless/v1/chat/completions
Model: zai-org/GLM-5.2

{"message":"invalid JSON payload: unknown enum value: 'disable'"}

{"message":"invalid JSON payload: unknown enum value: 'none'"}

To disable thinking it has to be done via chat_template_kwargs: { enable_thinking: true } option

outputPrice: 1.2,
cacheWritesPrice: 0,
cacheReadsPrice: 0.06,
supportsReasoningBinary: true,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On MiniMax-M2.5 This will render the checkbox Use reasoning in the settings.... but the thing is, this model always has reasoning on though right? We should introduce or reuse metadata that distinguishes required/always reasoning from optional binary reasoning, hide or disable the on/off control for this model, and always request parsed reasoning for MiniMax-M2.5. In addition to this, we should add tests for MiniMax with the reasoning flag false and unset, not only true.

I think these changes should be in a separate PR in order not to bloat this one

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review! I reverted changes related to Minimax-m2.5 issues and planning to treat this in separate PR.

@github-actions github-actions Bot added awaiting-author PR is waiting for the author to address requested changes and removed awaiting-review PR changes are ready and waiting for maintainer re-review labels Jul 13, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/api/providers/friendli.ts (1)

172-175: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove unused variable.

The variable modelInfo is destructured but never used in this method.

♻️ Proposed refactor
 	override async completePrompt(prompt: string): Promise<string> {
-		const { id: modelId, info: modelInfo } = this.getModel()
+		const { id: modelId } = this.getModel()
 		const friendliExtra = this.buildFriendliReasoningParams()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/friendli.ts` around lines 172 - 175, Remove the unused
modelInfo binding from the getModel() destructuring in completePrompt, while
preserving the modelId assignment and the existing buildFriendliReasoningParams
flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/api/providers/friendli.ts`:
- Around line 172-175: Remove the unused modelInfo binding from the getModel()
destructuring in completePrompt, while preserving the modelId assignment and the
existing buildFriendliReasoningParams flow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1db29ef9-2606-4e79-ab82-ec57f833dbb7

📥 Commits

Reviewing files that changed from the base of the PR and between 645b5f1 and 6b0dfa7.

📒 Files selected for processing (3)
  • packages/types/src/providers/friendli.ts
  • src/api/providers/__tests__/friendli.spec.ts
  • src/api/providers/friendli.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/api/providers/tests/friendli.spec.ts

@Lee-Si-Yoon
Lee-Si-Yoon requested a review from taltas July 19, 2026 12:07
@github-actions github-actions Bot added awaiting-review PR changes are ready and waiting for maintainer re-review and removed awaiting-author PR is waiting for the author to address requested changes labels Jul 19, 2026
@Lee-Si-Yoon

Copy link
Copy Markdown
Contributor Author

@taltas hey, I know you probably have a lot going on right now, but would you mind taking another look when you get a chance?

Both of your comments are addressed since the last review:

  • GLM "disable" / "none" key: Checked against the API — both throw 422 (unknown enum value). Thinking is controlled through chat_template_kwargs: { enable_thinking: false } instead, so I added that path and tests for it.
  • MiniMax-M2.5 always-reasoning: Pulled those changes out of this PR entirely. I will pick it up in a separate one so this stays scoped to controllable reasoning models.

Thanks again — the review pointed out exactly where the boundary should be.

@edelauna edelauna left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this contribution, can with reviewing - had some comments regarding implementation details.

Comment thread src/api/providers/friendli.ts Outdated
Comment thread src/api/providers/friendli.ts Outdated
Comment thread src/api/providers/friendli.ts Outdated
Comment thread src/api/providers/__tests__/friendli.spec.ts
Comment thread src/api/providers/__tests__/friendli.spec.ts
@github-actions github-actions Bot added awaiting-author PR is waiting for the author to address requested changes and removed awaiting-review PR changes are ready and waiting for maintainer re-review labels Jul 25, 2026
Lee-Si-Yoon added a commit to Lee-Si-Yoon/Zoo-Code that referenced this pull request Jul 26, 2026
…ions

- 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.
@Lee-Si-Yoon

Copy link
Copy Markdown
Contributor Author

Thanks for the review @edelauna — all five points are addressed in a66aab1:

  • completePrompt now accepts options?: CompletePromptOptions and threads abortSignal through to the SDK call.
  • Unused modelInfo destructuring removed.
  • Split FriendliChatCompletionParams into streaming and non-streaming variants (sharing a common FriendliReasoningParams). completePrompt now uses the non-streaming type, so the as any is gone.
  • Added include_reasoning assertions to the none/disable and completePrompt tests.

@github-actions github-actions Bot removed the awaiting-author PR is waiting for the author to address requested changes label Jul 26, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/api/providers/friendli.ts (2)

75-81: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use an own-property check for configured model IDs.

in also matches inherited properties, so strings like "toString" can be accepted as a supported Friendli model instead of falling back to the default. Use Object.prototype.hasOwnProperty.call(this.providerModels, this.options.apiModelId) before reading providerModels[id].

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/friendli.ts` around lines 75 - 81, Update getModel to
validate options.apiModelId with
Object.prototype.hasOwnProperty.call(this.providerModels,
this.options.apiModelId) instead of the in operator, ensuring inherited names
such as toString fall back to defaultProviderModelId before providerModels is
accessed.

178-185: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Await the streamed completion before wrapping in try.

With stream: true, create() may reject after createStream() returns, so the current synchronous try/catch won’t catch initial request failures. Await the SDK call inside the try block or attach .catch(...) to the returned SDK promise so handleOpenAIError can normalize initial streaming request errors.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/friendli.ts` around lines 178 - 185, The streaming
completion in the provider method must be awaited within the try block so
asynchronous SDK rejections are normalized by handleOpenAIError. Update the
client.chat.completions.create call in the shown method to await its returned
promise while preserving the existing parameters and error handler.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/api/providers/friendli.ts`:
- Around line 188-204: Update completePrompt() to forward options.timeoutMs in
the requestOptions passed to this.client.chat.completions.create, alongside the
existing abortSignal forwarding. Preserve undefined behavior when no timeout is
configured and continue honoring both per-call options.

---

Outside diff comments:
In `@src/api/providers/friendli.ts`:
- Around line 75-81: Update getModel to validate options.apiModelId with
Object.prototype.hasOwnProperty.call(this.providerModels,
this.options.apiModelId) instead of the in operator, ensuring inherited names
such as toString fall back to defaultProviderModelId before providerModels is
accessed.
- Around line 178-185: The streaming completion in the provider method must be
awaited within the try block so asynchronous SDK rejections are normalized by
handleOpenAIError. Update the client.chat.completions.create call in the shown
method to await its returned promise while preserving the existing parameters
and error handler.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 31dccd4a-08d7-4ab2-b5ea-5b9cc7bc2ec6

📥 Commits

Reviewing files that changed from the base of the PR and between 6b0dfa7 and a66aab1.

📒 Files selected for processing (2)
  • src/api/providers/__tests__/friendli.spec.ts
  • src/api/providers/friendli.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/api/providers/tests/friendli.spec.ts

Comment thread src/api/providers/friendli.ts
@Lee-Si-Yoon
Lee-Si-Yoon requested a review from edelauna July 26, 2026 06:18
@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-review PR changes are ready and waiting for maintainer re-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants