From e6332a82512eb40fc42d49beb6fefc26c7a89262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Sun, 30 Nov 2025 20:17:16 +0300 Subject: [PATCH 01/36] feat: context7 vercel ai sdk tools package --- .github/workflows/test.yml | 61 ++++++ package.json | 2 + packages/ai-sdk/eslint.config.js | 47 +++++ packages/ai-sdk/package.json | 78 ++++++++ packages/ai-sdk/src/agents/context7.ts | 77 ++++++++ packages/ai-sdk/src/agents/index.ts | 1 + packages/ai-sdk/src/index.test.ts | 148 +++++++++++++++ packages/ai-sdk/src/index.ts | 18 ++ packages/ai-sdk/src/prompts/index.ts | 5 + packages/ai-sdk/src/prompts/system.ts | 75 ++++++++ packages/ai-sdk/src/tools/context7.ts | 251 +++++++++++++++++++++++++ packages/ai-sdk/src/tools/index.ts | 1 + packages/ai-sdk/tsconfig.json | 19 ++ packages/ai-sdk/tsup.config.ts | 11 ++ packages/ai-sdk/vitest.config.ts | 9 + pnpm-lock.yaml | 125 +++++++++++- 16 files changed, 926 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 packages/ai-sdk/eslint.config.js create mode 100644 packages/ai-sdk/package.json create mode 100644 packages/ai-sdk/src/agents/context7.ts create mode 100644 packages/ai-sdk/src/agents/index.ts create mode 100644 packages/ai-sdk/src/index.test.ts create mode 100644 packages/ai-sdk/src/index.ts create mode 100644 packages/ai-sdk/src/prompts/index.ts create mode 100644 packages/ai-sdk/src/prompts/system.ts create mode 100644 packages/ai-sdk/src/tools/context7.ts create mode 100644 packages/ai-sdk/src/tools/index.ts create mode 100644 packages/ai-sdk/tsconfig.json create mode 100644 packages/ai-sdk/tsup.config.ts create mode 100644 packages/ai-sdk/vitest.config.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..8e706a2a7 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,61 @@ +name: Test + +on: + pull_request: + branches: [master] + push: + branches: [master] + +jobs: + detect-changes: + runs-on: ubuntu-latest + outputs: + packages: ${{ steps.filter.outputs.changes }} + steps: + - uses: actions/checkout@v4 + + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + sdk: + - 'packages/sdk/**' + mcp: + - 'packages/mcp/**' + ai-sdk: + - 'packages/ai-sdk/**' + + test: + needs: detect-changes + if: ${{ needs.detect-changes.outputs.packages != '[]' }} + runs-on: ubuntu-latest + strategy: + matrix: + package: ${{ fromJson(needs.detect-changes.outputs.packages) }} + steps: + - uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Install Dependencies + run: pnpm install --frozen-lockfile + + - name: Build dependencies + run: pnpm build + + - name: Typecheck ${{ matrix.package }} + run: pnpm --filter @upstash/context7-${{ matrix.package }} typecheck || true + + - name: Test ${{ matrix.package }} + run: pnpm --filter @upstash/context7-${{ matrix.package }} test + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + CONTEXT7_API_KEY: ${{ secrets.CONTEXT7_API_KEY }} diff --git a/package.json b/package.json index a777d6fda..dde54acc6 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,10 @@ "build": "pnpm -r run build", "build:sdk": "pnpm --filter @upstash/context7-sdk build", "build:mcp": "pnpm --filter @upstash/context7-mcp build", + "build:ai-sdk": "pnpm --filter @upstash/context7-ai-sdk build", "test": "pnpm -r run test", "test:sdk": "pnpm --filter @upstash/context7-sdk test", + "test:ai-sdk": "pnpm --filter @upstash/context7-ai-sdk test", "clean": "pnpm -r run clean && rm -rf node_modules", "lint": "pnpm -r run lint", "lint:check": "pnpm -r run lint:check", diff --git a/packages/ai-sdk/eslint.config.js b/packages/ai-sdk/eslint.config.js new file mode 100644 index 000000000..aeb85cedb --- /dev/null +++ b/packages/ai-sdk/eslint.config.js @@ -0,0 +1,47 @@ +import { defineConfig } from "eslint/config"; +import tseslint from "typescript-eslint"; +import eslintPluginPrettier from "eslint-plugin-prettier"; + +export default defineConfig( + { + // Base ESLint configuration + ignores: ["node_modules/**", "build/**", "dist/**", ".git/**", ".github/**"], + }, + { + files: ["**/*.ts", "**/*.tsx"], + languageOptions: { + ecmaVersion: 2020, + sourceType: "module", + parser: tseslint.parser, + parserOptions: { + project: "./tsconfig.json", + tsconfigRootDir: import.meta.dirname, + }, + globals: { + // Add Node.js globals + process: "readonly", + require: "readonly", + module: "writable", + console: "readonly", + }, + }, + // Settings for all files + linterOptions: { + reportUnusedDisableDirectives: true, + }, + plugins: { + "@typescript-eslint": tseslint.plugin, + prettier: eslintPluginPrettier, + }, + rules: { + // TypeScript recommended rules + ...tseslint.configs.recommended.rules, + // TypeScript rules + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], + "@typescript-eslint/no-explicit-any": "warn", + // Prettier integration + "prettier/prettier": "error", + }, + } +); diff --git a/packages/ai-sdk/package.json b/packages/ai-sdk/package.json new file mode 100644 index 000000000..86b4e3e04 --- /dev/null +++ b/packages/ai-sdk/package.json @@ -0,0 +1,78 @@ +{ + "name": "@upstash/context7-ai-sdk", + "version": "0.1.0", + "description": "Context7 AI SDK integration for Vercel AI SDK", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + }, + "./agent": { + "types": "./dist/agent.d.ts", + "import": "./dist/agent.js", + "require": "./dist/agent.cjs" + } + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "test": "vitest run", + "typecheck": "tsc --noEmit", + "clean": "rm -rf dist" + }, + "dependencies": { + "@upstash/context7-sdk": "workspace:*", + "ai": "^5.0.0", + "zod": "^3.24.0" + }, + "devDependencies": { + "@ai-sdk/anthropic": "^2.0.0", + "@ai-sdk/openai": "^2.0.74", + "@types/node": "^22.13.14", + "tsup": "^8.5.1", + "typescript": "^5.8.2", + "vitest": "^4.0.13" + }, + "peerDependencies": { + "@ai-sdk/anthropic": "^2.0.0", + "@ai-sdk/openai": "^2.0.0" + }, + "peerDependenciesMeta": { + "@ai-sdk/anthropic": { + "optional": true + }, + "@ai-sdk/openai": { + "optional": true + } + }, + "repository": { + "type": "git", + "url": "git+https://github.com/upstash/context7.git", + "directory": "packages/ai-sdk" + }, + "keywords": [ + "context7", + "ai-sdk", + "vercel", + "documentation", + "agent", + "upstash" + ], + "author": "Upstash", + "license": "MIT", + "bugs": { + "url": "https://github.com/upstash/context7/issues" + }, + "homepage": "https://github.com/upstash/context7#readme", + "publishConfig": { + "access": "public" + } +} diff --git a/packages/ai-sdk/src/agents/context7.ts b/packages/ai-sdk/src/agents/context7.ts new file mode 100644 index 000000000..e3e9dca56 --- /dev/null +++ b/packages/ai-sdk/src/agents/context7.ts @@ -0,0 +1,77 @@ +import { + Experimental_Agent as Agent, + type Experimental_AgentSettings as AgentSettings, + type LanguageModel, + stepCountIs, +} from "ai"; +import { resolveLibrary, getLibraryDocs, type Context7ToolsConfig } from "../tools"; +import { AGENT_PROMPT } from "../prompts"; + +/** + * Configuration for Context7 agent + */ +export interface Context7AgentConfig + extends Context7ToolsConfig, + Partial< + AgentSettings<{ + resolveLibrary: ReturnType; + getLibraryDocs: ReturnType; + }> + > { + /** + * Language model to use. Must be a LanguageModel instance from an AI SDK provider. + * @example anthropic('claude-sonnet-4-20250514') + * @example openai('gpt-4o') + */ + model?: LanguageModel; +} + +/** + * Creates a Context7 documentation search agent + * + * The agent follows a multi-step workflow: + * 1. Resolves library names to Context7 library IDs + * 2. Fetches documentation for the resolved library + * 3. Provides answers with code examples + * + * @param config Configuration options for the agent + * @returns A configured AI agent with Context7 search capabilities + * + * @example + * ```typescript + * import { context7Agent } from '@upstash/context7-ai-sdk'; + * import { anthropic } from '@ai-sdk/anthropic'; + * + * const agent = context7Agent({ + * model: anthropic('claude-sonnet-4-20250514'), + * apiKey: 'your-context7-api-key', + * }); + * + * const result = await agent.generate({ + * prompt: 'How do I use React Server Components?', + * }); + * ``` + */ +export function context7Agent(config: Context7AgentConfig = {}) { + const { + model, + stopWhen = stepCountIs(5), + system, + apiKey, + defaultMaxResults, + ...agentSettings + } = config; + + const context7Config: Context7ToolsConfig = { apiKey, defaultMaxResults }; + + return new Agent({ + ...agentSettings, + model: model as LanguageModel, + system: system || AGENT_PROMPT, + tools: { + resolveLibrary: resolveLibrary(context7Config), + getLibraryDocs: getLibraryDocs(context7Config), + }, + stopWhen, + }); +} diff --git a/packages/ai-sdk/src/agents/index.ts b/packages/ai-sdk/src/agents/index.ts new file mode 100644 index 000000000..e38bfa5dd --- /dev/null +++ b/packages/ai-sdk/src/agents/index.ts @@ -0,0 +1 @@ +export { context7Agent, type Context7AgentConfig } from "./context7"; diff --git a/packages/ai-sdk/src/index.test.ts b/packages/ai-sdk/src/index.test.ts new file mode 100644 index 000000000..414121975 --- /dev/null +++ b/packages/ai-sdk/src/index.test.ts @@ -0,0 +1,148 @@ +import { describe, test, expect } from "vitest"; +import { generateText, stepCountIs } from "ai"; +import { openai } from "@ai-sdk/openai"; +import { + resolveLibrary, + getLibraryDocs, + context7Agent, + SYSTEM_PROMPT, + AGENT_PROMPT, + RESOLVE_LIBRARY_PROMPT, +} from "./index"; + +describe("@upstash/context7-ai-sdk", () => { + describe("Tool structure", () => { + test("resolveLibrary() should return a tool object with correct structure", () => { + const tool = resolveLibrary(); + + expect(tool).toBeDefined(); + expect(tool).toHaveProperty("execute"); + expect(tool).toHaveProperty("inputSchema"); + expect(tool).toHaveProperty("description"); + expect(tool.description).toContain("library"); + }); + + test("getLibraryDocs() should return a tool object with correct structure", () => { + const tool = getLibraryDocs(); + + expect(tool).toBeDefined(); + expect(tool).toHaveProperty("execute"); + expect(tool).toHaveProperty("inputSchema"); + expect(tool).toHaveProperty("description"); + expect(tool.description).toContain("documentation"); + }); + + test("tools should accept custom config", () => { + const resolveTool = resolveLibrary({ + apiKey: "ctx7sk-test-key", + }); + + const docsTool = getLibraryDocs({ + apiKey: "ctx7sk-test-key", + defaultMaxResults: 5, + }); + + expect(resolveTool).toHaveProperty("execute"); + expect(docsTool).toHaveProperty("execute"); + }); + }); + + describe("Tool usage with generateText", () => { + test("resolveLibrary tool should be called when searching for a library", async () => { + const result = await generateText({ + model: openai("gpt-4o-mini"), + tools: { + resolveLibrary: resolveLibrary(), + }, + toolChoice: "required", + stopWhen: stepCountIs(2), + prompt: "Search for 'react' library", + }); + + expect(result.toolCalls.length).toBeGreaterThan(0); + expect(result.toolCalls[0].toolName).toBe("resolveLibrary"); + expect(result.toolResults.length).toBeGreaterThan(0); + }, 30000); + + test("getLibraryDocs tool should fetch documentation", async () => { + const result = await generateText({ + model: openai("gpt-4o-mini"), + tools: { + getLibraryDocs: getLibraryDocs(), + }, + toolChoice: "required", + stopWhen: stepCountIs(2), + prompt: "Fetch documentation for library ID '/facebook/react' with topic 'hooks'", + }); + + expect(result.toolCalls.length).toBeGreaterThan(0); + expect(result.toolCalls[0].toolName).toBe("getLibraryDocs"); + expect(result.toolResults.length).toBeGreaterThan(0); + }, 30000); + + test("both tools can work together in a multi-step flow", async () => { + const result = await generateText({ + model: openai("gpt-4o-mini"), + tools: { + resolveLibrary: resolveLibrary(), + getLibraryDocs: getLibraryDocs(), + }, + stopWhen: stepCountIs(5), + prompt: + "First use resolveLibrary to find the Next.js library, then use getLibraryDocs to get documentation about routing", + }); + + const allToolCalls = result.steps.flatMap((step) => step.toolCalls); + const toolNames = allToolCalls.map((call) => call.toolName); + expect(toolNames).toContain("resolveLibrary"); + expect(toolNames).toContain("getLibraryDocs"); + }, 60000); + }); + + describe("context7Agent factory", () => { + test("should create an agent instance", () => { + const agent = context7Agent(); + + expect(agent).toBeDefined(); + expect(agent).toHaveProperty("generate"); + }); + + test("should accept custom stopWhen condition", async () => { + const { stepCountIs } = await import("ai"); + + const agent = context7Agent({ + stopWhen: stepCountIs(3), + }); + + expect(agent).toBeDefined(); + }); + + test("should accept custom system prompt", () => { + const agent = context7Agent({ + system: "Custom system prompt for testing", + }); + + expect(agent).toBeDefined(); + }); + }); + + describe("Prompt exports", () => { + test("should export SYSTEM_PROMPT", () => { + expect(SYSTEM_PROMPT).toBeDefined(); + expect(typeof SYSTEM_PROMPT).toBe("string"); + expect(SYSTEM_PROMPT.length).toBeGreaterThan(0); + }); + + test("should export AGENT_PROMPT", () => { + expect(AGENT_PROMPT).toBeDefined(); + expect(typeof AGENT_PROMPT).toBe("string"); + expect(AGENT_PROMPT).toContain("Context7"); + }); + + test("should export RESOLVE_LIBRARY_PROMPT", () => { + expect(RESOLVE_LIBRARY_PROMPT).toBeDefined(); + expect(typeof RESOLVE_LIBRARY_PROMPT).toBe("string"); + expect(RESOLVE_LIBRARY_PROMPT).toContain("library"); + }); + }); +}); diff --git a/packages/ai-sdk/src/index.ts b/packages/ai-sdk/src/index.ts new file mode 100644 index 000000000..94365adac --- /dev/null +++ b/packages/ai-sdk/src/index.ts @@ -0,0 +1,18 @@ +// Agents +export { context7Agent, type Context7AgentConfig } from "./agents"; + +// Tools +export { resolveLibrary, getLibraryDocs, type Context7ToolsConfig } from "./tools"; + +// Prompts +export { SYSTEM_PROMPT, AGENT_PROMPT, RESOLVE_LIBRARY_PROMPT } from "./prompts"; + +// Re-export useful types from SDK +export type { + SearchResult, + SearchLibraryResponse, + CodeDocsResponse, + TextDocsResponse, + InfoDocsResponse, + Pagination, +} from "@upstash/context7-sdk"; diff --git a/packages/ai-sdk/src/prompts/index.ts b/packages/ai-sdk/src/prompts/index.ts new file mode 100644 index 000000000..8976f2e2d --- /dev/null +++ b/packages/ai-sdk/src/prompts/index.ts @@ -0,0 +1,5 @@ +export { + SYSTEM_PROMPT, + AGENT_PROMPT, + RESOLVE_LIBRARY_PROMPT, +} from "./system"; diff --git a/packages/ai-sdk/src/prompts/system.ts b/packages/ai-sdk/src/prompts/system.ts new file mode 100644 index 000000000..353208df5 --- /dev/null +++ b/packages/ai-sdk/src/prompts/system.ts @@ -0,0 +1,75 @@ +/** + * System prompts for Context7 AI SDK agents + */ + +/** + * Basic documentation assistant prompt + */ +export const SYSTEM_PROMPT = `You are a documentation search assistant powered by Context7. + +Your role is to help users find accurate, up-to-date documentation for libraries and frameworks. + +When answering questions: +1. Search for the relevant library documentation +2. Provide code examples when available +3. Cite your sources by mentioning the library ID used`; + +/** + * Detailed multi-step workflow prompt for comprehensive documentation retrieval + */ +export const AGENT_PROMPT = `You are a documentation search assistant powered by Context7. + +CRITICAL WORKFLOW - YOU MUST FOLLOW THESE STEPS: + +Step 1: ALWAYS start by calling 'resolveLibrary' with the library name from the user's query + - Extract the main library/framework name (e.g., "React", "Next.js", "Vue") + - Call resolveLibrary with just the library name + - Review ALL the search results returned + +Step 2: Analyze the results from resolveLibrary and select the BEST library ID based on: + - Official sources (e.g., /reactjs/react.dev for React, /vercel/next.js for Next.js) + - Name similarity to what the user is looking for + - Description relevance + - Source reputation (High/Medium is better) + - Code snippet coverage (higher is better) + - Benchmark score (higher is better) + +Step 3: Call 'getLibraryDocs' with the selected library ID + - Use the exact library ID from the resolveLibrary results + - ALWAYS extract and include a relevant topic from the user's query (e.g., "Server-Side Rendering", "routing", "authentication") + - Start with page=1 (default) + +Step 4: If the documentation from page 1 isn't sufficient, call 'getLibraryDocs' again with page=2 + - Use the same library ID and the SAME topic from step 3 + - This gives you more comprehensive documentation + +Step 5: Provide a clear answer with code examples from the documentation + +IMPORTANT: +- You MUST call resolveLibrary first before calling getLibraryDocs +- Do NOT skip resolveLibrary - it helps you find the correct official documentation +- Always cite which library ID you used`; + +/** + * Library resolution instructions for the resolveLibrary tool + */ +export const RESOLVE_LIBRARY_PROMPT = `Resolves a package/product name to a Context7-compatible library ID and returns a list of matching libraries. + +You MUST call this function before 'getLibraryDocs' to obtain a valid Context7-compatible library ID UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query. + +Selection Process: +1. Analyze the query to understand what library/package the user is looking for +2. Return the most relevant match based on: +- Name similarity to the query (exact matches prioritized) +- Description relevance to the query's intent +- Documentation coverage (prioritize libraries with higher Code Snippet counts) +- Source reputation (consider libraries with High or Medium reputation more authoritative) +- Benchmark Score: Quality indicator (100 is the highest score) + +Response Format: +- Return the selected library ID in a clearly marked section +- Provide a brief explanation for why this library was chosen +- If multiple good matches exist, acknowledge this but proceed with the most relevant one +- If no good matches exist, clearly state this and suggest query refinements + +For ambiguous queries, request clarification before proceeding with a best-guess match.`; diff --git a/packages/ai-sdk/src/tools/context7.ts b/packages/ai-sdk/src/tools/context7.ts new file mode 100644 index 000000000..55f7059d3 --- /dev/null +++ b/packages/ai-sdk/src/tools/context7.ts @@ -0,0 +1,251 @@ +import { tool } from "ai"; +import { z } from "zod"; +import { Context7, type SearchResult } from "@upstash/context7-sdk"; +import { RESOLVE_LIBRARY_PROMPT } from "../prompts"; + +/** + * Configuration for Context7 tools + */ +export interface Context7ToolsConfig { + /** + * Context7 API key. If not provided, will use CONTEXT7_API_KEY environment variable. + */ + apiKey?: string; + /** + * Default maximum number of documentation results per page. + * @default 10 + */ + defaultMaxResults?: number; +} + +/** + * Formats search results for agent consumption + */ +function formatSearchResults(results: SearchResult[]): string { + if (!results || results.length === 0) { + return "No results found."; + } + + return results + .map((result, index) => { + const trustScore = result.trustScore + ? result.trustScore >= 0.7 + ? "High" + : result.trustScore >= 0.4 + ? "Medium" + : "Low" + : "Unknown"; + + const versions = result.versions?.length ? `\n Versions: ${result.versions.join(", ")}` : ""; + + return `${index + 1}. ${result.title} + Library ID: ${result.id} + Description: ${result.description} + Code Snippets: ${result.totalSnippets} + Source Reputation: ${trustScore} + Benchmark Score: ${result.benchmarkScore || "N/A"}${versions}`; + }) + .join("\n\n"); +} + +/** + * Tool to resolve a library name to a Context7-compatible library ID. + * + * Can be called with or without configuration. Uses CONTEXT7_API_KEY environment + * variable for authentication when no API key is provided. + * + * @param config Optional configuration options + * @returns AI SDK tool for library resolution + * + * @example + * ```typescript + * import { resolveLibrary, getLibraryDocs } from '@upstash/context7-ai-sdk'; + * import { generateText } from 'ai'; + * import { openai } from '@ai-sdk/openai'; + * + * // Simple usage - uses CONTEXT7_API_KEY env var + * const { text } = await generateText({ + * model: openai('gpt-4o'), + * prompt: 'Find React documentation about hooks', + * tools: { + * resolveLibrary: resolveLibrary(), + * getLibraryDocs: getLibraryDocs(), + * }, + * }); + * + * // With custom config + * const { text } = await generateText({ + * model: openai('gpt-4o'), + * prompt: 'Find React documentation about hooks', + * tools: { + * resolveLibrary: resolveLibrary({ apiKey: 'your-api-key' }), + * getLibraryDocs: getLibraryDocs({ apiKey: 'your-api-key' }), + * }, + * }); + * ``` + */ +export function resolveLibrary(config: Context7ToolsConfig = {}) { + const { apiKey = process.env.CONTEXT7_API_KEY } = config; + const getClient = () => new Context7({ apiKey }); + + return tool({ + description: RESOLVE_LIBRARY_PROMPT, + inputSchema: z.object({ + libraryName: z + .string() + .describe("Library name to search for and retrieve a Context7-compatible library ID."), + }), + execute: async ({ libraryName }: { libraryName: string }) => { + try { + const client = getClient(); + const response = await client.searchLibrary(libraryName); + + if (!response.results || response.results.length === 0) { + return { + success: false, + error: "No libraries found matching your query.", + suggestions: "Try a different search term or check the library name.", + }; + } + + const resultsText = formatSearchResults(response.results); + const topResult = response.results[0]!; + + return { + success: true, + results: resultsText, + totalResults: response.results.length, + topMatch: { + id: topResult.id, + name: topResult.title, + description: topResult.description, + }, + }; + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : "Failed to search libraries", + suggestions: "Check your API key and try again, or try a different search term.", + }; + } + }, + }); +} + +/** + * Tool to fetch documentation for a library using its Context7 library ID. + * + * Can be called with or without configuration. Uses CONTEXT7_API_KEY environment + * variable for authentication when no API key is provided. + * + * @param config Optional configuration options + * @returns AI SDK tool for fetching library documentation + * + * @example + * ```typescript + * import { resolveLibrary, getLibraryDocs } from '@upstash/context7-ai-sdk'; + * import { generateText } from 'ai'; + * import { openai } from '@ai-sdk/openai'; + * + * // Simple usage - uses CONTEXT7_API_KEY env var + * const { text } = await generateText({ + * model: openai('gpt-4o'), + * prompt: 'Find React documentation about hooks', + * tools: { + * resolveLibrary: resolveLibrary(), + * getLibraryDocs: getLibraryDocs(), + * }, + * }); + * + * // With custom config + * const { text } = await generateText({ + * model: openai('gpt-4o'), + * prompt: 'Find React documentation about hooks', + * tools: { + * resolveLibrary: resolveLibrary({ apiKey: 'your-api-key' }), + * getLibraryDocs: getLibraryDocs({ + * apiKey: 'your-api-key', + * defaultMaxResults: 5, + * }), + * }, + * }); + * ``` + */ +export function getLibraryDocs(config: Context7ToolsConfig = {}) { + const { apiKey = process.env.CONTEXT7_API_KEY, defaultMaxResults = 10 } = config; + const getClient = () => new Context7({ apiKey }); + + return tool({ + description: `Fetches up-to-date documentation for a library. You must call 'resolveLibrary' first to obtain the exact Context7-compatible library ID required to use this tool, UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query.`, + inputSchema: z.object({ + libraryId: z + .string() + .describe( + "Exact Context7-compatible library ID (e.g., '/mongodb/docs', '/vercel/next.js', '/supabase/supabase', '/vercel/next.js/v14.3.0-canary.87') retrieved from 'resolveLibrary' or directly from user query in the format '/org/project' or '/org/project/version'." + ), + topic: z + .string() + .optional() + .describe("Topic to focus documentation on (e.g., 'hooks', 'routing')."), + page: z + .number() + .int() + .min(1) + .max(10) + .optional() + .describe( + "Page number for pagination (start: 1, default: 1). If the context is not sufficient, try page=2, page=3, page=4, etc. with the same topic." + ), + maxResults: z + .number() + .int() + .min(1) + .max(10) + .optional() + .describe("Optional: Maximum number of documentation pages to retrieve (default: 10)"), + }), + execute: async ({ + libraryId, + topic, + page = 1, + maxResults = defaultMaxResults, + }: { + libraryId: string; + topic?: string; + page?: number; + maxResults?: number; + }) => { + try { + const client = getClient(); + const response = await client.getDocs(libraryId, { + page, + limit: maxResults, + topic: topic?.trim() || undefined, + format: "txt", + }); + + if (!response.content) { + return { + success: false, + error: + "Documentation not found or not finalized for this library. This might have happened because you used an invalid Context7-compatible library ID. To get a valid Context7-compatible library ID, use the 'resolveLibrary' with the package name you wish to retrieve documentation for.", + libraryId, + }; + } + + return { + success: true, + libraryId, + documentation: response.content, + pagination: response.pagination, + }; + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : "Failed to fetch documentation", + libraryId, + }; + } + }, + }); +} diff --git a/packages/ai-sdk/src/tools/index.ts b/packages/ai-sdk/src/tools/index.ts new file mode 100644 index 000000000..f38d69f8a --- /dev/null +++ b/packages/ai-sdk/src/tools/index.ts @@ -0,0 +1 @@ +export { resolveLibrary, getLibraryDocs, type Context7ToolsConfig } from "./context7"; diff --git a/packages/ai-sdk/tsconfig.json b/packages/ai-sdk/tsconfig.json new file mode 100644 index 000000000..158fb487d --- /dev/null +++ b/packages/ai-sdk/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "lib": ["ESNext"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true + }, + "include": ["src/**/*", "tsup.config.ts", "vitest.config.ts", "eslint.config.js"], + "exclude": ["node_modules", "dist", "examples"] +} diff --git a/packages/ai-sdk/tsup.config.ts b/packages/ai-sdk/tsup.config.ts new file mode 100644 index 000000000..fca0e2243 --- /dev/null +++ b/packages/ai-sdk/tsup.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: { + index: "./src/index.ts", + agent: "./src/agents/index.ts", + }, + format: ["cjs", "esm"], + clean: true, + dts: true, +}); diff --git a/packages/ai-sdk/vitest.config.ts b/packages/ai-sdk/vitest.config.ts new file mode 100644 index 000000000..0f78dc014 --- /dev/null +++ b/packages/ai-sdk/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + globals: true, + environment: "node", + include: ["src/**/*.test.ts"], + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 58cde6489..f1ea2c8ea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,6 +39,37 @@ importers: specifier: ^8.28.0 version: 8.47.0(eslint@9.39.1)(typescript@5.9.3) + packages/ai-sdk: + dependencies: + '@upstash/context7-sdk': + specifier: workspace:* + version: link:../sdk + ai: + specifier: ^5.0.0 + version: 5.0.104(zod@3.25.76) + zod: + specifier: ^3.24.0 + version: 3.25.76 + devDependencies: + '@ai-sdk/anthropic': + specifier: ^2.0.0 + version: 2.0.50(zod@3.25.76) + '@ai-sdk/openai': + specifier: ^2.0.74 + version: 2.0.74(zod@3.25.76) + '@types/node': + specifier: ^22.13.14 + version: 22.19.1 + tsup: + specifier: ^8.5.1 + version: 8.5.1(postcss@8.5.6)(typescript@5.9.3) + typescript: + specifier: ^5.8.2 + version: 5.9.3 + vitest: + specifier: ^4.0.13 + version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@22.19.1) + packages/mcp: dependencies: '@modelcontextprotocol/sdk': @@ -83,10 +114,38 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.13 - version: 4.0.14(@types/node@22.19.1) + version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@22.19.1) packages: + '@ai-sdk/anthropic@2.0.50': + resolution: {integrity: sha512-21PaHfoLmouOXXNINTsZJsMw+wE5oLR2He/1kq/sKokTVKyq7ObGT1LDk6ahwxaz/GoaNaGankMh+EgVcdv2Cw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/gateway@2.0.17': + resolution: {integrity: sha512-oVAG6q72KsjKlrYdLhWjRO7rcqAR8CjokAbYuyVZoCO4Uh2PH/VzZoxZav71w2ipwlXhHCNaInGYWNs889MMDA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/openai@2.0.74': + resolution: {integrity: sha512-vvsL7rGoBEyQIePs630p31ebLeF+xxwLOrRKeIArHko8w7Wh9Kj3wL4Ns+PCzrEpAij31OKKDcxLQ1dSIg/qMw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider-utils@3.0.18': + resolution: {integrity: sha512-ypv1xXMsgGcNKUP+hglKqtdDuMg68nWHucPPAhIENrbFAI+xCHiqPVN8Zllxyv1TNZwGWUghPxJXU+Mqps0YRQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider@2.0.0': + resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==} + engines: {node: '>=18'} + '@babel/runtime@7.28.4': resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} @@ -561,6 +620,10 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + engines: {node: '>=8.0.0'} + '@pkgr/core@0.2.9': resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -788,6 +851,10 @@ packages: resolution: {integrity: sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@vercel/oidc@3.0.5': + resolution: {integrity: sha512-fnYhv671l+eTTp48gB4zEsTW/YtRgRPnkI2nT7x6qw5rkI1Lq2hTmQIpHPgyThI0znLK+vX2n9XxKdXZ7BUbbw==} + engines: {node: '>= 20'} + '@vitest/expect@4.0.14': resolution: {integrity: sha512-RHk63V3zvRiYOWAV0rGEBRO820ce17hz7cI2kDmEdfQsBjT2luEKB5tCOc91u1oSQoUOZkSv3ZyzkdkSLD7lKw==} @@ -831,6 +898,12 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + ai@5.0.104: + resolution: {integrity: sha512-MZOkL9++nY5PfkpWKBR3Rv+Oygxpb9S16ctv8h91GvrSif7UnNEdPMVZe3bUyMd2djxf0AtBk/csBixP0WwWZQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -1380,6 +1453,9 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -2009,6 +2085,36 @@ packages: snapshots: + '@ai-sdk/anthropic@2.0.50(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 2.0.0 + '@ai-sdk/provider-utils': 3.0.18(zod@3.25.76) + zod: 3.25.76 + + '@ai-sdk/gateway@2.0.17(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 2.0.0 + '@ai-sdk/provider-utils': 3.0.18(zod@3.25.76) + '@vercel/oidc': 3.0.5 + zod: 3.25.76 + + '@ai-sdk/openai@2.0.74(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 2.0.0 + '@ai-sdk/provider-utils': 3.0.18(zod@3.25.76) + zod: 3.25.76 + + '@ai-sdk/provider-utils@3.0.18(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 2.0.0 + '@standard-schema/spec': 1.0.0 + eventsource-parser: 3.0.6 + zod: 3.25.76 + + '@ai-sdk/provider@2.0.0': + dependencies: + json-schema: 0.4.0 + '@babel/runtime@7.28.4': {} '@changesets/apply-release-plan@7.0.13': @@ -2435,6 +2541,8 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 + '@opentelemetry/api@1.9.0': {} + '@pkgr/core@0.2.9': {} '@rollup/rollup-android-arm-eabi@4.53.3': @@ -2660,6 +2768,8 @@ snapshots: '@typescript-eslint/types': 8.47.0 eslint-visitor-keys: 4.2.1 + '@vercel/oidc@3.0.5': {} + '@vitest/expect@4.0.14': dependencies: '@standard-schema/spec': 1.0.0 @@ -2710,6 +2820,14 @@ snapshots: acorn@8.15.0: {} + ai@5.0.104(zod@3.25.76): + dependencies: + '@ai-sdk/gateway': 2.0.17(zod@3.25.76) + '@ai-sdk/provider': 2.0.0 + '@ai-sdk/provider-utils': 3.0.18(zod@3.25.76) + '@opentelemetry/api': 1.9.0 + zod: 3.25.76 + ajv-formats@3.0.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 @@ -3296,6 +3414,8 @@ snapshots: json-schema-traverse@1.0.0: {} + json-schema@0.4.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} jsonfile@4.0.0: @@ -3803,7 +3923,7 @@ snapshots: '@types/node': 22.19.1 fsevents: 2.3.3 - vitest@4.0.14(@types/node@22.19.1): + vitest@4.0.14(@opentelemetry/api@1.9.0)(@types/node@22.19.1): dependencies: '@vitest/expect': 4.0.14 '@vitest/mocker': 4.0.14(vite@7.2.4(@types/node@22.19.1)) @@ -3826,6 +3946,7 @@ snapshots: vite: 7.2.4(@types/node@22.19.1) why-is-node-running: 2.3.0 optionalDependencies: + '@opentelemetry/api': 1.9.0 '@types/node': 22.19.1 transitivePeerDependencies: - jiti From 6156060fac520834791f417453bf0bff9a590be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Sun, 30 Nov 2025 20:20:18 +0300 Subject: [PATCH 02/36] ci: remove master target condition on test action --- .github/workflows/test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8e706a2a7..6d4796d43 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,7 +2,6 @@ name: Test on: pull_request: - branches: [master] push: branches: [master] From ff65e5ddcc9120c43c2a97bcdfbfe4f92796a4c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Sun, 30 Nov 2025 20:22:07 +0300 Subject: [PATCH 03/36] ci: manual actions trigger for test --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6d4796d43..05dd6aa27 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,6 +4,7 @@ on: pull_request: push: branches: [master] + workflow_dispatch: jobs: detect-changes: From dd01697da8441906f071bb43aa0bd4e5b3787a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Sun, 30 Nov 2025 20:24:52 +0300 Subject: [PATCH 04/36] ci: always run all tests --- .github/workflows/test.yml | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 05dd6aa27..c0510c335 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,31 +7,8 @@ on: workflow_dispatch: jobs: - detect-changes: - runs-on: ubuntu-latest - outputs: - packages: ${{ steps.filter.outputs.changes }} - steps: - - uses: actions/checkout@v4 - - - uses: dorny/paths-filter@v3 - id: filter - with: - filters: | - sdk: - - 'packages/sdk/**' - mcp: - - 'packages/mcp/**' - ai-sdk: - - 'packages/ai-sdk/**' - test: - needs: detect-changes - if: ${{ needs.detect-changes.outputs.packages != '[]' }} runs-on: ubuntu-latest - strategy: - matrix: - package: ${{ fromJson(needs.detect-changes.outputs.packages) }} steps: - uses: actions/checkout@v4 @@ -48,14 +25,14 @@ jobs: - name: Install Dependencies run: pnpm install --frozen-lockfile - - name: Build dependencies + - name: Build run: pnpm build - - name: Typecheck ${{ matrix.package }} - run: pnpm --filter @upstash/context7-${{ matrix.package }} typecheck || true + - name: Typecheck + run: pnpm typecheck - - name: Test ${{ matrix.package }} - run: pnpm --filter @upstash/context7-${{ matrix.package }} test + - name: Test + run: pnpm test env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} CONTEXT7_API_KEY: ${{ secrets.CONTEXT7_API_KEY }} From 1bf82d95062c322c58788cf661a7679c0d8cd32c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Sun, 30 Nov 2025 20:59:07 +0300 Subject: [PATCH 05/36] update tests and imports --- .github/workflows/test.yml | 3 +- packages/ai-sdk/package.json | 15 +-- packages/ai-sdk/src/agents/context7.ts | 4 +- packages/ai-sdk/src/index.test.ts | 13 ++- packages/ai-sdk/src/index.ts | 6 +- packages/ai-sdk/src/prompts/index.ts | 6 +- packages/ai-sdk/src/tools/context7.ts | 2 +- packages/ai-sdk/tsconfig.json | 8 +- packages/ai-sdk/tsup.config.ts | 7 ++ packages/ai-sdk/vitest.config.ts | 8 ++ pnpm-lock.yaml | 150 ++++++++++++++++++++++--- 11 files changed, 175 insertions(+), 47 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c0510c335..cb31eb398 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,5 +34,6 @@ jobs: - name: Test run: pnpm test env: - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + AWS_REGION: ${{ secrets.AWS_REGION }} + AWS_BEARER_TOKEN_BEDROCK: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }} CONTEXT7_API_KEY: ${{ secrets.CONTEXT7_API_KEY }} diff --git a/packages/ai-sdk/package.json b/packages/ai-sdk/package.json index 86b4e3e04..69eaa2782 100644 --- a/packages/ai-sdk/package.json +++ b/packages/ai-sdk/package.json @@ -34,25 +34,12 @@ "zod": "^3.24.0" }, "devDependencies": { - "@ai-sdk/anthropic": "^2.0.0", - "@ai-sdk/openai": "^2.0.74", + "@ai-sdk/amazon-bedrock": "^3.0.55", "@types/node": "^22.13.14", "tsup": "^8.5.1", "typescript": "^5.8.2", "vitest": "^4.0.13" }, - "peerDependencies": { - "@ai-sdk/anthropic": "^2.0.0", - "@ai-sdk/openai": "^2.0.0" - }, - "peerDependenciesMeta": { - "@ai-sdk/anthropic": { - "optional": true - }, - "@ai-sdk/openai": { - "optional": true - } - }, "repository": { "type": "git", "url": "git+https://github.com/upstash/context7.git", diff --git a/packages/ai-sdk/src/agents/context7.ts b/packages/ai-sdk/src/agents/context7.ts index e3e9dca56..d42b20ba5 100644 --- a/packages/ai-sdk/src/agents/context7.ts +++ b/packages/ai-sdk/src/agents/context7.ts @@ -4,8 +4,8 @@ import { type LanguageModel, stepCountIs, } from "ai"; -import { resolveLibrary, getLibraryDocs, type Context7ToolsConfig } from "../tools"; -import { AGENT_PROMPT } from "../prompts"; +import { resolveLibrary, getLibraryDocs, type Context7ToolsConfig } from "@tools"; +import { AGENT_PROMPT } from "@prompts"; /** * Configuration for Context7 agent diff --git a/packages/ai-sdk/src/index.test.ts b/packages/ai-sdk/src/index.test.ts index 414121975..0c5a965a3 100644 --- a/packages/ai-sdk/src/index.test.ts +++ b/packages/ai-sdk/src/index.test.ts @@ -1,6 +1,6 @@ import { describe, test, expect } from "vitest"; import { generateText, stepCountIs } from "ai"; -import { openai } from "@ai-sdk/openai"; +import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock"; import { resolveLibrary, getLibraryDocs, @@ -10,6 +10,11 @@ import { RESOLVE_LIBRARY_PROMPT, } from "./index"; +const bedrock = createAmazonBedrock({ + region: process.env.AWS_REGION, + apiKey: process.env.AWS_BEARER_TOKEN_BEDROCK, +}); + describe("@upstash/context7-ai-sdk", () => { describe("Tool structure", () => { test("resolveLibrary() should return a tool object with correct structure", () => { @@ -50,7 +55,7 @@ describe("@upstash/context7-ai-sdk", () => { describe("Tool usage with generateText", () => { test("resolveLibrary tool should be called when searching for a library", async () => { const result = await generateText({ - model: openai("gpt-4o-mini"), + model: bedrock("anthropic.claude-3-haiku-20240307-v1:0"), tools: { resolveLibrary: resolveLibrary(), }, @@ -66,7 +71,7 @@ describe("@upstash/context7-ai-sdk", () => { test("getLibraryDocs tool should fetch documentation", async () => { const result = await generateText({ - model: openai("gpt-4o-mini"), + model: bedrock("anthropic.claude-3-haiku-20240307-v1:0"), tools: { getLibraryDocs: getLibraryDocs(), }, @@ -82,7 +87,7 @@ describe("@upstash/context7-ai-sdk", () => { test("both tools can work together in a multi-step flow", async () => { const result = await generateText({ - model: openai("gpt-4o-mini"), + model: bedrock("anthropic.claude-3-haiku-20240307-v1:0"), tools: { resolveLibrary: resolveLibrary(), getLibraryDocs: getLibraryDocs(), diff --git a/packages/ai-sdk/src/index.ts b/packages/ai-sdk/src/index.ts index 94365adac..719bc26bb 100644 --- a/packages/ai-sdk/src/index.ts +++ b/packages/ai-sdk/src/index.ts @@ -1,11 +1,11 @@ // Agents -export { context7Agent, type Context7AgentConfig } from "./agents"; +export { context7Agent, type Context7AgentConfig } from "@agents"; // Tools -export { resolveLibrary, getLibraryDocs, type Context7ToolsConfig } from "./tools"; +export { resolveLibrary, getLibraryDocs, type Context7ToolsConfig } from "@tools"; // Prompts -export { SYSTEM_PROMPT, AGENT_PROMPT, RESOLVE_LIBRARY_PROMPT } from "./prompts"; +export { SYSTEM_PROMPT, AGENT_PROMPT, RESOLVE_LIBRARY_PROMPT } from "@prompts"; // Re-export useful types from SDK export type { diff --git a/packages/ai-sdk/src/prompts/index.ts b/packages/ai-sdk/src/prompts/index.ts index 8976f2e2d..e4b372c10 100644 --- a/packages/ai-sdk/src/prompts/index.ts +++ b/packages/ai-sdk/src/prompts/index.ts @@ -1,5 +1 @@ -export { - SYSTEM_PROMPT, - AGENT_PROMPT, - RESOLVE_LIBRARY_PROMPT, -} from "./system"; +export { SYSTEM_PROMPT, AGENT_PROMPT, RESOLVE_LIBRARY_PROMPT } from "./system"; diff --git a/packages/ai-sdk/src/tools/context7.ts b/packages/ai-sdk/src/tools/context7.ts index 55f7059d3..83888feda 100644 --- a/packages/ai-sdk/src/tools/context7.ts +++ b/packages/ai-sdk/src/tools/context7.ts @@ -1,7 +1,7 @@ import { tool } from "ai"; import { z } from "zod"; import { Context7, type SearchResult } from "@upstash/context7-sdk"; -import { RESOLVE_LIBRARY_PROMPT } from "../prompts"; +import { RESOLVE_LIBRARY_PROMPT } from "@prompts"; /** * Configuration for Context7 tools diff --git a/packages/ai-sdk/tsconfig.json b/packages/ai-sdk/tsconfig.json index 158fb487d..67cbe80f1 100644 --- a/packages/ai-sdk/tsconfig.json +++ b/packages/ai-sdk/tsconfig.json @@ -12,7 +12,13 @@ "skipLibCheck": true, "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, - "allowJs": true + "allowJs": true, + "baseUrl": ".", + "paths": { + "@tools": ["./src/tools/index.ts"], + "@agents": ["./src/agents/index.ts"], + "@prompts": ["./src/prompts/index.ts"] + } }, "include": ["src/**/*", "tsup.config.ts", "vitest.config.ts", "eslint.config.js"], "exclude": ["node_modules", "dist", "examples"] diff --git a/packages/ai-sdk/tsup.config.ts b/packages/ai-sdk/tsup.config.ts index fca0e2243..590d55a08 100644 --- a/packages/ai-sdk/tsup.config.ts +++ b/packages/ai-sdk/tsup.config.ts @@ -8,4 +8,11 @@ export default defineConfig({ format: ["cjs", "esm"], clean: true, dts: true, + esbuildOptions(options) { + options.alias = { + "@tools": "./src/tools/index.ts", + "@agents": "./src/agents/index.ts", + "@prompts": "./src/prompts/index.ts", + }; + }, }); diff --git a/packages/ai-sdk/vitest.config.ts b/packages/ai-sdk/vitest.config.ts index 0f78dc014..00e330328 100644 --- a/packages/ai-sdk/vitest.config.ts +++ b/packages/ai-sdk/vitest.config.ts @@ -1,4 +1,5 @@ import { defineConfig } from "vitest/config"; +import path from "path"; export default defineConfig({ test: { @@ -6,4 +7,11 @@ export default defineConfig({ environment: "node", include: ["src/**/*.test.ts"], }, + resolve: { + alias: { + "@tools": path.resolve(__dirname, "./src/tools/index.ts"), + "@agents": path.resolve(__dirname, "./src/agents/index.ts"), + "@prompts": path.resolve(__dirname, "./src/prompts/index.ts"), + }, + }, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f1ea2c8ea..3b9f2a124 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,12 +51,9 @@ importers: specifier: ^3.24.0 version: 3.25.76 devDependencies: - '@ai-sdk/anthropic': - specifier: ^2.0.0 - version: 2.0.50(zod@3.25.76) - '@ai-sdk/openai': - specifier: ^2.0.74 - version: 2.0.74(zod@3.25.76) + '@ai-sdk/amazon-bedrock': + specifier: ^3.0.55 + version: 3.0.62(zod@3.25.76) '@types/node': specifier: ^22.13.14 version: 22.19.1 @@ -118,20 +115,20 @@ importers: packages: - '@ai-sdk/anthropic@2.0.50': - resolution: {integrity: sha512-21PaHfoLmouOXXNINTsZJsMw+wE5oLR2He/1kq/sKokTVKyq7ObGT1LDk6ahwxaz/GoaNaGankMh+EgVcdv2Cw==} + '@ai-sdk/amazon-bedrock@3.0.62': + resolution: {integrity: sha512-vVtndaj5zfHmgw8NSqN4baFDbFDTBZP6qufhKfqSNLtygEm8+8PL9XQX9urgzSzU3zp+zi3AmNNemvKLkkqblg==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/gateway@2.0.17': - resolution: {integrity: sha512-oVAG6q72KsjKlrYdLhWjRO7rcqAR8CjokAbYuyVZoCO4Uh2PH/VzZoxZav71w2ipwlXhHCNaInGYWNs889MMDA==} + '@ai-sdk/anthropic@2.0.50': + resolution: {integrity: sha512-21PaHfoLmouOXXNINTsZJsMw+wE5oLR2He/1kq/sKokTVKyq7ObGT1LDk6ahwxaz/GoaNaGankMh+EgVcdv2Cw==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai@2.0.74': - resolution: {integrity: sha512-vvsL7rGoBEyQIePs630p31ebLeF+xxwLOrRKeIArHko8w7Wh9Kj3wL4Ns+PCzrEpAij31OKKDcxLQ1dSIg/qMw==} + '@ai-sdk/gateway@2.0.17': + resolution: {integrity: sha512-oVAG6q72KsjKlrYdLhWjRO7rcqAR8CjokAbYuyVZoCO4Uh2PH/VzZoxZav71w2ipwlXhHCNaInGYWNs889MMDA==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -146,6 +143,17 @@ packages: resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==} engines: {node: '>=18'} + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/types@3.936.0': + resolution: {integrity: sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg==} + engines: {node: '>=18.0.0'} + '@babel/runtime@7.28.4': resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} @@ -738,6 +746,42 @@ packages: cpu: [x64] os: [win32] + '@smithy/eventstream-codec@4.2.5': + resolution: {integrity: sha512-Ogt4Zi9hEbIP17oQMd68qYOHUzmH47UkK7q7Gl55iIm9oKt27MUGrC5JfpMroeHjdkOliOA4Qt3NQ1xMq/nrlA==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/is-array-buffer@4.2.0': + resolution: {integrity: sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.9.0': + resolution: {integrity: sha512-MvUbdnXDTwykR8cB1WZvNNwqoWVaTRA0RLlLmf/cIFNMM2cKWz01X4Ly6SMC4Kks30r8tT3Cty0jmeWfiuyHTA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-buffer-from@4.2.0': + resolution: {integrity: sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==} + engines: {node: '>=18.0.0'} + + '@smithy/util-hex-encoding@4.2.0': + resolution: {integrity: sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@4.2.0': + resolution: {integrity: sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==} + engines: {node: '>=18.0.0'} + '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} @@ -947,6 +991,9 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + aws4fetch@1.0.20: + resolution: {integrity: sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -1916,6 +1963,9 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsup@8.5.1: resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} engines: {node: '>=18'} @@ -2085,23 +2135,27 @@ packages: snapshots: - '@ai-sdk/anthropic@2.0.50(zod@3.25.76)': + '@ai-sdk/amazon-bedrock@3.0.62(zod@3.25.76)': dependencies: + '@ai-sdk/anthropic': 2.0.50(zod@3.25.76) '@ai-sdk/provider': 2.0.0 '@ai-sdk/provider-utils': 3.0.18(zod@3.25.76) + '@smithy/eventstream-codec': 4.2.5 + '@smithy/util-utf8': 4.2.0 + aws4fetch: 1.0.20 zod: 3.25.76 - '@ai-sdk/gateway@2.0.17(zod@3.25.76)': + '@ai-sdk/anthropic@2.0.50(zod@3.25.76)': dependencies: '@ai-sdk/provider': 2.0.0 '@ai-sdk/provider-utils': 3.0.18(zod@3.25.76) - '@vercel/oidc': 3.0.5 zod: 3.25.76 - '@ai-sdk/openai@2.0.74(zod@3.25.76)': + '@ai-sdk/gateway@2.0.17(zod@3.25.76)': dependencies: '@ai-sdk/provider': 2.0.0 '@ai-sdk/provider-utils': 3.0.18(zod@3.25.76) + '@vercel/oidc': 3.0.5 zod: 3.25.76 '@ai-sdk/provider-utils@3.0.18(zod@3.25.76)': @@ -2115,6 +2169,23 @@ snapshots: dependencies: json-schema: 0.4.0 + '@aws-crypto/crc32@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.936.0 + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/types@3.936.0': + dependencies: + '@smithy/types': 4.9.0 + tslib: 2.8.1 + '@babel/runtime@7.28.4': {} '@changesets/apply-release-plan@7.0.13': @@ -2611,6 +2682,49 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.53.3': optional: true + '@smithy/eventstream-codec@4.2.5': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.9.0 + '@smithy/util-hex-encoding': 4.2.0 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/is-array-buffer@4.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/types@4.9.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-buffer-from@4.2.0': + dependencies: + '@smithy/is-array-buffer': 4.2.0 + tslib: 2.8.1 + + '@smithy/util-hex-encoding@4.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@4.2.0': + dependencies: + '@smithy/util-buffer-from': 4.2.0 + tslib: 2.8.1 + '@standard-schema/spec@1.0.0': {} '@types/body-parser@1.19.6': @@ -2866,6 +2980,8 @@ snapshots: assertion-error@2.0.1: {} + aws4fetch@1.0.20: {} + balanced-match@1.0.2: {} better-path-resolve@1.0.0: @@ -3844,6 +3960,8 @@ snapshots: ts-interface-checker@0.1.13: {} + tslib@2.8.1: {} + tsup@8.5.1(postcss@8.5.6)(typescript@5.9.3): dependencies: bundle-require: 5.1.0(esbuild@0.27.0) From b6b5d3cd5073f7c0bd152cb5a6329536880d4263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Sun, 30 Nov 2025 21:04:40 +0300 Subject: [PATCH 06/36] ci: typecheck command --- package.json | 1 + packages/mcp/package.json | 3 ++- packages/sdk/package.json | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index dde54acc6..5b588ae9b 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build:sdk": "pnpm --filter @upstash/context7-sdk build", "build:mcp": "pnpm --filter @upstash/context7-mcp build", "build:ai-sdk": "pnpm --filter @upstash/context7-ai-sdk build", + "typecheck": "pnpm -r run typecheck", "test": "pnpm -r run test", "test:sdk": "pnpm --filter @upstash/context7-sdk test", "test:ai-sdk": "pnpm --filter @upstash/context7-ai-sdk test", diff --git a/packages/mcp/package.json b/packages/mcp/package.json index 8425abb85..5cb232e6f 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -5,7 +5,8 @@ "description": "MCP server for Context7", "scripts": { "build": "tsc && chmod 755 dist/index.js", - "test": "echo \"Error: no test specified\" && exit 1", + "test": "echo \"No tests yet\"", + "typecheck": "tsc --noEmit", "lint": "eslint .", "lint:check": "eslint .", "format": "prettier --write .", diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 9bc2006c1..e556295c3 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -6,6 +6,7 @@ "build": "tsup", "test": "vitest run", "test:watch": "vitest", + "typecheck": "tsc --noEmit", "dev": "tsup --watch", "clean": "rm -rf dist", "lint": "eslint .", From 28efd6003336c814296fa4235661786e427ba6f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Sun, 30 Nov 2025 21:13:10 +0300 Subject: [PATCH 07/36] fix: tests --- packages/ai-sdk/src/index.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ai-sdk/src/index.test.ts b/packages/ai-sdk/src/index.test.ts index 0c5a965a3..b6ba61858 100644 --- a/packages/ai-sdk/src/index.test.ts +++ b/packages/ai-sdk/src/index.test.ts @@ -59,7 +59,7 @@ describe("@upstash/context7-ai-sdk", () => { tools: { resolveLibrary: resolveLibrary(), }, - toolChoice: "required", + toolChoice: { type: "tool", toolName: "resolveLibrary" }, stopWhen: stepCountIs(2), prompt: "Search for 'react' library", }); @@ -75,7 +75,7 @@ describe("@upstash/context7-ai-sdk", () => { tools: { getLibraryDocs: getLibraryDocs(), }, - toolChoice: "required", + toolChoice: { type: "tool", toolName: "getLibraryDocs" }, stopWhen: stepCountIs(2), prompt: "Fetch documentation for library ID '/facebook/react' with topic 'hooks'", }); From 677c173feea7c5a1830ba5e47742102654850a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Tue, 2 Dec 2025 18:55:51 +0300 Subject: [PATCH 08/36] docs: add readme --- packages/ai-sdk/README.md | 101 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 packages/ai-sdk/README.md diff --git a/packages/ai-sdk/README.md b/packages/ai-sdk/README.md new file mode 100644 index 000000000..5687c5941 --- /dev/null +++ b/packages/ai-sdk/README.md @@ -0,0 +1,101 @@ +# Upstash Context7 AI SDK + +`@upstash/context7-ai-sdk` provides [Vercel AI SDK](https://sdk.vercel.ai/) compatible tools and agents that give your AI applications access to up to date library documentation through Context7. + +Use this package to: + +- Add documentation lookup tools to your AI SDK workflows with `generateText` or `streamText` +- Create documentation aware agents using the pre-configured `context7Agent` +- Build RAG pipelines that retrieve accurate, version specific code examples + +The package provides two main tools: + +- `resolveLibrary` - Searches Context7's database to find the correct library ID +- `getLibraryDocs` - Fetches documentation for a specific library with optional topic filtering + +## Quick Start + +### Install + +```bash +npm install @upstash/context7-ai-sdk +``` + +### Get API Key + +Get your API key from [Context7](https://context7.com) + +## Usage + +### Using Tools with `generateText` + +```typescript +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; +import { generateText } from "ai"; +import { openai } from "@ai-sdk/openai"; + +const { text } = await generateText({ + model: openai("gpt-4o"), + prompt: "How do I use React Server Components?", + tools: { + resolveLibrary: resolveLibrary(), + getLibraryDocs: getLibraryDocs(), + }, + maxSteps: 5, +}); + +console.log(text); +``` + +### Using the Context7 Agent + +The package provides a pre-configured agent that handles the multi-step workflow automatically: + +```typescript +import { context7Agent } from "@upstash/context7-ai-sdk"; +import { anthropic } from "@ai-sdk/anthropic"; + +const agent = context7Agent({ + model: anthropic("claude-sonnet-4-20250514"), +}); + +const { text } = await agent.generate({ + prompt: "How do I set up routing in Next.js?", +}); + +console.log(text); +``` + +## Configuration + +### Environment Variables + +Set your API key via environment variable: + +```sh +CONTEXT7_API_KEY=ctx7sk-... +``` + +Then use tools and agents without explicit configuration: + +```typescript +const tool = resolveLibrary(); // Uses CONTEXT7_API_KEY automatically +``` + +## Docs + +See the [documentation](https://context7.com/docs/sdks/ai-sdk/getting-started) for details. + +## Contributing + +### Running tests + +```sh +pnpm test +``` + +### Building + +```sh +pnpm build +``` From 908d522200be9122bbfd18bbea349d6578b44585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Wed, 3 Dec 2025 11:57:10 +0300 Subject: [PATCH 09/36] update folder structure and tool descriptions --- packages/ai-sdk/src/prompts/index.ts | 7 +- packages/ai-sdk/src/prompts/system.ts | 3 + packages/ai-sdk/src/tools/context7.ts | 251 ------------------ packages/ai-sdk/src/tools/get-library-docs.ts | 114 ++++++++ packages/ai-sdk/src/tools/index.ts | 4 +- packages/ai-sdk/src/tools/resolve-library.ts | 70 +++++ packages/ai-sdk/src/tools/types.ts | 14 + 7 files changed, 210 insertions(+), 253 deletions(-) delete mode 100644 packages/ai-sdk/src/tools/context7.ts create mode 100644 packages/ai-sdk/src/tools/get-library-docs.ts create mode 100644 packages/ai-sdk/src/tools/resolve-library.ts create mode 100644 packages/ai-sdk/src/tools/types.ts diff --git a/packages/ai-sdk/src/prompts/index.ts b/packages/ai-sdk/src/prompts/index.ts index e4b372c10..9c5c7312c 100644 --- a/packages/ai-sdk/src/prompts/index.ts +++ b/packages/ai-sdk/src/prompts/index.ts @@ -1 +1,6 @@ -export { SYSTEM_PROMPT, AGENT_PROMPT, RESOLVE_LIBRARY_PROMPT } from "./system"; +export { + SYSTEM_PROMPT, + AGENT_PROMPT, + RESOLVE_LIBRARY_PROMPT, + GET_LIBRARY_DOCS_PROMPT, +} from "./system"; diff --git a/packages/ai-sdk/src/prompts/system.ts b/packages/ai-sdk/src/prompts/system.ts index 353208df5..2e218a629 100644 --- a/packages/ai-sdk/src/prompts/system.ts +++ b/packages/ai-sdk/src/prompts/system.ts @@ -73,3 +73,6 @@ Response Format: - If no good matches exist, clearly state this and suggest query refinements For ambiguous queries, request clarification before proceeding with a best-guess match.`; + +export const GET_LIBRARY_DOCS_PROMPT = + "Fetches up-to-date documentation for a library. You must call 'resolveLibrary' first to obtain the exact Context7-compatible library ID required to use this tool, UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query. Use mode='code' (default) for API references and code examples, or mode='info' for conceptual guides, narrative information, and architectural questions."; diff --git a/packages/ai-sdk/src/tools/context7.ts b/packages/ai-sdk/src/tools/context7.ts deleted file mode 100644 index 83888feda..000000000 --- a/packages/ai-sdk/src/tools/context7.ts +++ /dev/null @@ -1,251 +0,0 @@ -import { tool } from "ai"; -import { z } from "zod"; -import { Context7, type SearchResult } from "@upstash/context7-sdk"; -import { RESOLVE_LIBRARY_PROMPT } from "@prompts"; - -/** - * Configuration for Context7 tools - */ -export interface Context7ToolsConfig { - /** - * Context7 API key. If not provided, will use CONTEXT7_API_KEY environment variable. - */ - apiKey?: string; - /** - * Default maximum number of documentation results per page. - * @default 10 - */ - defaultMaxResults?: number; -} - -/** - * Formats search results for agent consumption - */ -function formatSearchResults(results: SearchResult[]): string { - if (!results || results.length === 0) { - return "No results found."; - } - - return results - .map((result, index) => { - const trustScore = result.trustScore - ? result.trustScore >= 0.7 - ? "High" - : result.trustScore >= 0.4 - ? "Medium" - : "Low" - : "Unknown"; - - const versions = result.versions?.length ? `\n Versions: ${result.versions.join(", ")}` : ""; - - return `${index + 1}. ${result.title} - Library ID: ${result.id} - Description: ${result.description} - Code Snippets: ${result.totalSnippets} - Source Reputation: ${trustScore} - Benchmark Score: ${result.benchmarkScore || "N/A"}${versions}`; - }) - .join("\n\n"); -} - -/** - * Tool to resolve a library name to a Context7-compatible library ID. - * - * Can be called with or without configuration. Uses CONTEXT7_API_KEY environment - * variable for authentication when no API key is provided. - * - * @param config Optional configuration options - * @returns AI SDK tool for library resolution - * - * @example - * ```typescript - * import { resolveLibrary, getLibraryDocs } from '@upstash/context7-ai-sdk'; - * import { generateText } from 'ai'; - * import { openai } from '@ai-sdk/openai'; - * - * // Simple usage - uses CONTEXT7_API_KEY env var - * const { text } = await generateText({ - * model: openai('gpt-4o'), - * prompt: 'Find React documentation about hooks', - * tools: { - * resolveLibrary: resolveLibrary(), - * getLibraryDocs: getLibraryDocs(), - * }, - * }); - * - * // With custom config - * const { text } = await generateText({ - * model: openai('gpt-4o'), - * prompt: 'Find React documentation about hooks', - * tools: { - * resolveLibrary: resolveLibrary({ apiKey: 'your-api-key' }), - * getLibraryDocs: getLibraryDocs({ apiKey: 'your-api-key' }), - * }, - * }); - * ``` - */ -export function resolveLibrary(config: Context7ToolsConfig = {}) { - const { apiKey = process.env.CONTEXT7_API_KEY } = config; - const getClient = () => new Context7({ apiKey }); - - return tool({ - description: RESOLVE_LIBRARY_PROMPT, - inputSchema: z.object({ - libraryName: z - .string() - .describe("Library name to search for and retrieve a Context7-compatible library ID."), - }), - execute: async ({ libraryName }: { libraryName: string }) => { - try { - const client = getClient(); - const response = await client.searchLibrary(libraryName); - - if (!response.results || response.results.length === 0) { - return { - success: false, - error: "No libraries found matching your query.", - suggestions: "Try a different search term or check the library name.", - }; - } - - const resultsText = formatSearchResults(response.results); - const topResult = response.results[0]!; - - return { - success: true, - results: resultsText, - totalResults: response.results.length, - topMatch: { - id: topResult.id, - name: topResult.title, - description: topResult.description, - }, - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : "Failed to search libraries", - suggestions: "Check your API key and try again, or try a different search term.", - }; - } - }, - }); -} - -/** - * Tool to fetch documentation for a library using its Context7 library ID. - * - * Can be called with or without configuration. Uses CONTEXT7_API_KEY environment - * variable for authentication when no API key is provided. - * - * @param config Optional configuration options - * @returns AI SDK tool for fetching library documentation - * - * @example - * ```typescript - * import { resolveLibrary, getLibraryDocs } from '@upstash/context7-ai-sdk'; - * import { generateText } from 'ai'; - * import { openai } from '@ai-sdk/openai'; - * - * // Simple usage - uses CONTEXT7_API_KEY env var - * const { text } = await generateText({ - * model: openai('gpt-4o'), - * prompt: 'Find React documentation about hooks', - * tools: { - * resolveLibrary: resolveLibrary(), - * getLibraryDocs: getLibraryDocs(), - * }, - * }); - * - * // With custom config - * const { text } = await generateText({ - * model: openai('gpt-4o'), - * prompt: 'Find React documentation about hooks', - * tools: { - * resolveLibrary: resolveLibrary({ apiKey: 'your-api-key' }), - * getLibraryDocs: getLibraryDocs({ - * apiKey: 'your-api-key', - * defaultMaxResults: 5, - * }), - * }, - * }); - * ``` - */ -export function getLibraryDocs(config: Context7ToolsConfig = {}) { - const { apiKey = process.env.CONTEXT7_API_KEY, defaultMaxResults = 10 } = config; - const getClient = () => new Context7({ apiKey }); - - return tool({ - description: `Fetches up-to-date documentation for a library. You must call 'resolveLibrary' first to obtain the exact Context7-compatible library ID required to use this tool, UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query.`, - inputSchema: z.object({ - libraryId: z - .string() - .describe( - "Exact Context7-compatible library ID (e.g., '/mongodb/docs', '/vercel/next.js', '/supabase/supabase', '/vercel/next.js/v14.3.0-canary.87') retrieved from 'resolveLibrary' or directly from user query in the format '/org/project' or '/org/project/version'." - ), - topic: z - .string() - .optional() - .describe("Topic to focus documentation on (e.g., 'hooks', 'routing')."), - page: z - .number() - .int() - .min(1) - .max(10) - .optional() - .describe( - "Page number for pagination (start: 1, default: 1). If the context is not sufficient, try page=2, page=3, page=4, etc. with the same topic." - ), - maxResults: z - .number() - .int() - .min(1) - .max(10) - .optional() - .describe("Optional: Maximum number of documentation pages to retrieve (default: 10)"), - }), - execute: async ({ - libraryId, - topic, - page = 1, - maxResults = defaultMaxResults, - }: { - libraryId: string; - topic?: string; - page?: number; - maxResults?: number; - }) => { - try { - const client = getClient(); - const response = await client.getDocs(libraryId, { - page, - limit: maxResults, - topic: topic?.trim() || undefined, - format: "txt", - }); - - if (!response.content) { - return { - success: false, - error: - "Documentation not found or not finalized for this library. This might have happened because you used an invalid Context7-compatible library ID. To get a valid Context7-compatible library ID, use the 'resolveLibrary' with the package name you wish to retrieve documentation for.", - libraryId, - }; - } - - return { - success: true, - libraryId, - documentation: response.content, - pagination: response.pagination, - }; - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : "Failed to fetch documentation", - libraryId, - }; - } - }, - }); -} diff --git a/packages/ai-sdk/src/tools/get-library-docs.ts b/packages/ai-sdk/src/tools/get-library-docs.ts new file mode 100644 index 000000000..c5d432d7a --- /dev/null +++ b/packages/ai-sdk/src/tools/get-library-docs.ts @@ -0,0 +1,114 @@ +import { tool } from "ai"; +import { z } from "zod"; +import { Context7 } from "@upstash/context7-sdk"; +import type { Context7ToolsConfig } from "./types"; +import { GET_LIBRARY_DOCS_PROMPT } from "@prompts"; + +/** + * Tool to fetch documentation for a library using its Context7 library ID. + * + * Can be called with or without configuration. Uses CONTEXT7_API_KEY environment + * variable for authentication when no API key is provided. + * + * @param config Optional configuration options + * @returns AI SDK tool for fetching library documentation + * + * @example + * ```typescript + * import { resolveLibrary, getLibraryDocs } from '@upstash/context7-ai-sdk'; + * import { generateText } from 'ai'; + * import { openai } from '@ai-sdk/openai'; + * + * const { text } = await generateText({ + * model: openai('gpt-4o'), + * prompt: 'Find React documentation about hooks', + * tools: { + * resolveLibrary: resolveLibrary(), + * getLibraryDocs: getLibraryDocs(), + * }, + * }); + * ``` + */ +export function getLibraryDocs(config: Context7ToolsConfig = {}) { + const { apiKey = process.env.CONTEXT7_API_KEY, defaultMaxResults = 10 } = config; + const getClient = () => new Context7({ apiKey }); + + return tool({ + description: GET_LIBRARY_DOCS_PROMPT, + inputSchema: z.object({ + libraryId: z + .string() + .describe( + "Exact Context7-compatible library ID (e.g., '/mongodb/docs', '/vercel/next.js', '/supabase/supabase', '/vercel/next.js/v14.3.0-canary.87') retrieved from 'resolveLibrary' or directly from user query in the format '/org/project' or '/org/project/version'." + ), + mode: z + .enum(["code", "info"]) + .optional() + .default("code") + .describe( + "Documentation mode: 'code' for API references and code examples (default), 'info' for conceptual guides, narrative information, and architectural questions." + ), + topic: z + .string() + .optional() + .describe("Topic to focus documentation on (e.g., 'hooks', 'routing')."), + page: z + .number() + .int() + .min(1) + .max(10) + .optional() + .describe( + "Page number for pagination (start: 1, default: 1). If the context is not sufficient, try page=2, page=3, page=4, etc. with the same topic." + ), + }), + execute: async ({ + libraryId, + mode = "code", + topic, + page = 1, + }: { + libraryId: string; + mode?: "code" | "info"; + topic?: string; + page?: number; + }) => { + try { + const client = getClient(); + const baseOptions = { + page, + limit: defaultMaxResults, + topic: topic?.trim() || undefined, + }; + + const response = + mode === "info" + ? await client.getDocs(libraryId, { ...baseOptions, mode: "info" }) + : await client.getDocs(libraryId, { ...baseOptions, mode: "code" }); + + if (!response.snippets?.length) { + return { + success: false, + error: + "Documentation not found or not finalized for this library. This might have happened because you used an invalid Context7-compatible library ID. To get a valid Context7-compatible library ID, use the 'resolveLibrary' with the package name you wish to retrieve documentation for.", + libraryId, + }; + } + + return { + success: true, + libraryId, + snippets: response.snippets, + pagination: response.pagination, + totalTokens: response.totalTokens, + }; + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : "Failed to fetch documentation", + libraryId, + }; + } + }, + }); +} diff --git a/packages/ai-sdk/src/tools/index.ts b/packages/ai-sdk/src/tools/index.ts index f38d69f8a..5d93fe7cf 100644 --- a/packages/ai-sdk/src/tools/index.ts +++ b/packages/ai-sdk/src/tools/index.ts @@ -1 +1,3 @@ -export { resolveLibrary, getLibraryDocs, type Context7ToolsConfig } from "./context7"; +export { resolveLibrary } from "./resolve-library"; +export { getLibraryDocs } from "./get-library-docs"; +export type { Context7ToolsConfig } from "./types"; diff --git a/packages/ai-sdk/src/tools/resolve-library.ts b/packages/ai-sdk/src/tools/resolve-library.ts new file mode 100644 index 000000000..5f5bde913 --- /dev/null +++ b/packages/ai-sdk/src/tools/resolve-library.ts @@ -0,0 +1,70 @@ +import { tool } from "ai"; +import { z } from "zod"; +import { Context7 } from "@upstash/context7-sdk"; +import { RESOLVE_LIBRARY_PROMPT } from "@prompts"; +import type { Context7ToolsConfig } from "./types"; + +/** + * Tool to resolve a library name to a Context7-compatible library ID. + * + * Can be called with or without configuration. Uses CONTEXT7_API_KEY environment + * variable for authentication when no API key is provided. + * + * @param config Optional configuration options + * @returns AI SDK tool for library resolution + * + * @example + * ```typescript + * import { resolveLibrary, getLibraryDocs } from '@upstash/context7-ai-sdk'; + * import { generateText } from 'ai'; + * import { openai } from '@ai-sdk/openai'; + * + * const { text } = await generateText({ + * model: openai('gpt-4o'), + * prompt: 'Find React documentation about hooks', + * tools: { + * resolveLibrary: resolveLibrary(), + * getLibraryDocs: getLibraryDocs(), + * }, + * }); + * ``` + */ +export function resolveLibrary(config: Context7ToolsConfig = {}) { + const { apiKey = process.env.CONTEXT7_API_KEY } = config; + const getClient = () => new Context7({ apiKey }); + + return tool({ + description: RESOLVE_LIBRARY_PROMPT, + inputSchema: z.object({ + libraryName: z + .string() + .describe("Library name to search for and retrieve a Context7-compatible library ID."), + }), + execute: async ({ libraryName }: { libraryName: string }) => { + try { + const client = getClient(); + const response = await client.searchLibrary(libraryName); + + if (!response.results || response.results.length === 0) { + return { + success: false, + error: "No libraries found matching your query.", + suggestions: "Try a different search term or check the library name.", + }; + } + + return { + success: true, + results: response.results, + totalResults: response.results.length, + }; + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : "Failed to search libraries", + suggestions: "Check your API key and try again, or try a different search term.", + }; + } + }, + }); +} diff --git a/packages/ai-sdk/src/tools/types.ts b/packages/ai-sdk/src/tools/types.ts new file mode 100644 index 000000000..380d012f7 --- /dev/null +++ b/packages/ai-sdk/src/tools/types.ts @@ -0,0 +1,14 @@ +/** + * Configuration for Context7 tools + */ +export interface Context7ToolsConfig { + /** + * Context7 API key. If not provided, will use CONTEXT7_API_KEY environment variable. + */ + apiKey?: string; + /** + * Default maximum number of documentation results per page. + * @default 10 + */ + defaultMaxResults?: number; +} From d99cba0faba7625c8a98536c43f861de559de3d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Wed, 3 Dec 2025 11:57:47 +0300 Subject: [PATCH 10/36] docs: context7-ai-sdk --- .../ai-sdk/agents/context7-agent.mdx | 208 +++++++++++++ docs/agentic-tools/ai-sdk/getting-started.mdx | 167 ++++++++++ .../ai-sdk/tools/get-library-docs.mdx | 285 ++++++++++++++++++ .../ai-sdk/tools/resolve-library.mdx | 177 +++++++++++ docs/agentic-tools/overview.mdx | 148 +++++++++ docs/docs.json | 25 ++ 6 files changed, 1010 insertions(+) create mode 100644 docs/agentic-tools/ai-sdk/agents/context7-agent.mdx create mode 100644 docs/agentic-tools/ai-sdk/getting-started.mdx create mode 100644 docs/agentic-tools/ai-sdk/tools/get-library-docs.mdx create mode 100644 docs/agentic-tools/ai-sdk/tools/resolve-library.mdx create mode 100644 docs/agentic-tools/overview.mdx diff --git a/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx b/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx new file mode 100644 index 000000000..d8807d400 --- /dev/null +++ b/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx @@ -0,0 +1,208 @@ +--- +title: "context7Agent" +sidebarTitle: "context7Agent" +description: "Pre-built AI agent for documentation lookup workflows" +--- + +# context7Agent + +The `context7Agent` is a pre-configured AI agent that handles the complete documentation lookup workflow automatically. It combines both `resolveLibrary` and `getLibraryDocs` tools with an optimized system prompt. + +## Usage + +```typescript +import { context7Agent } from "@upstash/context7-ai-sdk"; +import { anthropic } from "@ai-sdk/anthropic"; + +const agent = context7Agent({ + model: anthropic("claude-sonnet-4-20250514"), +}); + +const { text } = await agent.generate({ + prompt: "How do I use React Server Components?", +}); + +console.log(text); +``` + +## Configuration + +```typescript +context7Agent(config?: Context7AgentConfig) +``` + +### Parameters + + + Configuration options for the agent. + + + + Language model to use. Must be a LanguageModel instance from an AI SDK provider. + + Examples: + - `anthropic('claude-sonnet-4-20250514')` + - `openai('gpt-4o')` + - `google('gemini-1.5-pro')` + + + Context7 API key. If not provided, uses the `CONTEXT7_API_KEY` environment variable. + + + Default maximum number of documentation results per request. + + + Custom system prompt. Overrides the default `AGENT_PROMPT`. + + + Condition for when the agent should stop. Defaults to stopping after 5 steps. + + + + + +### Returns + +Returns an AI SDK `Agent` instance with `generate()` and `stream()` methods. + +## Agent Workflow + +The agent follows a structured multi-step workflow: + +```mermaid +flowchart TD + A[User Query] --> B[Extract Library Name] + B --> C[Call resolveLibrary] + C --> D{Results Found?} + D -->|Yes| E[Select Best Match] + D -->|No| F[Report No Results] + E --> G[Call getLibraryDocs] + G --> H{Sufficient Context?} + H -->|Yes| I[Generate Response] + H -->|No| J[Fetch More Pages] + J --> H + I --> K[Return Answer with Examples] +``` + +### Step-by-Step + +1. **Extract library name** - Identifies the library/framework from the user's query +2. **Resolve library** - Calls `resolveLibrary` to find the Context7 library ID +3. **Select best match** - Analyzes results based on reputation, coverage, and relevance +4. **Fetch documentation** - Calls `getLibraryDocs` with the selected library ID and relevant topic +5. **Paginate if needed** - Fetches additional pages if initial context is insufficient +6. **Generate response** - Provides an answer with code examples from the documentation + +## Examples + +### Basic Usage + +```typescript +import { context7Agent } from "@upstash/context7-ai-sdk"; +import { anthropic } from "@ai-sdk/anthropic"; + +const agent = context7Agent({ + model: anthropic("claude-sonnet-4-20250514"), +}); + +const { text } = await agent.generate({ + prompt: "How do I set up authentication in Next.js?", +}); + +console.log(text); +``` + +### With OpenAI + +```typescript +import { context7Agent } from "@upstash/context7-ai-sdk"; +import { openai } from "@ai-sdk/openai"; + +const agent = context7Agent({ + model: openai("gpt-4o"), +}); + +const { text } = await agent.generate({ + prompt: "Explain Tanstack Query's useQuery hook", +}); +``` + +### Streaming Responses + +```typescript +import { context7Agent } from "@upstash/context7-ai-sdk"; +import { anthropic } from "@ai-sdk/anthropic"; + +const agent = context7Agent({ + model: anthropic("claude-sonnet-4-20250514"), +}); + +const { textStream } = await agent.stream({ + prompt: "How do I create a Supabase Edge Function?", +}); + +for await (const chunk of textStream) { + process.stdout.write(chunk); +} +``` + +### Custom Configuration + +```typescript +import { context7Agent } from "@upstash/context7-ai-sdk"; +import { anthropic } from "@ai-sdk/anthropic"; +import { stepCountIs } from "ai"; + +const agent = context7Agent({ + model: anthropic("claude-sonnet-4-20250514"), + apiKey: process.env.CONTEXT7_API_KEY, + defaultMaxResults: 5, + stopWhen: stepCountIs(8), // Allow more steps for complex queries +}); +``` + +### Custom System Prompt + +```typescript +import { context7Agent, AGENT_PROMPT } from "@upstash/context7-ai-sdk"; +import { openai } from "@ai-sdk/openai"; + +const agent = context7Agent({ + model: openai("gpt-4o"), + system: `${AGENT_PROMPT} + +Additional instructions: +- Always include TypeScript examples +- Mention version compatibility when relevant +- Suggest related documentation topics`, +}); +``` + +## Comparison: Agent vs Tools + +| Feature | context7Agent | Individual Tools | +| ------------- | -------------------- | -------------------- | +| Setup | Single configuration | Configure each tool | +| Workflow | Automatic multi-step | Manual orchestration | +| System prompt | Optimized default | You provide | +| Customization | Limited | Full control | +| Best for | Quick integration | Custom workflows | + +### When to Use the Agent + +- Rapid prototyping +- Standard documentation lookup use cases +- When you want sensible defaults + +### When to Use Individual Tools + +- Custom agentic workflows +- Integration with other tools +- Fine-grained control over the process +- Custom system prompts with specific behavior + +## Related + +- [resolveLibrary](/agentic-tools/ai-sdk/tools/resolve-library) - The library search tool used by the agent +- [getLibraryDocs](/agentic-tools/ai-sdk/tools/get-library-docs) - The documentation fetch tool used by the agent +- [Getting Started](/agentic-tools/ai-sdk/getting-started) - Overview of the AI SDK integration diff --git a/docs/agentic-tools/ai-sdk/getting-started.mdx b/docs/agentic-tools/ai-sdk/getting-started.mdx new file mode 100644 index 000000000..ed4d4c57b --- /dev/null +++ b/docs/agentic-tools/ai-sdk/getting-started.mdx @@ -0,0 +1,167 @@ +--- +title: "Getting Started" +sidebarTitle: "Getting Started" +description: "Add Context7 documentation tools to your Vercel AI SDK applications" +--- + +# Getting Started with AI SDK + +`@upstash/context7-ai-sdk` provides [Vercel AI SDK](https://sdk.vercel.ai/) compatible tools and agents that give your AI applications access to up-to-date library documentation. + +When building AI-powered applications with the Vercel AI SDK, your models often need accurate information about libraries and frameworks. Instead of relying on potentially outdated training data, Context7 tools let your AI fetch current documentation on-demand, ensuring responses include correct API usage, current best practices, and working code examples. + +The package gives you two ways to integrate: + +1. **Individual tools** (`resolveLibrary` and `getLibraryDocs`) that you add to your existing `generateText` or `streamText` calls +2. **A pre-built agent** (`context7Agent`) that handles the entire documentation lookup workflow automatically + +Both approaches work with any AI provider supported by the Vercel AI SDK, including OpenAI, Anthropic, Google, and others. + +## Installation + + +```bash npm +npm install @upstash/context7-ai-sdk +``` + +```bash pnpm +pnpm add @upstash/context7-ai-sdk +``` + +```bash yarn +yarn add @upstash/context7-ai-sdk +``` + +```bash bun +bun add @upstash/context7-ai-sdk +``` + + + +## Prerequisites + +You'll need: + +1. A Context7 API key from the [Context7 Dashboard](https://context7.com/dashboard) +2. An AI provider SDK (e.g., `@ai-sdk/openai`, `@ai-sdk/anthropic`) + +## Configuration + +Set your Context7 API key as an environment variable: + +```bash +CONTEXT7_API_KEY=ctx7sk-... +``` + +The tools and agents will automatically use this key. + +## Quick Start + +### Using Tools with generateText + +The simplest way to add documentation lookup to your AI application: + +```typescript +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; +import { generateText } from "ai"; +import { openai } from "@ai-sdk/openai"; + +const { text } = await generateText({ + model: openai("gpt-4o"), + prompt: "How do I create a server action in Next.js?", + tools: { + resolveLibrary: resolveLibrary(), + getLibraryDocs: getLibraryDocs(), + }, + maxSteps: 5, +}); + +console.log(text); +``` + +### Using the Context7 Agent + +For a more streamlined experience, use the pre-configured agent: + +```typescript +import { context7Agent } from "@upstash/context7-ai-sdk"; +import { anthropic } from "@ai-sdk/anthropic"; + +const agent = context7Agent({ + model: anthropic("claude-sonnet-4-20250514"), +}); + +const { text } = await agent.generate({ + prompt: "How do I use React Server Components?", +}); + +console.log(text); +``` + +### Using Tools with streamText + +For streaming responses: + +```typescript +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; +import { streamText } from "ai"; +import { openai } from "@ai-sdk/openai"; + +const { textStream } = streamText({ + model: openai("gpt-4o"), + prompt: "Explain how to use Tanstack Query for data fetching", + tools: { + resolveLibrary: resolveLibrary(), + getLibraryDocs: getLibraryDocs(), + }, + maxSteps: 5, +}); + +for await (const chunk of textStream) { + process.stdout.write(chunk); +} +``` + +## Explicit Configuration + +You can also pass the API key directly if needed: + +```typescript +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; + +const tools = { + resolveLibrary: resolveLibrary({ apiKey: "your-api-key" }), + getLibraryDocs: getLibraryDocs({ apiKey: "your-api-key" }), +}; +``` + +## How It Works + +The tools follow a two-step workflow: + +1. **`resolveLibrary`** - Searches Context7's database to find the correct library ID for a given query (e.g., "react" → `/reactjs/react.dev`) + +2. **`getLibraryDocs`** - Fetches documentation for the resolved library with options for: + - **mode** - `"code"` for API references and examples, `"info"` for conceptual guides + - **topic** - Filter documentation by topic (e.g., "hooks", "routing") + - **page** - Pagination for comprehensive results + +The AI model orchestrates these tools automatically based on the user's prompt, fetching relevant documentation before generating a response. + +## Next Steps + + + + Search for libraries and get Context7-compatible IDs + + + Fetch documentation for a specific library + + + Use the pre-built documentation agent + + diff --git a/docs/agentic-tools/ai-sdk/tools/get-library-docs.mdx b/docs/agentic-tools/ai-sdk/tools/get-library-docs.mdx new file mode 100644 index 000000000..dc47d80de --- /dev/null +++ b/docs/agentic-tools/ai-sdk/tools/get-library-docs.mdx @@ -0,0 +1,285 @@ +--- +title: "getLibraryDocs" +sidebarTitle: "getLibraryDocs" +description: "Fetch up-to-date documentation for a specific library" +--- + +# getLibraryDocs + +The `getLibraryDocs` tool fetches documentation for a library using its Context7-compatible library ID. This tool is typically called after `resolveLibrary` has identified the correct library. + +## Usage + +```typescript +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; +import { generateText } from "ai"; +import { openai } from "@ai-sdk/openai"; + +const { text } = await generateText({ + model: openai("gpt-4o"), + prompt: "How do I use React Server Components?", + tools: { + resolveLibrary: resolveLibrary(), + getLibraryDocs: getLibraryDocs(), + }, + maxSteps: 5, +}); +``` + +## Configuration + +```typescript +getLibraryDocs(config?: Context7ToolsConfig) +``` + +### Parameters + + + Configuration options for the tool. + + + + Context7 API key. If not provided, uses the `CONTEXT7_API_KEY` environment variable. + + + Default maximum number of documentation results per request. + + + + +### Returns + +Returns an AI SDK `tool` that can be used with `generateText`, `streamText`, or agents. + +## Tool Behavior + +When the AI model calls this tool, it: + +1. Takes a library ID and optional parameters from the model +2. Fetches documentation from Context7's API +3. Returns the documentation content with pagination info + +### Input Schema + +The tool accepts the following inputs from the AI model: + + + Context7-compatible library ID (e.g., `/reactjs/react.dev`, `/vercel/next.js`) + + + + Documentation mode: + - `"code"` - API references and code examples (default) + - `"info"` - Conceptual guides, narrative information, and architectural questions + + + + Topic to focus documentation on (e.g., "hooks", "routing", "authentication") + + + + Page number for pagination (1-10) + + +### Output Format + +The output structure depends on the `mode` parameter. + +#### Code Mode (default) + +When `mode="code"`, the tool returns structured code snippets: + +```typescript +{ + success: true, + libraryId: "/reactjs/react.dev", + snippets: [ + { + codeTitle: "Server Components", + codeDescription: "How to use React Server Components", + codeLanguage: "tsx", + codeTokens: 150, + codeId: "abc123", + pageTitle: "React Server Components", + codeList: [ + { + language: "tsx", + code: "async function ServerComponent() {\n const data = await fetchData();\n return
{data}
;\n}" + } + ] + }, + // ... more snippets + ], + pagination: { + page: 1, + limit: 10, + totalPages: 5, + hasNext: true, + hasPrev: false + }, + totalTokens: 1500 +} +``` + +#### Info Mode + +When `mode="info"`, the tool returns conceptual documentation content: + +```typescript +{ + success: true, + libraryId: "/reactjs/react.dev", + snippets: [ + { + pageId: "server-components-intro", + breadcrumb: "React > Advanced > Server Components", + content: "Server Components let you write UI that can be rendered and optionally cached on the server...", + contentTokens: 250 + }, + // ... more snippets + ], + pagination: { + page: 1, + limit: 10, + totalPages: 3, + hasNext: true, + hasPrev: false + }, + totalTokens: 2500 +} +``` + +#### On Failure + +```typescript +{ + success: false, + error: "Documentation not found or not finalized for this library.", + libraryId: "/invalid/library" +} +``` + +## Examples + +### Basic Usage with Both Tools + +```typescript +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; +import { generateText } from "ai"; +import { openai } from "@ai-sdk/openai"; + +const { text } = await generateText({ + model: openai("gpt-4o"), + prompt: "Show me how to set up routing in Next.js App Router", + tools: { + resolveLibrary: resolveLibrary(), + getLibraryDocs: getLibraryDocs(), + }, + maxSteps: 5, +}); + +// The model will: +// 1. Call resolveLibrary("next.js") to get the library ID +// 2. Call getLibraryDocs({ libraryId: "/vercel/next.js", topic: "routing" }) +// 3. Generate a response using the fetched documentation +``` + +### With Custom Configuration + +```typescript +import { getLibraryDocs } from "@upstash/context7-ai-sdk"; + +const tool = getLibraryDocs({ + apiKey: process.env.CONTEXT7_API_KEY, + defaultMaxResults: 5, // Fetch fewer results by default +}); +``` + +### Direct Library ID (Skip resolveLibrary) + +If the user provides a library ID directly, the model can skip the resolution step: + +```typescript +import { getLibraryDocs } from "@upstash/context7-ai-sdk"; +import { generateText } from "ai"; +import { openai } from "@ai-sdk/openai"; + +const { text } = await generateText({ + model: openai("gpt-4o"), + prompt: "Using /vercel/next.js, explain middleware", + tools: { + getLibraryDocs: getLibraryDocs(), + }, + maxSteps: 3, +}); + +// The model recognizes the /org/project format and calls getLibraryDocs directly +``` + +### Paginated Results + +For comprehensive documentation, the model can request multiple pages: + +```typescript +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; +import { generateText } from "ai"; +import { anthropic } from "@ai-sdk/anthropic"; + +const { text } = await generateText({ + model: anthropic("claude-sonnet-4-20250514"), + prompt: "Give me a comprehensive guide to Supabase authentication", + tools: { + resolveLibrary: resolveLibrary(), + getLibraryDocs: getLibraryDocs(), + }, + maxSteps: 8, // Allow more steps for pagination +}); + +// The model may call getLibraryDocs multiple times with page=1, page=2, etc. +// to gather comprehensive documentation +``` + +## Topic Filtering + +The `topic` parameter helps focus the documentation results. The AI model extracts relevant topics from the user's query: + +| User Query | Extracted Topic | +| ---------------------------------- | ------------------------------ | +| "How do I use React hooks?" | "hooks" | +| "Set up authentication in Next.js" | "authentication" | +| "Supabase real-time subscriptions" | "real-time" or "subscriptions" | +| "Vue component lifecycle" | "lifecycle" | + +## Mode Selection + +The `mode` parameter determines the type of documentation returned: + +| Mode | Best For | Returns | +| ------ | ----------------------------------------------------- | ------------------------------------ | +| `code` | API references, code examples, implementation details | `CodeSnippet` with code blocks | +| `info` | Conceptual guides, architecture, explanations | `InfoSnippet` with narrative content | + +The AI model automatically selects the appropriate mode based on the user's question: +- "How do I implement..." → `mode: "code"` +- "What is the architecture of..." → `mode: "info"` +- "Show me an example of..." → `mode: "code"` +- "Explain how ... works" → `mode: "info"` + +## Version-Specific Documentation + +Library IDs can include version specifiers: + +```typescript +// Latest version +"/vercel/next.js"; + +// Specific version +"/vercel/next.js/v14.3.0-canary.87"; +``` + +The model can request documentation for specific versions when the user asks about a particular version. + +## Related + +- [resolveLibrary](/agentic-tools/ai-sdk/tools/resolve-library) - Search for libraries and get their IDs +- [context7Agent](/agentic-tools/ai-sdk/agents/context7-agent) - Pre-built agent that handles the full workflow diff --git a/docs/agentic-tools/ai-sdk/tools/resolve-library.mdx b/docs/agentic-tools/ai-sdk/tools/resolve-library.mdx new file mode 100644 index 000000000..72a701f17 --- /dev/null +++ b/docs/agentic-tools/ai-sdk/tools/resolve-library.mdx @@ -0,0 +1,177 @@ +--- +title: "resolveLibrary" +sidebarTitle: "resolveLibrary" +description: "Search for libraries and resolve them to Context7-compatible IDs" +--- + +# resolveLibrary + +The `resolveLibrary` tool searches Context7's library database and returns matching results with their Context7-compatible library IDs. This is typically the first step in a documentation lookup workflow. + +## Usage + +```typescript +import { resolveLibrary } from "@upstash/context7-ai-sdk"; +import { generateText } from "ai"; +import { openai } from "@ai-sdk/openai"; + +const { text } = await generateText({ + model: openai("gpt-4o"), + prompt: "Find documentation for React hooks", + tools: { + resolveLibrary: resolveLibrary(), + }, + maxSteps: 3, +}); +``` + +## Configuration + +```typescript +resolveLibrary(config?: Context7ToolsConfig) +``` + +### Parameters + + + Configuration options for the tool. + + + + Context7 API key. If not provided, uses the `CONTEXT7_API_KEY` environment variable. + + + + +### Returns + +Returns an AI SDK `tool` that can be used with `generateText`, `streamText`, or agents. + +## Tool Behavior + +When the AI model calls this tool, it: + +1. Takes a `libraryName` parameter from the model +2. Searches Context7's database for matching libraries +3. Returns formatted results including: + - Library ID (e.g., `/reactjs/react.dev`) + - Title and description + - Number of code snippets available + - Source reputation score + - Available versions + +### Input Schema + +The tool accepts the following input from the AI model: + + + Library name to search for (e.g., "react", "next.js", "vue") + + +### Output Format + +On success, the tool returns the search results as JSON: + +```typescript +{ + success: true, + results: [ + { + id: "/reactjs/react.dev", + title: "React Documentation", + description: "The library for web and native user interfaces", + totalSnippets: 1250, + trustScore: 0.95, + benchmarkScore: 98, + versions: ["19.0.0", "18.3.1", "18.2.0"] + }, + // ... more results + ], + totalResults: 5 +} +``` + +On failure: + +```typescript +{ + success: false, + error: "No libraries found matching your query.", + suggestions: "Try a different search term or check the library name." +} +``` + +## Examples + +### Basic Usage + +```typescript +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; +import { generateText } from "ai"; +import { openai } from "@ai-sdk/openai"; + +const { text, toolCalls } = await generateText({ + model: openai("gpt-4o"), + prompt: "What libraries are available for React?", + tools: { + resolveLibrary: resolveLibrary(), + getLibraryDocs: getLibraryDocs(), + }, + maxSteps: 5, +}); + +// The model will call resolveLibrary("react") and receive a list of matching libraries +console.log(text); +``` + +### With Custom API Key + +```typescript +import { resolveLibrary } from "@upstash/context7-ai-sdk"; + +const tool = resolveLibrary({ + apiKey: process.env.CONTEXT7_API_KEY, +}); +``` + +### Inspecting Tool Calls + +```typescript +import { resolveLibrary } from "@upstash/context7-ai-sdk"; +import { generateText } from "ai"; +import { openai } from "@ai-sdk/openai"; + +const { toolCalls, toolResults } = await generateText({ + model: openai("gpt-4o"), + prompt: "Find the official Next.js documentation", + tools: { + resolveLibrary: resolveLibrary(), + }, + maxSteps: 3, +}); + +// See what the model searched for +for (const call of toolCalls) { + console.log("Searched for:", call.args.libraryName); +} + +// See the results +for (const result of toolResults) { + console.log("Found:", result.result); +} +``` + +## Selection Guidance + +The tool's description instructs the AI model to select libraries based on: + +1. **Name similarity** - Exact matches are prioritized +2. **Description relevance** - How well the description matches the query intent +3. **Documentation coverage** - Libraries with more code snippets are preferred +4. **Source reputation** - High/Medium reputation sources are more authoritative +5. **Benchmark score** - Quality indicator (100 is the highest) + +## Related + +- [getLibraryDocs](/agentic-tools/ai-sdk/tools/get-library-docs) - Fetch documentation using the resolved library ID +- [context7Agent](/agentic-tools/ai-sdk/agents/context7-agent) - Pre-built agent that handles the full workflow diff --git a/docs/agentic-tools/overview.mdx b/docs/agentic-tools/overview.mdx new file mode 100644 index 000000000..58f50b639 --- /dev/null +++ b/docs/agentic-tools/overview.mdx @@ -0,0 +1,148 @@ +--- +title: "Overview" +sidebarTitle: "Overview" +description: "Build AI agents with up-to-date library documentation" +--- + +# Agentic Tools + +Context7 provides tools and integrations that give your AI agents access to accurate, up-to-date library documentation. Instead of relying on potentially outdated training data, your agents can fetch real-time documentation to answer questions and generate code. + +## Why Agentic Tools? + +AI agents often struggle with: + +- **Outdated knowledge** - Training data becomes stale, leading to deprecated API usage +- **Hallucinated APIs** - Models confidently suggest methods that don't exist +- **Version mismatches** - Code examples from old versions that no longer work + +Context7's agentic tools solve these problems by giving your agents direct access to current documentation during inference. + +## Available Integrations + + + + Add Context7 tools to your AI SDK workflows with `generateText`, `streamText`, or use the + pre-built `context7Agent` for automatic documentation lookup. + + + +## How It Works + +```mermaid +sequenceDiagram + participant User + participant Agent + participant Context7 + participant Docs + + User->>Agent: "How do I use React Server Components?" + Agent->>Context7: resolveLibrary("react") + Context7-->>Agent: Library ID: /reactjs/react.dev + Agent->>Context7: getLibraryDocs("/reactjs/react.dev", topic: "server components") + Context7->>Docs: Fetch latest documentation + Docs-->>Context7: Current docs with examples + Context7-->>Agent: Documentation content + Agent->>User: Answer with accurate, up-to-date code examples +``` + +## Use Cases + + + + Build chatbots that answer framework questions with accurate, version-specific information: + + ```typescript + import { generateText } from "ai"; + import { openai } from "@ai-sdk/openai"; + import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; + + const { text } = await generateText({ + model: openai("gpt-4o"), + prompt: "How do I set up authentication in Next.js 15?", + tools: { + resolveLibrary: resolveLibrary(), + getLibraryDocs: getLibraryDocs(), + }, + maxSteps: 5, + }); + ``` + + + + Ensure generated code uses current APIs and best practices: + + ```typescript + import { context7Agent } from "@upstash/context7-ai-sdk"; + import { anthropic } from "@ai-sdk/anthropic"; + + const agent = context7Agent({ + model: anthropic("claude-sonnet-4-20250514"), + }); + + const { text } = await agent.generate({ + prompt: "Generate a Supabase Edge Function that handles webhooks", + }); + ``` + + + + Build code review agents that verify implementations against current API documentation: + + ```typescript + import { generateText } from "ai"; + import { anthropic } from "@ai-sdk/anthropic"; + import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; + + const codeToReview = ` + const { data } = await supabase + .from('users') + .select('*') + .eq('id', userId) + .single(); + `; + + const { text } = await generateText({ + model: anthropic("claude-sonnet-4-20250514"), + prompt: `Review this Supabase code for correctness and best practices: + + ${codeToReview} + + Check against the latest Supabase documentation.`, + tools: { + resolveLibrary: resolveLibrary(), + getLibraryDocs: getLibraryDocs(), + }, + maxSteps: 5, + }); + + // Agent fetches current Supabase docs to verify: + // - Correct method signatures + // - Deprecated patterns + // - Security best practices + // - Error handling recommendations + ``` + + + + Augment your developer tools with real-time documentation retrieval for IDE extensions, CLI tools, or code review systems. + + - **IDE Extensions** - Provide inline documentation suggestions based on the libraries in use + - **CLI Tools** - Build command-line assistants that help developers with framework-specific questions + - **Documentation Search** - Create search interfaces that return accurate, up-to-date code examples + + + +## Getting Started + +Choose your integration to get started: + + + + The fastest way to add documentation lookup to your AI applications + + diff --git a/docs/docs.json b/docs/docs.json index 666148eb2..9b2a66c4c 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -48,6 +48,31 @@ } ] }, + { + "group": "Agentic Tools", + "pages": [ + "agentic-tools/overview", + { + "group": "Vercel AI SDK", + "pages": [ + "agentic-tools/ai-sdk/getting-started", + { + "group": "Tools", + "pages": [ + "agentic-tools/ai-sdk/tools/resolve-library", + "agentic-tools/ai-sdk/tools/get-library-docs" + ] + }, + { + "group": "Agents", + "pages": [ + "agentic-tools/ai-sdk/agents/context7-agent" + ] + } + ] + } + ] + }, { "group": "API Reference", "openapi": "openapi.json" From 47b719f8cdcbda862783249b7398d5210935ef47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Wed, 3 Dec 2025 12:36:53 +0300 Subject: [PATCH 11/36] tests: fix test env vars --- packages/ai-sdk/package.json | 1 + packages/ai-sdk/vitest.config.ts | 3 +++ pnpm-lock.yaml | 3 +++ 3 files changed, 7 insertions(+) diff --git a/packages/ai-sdk/package.json b/packages/ai-sdk/package.json index 69eaa2782..dcaf941b1 100644 --- a/packages/ai-sdk/package.json +++ b/packages/ai-sdk/package.json @@ -36,6 +36,7 @@ "devDependencies": { "@ai-sdk/amazon-bedrock": "^3.0.55", "@types/node": "^22.13.14", + "dotenv": "^17.2.3", "tsup": "^8.5.1", "typescript": "^5.8.2", "vitest": "^4.0.13" diff --git a/packages/ai-sdk/vitest.config.ts b/packages/ai-sdk/vitest.config.ts index 00e330328..2b71b6761 100644 --- a/packages/ai-sdk/vitest.config.ts +++ b/packages/ai-sdk/vitest.config.ts @@ -1,5 +1,8 @@ import { defineConfig } from "vitest/config"; import path from "path"; +import { config } from "dotenv"; + +config(); export default defineConfig({ test: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3b9f2a124..cb2bbaf2b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -57,6 +57,9 @@ importers: '@types/node': specifier: ^22.13.14 version: 22.19.1 + dotenv: + specifier: ^17.2.3 + version: 17.2.3 tsup: specifier: ^8.5.1 version: 8.5.1(postcss@8.5.6)(typescript@5.9.3) From 12b7eaf59d589d882ce5371a4ea0dbe9ec156d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 12:37:25 +0300 Subject: [PATCH 12/36] ci: bump pnpm version --- .github/workflows/canary-release.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/canary-release.yml b/.github/workflows/canary-release.yml index d6388d1f3..48b9d5964 100644 --- a/.github/workflows/canary-release.yml +++ b/.github/workflows/canary-release.yml @@ -28,7 +28,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 9 + version: 10 - name: Configure npm authentication run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 760e15f80..40d046286 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,7 +27,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 9 + version: 10 - name: Configure npm authentication run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cb31eb398..9a2536827 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 9 + version: 10 - name: Install Dependencies run: pnpm install --frozen-lockfile From 62c0e15d1beb67401a88e97c93b4001bb755b491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 12:38:22 +0300 Subject: [PATCH 13/36] update ai sdk step count api --- packages/ai-sdk/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ai-sdk/README.md b/packages/ai-sdk/README.md index 5687c5941..05dd37462 100644 --- a/packages/ai-sdk/README.md +++ b/packages/ai-sdk/README.md @@ -31,7 +31,7 @@ Get your API key from [Context7](https://context7.com) ```typescript import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; -import { generateText } from "ai"; +import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { text } = await generateText({ @@ -41,7 +41,7 @@ const { text } = await generateText({ resolveLibrary: resolveLibrary(), getLibraryDocs: getLibraryDocs(), }, - maxSteps: 5, + stopWhen: stepCountIs(5), }); console.log(text); From 5fcfa2146cf0fb58111b169fddfeb8e3bbc9521e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 12:53:30 +0300 Subject: [PATCH 14/36] Add stopWhen to docstring examples --- packages/ai-sdk/src/tools/get-library-docs.ts | 5 +++-- packages/ai-sdk/src/tools/resolve-library.ts | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/ai-sdk/src/tools/get-library-docs.ts b/packages/ai-sdk/src/tools/get-library-docs.ts index c5d432d7a..602817bd1 100644 --- a/packages/ai-sdk/src/tools/get-library-docs.ts +++ b/packages/ai-sdk/src/tools/get-library-docs.ts @@ -16,7 +16,7 @@ import { GET_LIBRARY_DOCS_PROMPT } from "@prompts"; * @example * ```typescript * import { resolveLibrary, getLibraryDocs } from '@upstash/context7-ai-sdk'; - * import { generateText } from 'ai'; + * import { generateText, stepCountIs } from 'ai'; * import { openai } from '@ai-sdk/openai'; * * const { text } = await generateText({ @@ -26,11 +26,12 @@ import { GET_LIBRARY_DOCS_PROMPT } from "@prompts"; * resolveLibrary: resolveLibrary(), * getLibraryDocs: getLibraryDocs(), * }, + * stopWhen: stepCountIs(5), * }); * ``` */ export function getLibraryDocs(config: Context7ToolsConfig = {}) { - const { apiKey = process.env.CONTEXT7_API_KEY, defaultMaxResults = 10 } = config; + const { apiKey, defaultMaxResults = 10 } = config; const getClient = () => new Context7({ apiKey }); return tool({ diff --git a/packages/ai-sdk/src/tools/resolve-library.ts b/packages/ai-sdk/src/tools/resolve-library.ts index 5f5bde913..dcf463577 100644 --- a/packages/ai-sdk/src/tools/resolve-library.ts +++ b/packages/ai-sdk/src/tools/resolve-library.ts @@ -16,7 +16,7 @@ import type { Context7ToolsConfig } from "./types"; * @example * ```typescript * import { resolveLibrary, getLibraryDocs } from '@upstash/context7-ai-sdk'; - * import { generateText } from 'ai'; + * import { generateText, stepCountIs } from 'ai'; * import { openai } from '@ai-sdk/openai'; * * const { text } = await generateText({ @@ -26,11 +26,12 @@ import type { Context7ToolsConfig } from "./types"; * resolveLibrary: resolveLibrary(), * getLibraryDocs: getLibraryDocs(), * }, + * stopWhen: stepCountIs(5), * }); * ``` */ export function resolveLibrary(config: Context7ToolsConfig = {}) { - const { apiKey = process.env.CONTEXT7_API_KEY } = config; + const { apiKey } = config; const getClient = () => new Context7({ apiKey }); return tool({ From f4229a66db00ecebce491308e61d4899f0b2ca94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 13:09:59 +0300 Subject: [PATCH 15/36] update tests --- packages/ai-sdk/src/index.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/ai-sdk/src/index.test.ts b/packages/ai-sdk/src/index.test.ts index b6ba61858..896519ae5 100644 --- a/packages/ai-sdk/src/index.test.ts +++ b/packages/ai-sdk/src/index.test.ts @@ -67,6 +67,8 @@ describe("@upstash/context7-ai-sdk", () => { expect(result.toolCalls.length).toBeGreaterThan(0); expect(result.toolCalls[0].toolName).toBe("resolveLibrary"); expect(result.toolResults.length).toBeGreaterThan(0); + const toolResult = result.toolResults[0] as unknown as { output: { success: boolean } }; + expect(toolResult.output.success).toBe(true); }, 30000); test("getLibraryDocs tool should fetch documentation", async () => { @@ -83,6 +85,8 @@ describe("@upstash/context7-ai-sdk", () => { expect(result.toolCalls.length).toBeGreaterThan(0); expect(result.toolCalls[0].toolName).toBe("getLibraryDocs"); expect(result.toolResults.length).toBeGreaterThan(0); + const toolResult = result.toolResults[0] as unknown as { output: { success: boolean } }; + expect(toolResult.output.success).toBe(true); }, 30000); test("both tools can work together in a multi-step flow", async () => { From 19bd3a5574e6730627ea5ad483cbbc1b84971f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 13:12:49 +0300 Subject: [PATCH 16/36] update prompt name --- packages/ai-sdk/src/index.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/ai-sdk/src/index.ts b/packages/ai-sdk/src/index.ts index 719bc26bb..8775b1ca3 100644 --- a/packages/ai-sdk/src/index.ts +++ b/packages/ai-sdk/src/index.ts @@ -5,7 +5,12 @@ export { context7Agent, type Context7AgentConfig } from "@agents"; export { resolveLibrary, getLibraryDocs, type Context7ToolsConfig } from "@tools"; // Prompts -export { SYSTEM_PROMPT, AGENT_PROMPT, RESOLVE_LIBRARY_PROMPT } from "@prompts"; +export { + SYSTEM_PROMPT, + AGENT_PROMPT, + RESOLVE_LIBRARY_PROMPT, + GET_LIBRARY_DOCS_PROMPT, +} from "@prompts"; // Re-export useful types from SDK export type { From f56da4de30db784511ca52e54fac7ab0c07ee047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 13:14:46 +0300 Subject: [PATCH 17/36] update context7 agent name --- packages/ai-sdk/README.md | 6 +++--- packages/ai-sdk/src/agents/context7.ts | 6 +++--- packages/ai-sdk/src/agents/index.ts | 2 +- packages/ai-sdk/src/index.test.ts | 10 +++++----- packages/ai-sdk/src/index.ts | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/ai-sdk/README.md b/packages/ai-sdk/README.md index 05dd37462..0c398e8ee 100644 --- a/packages/ai-sdk/README.md +++ b/packages/ai-sdk/README.md @@ -5,7 +5,7 @@ Use this package to: - Add documentation lookup tools to your AI SDK workflows with `generateText` or `streamText` -- Create documentation aware agents using the pre-configured `context7Agent` +- Create documentation aware agents using the pre-configured `Context7Agent` - Build RAG pipelines that retrieve accurate, version specific code examples The package provides two main tools: @@ -52,10 +52,10 @@ console.log(text); The package provides a pre-configured agent that handles the multi-step workflow automatically: ```typescript -import { context7Agent } from "@upstash/context7-ai-sdk"; +import { Context7Agent } from "@upstash/context7-ai-sdk"; import { anthropic } from "@ai-sdk/anthropic"; -const agent = context7Agent({ +const agent = Context7Agent({ model: anthropic("claude-sonnet-4-20250514"), }); diff --git a/packages/ai-sdk/src/agents/context7.ts b/packages/ai-sdk/src/agents/context7.ts index d42b20ba5..c7024c70c 100644 --- a/packages/ai-sdk/src/agents/context7.ts +++ b/packages/ai-sdk/src/agents/context7.ts @@ -39,10 +39,10 @@ export interface Context7AgentConfig * * @example * ```typescript - * import { context7Agent } from '@upstash/context7-ai-sdk'; + * import { Context7Agent } from '@upstash/context7-ai-sdk'; * import { anthropic } from '@ai-sdk/anthropic'; * - * const agent = context7Agent({ + * const agent = Context7Agent({ * model: anthropic('claude-sonnet-4-20250514'), * apiKey: 'your-context7-api-key', * }); @@ -52,7 +52,7 @@ export interface Context7AgentConfig * }); * ``` */ -export function context7Agent(config: Context7AgentConfig = {}) { +export function Context7Agent(config: Context7AgentConfig = {}) { const { model, stopWhen = stepCountIs(5), diff --git a/packages/ai-sdk/src/agents/index.ts b/packages/ai-sdk/src/agents/index.ts index e38bfa5dd..d803381d0 100644 --- a/packages/ai-sdk/src/agents/index.ts +++ b/packages/ai-sdk/src/agents/index.ts @@ -1 +1 @@ -export { context7Agent, type Context7AgentConfig } from "./context7"; +export { Context7Agent, type Context7AgentConfig } from "./context7"; diff --git a/packages/ai-sdk/src/index.test.ts b/packages/ai-sdk/src/index.test.ts index 896519ae5..999a8491c 100644 --- a/packages/ai-sdk/src/index.test.ts +++ b/packages/ai-sdk/src/index.test.ts @@ -4,7 +4,7 @@ import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock"; import { resolveLibrary, getLibraryDocs, - context7Agent, + Context7Agent, SYSTEM_PROMPT, AGENT_PROMPT, RESOLVE_LIBRARY_PROMPT, @@ -108,9 +108,9 @@ describe("@upstash/context7-ai-sdk", () => { }, 60000); }); - describe("context7Agent factory", () => { + describe("Context7Agent factory", () => { test("should create an agent instance", () => { - const agent = context7Agent(); + const agent = Context7Agent(); expect(agent).toBeDefined(); expect(agent).toHaveProperty("generate"); @@ -119,7 +119,7 @@ describe("@upstash/context7-ai-sdk", () => { test("should accept custom stopWhen condition", async () => { const { stepCountIs } = await import("ai"); - const agent = context7Agent({ + const agent = Context7Agent({ stopWhen: stepCountIs(3), }); @@ -127,7 +127,7 @@ describe("@upstash/context7-ai-sdk", () => { }); test("should accept custom system prompt", () => { - const agent = context7Agent({ + const agent = Context7Agent({ system: "Custom system prompt for testing", }); diff --git a/packages/ai-sdk/src/index.ts b/packages/ai-sdk/src/index.ts index 8775b1ca3..9240b58c6 100644 --- a/packages/ai-sdk/src/index.ts +++ b/packages/ai-sdk/src/index.ts @@ -1,5 +1,5 @@ // Agents -export { context7Agent, type Context7AgentConfig } from "@agents"; +export { Context7Agent, type Context7AgentConfig } from "@agents"; // Tools export { resolveLibrary, getLibraryDocs, type Context7ToolsConfig } from "@tools"; From 7b7c94e1df25d598a258637273aaedf5ef17cb9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 13:18:06 +0300 Subject: [PATCH 18/36] update tool description var to description --- packages/ai-sdk/src/index.test.ts | 10 +++++----- packages/ai-sdk/src/index.ts | 4 ++-- packages/ai-sdk/src/prompts/index.ts | 4 ++-- packages/ai-sdk/src/prompts/system.ts | 9 ++++++--- packages/ai-sdk/src/tools/get-library-docs.ts | 4 ++-- packages/ai-sdk/src/tools/resolve-library.ts | 4 ++-- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/packages/ai-sdk/src/index.test.ts b/packages/ai-sdk/src/index.test.ts index 999a8491c..bd93a4f10 100644 --- a/packages/ai-sdk/src/index.test.ts +++ b/packages/ai-sdk/src/index.test.ts @@ -7,7 +7,7 @@ import { Context7Agent, SYSTEM_PROMPT, AGENT_PROMPT, - RESOLVE_LIBRARY_PROMPT, + RESOLVE_LIBRARY_DESCRIPTION, } from "./index"; const bedrock = createAmazonBedrock({ @@ -148,10 +148,10 @@ describe("@upstash/context7-ai-sdk", () => { expect(AGENT_PROMPT).toContain("Context7"); }); - test("should export RESOLVE_LIBRARY_PROMPT", () => { - expect(RESOLVE_LIBRARY_PROMPT).toBeDefined(); - expect(typeof RESOLVE_LIBRARY_PROMPT).toBe("string"); - expect(RESOLVE_LIBRARY_PROMPT).toContain("library"); + test("should export RESOLVE_LIBRARY_DESCRIPTION", () => { + expect(RESOLVE_LIBRARY_DESCRIPTION).toBeDefined(); + expect(typeof RESOLVE_LIBRARY_DESCRIPTION).toBe("string"); + expect(RESOLVE_LIBRARY_DESCRIPTION).toContain("library"); }); }); }); diff --git a/packages/ai-sdk/src/index.ts b/packages/ai-sdk/src/index.ts index 9240b58c6..8b24b1e3d 100644 --- a/packages/ai-sdk/src/index.ts +++ b/packages/ai-sdk/src/index.ts @@ -8,8 +8,8 @@ export { resolveLibrary, getLibraryDocs, type Context7ToolsConfig } from "@tools export { SYSTEM_PROMPT, AGENT_PROMPT, - RESOLVE_LIBRARY_PROMPT, - GET_LIBRARY_DOCS_PROMPT, + RESOLVE_LIBRARY_DESCRIPTION, + GET_LIBRARY_DOCS_DESCRIPTION, } from "@prompts"; // Re-export useful types from SDK diff --git a/packages/ai-sdk/src/prompts/index.ts b/packages/ai-sdk/src/prompts/index.ts index 9c5c7312c..407fb9970 100644 --- a/packages/ai-sdk/src/prompts/index.ts +++ b/packages/ai-sdk/src/prompts/index.ts @@ -1,6 +1,6 @@ export { SYSTEM_PROMPT, AGENT_PROMPT, - RESOLVE_LIBRARY_PROMPT, - GET_LIBRARY_DOCS_PROMPT, + RESOLVE_LIBRARY_DESCRIPTION, + GET_LIBRARY_DOCS_DESCRIPTION, } from "./system"; diff --git a/packages/ai-sdk/src/prompts/system.ts b/packages/ai-sdk/src/prompts/system.ts index 2e218a629..44103ad6b 100644 --- a/packages/ai-sdk/src/prompts/system.ts +++ b/packages/ai-sdk/src/prompts/system.ts @@ -51,9 +51,9 @@ IMPORTANT: - Always cite which library ID you used`; /** - * Library resolution instructions for the resolveLibrary tool + * Library resolution tool description */ -export const RESOLVE_LIBRARY_PROMPT = `Resolves a package/product name to a Context7-compatible library ID and returns a list of matching libraries. +export const RESOLVE_LIBRARY_DESCRIPTION = `Resolves a package/product name to a Context7-compatible library ID and returns a list of matching libraries. You MUST call this function before 'getLibraryDocs' to obtain a valid Context7-compatible library ID UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query. @@ -74,5 +74,8 @@ Response Format: For ambiguous queries, request clarification before proceeding with a best-guess match.`; -export const GET_LIBRARY_DOCS_PROMPT = +/** + * Get library docs tool description + */ +export const GET_LIBRARY_DOCS_DESCRIPTION = "Fetches up-to-date documentation for a library. You must call 'resolveLibrary' first to obtain the exact Context7-compatible library ID required to use this tool, UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query. Use mode='code' (default) for API references and code examples, or mode='info' for conceptual guides, narrative information, and architectural questions."; diff --git a/packages/ai-sdk/src/tools/get-library-docs.ts b/packages/ai-sdk/src/tools/get-library-docs.ts index 602817bd1..4584bfb08 100644 --- a/packages/ai-sdk/src/tools/get-library-docs.ts +++ b/packages/ai-sdk/src/tools/get-library-docs.ts @@ -2,7 +2,7 @@ import { tool } from "ai"; import { z } from "zod"; import { Context7 } from "@upstash/context7-sdk"; import type { Context7ToolsConfig } from "./types"; -import { GET_LIBRARY_DOCS_PROMPT } from "@prompts"; +import { GET_LIBRARY_DOCS_DESCRIPTION } from "@prompts"; /** * Tool to fetch documentation for a library using its Context7 library ID. @@ -35,7 +35,7 @@ export function getLibraryDocs(config: Context7ToolsConfig = {}) { const getClient = () => new Context7({ apiKey }); return tool({ - description: GET_LIBRARY_DOCS_PROMPT, + description: GET_LIBRARY_DOCS_DESCRIPTION, inputSchema: z.object({ libraryId: z .string() diff --git a/packages/ai-sdk/src/tools/resolve-library.ts b/packages/ai-sdk/src/tools/resolve-library.ts index dcf463577..ded071062 100644 --- a/packages/ai-sdk/src/tools/resolve-library.ts +++ b/packages/ai-sdk/src/tools/resolve-library.ts @@ -1,7 +1,7 @@ import { tool } from "ai"; import { z } from "zod"; import { Context7 } from "@upstash/context7-sdk"; -import { RESOLVE_LIBRARY_PROMPT } from "@prompts"; +import { RESOLVE_LIBRARY_DESCRIPTION } from "@prompts"; import type { Context7ToolsConfig } from "./types"; /** @@ -35,7 +35,7 @@ export function resolveLibrary(config: Context7ToolsConfig = {}) { const getClient = () => new Context7({ apiKey }); return tool({ - description: RESOLVE_LIBRARY_PROMPT, + description: RESOLVE_LIBRARY_DESCRIPTION, inputSchema: z.object({ libraryName: z .string() From 8d0d3949e17c97bd4dc97ccc47afbe9b7ff511e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 13:18:47 +0300 Subject: [PATCH 19/36] make context7agent config optional --- packages/ai-sdk/src/agents/context7.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ai-sdk/src/agents/context7.ts b/packages/ai-sdk/src/agents/context7.ts index c7024c70c..718af74fd 100644 --- a/packages/ai-sdk/src/agents/context7.ts +++ b/packages/ai-sdk/src/agents/context7.ts @@ -52,7 +52,7 @@ export interface Context7AgentConfig * }); * ``` */ -export function Context7Agent(config: Context7AgentConfig = {}) { +export function Context7Agent(config?: Context7AgentConfig) { const { model, stopWhen = stepCountIs(5), @@ -60,7 +60,7 @@ export function Context7Agent(config: Context7AgentConfig = {}) { apiKey, defaultMaxResults, ...agentSettings - } = config; + } = config || {}; const context7Config: Context7ToolsConfig = { apiKey, defaultMaxResults }; From 410098eec17d84ae1189afee08b15d3f7895b9a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 13:21:49 +0300 Subject: [PATCH 20/36] ci: add changeset --- .changeset/slimy-dancers-wait.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .changeset/slimy-dancers-wait.md diff --git a/.changeset/slimy-dancers-wait.md b/.changeset/slimy-dancers-wait.md new file mode 100644 index 000000000..61390a0dc --- /dev/null +++ b/.changeset/slimy-dancers-wait.md @@ -0,0 +1,12 @@ +--- +"@upstash/context7-ai-sdk": minor +--- + +Initial release of `@upstash/context7-ai-sdk` - Vercel AI SDK integration for Context7. + +### Features + +- **Tools**: `resolveLibrary()` and `getLibraryDocs()` tools compatible with AI SDK's `generateText` and `streamText` +- **Agent**: Pre-configured `Context7Agent` that handles the multi-step documentation retrieval workflow automatically +- **Prompts**: Exported `SYSTEM_PROMPT`, `AGENT_PROMPT`, `RESOLVE_LIBRARY_DESCRIPTION`, and `GET_LIBRARY_DOCS_DESCRIPTION` for customization + From 6ebfdce2fe54eb02fe6caf737db98cb8d12b1557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 13:23:59 +0300 Subject: [PATCH 21/36] make context7-sdk peer deps --- .changeset/slimy-dancers-wait.md | 1 - packages/ai-sdk/README.md | 2 +- packages/ai-sdk/package.json | 11 +++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.changeset/slimy-dancers-wait.md b/.changeset/slimy-dancers-wait.md index 61390a0dc..398bb9d58 100644 --- a/.changeset/slimy-dancers-wait.md +++ b/.changeset/slimy-dancers-wait.md @@ -8,5 +8,4 @@ Initial release of `@upstash/context7-ai-sdk` - Vercel AI SDK integration for Co - **Tools**: `resolveLibrary()` and `getLibraryDocs()` tools compatible with AI SDK's `generateText` and `streamText` - **Agent**: Pre-configured `Context7Agent` that handles the multi-step documentation retrieval workflow automatically -- **Prompts**: Exported `SYSTEM_PROMPT`, `AGENT_PROMPT`, `RESOLVE_LIBRARY_DESCRIPTION`, and `GET_LIBRARY_DOCS_DESCRIPTION` for customization diff --git a/packages/ai-sdk/README.md b/packages/ai-sdk/README.md index 0c398e8ee..847619f99 100644 --- a/packages/ai-sdk/README.md +++ b/packages/ai-sdk/README.md @@ -18,7 +18,7 @@ The package provides two main tools: ### Install ```bash -npm install @upstash/context7-ai-sdk +npm install @upstash/context7-ai-sdk @upstash/context7-sdk ai zod ``` ### Get API Key diff --git a/packages/ai-sdk/package.json b/packages/ai-sdk/package.json index dcaf941b1..54770be7a 100644 --- a/packages/ai-sdk/package.json +++ b/packages/ai-sdk/package.json @@ -28,12 +28,15 @@ "typecheck": "tsc --noEmit", "clean": "rm -rf dist" }, - "dependencies": { - "@upstash/context7-sdk": "workspace:*", - "ai": "^5.0.0", - "zod": "^3.24.0" + "peerDependencies": { + "@upstash/context7-sdk": ">=0.1.0", + "ai": ">=5.0.0", + "zod": ">=3.24.0" }, "devDependencies": { + "@upstash/context7-sdk": "workspace:*", + "ai": "^5.0.0", + "zod": "^3.24.0", "@ai-sdk/amazon-bedrock": "^3.0.55", "@types/node": "^22.13.14", "dotenv": "^17.2.3", From 6f77788d3c6edc93c463ba5d4299748bffc0a3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 13:25:29 +0300 Subject: [PATCH 22/36] update pnpm-lock.yaml --- pnpm-lock.yaml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cb2bbaf2b..912bc8ebb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,16 +40,6 @@ importers: version: 8.47.0(eslint@9.39.1)(typescript@5.9.3) packages/ai-sdk: - dependencies: - '@upstash/context7-sdk': - specifier: workspace:* - version: link:../sdk - ai: - specifier: ^5.0.0 - version: 5.0.104(zod@3.25.76) - zod: - specifier: ^3.24.0 - version: 3.25.76 devDependencies: '@ai-sdk/amazon-bedrock': specifier: ^3.0.55 @@ -57,6 +47,12 @@ importers: '@types/node': specifier: ^22.13.14 version: 22.19.1 + '@upstash/context7-sdk': + specifier: workspace:* + version: link:../sdk + ai: + specifier: ^5.0.0 + version: 5.0.104(zod@3.25.76) dotenv: specifier: ^17.2.3 version: 17.2.3 @@ -69,6 +65,9 @@ importers: vitest: specifier: ^4.0.13 version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@22.19.1) + zod: + specifier: ^3.24.0 + version: 3.25.76 packages/mcp: dependencies: From 600f7e73bec9c5e7c40331bb0e394989b69e6a64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 13:50:47 +0300 Subject: [PATCH 23/36] update package name to @upstash/context7-tools-ai-sdk --- .changeset/slimy-dancers-wait.md | 4 ++-- packages/{ai-sdk => tools-ai-sdk}/README.md | 8 ++++---- packages/{ai-sdk => tools-ai-sdk}/eslint.config.js | 0 packages/{ai-sdk => tools-ai-sdk}/package.json | 6 +++--- packages/{ai-sdk => tools-ai-sdk}/src/agents/context7.ts | 0 packages/{ai-sdk => tools-ai-sdk}/src/agents/index.ts | 0 packages/{ai-sdk => tools-ai-sdk}/src/index.test.ts | 0 packages/{ai-sdk => tools-ai-sdk}/src/index.ts | 0 packages/{ai-sdk => tools-ai-sdk}/src/prompts/index.ts | 0 packages/{ai-sdk => tools-ai-sdk}/src/prompts/system.ts | 0 .../src/tools/get-library-docs.ts | 0 packages/{ai-sdk => tools-ai-sdk}/src/tools/index.ts | 0 .../{ai-sdk => tools-ai-sdk}/src/tools/resolve-library.ts | 0 packages/{ai-sdk => tools-ai-sdk}/src/tools/types.ts | 0 packages/{ai-sdk => tools-ai-sdk}/tsconfig.json | 0 packages/{ai-sdk => tools-ai-sdk}/tsup.config.ts | 0 packages/{ai-sdk => tools-ai-sdk}/vitest.config.ts | 0 17 files changed, 9 insertions(+), 9 deletions(-) rename packages/{ai-sdk => tools-ai-sdk}/README.md (84%) rename packages/{ai-sdk => tools-ai-sdk}/eslint.config.js (100%) rename packages/{ai-sdk => tools-ai-sdk}/package.json (91%) rename packages/{ai-sdk => tools-ai-sdk}/src/agents/context7.ts (100%) rename packages/{ai-sdk => tools-ai-sdk}/src/agents/index.ts (100%) rename packages/{ai-sdk => tools-ai-sdk}/src/index.test.ts (100%) rename packages/{ai-sdk => tools-ai-sdk}/src/index.ts (100%) rename packages/{ai-sdk => tools-ai-sdk}/src/prompts/index.ts (100%) rename packages/{ai-sdk => tools-ai-sdk}/src/prompts/system.ts (100%) rename packages/{ai-sdk => tools-ai-sdk}/src/tools/get-library-docs.ts (100%) rename packages/{ai-sdk => tools-ai-sdk}/src/tools/index.ts (100%) rename packages/{ai-sdk => tools-ai-sdk}/src/tools/resolve-library.ts (100%) rename packages/{ai-sdk => tools-ai-sdk}/src/tools/types.ts (100%) rename packages/{ai-sdk => tools-ai-sdk}/tsconfig.json (100%) rename packages/{ai-sdk => tools-ai-sdk}/tsup.config.ts (100%) rename packages/{ai-sdk => tools-ai-sdk}/vitest.config.ts (100%) diff --git a/.changeset/slimy-dancers-wait.md b/.changeset/slimy-dancers-wait.md index 398bb9d58..b9423d15d 100644 --- a/.changeset/slimy-dancers-wait.md +++ b/.changeset/slimy-dancers-wait.md @@ -1,8 +1,8 @@ --- -"@upstash/context7-ai-sdk": minor +"@upstash/context7-tools-ai-sdk": minor --- -Initial release of `@upstash/context7-ai-sdk` - Vercel AI SDK integration for Context7. +Initial release of `@upstash/context7-tools-ai-sdk` - Vercel AI SDK integration for Context7. ### Features diff --git a/packages/ai-sdk/README.md b/packages/tools-ai-sdk/README.md similarity index 84% rename from packages/ai-sdk/README.md rename to packages/tools-ai-sdk/README.md index 847619f99..b13ac9b84 100644 --- a/packages/ai-sdk/README.md +++ b/packages/tools-ai-sdk/README.md @@ -1,6 +1,6 @@ # Upstash Context7 AI SDK -`@upstash/context7-ai-sdk` provides [Vercel AI SDK](https://sdk.vercel.ai/) compatible tools and agents that give your AI applications access to up to date library documentation through Context7. +`@upstash/context7-tools-ai-sdk` provides [Vercel AI SDK](https://sdk.vercel.ai/) compatible tools and agents that give your AI applications access to up to date library documentation through Context7. Use this package to: @@ -18,7 +18,7 @@ The package provides two main tools: ### Install ```bash -npm install @upstash/context7-ai-sdk @upstash/context7-sdk ai zod +npm install @upstash/context7-tools-ai-sdk @upstash/context7-sdk ai zod ``` ### Get API Key @@ -30,7 +30,7 @@ Get your API key from [Context7](https://context7.com) ### Using Tools with `generateText` ```typescript -import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-tools-ai-sdk"; import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; @@ -52,7 +52,7 @@ console.log(text); The package provides a pre-configured agent that handles the multi-step workflow automatically: ```typescript -import { Context7Agent } from "@upstash/context7-ai-sdk"; +import { Context7Agent } from "@upstash/context7-tools-ai-sdk"; import { anthropic } from "@ai-sdk/anthropic"; const agent = Context7Agent({ diff --git a/packages/ai-sdk/eslint.config.js b/packages/tools-ai-sdk/eslint.config.js similarity index 100% rename from packages/ai-sdk/eslint.config.js rename to packages/tools-ai-sdk/eslint.config.js diff --git a/packages/ai-sdk/package.json b/packages/tools-ai-sdk/package.json similarity index 91% rename from packages/ai-sdk/package.json rename to packages/tools-ai-sdk/package.json index 54770be7a..661cc1b7d 100644 --- a/packages/ai-sdk/package.json +++ b/packages/tools-ai-sdk/package.json @@ -1,7 +1,7 @@ { - "name": "@upstash/context7-ai-sdk", + "name": "@upstash/context7-tools-ai-sdk", "version": "0.1.0", - "description": "Context7 AI SDK integration for Vercel AI SDK", + "description": "Context7 tools for Vercel AI SDK", "type": "module", "main": "./dist/index.cjs", "module": "./dist/index.js", @@ -47,7 +47,7 @@ "repository": { "type": "git", "url": "git+https://github.com/upstash/context7.git", - "directory": "packages/ai-sdk" + "directory": "packages/tools-ai-sdk" }, "keywords": [ "context7", diff --git a/packages/ai-sdk/src/agents/context7.ts b/packages/tools-ai-sdk/src/agents/context7.ts similarity index 100% rename from packages/ai-sdk/src/agents/context7.ts rename to packages/tools-ai-sdk/src/agents/context7.ts diff --git a/packages/ai-sdk/src/agents/index.ts b/packages/tools-ai-sdk/src/agents/index.ts similarity index 100% rename from packages/ai-sdk/src/agents/index.ts rename to packages/tools-ai-sdk/src/agents/index.ts diff --git a/packages/ai-sdk/src/index.test.ts b/packages/tools-ai-sdk/src/index.test.ts similarity index 100% rename from packages/ai-sdk/src/index.test.ts rename to packages/tools-ai-sdk/src/index.test.ts diff --git a/packages/ai-sdk/src/index.ts b/packages/tools-ai-sdk/src/index.ts similarity index 100% rename from packages/ai-sdk/src/index.ts rename to packages/tools-ai-sdk/src/index.ts diff --git a/packages/ai-sdk/src/prompts/index.ts b/packages/tools-ai-sdk/src/prompts/index.ts similarity index 100% rename from packages/ai-sdk/src/prompts/index.ts rename to packages/tools-ai-sdk/src/prompts/index.ts diff --git a/packages/ai-sdk/src/prompts/system.ts b/packages/tools-ai-sdk/src/prompts/system.ts similarity index 100% rename from packages/ai-sdk/src/prompts/system.ts rename to packages/tools-ai-sdk/src/prompts/system.ts diff --git a/packages/ai-sdk/src/tools/get-library-docs.ts b/packages/tools-ai-sdk/src/tools/get-library-docs.ts similarity index 100% rename from packages/ai-sdk/src/tools/get-library-docs.ts rename to packages/tools-ai-sdk/src/tools/get-library-docs.ts diff --git a/packages/ai-sdk/src/tools/index.ts b/packages/tools-ai-sdk/src/tools/index.ts similarity index 100% rename from packages/ai-sdk/src/tools/index.ts rename to packages/tools-ai-sdk/src/tools/index.ts diff --git a/packages/ai-sdk/src/tools/resolve-library.ts b/packages/tools-ai-sdk/src/tools/resolve-library.ts similarity index 100% rename from packages/ai-sdk/src/tools/resolve-library.ts rename to packages/tools-ai-sdk/src/tools/resolve-library.ts diff --git a/packages/ai-sdk/src/tools/types.ts b/packages/tools-ai-sdk/src/tools/types.ts similarity index 100% rename from packages/ai-sdk/src/tools/types.ts rename to packages/tools-ai-sdk/src/tools/types.ts diff --git a/packages/ai-sdk/tsconfig.json b/packages/tools-ai-sdk/tsconfig.json similarity index 100% rename from packages/ai-sdk/tsconfig.json rename to packages/tools-ai-sdk/tsconfig.json diff --git a/packages/ai-sdk/tsup.config.ts b/packages/tools-ai-sdk/tsup.config.ts similarity index 100% rename from packages/ai-sdk/tsup.config.ts rename to packages/tools-ai-sdk/tsup.config.ts diff --git a/packages/ai-sdk/vitest.config.ts b/packages/tools-ai-sdk/vitest.config.ts similarity index 100% rename from packages/ai-sdk/vitest.config.ts rename to packages/tools-ai-sdk/vitest.config.ts From 7657e9bdfdf341c64262729d764040a49839ee01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 13:52:40 +0300 Subject: [PATCH 24/36] remove check workflow --- .github/workflows/check.yaml | 55 ------------------------------------ .github/workflows/test.yml | 24 ++++++++++++++++ 2 files changed, 24 insertions(+), 55 deletions(-) delete mode 100644 .github/workflows/check.yaml diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml deleted file mode 100644 index 678e4a68a..000000000 --- a/.github/workflows/check.yaml +++ /dev/null @@ -1,55 +0,0 @@ -name: Build Check - -on: - push: - branches: [master] - pull_request: - branches: [master] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - name: Build - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: "20" - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 9 - - - name: Get pnpm store directory - id: pnpm-cache - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - - - name: Cache pnpm dependencies - uses: actions/cache@v4 - with: - path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Run linter - run: pnpm run lint:check - - - name: Check formatting - run: pnpm run format:check - - - name: Build project - run: pnpm run build diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9a2536827..77d41ca6d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,6 +6,10 @@ on: branches: [master] workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: test: runs-on: ubuntu-latest @@ -22,9 +26,29 @@ jobs: with: version: 10 + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Cache pnpm dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + - name: Install Dependencies run: pnpm install --frozen-lockfile + - name: Lint + run: pnpm lint:check + + - name: Format + run: pnpm format:check + - name: Build run: pnpm build From a7aa3ab201823df5eb69f80443595d72aeb4f304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 13:54:08 +0300 Subject: [PATCH 25/36] update pnpm lock --- pnpm-lock.yaml | 60 +++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 912bc8ebb..34d2b4b63 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,36 +39,6 @@ importers: specifier: ^8.28.0 version: 8.47.0(eslint@9.39.1)(typescript@5.9.3) - packages/ai-sdk: - devDependencies: - '@ai-sdk/amazon-bedrock': - specifier: ^3.0.55 - version: 3.0.62(zod@3.25.76) - '@types/node': - specifier: ^22.13.14 - version: 22.19.1 - '@upstash/context7-sdk': - specifier: workspace:* - version: link:../sdk - ai: - specifier: ^5.0.0 - version: 5.0.104(zod@3.25.76) - dotenv: - specifier: ^17.2.3 - version: 17.2.3 - tsup: - specifier: ^8.5.1 - version: 8.5.1(postcss@8.5.6)(typescript@5.9.3) - typescript: - specifier: ^5.8.2 - version: 5.9.3 - vitest: - specifier: ^4.0.13 - version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@22.19.1) - zod: - specifier: ^3.24.0 - version: 3.25.76 - packages/mcp: dependencies: '@modelcontextprotocol/sdk': @@ -115,6 +85,36 @@ importers: specifier: ^4.0.13 version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@22.19.1) + packages/tools-ai-sdk: + devDependencies: + '@ai-sdk/amazon-bedrock': + specifier: ^3.0.55 + version: 3.0.62(zod@3.25.76) + '@types/node': + specifier: ^22.13.14 + version: 22.19.1 + '@upstash/context7-sdk': + specifier: workspace:* + version: link:../sdk + ai: + specifier: ^5.0.0 + version: 5.0.104(zod@3.25.76) + dotenv: + specifier: ^17.2.3 + version: 17.2.3 + tsup: + specifier: ^8.5.1 + version: 8.5.1(postcss@8.5.6)(typescript@5.9.3) + typescript: + specifier: ^5.8.2 + version: 5.9.3 + vitest: + specifier: ^4.0.13 + version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@22.19.1) + zod: + specifier: ^3.24.0 + version: 3.25.76 + packages: '@ai-sdk/amazon-bedrock@3.0.62': From 935c0c2a238b48fed3dc86d11e503d1e23de6100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 14:09:20 +0300 Subject: [PATCH 26/36] make the agent a class instead of function --- package.json | 2 +- packages/tools-ai-sdk/README.md | 2 +- packages/tools-ai-sdk/src/agents/context7.ts | 54 ++++++++++---------- packages/tools-ai-sdk/src/index.test.ts | 8 +-- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 5b588ae9b..79fd5f34b 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "typecheck": "pnpm -r run typecheck", "test": "pnpm -r run test", "test:sdk": "pnpm --filter @upstash/context7-sdk test", - "test:ai-sdk": "pnpm --filter @upstash/context7-ai-sdk test", + "test:tools-ai-sdk": "pnpm --filter @upstash/context7-tools-ai-sdk test", "clean": "pnpm -r run clean && rm -rf node_modules", "lint": "pnpm -r run lint", "lint:check": "pnpm -r run lint:check", diff --git a/packages/tools-ai-sdk/README.md b/packages/tools-ai-sdk/README.md index b13ac9b84..ee539ab71 100644 --- a/packages/tools-ai-sdk/README.md +++ b/packages/tools-ai-sdk/README.md @@ -55,7 +55,7 @@ The package provides a pre-configured agent that handles the multi-step workflow import { Context7Agent } from "@upstash/context7-tools-ai-sdk"; import { anthropic } from "@ai-sdk/anthropic"; -const agent = Context7Agent({ +const agent = new Context7Agent({ model: anthropic("claude-sonnet-4-20250514"), }); diff --git a/packages/tools-ai-sdk/src/agents/context7.ts b/packages/tools-ai-sdk/src/agents/context7.ts index 718af74fd..c1933f4d7 100644 --- a/packages/tools-ai-sdk/src/agents/context7.ts +++ b/packages/tools-ai-sdk/src/agents/context7.ts @@ -27,22 +27,19 @@ export interface Context7AgentConfig } /** - * Creates a Context7 documentation search agent + * Context7 documentation search agent * * The agent follows a multi-step workflow: * 1. Resolves library names to Context7 library IDs * 2. Fetches documentation for the resolved library * 3. Provides answers with code examples * - * @param config Configuration options for the agent - * @returns A configured AI agent with Context7 search capabilities - * * @example * ```typescript - * import { Context7Agent } from '@upstash/context7-ai-sdk'; + * import { Context7Agent } from '@upstash/context7-tools-ai-sdk'; * import { anthropic } from '@ai-sdk/anthropic'; * - * const agent = Context7Agent({ + * const agent = new Context7Agent({ * model: anthropic('claude-sonnet-4-20250514'), * apiKey: 'your-context7-api-key', * }); @@ -52,26 +49,31 @@ export interface Context7AgentConfig * }); * ``` */ -export function Context7Agent(config?: Context7AgentConfig) { - const { - model, - stopWhen = stepCountIs(5), - system, - apiKey, - defaultMaxResults, - ...agentSettings - } = config || {}; +export class Context7Agent extends Agent<{ + resolveLibrary: ReturnType; + getLibraryDocs: ReturnType; +}> { + constructor(config?: Context7AgentConfig) { + const { + model, + stopWhen = stepCountIs(5), + system, + apiKey, + defaultMaxResults, + ...agentSettings + } = config || {}; - const context7Config: Context7ToolsConfig = { apiKey, defaultMaxResults }; + const context7Config: Context7ToolsConfig = { apiKey, defaultMaxResults }; - return new Agent({ - ...agentSettings, - model: model as LanguageModel, - system: system || AGENT_PROMPT, - tools: { - resolveLibrary: resolveLibrary(context7Config), - getLibraryDocs: getLibraryDocs(context7Config), - }, - stopWhen, - }); + super({ + ...agentSettings, + model: model as LanguageModel, + system: system || AGENT_PROMPT, + tools: { + resolveLibrary: resolveLibrary(context7Config), + getLibraryDocs: getLibraryDocs(context7Config), + }, + stopWhen, + }); + } } diff --git a/packages/tools-ai-sdk/src/index.test.ts b/packages/tools-ai-sdk/src/index.test.ts index bd93a4f10..3be3974d9 100644 --- a/packages/tools-ai-sdk/src/index.test.ts +++ b/packages/tools-ai-sdk/src/index.test.ts @@ -108,9 +108,9 @@ describe("@upstash/context7-ai-sdk", () => { }, 60000); }); - describe("Context7Agent factory", () => { + describe("Context7Agent class", () => { test("should create an agent instance", () => { - const agent = Context7Agent(); + const agent = new Context7Agent(); expect(agent).toBeDefined(); expect(agent).toHaveProperty("generate"); @@ -119,7 +119,7 @@ describe("@upstash/context7-ai-sdk", () => { test("should accept custom stopWhen condition", async () => { const { stepCountIs } = await import("ai"); - const agent = Context7Agent({ + const agent = new Context7Agent({ stopWhen: stepCountIs(3), }); @@ -127,7 +127,7 @@ describe("@upstash/context7-ai-sdk", () => { }); test("should accept custom system prompt", () => { - const agent = Context7Agent({ + const agent = new Context7Agent({ system: "Custom system prompt for testing", }); From 6b690e7da2ae46549bfd9d4e4f18fccc744c2c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 14:10:24 +0300 Subject: [PATCH 27/36] replace all name instances --- package.json | 2 +- packages/tools-ai-sdk/src/index.test.ts | 2 +- packages/tools-ai-sdk/src/tools/get-library-docs.ts | 2 +- packages/tools-ai-sdk/src/tools/resolve-library.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 79fd5f34b..5d9aaf5f9 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "build": "pnpm -r run build", "build:sdk": "pnpm --filter @upstash/context7-sdk build", "build:mcp": "pnpm --filter @upstash/context7-mcp build", - "build:ai-sdk": "pnpm --filter @upstash/context7-ai-sdk build", + "build:ai-sdk": "pnpm --filter @upstash/context7-tools-ai-sdk build", "typecheck": "pnpm -r run typecheck", "test": "pnpm -r run test", "test:sdk": "pnpm --filter @upstash/context7-sdk test", diff --git a/packages/tools-ai-sdk/src/index.test.ts b/packages/tools-ai-sdk/src/index.test.ts index 3be3974d9..a60eb8529 100644 --- a/packages/tools-ai-sdk/src/index.test.ts +++ b/packages/tools-ai-sdk/src/index.test.ts @@ -15,7 +15,7 @@ const bedrock = createAmazonBedrock({ apiKey: process.env.AWS_BEARER_TOKEN_BEDROCK, }); -describe("@upstash/context7-ai-sdk", () => { +describe("@upstash/context7-tools-ai-sdk", () => { describe("Tool structure", () => { test("resolveLibrary() should return a tool object with correct structure", () => { const tool = resolveLibrary(); diff --git a/packages/tools-ai-sdk/src/tools/get-library-docs.ts b/packages/tools-ai-sdk/src/tools/get-library-docs.ts index 4584bfb08..04d28ab20 100644 --- a/packages/tools-ai-sdk/src/tools/get-library-docs.ts +++ b/packages/tools-ai-sdk/src/tools/get-library-docs.ts @@ -15,7 +15,7 @@ import { GET_LIBRARY_DOCS_DESCRIPTION } from "@prompts"; * * @example * ```typescript - * import { resolveLibrary, getLibraryDocs } from '@upstash/context7-ai-sdk'; + * import { resolveLibrary, getLibraryDocs } from '@upstash/context7-tools-ai-sdk'; * import { generateText, stepCountIs } from 'ai'; * import { openai } from '@ai-sdk/openai'; * diff --git a/packages/tools-ai-sdk/src/tools/resolve-library.ts b/packages/tools-ai-sdk/src/tools/resolve-library.ts index ded071062..1c9771b0e 100644 --- a/packages/tools-ai-sdk/src/tools/resolve-library.ts +++ b/packages/tools-ai-sdk/src/tools/resolve-library.ts @@ -15,7 +15,7 @@ import type { Context7ToolsConfig } from "./types"; * * @example * ```typescript - * import { resolveLibrary, getLibraryDocs } from '@upstash/context7-ai-sdk'; + * import { resolveLibrary, getLibraryDocs } from '@upstash/context7-tools-ai-sdk'; * import { generateText, stepCountIs } from 'ai'; * import { openai } from '@ai-sdk/openai'; * From 50273ba1eb3453f1b6f8dd07d1ed2894f69333fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 14:14:46 +0300 Subject: [PATCH 28/36] add agent generate test --- packages/tools-ai-sdk/src/index.test.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/tools-ai-sdk/src/index.test.ts b/packages/tools-ai-sdk/src/index.test.ts index a60eb8529..8ff7f4b1a 100644 --- a/packages/tools-ai-sdk/src/index.test.ts +++ b/packages/tools-ai-sdk/src/index.test.ts @@ -133,6 +133,24 @@ describe("@upstash/context7-tools-ai-sdk", () => { expect(agent).toBeDefined(); }); + + test("should generate response using agent workflow", async () => { + const agent = new Context7Agent({ + model: bedrock("anthropic.claude-3-haiku-20240307-v1:0"), + stopWhen: stepCountIs(5), + }); + + const result = await agent.generate({ + prompt: "Find the React library and get documentation about hooks", + }); + + expect(result).toBeDefined(); + expect(result.steps.length).toBeGreaterThan(0); + + const allToolCalls = result.steps.flatMap((step) => step.toolCalls); + const toolNames = allToolCalls.map((call) => call.toolName); + expect(toolNames).toContain("resolveLibrary"); + }, 60000); }); describe("Prompt exports", () => { From e904a85f8e0e17d258fe4fa98fc2d323b946ac55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 14:23:56 +0300 Subject: [PATCH 29/36] update docs with latest changes and updated veai sdk examples --- .../ai-sdk/agents/context7-agent.mdx | 38 +++++++++---------- docs/agentic-tools/ai-sdk/getting-started.mdx | 32 ++++++++-------- .../ai-sdk/tools/get-library-docs.mdx | 28 +++++++------- .../ai-sdk/tools/resolve-library.mdx | 22 +++++------ docs/agentic-tools/overview.mdx | 18 ++++----- 5 files changed, 69 insertions(+), 69 deletions(-) diff --git a/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx b/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx index d8807d400..437463664 100644 --- a/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx +++ b/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx @@ -1,20 +1,20 @@ --- -title: "context7Agent" -sidebarTitle: "context7Agent" +title: "Context7Agent" +sidebarTitle: "Context7Agent" description: "Pre-built AI agent for documentation lookup workflows" --- -# context7Agent +# Context7Agent -The `context7Agent` is a pre-configured AI agent that handles the complete documentation lookup workflow automatically. It combines both `resolveLibrary` and `getLibraryDocs` tools with an optimized system prompt. +The `Context7Agent` class is a pre-configured AI agent that handles the complete documentation lookup workflow automatically. It combines both `resolveLibrary` and `getLibraryDocs` tools with an optimized system prompt. ## Usage ```typescript -import { context7Agent } from "@upstash/context7-ai-sdk"; +import { Context7Agent } from "@upstash/context7-tools-ai-sdk"; import { anthropic } from "@ai-sdk/anthropic"; -const agent = context7Agent({ +const agent = new Context7Agent({ model: anthropic("claude-sonnet-4-20250514"), }); @@ -28,7 +28,7 @@ console.log(text); ## Configuration ```typescript -context7Agent(config?: Context7AgentConfig) +new Context7Agent(config?: Context7AgentConfig) ``` ### Parameters @@ -63,7 +63,7 @@ context7Agent(config?: Context7AgentConfig) ### Returns -Returns an AI SDK `Agent` instance with `generate()` and `stream()` methods. +`Context7Agent` extends the AI SDK `Agent` class and provides `generate()` and `stream()` methods. ## Agent Workflow @@ -98,10 +98,10 @@ flowchart TD ### Basic Usage ```typescript -import { context7Agent } from "@upstash/context7-ai-sdk"; +import { Context7Agent } from "@upstash/context7-tools-ai-sdk"; import { anthropic } from "@ai-sdk/anthropic"; -const agent = context7Agent({ +const agent = new Context7Agent({ model: anthropic("claude-sonnet-4-20250514"), }); @@ -115,10 +115,10 @@ console.log(text); ### With OpenAI ```typescript -import { context7Agent } from "@upstash/context7-ai-sdk"; +import { Context7Agent } from "@upstash/context7-tools-ai-sdk"; import { openai } from "@ai-sdk/openai"; -const agent = context7Agent({ +const agent = new Context7Agent({ model: openai("gpt-4o"), }); @@ -130,10 +130,10 @@ const { text } = await agent.generate({ ### Streaming Responses ```typescript -import { context7Agent } from "@upstash/context7-ai-sdk"; +import { Context7Agent } from "@upstash/context7-tools-ai-sdk"; import { anthropic } from "@ai-sdk/anthropic"; -const agent = context7Agent({ +const agent = new Context7Agent({ model: anthropic("claude-sonnet-4-20250514"), }); @@ -149,11 +149,11 @@ for await (const chunk of textStream) { ### Custom Configuration ```typescript -import { context7Agent } from "@upstash/context7-ai-sdk"; +import { Context7Agent } from "@upstash/context7-tools-ai-sdk"; import { anthropic } from "@ai-sdk/anthropic"; import { stepCountIs } from "ai"; -const agent = context7Agent({ +const agent = new Context7Agent({ model: anthropic("claude-sonnet-4-20250514"), apiKey: process.env.CONTEXT7_API_KEY, defaultMaxResults: 5, @@ -164,10 +164,10 @@ const agent = context7Agent({ ### Custom System Prompt ```typescript -import { context7Agent, AGENT_PROMPT } from "@upstash/context7-ai-sdk"; +import { Context7Agent, AGENT_PROMPT } from "@upstash/context7-tools-ai-sdk"; import { openai } from "@ai-sdk/openai"; -const agent = context7Agent({ +const agent = new Context7Agent({ model: openai("gpt-4o"), system: `${AGENT_PROMPT} @@ -180,7 +180,7 @@ Additional instructions: ## Comparison: Agent vs Tools -| Feature | context7Agent | Individual Tools | +| Feature | Context7Agent | Individual Tools | | ------------- | -------------------- | -------------------- | | Setup | Single configuration | Configure each tool | | Workflow | Automatic multi-step | Manual orchestration | diff --git a/docs/agentic-tools/ai-sdk/getting-started.mdx b/docs/agentic-tools/ai-sdk/getting-started.mdx index ed4d4c57b..a20c22eed 100644 --- a/docs/agentic-tools/ai-sdk/getting-started.mdx +++ b/docs/agentic-tools/ai-sdk/getting-started.mdx @@ -6,14 +6,14 @@ description: "Add Context7 documentation tools to your Vercel AI SDK application # Getting Started with AI SDK -`@upstash/context7-ai-sdk` provides [Vercel AI SDK](https://sdk.vercel.ai/) compatible tools and agents that give your AI applications access to up-to-date library documentation. +`@upstash/context7-tools-ai-sdk` provides [Vercel AI SDK](https://sdk.vercel.ai/) compatible tools and agents that give your AI applications access to up-to-date library documentation. When building AI-powered applications with the Vercel AI SDK, your models often need accurate information about libraries and frameworks. Instead of relying on potentially outdated training data, Context7 tools let your AI fetch current documentation on-demand, ensuring responses include correct API usage, current best practices, and working code examples. The package gives you two ways to integrate: 1. **Individual tools** (`resolveLibrary` and `getLibraryDocs`) that you add to your existing `generateText` or `streamText` calls -2. **A pre-built agent** (`context7Agent`) that handles the entire documentation lookup workflow automatically +2. **A pre-built agent** (`Context7Agent`) that handles the entire documentation lookup workflow automatically Both approaches work with any AI provider supported by the Vercel AI SDK, including OpenAI, Anthropic, Google, and others. @@ -21,19 +21,19 @@ Both approaches work with any AI provider supported by the Vercel AI SDK, includ ```bash npm -npm install @upstash/context7-ai-sdk +npm install @upstash/context7-tools-ai-sdk ``` ```bash pnpm -pnpm add @upstash/context7-ai-sdk +pnpm add @upstash/context7-tools-ai-sdk ``` ```bash yarn -yarn add @upstash/context7-ai-sdk +yarn add @upstash/context7-tools-ai-sdk ``` ```bash bun -bun add @upstash/context7-ai-sdk +bun add @upstash/context7-tools-ai-sdk ``` @@ -62,8 +62,8 @@ The tools and agents will automatically use this key. The simplest way to add documentation lookup to your AI application: ```typescript -import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; -import { generateText } from "ai"; +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-tools-ai-sdk"; +import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { text } = await generateText({ @@ -73,7 +73,7 @@ const { text } = await generateText({ resolveLibrary: resolveLibrary(), getLibraryDocs: getLibraryDocs(), }, - maxSteps: 5, + stopWhen: stepCountIs(5), }); console.log(text); @@ -84,10 +84,10 @@ console.log(text); For a more streamlined experience, use the pre-configured agent: ```typescript -import { context7Agent } from "@upstash/context7-ai-sdk"; +import { Context7Agent } from "@upstash/context7-tools-ai-sdk"; import { anthropic } from "@ai-sdk/anthropic"; -const agent = context7Agent({ +const agent = new Context7Agent({ model: anthropic("claude-sonnet-4-20250514"), }); @@ -103,8 +103,8 @@ console.log(text); For streaming responses: ```typescript -import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; -import { streamText } from "ai"; +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-tools-ai-sdk"; +import { streamText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { textStream } = streamText({ @@ -114,7 +114,7 @@ const { textStream } = streamText({ resolveLibrary: resolveLibrary(), getLibraryDocs: getLibraryDocs(), }, - maxSteps: 5, + stopWhen: stepCountIs(5), }); for await (const chunk of textStream) { @@ -127,7 +127,7 @@ for await (const chunk of textStream) { You can also pass the API key directly if needed: ```typescript -import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-tools-ai-sdk"; const tools = { resolveLibrary: resolveLibrary({ apiKey: "your-api-key" }), @@ -161,7 +161,7 @@ The AI model orchestrates these tools automatically based on the user's prompt, Fetch documentation for a specific library - + Use the pre-built documentation agent diff --git a/docs/agentic-tools/ai-sdk/tools/get-library-docs.mdx b/docs/agentic-tools/ai-sdk/tools/get-library-docs.mdx index dc47d80de..dbd61a465 100644 --- a/docs/agentic-tools/ai-sdk/tools/get-library-docs.mdx +++ b/docs/agentic-tools/ai-sdk/tools/get-library-docs.mdx @@ -11,8 +11,8 @@ The `getLibraryDocs` tool fetches documentation for a library using its Context7 ## Usage ```typescript -import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; -import { generateText } from "ai"; +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-tools-ai-sdk"; +import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { text } = await generateText({ @@ -22,7 +22,7 @@ const { text } = await generateText({ resolveLibrary: resolveLibrary(), getLibraryDocs: getLibraryDocs(), }, - maxSteps: 5, + stopWhen: stepCountIs(5), }); ``` @@ -164,8 +164,8 @@ When `mode="info"`, the tool returns conceptual documentation content: ### Basic Usage with Both Tools ```typescript -import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; -import { generateText } from "ai"; +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-tools-ai-sdk"; +import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { text } = await generateText({ @@ -175,7 +175,7 @@ const { text } = await generateText({ resolveLibrary: resolveLibrary(), getLibraryDocs: getLibraryDocs(), }, - maxSteps: 5, + stopWhen: stepCountIs(5), }); // The model will: @@ -187,7 +187,7 @@ const { text } = await generateText({ ### With Custom Configuration ```typescript -import { getLibraryDocs } from "@upstash/context7-ai-sdk"; +import { getLibraryDocs } from "@upstash/context7-tools-ai-sdk"; const tool = getLibraryDocs({ apiKey: process.env.CONTEXT7_API_KEY, @@ -200,8 +200,8 @@ const tool = getLibraryDocs({ If the user provides a library ID directly, the model can skip the resolution step: ```typescript -import { getLibraryDocs } from "@upstash/context7-ai-sdk"; -import { generateText } from "ai"; +import { getLibraryDocs } from "@upstash/context7-tools-ai-sdk"; +import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { text } = await generateText({ @@ -210,7 +210,7 @@ const { text } = await generateText({ tools: { getLibraryDocs: getLibraryDocs(), }, - maxSteps: 3, + stopWhen: stepCountIs(3), }); // The model recognizes the /org/project format and calls getLibraryDocs directly @@ -221,8 +221,8 @@ const { text } = await generateText({ For comprehensive documentation, the model can request multiple pages: ```typescript -import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; -import { generateText } from "ai"; +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-tools-ai-sdk"; +import { generateText, stepCountIs } from "ai"; import { anthropic } from "@ai-sdk/anthropic"; const { text } = await generateText({ @@ -232,7 +232,7 @@ const { text } = await generateText({ resolveLibrary: resolveLibrary(), getLibraryDocs: getLibraryDocs(), }, - maxSteps: 8, // Allow more steps for pagination + stopWhen: stepCountIs(8), // Allow more steps for pagination }); // The model may call getLibraryDocs multiple times with page=1, page=2, etc. @@ -282,4 +282,4 @@ The model can request documentation for specific versions when the user asks abo ## Related - [resolveLibrary](/agentic-tools/ai-sdk/tools/resolve-library) - Search for libraries and get their IDs -- [context7Agent](/agentic-tools/ai-sdk/agents/context7-agent) - Pre-built agent that handles the full workflow +- [Context7Agent](/agentic-tools/ai-sdk/agents/context7-agent) - Pre-built agent that handles the full workflow diff --git a/docs/agentic-tools/ai-sdk/tools/resolve-library.mdx b/docs/agentic-tools/ai-sdk/tools/resolve-library.mdx index 72a701f17..0c6e7bb25 100644 --- a/docs/agentic-tools/ai-sdk/tools/resolve-library.mdx +++ b/docs/agentic-tools/ai-sdk/tools/resolve-library.mdx @@ -11,8 +11,8 @@ The `resolveLibrary` tool searches Context7's library database and returns match ## Usage ```typescript -import { resolveLibrary } from "@upstash/context7-ai-sdk"; -import { generateText } from "ai"; +import { resolveLibrary } from "@upstash/context7-tools-ai-sdk"; +import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { text } = await generateText({ @@ -21,7 +21,7 @@ const { text } = await generateText({ tools: { resolveLibrary: resolveLibrary(), }, - maxSteps: 3, + stopWhen: stepCountIs(3), }); ``` @@ -106,8 +106,8 @@ On failure: ### Basic Usage ```typescript -import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; -import { generateText } from "ai"; +import { resolveLibrary, getLibraryDocs } from "@upstash/context7-tools-ai-sdk"; +import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { text, toolCalls } = await generateText({ @@ -117,7 +117,7 @@ const { text, toolCalls } = await generateText({ resolveLibrary: resolveLibrary(), getLibraryDocs: getLibraryDocs(), }, - maxSteps: 5, + stopWhen: stepCountIs(5), }); // The model will call resolveLibrary("react") and receive a list of matching libraries @@ -127,7 +127,7 @@ console.log(text); ### With Custom API Key ```typescript -import { resolveLibrary } from "@upstash/context7-ai-sdk"; +import { resolveLibrary } from "@upstash/context7-tools-ai-sdk"; const tool = resolveLibrary({ apiKey: process.env.CONTEXT7_API_KEY, @@ -137,8 +137,8 @@ const tool = resolveLibrary({ ### Inspecting Tool Calls ```typescript -import { resolveLibrary } from "@upstash/context7-ai-sdk"; -import { generateText } from "ai"; +import { resolveLibrary } from "@upstash/context7-tools-ai-sdk"; +import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { toolCalls, toolResults } = await generateText({ @@ -147,7 +147,7 @@ const { toolCalls, toolResults } = await generateText({ tools: { resolveLibrary: resolveLibrary(), }, - maxSteps: 3, + stopWhen: stepCountIs(3), }); // See what the model searched for @@ -174,4 +174,4 @@ The tool's description instructs the AI model to select libraries based on: ## Related - [getLibraryDocs](/agentic-tools/ai-sdk/tools/get-library-docs) - Fetch documentation using the resolved library ID -- [context7Agent](/agentic-tools/ai-sdk/agents/context7-agent) - Pre-built agent that handles the full workflow +- [Context7Agent](/agentic-tools/ai-sdk/agents/context7-agent) - Pre-built agent that handles the full workflow diff --git a/docs/agentic-tools/overview.mdx b/docs/agentic-tools/overview.mdx index 58f50b639..16ff22f50 100644 --- a/docs/agentic-tools/overview.mdx +++ b/docs/agentic-tools/overview.mdx @@ -27,7 +27,7 @@ Context7's agentic tools solve these problems by giving your agents direct acces href="/agentic-tools/ai-sdk/getting-started" > Add Context7 tools to your AI SDK workflows with `generateText`, `streamText`, or use the - pre-built `context7Agent` for automatic documentation lookup. + pre-built `Context7Agent` for automatic documentation lookup. @@ -57,9 +57,9 @@ sequenceDiagram Build chatbots that answer framework questions with accurate, version-specific information: ```typescript - import { generateText } from "ai"; + import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; - import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; + import { resolveLibrary, getLibraryDocs } from "@upstash/context7-tools-ai-sdk"; const { text } = await generateText({ model: openai("gpt-4o"), @@ -68,7 +68,7 @@ sequenceDiagram resolveLibrary: resolveLibrary(), getLibraryDocs: getLibraryDocs(), }, - maxSteps: 5, + stopWhen: stepCountIs(5), }); ``` @@ -77,10 +77,10 @@ sequenceDiagram Ensure generated code uses current APIs and best practices: ```typescript - import { context7Agent } from "@upstash/context7-ai-sdk"; + import { Context7Agent } from "@upstash/context7-tools-ai-sdk"; import { anthropic } from "@ai-sdk/anthropic"; - const agent = context7Agent({ + const agent = new Context7Agent({ model: anthropic("claude-sonnet-4-20250514"), }); @@ -94,9 +94,9 @@ sequenceDiagram Build code review agents that verify implementations against current API documentation: ```typescript - import { generateText } from "ai"; + import { generateText, stepCountIs } from "ai"; import { anthropic } from "@ai-sdk/anthropic"; - import { resolveLibrary, getLibraryDocs } from "@upstash/context7-ai-sdk"; + import { resolveLibrary, getLibraryDocs } from "@upstash/context7-tools-ai-sdk"; const codeToReview = ` const { data } = await supabase @@ -117,7 +117,7 @@ sequenceDiagram resolveLibrary: resolveLibrary(), getLibraryDocs: getLibraryDocs(), }, - maxSteps: 5, + stopWhen: stepCountIs(5), }); // Agent fetches current Supabase docs to verify: From 62bba8b22ea72a7574af2a74104e045e406595ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 14:29:28 +0300 Subject: [PATCH 30/36] finalize docs --- docs/agentic-tools/overview.mdx | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/docs/agentic-tools/overview.mdx b/docs/agentic-tools/overview.mdx index 16ff22f50..2594783e1 100644 --- a/docs/agentic-tools/overview.mdx +++ b/docs/agentic-tools/overview.mdx @@ -71,6 +71,7 @@ sequenceDiagram stopWhen: stepCountIs(5), }); ``` + @@ -88,6 +89,7 @@ sequenceDiagram prompt: "Generate a Supabase Edge Function that handles webhooks", }); ``` + @@ -126,23 +128,6 @@ sequenceDiagram // - Security best practices // - Error handling recommendations ``` - - - - Augment your developer tools with real-time documentation retrieval for IDE extensions, CLI tools, or code review systems. - - **IDE Extensions** - Provide inline documentation suggestions based on the libraries in use - - **CLI Tools** - Build command-line assistants that help developers with framework-specific questions - - **Documentation Search** - Create search interfaces that return accurate, up-to-date code examples - -## Getting Started - -Choose your integration to get started: - - - - The fastest way to add documentation lookup to your AI applications - - From 3f6db0cae972f3f71b10cd29d15fb47b4802b307 Mon Sep 17 00:00:00 2001 From: enesgules Date: Thu, 4 Dec 2025 15:18:40 +0300 Subject: [PATCH 31/36] docs: remove duplicate H1 headers from AI SDK documentation pages --- docs/agentic-tools/ai-sdk/agents/context7-agent.mdx | 2 -- docs/agentic-tools/ai-sdk/getting-started.mdx | 2 -- docs/agentic-tools/ai-sdk/tools/get-library-docs.mdx | 2 -- docs/agentic-tools/ai-sdk/tools/resolve-library.mdx | 2 -- 4 files changed, 8 deletions(-) diff --git a/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx b/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx index 437463664..47817d220 100644 --- a/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx +++ b/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx @@ -4,8 +4,6 @@ sidebarTitle: "Context7Agent" description: "Pre-built AI agent for documentation lookup workflows" --- -# Context7Agent - The `Context7Agent` class is a pre-configured AI agent that handles the complete documentation lookup workflow automatically. It combines both `resolveLibrary` and `getLibraryDocs` tools with an optimized system prompt. ## Usage diff --git a/docs/agentic-tools/ai-sdk/getting-started.mdx b/docs/agentic-tools/ai-sdk/getting-started.mdx index a20c22eed..ec8c95ae0 100644 --- a/docs/agentic-tools/ai-sdk/getting-started.mdx +++ b/docs/agentic-tools/ai-sdk/getting-started.mdx @@ -4,8 +4,6 @@ sidebarTitle: "Getting Started" description: "Add Context7 documentation tools to your Vercel AI SDK applications" --- -# Getting Started with AI SDK - `@upstash/context7-tools-ai-sdk` provides [Vercel AI SDK](https://sdk.vercel.ai/) compatible tools and agents that give your AI applications access to up-to-date library documentation. When building AI-powered applications with the Vercel AI SDK, your models often need accurate information about libraries and frameworks. Instead of relying on potentially outdated training data, Context7 tools let your AI fetch current documentation on-demand, ensuring responses include correct API usage, current best practices, and working code examples. diff --git a/docs/agentic-tools/ai-sdk/tools/get-library-docs.mdx b/docs/agentic-tools/ai-sdk/tools/get-library-docs.mdx index dbd61a465..50c54add9 100644 --- a/docs/agentic-tools/ai-sdk/tools/get-library-docs.mdx +++ b/docs/agentic-tools/ai-sdk/tools/get-library-docs.mdx @@ -4,8 +4,6 @@ sidebarTitle: "getLibraryDocs" description: "Fetch up-to-date documentation for a specific library" --- -# getLibraryDocs - The `getLibraryDocs` tool fetches documentation for a library using its Context7-compatible library ID. This tool is typically called after `resolveLibrary` has identified the correct library. ## Usage diff --git a/docs/agentic-tools/ai-sdk/tools/resolve-library.mdx b/docs/agentic-tools/ai-sdk/tools/resolve-library.mdx index 0c6e7bb25..eb298aa36 100644 --- a/docs/agentic-tools/ai-sdk/tools/resolve-library.mdx +++ b/docs/agentic-tools/ai-sdk/tools/resolve-library.mdx @@ -4,8 +4,6 @@ sidebarTitle: "resolveLibrary" description: "Search for libraries and resolve them to Context7-compatible IDs" --- -# resolveLibrary - The `resolveLibrary` tool searches Context7's library database and returns matching results with their Context7-compatible library IDs. This is typically the first step in a documentation lookup workflow. ## Usage From e5c88fb1381b934c47e6cc6109a1067639e449b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 15:28:03 +0300 Subject: [PATCH 32/36] simplify agent config --- packages/tools-ai-sdk/src/agents/context7.ts | 42 ++++++------- packages/tools-ai-sdk/src/index.test.ts | 65 ++++++++++++++++++-- 2 files changed, 78 insertions(+), 29 deletions(-) diff --git a/packages/tools-ai-sdk/src/agents/context7.ts b/packages/tools-ai-sdk/src/agents/context7.ts index c1933f4d7..817562da2 100644 --- a/packages/tools-ai-sdk/src/agents/context7.ts +++ b/packages/tools-ai-sdk/src/agents/context7.ts @@ -1,29 +1,26 @@ import { Experimental_Agent as Agent, type Experimental_AgentSettings as AgentSettings, - type LanguageModel, + type ToolSet, stepCountIs, } from "ai"; -import { resolveLibrary, getLibraryDocs, type Context7ToolsConfig } from "@tools"; +import { resolveLibrary, getLibraryDocs } from "@tools"; import { AGENT_PROMPT } from "@prompts"; /** - * Configuration for Context7 agent + * Configuration for Context7 agent. */ -export interface Context7AgentConfig - extends Context7ToolsConfig, - Partial< - AgentSettings<{ - resolveLibrary: ReturnType; - getLibraryDocs: ReturnType; - }> - > { +export interface Context7AgentConfig extends AgentSettings { /** - * Language model to use. Must be a LanguageModel instance from an AI SDK provider. - * @example anthropic('claude-sonnet-4-20250514') - * @example openai('gpt-4o') + * Context7 API key. If not provided, uses the CONTEXT7_API_KEY environment variable. */ - model?: LanguageModel; + apiKey?: string; + + /** + * Default maximum number of documentation results per request. + * @default 10 + */ + defaultMaxResults?: number; } /** @@ -49,27 +46,26 @@ export interface Context7AgentConfig * }); * ``` */ -export class Context7Agent extends Agent<{ - resolveLibrary: ReturnType; - getLibraryDocs: ReturnType; -}> { - constructor(config?: Context7AgentConfig) { +export class Context7Agent extends Agent { + constructor(config: Context7AgentConfig) { const { model, stopWhen = stepCountIs(5), system, apiKey, defaultMaxResults, + tools, ...agentSettings - } = config || {}; + } = config; - const context7Config: Context7ToolsConfig = { apiKey, defaultMaxResults }; + const context7Config = { apiKey, defaultMaxResults }; super({ ...agentSettings, - model: model as LanguageModel, + model, system: system || AGENT_PROMPT, tools: { + ...tools, resolveLibrary: resolveLibrary(context7Config), getLibraryDocs: getLibraryDocs(context7Config), }, diff --git a/packages/tools-ai-sdk/src/index.test.ts b/packages/tools-ai-sdk/src/index.test.ts index 8ff7f4b1a..58750d045 100644 --- a/packages/tools-ai-sdk/src/index.test.ts +++ b/packages/tools-ai-sdk/src/index.test.ts @@ -1,6 +1,7 @@ import { describe, test, expect } from "vitest"; -import { generateText, stepCountIs } from "ai"; +import { generateText, stepCountIs, tool } from "ai"; import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock"; +import { z } from "zod"; import { resolveLibrary, getLibraryDocs, @@ -109,17 +110,19 @@ describe("@upstash/context7-tools-ai-sdk", () => { }); describe("Context7Agent class", () => { - test("should create an agent instance", () => { - const agent = new Context7Agent(); + test("should create an agent instance with model", () => { + const agent = new Context7Agent({ + model: bedrock("anthropic.claude-3-haiku-20240307-v1:0"), + }); expect(agent).toBeDefined(); expect(agent).toHaveProperty("generate"); + expect(agent).toHaveProperty("stream"); }); - test("should accept custom stopWhen condition", async () => { - const { stepCountIs } = await import("ai"); - + test("should accept custom stopWhen condition", () => { const agent = new Context7Agent({ + model: bedrock("anthropic.claude-3-haiku-20240307-v1:0"), stopWhen: stepCountIs(3), }); @@ -128,12 +131,42 @@ describe("@upstash/context7-tools-ai-sdk", () => { test("should accept custom system prompt", () => { const agent = new Context7Agent({ + model: bedrock("anthropic.claude-3-haiku-20240307-v1:0"), system: "Custom system prompt for testing", }); expect(agent).toBeDefined(); }); + test("should accept Context7 config options", () => { + const agent = new Context7Agent({ + model: bedrock("anthropic.claude-3-haiku-20240307-v1:0"), + apiKey: "ctx7sk-test-key", + defaultMaxResults: 5, + }); + + expect(agent).toBeDefined(); + }); + + test("should accept additional tools alongside Context7 tools", () => { + const customTool = tool({ + description: "A custom test tool", + inputSchema: z.object({ + input: z.string().describe("Test input"), + }), + execute: async ({ input }) => ({ result: `processed: ${input}` }), + }); + + const agent = new Context7Agent({ + model: bedrock("anthropic.claude-3-haiku-20240307-v1:0"), + tools: { + customTool, + }, + }); + + expect(agent).toBeDefined(); + }); + test("should generate response using agent workflow", async () => { const agent = new Context7Agent({ model: bedrock("anthropic.claude-3-haiku-20240307-v1:0"), @@ -151,6 +184,26 @@ describe("@upstash/context7-tools-ai-sdk", () => { const toolNames = allToolCalls.map((call) => call.toolName); expect(toolNames).toContain("resolveLibrary"); }, 60000); + + test("should include Context7 tools in generate result", async () => { + const agent = new Context7Agent({ + model: bedrock("anthropic.claude-3-haiku-20240307-v1:0"), + stopWhen: stepCountIs(5), + }); + + const result = await agent.generate({ + prompt: + "Use resolveLibrary to search for Next.js, then use getLibraryDocs to get routing documentation", + }); + + expect(result).toBeDefined(); + + const allToolCalls = result.steps.flatMap((step) => step.toolCalls); + const toolNames = allToolCalls.map((call) => call.toolName); + + expect(toolNames).toContain("resolveLibrary"); + expect(toolNames).toContain("getLibraryDocs"); + }, 60000); }); describe("Prompt exports", () => { From a3ced6dbaaa2b49d43d03748aa0658a28cae2823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Thu, 4 Dec 2025 20:41:54 +0300 Subject: [PATCH 33/36] fix refs --- packages/tools-ai-sdk/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/tools-ai-sdk/README.md b/packages/tools-ai-sdk/README.md index ee539ab71..6afb130e4 100644 --- a/packages/tools-ai-sdk/README.md +++ b/packages/tools-ai-sdk/README.md @@ -1,6 +1,6 @@ # Upstash Context7 AI SDK -`@upstash/context7-tools-ai-sdk` provides [Vercel AI SDK](https://sdk.vercel.ai/) compatible tools and agents that give your AI applications access to up to date library documentation through Context7. +`@upstash/context7-tools-ai-sdk` provides [Vercel AI SDK](https://ai-sdk.dev/) compatible tools and agents that give your AI applications access to up to date library documentation through Context7. Use this package to: @@ -84,7 +84,7 @@ const tool = resolveLibrary(); // Uses CONTEXT7_API_KEY automatically ## Docs -See the [documentation](https://context7.com/docs/sdks/ai-sdk/getting-started) for details. +See the [documentation](https://context7.com/docs/agentic-tools/ai-sdk/getting-started) for details. ## Contributing From b4c3ace070ea37ae921d0b987418f0c50a91a2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Tue, 6 Jan 2026 15:43:46 +0300 Subject: [PATCH 34/36] remove changeset --- .changeset/slimy-dancers-wait.md | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 .changeset/slimy-dancers-wait.md diff --git a/.changeset/slimy-dancers-wait.md b/.changeset/slimy-dancers-wait.md deleted file mode 100644 index b9423d15d..000000000 --- a/.changeset/slimy-dancers-wait.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@upstash/context7-tools-ai-sdk": minor ---- - -Initial release of `@upstash/context7-tools-ai-sdk` - Vercel AI SDK integration for Context7. - -### Features - -- **Tools**: `resolveLibrary()` and `getLibraryDocs()` tools compatible with AI SDK's `generateText` and `streamText` -- **Agent**: Pre-configured `Context7Agent` that handles the multi-step documentation retrieval workflow automatically - From a6fb8878c54e7a5466f63099164b82182f2cdf5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Tue, 6 Jan 2026 15:52:00 +0300 Subject: [PATCH 35/36] feat: update diagram with query param --- docs/agentic-tools/overview.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/agentic-tools/overview.mdx b/docs/agentic-tools/overview.mdx index 70064d340..81032b4e6 100644 --- a/docs/agentic-tools/overview.mdx +++ b/docs/agentic-tools/overview.mdx @@ -41,9 +41,9 @@ sequenceDiagram participant Docs User->>Agent: "How do I use React Server Components?" - Agent->>Context7: resolveLibraryId("react") + Agent->>Context7: resolveLibraryId(query: "React Server Components", libraryName: "react") Context7-->>Agent: Library ID: /reactjs/react.dev - Agent->>Context7: queryDocs("/reactjs/react.dev", query: "server components") + Agent->>Context7: queryDocs(libraryId: "/reactjs/react.dev", query: "server components") Context7->>Docs: Fetch latest documentation Docs-->>Context7: Current docs with examples Context7-->>Agent: Documentation content From 766c4fdfa44af087eb6ca0d42568729429960c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fahreddin=20=C3=96zcan?= Date: Wed, 7 Jan 2026 17:57:19 +0300 Subject: [PATCH 36/36] fix: address reviews --- .../ai-sdk/agents/context7-agent.mdx | 6 +-- docs/agentic-tools/ai-sdk/getting-started.mdx | 4 +- .../agentic-tools/ai-sdk/tools/query-docs.mdx | 52 +++++++++---------- .../ai-sdk/tools/resolve-library-id.mdx | 49 ++++++++--------- docs/agentic-tools/overview.mdx | 2 +- 5 files changed, 52 insertions(+), 61 deletions(-) diff --git a/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx b/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx index 484deb2e2..7af48abdb 100644 --- a/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx +++ b/docs/agentic-tools/ai-sdk/agents/context7-agent.mdx @@ -40,7 +40,7 @@ new Context7Agent(config?: Context7AgentConfig) Examples: - `anthropic('claude-sonnet-4-20250514')` - - `openai('gpt-4o')` + - `openai('gpt-5.2')` - `google('gemini-1.5-pro')` @@ -114,7 +114,7 @@ import { Context7Agent } from "@upstash/context7-tools-ai-sdk"; import { openai } from "@ai-sdk/openai"; const agent = new Context7Agent({ - model: openai("gpt-4o"), + model: openai("gpt-5.2"), }); const { text } = await agent.generate({ @@ -162,7 +162,7 @@ import { Context7Agent, AGENT_PROMPT } from "@upstash/context7-tools-ai-sdk"; import { openai } from "@ai-sdk/openai"; const agent = new Context7Agent({ - model: openai("gpt-4o"), + model: openai("gpt-5.2"), system: `${AGENT_PROMPT} Additional instructions: diff --git a/docs/agentic-tools/ai-sdk/getting-started.mdx b/docs/agentic-tools/ai-sdk/getting-started.mdx index 11580295d..dc9c57fe7 100644 --- a/docs/agentic-tools/ai-sdk/getting-started.mdx +++ b/docs/agentic-tools/ai-sdk/getting-started.mdx @@ -65,7 +65,7 @@ import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { text } = await generateText({ - model: openai("gpt-4o"), + model: openai("gpt-5.2"), prompt: "How do I create a server action in Next.js?", tools: { resolveLibraryId: resolveLibraryId(), @@ -106,7 +106,7 @@ import { streamText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { textStream } = streamText({ - model: openai("gpt-4o"), + model: openai("gpt-5.2"), prompt: "Explain how to use Tanstack Query for data fetching", tools: { resolveLibraryId: resolveLibraryId(), diff --git a/docs/agentic-tools/ai-sdk/tools/query-docs.mdx b/docs/agentic-tools/ai-sdk/tools/query-docs.mdx index 28d136902..84525a4f0 100644 --- a/docs/agentic-tools/ai-sdk/tools/query-docs.mdx +++ b/docs/agentic-tools/ai-sdk/tools/query-docs.mdx @@ -14,7 +14,7 @@ import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { text } = await generateText({ - model: openai("gpt-4o"), + model: openai("gpt-5.2"), prompt: "How do I use React Server Components?", tools: { resolveLibraryId: resolveLibraryId(), @@ -68,37 +68,33 @@ The tool accepts the following inputs from the AI model: ### Output Format -On success, the tool returns the documentation: +On success, the tool returns the documentation as plain text, formatted for easy consumption by the AI model: -```typescript -{ - success: true, - libraryId: "/reactjs/react.dev", - documentation: [ - { - title: "Server Components", - content: "Server Components let you write UI that can be rendered...", - codeExamples: [ - { - language: "tsx", - code: "async function ServerComponent() {\n const data = await fetchData();\n return
{data}
;\n}" - } - ] - }, - // ... more documentation - ], - totalResults: 5 +``` +# Server Components + +Server Components let you write UI that can be rendered and optionally cached on the server. + +## Example + +\`\`\`tsx +async function ServerComponent() { + const data = await fetchData(); + return
{data}
; } +\`\`\` + +--- + +# Using Server Components with Client Components + +You can import Server Components into Client Components... ``` #### On Failure -```typescript -{ - success: false, - error: "Documentation not found or not finalized for this library.", - libraryId: "/invalid/library" -} +``` +No documentation found for library "/invalid/library". This might have happened because you used an invalid Context7-compatible library ID. Use 'resolveLibraryId' to get a valid ID. ``` ## Examples @@ -111,7 +107,7 @@ import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { text } = await generateText({ - model: openai("gpt-4o"), + model: openai("gpt-5.2"), prompt: "Show me how to set up routing in Next.js App Router", tools: { resolveLibraryId: resolveLibraryId(), @@ -146,7 +142,7 @@ import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { text } = await generateText({ - model: openai("gpt-4o"), + model: openai("gpt-5.2"), prompt: "Using /vercel/next.js, explain middleware", tools: { queryDocs: queryDocs(), diff --git a/docs/agentic-tools/ai-sdk/tools/resolve-library-id.mdx b/docs/agentic-tools/ai-sdk/tools/resolve-library-id.mdx index 7fe8d7a2f..1c5a7e6c7 100644 --- a/docs/agentic-tools/ai-sdk/tools/resolve-library-id.mdx +++ b/docs/agentic-tools/ai-sdk/tools/resolve-library-id.mdx @@ -14,7 +14,7 @@ import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { text } = await generateText({ - model: openai("gpt-4o"), + model: openai("gpt-5.2"), prompt: "Find documentation for React hooks", tools: { resolveLibraryId: resolveLibraryId(), @@ -72,35 +72,30 @@ The tool accepts the following input from the AI model: ### Output Format -On success, the tool returns the search results as JSON: +On success, the tool returns the search results as plain text, formatted for easy consumption by the AI model: -```typescript -{ - success: true, - results: [ - { - id: "/reactjs/react.dev", - title: "React Documentation", - description: "The library for web and native user interfaces", - totalSnippets: 1250, - trustScore: 0.95, - benchmarkScore: 98, - versions: ["19.0.0", "18.3.1", "18.2.0"] - }, - // ... more results - ], - totalResults: 5 -} +``` +- Title: React Documentation +- Context7-compatible library ID: /reactjs/react.dev +- Description: The library for web and native user interfaces +- Code Snippets: 1250 +- Trust Score: High +- Benchmark Score: 98 +- Versions: 19.0.0, 18.3.1, 18.2.0 +---------- +- Title: React Native +- Context7-compatible library ID: /facebook/react-native +- Description: A framework for building native applications using React +- Code Snippets: 890 +- Trust Score: High +- Benchmark Score: 95 +- Versions: 0.76.0, 0.75.4 ``` On failure: -```typescript -{ - success: false, - error: "No libraries found matching your query.", - suggestions: "Try a different search term or check the library name." -} +``` +No libraries found matching "unknown-lib". Try a different search term or check the library name. ``` ## Examples @@ -113,7 +108,7 @@ import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { text, toolCalls } = await generateText({ - model: openai("gpt-4o"), + model: openai("gpt-5.2"), prompt: "What libraries are available for React?", tools: { resolveLibraryId: resolveLibraryId(), @@ -144,7 +139,7 @@ import { generateText, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; const { toolCalls, toolResults } = await generateText({ - model: openai("gpt-4o"), + model: openai("gpt-5.2"), prompt: "Find the official Next.js documentation", tools: { resolveLibraryId: resolveLibraryId(), diff --git a/docs/agentic-tools/overview.mdx b/docs/agentic-tools/overview.mdx index 81032b4e6..9f525edd9 100644 --- a/docs/agentic-tools/overview.mdx +++ b/docs/agentic-tools/overview.mdx @@ -62,7 +62,7 @@ sequenceDiagram import { resolveLibraryId, queryDocs } from "@upstash/context7-tools-ai-sdk"; const { text } = await generateText({ - model: openai("gpt-4o"), + model: openai("gpt-5.2"), prompt: "How do I set up authentication in Next.js 15?", tools: { resolveLibraryId: resolveLibraryId(),