Example: an issue triage bot with Chat SDK
Build an issue triage bot with Chat SDK
@mention the bot on an issue and it classifies it (bug, feature, or question), applies a matching label, and posts a short triage note. Same shape as the PR review bot example, different preset and a different job.
Files
import { Chat, emoji, type Message, type Thread } from 'chat'
import { createGitHubAdapter } from '@chat-adapter/github'
import { createMemoryState } from '@chat-adapter/state-memory'
import { start } from 'workflow/api'
import { triageWorkflow } from '../workflows/triage'
const adapters = { github: createGitHubAdapter() }
export const agent = new Chat<typeof adapters>({
userName: process.env.GITHUB_AGENT_USERNAME || 'triage-bot',
adapters,
state: createMemoryState(),
}).registerSingleton()
agent.onNewMention(async (thread: Thread, message: Message) => {
const sent = thread.createSentMessageFromMessage(message)
await sent.addReaction(emoji.eyes)
await start(triageWorkflow, [message.text])
})
import { createGithubAgent } from '@github-tools/sdk'
import { connectGithubToken } from '@github-tools/sdk/connect'
async function runTriageTurn(prompt: string) {
'use step'
const agent = createGithubAgent({
model: 'anthropic/claude-sonnet-4.6',
token: connectGithubToken('github/my-connector', { preset: 'issue-triage' }),
preset: 'issue-triage',
requireApproval: false,
additionalInstructions: `
Classify the issue as bug, feature, or question.
Apply the matching label with addLabels, then post one comment with the
classification and a one-line suggested next step. Do not close anything.
`,
})
const { text } = await agent.generate({ prompt })
return text
}
export async function triageWorkflow(prompt: string) {
'use workflow'
await runTriageTurn(prompt)
}
import { defineHandler } from 'nitro/h3'
import { agent } from '../../lib/agent'
export default defineHandler(async (event) => {
const handler = agent.webhooks.github
if (!handler) {
return new Response('GitHub adapter not configured', { status: 404 })
}
return handler(event.req, {
waitUntil: (task: Promise<unknown>) => event.waitUntil(task),
})
})
# Vercel Connect OIDC token, required by the "github/my-connector" connector.
# vercel link && vercel env pull
VERCEL_OIDC_TOKEN=
# Webhook secret (must match your GitHub webhook config)
GITHUB_WEBHOOK_SECRET=
# Bot account username, for @mention detection
GITHUB_AGENT_USERNAME=triage-bot
Install
pnpm add @github-tools/sdk @vercel/connect chat @chat-adapter/github @chat-adapter/state-memory workflow ai zod
npm install @github-tools/sdk @vercel/connect chat @chat-adapter/github @chat-adapter/state-memory workflow ai zod
yarn add @github-tools/sdk @vercel/connect chat @chat-adapter/github @chat-adapter/state-memory workflow ai zod
bun add @github-tools/sdk @vercel/connect chat @chat-adapter/github @chat-adapter/state-memory workflow ai zod
Set up the connector and webhook
Create a GitHub connector
Create a github/my-connector connector installed on the repositories this bot triages. See Vercel Connect for the full checklist.
Pull a local OIDC token
vercel link
vercel env pull
Configure the GitHub webhook
In Settings → Webhooks, point a webhook at /webhooks/github with content type application/json, the same secret as GITHUB_WEBHOOK_SECRET, and the Issue comments event.
GITHUB_AGENT_USERNAME to that account.Run it
pnpm dev
Comment @triage-bot triage this on an issue. The bot reacts, labels the issue, and posts its classification, no approval prompt, since requireApproval: false and this job never closes or deletes anything.
Go further
- Set
requireApproval: { closeIssue: true }and let the bot close issues once the author confirms it's resolved, instead of leaving that to a human every time - Reuse the same
agent.tsshape with@chat-adapter/slackto triage from a Slack channel instead of GitHub comments, see Beyond GitHub - Compare with the PR review bot to see the same architecture applied to a different preset and prompt
CI failure bot
A durable chat backend that diagnoses failing GitHub Actions runs, built with createDurableGithubAgent, the ci-ops preset, and Vercel Connect.
Manager & sub-agents
A broadly-capable GitHub manager agent that delegates to specialist eve sub-agents, each scoped to one preset (code-review, issue-triage, release-manager), instead of one agent holding every tool.