{#if fileUpload.isDragging}
Drop the image here to upload
{/if}
{message?.role}
{#if parsedMessage.thinking && message?.role === "assistant"}
(isReasoningExpanded = !isReasoningExpanded)} class="flex items-center gap-2 self-start rounded-md px-2 py-1 text-sm font-medium text-gray-600 hover:bg-gray-100 hover:text-gray-800 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200" > {#if isReasoningExpanded}
{:else}
{/if} Reasoning
{#if isReasoningExpanded} {#if conversation.data.parseMarkdown && !isEditing}
{@html parsedReasoning}
{:else}
{ const el = e.target as HTMLTextAreaElement; const reasoningContent = el?.value ?? ""; if (!message) return; // Reconstruct the full message with updated reasoning const newContent = reasoningContent ? `
${reasoningContent}
\n\n${parsedMessage.content}` : parsedMessage.content; conversation.updateMessage({ index, message: { ...message, content: newContent } }); }} onkeydown={e => { if ((e.ctrlKey || e.metaKey) && e.key === "g") { e.preventDefault(); e.stopPropagation(); onRegen?.(); } }} placeholder="Enter reasoning content" class="w-full resize-none overflow-hidden rounded-lg bg-transparent px-2 py-2.5 ring-gray-100 outline-none group-hover/message:ring-3 hover:bg-white focus:bg-white focus:ring-3 @2xl:px-3 dark:ring-gray-600 dark:hover:bg-gray-900 dark:focus:bg-gray-900" rows="1" {@attach reasoningAutosized.attachment} >
{/if} {/if}
{/if} {#if conversation.data.parseMarkdown && message?.role === "assistant"}
(isEditing = false))} >
{#snippet trigger(tooltip)}
{ isEditing = !isEditing; }} type="button" class="absolute top-1 right-1 grid size-6 place-items-center rounded border border-gray-200 bg-white text-xs transition-opacity hover:bg-gray-100 hover:text-blue-700 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white {isEditing ? 'opacity-100' : 'opacity-0 group-hover/message:opacity-100'}" {...tooltip.trigger} >
{/snippet} {isEditing ? "Stop editing" : "Edit"}
{#if !isEditing}
{@html parsedContent}
{:else}
{ const el = e.target as HTMLTextAreaElement; const content = el?.value; if (!message || !content) return; conversation.updateMessage({ index, message: { ...message, content } }); }} onkeydown={e => { if ((e.ctrlKey || e.metaKey) && e.key === "g") { e.preventDefault(); e.stopPropagation(); onRegen?.(); } }} placeholder="Enter {message?.role} message" class="w-full resize-none overflow-hidden border-none bg-transparent outline-none" rows="1" {@attach autosized.attachment} >
{/if}
{:else}
{ const el = e.target as HTMLTextAreaElement; const content = el?.value; if (!message || content === undefined) return; // If there was reasoning content, we need to preserve it when editing the main content const finalContent = parsedMessage.thinking ? `
${parsedMessage.thinking}
\n\n${content}` : content; conversation.updateMessage({ index, message: { ...message, content: finalContent } }); }} onkeydown={e => { if ((e.ctrlKey || e.metaKey) && e.key === "g") { e.preventDefault(); e.stopPropagation(); onRegen?.(); } }} placeholder="Enter {message?.role} message" class="grow resize-none overflow-hidden rounded-lg bg-transparent px-2 py-2.5 ring-gray-100 outline-none group-hover/message:ring-3 hover:bg-white focus:bg-white focus:ring-3 @2xl:px-3 dark:ring-gray-600 dark:hover:bg-gray-900 dark:focus:bg-gray-900" rows="1" data-message data-test-id={TEST_IDS.message} {@attach autosized.attachment} >
{/if}
button]:-my-px @2xl:[&>button]:-mx-px @max-2xl:[&>button:first-of-type]:rounded-t-md @2xl:[&>button:first-of-type]:rounded-l-md @max-2xl:[&>button:last-of-type]:rounded-b-md @2xl:[&>button:last-of-type]:rounded-r-md", shouldStick && "sticky", ]} > {#if canUploadImgs}
{#snippet trigger(tooltip)}
{/snippet} Add image
{/if}
{#snippet trigger(tooltip)}
{#snippet children({ trigger, addToast })}
{ copyToClipboard(message.content ?? ""); addToast({ data: { content: "✓", variant: "info" } }); }} type="button" class="grid size-7 place-items-center border border-gray-200 bg-white text-xs font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 focus:outline-hidden dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700" {...tooltip.trigger} {...trigger} >
{/snippet}
{/snippet} Copy
{#snippet trigger(tooltip)}
{/snippet}
{regenLabel}
{cmdOrCtrl}
G
{#snippet trigger(tooltip)}
{ try { await projects.branch(projects.activeId, index); } catch (error) { addToast({ title: "Error", description: error instanceof Error ? error.message : "Failed to create branch", variant: "error", }); } }} type="button" class="grid size-7 place-items-center border border-gray-200 bg-white text-xs font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 focus:outline-hidden dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700" {...tooltip.trigger} >
{/snippet} Branch from here
{#snippet trigger(tooltip)}
✕
{/snippet} Delete
{#each message.images ?? [] as imgKey (imgKey)} {#await images.get(imgKey)} {:then imgSrc}
previewImage(imgSrc)} >
{ e.stopPropagation(); await conversation.updateMessage({ index, message: { images: message.images?.filter(i => i !== imgKey) }, }); images.delete(imgKey); }} class="invisible absolute -top-1 -right-1 z-20 grid size-5 place-items-center rounded-full bg-gray-800 text-xs text-white group-hover/img:visible hover:bg-gray-700" > ✕
{/await} {/each}
{#if projects.current?.branchedFromId && projects.current?.branchedFromMessageIndex === index}
Branched from
{ if (!projects.current?.branchedFromId) return; projects.activeId = projects.current.branchedFromId; }} class="font-medium text-blue-600 underline hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300" > {projects.getBranchedFromProject(projects.current.id)?.name || "original project"}
{/if}