Skip to content

Commit 2f014e4

Browse files
Merge remote-tracking branch 'upstream/main' into feat/abort-r2-lmstudio-qwen
# Conflicts: # src/api/providers/utils/__tests__/abort-signal.spec.ts
2 parents 235257a + 5cc5a37 commit 2f014e4

238 files changed

Lines changed: 13034 additions & 1243 deletions

File tree

Some content is hidden

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

‎.github/actions/setup-node-pnpm/action.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ inputs:
66
node-version:
77
description: "Node.js version to use"
88
required: false
9-
default: "22.23.1"
9+
default: "22.23.4"
1010
pnpm-version:
1111
description: "pnpm version to use"
1212
required: false

‎.github/workflows/code-qa.yml‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ jobs:
9898
run: pnpm check-types
9999
- name: Validate Code QA workflow
100100
run: pnpm test:code-qa-ci
101+
- name: Validate Solheim provider smoke workflow
102+
run: pnpm test:solheim-smoke-ci
103+
- name: Test Solheim provider smoke units
104+
run: pnpm test:solheim-smoke:unit
105+
- name: Check Solheim provider smoke types
106+
run: pnpm solheim-smoke:check-types
107+
- name: Test agent evals units
108+
run: pnpm test:agent-evals:unit
109+
- name: Check agent evals types
110+
run: pnpm agent-evals:check-types
101111
- name: Model-check task lifecycle protocols
102112
run: pnpm lifecycle:model-check
103113
- name: Validate MCP OAuth integration

‎.github/workflows/release-kickoff.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ name: Weekly release kickoff
2323

2424
on:
2525
schedule:
26-
# Friday at 7:00pm ET (23:00 UTC during daylight saving time).
27-
# This fixed UTC cron fires at 6:00pm ET while the US is on EST.
28-
- cron: "0 23 * * 5"
26+
# Friday at 12:00pm EST (17:00 UTC).
27+
# This fixed UTC cron fires at 1:00pm ET while the US is on EDT.
28+
- cron: "0 17 * * 5"
2929
workflow_dispatch:
3030

3131
permissions: {}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
name: Solheim provider smoke
2+
3+
# Project A: infrastructure validation only. No PR diff, review judgment, router,
4+
# deterministic review rule, or GitHub posting. Only trusted main-branch code runs.
5+
on:
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
11+
concurrency:
12+
group: solheim-provider-smoke
13+
cancel-in-progress: false
14+
15+
jobs:
16+
smoke:
17+
if: github.ref == 'refs/heads/main'
18+
runs-on: ubuntu-24.04
19+
timeout-minutes: 25
20+
# Retain the existing protected environment and secret names for compatibility.
21+
# The environment requires reviewer approval, matching the deploy
22+
# environment. The job guard above restricts runs to main, so the
23+
# secret is released only for an approved main run. See
24+
# scripts/solheim-smoke/README.md.
25+
environment: final-vscode-review-smoke
26+
steps:
27+
- name: Checkout exact trusted main revision
28+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
29+
with:
30+
ref: ${{ github.sha }}
31+
persist-credentials: false
32+
33+
- name: Setup Node.js and pnpm
34+
uses: ./.github/actions/setup-node-pnpm
35+
with:
36+
install-args: "--frozen-lockfile"
37+
38+
- name: Build trusted extension and webview
39+
run: |
40+
pnpm -w bundle
41+
pnpm --filter @roo-code/vscode-webview build
42+
43+
- name: Install display dependencies
44+
run: sudo apt-get update && sudo apt-get install -y xvfb ffmpeg libasound2t64
45+
46+
- name: Run Solheim provider smoke
47+
id: provider
48+
timeout-minutes: 8
49+
env:
50+
SOLHEIM_API_KEY: ${{ secrets.FINAL_SMOKE_OPENAI_API_KEY }}
51+
SOLHEIM_SMOKE_OUT_DIR: ${{ runner.temp }}/solheim-provider-smoke
52+
run: xvfb-run -a -s "-screen 0 1280x720x24 -nolisten tcp" bash scripts/solheim-smoke/record.sh
53+
54+
# The recorder publishes smoke.mp4 only through an atomic rename
55+
# after a nonempty check and ffprobe validation, so the published
56+
# final is the commit marker: present and nonempty means complete.
57+
# There is no separate persisted status marker.
58+
- name: Verify recording integrity
59+
if: ${{ !cancelled() && (steps.provider.outcome == 'success' || steps.provider.outcome == 'failure') }}
60+
env:
61+
SOLHEIM_SMOKE_OUT_DIR: ${{ runner.temp }}/solheim-provider-smoke
62+
run: |
63+
test -s "$SOLHEIM_SMOKE_OUT_DIR/smoke.mp4"
64+
echo "Recording published and nonempty: $SOLHEIM_SMOKE_OUT_DIR/smoke.mp4"
65+
66+
# Verdict and trace evidence must survive even when the recording
67+
# is missing, so metadata and video are uploaded separately.
68+
- name: Upload provider smoke verdict and trace
69+
if: ${{ !cancelled() && (steps.provider.outcome == 'success' || steps.provider.outcome == 'failure') }}
70+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
71+
with:
72+
name: solheim-provider-smoke-${{ github.sha }}
73+
path: |
74+
${{ runner.temp }}/solheim-provider-smoke/verdict.json
75+
${{ runner.temp }}/solheim-provider-smoke/trace.json
76+
if-no-files-found: error
77+
retention-days: 7
78+
79+
# Exact validated final path only; the recorder leaves no temporary
80+
# file behind, so a failed upload here reports the missing recording.
81+
- name: Upload provider smoke recording
82+
if: ${{ !cancelled() && (steps.provider.outcome == 'success' || steps.provider.outcome == 'failure') }}
83+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
84+
with:
85+
name: solheim-provider-smoke-recording-${{ github.sha }}
86+
path: ${{ runner.temp }}/solheim-provider-smoke/smoke.mp4
87+
if-no-files-found: error
88+
retention-days: 7

