Nimble Web Search as a ready-made Vercel AI SDK tool. Give any AI SDK agent the ability to search the web with Nimble in a few lines.
- Web Search — a
nimbleSearch()tool the model can call to retrieve ranked, real-time web results and ground its answers in them. - Model- and gateway-agnostic — an app-side
tool(); works the same with the Vercel AI Gateway or a direct provider. - Typed — typed config and normalized output; an injectable client for testing.
Extract, Map, and Crawl tools are planned follow-ups.
npm install @nimble-way/ai-sdk ai
# pnpm add @nimble-way/ai-sdk ai
# yarn add @nimble-way/ai-sdk aiai (v6) and zod are peer dependencies — you provide your app's copy.
A Nimble API key (get one at app.nimbleway.com):
export NIMBLE_API_KEY=... # picked up automaticallyOr pass it directly: nimbleSearch({ apiKey: '...' }).
import { generateText, stepCountIs } from 'ai';
import { nimbleSearch } from '@nimble-way/ai-sdk';
const { text } = await generateText({
model: 'openai/gpt-4o-mini',
prompt: 'What are the latest developments in agentic web search? Cite sources.',
tools: {
webSearch: nimbleSearch({ searchDepth: 'lite', maxResults: 5 }),
},
stopWhen: stepCountIs(3),
});
console.log(text);streamText works the same way — register the tool under tools.
// app/api/chat/route.ts
import { convertToModelMessages, streamText, stepCountIs, type UIMessage } from 'ai';
import { nimbleSearch } from '@nimble-way/ai-sdk';
export async function POST(req: Request) {
const { messages }: { messages: UIMessage[] } = await req.json();
const result = streamText({
model: 'openai/gpt-4o-mini',
messages: await convertToModelMessages(messages),
tools: {
webSearch: nimbleSearch({ searchDepth: 'lite', maxResults: 5 }),
},
stopWhen: stepCountIs(5),
});
return result.toUIMessageStreamResponse();
}The tool runs in your app (an app-side tool(), not a provider/server-executed search). It is therefore gateway-agnostic: it behaves identically whether you route your model through the Vercel AI Gateway (plain-string model IDs like 'openai/gpt-4o-mini') or call a provider SDK directly. The gateway, if present, only routes the model call.
nimbleSearch(config) — all fields optional:
| Option | Type | Default | Notes |
|---|---|---|---|
apiKey |
string |
process.env.NIMBLE_API_KEY |
Nimble API key. |
client |
NimbleSearchClient |
— | Inject a pre-built/mock client (tests, advanced use). |
maxResults |
number |
5 |
Results when the model doesn't specify. |
maxResultsCap |
number |
10 |
Hard upper bound, regardless of model request. |
searchDepth |
'lite' | 'deep' |
'lite' |
lite = fast metadata; deep = full page content. |
country |
string |
'US' |
Result localization. |
locale |
string |
'en' |
Result localization. |
maxContentLength |
number |
10_000 |
Truncate each result body. |
The model-facing input is just { query: string, maxResults?: number } — all policy above is developer-controlled, not model-controlled.
{
query: string;
requestId?: string;
totalResults?: number;
results: Array<{
title: string;
url: string;
description?: string;
content?: string; // present in `deep`
position?: number;
entityType?: string;
}>;
}- Search only. Extract / Map / Crawl / Agents are follow-ups.
- No answer generation.
include_answeris intentionally not exposed. searchDepth: 'fast'is not available (enterprise-gated).- Runtime: targets the Node.js runtime (Node ≥ 18). Edge/serverless is expected to work but not yet verified — prefer the Node runtime.
| Symptom | Fix |
|---|---|
NimbleConfigError: missing API key |
Set NIMBLE_API_KEY or pass apiKey. |
NimbleSearchError with a status |
The Nimble API returned an error; the HTTP status is on err.status. |
| Tool never called | Ensure your prompt invites tool use and stopWhen allows multiple steps. |
Apache-2.0