handleWindowSize tracks new dimensions, rebuilds the glamour renderer on a wrap-width change, emits the splash on the first frame, and on a true width change starts the debounced resize-settle cycle (suppressView until the settle tick lands at the matching gen).
(msg tea.WindowSizeMsg)
| 511 | if msg.ch != m.stream { |
| 512 | return m, nil |
| 513 | } |
| 514 | return m.handleStreamClosed() |
| 515 | |
| 516 | case toolResultMsg: |
| 517 | // Stale result from a turn the user already cancelled. Without this |
| 518 | // drop, the orphan tool message gets appended to the live turn's history |
| 519 | // (no preceding assistant.tool_calls → the next /v1 request 400s) and |
| 520 | // startChat would abandon the in-flight stream. The turnCtx tag was |
| 521 | // captured at runToolCall time; endTurn nils m.turnCtx and a fresh |
| 522 | // beginTurn installs a new one that can't match. |
| 523 | if msg.turnCtx != m.turnCtx { |
| 524 | return m, nil |
| 525 | } |
| 526 | dbgWriteMessage("tool_result", msg.Msg) |
| 527 | m.history = append(m.history, msg.Msg) |
| 528 | m.recordToolOutcome(msg.Msg.ToolName, msg.Msg.Content) |
| 529 | // Drain every remaining call before re-entering chat: OpenAI rejects an |
| 530 | // assistant.tool_calls message followed by fewer tool messages than |
| 531 | // calls issued, so a partial dispatch 400s and loses the rest. |
| 532 | // Sequential dispatch in emit order keeps the pairing intact. |
| 533 | if len(m.pending) > 0 { |
| 534 | return m.dispatchNextTool() |
| 535 | } |
| 536 | // Queue drained: only now is it safe to inject a system nudge. A |
| 537 | // system message wedged between assistant.tool_calls and its tool |
| 538 | // results would break that pairing and 400 the next request. |
| 539 | m.maybeFailureNudge() |
| 540 | m.maybeRunawayNudge() |
| 541 | m.phase = phaseThinking |
| 542 | return m, m.startChat() |
| 543 | |
| 544 | case quitArmResetMsg: |
| 545 | if !m.quitArmedAt.IsZero() && time.Now().After(m.quitArmedAt) { |
no test coverage detected