Commit da4928f
fix(cli): unstick streamingState after Esc-cancel + close leaked turn span (#145)
Symptom (also reported on the Langfuse trace, session 442ed5c7,
turn ba924d250d7c with 739s latency and zero LLM activity in the
middle): user presses Esc to cancel, then any subsequent input is
silently dropped — UI stays in the loading indicator forever.
Root cause:
- cancelOngoingRequest aborts the AbortController and flips
isResponding=false, but does not clear toolCalls. If a tool
ignores its AbortSignal, it stays in 'executing' / 'scheduled' /
etc., or finishes with responseSubmittedToGemini=false. Either
way, streamingState computes 'Responding' (useGeminiStream.ts:
424-437) and submitQuery's guard (1305-1314) silently drops the
next user submission. The in-code comment at line 244-245 even
flags this class of bug for a different cause.
- cancelOngoingRequest never calls endTurnSpan, so the OTel turn
span leaks. The recap + prompt-suggestion LLM calls that fire on
streamingState=Idle then attach to the dead span — Langfuse
reports the turn as 12 minutes long when the actual model work
was 1.7 seconds.
Inheritance: upstream qwen-code has the identical cancelOngoingRequest
shape and the identical silent-return guard. gemini-cli upstream's
PR #21960 (closing #21096) addressed a different cancel-related bug
(retry-loop loading indicator showing stale "still on it" text), not
the stuck-toolCalls case. Issue #18525 there ("Agent Stuck between
Responses") is essentially the same symptom and is still open. So
this is inherited, not introduced — but the leaked turn span is
fork-only, since startTurnSpan/endTurnSpan are part of our agent
harness.
Fix:
- useReactToolScheduler exposes a new forceCancelStaleToolCalls()
that flips responseSubmittedToGemini=true on terminal calls and
synthesizes a 'cancelled' state for any non-terminal call (with a
clear "User cancelled. Tool was force-cleared after the abort
signal did not stop it within the grace window" message in the
responseParts so downstream consumers don't choke).
- cancelOngoingRequest in useGeminiStream:
* marks every current toolCall as submitted immediately (handles
the common case where the tool finished but the flag wasn't
flipped),
* schedules a 3s setTimeout that calls forceCancelStaleToolCalls
and surfaces a WARNING if anything had to be force-cleared so
the user knows the underlying process may still be running,
* calls endTurnSpan('ok') so the recap/suggestion LLM calls don't
keep nesting under a dead turn span in Langfuse.
- submitQuery no longer silently drops submissions when streamingState
is non-Idle. It logs a clear WARNING explaining what state we're
in (Responding / WaitingForConfirmation / Backgrounded) and what
the user should do (approve the tool, wait, or press Esc).
Tests: 3,767 cli tests + 5,337 core tests pass. Existing cancellation
tests in useGeminiStream.test.tsx (49 tests in that file) continue to
pass with the new flow.
Co-authored-by: Automaker <automaker@localhost>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>1 parent d697ddf commit da4928f
2 files changed
Lines changed: 168 additions & 10 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
41 | 42 | | |
42 | 43 | | |
43 | 44 | | |
| |||
262 | 263 | | |
263 | 264 | | |
264 | 265 | | |
265 | | - | |
266 | | - | |
267 | | - | |
268 | | - | |
269 | | - | |
270 | | - | |
271 | | - | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
272 | 287 | | |
273 | 288 | | |
274 | 289 | | |
| |||
510 | 525 | | |
511 | 526 | | |
512 | 527 | | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
513 | 562 | | |
514 | 563 | | |
515 | 564 | | |
| |||
1310 | 1359 | | |
1311 | 1360 | | |
1312 | 1361 | | |
| 1362 | + | |
| 1363 | + | |
| 1364 | + | |
| 1365 | + | |
| 1366 | + | |
| 1367 | + | |
| 1368 | + | |
| 1369 | + | |
| 1370 | + | |
| 1371 | + | |
| 1372 | + | |
| 1373 | + | |
| 1374 | + | |
| 1375 | + | |
| 1376 | + | |
| 1377 | + | |
| 1378 | + | |
| 1379 | + | |
| 1380 | + | |
| 1381 | + | |
| 1382 | + | |
| 1383 | + | |
| 1384 | + | |
| 1385 | + | |
| 1386 | + | |
1313 | 1387 | | |
1314 | 1388 | | |
1315 | 1389 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
41 | 51 | | |
42 | 52 | | |
43 | 53 | | |
| |||
72 | 82 | | |
73 | 83 | | |
74 | 84 | | |
75 | | - | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
76 | 91 | | |
77 | 92 | | |
78 | 93 | | |
| |||
179 | 194 | | |
180 | 195 | | |
181 | 196 | | |
182 | | - | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
183 | 267 | | |
184 | 268 | | |
185 | 269 | | |
| |||
0 commit comments