feat(ui): toggle tool call input yaml
This commit is contained in:
3
package-lock.json
generated
3
package-lock.json
generated
@@ -12092,7 +12092,8 @@
|
|||||||
"shiki": "^3.13.0",
|
"shiki": "^3.13.0",
|
||||||
"solid-js": "^1.8.0",
|
"solid-js": "^1.8.0",
|
||||||
"solid-toast": "^0.5.0",
|
"solid-toast": "^0.5.0",
|
||||||
"tauri-plugin-keepawake-api": "^0.1.0"
|
"tauri-plugin-keepawake-api": "^0.1.0",
|
||||||
|
"yaml": "^2.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vite-pwa/assets-generator": "^1.0.2",
|
"@vite-pwa/assets-generator": "^1.0.2",
|
||||||
|
|||||||
@@ -30,7 +30,8 @@
|
|||||||
"shiki": "^3.13.0",
|
"shiki": "^3.13.0",
|
||||||
"solid-js": "^1.8.0",
|
"solid-js": "^1.8.0",
|
||||||
"solid-toast": "^0.5.0",
|
"solid-toast": "^0.5.0",
|
||||||
"tauri-plugin-keepawake-api": "^0.1.0"
|
"tauri-plugin-keepawake-api": "^0.1.0",
|
||||||
|
"yaml": "^2.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vite-pwa/assets-generator": "^1.0.2",
|
"@vite-pwa/assets-generator": "^1.0.2",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { createSignal, Show, createEffect, createMemo, onCleanup } from "solid-js"
|
import { createSignal, Show, createEffect, createMemo, onCleanup } from "solid-js"
|
||||||
import { Copy } from "lucide-solid"
|
import { AlignJustify, Copy } from "lucide-solid"
|
||||||
|
import { stringify as stringifyYaml } from "yaml"
|
||||||
import { messageStoreBus } from "../stores/message-v2/bus"
|
import { messageStoreBus } from "../stores/message-v2/bus"
|
||||||
import { useTheme } from "../lib/theme"
|
import { useTheme } from "../lib/theme"
|
||||||
import { useGlobalCache } from "../lib/hooks/use-global-cache"
|
import { useGlobalCache } from "../lib/hooks/use-global-cache"
|
||||||
@@ -27,7 +28,17 @@ import type {
|
|||||||
ToolRendererContext,
|
ToolRendererContext,
|
||||||
ToolScrollHelpers,
|
ToolScrollHelpers,
|
||||||
} from "./tool-call/types"
|
} from "./tool-call/types"
|
||||||
import { getRelativePath, getToolIcon, getToolName, isToolStateCompleted, isToolStateError, isToolStateRunning, getDefaultToolAction } from "./tool-call/utils"
|
import {
|
||||||
|
ensureMarkdownContent,
|
||||||
|
getRelativePath,
|
||||||
|
getToolIcon,
|
||||||
|
getToolName,
|
||||||
|
isToolStateCompleted,
|
||||||
|
isToolStateError,
|
||||||
|
isToolStateRunning,
|
||||||
|
getDefaultToolAction,
|
||||||
|
readToolStatePayload,
|
||||||
|
} from "./tool-call/utils"
|
||||||
import { resolveTitleForTool } from "./tool-call/tool-title"
|
import { resolveTitleForTool } from "./tool-call/tool-title"
|
||||||
import { getLogger } from "../lib/logger"
|
import { getLogger } from "../lib/logger"
|
||||||
|
|
||||||
@@ -161,6 +172,7 @@ export default function ToolCall(props: ToolCallProps) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const [userExpanded, setUserExpanded] = createSignal<boolean | null>(null)
|
const [userExpanded, setUserExpanded] = createSignal<boolean | null>(null)
|
||||||
|
const [inputExpanded, setInputExpanded] = createSignal(false)
|
||||||
|
|
||||||
const isPermissionActive = createMemo(() => {
|
const isPermissionActive = createMemo(() => {
|
||||||
const pending = pendingPermission()
|
const pending = pendingPermission()
|
||||||
@@ -183,6 +195,35 @@ export default function ToolCall(props: ToolCallProps) {
|
|||||||
return defaultExpandedForTool()
|
return defaultExpandedForTool()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toolInput = createMemo(() => {
|
||||||
|
const state = toolState()
|
||||||
|
return readToolStatePayload(state).input
|
||||||
|
})
|
||||||
|
|
||||||
|
const hasToolInput = createMemo(() => {
|
||||||
|
const input = toolInput()
|
||||||
|
return input && Object.keys(input).length > 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const toolInputMarkdown = createMemo(() => {
|
||||||
|
const input = toolInput()
|
||||||
|
if (!input || Object.keys(input).length === 0) return null
|
||||||
|
|
||||||
|
try {
|
||||||
|
const yamlText = stringifyYaml(input)
|
||||||
|
return ensureMarkdownContent(yamlText, "yaml", true)
|
||||||
|
} catch (error) {
|
||||||
|
log.error("Failed to convert tool call input to YAML", error)
|
||||||
|
try {
|
||||||
|
const jsonText = JSON.stringify(input, null, 2)
|
||||||
|
return ensureMarkdownContent(jsonText, "json", true)
|
||||||
|
} catch (nestedError) {
|
||||||
|
log.error("Failed to stringify tool call input", nestedError)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const permissionDetails = createMemo(() => pendingPermission()?.permission)
|
const permissionDetails = createMemo(() => pendingPermission()?.permission)
|
||||||
const questionDetails = createMemo(() => pendingQuestion()?.request)
|
const questionDetails = createMemo(() => pendingQuestion()?.request)
|
||||||
|
|
||||||
@@ -548,6 +589,15 @@ export default function ToolCall(props: ToolCallProps) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleToggleInput = (event: MouseEvent) => {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
if (!expanded()) {
|
||||||
|
toggle()
|
||||||
|
}
|
||||||
|
setInputExpanded((prev) => !prev)
|
||||||
|
}
|
||||||
|
|
||||||
const renderer = createMemo(() => resolveToolRenderer(toolName()))
|
const renderer = createMemo(() => resolveToolRenderer(toolName()))
|
||||||
|
|
||||||
const { renderAnsiContent } = createAnsiContentRenderer({
|
const { renderAnsiContent } = createAnsiContentRenderer({
|
||||||
@@ -789,6 +839,23 @@ export default function ToolCall(props: ToolCallProps) {
|
|||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<Show when={hasToolInput()}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="tool-call-header-input"
|
||||||
|
onClick={handleToggleInput}
|
||||||
|
aria-pressed={inputExpanded()}
|
||||||
|
aria-label={
|
||||||
|
inputExpanded()
|
||||||
|
? t("toolCall.header.hideInputAriaLabel")
|
||||||
|
: t("toolCall.header.showInputAriaLabel")
|
||||||
|
}
|
||||||
|
title={inputExpanded() ? t("toolCall.header.hideInputTitle") : t("toolCall.header.showInputTitle")}
|
||||||
|
>
|
||||||
|
<AlignJustify class="w-3.5 h-3.5" />
|
||||||
|
</button>
|
||||||
|
</Show>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="tool-call-header-copy"
|
class="tool-call-header-copy"
|
||||||
@@ -806,6 +873,14 @@ export default function ToolCall(props: ToolCallProps) {
|
|||||||
|
|
||||||
{expanded() && (
|
{expanded() && (
|
||||||
<div class="tool-call-details">
|
<div class="tool-call-details">
|
||||||
|
<Show when={inputExpanded() && hasToolInput()}>
|
||||||
|
{(() => {
|
||||||
|
const content = toolInputMarkdown()
|
||||||
|
if (!content) return null
|
||||||
|
return renderMarkdownContent({ content, cacheKey: "input" })
|
||||||
|
})()}
|
||||||
|
</Show>
|
||||||
|
|
||||||
{renderToolBody()}
|
{renderToolBody()}
|
||||||
|
|
||||||
{renderError()}
|
{renderError()}
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ export const toolCallMessages = {
|
|||||||
"toolCall.header.copyTitle": "Copy tool call title",
|
"toolCall.header.copyTitle": "Copy tool call title",
|
||||||
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
||||||
|
|
||||||
|
"toolCall.header.showInputTitle": "Show tool call input",
|
||||||
|
"toolCall.header.showInputAriaLabel": "Show tool call input",
|
||||||
|
"toolCall.header.hideInputTitle": "Hide tool call input",
|
||||||
|
"toolCall.header.hideInputAriaLabel": "Hide tool call input",
|
||||||
|
|
||||||
"toolCall.diff.label": "Diff",
|
"toolCall.diff.label": "Diff",
|
||||||
"toolCall.diff.label.withPath": "Diff · {path}",
|
"toolCall.diff.label.withPath": "Diff · {path}",
|
||||||
"toolCall.diff.viewMode.ariaLabel": "Diff view mode",
|
"toolCall.diff.viewMode.ariaLabel": "Diff view mode",
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ export const toolCallMessages = {
|
|||||||
"toolCall.header.copyTitle": "Copy tool call title",
|
"toolCall.header.copyTitle": "Copy tool call title",
|
||||||
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
||||||
|
|
||||||
|
"toolCall.header.showInputTitle": "Show tool call input",
|
||||||
|
"toolCall.header.showInputAriaLabel": "Show tool call input",
|
||||||
|
"toolCall.header.hideInputTitle": "Hide tool call input",
|
||||||
|
"toolCall.header.hideInputAriaLabel": "Hide tool call input",
|
||||||
|
|
||||||
"toolCall.diff.label": "Diff",
|
"toolCall.diff.label": "Diff",
|
||||||
"toolCall.diff.label.withPath": "Diff · {path}",
|
"toolCall.diff.label.withPath": "Diff · {path}",
|
||||||
"toolCall.diff.viewMode.ariaLabel": "Modo de vista de diff",
|
"toolCall.diff.viewMode.ariaLabel": "Modo de vista de diff",
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ export const toolCallMessages = {
|
|||||||
"toolCall.header.copyTitle": "Copy tool call title",
|
"toolCall.header.copyTitle": "Copy tool call title",
|
||||||
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
||||||
|
|
||||||
|
"toolCall.header.showInputTitle": "Show tool call input",
|
||||||
|
"toolCall.header.showInputAriaLabel": "Show tool call input",
|
||||||
|
"toolCall.header.hideInputTitle": "Hide tool call input",
|
||||||
|
"toolCall.header.hideInputAriaLabel": "Hide tool call input",
|
||||||
|
|
||||||
"toolCall.diff.label": "Diff",
|
"toolCall.diff.label": "Diff",
|
||||||
"toolCall.diff.label.withPath": "Diff · {path}",
|
"toolCall.diff.label.withPath": "Diff · {path}",
|
||||||
"toolCall.diff.viewMode.ariaLabel": "Mode d'affichage du diff",
|
"toolCall.diff.viewMode.ariaLabel": "Mode d'affichage du diff",
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ export const toolCallMessages = {
|
|||||||
"toolCall.header.copyTitle": "Copy tool call title",
|
"toolCall.header.copyTitle": "Copy tool call title",
|
||||||
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
||||||
|
|
||||||
|
"toolCall.header.showInputTitle": "Show tool call input",
|
||||||
|
"toolCall.header.showInputAriaLabel": "Show tool call input",
|
||||||
|
"toolCall.header.hideInputTitle": "Hide tool call input",
|
||||||
|
"toolCall.header.hideInputAriaLabel": "Hide tool call input",
|
||||||
|
|
||||||
"toolCall.diff.label": "Diff",
|
"toolCall.diff.label": "Diff",
|
||||||
"toolCall.diff.label.withPath": "Diff · {path}",
|
"toolCall.diff.label.withPath": "Diff · {path}",
|
||||||
"toolCall.diff.viewMode.ariaLabel": "diff 表示モード",
|
"toolCall.diff.viewMode.ariaLabel": "diff 表示モード",
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ export const toolCallMessages = {
|
|||||||
"toolCall.header.copyTitle": "Copy tool call title",
|
"toolCall.header.copyTitle": "Copy tool call title",
|
||||||
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
||||||
|
|
||||||
|
"toolCall.header.showInputTitle": "Show tool call input",
|
||||||
|
"toolCall.header.showInputAriaLabel": "Show tool call input",
|
||||||
|
"toolCall.header.hideInputTitle": "Hide tool call input",
|
||||||
|
"toolCall.header.hideInputAriaLabel": "Hide tool call input",
|
||||||
|
|
||||||
"toolCall.diff.label": "Diff",
|
"toolCall.diff.label": "Diff",
|
||||||
"toolCall.diff.label.withPath": "Diff · {path}",
|
"toolCall.diff.label.withPath": "Diff · {path}",
|
||||||
"toolCall.diff.viewMode.ariaLabel": "Режим просмотра diff",
|
"toolCall.diff.viewMode.ariaLabel": "Режим просмотра diff",
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ export const toolCallMessages = {
|
|||||||
"toolCall.header.copyTitle": "Copy tool call title",
|
"toolCall.header.copyTitle": "Copy tool call title",
|
||||||
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
||||||
|
|
||||||
|
"toolCall.header.showInputTitle": "Show tool call input",
|
||||||
|
"toolCall.header.showInputAriaLabel": "Show tool call input",
|
||||||
|
"toolCall.header.hideInputTitle": "Hide tool call input",
|
||||||
|
"toolCall.header.hideInputAriaLabel": "Hide tool call input",
|
||||||
|
|
||||||
"toolCall.diff.label": "Diff",
|
"toolCall.diff.label": "Diff",
|
||||||
"toolCall.diff.label.withPath": "Diff · {path}",
|
"toolCall.diff.label.withPath": "Diff · {path}",
|
||||||
"toolCall.diff.viewMode.ariaLabel": "Diff 视图模式",
|
"toolCall.diff.viewMode.ariaLabel": "Diff 视图模式",
|
||||||
|
|||||||
@@ -127,11 +127,30 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tool-call-header-input {
|
||||||
|
@apply inline-flex items-center justify-center;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
border-radius: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.tool-call-header-copy:hover {
|
.tool-call-header-copy:hover {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tool-call-header-input:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-call-header-input[aria-pressed="true"] {
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
.tool-call-header-status {
|
.tool-call-header-status {
|
||||||
@apply inline-flex items-center justify-center;
|
@apply inline-flex items-center justify-center;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
|
|||||||
Reference in New Issue
Block a user