mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-08-07 15:33:30 +00:00
style(ui): render skill output like read
Route the skill tool through the read renderer so skill output uses the same preview, language detection, copy, and wrapping chrome as read output while preserving a skill-specific title label. Keep skill collapsed by default with the same error-expands behavior as read, and include path/name inputs in read-style search text so skill content remains discoverable. Validated with npm run typecheck --workspace @codenomad/ui.
This commit is contained in:
parent
64671da4cf
commit
2cc6630d40
4 changed files with 19 additions and 7 deletions
|
|
@ -756,7 +756,7 @@ export default function ToolCall(props: ToolCallProps) {
|
|||
}
|
||||
const prefExpanded = toolOutputDefaultExpanded()
|
||||
const toolName = toolCallMemo()?.tool || ""
|
||||
if (toolName === "read") {
|
||||
if (toolName === "read" || toolName === "skill") {
|
||||
const state = toolState()
|
||||
if (state?.status === "error") {
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -3,15 +3,23 @@ import { ensureMarkdownContent, getRelativePath, getToolName, inferLanguageFromP
|
|||
import { tGlobal } from "../../../lib/i18n"
|
||||
import { getReadToolSearchText } from "../search-text"
|
||||
|
||||
function getReadPath(input: Record<string, any>): string {
|
||||
const filePath = typeof input.filePath === "string" ? input.filePath : ""
|
||||
if (filePath) return filePath
|
||||
const path = typeof input.path === "string" ? input.path : ""
|
||||
if (path) return path
|
||||
return typeof input.name === "string" ? input.name : ""
|
||||
}
|
||||
|
||||
export const readRenderer: ToolRenderer = {
|
||||
tools: ["read"],
|
||||
tools: ["read", "skill"],
|
||||
getSearchText: getReadToolSearchText,
|
||||
getAction: () => tGlobal("toolCall.renderer.action.readingFile"),
|
||||
getTitle({ toolState }) {
|
||||
getTitle({ toolName, toolState }) {
|
||||
const state = toolState()
|
||||
if (!state) return undefined
|
||||
const { input } = readToolStatePayload(state)
|
||||
const filePath = typeof input.filePath === "string" ? input.filePath : ""
|
||||
const filePath = getReadPath(input)
|
||||
const offset = typeof input.offset === "number" ? input.offset : undefined
|
||||
const limit = typeof input.limit === "number" ? input.limit : undefined
|
||||
const relativePath = filePath ? getRelativePath(filePath) : ""
|
||||
|
|
@ -25,7 +33,8 @@ export const readRenderer: ToolRenderer = {
|
|||
detailParts.push(tGlobal("toolCall.renderer.read.detail.limit", { limit }))
|
||||
}
|
||||
|
||||
const baseTitle = relativePath ? `${getToolName("read")} ${relativePath}` : getToolName("read")
|
||||
const toolLabel = getToolName(toolName())
|
||||
const baseTitle = relativePath ? `${toolLabel} ${relativePath}` : toolLabel
|
||||
if (!detailParts.length) {
|
||||
return baseTitle
|
||||
}
|
||||
|
|
@ -38,7 +47,7 @@ export const readRenderer: ToolRenderer = {
|
|||
const { metadata, input } = readToolStatePayload(state)
|
||||
const preview = typeof metadata.preview === "string" ? metadata.preview : null
|
||||
if (!preview) return undefined
|
||||
const language = inferLanguageFromPath(typeof input.filePath === "string" ? input.filePath : undefined) ?? "text"
|
||||
const language = inferLanguageFromPath(getReadPath(input)) ?? "text"
|
||||
return { language, copyText: preview, wrapToggle: true, suppressInnerHeader: true }
|
||||
},
|
||||
renderBody({ toolState, renderMarkdown }) {
|
||||
|
|
@ -46,7 +55,7 @@ export const readRenderer: ToolRenderer = {
|
|||
if (!state || state.status === "pending") return null
|
||||
const { metadata, input } = readToolStatePayload(state)
|
||||
const preview = typeof metadata.preview === "string" ? metadata.preview : null
|
||||
const language = inferLanguageFromPath(typeof input.filePath === "string" ? input.filePath : undefined)
|
||||
const language = inferLanguageFromPath(getReadPath(input))
|
||||
const content = ensureMarkdownContent(preview, language, true)
|
||||
if (!content) return null
|
||||
return renderMarkdown({ content, disableHighlight: state.status === "running" })
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ export function getReadToolSearchText(context: ToolSearchTextContext): string[]
|
|||
const { input, metadata } = readToolStatePayload(context.toolState)
|
||||
appendBaseToolText(values, context)
|
||||
appendString(values, input.filePath)
|
||||
appendString(values, input.path)
|
||||
appendString(values, input.name)
|
||||
appendString(values, metadata.preview)
|
||||
appendToolErrorText(values, context)
|
||||
return values
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { searchRenderer } from "./renderers/search"
|
|||
const TITLE_RENDERERS: Record<string, ToolRenderer> = {
|
||||
bash: bashRenderer,
|
||||
read: readRenderer,
|
||||
skill: readRenderer,
|
||||
write: writeRenderer,
|
||||
edit: editRenderer,
|
||||
apply_patch: applyPatchRenderer,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue