Repository navigation
Commit 667ff58
* fix(tool-call-dedup): use compound key (id, name) for tool call deduplication
* test(src): add missing tests for streaming tool call coverage
- Add NativeToolCallParser tests for hasActiveStreamingToolCalls() and getStreamingToolName()
- Add openai-compatible tests for streamText multiple parts and usage handling
- Add Task integration tests for tool_call_start/delta/end lifecycle
* test(task): stabilize streaming tool call compound-key specs
* fix(api): correct openai-compatible import path to error-handler
* fix(scripts): adapt parser-scoping model check to compound streaming keys
The shared-SDK error-handle PR keys streaming tool-call state by the compound id::name key and emits the tool name on tool_call_end. Update the scoping model-check harness to construct the same compound keys and expect the name field, preserving all 924 schedules, invariants, and landmarks.
* test: remove explicit any usages from streaming tool call and openai-compatible specs
* fix(task): address streaming tool-call review findings
- Route tool_call_delta through the compound (id, name) key so same-ID calls cannot share an accumulator; keep the deprecated ID-only lookup as a fallback for nameless legacy deltas
- Lock the tracked raw-chunk name after start so a later chunk with a different name cannot orphan the parser entry or the dedup tracking
- Resolve the tracked entry by id when a finalization end event misses the compound key, so cleanup always targets the real parser and dedup entries
- Throw handleOpenAIError for streamed error parts so provider errors keep their status and provider name
- Cover the paths with real Task-level integration tests, provider error-part and synchronous streamText failure tests, and per-call nativeArgs assertions
* test: expect tool name in streamed tool_call_delta events
The delta contract change adds the tracked tool name to every tool_call_delta parser event; update the parser-scope model check and the openai-compatible provider native-tools specs (lmstudio, openrouter, qwen) to assert the name alongside id and delta.
* test(test-utils): expect tool name in streamed tool_call_delta events
* fix(api): wrap streamed provider errors exactly once in openai-compatible
* test(api): cover getLanguageModel() failure in completePrompt
* fix(core): use injective streaming key for native tool calls
makeStreamingKey escapes the :: delimiter inside each segment so distinct (id, name) pairs can no longer share a parser/Task key. Task now builds every dedup key through the helper and reuses the streaming key for the delta lookup. Adds regression tests: colliding pairs stay separate, malformed arguments finalize gracefully through real Task streaming, and result.usage failures are wrapped with status and provider name.
* fix: harden streaming tool-call keys against backslash collisions and reconcile same-ID calls
- makeStreamingKey now escapes the escape character and every colon, so segment pairs that differ only by a trailing backslash (e.g. (a\\, b::c) vs (a::b\\, c)) produce distinct keys
* fix(task): reject any reused call ID regardless of entry displayed name
The same-ID collision check compared entry.name against the incoming start name. Alias resolution renames a streaming entry to its canonical tool as its arguments stream in (the streamed name is kept in originalName), so a later start reusing the ID under the canonical name - e.g. search_and_replace followed by edit - matched the renamed entry's displayed name and was retained. The API history builder dedupes tool_use blocks by ID and results are matched by tool_use_id, so the second entry would be orphaned. The compound-key check already rejects an identical (id, name) start, so reject any remaining start whose ID is already present in assistantMessageContent, and add the alias-then-canonical regression case.
* fix(api): preserve APICallError statusCode as .status; drop superseded local-copy test blocks (#797)
- handleProviderError now falls back to the AI SDK APICallError statusCode so a real 429 reaches Task.backoffAndAnnounce's .status === 429 check (addressed maintainer review)
- openai-compatible.spec.ts 429 test uses a real APICallError instead of a fabricated {status: 429}
- removed two local-map-copy test blocks superseded by the real-Task integration tests (duplicate-tool-use-ids compound-key block; Task.streaming-tool-calls local-copy block)
- PR description: corrected the Novita/Moonshot/Poe inheritance claim and documented the first-call-wins dedup rule
* test: add mutation-gate kill tests and document unreachable defensive paths
Closes the local preflight gaps found on the streaming-tool-call and error
handler work, with every survivor either killed by a new test or documented:
- error-handler: non-Error statusCode fallback, missing-status negative case,
non-numeric statusCode rejection, and the null-throw path.
- openai-compatible: configured temperature must reach generateText
unchanged (guards the ?? 0 fallback).
- Task: a real-Task stream test proving distinct call IDs are all accepted
(the ID guard is per-ID, not a global lock) and a reused ID already held by
an mcp_tool_use entry is rejected.
- NativeToolCallParser: exact compound-key escape encoding, the naive-join
collision case, and the defensive lookups' total behavior.
- Task: six `Stryker disable next-line` directives with concrete proofs for
the unreachable defensive checks around the compound streaming key.
* fix(api): select a numeric status before falling back to statusCode
A null or nonnumeric Error.status was taken as-is, so a nonnumeric value reached
Task.backoffAndAnnounce's retry header and a numeric statusCode was ignored.
The describe block named for Task integration only exercised the parser directly,
so rename it to name the parser as its subject.
* Assert the string statusCode is not copied into status
The test only checked the instance type, which also passes if the string "429"
is copied into .status - the exact regression the typeof guard prevents.
* test(parser): cover the name lock with a post-start name change
The Task test for the name change still passes without the lock because the id
fallback finalizes the entry. Add a parser test that streams a different name
after the start event: the delta and end events must still report the name the
call started with. Verified by removing the lock - this test fails.
* refactor(task): reuse the compound key already computed for the tool call
The finalize call recomputed makeStreamingKey with the same arguments as the dedupKey two lines
above it, and the defensive branch repeated the same pattern. Finalization and index cleanup now
use one key, so they cannot diverge.
tsc clean, 168 tests pass, ESLint --max-warnings=0 clean, no suppression change.
* chore: fix Prettier drift and check formatting in CI
---------
Co-authored-by: Eason Liang <[email protected]>
Co-authored-by: easonLiangWorldedtech <[email protected]>
Co-authored-by: Elliott de Launay <[email protected]>
Co-authored-by: edelauna <[email protected]>
1 parent d1f5845 commit 667ff58
48 files changed
Lines changed: 12172 additions & 9713 deletions
File tree
- .github
- ISSUE_TEMPLATE
- actions/slack-notify
- workflows
- .roo
- commands
- skills
- roo-conflict-resolution
- roo-translation
- apps/cli
- packages/types/src
- scripts
- src
- api
- providers
- __tests__
- utils
- __tests__
- transform
- assets/marketplace
- core
- assistant-message
- __tests__
- task
- __tests__
- tools/__tests__
- scripts/__tests__
- services/marketplace/__tests__
- test-utils/__tests__
- webview-ui/src/components
- chat/__tests__
- settings/__tests__
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | | - | |
| 6 | + | |
7 | 7 | | |
8 | | - | |
9 | 8 | | |
10 | 9 | | |
11 | 10 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
| 6 | + | |
7 | 7 | | |
8 | | - | |
9 | 8 | | |
10 | 9 | | |
11 | 10 | | |
12 | 11 | | |
13 | 12 | | |
14 | 13 | | |
15 | 14 | | |
| 15 | + | |
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
7 | | - | |
8 | | - | |
9 | | - | |
10 | | - | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
11 | 11 | | |
12 | | - | |
13 | | - | |
14 | | - | |
15 | | - | |
16 | | - | |
17 | | - | |
18 | | - | |
19 | | - | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
20 | 20 | | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
29 | 29 | | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
41 | 41 | | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
49 | 49 | | |
50 | | - | |
51 | | - | |
52 | | - | |
53 | | - | |
54 | | - | |
55 | | - | |
56 | | - | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
57 | 57 | | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
64 | 64 | | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
69 | | - | |
70 | | - | |
71 | | - | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
72 | 72 | | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | | - | |
84 | | - | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | | - | |
99 | | - | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
100 | 100 | | |
101 | | - | |
102 | | - | |
103 | | - | |
104 | | - | |
105 | | - | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
106 | 106 | | |
107 | | - | |
108 | | - | |
109 | | - | |
110 | | - | |
111 | | - | |
112 | | - | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
113 | 113 | | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | | - | |
| 6 | + | |
7 | 7 | | |
8 | | - | |
9 | 8 | | |
10 | 9 | | |
11 | 10 | | |
| |||
0 commit comments