chat
Version:
Unified chat abstraction for Slack, Teams, Google Chat, and Discord
228 lines (175 loc) • 8.92 kB
text/mdx
---
title: AI SDK Tools
description: Give an AI agent the ability to operate inside your workspace. Post messages, send DMs, react, edit, delete; all with built-in approval gates.
type: guide
prerequisites:
- /docs/usage
related:
- /docs/ai
- /docs/ai/to-ai-messages
- /docs/streaming
- /docs/conversation-history
---
`createChatTools` exposes Chat SDK operations as ready-to-use [AI SDK](https://ai-sdk.dev) tools so an agent can act inside the same workspaces your bot is connected to: read messages, post replies, send DMs, react, edit, delete, and manage thread subscriptions across every adapter you've registered.
Write operations require user approval out of the box, toggle them globally or per-tool when you want unattended execution.
## Installation
The tools live in the [`chat/ai`](/docs/ai) subpath of the core `chat` package:
```ts
import { createChatTools } from "chat/ai";
```
`ai` and `zod` are optional peer dependencies — install them if you haven't already:
<PackageInstall package="ai zod" />
<Callout>
Pair `createChatTools` with [`toAiMessages`](/docs/ai/to-ai-messages)
to feed prior thread history into the agent before it picks a tool.
Both ship from the same `chat/ai` subpath, which keeps the optional
`ai` / `zod` peer deps out of bundles that don't import them.
</Callout>
## Quick start
Pass your `Chat` instance and the tools you want into any AI SDK call:
```typescript title="lib/agent.ts" lineNumbers
import { Chat } from "chat";
import { createChatTools } from "chat/ai";
import { createSlackAdapter } from "@chat-adapter/slack";
import { createMemoryState } from "@chat-adapter/state-memory";
import { generateText } from "ai";
const chat = new Chat({
userName: "mybot",
adapters: { slack: createSlackAdapter() },
state: createMemoryState(),
});
const result = await generateText({
model: "anthropic/claude-sonnet-4.6",
tools: createChatTools({
chat,
preset: "messenger",
requireApproval: false, // unattended script, no human-in-the-loop needed
}),
prompt:
"Post a friendly hello in slack:C0123ABC and react to it with a thumbs up.",
});
```
Each tool resolves the right adapter from the id prefix you give it (`slack:...`, `discord:...`, `gchat:...`), so the same agent can drive any platform your `Chat` instance is wired up to.
## Presets
Pass `preset` to scope the toolset down to what an agent actually needs.
```typescript
// Read-only — fetch messages, threads, channel info, users
createChatTools({ chat, preset: "reader" });
// Basic posting — read + post + DM + react + typing indicator
createChatTools({ chat, preset: "messenger" });
// Full management — everything including edit, delete, subscriptions
createChatTools({ chat, preset: "moderator" });
```
Presets compose — pass an array to combine them:
```typescript
createChatTools({ chat, preset: ["reader", "messenger"] });
```
Omit `preset` entirely to get every tool (same as `'moderator'`).
| Preset | Tools included |
|---|---|
| `reader` | `fetchMessages`, `fetchChannelMessages`, `fetchThread`, `listThreads`, `getThreadParticipants`, `getChannelInfo`, `getUser` |
| `messenger` | `fetchMessages`, `fetchThread`, `getChannelInfo`, `getUser`, `postMessage`, `postChannelMessage`, `sendDirectMessage`, `addReaction`, `removeReaction`, `startTyping` |
| `moderator` | All read tools plus `postMessage`, `postChannelMessage`, `sendDirectMessage`, `editMessage`, `deleteMessage`, `addReaction`, `removeReaction`, `subscribeThread`, `unsubscribeThread`, `startTyping` |
## Approval control
Write operations (posting, editing, deleting, reacting, subscribing) default to `needsApproval: true`. The AI SDK pauses execution and surfaces an approval request that your application is expected to confirm before the tool runs. This keeps a human in the loop for anything visible to the workspace.
```typescript
// All writes need approval (default)
createChatTools({ chat });
// No approval needed
createChatTools({ chat, requireApproval: false });
// Per-tool — only destructive actions need approval
createChatTools({
chat,
requireApproval: {
deleteMessage: true,
editMessage: true,
sendDirectMessage: false,
postMessage: false,
addReaction: false,
},
});
```
Read tools (`fetchMessages`, `fetchThread`, `getChannelInfo`, …) and the `startTyping` indicator never require approval.
## Cherry-picking tools
Each tool is also exported as a standalone factory you can hand to `tools` directly:
```typescript title="lib/agent.ts" lineNumbers
import { fetchMessages, postMessage, addReaction } from "chat/ai";
const tools = {
fetchMessages: fetchMessages(chat),
postMessage: postMessage(chat, { needsApproval: false }),
addReaction: addReaction(chat, { needsApproval: false }),
};
```
Useful when you want a small, targeted toolset without going through `createChatTools`.
## Tool overrides
Customize any AI SDK [`tool()`](https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling) property per tool, keyed by tool name:
```typescript
import type { ChatToolName, ToolOverrides } from "chat/ai";
createChatTools({
chat,
overrides: {
postMessage: {
description: "Reply in the active customer support thread.",
needsApproval: false,
},
deleteMessage: { needsApproval: true },
},
});
```
| Property | Type | Description |
|---|---|---|
| `description` | `string` | Custom tool description shown to the model |
| `title` | `string` | Human-readable title |
| `strict` | `boolean` | Strict mode for input generation |
| `inputExamples` | `array` | Examples that show the model what tool input should look like |
| `metadata` | `object` | Tool metadata propagated to tool call and result parts |
| `needsApproval` | `boolean \| function` | Gate execution behind an approval request |
| `providerOptions` | `ProviderOptions` | Provider-specific metadata |
| `onInputStart` | `function` | Callback when argument streaming starts |
| `onInputDelta` | `function` | Callback on each streaming delta |
| `onInputAvailable` | `function` | Callback when full input is available |
| `toModelOutput` | `function` | Custom mapping of tool result to model output |
Core properties (`execute`, `inputSchema`, `outputSchema`, and tool-kind fields like `type`, `id`, `args`) cannot be overridden so tool semantics stay stable.
## Available tools
All ids accept the full Chat SDK form: `slack:C123ABC:1234567890.123456` for a thread, `slack:C123ABC` for a channel, and the platform-native user id (e.g. `U123456` on Slack, `users/123` on Google Chat). The tools auto-detect the adapter from the prefix.
### Reading
| Tool | Description |
|---|---|
| `fetchMessages` | Fetch recent messages from a thread (paginated) |
| `fetchChannelMessages` | Fetch top-level messages in a channel (not thread replies) |
| `fetchThread` | Fetch metadata for a thread (channel id, visibility, DM status) |
| `listThreads` | List recent threads in a channel with their root message |
| `getThreadParticipants` | Return the unique non-bot participants in a thread |
| `getChannelInfo` | Fetch channel metadata (name, member count, visibility) |
| `getUser` | Look up a user's profile by id |
### Writing
| Tool | Description | Default approval |
|---|---|---|
| `postMessage` | Post a reply in an existing thread | required |
| `postChannelMessage` | Post a top-level message in a channel | required |
| `sendDirectMessage` | Open a DM with a user and post in it | required |
| `editMessage` | Edit a message the bot previously posted | required |
| `deleteMessage` | Delete a message the bot previously posted | required |
| `addReaction` | Add an emoji reaction to a message | required |
| `removeReaction` | Remove a previously-added reaction | required |
| `subscribeThread` | Subscribe the bot to all future messages in a thread | required |
| `unsubscribeThread` | Stop receiving non-mention messages in a thread | required |
| `startTyping` | Show a typing indicator in a thread | not gated |
## API
### `createChatTools(options)`
Returns an object of tools, ready to spread into `tools` of any AI SDK call.
```typescript
type ChatToolsOptions = {
chat: Chat;
requireApproval?: boolean | Partial<Record<ChatWriteToolName, boolean>>;
preset?: ChatToolPreset | ChatToolPreset[];
overrides?: Partial<Record<ChatToolName, ToolOverrides>>;
};
type ChatToolPreset = "reader" | "messenger" | "moderator";
```
| Option | Description |
|---|---|
| `chat` | The `Chat` instance the tools dispatch operations against. Required. |
| `preset` | Preset (or array of presets) restricting which tools are returned. Omit to get every tool. |
| `requireApproval` | `true` (default), `false`, or per-tool overrides. Read tools and `startTyping` are never gated. |
| `overrides` | Per-tool customization of any AI SDK `tool()` property except `execute`, `inputSchema`, and `outputSchema`. |