---
title: "Tool calls"
description: "Follow one GitHub tool call from the model's choice to the result it reads, including approval, tokens, paging and errors."
canonical_url: "https://github-tools.com/learn/tool-calls"
---
# Tool calls

> Follow one GitHub tool call from the model's choice to the result it reads, including approval, tokens, paging and errors.

A tool call is one request from the model to run a named tool with an input it filled in. The SDK checks whether the call needs approval, calls the GitHub API with your token, and returns a trimmed result that the model reads before it decides what to do next.

<tool-call-lifecycle>



</tool-call-lifecycle>

## One call, step by step

Take the request "what are the open bugs on vercel/ai?" given to an agent with the `issue-triage` preset.

### 1. The model picks a tool and fills its input

The model reads the tool descriptions it was given and picks `listIssues`. It writes the input as JSON that matches the tool's schema:

```json
{ "owner": "vercel", "repo": "ai", "labels": "bug" }
```

The AI SDK checks the input against the schema and fills the defaults the model left out: `state: 'open'`, `perPage: 30` and `page: 1`. If you set a [working context](https://github-tools.com/context) such as `{ owner: 'vercel', repo: 'ai' }`, the model can leave out `owner` and `repo`, and the context fills them in.

If the input doesn't match the schema, the tool doesn't run. The model gets the validation error and can try again with corrected input.

### 2. The SDK checks approval

`listIssues` is a read tool, so it runs straight away. Had the model called a write tool such as `addLabels`, the call would stop here: the agent returns an approval request with the tool name and input, and nothing reaches GitHub until someone answers. A denied write returns a denial the model reads, and the system prompt from `createGithubAgent()` tells it not to retry. [Approval](https://github-tools.com/approval) covers the options.

### 3. The SDK resolves the token

The tool asks for a token only once it runs, which is after approval. With a token string or `GITHUB_TOKEN`, that's the same token every time. With a function, the SDK calls it with the tool call: the tool name, its input after context defaults, and the `owner` and `repo` it targets. That lets you return a token for the right GitHub App installation, or a short-lived one from [Vercel Connect](https://github-tools.com/auth#vercel-connect).

### 4. The SDK calls GitHub

The tool makes the REST request with [Octokit](https://github.com/octokit/octokit.js), GitHub's JavaScript client. Here, that's one `GET /repos/vercel/ai/issues` request filtered by the `bug` label.

### 5. The SDK shapes the result

GitHub's response for one issue has dozens of fields. `listIssues` keeps the ones a model uses, and drops pull requests, which GitHub's issues endpoint also returns:

```json
{
  "items": [
    {
      "number": 1234,
      "title": "streamText drops the last chunk",
      "state": "open",
      "url": "https://github.com/vercel/ai/issues/1234",
      "author": "octocat",
      "labels": ["bug"],
      "createdAt": "2026-10-02T09:14:00Z",
      "updatedAt": "2026-10-05T16:40:00Z"
    }
  ],
  "hasMore": false,
  "page": 1,
  "perPage": 30
}
```

Other tools trim in the same spirit: issue and pull request bodies are cut to about 500 characters unless the model passes `detail: 'full'`, and diffs are left out unless it passes `includePatch: true`. [Tools](https://github-tools.com/tools#output-size) lists every limit.

The result also carries a `rateLimit` field with GitHub's remaining request count. Your code can read it, but the SDK removes it from what the model sees.

### 6. The model reads the result

The result goes back into the conversation, and the model is called again. It can answer, or call another tool, such as `getIssueContext` on the bug that looks most urgent. Each round of "call the model, run its tools" is one step.

`generateText` and `streamText` stop after one step unless you set `stopWhen`, so pass `stopWhen: stepCountIs(10)` or similar to let the model read a result and keep going. An agent from `createGithubAgent()` runs up to 20 steps by default.

## Page through long lists

A repository can have thousands of issues, so list tools return one page at a time. Every list result has the same paging fields:

```ts
{ items, hasMore, page, perPage, nextPage? }
```

When `hasMore` is `true`, the model calls the tool again with `page: nextPage` to get the next page. It can also pass `maxPages`, up to 20, to fetch several pages in one call. The tool descriptions, and the system prompt from `createGithubAgent()`, tell the model to use `nextPage` instead of asking for the same page twice.

## Errors come back as data

When GitHub refuses a call, the loop doesn't stop. The failure becomes the tool's result, with a stable code, the likely cause, and a fix the model can act on:

```json
{
  "message": "GitHub resource not found (404): Not Found",
  "status": 404,
  "data": {
    "code": "github_tools.NOT_FOUND",
    "why": "Either the resource does not exist, or the token cannot see it ...",
    "fix": "Check the owner/repo/number input first. If it is correct, the token lacks access ..."
  }
}
```

The model can correct a typo in the repository name and call again, or tell the user which permission the token is missing. [Errors](https://github-tools.com/errors) lists every code. Errors in your own setup, such as a missing token when you create the tools, throw from your code instead.

## FAQ

<accordion>
<accordion-item label="Can the model call several tools in one step?">

Yes. A model can return several tool calls at once, and the AI SDK runs them before the next step. The system prompt from `createGithubAgent()` asks the model to call independent reads together.

</accordion-item>

<accordion-item label="Can I run a tool without a model?">

Yes. Every tool has an `execute` function that your code can call with an input, and it returns the same shaped result. [Tools](https://github-tools.com/tools#call-a-tool-from-your-code) shows how.

</accordion-item>

<accordion-item label="Does the model see my token?">

No. The token stays in your process and is only sent to GitHub. The model only sees tool inputs and shaped results.

</accordion-item>

<accordion-item label="What is a context tool?">

A read tool that answers a whole question in one call, such as `getCiFailureContext`, which returns the failing checks, jobs and the end of their logs. It saves the model several steps. See [Context](https://github-tools.com/context#context-tools).

</accordion-item>
</accordion>


## Sitemap

See the full [sitemap](https://github-tools.com/sitemap.md) for all pages.
