Documentation Index
Fetch the complete documentation index at: https://docs.terminaluse.com/llms.txt
Use this file to discover all available pages before exploring further.
Architecture
The frontend uses the Vercel AI SDK’s useChat hook. API routes proxy requests to Terminal Use and stream responses back.
Setup
npm install @terminaluse/vercel-ai-sdk-provider
Creating Tasks
// Create task on first message
const response = await fetch('/api/tasks', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ agentName: AGENT_NAME, filesystemId }),
});
const task = await response.json();
setTaskId(task.id);
Sending Messages
import { useChat } from '@ai-sdk/react';
import { DefaultChatTransport } from 'ai';
const AGENT_NAME = 'my-namespace/my-agent';
// Configure transport with task context
const transport = useMemo(
() => new DefaultChatTransport({
api: '/api/chat',
body: { agentName: AGENT_NAME, taskId },
}),
[taskId]
);
const { messages, sendMessage, status } = useChat({
id: 'chat-session', // Client-generated session ID
transport,
});
// Send message with task context
await sendMessage(
{ text: inputValue },
{ body: { agentName: AGENT_NAME, taskId } }
);
Loading Message History
When resuming an existing task, fetch and display previous messages.
import { useQuery } from '@tanstack/react-query';
import { useLayoutEffect } from 'react';
function ExistingTaskChat({ taskId }: { taskId: string }) {
const { data: history, isLoading } = useQuery({
queryKey: ['taskMessages', taskId],
queryFn: async () => {
const response = await fetch(`/api/tasks/${taskId}/messages`);
return response.json();
},
});
const { messages, setMessages } = useChat({ id: taskId, transport });
// Initialize with history
useLayoutEffect(() => {
if (history) setMessages(history);
}, [history, setMessages]);
if (isLoading) return <div>Loading...</div>;
// ... render chat interface
}
Handling Message Parts
The following is a sample implementation. See the Vercel AI SDK documentation for more details on displaying UIMessage parts.
import { isTextUIPart, isReasoningUIPart, isToolUIPart } from 'ai';
import type { UIMessage, ToolUIPart } from 'ai';
function MessagePart({ part }: { part: UIMessage['parts'][number] }) {
if (isTextUIPart(part)) {
return <p>{part.text}</p>;
}
if (isReasoningUIPart(part)) {
return (
<div className="italic text-gray-600">
<span className="font-medium">Reasoning:</span> {part.text}
</div>
);
}
if (isToolUIPart(part)) {
const toolPart = part as ToolUIPart;
return (
<div className="my-2 p-3 border rounded">
<div className="font-medium">{toolPart.toolName}</div>
<pre className="text-sm">{JSON.stringify(toolPart.input, null, 2)}</pre>
{toolPart.output && (
<pre className="text-sm">{JSON.stringify(toolPart.output, null, 2)}</pre>
)}
</div>
);
}
return null;
}
Environment Variables
TERMINALUSE_API_KEY=your_api_key
TERMINALUSE_BASE_URL=https://api.terminaluse.com # Optional, defaults to production
| Variable | Required | Default | Description |
|---|
TERMINALUSE_API_KEY | Yes | — | Your API key from the platform |
TERMINALUSE_BASE_URL | No | https://api.terminaluse.com | API base URL (override for self-hosted or staging) |