Skip to content

Commit 43c1f3f

Browse files
author
Zoo (VP)
committed
fix: sync CI fixes from pr/b03-error-integration-v2
1 parent acdb211 commit 43c1f3f

120 files changed

Lines changed: 4161 additions & 5342 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.

.gitignore

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,3 @@ qdrant_storage/
5555
plans/
5656

5757
roo-cli-*.tar.gz*
58-
59-
# Local dev scripts (not for CI)
60-
/ci-fix-commit.ps1
61-
/commit-and-push.ps1
62-
/commit-message.txt
63-
/resolve_conflicts.py
64-
65-
# AI session artifacts (timestamped session directories)
66-
/docs/*_session_*/

CHANGELOG.md

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

3+
## [3.74.0]
4+
5+
### Minor Changes
6+
7+
- Add Fast priority mode for OpenAI Codex, persisting the selection and sending it with requests (PR #1063 by @WebMad)
8+
- Add higher reasoning-effort options for OpenAI-compatible models (#882 by @MINLEGO, PR #1051 by @ivanarifin)
9+
- Fetch router-provider model metadata before making context-management decisions (PR #1053 by @JamesRobert20)
10+
- Make Ollama model refreshes reliable, surface refresh errors, and use the base URL currently being edited (#877 by @navedmerchant, PR #878 by @navedmerchant)
11+
- Fix Amazon Bedrock DNS resolution when using a corporate proxy (#905 by @LouisClt, PR #906 by @LouisClt)
12+
- Add reasoning-parameter support to the Friendli provider (PR #886 by @Lee-Si-Yoon)
13+
- Keep Save-managed settings in the local editing buffer until the user explicitly saves (#862 by @JunyongParkDev, PR #872 by @JunyongParkDev)
14+
- Stop prompting about command output after short foreground commands have already completed (#1042 by @edelauna, PR #1043 by @app/zoomote)
15+
- Keep Architect mode plans workspace-relative so creating `./plans` does not fail on read-only filesystem roots (#965 by @juneleung, PR #968 by @app/zoomote)
16+
- Replace remaining user-facing Roo branding with Zoo branding (#551 by @proyectoauraorg, PR #971 by @rrewll)
17+
- Introduce a semaphore-based task scheduler for controlled task execution (#358 by @edelauna, PR #1031 by @edelauna)
18+
- Introduce `TaskRegistry` and migrate task-stack management to it (#367 by @edelauna, PR #1014 by @edelauna)
19+
- Complete the API provider migration to canonical provider identifiers (#955 by @WebMad, PR #1012 by @WebMad)
20+
- Use canonical provider identifiers for default model definitions (#954 by @WebMad, PR #991 by @WebMad)
21+
- Use canonical provider identifiers for API model caches (#957 by @WebMad, PR #1020 by @WebMad)
22+
- Use canonical provider identifiers in shared profile settings (#956 by @WebMad, PR #1019 by @WebMad)
23+
- Use canonical provider identifiers throughout extension-core flows (#958 by @WebMad, PR #1022 by @WebMad)
24+
- Use canonical provider identifiers throughout the webview (#959 by @WebMad, PR #1023 by @WebMad)
25+
- Finish the repository-wide canonical provider identifier audit (#960 by @WebMad, PR #1030 by @WebMad)
26+
- Centralize API service-tier types and helpers (PR #1040 by @WebMad)
27+
- Support the platform-package layout introduced by `@vscode/ripgrep` 1.18 and later (#1024 by @saravanaraj0078-lab, PR #1032 by @edelauna)
28+
- Update `shell-quote` to 1.9.0 to incorporate security fixes (PR #986 by @app/renovate)
29+
- Update the development and build toolchain to Node.js 22.23.1 LTS (PR #743 by @app/renovate)
30+
- Add a Playwright visual-regression harness for webview components (#515 by @edelauna, PR #526 by @edelauna)
31+
- Enforce the no-floating-promises lint ratchet in `core/webview` (#949 by @edelauna, PR #950 by @morgan-coded)
32+
- Harden the end-to-end workflow against transient VS Code binary download failures (#1044 by @edelauna, PR #1045 by @app/zoomote)
33+
- Isolate mocked subtask fixtures to prevent flaky parent-resume tests (#1001 by @app/zoomote, PR #1002 by @app/zoomote)
34+
- Prevent cancelled delayed mock streams from leaking between subtask end-to-end tests (PR #1074 by @app/zoomote)
35+
- Merge the v3.72.0 release preparation branch into `main` (PR #1013 by @navedmerchant)
36+
337
## [3.72.0]
438

539
### Minor Changes

README.md

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,28 @@
3535
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)
3636
for this exact support, so if you are having problems or if you have question, jump on and ask.
3737

38-
## What's New in v3.72.0
38+
## What's New in v3.74.0
3939

40-
- **Moonshot and Kimi Code providers** — discover Moonshot models dynamically or sign in to Kimi Code through its OAuth device flow.
41-
- **Latest model support** — use Claude Opus 5 across providers, plus Kimi K3, Gemini 3.6 Flash, and MiniMax-M3.
42-
- **Improved subtask workflows** — abandon interrupted subtasks cleanly, with safer task-history invalidation and better resume coverage.
43-
- **Expanded codebase indexing** — index Dart and plain-text files.
44-
- **Provider reliability** — fixes for GPT-5.6 Luna with ChatGPT OAuth, LiteLLM reasoning content, and DeepSeek V4 image input.
45-
- **Smoother setup and settings** — improved Zoo Gateway sign-in and mode-switch behavior.
46-
- API, provider-type, dependency, localization, and CI improvements.
40+
**Zoo Gateway is live!**
41+
42+
The gateway is a single endpoint for all providers, with one balance and per-request spending/usage breakdown.
43+
44+
**Setup:**
45+
46+
- Add credits: https://www.zoocode.dev/dashboard/credits
47+
- Sign in from the extension.
48+
- In the settings, select Zoo Gateway as the provider when creating profiles for different models
49+
50+
Usage and charges can be viewed in the [dashboard](https://www.zoocode.dev/dashboard).
51+
52+
Models: https://www.zoocode.dev/dashboard/models
53+
54+
- **More OpenAI controls** — use Fast priority mode with OpenAI Codex and choose higher reasoning effort for OpenAI-compatible models.
55+
- **More reliable providers and models** — improved router metadata handling, Ollama model refresh, Bedrock proxy support, and Friendli reasoning controls.
56+
- **Smoother settings and developer workflows** — settings now preserve unsaved edits, short terminal commands complete cleanly, architect plans use workspace-relative paths, and remaining user-facing Roo branding is updated to Zoo.
57+
- **Stronger task foundations** — new task registry and semaphore-based scheduler primitives prepare Zoo Code for safer task coordination.
58+
- **Consistent provider architecture** — provider identifiers and service-tier primitives are now centralized across the API, core, shared types, and webview.
59+
- Security, dependency, lint, visual-regression, and end-to-end test improvements.
4760

4861
<details>
4962
<summary>🌐 Available languages</summary>
@@ -66,6 +79,7 @@ for this exact support, so if you are having problems or if you have question, j
6679
- [Tiếng Việt](locales/vi/README.md)
6780
- [简体中文](locales/zh-CN/README.md)
6881
- [繁體中文](locales/zh-TW/README.md)
82+
6983
</details>
7084

7185
---

apps/vscode-e2e/AGENTS.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,17 @@ Example:
121121
122122
The `model` field can be added to either match when a test targets a specific model.
123123
124+
## Delaying a fixture response (simulating a slow or hung provider)
125+
126+
Use `streamingProfile: { ttft: <ms> }` on a fixture, not a flat `latency: <ms>`, when a test needs
127+
to simulate a slow or hung provider (e.g. to cancel an in-flight request mid-stream). `ttft` delays
128+
only the first SSE chunk, so the pending window is exactly the configured value. Flat `latency`
129+
delays _every_ chunk, and aimock never observes client disconnects — after a test cancels the
130+
request, a flat-latency stream keeps flushing chunks server-side for `chunks × latency` before
131+
reaching the dead socket, which can interleave with the next test's request against the same mock
132+
server. See `SUBTASK_API_HANG_RESPONSE_LATENCY_MS` in `fixtures/subtasks.ts` for an example,
133+
including the bounded post-test drain the calling suite uses to wait out that window.
134+
124135
## 404 errors in logs are expected
125136

126137
Background API calls from the extension (usage collection, initialization) hit aimock with no matching fixture and return 404. These do **not** affect test results — the tests still pass. You'll see `[OpenRouter] API error: { message: '404 No fixture matched' }` in the output; this is normal.

apps/vscode-e2e/src/fixtures/apply-diff.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export function addApplyDiffResultFixtures(mock: InstanceType<typeof LLMock>) {
3131
},
3232
{
3333
toolCallId: "call_apply_diff_error_001",
34-
expected: ["Category: DIFF_MATCH_FAILED", "Pattern: EI/DIFF_MATCH_FAILED/001"],
34+
expected: ["No sufficiently similar match found at line: 1", "This content does not exist"],
3535
result: "The apply_diff operation on `apply-diff-tool-fixture/error-handling.txt` was rejected - the search content did not match any content in the file, so it was not modified.",
3636
id: "call_apply_diff_error_002",
3737
},

apps/vscode-e2e/src/fixtures/subtasks.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ export const SUBTASK_API_HANG_RESUME_MESSAGE = "Continue after provider hang."
3333
export const SUBTASK_API_HANG_CHILD_RESULT = "Hung child completed"
3434
export const SUBTASK_API_HANG_PARENT_RESULT = "API hang parent resumed"
3535

36+
// How long the API-hang child's first mocked response stays pending before its first SSE
37+
// chunk. Shared with the subtask suite so its post-test drain waits exactly one window.
38+
// Correctness depends on no flat `latency` (fixture or LLMock default) being set on that
39+
// fixture — a flat latency would apply to every chunk after the first, not just the ttft.
40+
export const SUBTASK_API_HANG_RESPONSE_LATENCY_MS = 15_000
41+
3642
// Abandon-subtask scenario (#559) — separate markers to avoid sequenceIndex collisions with the
3743
// interrupted-child-resumes tests above, which exhaust the sequence count for INTERRUPT markers.
3844
const SUBTASK_ABANDON_PARENT_MARKER = "SUBTASK_PARENT_ABANDON_SEVER"
@@ -261,8 +267,14 @@ export function addSubtaskFixtures(mock: InstanceType<typeof LLMock>) {
261267
userMessage: apiHangChildMatch,
262268
sequenceIndex: 0,
263269
},
264-
// Keep the first child response pending long enough for the e2e test to cancel an in-flight API request.
265-
latency: 15_000,
270+
// Keep the first child response pending long enough for the e2e test to cancel an in-flight
271+
// API request. Delay only the first chunk (ttft) rather than using flat `latency`: aimock
272+
// applies `latency` to EVERY chunk and never observes client disconnects, so after the test
273+
// cancels, a flat-latency stream would stay pending server-side for chunks × latency before
274+
// flushing to the dead socket. With ttft the pending window is exactly
275+
// SUBTASK_API_HANG_RESPONSE_LATENCY_MS (see its doc comment for the no-flat-latency
276+
// invariant this relies on), which is what the suite's post-test drain waits out.
277+
streamingProfile: { ttft: SUBTASK_API_HANG_RESPONSE_LATENCY_MS },
266278
response: {
267279
toolCalls: [
268280
{

apps/vscode-e2e/src/suite/subtasks.test.ts

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
SUBTASK_API_HANG_PARENT_MARKER,
1717
SUBTASK_API_HANG_PARENT_PROMPT,
1818
SUBTASK_API_HANG_PARENT_RESULT,
19+
SUBTASK_API_HANG_RESPONSE_LATENCY_MS,
1920
SUBTASK_API_HANG_RESUME_MESSAGE,
2021
SUBTASK_CHILD_FOLLOWUP_ANSWER,
2122
SUBTASK_FAST_CHILD_RESULT,
@@ -33,6 +34,7 @@ import {
3334
type AimockMessageContent = string | Array<{ type?: string; text?: string }>
3435

3536
type AimockJournalEntry = {
37+
timestamp?: number
3638
body?: {
3739
messages?: Array<{
3840
role?: string
@@ -49,24 +51,67 @@ const messageContentText = (content?: AimockMessageContent) => {
4951
return content?.map((part) => part.text ?? "").join("") ?? ""
5052
}
5153

52-
const waitForAimockRequestContaining = async (expectedText: string, excludeText?: string) => {
54+
const fetchAimockJournal = async () => {
5355
const aimockUrl = process.env.AIMOCK_URL
5456
assert.ok(aimockUrl, "AIMOCK_URL must be set for aimock journal assertions")
5557

58+
const response = await fetch(`${aimockUrl}/__aimock/journal`)
59+
return (await response.json()) as AimockJournalEntry[]
60+
}
61+
62+
const findAimockRequest = (entries: AimockJournalEntry[], expectedText: string, excludeText?: string) =>
63+
entries.find((entry) => {
64+
const messages = entry.body?.messages
65+
if (!messages) return false
66+
const entryText = messages.map((m) => messageContentText(m.content)).join("")
67+
if (excludeText && entryText.includes(excludeText)) return false
68+
return messages.some(
69+
(message) => message.role === "user" && messageContentText(message.content).includes(expectedText),
70+
)
71+
})
72+
73+
// Waits for a matching request to appear in the aimock journal and returns its journal
74+
// timestamp, so callers can anchor post-test drains to the exact request this test created.
75+
const waitForAimockRequestContaining = async (
76+
expectedText: string,
77+
excludeText?: string,
78+
): Promise<number | undefined> => {
79+
let matchedAt: number | undefined
80+
5681
await waitFor(async () => {
57-
const response = await fetch(`${aimockUrl}/__aimock/journal`)
58-
const entries = (await response.json()) as AimockJournalEntry[]
59-
60-
return entries.some((entry) => {
61-
const messages = entry.body?.messages
62-
if (!messages) return false
63-
const entryText = messages.map((m) => messageContentText(m.content)).join("")
64-
if (excludeText && entryText.includes(excludeText)) return false
65-
return messages.some(
66-
(message) => message.role === "user" && messageContentText(message.content).includes(expectedText),
67-
)
68-
})
82+
matchedAt = findAimockRequest(await fetchAimockJournal(), expectedText, excludeText)?.timestamp
83+
return matchedAt !== undefined
6984
})
85+
86+
return matchedAt
87+
}
88+
89+
// Grace period after the delayed window for aimock to flush the stream's remaining chunks to
90+
// the dead socket. 500ms is an empirical margin for that flush plus socket teardown; if this
91+
// suite becomes flaky again on slow CI runners, widen this value first.
92+
const SUBTASK_API_HANG_DRAIN_GRACE_MS = 500
93+
94+
// aimock does not observe client disconnects: after the API-hang child request is cancelled,
95+
// the mock keeps the delayed stream pending server-side until the fixture's ttft has fully
96+
// elapsed, then flushes the remaining chunks to the dead socket. A streamed request opened by
97+
// the next test can interleave with that late flush, so wait out the remainder of the delayed
98+
// window before the next test runs. The deadline is anchored to the journal timestamp of the
99+
// request this test created (never earlier traffic), and bounded by one latency window plus
100+
// grace, so it cannot hide a genuine hang.
101+
const waitForDelayedSubtaskStreamDrain = async (delayedRequestStartedAt: number | undefined) => {
102+
if (delayedRequestStartedAt === undefined) {
103+
// The delayed request never reached the mock (the test failed before cancelling
104+
// an in-flight request), so there is no delayed stream to drain.
105+
return
106+
}
107+
108+
const drainDeadlineMs =
109+
delayedRequestStartedAt + SUBTASK_API_HANG_RESPONSE_LATENCY_MS + SUBTASK_API_HANG_DRAIN_GRACE_MS
110+
const remainingMs = drainDeadlineMs - Date.now()
111+
112+
if (remainingMs > 0) {
113+
await sleep(remainingMs)
114+
}
70115
}
71116

72117
suite("Roo Code Subtasks", function () {
@@ -482,6 +527,7 @@ suite("Roo Code Subtasks", function () {
482527
const api = globalThis.api
483528
const asks: Record<string, ClineMessage[]> = {}
484529
const says: Record<string, ClineMessage[]> = {}
530+
let delayedChildRequestStartedAt: number | undefined
485531

486532
const messageHandler = ({ taskId, message }: { taskId: string; message: ClineMessage }) => {
487533
if (message.type === "ask") {
@@ -519,7 +565,10 @@ suite("Roo Code Subtasks", function () {
519565
return false
520566
})
521567

522-
await waitForAimockRequestContaining(SUBTASK_API_HANG_CHILD_MARKER, SUBTASK_API_HANG_PARENT_MARKER)
568+
delayedChildRequestStartedAt = await waitForAimockRequestContaining(
569+
SUBTASK_API_HANG_CHILD_MARKER,
570+
SUBTASK_API_HANG_PARENT_MARKER,
571+
)
523572

524573
await api.cancelCurrentTask()
525574

@@ -580,6 +629,9 @@ suite("Roo Code Subtasks", function () {
580629
await api.clearCurrentTask()
581630
}
582631
await waitFor(() => api.getCurrentTaskStack().length === 0).catch(() => {})
632+
// Drain the cancelled delayed stream before the next test can open another
633+
// streamed request against the mock.
634+
await waitForDelayedSubtaskStreamDrain(delayedChildRequestStartedAt)
583635
}
584636
})
585637

@@ -692,9 +744,6 @@ suite("Roo Code Subtasks", function () {
692744
}
693745
})
694746

695-
// NOTE: This test exercises parent-child resume via mock fixtures with overlapping
696-
// predicates. If it flakes on CI, the fixture chain may need tighter matching.
697-
// See debug-systemic report 190600 for root-cause analysis.
698747
// Issue #560: interrupted child resumes and reports back to parent.
699748
// Before the fix, cancelTask() severed the parent link, so the resumed child
700749
// fell through to "Start New Task" instead of delegating back to the parent.

locales/ca/README.md

Lines changed: 22 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)