summaryrefslogtreecommitdiffhomepage
path: root/packages/frontend/src/lib/components
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-05-19 21:29:08 +0900
committerAdam Malczewski <[email protected]>2026-05-19 21:29:08 +0900
commit0ae805b28b5160b8d9fb43635fa172961f6550cc (patch)
treee9fb7cbad0755cd7608ea56012c986a4a47b2aaf /packages/frontend/src/lib/components
parentde6df4abdd8a6eb9a0217050ce17e0925f04602b (diff)
downloaddispatch-0ae805b28b5160b8d9fb43635fa172961f6550cc.tar.gz
dispatch-0ae805b28b5160b8d9fb43635fa172961f6550cc.zip
feat: inline tool display and thinking/reasoning support
- Tool calls now appear at their stream position within messages (ContentSegment model) - Added reasoning/thinking display: collapsible <details> block above content - Set DeepSeek V4 Flash reasoningEffort to max via providerOptions - ChatMessage.content changed from string to ContentSegment[] (text | tool-call) - Agent handles AI SDK reasoning events, yields reasoning-delta - Fixed duplicate key in ChatMessage.svelte each block
Diffstat (limited to 'packages/frontend/src/lib/components')
-rw-r--r--packages/frontend/src/lib/components/ChatMessage.svelte21
1 files changed, 12 insertions, 9 deletions
diff --git a/packages/frontend/src/lib/components/ChatMessage.svelte b/packages/frontend/src/lib/components/ChatMessage.svelte
index 447bb29..5212790 100644
--- a/packages/frontend/src/lib/components/ChatMessage.svelte
+++ b/packages/frontend/src/lib/components/ChatMessage.svelte
@@ -9,18 +9,21 @@ const isUser = $derived(message.role === "user");
<div class="chat {isUser ? 'chat-end' : 'chat-start'} mb-2">
<div class="chat-bubble {isUser ? 'chat-bubble-primary' : 'chat-bubble-secondary'} max-w-[80%] break-words">
- {#if message.content}
- <span>{message.content}</span>
+ {#if message.thinking}
+ <details class="mb-2">
+ <summary class="cursor-pointer text-sm text-base-content/60 italic">Thinking...</summary>
+ <p class="text-sm text-base-content/60 italic mt-1 whitespace-pre-wrap">{message.thinking}</p>
+ </details>
{/if}
+ {#each message.content as segment, i (segment.type === "tool-call" ? segment.id : i)}
+ {#if segment.type === "text"}
+ <span>{segment.text}</span>
+ {:else if segment.type === "tool-call"}
+ <ToolCallDisplay toolCall={segment} />
+ {/if}
+ {/each}
{#if message.isStreaming}
<span class="inline-block w-2 h-4 bg-current animate-pulse ml-0.5 align-middle">▌</span>
{/if}
- {#if message.toolCalls && message.toolCalls.length > 0}
- <div class="mt-2">
- {#each message.toolCalls as toolCall (toolCall.id)}
- <ToolCallDisplay {toolCall} />
- {/each}
- </div>
- {/if}
</div>
</div>