Skip to main content

Overview

The @nimble-way/ai-sdk package provides pre-built tools for Vercel’s AI SDK v6. Register them on an agent and the model decides when to search the web, read a page, or commission deeper research. Nimble runs the request and returns clean, structured results to cite.
  • Five tools, zero boilerplate: search, extract, and the three deep-research run tools.
  • Works with any model: OpenAI, Anthropic, Google, and others supported by the AI SDK.
  • Two search depths: lite for fast metadata, deep for full page content.
  • Asynchronous deep research: start a Web Search Agent run, collect the cited answer minutes later.
  • Type-safe: written in TypeScript with typed options and output.
These are app-side AI SDK tool() definitions, not provider-executed search. They behave the same whether the model call routes through the Vercel AI Gateway or a provider SDK directly. The gateway, when present, routes only the model call.
Ships Search, Extract, and Web Search Agent runs. Map and Crawl are planned as follow-ups.
Building on eve, Vercel’s agent framework? Use the Vercel eve connector instead. It mounts the same capabilities as an eve extension and can replace eve’s built-in web_search and web_fetch.

Prerequisites

The package targets the Node.js runtime. Edge and serverless runtimes are expected to work but are not yet verified, so prefer the Node runtime.
ai (v6) and zod (^3.25.76 or ^4.1.8) are peer dependencies. Your app supplies both.
Required by every tool. Get a key from the dashboard. Keep it server-side: the key never appears in model inputs or tool outputs.
Required by the three agent run tools. A Web Search Agent instance, created once in the dashboard or through POST /v2/agents. The ID looks like wsa_01j9x8.... The search and extract tools do not need it.

Quick Start

1

Install

ai (v6) and zod are peer dependencies. The examples use OpenAI via @ai-sdk/openai, but nimbleSearch works with any AI SDK model provider.
2

Set your API keys

Get a Nimble key from the dashboard (free trial available), then set both keys:
You can also pass the Nimble key inline: nimbleSearch({ apiKey: '...' }).For deep research, also set NIMBLE_AGENT_ID.
3

Add the tool to an agent

How it works

1

The model receives the tool

nimbleSearch() registers a webSearch tool the model can call when it needs current information.
2

The model decides to search

When the prompt needs live data, the model emits a tool call with a query (and optional maxResults).
3

Nimble runs the search

The query goes to Nimble’s Web Search API, which returns clean, structured results.
4

The model answers

Results are fed back to the model, which uses them to write a grounded, citable answer. stopWhen: stepCountIs(n) caps how many search rounds a single turn can take.
Use stepCountIs, not isStepCount. The latter does not exist in ai v6. Set it on every agent to prevent runaway loops and unbounded cost: 35 for chat, higher for autonomous agents.
nimbleSearch() grounds an answer in live web results. Configure it once; the model only ever supplies { query, maxResults? }.

Next.js route handler

For a streaming chat app, swap generateText for streamText inside a route handler and return toUIMessageStreamResponse(). The client connects with the AI SDK useChat hook, with no extra wiring needed.

Search options

Nimble API credentials. Defaults to process.env.NIMBLE_API_KEY.
'lite' returns metadata only (fast); 'deep' returns full page content. Default 'lite'.
Default number of results per search. Type number, default 5.
Hard upper limit on results the model can request. Type number, default 10.
Per-result content truncation, in characters. Type number, default 10_000.
Two-letter country code for localization. Type string, default 'US'.
Language preference. Type string, default 'en'.
Injectable NimbleSearchClient for testing. Optional.

Search response

Each tool call returns a structured result the model can reason over:

Extract

nimbleExtract() registers an extract tool that takes a single URL and returns clean page content, markdown by default, for the model to read, quote, or summarize. The model only ever supplies { url }; all policy below is developer-controlled.
Register both tools together so the model can search, then read the best result:

Extract options

Configure nimbleExtract() once; the model only ever supplies { url }.
Nimble API credentials. Defaults to process.env.NIMBLE_API_KEY.
Content format returned to the model: 'markdown' or 'html'. Default 'markdown'.
Two-letter ISO country code for geolocation / proxy. Type string, optional.
Extracted content truncation, in characters. Type number, default 50_000.
Injectable NimbleExtractClient for testing. Optional.

Extract response

Deep research with Web Search Agents

