import type { Meta, StoryObj } from '@storybook/react'
import { InlineToolItem } from './inline-tool-item'
import type { ToolPart } from '../types/parts'
const NOW = Date.now()
// -- Fixtures --
const bashComplete: ToolPart = {
type: 'tool',
id: 'tool-bash-1',
tool: 'bash',
state: {
status: 'completed',
input: { command: 'pnpm test --run --reporter=verbose' },
output: `> test\n\n ✓ src/utils/format.test.ts (4)\n ✓ src/utils/tool-display.test.ts (11)\n\nTest Files 2 passed (2)\n Tests 15 passed (15)\n Duration 1.42s`,
time: { start: NOW - 3800, end: NOW - 2380 },
},
}
const bashRunning: ToolPart = {
type: 'tool',
id: 'tool-bash-running',
tool: 'bash',
state: {
status: 'running',
input: { command: 'pnpm build' },
time: { start: NOW - 4200 },
},
}
const bashError: ToolPart = {
type: 'tool',
id: 'tool-bash-error',
tool: 'bash',
state: {
status: 'error',
input: { command: 'pnpm test --run' },
error: 'Process exited with code 1\nTypeError: Cannot read properties of undefined (reading \'map\')\n at render (src/components/List.tsx:42:18)',
time: { start: NOW - 2100, end: NOW - 1600 },
},
}
const readFile: ToolPart = {
type: 'tool',
id: 'tool-read-1',
tool: 'read',
state: {
status: 'completed',
input: { file_path: '/home/user/project/src/components/Button.tsx' },
output: `import { cn } from '../lib/utils'\n\nexport function Button({ children, variant = 'default', ...props }) {\n return (\n \n )\n}`,
time: { start: NOW - 1200, end: NOW - 1140 },
},
}
const writeFile: ToolPart = {
type: 'tool',
id: 'tool-write-1',
tool: 'write',
state: {
status: 'completed',
input: {
file_path: '/home/user/project/src/utils/format.ts',
content: 'export function formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`\n return `${(ms / 1000).toFixed(1)}s`\n}',
},
output: 'File written successfully.',
time: { start: NOW - 900, end: NOW - 855 },
},
}
const webSearch: ToolPart = {
type: 'tool',
id: 'tool-web-1',
tool: 'web_search',
state: {
status: 'completed',
input: { query: 'vitest mock module typescript best practices 2024' },
output: JSON.stringify([
{ title: 'Vitest Mocking Guide', url: 'https://vitest.dev/guide/mocking', snippet: 'Learn how to mock modules in Vitest...' },
{ title: 'Testing Library Best Practices', url: 'https://testing-library.com/docs/', snippet: 'Avoid implementation details...' },
]),
time: { start: NOW - 2800, end: NOW - 1900 },
},
}
const grepSearch: ToolPart = {
type: 'tool',
id: 'tool-grep-1',
tool: 'grep',
state: {
status: 'completed',
input: { pattern: 'useCallback', path: 'src/' },
output: 'src/hooks/useSession.ts:14: const handleMessage = useCallback((msg) => {\nsrc/hooks/useStream.ts:22: const send = useCallback(async (text) => {\nsrc/components/Chat.tsx:88: const onSubmit = useCallback(() => {',
time: { start: NOW - 600, end: NOW - 560 },
},
}
const editFile: ToolPart = {
type: 'tool',
id: 'tool-edit-1',
tool: 'edit',
state: {
status: 'completed',
input: {
file_path: '/home/user/project/src/utils/format.ts',
old_string: 'return `${(ms / 1000).toFixed(1)}s`',
new_string: 'if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`\n return `${Math.floor(ms / 60_000)}m ${Math.floor((ms % 60_000) / 1000)}s`',
},
output: 'Edit applied.',
time: { start: NOW - 450, end: NOW - 420 },
},
}
// --
const meta: Meta = {
title: 'Run/InlineToolItem',
component: InlineToolItem,
parameters: {
layout: 'fullscreen',
backgrounds: { default: 'dark' },
},
}
export default meta
type Story = StoryObj
export const BashComplete: Story = {
args: { part: bashComplete, groupPosition: 'single' },
render: (args) => (
),
}
export const BashRunning: Story = {
args: { part: bashRunning, groupPosition: 'single' },
render: (args) => (
),
}
export const BashError: Story = {
args: { part: bashError, groupPosition: 'single' },
render: (args) => (
),
}
export const ReadFile: Story = {
args: { part: readFile, groupPosition: 'single' },
render: (args) => (
),
}
export const WriteFile: Story = {
args: { part: writeFile, groupPosition: 'single' },
render: (args) => (
),
}
export const WebSearch: Story = {
args: { part: webSearch, groupPosition: 'single' },
render: (args) => (
),
}
export const GrepSearch: Story = {
args: { part: grepSearch, groupPosition: 'single' },
render: (args) => (
),
}
export const EditFile: Story = {
args: { part: editFile, groupPosition: 'single' },
render: (args) => (
),
}
/** Three consecutive tool calls showing group position rounding. */
export const GroupedSequence: Story = {
render: () => (
),
}
export const AllStates: Story = {
render: () => (
),
}