Adam 2 месяцев назад
Родитель
Сommit
bf420e7df6

+ 23 - 18
packages/ui/src/components/message-part.tsx

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

+ 2 - 4
packages/ui/src/components/session-turn.tsx

@@ -33,7 +33,6 @@ export function SessionTurn(
 ) {
   const data = useData()
   const diffComponent = useDiffComponent()
-  const sanitizer = createMemo(() => (data.directory ? new RegExp(`${data.directory}/`, "g") : undefined))
   const messages = createMemo(() => (props.sessionID ? (data.store.message[props.sessionID] ?? []) : []))
   const userMessages = createMemo(() =>
     messages()
@@ -208,7 +207,7 @@ export function SessionTurn(
                   </div>
                 </div>
                 <div data-slot="session-turn-message-content">
-                  <Message message={message()} parts={parts()} sanitize={sanitizer()} />
+                  <Message message={message()} parts={parts()} />
                 </div>
                 {/* Response */}
                 <div data-slot="session-turn-response-section">
@@ -252,11 +251,10 @@ export function SessionTurn(
                                   <Message
                                     message={assistantMessage}
                                     parts={parts().filter((p) => p?.id !== last()?.id)}
-                                    sanitize={sanitizer()}
                                   />
                                 </Match>
                                 <Match when={true}>
-                                  <Message message={assistantMessage} parts={parts()} sanitize={sanitizer()} />
+                                  <Message message={assistantMessage} parts={parts()} />
                                 </Match>
                               </Switch>
                             )

+ 0 - 28
packages/util/src/sanitize.ts

@@ -1,28 +0,0 @@
-import type { Part } from "@opencode-ai/sdk/v2/client"
-
-export const sanitize = (text: string | undefined, remove?: RegExp) => (remove ? text?.replace(remove, "") : text) ?? ""
-
-export const sanitizePart = (part: Part, remove: RegExp | undefined) => {
-  if (part.type === "text") {
-    part.text = sanitize(part.text, remove)
-  } else if (part.type === "reasoning") {
-    part.text = sanitize(part.text, remove)
-  } else if (part.type === "tool") {
-    if (part.state.status === "completed" || part.state.status === "error") {
-      for (const key in part.state.metadata) {
-        if (typeof part.state.metadata[key] === "string") {
-          part.state.metadata[key] = sanitize(part.state.metadata[key] as string, remove)
-        }
-      }
-      for (const key in part.state.input) {
-        if (typeof part.state.input[key] === "string") {
-          part.state.input[key] = sanitize(part.state.input[key] as string, remove)
-        }
-      }
-      if ("error" in part.state) {
-        part.state.error = sanitize(part.state.error as string, remove)
-      }
-    }
-  }
-  return part
-}