@yourgpt/copilot-sdk 2.0.0 → 2.0.2-beta.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/README.md +68 -27
- package/dist/{ThreadManager-JT0sqSSD.d.ts → ThreadManager-Dkp_eLty.d.ts} +1 -1
- package/dist/{ThreadManager-CUq5Ocu2.d.cts → ThreadManager-LfFRhr4e.d.cts} +1 -1
- package/dist/anthropic-6F5GRE3B.js +4 -0
- package/dist/anthropic-6F5GRE3B.js.map +1 -0
- package/dist/anthropic-DGalr_Fw.d.cts +17 -0
- package/dist/anthropic-DkCEDYOt.d.ts +17 -0
- package/dist/anthropic-NMTRABEH.cjs +21 -0
- package/dist/anthropic-NMTRABEH.cjs.map +1 -0
- package/dist/brave-DdnWb7Gb.d.cts +17 -0
- package/dist/brave-DsI9n7Wr.d.ts +17 -0
- package/dist/brave-OYKCOZEM.cjs +21 -0
- package/dist/brave-OYKCOZEM.cjs.map +1 -0
- package/dist/brave-XSASGGH2.js +4 -0
- package/dist/brave-XSASGGH2.js.map +1 -0
- package/dist/chunk-2FAWEBZS.cjs +88 -0
- package/dist/chunk-2FAWEBZS.cjs.map +1 -0
- package/dist/{chunk-CJ7UWN2Y.js → chunk-3YKHVLNP.js} +397 -7
- package/dist/chunk-3YKHVLNP.js.map +1 -0
- package/dist/chunk-4WWWMNUA.js +1142 -0
- package/dist/chunk-4WWWMNUA.js.map +1 -0
- package/dist/chunk-53UGJNHN.js +92 -0
- package/dist/chunk-53UGJNHN.js.map +1 -0
- package/dist/chunk-6BXQFCK3.js +79 -0
- package/dist/chunk-6BXQFCK3.js.map +1 -0
- package/dist/chunk-6T5XXJEP.cjs +80 -0
- package/dist/chunk-6T5XXJEP.cjs.map +1 -0
- package/dist/chunk-7W7QLZNC.js +72 -0
- package/dist/chunk-7W7QLZNC.js.map +1 -0
- package/dist/chunk-ASV6JLYG.cjs +99 -0
- package/dist/chunk-ASV6JLYG.cjs.map +1 -0
- package/dist/chunk-CBAHCI4R.cjs +76 -0
- package/dist/chunk-CBAHCI4R.cjs.map +1 -0
- package/dist/chunk-CEOMTQTP.js +85 -0
- package/dist/chunk-CEOMTQTP.js.map +1 -0
- package/dist/chunk-DABZYCVX.js +84 -0
- package/dist/chunk-DABZYCVX.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +10 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/dist/{chunk-4PRWNAXQ.cjs → chunk-DUPNYVBP.cjs} +27 -89
- package/dist/chunk-DUPNYVBP.cjs.map +1 -0
- package/dist/chunk-DVC63PGD.cjs +1160 -0
- package/dist/chunk-DVC63PGD.cjs.map +1 -0
- package/dist/chunk-G4SF2PNQ.js +33 -0
- package/dist/chunk-G4SF2PNQ.js.map +1 -0
- package/dist/chunk-GANCV72Z.cjs +110 -0
- package/dist/chunk-GANCV72Z.cjs.map +1 -0
- package/dist/chunk-J4OMGO5O.js +66 -0
- package/dist/chunk-J4OMGO5O.js.map +1 -0
- package/dist/chunk-JEQ2X3Z6.cjs +12 -0
- package/dist/chunk-JEQ2X3Z6.cjs.map +1 -0
- package/dist/chunk-JO4BHPAD.cjs +40 -0
- package/dist/chunk-JO4BHPAD.cjs.map +1 -0
- package/dist/chunk-MEBXW75C.cjs +89 -0
- package/dist/chunk-MEBXW75C.cjs.map +1 -0
- package/dist/chunk-MNDGIW47.js +76 -0
- package/dist/chunk-MNDGIW47.js.map +1 -0
- package/dist/chunk-PPFHA6IL.js +83 -0
- package/dist/chunk-PPFHA6IL.js.map +1 -0
- package/dist/{chunk-BLSI67J6.cjs → chunk-RBZXLBGI.cjs} +425 -30
- package/dist/chunk-RBZXLBGI.cjs.map +1 -0
- package/dist/chunk-RQ74USYU.js +128 -0
- package/dist/chunk-RQ74USYU.js.map +1 -0
- package/dist/chunk-TX7CGITI.cjs +82 -0
- package/dist/chunk-TX7CGITI.cjs.map +1 -0
- package/dist/chunk-TXLIY7GF.cjs +132 -0
- package/dist/chunk-TXLIY7GF.cjs.map +1 -0
- package/dist/chunk-VD74IPKB.js +106 -0
- package/dist/chunk-VD74IPKB.js.map +1 -0
- package/dist/chunk-W73FBYIH.cjs +87 -0
- package/dist/chunk-W73FBYIH.cjs.map +1 -0
- package/dist/chunk-W74OTXXX.cjs +73 -0
- package/dist/chunk-W74OTXXX.cjs.map +1 -0
- package/dist/chunk-XGITAEXU.js +93 -0
- package/dist/chunk-XGITAEXU.js.map +1 -0
- package/dist/chunk-XWOHNY3F.cjs +96 -0
- package/dist/chunk-XWOHNY3F.cjs.map +1 -0
- package/dist/{chunk-JM7PB2LP.js → chunk-Z7PHGSJT.js} +10 -66
- package/dist/chunk-Z7PHGSJT.js.map +1 -0
- package/dist/core/index.cjs +156 -84
- package/dist/core/index.d.cts +16 -4
- package/dist/core/index.d.ts +16 -4
- package/dist/core/index.js +13 -1
- package/dist/exa-72KFY5A7.cjs +21 -0
- package/dist/exa-72KFY5A7.cjs.map +1 -0
- package/dist/exa-Dp9U-WTc.d.ts +17 -0
- package/dist/exa-NNVPBC2M.js +4 -0
- package/dist/exa-NNVPBC2M.js.map +1 -0
- package/dist/exa-jJSPhyUW.d.cts +17 -0
- package/dist/google-CHU2yycE.d.cts +17 -0
- package/dist/google-CTEK6SV2.js +4 -0
- package/dist/google-CTEK6SV2.js.map +1 -0
- package/dist/google-Da8IQxaI.d.ts +17 -0
- package/dist/google-IIUXFFVF.cjs +21 -0
- package/dist/google-IIUXFFVF.cjs.map +1 -0
- package/dist/index-DBNh0jhE.d.ts +206 -0
- package/dist/index-DOlhSb79.d.cts +206 -0
- package/dist/mcp/index.cjs +670 -0
- package/dist/mcp/index.cjs.map +1 -0
- package/dist/mcp/index.d.cts +779 -0
- package/dist/mcp/index.d.ts +779 -0
- package/dist/mcp/index.js +574 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/openai-6KTCQ7PZ.cjs +21 -0
- package/dist/openai-6KTCQ7PZ.cjs.map +1 -0
- package/dist/openai-7W2PCNW5.js +4 -0
- package/dist/openai-7W2PCNW5.js.map +1 -0
- package/dist/openai-Cam8hF4f.d.ts +17 -0
- package/dist/openai-HVSCuXgO.d.cts +17 -0
- package/dist/react/index.cjs +75 -42
- package/dist/react/index.d.cts +270 -45
- package/dist/react/index.d.ts +270 -45
- package/dist/react/index.js +15 -2
- package/dist/searxng-AXLVGY7Z.js +4 -0
- package/dist/searxng-AXLVGY7Z.js.map +1 -0
- package/dist/searxng-EJKNY236.cjs +21 -0
- package/dist/searxng-EJKNY236.cjs.map +1 -0
- package/dist/searxng-K0qtY9vp.d.ts +17 -0
- package/dist/searxng-QGOte_Gq.d.cts +17 -0
- package/dist/serper-3JYJHJX6.js +4 -0
- package/dist/serper-3JYJHJX6.js.map +1 -0
- package/dist/serper-63FT4AOL.cjs +21 -0
- package/dist/serper-63FT4AOL.cjs.map +1 -0
- package/dist/serper-7Czya3PW.d.ts +17 -0
- package/dist/serper-JzdaSnS9.d.cts +17 -0
- package/dist/styles.css +38 -0
- package/dist/tavily-AWFP4RM7.cjs +21 -0
- package/dist/tavily-AWFP4RM7.cjs.map +1 -0
- package/dist/tavily-C8cXXojE.d.cts +17 -0
- package/dist/tavily-CIWAAZPH.js +4 -0
- package/dist/tavily-CIWAAZPH.js.map +1 -0
- package/dist/tavily-DdSGVgkE.d.ts +17 -0
- package/dist/themes/catppuccin.css +2 -0
- package/dist/themes/claude.css +2 -0
- package/dist/themes/linear.css +2 -0
- package/dist/themes/modern-minimal.css +2 -0
- package/dist/themes/posthog.css +2 -0
- package/dist/themes/supabase.css +2 -0
- package/dist/themes/twitter.css +2 -0
- package/dist/themes/vercel.css +2 -0
- package/dist/tools/anthropic/index.cjs +61 -0
- package/dist/tools/anthropic/index.cjs.map +1 -0
- package/dist/tools/anthropic/index.d.cts +67 -0
- package/dist/tools/anthropic/index.d.ts +67 -0
- package/dist/tools/anthropic/index.js +56 -0
- package/dist/tools/anthropic/index.js.map +1 -0
- package/dist/tools/brave/index.cjs +85 -0
- package/dist/tools/brave/index.cjs.map +1 -0
- package/dist/tools/brave/index.d.cts +91 -0
- package/dist/tools/brave/index.d.ts +91 -0
- package/dist/tools/brave/index.js +80 -0
- package/dist/tools/brave/index.js.map +1 -0
- package/dist/tools/exa/index.cjs +90 -0
- package/dist/tools/exa/index.cjs.map +1 -0
- package/dist/tools/exa/index.d.cts +92 -0
- package/dist/tools/exa/index.d.ts +92 -0
- package/dist/tools/exa/index.js +85 -0
- package/dist/tools/exa/index.js.map +1 -0
- package/dist/tools/google/index.cjs +81 -0
- package/dist/tools/google/index.cjs.map +1 -0
- package/dist/tools/google/index.d.cts +81 -0
- package/dist/tools/google/index.d.ts +81 -0
- package/dist/tools/google/index.js +76 -0
- package/dist/tools/google/index.js.map +1 -0
- package/dist/tools/openai/index.cjs +83 -0
- package/dist/tools/openai/index.cjs.map +1 -0
- package/dist/tools/openai/index.d.cts +84 -0
- package/dist/tools/openai/index.d.ts +84 -0
- package/dist/tools/openai/index.js +78 -0
- package/dist/tools/openai/index.js.map +1 -0
- package/dist/tools/searxng/index.cjs +85 -0
- package/dist/tools/searxng/index.cjs.map +1 -0
- package/dist/tools/searxng/index.d.cts +91 -0
- package/dist/tools/searxng/index.d.ts +91 -0
- package/dist/tools/searxng/index.js +80 -0
- package/dist/tools/searxng/index.js.map +1 -0
- package/dist/tools/serper/index.cjs +85 -0
- package/dist/tools/serper/index.cjs.map +1 -0
- package/dist/tools/serper/index.d.cts +91 -0
- package/dist/tools/serper/index.d.ts +91 -0
- package/dist/tools/serper/index.js +80 -0
- package/dist/tools/serper/index.js.map +1 -0
- package/dist/tools/tavily/index.cjs +91 -0
- package/dist/tools/tavily/index.cjs.map +1 -0
- package/dist/tools/tavily/index.d.cts +95 -0
- package/dist/tools/tavily/index.d.ts +95 -0
- package/dist/tools/tavily/index.js +86 -0
- package/dist/tools/tavily/index.js.map +1 -0
- package/dist/tools/web-search/index.cjs +31 -0
- package/dist/tools/web-search/index.cjs.map +1 -0
- package/dist/tools/web-search/index.d.cts +3 -0
- package/dist/tools/web-search/index.d.ts +3 -0
- package/dist/tools/web-search/index.js +14 -0
- package/dist/tools/web-search/index.js.map +1 -0
- package/dist/{types-BtAaOV07.d.cts → tools-EiPWA9Ay.d.cts} +34 -367
- package/dist/{types-BtAaOV07.d.ts → tools-EiPWA9Ay.d.ts} +34 -367
- package/dist/types-B20VCJXL.d.cts +347 -0
- package/dist/types-B20VCJXL.d.ts +347 -0
- package/dist/types-CKA6U74u.d.cts +441 -0
- package/dist/types-DG2ya08y.d.cts +367 -0
- package/dist/types-DG2ya08y.d.ts +367 -0
- package/dist/types-ZguuKEs_.d.cts +127 -0
- package/dist/types-ZguuKEs_.d.ts +127 -0
- package/dist/types-iBkPICvQ.d.ts +441 -0
- package/dist/ui/index.cjs +1069 -146
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +410 -4
- package/dist/ui/index.d.ts +410 -4
- package/dist/ui/index.js +1001 -94
- package/dist/ui/index.js.map +1 -1
- package/package.json +53 -2
- package/dist/chunk-4PRWNAXQ.cjs.map +0 -1
- package/dist/chunk-BLSI67J6.cjs.map +0 -1
- package/dist/chunk-CJ7UWN2Y.js.map +0 -1
- package/dist/chunk-JM7PB2LP.js.map +0 -1
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// src/core/tools/webSearch/providers/anthropic.ts
|
|
2
|
+
var ANTHROPIC_API_URL = "https://api.anthropic.com/v1/messages";
|
|
3
|
+
function validateAnthropicConfig(config) {
|
|
4
|
+
if (!config.apiKey) {
|
|
5
|
+
throw new Error(
|
|
6
|
+
"Anthropic API key is required for native web search. Pass apiKey or set ANTHROPIC_API_KEY environment variable."
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
async function searchAnthropic(params, config) {
|
|
11
|
+
validateAnthropicConfig(config);
|
|
12
|
+
const startTime = Date.now();
|
|
13
|
+
const apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY;
|
|
14
|
+
const webSearchTool = {
|
|
15
|
+
type: "web_search_20250305",
|
|
16
|
+
// Use stable version
|
|
17
|
+
name: "web_search",
|
|
18
|
+
max_uses: config.maxResults ?? 5
|
|
19
|
+
};
|
|
20
|
+
if (config.includeDomains?.length) {
|
|
21
|
+
webSearchTool.allowed_domains = config.includeDomains;
|
|
22
|
+
}
|
|
23
|
+
if (config.excludeDomains?.length) {
|
|
24
|
+
webSearchTool.blocked_domains = config.excludeDomains;
|
|
25
|
+
}
|
|
26
|
+
if (config.country) {
|
|
27
|
+
webSearchTool.user_location = {
|
|
28
|
+
type: "approximate",
|
|
29
|
+
country: config.country.toUpperCase()
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const response = await fetch(ANTHROPIC_API_URL, {
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: {
|
|
35
|
+
"Content-Type": "application/json",
|
|
36
|
+
"x-api-key": apiKey,
|
|
37
|
+
"anthropic-version": "2023-06-01"
|
|
38
|
+
},
|
|
39
|
+
body: JSON.stringify({
|
|
40
|
+
model: "claude-sonnet-4-20250514",
|
|
41
|
+
// Use Sonnet 4 for balance of speed/quality
|
|
42
|
+
max_tokens: 2048,
|
|
43
|
+
tools: [webSearchTool],
|
|
44
|
+
messages: [
|
|
45
|
+
{
|
|
46
|
+
role: "user",
|
|
47
|
+
content: params.query
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}),
|
|
51
|
+
signal: config.timeout ? AbortSignal.timeout(config.timeout) : void 0
|
|
52
|
+
});
|
|
53
|
+
if (!response.ok) {
|
|
54
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
55
|
+
console.error(
|
|
56
|
+
"[Anthropic Native Search] API error:",
|
|
57
|
+
response.status,
|
|
58
|
+
errorText
|
|
59
|
+
);
|
|
60
|
+
throw new Error(
|
|
61
|
+
`Anthropic Messages API error (${response.status}): ${errorText}`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
const data = await response.json();
|
|
65
|
+
const searchTime = Date.now() - startTime;
|
|
66
|
+
let outputText = "";
|
|
67
|
+
const sources = [];
|
|
68
|
+
const searchResults = [];
|
|
69
|
+
if (data.content && Array.isArray(data.content)) {
|
|
70
|
+
for (const block of data.content) {
|
|
71
|
+
if (block.type === "text" && block.text) {
|
|
72
|
+
outputText += block.text;
|
|
73
|
+
if (block.citations && Array.isArray(block.citations)) {
|
|
74
|
+
for (const citation of block.citations) {
|
|
75
|
+
if (citation.url && !sources.find((s) => s.url === citation.url)) {
|
|
76
|
+
sources.push({
|
|
77
|
+
url: citation.url,
|
|
78
|
+
title: citation.title || extractDomain(citation.url),
|
|
79
|
+
cited_text: citation.cited_text
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (block.type === "web_search_tool_result" && block.content) {
|
|
86
|
+
for (const result of block.content) {
|
|
87
|
+
if (result.type === "web_search_result" && result.url) {
|
|
88
|
+
searchResults.push({
|
|
89
|
+
url: result.url,
|
|
90
|
+
title: result.title || extractDomain(result.url),
|
|
91
|
+
page_age: result.page_age
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const finalSources = sources.length > 0 ? sources : searchResults;
|
|
99
|
+
return {
|
|
100
|
+
query: params.query,
|
|
101
|
+
answer: outputText,
|
|
102
|
+
results: finalSources.slice(0, params.maxResults ?? config.maxResults ?? 5).map((source, i) => ({
|
|
103
|
+
title: source.title,
|
|
104
|
+
url: source.url,
|
|
105
|
+
content: "cited_text" in source ? source.cited_text || "" : "",
|
|
106
|
+
score: 1 - i * 0.1,
|
|
107
|
+
domain: extractDomain(source.url)
|
|
108
|
+
})),
|
|
109
|
+
provider: "anthropic",
|
|
110
|
+
totalResults: finalSources.length,
|
|
111
|
+
searchTime
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function extractDomain(url) {
|
|
115
|
+
try {
|
|
116
|
+
return new URL(url).hostname.replace("www.", "");
|
|
117
|
+
} catch {
|
|
118
|
+
return url;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
var anthropicProvider = {
|
|
122
|
+
search: searchAnthropic,
|
|
123
|
+
validateConfig: validateAnthropicConfig
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export { anthropicProvider, searchAnthropic, validateAnthropicConfig };
|
|
127
|
+
//# sourceMappingURL=chunk-RQ74USYU.js.map
|
|
128
|
+
//# sourceMappingURL=chunk-RQ74USYU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/tools/webSearch/providers/anthropic.ts"],"names":[],"mappings":"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","file":"chunk-RQ74USYU.js","sourcesContent":["/**\n * Anthropic Web Search Provider\n *\n * Uses Anthropic's built-in web_search tool via the Messages API.\n * Returns reliable citations with cited_text, url, and title.\n *\n * @see https://docs.anthropic.com/en/docs/build-with-claude/tool-use/web-search-tool\n */\n\nimport type {\n WebSearchConfig,\n WebSearchParams,\n WebSearchResponse,\n WebSearchProviderInterface,\n} from \"../types\";\n\nconst ANTHROPIC_API_URL = \"https://api.anthropic.com/v1/messages\";\n\n/**\n * Validate Anthropic native search configuration\n */\nexport function validateAnthropicConfig(config: WebSearchConfig): void {\n if (!config.apiKey) {\n throw new Error(\n \"Anthropic API key is required for native web search. \" +\n \"Pass apiKey or set ANTHROPIC_API_KEY environment variable.\",\n );\n }\n}\n\n// Type definitions for Anthropic response\ninterface AnthropicWebSearchResult {\n type: \"web_search_result\";\n url: string;\n title: string;\n encrypted_content?: string;\n page_age?: string;\n}\n\ninterface AnthropicCitation {\n type: \"web_search_result_location\";\n url: string;\n title: string;\n encrypted_index?: string;\n cited_text?: string;\n}\n\ninterface AnthropicContentBlock {\n type: string;\n text?: string;\n tool_use_id?: string;\n content?: AnthropicWebSearchResult[];\n citations?: AnthropicCitation[];\n}\n\ninterface AnthropicMessagesResponse {\n id: string;\n content: AnthropicContentBlock[];\n usage?: {\n input_tokens: number;\n output_tokens: number;\n server_tool_use?: {\n web_search_requests?: number;\n };\n };\n}\n\n/**\n * Search using Anthropic's native web_search tool\n */\nexport async function searchAnthropic(\n params: WebSearchParams,\n config: WebSearchConfig,\n): Promise<WebSearchResponse> {\n validateAnthropicConfig(config);\n\n const startTime = Date.now();\n const apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY;\n\n // Build web search tool configuration\n const webSearchTool: Record<string, unknown> = {\n type: \"web_search_20250305\", // Use stable version\n name: \"web_search\",\n max_uses: config.maxResults ?? 5,\n };\n\n // Add domain filtering if provided\n if (config.includeDomains?.length) {\n webSearchTool.allowed_domains = config.includeDomains;\n }\n if (config.excludeDomains?.length) {\n webSearchTool.blocked_domains = config.excludeDomains;\n }\n\n // Add user location if country is set\n if (config.country) {\n webSearchTool.user_location = {\n type: \"approximate\",\n country: config.country.toUpperCase(),\n };\n }\n\n // Call Anthropic Messages API\n const response = await fetch(ANTHROPIC_API_URL, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": apiKey!,\n \"anthropic-version\": \"2023-06-01\",\n },\n body: JSON.stringify({\n model: \"claude-sonnet-4-20250514\", // Use Sonnet 4 for balance of speed/quality\n max_tokens: 2048,\n tools: [webSearchTool],\n messages: [\n {\n role: \"user\",\n content: params.query,\n },\n ],\n }),\n signal: config.timeout ? AbortSignal.timeout(config.timeout) : undefined,\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"Unknown error\");\n console.error(\n \"[Anthropic Native Search] API error:\",\n response.status,\n errorText,\n );\n throw new Error(\n `Anthropic Messages API error (${response.status}): ${errorText}`,\n );\n }\n\n const data: AnthropicMessagesResponse = await response.json();\n const searchTime = Date.now() - startTime;\n\n // Extract answer text and citations\n let outputText = \"\";\n const sources: Array<{ url: string; title: string; cited_text?: string }> =\n [];\n const searchResults: Array<{\n url: string;\n title: string;\n page_age?: string;\n }> = [];\n\n if (data.content && Array.isArray(data.content)) {\n for (const block of data.content) {\n // Extract text blocks\n if (block.type === \"text\" && block.text) {\n outputText += block.text;\n\n // Extract citations from text blocks\n if (block.citations && Array.isArray(block.citations)) {\n for (const citation of block.citations) {\n if (citation.url && !sources.find((s) => s.url === citation.url)) {\n sources.push({\n url: citation.url,\n title: citation.title || extractDomain(citation.url),\n cited_text: citation.cited_text,\n });\n }\n }\n }\n }\n\n // Extract search results from web_search_tool_result\n if (block.type === \"web_search_tool_result\" && block.content) {\n for (const result of block.content) {\n if (result.type === \"web_search_result\" && result.url) {\n searchResults.push({\n url: result.url,\n title: result.title || extractDomain(result.url),\n page_age: result.page_age,\n });\n }\n }\n }\n }\n }\n\n // Prefer citations (have cited_text) over raw search results\n const finalSources = sources.length > 0 ? sources : searchResults;\n\n return {\n query: params.query,\n answer: outputText,\n results: finalSources\n .slice(0, params.maxResults ?? config.maxResults ?? 5)\n .map((source, i) => ({\n title: source.title,\n url: source.url,\n content: \"cited_text\" in source ? source.cited_text || \"\" : \"\",\n score: 1 - i * 0.1,\n domain: extractDomain(source.url),\n })),\n provider: \"anthropic\",\n totalResults: finalSources.length,\n searchTime,\n };\n}\n\n/**\n * Extract domain from URL\n */\nfunction extractDomain(url: string): string {\n try {\n return new URL(url).hostname.replace(\"www.\", \"\");\n } catch {\n return url;\n }\n}\n\n/**\n * Anthropic native search provider implementation\n */\nexport const anthropicProvider: WebSearchProviderInterface = {\n search: searchAnthropic,\n validateConfig: validateAnthropicConfig,\n};\n"]}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkW74OTXXX_cjs = require('./chunk-W74OTXXX.cjs');
|
|
4
|
+
var chunkASV6JLYG_cjs = require('./chunk-ASV6JLYG.cjs');
|
|
5
|
+
|
|
6
|
+
// src/core/tools/builtin/webSearch.ts
|
|
7
|
+
var webSearchTool = chunkW74OTXXX_cjs.tool({
|
|
8
|
+
description: `Search the web for current information. Use this when the user asks about:
|
|
9
|
+
- Recent events, news, or current affairs
|
|
10
|
+
- Real-time data (prices, weather, stocks, sports scores)
|
|
11
|
+
- Information that might have changed after your training cutoff
|
|
12
|
+
- Facts that need verification with current sources
|
|
13
|
+
- Research topics that require up-to-date information`,
|
|
14
|
+
location: "server",
|
|
15
|
+
// Runs on server to protect API keys
|
|
16
|
+
title: (args) => `Searching for "${args.query}"`,
|
|
17
|
+
executingTitle: (args) => `Searching the web for "${args.query}"...`,
|
|
18
|
+
completedTitle: (args) => `Found results for "${args.query}"`,
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: {
|
|
22
|
+
query: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "The search query to find relevant information"
|
|
25
|
+
},
|
|
26
|
+
maxResults: {
|
|
27
|
+
type: "number",
|
|
28
|
+
description: "Maximum number of results to return (default: 5, max: 10)",
|
|
29
|
+
minimum: 1,
|
|
30
|
+
maximum: 10
|
|
31
|
+
},
|
|
32
|
+
searchDepth: {
|
|
33
|
+
type: "string",
|
|
34
|
+
enum: ["basic", "advanced"],
|
|
35
|
+
description: "Search depth - 'advanced' provides more thorough results but may be slower"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
required: ["query"]
|
|
39
|
+
},
|
|
40
|
+
needsApproval: false,
|
|
41
|
+
// No user data exposed, just searching
|
|
42
|
+
// Control what AI sees from results
|
|
43
|
+
aiResponseMode: "full",
|
|
44
|
+
aiContext: (result, args) => {
|
|
45
|
+
if (!result.success) return `Search failed: ${result.error}`;
|
|
46
|
+
const data = result.data;
|
|
47
|
+
return chunkASV6JLYG_cjs.formatSearchResultsForAI(data);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
function createWebSearchTool(config) {
|
|
51
|
+
return {
|
|
52
|
+
name: "web_search",
|
|
53
|
+
...webSearchTool,
|
|
54
|
+
handler: async (params) => {
|
|
55
|
+
try {
|
|
56
|
+
const response = await chunkASV6JLYG_cjs.executeWebSearch(
|
|
57
|
+
{
|
|
58
|
+
query: params.query,
|
|
59
|
+
maxResults: params.maxResults ?? config.maxResults ?? 5,
|
|
60
|
+
searchDepth: params.searchDepth ?? config.searchDepth ?? "basic"
|
|
61
|
+
},
|
|
62
|
+
config
|
|
63
|
+
);
|
|
64
|
+
const aiContext = chunkASV6JLYG_cjs.formatSearchResultsForAI(response);
|
|
65
|
+
return {
|
|
66
|
+
success: true,
|
|
67
|
+
message: chunkASV6JLYG_cjs.summarizeSearchResults(response),
|
|
68
|
+
data: response,
|
|
69
|
+
_aiContext: aiContext
|
|
70
|
+
};
|
|
71
|
+
} catch (error) {
|
|
72
|
+
const errorMessage = error instanceof Error ? error.message : "Web search failed";
|
|
73
|
+
return chunkW74OTXXX_cjs.failure(errorMessage);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
exports.createWebSearchTool = createWebSearchTool;
|
|
80
|
+
exports.webSearchTool = webSearchTool;
|
|
81
|
+
//# sourceMappingURL=chunk-TX7CGITI.cjs.map
|
|
82
|
+
//# sourceMappingURL=chunk-TX7CGITI.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/tools/builtin/webSearch.ts"],"names":["tool","formatSearchResultsForAI","executeWebSearch","summarizeSearchResults","failure"],"mappings":";;;;;;AAoDO,IAAM,gBAAgBA,sBAAA,CAAsB;AAAA,EACjD,WAAA,EAAa,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qDAAA,CAAA;AAAA,EAOb,QAAA,EAAU,QAAA;AAAA;AAAA,EAEV,KAAA,EAAO,CAAC,IAAA,KAAS,CAAA,eAAA,EAAkB,KAAK,KAAK,CAAA,CAAA,CAAA;AAAA,EAC7C,cAAA,EAAgB,CAAC,IAAA,KAAS,CAAA,uBAAA,EAA0B,KAAK,KAAK,CAAA,IAAA,CAAA;AAAA,EAC9D,cAAA,EAAgB,CAAC,IAAA,KAAS,CAAA,mBAAA,EAAsB,KAAK,KAAK,CAAA,CAAA,CAAA;AAAA,EAE1D,WAAA,EAAa;AAAA,IACX,IAAA,EAAM,QAAA;AAAA,IACN,UAAA,EAAY;AAAA,MACV,KAAA,EAAO;AAAA,QACL,IAAA,EAAM,QAAA;AAAA,QACN,WAAA,EAAa;AAAA,OACf;AAAA,MACA,UAAA,EAAY;AAAA,QACV,IAAA,EAAM,QAAA;AAAA,QACN,WAAA,EACE,2DAAA;AAAA,QACF,OAAA,EAAS,CAAA;AAAA,QACT,OAAA,EAAS;AAAA,OACX;AAAA,MACA,WAAA,EAAa;AAAA,QACX,IAAA,EAAM,QAAA;AAAA,QACN,IAAA,EAAM,CAAC,OAAA,EAAS,UAAU,CAAA;AAAA,QAC1B,WAAA,EACE;AAAA;AACJ,KACF;AAAA,IACA,QAAA,EAAU,CAAC,OAAO;AAAA,GACpB;AAAA,EAEA,aAAA,EAAe,KAAA;AAAA;AAAA;AAAA,EAGf,cAAA,EAAgB,MAAA;AAAA,EAChB,SAAA,EAAW,CAAC,MAAA,EAAQ,IAAA,KAAS;AAC3B,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,CAAA,eAAA,EAAkB,OAAO,KAAK,CAAA,CAAA;AAC1D,IAAA,MAAM,OAAO,MAAA,CAAO,IAAA;AACpB,IAAA,OAAOC,2CAAyB,IAAI,CAAA;AAAA,EACtC;AACF,CAAC;AAoEM,SAAS,oBACd,MAAA,EACiC;AACjC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,YAAA;AAAA,IACN,GAAG,aAAA;AAAA,IACH,OAAA,EAAS,OAAO,MAAA,KAA4B;AAC1C,MAAA,IAAI;AACF,QAAA,MAAM,WAAW,MAAMC,kCAAA;AAAA,UACrB;AAAA,YACE,OAAO,MAAA,CAAO,KAAA;AAAA,YACd,UAAA,EAAY,MAAA,CAAO,UAAA,IAAc,MAAA,CAAO,UAAA,IAAc,CAAA;AAAA,YACtD,WAAA,EAAa,MAAA,CAAO,WAAA,IAAe,MAAA,CAAO,WAAA,IAAe;AAAA,WAC3D;AAAA,UACA;AAAA,SACF;AAGA,QAAA,MAAM,SAAA,GAAYD,2CAAyB,QAAQ,CAAA;AAEnD,QAAA,OAAO;AAAA,UACL,OAAA,EAAS,IAAA;AAAA,UACT,OAAA,EAASE,yCAAuB,QAAQ,CAAA;AAAA,UACxC,IAAA,EAAM,QAAA;AAAA,UACN,UAAA,EAAY;AAAA,SACd;AAAA,MACF,SAAS,KAAA,EAAO;AACd,QAAA,MAAM,YAAA,GACJ,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,mBAAA;AAC3C,QAAA,OAAOC,0BAAQ,YAAY,CAAA;AAAA,MAC7B;AAAA,IACF;AAAA,GACF;AACF","file":"chunk-TX7CGITI.cjs","sourcesContent":["/**\n * Built-in Web Search Tool\n *\n * A pre-configured tool for searching the web with multiple provider support.\n * Runs on the server to protect API keys.\n *\n * Supports tree-shaking - import providers directly for smaller bundles.\n *\n * @example\n * ```typescript\n * // Option 1: String provider (lazy loaded at runtime)\n * import { createWebSearchTool } from '@yourgpt/copilot-sdk';\n * const webSearch = createWebSearchTool({\n * provider: 'tavily',\n * apiKey: process.env.TAVILY_API_KEY,\n * });\n *\n * // Option 2: Direct provider import (best for tree-shaking)\n * import { createWebSearchTool, tavilyProvider } from '@yourgpt/copilot-sdk';\n * const webSearch = createWebSearchTool({\n * provider: tavilyProvider,\n * apiKey: process.env.TAVILY_API_KEY,\n * });\n *\n * // Add to your runtime\n * const runtime = createRuntime({\n * tools: [webSearch],\n * });\n * ```\n */\n\nimport { tool, success, failure } from \"../../types/tools\";\nimport type { ToolDefinition } from \"../../types/tools\";\nimport {\n executeWebSearch,\n formatSearchResultsForAI,\n summarizeSearchResults,\n type WebSearchConfigExtended,\n} from \"../webSearch\";\nimport type {\n WebSearchConfig,\n WebSearchParams,\n WebSearchResponse,\n WebSearchProviderInterface,\n} from \"../webSearch/types\";\n\n/**\n * Base web search tool definition\n *\n * This is the core tool definition. Use `createWebSearchTool()` to create\n * a configured instance with your provider settings.\n */\nexport const webSearchTool = tool<WebSearchParams>({\n description: `Search the web for current information. Use this when the user asks about:\n- Recent events, news, or current affairs\n- Real-time data (prices, weather, stocks, sports scores)\n- Information that might have changed after your training cutoff\n- Facts that need verification with current sources\n- Research topics that require up-to-date information`,\n\n location: \"server\", // Runs on server to protect API keys\n\n title: (args) => `Searching for \"${args.query}\"`,\n executingTitle: (args) => `Searching the web for \"${args.query}\"...`,\n completedTitle: (args) => `Found results for \"${args.query}\"`,\n\n inputSchema: {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description: \"The search query to find relevant information\",\n },\n maxResults: {\n type: \"number\",\n description:\n \"Maximum number of results to return (default: 5, max: 10)\",\n minimum: 1,\n maximum: 10,\n },\n searchDepth: {\n type: \"string\",\n enum: [\"basic\", \"advanced\"],\n description:\n \"Search depth - 'advanced' provides more thorough results but may be slower\",\n },\n },\n required: [\"query\"],\n },\n\n needsApproval: false, // No user data exposed, just searching\n\n // Control what AI sees from results\n aiResponseMode: \"full\",\n aiContext: (result, args) => {\n if (!result.success) return `Search failed: ${result.error}`;\n const data = result.data as WebSearchResponse;\n return formatSearchResultsForAI(data);\n },\n});\n\n/**\n * Create a configured web search tool\n *\n * Supports both string provider names (lazy loaded) and direct provider imports (tree-shakeable).\n *\n * @param config - Web search configuration including provider and API key\n * @returns A configured tool definition ready to use\n *\n * @example\n * ```typescript\n * // ===== BEST FOR TREE-SHAKING: Direct provider import =====\n * import { createWebSearchTool, openaiProvider } from '@yourgpt/copilot-sdk/core';\n *\n * const webSearch = createWebSearchTool({\n * provider: openaiProvider, // Only this provider in bundle\n * apiKey: process.env.OPENAI_API_KEY,\n * });\n *\n * // ===== STRING PROVIDERS (Lazy loaded at runtime) =====\n *\n * // OpenAI (uses your OpenAI API key)\n * const webSearch = createWebSearchTool({\n * provider: 'openai',\n * apiKey: process.env.OPENAI_API_KEY,\n * });\n *\n * // Google (uses your Google/Gemini API key)\n * const webSearch = createWebSearchTool({\n * provider: 'google',\n * apiKey: process.env.GOOGLE_API_KEY,\n * });\n *\n * // Tavily (AI-optimized search with answer generation)\n * const webSearch = createWebSearchTool({\n * provider: 'tavily',\n * apiKey: process.env.TAVILY_API_KEY,\n * includeAnswer: true,\n * maxResults: 5,\n * });\n *\n * // Serper (Google results)\n * const webSearch = createWebSearchTool({\n * provider: 'serper',\n * apiKey: process.env.SERPER_API_KEY,\n * });\n *\n * // Brave Search (privacy-focused)\n * const webSearch = createWebSearchTool({\n * provider: 'brave',\n * apiKey: process.env.BRAVE_API_KEY,\n * });\n *\n * // Self-hosted SearXNG (no API key needed)\n * const webSearch = createWebSearchTool({\n * provider: 'searxng',\n * baseUrl: 'https://your-searxng-instance.com',\n * });\n *\n * // Exa (AI-optimized semantic search)\n * const webSearch = createWebSearchTool({\n * provider: 'exa',\n * apiKey: process.env.EXA_API_KEY,\n * searchDepth: 'advanced',\n * });\n * ```\n */\nexport function createWebSearchTool(\n config: WebSearchConfigExtended,\n): ToolDefinition<WebSearchParams> {\n return {\n name: \"web_search\",\n ...webSearchTool,\n handler: async (params: WebSearchParams) => {\n try {\n const response = await executeWebSearch(\n {\n query: params.query,\n maxResults: params.maxResults ?? config.maxResults ?? 5,\n searchDepth: params.searchDepth ?? config.searchDepth ?? \"basic\",\n },\n config,\n );\n\n // Build the AI context string\n const aiContext = formatSearchResultsForAI(response);\n\n return {\n success: true,\n message: summarizeSearchResults(response),\n data: response,\n _aiContext: aiContext,\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : \"Web search failed\";\n return failure(errorMessage);\n }\n },\n };\n}\n\n/**\n * Utility types for web search tool configuration\n */\nexport type {\n WebSearchConfig,\n WebSearchParams,\n WebSearchResponse,\n WebSearchProviderInterface,\n};\nexport type { WebSearchConfigExtended };\n"]}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/core/tools/webSearch/providers/anthropic.ts
|
|
4
|
+
var ANTHROPIC_API_URL = "https://api.anthropic.com/v1/messages";
|
|
5
|
+
function validateAnthropicConfig(config) {
|
|
6
|
+
if (!config.apiKey) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
"Anthropic API key is required for native web search. Pass apiKey or set ANTHROPIC_API_KEY environment variable."
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
async function searchAnthropic(params, config) {
|
|
13
|
+
validateAnthropicConfig(config);
|
|
14
|
+
const startTime = Date.now();
|
|
15
|
+
const apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY;
|
|
16
|
+
const webSearchTool = {
|
|
17
|
+
type: "web_search_20250305",
|
|
18
|
+
// Use stable version
|
|
19
|
+
name: "web_search",
|
|
20
|
+
max_uses: config.maxResults ?? 5
|
|
21
|
+
};
|
|
22
|
+
if (config.includeDomains?.length) {
|
|
23
|
+
webSearchTool.allowed_domains = config.includeDomains;
|
|
24
|
+
}
|
|
25
|
+
if (config.excludeDomains?.length) {
|
|
26
|
+
webSearchTool.blocked_domains = config.excludeDomains;
|
|
27
|
+
}
|
|
28
|
+
if (config.country) {
|
|
29
|
+
webSearchTool.user_location = {
|
|
30
|
+
type: "approximate",
|
|
31
|
+
country: config.country.toUpperCase()
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const response = await fetch(ANTHROPIC_API_URL, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: {
|
|
37
|
+
"Content-Type": "application/json",
|
|
38
|
+
"x-api-key": apiKey,
|
|
39
|
+
"anthropic-version": "2023-06-01"
|
|
40
|
+
},
|
|
41
|
+
body: JSON.stringify({
|
|
42
|
+
model: "claude-sonnet-4-20250514",
|
|
43
|
+
// Use Sonnet 4 for balance of speed/quality
|
|
44
|
+
max_tokens: 2048,
|
|
45
|
+
tools: [webSearchTool],
|
|
46
|
+
messages: [
|
|
47
|
+
{
|
|
48
|
+
role: "user",
|
|
49
|
+
content: params.query
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}),
|
|
53
|
+
signal: config.timeout ? AbortSignal.timeout(config.timeout) : void 0
|
|
54
|
+
});
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
57
|
+
console.error(
|
|
58
|
+
"[Anthropic Native Search] API error:",
|
|
59
|
+
response.status,
|
|
60
|
+
errorText
|
|
61
|
+
);
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Anthropic Messages API error (${response.status}): ${errorText}`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
const data = await response.json();
|
|
67
|
+
const searchTime = Date.now() - startTime;
|
|
68
|
+
let outputText = "";
|
|
69
|
+
const sources = [];
|
|
70
|
+
const searchResults = [];
|
|
71
|
+
if (data.content && Array.isArray(data.content)) {
|
|
72
|
+
for (const block of data.content) {
|
|
73
|
+
if (block.type === "text" && block.text) {
|
|
74
|
+
outputText += block.text;
|
|
75
|
+
if (block.citations && Array.isArray(block.citations)) {
|
|
76
|
+
for (const citation of block.citations) {
|
|
77
|
+
if (citation.url && !sources.find((s) => s.url === citation.url)) {
|
|
78
|
+
sources.push({
|
|
79
|
+
url: citation.url,
|
|
80
|
+
title: citation.title || extractDomain(citation.url),
|
|
81
|
+
cited_text: citation.cited_text
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (block.type === "web_search_tool_result" && block.content) {
|
|
88
|
+
for (const result of block.content) {
|
|
89
|
+
if (result.type === "web_search_result" && result.url) {
|
|
90
|
+
searchResults.push({
|
|
91
|
+
url: result.url,
|
|
92
|
+
title: result.title || extractDomain(result.url),
|
|
93
|
+
page_age: result.page_age
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const finalSources = sources.length > 0 ? sources : searchResults;
|
|
101
|
+
return {
|
|
102
|
+
query: params.query,
|
|
103
|
+
answer: outputText,
|
|
104
|
+
results: finalSources.slice(0, params.maxResults ?? config.maxResults ?? 5).map((source, i) => ({
|
|
105
|
+
title: source.title,
|
|
106
|
+
url: source.url,
|
|
107
|
+
content: "cited_text" in source ? source.cited_text || "" : "",
|
|
108
|
+
score: 1 - i * 0.1,
|
|
109
|
+
domain: extractDomain(source.url)
|
|
110
|
+
})),
|
|
111
|
+
provider: "anthropic",
|
|
112
|
+
totalResults: finalSources.length,
|
|
113
|
+
searchTime
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function extractDomain(url) {
|
|
117
|
+
try {
|
|
118
|
+
return new URL(url).hostname.replace("www.", "");
|
|
119
|
+
} catch {
|
|
120
|
+
return url;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
var anthropicProvider = {
|
|
124
|
+
search: searchAnthropic,
|
|
125
|
+
validateConfig: validateAnthropicConfig
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
exports.anthropicProvider = anthropicProvider;
|
|
129
|
+
exports.searchAnthropic = searchAnthropic;
|
|
130
|
+
exports.validateAnthropicConfig = validateAnthropicConfig;
|
|
131
|
+
//# sourceMappingURL=chunk-TXLIY7GF.cjs.map
|
|
132
|
+
//# sourceMappingURL=chunk-TXLIY7GF.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/tools/webSearch/providers/anthropic.ts"],"names":[],"mappings":"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","file":"chunk-TXLIY7GF.cjs","sourcesContent":["/**\n * Anthropic Web Search Provider\n *\n * Uses Anthropic's built-in web_search tool via the Messages API.\n * Returns reliable citations with cited_text, url, and title.\n *\n * @see https://docs.anthropic.com/en/docs/build-with-claude/tool-use/web-search-tool\n */\n\nimport type {\n WebSearchConfig,\n WebSearchParams,\n WebSearchResponse,\n WebSearchProviderInterface,\n} from \"../types\";\n\nconst ANTHROPIC_API_URL = \"https://api.anthropic.com/v1/messages\";\n\n/**\n * Validate Anthropic native search configuration\n */\nexport function validateAnthropicConfig(config: WebSearchConfig): void {\n if (!config.apiKey) {\n throw new Error(\n \"Anthropic API key is required for native web search. \" +\n \"Pass apiKey or set ANTHROPIC_API_KEY environment variable.\",\n );\n }\n}\n\n// Type definitions for Anthropic response\ninterface AnthropicWebSearchResult {\n type: \"web_search_result\";\n url: string;\n title: string;\n encrypted_content?: string;\n page_age?: string;\n}\n\ninterface AnthropicCitation {\n type: \"web_search_result_location\";\n url: string;\n title: string;\n encrypted_index?: string;\n cited_text?: string;\n}\n\ninterface AnthropicContentBlock {\n type: string;\n text?: string;\n tool_use_id?: string;\n content?: AnthropicWebSearchResult[];\n citations?: AnthropicCitation[];\n}\n\ninterface AnthropicMessagesResponse {\n id: string;\n content: AnthropicContentBlock[];\n usage?: {\n input_tokens: number;\n output_tokens: number;\n server_tool_use?: {\n web_search_requests?: number;\n };\n };\n}\n\n/**\n * Search using Anthropic's native web_search tool\n */\nexport async function searchAnthropic(\n params: WebSearchParams,\n config: WebSearchConfig,\n): Promise<WebSearchResponse> {\n validateAnthropicConfig(config);\n\n const startTime = Date.now();\n const apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY;\n\n // Build web search tool configuration\n const webSearchTool: Record<string, unknown> = {\n type: \"web_search_20250305\", // Use stable version\n name: \"web_search\",\n max_uses: config.maxResults ?? 5,\n };\n\n // Add domain filtering if provided\n if (config.includeDomains?.length) {\n webSearchTool.allowed_domains = config.includeDomains;\n }\n if (config.excludeDomains?.length) {\n webSearchTool.blocked_domains = config.excludeDomains;\n }\n\n // Add user location if country is set\n if (config.country) {\n webSearchTool.user_location = {\n type: \"approximate\",\n country: config.country.toUpperCase(),\n };\n }\n\n // Call Anthropic Messages API\n const response = await fetch(ANTHROPIC_API_URL, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": apiKey!,\n \"anthropic-version\": \"2023-06-01\",\n },\n body: JSON.stringify({\n model: \"claude-sonnet-4-20250514\", // Use Sonnet 4 for balance of speed/quality\n max_tokens: 2048,\n tools: [webSearchTool],\n messages: [\n {\n role: \"user\",\n content: params.query,\n },\n ],\n }),\n signal: config.timeout ? AbortSignal.timeout(config.timeout) : undefined,\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"Unknown error\");\n console.error(\n \"[Anthropic Native Search] API error:\",\n response.status,\n errorText,\n );\n throw new Error(\n `Anthropic Messages API error (${response.status}): ${errorText}`,\n );\n }\n\n const data: AnthropicMessagesResponse = await response.json();\n const searchTime = Date.now() - startTime;\n\n // Extract answer text and citations\n let outputText = \"\";\n const sources: Array<{ url: string; title: string; cited_text?: string }> =\n [];\n const searchResults: Array<{\n url: string;\n title: string;\n page_age?: string;\n }> = [];\n\n if (data.content && Array.isArray(data.content)) {\n for (const block of data.content) {\n // Extract text blocks\n if (block.type === \"text\" && block.text) {\n outputText += block.text;\n\n // Extract citations from text blocks\n if (block.citations && Array.isArray(block.citations)) {\n for (const citation of block.citations) {\n if (citation.url && !sources.find((s) => s.url === citation.url)) {\n sources.push({\n url: citation.url,\n title: citation.title || extractDomain(citation.url),\n cited_text: citation.cited_text,\n });\n }\n }\n }\n }\n\n // Extract search results from web_search_tool_result\n if (block.type === \"web_search_tool_result\" && block.content) {\n for (const result of block.content) {\n if (result.type === \"web_search_result\" && result.url) {\n searchResults.push({\n url: result.url,\n title: result.title || extractDomain(result.url),\n page_age: result.page_age,\n });\n }\n }\n }\n }\n }\n\n // Prefer citations (have cited_text) over raw search results\n const finalSources = sources.length > 0 ? sources : searchResults;\n\n return {\n query: params.query,\n answer: outputText,\n results: finalSources\n .slice(0, params.maxResults ?? config.maxResults ?? 5)\n .map((source, i) => ({\n title: source.title,\n url: source.url,\n content: \"cited_text\" in source ? source.cited_text || \"\" : \"\",\n score: 1 - i * 0.1,\n domain: extractDomain(source.url),\n })),\n provider: \"anthropic\",\n totalResults: finalSources.length,\n searchTime,\n };\n}\n\n/**\n * Extract domain from URL\n */\nfunction extractDomain(url: string): string {\n try {\n return new URL(url).hostname.replace(\"www.\", \"\");\n } catch {\n return url;\n }\n}\n\n/**\n * Anthropic native search provider implementation\n */\nexport const anthropicProvider: WebSearchProviderInterface = {\n search: searchAnthropic,\n validateConfig: validateAnthropicConfig,\n};\n"]}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// src/core/tools/webSearch/providers/openai.ts
|
|
2
|
+
function validateOpenAIConfig(config) {
|
|
3
|
+
if (!config.apiKey) {
|
|
4
|
+
throw new Error(
|
|
5
|
+
"OpenAI API key is required for native web search. Pass apiKey or set OPENAI_API_KEY environment variable."
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
async function searchOpenAI(params, config) {
|
|
10
|
+
validateOpenAIConfig(config);
|
|
11
|
+
const startTime = Date.now();
|
|
12
|
+
const apiKey = config.apiKey || process.env.OPENAI_API_KEY;
|
|
13
|
+
const tools = [
|
|
14
|
+
{
|
|
15
|
+
type: "web_search",
|
|
16
|
+
// Domain filtering if provided
|
|
17
|
+
...config.includeDomains?.length && {
|
|
18
|
+
filters: {
|
|
19
|
+
domains: config.includeDomains
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
];
|
|
24
|
+
const response = await fetch("https://api.openai.com/v1/responses", {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: {
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
Authorization: `Bearer ${apiKey}`
|
|
29
|
+
},
|
|
30
|
+
body: JSON.stringify({
|
|
31
|
+
model: "gpt-4o",
|
|
32
|
+
// Use GPT-4o for web search
|
|
33
|
+
tools,
|
|
34
|
+
input: params.query
|
|
35
|
+
}),
|
|
36
|
+
signal: config.timeout ? AbortSignal.timeout(config.timeout) : void 0
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
40
|
+
console.error(
|
|
41
|
+
"[OpenAI Native Search] API error:",
|
|
42
|
+
response.status,
|
|
43
|
+
errorText
|
|
44
|
+
);
|
|
45
|
+
throw new Error(
|
|
46
|
+
`OpenAI Responses API error (${response.status}): ${errorText}`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
const data = await response.json();
|
|
50
|
+
const searchTime = Date.now() - startTime;
|
|
51
|
+
let outputText = "";
|
|
52
|
+
const sources = [];
|
|
53
|
+
if (data.output && Array.isArray(data.output)) {
|
|
54
|
+
for (const item of data.output) {
|
|
55
|
+
if (item.type === "message" && item.content) {
|
|
56
|
+
for (const contentPart of item.content) {
|
|
57
|
+
if (contentPart.type === "output_text" && contentPart.text) {
|
|
58
|
+
outputText = contentPart.text;
|
|
59
|
+
}
|
|
60
|
+
if (contentPart.annotations && Array.isArray(contentPart.annotations)) {
|
|
61
|
+
for (const annotation of contentPart.annotations) {
|
|
62
|
+
if (annotation.type === "url_citation" && annotation.url) {
|
|
63
|
+
if (!sources.find((s) => s.url === annotation.url)) {
|
|
64
|
+
sources.push({
|
|
65
|
+
url: annotation.url,
|
|
66
|
+
title: annotation.title || extractDomain(annotation.url)
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
query: params.query,
|
|
78
|
+
answer: outputText,
|
|
79
|
+
results: sources.slice(0, params.maxResults ?? config.maxResults ?? 5).map((source, i) => ({
|
|
80
|
+
title: source.title,
|
|
81
|
+
url: source.url,
|
|
82
|
+
content: "",
|
|
83
|
+
// OpenAI returns answer with inline citations, not separate snippets
|
|
84
|
+
score: 1 - i * 0.1,
|
|
85
|
+
domain: extractDomain(source.url)
|
|
86
|
+
})),
|
|
87
|
+
provider: "openai",
|
|
88
|
+
totalResults: sources.length,
|
|
89
|
+
searchTime
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function extractDomain(url) {
|
|
93
|
+
try {
|
|
94
|
+
return new URL(url).hostname.replace("www.", "");
|
|
95
|
+
} catch {
|
|
96
|
+
return url;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
var openaiProvider = {
|
|
100
|
+
search: searchOpenAI,
|
|
101
|
+
validateConfig: validateOpenAIConfig
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export { openaiProvider, searchOpenAI, validateOpenAIConfig };
|
|
105
|
+
//# sourceMappingURL=chunk-VD74IPKB.js.map
|
|
106
|
+
//# sourceMappingURL=chunk-VD74IPKB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/tools/webSearch/providers/openai.ts"],"names":[],"mappings":"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","file":"chunk-VD74IPKB.js","sourcesContent":["/**\n * OpenAI Web Search Provider\n *\n * Uses OpenAI's built-in web_search tool via the Responses API.\n * No third-party API key required - uses your OpenAI API key.\n *\n * @see https://platform.openai.com/docs/guides/tools-web-search\n */\n\nimport type {\n WebSearchConfig,\n WebSearchParams,\n WebSearchResponse,\n WebSearchProviderInterface,\n} from \"../types\";\n\n/**\n * Validate OpenAI native search configuration\n */\nexport function validateOpenAIConfig(config: WebSearchConfig): void {\n if (!config.apiKey) {\n throw new Error(\n \"OpenAI API key is required for native web search. \" +\n \"Pass apiKey or set OPENAI_API_KEY environment variable.\",\n );\n }\n}\n\n/**\n * Search using OpenAI's native web_search tool (Responses API)\n */\nexport async function searchOpenAI(\n params: WebSearchParams,\n config: WebSearchConfig,\n): Promise<WebSearchResponse> {\n validateOpenAIConfig(config);\n\n const startTime = Date.now();\n const apiKey = config.apiKey || process.env.OPENAI_API_KEY;\n\n // Build tools array with web_search\n const tools: Array<Record<string, unknown>> = [\n {\n type: \"web_search\",\n // Domain filtering if provided\n ...(config.includeDomains?.length && {\n filters: {\n domains: config.includeDomains,\n },\n }),\n },\n ];\n\n // Call OpenAI Responses API\n const response = await fetch(\"https://api.openai.com/v1/responses\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model: \"gpt-4o\", // Use GPT-4o for web search\n tools,\n input: params.query,\n }),\n signal: config.timeout ? AbortSignal.timeout(config.timeout) : undefined,\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"Unknown error\");\n console.error(\n \"[OpenAI Native Search] API error:\",\n response.status,\n errorText,\n );\n throw new Error(\n `OpenAI Responses API error (${response.status}): ${errorText}`,\n );\n }\n\n const data = await response.json();\n const searchTime = Date.now() - startTime;\n\n // Extract answer text and annotations from the message output\n let outputText = \"\";\n const sources: Array<{ url: string; title: string }> = [];\n\n if (data.output && Array.isArray(data.output)) {\n for (const item of data.output) {\n // Find the message with content\n if (item.type === \"message\" && item.content) {\n for (const contentPart of item.content) {\n // Extract text\n if (contentPart.type === \"output_text\" && contentPart.text) {\n outputText = contentPart.text;\n }\n\n // Extract sources from annotations (url_citation)\n if (\n contentPart.annotations &&\n Array.isArray(contentPart.annotations)\n ) {\n for (const annotation of contentPart.annotations) {\n if (annotation.type === \"url_citation\" && annotation.url) {\n // Avoid duplicates\n if (!sources.find((s) => s.url === annotation.url)) {\n sources.push({\n url: annotation.url,\n title: annotation.title || extractDomain(annotation.url),\n });\n }\n }\n }\n }\n }\n }\n }\n }\n\n return {\n query: params.query,\n answer: outputText,\n results: sources\n .slice(0, params.maxResults ?? config.maxResults ?? 5)\n .map((source, i) => ({\n title: source.title,\n url: source.url,\n content: \"\", // OpenAI returns answer with inline citations, not separate snippets\n score: 1 - i * 0.1,\n domain: extractDomain(source.url),\n })),\n provider: \"openai\",\n totalResults: sources.length,\n searchTime,\n };\n}\n\n/**\n * Extract domain from URL\n */\nfunction extractDomain(url: string): string {\n try {\n return new URL(url).hostname.replace(\"www.\", \"\");\n } catch {\n return url;\n }\n}\n\n/**\n * OpenAI native search provider implementation\n */\nexport const openaiProvider: WebSearchProviderInterface = {\n search: searchOpenAI,\n validateConfig: validateOpenAIConfig,\n};\n"]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/core/tools/webSearch/providers/brave.ts
|
|
4
|
+
var BRAVE_API_URL = "https://api.search.brave.com/res/v1/web/search";
|
|
5
|
+
function validateBraveConfig(config) {
|
|
6
|
+
if (!config.apiKey) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
"Brave Search API key is required. Get one at https://brave.com/search/api/"
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
async function searchBrave(params, config) {
|
|
13
|
+
validateBraveConfig(config);
|
|
14
|
+
const startTime = Date.now();
|
|
15
|
+
const searchParams = new URLSearchParams({
|
|
16
|
+
q: params.query,
|
|
17
|
+
count: String(params.maxResults ?? config.maxResults ?? 5)
|
|
18
|
+
});
|
|
19
|
+
if (config.country) {
|
|
20
|
+
searchParams.set("country", config.country);
|
|
21
|
+
}
|
|
22
|
+
if (config.language) {
|
|
23
|
+
searchParams.set("search_lang", config.language);
|
|
24
|
+
}
|
|
25
|
+
const url = `${BRAVE_API_URL}?${searchParams.toString()}`;
|
|
26
|
+
const response = await fetch(url, {
|
|
27
|
+
method: "GET",
|
|
28
|
+
headers: {
|
|
29
|
+
Accept: "application/json",
|
|
30
|
+
"Accept-Encoding": "gzip",
|
|
31
|
+
"X-Subscription-Token": config.apiKey
|
|
32
|
+
},
|
|
33
|
+
signal: config.timeout ? AbortSignal.timeout(config.timeout) : void 0
|
|
34
|
+
});
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Brave Search API error (${response.status}): ${errorText}`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
const data = await response.json();
|
|
42
|
+
const searchTime = Date.now() - startTime;
|
|
43
|
+
let results = data.web?.results || [];
|
|
44
|
+
if (config.includeDomains?.length) {
|
|
45
|
+
results = results.filter(
|
|
46
|
+
(r) => config.includeDomains.some((domain) => r.url.includes(domain))
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
if (config.excludeDomains?.length) {
|
|
50
|
+
results = results.filter(
|
|
51
|
+
(r) => !config.excludeDomains.some((domain) => r.url.includes(domain))
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
const answer = data.infobox?.description;
|
|
55
|
+
return {
|
|
56
|
+
query: params.query,
|
|
57
|
+
answer,
|
|
58
|
+
results: results.map((result) => ({
|
|
59
|
+
title: result.title,
|
|
60
|
+
url: result.url,
|
|
61
|
+
content: result.description,
|
|
62
|
+
publishedDate: result.page_age,
|
|
63
|
+
image: result.thumbnail?.src,
|
|
64
|
+
domain: extractDomain(result.url)
|
|
65
|
+
})),
|
|
66
|
+
provider: "brave",
|
|
67
|
+
totalResults: results.length,
|
|
68
|
+
searchTime
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function extractDomain(url) {
|
|
72
|
+
try {
|
|
73
|
+
return new URL(url).hostname;
|
|
74
|
+
} catch {
|
|
75
|
+
return url;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
var braveProvider = {
|
|
79
|
+
search: searchBrave,
|
|
80
|
+
validateConfig: validateBraveConfig
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
exports.braveProvider = braveProvider;
|
|
84
|
+
exports.searchBrave = searchBrave;
|
|
85
|
+
exports.validateBraveConfig = validateBraveConfig;
|
|
86
|
+
//# sourceMappingURL=chunk-W73FBYIH.cjs.map
|
|
87
|
+
//# sourceMappingURL=chunk-W73FBYIH.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/tools/webSearch/providers/brave.ts"],"names":[],"mappings":"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","file":"chunk-W73FBYIH.cjs","sourcesContent":["/**\n * Brave Search Provider\n *\n * Brave Search is a privacy-focused search engine with its own index.\n * Provides independent search results without tracking.\n *\n * @see https://brave.com/search/api/\n */\n\nimport type {\n WebSearchConfig,\n WebSearchParams,\n WebSearchResponse,\n BraveApiResponse,\n WebSearchProviderInterface,\n} from \"../types\";\n\nconst BRAVE_API_URL = \"https://api.search.brave.com/res/v1/web/search\";\n\n/**\n * Validate Brave configuration\n */\nexport function validateBraveConfig(config: WebSearchConfig): void {\n if (!config.apiKey) {\n throw new Error(\n \"Brave Search API key is required. Get one at https://brave.com/search/api/\",\n );\n }\n}\n\n/**\n * Search using Brave Search API\n */\nexport async function searchBrave(\n params: WebSearchParams,\n config: WebSearchConfig,\n): Promise<WebSearchResponse> {\n validateBraveConfig(config);\n\n const startTime = Date.now();\n\n const searchParams = new URLSearchParams({\n q: params.query,\n count: String(params.maxResults ?? config.maxResults ?? 5),\n });\n\n // Add locale settings\n if (config.country) {\n searchParams.set(\"country\", config.country);\n }\n if (config.language) {\n searchParams.set(\"search_lang\", config.language);\n }\n\n const url = `${BRAVE_API_URL}?${searchParams.toString()}`;\n\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n Accept: \"application/json\",\n \"Accept-Encoding\": \"gzip\",\n \"X-Subscription-Token\": config.apiKey!,\n },\n signal: config.timeout ? AbortSignal.timeout(config.timeout) : undefined,\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"Unknown error\");\n throw new Error(\n `Brave Search API error (${response.status}): ${errorText}`,\n );\n }\n\n const data: BraveApiResponse = await response.json();\n const searchTime = Date.now() - startTime;\n\n // Filter by domains if specified\n let results = data.web?.results || [];\n if (config.includeDomains?.length) {\n results = results.filter((r) =>\n config.includeDomains!.some((domain) => r.url.includes(domain)),\n );\n }\n if (config.excludeDomains?.length) {\n results = results.filter(\n (r) => !config.excludeDomains!.some((domain) => r.url.includes(domain)),\n );\n }\n\n // Extract answer from infobox if available\n const answer = data.infobox?.description;\n\n return {\n query: params.query,\n answer,\n results: results.map((result) => ({\n title: result.title,\n url: result.url,\n content: result.description,\n publishedDate: result.page_age,\n image: result.thumbnail?.src,\n domain: extractDomain(result.url),\n })),\n provider: \"brave\",\n totalResults: results.length,\n searchTime,\n };\n}\n\n/**\n * Extract domain from URL\n */\nfunction extractDomain(url: string): string {\n try {\n return new URL(url).hostname;\n } catch {\n return url;\n }\n}\n\n/**\n * Brave provider implementation\n */\nexport const braveProvider: WebSearchProviderInterface = {\n search: searchBrave,\n validateConfig: validateBraveConfig,\n};\n"]}
|