AI thinking state
Collapsible "Thinking..." block for reasoning models (Claude extended thinking, DeepSeek R1, OpenAI o-family). Separates chain-of-thought from final response. Hosted by chat-message-bubble (#105) and agent-step-trace (#108).
Spec — AI thinking state
Hosted by
chat-message-bubble.kmdeagent-step-trace.kmd. Streams viastreaming-text.kmd(separate stream channelreasoning).
Princípios
- *rovider abstraction*— gateway expõe
reasoning_contentseparated fromcontent; SDK detecta provider. - *ollapsed by default*— pra reduzir noise; user expande quando quer detalhes.
- *uto-close on stream end*— opcional, configurable; default close.
- *reserve manual expand*— user expandeu → não auto-close.
R1 — Anatomia
┌───────────────────────────────────────────┐
│ 💭 Thinking · 4.2s [▼] │ ← collapsed (default)
└───────────────────────────────────────────┘
┌───────────────────────────────────────────┐
│ 💭 Thinking · 4.2s · 234 words [▲] │ ← expanded
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ "I need to find recent docs about │
│ Koder Stack architecture. The user is │
│ asking about the Foundation layer..." │
│ │
│ [reasoning trace continues...] │
└───────────────────────────────────────────┘Slots:
| Slot | Content |
|---|---|
| Icon | 💭 (thinking) or ⚙ (running animated) |
| Label | "Thinking..." (streaming) → "Thought for {duration}" (complete) |
| Duration | live timer during stream; final on complete |
| Word count | when complete (optional) |
| Toggle | expand/collapse chevron |
| Body | full reasoning text (when expanded) |
R2 — States
| State | Visual |
|---|---|
| streaming | "Thinking..." + breathing dot + live timer |
| complete | "Thought for 4.2s" + chevron + word count |
| collapsed | header only |
| expanded | header + body |
R3 — Provider abstraction
Gateway response includes optional reasoning_content:
{
"content": [{"type": "text", "text": "..."}],
"reasoning_content": "I need to think about this...",
"reasoning_meta": {
"model_supports": true,
"duration_ms": 4200,
"tokens": 234
}
}If reasoning_content is null/missing: do NOT render thinking block.
Provider support:
| Provider | Native reasoning_content? |
|---|---|
| Anthropic (Claude extended thinking) | Yes |
| OpenAI (o-family) | Yes (different field, gateway translates) |
| DeepSeek (R1) | Yes |
| Google (Gemini reasoning) | Yes |
| Self-hosted Koder LLM | Optional |
Gateway translates provider-specific to canonical shape above.
R4 — Auto-close
On done event of reasoning stream:
- If
auto_close: true(default): collapse animated (smooth). - If user already expanded manually: preserve expanded state.
User preference: stored per (koder_user_id, workspace_id).
R5 — Multiple thinking blocks (accordion)
Agent runs with reasoning per step (cross-link #108):
[Step 1] ▼ Thinking · 2s
[Step 2] ▶ Thinking · 1.5s
[Step 3] ▼ Thinking · 3sIndependent collapse/expand state per block.
R6 — Surface bindings
| Surface | API |
|---|---|
| Flutter | KoderThinkingBlock({required content, duration, autoClose}) em koder_kit/lib/src/ai/thinking_block.dart |
| Web | <koder-thinking-block> |
| Compose/SwiftUI | futuro |
| CLI / TUI | Plain: prefix [think] ... indented; toggle via key shortcut |
R7 — Acessibilidade
- Block:
<details><summary>semantically (Web); equivalente Flutter. - Toggle: keyboard Enter/Space.
- aria-live="polite" during streaming.
- Reduced-motion: no smooth collapse; instant.
R8 — i18n
| Key | en-US | pt-BR |
|---|---|---|
ai.thinking.streaming |
"Thinking..." | "Pensando..." |
ai.thinking.complete |
"Thought for {duration}" | "Pensou por {duration}" |
ai.thinking.words |
"{n} words" | "{n} palavras" |
T-suite
- *1*Mount streaming: response has reasoning_content streaming → block visible with "Thinking..." + breathing dot.
- *2*Done: stream complete → label becomes "Thought for 4.2s"; collapse animated.
- *3*No reasoning_content: response without field → block NOT rendered.
- *4*Manual expand: user clicks → expand; subsequent
donedoes NOT collapse. - *5*Multiple blocks (agent steps): each independent.
- *6*Reduced-motion: collapse instant.
- *7*Provider abstraction: OpenAI o-family + Claude responses both render correctly.
Cross-link
- Companion:
chat-message-bubble.kmd,agent-step-trace.kmd,streaming-text.kmd - Backend:
services/ai/gateway/(provider translation) - Refs: MUI X Chat Reasoning, agents-kit Reasoning, Anthropic extended thinking