# Tool

Compact, expandable AI tool calls for chat transcripts. Use variant="quiet" for a content-width task summary inside a response.

- Package: `@mielui/svelte`
- Component version: `1.2.0`
- Depends on Mielui components: _internal/utils, _internal/disclosure, spinner
- Shared utilities: hugeicons-icon, utils.cn, utils.pressable, utils.createContext, transition

## Install

~~~~sh
pnpm dlx @mielui/svelte add tool
~~~~

## API

This reference is generated at build time from the component manifest, public `index.ts`, and documentation examples below. Changes to those source files are reflected here in the published Markdown. Standard Svelte and HTML attributes accepted by the exported prop types are supported.


### Content

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Input

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| label | string \| undefined | - | No | No | Heading of the section. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| class | (string & (ClassValue \| null)) \| undefined | - | No | No | Classes added to the element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Item

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| name | string | - | Yes | No | Name of the step, such as the tool that ran. |
| detail | string \| undefined | - | No | No | What the step acted on, such as a path or query. |
| kind | "command" \| "search" \| "read" \| undefined | 'command' | No | No | Kind of step, which sets its icon. |
| class | string \| undefined | - | No | No | Classes added to the element. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |



### Output

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| label | string \| undefined | - | No | No | Heading of the section. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| class | (string & (ClassValue \| null)) \| undefined | - | No | No | Classes added to the element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Root

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| labels | ToolLabels \| undefined | - | No | No | Overrides the built-in text and accessible names. Every key is optional and English is the fallback. |
| name | string | - | Yes | No | A concise summary of the work completed by this task group. |
| state | ToolState \| undefined | 'running' | No | No | State of the run, which sets the indicator and summary. |
| variant | ToolVariant \| undefined | 'default' | No | No | A low-emphasis presentation for inline transcript details. |
| duration | string \| undefined | - | No | No | A compact summary of how long the task took, such as 6s. |
| open | boolean \| undefined | true | No | Yes | Whether the individual tool calls are visible. |
| onOpenChange | ((open: boolean) => void) \| undefined | - | No | No | Called with the new state whenever it opens or closes. |
| onOpenChangeComplete | ((open: boolean) => void) \| undefined | - | No | No | Called after the open or close animation finishes. |
| composed | boolean \| undefined | false | No | No | Render explicit Trigger and Content parts through children. |
| trigger | Snippet<[Readonly<{ open: boolean; state: ToolState; name: string; duration?: string \| undefined; }>]> \| undefined | - | No | No | Replaces the default trigger. It receives the open state, the run state, and the name. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| class | (string & (ClassValue \| null)) \| undefined | - | No | No | Classes added to the element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Trigger

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| children | Snippet<[Readonly<{ open: boolean; state: ToolState; name: string; duration?: string \| undefined; }>]> \| undefined | - | No | No | Content rendered inside. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Public types

