bashkit 0.2.1 → 0.2.3

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/AGENTS.md CHANGED
@@ -21,9 +21,9 @@ bun add bashkit ai @ai-sdk/anthropic
21
21
  Runs commands directly on the local machine. Use for development/testing only.
22
22
 
23
23
  ```typescript
24
- import { createAgentTools, LocalSandbox } from "bashkit";
24
+ import { createAgentTools, createLocalSandbox } from "bashkit";
25
25
 
26
- const sandbox = new LocalSandbox("/tmp/workspace");
26
+ const sandbox = createLocalSandbox({ cwd: "/tmp/workspace" });
27
27
  const { tools } = createAgentTools(sandbox);
28
28
  ```
29
29
 
@@ -32,9 +32,9 @@ const { tools } = createAgentTools(sandbox);
32
32
  Runs in isolated Firecracker microVMs on Vercel's infrastructure.
33
33
 
34
34
  ```typescript
35
- import { createAgentTools, VercelSandbox } from "bashkit";
35
+ import { createAgentTools, createVercelSandbox } from "bashkit";
36
36
 
37
- const sandbox = new VercelSandbox({
37
+ const sandbox = createVercelSandbox({
38
38
  runtime: "node22",
39
39
  resources: { vcpus: 2 },
40
40
  });
@@ -44,6 +44,49 @@ const { tools } = createAgentTools(sandbox);
44
44
  await sandbox.destroy();
45
45
  ```
46
46
 
47
+ ### E2BSandbox (Production)
48
+
49
+ Runs in E2B's cloud sandboxes. Requires `@e2b/code-interpreter` peer dependency.
50
+
51
+ ```typescript
52
+ import { createAgentTools, createE2BSandbox } from "bashkit";
53
+
54
+ const sandbox = createE2BSandbox({
55
+ apiKey: process.env.E2B_API_KEY,
56
+ });
57
+ const { tools } = createAgentTools(sandbox);
58
+
59
+ await sandbox.destroy();
60
+ ```
61
+
62
+ ### Sandbox Reconnection (Cloud Sandboxes)
63
+
64
+ Cloud sandboxes (E2B, Vercel) support reconnection via the `id` property and `sandboxId` config:
65
+
66
+ ```typescript
67
+ // Create a new sandbox
68
+ const sandbox = createE2BSandbox({ apiKey: process.env.E2B_API_KEY });
69
+
70
+ // After first operation, the sandbox ID is available
71
+ await sandbox.exec("echo hello");
72
+ const sandboxId = sandbox.id; // "sbx_abc123..."
73
+
74
+ // Store sandboxId in your database (e.g., chat metadata)
75
+ await db.chat.update({ where: { id: chatId }, data: { sandboxId } });
76
+
77
+ // Later: reconnect to the same sandbox
78
+ const savedId = chat.sandboxId;
79
+ const reconnected = createE2BSandbox({
80
+ apiKey: process.env.E2B_API_KEY,
81
+ sandboxId: savedId, // Reconnects instead of creating new
82
+ });
83
+ ```
84
+
85
+ This is useful for:
86
+ - Reusing sandboxes across multiple requests in the same conversation
87
+ - Persisting sandbox state between server restarts
88
+ - Reducing sandbox creation overhead
89
+
47
90
  ## Available Tools
48
91
 
49
92
  ### Default Tools (always included)
@@ -89,11 +132,11 @@ import { generateText, wrapLanguageModel, stepCountIs } from "ai";
89
132
  import { anthropic } from "@ai-sdk/anthropic";
90
133
  import {
91
134
  createAgentTools,
92
- LocalSandbox,
135
+ createLocalSandbox,
93
136
  anthropicPromptCacheMiddleware,
94
137
  } from "bashkit";
95
138
 
96
- const sandbox = new LocalSandbox("/tmp/workspace");
139
+ const sandbox = createLocalSandbox({ cwd: "/tmp/workspace" });
97
140
  const { tools } = createAgentTools(sandbox);
98
141
 
99
142
  // Wrap model with prompt caching (recommended)
@@ -311,12 +354,12 @@ const skills = await discoverSkills();
311
354
  ### Using Skills with Agents
312
355
 
