feat: display thinking/reasoning content during streaming
Extract thinking blocks from delta events and render them inline using the existing ThinkingBlock component. Previously, thinking content was only visible after the stream finished (via history reload). Now it appears in real-time as the agent reasons. Closes feedback #57.
This commit is contained in:
@@ -6,7 +6,7 @@ import { isSystemEvent } from '../lib/systemEvent';
|
|||||||
import type { ChatMessage, MessageBlock, ConnectionStatus, Session, AgentIdentity } from '../types';
|
import type { ChatMessage, MessageBlock, ConnectionStatus, Session, AgentIdentity } from '../types';
|
||||||
|
|
||||||
interface ChatPayloadMessage {
|
interface ChatPayloadMessage {
|
||||||
content?: string | Array<{ type: string; text?: string }>;
|
content?: string | Array<{ type: string; text?: string; thinking?: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractText(message: ChatPayloadMessage | undefined): string {
|
function extractText(message: ChatPayloadMessage | undefined): string {
|
||||||
@@ -22,6 +22,16 @@ function extractText(message: ChatPayloadMessage | undefined): string {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractThinking(message: ChatPayloadMessage | undefined): string {
|
||||||
|
if (!message) return '';
|
||||||
|
const content = message.content;
|
||||||
|
if (!Array.isArray(content)) return '';
|
||||||
|
return content
|
||||||
|
.filter((b) => b.type === 'thinking')
|
||||||
|
.map((b) => b.thinking || b.text || '')
|
||||||
|
.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
export function useGateway() {
|
export function useGateway() {
|
||||||
const clientRef = useRef<GatewayClient | null>(null);
|
const clientRef = useRef<GatewayClient | null>(null);
|
||||||
const [status, setStatus] = useState<ConnectionStatus>('disconnected');
|
const [status, setStatus] = useState<ConnectionStatus>('disconnected');
|
||||||
@@ -304,6 +314,7 @@ export function useGateway() {
|
|||||||
|
|
||||||
if (state === 'delta') {
|
if (state === 'delta') {
|
||||||
const text = extractText(message);
|
const text = extractText(message);
|
||||||
|
const thinking = extractThinking(message);
|
||||||
currentRunIdRef.current = runId;
|
currentRunIdRef.current = runId;
|
||||||
|
|
||||||
setMessages(prev => {
|
setMessages(prev => {
|
||||||
@@ -311,16 +322,24 @@ export function useGateway() {
|
|||||||
if (last && last.role === 'assistant' && last.isStreaming && last.runId === runId) {
|
if (last && last.role === 'assistant' && last.isStreaming && last.runId === runId) {
|
||||||
const updated = { ...last };
|
const updated = { ...last };
|
||||||
updated.content = text;
|
updated.content = text;
|
||||||
const nonTextBlocks = updated.blocks.filter(b => b.type !== 'text');
|
// Preserve tool blocks, rebuild text + thinking blocks from latest delta
|
||||||
updated.blocks = [...nonTextBlocks, { type: 'text' as const, text }];
|
const toolBlocks = updated.blocks.filter(b => b.type === 'tool_use' || b.type === 'tool_result');
|
||||||
|
const newBlocks: MessageBlock[] = [];
|
||||||
|
if (thinking) newBlocks.push({ type: 'thinking' as const, text: thinking });
|
||||||
|
newBlocks.push(...toolBlocks);
|
||||||
|
newBlocks.push({ type: 'text' as const, text });
|
||||||
|
updated.blocks = newBlocks;
|
||||||
return [...prev.slice(0, -1), updated];
|
return [...prev.slice(0, -1), updated];
|
||||||
}
|
}
|
||||||
|
const blocks: MessageBlock[] = [];
|
||||||
|
if (thinking) blocks.push({ type: 'thinking' as const, text: thinking });
|
||||||
|
blocks.push({ type: 'text' as const, text });
|
||||||
const msg: ChatMessage = {
|
const msg: ChatMessage = {
|
||||||
id: runId + '-' + Date.now(),
|
id: runId + '-' + Date.now(),
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: text,
|
content: text,
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
blocks: [{ type: 'text', text }],
|
blocks,
|
||||||
isStreaming: true,
|
isStreaming: true,
|
||||||
runId,
|
runId,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user