Skip to content

Commit 0365972

Browse files
author
Zeph Gillen
committed
Merge upstream v3.56.0 into local/daily-driver
Brings in: - chore: prepare v3.56.0 release (Zoo-Code-Org#398) - fix: API requests hang indefinitely on VS Code 1.122.0+ (Zoo-Code-Org#383) - feat: add Claude Opus 4.8 support across Anthropic, Bedrock, and Vertex (Zoo-Code-Org#386) - Show Zoo Code in outbound provider activity logs (Zoo-Code-Org#219) Conflict resolutions and adjustments below. Anthropic Opus 4.8 (packages/types/src/providers/anthropic.ts) -------------------------------------------------------------- Kept our effort-array shape from 64fc5fc (supportsReasoningEffort: [low, medium, high, xhigh, max], default "high", requiredReasoningEffort: true). Discarded upstream's binary supportsReasoningBudget + supportsReasoningBinary shape -- the local fork uses effort-based reasoning across all Anthropic Opus 4.x models (foundation: fd93c5b). Vertex Opus 4.8 (packages/types/src/providers/vertex.ts) -------------------------------------------------------- Upstream's verbatim Vertex 4.8 entry would emit a 400 in our codebase: unlike Bedrock, Vertex has no provider-side adaptive-thinking guard, so the registry shape alone decides the request payload. With supportsReasoningBudget: true, our getAnthropicReasoning() would emit { thinking: { type: "enabled", budget_tokens } } -- which Opus 4.8 rejects. Converted Vertex 4.8 to the same effort-array shape as our Anthropic 4.8 so the helper hits the adaptive/effort branch and emits { thinking: { type: "adaptive" }, output_config: { effort: "high" } }. The pre-existing Vertex Opus 4.7 entry still uses the legacy budget shape (also broken on the API). That's a known follow-up from fd93c5b and intentionally out of scope for this merge. Vertex provider (src/api/providers/anthropic-vertex.ts) ------------------------------------------------------- Dropped upstream's explicit getAnthropicProviderReasoning() call in getModel() and the associated import. Our getModelParams({format: "anthropic"}) already returns params.reasoning via the unified getAnthropicReasoning helper (post-fd93c5bde), so the explicit call would duplicate the wiring and lose user-chosen efforts (upstream's call site omits reasoningEffort). Bedrock (src/api/providers/bedrock.ts, packages/types/src/providers/bedrock.ts) ------------------------------------------------------------------------------ Took upstream verbatim. The Bedrock provider has its own isAdaptiveThinkingModel guard that overrides the request payload regardless of registry shape, so the budget-shape registry entries are fine here. Tests (src/api/providers/__tests__/anthropic.spec.ts) ----------------------------------------------------- Rewrote four upstream-added Opus 4.8 tests that asserted the budget/binary shape to mirror our existing 4.7 effort-shape tests: - "should use adaptive thinking ..." -> assert output_config.effort: "high" - "should omit thinking when reasoning disabled" -> replaced with "should always emit adaptive thinking (reasoning is required)" - "should preserve custom maxTokens" -> replaced with "should honor user-chosen effort" (matching our 4.7 pattern) - "should handle Claude Opus 4.8 model correctly" -> assert supportsReasoningEffort array, default "high", requiredReasoningEffort Verification ------------ - pnpm -w check-types: 11/11 packages clean - pnpm -w test: 22 failures, all pre-existing in reasoning.spec.ts and model-params.spec.ts (matches MEMORY baseline from fd93c5b fixture drift). Zero new failures.
2 parents 64fc5fc + a88d480 commit 0365972

81 files changed

Lines changed: 1674 additions & 765 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.

.changeset/terminate-process-on-cancel.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/vertex-credentials-field-validation.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.roo/commands/release.md

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,29 +53,20 @@ mode: code
5353
- Order the list from most important to least important.
5454
- Include every PR in the release window. Count the PRs and cross-reference the list before continuing.
5555
56-
7. If an image generation tool is available, create a release image at `releases/[version]-release.png`.
57-
58-
- The image should relate to the main release highlight and fit the existing release-image style.
59-
- Add the generated image to `.changeset/v[version].md` before the list of changes:
60-
61-
```md
62-
![X.Y.Z Release - Description](/releases/X.Y.Z-release.png)
63-
```
64-
65-
8. For a major or minor release:
56+
7. For a major or minor release:
6657
6758
- Ask the user what three areas should be highlighted.
6859
- Update relevant announcement files and documentation, including `webview-ui/src/components/chat/Announcement.tsx`, `README.md`, and the `latestAnnouncementId` in `src/core/webview/ClineProvider.ts`.
6960
- Ask the user to confirm the English announcement before proceeding.
7061
- Arrange translation updates for all supported locales affected by README, announcement, or package localization changes.
7162
72-
9. Create the release branch:
63+
8. Create the release branch:
7364
7465
```bash
7566
git checkout -b release/v[version]
7667
```
7768
78-
10. Generate the final release state on that branch:
69+
9. Generate the final release state on that branch:
7970
8071
```bash
8172
pnpm changeset:version
@@ -84,23 +75,23 @@ mode: code
8475
- This should update `src/package.json`, `CHANGELOG.md`, and `src/CHANGELOG.md`, then consume the `.changeset` file.
8576
- Review the generated version and changelog before opening the PR.
8677
87-
11. Open a single release PR with the fully generated release state.
78+
10. Open a single release PR with the fully generated release state.
8879
8980
```bash
9081
git add CHANGELOG.md src/CHANGELOG.md src/package.json README.md locales/*/README.md src/package.nls*.json
9182
# If generated or updated:
92-
git add releases/[version]-release.png webview-ui/src/components/chat/Announcement.tsx src/core/webview/ClineProvider.ts
83+
git add webview-ui/src/components/chat/Announcement.tsx src/core/webview/ClineProvider.ts
9384
git commit -m "chore: prepare v[version] release"
9485
git push origin release/v[version]
95-
gh pr create --title "Release v[version]" --body "Release preparation for v[version]. This PR includes the final version bump, changelog updates, Marketplace README updates, and any release assets or announcement changes." --base main --head release/v[version]
86+
gh pr create --title "Release v[version]" --body "Release preparation for v[version]. This PR includes the final version bump, changelog updates, Marketplace README updates, and any announcement changes." --base main --head release/v[version]
9687
```
9788
9889
- There is no separate version-bump PR in this flow.
9990
- The release PR should already contain the final version number and generated changelog updates.
10091
- If the release includes translated README or package-localization updates, include those files in the same PR.
10192
- Let the release validation workflow and normal PR checks run before merge.
10293
103-
12. After the release PR is merged, stop for a release review on the resulting `main` commit.
94+
11. After the release PR is merged, stop for a release review on the resulting `main` commit.
10495
10596
```bash
10697
git switch main
@@ -115,7 +106,7 @@ mode: code
115106
- Share that review summary, including `REVIEWED_SHA`, with the user and wait for explicit confirmation before creating the tag.
116107
- Do not create the tag or trigger publishing until the user says to proceed.
117108
118-
13. Only after explicit confirmation, create the release tag on that reviewed `main` commit:
109+
12. Only after explicit confirmation, create the release tag on that reviewed `main` commit:
119110
120111
```bash
121112
git tag v[version] "$REVIEWED_SHA"
@@ -124,7 +115,7 @@ mode: code
124115
125116
- If `main` advances after the review pause, keep using the pinned `REVIEWED_SHA` for the tag instead of silently tagging a newer commit.
126117
127-
14. The stable publish workflow runs from the `v[version]` tag.
118+
13. The stable publish workflow runs from the `v[version]` tag.
128119
129120
- Do not create the tag before the release PR is merged.
130121
- The publish workflow validates that the tag version matches `src/package.json`.

CHANGELOG.md

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

3+
## 3.56.0
4+
5+
### Minor Changes
6+
7+
- Add Claude Opus 4.8 support across Anthropic, Bedrock, and Vertex providers (PR #386 by @vandre-sales)
8+
- Add Opencode Go as a first-class provider (#172 by @vijay-0001, PR #319 by @proyectoauraorg)
9+
- Add glm-5.1, kimi-k2.6, and deepseek-v4-pro models to the Fireworks provider (#198 by @DeCodeTheWeb, PR #231 by @proyectoauraorg)
10+
- Show Zoo Code identity in outbound provider activity logs (#203 by @yfdyh000, PR #219 by @app/roomote)
11+
- Fix API requests hanging indefinitely on VS Code 1.122.0+ (#381 by @greatgradz-svg, #382 by @abcxlab, PR #383 by @app/roomote)
12+
- Fix terminal task cancellation so the running process is terminated when a task is cancelled (#245 by @proyectoauraorg, PR #261 by @proyectoauraorg)
13+
- Fix terminal Ctrl+C retry so processes that need multiple SIGINT signals are properly stopped (#266 by @edelauna, PR #272 by @proyectoauraorg)
14+
- Fix Gemini provider to honor custom model IDs instead of falling back to the default (#227 by @notoccupy2023-design, PR #317 by @proyectoauraorg)
15+
- Fix truncated Grok diffs caused by missing diff markers (#186 by @jcalfee, PR #230 by @proyectoauraorg)
16+
- Fix PowerShell detection on Windows when no shell profile is configured (#82 by @rossdonald, PR #239 by @proyectoauraorg)
17+
- Fix Vertex AI warning when the Google Cloud Credentials field receives a file path instead of JSON (PR #294 by @0xMink)
18+
- Rename Zoo Code in VS Code code actions (#328 by @rrewll, PR #329 by @rrewll)
19+
- Localize VS Code code action commands (#334 by @edelauna, PR #339 by @rrewll)
20+
- Migrate webview build to Vite 8 (PR #214 by @maxdewald)
21+
- Add comprehensive unit tests for AskFollowupQuestionTool and ListFilesTool (#206 by @app/roomote, PR #212, #213 by @proyectoauraorg)
22+
- Update `diff` to v5.2.2 for a security fix (PR #173 by @app/renovate)
23+
- Update `i18next-http-backend` to v3.0.5 for a security fix (PR #174 by @app/renovate)
24+
- Update `fast-xml-parser` to v5.7.0 for a security fix (PR #179 by @app/renovate)
25+
- Update `simple-git` to v3.36.0 for a security fix (PR #182 by @app/renovate)
26+
- Update `uuid` and pin esbuild/rollup/vite for a security fix (PR #205 by @app/renovate)
27+
- Update `turbo` to v2.9.14 for a security fix (PR #236 by @app/renovate)
28+
29+
## 3.55.1
30+
31+
### Patch Changes
32+
33+
- Fix API requests hanging indefinitely on VS Code 1.122.0+ when Zoo Code could not find the bundled ripgrep binary after the `@vscode/ripgrep-universal` rename (#381 by @greatgradz-svg, PR #248 by @0xMink).
34+
335
All notable changes to Zoo Code will be documented in this file.
436

537
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and Zoo Code uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

README.md

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,17 @@
5353
You can find a quick guide for migrating from Roo Code to Zoo Code in the [Roo→Zoo migration guide](https://docs.zoocode.dev/roo-to-zoo-migration). We plan to try and help users as they transition over, we have our [Reddit](https://www.reddit.com/r/ZooCode) and [Discord](https://discord.gg/VxfP4Vx3gX)
5454
for this exact support, so if you are having problems or if you have question, jump on and ask.
5555

56-
## What's New in v3.55.0
57-
58-
**Zoo Code's first feature release** builds on the marketplace handoff with a
59-
new provider, the upstream sunset merge, and a round of user-facing fixes
60-
across chat, provider settings, and rendering.
61-
62-
- Add Xiaomi MiMo as a first-class API provider
63-
- Pull in the upstream Roo Code sunset merge and related platform updates
64-
- Fix MCP sign-in copy, Gemini full-tool requests, and OpenAI temperature
65-
handling for unsupported models
66-
- Fix Markdown single-tilde rendering and diagnostics temp-file naming
67-
- Improve provider defaults and region coverage for Z.AI, GLM, and Vertex AI
56+
## What's New in v3.56.0
57+
58+
- **Claude Opus 4.8** support across Anthropic, Bedrock, and Vertex providers
59+
- **Opencode Go** added as a new first-class API provider
60+
- **Reliable task cancellation** — cancelling a task now terminates the running process, with automatic Ctrl+C retry for stubborn processes
61+
- Fix Gemini custom model IDs being ignored and falling back to the default
62+
- Fix truncated Grok diffs caused by missing diff markers
63+
- Fix PowerShell detection on Windows when no shell profile is configured
64+
- Fix VS Code code actions still showing Roo Code branding; localized into all supported languages
65+
- Fix Vertex AI warning when the Google Cloud Credentials field receives a file path
66+
- Six security dependency updates (diff, i18next-http-backend, fast-xml-parser, simple-git, uuid, turbo)
6867

6968
<details>
7069
<summary>🌐 Available languages</summary>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"fixtures": [
3+
{
4+
"match": {
5+
"userMessage": "bedrock-identity-smoke"
6+
},
7+
"response": {
8+
"toolCalls": [
9+
{
10+
"name": "attempt_completion",
11+
"arguments": "{\"result\":\"4\"}",
12+
"id": "call_bedrock_identity_001"
13+
}
14+
]
15+
}
16+
}
17+
]
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"fixtures": [
3+
{
4+
"match": {
5+
"userMessage": "openrouter-identity-smoke"
6+
},
7+
"response": {
8+
"toolCalls": [
9+
{
10+
"name": "attempt_completion",
11+
"arguments": "{\"result\":\"4\"}",
12+
"id": "call_openrouter_identity_001"
13+
}
14+
]
15+
}
16+
}
17+
]
18+
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import * as http2 from "http2"
2+
import * as net from "net"
3+
import { crc32 } from "zlib"
4+
5+
export interface BedrockMockServer {
6+
url: string
7+
/** Headers from the most recent converse-stream request (populated after first call). */
8+
lastRequestHeaders: http2.IncomingHttpHeaders | undefined
9+
close(): Promise<void>
10+
}
11+
12+
// AWS binary event stream encoder — matches the real Bedrock wire format.
13+
// Derived from the live converse-stream capture:
14+
// { contentBlockDelta: { contentBlockIndex: 0, delta: { toolUse: { input: "..." } } } }
15+
// aimock's builder nests the payload one level too deep (contentBlockDelta inside contentBlockDelta),
16+
// causing the AWS SDK deserializer's take() to miss the delta field entirely.
17+
function encodeHeaders(headers: Record<string, string>): Buffer {
18+
const parts: Buffer[] = []
19+
for (const [name, value] of Object.entries(headers)) {
20+
const nameBytes = Buffer.from(name, "utf8")
21+
const valueBytes = Buffer.from(value, "utf8")
22+
const buf = Buffer.alloc(1 + nameBytes.length + 1 + 2 + valueBytes.length)
23+
let off = 0
24+
buf.writeUInt8(nameBytes.length, off)
25+
off += 1
26+
nameBytes.copy(buf, off)
27+
off += nameBytes.length
28+
buf.writeUInt8(7, off)
29+
off += 1 // type 7 = string
30+
buf.writeUInt16BE(valueBytes.length, off)
31+
off += 2
32+
valueBytes.copy(buf, off)
33+
parts.push(buf)
34+
}
35+
return Buffer.concat(parts)
36+
}
37+
38+
function encodeFrame(eventType: string, payload: object): Buffer {
39+
const hdrs = encodeHeaders({
40+
":content-type": "application/json",
41+
":event-type": eventType,
42+
":message-type": "event",
43+
})
44+
const body = Buffer.from(JSON.stringify(payload), "utf8")
45+
const total = 12 + hdrs.length + body.length + 4
46+
const frame = Buffer.alloc(total)
47+
let off = 0
48+
frame.writeUInt32BE(total, off)
49+
off += 4
50+
frame.writeUInt32BE(hdrs.length, off)
51+
off += 4
52+
frame.writeUInt32BE(crc32(frame.subarray(0, 8)) >>> 0, off)
53+
off += 4
54+
hdrs.copy(frame, off)
55+
off += hdrs.length
56+
body.copy(frame, off)
57+
off += body.length
58+
frame.writeUInt32BE(crc32(frame.subarray(0, total - 4)) >>> 0, off)
59+
return frame
60+
}
61+
62+
function buildToolCallFrames(toolName: string, toolUseId: string, argsJson: string): Buffer[] {
63+
const frames: Buffer[] = []
64+
frames.push(encodeFrame("messageStart", { role: "assistant" }))
65+
frames.push(
66+
encodeFrame("contentBlockStart", {
67+
contentBlockIndex: 0,
68+
start: { toolUse: { name: toolName, toolUseId } },
69+
}),
70+
)
71+
const CHUNK = 20
72+
for (let i = 0; i < argsJson.length; i += CHUNK) {
73+
frames.push(
74+
encodeFrame("contentBlockDelta", {
75+
contentBlockIndex: 0,
76+
delta: { toolUse: { input: argsJson.slice(i, i + CHUNK) } },
77+
}),
78+
)
79+
}
80+
frames.push(encodeFrame("contentBlockStop", { contentBlockIndex: 0 }))
81+
frames.push(encodeFrame("messageStop", { stopReason: "tool_use" }))
82+
frames.push(
83+
encodeFrame("metadata", {
84+
metrics: { latencyMs: 1 },
85+
usage: { inputTokens: 100, outputTokens: 10, totalTokens: 110, serverToolUsage: {} },
86+
}),
87+
)
88+
return frames
89+
}
90+
91+
export async function startBedrockMockServer(): Promise<BedrockMockServer> {
92+
// HTTP/2 cleartext (h2c) — matches what @aws-sdk/client-bedrock-runtime uses by default.
93+
const server = http2.createServer()
94+
let lastRequestHeaders: http2.IncomingHttpHeaders | undefined
95+
const sessions = new Set<http2.ServerHttp2Session>()
96+
97+
server.on("session", (session) => {
98+
sessions.add(session)
99+
session.on("close", () => sessions.delete(session))
100+
})
101+
102+
server.on("stream", (stream, headers) => {
103+
const path = headers[":path"] as string
104+
const method = headers[":method"] as string
105+
106+
if (!path?.includes("converse-stream") || method !== "POST") {
107+
stream.respond({ ":status": 404 })
108+
stream.end(JSON.stringify({ error: { message: "Not found", type: "not_found" } }))
109+
return
110+
}
111+
112+
lastRequestHeaders = headers
113+
114+
// Drain the request body before responding (AWS SDK sends the full request before reading).
115+
stream.resume()
116+
stream.on("end", () => {
117+
stream.respond({
118+
":status": 200,
119+
"content-type": "application/vnd.amazon.eventstream",
120+
})
121+
const frames = buildToolCallFrames(
122+
"attempt_completion",
123+
"tooluse_bedrock_mock_001",
124+
JSON.stringify({ result: "4" }),
125+
)
126+
for (const frame of frames) {
127+
stream.write(frame)
128+
}
129+
stream.end()
130+
})
131+
})
132+
133+
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve))
134+
const addr = server.address() as net.AddressInfo
135+
const url = `http://127.0.0.1:${addr.port}`
136+
137+
return {
138+
url,
139+
get lastRequestHeaders() {
140+
return lastRequestHeaders
141+
},
142+
close: () => {
143+
// Destroy all open HTTP/2 sessions first so server.close() resolves immediately
144+
// instead of waiting for the extension's retry loop to exhaust itself.
145+
for (const session of sessions) {
146+
session.destroy()
147+
}
148+
sessions.clear()
149+
return new Promise<void>((resolve, reject) => server.close((err) => (err ? reject(err) : resolve())))
150+
},
151+
}
152+
}