313
356
  ```typescript
314
- import { discoverSkills, skillsToXml, createAgentTools, LocalSandbox } from "bashkit";
357
+ import { discoverSkills, skillsToXml, createAgentTools, createLocalSandbox } from "bashkit";
315
358
  import { generateText, stepCountIs } from "ai";
316
359
  import { anthropic } from "@ai-sdk/anthropic";
317
360
 
318
361
  const skills = await discoverSkills();
319
- const sandbox = new LocalSandbox("/tmp/workspace");
362
+ const sandbox = createLocalSandbox({ cwd: "/tmp/workspace" });
320
363
  const { tools } = createAgentTools(sandbox);
321
364
 
322
365
  const result = await generateText({
@@ -421,13 +464,13 @@ import {
421
464
  createAgentTools,
422
465
  createTaskTool,
423
466
  createTodoWriteTool,
424
- LocalSandbox,
467
+ createLocalSandbox,
425
468
  anthropicPromptCacheMiddleware,
426
469
  type TodoState,
427
470
  } from "bashkit";
428
471
 
429
472
  // 1. Create sandbox
430
- const sandbox = new LocalSandbox("/tmp/workspace");
473
+ const sandbox = createLocalSandbox({ cwd: "/tmp/workspace" });
431
474
 
432
475
  // 2. Create sandbox tools
433
476
  const { tools: sandboxTools } = createAgentTools(sandbox);
@@ -489,9 +532,9 @@ const { tools } = createAgentTools(sandbox, {
489
532
  Cache tool execution results to avoid redundant operations:
490
533
 
491
534
  ```typescript
492
- import { createAgentTools, LocalSandbox } from "bashkit";
535
+ import { createAgentTools, createLocalSandbox } from "bashkit";
493
536
 
494
- const sandbox = new LocalSandbox("/tmp/workspace");
537
+ const sandbox = createLocalSandbox({ cwd: "/tmp/workspace" });
495
538
 
496
539
  // Enable caching with defaults (LRU, 5min TTL)
497
540
  const { tools } = createAgentTools(sandbox, { cache: true });
package/README.md CHANGED
@@ -148,6 +148,15 @@ const sandbox = createVercelSandbox({
148
148
  runtime: 'node22',
149
149
  resources: { vcpus: 2 },
150
150
  });
151
+
152
+ // After first operation, get the sandbox ID for persistence
153
+ await sandbox.exec('echo hello');
154
+ console.log(sandbox.id); // Sandbox ID for reconnection
155
+
156
+ // Later: reconnect to the same sandbox
157
+ const reconnected = createVercelSandbox({
158
+ sandboxId: 'existing-sandbox-id',
159
+ });
151
160
  ```
152
161
 
153
162
  ### E2BSandbox
@@ -158,7 +167,17 @@ Runs in E2B's cloud sandboxes. Requires `@e2b/code-interpreter` peer dependency.
158
167
  import { createE2BSandbox } from 'bashkit';
159
168
 
160
169
  const sandbox = createE2BSandbox({
161
- // E2B config
170
+ apiKey: process.env.E2B_API_KEY,
171
+ });
172
+
173
+ // After first operation, get the sandbox ID for persistence
174
+ await sandbox.exec('echo hello');
175
+ console.log(sandbox.id); // "sbx_abc123..."
176
+
177
+ // Later: reconnect to the same sandbox
178
+ const reconnected = createE2BSandbox({
179
+ apiKey: process.env.E2B_API_KEY,
180
+ sandboxId: 'sbx_abc123...', // Reconnect to existing sandbox
162
181
  });
163
182
  ```
164
183
 
@@ -764,9 +783,14 @@ interface Sandbox {
764
783
  readDir(path: string): Promise<string[]>;
765
784
  fileExists(path: string): Promise<boolean>;
766
785
  destroy(): Promise<void>;
786
+
787
+ // Optional: Sandbox ID for reconnection (cloud providers only)
788
+ readonly id?: string;
767
789
  }
768
790
  ```
769
791
 
792
+ The `id` property is available on cloud sandboxes (E2B, Vercel) after the first operation. Use it to persist the sandbox ID and reconnect later.
793
+
770
794
  ### Custom Sandbox Example
771
795
 
772
796
  ```typescript
package/dist/index.js CHANGED
@@ -50,19 +50,31 @@ var anthropicPromptCacheMiddleware = {
50
50
  transformParams: async ({ params }) => applyCacheMarkers(params)
51
51
  };
