You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 00e83eb
Browse filesBrowse the repository at this point in the historyBrowse files
fix(chat): keep focus when a waiting call lapses or is dropped
MessageParts moved focus only after a decision made through its own
decide. When the server resolved a call to timeout or expired while
focus was on its buttons, the call folded into its run, the buttons
unmounted, and focus fell to the page. The same happened when a host
recorded a decision by removing the call from parts.
Track which waiting call's card holds focus from the root's focus and
blur events, and give a call that stops waiting under focus the same
handoff as a decided one: the next waiting call in a batch, else the
run's trigger. For a call that is gone from parts, fall back to the
group it stood in, then the group before it, then the first control in
the message.
Document the markup custom renderBatch and renderActivity must keep
for the handoff, and that renderText takes precedence over
renderMarkdown. Point the 0.3 upgrade rows at MessageParts, and name
the image adapter's argument index.
| `ChatThread`, `ChatThreadProps` | `Conversation` with `ConversationContent`, a `ConversationItem` per message and `ConversationScrollButton`|
341
-
| `AgentTurn`, `AgentTurnProps` | `Message` with `from="agent"`, `MessageAvatar`, `MessageHeader` and `MessageContent`; thinking and tool calls through `groupActivity` and `Activity` |
342
-
| `MessageBubble`, `MessageBubbleProps` | `Message` with `MessageContent`; `from="own"` draws the bubble |
343
-
| `PartsRenderer`, `PartsRendererProps` | Map `groupActivity(message.parts)` to `Activity`, `MessageContent`, `ToolApproval`, `ToolGroup`, `GeneratedImages`, `Sources` and `Attachments`; `block` parts are the host's to render |
344
-
| `toolTraceToBlockState` | No replacement: `Tool` reads `ToolTraceStatus` and the approval record directly |
345
-
| `ReasoningBlock`, `ReasoningBlockProps` | `Reasoning` (`ReasoningTrigger`, `ReasoningContent`) on a `PartReasoning`|
346
-
| `ToolBlock`, `ToolBlockProps`, `ToolBlockState` | `Tool` (`ToolHeader`, `ToolInput`, `ToolOutput`) on a `PartTool`; the state is its `ToolTraceStatus`|
347
-
| `ToolNarrative`, `ToolNarrativeProps` | `Tool`, or `ToolGroup` for calls that ran together |
348
-
| `ApprovalCard`, `ApprovalCardProps` | `ToolApproval` on a `PartTool` with a `ToolApprovalRecord`; `onApprove`, `onReject` and `onAllowAlways` become `onDecide(ToolApprovalDecision)`, and a busy `state` becomes `disabled`|
349
-
| `ApprovalRequest`, `ApprovalDetail` | The `PartTool` itself: `name` and `input`, with the host's own account of the action as `ToolApproval`'s children |
350
-
| `ApprovalState` | `ToolApprovalRecord`'s `status` for the outcome, `ToolApproval`'s `disabled` while a decision is recorded |
351
-
| `ChatInput`, `ChatInputProps` | `PromptInput` with `PromptInputTextarea` and `PromptInputSubmit`; `PromptInputToolbar` for controls under the text |
352
-
| `ChatAttachment` | `AttachmentData` for `Attachments`, `AttachmentItem` from `useAttachments`|
353
-
| `ChatComposer`, `ChatComposerProps` | `PromptInput`, with `ConversationEmptyState` for an empty conversation |
354
-
| `QuickReplyChips`, `QuickReply` | No replacement: suggested replies are the host's own buttons, for example inside `ConversationEmptyState`|
355
-
| `ChatPanel`, `ChatPanelHeader`, `ChatPanelFooter` | `Panel`, `PanelHeader` and `PanelContent` for a side panel; put `Conversation` and `PromptInput` in your own frame |
| `AgentIdentity` | `ConversationParticipant` with `kind:"agent"`; `tagline` becomes `role`, and `MessageAvatar` takes `initials`|
364
-
| `agentInitials` | `MessageAvatar`, which derives initials from `name`|
365
-
| `SubagentRun`, `SubagentState` | No replacement: the conversation model has no subagent type; show a helper's calls as `PartTool`s or a `PartToolBatch`|
366
-
| `ChatThreadSummary` | No replacement: a list of conversations is the host's own data |
367
-
| `messageText`, `reasoningText`, `toolParts` | No replacement: filter `message.parts` by `kind`|
368
-
| `isTurnWorking` | `parts.some((p) =>p.kind==="tool-trace"&&p.status==="running")` (any tool still running; `message.status==="streaming"` is the whole message) |
369
-
| `toolLabel` | No replacement: `ToolHeader` shows the raw tool name, after the `label` you pass |
370
-
| `ToolProviderMark`, `ToolProviderMarkProps` | `ProviderMark` with the provider read off the tool id (`name.split("__")[0]`, for ids shaped `provider__operation`) |
371
-
| `useDelayedAutofocus` | No replacement: focus the element from an effect once its entrance has finished |
| `ChatThread`, `ChatThreadProps` | `Conversation` with `ConversationContent`, a `ConversationItem` per message and `ConversationScrollButton` |
341
+
| `AgentTurn`, `AgentTurnProps` | `Message` with `from="agent"`, `MessageAvatar`, `MessageHeader` and `MessageContent`, with `MessageParts` for the parts |
342
+
| `MessageBubble`, `MessageBubbleProps` | `Message` with `MessageContent`; `from="own"` draws the bubble |
343
+
| `PartsRenderer`, `PartsRendererProps` | `MessageParts` inside a `Message`; `renderBlock` for `block` parts |
344
+
| `toolTraceToBlockState` | No replacement: `Tool` reads `ToolTraceStatus` and the approval record directly |
345
+
| `ReasoningBlock`, `ReasoningBlockProps` | `Reasoning` (`ReasoningTrigger`, `ReasoningContent`) on a `PartReasoning` |
346
+
| `ToolBlock`, `ToolBlockProps`, `ToolBlockState` | `Tool` (`ToolHeader`, `ToolInput`, `ToolOutput`) on a `PartTool`; the state is its `ToolTraceStatus` |
347
+
| `ToolNarrative`, `ToolNarrativeProps` | `Tool`, or `ToolGroup` for calls that ran together |
348
+
| `ApprovalCard`, `ApprovalCardProps` | `ToolApproval` on a `PartTool` with a `ToolApprovalRecord`; `onApprove`, `onReject` and `onAllowAlways` become `onDecide(ToolApprovalDecision)`, and a busy `state` becomes `disabled` |
349
+
| `ApprovalRequest`, `ApprovalDetail` | The `PartTool` itself: `name` and `input`, with the host's own account of the action as `ToolApproval`'s children |
350
+
| `ApprovalState` | `ToolApprovalRecord`'s `status` for the outcome, `ToolApproval`'s `disabled` while a decision is recorded |
351
+
| `ChatInput`, `ChatInputProps` | `PromptInput` with `PromptInputTextarea` and `PromptInputSubmit`; `PromptInputToolbar` for controls under the text |
352
+
| `ChatAttachment` | `AttachmentData` for `Attachments`, `AttachmentItem` from `useAttachments` |
353
+
| `ChatComposer`, `ChatComposerProps` | `PromptInput`, with `ConversationEmptyState` for an empty conversation |
354
+
| `QuickReplyChips`, `QuickReply` | No replacement: suggested replies are the host's own buttons, for example inside `ConversationEmptyState` |
355
+
| `ChatPanel`, `ChatPanelHeader`, `ChatPanelFooter` | `Panel`, `PanelHeader` and `PanelContent` for a side panel; put `Conversation` and `PromptInput` in your own frame |
| `AgentIdentity` | `ConversationParticipant` with `kind:"agent"`; `tagline` becomes `role`, and `MessageAvatar` takes `initials` |
364
+
| `agentInitials` | `MessageAvatar`, which derives initials from `name` |
365
+
| `SubagentRun`, `SubagentState` | No replacement: the conversation model has no subagent type; show a helper's calls as `PartTool`s or a `PartToolBatch` |
366
+
| `ChatThreadSummary` | No replacement: a list of conversations is the host's own data |
367
+
| `messageText`, `reasoningText`, `toolParts` | No replacement: filter `message.parts` by `kind` |
368
+
| `isTurnWorking` | `parts.some((p) =>p.kind==="tool-trace"&&p.status==="running")` (any tool still running; `message.status==="streaming"` is the whole message) |
369
+
| `toolLabel` | No replacement: `ToolHeader` shows the raw tool name, after the `label` you pass |
370
+
| `ToolProviderMark`, `ToolProviderMarkProps` | `ProviderMark` with the provider read off the tool id (`name.split("__")[0]`, for ids shaped `provider__operation`) |
371
+
| `useDelayedAutofocus` | No replacement: focus the element from an effect once its entrance has finished |
0 commit comments