GitHub Tools
Frameworks
Run GitHub tools as durable, retryable steps with createDurableGithubAgent — crash-safe agents for Nuxt and Next.js apps on Vercel.

Long-running assistants and chat backends often need durable execution: if a function restarts, the same logical run should resume, tool calls should retry safely, and each step should be observable. @github-tools/sdk supports this through the Vercel Workflow SDK and the @github-tools/sdk/workflow entry point.

Integrate a durable GitHub assistant

What “durable” means here

  • "use workflow" — Your orchestration function is a workflow: the platform can pause, resume, and replay it across failures and deploys.
  • "use step" — Each GitHub tool implementation runs inside a named, module-level step. Every tool call is a durable step with retries and full Node.js access in the workflow runtime.
  • createDurableGithubAgent — Wraps the same GitHub tools in a WorkflowAgent from @ai-sdk/workflow so LLM turns and tool invocations participate in that durable model (not just raw generateText in a plain serverless handler).

Together, this is the recommended pattern when you build Nuxt, Next.js, or other apps that expose a chat or agent API and must not lose progress on timeout or cold start.

Install optional workflow dependencies

Durable agents are optional. Add them only when you use @github-tools/sdk/workflow:

pnpm add workflow @ai-sdk/workflow

You still need ai, zod, and @github-tools/sdk as documented in Installation.

Minimal durable workflow

createDurableGithubAgent returns a DurableGithubAgent with two methods:

  • .stream() — real-time output to a WritableStream (for chat UIs)
  • .generate() — non-streaming, returns the full text response (for bots, background jobs, webhooks)

Both methods execute each tool call as a durable workflow step with automatic retries.

Streaming (chat UI)

durable-chat.workflow.ts
import { createDurableGithubAgent } from '@github-tools/sdk/workflow'
import { getWritable } from 'workflow'
import type { ModelCallStreamPart, ModelMessage } from 'ai'

export async function durableGithubChat(
  messages: ModelMessage[],
  token: string,
  model: string
) {
  'use workflow'

  const writable = getWritable<ModelCallStreamPart>()

  const agent = createDurableGithubAgent({
    model,
    token,
    preset: 'code-review',
    requireApproval: true,
  })

  await agent.stream({ messages, writable })
}

Non-streaming (bot / background job)

For non-streaming use cases (bots, webhooks, background jobs), use createGithubAgent inside a "use step" function. This gives you the full tool loop while keeping the step durable:

review-agent.workflow.ts
import { createGithubAgent } from '@github-tools/sdk'

async function runAgentTurn(prompt: string) {
  'use step'
  const agent = createGithubAgent({
    model: 'anthropic/claude-sonnet-4.6',
    preset: 'code-review',
    requireApproval: false,
  })
  const { text } = await agent.generate({ prompt })
  return text
}

export async function reviewWorkflow(prompt: string) {
  'use workflow'
  await runAgentTurn(prompt)
}

Wire it into your framework

Workflows are plain exported functions — your framework's Workflow integration starts the run from an API route and streams results to the client.

Place workflows under server/workflows/ and start them from a Nitro server route:

server/api/chat.post.ts
import { start } from 'workflow/api'
import { durableGithubChat } from '../workflows/durable-chat.workflow'

export default defineEventHandler(async (event) => {
  const { messages, model } = await readBody(event)
  const session = await requireUserSession(event)

  const run = await start(durableGithubChat, [messages, session.secure.githubToken, model])

  setHeader(event, 'x-workflow-run-id', run.runId)
  return run.readable
})
For a complete working example that connects a durable agent to GitHub via Chat SDK, see the examples/pr-review-agent/ starter — a ~60-line PR review agent with multi-turn durable sessions and evlog AI observability. Full walkthrough: Chat SDK.

Presets and options

All presets (code-review, issue-triage, repo-explorer, ci-ops, maintainer) work with createDurableGithubAgent. Options mirror createGithubAgent for model, token, preset, instructions, and temperature, with additional pass-through for WorkflowAgentOptions fields like experimental_telemetry, onStepEnd, onEnd, and prepareStep. Use stopWhen (for example stepCountIs(n)) instead of the deprecated maxSteps parameter.

Approval control and durable agents

requireApproval maps to needsApproval on write tools. When a tool needs approval, WorkflowAgent pauses the workflow, emits an approval request to the stream, and resumes when the user approves or denies — the same UX as createGithubAgent, but durable across restarts.

Wire the client with WorkflowChatTransport and a GET reconnect route ({api}/{runId}/stream) so long runs survive timeouts. The demo chat app toggles this with the shield icon.

For richer approval policies — 'once' per session, input-dependent predicates — use eve agents.

Standard agents vs durable agents

createGithubAgentcreateDurableGithubAgent
Import@github-tools/sdk@github-tools/sdk/workflow
RuntimeIn-process ToolLoopAgentDurableGithubAgent inside "use workflow"
Methods.generate(), .stream().generate(), .stream()
Retries / resumeYou handleWorkflow-managed durable steps
requireApprovalSupportedSupported (via needsApproval on tools)

Durable steps on every tool

Even if you do not use createDurableGithubAgent, spreading createGithubTools() inside a workflow still benefits from per-tool "use step" boundaries when the AI SDK executes tools — each GitHub operation remains a proper workflow step. The durable agent entry point additionally durably wraps the LLM loop itself.

External references