@search1api/ai-sdk 0.1.2 → 0.2.0
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/README.md +42 -15
- package/dist/index.cjs +33 -5
- package/dist/index.cjs.map +2 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -5
- package/dist/index.js.map +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Search1API tools for the Vercel AI SDK
|
|
2
2
|
|
|
3
|
-
Add web search, news search,
|
|
4
|
-
use the official
|
|
5
|
-
for transport,
|
|
3
|
+
Add web search, news search, webpage reading, and agentic search to an AI SDK
|
|
4
|
+
agent. The tools use the official
|
|
5
|
+
[`@search1api/client`](https://s1.dev/docs/integrations/sdks) for transport,
|
|
6
|
+
retries, timeouts, and typed API errors.
|
|
6
7
|
|
|
7
8
|
## Install
|
|
8
9
|
|
|
@@ -32,26 +33,52 @@ const result = await generateText({
|
|
|
32
33
|
console.log(result.text);
|
|
33
34
|
```
|
|
34
35
|
|
|
35
|
-
The tool set has
|
|
36
|
+
The tool set has four entries:
|
|
36
37
|
|
|
37
38
|
| Tool | Model input | API | Output |
|
|
38
39
|
| --- | --- | --- | --- |
|
|
39
|
-
| `search` | `{ query, search_service?, max_results?, include_sites?, exclude_sites?, time_range? }` | `/search` | Typed results with titles, links, and snippets |
|
|
40
|
-
| `news` | Same fields as `search`, with news engines | `/news` | Typed news results and source links |
|
|
40
|
+
| `search` | `{ query, search_service?, page?, max_results?, include_sites?, exclude_sites?, time_range? }` | `/search` | Typed results with titles, links, and snippets |
|
|
41
|
+
| `news` | Same fields as `search` except `page`, with news engines | `/news` | Typed news results and source links |
|
|
41
42
|
| `crawl` | `{ url }` | `/crawl` | A page's title, URL, and readable content |
|
|
43
|
+
| `ask` | `{ query }` | `/ask` | Up to 10 results ranked by relevance, plus the engines and window used |
|
|
42
44
|
|
|
43
45
|
The model-facing parameters match the
|
|
44
46
|
[Search1API MCP server](https://s1.dev/docs/integrations/mcp). The model can
|
|
45
|
-
pick an engine (`google`, `bing`, `
|
|
46
|
-
`youtube`, `arxiv`, `wechat`, `bilibili`, `imdb`,
|
|
47
|
-
`
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
pick an engine (`google`, `bing`, `bingcn`, `duckduckgo`, `yahoo`, `yandex`,
|
|
48
|
+
`x`, `reddit`, `github`, `youtube`, `arxiv`, `wechat`, `bilibili`, `imdb`,
|
|
49
|
+
`wikipedia`, `grokipedia`; news supports `google`, `bing`, `duckduckgo`,
|
|
50
|
+
`yahoo`, and `hackernews`), return 1–50 results, request a later results page
|
|
51
|
+
(only `bing`, `bingcn`, `baidu`, and `grokipedia` paginate), scope or exclude
|
|
52
|
+
domains, and limit results to the past day, week, month, or year. Result page
|
|
53
|
+
crawling is not exposed to the model. Unknown arguments are ignored rather than
|
|
54
|
+
failing the call.
|
|
51
55
|
|
|
52
56
|
Outputs preserve the API response, including optional publication dates,
|
|
53
|
-
metadata, and content. Empty results remain
|
|
54
|
-
returned links; these tools do not add AI SDK
|
|
57
|
+
GitHub and Hacker News fields, metadata, and content. Empty results remain
|
|
58
|
+
empty. Ask the model to cite the returned links; these tools do not add AI SDK
|
|
59
|
+
source events automatically. When an answer uses `grokipedia` results, credit
|
|
60
|
+
them as "Powered by xAI"; see
|
|
61
|
+
[Improving search results](https://s1.dev/docs/guides/improving-search-results).
|
|
62
|
+
|
|
63
|
+
## Agentic search with ask
|
|
64
|
+
|
|
65
|
+
`ask` sends a natural-language request to
|
|
66
|
+
[`POST /ask`](https://s1.dev/docs/basic/ask). Search1API chooses up to five
|
|
67
|
+
engines and a time window, drops off-topic results, and returns at most 10
|
|
68
|
+
results ranked by relevance. Each call costs 5 credits, compared with 1 credit
|
|
69
|
+
for `search`. `ask` is in the default tool set, matching the MCP server; leave
|
|
70
|
+
it out with `only`, or create it on its own with `search1apiAsk()`:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { search1apiAsk, search1apiTools } from '@search1api/ai-sdk';
|
|
74
|
+
|
|
75
|
+
const withoutAsk = search1apiTools({ only: ['search', 'news', 'crawl'] });
|
|
76
|
+
const askOnly = { ask: search1apiAsk() };
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The SDK gives `ask` a 45-second timeout. `ask` is not available with
|
|
80
|
+
pay-per-request payments. Prefer `search` when the agent already knows the
|
|
81
|
+
engine and keywords.
|
|
55
82
|
|
|
56
83
|
## Configure one tool
|
|
57
84
|
|
|
@@ -141,7 +168,7 @@ To verify the current version from the public registry, run
|
|
|
141
168
|
`node scripts/verify-package.mjs --registry` after publication.
|
|
142
169
|
|
|
143
170
|
To validate a local build, create and install the tarball with
|
|
144
|
-
`npm pack` and `npm install /absolute/path/search1api-ai-sdk-0.
|
|
171
|
+
`npm pack` and `npm install /absolute/path/search1api-ai-sdk-0.2.0.tgz`.
|
|
145
172
|
Publication tracking is in [RELEASE.md](https://github.com/superagents-lab/search1api-ai-sdk/blob/main/RELEASE.md).
|
|
146
173
|
|
|
147
174
|
## License
|
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
search1apiAsk: () => search1apiAsk,
|
|
23
24
|
search1apiCrawl: () => search1apiCrawl,
|
|
24
25
|
search1apiNews: () => search1apiNews,
|
|
25
26
|
search1apiSearch: () => search1apiSearch,
|
|
@@ -32,8 +33,10 @@ var import_zod = require("zod");
|
|
|
32
33
|
var SEARCH_ENGINES = [
|
|
33
34
|
"google",
|
|
34
35
|
"bing",
|
|
36
|
+
"bingcn",
|
|
35
37
|
"duckduckgo",
|
|
36
38
|
"yahoo",
|
|
39
|
+
"yandex",
|
|
37
40
|
"x",
|
|
38
41
|
"reddit",
|
|
39
42
|
"github",
|
|
@@ -42,7 +45,8 @@ var SEARCH_ENGINES = [
|
|
|
42
45
|
"wechat",
|
|
43
46
|
"bilibili",
|
|
44
47
|
"imdb",
|
|
45
|
-
"wikipedia"
|
|
48
|
+
"wikipedia",
|
|
49
|
+
"grokipedia"
|
|
46
50
|
];
|
|
47
51
|
var NEWS_ENGINES = [
|
|
48
52
|
"google",
|
|
@@ -62,7 +66,7 @@ function queryFields(kind) {
|
|
|
62
66
|
exclude_sites: import_zod.z.array(import_zod.z.string()).optional().describe(
|
|
63
67
|
kind === "search" ? "Domains to exclude from the search" : "News domains to exclude"
|
|
64
68
|
),
|
|
65
|
-
time_range: import_zod.z.enum(["day", "month", "year"]).optional().describe(
|
|
69
|
+
time_range: import_zod.z.enum(["day", "week", "month", "year"]).optional().describe(
|
|
66
70
|
kind === "search" ? "Optional recency window for time-sensitive searches" : "Optional recency window; use day for breaking news"
|
|
67
71
|
)
|
|
68
72
|
};
|
|
@@ -71,6 +75,9 @@ var searchSchema = import_zod.z.object({
|
|
|
71
75
|
...queryFields("search"),
|
|
72
76
|
search_service: import_zod.z.enum(SEARCH_ENGINES).optional().describe(
|
|
73
77
|
"Search engine to use; choose one only when it matches the user's source intent"
|
|
78
|
+
),
|
|
79
|
+
page: import_zod.z.number().int().min(1).max(100).optional().describe(
|
|
80
|
+
"Results page to fetch; only bing, bingcn, baidu, and grokipedia paginate, other engines ignore it"
|
|
74
81
|
)
|
|
75
82
|
});
|
|
76
83
|
var newsSchema = import_zod.z.object({
|
|
@@ -83,13 +90,19 @@ var crawlSchema = import_zod.z.object({
|
|
|
83
90
|
"Use an HTTP or HTTPS URL."
|
|
84
91
|
).describe("Public HTTP or HTTPS URL to retrieve")
|
|
85
92
|
});
|
|
93
|
+
var askSchema = import_zod.z.object({
|
|
94
|
+
query: import_zod.z.string().trim().min(1).max(500).describe(
|
|
95
|
+
"Natural-language description of what to find, including any platform or time frame"
|
|
96
|
+
)
|
|
97
|
+
});
|
|
86
98
|
function requestOptions(defaults, input) {
|
|
87
99
|
const fromModel = {
|
|
88
100
|
searchService: input.search_service,
|
|
89
101
|
maxResults: input.max_results,
|
|
90
102
|
includeSites: input.include_sites,
|
|
91
103
|
excludeSites: input.exclude_sites,
|
|
92
|
-
timeRange: input.time_range
|
|
104
|
+
timeRange: input.time_range,
|
|
105
|
+
page: input.page
|
|
93
106
|
};
|
|
94
107
|
const overrides = Object.fromEntries(
|
|
95
108
|
Object.entries(fromModel).filter(([, value]) => value !== void 0)
|
|
@@ -161,6 +174,17 @@ function crawlTool(getClient, settings = {}) {
|
|
|
161
174
|
}
|
|
162
175
|
});
|
|
163
176
|
}
|
|
177
|
+
function askTool(getClient) {
|
|
178
|
+
return (0, import_ai.tool)({
|
|
179
|
+
description: "Describe what you need in natural language; Search1API chooses up to five engines and a time window, then returns at most 10 results ranked by relevance, with the engines and window it used. Costs 5 credits per call. Use search instead when you already know the engine and keywords.",
|
|
180
|
+
inputSchema: askSchema,
|
|
181
|
+
execute: async (input, { abortSignal }) => {
|
|
182
|
+
abortSignal?.throwIfAborted();
|
|
183
|
+
const { query } = askSchema.parse(input);
|
|
184
|
+
return getClient().ask(query, { signal: abortSignal });
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
164
188
|
function search1apiSearch(options = {}) {
|
|
165
189
|
return searchTool(clientGetter(options), options.search);
|
|
166
190
|
}
|
|
@@ -170,14 +194,18 @@ function search1apiNews(options = {}) {
|
|
|
170
194
|
function search1apiCrawl(options = {}) {
|
|
171
195
|
return crawlTool(clientGetter(options), options.crawl);
|
|
172
196
|
}
|
|
197
|
+
function search1apiAsk(options = {}) {
|
|
198
|
+
return askTool(clientGetter(options));
|
|
199
|
+
}
|
|
173
200
|
function search1apiTools(options = {}) {
|
|
174
201
|
const getClient = clientGetter(options);
|
|
175
202
|
const tools = {
|
|
176
203
|
search: searchTool(getClient, options.search),
|
|
177
204
|
news: newsTool(getClient, options.news),
|
|
178
|
-
crawl: crawlTool(getClient, options.crawl)
|
|
205
|
+
crawl: crawlTool(getClient, options.crawl),
|
|
206
|
+
ask: askTool(getClient)
|
|
179
207
|
};
|
|
180
|
-
const names = options.only ?? ["search", "news", "crawl"];
|
|
208
|
+
const names = options.only ?? ["search", "news", "crawl", "ask"];
|
|
181
209
|
const selected = {};
|
|
182
210
|
for (const name of names) {
|
|
183
211
|
if (!Object.hasOwn(tools, name)) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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 /** Default search settings; values the model supplies take precedence. */\n search?: SearchOptions;\n}\n\nexport interface Search1APINewsOptions extends Search1APIToolOptions {\n /** Default news settings; values the model supplies take precedence. */\n news?: NewsOptions;\n}\n\nexport interface Search1APICrawlOptions extends Search1APIToolOptions {\n crawl?: CrawlOptions;\n}\n\nexport type CrawlInput = { url: string };\n\n// Model-facing parameters mirror the Search1API MCP server's tool schemas,\n// except result crawling, which only application settings can enable.\nconst SEARCH_ENGINES = [\n 'google',\n 'bing',\n 'duckduckgo',\n 'yahoo',\n 'x',\n 'reddit',\n 'github',\n 'youtube',\n 'arxiv',\n 'wechat',\n 'bilibili',\n 'imdb',\n 'wikipedia',\n] as const;\nconst NEWS_ENGINES = [\n 'google',\n 'bing',\n 'duckduckgo',\n 'yahoo',\n 'hackernews',\n] as const;\n\nfunction queryFields(kind: 'search' | 'news') {\n const noun = kind === 'search' ? 'results' : 'articles';\n return {\n query: z\n .string()\n .trim()\n .min(1)\n .describe(`Short, focused ${kind} query`),\n max_results: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe(`Maximum number of ${noun} to return`),\n include_sites: z\n .array(z.string())\n .optional()\n .describe(\n kind === 'search'\n ? 'Domains to include when the user explicitly scopes the search'\n : 'News domains to include'\n ),\n exclude_sites: z\n .array(z.string())\n .optional()\n .describe(\n kind === 'search'\n ? 'Domains to exclude from the search'\n : 'News domains to exclude'\n ),\n time_range: z\n .enum(['day', 'month', 'year'])\n .optional()\n .describe(\n kind === 'search'\n ? 'Optional recency window for time-sensitive searches'\n : 'Optional recency window; use day for breaking news'\n ),\n };\n}\n\n// Unknown keys are stripped rather than rejected so a stray argument does not\n// cost the agent a retry step.\nconst searchSchema = z.object({\n ...queryFields('search'),\n search_service: z\n .enum(SEARCH_ENGINES)\n .optional()\n .describe(\n \"Search engine to use; choose one only when it matches the user's source intent\"\n ),\n});\n\nconst newsSchema = z.object({\n ...queryFields('news'),\n search_service: z\n .enum(NEWS_ENGINES)\n .optional()\n .describe('News search engine to use'),\n});\n\nconst crawlSchema = z.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('Public HTTP or HTTPS URL to retrieve'),\n});\n\nexport type SearchInput = z.input<typeof searchSchema>;\nexport type NewsInput = z.input<typeof newsSchema>;\n\ntype ModelQueryInput =\n | z.output<typeof searchSchema>\n | z.output<typeof newsSchema>;\n\n// Merge model-supplied values over application defaults, dropping omitted keys.\nfunction requestOptions<Options extends SearchOptions | NewsOptions>(\n defaults: Options,\n input: ModelQueryInput\n): Options {\n const fromModel = {\n searchService: input.search_service,\n maxResults: input.max_results,\n includeSites: input.include_sites,\n excludeSites: input.exclude_sites,\n timeRange: input.time_range,\n };\n const overrides = Object.fromEntries(\n Object.entries(fromModel).filter(([, value]) => value !== undefined)\n );\n return { ...defaults, ...overrides } as Options;\n}\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<SearchInput, SearchResponse> {\n const defaults: SearchOptions = {\n maxResults: 10,\n crawlResults: 0,\n ...settings,\n };\n return tool({\n description:\n 'Search the live public web when the user needs current information, sources, or research. Returns titles, links, and snippets. Use crawl to read a result page in full.',\n inputSchema: searchSchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const parsed = searchSchema.parse(input);\n return getClient().search(\n parsed.query,\n requestOptions(defaults, parsed),\n { signal: abortSignal }\n );\n },\n });\n}\n\nfunction newsTool(\n getClient: ClientGetter,\n settings: NewsOptions = {}\n): Tool<NewsInput, NewsResponse> {\n const defaults: NewsOptions = {\n maxResults: 10,\n crawlResults: 0,\n ...settings,\n };\n return tool({\n description:\n 'Search current news when the user asks about recent events, announcements, or coverage. Returns article titles, links, and snippets. Use crawl to read an article in full.',\n inputSchema: newsSchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const parsed = newsSchema.parse(input);\n return getClient().news(parsed.query, requestOptions(defaults, parsed), {\n signal: abortSignal,\n });\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<SearchInput, SearchResponse> {\n return searchTool(clientGetter(options), options.search);\n}\n\nexport function search1apiNews(\n options: Search1APINewsOptions = {}\n): Tool<NewsInput, 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<SearchInput, SearchResponse>;\n news: Tool<NewsInput, 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": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA2B;
|
|
4
|
+
"sourcesContent": ["import { Search1API } from '@search1api/client';\nimport type {\n AskResponse,\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 /** Default search settings; values the model supplies take precedence. */\n search?: SearchOptions;\n}\n\nexport interface Search1APINewsOptions extends Search1APIToolOptions {\n /** Default news settings; values the model supplies take precedence. */\n news?: NewsOptions;\n}\n\nexport interface Search1APICrawlOptions extends Search1APIToolOptions {\n crawl?: CrawlOptions;\n}\n\nexport type CrawlInput = { url: string };\nexport type AskInput = { query: string };\n\n// Model-facing parameters mirror the Search1API MCP server's tool schemas,\n// except result crawling, which only application settings can enable.\nconst SEARCH_ENGINES = [\n 'google',\n 'bing',\n 'bingcn',\n 'duckduckgo',\n 'yahoo',\n 'yandex',\n 'x',\n 'reddit',\n 'github',\n 'youtube',\n 'arxiv',\n 'wechat',\n 'bilibili',\n 'imdb',\n 'wikipedia',\n 'grokipedia',\n] as const;\nconst NEWS_ENGINES = [\n 'google',\n 'bing',\n 'duckduckgo',\n 'yahoo',\n 'hackernews',\n] as const;\n\nfunction queryFields(kind: 'search' | 'news') {\n const noun = kind === 'search' ? 'results' : 'articles';\n return {\n query: z\n .string()\n .trim()\n .min(1)\n .describe(`Short, focused ${kind} query`),\n max_results: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe(`Maximum number of ${noun} to return`),\n include_sites: z\n .array(z.string())\n .optional()\n .describe(\n kind === 'search'\n ? 'Domains to include when the user explicitly scopes the search'\n : 'News domains to include'\n ),\n exclude_sites: z\n .array(z.string())\n .optional()\n .describe(\n kind === 'search'\n ? 'Domains to exclude from the search'\n : 'News domains to exclude'\n ),\n time_range: z\n .enum(['day', 'week', 'month', 'year'])\n .optional()\n .describe(\n kind === 'search'\n ? 'Optional recency window for time-sensitive searches'\n : 'Optional recency window; use day for breaking news'\n ),\n };\n}\n\n// Unknown keys are stripped rather than rejected so a stray argument does not\n// cost the agent a retry step.\nconst searchSchema = z.object({\n ...queryFields('search'),\n search_service: z\n .enum(SEARCH_ENGINES)\n .optional()\n .describe(\n \"Search engine to use; choose one only when it matches the user's source intent\"\n ),\n page: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe(\n 'Results page to fetch; only bing, bingcn, baidu, and grokipedia paginate, other engines ignore it'\n ),\n});\n\nconst newsSchema = z.object({\n ...queryFields('news'),\n search_service: z\n .enum(NEWS_ENGINES)\n .optional()\n .describe('News search engine to use'),\n});\n\nconst crawlSchema = z.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('Public HTTP or HTTPS URL to retrieve'),\n});\n\nconst askSchema = z.object({\n query: z\n .string()\n .trim()\n .min(1)\n .max(500)\n .describe(\n 'Natural-language description of what to find, including any platform or time frame'\n ),\n});\n\nexport type SearchInput = z.input<typeof searchSchema>;\nexport type NewsInput = z.input<typeof newsSchema>;\n\ntype ModelQueryInput =\n | z.output<typeof searchSchema>\n | (z.output<typeof newsSchema> & { page?: undefined });\n\n// Merge model-supplied values over application defaults, dropping omitted keys.\nfunction requestOptions<Options extends SearchOptions | NewsOptions>(\n defaults: Options,\n input: ModelQueryInput\n): Options {\n const fromModel = {\n searchService: input.search_service,\n maxResults: input.max_results,\n includeSites: input.include_sites,\n excludeSites: input.exclude_sites,\n timeRange: input.time_range,\n page: input.page,\n };\n const overrides = Object.fromEntries(\n Object.entries(fromModel).filter(([, value]) => value !== undefined)\n );\n return { ...defaults, ...overrides } as Options;\n}\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<SearchInput, SearchResponse> {\n const defaults: SearchOptions = {\n maxResults: 10,\n crawlResults: 0,\n ...settings,\n };\n return tool({\n description:\n 'Search the live public web when the user needs current information, sources, or research. Returns titles, links, and snippets. Use crawl to read a result page in full.',\n inputSchema: searchSchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const parsed = searchSchema.parse(input);\n return getClient().search(\n parsed.query,\n requestOptions(defaults, parsed),\n { signal: abortSignal }\n );\n },\n });\n}\n\nfunction newsTool(\n getClient: ClientGetter,\n settings: NewsOptions = {}\n): Tool<NewsInput, NewsResponse> {\n const defaults: NewsOptions = {\n maxResults: 10,\n crawlResults: 0,\n ...settings,\n };\n return tool({\n description:\n 'Search current news when the user asks about recent events, announcements, or coverage. Returns article titles, links, and snippets. Use crawl to read an article in full.',\n inputSchema: newsSchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const parsed = newsSchema.parse(input);\n return getClient().news(parsed.query, requestOptions(defaults, parsed), {\n signal: abortSignal,\n });\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\nfunction askTool(getClient: ClientGetter): Tool<AskInput, AskResponse> {\n return tool({\n description:\n 'Describe what you need in natural language; Search1API chooses up to five engines and a time window, then returns at most 10 results ranked by relevance, with the engines and window it used. Costs 5 credits per call. Use search instead when you already know the engine and keywords.',\n inputSchema: askSchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const { query } = askSchema.parse(input);\n return getClient().ask(query, { signal: abortSignal });\n },\n });\n}\n\nexport function search1apiSearch(\n options: Search1APISearchOptions = {}\n): Tool<SearchInput, SearchResponse> {\n return searchTool(clientGetter(options), options.search);\n}\n\nexport function search1apiNews(\n options: Search1APINewsOptions = {}\n): Tool<NewsInput, 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\n/** Agentic search through `POST /ask`. Costs 5 credits per call. */\nexport function search1apiAsk(\n options: Search1APIToolOptions = {}\n): Tool<AskInput, AskResponse> {\n return askTool(clientGetter(options));\n}\n\nexport interface Search1APIToolSet {\n search: Tool<SearchInput, SearchResponse>;\n news: Tool<NewsInput, NewsResponse>;\n crawl: Tool<CrawlInput, CrawlResponse>;\n ask: Tool<AskInput, AskResponse>;\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 four 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 ask: askTool(getClient),\n };\n const names =\n options.only ?? (['search', 'news', 'crawl', 'ask'] 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
6
|
"names": []
|
|
7
7
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Search1API } from '@search1api/client';
|
|
2
|
-
import type { CrawlOptions, CrawlResponse, NewsOptions, NewsResponse, Search1APIOptions, SearchOptions, SearchResponse } from '@search1api/client';
|
|
2
|
+
import type { AskResponse, CrawlOptions, CrawlResponse, NewsOptions, NewsResponse, Search1APIOptions, SearchOptions, SearchResponse } from '@search1api/client';
|
|
3
3
|
import type { Tool } from 'ai';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
export interface Search1APIToolOptions extends Search1APIOptions {
|
|
@@ -20,12 +20,17 @@ export interface Search1APICrawlOptions extends Search1APIToolOptions {
|
|
|
20
20
|
export type CrawlInput = {
|
|
21
21
|
url: string;
|
|
22
22
|
};
|
|
23
|
+
export type AskInput = {
|
|
24
|
+
query: string;
|
|
25
|
+
};
|
|
23
26
|
declare const searchSchema: z.ZodObject<{
|
|
24
27
|
search_service: z.ZodOptional<z.ZodEnum<{
|
|
25
28
|
google: "google";
|
|
26
29
|
bing: "bing";
|
|
30
|
+
bingcn: "bingcn";
|
|
27
31
|
duckduckgo: "duckduckgo";
|
|
28
32
|
yahoo: "yahoo";
|
|
33
|
+
yandex: "yandex";
|
|
29
34
|
x: "x";
|
|
30
35
|
reddit: "reddit";
|
|
31
36
|
github: "github";
|
|
@@ -35,13 +40,16 @@ declare const searchSchema: z.ZodObject<{
|
|
|
35
40
|
bilibili: "bilibili";
|
|
36
41
|
imdb: "imdb";
|
|
37
42
|
wikipedia: "wikipedia";
|
|
43
|
+
grokipedia: "grokipedia";
|
|
38
44
|
}>>;
|
|
45
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
39
46
|
query: z.ZodString;
|
|
40
47
|
max_results: z.ZodOptional<z.ZodNumber>;
|
|
41
48
|
include_sites: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
42
49
|
exclude_sites: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
43
50
|
time_range: z.ZodOptional<z.ZodEnum<{
|
|
44
51
|
day: "day";
|
|
52
|
+
week: "week";
|
|
45
53
|
month: "month";
|
|
46
54
|
year: "year";
|
|
47
55
|
}>>;
|
|
@@ -60,6 +68,7 @@ declare const newsSchema: z.ZodObject<{
|
|
|
60
68
|
exclude_sites: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
61
69
|
time_range: z.ZodOptional<z.ZodEnum<{
|
|
62
70
|
day: "day";
|
|
71
|
+
week: "week";
|
|
63
72
|
month: "month";
|
|
64
73
|
year: "year";
|
|
65
74
|
}>>;
|
|
@@ -69,14 +78,17 @@ export type NewsInput = z.input<typeof newsSchema>;
|
|
|
69
78
|
export declare function search1apiSearch(options?: Search1APISearchOptions): Tool<SearchInput, SearchResponse>;
|
|
70
79
|
export declare function search1apiNews(options?: Search1APINewsOptions): Tool<NewsInput, NewsResponse>;
|
|
71
80
|
export declare function search1apiCrawl(options?: Search1APICrawlOptions): Tool<CrawlInput, CrawlResponse>;
|
|
81
|
+
/** Agentic search through `POST /ask`. Costs 5 credits per call. */
|
|
82
|
+
export declare function search1apiAsk(options?: Search1APIToolOptions): Tool<AskInput, AskResponse>;
|
|
72
83
|
export interface Search1APIToolSet {
|
|
73
84
|
search: Tool<SearchInput, SearchResponse>;
|
|
74
85
|
news: Tool<NewsInput, NewsResponse>;
|
|
75
86
|
crawl: Tool<CrawlInput, CrawlResponse>;
|
|
87
|
+
ask: Tool<AskInput, AskResponse>;
|
|
76
88
|
}
|
|
77
89
|
export type Search1APIToolName = keyof Search1APIToolSet;
|
|
78
90
|
export interface Search1APIToolsOptions<Name extends Search1APIToolName = Search1APIToolName> extends Search1APIToolOptions {
|
|
79
|
-
/** Include only these tools. By default all
|
|
91
|
+
/** Include only these tools. By default all four are included. */
|
|
80
92
|
only?: readonly Name[];
|
|
81
93
|
search?: SearchOptions;
|
|
82
94
|
news?: NewsOptions;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +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;AAC/B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,iFAAiF;IACjF,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,0EAA0E;IAC1E,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAClE,wEAAwE;IACxE,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,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
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,WAAW,EACX,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;AAC/B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,iFAAiF;IACjF,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,0EAA0E;IAC1E,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAClE,wEAAwE;IACxE,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,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AACzC,MAAM,MAAM,QAAQ,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AA0EzC,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiBhB,CAAC;AAEH,QAAA,MAAM,UAAU;;;;;;;;;;;;;;;;;;iBAMd,CAAC;AAwBH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AACvD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AA4HnD,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,uBAA4B,GACpC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAEnC;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,qBAA0B,GAClC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAE/B;AAED,wBAAgB,eAAe,CAC7B,OAAO,GAAE,sBAA2B,GACnC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAEjC;AAED,oEAAoE;AACpE,wBAAgB,aAAa,CAC3B,OAAO,GAAE,qBAA0B,GAClC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAE7B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IAC1C,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IACpC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IACvC,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;CAClC;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,iBAAiB,CAAC;AAEzD,MAAM,WAAW,sBAAsB,CACrC,IAAI,SAAS,kBAAkB,GAAG,kBAAkB,CACpD,SAAQ,qBAAqB;IAC7B,kEAAkE;IAClE,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,CAkB3E"}
|
package/dist/index.js
CHANGED
|
@@ -5,8 +5,10 @@ import { z } from "zod";
|
|
|
5
5
|
var SEARCH_ENGINES = [
|
|
6
6
|
"google",
|
|
7
7
|
"bing",
|
|
8
|
+
"bingcn",
|
|
8
9
|
"duckduckgo",
|
|
9
10
|
"yahoo",
|
|
11
|
+
"yandex",
|
|
10
12
|
"x",
|
|
11
13
|
"reddit",
|
|
12
14
|
"github",
|
|
@@ -15,7 +17,8 @@ var SEARCH_ENGINES = [
|
|
|
15
17
|
"wechat",
|
|
16
18
|
"bilibili",
|
|
17
19
|
"imdb",
|
|
18
|
-
"wikipedia"
|
|
20
|
+
"wikipedia",
|
|
21
|
+
"grokipedia"
|
|
19
22
|
];
|
|
20
23
|
var NEWS_ENGINES = [
|
|
21
24
|
"google",
|
|
@@ -35,7 +38,7 @@ function queryFields(kind) {
|
|
|
35
38
|
exclude_sites: z.array(z.string()).optional().describe(
|
|
36
39
|
kind === "search" ? "Domains to exclude from the search" : "News domains to exclude"
|
|
37
40
|
),
|
|
38
|
-
time_range: z.enum(["day", "month", "year"]).optional().describe(
|
|
41
|
+
time_range: z.enum(["day", "week", "month", "year"]).optional().describe(
|
|
39
42
|
kind === "search" ? "Optional recency window for time-sensitive searches" : "Optional recency window; use day for breaking news"
|
|
40
43
|
)
|
|
41
44
|
};
|
|
@@ -44,6 +47,9 @@ var searchSchema = z.object({
|
|
|
44
47
|
...queryFields("search"),
|
|
45
48
|
search_service: z.enum(SEARCH_ENGINES).optional().describe(
|
|
46
49
|
"Search engine to use; choose one only when it matches the user's source intent"
|
|
50
|
+
),
|
|
51
|
+
page: z.number().int().min(1).max(100).optional().describe(
|
|
52
|
+
"Results page to fetch; only bing, bingcn, baidu, and grokipedia paginate, other engines ignore it"
|
|
47
53
|
)
|
|
48
54
|
});
|
|
49
55
|
var newsSchema = z.object({
|
|
@@ -56,13 +62,19 @@ var crawlSchema = z.object({
|
|
|
56
62
|
"Use an HTTP or HTTPS URL."
|
|
57
63
|
).describe("Public HTTP or HTTPS URL to retrieve")
|
|
58
64
|
});
|
|
65
|
+
var askSchema = z.object({
|
|
66
|
+
query: z.string().trim().min(1).max(500).describe(
|
|
67
|
+
"Natural-language description of what to find, including any platform or time frame"
|
|
68
|
+
)
|
|
69
|
+
});
|
|
59
70
|
function requestOptions(defaults, input) {
|
|
60
71
|
const fromModel = {
|
|
61
72
|
searchService: input.search_service,
|
|
62
73
|
maxResults: input.max_results,
|
|
63
74
|
includeSites: input.include_sites,
|
|
64
75
|
excludeSites: input.exclude_sites,
|
|
65
|
-
timeRange: input.time_range
|
|
76
|
+
timeRange: input.time_range,
|
|
77
|
+
page: input.page
|
|
66
78
|
};
|
|
67
79
|
const overrides = Object.fromEntries(
|
|
68
80
|
Object.entries(fromModel).filter(([, value]) => value !== void 0)
|
|
@@ -134,6 +146,17 @@ function crawlTool(getClient, settings = {}) {
|
|
|
134
146
|
}
|
|
135
147
|
});
|
|
136
148
|
}
|
|
149
|
+
function askTool(getClient) {
|
|
150
|
+
return tool({
|
|
151
|
+
description: "Describe what you need in natural language; Search1API chooses up to five engines and a time window, then returns at most 10 results ranked by relevance, with the engines and window it used. Costs 5 credits per call. Use search instead when you already know the engine and keywords.",
|
|
152
|
+
inputSchema: askSchema,
|
|
153
|
+
execute: async (input, { abortSignal }) => {
|
|
154
|
+
abortSignal?.throwIfAborted();
|
|
155
|
+
const { query } = askSchema.parse(input);
|
|
156
|
+
return getClient().ask(query, { signal: abortSignal });
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
137
160
|
function search1apiSearch(options = {}) {
|
|
138
161
|
return searchTool(clientGetter(options), options.search);
|
|
139
162
|
}
|
|
@@ -143,14 +166,18 @@ function search1apiNews(options = {}) {
|
|
|
143
166
|
function search1apiCrawl(options = {}) {
|
|
144
167
|
return crawlTool(clientGetter(options), options.crawl);
|
|
145
168
|
}
|
|
169
|
+
function search1apiAsk(options = {}) {
|
|
170
|
+
return askTool(clientGetter(options));
|
|
171
|
+
}
|
|
146
172
|
function search1apiTools(options = {}) {
|
|
147
173
|
const getClient = clientGetter(options);
|
|
148
174
|
const tools = {
|
|
149
175
|
search: searchTool(getClient, options.search),
|
|
150
176
|
news: newsTool(getClient, options.news),
|
|
151
|
-
crawl: crawlTool(getClient, options.crawl)
|
|
177
|
+
crawl: crawlTool(getClient, options.crawl),
|
|
178
|
+
ask: askTool(getClient)
|
|
152
179
|
};
|
|
153
|
-
const names = options.only ?? ["search", "news", "crawl"];
|
|
180
|
+
const names = options.only ?? ["search", "news", "crawl", "ask"];
|
|
154
181
|
const selected = {};
|
|
155
182
|
for (const name of names) {
|
|
156
183
|
if (!Object.hasOwn(tools, name)) {
|
|
@@ -161,6 +188,7 @@ function search1apiTools(options = {}) {
|
|
|
161
188
|
return selected;
|
|
162
189
|
}
|
|
163
190
|
export {
|
|
191
|
+
search1apiAsk,
|
|
164
192
|
search1apiCrawl,
|
|
165
193
|
search1apiNews,
|
|
166
194
|
search1apiSearch,
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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 /** Default search settings; values the model supplies take precedence. */\n search?: SearchOptions;\n}\n\nexport interface Search1APINewsOptions extends Search1APIToolOptions {\n /** Default news settings; values the model supplies take precedence. */\n news?: NewsOptions;\n}\n\nexport interface Search1APICrawlOptions extends Search1APIToolOptions {\n crawl?: CrawlOptions;\n}\n\nexport type CrawlInput = { url: string };\n\n// Model-facing parameters mirror the Search1API MCP server's tool schemas,\n// except result crawling, which only application settings can enable.\nconst SEARCH_ENGINES = [\n 'google',\n 'bing',\n 'duckduckgo',\n 'yahoo',\n 'x',\n 'reddit',\n 'github',\n 'youtube',\n 'arxiv',\n 'wechat',\n 'bilibili',\n 'imdb',\n 'wikipedia',\n] as const;\nconst NEWS_ENGINES = [\n 'google',\n 'bing',\n 'duckduckgo',\n 'yahoo',\n 'hackernews',\n] as const;\n\nfunction queryFields(kind: 'search' | 'news') {\n const noun = kind === 'search' ? 'results' : 'articles';\n return {\n query: z\n .string()\n .trim()\n .min(1)\n .describe(`Short, focused ${kind} query`),\n max_results: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe(`Maximum number of ${noun} to return`),\n include_sites: z\n .array(z.string())\n .optional()\n .describe(\n kind === 'search'\n ? 'Domains to include when the user explicitly scopes the search'\n : 'News domains to include'\n ),\n exclude_sites: z\n .array(z.string())\n .optional()\n .describe(\n kind === 'search'\n ? 'Domains to exclude from the search'\n : 'News domains to exclude'\n ),\n time_range: z\n .enum(['day', 'month', 'year'])\n .optional()\n .describe(\n kind === 'search'\n ? 'Optional recency window for time-sensitive searches'\n : 'Optional recency window; use day for breaking news'\n ),\n };\n}\n\n// Unknown keys are stripped rather than rejected so a stray argument does not\n// cost the agent a retry step.\nconst searchSchema = z.object({\n ...queryFields('search'),\n search_service: z\n .enum(SEARCH_ENGINES)\n .optional()\n .describe(\n \"Search engine to use; choose one only when it matches the user's source intent\"\n ),\n});\n\nconst newsSchema = z.object({\n ...queryFields('news'),\n search_service: z\n .enum(NEWS_ENGINES)\n .optional()\n .describe('News search engine to use'),\n});\n\nconst crawlSchema = z.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('Public HTTP or HTTPS URL to retrieve'),\n});\n\nexport type SearchInput = z.input<typeof searchSchema>;\nexport type NewsInput = z.input<typeof newsSchema>;\n\ntype ModelQueryInput =\n | z.output<typeof searchSchema>\n | z.output<typeof newsSchema>;\n\n// Merge model-supplied values over application defaults, dropping omitted keys.\nfunction requestOptions<Options extends SearchOptions | NewsOptions>(\n defaults: Options,\n input: ModelQueryInput\n): Options {\n const fromModel = {\n searchService: input.search_service,\n maxResults: input.max_results,\n includeSites: input.include_sites,\n excludeSites: input.exclude_sites,\n timeRange: input.time_range,\n };\n const overrides = Object.fromEntries(\n Object.entries(fromModel).filter(([, value]) => value !== undefined)\n );\n return { ...defaults, ...overrides } as Options;\n}\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<SearchInput, SearchResponse> {\n const defaults: SearchOptions = {\n maxResults: 10,\n crawlResults: 0,\n ...settings,\n };\n return tool({\n description:\n 'Search the live public web when the user needs current information, sources, or research. Returns titles, links, and snippets. Use crawl to read a result page in full.',\n inputSchema: searchSchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const parsed = searchSchema.parse(input);\n return getClient().search(\n parsed.query,\n requestOptions(defaults, parsed),\n { signal: abortSignal }\n );\n },\n });\n}\n\nfunction newsTool(\n getClient: ClientGetter,\n settings: NewsOptions = {}\n): Tool<NewsInput, NewsResponse> {\n const defaults: NewsOptions = {\n maxResults: 10,\n crawlResults: 0,\n ...settings,\n };\n return tool({\n description:\n 'Search current news when the user asks about recent events, announcements, or coverage. Returns article titles, links, and snippets. Use crawl to read an article in full.',\n inputSchema: newsSchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const parsed = newsSchema.parse(input);\n return getClient().news(parsed.query, requestOptions(defaults, parsed), {\n signal: abortSignal,\n });\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<SearchInput, SearchResponse> {\n return searchTool(clientGetter(options), options.search);\n}\n\nexport function search1apiNews(\n options: Search1APINewsOptions = {}\n): Tool<NewsInput, 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<SearchInput, SearchResponse>;\n news: Tool<NewsInput, 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": ";AAAA,SAAS,kBAAkB;
|
|
4
|
+
"sourcesContent": ["import { Search1API } from '@search1api/client';\nimport type {\n AskResponse,\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 /** Default search settings; values the model supplies take precedence. */\n search?: SearchOptions;\n}\n\nexport interface Search1APINewsOptions extends Search1APIToolOptions {\n /** Default news settings; values the model supplies take precedence. */\n news?: NewsOptions;\n}\n\nexport interface Search1APICrawlOptions extends Search1APIToolOptions {\n crawl?: CrawlOptions;\n}\n\nexport type CrawlInput = { url: string };\nexport type AskInput = { query: string };\n\n// Model-facing parameters mirror the Search1API MCP server's tool schemas,\n// except result crawling, which only application settings can enable.\nconst SEARCH_ENGINES = [\n 'google',\n 'bing',\n 'bingcn',\n 'duckduckgo',\n 'yahoo',\n 'yandex',\n 'x',\n 'reddit',\n 'github',\n 'youtube',\n 'arxiv',\n 'wechat',\n 'bilibili',\n 'imdb',\n 'wikipedia',\n 'grokipedia',\n] as const;\nconst NEWS_ENGINES = [\n 'google',\n 'bing',\n 'duckduckgo',\n 'yahoo',\n 'hackernews',\n] as const;\n\nfunction queryFields(kind: 'search' | 'news') {\n const noun = kind === 'search' ? 'results' : 'articles';\n return {\n query: z\n .string()\n .trim()\n .min(1)\n .describe(`Short, focused ${kind} query`),\n max_results: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe(`Maximum number of ${noun} to return`),\n include_sites: z\n .array(z.string())\n .optional()\n .describe(\n kind === 'search'\n ? 'Domains to include when the user explicitly scopes the search'\n : 'News domains to include'\n ),\n exclude_sites: z\n .array(z.string())\n .optional()\n .describe(\n kind === 'search'\n ? 'Domains to exclude from the search'\n : 'News domains to exclude'\n ),\n time_range: z\n .enum(['day', 'week', 'month', 'year'])\n .optional()\n .describe(\n kind === 'search'\n ? 'Optional recency window for time-sensitive searches'\n : 'Optional recency window; use day for breaking news'\n ),\n };\n}\n\n// Unknown keys are stripped rather than rejected so a stray argument does not\n// cost the agent a retry step.\nconst searchSchema = z.object({\n ...queryFields('search'),\n search_service: z\n .enum(SEARCH_ENGINES)\n .optional()\n .describe(\n \"Search engine to use; choose one only when it matches the user's source intent\"\n ),\n page: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe(\n 'Results page to fetch; only bing, bingcn, baidu, and grokipedia paginate, other engines ignore it'\n ),\n});\n\nconst newsSchema = z.object({\n ...queryFields('news'),\n search_service: z\n .enum(NEWS_ENGINES)\n .optional()\n .describe('News search engine to use'),\n});\n\nconst crawlSchema = z.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('Public HTTP or HTTPS URL to retrieve'),\n});\n\nconst askSchema = z.object({\n query: z\n .string()\n .trim()\n .min(1)\n .max(500)\n .describe(\n 'Natural-language description of what to find, including any platform or time frame'\n ),\n});\n\nexport type SearchInput = z.input<typeof searchSchema>;\nexport type NewsInput = z.input<typeof newsSchema>;\n\ntype ModelQueryInput =\n | z.output<typeof searchSchema>\n | (z.output<typeof newsSchema> & { page?: undefined });\n\n// Merge model-supplied values over application defaults, dropping omitted keys.\nfunction requestOptions<Options extends SearchOptions | NewsOptions>(\n defaults: Options,\n input: ModelQueryInput\n): Options {\n const fromModel = {\n searchService: input.search_service,\n maxResults: input.max_results,\n includeSites: input.include_sites,\n excludeSites: input.exclude_sites,\n timeRange: input.time_range,\n page: input.page,\n };\n const overrides = Object.fromEntries(\n Object.entries(fromModel).filter(([, value]) => value !== undefined)\n );\n return { ...defaults, ...overrides } as Options;\n}\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<SearchInput, SearchResponse> {\n const defaults: SearchOptions = {\n maxResults: 10,\n crawlResults: 0,\n ...settings,\n };\n return tool({\n description:\n 'Search the live public web when the user needs current information, sources, or research. Returns titles, links, and snippets. Use crawl to read a result page in full.',\n inputSchema: searchSchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const parsed = searchSchema.parse(input);\n return getClient().search(\n parsed.query,\n requestOptions(defaults, parsed),\n { signal: abortSignal }\n );\n },\n });\n}\n\nfunction newsTool(\n getClient: ClientGetter,\n settings: NewsOptions = {}\n): Tool<NewsInput, NewsResponse> {\n const defaults: NewsOptions = {\n maxResults: 10,\n crawlResults: 0,\n ...settings,\n };\n return tool({\n description:\n 'Search current news when the user asks about recent events, announcements, or coverage. Returns article titles, links, and snippets. Use crawl to read an article in full.',\n inputSchema: newsSchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const parsed = newsSchema.parse(input);\n return getClient().news(parsed.query, requestOptions(defaults, parsed), {\n signal: abortSignal,\n });\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\nfunction askTool(getClient: ClientGetter): Tool<AskInput, AskResponse> {\n return tool({\n description:\n 'Describe what you need in natural language; Search1API chooses up to five engines and a time window, then returns at most 10 results ranked by relevance, with the engines and window it used. Costs 5 credits per call. Use search instead when you already know the engine and keywords.',\n inputSchema: askSchema,\n execute: async (input, { abortSignal }) => {\n abortSignal?.throwIfAborted();\n const { query } = askSchema.parse(input);\n return getClient().ask(query, { signal: abortSignal });\n },\n });\n}\n\nexport function search1apiSearch(\n options: Search1APISearchOptions = {}\n): Tool<SearchInput, SearchResponse> {\n return searchTool(clientGetter(options), options.search);\n}\n\nexport function search1apiNews(\n options: Search1APINewsOptions = {}\n): Tool<NewsInput, 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\n/** Agentic search through `POST /ask`. Costs 5 credits per call. */\nexport function search1apiAsk(\n options: Search1APIToolOptions = {}\n): Tool<AskInput, AskResponse> {\n return askTool(clientGetter(options));\n}\n\nexport interface Search1APIToolSet {\n search: Tool<SearchInput, SearchResponse>;\n news: Tool<NewsInput, NewsResponse>;\n crawl: Tool<CrawlInput, CrawlResponse>;\n ask: Tool<AskInput, AskResponse>;\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 four 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 ask: askTool(getClient),\n };\n const names =\n options.only ?? (['search', 'news', 'crawl', 'ask'] 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": ";AAAA,SAAS,kBAAkB;AAW3B,SAAS,YAAY;AAErB,SAAS,SAAS;AA0BlB,IAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACA,IAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,YAAY,MAAyB;AAC5C,QAAM,OAAO,SAAS,WAAW,YAAY;AAC7C,SAAO;AAAA,IACL,OAAO,EACJ,OAAO,EACP,KAAK,EACL,IAAI,CAAC,EACL,SAAS,kBAAkB,IAAI,QAAQ;AAAA,IAC1C,aAAa,EACV,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,EACL,IAAI,EAAE,EACN,SAAS,EACT,SAAS,qBAAqB,IAAI,YAAY;AAAA,IACjD,eAAe,EACZ,MAAM,EAAE,OAAO,CAAC,EAChB,SAAS,EACT;AAAA,MACC,SAAS,WACL,kEACA;AAAA,IACN;AAAA,IACF,eAAe,EACZ,MAAM,EAAE,OAAO,CAAC,EAChB,SAAS,EACT;AAAA,MACC,SAAS,WACL,uCACA;AAAA,IACN;AAAA,IACF,YAAY,EACT,KAAK,CAAC,OAAO,QAAQ,SAAS,MAAM,CAAC,EACrC,SAAS,EACT;AAAA,MACC,SAAS,WACL,wDACA;AAAA,IACN;AAAA,EACJ;AACF;AAIA,IAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,GAAG,YAAY,QAAQ;AAAA,EACvB,gBAAgB,EACb,KAAK,cAAc,EACnB,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,MAAM,EACH,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,EACL,IAAI,GAAG,EACP,SAAS,EACT;AAAA,IACC;AAAA,EACF;AACJ,CAAC;AAED,IAAM,aAAa,EAAE,OAAO;AAAA,EAC1B,GAAG,YAAY,MAAM;AAAA,EACrB,gBAAgB,EACb,KAAK,YAAY,EACjB,SAAS,EACT,SAAS,2BAA2B;AACzC,CAAC;AAED,IAAM,cAAc,EAAE,OAAO;AAAA,EAC3B,KAAK,EACF,OAAO,EACP,IAAI,EACJ;AAAA,IACC,CAAC,QAAQ,CAAC,SAAS,QAAQ,EAAE,SAAS,IAAI,IAAI,GAAG,EAAE,QAAQ;AAAA,IAC3D;AAAA,EACF,EACC,SAAS,sCAAsC;AACpD,CAAC;AAED,IAAM,YAAY,EAAE,OAAO;AAAA,EACzB,OAAO,EACJ,OAAO,EACP,KAAK,EACL,IAAI,CAAC,EACL,IAAI,GAAG,EACP;AAAA,IACC;AAAA,EACF;AACJ,CAAC;AAUD,SAAS,eACP,UACA,OACS;AACT,QAAM,YAAY;AAAA,IAChB,eAAe,MAAM;AAAA,IACrB,YAAY,MAAM;AAAA,IAClB,cAAc,MAAM;AAAA,IACpB,cAAc,MAAM;AAAA,IACpB,WAAW,MAAM;AAAA,IACjB,MAAM,MAAM;AAAA,EACd;AACA,QAAM,YAAY,OAAO;AAAA,IACvB,OAAO,QAAQ,SAAS,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,MAAS;AAAA,EACrE;AACA,SAAO,EAAE,GAAG,UAAU,GAAG,UAAU;AACrC;AAIA,SAAS,aAAa,SAA8C;AAClE,MAAI,SAAS,QAAQ;AACrB,QAAM,EAAE,QAAQ,SAAS,GAAG,SAAS,IAAI;AACzC,SAAO,MAAM;AACX,QAAI,CAAC,QAAQ;AACX,YAAM,cAAc;AAGpB,YAAM,MAAM,YAAY,SAAS;AACjC,eAAS,IAAI,WAAW;AAAA,QACtB,GAAG;AAAA,QACH,QACE,SAAS,UAAU,KAAK,sBAAsB,KAAK;AAAA,MACvD,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,WACP,WACA,WAA0B,CAAC,GACQ;AACnC,QAAM,WAA0B;AAAA,IAC9B,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,GAAG;AAAA,EACL;AACA,SAAO,KAAK;AAAA,IACV,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS,OAAO,OAAO,EAAE,YAAY,MAAM;AACzC,mBAAa,eAAe;AAC5B,YAAM,SAAS,aAAa,MAAM,KAAK;AACvC,aAAO,UAAU,EAAE;AAAA,QACjB,OAAO;AAAA,QACP,eAAe,UAAU,MAAM;AAAA,QAC/B,EAAE,QAAQ,YAAY;AAAA,MACxB;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,SAAS,SACP,WACA,WAAwB,CAAC,GACM;AAC/B,QAAM,WAAwB;AAAA,IAC5B,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,GAAG;AAAA,EACL;AACA,SAAO,KAAK;AAAA,IACV,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS,OAAO,OAAO,EAAE,YAAY,MAAM;AACzC,mBAAa,eAAe;AAC5B,YAAM,SAAS,WAAW,MAAM,KAAK;AACrC,aAAO,UAAU,EAAE,KAAK,OAAO,OAAO,eAAe,UAAU,MAAM,GAAG;AAAA,QACtE,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH;AAEA,SAAS,UACP,WACA,WAAyB,CAAC,GACO;AACjC,QAAM,UAAU,EAAE,GAAG,SAAS;AAC9B,SAAO,KAAK;AAAA,IACV,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS,OAAO,OAAO,EAAE,YAAY,MAAM;AACzC,mBAAa,eAAe;AAC5B,YAAM,EAAE,IAAI,IAAI,YAAY,MAAM,KAAK;AACvC,aAAO,UAAU,EAAE,MAAM,KAAK,SAAS,EAAE,QAAQ,YAAY,CAAC;AAAA,IAChE;AAAA,EACF,CAAC;AACH;AAEA,SAAS,QAAQ,WAAsD;AACrE,SAAO,KAAK;AAAA,IACV,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS,OAAO,OAAO,EAAE,YAAY,MAAM;AACzC,mBAAa,eAAe;AAC5B,YAAM,EAAE,MAAM,IAAI,UAAU,MAAM,KAAK;AACvC,aAAO,UAAU,EAAE,IAAI,OAAO,EAAE,QAAQ,YAAY,CAAC;AAAA,IACvD;AAAA,EACF,CAAC;AACH;AAEO,SAAS,iBACd,UAAmC,CAAC,GACD;AACnC,SAAO,WAAW,aAAa,OAAO,GAAG,QAAQ,MAAM;AACzD;AAEO,SAAS,eACd,UAAiC,CAAC,GACH;AAC/B,SAAO,SAAS,aAAa,OAAO,GAAG,QAAQ,IAAI;AACrD;AAEO,SAAS,gBACd,UAAkC,CAAC,GACF;AACjC,SAAO,UAAU,aAAa,OAAO,GAAG,QAAQ,KAAK;AACvD;AAGO,SAAS,cACd,UAAiC,CAAC,GACL;AAC7B,SAAO,QAAQ,aAAa,OAAO,CAAC;AACtC;AAqBO,SAAS,gBAEd,UAAwC,CAAC,GAAkC;AAC3E,QAAM,YAAY,aAAa,OAAO;AACtC,QAAM,QAA2B;AAAA,IAC/B,QAAQ,WAAW,WAAW,QAAQ,MAAM;AAAA,IAC5C,MAAM,SAAS,WAAW,QAAQ,IAAI;AAAA,IACtC,OAAO,UAAU,WAAW,QAAQ,KAAK;AAAA,IACzC,KAAK,QAAQ,SAAS;AAAA,EACxB;AACA,QAAM,QACJ,QAAQ,QAAS,CAAC,UAAU,QAAQ,SAAS,KAAK;AACpD,QAAM,WAAW,CAAC;AAClB,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,OAAO,OAAO,OAAO,IAAI,GAAG;AAC/B,YAAM,IAAI,MAAM,4BAA4B,IAAI,EAAE;AAAA,IACpD;AACA,WAAO,OAAO,UAAU,EAAE,CAAC,IAAI,GAAG,MAAM,IAAI,EAAE,CAAC;AAAA,EACjD;AACA,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@search1api/ai-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Official Search1API web search, news, and page reading tools for the Vercel AI SDK.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"prepack": "npm run build"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@search1api/client": "^0.
|
|
56
|
+
"@search1api/client": "^0.3.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"ai": "^5.0.0 || ^6.0.0 || ^7.0.0",
|