feat: render LSP tool output in chat
Adds expandable LSP tool rows with scan icon and stable file path display Adds formatted/raw JSON output toggle and copy action Improves compact LSP input formatting
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"lsp": {
|
||||
"tailwindcss": {
|
||||
"command": ["tailwindcss-language-server", "--stdio"],
|
||||
"extensions": [".ts", ".tsx", ".js", ".jsx", ".css", ".html"]
|
||||
},
|
||||
"css": {
|
||||
"command": ["vscode-css-language-server", "--stdio"],
|
||||
"extensions": [".css", ".scss", ".less"]
|
||||
},
|
||||
"html": {
|
||||
"command": ["vscode-html-language-server", "--stdio"],
|
||||
"extensions": [".html"]
|
||||
},
|
||||
"json": {
|
||||
"command": ["vscode-json-language-server", "--stdio"],
|
||||
"extensions": [".json", ".jsonc"]
|
||||
},
|
||||
"mdx": {
|
||||
"command": ["mdx-language-server", "--stdio"],
|
||||
"extensions": [".mdx"]
|
||||
},
|
||||
"marksman": {
|
||||
"command": ["marksman", "server"],
|
||||
"extensions": [".md"]
|
||||
},
|
||||
"dockerfile": {
|
||||
"command": ["docker-langserver", "--stdio"],
|
||||
"extensions": ["Dockerfile", ".dockerfile"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2022", "DOM"],
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"moduleDetection": "force",
|
||||
"allowJs": true,
|
||||
"checkJs": false,
|
||||
"resolveJsonModule": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"types": ["node", "electron"]
|
||||
},
|
||||
"include": ["*.mjs", "*.cjs", "scripts/**/*.mjs", "scripts/**/*.cjs"]
|
||||
}
|
||||
@@ -20,8 +20,11 @@ import { opencodeClient } from '@/lib/opencode/client';
|
||||
import { isVSCodeRuntime } from '@/lib/desktop';
|
||||
import { sessionEvents } from '@/lib/sessionEvents';
|
||||
import { ScrollShadow } from '@/components/ui/ScrollShadow';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { toast } from '@/components/ui';
|
||||
import { Text } from '@/components/ui/text';
|
||||
import { FileTypeIcon } from '@/components/icons/FileTypeIcon';
|
||||
import { copyTextToClipboard } from '@/lib/clipboard';
|
||||
import type { ContentChangeReason } from '@/hooks/useChatAutoFollow';
|
||||
import type { ToolPopupContent } from '../types';
|
||||
import { ensurePierreThemeRegistered } from '@/lib/shiki/appThemeRegistry';
|
||||
@@ -665,9 +668,49 @@ const getToolDescriptionPath = (part: ToolPartType, state: ToolStateUnion, curre
|
||||
}
|
||||
}
|
||||
|
||||
if (part.tool === 'lsp' && input) {
|
||||
const filePath = input?.filePath || input?.file_path || input?.path;
|
||||
if (typeof filePath === 'string') {
|
||||
return getRelativePath(filePath, currentDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const getLspToolDescription = (input: Record<string, unknown> | undefined, currentDirectory: string): string => {
|
||||
if (!input) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const operation = typeof input.operation === 'string' ? input.operation : 'lsp';
|
||||
if (operation === 'workspaceSymbol') {
|
||||
const query = typeof input.query === 'string' && input.query.trim().length > 0
|
||||
? ` "${input.query.trim()}"`
|
||||
: '';
|
||||
return `${operation}${query}`;
|
||||
}
|
||||
|
||||
const filePath = typeof input.filePath === 'string'
|
||||
? input.filePath
|
||||
: typeof input.file_path === 'string'
|
||||
? input.file_path
|
||||
: typeof input.path === 'string'
|
||||
? input.path
|
||||
: '';
|
||||
const displayPath = filePath ? getRelativePath(filePath, currentDirectory) : '';
|
||||
|
||||
if (operation === 'documentSymbol') {
|
||||
return displayPath ? `${operation} ${displayPath}` : operation;
|
||||
}
|
||||
|
||||
const line = typeof input.line === 'number' && Number.isFinite(input.line) ? Math.trunc(input.line) : undefined;
|
||||
const character = typeof input.character === 'number' && Number.isFinite(input.character) ? Math.trunc(input.character) : undefined;
|
||||
const position = line !== undefined && character !== undefined ? `:${line}:${character}` : '';
|
||||
|
||||
return displayPath ? `${operation} ${displayPath}${position}` : operation;
|
||||
};
|
||||
|
||||
const getToolDescription = (part: ToolPartType, state: ToolStateUnion, currentDirectory: string): string => {
|
||||
const stateWithData = state as ToolStateWithMetadata;
|
||||
const metadata = stateWithData.metadata;
|
||||
@@ -701,6 +744,10 @@ const getToolDescription = (part: ToolPartType, state: ToolStateUnion, currentDi
|
||||
return input.description.substring(0, 80);
|
||||
}
|
||||
|
||||
if (part.tool === 'lsp') {
|
||||
return getLspToolDescription(input, currentDirectory);
|
||||
}
|
||||
|
||||
const desc = input?.description || metadata?.description || ('title' in state && state.title) || '';
|
||||
return typeof desc === 'string' ? desc : '';
|
||||
};
|
||||
@@ -768,18 +815,83 @@ const ToolScrollableTextOutput: React.FC<{
|
||||
input: Record<string, unknown> | undefined;
|
||||
syntaxTheme: { [key: string]: React.CSSProperties };
|
||||
}> = ({ output, part, metadata, input, syntaxTheme }) => {
|
||||
const { t } = useI18n();
|
||||
const renderedOutput = getToolOutputText(output, part, metadata);
|
||||
const outputLanguage = getToolOutputLanguage(output, part, metadata, input);
|
||||
const jsonResult = React.useMemo(() => tryParseJsonOutput(renderedOutput), [renderedOutput]);
|
||||
const [jsonViewMode, setJsonViewMode] = React.useState<'formatted' | 'raw'>('formatted');
|
||||
const [copiedJson, setCopiedJson] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
setJsonViewMode('formatted');
|
||||
setCopiedJson(false);
|
||||
}, [renderedOutput]);
|
||||
|
||||
const handleToggleJsonView = React.useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
event.stopPropagation();
|
||||
setJsonViewMode((prev) => prev === 'formatted' ? 'raw' : 'formatted');
|
||||
}, []);
|
||||
|
||||
const handleCopyOutput = React.useCallback(async (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
event.stopPropagation();
|
||||
const result = await copyTextToClipboard(renderedOutput);
|
||||
if (!result.ok) {
|
||||
toast.error(t('chat.toolPart.copyOutputFailed'));
|
||||
return;
|
||||
}
|
||||
setCopiedJson(true);
|
||||
if (typeof window !== 'undefined') {
|
||||
window.setTimeout(() => setCopiedJson(false), 1200);
|
||||
}
|
||||
}, [renderedOutput, t]);
|
||||
|
||||
if (jsonResult.isJson) {
|
||||
return (
|
||||
<div className="tool-output-surface p-2 rounded-xl w-full min-w-0">
|
||||
<JsonTreeViewer
|
||||
data={jsonResult.data}
|
||||
initiallyExpandedDepth={1}
|
||||
maxHeight="400px"
|
||||
/>
|
||||
<div className="tool-output-surface relative p-2 rounded-xl w-full min-w-0">
|
||||
<div className="absolute right-2 top-2 z-10 flex items-center gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-6 w-6 rounded-md bg-[var(--surface-elevated)]/80 text-muted-foreground hover:text-foreground"
|
||||
onClick={handleToggleJsonView}
|
||||
onPointerDown={(event) => event.stopPropagation()}
|
||||
aria-label={jsonViewMode === 'formatted' ? t('chat.toolPart.showRawJson') : t('chat.toolPart.showFormattedJson')}
|
||||
title={jsonViewMode === 'formatted' ? t('chat.toolPart.showRawJson') : t('chat.toolPart.showFormattedJson')}
|
||||
>
|
||||
<Icon name={jsonViewMode === 'formatted' ? 'code-box' : 'list-check-2'} className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-6 w-6 rounded-md bg-[var(--surface-elevated)]/80 text-muted-foreground hover:text-foreground"
|
||||
onClick={handleCopyOutput}
|
||||
onPointerDown={(event) => event.stopPropagation()}
|
||||
aria-label={copiedJson ? t('chat.toolPart.copiedOutput') : t('chat.toolPart.copyOutput')}
|
||||
title={copiedJson ? t('chat.toolPart.copiedOutput') : t('chat.toolPart.copyOutput')}
|
||||
>
|
||||
<Icon name={copiedJson ? 'check' : 'file-copy'} className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
{jsonViewMode === 'formatted' ? (
|
||||
<JsonTreeViewer
|
||||
data={jsonResult.data}
|
||||
initiallyExpandedDepth={1}
|
||||
maxHeight="400px"
|
||||
/>
|
||||
) : (
|
||||
<div className="typography-code pr-12 text-muted-foreground/90">
|
||||
<SyntaxHighlighter
|
||||
style={syntaxTheme}
|
||||
language="json"
|
||||
PreTag="div"
|
||||
customStyle={TOOL_COLLAPSED_CUSTOM_STYLE}
|
||||
codeTagProps={CODE_TAG_PROPS}
|
||||
wrapLongLines
|
||||
>
|
||||
{renderedOutput}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2461,6 +2573,9 @@ const ToolPartContent: React.FC<ToolPartProps> = ({
|
||||
if (normalizedPartTool === 'apply_patch') {
|
||||
return null;
|
||||
}
|
||||
if (normalizedPartTool === 'lsp') {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
descriptionPath
|
||||
&& (normalizedPartTool === 'apply_patch' || normalizedPartTool === 'edit' || normalizedPartTool === 'multiedit' || normalizedPartTool === 'write')
|
||||
@@ -2477,7 +2592,6 @@ const ToolPartContent: React.FC<ToolPartProps> = ({
|
||||
}
|
||||
return null;
|
||||
}, [descriptionPath, normalizedPartTool, stateWithData, input]);
|
||||
|
||||
const runtime = React.useContext(RuntimeAPIContext);
|
||||
|
||||
const handleMainClick = (e: { stopPropagation: () => void }) => {
|
||||
@@ -2505,6 +2619,10 @@ const ToolPartContent: React.FC<ToolPartProps> = ({
|
||||
}
|
||||
} else if (['write', 'create', 'file_write'].includes(part.tool)) {
|
||||
filePath = input?.filePath || input?.file_path || input?.path || metadata?.filePath || metadata?.file_path || metadata?.path;
|
||||
} else if (part.tool === 'lsp') {
|
||||
filePath = input?.filePath || input?.file_path || input?.path;
|
||||
const line = input?.line;
|
||||
targetLine = typeof line === 'number' && Number.isFinite(line) ? Math.trunc(line) : undefined;
|
||||
}
|
||||
|
||||
if (typeof filePath === 'string') {
|
||||
@@ -2632,7 +2750,10 @@ const ToolPartContent: React.FC<ToolPartProps> = ({
|
||||
{justificationText}
|
||||
</span>
|
||||
)}
|
||||
{!justificationText && description && (
|
||||
{!justificationText && normalizedPartTool === 'lsp' && descriptionPath ? (
|
||||
renderAnimatedPathWithIcon(descriptionPath, animateTailText, false, showToolFileIcons)
|
||||
) : null}
|
||||
{!justificationText && normalizedPartTool !== 'lsp' && description && (
|
||||
descriptionPath && description === descriptionPath ? (
|
||||
renderAnimatedPathWithIcon(descriptionPath, animateTailText, false, showToolFileIcons)
|
||||
) : (
|
||||
|
||||
@@ -56,6 +56,9 @@ export const getToolIcon = (toolName: string) => {
|
||||
if (tool === 'question') {
|
||||
return <Icon name="survey" className={iconClass} />;
|
||||
}
|
||||
if (tool === 'lsp') {
|
||||
return <Icon name="scan-2" className={iconClass} />;
|
||||
}
|
||||
if (tool === 'plan_enter') {
|
||||
return <Icon name="file-list-2" className={iconClass} />;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ const EXPANDABLE_TOOL_NAMES = new Set<string>([
|
||||
'edit', 'multiedit', 'apply_patch', 'str_replace', 'str_replace_based_edit_tool',
|
||||
'bash', 'shell', 'cmd', 'terminal',
|
||||
'write', 'create', 'file_write',
|
||||
'question', 'task',
|
||||
'question', 'task', 'lsp',
|
||||
]);
|
||||
|
||||
const STANDALONE_TOOL_NAMES = new Set<string>(['task']);
|
||||
|
||||
@@ -156,6 +156,7 @@ export const iconSpriteData = {
|
||||
"macbook": `<path d="M4 5V16H20V5H4ZM2 4.00748C2 3.45107 2.45531 3 2.9918 3H21.0082C21.556 3 22 3.44892 22 4.00748V18H2V4.00748ZM1 19H23V21H1V19Z" fill="currentColor"/>`,
|
||||
"menu-2": `<path d="M3 4H21V6H3V4ZM3 11H15V13H3V11ZM3 18H21V20H3V18Z" fill="currentColor"/>`,
|
||||
"menu-fold-2": `<path d="M4.40347 3.90332L2.98926 5.31753L6.17124 8.49951L2.98926 11.6815L4.40347 13.0957L8.99967 8.49951L4.40347 3.90332ZM20.9997 19.9995V17.9995H2.99967V19.9995H20.9997ZM20.9997 12.9995V10.9995H11.9997V12.9995H20.9997ZM20.9997 5.99951V3.99951H11.9997V5.99951H20.9997Z" fill="currentColor"/>`,
|
||||
"menu": `<path d="M3 4H21V6H3V4ZM3 11H21V13H3V11ZM3 18H21V20H3V18Z" fill="currentColor"/>`,
|
||||
"menu-search": `<path d="M15.5 5C13.567 5 12 6.567 12 8.5C12 10.433 13.567 12 15.5 12C17.433 12 19 10.433 19 8.5C19 6.567 17.433 5 15.5 5ZM10 8.5C10 5.46243 12.4624 3 15.5 3C18.5376 3 21 5.46243 21 8.5C21 9.6575 20.6424 10.7315 20.0317 11.6175L22.7071 14.2929L21.2929 15.7071L18.6175 13.0317C17.7315 13.6424 16.6575 14 15.5 14C12.4624 14 10 11.5376 10 8.5ZM3 4H8V6H3V4ZM3 11H8V13H3V11ZM21 18V20H3V18H21Z" fill="currentColor"/>`,
|
||||
"mic": `<path d="M11.9998 3C10.3429 3 8.99976 4.34315 8.99976 6V10C8.99976 11.6569 10.3429 13 11.9998 13C13.6566 13 14.9998 11.6569 14.9998 10V6C14.9998 4.34315 13.6566 3 11.9998 3ZM11.9998 1C14.7612 1 16.9998 3.23858 16.9998 6V10C16.9998 12.7614 14.7612 15 11.9998 15C9.23833 15 6.99976 12.7614 6.99976 10V6C6.99976 3.23858 9.23833 1 11.9998 1ZM3.05469 11H5.07065C5.55588 14.3923 8.47329 17 11.9998 17C15.5262 17 18.4436 14.3923 18.9289 11H20.9448C20.4837 15.1716 17.1714 18.4839 12.9998 18.9451V23H10.9998V18.9451C6.82814 18.4839 3.51584 15.1716 3.05469 11Z" fill="currentColor"/>`,
|
||||
"mic-off": `<path d="M16.4249 17.839L21.1925 22.6066L22.6068 21.1924L2.80777 1.3934L1.39355 2.80761L7.00016 8.41421V10C7.00016 12.7614 9.23873 15 12.0002 15C12.4825 15 12.9489 14.9317 13.3902 14.8042L14.9404 16.3544C14.0464 16.7688 13.0503 17 12.0002 17C8.47368 17 5.55627 14.3923 5.07105 11H3.05509C3.51623 15.1716 6.82854 18.4839 11.0002 18.9451V23H13.0002V18.9451C14.2341 18.8087 15.3929 18.4228 16.4249 17.839ZM11.5528 12.9669C10.2541 12.7727 9.22745 11.7461 9.03328 10.4473L11.5528 12.9669ZM19.3747 15.1604L17.9323 13.7179C18.4407 12.9084 18.788 11.9874 18.9293 11H20.9452C20.7754 12.5366 20.2187 13.9565 19.3747 15.1604ZM16.4658 12.2514L14.9173 10.703C14.9715 10.4775 15.0002 10.2421 15.0002 10V6C15.0002 4.34315 13.657 3 12.0002 3C10.7059 3 9.6031 3.81956 9.18237 4.96802L7.68575 3.47139C8.55427 1.99268 10.1613 1 12.0002 1C14.7616 1 17.0002 3.23858 17.0002 6V10C17.0002 10.8099 16.8076 11.5748 16.4658 12.2514Z" fill="currentColor"/>`,
|
||||
@@ -187,6 +188,7 @@ export const iconSpriteData = {
|
||||
"rocket": `<path d="M4.99958 12.9999C4.99958 7.91198 7.90222 3.5636 11.9996 1.81799C16.0969 3.5636 18.9996 7.91198 18.9996 12.9999C18.9996 13.8229 18.9236 14.6264 18.779 15.4027L20.7194 17.2353C20.8845 17.3913 20.9238 17.6389 20.815 17.8383L18.3196 22.4133C18.1873 22.6557 17.8836 22.7451 17.6412 22.6128C17.5993 22.59 17.5608 22.5612 17.5271 22.5274L15.2925 20.2928C15.1049 20.1053 14.8506 19.9999 14.5854 19.9999H9.41379C9.14857 19.9999 8.89422 20.1053 8.70668 20.2928L6.47209 22.5274C6.27683 22.7227 5.96025 22.7227 5.76498 22.5274C5.73122 22.4937 5.70246 22.4552 5.67959 22.4133L3.18412 17.8383C3.07537 17.6389 3.11464 17.3913 3.27975 17.2353L5.22014 15.4027C5.07551 14.6264 4.99958 13.8229 4.99958 12.9999ZM6.47542 19.6957L7.29247 18.8786C7.85508 18.316 8.61814 17.9999 9.41379 17.9999H14.5854C15.381 17.9999 16.1441 18.316 16.7067 18.8786L17.5237 19.6957L18.5056 17.8955L17.4058 16.8568C16.9117 16.3901 16.6884 15.7045 16.8128 15.0364C16.9366 14.3722 16.9996 13.6911 16.9996 12.9999C16.9996 9.13037 15.0045 5.69965 11.9996 4.04033C8.99462 5.69965 6.99958 9.13037 6.99958 12.9999C6.99958 13.6911 7.06255 14.3722 7.18631 15.0364C7.31078 15.7045 7.08746 16.3901 6.59338 16.8568L5.49353 17.8955L6.47542 19.6957ZM11.9996 12.9999C10.895 12.9999 9.99958 12.1045 9.99958 10.9999C9.99958 9.89537 10.895 8.99994 11.9996 8.99994C13.1041 8.99994 13.9996 9.89537 13.9996 10.9999C13.9996 12.1045 13.1041 12.9999 11.9996 12.9999Z" fill="currentColor"/>`,
|
||||
"save-3": `<path d="M18 19H19V6.82843L17.1716 5H16V9H7V5H5V19H6V12H18V19ZM4 3H18L20.7071 5.70711C20.8946 5.89464 21 6.149 21 6.41421V20C21 20.5523 20.5523 21 20 21H4C3.44772 21 3 20.5523 3 20V4C3 3.44772 3.44772 3 4 3ZM8 14V19H16V14H8Z" fill="currentColor"/>`,
|
||||
"scales-3": `<path d="M12.9985 2L12.9979 3.278L17.9985 4.94591L21.631 3.73509L22.2634 5.63246L19.2319 6.643L22.3272 15.1549C21.2353 16.2921 19.6996 17 17.9985 17C16.2975 17 14.7618 16.2921 13.6699 15.1549L16.7639 6.643L12.9979 5.387V19H16.9985V21H6.99854V19H10.9979V5.387L7.23192 6.643L10.3272 15.1549C9.23528 16.2921 7.69957 17 5.99854 17C4.2975 17 2.76179 16.2921 1.66992 15.1549L4.76392 6.643L1.73363 5.63246L2.36608 3.73509L5.99854 4.94591L10.9979 3.278L10.9985 2H12.9985ZM17.9985 9.10267L16.04 14.4892C16.628 14.8201 17.2979 15 17.9985 15C18.6992 15 19.3691 14.8201 19.957 14.4892L17.9985 9.10267ZM5.99854 9.10267L4.04004 14.4892C4.62795 14.8201 5.29792 15 5.99854 15C6.69916 15 7.36912 14.8201 7.95703 14.4892L5.99854 9.10267Z" fill="currentColor"/>`,
|
||||
"scan-2": `<path d="M5.67127 4.25705L13.4142 12L12 13.4142L8.55382 9.96803C8.20193 10.5635 8 11.2582 8 12C8 14.2091 9.79086 16 12 16C14.2091 16 16 14.2091 16 12C16 9.87494 14.3429 8.13693 12.2503 8.00771L10.4459 6.20323C10.9416 6.07067 11.4625 6 12 6C15.3137 6 18 8.68629 18 12C18 15.3137 15.3137 18 12 18C8.68629 18 6 15.3137 6 12C6 10.7042 6.41079 9.50428 7.10925 8.52347L5.68014 7.09436C4.62708 8.44904 4 10.1513 4 12C4 16.4183 7.58172 20 12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C10.8915 4 9.83557 4.22547 8.8757 4.63306L7.37443 3.13179C8.75768 2.40883 10.3311 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 8.87842 3.43029 6.09091 5.67127 4.25705Z" fill="currentColor"/>`,
|
||||
"scissors": `<path d="M9.44618 8.02867L12 10.5825L18.7279 3.85457C19.509 3.07352 20.7753 3.07352 21.5563 3.85457L9.44618 15.9647C9.79807 16.5603 10 17.2549 10 17.9967C10 20.2058 8.20914 21.9967 6 21.9967C3.79086 21.9967 2 20.2058 2 17.9967C2 15.7876 3.79086 13.9967 6 13.9967C6.74181 13.9967 7.43645 14.1986 8.03197 14.5505L10.5858 11.9967L8.03197 9.44289C7.43645 9.79478 6.74181 9.9967 6 9.9967C3.79086 9.9967 2 8.20584 2 5.9967C2 3.78756 3.79086 1.9967 6 1.9967C8.20914 1.9967 10 3.78756 10 5.9967C10 6.73851 9.79807 7.43316 9.44618 8.02867ZM14.8255 13.408L21.5563 20.1388C20.7753 20.9199 19.509 20.9199 18.7279 20.1388L13.4113 14.8222L14.8255 13.408ZM7.41421 16.5825C7.05228 16.2206 6.55228 15.9967 6 15.9967C4.89543 15.9967 4 16.8921 4 17.9967C4 19.1013 4.89543 19.9967 6 19.9967C7.10457 19.9967 8 19.1013 8 17.9967C8 17.4444 7.77614 16.9444 7.41421 16.5825ZM7.41421 7.41092C7.77614 7.04899 8 6.54899 8 5.9967C8 4.89213 7.10457 3.9967 6 3.9967C4.89543 3.9967 4 4.89213 4 5.9967C4 7.10127 4.89543 7.9967 6 7.9967C6.55228 7.9967 7.05228 7.77285 7.41421 7.41092Z" fill="currentColor"/>`,
|
||||
"search-eye": `<path d="M18.031 16.6168L22.3137 20.8995L20.8995 22.3137L16.6168 18.031C15.0769 19.263 13.124 20 11 20C6.032 20 2 15.968 2 11C2 6.032 6.032 2 11 2C15.968 2 20 6.032 20 11C20 13.124 19.263 15.0769 18.031 16.6168ZM16.0247 15.8748C17.2475 14.6146 18 12.8956 18 11C18 7.1325 14.8675 4 11 4C7.1325 4 4 7.1325 4 11C4 14.8675 7.1325 18 11 18C12.8956 18 14.6146 17.2475 15.8748 16.0247L16.0247 15.8748ZM12.1779 7.17624C11.4834 7.48982 11 8.18846 11 9C11 10.1046 11.8954 11 13 11C13.8115 11 14.5102 10.5166 14.8238 9.82212C14.9383 10.1945 15 10.59 15 11C15 13.2091 13.2091 15 11 15C8.79086 15 7 13.2091 7 11C7 8.79086 8.79086 7 11 7C11.41 7 11.8055 7.06167 12.1779 7.17624Z" fill="currentColor"/>`,
|
||||
"search": `<path d="M18.031 16.6168L22.3137 20.8995L20.8995 22.3137L16.6168 18.031C15.0769 19.263 13.124 20 11 20C6.032 20 2 15.968 2 11C2 6.032 6.032 2 11 2C15.968 2 20 6.032 20 11C20 13.124 19.263 15.0769 18.031 16.6168ZM16.0247 15.8748C17.2475 14.6146 18 12.8956 18 11C18 7.1325 14.8675 4 11 4C7.1325 4 4 7.1325 4 11C4 14.8675 7.1325 18 11 18C12.8956 18 14.6146 17.2475 15.8748 16.0247L16.0247 15.8748Z" fill="currentColor"/>`,
|
||||
|
||||
@@ -1826,6 +1826,11 @@ export const dict = {
|
||||
'chat.toolPart.awaitingResponse': 'Awaiting response...',
|
||||
'chat.toolPart.noOutputProduced': 'No output produced',
|
||||
'chat.toolPart.output': 'Output',
|
||||
'chat.toolPart.showRawJson': 'Show raw JSON',
|
||||
'chat.toolPart.showFormattedJson': 'Show formatted JSON',
|
||||
'chat.toolPart.copyOutput': 'Copy output',
|
||||
'chat.toolPart.copiedOutput': 'Copied output',
|
||||
'chat.toolPart.copyOutputFailed': 'Failed to copy output',
|
||||
'chat.toolPart.openSubtask': 'Open {type} subtask',
|
||||
'chat.todo.total': 'Total',
|
||||
'chat.todo.inProgress': 'In Progress',
|
||||
|
||||
@@ -1792,6 +1792,11 @@ export const dict: Record<I18nKey, string> = {
|
||||
"chat.toolPart.awaitingResponse": "Esperando respuesta...",
|
||||
"chat.toolPart.noOutputProduced": "No se produjo ninguna salida",
|
||||
"chat.toolPart.output": "Salida",
|
||||
"chat.toolPart.showRawJson": "Mostrar JSON sin formato",
|
||||
"chat.toolPart.showFormattedJson": "Mostrar JSON formateado",
|
||||
"chat.toolPart.copyOutput": "Copiar salida",
|
||||
"chat.toolPart.copiedOutput": "Salida copiada",
|
||||
"chat.toolPart.copyOutputFailed": "No se pudo copiar la salida",
|
||||
"chat.toolPart.openSubtask": "Abrir subtarea {type}",
|
||||
"chat.todo.total": "Total",
|
||||
"chat.todo.inProgress": "En progreso",
|
||||
|
||||
@@ -1826,6 +1826,11 @@ export const dict: Record<I18nKey, string> = {
|
||||
'chat.toolPart.awaitingResponse': '응답 대기 중…',
|
||||
'chat.toolPart.noOutputProduced': '출력 없음',
|
||||
'chat.toolPart.output': '출력',
|
||||
'chat.toolPart.showRawJson': '원시 JSON 표시',
|
||||
'chat.toolPart.showFormattedJson': '형식화된 JSON 표시',
|
||||
'chat.toolPart.copyOutput': '출력 복사',
|
||||
'chat.toolPart.copiedOutput': '출력 복사됨',
|
||||
'chat.toolPart.copyOutputFailed': '출력을 복사하지 못했습니다',
|
||||
'chat.toolPart.openSubtask': '{type} 하위 작업 열기',
|
||||
'chat.todo.total': '전체',
|
||||
'chat.todo.inProgress': '진행 중',
|
||||
|
||||
@@ -1199,6 +1199,11 @@ export const dict: Record<I18nKey, string> = {
|
||||
'chat.toolPart.noOutputProduced': 'Brak wygenerowanego wyniku',
|
||||
'chat.toolPart.openSubtask': 'Otwórz podzadanie typu {type}',
|
||||
'chat.toolPart.output': 'Wyjście',
|
||||
'chat.toolPart.showRawJson': 'Pokaż surowy JSON',
|
||||
'chat.toolPart.showFormattedJson': 'Pokaż sformatowany JSON',
|
||||
'chat.toolPart.copyOutput': 'Kopiuj wyjście',
|
||||
'chat.toolPart.copiedOutput': 'Skopiowano wyjście',
|
||||
'chat.toolPart.copyOutputFailed': 'Nie udało się skopiować wyjścia',
|
||||
'commandPalette.description': 'Szukaj plików, sesji i poleceń.',
|
||||
'commandPalette.empty.noResults': 'Nie znaleziono wyników.',
|
||||
'commandPalette.empty.searchingFiles': 'Wyszukiwanie plików...',
|
||||
|
||||
@@ -1792,6 +1792,11 @@ export const dict: Record<I18nKey, string> = {
|
||||
"chat.toolPart.awaitingResponse": "Aguardando resposta...",
|
||||
"chat.toolPart.noOutputProduced": "Nenhuma saída produzida",
|
||||
"chat.toolPart.output": "Saída",
|
||||
"chat.toolPart.showRawJson": "Mostrar JSON bruto",
|
||||
"chat.toolPart.showFormattedJson": "Mostrar JSON formatado",
|
||||
"chat.toolPart.copyOutput": "Copiar saída",
|
||||
"chat.toolPart.copiedOutput": "Saída copiada",
|
||||
"chat.toolPart.copyOutputFailed": "Falha ao copiar saída",
|
||||
"chat.toolPart.openSubtask": "Abrir subtarefa {type}",
|
||||
"chat.todo.total": "Total",
|
||||
"chat.todo.inProgress": "Em andamento",
|
||||
|
||||
@@ -1792,6 +1792,11 @@ export const dict: Record<I18nKey, string> = {
|
||||
"chat.toolPart.awaitingResponse": "Очікування відповіді...",
|
||||
"chat.toolPart.noOutputProduced": "Вивід відсутній",
|
||||
"chat.toolPart.output": "Вивід",
|
||||
"chat.toolPart.showRawJson": "Показати сирий JSON",
|
||||
"chat.toolPart.showFormattedJson": "Показати форматований JSON",
|
||||
"chat.toolPart.copyOutput": "Скопіювати вивід",
|
||||
"chat.toolPart.copiedOutput": "Вивід скопійовано",
|
||||
"chat.toolPart.copyOutputFailed": "Не вдалося скопіювати вивід",
|
||||
"chat.toolPart.openSubtask": "Відкрити підзавдання {type}",
|
||||
"chat.todo.total": "Усього",
|
||||
"chat.todo.inProgress": "В роботі",
|
||||
|
||||
@@ -1792,6 +1792,11 @@ export const dict: Record<I18nKey, string> = {
|
||||
'chat.toolPart.awaitingResponse': '等待响应...',
|
||||
'chat.toolPart.noOutputProduced': '未产生输出',
|
||||
'chat.toolPart.output': '输出',
|
||||
'chat.toolPart.showRawJson': '显示原始 JSON',
|
||||
'chat.toolPart.showFormattedJson': '显示格式化 JSON',
|
||||
'chat.toolPart.copyOutput': '复制输出',
|
||||
'chat.toolPart.copiedOutput': '已复制输出',
|
||||
'chat.toolPart.copyOutputFailed': '复制输出失败',
|
||||
'chat.toolPart.openSubtask': '打开{type}子任务',
|
||||
'chat.todo.total': '总计',
|
||||
'chat.todo.inProgress': '进行中',
|
||||
|
||||
@@ -1796,6 +1796,11 @@ export const dict: Record<I18nKey, string> = {
|
||||
'chat.toolPart.awaitingResponse': '等待回應...',
|
||||
'chat.toolPart.noOutputProduced': '未產生輸出',
|
||||
'chat.toolPart.output': '輸出',
|
||||
'chat.toolPart.showRawJson': '顯示原始 JSON',
|
||||
'chat.toolPart.showFormattedJson': '顯示格式化 JSON',
|
||||
'chat.toolPart.copyOutput': '複製輸出',
|
||||
'chat.toolPart.copiedOutput': '已複製輸出',
|
||||
'chat.toolPart.copyOutputFailed': '複製輸出失敗',
|
||||
'chat.toolPart.openSubtask': '開啟{type}子任務',
|
||||
'chat.todo.total': '總計',
|
||||
'chat.todo.inProgress': '進行中',
|
||||
|
||||
@@ -165,12 +165,25 @@ export const TOOL_METADATA: Record<string, ToolMetadata> = {
|
||||
{ key: 'name', label: 'Skill Name', type: 'text' }
|
||||
]
|
||||
},
|
||||
question: {
|
||||
displayName: 'Question',
|
||||
category: 'ai',
|
||||
outputLanguage: 'text',
|
||||
question: {
|
||||
displayName: 'Question',
|
||||
category: 'ai',
|
||||
outputLanguage: 'text',
|
||||
inputFields: [
|
||||
{ key: 'questions', label: 'Questions', type: 'code', language: 'json' }
|
||||
]
|
||||
},
|
||||
|
||||
lsp: {
|
||||
displayName: 'LSP',
|
||||
category: 'code',
|
||||
outputLanguage: 'json',
|
||||
inputFields: [
|
||||
{ key: 'questions', label: 'Questions', type: 'code', language: 'json' }
|
||||
{ key: 'operation', label: 'Operation', type: 'text' },
|
||||
{ key: 'filePath', label: 'File Path', type: 'file' },
|
||||
{ key: 'line', label: 'Line', type: 'text' },
|
||||
{ key: 'character', label: 'Character', type: 'text' },
|
||||
{ key: 'query', label: 'Query', type: 'text' }
|
||||
]
|
||||
},
|
||||
|
||||
@@ -702,6 +715,26 @@ export function formatToolInput(input: Record<string, unknown>, toolName: string
|
||||
if (cmd) return cmd;
|
||||
}
|
||||
|
||||
if (toolName === 'lsp') {
|
||||
const operation = getString('operation') || 'lsp';
|
||||
const filePath = getString('filePath') || getString('file_path') || getString('path');
|
||||
const line = getString('line');
|
||||
const character = getString('character');
|
||||
const query = getString('query');
|
||||
const position = line && character ? ` (Line: ${line}; Character: ${character})` : '';
|
||||
|
||||
if (operation === 'workspaceSymbol') {
|
||||
return query ? `Operation: ${operation} (Query: "${query}")` : `Operation: ${operation}`;
|
||||
}
|
||||
|
||||
const summary = `Operation: ${operation}${position}`;
|
||||
if (filePath) {
|
||||
return `${summary}\n${filePath}`;
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
if (toolName === 'task') {
|
||||
const prompt = getString('prompt');
|
||||
if (prompt) return prompt;
|
||||
|
||||
Reference in New Issue
Block a user