summaryrefslogtreecommitdiffhomepage
path: root/packages/ui/src/components
diff options
context:
space:
mode:
authorDavid Hill <[email protected]>2025-12-02 17:00:45 +0000
committerDavid Hill <[email protected]>2025-12-02 17:00:45 +0000
commit58b30d678a910378a554b2ab580da4a2e17796cd (patch)
tree6be6118d39755712ffb875f4771ddfe35256b43a /packages/ui/src/components
parent408cdaf5e05dacc0675a15205fa2c80e667d2f03 (diff)
parentcae23cde09b5e0fa2c15a240135e2d2e4f864613 (diff)
downloadopencode-58b30d678a910378a554b2ab580da4a2e17796cd.tar.gz
opencode-58b30d678a910378a554b2ab580da4a2e17796cd.zip
Merge branch 'dev' of https://github.com/sst/opencode into dev
Diffstat (limited to 'packages/ui/src/components')
-rw-r--r--packages/ui/src/components/code.tsx29
-rw-r--r--packages/ui/src/components/diff-ssr.tsx75
-rw-r--r--packages/ui/src/components/diff.tsx98
-rw-r--r--packages/ui/src/components/message-part.tsx32
-rw-r--r--packages/ui/src/components/message-progress.tsx28
-rw-r--r--packages/ui/src/components/pierre.ts68
-rw-r--r--packages/ui/src/components/session-review.tsx8
-rw-r--r--packages/ui/src/components/session-turn.tsx37
8 files changed, 213 insertions, 162 deletions
diff --git a/packages/ui/src/components/code.tsx b/packages/ui/src/components/code.tsx
index 788baf549..b4b772816 100644
--- a/packages/ui/src/components/code.tsx
+++ b/packages/ui/src/components/code.tsx
@@ -1,6 +1,22 @@
import { type FileContents, File, FileOptions, LineAnnotation } from "@pierre/precision-diffs"
import { ComponentProps, createEffect, splitProps } from "solid-js"
-import { createDefaultOptions, styleVariables } from "./pierre"
+import { createDefaultOptions, styleVariables } from "../pierre"
+import { getOrCreateWorkerPoolSingleton } from "@pierre/precision-diffs/worker"
+import { workerFactory } from "../pierre/worker"
+
+const workerPool = getOrCreateWorkerPoolSingleton({
+ poolOptions: {
+ workerFactory,
+ // poolSize defaults to 8. More workers = more parallelism but
+ // also more memory. Too many can actually slow things down.
+ // poolSize: 8,
+ },
+ highlighterOptions: {
+ theme: "OpenCode",
+ // Optionally preload languages to avoid lazy-loading delays
+ // langs: ["typescript", "javascript", "css", "html"],
+ },
+})
export type CodeProps<T = {}> = FileOptions<T> & {
file: FileContents
@@ -14,10 +30,13 @@ export function Code<T>(props: CodeProps<T>) {
const [local, others] = splitProps(props, ["file", "class", "classList", "annotations"])
createEffect(() => {
- const instance = new File<T>({
- ...createDefaultOptions<T>("unified"),
- ...others,
- })
+ const instance = new File<T>(
+ {
+ ...createDefaultOptions<T>("unified"),
+ ...others,
+ },
+ workerPool,
+ )
container.innerHTML = ""
instance.render({
diff --git a/packages/ui/src/components/diff-ssr.tsx b/packages/ui/src/components/diff-ssr.tsx
new file mode 100644
index 000000000..800aa3730
--- /dev/null
+++ b/packages/ui/src/components/diff-ssr.tsx
@@ -0,0 +1,75 @@
+import { FileDiff } from "@pierre/precision-diffs"
+import { PreloadMultiFileDiffResult } from "@pierre/precision-diffs/ssr"
+import { onCleanup, onMount, Show, splitProps } from "solid-js"
+import { isServer } from "solid-js/web"
+import { createDefaultOptions, styleVariables, type DiffProps } from "../pierre"
+
+export type SSRDiffProps<T = {}> = DiffProps<T> & {
+ preloadedDiff: PreloadMultiFileDiffResult<T>
+}
+
+export function Diff<T>(props: SSRDiffProps<T>) {
+ let container!: HTMLDivElement
+ let fileDiffRef!: HTMLElement
+ const [local, others] = splitProps(props, ["before", "after", "class", "classList", "annotations"])
+
+ let fileDiffInstance: FileDiff<T> | undefined
+ const cleanupFunctions: Array<() => void> = []
+
+ onMount(() => {
+ if (isServer || !props.preloadedDiff) return
+ fileDiffInstance = new FileDiff<T>({
+ ...createDefaultOptions(props.diffStyle),
+ ...others,
+ ...props.preloadedDiff,
+ })
+ // @ts-expect-error - fileContainer is private but needed for SSR hydration
+ fileDiffInstance.fileContainer = fileDiffRef
+ fileDiffInstance.hydrate({
+ oldFile: local.before,
+ newFile: local.after,
+ lineAnnotations: local.annotations,
+ fileContainer: fileDiffRef,
+ containerWrapper: container,
+ })
+
+ // Hydrate annotation slots with interactive SolidJS components
+ // if (props.annotations.length > 0 && props.renderAnnotation != null) {
+ // for (const annotation of props.annotations) {
+ // const slotName = `annotation-${annotation.side}-${annotation.lineNumber}`;
+ // const slotElement = fileDiffRef.querySelector(
+ // `[slot="${slotName}"]`
+ // ) as HTMLElement;
+ //
+ // if (slotElement != null) {
+ // // Clear the static server-rendered content from the slot
+ // slotElement.innerHTML = '';
+ //
+ // // Mount a fresh SolidJS component into this slot using render().
+ // // This enables full SolidJS reactivity (signals, effects, etc.)
+ // const dispose = render(
+ // () => props.renderAnnotation!(annotation),
+ // slotElement
+ // );
+ // cleanupFunctions.push(dispose);
+ // }
+ // }
+ // }
+ })
+
+ onCleanup(() => {
+ // Clean up FileDiff event handlers and dispose SolidJS components
+ fileDiffInstance?.cleanUp()
+ cleanupFunctions.forEach((dispose) => dispose())
+ })
+
+ return (
+ <div data-component="diff" style={styleVariables} ref={container}>
+ <file-diff ref={fileDiffRef} id="ssr-diff">
+ <Show when={isServer}>
+ <template shadowrootmode="open" innerHTML={props.preloadedDiff.prerenderedHTML} />
+ </Show>
+ </file-diff>
+ </div>
+ )
+}
diff --git a/packages/ui/src/components/diff.tsx b/packages/ui/src/components/diff.tsx
index bd2134515..8e19c3172 100644
--- a/packages/ui/src/components/diff.tsx
+++ b/packages/ui/src/components/diff.tsx
@@ -1,17 +1,22 @@
-import { type FileContents, FileDiff, type DiffLineAnnotation, FileDiffOptions } from "@pierre/precision-diffs"
-import { PreloadMultiFileDiffResult } from "@pierre/precision-diffs/ssr"
-import { ComponentProps, createEffect, onCleanup, onMount, Show, splitProps } from "solid-js"
-import { isServer } from "solid-js/web"
-import { createDefaultOptions, styleVariables } from "./pierre"
-
-export type DiffProps<T = {}> = FileDiffOptions<T> & {
- preloadedDiff?: PreloadMultiFileDiffResult<T>
- before: FileContents
- after: FileContents
- annotations?: DiffLineAnnotation<T>[]
- class?: string
- classList?: ComponentProps<"div">["classList"]
-}
+import { FileDiff } from "@pierre/precision-diffs"
+import { getOrCreateWorkerPoolSingleton } from "@pierre/precision-diffs/worker"
+import { createEffect, onCleanup, splitProps } from "solid-js"
+import { createDefaultOptions, type DiffProps, styleVariables } from "../pierre"
+import { workerFactory } from "../pierre/worker"
+
+const workerPool = getOrCreateWorkerPoolSingleton({
+ poolOptions: {
+ workerFactory,
+ // poolSize defaults to 8. More workers = more parallelism but
+ // also more memory. Too many can actually slow things down.
+ // poolSize: 8,
+ },
+ highlighterOptions: {
+ theme: "OpenCode",
+ // Optionally preload languages to avoid lazy-loading delays
+ // langs: ["typescript", "javascript", "css", "html"],
+ },
+})
// interface ThreadMetadata {
// threadId: string
@@ -21,21 +26,21 @@ export type DiffProps<T = {}> = FileDiffOptions<T> & {
export function Diff<T>(props: DiffProps<T>) {
let container!: HTMLDivElement
- let fileDiffRef!: HTMLElement
const [local, others] = splitProps(props, ["before", "after", "class", "classList", "annotations"])
let fileDiffInstance: FileDiff<T> | undefined
const cleanupFunctions: Array<() => void> = []
createEffect(() => {
- if (props.preloadedDiff) return
container.innerHTML = ""
if (!fileDiffInstance) {
- fileDiffInstance = new FileDiff<T>({
- ...createDefaultOptions(props.diffStyle),
- ...others,
- ...(props.preloadedDiff ?? {}),
- })
+ fileDiffInstance = new FileDiff<T>(
+ {
+ ...createDefaultOptions(props.diffStyle),
+ ...others,
+ },
+ workerPool,
+ )
}
fileDiffInstance.render({
oldFile: local.before,
@@ -45,60 +50,11 @@ export function Diff<T>(props: DiffProps<T>) {
})
})
- onMount(() => {
- if (isServer || !props.preloadedDiff) return
- fileDiffInstance = new FileDiff<T>({
- ...createDefaultOptions(props.diffStyle),
- ...others,
- ...(props.preloadedDiff ?? {}),
- })
- // @ts-expect-error - fileContainer is private but needed for SSR hydration
- fileDiffInstance.fileContainer = fileDiffRef
- fileDiffInstance.hydrate({
- oldFile: local.before,
- newFile: local.after,
- lineAnnotations: local.annotations,
- fileContainer: fileDiffRef,
- containerWrapper: container,
- })
-
- // Hydrate annotation slots with interactive SolidJS components
- // if (props.annotations.length > 0 && props.renderAnnotation != null) {
- // for (const annotation of props.annotations) {
- // const slotName = `annotation-${annotation.side}-${annotation.lineNumber}`;
- // const slotElement = fileDiffRef.querySelector(
- // `[slot="${slotName}"]`
- // ) as HTMLElement;
- //
- // if (slotElement != null) {
- // // Clear the static server-rendered content from the slot
- // slotElement.innerHTML = '';
- //
- // // Mount a fresh SolidJS component into this slot using render().
- // // This enables full SolidJS reactivity (signals, effects, etc.)
- // const dispose = render(
- // () => props.renderAnnotation!(annotation),
- // slotElement
- // );
- // cleanupFunctions.push(dispose);
- // }
- // }
- // }
- })
-
onCleanup(() => {
// Clean up FileDiff event handlers and dispose SolidJS components
fileDiffInstance?.cleanUp()
cleanupFunctions.forEach((dispose) => dispose())
})
- return (
- <div data-component="diff" style={styleVariables} ref={container}>
- <file-diff ref={fileDiffRef} id="ssr-diff">
- <Show when={isServer && props.preloadedDiff}>
- {(preloadedDiff) => <template shadowrootmode="open" innerHTML={preloadedDiff().prerenderedHTML} />}
- </Show>
- </file-diff>
- </div>
- )
+ return <div data-component="diff" style={styleVariables} ref={container} />
}
diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx
index 807e56db0..a0e6e91b6 100644
--- a/packages/ui/src/components/message-part.tsx
+++ b/packages/ui/src/components/message-part.tsx
@@ -1,4 +1,4 @@
-import { Component, createMemo, For, Match, Show, Switch } from "solid-js"
+import { Component, createMemo, For, Match, Show, Switch, ValidComponent } from "solid-js"
import { Dynamic } from "solid-js/web"
import {
AssistantMessage,
@@ -13,7 +13,6 @@ import { GenericTool } from "./basic-tool"
import { Card } from "./card"
import { Icon } from "./icon"
import { Checkbox } from "./checkbox"
-import { Diff } from "./diff"
import { DiffChanges } from "./diff-changes"
import { Markdown } from "./markdown"
import { getDirectory, getFilename } from "@opencode-ai/util/path"
@@ -23,12 +22,14 @@ import { unwrap } from "solid-js/store"
export interface MessageProps {
message: MessageType
parts: PartType[]
+ diffComponent: ValidComponent
sanitize?: RegExp
}
export interface MessagePartProps {
part: PartType
message: MessageType
+ diffComponent: ValidComponent
hideDetails?: boolean
sanitize?: RegExp
}
@@ -53,6 +54,7 @@ export function Message(props: MessageProps) {
message={assistantMessage() as AssistantMessage}
parts={props.parts}
sanitize={props.sanitize}
+ diffComponent={props.diffComponent}
/>
)}
</Match>
@@ -60,7 +62,12 @@ export function Message(props: MessageProps) {
)
}
-export function AssistantMessageDisplay(props: { message: AssistantMessage; parts: PartType[]; sanitize?: RegExp }) {
+export function AssistantMessageDisplay(props: {
+ message: AssistantMessage
+ parts: PartType[]
+ sanitize?: RegExp
+ diffComponent: ValidComponent
+}) {
const filteredParts = createMemo(() => {
return props.parts?.filter((x) => {
if (x.type === "reasoning") return false
@@ -68,7 +75,11 @@ export function AssistantMessageDisplay(props: { message: AssistantMessage; part
})
})
return (
- <For each={filteredParts()}>{(part) => <Part part={part} message={props.message} sanitize={props.sanitize} />}</For>
+ <For each={filteredParts()}>
+ {(part) => (
+ <Part part={part} message={props.message} sanitize={props.sanitize} diffComponent={props.diffComponent} />
+ )}
+ </For>
)
}
@@ -87,7 +98,13 @@ export function Part(props: MessagePartProps) {
const part = createMemo(() => sanitizePart(unwrap(props.part), props.sanitize))
return (
<Show when={component()}>
- <Dynamic component={component()} part={part()} message={props.message} hideDetails={props.hideDetails} />
+ <Dynamic
+ component={component()}
+ part={part()}
+ message={props.message}
+ diffComponent={props.diffComponent}
+ hideDetails={props.hideDetails}
+ />
</Show>
)
}
@@ -96,6 +113,7 @@ export interface ToolProps {
input: Record<string, any>
metadata: Record<string, any>
tool: string
+ diffComponent: ValidComponent
output?: string
hideDetails?: boolean
}
@@ -162,6 +180,7 @@ PART_MAPPING["tool"] = function ToolPartDisplay(props) {
component={render}
input={input}
tool={part.tool}
+ diffComponent={props.diffComponent}
metadata={metadata}
output={part.state.status === "completed" ? part.state.output : undefined}
hideDetails={props.hideDetails}
@@ -361,7 +380,8 @@ ToolRegistry.register({
>
<Show when={props.metadata.filediff}>
<div data-component="edit-content">
- <Diff
+ <Dynamic
+ component={props.diffComponent}
before={{
name: getFilename(props.metadata.filediff.path),
contents: props.metadata.filediff.before,
diff --git a/packages/ui/src/components/message-progress.tsx b/packages/ui/src/components/message-progress.tsx
index efe4dfd8f..afd7f754a 100644
--- a/packages/ui/src/components/message-progress.tsx
+++ b/packages/ui/src/components/message-progress.tsx
@@ -1,10 +1,27 @@
-import { For, JSXElement, Match, Show, Switch, createEffect, createMemo, createSignal, onCleanup } from "solid-js"
+import {
+ For,
+ JSXElement,
+ Match,
+ Show,
+ Switch,
+ ValidComponent,
+ createEffect,
+ createMemo,
+ createSignal,
+ onCleanup,
+} from "solid-js"
import { Part } from "./message-part"
import { Spinner } from "./spinner"
import { useData } from "../context/data"
import type { AssistantMessage as AssistantMessageType, ToolPart } from "@opencode-ai/sdk"
-export function MessageProgress(props: { assistantMessages: () => AssistantMessageType[]; done?: boolean }) {
+export interface MessageProgressProps {
+ assistantMessages: () => AssistantMessageType[]
+ diffComponent: ValidComponent
+ done?: boolean
+}
+
+export function MessageProgress(props: MessageProgressProps) {
const data = useData()
const sanitizer = createMemo(() => (data.directory ? new RegExp(`${data.directory}/`, "g") : undefined))
const parts = createMemo(() => props.assistantMessages().flatMap((m) => data.store.part[m.id]))
@@ -155,7 +172,12 @@ export function MessageProgress(props: { assistantMessages: () => AssistantMessa
)
return (
<div data-slot="message-progress-item">
- <Part message={message()!} part={part} sanitize={sanitizer()} />
+ <Part
+ message={message()!}
+ part={part}
+ sanitize={sanitizer()}
+ diffComponent={props.diffComponent}
+ />
</div>
)
}}
diff --git a/packages/ui/src/components/pierre.ts b/packages/ui/src/components/pierre.ts
deleted file mode 100644
index 5821697c7..000000000
--- a/packages/ui/src/components/pierre.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import { FileDiffOptions } from "@pierre/precision-diffs"
-
-export function createDefaultOptions<T>(style: FileDiffOptions<T>["diffStyle"]) {
- return {
- theme: "OpenCode",
- themeType: "system",
- disableLineNumbers: false,
- overflow: "wrap",
- diffStyle: style ?? "unified",
- diffIndicators: "bars",
- disableBackground: false,
- expansionLineCount: 20,
- lineDiffType: style === "split" ? "word-alt" : "none",
- maxLineDiffLength: 1000,
- maxLineLengthForHighlighting: 1000,
- disableFileHeader: true,
- unsafeCSS: `
-[data-pjs-header],
-[data-pjs] {
- [data-separator-wrapper] {
- margin: 0 !important;
- border-radius: 0 !important;
- }
- [data-expand-button] {
- width: 6.5ch !important;
- height: 24px !important;
- justify-content: end !important;
- padding-left: 3ch !important;
- padding-inline: 1ch !important;
- }
- [data-separator-multi-button] {
- grid-template-rows: 10px 10px !important;
- [data-expand-button] {
- height: 12px !important;
- }
- }
- [data-separator-content] {
- height: 24px !important;
- }
-}`,
- // hunkSeparators(hunkData: HunkData) {
- // const fragment = document.createDocumentFragment()
- // const numCol = document.createElement("div")
- // numCol.innerHTML = `<svg data-slot="diff-hunk-separator-line-number-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.97978 14.0204L8.62623 13.6668L9.33334 12.9597L9.68689 13.3133L9.33333 13.6668L8.97978 14.0204ZM12 16.3335L12.3535 16.6871L12 17.0406L11.6464 16.687L12 16.3335ZM14.3131 13.3133L14.6667 12.9597L15.3738 13.6668L15.0202 14.0204L14.6667 13.6668L14.3131 13.3133ZM12.5 16.0002V16.5002H11.5V16.0002H12H12.5ZM9.33333 13.6668L9.68689 13.3133L12.3535 15.9799L12 16.3335L11.6464 16.687L8.97978 14.0204L9.33333 13.6668ZM12 16.3335L11.6464 15.9799L14.3131 13.3133L14.6667 13.6668L15.0202 14.0204L12.3535 16.6871L12 16.3335ZM6.5 8.00016V7.50016H8.5V8.00016V8.50016H6.5V8.00016ZM9.5 8.00016V7.50016H11.5V8.00016V8.50016H9.5V8.00016ZM12.5 8.00016V7.50016H14.5V8.00016V8.50016H12.5V8.00016ZM15.5 8.00016V7.50016H17.5V8.00016V8.50016H15.5V8.00016ZM12 10.5002H12.5V16.0002H12H11.5V10.5002H12Z" fill="currentColor"/></svg> `
- // numCol.dataset["slot"] = "diff-hunk-separator-line-number"
- // fragment.appendChild(numCol)
- // const contentCol = document.createElement("div")
- // contentCol.dataset["slot"] = "diff-hunk-separator-content"
- // const span = document.createElement("span")
- // span.dataset["slot"] = "diff-hunk-separator-content-span"
- // span.textContent = `${hunkData.lines} unmodified lines`
- // contentCol.appendChild(span)
- // fragment.appendChild(contentCol)
- // return fragment
- // },
- } as const
-}
-
-export const styleVariables = {
- "--pjs-font-family": "var(--font-family-mono)",
- "--pjs-font-size": "var(--font-size-small)",
- "--pjs-line-height": "24px",
- "--pjs-tab-size": 2,
- "--pjs-font-features": "var(--font-family-mono--font-feature-settings)",
- "--pjs-header-font-family": "var(--font-family-sans)",
- "--pjs-gap-block": 0,
- "--pjs-min-number-column-width": "4ch",
-}
diff --git a/packages/ui/src/components/session-review.tsx b/packages/ui/src/components/session-review.tsx
index 376317e1b..ea5871b95 100644
--- a/packages/ui/src/components/session-review.tsx
+++ b/packages/ui/src/components/session-review.tsx
@@ -1,15 +1,15 @@
import { Accordion } from "./accordion"
import { Button } from "./button"
-import { Diff } from "./diff"
import { DiffChanges } from "./diff-changes"
import { FileIcon } from "./file-icon"
import { Icon } from "./icon"
import { StickyAccordionHeader } from "./sticky-accordion-header"
import { getDirectory, getFilename } from "@opencode-ai/util/path"
-import { For, Match, Show, Switch, type JSX } from "solid-js"
+import { For, Match, Show, Switch, ValidComponent, type JSX } from "solid-js"
import { createStore } from "solid-js/store"
import { type FileDiff } from "@opencode-ai/sdk"
import { PreloadMultiFileDiffResult } from "@pierre/precision-diffs/ssr"
+import { Dynamic } from "solid-js/web"
export interface SessionReviewProps {
split?: boolean
@@ -18,6 +18,7 @@ export interface SessionReviewProps {
classes?: { root?: string; header?: string; container?: string }
actions?: JSX.Element
diffs: (FileDiff & { preloaded?: PreloadMultiFileDiffResult<any> })[]
+ diffComponent: ValidComponent
}
export const SessionReview = (props: SessionReviewProps) => {
@@ -96,7 +97,8 @@ export const SessionReview = (props: SessionReviewProps) => {
</Accordion.Trigger>
</StickyAccordionHeader>
<Accordion.Content data-slot="session-review-accordion-content">
- <Diff
+ <Dynamic
+ component={props.diffComponent}
preloadedDiff={diff.preloaded}
diffStyle={props.split ? "split" : "unified"}
before={{
diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx
index c61b23068..963713a22 100644
--- a/packages/ui/src/components/session-turn.tsx
+++ b/packages/ui/src/components/session-turn.tsx
@@ -2,7 +2,18 @@ import { AssistantMessage } from "@opencode-ai/sdk"
import { useData } from "../context"
import { Binary } from "@opencode-ai/util/binary"
import { getDirectory, getFilename } from "@opencode-ai/util/path"
-import { createEffect, createMemo, createSignal, For, Match, onMount, ParentProps, Show, Switch } from "solid-js"
+import {
+ createEffect,
+ createMemo,
+ createSignal,
+ For,
+ Match,
+ onMount,
+ ParentProps,
+ Show,
+ Switch,
+ ValidComponent,
+} from "solid-js"
import { DiffChanges } from "./diff-changes"
import { Typewriter } from "./typewriter"
import { Message } from "./message-part"
@@ -11,10 +22,10 @@ import { Accordion } from "./accordion"
import { StickyAccordionHeader } from "./sticky-accordion-header"
import { FileIcon } from "./file-icon"
import { Icon } from "./icon"
-import { Diff } from "./diff"
import { Card } from "./card"
import { MessageProgress } from "./message-progress"
import { Collapsible } from "./collapsible"
+import { Dynamic } from "solid-js/web"
export function SessionTurn(
props: ParentProps<{
@@ -25,6 +36,7 @@ export function SessionTurn(
content?: string
container?: string
}
+ diffComponent: ValidComponent
}>,
) {
const data = useData()
@@ -117,7 +129,7 @@ export function SessionTurn(
</div>
</div>
<div data-slot="session-turn-message-content">
- <Message message={msg()} parts={parts()} sanitize={sanitizer()} />
+ <Message message={msg()} parts={parts()} sanitize={sanitizer()} diffComponent={props.diffComponent} />
</div>
{/* Summary */}
<Show when={completed()}>
@@ -167,7 +179,8 @@ export function SessionTurn(
</Accordion.Trigger>
</StickyAccordionHeader>
<Accordion.Content data-slot="session-turn-accordion-content">
- <Diff
+ <Dynamic
+ component={props.diffComponent}
before={{
name: diff.file!,
contents: diff.before!,
@@ -193,7 +206,11 @@ export function SessionTurn(
<div data-slot="session-turn-response-section">
<Switch>
<Match when={!completed()}>
- <MessageProgress assistantMessages={assistantMessages} done={!messageWorking()} />
+ <MessageProgress
+ assistantMessages={assistantMessages}
+ done={!messageWorking()}
+ diffComponent={props.diffComponent}
+ />
</Match>
<Match when={completed() && hasToolPart()}>
<Collapsible variant="ghost" open={detailsExpanded()} onOpenChange={setDetailsExpanded}>
@@ -224,10 +241,18 @@ export function SessionTurn(
message={assistantMessage}
parts={parts().filter((p) => p?.id !== last()?.id)}
sanitize={sanitizer()}
+ diffComponent={props.diffComponent}
/>
)
}
- return <Message message={assistantMessage} parts={parts()} sanitize={sanitizer()} />
+ return (
+ <Message
+ message={assistantMessage}
+ parts={parts()}
+ sanitize={sanitizer()}
+ diffComponent={props.diffComponent}
+ />
+ )
}}
</For>
<Show when={error()}>