Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/sdk-source-reputation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@upstash/context7-sdk": minor
---

`searchLibrary` returns an empty list (or, with `type: "txt"`, a "No libraries found" message) when nothing matches, instead of throwing a 404 `Context7Error`. Text results label the trust score as "Source Reputation", the same as the MCP server.
5 changes: 5 additions & 0 deletions .changeset/tools-no-match-messages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@upstash/context7-tools-ai-sdk": patch
---

`resolveLibraryId` returns the SDK's "No libraries found" message when nothing matches, and `queryDocs` returns its "No documentation found" message for an unknown library ID. Other errors no longer end with ".. Check your API key and try again."
4 changes: 2 additions & 2 deletions docs/agentic-tools/ai-sdk/tools/resolve-library-id.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ On success, the tool returns the search results as plain text, formatted for eas
- Versions: 0.76.0, 0.75.4
```

On failure:
When nothing matches:

```
No libraries found matching "unknown-lib". Try a different search term or check the library name.
No libraries found matching your query. Try a different search term or check the library name.
```

## Examples
Expand Down
15 changes: 14 additions & 1 deletion packages/sdk/src/commands/search-library/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, test, expect } from "vitest";
import { SearchLibraryCommand } from "./index";
import { Context7Error } from "@error";
import { requesterWith } from "@utils/test-utils";
import type { Requester } from "@http";

const apiResult = {
results: [
Expand Down Expand Up @@ -42,7 +43,7 @@ describe("SearchLibraryCommand", () => {
const result = await command.exec(requesterWith(apiResult));

expect(result).toContain("Context7-compatible library ID: /facebook/react");
expect(result).toContain("Trust Score: High");
expect(result).toContain("Source Reputation: High");
});

test("throws a Context7 error when the response has no result", async () => {
Expand All @@ -57,6 +58,18 @@ describe("SearchLibraryCommand", () => {
});
});

test("returns no libraries when the API finds no match", async () => {
const notFound: Requester = {
request: async () => {
throw new Context7Error("No libraries found", { status: 404, code: "no_libraries_found" });
},
};

await expect(new SearchLibraryCommand("query", "unknown-lib").exec(notFound)).resolves.toEqual(
[]
);
});

test("rejects missing inputs without making a request", () => {
expect(() => new SearchLibraryCommand("", "react")).toThrow(Context7Error);
expect(() => new SearchLibraryCommand("query", "")).toThrow(Context7Error);
Expand Down
16 changes: 13 additions & 3 deletions packages/sdk/src/commands/search-library/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,24 @@ export class SearchLibraryCommand extends Command<Library[] | string> {
}

public override async exec(client: Requester): Promise<Library[] | string> {
const result = await this.requestResult<ApiSearchResponse>(client);

const libraries = result.results.map(formatLibrary);
const libraries = await this.findLibraries(client);

if (this.responseType === "txt") {
return formatLibrariesAsText(libraries);
}

return libraries;
}

private async findLibraries(client: Requester): Promise<Library[]> {
try {
const result = await this.requestResult<ApiSearchResponse>(client);
return result.results.map(formatLibrary);
} catch (error) {
// The API answers 404 when nothing matches. A search with no hits is an
// empty result, not a failure.
if (error instanceof Context7Error && error.status === 404) return [];
throw error;
}
}
}
8 changes: 4 additions & 4 deletions packages/sdk/src/utils/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ export function formatLibrary(r: {
}

/**
* Maps numeric trust score to an interpretable label.
* Maps the numeric trust score to a source reputation label, as the MCP server does.
*/
function getTrustScoreLabel(trustScore?: number): "High" | "Medium" | "Low" | "Unknown" {
function getSourceReputationLabel(trustScore?: number): "High" | "Medium" | "Low" | "Unknown" {
if (trustScore === undefined || trustScore < 0) return "Unknown";
if (trustScore >= 7) return "High";
if (trustScore >= 4) return "Medium";
Expand All @@ -69,7 +69,7 @@ export function formatLibraryAsText(library: Library): string {
lines.push(`- Code Snippets: ${library.totalSnippets}`);
}

lines.push(`- Trust Score: ${getTrustScoreLabel(library.trustScore)}`);
lines.push(`- Source Reputation: ${getSourceReputationLabel(library.trustScore)}`);

if (library.benchmarkScore > 0) {
lines.push(`- Benchmark Score: ${library.benchmarkScore}`);
Expand All @@ -87,7 +87,7 @@ export function formatLibraryAsText(library: Library): string {
*/
export function formatLibrariesAsText(libraries: Library[]): string {
if (libraries.length === 0) {
return "No documentation libraries found matching your query.";
return "No libraries found matching your query. Try a different search term or check the library name.";
}

return libraries.map(formatLibraryAsText).join("\n----------\n");
Expand Down
13 changes: 9 additions & 4 deletions packages/tools-ai-sdk/src/tools/query-docs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { tool } from "ai";
import { z } from "zod";
import { Context7 } from "@upstash/context7-sdk";
import { Context7, Context7Error } from "@upstash/context7-sdk";
import type { Context7ToolsConfig } from "./types";
import { QUERY_DOCS_DESCRIPTION } from "@prompts";

Expand Down Expand Up @@ -53,16 +53,21 @@ export function queryDocs(config: Context7ToolsConfig = {}) {
const client = getClient();
const documentation = await client.getContext(query, libraryId, { type: "txt" });

if (!documentation || documentation.length === 0) {
return `No documentation found for library "${libraryId}". This might have happened because you used an invalid Context7-compatible library ID. Use 'resolveLibraryId' to get a valid ID.`;
}
if (!documentation || documentation.length === 0) return noDocumentation(libraryId);

return documentation;
} catch (error) {
// The API answers 404 for an unknown library ID; point the agent back to resolveLibraryId.
if (error instanceof Context7Error && error.status === 404)
return noDocumentation(libraryId);
const errorMessage =
error instanceof Error ? error.message : "Failed to fetch documentation";
return `Error fetching documentation for "${libraryId}": ${errorMessage}`;
}
},
});
}

function noDocumentation(libraryId: string): string {
return `No documentation found for library "${libraryId}". This might have happened because you used an invalid Context7-compatible library ID. Use 'resolveLibraryId' to get a valid ID.`;
}
10 changes: 2 additions & 8 deletions packages/tools-ai-sdk/src/tools/resolve-library-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,10 @@ export function resolveLibraryId(config: Context7ToolsConfig = {}) {
execute: async ({ query, libraryName }: { query: string; libraryName: string }) => {
try {
const client = getClient();
const results = await client.searchLibrary(query, libraryName, { type: "txt" });

if (!results || results.length === 0) {
return `No libraries found matching "${libraryName}". Try a different search term or check the library name.`;
}

return results;
return await client.searchLibrary(query, libraryName, { type: "txt" });
} catch (error) {
const errorMessage = error instanceof Error ? error.message : "Failed to search libraries";
return `Error searching for libraries: ${errorMessage}. Check your API key and try again.`;
return `Error searching for libraries: ${errorMessage}`;
}
},
});
Expand Down
Loading