nimbleSearch() and nimbleExtract() are synchronous building blocks: one call, one response, seconds. A Web Search Agent run is a different capability. An autonomous agent plans, searches, reads, and cross-checks many sources, then returns a final answer with per-claim citations and confidence. It takes minutes, not seconds. Because a run outlives any sensible HTTP request, the package splits the lifecycle across three tools. By default, no chat request is held open for the research duration.

nimbleAgentStartRun()

Starts a run. Returns the run ID immediately, without waiting for the research.

nimbleAgentRunStatus()

Reports the current status. Instant, and never waits.

nimbleAgentRunResult()

Fetches the answer once the run completes.

Start now, answer later

Point NIMBLE_AGENT_ID at your agent instance, then start the run and persist the returned runId.
The start tool returns the handle you need to resume:
Preserve runId outside the request. Write it to your database, session, or job queue. Research runs take minutes, so a run started in one request is almost never finished in that same request. Holding an ordinary chat request open until completion times out the request and wastes the async design.
Minutes later, in a different request, server, or process, only the runId crosses over.
Register all three tools together when the model should also be able to check progress:

Runs that are still working

A run that has not finished is a normal state, not an error. nimbleAgentRunResult() returns ready: false so the model can tell the user to check back.
Use nimbleAgentRunStatus() for cheap progress checks that never fetch the result. Its output adds isActive, startedAt, completedAt, and error on failed runs.
By default the result tool never blocks. Behind a queue worker, rather than a chat route, you can let a single call ride out a short remainder:
Pass wait: true for the defaults: a 300_000 ms timeout and a 2_000 ms poll interval, with a 100 ms floor on the interval. On timeout the tool returns ready: false and the run stays healthy. The package never polls without a bound.
Waiting honors the AI SDK’s per-call AbortSignal. Aborting stops the wait only. The run keeps going on Nimble’s side and stays resumable from the same runId.
A terminally failed or cancelled run throws a typed NimbleAgentRunError. Its reason is 'failed', 'cancelled', 'protocol', or 'request', and it always carries runId so your code can still reference the run. An HTTP status, when there is one, is on error.status.
A still-active run and a wait timeout are not errors.

Results and citations

A completed run returns prose or structured data, along with trust metadata passed through verbatim from the API so citation markers stay aligned with the answer.
trust carries the sources consulted, the per-claim citations, and confidence:
Text answers key each claim by callout, matching the numeric markers in the prose. Structured answers key each claim by path, the JSON path of the value. Exactly one of the two is present. See Trust and citations for how confidence is graded.

Agent run options

All three factories share this configuration. Every field is optional.
The Web Search Agent instance to run, in the form wsa_.... Defaults to process.env.NIMBLE_AGENT_ID. Resolved when the tool executes, so the model can never choose the agent.
Nimble API credentials. Defaults to process.env.NIMBLE_API_KEY.
Injectable NimbleAgentRunsClient for testing. Optional.
Passthrough for baseURL, fetch, timeout, and maxRetries on the Nimble client. Optional.
nimbleAgentStartRun() adds two more:
Effort used when the model does not choose one: 'low', 'medium', 'high', 'x-high', or 'max'. Leave it unset to use the agent instance’s own default. Higher tiers research more sources and take longer. See Efforts.
Upper bound on the effort the model may request. Model choices above the cap are clamped down to it. Default 'high', so a model cannot trigger the x-high or max cost tiers on its own. It never limits the developer-set effort.
nimbleAgentRunResult() adds wait, documented under bounded waiting. The model-facing inputs stay small: { task, effort? } for the start tool and { runId } for the status and result tools. The agent identity, credentials, and wait policy are never model-controlled.

Limitations

  • Search, Extract, and Web Search Agent runs ship today. Map and Crawl are planned follow-ups.
  • Agent runs need a pre-created agent instance. Set NIMBLE_AGENT_ID. Creating and managing agents, and managing templates, are deliberately not model-callable tools in this release.
  • Run event streaming (SSE) is not exposed by this release. Use the status and result tools.
  • No built-in answer generation in Search. The tool returns results and the model writes the answer.
  • searchDepth: 'fast' is not available in this package.
  • Node.js runtime (18 or later) is the supported target. Edge and serverless compatibility is unverified.

Resources

npm Package

@nimble-way/ai-sdk on npm.

GitHub Repository

Source, README, and issues.

Web Search API

Nimble’s underlying search capability.

Extract API

Nimble’s underlying page extraction capability.

Web Search Agent

The deep-research capability behind the run tools.

Example Cookbook

Runnable integration examples.