@memoryblock/plugin-web-search 0.1.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +0 -0
- package/README.md +0 -0
- package/dist/base.d.ts +18 -0
- package/dist/base.d.ts.map +1 -0
- package/dist/base.js +2 -0
- package/dist/base.js.map +1 -0
- package/dist/brave/index.d.ts +10 -0
- package/dist/brave/index.d.ts.map +1 -0
- package/dist/brave/index.js +40 -0
- package/dist/brave/index.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/package.json +17 -0
- package/src/base.ts +19 -0
- package/src/brave/index.ts +57 -0
- package/src/index.ts +53 -0
- package/tsconfig.json +10 -0
package/LICENSE
ADDED
|
File without changes
|
package/README.md
ADDED
|
File without changes
|
package/dist/base.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search provider contract.
|
|
3
|
+
* All search providers (Brave, Google, etc.) must implement this.
|
|
4
|
+
*/
|
|
5
|
+
export interface SearchResult {
|
|
6
|
+
title: string;
|
|
7
|
+
url: string;
|
|
8
|
+
snippet: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SearchOptions {
|
|
11
|
+
count?: number;
|
|
12
|
+
language?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface SearchProvider {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
search(query: string, options?: SearchOptions): Promise<SearchResult[]>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,YAAY;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;CAC3E"}
|
package/dist/base.js
ADDED
package/dist/base.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SearchProvider, SearchResult, SearchOptions } from '../base.js';
|
|
2
|
+
/**
|
|
3
|
+
* Brave Search API provider.
|
|
4
|
+
* Uses native fetch() (Node 18+ built-in).
|
|
5
|
+
*/
|
|
6
|
+
export declare class BraveSearchProvider implements SearchProvider {
|
|
7
|
+
readonly name = "brave";
|
|
8
|
+
search(query: string, options?: SearchOptions): Promise<SearchResult[]>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/brave/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAU9E;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,cAAc;IACtD,QAAQ,CAAC,IAAI,WAAW;IAElB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CAsChF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { loadAuth } from 'memoryblock';
|
|
2
|
+
const BRAVE_API_URL = 'https://api.search.brave.com/res/v1/web/search';
|
|
3
|
+
/**
|
|
4
|
+
* Brave Search API provider.
|
|
5
|
+
* Uses native fetch() (Node 18+ built-in).
|
|
6
|
+
*/
|
|
7
|
+
export class BraveSearchProvider {
|
|
8
|
+
name = 'brave';
|
|
9
|
+
async search(query, options) {
|
|
10
|
+
const auth = await loadAuth();
|
|
11
|
+
const apiKey = auth.brave?.apiKey;
|
|
12
|
+
if (!apiKey) {
|
|
13
|
+
throw new Error('Brave API key not configured. Add it to ~/.memoryblock/auth.json:\n' +
|
|
14
|
+
' { "brave": { "apiKey": "..." } }');
|
|
15
|
+
}
|
|
16
|
+
const count = options?.count || 5;
|
|
17
|
+
const params = new URLSearchParams({
|
|
18
|
+
q: query,
|
|
19
|
+
count: String(count),
|
|
20
|
+
});
|
|
21
|
+
const response = await fetch(`${BRAVE_API_URL}?${params}`, {
|
|
22
|
+
headers: {
|
|
23
|
+
'Accept': 'application/json',
|
|
24
|
+
'Accept-Encoding': 'gzip',
|
|
25
|
+
'X-Subscription-Token': apiKey,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
throw new Error(`Brave Search API error: ${response.status} ${response.statusText}`);
|
|
30
|
+
}
|
|
31
|
+
const data = await response.json();
|
|
32
|
+
const results = data.web?.results || [];
|
|
33
|
+
return results.map((r) => ({
|
|
34
|
+
title: r.title || '',
|
|
35
|
+
url: r.url || '',
|
|
36
|
+
snippet: r.description || '',
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/brave/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,MAAM,aAAa,GAAG,gDAAgD,CAAC;AAQvE;;;GAGG;AACH,MAAM,OAAO,mBAAmB;IACnB,IAAI,GAAG,OAAO,CAAC;IAExB,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,OAAuB;QAC/C,MAAM,IAAI,GAAG,MAAM,QAAQ,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC;QAElC,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CACX,qEAAqE;gBACrE,oCAAoC,CACvC,CAAC;QACN,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YAC/B,CAAC,EAAE,KAAK;YACR,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;SACvB,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,aAAa,IAAI,MAAM,EAAE,EAAE;YACvD,OAAO,EAAE;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,iBAAiB,EAAE,MAAM;gBACzB,sBAAsB,EAAE,MAAM;aACjC;SACJ,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACzF,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA8C,CAAC;QAC/E,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,IAAI,EAAE,CAAC;QAExC,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAiB,EAAE,EAAE,CAAC,CAAC;YACvC,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE;YACpB,GAAG,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE;YAChB,OAAO,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;SAC/B,CAAC,CAAC,CAAC;IACR,CAAC;CACJ"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ToolExecutionResult, ToolContext, ToolDefinition } from 'memoryblock';
|
|
2
|
+
export type { SearchProvider, SearchResult, SearchOptions } from './base.js';
|
|
3
|
+
export { BraveSearchProvider } from './brave/index.js';
|
|
4
|
+
/** Web search tool — usable by the tool registry. */
|
|
5
|
+
export declare const webSearchTool: {
|
|
6
|
+
definition: ToolDefinition;
|
|
7
|
+
execute(params: Record<string, unknown>, _context: ToolContext): Promise<ToolExecutionResult>;
|
|
8
|
+
};
|
|
9
|
+
/** Export as array for registry plugin loading. */
|
|
10
|
+
export declare const tools: {
|
|
11
|
+
definition: ToolDefinition;
|
|
12
|
+
execute(params: Record<string, unknown>, _context: ToolContext): Promise<ToolExecutionResult>;
|
|
13
|
+
}[];
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGpF,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAsBvD,qDAAqD;AACrD,eAAO,MAAM,aAAa;;oBAEA,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAoBtG,CAAC;AAEF,mDAAmD;AACnD,eAAO,MAAM,KAAK;;oBAvBQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC;GAuBnE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { BraveSearchProvider } from './brave/index.js';
|
|
2
|
+
export { BraveSearchProvider } from './brave/index.js';
|
|
3
|
+
const braveProvider = new BraveSearchProvider();
|
|
4
|
+
/**
|
|
5
|
+
* Web search tool definition — registers as a tool in the registry.
|
|
6
|
+
*/
|
|
7
|
+
const webSearchToolDefinition = {
|
|
8
|
+
name: 'web_search',
|
|
9
|
+
description: 'Search the web for current information. Returns titles, URLs, and snippets.',
|
|
10
|
+
parameters: {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
query: { type: 'string', description: 'The search query.' },
|
|
14
|
+
count: { type: 'number', description: 'Number of results (default: 5, max: 10).' },
|
|
15
|
+
},
|
|
16
|
+
required: ['query'],
|
|
17
|
+
additionalProperties: false,
|
|
18
|
+
},
|
|
19
|
+
requiresApproval: false,
|
|
20
|
+
};
|
|
21
|
+
/** Web search tool — usable by the tool registry. */
|
|
22
|
+
export const webSearchTool = {
|
|
23
|
+
definition: webSearchToolDefinition,
|
|
24
|
+
async execute(params, _context) {
|
|
25
|
+
try {
|
|
26
|
+
const query = params.query;
|
|
27
|
+
const count = Math.min(params.count || 5, 10);
|
|
28
|
+
const results = await braveProvider.search(query, { count });
|
|
29
|
+
if (results.length === 0) {
|
|
30
|
+
return { content: 'No results found.', isError: false };
|
|
31
|
+
}
|
|
32
|
+
const formatted = results
|
|
33
|
+
.map((r, i) => `${i + 1}. **${r.title}**\n ${r.url}\n ${r.snippet}`)
|
|
34
|
+
.join('\n\n');
|
|
35
|
+
return { content: formatted, isError: false };
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
39
|
+
return { content: `Web search failed: ${message}`, isError: true };
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
/** Export as array for registry plugin loading. */
|
|
44
|
+
export const tools = [webSearchTool];
|
|
45
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,aAAa,GAAG,IAAI,mBAAmB,EAAE,CAAC;AAEhD;;GAEG;AACH,MAAM,uBAAuB,GAAmB;IAC5C,IAAI,EAAE,YAAY;IAClB,WAAW,EAAE,6EAA6E;IAC1F,UAAU,EAAE;QACR,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACR,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mBAAmB,EAAE;YAC3D,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0CAA0C,EAAE;SACrF;QACD,QAAQ,EAAE,CAAC,OAAO,CAAC;QACnB,oBAAoB,EAAE,KAAK;KAC9B;IACD,gBAAgB,EAAE,KAAK;CAC1B,CAAC;AAEF,qDAAqD;AACrD,MAAM,CAAC,MAAM,aAAa,GAAG;IACzB,UAAU,EAAE,uBAAuB;IACnC,KAAK,CAAC,OAAO,CAAC,MAA+B,EAAE,QAAqB;QAChE,IAAI,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAe,CAAC;YACrC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAE,MAAM,CAAC,KAAgB,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1D,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YAE7D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YAC5D,CAAC;YAED,MAAM,SAAS,GAAG,OAAO;iBACpB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC;iBACvE,IAAI,CAAC,MAAM,CAAC,CAAC;YAElB,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAClD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,EAAE,OAAO,EAAE,sBAAsB,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACvE,CAAC;IACL,CAAC;CACJ,CAAC;AAEF,mDAAmD;AACnD,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,aAAa,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@memoryblock/plugin-web-search",
|
|
3
|
+
"version": "0.1.0-beta",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"import": "./dist/index.js"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"memoryblock": "0.1.0-beta"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc -p tsconfig.json"
|
|
16
|
+
}
|
|
17
|
+
}
|
package/src/base.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search provider contract.
|
|
3
|
+
* All search providers (Brave, Google, etc.) must implement this.
|
|
4
|
+
*/
|
|
5
|
+
export interface SearchResult {
|
|
6
|
+
title: string;
|
|
7
|
+
url: string;
|
|
8
|
+
snippet: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface SearchOptions {
|
|
12
|
+
count?: number;
|
|
13
|
+
language?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface SearchProvider {
|
|
17
|
+
readonly name: string;
|
|
18
|
+
search(query: string, options?: SearchOptions): Promise<SearchResult[]>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { loadAuth } from 'memoryblock';
|
|
2
|
+
import type { SearchProvider, SearchResult, SearchOptions } from '../base.js';
|
|
3
|
+
|
|
4
|
+
const BRAVE_API_URL = 'https://api.search.brave.com/res/v1/web/search';
|
|
5
|
+
|
|
6
|
+
interface BraveWebResult {
|
|
7
|
+
title?: string;
|
|
8
|
+
url?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Brave Search API provider.
|
|
14
|
+
* Uses native fetch() (Node 18+ built-in).
|
|
15
|
+
*/
|
|
16
|
+
export class BraveSearchProvider implements SearchProvider {
|
|
17
|
+
readonly name = 'brave';
|
|
18
|
+
|
|
19
|
+
async search(query: string, options?: SearchOptions): Promise<SearchResult[]> {
|
|
20
|
+
const auth = await loadAuth();
|
|
21
|
+
const apiKey = auth.brave?.apiKey;
|
|
22
|
+
|
|
23
|
+
if (!apiKey) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
'Brave API key not configured. Add it to ~/.memoryblock/auth.json:\n' +
|
|
26
|
+
' { "brave": { "apiKey": "..." } }',
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const count = options?.count || 5;
|
|
31
|
+
const params = new URLSearchParams({
|
|
32
|
+
q: query,
|
|
33
|
+
count: String(count),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const response = await fetch(`${BRAVE_API_URL}?${params}`, {
|
|
37
|
+
headers: {
|
|
38
|
+
'Accept': 'application/json',
|
|
39
|
+
'Accept-Encoding': 'gzip',
|
|
40
|
+
'X-Subscription-Token': apiKey,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error(`Brave Search API error: ${response.status} ${response.statusText}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const data = await response.json() as { web?: { results?: BraveWebResult[] } };
|
|
49
|
+
const results = data.web?.results || [];
|
|
50
|
+
|
|
51
|
+
return results.map((r: BraveWebResult) => ({
|
|
52
|
+
title: r.title || '',
|
|
53
|
+
url: r.url || '',
|
|
54
|
+
snippet: r.description || '',
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ToolExecutionResult, ToolContext, ToolDefinition } from 'memoryblock';
|
|
2
|
+
import { BraveSearchProvider } from './brave/index.js';
|
|
3
|
+
|
|
4
|
+
export type { SearchProvider, SearchResult, SearchOptions } from './base.js';
|
|
5
|
+
export { BraveSearchProvider } from './brave/index.js';
|
|
6
|
+
|
|
7
|
+
const braveProvider = new BraveSearchProvider();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Web search tool definition — registers as a tool in the registry.
|
|
11
|
+
*/
|
|
12
|
+
const webSearchToolDefinition: ToolDefinition = {
|
|
13
|
+
name: 'web_search',
|
|
14
|
+
description: 'Search the web for current information. Returns titles, URLs, and snippets.',
|
|
15
|
+
parameters: {
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
query: { type: 'string', description: 'The search query.' },
|
|
19
|
+
count: { type: 'number', description: 'Number of results (default: 5, max: 10).' },
|
|
20
|
+
},
|
|
21
|
+
required: ['query'],
|
|
22
|
+
additionalProperties: false,
|
|
23
|
+
},
|
|
24
|
+
requiresApproval: false,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** Web search tool — usable by the tool registry. */
|
|
28
|
+
export const webSearchTool = {
|
|
29
|
+
definition: webSearchToolDefinition,
|
|
30
|
+
async execute(params: Record<string, unknown>, _context: ToolContext): Promise<ToolExecutionResult> {
|
|
31
|
+
try {
|
|
32
|
+
const query = params.query as string;
|
|
33
|
+
const count = Math.min((params.count as number) || 5, 10);
|
|
34
|
+
const results = await braveProvider.search(query, { count });
|
|
35
|
+
|
|
36
|
+
if (results.length === 0) {
|
|
37
|
+
return { content: 'No results found.', isError: false };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const formatted = results
|
|
41
|
+
.map((r, i) => `${i + 1}. **${r.title}**\n ${r.url}\n ${r.snippet}`)
|
|
42
|
+
.join('\n\n');
|
|
43
|
+
|
|
44
|
+
return { content: formatted, isError: false };
|
|
45
|
+
} catch (err) {
|
|
46
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
47
|
+
return { content: `Web search failed: ${message}`, isError: true };
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** Export as array for registry plugin loading. */
|
|
53
|
+
export const tools = [webSearchTool];
|