@search1api/ai-sdk 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Search1API
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,140 @@
1
- # Temporary Holding Version
1
+ # Search1API tools for the Vercel AI SDK
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Add web search, news search, and webpage reading to an AI SDK agent. The tools
4
+ use the official [`@search1api/client`](https://s1.dev/docs/integrations/sdks)
5
+ for transport, retries, timeouts, and typed API errors.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @search1api/ai-sdk ai zod
11
+ ```
12
+
13
+ Create a Search1API key in the [dashboard](https://app.s1.dev), then set
14
+ `SEARCH1API_API_KEY`. `SEARCH1API_KEY` is also accepted for compatibility with
15
+ the CLI. An explicit `apiKey` takes precedence over either environment variable.
16
+ The example below uses Vercel AI Gateway; configure `AI_GATEWAY_API_KEY` or use
17
+ your preferred AI SDK model provider.
18
+
19
+ ## Search and read sources
20
+
21
+ ```ts
22
+ import { gateway, generateText, stepCountIs } from 'ai';
23
+ import { search1apiTools } from '@search1api/ai-sdk';
24
+
25
+ const result = await generateText({
26
+ model: gateway('openai/gpt-5-mini'),
27
+ tools: search1apiTools({ only: ['search', 'crawl'] }),
28
+ stopWhen: stepCountIs(5),
29
+ prompt: 'Find the AI SDK tool calling documentation, read it, and explain how tools work. Cite the URLs you used.',
30
+ });
31
+
32
+ console.log(result.text);
33
+ ```
34
+
35
+ The tool set has three entries:
36
+
37
+ | Tool | Model input | API | Output |
38
+ | --- | --- | --- | --- |
39
+ | `search` | `{ query }` | `/search` | Typed results with titles, links, and snippets |
40
+ | `news` | `{ query }` | `/news` | Typed news results and source links |
41
+ | `crawl` | `{ url }` | `/crawl` | A page's title, URL, and readable content |
42
+
43
+ Outputs preserve the API response, including optional publication dates,
44
+ metadata, and content. Empty results remain empty. Ask the model to cite the
45
+ returned links; these tools do not add AI SDK source events automatically.
46
+
47
+ ## Configure one tool
48
+
49
+ Applications control the engine, result count, domains, language, and time
50
+ window. The model sees only the query or URL, so it cannot change those settings
51
+ or enable extra result crawling.
52
+
53
+ ```ts
54
+ import { search1apiSearch, search1apiCrawl } from '@search1api/ai-sdk';
55
+
56
+ const tools = {
57
+ webSearch: search1apiSearch({
58
+ search: { maxResults: 5, includeSites: ['ai-sdk.dev'], timeRange: 'month' },
59
+ }),
60
+ readPage: search1apiCrawl({ crawl: { enableFallback: true } }),
61
+ };
62
+ ```
63
+
64
+ `search1apiNews({ news: { timeRange: 'day' } })` creates the news tool. A tool
65
+ set accepts the same settings under `search`, `news`, and `crawl`:
66
+
67
+ ```ts
68
+ const tools = search1apiTools({
69
+ only: ['search', 'news', 'crawl'],
70
+ search: { maxResults: 5 },
71
+ news: { maxResults: 3, timeRange: 'week' },
72
+ });
73
+ ```
74
+
75
+ Search and news default to five results with `crawlResults: 0`. Set
76
+ `search.crawlResults` or `news.crawlResults` explicitly when you want result page
77
+ content included. Each successful page retrieval incurs a separate crawl charge;
78
+ see [pricing](https://s1.dev/pricing).
79
+
80
+ ## Reuse a client
81
+
82
+ ```ts
83
+ import { Search1API } from '@search1api/client';
84
+ import { search1apiTools } from '@search1api/ai-sdk';
85
+
86
+ const client = new Search1API({ apiKey: 'your-api-key', timeoutMs: 15_000 });
87
+ const tools = search1apiTools({ client });
88
+ ```
89
+
90
+ Factories and tool sets also accept SDK client settings directly: `apiKey`,
91
+ `baseUrl`, `fetch`, `headers`, `timeoutMs`, `maxRetries`, and `retryDelayMs`.
92
+ When `client` is supplied, the other client settings are ignored.
93
+
94
+ The tools create their client on the first execution, so defining tools at
95
+ module scope does not require a key during `next build`. An injected client has
96
+ already been constructed and follows the SDK's normal constructor behavior.
97
+
98
+ ## Streaming, cancellation, and errors
99
+
100
+ Use the same tools with `streamText` or an AI SDK agent. Pass an `abortSignal`
101
+ to the AI SDK call to cancel pending tool requests. Already cancelled calls do
102
+ not create a client or send a request.
103
+
104
+ SDK errors propagate with their type, status code, body, and request ID intact.
105
+ The SDK defaults to a 30-second timeout and two retries for rate limits and
106
+ transient server failures; authentication, credit, and validation errors are
107
+ not retried. The AI SDK represents a failed tool execution as a tool error so
108
+ the agent can handle it in a subsequent step.
109
+
110
+ Keep the key in server code. For a Next.js route handler, see the
111
+ [Next.js example](https://github.com/superagents-lab/search1api-ai-sdk/tree/main/examples/nextjs).
112
+
113
+ ## Compatibility
114
+
115
+ AI SDK 5, 6, and 7 with Zod 3.25.76+ or 4.1.8+. The package targets Node.js 18+
116
+ and uses standard `fetch`; use a Node version supported by your AI SDK release
117
+ (AI SDK 7 requires Node.js 22+).
118
+
119
+ ## Development
120
+
121
+ ```bash
122
+ npm ci
123
+ npm run typecheck
124
+ npm test
125
+ npm run build
126
+ npm run test:smoke
127
+ npm run test:compatibility
128
+ npm pack --dry-run
129
+ ```
130
+
131
+ To verify the current version from the public registry, run
132
+ `node scripts/verify-package.mjs --registry` after publication.
133
+
134
+ To validate a local build, create and install the tarball with
135
+ `npm pack` and `npm install /absolute/path/search1api-ai-sdk-0.1.0.tgz`.
136
+ Publication tracking is in [RELEASE.md](https://github.com/superagents-lab/search1api-ai-sdk/blob/main/RELEASE.md).
137
+
138
+ ## License
139
+
140
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ search1apiCrawl: () => search1apiCrawl,
24
+ search1apiNews: () => search1apiNews,
25
+ search1apiSearch: () => search1apiSearch,
26
+ search1apiTools: () => search1apiTools
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+ var import_client = require("@search1api/client");
30
+ var import_ai = require("ai");
31
+ var import_zod = require("zod");
32
+ var querySchema = import_zod.z.object({
33
+ query: import_zod.z.string().trim().min(1).describe("Search keywords or a specific question.")
34
+ }).strict();
35
+ var crawlSchema = import_zod.z.object({
36
+ url: import_zod.z.string().url().refine(
37
+ (url) => ["http:", "https:"].includes(new URL(url).protocol),
38
+ "Use an HTTP or HTTPS URL."
39
+ ).describe("A public webpage URL, for example a link returned by search.")
40
+ }).strict();
41
+ function clientGetter(options) {
42
+ let client = options.client;
43
+ const { client: _client, ...settings } = options;
44
+ return () => {
45
+ if (!client) {
46
+ const processLike = globalThis;
47
+ const env = processLike.process?.env;
48
+ client = new import_client.Search1API({
49
+ ...settings,
50
+ apiKey: settings.apiKey || env?.SEARCH1API_API_KEY || env?.SEARCH1API_KEY
51
+ });
52
+ }
53
+ return client;
54
+ };
55
+ }
56
+ function searchTool(getClient, settings = {}) {
57
+ const options = { maxResults: 5, crawlResults: 0, ...settings };
58
+ return (0, import_ai.tool)({
59
+ description: "Search the public web for current information and sources. Returns titles, links, and snippets. Use crawl to read a result page in full.",
60
+ inputSchema: querySchema,
61
+ execute: async (input, { abortSignal }) => {
62
+ abortSignal?.throwIfAborted();
63
+ const { query } = querySchema.parse(input);
64
+ return getClient().search(query, options, { signal: abortSignal });
65
+ }
66
+ });
67
+ }
68
+ function newsTool(getClient, settings = {}) {
69
+ const options = { maxResults: 5, crawlResults: 0, ...settings };
70
+ return (0, import_ai.tool)({
71
+ description: "Search news coverage of recent events and announcements. Returns article titles, links, and snippets. Use crawl to read an article in full.",
72
+ inputSchema: querySchema,
73
+ execute: async (input, { abortSignal }) => {
74
+ abortSignal?.throwIfAborted();
75
+ const { query } = querySchema.parse(input);
76
+ return getClient().news(query, options, { signal: abortSignal });
77
+ }
78
+ });
79
+ }
80
+ function crawlTool(getClient, settings = {}) {
81
+ const options = { ...settings };
82
+ return (0, import_ai.tool)({
83
+ description: "Read one public webpage and return its title, source URL, and readable content. Use a URL supplied by the user or returned by search or news.",
84
+ inputSchema: crawlSchema,
85
+ execute: async (input, { abortSignal }) => {
86
+ abortSignal?.throwIfAborted();
87
+ const { url } = crawlSchema.parse(input);
88
+ return getClient().crawl(url, options, { signal: abortSignal });
89
+ }
90
+ });
91
+ }
92
+ function search1apiSearch(options = {}) {
93
+ return searchTool(clientGetter(options), options.search);
94
+ }
95
+ function search1apiNews(options = {}) {
96
+ return newsTool(clientGetter(options), options.news);
97
+ }
98
+ function search1apiCrawl(options = {}) {
99
+ return crawlTool(clientGetter(options), options.crawl);
100
+ }
101
+ function search1apiTools(options = {}) {
102
+ const getClient = clientGetter(options);
103
+ const tools = {
104
+ search: searchTool(getClient, options.search),
105
+ news: newsTool(getClient, options.news),
106
+ crawl: crawlTool(getClient, options.crawl)
107
+ };
108
+ const names = options.only ?? ["search", "news", "crawl"];
109
+ const selected = {};
110
+ for (const name of names) {
111
+ if (!Object.hasOwn(tools, name)) {
112
+ throw new Error(`Unknown Search1API tool: ${name}`);
113
+ }
114
+ Object.assign(selected, { [name]: tools[name] });
115
+ }
116
+ return selected;
117
+ }
118
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["import { Search1API } from '@search1api/client';\nimport type {\n CrawlOptions,\n CrawlResponse,\n NewsOptions,\n NewsResponse,\n Search1APIOptions,\n SearchOptions,\n SearchResponse,\n} from '@search1api/client';\nimport { tool } from 'ai';\nimport type { Tool } from 'ai';\nimport { z } from 'zod';\n\nexport interface Search1APIToolOptions extends Search1APIOptions {\n /** Reuse an existing client. When supplied, other client options are ignored. */\n client?: Search1API;\n}\n\nexport interface Search1APISearchOptions extends Search1APIToolOptions {\n /** Application-owned search settings; the model only supplies the query. */\n search?: SearchOptions;\n}\n\nexport interface Search1APINewsOptions extends Search1APIToolOptions {\n /** Application-owned news settings; the model only supplies the query. */\n news?: NewsOptions;\n}\n\nexport interface Search1APICrawlOptions extends Search1APIToolOptions {\n crawl?: CrawlOptions;\n}\n\nexport type QueryInput = { query: string };\nexport type CrawlInput = { url: string };\n\nconst querySchema = z\n .object({\n query: z\n .string()\n .trim()\n .min(1)\n .describe('Search keywords or a specific question.'),\n })\n .strict();\n\nconst crawlSchema = z\n .object({\n url: z\n .string()\n .url()\n .refine(\n (url) => ['http:', 'https:'].includes(new URL(url).protocol),\n 'Use an HTTP or HTTPS URL.'\n )\n .describe('A public webpage URL, for example a link returned by search.'),\n })\n .strict();\n\ntype ClientGetter = () => Search1API;\n\nfunction clientGetter(options: Search1APIToolOptions): ClientGetter {\n let client = options.client;\n const { client: _client, ...settings } = options;\n return () => {\n if (!client) {\n const processLike = globalThis as typeof globalThis & {\n process?: { env?: Record<string, string | undefined> };\n };\n const env = processLike.process?.env;\n client = new Search1API({\n ...settings,\n apiKey:\n settings.apiKey || env?.SEARCH1API_API_KEY || env?.SEARCH1API_KEY,\n });\n }\n return client;\n };\n}\n\nfunction searchTool(\n getClient: ClientGetter,\n settings: SearchOptions = {}\n): Tool<QueryInput, SearchResponse> {\n const options = { maxResults: 5, crawlResults: 0, ...settings };\n return tool({\n description:\n 'Search the public web for current information and sources. Returns titles, links, and snippets. Use crawl to read a result page in full.',\n inputSchema: querySchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const { query } = querySchema.parse(input);\n return getClient().search(query, options, { signal: abortSignal });\n },\n });\n}\n\nfunction newsTool(\n getClient: ClientGetter,\n settings: NewsOptions = {}\n): Tool<QueryInput, NewsResponse> {\n const options = { maxResults: 5, crawlResults: 0, ...settings };\n return tool({\n description:\n 'Search news coverage of recent events and announcements. Returns article titles, links, and snippets. Use crawl to read an article in full.',\n inputSchema: querySchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const { query } = querySchema.parse(input);\n return getClient().news(query, options, { signal: abortSignal });\n },\n });\n}\n\nfunction crawlTool(\n getClient: ClientGetter,\n settings: CrawlOptions = {}\n): Tool<CrawlInput, CrawlResponse> {\n const options = { ...settings };\n return tool({\n description:\n 'Read one public webpage and return its title, source URL, and readable content. Use a URL supplied by the user or returned by search or news.',\n inputSchema: crawlSchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const { url } = crawlSchema.parse(input);\n return getClient().crawl(url, options, { signal: abortSignal });\n },\n });\n}\n\nexport function search1apiSearch(\n options: Search1APISearchOptions = {}\n): Tool<QueryInput, SearchResponse> {\n return searchTool(clientGetter(options), options.search);\n}\n\nexport function search1apiNews(\n options: Search1APINewsOptions = {}\n): Tool<QueryInput, NewsResponse> {\n return newsTool(clientGetter(options), options.news);\n}\n\nexport function search1apiCrawl(\n options: Search1APICrawlOptions = {}\n): Tool<CrawlInput, CrawlResponse> {\n return crawlTool(clientGetter(options), options.crawl);\n}\n\nexport interface Search1APIToolSet {\n search: Tool<QueryInput, SearchResponse>;\n news: Tool<QueryInput, NewsResponse>;\n crawl: Tool<CrawlInput, CrawlResponse>;\n}\n\nexport type Search1APIToolName = keyof Search1APIToolSet;\n\nexport interface Search1APIToolsOptions<\n Name extends Search1APIToolName = Search1APIToolName,\n> extends Search1APIToolOptions {\n /** Include only these tools. By default all three are included. */\n only?: readonly Name[];\n search?: SearchOptions;\n news?: NewsOptions;\n crawl?: CrawlOptions;\n}\n\nexport function search1apiTools<\n Name extends Search1APIToolName = Search1APIToolName,\n>(options: Search1APIToolsOptions<Name> = {}): Pick<Search1APIToolSet, Name> {\n const getClient = clientGetter(options);\n const tools: Search1APIToolSet = {\n search: searchTool(getClient, options.search),\n news: newsTool(getClient, options.news),\n crawl: crawlTool(getClient, options.crawl),\n };\n const names = options.only ?? (['search', 'news', 'crawl'] as const);\n const selected = {} as Pick<Search1APIToolSet, Name>;\n for (const name of names) {\n if (!Object.hasOwn(tools, name)) {\n throw new Error(`Unknown Search1API tool: ${name}`);\n }\n Object.assign(selected, { [name]: tools[name] });\n }\n return selected;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,42 @@
1
+ import { Search1API } from '@search1api/client';
2
+ import type { CrawlOptions, CrawlResponse, NewsOptions, NewsResponse, Search1APIOptions, SearchOptions, SearchResponse } from '@search1api/client';
3
+ import type { Tool } from 'ai';
4
+ export interface Search1APIToolOptions extends Search1APIOptions {
5
+ /** Reuse an existing client. When supplied, other client options are ignored. */
6
+ client?: Search1API;
7
+ }
8
+ export interface Search1APISearchOptions extends Search1APIToolOptions {
9
+ /** Application-owned search settings; the model only supplies the query. */
10
+ search?: SearchOptions;
11
+ }
12
+ export interface Search1APINewsOptions extends Search1APIToolOptions {
13
+ /** Application-owned news settings; the model only supplies the query. */
14
+ news?: NewsOptions;
15
+ }
16
+ export interface Search1APICrawlOptions extends Search1APIToolOptions {
17
+ crawl?: CrawlOptions;
18
+ }
19
+ export type QueryInput = {
20
+ query: string;
21
+ };
22
+ export type CrawlInput = {
23
+ url: string;
24
+ };
25
+ export declare function search1apiSearch(options?: Search1APISearchOptions): Tool<QueryInput, SearchResponse>;
26
+ export declare function search1apiNews(options?: Search1APINewsOptions): Tool<QueryInput, NewsResponse>;
27
+ export declare function search1apiCrawl(options?: Search1APICrawlOptions): Tool<CrawlInput, CrawlResponse>;
28
+ export interface Search1APIToolSet {
29
+ search: Tool<QueryInput, SearchResponse>;
30
+ news: Tool<QueryInput, NewsResponse>;
31
+ crawl: Tool<CrawlInput, CrawlResponse>;
32
+ }
33
+ export type Search1APIToolName = keyof Search1APIToolSet;
34
+ export interface Search1APIToolsOptions<Name extends Search1APIToolName = Search1APIToolName> extends Search1APIToolOptions {
35
+ /** Include only these tools. By default all three are included. */
36
+ only?: readonly Name[];
37
+ search?: SearchOptions;
38
+ news?: NewsOptions;
39
+ crawl?: CrawlOptions;
40
+ }
41
+ export declare function search1apiTools<Name extends Search1APIToolName = Search1APIToolName>(options?: Search1APIToolsOptions<Name>): Pick<Search1APIToolSet, Name>;
42
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,cAAc,EACf,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAG/B,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,iFAAiF;IACjF,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,4EAA4E;IAC5E,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAClE,0EAA0E;IAC1E,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAED,MAAM,WAAW,sBAAuB,SAAQ,qBAAqB;IACnE,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,MAAM,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAC3C,MAAM,MAAM,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAiGzC,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,uBAA4B,GACpC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAElC;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,qBAA0B,GAClC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAEhC;AAED,wBAAgB,eAAe,CAC7B,OAAO,GAAE,sBAA2B,GACnC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAEjC;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACzC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IACrC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;CACxC;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,iBAAiB,CAAC;AAEzD,MAAM,WAAW,sBAAsB,CACrC,IAAI,SAAS,kBAAkB,GAAG,kBAAkB,CACpD,SAAQ,qBAAqB;IAC7B,mEAAmE;IACnE,IAAI,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAED,wBAAgB,eAAe,CAC7B,IAAI,SAAS,kBAAkB,GAAG,kBAAkB,EACpD,OAAO,GAAE,sBAAsB,CAAC,IAAI,CAAM,GAAG,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAgB3E"}
package/dist/index.js ADDED
@@ -0,0 +1,97 @@
1
+ // src/index.ts
2
+ import { Search1API } from "@search1api/client";
3
+ import { tool } from "ai";
4
+ import { z } from "zod";
5
+ var querySchema = z.object({
6
+ query: z.string().trim().min(1).describe("Search keywords or a specific question.")
7
+ }).strict();
8
+ var crawlSchema = z.object({
9
+ url: z.string().url().refine(
10
+ (url) => ["http:", "https:"].includes(new URL(url).protocol),
11
+ "Use an HTTP or HTTPS URL."
12
+ ).describe("A public webpage URL, for example a link returned by search.")
13
+ }).strict();
14
+ function clientGetter(options) {
15
+ let client = options.client;
16
+ const { client: _client, ...settings } = options;
17
+ return () => {
18
+ if (!client) {
19
+ const processLike = globalThis;
20
+ const env = processLike.process?.env;
21
+ client = new Search1API({
22
+ ...settings,
23
+ apiKey: settings.apiKey || env?.SEARCH1API_API_KEY || env?.SEARCH1API_KEY
24
+ });
25
+ }
26
+ return client;
27
+ };
28
+ }
29
+ function searchTool(getClient, settings = {}) {
30
+ const options = { maxResults: 5, crawlResults: 0, ...settings };
31
+ return tool({
32
+ description: "Search the public web for current information and sources. Returns titles, links, and snippets. Use crawl to read a result page in full.",
33
+ inputSchema: querySchema,
34
+ execute: async (input, { abortSignal }) => {
35
+ abortSignal?.throwIfAborted();
36
+ const { query } = querySchema.parse(input);
37
+ return getClient().search(query, options, { signal: abortSignal });
38
+ }
39
+ });
40
+ }
41
+ function newsTool(getClient, settings = {}) {
42
+ const options = { maxResults: 5, crawlResults: 0, ...settings };
43
+ return tool({
44
+ description: "Search news coverage of recent events and announcements. Returns article titles, links, and snippets. Use crawl to read an article in full.",
45
+ inputSchema: querySchema,
46
+ execute: async (input, { abortSignal }) => {
47
+ abortSignal?.throwIfAborted();
48
+ const { query } = querySchema.parse(input);
49
+ return getClient().news(query, options, { signal: abortSignal });
50
+ }
51
+ });
52
+ }
53
+ function crawlTool(getClient, settings = {}) {
54
+ const options = { ...settings };
55
+ return tool({
56
+ description: "Read one public webpage and return its title, source URL, and readable content. Use a URL supplied by the user or returned by search or news.",
57
+ inputSchema: crawlSchema,
58
+ execute: async (input, { abortSignal }) => {
59
+ abortSignal?.throwIfAborted();
60
+ const { url } = crawlSchema.parse(input);
61
+ return getClient().crawl(url, options, { signal: abortSignal });
62
+ }
63
+ });
64
+ }
65
+ function search1apiSearch(options = {}) {
66
+ return searchTool(clientGetter(options), options.search);
67
+ }
68
+ function search1apiNews(options = {}) {
69
+ return newsTool(clientGetter(options), options.news);
70
+ }
71
+ function search1apiCrawl(options = {}) {
72
+ return crawlTool(clientGetter(options), options.crawl);
73
+ }
74
+ function search1apiTools(options = {}) {
75
+ const getClient = clientGetter(options);
76
+ const tools = {
77
+ search: searchTool(getClient, options.search),
78
+ news: newsTool(getClient, options.news),
79
+ crawl: crawlTool(getClient, options.crawl)
80
+ };
81
+ const names = options.only ?? ["search", "news", "crawl"];
82
+ const selected = {};
83
+ for (const name of names) {
84
+ if (!Object.hasOwn(tools, name)) {
85
+ throw new Error(`Unknown Search1API tool: ${name}`);
86
+ }
87
+ Object.assign(selected, { [name]: tools[name] });
88
+ }
89
+ return selected;
90
+ }
91
+ export {
92
+ search1apiCrawl,
93
+ search1apiNews,
94
+ search1apiSearch,
95
+ search1apiTools
96
+ };
97
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["import { Search1API } from '@search1api/client';\nimport type {\n CrawlOptions,\n CrawlResponse,\n NewsOptions,\n NewsResponse,\n Search1APIOptions,\n SearchOptions,\n SearchResponse,\n} from '@search1api/client';\nimport { tool } from 'ai';\nimport type { Tool } from 'ai';\nimport { z } from 'zod';\n\nexport interface Search1APIToolOptions extends Search1APIOptions {\n /** Reuse an existing client. When supplied, other client options are ignored. */\n client?: Search1API;\n}\n\nexport interface Search1APISearchOptions extends Search1APIToolOptions {\n /** Application-owned search settings; the model only supplies the query. */\n search?: SearchOptions;\n}\n\nexport interface Search1APINewsOptions extends Search1APIToolOptions {\n /** Application-owned news settings; the model only supplies the query. */\n news?: NewsOptions;\n}\n\nexport interface Search1APICrawlOptions extends Search1APIToolOptions {\n crawl?: CrawlOptions;\n}\n\nexport type QueryInput = { query: string };\nexport type CrawlInput = { url: string };\n\nconst querySchema = z\n .object({\n query: z\n .string()\n .trim()\n .min(1)\n .describe('Search keywords or a specific question.'),\n })\n .strict();\n\nconst crawlSchema = z\n .object({\n url: z\n .string()\n .url()\n .refine(\n (url) => ['http:', 'https:'].includes(new URL(url).protocol),\n 'Use an HTTP or HTTPS URL.'\n )\n .describe('A public webpage URL, for example a link returned by search.'),\n })\n .strict();\n\ntype ClientGetter = () => Search1API;\n\nfunction clientGetter(options: Search1APIToolOptions): ClientGetter {\n let client = options.client;\n const { client: _client, ...settings } = options;\n return () => {\n if (!client) {\n const processLike = globalThis as typeof globalThis & {\n process?: { env?: Record<string, string | undefined> };\n };\n const env = processLike.process?.env;\n client = new Search1API({\n ...settings,\n apiKey:\n settings.apiKey || env?.SEARCH1API_API_KEY || env?.SEARCH1API_KEY,\n });\n }\n return client;\n };\n}\n\nfunction searchTool(\n getClient: ClientGetter,\n settings: SearchOptions = {}\n): Tool<QueryInput, SearchResponse> {\n const options = { maxResults: 5, crawlResults: 0, ...settings };\n return tool({\n description:\n 'Search the public web for current information and sources. Returns titles, links, and snippets. Use crawl to read a result page in full.',\n inputSchema: querySchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const { query } = querySchema.parse(input);\n return getClient().search(query, options, { signal: abortSignal });\n },\n });\n}\n\nfunction newsTool(\n getClient: ClientGetter,\n settings: NewsOptions = {}\n): Tool<QueryInput, NewsResponse> {\n const options = { maxResults: 5, crawlResults: 0, ...settings };\n return tool({\n description:\n 'Search news coverage of recent events and announcements. Returns article titles, links, and snippets. Use crawl to read an article in full.',\n inputSchema: querySchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const { query } = querySchema.parse(input);\n return getClient().news(query, options, { signal: abortSignal });\n },\n });\n}\n\nfunction crawlTool(\n getClient: ClientGetter,\n settings: CrawlOptions = {}\n): Tool<CrawlInput, CrawlResponse> {\n const options = { ...settings };\n return tool({\n description:\n 'Read one public webpage and return its title, source URL, and readable content. Use a URL supplied by the user or returned by search or news.',\n inputSchema: crawlSchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const { url } = crawlSchema.parse(input);\n return getClient().crawl(url, options, { signal: abortSignal });\n },\n });\n}\n\nexport function search1apiSearch(\n options: Search1APISearchOptions = {}\n): Tool<QueryInput, SearchResponse> {\n return searchTool(clientGetter(options), options.search);\n}\n\nexport function search1apiNews(\n options: Search1APINewsOptions = {}\n): Tool<QueryInput, NewsResponse> {\n return newsTool(clientGetter(options), options.news);\n}\n\nexport function search1apiCrawl(\n options: Search1APICrawlOptions = {}\n): Tool<CrawlInput, CrawlResponse> {\n return crawlTool(clientGetter(options), options.crawl);\n}\n\nexport interface Search1APIToolSet {\n search: Tool<QueryInput, SearchResponse>;\n news: Tool<QueryInput, NewsResponse>;\n crawl: Tool<CrawlInput, CrawlResponse>;\n}\n\nexport type Search1APIToolName = keyof Search1APIToolSet;\n\nexport interface Search1APIToolsOptions<\n Name extends Search1APIToolName = Search1APIToolName,\n> extends Search1APIToolOptions {\n /** Include only these tools. By default all three are included. */\n only?: readonly Name[];\n search?: SearchOptions;\n news?: NewsOptions;\n crawl?: CrawlOptions;\n}\n\nexport function search1apiTools<\n Name extends Search1APIToolName = Search1APIToolName,\n>(options: Search1APIToolsOptions<Name> = {}): Pick<Search1APIToolSet, Name> {\n const getClient = clientGetter(options);\n const tools: Search1APIToolSet = {\n search: searchTool(getClient, options.search),\n news: newsTool(getClient, options.news),\n crawl: crawlTool(getClient, options.crawl),\n };\n const names = options.only ?? (['search', 'news', 'crawl'] as const);\n const selected = {} as Pick<Search1APIToolSet, Name>;\n for (const name of names) {\n if (!Object.hasOwn(tools, name)) {\n throw new Error(`Unknown Search1API tool: ${name}`);\n }\n Object.assign(selected, { [name]: tools[name] });\n }\n return selected;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,6 +1,70 @@
1
1
  {
2
2
  "name": "@search1api/ai-sdk",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "Official Search1API web search, news, and page reading tools for the Vercel AI SDK.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.cjs"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md",
20
+ "LICENSE"
21
+ ],
22
+ "sideEffects": false,
23
+ "engines": {
24
+ "node": ">=18"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/superagents-lab/search1api-ai-sdk.git"
29
+ },
30
+ "homepage": "https://s1.dev",
31
+ "bugs": {
32
+ "url": "https://github.com/superagents-lab/search1api-ai-sdk/issues"
33
+ },
34
+ "keywords": [
35
+ "search1api",
36
+ "ai-sdk",
37
+ "vercel",
38
+ "tools",
39
+ "web-search",
40
+ "crawl",
41
+ "news",
42
+ "agents"
43
+ ],
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "scripts": {
48
+ "build": "node scripts/build.mjs && tsc -p tsconfig.build.json",
49
+ "test": "vitest run",
50
+ "test:smoke": "node scripts/smoke.mjs",
51
+ "test:compatibility": "node scripts/check-compatibility.mjs",
52
+ "typecheck": "tsc --noEmit",
53
+ "prepack": "npm run build"
54
+ },
55
+ "dependencies": {
56
+ "@search1api/client": "^0.2.1"
57
+ },
58
+ "peerDependencies": {
59
+ "ai": "^5.0.0 || ^6.0.0 || ^7.0.0",
60
+ "zod": "^3.25.76 || ^4.1.8"
61
+ },
62
+ "devDependencies": {
63
+ "@types/node": "^22.14.0",
64
+ "ai": "^7.0.130",
65
+ "esbuild": "^0.28.1",
66
+ "typescript": "^5.8.3",
67
+ "vitest": "^3.2.6",
68
+ "zod": "^4.1.8"
69
+ }
70
+ }