Skip to main content
The primary hook that powers the assistant agent. Handles action execution, documentation search, and support escalation.

Import

import { useAssistant } from "modifywithai"

Usage

const assistant = useAssistant({
    availableActions: [...],
    getContext: () => ({...}),
    onAction: (action) => {...},
})

Options

OptionTypeRequiredDefaultDescription
availableActionsActionDefinition[]YesActions the AI can perform
getContext() => objectNo() => ({})Returns current app state
onAction(action: ToolAction) => voidNoCalled when action executes
tokenEndpointstringNo/api/mwai/tokenToken generation endpoint
endUserIdstringNoAuto-generatedUser identifier
escalationMessagestringNoDefault messageCustom message when escalating to support
onError(error: Error) => voidNoError callback

Return Value

Chat State

PropertyTypeDescription
messagesMessage[]All messages in the conversation
status"ready" | "streaming" | "submitted" | "error"Current chat state
errorError | nullLast error if any

Input Handling

PropertyTypeDescription
inputstringCurrent input value
setInput(value: string) => voidUpdate input value
handleSubmit(e: FormEvent) => voidForm submit handler
sendMessage(text: string) => voidSend message programmatically

Token State

PropertyTypeDescription
isReadybooleanToken loaded and ready
tokenErrorError | nullToken fetch error
refreshToken() => Promise<void>Manually refresh token

Approval

PropertyTypeDescription
addToolApprovalResponse(toolCallId: string, approved: boolean) => voidRespond to approval request

Examples

Basic Usage

function Assistant() {
    const assistant = useAssistant({
        availableActions: [
            {
                name: "greet",
                description: "Say hello to someone",
                options: {
                    name: { type: "string", required: true },
                },
            },
        ],
        onAction: (action) => {
            if (action.name === "greet") {
                alert(`Hello, ${action.options.name}!`)
            }
        },
    })

    if (!assistant.isReady) return <div>Loading...</div>

    return (
        <form onSubmit={assistant.handleSubmit}>
            <input
                value={assistant.input}
                onChange={(e) => assistant.setInput(e.target.value)}
            />
            <button type="submit">Send</button>
        </form>
    )
}

With Context

const [todos, setTodos] = useState([])

const assistant = useAssistant({
    availableActions: [...],
    getContext: () => ({
        todos: todos.map(t => ({ id: t.id, title: t.title, done: t.done })),
        totalCount: todos.length,
        completedCount: todos.filter(t => t.done).length,
    }),
    onAction: handleAction,
})

With Custom Token Endpoint

const assistant = useAssistant({
    tokenEndpoint: "/api/my-custom-token-route",
    availableActions: [...],
    onAction: handleAction,
})

Handling Errors

const assistant = useAssistant({
    availableActions: [...],
    onAction: handleAction,
    onError: (error) => {
        console.error("Assistant error:", error)
        toast.error("Something went wrong")
    },
})

// Also check for errors in render
if (assistant.error) {
    return <div>Error: {assistant.error.message}</div>
}

Programmatic Messages

const assistant = useAssistant({...})

// Send a message without a form
function askQuestion(question: string) {
    assistant.sendMessage(question)
}

<button onClick={() => askQuestion("What can you help me with?")}>
    Get Started
</button>

Status Values

StatusDescription
readyWaiting for user input
submittedMessage sent, waiting for response
streamingReceiving streamed response
errorAn error occurred

Message Structure

interface Message {
    id: string
    role: "user" | "assistant" | "system"
    parts: MessagePart[]
    createdAt?: Date
}

type MessagePart =
    | { type: "text"; text: string }
    | { type: "tool-invocation"; toolInvocation: ToolInvocation }