优化消息的部分call tool显示
This commit is contained in:
@@ -22,6 +22,7 @@ import { useTranslations } from "next-intl"
|
|||||||
import { isValidElement } from "react"
|
import { isValidElement } from "react"
|
||||||
|
|
||||||
import { CodeBlock } from "./code-block"
|
import { CodeBlock } from "./code-block"
|
||||||
|
import { MessageResponse } from "./message"
|
||||||
|
|
||||||
export type ToolProps = ComponentProps<typeof Collapsible>
|
export type ToolProps = ComponentProps<typeof Collapsible>
|
||||||
|
|
||||||
@@ -315,12 +316,34 @@ function isDuplicateErrorOutput(
|
|||||||
export type ToolOutputProps = ComponentProps<"div"> & {
|
export type ToolOutputProps = ComponentProps<"div"> & {
|
||||||
output: ToolPart["output"]
|
output: ToolPart["output"]
|
||||||
errorText: ToolPart["errorText"]
|
errorText: ToolPart["errorText"]
|
||||||
|
renderAsMarkdown?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const MD_INDICATORS = [
|
||||||
|
/^#{1,6}\s/m,
|
||||||
|
/^\s*[-*+]\s/m,
|
||||||
|
/^\s*\d+\.\s/m,
|
||||||
|
/\*\*[^*]+\*\*/,
|
||||||
|
/\[.+\]\(.+\)/,
|
||||||
|
/```[\s\S]*?```/,
|
||||||
|
/^\s*>/m,
|
||||||
|
/^\|.+\|$/m,
|
||||||
|
]
|
||||||
|
|
||||||
|
function looksLikeMarkdown(text: string): boolean {
|
||||||
|
let count = 0
|
||||||
|
for (const re of MD_INDICATORS) {
|
||||||
|
if (re.test(text)) count++
|
||||||
|
if (count >= 2) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ToolOutput = ({
|
export const ToolOutput = ({
|
||||||
className,
|
className,
|
||||||
output,
|
output,
|
||||||
errorText,
|
errorText,
|
||||||
|
renderAsMarkdown,
|
||||||
...props
|
...props
|
||||||
}: ToolOutputProps) => {
|
}: ToolOutputProps) => {
|
||||||
const t = useTranslations("Folder.chat.tool")
|
const t = useTranslations("Folder.chat.tool")
|
||||||
@@ -342,8 +365,18 @@ export const ToolOutput = ({
|
|||||||
<CodeBlock code={JSON.stringify(output, null, 2)} language="json" />
|
<CodeBlock code={JSON.stringify(output, null, 2)} language="json" />
|
||||||
)
|
)
|
||||||
} else if (typeof output === "string") {
|
} else if (typeof output === "string") {
|
||||||
const language = detectOutputLanguage(output)
|
const shouldRenderMd =
|
||||||
Output = <CodeBlock code={output} language={language} />
|
renderAsMarkdown ?? (detectOutputLanguage(output) === "log" && looksLikeMarkdown(output))
|
||||||
|
if (shouldRenderMd) {
|
||||||
|
Output = (
|
||||||
|
<div className="prose prose-sm dark:prose-invert max-w-none p-3 text-sm [&_ul]:list-inside [&_ol]:list-inside">
|
||||||
|
<MessageResponse>{output}</MessageResponse>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
const language = detectOutputLanguage(output)
|
||||||
|
Output = <CodeBlock code={output} language={language} />
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -871,6 +871,7 @@ function getToolIcon(
|
|||||||
if (name === "task") return getTaskToolIcon(input ?? null)
|
if (name === "task") return getTaskToolIcon(input ?? null)
|
||||||
if (name === "taskcreate" || name === "taskupdate" || name === "tasklist")
|
if (name === "taskcreate" || name === "taskupdate" || name === "tasklist")
|
||||||
return <ListTodoIcon className={ICON_CLASS} />
|
return <ListTodoIcon className={ICON_CLASS} />
|
||||||
|
if (name === "agent") return getTaskToolIcon(input ?? null)
|
||||||
if (name === "skill") return <SparklesIcon className={ICON_CLASS} />
|
if (name === "skill") return <SparklesIcon className={ICON_CLASS} />
|
||||||
if (name === "enterplanmode" || name === "exitplanmode")
|
if (name === "enterplanmode" || name === "exitplanmode")
|
||||||
return <BrainIcon className={ICON_CLASS} />
|
return <BrainIcon className={ICON_CLASS} />
|
||||||
@@ -1000,6 +1001,13 @@ function deriveToolTitle(
|
|||||||
if (desc) return `${prefix}${ellipsis(desc, 60 - prefix.length)}`
|
if (desc) return `${prefix}${ellipsis(desc, 60 - prefix.length)}`
|
||||||
if (subagent) return subagent
|
if (subagent) return subagent
|
||||||
}
|
}
|
||||||
|
if (name === "agent") {
|
||||||
|
const subagent = getField("subagent_type")
|
||||||
|
const desc = getField("description")
|
||||||
|
const prefix = subagent ? `${subagent}: ` : ""
|
||||||
|
if (desc) return `${prefix}${ellipsis(desc, 60 - prefix.length)}`
|
||||||
|
if (subagent) return subagent
|
||||||
|
}
|
||||||
if (name === "taskcreate") {
|
if (name === "taskcreate") {
|
||||||
const subj = getField("subject")
|
const subj = getField("subject")
|
||||||
if (subj) return `TaskCreate: ${ellipsis(subj, 50)}`
|
if (subj) return `TaskCreate: ${ellipsis(subj, 50)}`
|
||||||
@@ -2156,7 +2164,8 @@ const ToolCallPart = memo(function ToolCallPart({
|
|||||||
input={part.input}
|
input={part.input}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{toolNameLower === "task" && part.output ? (
|
{(toolNameLower === "task" || toolNameLower === "agent") &&
|
||||||
|
part.output ? (
|
||||||
<div className="text-sm prose prose-sm dark:prose-invert max-w-none [&_ul]:list-inside [&_ol]:list-inside">
|
<div className="text-sm prose prose-sm dark:prose-invert max-w-none [&_ul]:list-inside [&_ol]:list-inside">
|
||||||
<MessageResponse>{part.output}</MessageResponse>
|
<MessageResponse>{part.output}</MessageResponse>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -32,6 +32,29 @@ const EXACT_TOOL_NAME_ALIASES: Record<string, string> = {
|
|||||||
web_search: "websearch",
|
web_search: "websearch",
|
||||||
context7_query_docs: "context7_query-docs",
|
context7_query_docs: "context7_query-docs",
|
||||||
context7_resolve_library_id: "context7_resolve-library-id",
|
context7_resolve_library_id: "context7_resolve-library-id",
|
||||||
|
agent: "agent",
|
||||||
|
// Gemini CLI
|
||||||
|
searchtext: "grep",
|
||||||
|
search_text: "grep",
|
||||||
|
writefile: "write",
|
||||||
|
editfile: "edit",
|
||||||
|
// Codex
|
||||||
|
update_plan: "task",
|
||||||
|
request_user_input: "question",
|
||||||
|
// OpenCode
|
||||||
|
delegate_task: "task",
|
||||||
|
call_omo_agent: "agent",
|
||||||
|
ast_grep_search: "grep",
|
||||||
|
ast_grep_replace: "edit",
|
||||||
|
background_task: "task",
|
||||||
|
background_cancel: "task",
|
||||||
|
background_output: "task",
|
||||||
|
slashcommand: "skill",
|
||||||
|
question: "question",
|
||||||
|
lsp_diagnostics: "lsp",
|
||||||
|
lsp_document_symbols: "lsp",
|
||||||
|
lsp_goto_definition: "lsp",
|
||||||
|
lsp_servers: "lsp",
|
||||||
execute: "bash",
|
execute: "bash",
|
||||||
search: "grep",
|
search: "grep",
|
||||||
fetch: "webfetch",
|
fetch: "webfetch",
|
||||||
@@ -65,6 +88,10 @@ function inferFromFreeformName(input: string): string | null {
|
|||||||
if (/^glob(?:\b|[_\s:-])/.test(normalized)) return "glob"
|
if (/^glob(?:\b|[_\s:-])/.test(normalized)) return "glob"
|
||||||
if (/^webfetch(?:\b|[_\s:-])/.test(normalized)) return "webfetch"
|
if (/^webfetch(?:\b|[_\s:-])/.test(normalized)) return "webfetch"
|
||||||
if (/^websearch(?:\b|[_\s:-])/.test(normalized)) return "websearch"
|
if (/^websearch(?:\b|[_\s:-])/.test(normalized)) return "websearch"
|
||||||
|
if (/\bweb[_\s-]?search\b/.test(normalized)) return "websearch"
|
||||||
|
if (/\bgrep\b/.test(normalized)) return "grep"
|
||||||
|
if (/\bagent\b/.test(normalized)) return "agent"
|
||||||
|
if (/\blsp\b/.test(normalized)) return "lsp"
|
||||||
if (/^todowrite(?:\b|[_\s:-])/.test(normalized)) return "todowrite"
|
if (/^todowrite(?:\b|[_\s:-])/.test(normalized)) return "todowrite"
|
||||||
if (/^taskupdate(?:\b|[_\s:-])/.test(normalized)) return "taskupdate"
|
if (/^taskupdate(?:\b|[_\s:-])/.test(normalized)) return "taskupdate"
|
||||||
if (/^taskcreate(?:\b|[_\s:-])/.test(normalized)) return "taskcreate"
|
if (/^taskcreate(?:\b|[_\s:-])/.test(normalized)) return "taskcreate"
|
||||||
|
|||||||
Reference in New Issue
Block a user