ydc-ai-sdk-integration
Integrate Vercel AI SDK applications with You.com tools (web search, AI agent, content extraction).
Installation
npx clawhub@latest install ydc-ai-sdk-integrationView the full skill documentation and source below.
Documentation
Integrate AI SDK with You.com Tools
Interactive workflow to add You.com tools to your Vercel AI SDK application using @youdotcom-oss/ai-sdk-plugin.
Workflow
* Which package manager? (npm, bun, yarn, pnpm)
* Install package using their choice:
npm install @youdotcom-oss/ai-sdk-plugin
# or bun add @youdotcom-oss/ai-sdk-plugin
# or yarn add @youdotcom-oss/ai-sdk-plugin
# or pnpm add @youdotcom-oss/ai-sdk-plugin
* Using standard
YDC_API_KEY?* Or custom name? (if custom, get the name)
* Have they set it in their environment?
* If NO: Guide them to get key from
* Do they use
generateText()?* Do they use
streamText()?* Both?
* EXISTING: Ask which file(s) to edit
* NEW: Ask where to create file(s) and what to name them
* Which tools to add?
-
youSearch (web search)-
youExpress (AI agent)-
youContents (content extraction)- Multiple? (which combination?)
* Using
generateText() or streamText() in this file?* Which AI provider model? (to determine if stopWhen needed)
See "Integration Examples" section below for complete code patterns:
* generateText() - Basic text generation with tools
* streamText() - Streaming responses with web frameworks (Next.js, Express, React)
For each file:
* Reference integration examples (generateText or streamText based on their answer)
* Add import for selected tools
* If EXISTING file: Find their generateText/streamText call and add tools object
* If NEW file: Create file with example structure
* Tool invocation pattern based on env var name:
- Standard YDC_API_KEY: youSearch()
- Custom name: youSearch({ apiKey: process.env.CUSTOM_NAME })
* Add selected tools to tools object
* If streamText + Anthropic: Add stopWhen parameter
Integration Examples
generateText() - Basic Text Generation
Environment Variables Setup:
import { anthropic } from '@ai-sdk/anthropic';
import { generateText } from 'ai';
import { youContents, youExpress, youSearch } from '@youdotcom-oss/ai-sdk-plugin';
// Reads YDC_API_KEY from environment automatically
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: {
search: youSearch(),
},
prompt: 'What are the latest developments in quantum computing?',
});
console.log(result.text);
Multiple Tools:
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: {
search: youSearch(), // Web search with citations
agent: youExpress(), // AI answers with web context
extract: youContents(), // Content extraction from URLs
},
prompt: 'Research quantum computing and summarize the key papers',
});
Custom API Key:
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: {
search: youSearch({ apiKey: 'your-custom-key' }),
},
prompt: 'Your prompt here',
});
Complete Example:
import { anthropic } from '@ai-sdk/anthropic';
import { generateText } from 'ai';
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
const main = async () => {
try {
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: {
search: youSearch(),
},
maxSteps: 5,
prompt: 'What are the latest developments in quantum computing?',
});
console.log('Generated text:', result.text);
console.log('\nTool calls:', result.steps.flatMap(s => s.toolCalls));
} catch (error) {
console.error('Error:', error);
process.exit(1);
}
};
main();
streamText() - Streaming Responses
Basic Streaming with stopWhen Pattern:
import { anthropic } from '@ai-sdk/anthropic';
import { streamText, type StepResult } from 'ai';
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
// CRITICAL: Always use stopWhen for Anthropic streaming
// Anthropic's SDK requires explicit stop conditions
const stepCountIs = (n: number) => (stepResult: StepResult<any>) =>
stepResult.stepNumber >= n;
const result = streamText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: { search: youSearch() },
stopWhen: stepCountIs(3), // Required for Anthropic
prompt: 'What are the latest AI developments?',
});
// Consume stream
for await (const chunk of result.textStream) {
process.stdout.write(chunk);
}
Next.js Integration (App Router):
// app/api/chat/route.ts
import { anthropic } from '@ai-sdk/anthropic';
import { streamText, type StepResult } from 'ai';
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
const stepCountIs = (n: number) => (stepResult: StepResult<any>) =>
stepResult.stepNumber >= n;
export async function POST(req: Request) {
const { prompt } = await req.json();
const result = streamText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: { search: youSearch() },
stopWhen: stepCountIs(5),
prompt,
});
return result.toDataStreamResponse();
}
Express.js Integration:
// server.ts
import express from 'express';
import { anthropic } from '@ai-sdk/anthropic';
import { streamText, type StepResult } from 'ai';
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
const app = express();
app.use(express.json());
const stepCountIs = (n: number) => (stepResult: StepResult<any>) =>
stepResult.stepNumber >= n;
app.post('/api/chat', async (req, res) => {
const { prompt } = req.body;
const result = streamText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: { search: youSearch() },
stopWhen: stepCountIs(5),
prompt,
});
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.setHeader('Transfer-Encoding', 'chunked');
for await (const chunk of result.textStream) {
res.write(chunk);
}
res.end();
});
app.listen(3000);
React Client (with Next.js):
// components/Chat.tsx
'use client';
import { useChat } from 'ai/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat({
api: '/api/chat',
});
return (
<div>
{messages.map(m => (
<div key={m.id}>
<strong>{m.role}:</strong> {m.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
<button type="submit">Send</button>
</form>
</div>
);
}
Complete Streaming Example:
import { anthropic } from '@ai-sdk/anthropic';
import { streamText, type StepResult } from 'ai';
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
const stepCountIs = (n: number) => (stepResult: StepResult<any>) =>
stepResult.stepNumber >= n;
const main = async () => {
try {
const result = streamText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: {
search: youSearch(),
},
stopWhen: stepCountIs(3),
prompt: 'What are the latest AI developments?',
});
// Stream to stdout
console.log('Streaming response:\n');
for await (const chunk of result.textStream) {
process.stdout.write(chunk);
}
console.log('\n\nDone!');
} catch (error) {
console.error('Error:', error);
process.exit(1);
}
};
main();
Tool Invocation Patterns
Based on env var name from step 2:
Standard YDC_API_KEY:
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
tools: {
search: youSearch(),
}
Custom env var:
import { youSearch } from '@youdotcom-oss/ai-sdk-plugin';
const apiKey = process.env.THEIR_CUSTOM_NAME;
tools: {
search: youSearch({ apiKey }),
}
Multiple tools with standard env var:
import { youSearch, youExpress, youContents } from '@youdotcom-oss/ai-sdk-plugin';
tools: {
search: youSearch(),
agent: youExpress(),
extract: youContents(),
}
Multiple tools with custom env var:
import { youSearch, youExpress, youContents } from '@youdotcom-oss/ai-sdk-plugin';
const apiKey = process.env.THEIR_CUSTOM_NAME;
tools: {
search: youSearch({ apiKey }),
agent: youExpress({ apiKey }),
extract: youContents({ apiKey }),
}
Available Tools
youSearch
Web and news search - model determines parameters (query, count, country, etc.)youExpress
AI agent with web context - model determines parameters (input, tools)youContents
Web page content extraction - model determines parameters (urls, format)Key Integration Patterns
The examples above demonstrate:
- Import statements (AI SDK + provider + You.com tools)
- Env var validation (optional for new files)
- Tool configuration based on env var
- generateText/streamText usage with tools
- Result handling (especially textStream destructuring for streamText)
- Anthropic streaming pattern (stopWhen: stepCountIs(3))
- Web framework integration (Next.js, Express, React)
Implementation Checklist
For each file being updated/created:
- ○Import added for selected tools
- ○If custom env var: Variable declared with correct name
- ○tools object added to generateText/streamText
- ○Each selected tool invoked correctly:
toolName()
- Custom env: toolName({ apiKey })
- ○If streamText: Destructured
const { textStream } = ... - ○If Anthropic + streamText: Added
stopWhen: stepCountIs(3)
- ○Package installed with their package manager
- ○Env var set in their environment
- ○All files updated/created
- ○Ready to test
Common Issues
Issue: "Cannot find module @youdotcom-oss/ai-sdk-plugin"
Fix: Install with their package manager
Issue: "YDC_API_KEY (or custom name) environment variable is required"
Fix: Set in their environment (get key: )
Issue: "Tool execution fails with 401"
Fix: Verify API key is valid
Issue: "Incomplete or missing response"
Fix: If using streamText, increase the step count. Start with 3 and iterate up as needed (see README troubleshooting)
Issue: "textStream is not iterable"
Fix: Destructure: const { textStream } = streamText(...)
Issue: "Custom env var not working"
Fix: Pass to each tool: youSearch({ apiKey })
Advanced: Tool Development Patterns
For developers creating custom AI SDK tools or contributing to @youdotcom-oss/ai-sdk-plugin:
Tool Function Structure
Each tool function follows this pattern:
export const youToolName = (config: YouToolsConfig = {}) => {
const apiKey = config.apiKey ?? process.env.YDC_API_KEY;
return tool({
description: 'Tool description for AI model',
inputSchema: ZodSchema,
execute: async (params) => {
if (!apiKey) {
throw new Error('YDC_API_KEY is required');
}
const response = await callApiUtility({
params,
YDC_API_KEY: apiKey,
getUserAgent,
});
// Return raw API response for maximum flexibility
return response;
},
});
};
Input Schemas Enable Smart Queries
Always use schemas from @youdotcom-oss/mcp:
// ✅ Import from @youdotcom-oss/mcp
import { SearchQuerySchema } from '@youdotcom-oss/mcp';
export const youSearch = (config: YouToolsConfig = {}) => {
return tool({
description: '...',
inputSchema: SearchQuerySchema, // Enables AI to use all search parameters
execute: async (params) => { ... },
});
};
// ❌ Don't duplicate or simplify schemas
const MySearchSchema = z.object({ query: z.string() }); // Missing filters!
Why this matters:
- Rich schemas enable AI to use advanced query parameters (filters, freshness, country, etc.)
- AI can construct more intelligent queries based on user intent
- Prevents duplicating schema definitions across packages
- Ensures consistency with MCP server schemas
API Key Handling
Always provide environment variable fallback and validate before API calls:
// ✅ Automatic environment variable fallback
const apiKey = config.apiKey ?? process.env.YDC_API_KEY;
// ✅ Check API key in execute function
execute: async (params) => {
if (!apiKey) {
throw new Error('YDC_API_KEY is required');
}
const response = await callApi(...);
}
Response Format
Always return raw API response for maximum flexibility:
// ✅ Return raw API response
execute: async (params) => {
const response = await fetchSearchResults({
searchQuery: params,
YDC_API_KEY: apiKey,
getUserAgent,
});
return response; // Raw response for maximum flexibility
}
// ❌ Don't format or transform responses
return {
text: formatResponse(response),
data: response,
};
Why raw responses?
- Maximum flexibility for AI SDK to process results
- No information loss from formatting
- AI SDK handles presentation layer
- Easier to debug (see actual API response)
Tool Descriptions
Write descriptions that guide AI behavior:
// ✅ Clear guidance for AI model
description: 'Search the web for current information, news, articles, and content using You.com. Returns web results with snippets and news articles. Use this when you need up-to-date information or facts from the internet.'
// ❌ Too brief
description: 'Search the web'
Additional Resources
- Package README:
- Vercel AI SDK Docs:
- You.com API: