|
@@ -8,6 +8,7 @@ import {
|
|
|
ToolPart,
|
|
ToolPart,
|
|
|
UserMessage,
|
|
UserMessage,
|
|
|
} from "@opencode-ai/sdk/v2"
|
|
} from "@opencode-ai/sdk/v2"
|
|
|
|
|
+import { useData } from "../context"
|
|
|
import { useDiffComponent } from "../context/diff"
|
|
import { useDiffComponent } from "../context/diff"
|
|
|
import { BasicTool } from "./basic-tool"
|
|
import { BasicTool } from "./basic-tool"
|
|
|
import { GenericTool } from "./basic-tool"
|
|
import { GenericTool } from "./basic-tool"
|
|
@@ -16,26 +17,34 @@ import { Icon } from "./icon"
|
|
|
import { Checkbox } from "./checkbox"
|
|
import { Checkbox } from "./checkbox"
|
|
|
import { DiffChanges } from "./diff-changes"
|
|
import { DiffChanges } from "./diff-changes"
|
|
|
import { Markdown } from "./markdown"
|
|
import { Markdown } from "./markdown"
|
|
|
-import { getDirectory, getFilename } from "@opencode-ai/util/path"
|
|
|
|
|
-import { sanitizePart } from "@opencode-ai/util/sanitize"
|
|
|
|
|
|
|
+import { getDirectory as _getDirectory, getFilename } from "@opencode-ai/util/path"
|
|
|
|
|
|
|
|
export interface MessageProps {
|
|
export interface MessageProps {
|
|
|
message: MessageType
|
|
message: MessageType
|
|
|
parts: PartType[]
|
|
parts: PartType[]
|
|
|
- sanitize?: RegExp
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export interface MessagePartProps {
|
|
export interface MessagePartProps {
|
|
|
part: PartType
|
|
part: PartType
|
|
|
message: MessageType
|
|
message: MessageType
|
|
|
hideDetails?: boolean
|
|
hideDetails?: boolean
|
|
|
- sanitize?: RegExp
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export type PartComponent = Component<MessagePartProps>
|
|
export type PartComponent = Component<MessagePartProps>
|
|
|
|
|
|
|
|
export const PART_MAPPING: Record<string, PartComponent | undefined> = {}
|
|
export const PART_MAPPING: Record<string, PartComponent | undefined> = {}
|
|
|
|
|
|
|
|
|
|
+function relativizeProjectPaths(text: string, directory?: string) {
|
|
|
|
|
+ if (!text) return ""
|
|
|
|
|
+ if (!directory) return text
|
|
|
|
|
+ return text.split(directory).join("")
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function getDirectory(path: string | undefined) {
|
|
|
|
|
+ const data = useData()
|
|
|
|
|
+ return relativizeProjectPaths(_getDirectory(path), data.directory)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
export function registerPartComponent(type: string, component: PartComponent) {
|
|
export function registerPartComponent(type: string, component: PartComponent) {
|
|
|
PART_MAPPING[type] = component
|
|
PART_MAPPING[type] = component
|
|
|
}
|
|
}
|
|
@@ -48,26 +57,20 @@ export function Message(props: MessageProps) {
|
|
|
</Match>
|
|
</Match>
|
|
|
<Match when={props.message.role === "assistant" && props.message}>
|
|
<Match when={props.message.role === "assistant" && props.message}>
|
|
|
{(assistantMessage) => (
|
|
{(assistantMessage) => (
|
|
|
- <AssistantMessageDisplay
|
|
|
|
|
- message={assistantMessage() as AssistantMessage}
|
|
|
|
|
- parts={props.parts}
|
|
|
|
|
- sanitize={props.sanitize}
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <AssistantMessageDisplay message={assistantMessage() as AssistantMessage} parts={props.parts} />
|
|
|
)}
|
|
)}
|
|
|
</Match>
|
|
</Match>
|
|
|
</Switch>
|
|
</Switch>
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-export function AssistantMessageDisplay(props: { message: AssistantMessage; parts: PartType[]; sanitize?: RegExp }) {
|
|
|
|
|
|
|
+export function AssistantMessageDisplay(props: { message: AssistantMessage; parts: PartType[] }) {
|
|
|
const filteredParts = createMemo(() => {
|
|
const filteredParts = createMemo(() => {
|
|
|
return props.parts?.filter((x) => {
|
|
return props.parts?.filter((x) => {
|
|
|
return x.type !== "tool" || (x as ToolPart).tool !== "todoread"
|
|
return x.type !== "tool" || (x as ToolPart).tool !== "todoread"
|
|
|
})
|
|
})
|
|
|
})
|
|
})
|
|
|
- return (
|
|
|
|
|
- <For each={filteredParts()}>{(part) => <Part part={part} message={props.message} sanitize={props.sanitize} />}</For>
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ return <For each={filteredParts()}>{(part) => <Part part={part} message={props.message} />}</For>
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export function UserMessageDisplay(props: { message: UserMessage; parts: PartType[] }) {
|
|
export function UserMessageDisplay(props: { message: UserMessage; parts: PartType[] }) {
|
|
@@ -82,10 +85,9 @@ export function UserMessageDisplay(props: { message: UserMessage; parts: PartTyp
|
|
|
|
|
|
|
|
export function Part(props: MessagePartProps) {
|
|
export function Part(props: MessagePartProps) {
|
|
|
const component = createMemo(() => PART_MAPPING[props.part.type])
|
|
const component = createMemo(() => PART_MAPPING[props.part.type])
|
|
|
- const part = createMemo(() => sanitizePart(props.part, props.sanitize))
|
|
|
|
|
return (
|
|
return (
|
|
|
<Show when={component()}>
|
|
<Show when={component()}>
|
|
|
- <Dynamic component={component()} part={part()} message={props.message} hideDetails={props.hideDetails} />
|
|
|
|
|
|
|
+ <Dynamic component={component()} part={props.part} message={props.message} hideDetails={props.hideDetails} />
|
|
|
</Show>
|
|
</Show>
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
@@ -173,12 +175,15 @@ PART_MAPPING["tool"] = function ToolPartDisplay(props) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
PART_MAPPING["text"] = function TextPartDisplay(props) {
|
|
PART_MAPPING["text"] = function TextPartDisplay(props) {
|
|
|
|
|
+ const data = useData()
|
|
|
const part = props.part as TextPart
|
|
const part = props.part as TextPart
|
|
|
- const sanitized = createMemo(() => (props.sanitize ? (sanitizePart(part, props.sanitize) as TextPart) : part))
|
|
|
|
|
|
|
+ const content = createMemo(() => (part.text ?? "").trim())
|
|
|
|
|
+ const displayText = createMemo(() => relativizeProjectPaths(content(), data.directory))
|
|
|
|
|
+
|
|
|
return (
|
|
return (
|
|
|
- <Show when={part.text.trim()}>
|
|
|
|
|
|
|
+ <Show when={displayText()}>
|
|
|
<div data-component="text-part">
|
|
<div data-component="text-part">
|
|
|
- <Markdown text={sanitized().text.trim()} />
|
|
|
|
|
|
|
+ <Markdown text={displayText()} />
|
|
|
</div>
|
|
</div>
|
|
|
</Show>
|
|
</Show>
|
|
|
)
|
|
)
|