feat(friendli): add reasoning params support - #1
Closed
Lee-Si-Yoon wants to merge 53 commits into
Closed
Conversation
* feat(settings): add rules management UI * fix: address rules settings review feedback * test: increase rules settings coverage * test: improve rules settings patch coverage * fix: address rules settings review feedback
…de-Org#324) * fix: parse Gemma 4 <thought> reasoning tags alongside <think> Gemma 4 streams reasoning inside <thought>...</thought> instead of <think>...</think>. Without this the content leaks into chat text and the agent triggers a retry on the first turn. - TagMatcher: support multiple tag names - string[], track activeTagName so <think> is never closed by </thought> (and vice-versa). - base-openai-compatible-provider and openai handler: match both tags. - Tests: <thought> parsing, cross-tag isolation, and invariants. * fix: support nested reasoning tags in TagMatcher and add comprehensive streaming tests * test(tag-matcher): add tests for unmatched closing tags Add two regression tests that verify depth never goes negative: 1. stray closer with no opener "final</think>text" → stays text 2. duplicate closer after a proper close "<think>thinking</think>final</think>text" → second </think> stays text Both cases ensure we only decrement depth and pop activeTagNames when depth > 0, preventing underflow and treating the extra tag as plain text. * Apply suggestion from @edelauna Co-authored-by: edelauna <54631123+edelauna@users.noreply.github.com> * refactor(providers): updating tag matcher * test(TagMatcher): adding tests for new logic * test(tag-matcher): consolidate reasoning tag tests into tag-matcher.spec.ts --------- Co-authored-by: Sagid Magomedov <sagidsmagomedov@gmail.com> Co-authored-by: edelauna <54631123+edelauna@users.noreply.github.com> Co-authored-by: Elliott de Launay <edelauna@gmail.com>
* chore(deps): update dependency only-allow to v1.2.2 * deps(only-allow): removing unused dep --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Elliott de Launay <edelauna@gmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* chore(deps): update dependency react-use to v17.6.1 * deps(csstype): pinning to 3.1.3 --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Elliott de Launay <edelauna@gmail.com>
* chore(deps): update dependency ovsx to v0.10.12 * deps(vsce): bumped to 3.9.2 for consistency --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Elliott de Launay <edelauna@gmail.com> Co-authored-by: edelauna <54631123+edelauna@users.noreply.github.com>
…o-Code-Org#741) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…sdk to 0.17.1 (Zoo-Code-Org#600) * chore: upgrade @anthropic-ai/sdk to 0.104.1 and @anthropic-ai/vertex-sdk to 0.17.1 * fix(transform): handle URL-sourced images and non-base64 blocks in format converters * test: bumping coverage * test(e2e): adding image test --------- Co-authored-by: Elliott de Launay <edelauna@gmail.com>
* fix(deps): update ai sdks and providers * fix(deps): update ai sdks and providers * deps(ai-sdk): cleaning up orphaned packages --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Elliott de Launay <edelauna@gmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* chore(deps): update dependency mermaid to v11.16.0 * test(e2e): addressing zai test flake --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Elliott de Launay <edelauna@gmail.com>
* chore(deps): update build, lint, and test tooling * deps(knip): cleaning up knip, and downgrading since zod upgrade required first --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Elliott de Launay <edelauna@gmail.com>
…default model (Zoo-Code-Org#647) * fix: LiteLLM provider model desync after Sync Models or settings navigation - Invalidate React Query router-models cache on successful sync in LiteLLM.tsx so useSelectedModel picks up the refreshed list (mirrors Poe.tsx fix) - Preserve configured litellm model ID when model list is empty/loading in useSelectedModel.ts instead of silently falling back to hardcoded default - Pass litellm credentials in the debounced requestRouterModels message in ApiOptions.tsx to prevent fetches with stale config from clearing the model list * fix: address CodeRabbit review comments on litellm model desync - Refactor getCacheKey to compute URL and key components independently, preventing key-scoped providers on the default server from collapsing to the same cache entry - Replace character-substitution in cacheKeyToFilename with SHA-256 hash for collision-free filesystem-safe filenames - Block AUTH_SCOPED_PROVIDERS (zoo-gateway) in getModelsFromCache to prevent stale user-specific model lists from leaking across sessions - Wrap requestRouterModels switch case body in braces to satisfy Biome noSwitchDeclarations lint rule - Preserve configured modelId in RouterProvider.getModel() last-resort fallback instead of silently defaulting to hardcoded defaultModelId - Add codeql[js/insufficient-password-hash] suppressions on SHA-256 cache key discriminator calls (false positive: not password hashing) * chore: remove ineffective codeql suppression directives The inline // codeql[js/insufficient-password-hash] comments did not suppress the alert because CodeQL tracks taint flow from source variables in other files. Retaining the explanatory prose comments for human reviewers; the false positive requires maintainer dismissal in the GitHub Security tab. * test(webviewMessageHandler): correct LiteLLM credential priority assertion The test "prefers config values over message values for LiteLLM" was asserting the old || behavior. The handler now uses ?? so message.values takes precedence over saved config, matching the DeepSeek pattern and allowing unsaved settings UI state to be used during Sync Models. * fix(security): derive cache-key discriminator without flagged API-key hashing Replace the SHA-256 hash of the API key in the LiteLLM/key-scoped cache key with a memoized, truncated PBKDF2-derived 32-bit discriminator. This resolves the CodeQL js/insufficient-password-hash alert at the source (Node crypto.pbkdf2Sync is not modeled as a weak-hash sink) rather than dismissing it as a false positive, and the heavy truncation makes the value written to the on-disk cache filename non-reversible to the API key. Add provider-agnostic tests covering per-key separation, determinism, and the non-identifying discriminator shape. * fix(security): derive cache filename digest via KDF to clear residual CodeQL taint The API-key discriminator is embedded in the compound cache key, so CodeQL taint tracking treats the cache key as password-derived and flagged the remaining createHash(sha256) in cacheKeyToFilename. Route the filename digest through the same truncated PBKDF2 helper (deriveCacheDigest) and remove createHash entirely, eliminating the last weak-hash sink the tainted value can reach. Filename width is preserved (64-bit/16-hex). * test: cover all getCacheKey scoping branches in modelCache * fix: resolve check-types errors in modelCache tests * fix: address PR review for LiteLLM cache key collision fix - poe/lm-studio getModel() pass GetModelsOptions so compound cache key matches; bare-string lookups previously always missed and fell back to defaults - router-provider uses || so empty-string modelId falls back to default instead of forwarding "" to the API - LiteLLM Sync invalidates the exact ["routerModels","litellm"] query rather than the broad ["routerModels"] prefix - document in-flight dedup microtask-safety invariant in modelCache - add tests: list non-empty->empty transition preserves selection; key-scoped in-flight dedup (different keys -> separate fetch)
* fix(shell): validate defaultProfileName is a string before calling .toLowerCase() config.get<string>() has no runtime type check, so non-string values (number, boolean, array, object) from settings.json pass through and cause a TypeError. Add typeof guard in each platform's terminal config helper and add corresponding test cases. * refactor(shell): unify platform terminal config helpers into generic getTerminalConfig<T>() * test(shell): add test cases for getTerminalConfig behavior * refactor(shell): apply code review feedback to getTerminalConfig - Replace TerminalProfiles union with PlatformProfilesMap mapped type so the return type is inferred from the platform key, eliminating explicit type parameters at each call site and making mismatches a compile error - Change || to ?? when falling back to empty profiles object - Add JSDoc explaining the key constraint and inferred return type - Add missing boolean/array non-string defaultProfileName test cases for macOS and Linux to match Windows coverage - Add mutation-resistant tests for macOS and Linux that verify the typeof guard is load-bearing (numeric key matching a real profile entry)
* fix(task): handle rejections on void-prefixed async calls in Task.ts Per Copilot review on Zoo-Code-Org#253: the void-prefixed async calls flagged by the reviewer (postStateToWebviewWithoutTaskHistory, startTask and resumeTaskFromHistory in the constructor, startTask in start(), and the nine presentAssistantMessage(this) sites in the streaming loop) can become unhandled promise rejections on failure and crash the extension host. Each flagged site now has a .catch handler that logs the rejection without re-throwing, while keeping the void prefix to satisfy no-floating-promises. presentAssistantMessage was wrapped in a small private helper, presentAssistantMessageSafe, that distinguishes the expected throw-on-abort path (silently swallowed) from real failures (logged). All nine streaming presenter call sites delegate through the helper so the rejection-handling logic lives in one place. Adds six specs under "unhandled-rejection guards on void async calls" that pin the new behavior: every catch handler is asserted to log on rejection, and the helper's abort vs non-abort branches are both exercised. Single-line fire-and-forget UI updates and the streaming presenter call sites carry /* v8 ignore next */ markers with a short rationale, since the rejection-handling logic they delegate to is covered separately by the helper specs. * fix(Task): match the abort error message in presentAssistantMessageSafe The helper's catch handler was distinguishing abort from real failures via `this.abort` state at catch time, which has a real TOCTOU window: a non-abort throw followed by an abort flip between throw and catch microtask would silently swallow the real error. Switched to matching `error.message.endsWith("aborted")` — the literal contract presentAssistantMessage itself throws on abort. Same suppression for the abort case, no swallow window for real errors. Added a test that pins the message-based discriminator: a non-abort error with `this.abort = true` now correctly logs (would have been swallowed under the state-based check). Also added a regression test for the abort-message-match path so a future refactor can't drift back to the state check. * fix(Task): catch updateClineMessage rejections on partial-message paths The four fire-and-forget updateClineMessage calls in say()/ask() partial-message branches were void-prefixed without .catch arms. The callee's webview post is internally guarded, but its synchronous RooCodeEventName.Message emit can throw via a consumer-attached listener — so the void sites can produce unhandled rejections. Replace each `void this.updateClineMessage(...)` with an explicit .catch arm that logs the error, matching the other rejection-handling sites in this file. Two new tests pin the say() and ask() catch arms. Also pin the void on getCheckpointService with a rationale comment: its top-level try/catch returns undefined on failure, so .catch is not needed there. * feat(Task): adding catch block to log any errors * test(Task): coverage --------- Co-authored-by: 0xMink <260166390+0xMink@users.noreply.github.com> Co-authored-by: Elliott de Launay <edelauna@gmail.com>
…Zoo-Code-Org#228) * feat(label-pr-review-state): updating logic for awaiting-review * feat(label-pr-review-state): check only required steps --------- Co-authored-by: Elliott de Launay <edelauna@gmail.com>
…-Code-Org#725) * fix(delegation): atomically serialize reopenParentFromDelegation * fix(delegation): harden atomic parent reopen handoff * fix(delegation): broadcast atomic handoff history updates
* fix(vscode-lm): reliable auto context condensing Port of simurg79/Roo-Code#11 into Zoo-Code. * test(vscode-lm): cover condense-window edge branches for codecov/patch Add targeted tests for the previously-uncovered ported branches: the availableInputTokens<=0 fallback to 100% in willManageContext/manageContext, getCondenseContextWindow() guard fallbacks, and the vscode-lm UI family-miss window resolution. Raises patch coverage to satisfy the codecov/patch 80% gate. * chore(vscode-lm): address review — drop changeset, fix condense-window guard test - Remove .changeset/vscode-lm-condense-fix.md (changesets are maintainer-managed per AGENTS.md; CodeRabbit flagged). - Fix getCondenseContextWindow() non-positive-guard test so the selector family (claude-opus-4.8) drives the lookup and the zeroed static row actually exercises the maxInputTokens > 0 guard before falling back. * fix(vscode-lm): scope available-input condense denominator to vscode-lm; address review Address review feedback from edelauna on Zoo-Code-Org#710: - Scope the available-input-space condense percent denominator to vscode-lm only (via the getCondenseContextWindow seam); all other providers keep dividing by the full context window. The maxTokens:-1 reserve guard remains global. - Correct the misleading useSelectedModel comment: the gate's primary window is getCondenseContextWindow() (static maxInputTokens), not getModel().info.contextWindow. - Strengthen the listed-family test with a claude-opus-4.8 case (contextWindow != maxInputTokens) to catch a field swap. * docs(vscode-lm): tighten auto-condense comments Simplify comments added in PR Zoo-Code-Org#710 to be brief and rationale-focused; no logic, assertions, or test values changed. * test(vscode-lm): harden condense reserve-guard coverage Address review: make the negative-reserve percent test discriminate the maxTokens>0 guard (-200000), and add a manageContext truncation-path test so both copies of the -1 reserve guard are covered. Test-only; no product code changed. * test(task): fix Task.dispose teardown-race flake Mock utils/storage and OutputInterceptor in Task.dispose.test.ts so dispose()'s unawaited cleanup chain cannot emit a late console.error during Vitest worker teardown (EnvironmentTeardownError: Closing rpc while onUserConsoleLog was pending). Test-only; no product code changed. * refactor(vscode-lm): default-row condense fallback + shared contextPercent helper getCondenseContextWindow() resolves the default vscode-lm row for an unknown/absent family (catalog drift) instead of the inflated live window; only a non-positive static maxInputTokens still falls back to it. Extract the duplicated contextPercent math shared by willManageContext and manageContext into computeContextPercent so the two stay in lockstep. Addresses PR review feedback. --------- Co-authored-by: Bertan Ari <bertanari@microsoft.com>
…values (Zoo-Code-Org#713) (Zoo-Code-Org#774) * fix(ThinkingBudget): handling xhigh, max and disabled values * feat(ThinkingBudget): set dropdown to available options * test(ThikningBudget): coverage
* feat: implement Claude Sonnet 5 support in Zoo Code Add full Claude Sonnet 5 support across all provider paths with correct model definitions, adaptive-thinking handling, fetcher overrides, and accurate introductory pricing. Model definitions (anthropic.ts, bedrock.ts, vertex.ts): - 1M native context window (no beta header required) - Adaptive-thinking binary toggle (supportsReasoningBudget/Binary) - supportsTemperature: false (sampling params return a 400) - Introductory pricing through Aug 31, 2026: inputPrice 2.0, outputPrice 10.0, cacheWrites 2.5, cacheReads 0.2 (standard $3/$15 rates take effect Sep 1, 2026) Provider handling: - Add sonnet-5 to the Bedrock adaptive-thinking guard - Add claude-sonnet-5 to OpenRouter and Vercel AI Gateway allow-lists - Apply Sonnet 5 overrides (maxTokens, reasoning budget, temperature) in the openrouter, requesty, and vercel-ai-gateway fetchers Tests: - Add Sonnet 5 coverage across provider and fetcher test suites Closes Zoo-Code-Org#777 * test(bedrock,vercel): address Sonnet 5 PR review feedback - Add Bedrock createMessage adaptive-thinking test for claude-sonnet-5 (mirrors Opus 4.7/4.8: asserts thinking.type 'adaptive', output_config.effort 'xhigh', and temperature omitted). - Tighten Vercel AI Gateway Sonnet 5 temperature assertion to extract the call arg directly instead of objectContaining({ temperature: undefined }), which can't distinguish absent from explicitly undefined. Refs Zoo-Code-Org#778
…tion reconciliation (Zoo-Code-Org#692) * feat(task-lifecycle): transition guard and startup delegation reconciliation * test: updating TaskPersistence vitest mocks * fix(task-persistence): enforce status transition guard at upsertCore write boundary * fix(delegation): guard concurrent rollback pop and add transition tests * feat(ClineProvider): guarding parent, child transitions * feat(ClineProvider): adding delegatedToId * test(subtask): adding e2e test and apis for history tracking --------- Co-authored-by: Naved Merchant <naved.merchant@gmail.com>
…o-Code-Org#726) * fix: provider cache reset after settings import SettingsView keeps a local cachedState buffer so settings edits do not write through to the live extension state before Save. After importing settings, the import timestamp was used to bust that cache, but the effect could run again for the same import timestamp whenever extensionState changed identity. That allowed a later live state update to overwrite an in-progress provider edit with the previously saved provider, causing the provider UI to briefly switch and then revert. Track the handled settingsImportedAt value and only reset cachedState once per import event. Add a regression test for the imported-settings flow where Baseten is saved with an API key, the same import timestamp is replayed, and a subsequent DeepSeek provider edit is preserved and saved. * test: cover settings import timestamp cache reset behavior Strengthen SettingsView regression coverage around settingsImportedAt. Verify that replaying the same import timestamp does not let the cache-busting effect overwrite an in-progress provider edit, and add the inverse case to prove a fresh import timestamp still refreshes cachedState from the latest extensionState apiConfiguration. Also assert that a fresh import clears the dirty state by disabling the Save button after pending edits are replaced by imported settings.
…tus messages (Zoo-Code-Org#734) * feat(semble): upgrade to v0.4.1, flatten result parsing, localize status messages - Bump SEMBLE_VERSION v0.3.1 -> v0.4.1 and refresh SEMBLE_SHA256 checksums - Adapt to semble v0.4.0+ flat JSON output (no chunk wrapper); remove SembleChunk and flatten SembleSearchResult (file_path, start_line, end_line, score, content) - Update provider.ts and semble-cli.ts parsing accordingly - Version-prefix the local archive cache path so a stale archive from a previous semble version is never reused or verified against the new checksum; remove partial archive before re-downloading - Add cleanupStaleArchives to best-effort sweep orphaned archives after a version upgrade - Localize SembleProvider status strings via i18n embeddings:semble.* keys across all 18 locales - Update provider/cli/downloader unit tests for the new shape and version-prefixed cache path Closes Zoo-Code-Org#733 * fix(semble): clean legacy unversioned archives and cover stale-archive sweep CodeRabbit PR Zoo-Code-Org#734 follow-ups: - cleanupStaleArchives now also matches the exact unversioned archive name (pre-v0.4.0 cache layout) in addition to the version-prefixed suffix, so a v0.3.1 -> v0.4.1 upgrade also clears the legacy file. The current archive path is still preserved. - semble-downloader.spec: the version-upgrade test now simulates a prior-version archive (v0.4.0-*) and a legacy unversioned archive in the cache, and asserts both are swept during the upgrade flow. - Add coverage for the cleanupStaleArchives catch block (readdir rejects) and for the current-archive/unrelated-file preservation behavior. - provider.spec: add a test that rejects search with a non-Error value to cover the 'error instanceof Error' false branch of the telemetry payload (stack: undefined), raising provider.ts patch coverage. * feat(semble): surface active version in the CodeIndexPopover status message Export SEMBLE_VERSION from semble-downloader and re-export from the semble barrel. SembleProvider now interpolates the active version into the 'embeddings:semble.ready' system-state message (set in both _doInitialize and startIndexing), so the CodeIndexPopover status line shows e.g. 'Indexed - Semble v0.4.1 is ready. Searches index on-the-fly.' - semble-downloader.ts: export SEMBLE_VERSION. - index.ts: re-export SEMBLE_VERSION. - provider.ts: pass { version: SEMBLE_VERSION } to t('embeddings:semble.ready'). - i18n: update semble.ready across all 18 locales to include {{version}}. - provider.spec.ts: mock SEMBLE_VERSION, update the ready-message mock to interpolate version, and add a test asserting the version appears in the ready status message. * fix review comments
…st-privilege workflow permissions (Zoo-Code-Org#782) (Zoo-Code-Org#783) * deps: updating security posture in ci * deps: addressing feedback --------- Co-authored-by: Naved Merchant <naved.merchant@gmail.com>
…nt 400 errors (Zoo-Code-Org#775) * fix(deepseek): reasoning_content handler across deepseek model providers * fix(openai-format): accumulate all parts * fix(openai-format): update types for deepseek * test(openai-format): cover getReasoningBlockText non-object guard Add a regression test that passes a non-object content part (a stray string) through convertToOpenAiMessages, exercising the defensive early-return in getReasoningBlockText (line 276). This was the only uncovered line in the PR patch, causing the codecov/patch check to fail. --------- Co-authored-by: Naved Merchant <naved.merchant@gmail.com>
…Org#234) Co-authored-by: Elliott de Launay <edelauna@gmail.com>
…andler (Zoo-Code-Org#767) * refactor: remove deprecated openai-error-handler and consolidate into error-handler Replace all imports of the deprecated `openai-error-handler` shim with `error-handler`, which has been the canonical source since #10204. Delete `openai-error-handler.ts` and its duplicate test file, as `error-handler.spec.ts` already covers the same behavior. Signed-off-by: daewoongoh <dw.oh@samsung.com> * test(deepseek): add test for API error handling in createMessage Cover the catch block that wraps API errors via handleOpenAIError, fixing 0% patch coverage on the error path. Signed-off-by: daewoongoh <dw.oh@samsung.com> * refactor(deepseek): convert dynamic import to static for handleOpenAIError Replace dynamic `await import()` with a static import for `handleOpenAIError` in the catch block, and update the error handler test to also assert the HTTP status code (401) on the thrown error. Signed-off-by: daewoongoh <dw.oh@samsung.com> --------- Signed-off-by: daewoongoh <dw.oh@samsung.com>
Co-authored-by: Elliott de Launay <edelauna@gmail.com>
Zoo-Code-Org#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>
…k is interrupted (Zoo-Code-Org#560) (Zoo-Code-Org#787) * fix(task-lifecycle): preserve parent-child link when delegated subtask is interrupted * test(e2e): interrupted child resumes and reports back to parent * Fix interrupted subtask resume state restoration * fix(task-lifecycle): prevent parent repair from winning race against child cancellation * fix(api): return 0 instead of throwing for unavailable task history length * test(webview-settings): increase change-detection test timeout to resolve CI flakes --------- Co-authored-by: Naved Merchant <naved.merchant@gmail.com> Co-authored-by: Test User <test@example.com>
…Org#803) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…#805) * chore(deps): update dependency @types/react to v18.3.31 * fix(nightl-publish): too agressively skipping pre-releases --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Test User <test@example.com>
…Org#721) * feat(friendli): add provider + 4 models Friendli OpenAI-compatible provider. Models: GLM-5.2, GLM-5.1, DeepSeek-V3.2, MiniMax-M2.5. Pricing from friendli.ai pricing API. Mirror fireworks provider pattern (commit 4a9222b): - types: model info, schema, secret key, provider name - api: BaseOpenAiCompatibleProvider handler at api.friendli.ai/serverless/v1 - webview: provider UI, model picker, validation, i18n (18 locales) - tests: handler spec, ProfileValidator entry Reasoning streams back via base handler's reasoning_content extraction. Friendli defaults parse_reasoning=true for GLM reasoning models. * docs(friendli): add docstrings to handler and UI component + revert bug_report.yml Friendli entry * docs(friendli): add docstrings to handler class and settings component * test(friendli): add wiring coverage for validate, useSelectedModel, Friendli.tsx * test(friendli): cover onInput, ApiOptions wiring, buildApiHandler switch * test: add friendli to SettingsView change-detection mock provider list * test(friendli): assert supportsMaxTokens/cacheWritesPrice, cover GLM-5.1 clamping path - Add supportsMaxTokens and cacheWritesPrice assertions to GLM-5.2 single test and it.each model table - Add getModelMaxOutputTokens integration tests verifying: - GLM-5.2: 131k < 20% of 1M context → clamp no-op - GLM-5.1: 131k > 20% of 200k context → clamp binds to 40k - GLM-5.1 with user modelMaxTokens: honors override capped at model maxTokens - Cast friendliModels[modelId] to ModelInfo to avoid union-type narrowing issue with as const satisfies * test: restrict webview-ui workers in CI to prevent JSDOM CPU starvation --------- Co-authored-by: siyoon <leesiyoon0120@gmail.com> Co-authored-by: Elliott de Launay <edelaunay@wealthsimple.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* feat(ollama): add native thinking/reasoning support - Add Enable Thinking checkbox + ThinkingBudget selector to Ollama settings - Map reasoning effort to Ollama native think param (low/medium/high) - Stream message.thinking as reasoning chunks - Round-trip prior reasoning/thinking blocks for multi-turn thinking - Add unit tests for native-ollama and Ollama settings component - Add i18n strings for thinking toggle Closes Zoo-Code-Org#831 * i18n: add Ollama thinking translations for all locales Adds thinking and thinkingHelp strings for the new Ollama native thinking toggle across all 17 non-English webview-ui locales. Part of Zoo-Code-Org#831 * fix(ollama): resolve check-types error, gate think param on opt-in, address CodeRabbit comments - Fix TS2367 in native-ollama.ts: remove unreachable 'image' branch from assistant message conversion (Anthropic ContentBlock union has no 'image'; assistant cannot send images). User-message image handling is preserved. - Gate getOllamaThinkParam on enableReasoningEffort === true so a stale reasoningEffort inherited from another provider config cannot silently emit a think param when the Ollama UI checkbox is unchecked. - Extract buildChatRequestOptions() helper shared by createMessage and completePrompt to eliminate duplicated request-option assembly. - Ollama settings UI: preserve reasoningEffort across checkbox toggles instead of wiping it to undefined when unchecked; restore the prior value on re-enable rather than forcing 'medium'. - Add tests for the stale-config case, the disable+opt-in case, and the completePrompt non-Error throw branch. Coverage now 83.89% (>= 80%). * docs(ollama): add explanatory comment for removed Anthropic image branch in assistant messages * test(ollama): improve patch coverage for native thinking support Add tests covering previously uncovered branches in native-ollama.ts: - Anthropic-protocol thinking block round-tripping (block.type === thinking) - Concatenation of multiple reasoning/thinking blocks with newline joins - Empty reasoning/thinking blocks (length > 0 false branch + reasoningText || undefined) - Plain assistant message without reasoning blocks (falsy reasoningText branch) - Unknown reasoningEffort value (default switch branch returns undefined) - Stream processing error wrapping (catch streamError branch + Unknown error fallback) - Non-ECONNREFUSED non-404 error rethrow (fall-through throw error branch) Also strengthen the Ollama.spec.tsx toggle-off assertion per CodeRabbit nitpick: assert no call with reasoningEffort as the first argument at all, instead of only ruling out undefined. Patch coverage for native-ollama.ts rises from 71.05% to ~100% of new lines, clearing the codecov/patch 80% threshold.
…nsing (Zoo-Code-Org#848) * ollama fixes * fix(ollama): isolate failing model fetches and address PR Zoo-Code-Org#848 review - getOllamaModels: append per-request .catch() so a single failing /api/show no longer rejects the whole Promise.all and wipes out all healthy models (issue Zoo-Code-Org#851) - native-ollama: keep tool results text-only; move images extracted from tool results onto the adjacent user message and reset the per-result image accumulator to prevent leakage between tool results - native-ollama: recursively strip additionalProperties from tool schemas (top-level and nested properties/items) instead of only the top level - tests: update ollama fetcher maxTokens expectations to the inherited default (4096), add regression test for individual model fetch failure, and add coverage for text-only tool results, image relocation, image leakage prevention, and nested additionalProperties stripping
…g to claude-sonnet-4-5 (Zoo-Code-Org#842) * fix(anthropic): honor custom apiModelId instead of silently defaulting to claude-sonnet-4-5 Unrecognized model IDs were coerced to the hardcoded default before being sent to the API and for capability lookups, breaking custom deployments and picking the wrong thinking config. Fixes Zoo-Code-Org#418 * style: trim comments to a single line * chore: add changeset for anthropic custom model id fallback fix * Hoist sorted model IDs out of guessModelInfoFromId method; Make model ID matching case insensitive in Anthropic --------- Co-authored-by: Naved Merchant <naved.merchant@gmail.com>
…ode-Org#807) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…o-Code-Org#808) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…-Org#876) * feat(openai): add GPT-5.6 family (sol, terra, luna) support Add the GPT-5.6 model family to both the OpenAI Codex (ChatGPT subscription) and OpenAI Native (API) providers: - gpt-5.6-sol: flagship frontier reasoning/coding model - gpt-5.6-terra: balanced everyday model - gpt-5.6-luna: fastest, most affordable family member Update the default model id for both providers to gpt-5.6-sol and update the corresponding unit test assertions. Closes Zoo-Code-Org#871 * fix(openai-codex): correct GPT-5.6 context windows to 372000 Address review feedback on PR Zoo-Code-Org#876: the GPT-5.6 model context windows in the Codex provider were set to 400000, but the OpenAI codex models.json shows context_window and max_context_window of 372000 for all three GPT-5.6 variants (sol, terra, luna). Updated accordingly.
…g#809) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…Org#810) * chore(deps): update dependency sanitize-filename to v1.6.4 * test: fix flaky change detection test by wrapping rerender with act --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Elliott de Launay <edelaunay@wealthsimple.com>
…-Org#812) * chore(deps): update dependency tree-sitter-wasms to v0.1.13 * test: add tree-sitter-dart.wasm to verified dist assets list --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Elliott de Launay <edelaunay@wealthsimple.com>
…-Org#270) Co-authored-by: Elliott de Launay <edelauna@gmail.com>
…_template_kwargs, parse_reasoning - Add supportsReasoningEffort + reasoningEffort to GLM-5.x model catalog entries - Add supportsReasoningBinary to MiniMax-M2.5 model catalog entry - Add 'ultracode' to supportsReasoningEffort schema in model.ts - Override createStream + completePrompt in FriendliHandler - buildFriendliReasoningParams(): injects Friendli-specific reasoning params - Controllable (GLM-5.x): reasoning_effort + chat_template_kwargs + parse_reasoning - Always-reasoning (MiniMax-M2.5): parse_reasoning only - Non-reasoning: no extra params - Add 8 reasoning-specific test cases (29 total)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 baseBaseOpenAiCompatibleProviderdoes not handle. This PR overridescreateStreamandcompletePromptinFriendliHandlerto inject these parameters.Ref: https://friendli.ai/docs/guides/reasoning
Changes
Model catalog (
packages/types/src/providers/friendli.ts)supportsReasoningEffort: ["minimal","low","medium","high","xhigh","max"]+reasoningEffort: "high"(controllable reasoning models)supportsReasoningBinary: true(always-reasoning model)Handler (
src/api/providers/friendli.ts)createStreamandcompletePromptto inject Friendli reasoning params viabuildFriendliReasoningParams()reasoning_effort+chat_template_kwargs: { enable_thinking: true }+parse_reasoning/include_reasoningwhen user selects a valid effortparse_reasoning/include_reasoningonly"none"or"disable", orenableReasoningEffort=false, no Friendli reasoning params are sent — the model runs at its default behaviordelta.reasoning_contentstreaming already handled byextractReasoningFromDeltain base classTests (
src/api/providers/__tests__/friendli.spec.ts)Design decisions
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.ultracode: Friendli API supportsultracodein the enum but we do not surface it — only the standard efforts up tomax.preserveReasoning: Friendli only supports stateless responses API — multi-turn reasoning re-submission has no effect.Test plan
pnpm vitest run api/providers/__tests__/friendli.spec.ts— 29/29 passpnpm run build— successpnpm run lint(src + packages/types) — clean