code-yeongyu / code-yeongyu/senpi
claude-fable-5-1 (xhigh): terminal assistant message arrives truncated to a strict prefix
- Dominant language
- TypeScript
- Stars
- 429
- Forks
- 98
- Avg merge
- 5h 3m
- Merged PRs (30d)
- 526
Description
## Symptom
On omo-desktop (mengmotaHost, runtime omo 2f2f03e33 / senpi 933307abb), the provider's terminal assistant message sometimes carries only the FIRST N characters of a message whose deltas the projection already assembled in full. omo-desktop-app#449 added a guard that refuses to shorten the projection in that case and logs it:
```
WARN orchestration.assistant.text.terminal-truncated {
threadId: '2683d811-...', messageId: 'assistant:omo-message-mtscim2r-...',
projectedLength: 2983, authoritativeLength: , commonPrefixLength: <== authoritativeLength>
}
```
`commonPrefixLength === authoritativeLength` in every occurrence: the terminal text is a strict prefix of the assembled message, i.e. its own tail is missing.
## Trigger correlates exactly with one model
All 4 occurrences in one host lifetime, across 4 DISTINCT threads, are the same model selection:
`{"instanceId":"omo","model":"anthropic/claude-fable-5-1","options":[{"id":"thinkingLevel","value":"xhigh"}]}`
| time | thread | projected | authoritative |
|---|---|---|---|
| 16:36 | 7573ad1b | 1636 | 964 |
| 17:45 | 487bf1f9 | 436 | 79 |
| 17:48 | 825eaeb2 | 384 | 239 |
| 18:16 | 2683d811 | 2983 | (short) |
Control group in the same window: threads active since boot span 8+ model selections — `claude-fable-5` (53 threads), `claude-fable-5-1` (46), `gpt-5.6-sol-fast` (25), `kimi-k3-ultrafast-unlocked` (23), `gpt-6-astra-fast` (10), `claude-opus-5` (10), `kimi-k3-unlocked` (8), `claude-opus-4-6` (4). The benign self-heal event (`assistant.text.reconciled`, where the authoritative text is LONGER and correctly replaces a projection that lost a delta window) occurs across many of those models. Only `claude-fable-5-1` produces the truncated-terminal direction — notably NOT plain `claude-fable-5` despite a comparable thread count.
## Verification that this is a lost tail, not two merged messages
I explicitly tested and discarded the "projection concatenated two consecutive messages" theory:
- the stored row for `assistant:omo-message-mtscim2r-602` (384 chars) reads as ONE coherent turn (opens `Blocker 1 fixed with the minimal edit...`, closes with its Round-1 result list),
- neighbouring message ids on that thread (598 / 600 / 606) are separate rows with their own lengths,
- the shorter authoritative content exists as no row anywhere in `projection_thread_messages`.
The differing 24-char tail fields in the log are just an artifact of the authoritative text stopping mid-sentence.
## Impact without the desktop-side guard
Reconciliation trusted the terminal text in both directions, so before #449 this DELETED text the user had already read: 136 / 978 / 2947 / 672 / 357 chars observed, ~5,090 total. With the guard the projection is preserved and only this WARN is emitted.
## Ask
The desktop guard is a safety net, not a fix — the terminal message for `claude-fable-5-1` (xhigh) should carry the complete assistant text. Worth checking whether the xhigh thinking path truncates the final message payload before it reaches `after_provider_response`.
Not reproducible from a single short scratch turn; it needs a long fable-5-1 xhigh turn on the desktop RPC host.
Contributor guide
Research direction
Start by tracing the xhigh thinking path to `after_provider_response`, the entry point named in the issue. Reproduce a long `claude-fable-5-1` xhigh turn on the desktop RPC host and compare the terminal message with the assembled deltas. Done means the terminal message includes the full assistant text rather than a strict prefix.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- ai-infra-agents
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100