# How the AI SDK Tool Layer Handles Pagination for `ls`, `find`, and `grep`

> Learn how the AI SDK tool layer manages pagination for ls, find, and grep operations using limit and cursor objects. Discover efficient result slicing for directory listings and search.

- Repository: [Cloudflare/computer](https://github.com/cloudflare/computer)
- Tags: internals
- Published: 2026-08-14

---

**The AI SDK tool layer handles pagination by accepting a standard `{ limit?, cursor? }` object in each tool's payload, then applying result slicing after the core filesystem operation completes—either through workspace-level pagination for directory listings or via a shared `applyPagination` helper for search operations.**

Pagination in AI-powered filesystem tools prevents overwhelming responses when querying large codebases. In the `@cloudflare/computer` package, the **AI SDK tool layer** implements a consistent pagination contract across the three primary exploration tools: `ls`, `find`, and `grep`. This article examines how each tool processes pagination parameters, where the slicing logic resides, and how the cursor-based system enables efficient result navigation.

## How Pagination Flows Through the Tool Architecture

The AI SDK constructs its tool set in [`packages/computer/src/tools/ai.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/tools/ai.ts). Each filesystem tool—**`ls`**, **`find`**, and **`grep`**—receives pagination options through the tool-call payload and applies them at a specific stage of execution.

The pagination object follows a standard interface:

```typescript
interface PaginationOptions {
  limit?: number;   // Maximum entries to return
  cursor?: string;  // Opaque token from previous response
}

```

Tools return results with a `cursor` field when more data exists, enabling iterative page retrieval.

## `ls` Tool: Workspace-Level Pagination

The **`ls`** tool delegates pagination directly to the workspace filesystem.

**Implementation location:** `createListTool` in [`packages/computer/src/fs/list.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fs/list.ts)

When the AI client calls `ls` with pagination parameters, the tool invokes:

```typescript
workspace.list(path, { limit, cursor })

```

The workspace's `list` method returns an object shaped as `{ entries, cursor }`, where the `cursor` field contains an opaque token for the next page. This pushes pagination responsibility to the storage layer, which can optimize based on its internal indexing.

**Example: Paginated directory listing**

```typescript
await sdk.runTool("ls", {
  path: "/my/project",
  pagination: { limit: 10 }   // Returns up to 10 entries and a next-page cursor
});

```

The response includes `entries` (the directory items) and optionally `cursor` for subsequent requests.

## `find` Tool: Merge-Then-Slice Pattern

The **`find`** tool implements a different pattern: collect all results, merge pending state, then paginate.

**Implementation location:** `createFindTool` in [`packages/computer/src/fs/find.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fs/find.ts)

Execution follows three stages:

1. **Filesystem walk** — Recursively searches directories matching the query
2. **Pending file merge** — Combines any staged/uncommitted files into the result set
3. **Pagination application** — Slices results using `applyPagination(pagination, results)`

The `applyPagination` helper (exported from [`packages/computer/src/fs/pagination.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fs/pagination.ts)) handles the actual slicing and cursor generation.

**Example: Paginated file search**

```typescript
await sdk.runTool("find", {
  path: "/my/project",
  query: "*.js",
  pagination: { 
    limit: 25, 
    cursor: "eyJvZmZzZXQiOjI1fQ=="  // Opaque cursor from previous response
  }
});

```

The test suite in [`packages/computer/src/fs/find.test.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fs/find.test.ts) verifies that pending files merge **before** pagination applies, ensuring uncommitted changes appear in correct page positions.

## `grep` Tool: Filter-Then-Slice Pattern

The **`grep`** tool adds a pre-pagination filtering step for glob patterns.

**Implementation location:** `createGrepTool` in [`packages/computer/src/fs/grep.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fs/grep.ts)

Execution order:

1. **Glob filtering** — Applies `include` pattern to narrow candidate files
2. **Regex execution** — Runs pattern match against filtered files
3. **Pagination application** — Uses `applyPagination(pagination, matches)` to slice results

This ensures pagination operates on the actual match set, not the raw file list.

**Example: Paginated content search**

```typescript
await sdk.runTool("grep", {
  path: "/my/project",
  pattern: "TODO",
  include: "**/*.ts",        // Pre-filters to TypeScript files only
  pagination: { limit: 50 }  // Returns first 50 matches with cursor
});

```

The test in [`packages/computer/src/fs/grep.test.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fs/grep.test.ts) confirms that `include` filtering occurs **before** pagination, preventing empty or partial pages when glob patterns exclude many files.

## Shared Pagination Helper: `applyPagination`

Both `find` and `grep` rely on `applyPagination` from [`packages/computer/src/fs/pagination.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fs/pagination.ts). This utility:

- Accepts the pagination options object and full result array
- Calculates slice bounds from `limit` and `cursor`
- Returns the paginated subset plus a new `cursor` (or `undefined` if exhausted)

Using a centralized helper ensures consistent cursor encoding, edge-case handling, and behavior across search tools.

## Test Coverage for Pagination Propagation

The AI SDK test suite validates pagination at multiple integration points:

| Test file | Coverage |
|-----------|----------|
| [`packages/computer/src/tools/ai.test.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/tools/ai.test.ts) | Verifies pagination options pass through tool-call payload to underlying filesystem operations |
| [`packages/computer/src/fs/find.test.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fs/find.test.ts) | Confirms pending files merge before pagination slicing |
| [`packages/computer/src/fs/grep.test.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fs/grep.test.ts) | Validates `include` filtering precedes pagination application |

These tests ensure the pagination contract remains stable across tool implementations.

## Summary

- **`ls`** delegates pagination to `workspace.list()` for storage-layer optimization
- **`find`** merges pending files, then applies `applyPagination()` to slice results
- **`grep`** filters by `include` glob first, then applies `applyPagination()` to matches
- **All three tools** accept the same `{ limit?, cursor? }` interface for consistent client usage
- **Cursor generation** is handled by the shared `applyPagination` helper in [`packages/computer/src/fs/pagination.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fs/pagination.ts)

## Frequently Asked Questions

### What format does the pagination cursor use?

The cursor is an **opaque base64-encoded string** representing the offset state. Clients treat it as an opaque token—decode internals are managed by `applyPagination` in [`packages/computer/src/fs/pagination.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fs/pagination.ts). Passing the returned cursor to the next request continues pagination from the correct position.

### Why does `ls` use workspace-level pagination while `find` and `grep` slice after collection?

**`ls`** operates on indexed directory structures where the storage layer can efficiently paginate without loading full listings. **`find`** and **`grep`** perform recursive filesystem traversals that must complete to produce accurate results—particularly for pending file merge and glob filtering—making post-operation slicing necessary for correctness.

### How do I know if more results exist after a paginated request?

Check the **`cursor`** field in the response. If present and non-null, additional pages exist. If `cursor` is `undefined` or omitted, the result set is exhausted. The test suite in [`packages/computer/src/tools/ai.test.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/tools/ai.test.ts) validates this propagation behavior.

### Can I use pagination without specifying a limit?

Yes—omit the `limit` parameter to receive default-sized pages. However, explicit `limit` values are recommended for predictable response sizes when integrating with AI context windows that have token constraints.