‎.nvmrc‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
22.23.1
1+
22.23.4

‎.tool-versions‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
pnpm 10.8.1
2-
nodejs 22.23.1
2+
nodejs 22.23.4

‎CHANGELOG.md‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,73 @@
11
# Zoo Code Changelog
22

3+
## [3.92.0]
4+
5+
- ✨ **Faster model choice and stronger model support:** Switch models from the chat composer. Use Claude Haiku 5.5 on Amazon Bedrock, get more accurate Kimi K3 capabilities on OpenRouter, and use corrected Gemini 4 Argon limits on Vercel AI Gateway.
6+
- 🧭 **More reliable terminal, editing, chat, and remote workflows:** Collapse command output by default when you choose, get clearer editing failures, keep reasoning and API rows visible, and avoid startup and proxy issues in remote workspaces.
7+
- 🔌 **Expanded MCP marketplace:** Connect Zoo Code to AnySearch, Mailtea, and Tradehand through the MCP marketplace.
8+
9+
### Faster Model Choice and Stronger Model Support
10+
11+
- Add an inline model selector to the chat composer (#1502 by @daewoongoh, PR #2034 by @daewoongoh)
12+
- Add Claude Haiku 5.5 to the Amazon Bedrock model catalog (PR #2100 by @app/zoomote)
13+
- Correct Kimi K3 capabilities and reasoning effort on OpenRouter (#1316 by @CodeCruncher88, PR #1325 by @easonLiangWorldedtech)
14+
- Clamp Gemini 4 Argon to Google's limits on Vercel AI Gateway (PR #2073 by @taltas)
15+
16+
### Terminal, Editing, Chat, and Remote Reliability
17+
18+
- Add abort-signal support to the native Ollama provider (#404 by @Fuzzillogic, PR #1299 by @easonLiangWorldedtech)
19+
- Fix Destructive Command Guard startup errors in remote workspaces (#1603 by @atoomnetmarc, #1770 by @DaubnerF, PR #1639 by @PierrunoYT)
20+
- Route the Bedrock code-index embedder through the system proxy (#1772 by @LouisClt, PR #1773 by @LouisClt)
21+
- Require HTTPS for custom Google Gemini base URLs while allowing loopback HTTP (PR #2033 by @easonLiangWorldedtech)
22+
- Add a setting to collapse terminal command output by default (#605 by @AmitTzah, PR #2042 by @bigyao25)
23+
- Report all apply-diff failures with clearer diagnostics (PR #2053 by @simurg79)
24+
- Keep reasoning and API request rows visible after batched reads (#2061 by @danGO-79, PR #2126 by @PierrunoYT)
25+
26+
### Expanded MCP Marketplace
27+
28+
- Add AnySearch to the MCP marketplace (#1956 by @hieutran0413, PR #1955 by @hieutran0413)
29+
- Add Mailtea to the MCP marketplace (#2140 by @davepoon, PR #1869 by @davepoon)
30+
- Add Tradehand to the MCP marketplace (#2121 by @Blakefolgado, PR #2123 by @Blakefolgado)
31+
32+
### Task Lifecycle Reliability
33+
34+
- Add run-state divergence comparison and metrics (RSK-05) (#1795 by @edelauna, PR #2047 by @edelauna)
35+
- Add the run-state turn sub-machine (RSK-09) (#1800 by @edelauna, PR #2127 by @edelauna)
36+
- Route task latch and initialization writes through run-state events (RSK-06) (#1796 by @edelauna, PR #2128 by @edelauna)
37+
- Make Task.create share its startup path and promise with Task.run (#2145 by @edelauna, PR #2146 by @app/zoomote)
38+
39+
### Testing, Performance, and Repository Automation
40+
41+
- Enable Knip production analysis and remove dead code (#519 by @edelauna, PR #527 by @edelauna)
42+
- Add a trusted evaluation fixture runner and execution traces (#1896 by @edelauna, PR #1909 by @edelauna)
43+
- Keep the has-conflicts label while GitHub recomputes mergeability (#2045 by @edelauna, PR #2048 by @app/zoomote)
44+
- Refresh fork PR review-state labels after reviews (#2046 by @edelauna, PR #2049 by @app/zoomote)
45+
- Add weekly release kickoff automation with maintainer rotation (PR #2075 by @app/zoomote)
46+
- Base stale PR timing on author activity instead of bot activity (#2076 by @edelauna, PR #2077 by @app/zoomote)
47+
- Stabilize restart-persistence E2E coverage and improve task-message read errors (#2078 by @edelauna, PR #2080 by @app/zoomote)
48+
- Prevent the review-state label workflow from listening to itself (#2086 by @edelauna, PR #2088 by @app/zoomote)
49+
- Freeze review-state labels while GitHub computes mergeability (#2089 by @edelauna, PR #2091 by @app/zoomote)
50+
- Speed up lint and type checks with caching and staged-only pre-commit lint (#2090 by @edelauna, PR #2092 by @app/zoomote)
51+
- Keep conflict status separate from review-state turn labels (part of #2089 by @edelauna, PR #2102 by @app/zoomote)
52+
- Dispatch fork review follow-up using the correct repository metadata (#2133 by @edelauna, PR #2134 by @app/zoomote)
53+
54+
### Dependencies and Maintenance
55+
56+
- Update build, lint, and test tooling (PR #804 by @app/renovate)
57+
- Update KaTeX to v0.18 (PR #1975 by @app/renovate)
58+
- Update simple-git to v4 (PR #1976 by @app/renovate)
59+
- Update Zod to v4 (PR #2029 by @app/renovate)
60+
- Pin dependencies (PR #2035 by @app/renovate)
61+
- Update AI SDK core and providers (PR #2071 by @app/renovate)
62+
- Update @changesets/cli to v2.31.1 (PR #2081 by @app/renovate)
63+
- Pin dependencies after provider updates (PR #2087 by @app/renovate)
64+
- Update @eslint/js to v9.39.5 (PR #2094 by @app/renovate)
65+
- Refresh the lockfile (PR #2097 by @app/renovate)
66+
67+
### Housekeeping
68+
69+
- Merge the **previous v3.90.0 release preparation** after its publication; this is prior-release housekeeping, not a v3.92.0 feature (PR #2074 by @JamesRobert20)
70+
371
## [3.90.0]
472

573
- ✨ **Providers and models:** GitHub Copilot is now a provider: sign in and Zoo Code loads your Copilot models. IO Intelligence is a provider with its own API key. Gemini 4 Argon is on Gemini and Vertex. GPT-6 Luna is on OpenCode Go. Gemini 4 Argon and GPT-6 Luna are on Zoo Gateway as well.

‎README.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ Zoo Code builds on the foundation created by Roo Code and continues to expand it
4646
- **More dependable terminal and editing workflows** — fixes for premature terminal completion, task-state races, context management, diff editing, and provider-specific tool use.
4747
- **More control over your workspace** — rules management, per-mode MCP restrictions, multi-root path controls, model reasoning options, and completion change review actions.
4848

49-
## What's New in v3.90.0
49+
## What's New in v3.92.0
5050

51-
- ✨ **Providers and models:** GitHub Copilot is now a provider: sign in and Zoo Code loads your Copilot models. IO Intelligence is a provider with its own API key. Gemini 4 Argon is on Gemini and Vertex. GPT-6 Luna is on OpenCode Go. Gemini 4 Argon and GPT-6 Luna are on Zoo Gateway as well.
52-
- 🧭 **Tool execution:** Repeating the same tool call gets a warning, then Zoo Code stops that loop. Disabling `attempt_completion` no longer leaves a task unable to finish. Queued messages run the same command-protection checks as commands you send directly.
53-
- ⚡ **Reasoning and streaming:** Anthropic adaptive thinking shows in chat, and thinking tokens are counted. The R1 toggle keeps reasoning from llama.cpp, Ollama, and LM Studio. Codex keeps encrypted reasoning with the summary you see. VS Code language-model streams use guarded recovery when a stream fails.
51+
- ✨ **Faster model choice and stronger model support:** Switch models from the chat composer. Use Claude Haiku 5.5 on Amazon Bedrock, get more accurate Kimi K3 capabilities on OpenRouter, and use corrected Gemini 4 Argon limits on Vercel AI Gateway.
52+
- 🧭 **More reliable terminal, editing, chat, and remote workflows:** Collapse command output by default when you choose, get clearer editing failures, keep reasoning and API rows visible, and avoid startup and proxy issues in remote workspaces.
53+
- 🔌 **Expanded MCP marketplace:** Connect Zoo Code to AnySearch, Mailtea, and Tradehand through the MCP marketplace.
5454

5555
<details>
5656
<summary>🌐 Available languages</summary>

‎apps/cli/package.json‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@
3737
"devDependencies": {
3838
"@roo-code/config-eslint": "workspace:^",
3939
"@roo-code/config-typescript": "workspace:^",
40-
"@types/node": "22.20.1",
40+
"@types/node": "catalog:",
4141
"@types/react": "18.3.31",
42-
"@vitest/coverage-v8": "4.1.11",
42+
"@vitest/coverage-v8": "catalog:",
4343
"execa": "9.6.1",
4444
"ink-testing-library": "4.0.0",
4545
"rimraf": "6.0.1",
4646
"tsup": "8.5.1",
4747
"tsx": "4.23.15",
48-
"vitest": "4.1.11"
48+
"vitest": "catalog:"
4949
}
5050
}

‎apps/cli/src/lib/utils/__tests__/context-window.test.ts‎

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { providerIdentifiers, type ProviderSettings } from "@roo-code/types"
1+
import { providerIdentifiers, retiredProviderIdentifiers, type ProviderSettings } from "@roo-code/types"
22

33
import { DEFAULT_CONTEXT_WINDOW, getContextWindow } from "../context-window.js"
44

@@ -24,6 +24,60 @@ describe("getContextWindow", () => {
2424
expect(getContextWindow(routerModels, config)).toBe(123_456)
2525
})
2626

27+
it.each([
28+
providerIdentifiers.anthropic,
29+
providerIdentifiers.bedrock,
30+
providerIdentifiers.deepseek,
31+
providerIdentifiers.fireworks,
32+
providerIdentifiers.gemini,
33+
providerIdentifiers.mistral,
34+
providerIdentifiers.openaiNative,
35+
providerIdentifiers.vertex,
36+
providerIdentifiers.xai,
37+
] as const)("uses the shared apiModelId field for %s", (provider) => {
38+
const config: ProviderSettings = { apiProvider: provider, apiModelId: "selected-model" }
39+
const routerModels = { [provider]: { "selected-model": { contextWindow: 64_000 } } }
40+
41+
expect(getContextWindow(routerModels, config)).toBe(64_000)
42+
})
43+
44+
it("ignores another provider's model field", () => {
45+
const config: ProviderSettings = {
46+
apiProvider: providerIdentifiers.ollama,
47+
openRouterModelId: "openrouter-model",
48+
ollamaModelId: "ollama-model",
49+
}
50+
const routerModels = {
51+
[providerIdentifiers.ollama]: { "ollama-model": { contextWindow: 32_000 } },
52+
}
53+
54+
expect(getContextWindow(routerModels, config)).toBe(32_000)
55+
})
56+
57+
describe("VS Code LM", () => {
58+
const provider = providerIdentifiers.vscodeLm
59+
const routerModels = { [provider]: { "selected-model": { contextWindow: 123_456 } } }
60+
61+
it("takes the model from the saved selector", () => {
62+
const config: ProviderSettings = {
63+
apiProvider: provider,
64+
vsCodeLmModelSelector: { vendor: "copilot", id: "selected-model" },
65+
}
66+
67+
expect(getContextWindow(routerModels, config)).toBe(123_456)
68+
})
69+
70+
it("ignores apiModelId, which the selector replaces", () => {
71+
const config: ProviderSettings = {
72+
apiProvider: provider,
73+
apiModelId: "other-model",
74+
vsCodeLmModelSelector: { vendor: "copilot", id: "selected-model" },
75+
}
76+
77+
expect(getContextWindow(routerModels, config)).toBe(123_456)
78+
})
79+
})
80+
2781
describe("GitHub Copilot", () => {
2882
const provider = providerIdentifiers.githubCopilot
2983
const routerModels = { [provider]: { "selected-model": { contextWindow: 123_456 } } }
@@ -66,19 +120,41 @@ describe("getContextWindow", () => {
66120
})
67121
})
68122

69-
it("uses apiModelId for providers without a specialized model field", () => {
123+
it("returns the default when the selected model is unavailable", () => {
124+
const routerModels = { [providerIdentifiers.openrouter]: { "other-model": { contextWindow: 1_000 } } }
125+
const config: ProviderSettings = {
126+
apiProvider: providerIdentifiers.openrouter,
127+
openRouterModelId: "missing-model",
128+
}
129+
130+
expect(getContextWindow(routerModels, config)).toBe(DEFAULT_CONTEXT_WINDOW)
131+
})
132+
133+
it("returns the default when no provider is selected", () => {
134+
expect(getContextWindow({}, {})).toBe(DEFAULT_CONTEXT_WINDOW)
135+
})
136+
137+
it("returns the default when router models are unavailable for a retired provider", () => {
70138
const config: ProviderSettings = {
71-
apiProvider: providerIdentifiers.anthropic,
139+
apiProvider: retiredProviderIdentifiers.groq,
72140
apiModelId: "selected-model",
73141
}
74-
const routerModels = {
75-
[providerIdentifiers.anthropic]: { "selected-model": { contextWindow: 64_000 } },
142+
143+
expect(getContextWindow({}, config)).toBe(DEFAULT_CONTEXT_WINDOW)
144+
})
145+
146+
it("resolves the model for a retired provider instead of throwing", () => {
147+
const config: ProviderSettings = {
148+
apiProvider: retiredProviderIdentifiers.groq,
149+
apiModelId: "selected-model",
76150
}
151+
const routerModels = { [retiredProviderIdentifiers.groq]: { "selected-model": { contextWindow: 48_000 } } }
77152

78-
expect(getContextWindow(routerModels, config)).toBe(64_000)
153+
expect(getContextWindow(routerModels, config)).toBe(48_000)
79154
})
80155

81-
it("returns the default when the selected model is unavailable", () => {
82-
expect(getContextWindow({}, { apiProvider: providerIdentifiers.openrouter })).toBe(DEFAULT_CONTEXT_WINDOW)
156+
it("returns the default when router models or configuration is missing", () => {
157+
expect(getContextWindow(null, { apiProvider: providerIdentifiers.anthropic })).toBe(DEFAULT_CONTEXT_WINDOW)
158+
expect(getContextWindow({}, null)).toBe(DEFAULT_CONTEXT_WINDOW)
83159
})
84160
})

0 commit comments

Comments
 (0)