Make silent-stop auto-resume transparent by treating continuations as one logical user turn
- Dominant language
- TypeScript
- Stars
- 2.7k
- Forks
- 395
- Avg merge
- 21h 48m
- Merged PRs (30d)
- 776
Description
**客户端版本**: 0.1.61
**反馈类型**: feature
---
## Summary
Cindy already detects Claude Code silent-stop turns and automatically continues them by sending a hidden user message: `继续`. The recovery mechanism works, but the current UX is poor because every internal continuation is still exposed as a separate completed vendor turn.
As a result, one logical user task visually looks like it finishes, reports reconnection/resume, and runs multiple times. From the user's perspective, this feels like the same question is being answered two or three times. Silent-stop recovery should be treated as an internal continuation mechanism, not multiple user-visible turn boundaries.
## Environment
* Engine: Claude Code (Cindy-managed CLI / Agent SDK)
* Provider: custom Anthropic-compatible provider through CLIProxyAPI
* Upstream model: Gemini 3.7 Flash High
* OS: Windows 11
In observed silent-stop cases: HTTP succeeds, `stopReason = "end_turn"`, `terminalReason = "completed"`, `is_error = false`, `resultTextLen = 0`. Claude Code considers the vendor turn normally completed, and Cindy correctly detects silent stop and starts continuation.
## Reproduction observed in local logs
1. Vendor turn 1: 16 API calls, 15 tool uses, completed with empty assistant message (`stopReason: end_turn`, `resultTextLen: 0`). Cindy logged `SDK ◀ turn ended by silent stop`, dispatched auto-resume.
2. Vendor turn 2: 8 API calls, 7 tool uses, empty output, Cindy dispatched auto-resume.
3. Vendor turn 3: 5 API calls, 4 tool uses, empty output.
Budget exhausted: `模型连续多次返回空响应,自动续跑已暂停。点击「继续」恢复任务。`
## Current implementation
* `packages/maker-core/src/agents/claude-code/translator.ts`: detects silent stop (`lastAssistantMsgHadSubstance`, `isSilentStopTurn`) and emits `done` with `silentStop: true`.
* `apps/desktop/src/main/maker-ipc/silentStopAutoResume.ts`: sends `SILENT_STOP_RESUME_PROMPT = '继续'`.
The recovery mechanism exists, but the silent-stop vendor turn is exposed as a completion boundary before continuation.
## Actual vs Expected behavior
* **Actual**: User Prompt → Turn #1 → empty `end_turn` → UI idle/Done → sends `继续` → Turn #2 → UI idle/Done → sends `继续` → Turn #3 → Final result. User sees multiple "Working... Done ... Resumed" cycles.
* **Expected**: Logical User Turn contains internal continuation turns transparently. User sees continuous working progress until the substantive final response is produced. Only one visible completion boundary.
## Proposed direction
`Vendor turn boundary != Product/logical user turn boundary`
When `done.data.silentStop === true`:
* Preserve accounting, transcript data, tool results, and SDK session state.
* Internally dispatch continuation message while keeping product-level task in running state.
* Avoid transitioning renderer to idle/completed or creating visible new answer boundaries.
* Only emit true product-level completion when a substantive final response is produced.
## Silent stop is not a network reconnect
Silent stops (HTTP 200, `end_turn`, empty content) are not network disconnections (`socket hang up`, 502/503/504, aborted stream). Messages like `连接中断,已自动续接` are misleading here. Successful silent-stop continuations should be invisible with no reconnection banner.
## Continuation budget / session breaker
Review lifetime of breaker (`SILENT_STOP_SESSION_BREAKER_LIMIT = 6`). If session-wide `resumeCount` is cumulative across multiple tasks, occasional empty responses can permanently trip the breaker. Budget should be scoped per logical user turn, with session breaker only as safety backstop.
## Related upstream behavior
* `router-for-me/CLIProxyAPI#5227` (pure-thinking/empty outputs, normal STOP)
* `router-for-me/CLIProxyAPI#4886` (recommends new user message continuation)
## Desired result
One user prompt produces one task execution and one final answer UI boundary.
---
**OS**: win32 x64 (10.0.26220)
**界面语言**: zh-CN
Contributor guide
Research direction
Start with packages/maker-core/src/agents/claude-code/translator.ts and apps/desktop/src/main/maker-ipc/silentStopAutoResume.ts, then trace the silentStop done event into the renderer's task state and answer boundaries. Check how SILENT_STOP_SESSION_BREAKER_LIMIT and resumeCount are scoped. Done means continuations remain running and produce no reconnect banner or visible completion boundary, while substantive output still creates one final answer boundary.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- electron, typescript
- Domain
- ai, cli, desktop
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100