@alexanderfortin/pi-tavily-tools 0.1.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.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +366 -0
  3. package/dist/index.d.ts +17 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +38 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/tools/index.d.ts +7 -0
  8. package/dist/tools/index.d.ts.map +1 -0
  9. package/dist/tools/index.js +7 -0
  10. package/dist/tools/index.js.map +1 -0
  11. package/dist/tools/shared/truncation.d.ts +21 -0
  12. package/dist/tools/shared/truncation.d.ts.map +1 -0
  13. package/dist/tools/shared/truncation.js +55 -0
  14. package/dist/tools/shared/truncation.js.map +1 -0
  15. package/dist/tools/tavily/client.d.ts +27 -0
  16. package/dist/tools/tavily/client.d.ts.map +1 -0
  17. package/dist/tools/tavily/client.js +62 -0
  18. package/dist/tools/tavily/client.js.map +1 -0
  19. package/dist/tools/tavily/formatters.d.ts +21 -0
  20. package/dist/tools/tavily/formatters.d.ts.map +1 -0
  21. package/dist/tools/tavily/formatters.js +108 -0
  22. package/dist/tools/tavily/formatters.js.map +1 -0
  23. package/dist/tools/tavily/renderers.d.ts +28 -0
  24. package/dist/tools/tavily/renderers.d.ts.map +1 -0
  25. package/dist/tools/tavily/renderers.js +116 -0
  26. package/dist/tools/tavily/renderers.js.map +1 -0
  27. package/dist/tools/tavily/schemas.d.ts +24 -0
  28. package/dist/tools/tavily/schemas.d.ts.map +1 -0
  29. package/dist/tools/tavily/schemas.js +36 -0
  30. package/dist/tools/tavily/schemas.js.map +1 -0
  31. package/dist/tools/tavily/types.d.ts +53 -0
  32. package/dist/tools/tavily/types.d.ts.map +1 -0
  33. package/dist/tools/tavily/types.js +5 -0
  34. package/dist/tools/tavily/types.js.map +1 -0
  35. package/dist/tools/web-search.d.ts +16 -0
  36. package/dist/tools/web-search.d.ts.map +1 -0
  37. package/dist/tools/web-search.js +120 -0
  38. package/dist/tools/web-search.js.map +1 -0
  39. package/package.json +77 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alexander Fortin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,366 @@