apps/vscode-e2e/src/runTest.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,21 @@ function isDeepSeekTargetedRun(testFile?: string, testGrep?: string) {
2626
return testGrep?.toLowerCase().includes("deepseek") ?? false
2727
}
2828

29+
function isBedrockTargetedRun(testFile?: string, testGrep?: string) {
30+
if (testFile?.toLowerCase().includes("bedrock.test")) {
31+
return true
32+
}
33+
34+
return testGrep?.toLowerCase().includes("bedrock") ?? false
35+
}
36+
2937
async function main() {
3038
const isRecord = process.env.AIMOCK_RECORD === "true"
3139
const testGrep = getCliFlagValue("--grep") || process.env.TEST_GREP
3240
const testFile = getCliFlagValue("--file") || process.env.TEST_FILE
3341
const isDeepSeekTest = isDeepSeekTargetedRun(testFile, testGrep)
3442
const isGeminiTest = testFile?.toLowerCase().includes("gemini.test") ?? false
43+
const isBedrockTest = isBedrockTargetedRun(testFile, testGrep)
3544

3645
if (isRecord && isDeepSeekTest && !process.env.DEEPSEEK_API_KEY) {
3746
throw new Error("AIMOCK_RECORD=true requires DEEPSEEK_API_KEY to record DeepSeek fixtures")
@@ -49,7 +58,9 @@ async function main() {
4958
// Replay mode starts aimock when no real API key is present or USE_MOCK is forced.
5059
const hasRealApiKey = isDeepSeekTest
5160
? !!process.env.DEEPSEEK_API_KEY
52-
: !!(process.env.OPENROUTER_API_KEY || process.env.ANTHROPIC_API_KEY)
61+
: isBedrockTest
62+
? true // Bedrock test starts its own binary-event-stream mock server when no real token
63+
: !!(process.env.OPENROUTER_API_KEY || process.env.ANTHROPIC_API_KEY)
5364
const useMock = isRecord || !hasRealApiKey || process.env.USE_MOCK === "true"
5465

5566
let mock: InstanceType<typeof LLMock> | undefined

0 commit comments

Comments
 (0)