1- import type { Part , AssistantMessage , ReasoningPart , TextPart , ToolPart , Message } from "@opencode-ai/sdk"
1+ import type { Part , ReasoningPart , TextPart , ToolPart , Message , AssistantMessage , UserMessage } from "@opencode-ai/sdk"
22import { children , Component , createMemo , For , Match , Show , Switch , type JSX } from "solid-js"
33import { Dynamic } from "solid-js/web"
44import { Markdown } from "./markdown"
@@ -17,7 +17,20 @@ import type { WriteTool } from "opencode/tool/write"
1717import type { TodoWriteTool } from "opencode/tool/todo"
1818import { DiffChanges } from "./diff-changes"
1919
20- export function AssistantMessage ( props : { message : AssistantMessage ; parts : Part [ ] } ) {
20+ export function Message ( props : { message : Message ; parts : Part [ ] } ) {
21+ return (
22+ < Switch >
23+ < Match when = { props . message . role === "user" && props . message } >
24+ { ( userMessage ) => < UserMessage message = { userMessage ( ) } parts = { props . parts } /> }
25+ </ Match >
26+ < Match when = { props . message . role === "assistant" && props . message } >
27+ { ( assistantMessage ) => < AssistantMessage message = { assistantMessage ( ) } parts = { props . parts } /> }
28+ </ Match >
29+ </ Switch >
30+ )
31+ }
32+
33+ function AssistantMessage ( props : { message : AssistantMessage ; parts : Part [ ] } ) {
2134 const filteredParts = createMemo ( ( ) => {
2235 return props . parts ?. filter ( ( x ) => {
2336 if ( x . type === "reasoning" ) return false
@@ -31,11 +44,26 @@ export function AssistantMessage(props: { message: AssistantMessage; parts: Part
3144 )
3245}
3346
34- export function Part ( props : { part : Part ; message : Message ; readonly ?: boolean } ) {
47+ function UserMessage ( props : { message : UserMessage ; parts : Part [ ] } ) {
48+ const text = createMemo ( ( ) =>
49+ props . parts
50+ ?. filter ( ( p ) => p . type === "text" && ! p . synthetic )
51+ ?. map ( ( p ) => ( p as TextPart ) . text )
52+ ?. join ( "" ) ,
53+ )
54+ return < div class = "text-12-regular text-text-base line-clamp-3" > { text ( ) } </ div >
55+ }
56+
57+ export function Part ( props : { part : Part ; message : Message ; hideDetails ?: boolean } ) {
3558 const component = createMemo ( ( ) => PART_MAPPING [ props . part . type as keyof typeof PART_MAPPING ] )
3659 return (
3760 < Show when = { component ( ) } >
38- < Dynamic component = { component ( ) } part = { props . part as any } message = { props . message } readonly = { props . readonly } />
61+ < Dynamic
62+ component = { component ( ) }
63+ part = { props . part as any }
64+ message = { props . message }
65+ hideDetails = { props . hideDetails }
66+ />
3967 </ Show >
4068 )
4169}
@@ -62,7 +90,7 @@ function TextPart(props: { part: TextPart; message: Message }) {
6290 )
6391}
6492
65- function ToolPart ( props : { part : ToolPart ; message : Message ; readonly ?: boolean } ) {
93+ function ToolPart ( props : { part : ToolPart ; message : Message ; hideDetails ?: boolean } ) {
6694 const component = createMemo ( ( ) => {
6795 const render = ToolRegistry . render ( props . part . tool ) ?? GenericTool
6896 const metadata = props . part . state . status === "pending" ? { } : ( props . part . state . metadata ?? { } )
@@ -75,7 +103,7 @@ function ToolPart(props: { part: ToolPart; message: Message; readonly?: boolean
75103 tool = { props . part . tool }
76104 metadata = { metadata }
77105 output = { props . part . state . status === "completed" ? props . part . state . output : undefined }
78- readonly = { props . readonly }
106+ hideDetails = { props . hideDetails }
79107 />
80108 )
81109 } )
@@ -101,7 +129,7 @@ function BasicTool(props: {
101129 icon : IconProps [ "name" ]
102130 trigger : TriggerTitle | JSX . Element
103131 children ?: JSX . Element
104- readonly ?: boolean
132+ hideDetails ?: boolean
105133} ) {
106134 const resolved = children ( ( ) => props . children )
107135 return (
@@ -157,12 +185,12 @@ function BasicTool(props: {
157185 </ Switch >
158186 </ div >
159187 </ div >
160- < Show when = { resolved ( ) && ! props . readonly } >
188+ < Show when = { resolved ( ) && ! props . hideDetails } >
161189 < Collapsible . Arrow />
162190 </ Show >
163191 </ div >
164192 </ Collapsible . Trigger >
165- < Show when = { resolved ( ) && ! props . readonly } >
193+ < Show when = { resolved ( ) && ! props . hideDetails } >
166194 < Collapsible . Content > { resolved ( ) } </ Collapsible . Content >
167195 </ Show >
168196 </ Collapsible >
@@ -173,15 +201,15 @@ function BasicTool(props: {
173201}
174202
175203function GenericTool ( props : ToolProps < any > ) {
176- return < BasicTool icon = "mcp" trigger = { { title : props . tool } } readonly = { props . readonly } />
204+ return < BasicTool icon = "mcp" trigger = { { title : props . tool } } hideDetails = { props . hideDetails } />
177205}
178206
179207type ToolProps < T extends Tool . Info > = {
180208 input : Partial < Tool . InferParameters < T > >
181209 metadata : Partial < Tool . InferMetadata < T > >
182210 tool : string
183211 output ?: string
184- readonly ?: boolean
212+ hideDetails ?: boolean
185213}
186214
187215const ToolRegistry = ( ( ) => {
0 commit comments