Migrate Octokit calls to AI SDK tools
createGithubTools(options?)
Returns a record of AI SDK tools you can pass to generateText or streamText. All options are optional, the SDK reads GITHUB_TOKEN from your environment by default:
type GithubToolsOptions = {
token?: GithubTokenInput
requireApproval?: boolean | Partial<Record<GithubWriteToolName, boolean>>
overrides?: Partial<Record<string, ToolOverrides>>
preset?: GithubToolPreset | GithubToolPreset[]
author?: CommitIdentity
committer?: CommitIdentity
coAuthors?: CommitIdentity[]
}
type GithubTokenInput = string | (() => Promise<string>)
type CommitIdentity = {
name: string
email: string
}
type GithubToolPreset =
| 'code-review'
| 'issue-triage'
| 'repo-explorer'
| 'ci-ops'
| 'security-audit'
| 'release-manager'
| 'discussion-moderator'
| 'notification-inbox'
| 'pr-author'
| 'maintainer'
Minimal usage, reads GITHUB_TOKEN automatically:
import { createGithubTools } from '@github-tools/sdk'
const tools = createGithubTools()
With a preset and explicit token:
import { createGithubTools } from '@github-tools/sdk'
const tools = createGithubTools({
token: 'github_pat_xxxxxxxxxxxx',
preset: 'repo-explorer',
})
See Scope with presets for preset details and Control write safety for approval options.
Working context
Pass context to default owner / repo / pullNumber / issueNumber / ref on tool inputs. Matching schema fields become optional and fill from context when omitted. Agents also get a short system-prompt block describing the context:
import { createGithubTools, createGithubAgent } from '@github-tools/sdk'
const tools = createGithubTools({
preset: 'code-review',
context: { owner: 'vercel', repo: 'ai', pullNumber: 42 },
})
const agent = createGithubAgent({
model: 'anthropic/claude-sonnet-4.6',
preset: 'code-review',
context: { owner: 'vercel', repo: 'ai', pullNumber: 42 },
})
listPullRequestFiles, getCommit, and compareCommits omit diff patches by default (includePatch: false). Set includePatch: true — optionally with filenames on listPullRequestFiles — to fetch targeted diffs.
getPullRequest, getIssue, and release getters truncate bodies by default (detail: 'summary'). Pass detail: 'full' for the complete text. getIssueContext defaults to detail: 'full' (one-shot) and returns labelNames rather than full label objects.
Prefer composite tools (getPullRequestContext, getIssueContext, getReleaseContext, getCiFailureContext) for multi-part reads. Prefer getFileContent with startLine/endLine or maxLines for large files.
Tool overrides
The overrides option lets you customize any AI SDK tool() property on a per-tool basis, keyed by tool name:
import { createGithubTools } from '@github-tools/sdk'
const tools = createGithubTools({
overrides: {
deleteGist: { needsApproval: false },
listIssues: { description: 'List bugs for the current sprint' },
},
})
import type { ToolOverrides } from '@github-tools/sdk'
Supported override properties:
| Property | Type | Description |
|---|---|---|
description | string | Custom tool description for the model |
title | string | Human-readable title |
strict | boolean | Strict mode for input generation |
needsApproval | boolean | function | Gate execution behind approval |
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) cannot be overridden.
Rate-limit metadata
Object-shaped tool results include a rateLimit field from the last GitHub response (x-ratelimit-remaining, x-ratelimit-limit, x-ratelimit-reset, x-ratelimit-resource, and retry-after when present). REST list tools now return objects ({ items, hasMore, … } or keyed collections), so they carry rateLimit too. The field is stripped before the model sees the output (toModelOutput); hooks, channels, and the chat UI still receive it.
import type { GithubRateLimit } from '@github-tools/sdk'
const remaining = (result as { rateLimit?: GithubRateLimit }).rateLimit?.remaining
resource is core, search, or graphql — search is the tightest bucket. On HTTP 403/429 the thrown error message also includes remaining/reset.
Commit attribution
The author, committer, and coAuthors options control how commits are attributed when using createOrUpdateFile or mergePullRequest:
import { createGithubTools } from '@github-tools/sdk'
const tools = createGithubTools({
token: 'github_pat_xxxxxxxxxxxx',
coAuthors: [
{ name: 'my-bot[bot]', email: '12345+my-bot[bot]@users.noreply.github.com' }
]
})
| Option | Type | Description |
|---|---|---|
author | CommitIdentity | The person who wrote the code. Falls back to the authenticated user. |
committer | CommitIdentity | The person who applied the commit. Falls back to the authenticated user. |
coAuthors | CommitIdentity[] | Additional contributors. Added as Co-authored-by trailers to commit messages. |
Commits made via the GitHub API are automatically signed by GitHub's web-flow key, passing branch protection rules that require signed commits.
See Commit attribution for detailed guidance.
createGithubAgent(options)
Returns a ToolLoopAgent with GitHub tools and system instructions pre-configured. The token is also auto-detected from GITHUB_TOKEN:
type GithubAgentOptions = {
model: string
token?: GithubTokenInput
preset?: GithubToolPreset | GithubToolPreset[]
requireApproval?: boolean | Partial<Record<GithubWriteToolName, boolean>>
system?: string
author?: CommitIdentity
committer?: CommitIdentity
coAuthors?: CommitIdentity[]
}
Use this when you want:
- reusable
.generate()/.stream()calls across multiple prompts - preset-aware system instructions without manual wiring
- a centralized agent definition shared across your codebase
import { createGithubAgent } from '@github-tools/sdk'
const agent = createGithubAgent({
model: 'anthropic/claude-sonnet-4.6',
preset: 'code-review',
system: 'You review PRs for security issues. Cite file paths and line numbers.',
})
createDurableGithubAgent(options)
Returns a WorkflowAgent for use inside a Vercel Workflow function ("use workflow"). Each LLM step and each GitHub tool invocation runs as a durable, retryable workflow step. Import from the workflow subpath:
import { createDurableGithubAgent } from '@github-tools/sdk/workflow'
Requires optional peer dependencies workflow and @ai-sdk/workflow, see Installation.
Options align with createGithubAgent (model, token, preset, requireApproval, instructions, additionalInstructions, stopWhen, temperature, and other agent options passed through). Write tools honor requireApproval via needsApproval: the workflow pauses until the user approves or denies.
import { createDurableGithubAgent } from '@github-tools/sdk/workflow'
import { getWritable } from 'workflow'
import type { ModelCallStreamPart, ModelMessage } from 'ai'
export async function githubAssistant(messages: ModelMessage[], token: string) {
'use workflow'
const agent = createDurableGithubAgent({
model: 'anthropic/claude-sonnet-4.6',
token,
preset: 'maintainer',
requireApproval: true,
})
const writable = getWritable<ModelCallStreamPart>()
await agent.stream({ messages, writable })
}
Conceptual overview: Durable workflows (Vercel Workflow).
githubExtension(options): eve extension
The recommended way to add GitHub tools to an eve agent. From @github-tools/eve-extension, mounted under agent/extensions/:
import githubExtension from '@github-tools/eve-extension'
export default githubExtension({
preset: 'code-review',
requireApproval: {
mergePullRequest: true,
createIssue: 'once',
},
})
options mirrors EveGithubToolsOptions below (token, connector, connect, preset, include, exclude, requireApproval, overrides, author/committer/coAuthors). Full config table and Connect setup: eve extension guide. Package README: packages/github-tools-eve-extension.
createGithubTools(options) : eve (deprecated)
githubExtension from @github-tools/eve-extension instead. This direct import keeps working but is no longer the recommended path. Runtime helpers for the extension are on @github-tools/sdk/eve-runtime (not deprecated).Returns a defineDynamic sentinel for eve's agent/tools/ directory. Import from @github-tools/sdk/eve:
import { createGithubTools } from '@github-tools/sdk/eve'
Requires optional peer dependencies eve and ai v7, see Installation and eve (direct import).
import { createGithubTools } from '@github-tools/sdk/eve'
export default createGithubTools({
preset: 'code-review',
requireApproval: {
mergePullRequest: true,
createIssue: 'once',
addPullRequestComment: false,
},
})
@github-tools/sdk/eve-runtime
Shared eve primitives for @github-tools/eve-extension and advanced integrations: tool descriptors, executeGithubEveTool, formatGithubEveToolOutput / hasGithubEveToolModelOutput (built-in toModelOutput lookup by tool name), approval helpers (mapEveApprovalValue, resolveEveApproval), and related types. Not deprecated — this is the supported low-level surface the extension imports. Prefer the extension mount for agents; use this subpath only when building on top of the same runtime.
import {
listEveToolDescriptors,
executeGithubEveTool,
formatGithubEveToolOutput,
hasGithubEveToolModelOutput,
mapEveApprovalValue,
resolveEveApproval,
} from '@github-tools/sdk/eve-runtime'
type EveGithubToolsOptions = {
token?: GithubTokenInput
preset?: GithubToolPreset | GithubToolPreset[]
include?: GithubToolName[]
exclude?: GithubToolName[]
requireApproval?: boolean | Partial<Record<GithubWriteToolName, EveApprovalValue>>
overrides?: EveToolOverrides
author?: CommitIdentity
committer?: CommitIdentity
coAuthors?: CommitIdentity[]
}
type EveApprovalValue =
| boolean
| 'always'
| 'once'
| 'never'
| Approval // from eve/tools
include is a set of tool names. Pass it alone to hand-pick an exact set, or alongside preset to add tools the preset is missing (the effective set is the union of both). exclude removes tool names from that resolved preset + include set, use it to drop a couple of tools from a larger preset. Also exports individual eve tool factories (listPullRequests(), createIssue(), …) for one-tool-per-file layouts. Approval supports once, predicates, and eve helper passthrough. Unlike the Workflow subpath, approval is enforced at runtime.
connectGithubTools(connector, options?)
Import from @github-tools/sdk/connect. Returns the same tool record as createGithubTools, backed by a Vercel Connect connector. connector is a GithubConnectorInput: a name string or a () => string | Promise<string> resolver, re-resolved on every call (e.g. to pick a connector per environment or tenant). Scopes are derived from preset unless overridden in connect.scopes:
import { connectGithubTools } from '@github-tools/sdk/connect'
const tools = connectGithubTools('github/my-connector', {
preset: 'code-review',
connect: {
installationId: 'inst_abc',
repositories: ['my-org/my-repo'],
},
})
type ConnectGithubToolsOptions = GithubToolsOptions & {
connect?: GithubConnectParams
}
type GithubConnectParams = Omit<ConnectTokenParams, 'subject'> & {
subject?: ConnectTokenSubject
repositories?: string[]
}
type GithubConnectorInput = string | (() => string | Promise<string>)
subject defaults to { type: 'app' } (the project's GitHub App installation). Pass { type: 'user', id } to mint a token for that user's own connection — see per-user tokens. See the Vercel Connect guide for the dynamic connector example.
connectGithubTools(connector, options?): eve (deprecated)
connector directly to githubExtension instead; no separate Connect import is needed.Import from @github-tools/sdk/connect/eve. Same as the AI SDK variant but returns a defineDynamic sentinel. Set build.externalDependencies: ['@vercel/connect'] in agent.ts until eve externalizes transitive Connect imports from workspace-linked packages (TODO(eve-connect-bundle)).
import { connectGithubTools } from '@github-tools/sdk/connect/eve'
export default connectGithubTools('github/my-connector', {
preset: 'maintainer',
})
connectGithubToken(connector, options?)
Returns a lazy GithubTokenInput backed by getToken. connector accepts the same GithubConnectorInput (name or resolver function) as connectGithubTools. Use with createGithubTools when you only need the token provider:
import { connectGithubToken } from '@github-tools/sdk/connect'
import { createGithubTools } from '@github-tools/sdk'
const tools = createGithubTools({
preset: 'ci-ops',
token: connectGithubToken('github/my-connector', { preset: 'ci-ops' }),
})
Pass the same preset (and the same include / exclude, when you use them) to connectGithubToken: it derives Connect scopes independently of the selection given to createGithubTools. With include alone, scopes follow the selected tools rather than the full preset union.
connectGithubScopesForPreset(preset?)
Returns Vercel Connect scope strings for a preset or combined presets. Without a preset, returns the union of all preset scopes.
connectGithubScopesForSelection({ preset?, include?, exclude? })
Same mapping as connectGithubToken uses when params.scopes is omitted. With no include / exclude, identical to connectGithubScopesForPreset. When either is set, scopes are derived from the resolved tool names via connectGithubScopesForTools.
connectGithubScopesForTools(names)
Returns the Connect scopes covering exactly the given tool names. Always includes metadata:read. Gist and notification tools contribute no scopes (installation tokens cannot call those APIs).
resolveGithubToken(token?)
Resolves a GithubTokenInput (token string, async provider, or the process.env.GITHUB_TOKEN fallback) to a token string. Throws when no token is available.
createOctokit(token?)
Returns a configured @octokit/rest instance. Use this when you need lower-level GitHub API access or want to build custom tool factories:
import { createOctokit, resolveGithubToken } from '@github-tools/sdk'
const octokit = createOctokit(await resolveGithubToken())
const { data } = await octokit.repos.get({ owner: 'HugoRCD', repo: 'github-tools' })
External references
Tools Catalog
Every available tool, grouped by domain and write-safety status. Tools run as durable workflow steps when used with Vercel Workflow.
eve (direct import)
Deprecated. The direct @github-tools/sdk/eve import registers all 84 tools via defineDynamic with durable human-in-the-loop approval. Prefer the eve extension for new agents.