52
52
  // src/sandbox/e2b.ts
53
- import { Sandbox as E2BSandboxSDK } from "@e2b/code-interpreter";
54
53
  function createE2BSandbox(config = {}) {
55
54
  let sandbox = null;
55
+ let sandboxId = config.sandboxId;
56
56
  const workingDirectory = config.cwd || "/home/user";
57
57
  const timeout = config.timeout ?? 300000;
58
58
  const ensureSandbox = async () => {
59
59
  if (sandbox)
60
60
  return sandbox;
61
- sandbox = await E2BSandboxSDK.create({
62
- apiKey: config.apiKey,
63
- timeoutMs: timeout,
64
- metadata: config.metadata
65
- });
61
+ let E2BSandboxSDK;
62
+ try {
63
+ const module = await import("@e2b/code-interpreter");
64
+ E2BSandboxSDK = module.Sandbox;
65
+ } catch {
66
+ throw new Error("E2BSandbox requires @e2b/code-interpreter. Install with: npm install @e2b/code-interpreter");
67
+ }
68
+ if (config.sandboxId) {
69
+ sandbox = await E2BSandboxSDK.connect(config.sandboxId);
70
+ } else {
71
+ sandbox = await E2BSandboxSDK.create({
72
+ apiKey: config.apiKey,
73
+ timeoutMs: timeout,
74
+ metadata: config.metadata
75
+ });
76
+ sandboxId = sandbox.sandboxId;
77
+ }
66
78
  return sandbox;
67
79
  };
68
80
  const exec = async (command, options) => {
@@ -108,6 +120,9 @@ function createE2BSandbox(config = {}) {
108
120
  };
109
121
  return {
110
122
  exec,
123
+ get id() {
124
+ return sandboxId;
125
+ },
111
126
  async readFile(path) {
112
127
  const result = await exec(`cat "${path}"`);
113
128
  if (result.exitCode !== 0) {
@@ -224,9 +239,9 @@ function createLocalSandbox(config = {}) {
224
239
  };
225
240
  }
226
241
  // src/sandbox/vercel.ts
227
- import { Sandbox as VercelSandboxSDK } from "@vercel/sandbox";
228
242
  function createVercelSandbox(config = {}) {
229
243
  let sandbox = null;
244
+ let sandboxId = config.sandboxId;
230
245
  const workingDirectory = config.cwd || "/vercel/sandbox";
231
246
  const resolvedConfig = {
232
247
  runtime: config.runtime ?? "node22",
@@ -236,6 +251,13 @@ function createVercelSandbox(config = {}) {
236
251
  const ensureSandbox = async () => {
237
252
  if (sandbox)
238
253
  return sandbox;
254
+ let VercelSandboxSDK;
255
+ try {
256
+ const module = await import("@vercel/sandbox");
257
+ VercelSandboxSDK = module.Sandbox;
258
+ } catch {
259
+ throw new Error("VercelSandbox requires @vercel/sandbox. Install with: npm install @vercel/sandbox");
260
+ }
239
261
  const createOptions = {
240
262
  runtime: resolvedConfig.runtime,
241
263
  resources: resolvedConfig.resources,
@@ -247,7 +269,12 @@ function createVercelSandbox(config = {}) {
247
269
  token: config.token
248
270
  });
249
271
  }
250
- sandbox = await VercelSandboxSDK.create(createOptions);
272
+ if (config.sandboxId) {
273
+ sandbox = await VercelSandboxSDK.get({ sandboxId: config.sandboxId });
274
+ } else {
275
+ sandbox = await VercelSandboxSDK.create(createOptions);
276
+ }
277
+ sandboxId = sandbox.sandboxId;
251
278
  return sandbox;
252
279
  };
253
280
  const exec = async (command, options) => {
@@ -301,6 +328,9 @@ function createVercelSandbox(config = {}) {
301
328
  };
302
329
  return {
303
330
  exec,
331
+ get id() {
332
+ return sandboxId;
333
+ },
304
334
  async readFile(path) {
305
335
  const sbx = await ensureSandbox();
306
336
  const stream = await sbx.readFile({ path });
@@ -1372,13 +1402,56 @@ function createSkillTool(config) {
1372
1402
 
1373
1403
  // src/tools/web-fetch.ts
1374
1404
  import { generateText, tool as tool10, zodSchema as zodSchema10 } from "ai";
1375
- import Parallel from "parallel-web";
1376
1405
  import { z as z10 } from "zod";
1377
1406
 
1378
1407
  // src/utils/http-constants.ts
1379
1408
  var RETRYABLE_STATUS_CODES = [408, 429, 500, 502, 503];
1380
1409
 
1381
1410
  // src/tools/web-fetch.ts
1411
+ var parallelModule = null;
1412
+ async function getParallelModule() {
1413
+ if (!parallelModule) {
1414
+ try {
1415
+ parallelModule = await import("parallel-web");
1416
+ } catch {
1417
+ throw new Error("WebFetch requires parallel-web. Install with: npm install parallel-web");
1418
+ }
1419
+ }
1420
+ return parallelModule;
1421
+ }
1422
+ async function fetchWithParallel(url, apiKey) {
1423
+ const { default: Parallel } = await getParallelModule();
1424
+ const client = new Parallel({ apiKey });
1425
+ const extract = await client.beta.extract({
1426
+ urls: [url],
1427
+ excerpts: true,
1428
+ full_content: true
1429
+ });
1430
+ if (!extract.results || extract.results.length === 0) {
1431
+ throw new Error("No content extracted from URL");
1432
+ }
1433
+ const result = extract.results[0];
1434
+ const content = result.full_content || result.excerpts?.join(`
1435
+
1436
+ `) || "";
1437
+ if (!content) {
1438
+ throw new Error("No content available from URL");
1439
+ }
1440
+ return {
1441
+ content,
1442
+ finalUrl: result.url
1443
+ };
1444
+ }
1445
+ async function fetchContent(url, apiKey, provider) {
1446
+ switch (provider) {
1447
+ case "parallel":
1448
+ return fetchWithParallel(url, apiKey);
1449
+ default: {
1450
+ const _exhaustive = provider;
1451
+ throw new Error(`Unknown provider: ${_exhaustive}`);
1452
+ }
1453
+ }
1454
+ }
1382
1455
  var webFetchInputSchema = z10.object({
1383
1456
  url: z10.string().describe("The URL to fetch content from"),
1384
1457
  prompt: z10.string().describe("The prompt to run on the fetched content")
@@ -1400,7 +1473,14 @@ Usage notes:
1400
1473
  - When a URL redirects to a different host, the tool will inform you and provide the redirect URL. You should then make a new WebFetch request with the redirect URL to fetch the content.
1401
1474
  `;
1402
1475
  function createWebFetchTool(config) {
1403
- const { apiKey, model, strict, needsApproval, providerOptions } = config;
1476
+ const {
1477
+ provider = "parallel",
1478
+ apiKey,
1479
+ model,
1480
+ strict,
1481
+ needsApproval,
1482
+ providerOptions
1483
+ } = config;
1404
1484
  return tool10({
1405
1485
  description: WEB_FETCH_DESCRIPTION,
1406
1486
  inputSchema: zodSchema10(webFetchInputSchema),
@@ -1410,30 +1490,7 @@ function createWebFetchTool(config) {
1410
1490
  execute: async (input) => {
1411
1491
  const { url, prompt } = input;
1412
1492
  try {
1413
- const client = new Parallel({ apiKey });
1414
- const extract = await client.beta.extract({
1415
- urls: [url],
1416
- excerpts: true,
1417
- full_content: true
1418
- });
1419
- if (!extract.results || extract.results.length === 0) {
1420
- return {
1421
- error: "No content extracted from URL",
1422
- status_code: 404,
1423
- retryable: false
1424
- };
1425
- }
1426
- const extractedResult = extract.results[0];
1427
- const content = extractedResult.full_content || extractedResult.excerpts?.join(`
1428
-
1429
- `) || "";
1430
- if (!content) {
1431
- return {
1432
- error: "No content available from URL",
1433
- status_code: 404,
1434
- retryable: false
1435
- };
1436
- }
1493
+ const { content, finalUrl } = await fetchContent(url, apiKey, provider);
1437
1494
  const result = await generateText({
1438
1495
  model,
1439
1496
  prompt: `${prompt}
@@ -1445,7 +1502,7 @@ ${content}`
1445
1502
  return {
1446
1503
  response: result.text,
1447
1504
  url,
1448
- final_url: extractedResult.url || url
1505
+ final_url: finalUrl || url
1449
1506
  };
1450
1507
  } catch (error) {
1451
1508
  if (error && typeof error === "object" && "status" in error) {
@@ -1467,8 +1524,53 @@ ${content}`
1467
1524
 
1468
1525
  // src/tools/web-search.ts
1469
1526
  import { tool as tool11, zodSchema as zodSchema11 } from "ai";
1470
- import Parallel2 from "parallel-web";
1471
1527
  import { z as z11 } from "zod";
1528
+ var parallelModule2 = null;
1529
+ async function getParallelModule2() {
1530
+ if (!parallelModule2) {
1531
+ try {
1532
+ parallelModule2 = await import("parallel-web");
1533
+ } catch {
1534
+ throw new Error("WebSearch requires parallel-web. Install with: npm install parallel-web");
1535
+ }
1536
+ }
1537
+ return parallelModule2;
1538
+ }
1539
+ async function searchWithParallel(apiKey, options) {
1540
+ const { default: Parallel } = await getParallelModule2();
1541
+ const client = new Parallel({ apiKey });
1542
+ const sourcePolicy = options.allowedDomains || options.blockedDomains ? {
1543
+ ...options.allowedDomains && {
1544
+ include_domains: options.allowedDomains
1545
+ },
1546
+ ...options.blockedDomains && {
1547
+ exclude_domains: options.blockedDomains
1548
+ }
1549
+ } : undefined;
1550
+ const search = await client.beta.search({
1551
+ mode: "agentic",
1552
+ objective: options.query,
1553
+ max_results: 10,
1554
+ ...sourcePolicy && { source_policy: sourcePolicy }
1555
+ });
1556
+ return (search.results || []).map((result) => ({
1557
+ title: result.title ?? "",
1558
+ url: result.url ?? "",
1559
+ snippet: result.excerpts?.join(`
1560
+ `) ?? "",
1561
+ metadata: result.publish_date ? { publish_date: result.publish_date } : undefined
1562
+ }));
1563
+ }
1564
+ async function searchContent(apiKey, provider, options) {
1565
+ switch (provider) {
1566
+ case "parallel":
1567
+ return searchWithParallel(apiKey, options);
1568
+ default: {
1569
+ const _exhaustive = provider;
1570
+ throw new Error(`Unknown provider: ${_exhaustive}`);
1571
+ }
1572
+ }
1573
+ }
1472
1574
  var webSearchInputSchema = z11.object({
1473
1575
  query: z11.string().describe("The search query to use"),
1474
1576
  allowed_domains: z11.array(z11.string()).optional().describe("Only include results from these domains"),
@@ -1495,7 +1597,13 @@ When searching for recent information, documentation, or current events, use the
1495
1597
  - allowed_domains: Only include results from these domains
1496
1598
  - blocked_domains: Never include results from these domains`;
1497
1599
  function createWebSearchTool(config) {
1498
- const { apiKey, strict, needsApproval, providerOptions } = config;
1600
+ const {
1601
+ provider = "parallel",
1602
+ apiKey,
1603
+ strict,
1604
+ needsApproval,
1605
+ providerOptions
1606
+ } = config;
1499
1607
  return tool11({
1500
1608
  description: WEB_SEARCH_DESCRIPTION,
1501
1609
  inputSchema: zodSchema11(webSearchInputSchema),
@@ -1505,24 +1613,11 @@ function createWebSearchTool(config) {
1505
1613
  execute: async (input) => {
1506
1614
  const { query, allowed_domains, blocked_domains } = input;
1507
1615
  try {
1508
- const client = new Parallel2({ apiKey });
1509
- const sourcePolicy = allowed_domains || blocked_domains ? {
1510
- ...allowed_domains && { include_domains: allowed_domains },
1511
- ...blocked_domains && { exclude_domains: blocked_domains }
1512
- } : undefined;
1513
- const search = await client.beta.search({
1514
- mode: "agentic",
1515
- objective: query,
1516
- max_results: 10,
1517
- ...sourcePolicy && { source_policy: sourcePolicy }
1616
+ const results = await searchContent(apiKey, provider, {
1617
+ query,
1618
+ allowedDomains: allowed_domains,
1619
+ blockedDomains: blocked_domains
1518
1620
  });
1519
- const results = (search.results || []).map((result) => ({
1520
- title: result.title ?? "",
1521
- url: result.url ?? "",
1522
- snippet: result.excerpts?.join(`
1523
- `) ?? "",
1524
- metadata: result.publish_date ? { publish_date: result.publish_date } : undefined
1525
- }));
1526
1621
  return {
1527
1622
  results,
1528
1623
  total_results: results.length,
@@ -1,6 +1,8 @@
1
1
  import type { Sandbox } from "./interface";
2
2
  export interface E2BSandboxConfig {
3
3
  apiKey?: string;
4
+ /** Existing sandbox ID to reconnect to instead of creating new */
5
+ sandboxId?: string;
4
6
  template?: string;
5
7
  timeout?: number;
6
8
  cwd?: string;
@@ -18,4 +18,11 @@ export interface Sandbox {
18
18
  fileExists(path: string): Promise<boolean>;
19
19
  isDirectory(path: string): Promise<boolean>;
20
20
  destroy(): Promise<void>;
21
+ /**
22
+ * Sandbox ID for reconnection (cloud providers only).
23
+ * - For new sandboxes: available after first operation
24
+ * - For reconnected sandboxes: available immediately
25
+ * - For local sandboxes: always undefined
26
+ */
27
+ readonly id?: string;
21
28
  }
@@ -4,6 +4,8 @@ export interface VercelSandboxConfig {
4
4
  resources?: {
5
5
  vcpus: number;
6
6
  };
7
+ /** Existing sandbox ID to reconnect to instead of creating new */
8
+ sandboxId?: string;
7
9
  timeout?: number;
8
10
  cwd?: string;
9
11
  teamId?: string;
@@ -69,7 +69,7 @@ export type { SubagentEventData, SubagentStepEvent, SubagentTypeConfig, TaskErro
69
69
  export { createTaskTool } from "./task";
70
70
  export type { TodoItem, TodoState, TodoWriteError, TodoWriteOutput, } from "./todo-write";
71
71
  export { createTodoWriteTool } from "./todo-write";
72
- export type { WebFetchError, WebFetchOutput } from "./web-fetch";
72
+ export type { ExtractResult, WebFetchError, WebFetchOutput } from "./web-fetch";
73
73
  export { createWebFetchTool } from "./web-fetch";
74
74
  export type { WebSearchError, WebSearchOutput, WebSearchResult, } from "./web-search";
75
75
  export { createWebSearchTool } from "./web-search";
@@ -10,6 +10,14 @@ export interface WebFetchError {
10
10
  status_code?: number;
11
11
  retryable?: boolean;
12
12
  }
13
+ /**
14
+ * Result from a web fetch provider's extract operation.
15
+ * New providers should return this shape.
16
+ */
17
+ export interface ExtractResult {
18
+ content: string;
19
+ finalUrl?: string;
20
+ }
13
21
  export declare function createWebFetchTool(config: WebFetchConfig): import("ai").Tool<{
14
22
  url: string;
15
23
  prompt: string;
package/dist/types.d.ts CHANGED
@@ -25,10 +25,26 @@ export type GrepToolConfig = ToolConfig & {
25
25
  /** Use ripgrep (rg) instead of grep. Requires ripgrep to be installed. Default: false */
26
26
  useRipgrep?: boolean;
27
27
  };
28
+ /**
29
+ * Supported web search providers.
30
+ * Currently only 'parallel' is implemented.
31
+ * Add new providers here as union types (e.g., 'parallel' | 'serper' | 'tavily')
32
+ */
33
+ export type WebSearchProvider = "parallel";
34
+ /**
35
+ * Supported web fetch providers.
36
+ * Currently only 'parallel' is implemented.
37
+ * Add new providers here as union types (e.g., 'parallel' | 'firecrawl' | 'jina')
38
+ */
39
+ export type WebFetchProvider = "parallel";
28
40
  export type WebSearchConfig = {
41
+ /** Provider to use for web search. Default: 'parallel' */
42
+ provider?: WebSearchProvider;
29
43
  apiKey: string;
30
44
  } & SDKToolOptions;
31
45
  export type WebFetchConfig = {
46
+ /** Provider to use for web fetching. Default: 'parallel' */
47
+ provider?: WebFetchProvider;
32
48
  apiKey: string;
33
49
  model: LanguageModel;
34
50
  } & SDKToolOptions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bashkit",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Agentic coding tools for the Vercel AI SDK",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",