~~~~ts
import type { DefaultProps } from '@mielui/svelte/utils';
import type { Snippet } from 'svelte';
import type { HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements';
import Root from './tool.svelte';
import Content from './tool-content.svelte';
import Input from './tool-input.svelte';
import Item from './tool-item.svelte';
import Output from './tool-output.svelte';
import Trigger from './tool-trigger.svelte';

export type ToolState = 'running' | 'complete' | 'error';
export type ToolVariant = 'default' | 'quiet';

export type ToolLabels = {
    running?: string;
    complete?: string;
    failed?: string;
    input?: string;
    output?: string;
};

export type ToolProps = {
    /**
     * Overrides the built-in text and accessible names. Every key is optional and English is the
     * fallback.
     */
    labels?: ToolLabels;
    /** A concise summary of the work completed by this task group. */
    name: string;
    /** State of the run, which sets the indicator and summary. */
    state?: ToolState;
    /** A low-emphasis presentation for inline transcript details. */
    variant?: ToolVariant;
    /** A compact summary of how long the task took, such as 6s. */
    duration?: string;
    /** Whether the individual tool calls are visible. */
    open?: boolean;
    /** Called with the new state whenever it opens or closes. */
    onOpenChange?: (open: boolean) => void;
    /** Called after the open or close animation finishes. */
    onOpenChangeComplete?: (open: boolean) => void;
    /** Render explicit Trigger and Content parts through children. */
    composed?: boolean;
    /** Replaces the default trigger. It receives the open state, the run state, and the name. */
    trigger?: Snippet<[ToolTriggerState]>;
    /** Content rendered inside. */
    children?: Snippet;
} & DefaultProps &
    Omit<HTMLAttributes<HTMLElement>, 'children'>;

export type ToolTriggerState = Readonly<{
    open: boolean;
    state: ToolState;
    name: string;
    duration?: string;
}>;

export type ToolItemProps = {
    /** Name of the step, such as the tool that ran. */
    name: string;
    /** What the step acted on, such as a path or query. */
    detail?: string;
    /** Kind of step, which sets its icon. */
    kind?: 'command' | 'search' | 'read';
} & DefaultProps;

export type ToolInputProps = {
    /** Heading of the section. */
    label?: string;
    /** Content rendered inside. */
    children?: Snippet;
} & DefaultProps &
    Omit<HTMLAttributes<HTMLDivElement>, 'children'>;

export type ToolOutputProps = {
    /** Heading of the section. */
    label?: string;
    /** Content rendered inside. */
    children?: Snippet;
} & DefaultProps &
    Omit<HTMLAttributes<HTMLDivElement>, 'children'>;

export type ToolTriggerProps = {
    /** Content rendered inside. */
    children?: Snippet<[ToolTriggerState]>;
} & Omit<HTMLButtonAttributes, 'children'>;

export type ToolContentProps = {
    /** Content rendered inside. */
    children?: Snippet;
} & Omit<HTMLAttributes<HTMLDivElement>, 'children'>;

export { Content, Input, Item, Output, Root, Trigger };
~~~~

## Examples

### Quiet

~~~~svelte
<script lang="ts">
    import * as Tool from '@mielui/svelte/components/tool';
</script>

<Tool.Root name="Searched release history" state="complete" duration="2.4s" variant="quiet">
    <Tool.Item name="Grep" detail="release notes" kind="search" />
</Tool.Root>
~~~~

### Retry

~~~~svelte
<script lang="ts">
    import { Button } from '@mielui/svelte/components/button';
    import * as Tool from '@mielui/svelte/components/tool';
    import { onDestroy } from 'svelte';

    let state = $state<Tool.ToolState>('error');
    let timer: ReturnType<typeof setTimeout> | undefined;

    const output = $derived.by(() => {
        if (state === 'error') {
            return 'The file service timed out.';
        }

        return state === 'running'
            ? 'Reading the file…'
            : 'Found 12 changes. No breaking API changes.';
    });

    function retry() {
        state = 'running';
        timer = setTimeout(() => {
            state = 'complete';
        }, 1200);
    }

    onDestroy(() => {
        clearTimeout(timer);
    });
</script>

<div class="w-full max-w-xl space-y-3">
    <Tool.Root name="Check release notes" {state}>
        <Tool.Input><code>read release-notes.md</code></Tool.Input>
        <Tool.Output>{output}</Tool.Output>
    </Tool.Root>
    <Button variant="secondary" onclick={retry} disabled={state !== 'error'}>
        Retry file read
    </Button>
</div>
~~~~

### Tool States

~~~~svelte
<script lang="ts">
    import * as Tool from '@mielui/svelte/components/tool';
    import { onMount } from 'svelte';

    let elapsedTenths = $state(0);
    let running = $state(true);
    const elapsed = $derived(`${(elapsedTenths / 10).toFixed(1)}s`);

    onMount(() => {
        const id = setInterval(() => {
            elapsedTenths += 1;

            if (elapsedTenths >= 24) {
                running = false;
                clearInterval(id);
            }
        }, 100);

        return () => {
            clearInterval(id);
        };
    });
</script>

<div class="flex w-full max-w-xl flex-col gap-3">
    <Tool.Root name="2 customer records" state="complete" duration="1.2s">
        <Tool.Item name="Grep" detail="cus_4f81" kind="search" />
        <Tool.Item name="Read" detail="refund status" kind="read" />
    </Tool.Root>
    <Tool.Root name="1 recipient" state={running ? 'running' : 'complete'} duration={elapsed}>
        <Tool.Item name="Bash" detail="validate recipient address" />
    </Tool.Root>
</div>
~~~~

For the rendered reference, visit [/docs/components/tool](/docs/components/tool).
