bashkit 0.1.3 → 0.2.2
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 +108 -0
- package/README.md +148 -1
- package/dist/cache/cached.d.ts +37 -0
- package/dist/cache/index.d.ts +6 -0
- package/dist/cache/lru.d.ts +25 -0
- package/dist/cache/redis.d.ts +41 -0
- package/dist/cache/types.d.ts +53 -0
- package/dist/index.d.ts +7 -5
- package/dist/index.js +318 -43
- package/dist/middleware/anthropic-cache.d.ts +20 -1
- package/dist/middleware/index.d.ts +1 -1
- package/dist/sandbox/e2b.d.ts +2 -0
- package/dist/sandbox/interface.d.ts +7 -0
- package/dist/sandbox/vercel.d.ts +2 -0
- package/dist/skills/index.d.ts +1 -1
- package/dist/skills/loader.d.ts +36 -0
- package/dist/tools/exit-plan-mode.d.ts +1 -2
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/task.d.ts +11 -1
- package/dist/tools/todo-write.d.ts +1 -2
- package/dist/tools/web-constants.d.ts +5 -0
- package/dist/tools/web-fetch.d.ts +2 -6
- package/dist/tools/web-search.d.ts +2 -4
- package/dist/types.d.ts +54 -4
- package/dist/utils/http-constants.d.ts +5 -0
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -18,10 +18,8 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
18
18
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
19
|
|
|
20
20
|
// src/middleware/anthropic-cache.ts
|
|
21
|
-
function
|
|
22
|
-
if (!message)
|
|
23
|
-
return;
|
|
24
|
-
if (!("content" in message))
|
|
21
|
+
function addCacheMarker(message) {
|
|
22
|
+
if (!message || !("content" in message))
|
|
25
23
|
return;
|
|
26
24
|
const content = message.content;
|
|
27
25
|
if (!content || !Array.isArray(content))
|
|
@@ -36,36 +34,41 @@ function ensureCacheMarker(message) {
|
|
|
36
34
|
}
|
|
37
35
|
};
|
|
38
36
|
}
|
|
37
|
+
function applyCacheMarkers(params) {
|
|
38
|
+
const messages = params.prompt;
|
|
39
|
+
if (!messages || messages.length === 0)
|
|
40
|
+
return params;
|
|
41
|
+
addCacheMarker(messages.at(-1));
|
|
42
|
+
addCacheMarker(messages.slice(0, -1).findLast((m) => m.role !== "assistant"));
|
|
43
|
+
return params;
|
|
44
|
+
}
|
|
45
|
+
var anthropicPromptCacheMiddlewareV2 = {
|
|
46
|
+
transformParams: async ({ params }) => applyCacheMarkers(params)
|
|
47
|
+
};
|
|
39
48
|
var anthropicPromptCacheMiddleware = {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}) => {
|
|
43
|
-
const messages = params.prompt;
|
|
44
|
-
if (!messages || messages.length === 0) {
|
|
45
|
-
return params;
|
|
46
|
-
}
|
|
47
|
-
ensureCacheMarker(messages.at(-1));
|
|
48
|
-
ensureCacheMarker(messages.slice(0, -1).findLast((m) => m.role !== "assistant"));
|
|
49
|
-
return {
|
|
50
|
-
...params,
|
|
51
|
-
prompt: messages
|
|
52
|
-
};
|
|
53
|
-
}
|
|
49
|
+
specificationVersion: "v3",
|
|
50
|
+
transformParams: async ({ params }) => applyCacheMarkers(params)
|
|
54
51
|
};
|
|
55
52
|
// src/sandbox/e2b.ts
|
|
56
53
|
import { Sandbox as E2BSandboxSDK } from "@e2b/code-interpreter";
|
|
57
54
|
function createE2BSandbox(config = {}) {
|
|
58
55
|
let sandbox = null;
|
|
56
|
+
let sandboxId = config.sandboxId;
|
|
59
57
|
const workingDirectory = config.cwd || "/home/user";
|
|
60
58
|
const timeout = config.timeout ?? 300000;
|
|
61
59
|
const ensureSandbox = async () => {
|
|
62
60
|
if (sandbox)
|
|
63
61
|
return sandbox;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
if (config.sandboxId) {
|
|
63
|
+
sandbox = await E2BSandboxSDK.connect(config.sandboxId);
|
|
64
|
+
} else {
|
|
65
|
+
sandbox = await E2BSandboxSDK.create({
|
|
66
|
+
apiKey: config.apiKey,
|
|
67
|
+
timeoutMs: timeout,
|
|
68
|
+
metadata: config.metadata
|
|
69
|
+
});
|
|
70
|
+
sandboxId = sandbox.sandboxId;
|
|
71
|
+
}
|
|
69
72
|
return sandbox;
|
|
70
73
|
};
|
|
71
74
|
const exec = async (command, options) => {
|
|
@@ -111,6 +114,9 @@ function createE2BSandbox(config = {}) {
|
|
|
111
114
|
};
|
|
112
115
|
return {
|
|
113
116
|
exec,
|
|
117
|
+
get id() {
|
|
118
|
+
return sandboxId;
|
|
119
|
+
},
|
|
114
120
|
async readFile(path) {
|
|
115
121
|
const result = await exec(`cat "${path}"`);
|
|
116
122
|
if (result.exitCode !== 0) {
|
|
@@ -230,6 +236,7 @@ function createLocalSandbox(config = {}) {
|
|
|
230
236
|
import { Sandbox as VercelSandboxSDK } from "@vercel/sandbox";
|
|
231
237
|
function createVercelSandbox(config = {}) {
|
|
232
238
|
let sandbox = null;
|
|
239
|
+
let sandboxId = config.sandboxId;
|
|
233
240
|
const workingDirectory = config.cwd || "/vercel/sandbox";
|
|
234
241
|
const resolvedConfig = {
|
|
235
242
|
runtime: config.runtime ?? "node22",
|
|
@@ -250,7 +257,12 @@ function createVercelSandbox(config = {}) {
|
|
|
250
257
|
token: config.token
|
|
251
258
|
});
|
|
252
259
|
}
|
|
253
|
-
|
|
260
|
+
if (config.sandboxId) {
|
|
261
|
+
sandbox = await VercelSandboxSDK.get({ sandboxId: config.sandboxId });
|
|
262
|
+
} else {
|
|
263
|
+
sandbox = await VercelSandboxSDK.create(createOptions);
|
|
264
|
+
}
|
|
265
|
+
sandboxId = sandbox.sandboxId;
|
|
254
266
|
return sandbox;
|
|
255
267
|
};
|
|
256
268
|
const exec = async (command, options) => {
|
|
@@ -304,6 +316,9 @@ function createVercelSandbox(config = {}) {
|
|
|
304
316
|
};
|
|
305
317
|
return {
|
|
306
318
|
exec,
|
|
319
|
+
get id() {
|
|
320
|
+
return sandboxId;
|
|
321
|
+
},
|
|
307
322
|
async readFile(path) {
|
|
308
323
|
const sbx = await ensureSandbox();
|
|
309
324
|
const stream = await sbx.readFile({ path });
|
|
@@ -349,6 +364,132 @@ function createVercelSandbox(config = {}) {
|
|
|
349
364
|
}
|
|
350
365
|
};
|
|
351
366
|
}
|
|
367
|
+
// src/cache/lru.ts
|
|
368
|
+
class LRUCacheStore {
|
|
369
|
+
cache = new Map;
|
|
370
|
+
maxSize;
|
|
371
|
+
constructor(maxSize = 1000) {
|
|
372
|
+
this.maxSize = maxSize;
|
|
373
|
+
}
|
|
374
|
+
get(key) {
|
|
375
|
+
const entry = this.cache.get(key);
|
|
376
|
+
if (entry) {
|
|
377
|
+
this.cache.delete(key);
|
|
378
|
+
this.cache.set(key, entry);
|
|
379
|
+
}
|
|
380
|
+
return entry;
|
|
381
|
+
}
|
|
382
|
+
set(key, entry) {
|
|
383
|
+
if (this.cache.has(key)) {
|
|
384
|
+
this.cache.delete(key);
|
|
385
|
+
} else if (this.cache.size >= this.maxSize) {
|
|
386
|
+
const firstKey = this.cache.keys().next().value;
|
|
387
|
+
if (firstKey !== undefined) {
|
|
388
|
+
this.cache.delete(firstKey);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
this.cache.set(key, entry);
|
|
392
|
+
}
|
|
393
|
+
delete(key) {
|
|
394
|
+
this.cache.delete(key);
|
|
395
|
+
}
|
|
396
|
+
clear() {
|
|
397
|
+
this.cache.clear();
|
|
398
|
+
}
|
|
399
|
+
size() {
|
|
400
|
+
return this.cache.size;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
// src/cache/cached.ts
|
|
404
|
+
import { createHash } from "crypto";
|
|
405
|
+
function defaultKeyGenerator(toolName, params) {
|
|
406
|
+
const sortedKeys = params && typeof params === "object" ? Object.keys(params).sort() : undefined;
|
|
407
|
+
const serialized = JSON.stringify(params, sortedKeys);
|
|
408
|
+
const hash = createHash("sha256").update(serialized).digest("hex").slice(0, 16);
|
|
409
|
+
return `${toolName}:${hash}`;
|
|
410
|
+
}
|
|
411
|
+
function cached(tool, toolName, options = {}) {
|
|
412
|
+
const {
|
|
413
|
+
ttl = 5 * 60 * 1000,
|
|
414
|
+
store = new LRUCacheStore,
|
|
415
|
+
keyGenerator = defaultKeyGenerator,
|
|
416
|
+
debug = false,
|
|
417
|
+
onHit,
|
|
418
|
+
onMiss
|
|
419
|
+
} = options;
|
|
420
|
+
let hits = 0;
|
|
421
|
+
let misses = 0;
|
|
422
|
+
const log = debug ? console.log.bind(console) : () => {};
|
|
423
|
+
const cachedTool = {
|
|
424
|
+
...tool,
|
|
425
|
+
execute: async (params, execOptions) => {
|
|
426
|
+
const key = keyGenerator(toolName, params);
|
|
427
|
+
const now = Date.now();
|
|
428
|
+
const entry = await store.get(key);
|
|
429
|
+
if (entry && now - entry.timestamp < ttl) {
|
|
430
|
+
hits++;
|
|
431
|
+
log(`[Cache] HIT ${toolName}:${key.slice(-8)}`);
|
|
432
|
+
onHit?.(toolName, key);
|
|
433
|
+
return entry.result;
|
|
434
|
+
}
|
|
435
|
+
misses++;
|
|
436
|
+
log(`[Cache] MISS ${toolName}:${key.slice(-8)}`);
|
|
437
|
+
onMiss?.(toolName, key);
|
|
438
|
+
if (!tool.execute) {
|
|
439
|
+
throw new Error(`Tool ${toolName} has no execute function`);
|
|
440
|
+
}
|
|
441
|
+
const result = await tool.execute(params, execOptions);
|
|
442
|
+
if (result && typeof result === "object" && !("error" in result)) {
|
|
443
|
+
await store.set(key, { result, timestamp: now });
|
|
444
|
+
log(`[Cache] STORED ${toolName}:${key.slice(-8)}`);
|
|
445
|
+
}
|
|
446
|
+
return result;
|
|
447
|
+
},
|
|
448
|
+
async getStats() {
|
|
449
|
+
const total = hits + misses;
|
|
450
|
+
const size = await store.size?.() ?? 0;
|
|
451
|
+
return {
|
|
452
|
+
hits,
|
|
453
|
+
misses,
|
|
454
|
+
hitRate: total > 0 ? hits / total : 0,
|
|
455
|
+
size
|
|
456
|
+
};
|
|
457
|
+
},
|
|
458
|
+
async clearCache(key) {
|
|
459
|
+
if (key) {
|
|
460
|
+
await store.delete(key);
|
|
461
|
+
} else {
|
|
462
|
+
await store.clear();
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
return cachedTool;
|
|
467
|
+
}
|
|
468
|
+
// src/cache/redis.ts
|
|
469
|
+
function createRedisCacheStore(client, options = {}) {
|
|
470
|
+
const { prefix = "bashkit:" } = options;
|
|
471
|
+
return {
|
|
472
|
+
async get(key) {
|
|
473
|
+
const data = await client.get(`${prefix}${key}`);
|
|
474
|
+
return data ? JSON.parse(data) : undefined;
|
|
475
|
+
},
|
|
476
|
+
async set(key, entry) {
|
|
477
|
+
await client.set(`${prefix}${key}`, JSON.stringify(entry));
|
|
478
|
+
},
|
|
479
|
+
async delete(key) {
|
|
480
|
+
await client.del(`${prefix}${key}`);
|
|
481
|
+
},
|
|
482
|
+
async clear() {
|
|
483
|
+
const keys = await client.keys(`${prefix}*`);
|
|
484
|
+
if (keys.length)
|
|
485
|
+
await client.del(keys);
|
|
486
|
+
},
|
|
487
|
+
async size() {
|
|
488
|
+
const keys = await client.keys(`${prefix}*`);
|
|
489
|
+
return keys.length;
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
}
|
|
352
493
|
// src/types.ts
|
|
353
494
|
var DEFAULT_CONFIG = {
|
|
354
495
|
defaultTimeout: 120000,
|
|
@@ -500,6 +641,9 @@ function createBashTool(sandbox, config) {
|
|
|
500
641
|
return tool2({
|
|
501
642
|
description: BASH_DESCRIPTION,
|
|
502
643
|
inputSchema: zodSchema2(bashInputSchema),
|
|
644
|
+
strict: config?.strict,
|
|
645
|
+
needsApproval: config?.needsApproval,
|
|
646
|
+
providerOptions: config?.providerOptions,
|
|
503
647
|
execute: async ({
|
|
504
648
|
command,
|
|
505
649
|
timeout,
|
|
@@ -576,6 +720,9 @@ function createEditTool(sandbox, config) {
|
|
|
576
720
|
return tool3({
|
|
577
721
|
description: EDIT_DESCRIPTION,
|
|
578
722
|
inputSchema: zodSchema3(editInputSchema),
|
|
723
|
+
strict: config?.strict,
|
|
724
|
+
needsApproval: config?.needsApproval,
|
|
725
|
+
providerOptions: config?.providerOptions,
|
|
579
726
|
execute: async ({
|
|
580
727
|
file_path,
|
|
581
728
|
old_string,
|
|
@@ -750,7 +897,7 @@ Before using this tool, ensure your plan is clear and unambiguous. If there are
|
|
|
750
897
|
1. "Search for and understand the implementation of X" - Do NOT use this tool (research task)
|
|
751
898
|
2. "Help me implement feature Y" - Use this tool after planning the implementation steps
|
|
752
899
|
3. "Add user authentication" - If unsure about approach (OAuth vs JWT), clarify first, then use this tool`;
|
|
753
|
-
function createExitPlanModeTool(
|
|
900
|
+
function createExitPlanModeTool(onPlanSubmit) {
|
|
754
901
|
return tool5({
|
|
755
902
|
description: EXIT_PLAN_MODE_DESCRIPTION,
|
|
756
903
|
inputSchema: zodSchema5(exitPlanModeInputSchema),
|
|
@@ -794,6 +941,9 @@ function createGlobTool(sandbox, config) {
|
|
|
794
941
|
return tool6({
|
|
795
942
|
description: GLOB_DESCRIPTION,
|
|
796
943
|
inputSchema: zodSchema6(globInputSchema),
|
|
944
|
+
strict: config?.strict,
|
|
945
|
+
needsApproval: config?.needsApproval,
|
|
946
|
+
providerOptions: config?.providerOptions,
|
|
797
947
|
execute: async ({
|
|
798
948
|
pattern,
|
|
799
949
|
path
|
|
@@ -871,6 +1021,9 @@ function createGrepTool(sandbox, config) {
|
|
|
871
1021
|
return tool7({
|
|
872
1022
|
description: GREP_DESCRIPTION,
|
|
873
1023
|
inputSchema: zodSchema7(grepInputSchema),
|
|
1024
|
+
strict: config?.strict,
|
|
1025
|
+
needsApproval: config?.needsApproval,
|
|
1026
|
+
providerOptions: config?.providerOptions,
|
|
874
1027
|
execute: async (input) => {
|
|
875
1028
|
const {
|
|
876
1029
|
pattern,
|
|
@@ -1080,6 +1233,9 @@ function createReadTool(sandbox, config) {
|
|
|
1080
1233
|
return tool8({
|
|
1081
1234
|
description: READ_DESCRIPTION,
|
|
1082
1235
|
inputSchema: zodSchema8(readInputSchema),
|
|
1236
|
+
strict: config?.strict,
|
|
1237
|
+
needsApproval: config?.needsApproval,
|
|
1238
|
+
providerOptions: config?.providerOptions,
|
|
1083
1239
|
execute: async ({
|
|
1084
1240
|
file_path,
|
|
1085
1241
|
offset,
|
|
@@ -1236,11 +1392,15 @@ function createSkillTool(config) {
|
|
|
1236
1392
|
import { generateText, tool as tool10, zodSchema as zodSchema10 } from "ai";
|
|
1237
1393
|
import Parallel from "parallel-web";
|
|
1238
1394
|
import { z as z10 } from "zod";
|
|
1395
|
+
|
|
1396
|
+
// src/utils/http-constants.ts
|
|
1397
|
+
var RETRYABLE_STATUS_CODES = [408, 429, 500, 502, 503];
|
|
1398
|
+
|
|
1399
|
+
// src/tools/web-fetch.ts
|
|
1239
1400
|
var webFetchInputSchema = z10.object({
|
|
1240
1401
|
url: z10.string().describe("The URL to fetch content from"),
|
|
1241
1402
|
prompt: z10.string().describe("The prompt to run on the fetched content")
|
|
1242
1403
|
});
|
|
1243
|
-
var RETRYABLE_CODES = [408, 429, 500, 502, 503];
|
|
1244
1404
|
var WEB_FETCH_DESCRIPTION = `
|
|
1245
1405
|
- Fetches content from a specified URL and processes it using an AI model
|
|
1246
1406
|
- Takes a URL and a prompt as input
|
|
@@ -1258,10 +1418,13 @@ Usage notes:
|
|
|
1258
1418
|
- 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.
|
|
1259
1419
|
`;
|
|
1260
1420
|
function createWebFetchTool(config) {
|
|
1261
|
-
const { apiKey, model } = config;
|
|
1421
|
+
const { apiKey, model, strict, needsApproval, providerOptions } = config;
|
|
1262
1422
|
return tool10({
|
|
1263
1423
|
description: WEB_FETCH_DESCRIPTION,
|
|
1264
1424
|
inputSchema: zodSchema10(webFetchInputSchema),
|
|
1425
|
+
strict,
|
|
1426
|
+
needsApproval,
|
|
1427
|
+
providerOptions,
|
|
1265
1428
|
execute: async (input) => {
|
|
1266
1429
|
const { url, prompt } = input;
|
|
1267
1430
|
try {
|
|
@@ -1309,7 +1472,7 @@ ${content}`
|
|
|
1309
1472
|
return {
|
|
1310
1473
|
error: message,
|
|
1311
1474
|
status_code: statusCode,
|
|
1312
|
-
retryable:
|
|
1475
|
+
retryable: RETRYABLE_STATUS_CODES.includes(statusCode)
|
|
1313
1476
|
};
|
|
1314
1477
|
}
|
|
1315
1478
|
return {
|
|
@@ -1329,7 +1492,6 @@ var webSearchInputSchema = z11.object({
|
|
|
1329
1492
|
allowed_domains: z11.array(z11.string()).optional().describe("Only include results from these domains"),
|
|
1330
1493
|
blocked_domains: z11.array(z11.string()).optional().describe("Never include results from these domains")
|
|
1331
1494
|
});
|
|
1332
|
-
var RETRYABLE_CODES2 = [408, 429, 500, 502, 503];
|
|
1333
1495
|
var WEB_SEARCH_DESCRIPTION = `Searches the web and returns results with links. Use this for accessing up-to-date information beyond your knowledge cutoff.
|
|
1334
1496
|
|
|
1335
1497
|
**Capabilities:**
|
|
@@ -1351,10 +1513,13 @@ When searching for recent information, documentation, or current events, use the
|
|
|
1351
1513
|
- allowed_domains: Only include results from these domains
|
|
1352
1514
|
- blocked_domains: Never include results from these domains`;
|
|
1353
1515
|
function createWebSearchTool(config) {
|
|
1354
|
-
const { apiKey } = config;
|
|
1516
|
+
const { apiKey, strict, needsApproval, providerOptions } = config;
|
|
1355
1517
|
return tool11({
|
|
1356
1518
|
description: WEB_SEARCH_DESCRIPTION,
|
|
1357
1519
|
inputSchema: zodSchema11(webSearchInputSchema),
|
|
1520
|
+
strict,
|
|
1521
|
+
needsApproval,
|
|
1522
|
+
providerOptions,
|
|
1358
1523
|
execute: async (input) => {
|
|
1359
1524
|
const { query, allowed_domains, blocked_domains } = input;
|
|
1360
1525
|
try {
|
|
@@ -1388,7 +1553,7 @@ function createWebSearchTool(config) {
|
|
|
1388
1553
|
return {
|
|
1389
1554
|
error: message,
|
|
1390
1555
|
status_code: statusCode,
|
|
1391
|
-
retryable:
|
|
1556
|
+
retryable: RETRYABLE_STATUS_CODES.includes(statusCode)
|
|
1392
1557
|
};
|
|
1393
1558
|
}
|
|
1394
1559
|
return {
|
|
@@ -1422,6 +1587,9 @@ function createWriteTool(sandbox, config) {
|
|
|
1422
1587
|
return tool12({
|
|
1423
1588
|
description: WRITE_DESCRIPTION,
|
|
1424
1589
|
inputSchema: zodSchema12(writeInputSchema),
|
|
1590
|
+
strict: config?.strict,
|
|
1591
|
+
needsApproval: config?.needsApproval,
|
|
1592
|
+
providerOptions: config?.providerOptions,
|
|
1425
1593
|
execute: async ({
|
|
1426
1594
|
file_path,
|
|
1427
1595
|
content
|
|
@@ -1465,13 +1633,17 @@ import { z as z13 } from "zod";
|
|
|
1465
1633
|
var taskInputSchema = z13.object({
|
|
1466
1634
|
description: z13.string().describe("A short (3-5 word) description of the task"),
|
|
1467
1635
|
prompt: z13.string().describe("The task for the agent to perform"),
|
|
1468
|
-
subagent_type: z13.string().describe("The type of specialized agent to use for this task")
|
|
1636
|
+
subagent_type: z13.string().describe("The type of specialized agent to use for this task"),
|
|
1637
|
+
system_prompt: z13.string().optional().describe("Optional custom system prompt for this agent. If provided, overrides the default system prompt for the subagent type. Use this to create dynamic, specialized agents on the fly."),
|
|
1638
|
+
tools: z13.array(z13.string()).optional().describe("Optional list of tool names this agent can use (e.g., ['Read', 'Grep', 'WebSearch']). If provided, overrides the default tools for the subagent type. Use this to restrict or expand the agent's capabilities.")
|
|
1469
1639
|
});
|
|
1470
1640
|
var TASK_DESCRIPTION = `Launch a new agent to handle complex, multi-step tasks autonomously.
|
|
1471
1641
|
|
|
1472
1642
|
The Task tool launches specialized agents (subprocesses) that autonomously handle complex tasks. Each agent type has specific capabilities and tools available to it.
|
|
1473
1643
|
|
|
1474
|
-
|
|
1644
|
+
**Subagent types:**
|
|
1645
|
+
- Use predefined subagent_type values for common task patterns
|
|
1646
|
+
- For dynamic agents: provide custom system_prompt and/or tools to create a specialized agent on the fly
|
|
1475
1647
|
|
|
1476
1648
|
**When NOT to use the Task tool:**
|
|
1477
1649
|
- If you want to read a specific file path, use the Read or Glob tool instead, to find the match more quickly
|
|
@@ -1517,14 +1689,16 @@ function createTaskTool(config) {
|
|
|
1517
1689
|
execute: async ({
|
|
1518
1690
|
description,
|
|
1519
1691
|
prompt,
|
|
1520
|
-
subagent_type
|
|
1692
|
+
subagent_type,
|
|
1693
|
+
system_prompt,
|
|
1694
|
+
tools: customTools
|
|
1521
1695
|
}) => {
|
|
1522
1696
|
const startTime = performance.now();
|
|
1523
1697
|
try {
|
|
1524
1698
|
const typeConfig = subagentTypes[subagent_type] || {};
|
|
1525
1699
|
const model = typeConfig.model || defaultModel;
|
|
1526
|
-
const tools = filterTools(allTools, typeConfig.tools);
|
|
1527
|
-
const systemPrompt = typeConfig.systemPrompt;
|
|
1700
|
+
const tools = filterTools(allTools, customTools ?? typeConfig.tools);
|
|
1701
|
+
const systemPrompt = system_prompt ?? typeConfig.systemPrompt;
|
|
1528
1702
|
const commonOptions = {
|
|
1529
1703
|
model,
|
|
1530
1704
|
tools,
|
|
@@ -1677,7 +1851,7 @@ var TODO_WRITE_DESCRIPTION = `Use this tool to create and manage a structured ta
|
|
|
1677
1851
|
- Keep exactly ONE task in_progress at any time
|
|
1678
1852
|
- ONLY mark completed when FULLY accomplished
|
|
1679
1853
|
- If blocked/errors, keep in_progress and create new task for the blocker`;
|
|
1680
|
-
function createTodoWriteTool(state,
|
|
1854
|
+
function createTodoWriteTool(state, onUpdate) {
|
|
1681
1855
|
return tool14({
|
|
1682
1856
|
description: TODO_WRITE_DESCRIPTION,
|
|
1683
1857
|
inputSchema: zodSchema14(todoWriteInputSchema),
|
|
@@ -1709,6 +1883,58 @@ function createTodoWriteTool(state, config, onUpdate) {
|
|
|
1709
1883
|
}
|
|
1710
1884
|
|
|
1711
1885
|
// src/tools/index.ts
|
|
1886
|
+
var DEFAULT_CACHEABLE = [
|
|
1887
|
+
"Read",
|
|
1888
|
+
"Glob",
|
|
1889
|
+
"Grep",
|
|
1890
|
+
"WebFetch",
|
|
1891
|
+
"WebSearch"
|
|
1892
|
+
];
|
|
1893
|
+
function resolveCache(config) {
|
|
1894
|
+
if (!config) {
|
|
1895
|
+
return { store: null, ttl: 0, debug: false, enabled: new Set };
|
|
1896
|
+
}
|
|
1897
|
+
if (config === true) {
|
|
1898
|
+
return {
|
|
1899
|
+
store: new LRUCacheStore,
|
|
1900
|
+
ttl: 5 * 60 * 1000,
|
|
1901
|
+
debug: false,
|
|
1902
|
+
enabled: new Set(DEFAULT_CACHEABLE)
|
|
1903
|
+
};
|
|
1904
|
+
}
|
|
1905
|
+
if (typeof config === "object" && typeof config.get === "function" && typeof config.set === "function" && typeof config.delete === "function" && typeof config.clear === "function") {
|
|
1906
|
+
return {
|
|
1907
|
+
store: config,
|
|
1908
|
+
ttl: 5 * 60 * 1000,
|
|
1909
|
+
debug: false,
|
|
1910
|
+
enabled: new Set(DEFAULT_CACHEABLE)
|
|
1911
|
+
};
|
|
1912
|
+
}
|
|
1913
|
+
const enabled = new Set;
|
|
1914
|
+
for (const tool15 of DEFAULT_CACHEABLE) {
|
|
1915
|
+
if (config[tool15] !== false) {
|
|
1916
|
+
enabled.add(tool15);
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
for (const [key, value] of Object.entries(config)) {
|
|
1920
|
+
if (["store", "ttl", "debug", "onHit", "onMiss", "keyGenerator"].includes(key))
|
|
1921
|
+
continue;
|
|
1922
|
+
if (value === true)
|
|
1923
|
+
enabled.add(key);
|
|
1924
|
+
if (value === false)
|
|
1925
|
+
enabled.delete(key);
|
|
1926
|
+
}
|
|
1927
|
+
const cfg = config;
|
|
1928
|
+
return {
|
|
1929
|
+
store: cfg.store ?? new LRUCacheStore,
|
|
1930
|
+
ttl: cfg.ttl ?? 5 * 60 * 1000,
|
|
1931
|
+
debug: cfg.debug ?? false,
|
|
1932
|
+
onHit: cfg.onHit,
|
|
1933
|
+
onMiss: cfg.onMiss,
|
|
1934
|
+
keyGenerator: cfg.keyGenerator,
|
|
1935
|
+
enabled
|
|
1936
|
+
};
|
|
1937
|
+
}
|
|
1712
1938
|
function createAgentTools(sandbox, config) {
|
|
1713
1939
|
const toolsConfig = {
|
|
1714
1940
|
...DEFAULT_CONFIG.tools,
|
|
@@ -1744,6 +1970,21 @@ function createAgentTools(sandbox, config) {
|
|
|
1744
1970
|
if (config?.webFetch) {
|
|
1745
1971
|
tools.WebFetch = createWebFetchTool(config.webFetch);
|
|
1746
1972
|
}
|
|
1973
|
+
const cacheConfig = resolveCache(config?.cache);
|
|
1974
|
+
if (cacheConfig.store) {
|
|
1975
|
+
for (const [name, tool15] of Object.entries(tools)) {
|
|
1976
|
+
if (cacheConfig.enabled.has(name)) {
|
|
1977
|
+
tools[name] = cached(tool15, name, {
|
|
1978
|
+
store: cacheConfig.store,
|
|
1979
|
+
ttl: cacheConfig.ttl,
|
|
1980
|
+
debug: cacheConfig.debug,
|
|
1981
|
+
onHit: cacheConfig.onHit,
|
|
1982
|
+
onMiss: cacheConfig.onMiss,
|
|
1983
|
+
keyGenerator: cacheConfig.keyGenerator
|
|
1984
|
+
});
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1747
1988
|
return { tools, planModeState };
|
|
1748
1989
|
}
|
|
1749
1990
|
// src/utils/compact-conversation.ts
|
|
@@ -2097,11 +2338,13 @@ function contextNeedsCompaction(status) {
|
|
|
2097
2338
|
return status.status === "critical";
|
|
2098
2339
|
}
|
|
2099
2340
|
// src/skills/discovery.ts
|
|
2100
|
-
import { readdir, readFile, stat } from "node:fs/promises";
|
|
2341
|
+
import { readdir as readdir2, readFile as readFile2, stat } from "node:fs/promises";
|
|
2101
2342
|
import { homedir } from "node:os";
|
|
2102
|
-
import { join, resolve } from "node:path";
|
|
2343
|
+
import { join as join2, resolve } from "node:path";
|
|
2103
2344
|
|
|
2104
2345
|
// src/skills/loader.ts
|
|
2346
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2347
|
+
import { basename, dirname, join } from "node:path";
|
|
2105
2348
|
function parseSkillMetadata(content, skillPath) {
|
|
2106
2349
|
const frontmatter = extractFrontmatter(content);
|
|
2107
2350
|
if (!frontmatter) {
|
|
@@ -2190,6 +2433,32 @@ function parseYaml(yaml) {
|
|
|
2190
2433
|
}
|
|
2191
2434
|
return result;
|
|
2192
2435
|
}
|
|
2436
|
+
async function loadSkillBundle(skillDir) {
|
|
2437
|
+
const files = {};
|
|
2438
|
+
const name = basename(skillDir);
|
|
2439
|
+
async function readDirRecursive(dir, prefix = "") {
|
|
2440
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
2441
|
+
for (const entry of entries) {
|
|
2442
|
+
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
2443
|
+
const fullPath = join(dir, entry.name);
|
|
2444
|
+
if (entry.isDirectory()) {
|
|
2445
|
+
await readDirRecursive(fullPath, relativePath);
|
|
2446
|
+
} else {
|
|
2447
|
+
files[relativePath] = await readFile(fullPath, "utf-8");
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
await readDirRecursive(skillDir);
|
|
2452
|
+
return { name, files };
|
|
2453
|
+
}
|
|
2454
|
+
async function loadSkillBundles(skills) {
|
|
2455
|
+
const bundles = {};
|
|
2456
|
+
for (const skill of skills) {
|
|
2457
|
+
const skillDir = dirname(skill.path);
|
|
2458
|
+
bundles[skill.name] = await loadSkillBundle(skillDir);
|
|
2459
|
+
}
|
|
2460
|
+
return bundles;
|
|
2461
|
+
}
|
|
2193
2462
|
|
|
2194
2463
|
// src/skills/discovery.ts
|
|
2195
2464
|
var DEFAULT_SKILL_PATHS = [".skills", "~/.bashkit/skills"];
|
|
@@ -2212,7 +2481,7 @@ async function discoverSkills(options) {
|
|
|
2212
2481
|
}
|
|
2213
2482
|
function resolvePath(path, cwd) {
|
|
2214
2483
|
if (path.startsWith("~/")) {
|
|
2215
|
-
return
|
|
2484
|
+
return join2(homedir(), path.slice(2));
|
|
2216
2485
|
}
|
|
2217
2486
|
if (path.startsWith("/")) {
|
|
2218
2487
|
return path;
|
|
@@ -2222,18 +2491,18 @@ function resolvePath(path, cwd) {
|
|
|
2222
2491
|
async function scanDirectory(dirPath) {
|
|
2223
2492
|
const skills = [];
|
|
2224
2493
|
try {
|
|
2225
|
-
const entries = await
|
|
2494
|
+
const entries = await readdir2(dirPath, { withFileTypes: true });
|
|
2226
2495
|
for (const entry of entries) {
|
|
2227
2496
|
if (!entry.isDirectory()) {
|
|
2228
2497
|
continue;
|
|
2229
2498
|
}
|
|
2230
|
-
const skillPath =
|
|
2499
|
+
const skillPath = join2(dirPath, entry.name, "SKILL.md");
|
|
2231
2500
|
try {
|
|
2232
2501
|
const skillStat = await stat(skillPath);
|
|
2233
2502
|
if (!skillStat.isFile()) {
|
|
2234
2503
|
continue;
|
|
2235
2504
|
}
|
|
2236
|
-
const content = await
|
|
2505
|
+
const content = await readFile2(skillPath, "utf-8");
|
|
2237
2506
|
const metadata = parseSkillMetadata(content, skillPath);
|
|
2238
2507
|
if (metadata.name !== entry.name) {
|
|
2239
2508
|
console.warn(`Skill name "${metadata.name}" does not match folder name "${entry.name}" in ${skillPath}`);
|
|
@@ -2406,6 +2675,8 @@ export {
|
|
|
2406
2675
|
setupAgentEnvironment,
|
|
2407
2676
|
pruneMessagesByTokens,
|
|
2408
2677
|
parseSkillMetadata,
|
|
2678
|
+
loadSkillBundles,
|
|
2679
|
+
loadSkillBundle,
|
|
2409
2680
|
getContextStatus,
|
|
2410
2681
|
fetchSkills,
|
|
2411
2682
|
fetchSkill,
|
|
@@ -2420,6 +2691,7 @@ export {
|
|
|
2420
2691
|
createTodoWriteTool,
|
|
2421
2692
|
createTaskTool,
|
|
2422
2693
|
createSkillTool,
|
|
2694
|
+
createRedisCacheStore,
|
|
2423
2695
|
createReadTool,
|
|
2424
2696
|
createLocalSandbox,
|
|
2425
2697
|
createGrepTool,
|
|
@@ -2435,7 +2707,10 @@ export {
|
|
|
2435
2707
|
contextNeedsCompaction,
|
|
2436
2708
|
contextNeedsAttention,
|
|
2437
2709
|
compactConversation,
|
|
2710
|
+
cached,
|
|
2711
|
+
anthropicPromptCacheMiddlewareV2,
|
|
2438
2712
|
anthropicPromptCacheMiddleware,
|
|
2439
2713
|
MODEL_CONTEXT_LIMITS,
|
|
2714
|
+
LRUCacheStore,
|
|
2440
2715
|
DEFAULT_CONFIG
|
|
2441
2716
|
};
|
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import type { LanguageModelV2Middleware } from "@ai-sdk/provider";
|
|
2
|
+
import type { LanguageModelMiddleware } from "ai";
|
|
2
3
|
/**
|
|
3
4
|
* Middleware that enables Anthropic's prompt caching feature.
|
|
5
|
+
* For AI SDK v5 (LanguageModelV2).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { wrapLanguageModel } from 'ai';
|
|
10
|
+
* import { anthropic } from '@ai-sdk/anthropic';
|
|
11
|
+
* import { anthropicPromptCacheMiddlewareV2 } from 'bashkit';
|
|
12
|
+
*
|
|
13
|
+
* const model = wrapLanguageModel({
|
|
14
|
+
* model: anthropic('claude-sonnet-4-20250514'),
|
|
15
|
+
* middleware: anthropicPromptCacheMiddlewareV2,
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare const anthropicPromptCacheMiddlewareV2: LanguageModelV2Middleware;
|
|
20
|
+
/**
|
|
21
|
+
* Middleware that enables Anthropic's prompt caching feature.
|
|
22
|
+
* For AI SDK v6+ (LanguageModelV3).
|
|
4
23
|
*
|
|
5
24
|
* @example
|
|
6
25
|
* ```typescript
|
|
@@ -14,4 +33,4 @@ import type { LanguageModelV2Middleware } from "@ai-sdk/provider";
|
|
|
14
33
|
* });
|
|
15
34
|
* ```
|
|
16
35
|
*/
|
|
17
|
-
export declare const anthropicPromptCacheMiddleware:
|
|
36
|
+
export declare const anthropicPromptCacheMiddleware: LanguageModelMiddleware;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { anthropicPromptCacheMiddleware } from "./anthropic-cache";
|
|
1
|
+
export { anthropicPromptCacheMiddleware, anthropicPromptCacheMiddlewareV2, } from "./anthropic-cache";
|
package/dist/sandbox/e2b.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/sandbox/vercel.d.ts
CHANGED
package/dist/skills/index.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ export type { DiscoverSkillsOptions, SkillMetadata } from "./types";
|
|
|
2
2
|
export type { SkillBundle } from "./fetch";
|
|
3
3
|
export { discoverSkills } from "./discovery";
|
|
4
4
|
export { fetchSkill, fetchSkills } from "./fetch";
|
|
5
|
-
export { parseSkillMetadata } from "./loader";
|
|
5
|
+
export { parseSkillMetadata, loadSkillBundle, loadSkillBundles, } from "./loader";
|
|
6
6
|
export { skillsToXml } from "./xml";
|