1
+ # Pi Tavily Web Search Extension
2
+
3
+ Add web search capabilities to Pi using the Tavily search API.
4
+
5
+ This extension provides a `web_search` tool that the LLM can use to find current information, recent news, documentation, and time-sensitive data.
6
+
7
+ Requires a valid `TAVILY_API_KEY` exported in the enviornment, e.g.
8
+
9
+ ```bash
10
+ TAVILY_API_KEY=tvly-xxxx-xxxxxxx-xxxxxxxxxx pi
11
+ ```
12
+
13
+ You can get a free one at <https://tavily.com>
14
+
15
+ ## Features
16
+
17
+ - **Web Search:** Query the web for real-time information
18
+ - **AI-Generated Answers:** Get direct answers to questions powered by Tavily
19
+ - **Configurable Depth:** Choose between "basic" and "advanced" search modes
20
+ - **Time Filtering:** Limit results to recent timeframes (e.g., last 7 days)
21
+ - **Image Support:** Include relevant images in search results
22
+ - **Content Extraction:** Optional raw content for deeper analysis
23
+ - **Proper Truncation:** Output truncated to 50KB / 2000 lines to avoid context overflow
24
+ - **Custom TUI Rendering:** Beautiful display with expandable results
25
+ - **Error Handling:** Graceful failures with helpful error messages
26
+
27
+ ## Installation
28
+
29
+ ### Option 1: Install from npm (Recommended)
30
+
31
+ ```bash
32
+ pi install npm:@alexanderfortin/pi-tavily-tools
33
+ ```
34
+
35
+ ### Option 2: Install from Git
36
+
37
+ ```bash
38
+ pi install git:github.com/shaftoe/pi-tavily-tools
39
+ ```
40
+
41
+ ### Option 3: Quick Test with -e flag
42
+
43
+ ```bash
44
+ git clone https://github.com/shaftoe/pi-tavily-tools
45
+ cd pi-tavily-tools
46
+ pi -e ./src/index.ts
47
+ ```
48
+
49
+ ## Setup
50
+
51
+ ### 1. Get a Tavily API Key
52
+
53
+ Visit <https://tavily.com> and sign up for a free account. The free tier includes:
54
+
55
+ - 1,000 requests per month
56
+ - Basic search depth
57
+ - Standard rate limits
58
+
59
+ ### 2. Configure the API Key
60
+
61
+ Set the `TAVILY_API_KEY` environment variable:
62
+
63
+ ```bash
64
+ export TAVILY_API_KEY="your-api-key-here"
65
+ ```
66
+
67
+ **Add to your shell profile** (~/.zshrc, ~/.bashrc, etc.) for persistent access:
68
+
69
+ ```bash
70
+ echo 'export TAVILY_API_KEY="your-api-key-here"' >> ~/.zshrc
71
+ source ~/.zshrc
72
+ ```
73
+
74
+ ## Usage
75
+
76
+ ### Basic Web Search
77
+
78
+ Simply ask Pi to search the web:
79
+
80
+ ```
81
+ Search for the latest version of React
82
+ ```
83
+
84
+ ```
85
+ What are the new features in TypeScript 6.0?
86
+ ```
87
+
88
+ ```
89
+ Find recent news about artificial intelligence
90
+ ```
91
+
92
+ ### Time-Limited Search
93
+
94
+ Limit results to a specific timeframe:
95
+
96
+ ```
97
+ Search for AI news from the last 7 days
98
+ ```
99
+
100
+ ```
101
+ Show me the latest JavaScript updates from the past 30 days
102
+ ```
103
+
104
+ ### Advanced Search
105
+
106
+ Use advanced search depth for more detailed results:
107
+
108
+ ```
109
+ Search for quantum computing trends using advanced search
110
+ ```
111
+
112
+ ### Image Search
113
+
114
+ Include relevant images in results:
115
+
116
+ ```
117
+ Find cute cats with images
118
+ ```
119
+
120
+ ### Raw Content
121
+
122
+ Get detailed content from search results:
123
+
124
+ ```
125
+ Search for Bun test runner documentation and include raw content
126
+ ```
127
+
128
+ ## Available Parameters
129
+
130
+ The `web_search` tool accepts the following parameters:
131
+
132
+ | Parameter | Type | Required | Default | Description |
133
+ | --------------------- | ------- | -------- | ------- | ---------------------------------------------- |
134
+ | `query` | string | Yes | - | The search query string |
135
+ | `max_results` | number | No | 5 | Number of results to return (1-20) |
136
+ | `search_depth` | string | No | "basic" | Search depth: "basic" or "advanced" |
137
+ | `include_answer` | boolean | No | true | Include AI-generated answer |
138
+ | `include_raw_content` | boolean | No | false | Include raw page content (markdown or text) |
139
+ | `include_images` | boolean | No | false | Include relevant images |
140
+ | `days` | number | No | - | Limit results to last N days (e.g., 7, 30, 90) |
141
+
142
+ ### Parameter Examples
143
+
144
+ ```typescript
145
+ // Basic search
146
+ { query: "TypeScript 6" }
147
+
148
+ // Time-limited search
149
+ { query: "AI news", days: 7 }
150
+
151
+ // Advanced search with more results
152
+ { query: "quantum computing", search_depth: "advanced", max_results: 10 }
153
+
154
+ // Search with images
155
+ { query: "cute cats", include_images: true }
156
+
157
+ // Search with raw content
158
+ { query: "Bun documentation", include_raw_content: true }
159
+ ```
160
+
161
+ ## Output Truncation
162
+
163
+ To prevent overwhelming the LLM context, tool output is truncated to:
164
+
165
+ - **50KB** of data
166
+ - **2,000 lines** of text
167
+
168
+ Whichever limit is hit first triggers truncation.
169
+
170
+ When output is truncated:
171
+
172
+ - A warning is displayed in the results
173
+ - Full output is saved to a temp file in your project directory: `.pi-tavily-temp/search-{timestamp}.txt`
174
+ - The LLM is informed where to find the complete output
175
+
176
+ ## Troubleshooting
177
+
178
+ ### "TAVILY_API_KEY is not set"
179
+
180
+ **Error Message:**
181
+
182
+ ```
183
+ Error: TAVILY_API_KEY environment variable is not set.
184
+ ```
185
+
186
+ **Solution:**
187
+
188
+ 1. Get an API key from <https://tavily.com>
189
+ 2. Set the environment variable:
190
+ ```bash
191
+ export TAVILY_API_KEY="your-api-key-here"
192
+ ```
193
+ 3. Add to your shell profile for persistence:
194
+ ```bash
195
+ echo 'export TAVILY_API_KEY="your-api-key-here"' >> ~/.zshrc
196
+ source ~/.zshrc
197
+ ```
198
+
199
+ ### "Failed to initialize Tavily client"
200
+
201
+ **Error Message:**
202
+
203
+ ```
204
+ Error: Failed to initialize Tavily client: ...
205
+ ```
206
+
207
+ **Possible Causes:**
208
+
209
+ 1. Invalid API key format
210
+ 2. Network connectivity issues
211
+ 3. Tavily API is down
212
+
213
+ **Solutions:**
214
+
215
+ 1. Verify your API key is correct (should start with "tvly-")
216
+ 2. Check your internet connection
217
+ 3. Try a simple curl test:
218
+ ```bash
219
+ curl -X POST https://api.tavily.com/search \\
220
+ -H "Content-Type: application/json" \\
221
+ -d '{"api_key":"YOUR_KEY","query":"test","max_results":1}'
222
+ ```
223
+
224
+ ### Rate Limit Errors
225
+
226
+ **Error Message:**
227
+
228
+ ```
229
+ Error: You have exceeded your monthly request limit
230
+ ```
231
+
232
+ **Solution:**
233
+
234
+ - The free tier includes 1,000 requests per month
235
+ - Upgrade your Tavily plan if you need more requests
236
+ - Visit <https://tavily.com/pricing> for details
237
+
238
+ ### No Results Found
239
+
240
+ **Symptoms:**
241
+
242
+ - Search returns "No results found."
243
+ - Empty results list
244
+
245
+ **Solutions:**
246
+
247
+ 1. Try a broader or different search query
248
+ 2. Check spelling of your query
249
+ 3. Remove any special characters or complex filters
250
+ 4. Try basic search depth instead of advanced
251
+
252
+ ## Development
253
+
254
+ ### Project Structure
255
+
256
+ ```
257
+ pi-tavily-tools/
258
+ ├── .github/
259
+ │ └── dependabot.yml # Dependency update configuration
260
+ ├── .envrc # Direnv configuration for API keys
261
+ ├── .gitignore
262
+ ├── .prettierignore
263
+ ├── .prettierrc # Prettier code formatter config
264
+ ├── AGENTS.md # Project guidelines for Pi agents
265
+ ├── LICENSE
266
+ ├── README.md
267
+ ├── bun.lock
268
+ ├── eslint.config.js # ESLint linting config
269
+ ├── lefthook.yml # Git hooks configuration
270
+ ├── package.json # Package manifest
271
+ ├── tsconfig.json # TypeScript compiler config
272
+ ├── src/
273
+ │ ├── index.ts # Extension entry point
274
+ │ └── tools/
275
+ │ ├── index.ts # Tool exports
276
+ │ ├── web-search.ts # Web search tool implementation
277
+ │ ├── tavily/ # Tavily API integration
278
+ │ │ ├── client.ts # Tavily client & initialization
279
+ │ │ ├── formatters.ts # Response formatting
280
+ │ │ ├── renderers.ts # TUI rendering utilities
281
+ │ │ ├── schemas.ts # TypeBox parameter schemas
282
+ │ │ └── types.ts # Type definitions
283
+ │ └── shared/ # Shared utilities
284
+ │ └── truncation.ts # Output truncation utilities
285
+ └── tests/
286
+ ├── integration/ # Integration tests
287
+ │ └── web-search.test.ts
288
+ ├── client.test.ts
289
+ ├── create-error-output.test.ts
290
+ ├── formatters.test.ts
291
+ ├── renderers.test.ts
292
+ ├── schemas.test.ts
293
+ └── truncation.test.ts
294
+ ```
295
+
296
+ ### Running Type Checks
297
+
298
+ ```bash
299
+ bun run check
300
+ ```
301
+
302
+ Watch mode for instant feedback during development:
303
+
304
+ ```bash
305
+ bun run check:watch
306
+ ```
307
+
308
+ ### Running Tests
309
+
310
+ ```bash
311
+ bun run test
312
+ ```
313
+
314
+ Watch mode for continuous testing:
315
+
316
+ ```bash
317
+ bun run test:watch
318
+ ```
319
+
320
+ Run only integration tests (requires valid API key):
321
+
322
+ ```bash
323
+ bun test tests/integration/
324
+ ```
325
+
326
+ ### Running Linting
327
+
328
+ ```bash
329
+ bun run lint
330
+ ```
331
+
332
+ ### Formatting Code
333
+
334
+ ```bash
335
+ bun run format:fix
336
+ ```
337
+
338
+ ### All Checks
339
+
340
+ Run all checks before committing:
341
+
342
+ ```bash
343
+ bun run check && bun run lint && bun run test
344
+ ```
345
+
346
+ ## License
347
+
348
+ MIT License - see [LICENSE](LICENSE) file for details.
349
+
350
+ ## Contributing
351
+
352
+ Contributions are welcome! Please feel free to submit a Pull Request.
353
+
354
+ ## Support
355
+
356
+ - **GitHub Issues:** [shaftoe/pi-tavily-tools/issues](https://github.com/shaftoe/pi-tavily-tools/issues)
357
+ - **Tavily Documentation:** [https://docs.tavily.com](https://docs.tavily.com)
358
+ - **Pi Documentation:** [https://shittycodingagent.ai](https://shittycodingagent.ai)
359
+
360
+ ## Acknowledgments
361
+
362
+ Built with:
363
+
364
+ - [Tavily API](https://tavily.com) - Web search and AI answers
365
+ - [Pi Coding Agent](https://pi.dev) - Extension framework
366
+ - [Bun](https://bun.sh) - Package manager and test runner
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Pi Tavily Web Search Extension
3
+ *
4
+ * Provides web search capabilities to Pi using Tavily's search API.
5
+ * Adds a `web_search` tool that the LLM can use to find current
6
+ * information, recent news, documentation, and time-sensitive data.
7
+ */
8
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
9
+ /**
10
+ * Main extension entry point.
11
+ *
12
+ * Defers tool registration to `session_start` so Pi can start
13
+ * even if the TAVILY_API_KEY is missing. The tool is registered only
14
+ * once on the first agent run and persists across sessions.
15
+ */
16
+ export default function (pi: ExtensionAPI): void;
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAIlE;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,GAAG,IAAI,CAmB/C"}
package/dist/index.js ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Pi Tavily Web Search Extension
3
+ *
4
+ * Provides web search capabilities to Pi using Tavily's search API.
5
+ * Adds a `web_search` tool that the LLM can use to find current
6
+ * information, recent news, documentation, and time-sensitive data.
7
+ */
8
+ import { createTavilyClient } from "./tools/tavily/client.js";
9
+ import { registerWebSearchTool } from "./tools/web-search.js";
10
+ /**
11
+ * Main extension entry point.
12
+ *
13
+ * Defers tool registration to `session_start` so Pi can start
14
+ * even if the TAVILY_API_KEY is missing. The tool is registered only
15
+ * once on the first agent run and persists across sessions.
16
+ */
17
+ export default function (pi) {
18
+ let registered = false;
19
+ pi.on("session_start", (_event, ctx) => {
20
+ if (registered)
21
+ return;
22
+ registered = true;
23
+ try {
24
+ const client = createTavilyClient();
25
+ registerWebSearchTool(pi, client);
26
+ }
27
+ catch (error) {
28
+ if (error instanceof Error) {
29
+ ctx.ui.notify(`[pi-tavily-tools] ${error.message}`, "error");
30
+ }
31
+ else {
32
+ // Re-throw non-Error types (shouldn't happen, but be safe)
33
+ throw error;
34
+ }
35
+ }
36
+ });
37
+ }
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,WAAW,EAAgB;IACvC,IAAI,UAAU,GAAG,KAAK,CAAC;IAEvB,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;QACrC,IAAI,UAAU;YAAE,OAAO;QACvB,UAAU,GAAG,IAAI,CAAC;QAElB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;YACpC,qBAAqB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC3B,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,qBAAqB,KAAK,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;YAC/D,CAAC;iBAAM,CAAC;gBACN,2DAA2D;gBAC3D,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Tavily Tools for Pi
3
+ *
4
+ * This package provides Pi tools for interacting with Tavily's API.
5
+ */
6
+ export { registerWebSearchTool } from "./web-search.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Tavily Tools for Pi
3
+ *
4
+ * This package provides Pi tools for interacting with Tavily's API.
5
+ */
6
+ export { registerWebSearchTool } from "./web-search.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Shared truncation utilities
3
+ */
4
+ import { type TruncationResult } from "@mariozechner/pi-coding-agent";
5
+ export interface TruncatedOutput {
6
+ content: string;
7
+ truncation?: TruncationResult;
8
+ fullOutputPath?: string;
9
+ }
10
+ /**
11
+ * Apply truncation to output and save full content to temp file if needed
12
+ */
13
+ export declare function applyTruncation(fullOutput: string, cwd: string, toolName: string): Promise<TruncatedOutput>;
14
+ /**
15
+ * Create error output
16
+ */
17
+ export declare function createErrorOutput(errorMessage: string, baseDetails: Record<string, unknown>): {
18
+ content: string;
19
+ details: Record<string, unknown>;
20
+ };
21
+ //# sourceMappingURL=truncation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncation.d.ts","sourceRoot":"","sources":["../../../src/tools/shared/truncation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAML,KAAK,gBAAgB,EACtB,MAAM,+BAA+B,CAAC;AAMvC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,eAAe,CAAC,CAuC1B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAUvD"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Shared truncation utilities
3
+ */
4
+ import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateHead, withFileMutationQueue, } from "@mariozechner/pi-coding-agent";
5
+ /**
6
+ * Apply truncation to output and save full content to temp file if needed
7
+ */
8
+ export async function applyTruncation(fullOutput, cwd, toolName) {
9
+ const truncation = truncateHead(fullOutput, {
10
+ maxLines: DEFAULT_MAX_LINES,
11
+ maxBytes: DEFAULT_MAX_BYTES,
12
+ });
13
+ let content = truncation.content;
14
+ // Save full output to temp file if truncated
15
+ if (truncation.truncated) {
16
+ const tempDir = `${cwd}/.pi-tavily-temp`;
17
+ const timestamp = Date.now();
18
+ const tempFile = `${tempDir}/${toolName}-${timestamp}.txt`;
19
+ await withFileMutationQueue(tempFile, async () => {
20
+ const { writeFile, mkdir } = await import("node:fs/promises");
21
+ await mkdir(tempDir, { recursive: true });
22
+ await writeFile(tempFile, fullOutput, "utf8");
23
+ });
24
+ // Add truncation notice
25
+ const truncatedLines = truncation.totalLines - truncation.outputLines;
26
+ const truncatedBytes = truncation.totalBytes - truncation.outputBytes;
27
+ content += "\n\n";
28
+ content += "[Output truncated: ";
29
+ content += `showing ${truncation.outputLines} of ${truncation.totalLines} lines, `;
30
+ content += `(${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}). `;
31
+ content += `${truncatedLines} lines (${formatSize(truncatedBytes)}) omitted. `;
32
+ content += `Full output saved to: ${tempFile}]`;
33
+ return {
34
+ content,
35
+ truncation,
36
+ fullOutputPath: tempFile,
37
+ };
38
+ }
39
+ return { content };
40
+ }
41
+ /**
42
+ * Create error output
43
+ */
44
+ export function createErrorOutput(errorMessage, baseDetails) {
45
+ return {
46
+ content: `Error: ${errorMessage}`,
47
+ details: {
48
+ ...baseDetails,
49
+ resultCount: 0,
50
+ sources: [],
51
+ error: errorMessage,
52
+ },
53
+ };
54
+ }
55
+ //# sourceMappingURL=truncation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncation.js","sourceRoot":"","sources":["../../../src/tools/shared/truncation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,qBAAqB,GAEtB,MAAM,+BAA+B,CAAC;AAYvC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAkB,EAClB,GAAW,EACX,QAAgB;IAEhB,MAAM,UAAU,GAAG,YAAY,CAAC,UAAU,EAAE;QAC1C,QAAQ,EAAE,iBAAiB;QAC3B,QAAQ,EAAE,iBAAiB;KAC5B,CAAC,CAAC;IAEH,IAAI,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC;IAEjC,6CAA6C;IAC7C,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,GAAG,GAAG,kBAAkB,CAAC;QACzC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,GAAG,OAAO,IAAI,QAAQ,IAAI,SAAS,MAAM,CAAC;QAE3D,MAAM,qBAAqB,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;YAC/C,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;YAC9D,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1C,MAAM,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,wBAAwB;QACxB,MAAM,cAAc,GAAG,UAAU,CAAC,UAAU,GAAG,UAAU,CAAC,WAAW,CAAC;QACtE,MAAM,cAAc,GAAG,UAAU,CAAC,UAAU,GAAG,UAAU,CAAC,WAAW,CAAC;QAEtE,OAAO,IAAI,MAAM,CAAC;QAClB,OAAO,IAAI,qBAAqB,CAAC;QACjC,OAAO,IAAI,WAAW,UAAU,CAAC,WAAW,OAAO,UAAU,CAAC,UAAU,UAAU,CAAC;QACnF,OAAO,IAAI,IAAI,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,OAAO,UAAU,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC;QAC/F,OAAO,IAAI,GAAG,cAAc,WAAW,UAAU,CAAC,cAAc,CAAC,aAAa,CAAC;QAC/E,OAAO,IAAI,yBAAyB,QAAQ,GAAG,CAAC;QAEhD,OAAO;YACL,OAAO;YACP,UAAU;YACV,cAAc,EAAE,QAAQ;SACzB,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,YAAoB,EACpB,WAAoC;IAEpC,OAAO;QACL,OAAO,EAAE,UAAU,YAAY,EAAE;QACjC,OAAO,EAAE;YACP,GAAG,WAAW;YACd,WAAW,EAAE,CAAC;YACd,OAAO,EAAE,EAAE;YACX,KAAK,EAAE,YAAY;SACpB;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Tavily Client Management
3
+ *
4
+ * Creates Tavily client instances with proper initialization.
5
+ */
6
+ import { type TavilyClient, type TavilySearchOptions } from "@tavily/core";
7
+ /**
8
+ * Create a new Tavily client instance
9
+ * @throws {Error} If TAVILY_API_KEY is not set or client initialization fails
10
+ */
11
+ export declare function createTavilyClient(apiKey?: string): TavilyClient;
12
+ /**
13
+ * Build Tavily search options from parameters
14
+ */
15
+ export declare function buildSearchOptions(params: Record<string, unknown>): TavilySearchOptions;
16
+ /**
17
+ * Create a search function pre-bound with a client
18
+ * @param client Tavily client instance
19
+ * @returns Search function
20
+ */
21
+ export declare function createSearchFunction(client: TavilyClient): import("@tavily/core").TavilySearchFuncton;
22
+ /**
23
+ * Validate search query
24
+ * @throws {Error} If query is empty or whitespace only
25
+ */
26
+ export declare function validateQuery(query: string): string;
27
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/tools/tavily/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAU,KAAK,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAMnF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,CAiBhE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,mBAAmB,CAYvF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,8CAExD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMnD"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Tavily Client Management
3
+ *
4
+ * Creates Tavily client instances with proper initialization.
5
+ */
6
+ import { tavily } from "@tavily/core";
7
+ // ============================================================================
8
+ // Client Creation
9
+ // ============================================================================
10
+ /**
11
+ * Create a new Tavily client instance
12
+ * @throws {Error} If TAVILY_API_KEY is not set or client initialization fails
13
+ */
14
+ export function createTavilyClient(apiKey) {
15
+ const key = apiKey ?? process.env.TAVILY_API_KEY;
16
+ if (!key) {
17
+ throw new Error("TAVILY_API_KEY environment variable is not set. " +
18
+ 'Please set it with: export TAVILY_API_KEY="your-api-key" ' +
19
+ "or get a free key from https://tavily.com");
20
+ }
21
+ try {
22
+ return tavily({ apiKey: key });
23
+ }
24
+ catch (error) {
25
+ throw new Error(`Failed to initialize Tavily client: ${error instanceof Error ? error.message : String(error)}`);
26
+ }
27
+ }
28
+ /**
29
+ * Build Tavily search options from parameters
30
+ */
31
+ export function buildSearchOptions(params) {
32
+ return {
33
+ maxResults: typeof params.max_results === "number" ? Math.max(1, Math.min(20, params.max_results)) : 5,
34
+ searchDepth: params.search_depth ?? "basic",
35
+ includeAnswer: params.include_answer !== false,
36
+ includeImages: params.include_images === true,
37
+ includeRawContent: params.include_raw_content === true ? "markdown" : false,
38
+ days: typeof params.days === "number" ? params.days : undefined,
39
+ includeDomains: undefined,
40
+ excludeDomains: undefined,
41
+ };
42
+ }
43
+ /**
44
+ * Create a search function pre-bound with a client
45
+ * @param client Tavily client instance
46
+ * @returns Search function
47
+ */
48
+ export function createSearchFunction(client) {
49
+ return client.search.bind(client);
50
+ }
51
+ /**
52
+ * Validate search query
53
+ * @throws {Error} If query is empty or whitespace only
54
+ */
55
+ export function validateQuery(query) {
56
+ const trimmed = query.trim();
57
+ if (!trimmed) {
58
+ throw new Error("Query cannot be empty");
59
+ }
60
+ return trimmed;
61
+ }
62
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/tools/tavily/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAA+C,MAAM,cAAc,CAAC;AAEnF,+EAA+E;AAC/E,kBAAkB;AAClB,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAe;IAChD,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IACjD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,kDAAkD;YAChD,2DAA2D;YAC3D,2CAA2C,CAC9C,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,uCAAuC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAChG,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAA+B;IAChE,OAAO;QACL,UAAU,EACR,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5F,WAAW,EAAG,MAAM,CAAC,YAAqC,IAAI,OAAO;QACrE,aAAa,EAAE,MAAM,CAAC,cAAc,KAAK,KAAK;QAC9C,aAAa,EAAE,MAAM,CAAC,cAAc,KAAK,IAAI;QAC7C,iBAAiB,EAAE,MAAM,CAAC,mBAAmB,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK;QAC3E,IAAI,EAAE,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QAC/D,cAAc,EAAE,SAAS;QACzB,cAAc,EAAE,SAAS;KAC1B,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAoB;IACvD,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Response formatters for Tavily tools
3
+ */
4
+ import type { FormattedOutputParts, ImageResult, SearchResult } from "./types.js";
5
+ /**
6
+ * Format Tavily search response into human-readable text
7
+ */
8
+ export declare function formatWebSearchResponse(answer: string | null, results: SearchResult[], images: ImageResult[], includeImages: boolean | undefined): string;
9
+ /**
10
+ * Format Tavily search results into compact parts structure
11
+ */
12
+ export declare function formatSearchResults(answer: string | null, results: SearchResult[], images: ImageResult[], includeImages: boolean): FormattedOutputParts;
13
+ /**
14
+ * Extract and type-safe Tavily response data
15
+ */
16
+ export declare function extractSearchResults(response: unknown): {
17
+ answer: string | null;
18
+ results: SearchResult[];
19
+ images: ImageResult[];
20
+ };
21
+ //# sourceMappingURL=formatters.d.ts.map