deepagents 1.4.1 → 1.5.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.
package/dist/index.cjs CHANGED
@@ -33,6 +33,9 @@ micromatch = __toESM(micromatch);
33
33
  let path = require("path");
34
34
  let zod_v3 = require("zod/v3");
35
35
  let _langchain_core_messages = require("@langchain/core/messages");
36
+ let zod = require("zod");
37
+ let yaml = require("yaml");
38
+ yaml = __toESM(yaml);
36
39
  let node_fs_promises = require("node:fs/promises");
37
40
  node_fs_promises = __toESM(node_fs_promises);
38
41
  let node_fs = require("node:fs");
@@ -44,9 +47,6 @@ let fast_glob = require("fast-glob");
44
47
  fast_glob = __toESM(fast_glob);
45
48
  let node_os = require("node:os");
46
49
  node_os = __toESM(node_os);
47
- let zod = require("zod");
48
- let yaml = require("yaml");
49
- yaml = __toESM(yaml);
50
50
 
51
51
  //#region src/backends/protocol.ts
52
52
  /**
@@ -362,23 +362,12 @@ var StateBackend = class {
362
362
  * @param limit - Maximum number of lines to read
363
363
  * @returns Formatted file content with line numbers, or error message
364
364
  */
365
- read(filePath, offset = 0, limit = 2e3) {
365
+ read(filePath, offset = 0, limit = 500) {
366
366
  const fileData = this.getFiles()[filePath];
367
367
  if (!fileData) return `Error: File '${filePath}' not found`;
368
368
  return formatReadResponse(fileData, offset, limit);
369
369
  }
370
370
  /**
371
- * Read file content as raw FileData.
372
- *
373
- * @param filePath - Absolute file path
374
- * @returns Raw file content as FileData
375
- */
376
- readRaw(filePath) {
377
- const fileData = this.getFiles()[filePath];
378
- if (!fileData) throw new Error(`File '${filePath}' not found`);
379
- return fileData;
380
- }
381
- /**
382
371
  * Create a new file with content.
383
372
  * Returns WriteResult with filesUpdate to update LangGraph state.
384
373
  */
@@ -619,7 +608,7 @@ function createReadFileTool(backend, options) {
619
608
  state: (0, _langchain_langgraph.getCurrentTaskInput)(config),
620
609
  store: config.store
621
610
  });
622
- const { file_path, offset = 0, limit = 2e3 } = input;
611
+ const { file_path, offset = 0, limit = 500 } = input;
623
612
  return await resolvedBackend.read(file_path, offset, limit);
624
613
  }, {
625
614
  name: "read_file",
@@ -627,7 +616,7 @@ function createReadFileTool(backend, options) {
627
616
  schema: zod_v4.z.object({
628
617
  file_path: zod_v4.z.string().describe("Absolute path to the file to read"),
629
618
  offset: zod_v4.z.coerce.number().optional().default(0).describe("Line offset to start reading from (0-indexed)"),
630
- limit: zod_v4.z.coerce.number().optional().default(2e3).describe("Maximum number of lines to read")
619
+ limit: zod_v4.z.coerce.number().optional().default(500).describe("Maximum number of lines to read")
631
620
  })
632
621
  });
633
622
  }
@@ -883,7 +872,7 @@ const DEFAULT_SUBAGENT_PROMPT = "In order to complete the objective that the use
883
872
  const EXCLUDED_STATE_KEYS = [
884
873
  "messages",
885
874
  "todos",
886
- "jumpTo",
875
+ "structuredResponse",
887
876
  "files"
888
877
  ];
889
878
  const DEFAULT_GENERAL_PURPOSE_DESCRIPTION = "General-purpose agent for researching complex questions, searching for files and content, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you. This agent has access to all tools as the main agent.";
@@ -1141,14 +1130,10 @@ function createSubAgentMiddleware(options) {
1141
1130
  taskDescription
1142
1131
  })],
1143
1132
  wrapModelCall: async (request, handler) => {
1144
- if (systemPrompt !== null) {
1145
- const currentPrompt = request.systemPrompt || "";
1146
- const newPrompt = currentPrompt ? `${currentPrompt}\n\n${systemPrompt}` : systemPrompt;
1147
- return handler({
1148
- ...request,
1149
- systemPrompt: newPrompt
1150
- });
1151
- }
1133
+ if (systemPrompt !== null) return handler({
1134
+ ...request,
1135
+ systemMessage: request.systemMessage.concat(new langchain.SystemMessage({ content: systemPrompt }))
1136
+ });
1152
1137
  return handler(request);
1153
1138
  }
1154
1139
  });
@@ -1202,6 +1187,501 @@ function createPatchToolCallsMiddleware() {
1202
1187
  });
1203
1188
  }
1204
1189
 
1190
+ //#endregion
1191
+ //#region src/middleware/memory.ts
1192
+ /**
1193
+ * Middleware for loading agent memory/context from AGENTS.md files.
1194
+ *
1195
+ * This module implements support for the AGENTS.md specification (https://agents.md/),
1196
+ * loading memory/context from configurable sources and injecting into the system prompt.
1197
+ *
1198
+ * ## Overview
1199
+ *
1200
+ * AGENTS.md files provide project-specific context and instructions to help AI agents
1201
+ * work effectively. Unlike skills (which are on-demand workflows), memory is always
1202
+ * loaded and provides persistent context.
1203
+ *
1204
+ * ## Usage
1205
+ *
1206
+ * ```typescript
1207
+ * import { createMemoryMiddleware } from "@anthropic/deepagents";
1208
+ * import { FilesystemBackend } from "@anthropic/deepagents";
1209
+ *
1210
+ * // Security: FilesystemBackend allows reading/writing from the entire filesystem.
1211
+ * // Either ensure the agent is running within a sandbox OR add human-in-the-loop (HIL)
1212
+ * // approval to file operations.
1213
+ * const backend = new FilesystemBackend({ rootDir: "/" });
1214
+ *
1215
+ * const middleware = createMemoryMiddleware({
1216
+ * backend,
1217
+ * sources: [
1218
+ * "~/.deepagents/AGENTS.md",
1219
+ * "./.deepagents/AGENTS.md",
1220
+ * ],
1221
+ * });
1222
+ *
1223
+ * const agent = createDeepAgent({ middleware: [middleware] });
1224
+ * ```
1225
+ *
1226
+ * ## Memory Sources
1227
+ *
1228
+ * Sources are simply paths to AGENTS.md files that are loaded in order and combined.
1229
+ * Multiple sources are concatenated in order, with all content included.
1230
+ * Later sources appear after earlier ones in the combined prompt.
1231
+ *
1232
+ * ## File Format
1233
+ *
1234
+ * AGENTS.md files are standard Markdown with no required structure.
1235
+ * Common sections include:
1236
+ * - Project overview
1237
+ * - Build/test commands
1238
+ * - Code style guidelines
1239
+ * - Architecture notes
1240
+ */
1241
+ /**
1242
+ * State schema for memory middleware.
1243
+ */
1244
+ const MemoryStateSchema = zod.z.object({ memoryContents: zod.z.record(zod.z.string(), zod.z.string()).optional() });
1245
+ /**
1246
+ * Default system prompt template for memory.
1247
+ * Ported from Python's comprehensive memory guidelines.
1248
+ */
1249
+ const MEMORY_SYSTEM_PROMPT = `<agent_memory>
1250
+ {memory_contents}
1251
+ </agent_memory>
1252
+
1253
+ <memory_guidelines>
1254
+ The above <agent_memory> was loaded in from files in your filesystem. As you learn from your interactions with the user, you can save new knowledge by calling the \`edit_file\` tool.
1255
+
1256
+ **Learning from feedback:**
1257
+ - One of your MAIN PRIORITIES is to learn from your interactions with the user. These learnings can be implicit or explicit. This means that in the future, you will remember this important information.
1258
+ - When you need to remember something, updating memory must be your FIRST, IMMEDIATE action - before responding to the user, before calling other tools, before doing anything else. Just update memory immediately.
1259
+ - When user says something is better/worse, capture WHY and encode it as a pattern.
1260
+ - Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions.
1261
+ - A great opportunity to update your memories is when the user interrupts a tool call and provides feedback. You should update your memories immediately before revising the tool call.
1262
+ - Look for the underlying principle behind corrections, not just the specific mistake.
1263
+ - The user might not explicitly ask you to remember something, but if they provide information that is useful for future use, you should update your memories immediately.
1264
+
1265
+ **Asking for information:**
1266
+ - If you lack context to perform an action (e.g. send a Slack DM, requires a user ID/email) you should explicitly ask the user for this information.
1267
+ - It is preferred for you to ask for information, don't assume anything that you do not know!
1268
+ - When the user provides information that is useful for future use, you should update your memories immediately.
1269
+
1270
+ **When to update memories:**
1271
+ - When the user explicitly asks you to remember something (e.g., "remember my email", "save this preference")
1272
+ - When the user describes your role or how you should behave (e.g., "you are a web researcher", "always do X")
1273
+ - When the user gives feedback on your work - capture what was wrong and how to improve
1274
+ - When the user provides information required for tool use (e.g., slack channel ID, email addresses)
1275
+ - When the user provides context useful for future tasks, such as how to use tools, or which actions to take in a particular situation
1276
+ - When you discover new patterns or preferences (coding styles, conventions, workflows)
1277
+
1278
+ **When to NOT update memories:**
1279
+ - When the information is temporary or transient (e.g., "I'm running late", "I'm on my phone right now")
1280
+ - When the information is a one-time task request (e.g., "Find me a recipe", "What's 25 * 4?")
1281
+ - When the information is a simple question that doesn't reveal lasting preferences (e.g., "What day is it?", "Can you explain X?")
1282
+ - When the information is an acknowledgment or small talk (e.g., "Sounds good!", "Hello", "Thanks for that")
1283
+ - When the information is stale or irrelevant in future conversations
1284
+ - Never store API keys, access tokens, passwords, or any other credentials in any file, memory, or system prompt.
1285
+ - If the user asks where to put API keys or provides an API key, do NOT echo or save it.
1286
+
1287
+ **Examples:**
1288
+ Example 1 (remembering user information):
1289
+ User: Can you connect to my google account?
1290
+ Agent: Sure, I'll connect to your google account, what's your google account email?
1291
+ User: john@example.com
1292
+ Agent: Let me save this to my memory.
1293
+ Tool Call: edit_file(...) -> remembers that the user's google account email is john@example.com
1294
+
1295
+ Example 2 (remembering implicit user preferences):
1296
+ User: Can you write me an example for creating a deep agent in LangChain?
1297
+ Agent: Sure, I'll write you an example for creating a deep agent in LangChain <example code in Python>
1298
+ User: Can you do this in JavaScript
1299
+ Agent: Let me save this to my memory.
1300
+ Tool Call: edit_file(...) -> remembers that the user prefers to get LangChain code examples in JavaScript
1301
+ Agent: Sure, here is the JavaScript example<example code in JavaScript>
1302
+
1303
+ Example 3 (do not remember transient information):
1304
+ User: I'm going to play basketball tonight so I will be offline for a few hours.
1305
+ Agent: Okay I'll add a block to your calendar.
1306
+ Tool Call: create_calendar_event(...) -> just calls a tool, does not commit anything to memory, as it is transient information
1307
+ </memory_guidelines>`;
1308
+ /**
1309
+ * Format loaded memory contents for injection into prompt.
1310
+ * Pairs memory locations with their contents for clarity.
1311
+ */
1312
+ function formatMemoryContents(contents, sources) {
1313
+ if (Object.keys(contents).length === 0) return "(No memory loaded)";
1314
+ const sections = [];
1315
+ for (const path$4 of sources) if (contents[path$4]) sections.push(`${path$4}\n${contents[path$4]}`);
1316
+ if (sections.length === 0) return "(No memory loaded)";
1317
+ return sections.join("\n\n");
1318
+ }
1319
+ /**
1320
+ * Load memory content from a backend path.
1321
+ *
1322
+ * @param backend - Backend to load from.
1323
+ * @param path - Path to the AGENTS.md file.
1324
+ * @returns File content if found, null otherwise.
1325
+ */
1326
+ async function loadMemoryFromBackend(backend, path$4) {
1327
+ const results = await backend.downloadFiles([path$4]);
1328
+ if (results.length !== 1) throw new Error(`Expected 1 response for path ${path$4}, got ${results.length}`);
1329
+ const response = results[0];
1330
+ if (response.error != null) {
1331
+ if (response.error === "file_not_found") return null;
1332
+ throw new Error(`Failed to download ${path$4}: ${response.error}`);
1333
+ }
1334
+ if (response.content != null) return new TextDecoder().decode(response.content);
1335
+ return null;
1336
+ }
1337
+ /**
1338
+ * Create middleware for loading agent memory from AGENTS.md files.
1339
+ *
1340
+ * Loads memory content from configured sources and injects into the system prompt.
1341
+ * Supports multiple sources that are combined together.
1342
+ *
1343
+ * @param options - Configuration options
1344
+ * @returns AgentMiddleware for memory loading and injection
1345
+ *
1346
+ * @example
1347
+ * ```typescript
1348
+ * const middleware = createMemoryMiddleware({
1349
+ * backend: new FilesystemBackend({ rootDir: "/" }),
1350
+ * sources: [
1351
+ * "~/.deepagents/AGENTS.md",
1352
+ * "./.deepagents/AGENTS.md",
1353
+ * ],
1354
+ * });
1355
+ * ```
1356
+ */
1357
+ function createMemoryMiddleware(options) {
1358
+ const { backend, sources } = options;
1359
+ /**
1360
+ * Resolve backend from instance or factory.
1361
+ */
1362
+ function getBackend$1(state) {
1363
+ if (typeof backend === "function") return backend({ state });
1364
+ return backend;
1365
+ }
1366
+ return (0, langchain.createMiddleware)({
1367
+ name: "MemoryMiddleware",
1368
+ stateSchema: MemoryStateSchema,
1369
+ async beforeAgent(state) {
1370
+ if ("memoryContents" in state && state.memoryContents != null) return;
1371
+ const resolvedBackend = getBackend$1(state);
1372
+ const contents = {};
1373
+ for (const path$4 of sources) try {
1374
+ const content = await loadMemoryFromBackend(resolvedBackend, path$4);
1375
+ if (content) contents[path$4] = content;
1376
+ } catch (error) {
1377
+ console.debug(`Failed to load memory from ${path$4}:`, error);
1378
+ }
1379
+ return { memoryContents: contents };
1380
+ },
1381
+ wrapModelCall(request, handler) {
1382
+ const formattedContents = formatMemoryContents(request.state?.memoryContents || {}, sources);
1383
+ const memorySection = MEMORY_SYSTEM_PROMPT.replace("{memory_contents}", formattedContents);
1384
+ const currentSystemPrompt = request.systemPrompt || "";
1385
+ const newSystemPrompt = currentSystemPrompt ? `${memorySection}\n\n${currentSystemPrompt}` : memorySection;
1386
+ return handler({
1387
+ ...request,
1388
+ systemPrompt: newSystemPrompt
1389
+ });
1390
+ }
1391
+ });
1392
+ }
1393
+
1394
+ //#endregion
1395
+ //#region src/middleware/skills.ts
1396
+ /**
1397
+ * Backend-agnostic skills middleware for loading agent skills from any backend.
1398
+ *
1399
+ * This middleware implements Anthropic's agent skills pattern with progressive disclosure,
1400
+ * loading skills from backend storage via configurable sources.
1401
+ *
1402
+ * ## Architecture
1403
+ *
1404
+ * Skills are loaded from one or more **sources** - paths in a backend where skills are
1405
+ * organized. Sources are loaded in order, with later sources overriding earlier ones
1406
+ * when skills have the same name (last one wins). This enables layering: base -> user
1407
+ * -> project -> team skills.
1408
+ *
1409
+ * The middleware uses backend APIs exclusively (no direct filesystem access), making it
1410
+ * portable across different storage backends (filesystem, state, remote storage, etc.).
1411
+ *
1412
+ * ## Usage
1413
+ *
1414
+ * ```typescript
1415
+ * import { createSkillsMiddleware, FilesystemBackend } from "@anthropic/deepagents";
1416
+ *
1417
+ * const middleware = createSkillsMiddleware({
1418
+ * backend: new FilesystemBackend({ rootDir: "/" }),
1419
+ * sources: [
1420
+ * "/skills/user/",
1421
+ * "/skills/project/",
1422
+ * ],
1423
+ * });
1424
+ *
1425
+ * const agent = createDeepAgent({ middleware: [middleware] });
1426
+ * ```
1427
+ *
1428
+ * Or use the `skills` parameter on createDeepAgent:
1429
+ *
1430
+ * ```typescript
1431
+ * const agent = createDeepAgent({
1432
+ * skills: ["/skills/user/", "/skills/project/"],
1433
+ * });
1434
+ * ```
1435
+ */
1436
+ const MAX_SKILL_FILE_SIZE = 10 * 1024 * 1024;
1437
+ const MAX_SKILL_NAME_LENGTH = 64;
1438
+ const MAX_SKILL_DESCRIPTION_LENGTH = 1024;
1439
+ /**
1440
+ * State schema for skills middleware.
1441
+ */
1442
+ const SkillsStateSchema = zod.z.object({ skillsMetadata: zod.z.array(zod.z.object({
1443
+ name: zod.z.string(),
1444
+ description: zod.z.string(),
1445
+ path: zod.z.string(),
1446
+ license: zod.z.string().nullable().optional(),
1447
+ compatibility: zod.z.string().nullable().optional(),
1448
+ metadata: zod.z.record(zod.z.string(), zod.z.string()).optional(),
1449
+ allowedTools: zod.z.array(zod.z.string()).optional()
1450
+ })).optional() });
1451
+ /**
1452
+ * Skills System Documentation prompt template.
1453
+ */
1454
+ const SKILLS_SYSTEM_PROMPT = `
1455
+ ## Skills System
1456
+
1457
+ You have access to a skills library that provides specialized capabilities and domain knowledge.
1458
+
1459
+ {skills_locations}
1460
+
1461
+ **Available Skills:**
1462
+
1463
+ {skills_list}
1464
+
1465
+ **How to Use Skills (Progressive Disclosure):**
1466
+
1467
+ Skills follow a **progressive disclosure** pattern - you know they exist (name + description above), but you only read the full instructions when needed:
1468
+
1469
+ 1. **Recognize when a skill applies**: Check if the user's task matches any skill's description
1470
+ 2. **Read the skill's full instructions**: The skill list above shows the exact path to use with read_file
1471
+ 3. **Follow the skill's instructions**: SKILL.md contains step-by-step workflows, best practices, and examples
1472
+ 4. **Access supporting files**: Skills may include Python scripts, configs, or reference docs - use absolute paths
1473
+
1474
+ **When to Use Skills:**
1475
+ - When the user's request matches a skill's domain (e.g., "research X" → web-research skill)
1476
+ - When you need specialized knowledge or structured workflows
1477
+ - When a skill provides proven patterns for complex tasks
1478
+
1479
+ **Skills are Self-Documenting:**
1480
+ - Each SKILL.md tells you exactly what the skill does and how to use it
1481
+ - The skill list above shows the full path for each skill's SKILL.md file
1482
+
1483
+ **Executing Skill Scripts:**
1484
+ Skills may contain Python scripts or other executable files. Always use absolute paths from the skill list.
1485
+
1486
+ **Example Workflow:**
1487
+
1488
+ User: "Can you research the latest developments in quantum computing?"
1489
+
1490
+ 1. Check available skills above → See "web-research" skill with its full path
1491
+ 2. Read the skill using the path shown in the list
1492
+ 3. Follow the skill's research workflow (search → organize → synthesize)
1493
+ 4. Use any helper scripts with absolute paths
1494
+
1495
+ Remember: Skills are tools to make you more capable and consistent. When in doubt, check if a skill exists for the task!
1496
+ `;
1497
+ /**
1498
+ * Validate skill name per Agent Skills specification.
1499
+ */
1500
+ function validateSkillName$1(name, directoryName) {
1501
+ if (!name) return {
1502
+ valid: false,
1503
+ error: "name is required"
1504
+ };
1505
+ if (name.length > MAX_SKILL_NAME_LENGTH) return {
1506
+ valid: false,
1507
+ error: "name exceeds 64 characters"
1508
+ };
1509
+ if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) return {
1510
+ valid: false,
1511
+ error: "name must be lowercase alphanumeric with single hyphens only"
1512
+ };
1513
+ if (name !== directoryName) return {
1514
+ valid: false,
1515
+ error: `name '${name}' must match directory name '${directoryName}'`
1516
+ };
1517
+ return {
1518
+ valid: true,
1519
+ error: ""
1520
+ };
1521
+ }
1522
+ /**
1523
+ * Parse YAML frontmatter from SKILL.md content.
1524
+ */
1525
+ function parseSkillMetadataFromContent(content, skillPath, directoryName) {
1526
+ if (content.length > MAX_SKILL_FILE_SIZE) {
1527
+ console.warn(`Skipping ${skillPath}: content too large (${content.length} bytes)`);
1528
+ return null;
1529
+ }
1530
+ const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
1531
+ if (!match) {
1532
+ console.warn(`Skipping ${skillPath}: no valid YAML frontmatter found`);
1533
+ return null;
1534
+ }
1535
+ const frontmatterStr = match[1];
1536
+ let frontmatterData;
1537
+ try {
1538
+ frontmatterData = yaml.default.parse(frontmatterStr);
1539
+ } catch (e) {
1540
+ console.warn(`Invalid YAML in ${skillPath}:`, e);
1541
+ return null;
1542
+ }
1543
+ if (!frontmatterData || typeof frontmatterData !== "object") {
1544
+ console.warn(`Skipping ${skillPath}: frontmatter is not a mapping`);
1545
+ return null;
1546
+ }
1547
+ const name = frontmatterData.name;
1548
+ const description = frontmatterData.description;
1549
+ if (!name || !description) {
1550
+ console.warn(`Skipping ${skillPath}: missing required 'name' or 'description'`);
1551
+ return null;
1552
+ }
1553
+ const validation = validateSkillName$1(String(name), directoryName);
1554
+ if (!validation.valid) console.warn(`Skill '${name}' in ${skillPath} does not follow Agent Skills specification: ${validation.error}. Consider renaming for spec compliance.`);
1555
+ let descriptionStr = String(description).trim();
1556
+ if (descriptionStr.length > MAX_SKILL_DESCRIPTION_LENGTH) {
1557
+ console.warn(`Description exceeds ${MAX_SKILL_DESCRIPTION_LENGTH} characters in ${skillPath}, truncating`);
1558
+ descriptionStr = descriptionStr.slice(0, MAX_SKILL_DESCRIPTION_LENGTH);
1559
+ }
1560
+ const allowedToolsStr = frontmatterData["allowed-tools"];
1561
+ const allowedTools = allowedToolsStr ? allowedToolsStr.split(" ") : [];
1562
+ return {
1563
+ name: String(name),
1564
+ description: descriptionStr,
1565
+ path: skillPath,
1566
+ metadata: frontmatterData.metadata || {},
1567
+ license: typeof frontmatterData.license === "string" ? frontmatterData.license.trim() || null : null,
1568
+ compatibility: typeof frontmatterData.compatibility === "string" ? frontmatterData.compatibility.trim() || null : null,
1569
+ allowedTools
1570
+ };
1571
+ }
1572
+ /**
1573
+ * List all skills from a backend source.
1574
+ */
1575
+ async function listSkillsFromBackend(backend, sourcePath) {
1576
+ const skills = [];
1577
+ const normalizedPath = sourcePath.endsWith("/") ? sourcePath : `${sourcePath}/`;
1578
+ let fileInfos;
1579
+ try {
1580
+ fileInfos = await backend.lsInfo(normalizedPath);
1581
+ } catch {
1582
+ return [];
1583
+ }
1584
+ const entries = fileInfos.map((info) => ({
1585
+ name: info.path.replace(/\/$/, "").split("/").pop() || "",
1586
+ type: info.is_dir ? "directory" : "file"
1587
+ }));
1588
+ for (const entry of entries) {
1589
+ if (entry.type !== "directory") continue;
1590
+ const skillMdPath = `${normalizedPath}${entry.name}/SKILL.md`;
1591
+ const results = await backend.downloadFiles([skillMdPath]);
1592
+ if (results.length !== 1) continue;
1593
+ const response = results[0];
1594
+ if (response.error != null || response.content == null) continue;
1595
+ const metadata = parseSkillMetadataFromContent(new TextDecoder().decode(response.content), skillMdPath, entry.name);
1596
+ if (metadata) skills.push(metadata);
1597
+ }
1598
+ return skills;
1599
+ }
1600
+ /**
1601
+ * Format skills locations for display in system prompt.
1602
+ */
1603
+ function formatSkillsLocations(sources) {
1604
+ if (sources.length === 0) return "**Skills Sources:** None configured";
1605
+ const lines = ["**Skills Sources:**"];
1606
+ for (const source of sources) lines.push(`- \`${source}\``);
1607
+ return lines.join("\n");
1608
+ }
1609
+ /**
1610
+ * Format skills metadata for display in system prompt.
1611
+ */
1612
+ function formatSkillsList(skills, sources) {
1613
+ if (skills.length === 0) return `(No skills available yet. Skills can be created in ${sources.join(" or ")})`;
1614
+ const lines = [];
1615
+ for (const skill of skills) {
1616
+ lines.push(`- **${skill.name}**: ${skill.description}`);
1617
+ lines.push(` → Read \`${skill.path}\` for full instructions`);
1618
+ }
1619
+ return lines.join("\n");
1620
+ }
1621
+ /**
1622
+ * Create backend-agnostic middleware for loading and exposing agent skills.
1623
+ *
1624
+ * This middleware loads skills from configurable backend sources and injects
1625
+ * skill metadata into the system prompt. It implements the progressive disclosure
1626
+ * pattern: skill names and descriptions are shown in the prompt, but the agent
1627
+ * reads full SKILL.md content only when needed.
1628
+ *
1629
+ * @param options - Configuration options
1630
+ * @returns AgentMiddleware for skills loading and injection
1631
+ *
1632
+ * @example
1633
+ * ```typescript
1634
+ * const middleware = createSkillsMiddleware({
1635
+ * backend: new FilesystemBackend({ rootDir: "/" }),
1636
+ * sources: ["/skills/user/", "/skills/project/"],
1637
+ * });
1638
+ * ```
1639
+ */
1640
+ function createSkillsMiddleware(options) {
1641
+ const { backend, sources } = options;
1642
+ let loadedSkills = [];
1643
+ /**
1644
+ * Resolve backend from instance or factory.
1645
+ */
1646
+ function getBackend$1(state) {
1647
+ if (typeof backend === "function") return backend({ state });
1648
+ return backend;
1649
+ }
1650
+ return (0, langchain.createMiddleware)({
1651
+ name: "SkillsMiddleware",
1652
+ stateSchema: SkillsStateSchema,
1653
+ async beforeAgent(state) {
1654
+ if (loadedSkills.length > 0) return;
1655
+ if ("skillsMetadata" in state && state.skillsMetadata != null) {
1656
+ loadedSkills = state.skillsMetadata;
1657
+ return;
1658
+ }
1659
+ const resolvedBackend = getBackend$1(state);
1660
+ const allSkills = /* @__PURE__ */ new Map();
1661
+ for (const sourcePath of sources) try {
1662
+ const skills = await listSkillsFromBackend(resolvedBackend, sourcePath);
1663
+ for (const skill of skills) allSkills.set(skill.name, skill);
1664
+ } catch (error) {
1665
+ console.debug(`[BackendSkillsMiddleware] Failed to load skills from ${sourcePath}:`, error);
1666
+ }
1667
+ loadedSkills = Array.from(allSkills.values());
1668
+ return { skillsMetadata: loadedSkills };
1669
+ },
1670
+ wrapModelCall(request, handler) {
1671
+ const skillsMetadata = loadedSkills.length > 0 ? loadedSkills : request.state?.skillsMetadata || [];
1672
+ const skillsLocations = formatSkillsLocations(sources);
1673
+ const skillsList = formatSkillsList(skillsMetadata, sources);
1674
+ const skillsSection = SKILLS_SYSTEM_PROMPT.replace("{skills_locations}", skillsLocations).replace("{skills_list}", skillsList);
1675
+ const currentSystemPrompt = request.systemPrompt || "";
1676
+ const newSystemPrompt = currentSystemPrompt ? `${currentSystemPrompt}\n\n${skillsSection}` : skillsSection;
1677
+ return handler({
1678
+ ...request,
1679
+ systemPrompt: newSystemPrompt
1680
+ });
1681
+ }
1682
+ });
1683
+ }
1684
+
1205
1685
  //#endregion
1206
1686
  //#region src/backends/store.ts
1207
1687
  /**
@@ -1349,27 +1829,18 @@ var StoreBackend = class {
1349
1829
  * @param limit - Maximum number of lines to read
1350
1830
  * @returns Formatted file content with line numbers, or error message
1351
1831
  */
1352
- async read(filePath, offset = 0, limit = 2e3) {
1832
+ async read(filePath, offset = 0, limit = 500) {
1353
1833
  try {
1354
- return formatReadResponse(await this.readRaw(filePath), offset, limit);
1834
+ const store = this.getStore();
1835
+ const namespace = this.getNamespace();
1836
+ const item = await store.get(namespace, filePath);
1837
+ if (!item) return `Error: File '${filePath}' not found`;
1838
+ return formatReadResponse(this.convertStoreItemToFileData(item), offset, limit);
1355
1839
  } catch (e) {
1356
1840
  return `Error: ${e.message}`;
1357
1841
  }
1358
1842
  }
1359
1843
  /**
1360
- * Read file content as raw FileData.
1361
- *
1362
- * @param filePath - Absolute file path
1363
- * @returns Raw file content as FileData
1364
- */
1365
- async readRaw(filePath) {
1366
- const store = this.getStore();
1367
- const namespace = this.getNamespace();
1368
- const item = await store.get(namespace, filePath);
1369
- if (!item) throw new Error(`File '${filePath}' not found`);
1370
- return this.convertStoreItemToFileData(item);
1371
- }
1372
- /**
1373
1844
  * Create a new file with content.
1374
1845
  * Returns WriteResult. External storage sets filesUpdate=null.
1375
1846
  */
@@ -1643,7 +2114,7 @@ var FilesystemBackend = class {
1643
2114
  * @param limit - Maximum number of lines to read
1644
2115
  * @returns Formatted file content with line numbers, or error message
1645
2116
  */
1646
- async read(filePath, offset = 0, limit = 2e3) {
2117
+ async read(filePath, offset = 0, limit = 500) {
1647
2118
  try {
1648
2119
  const resolvedPath = this.resolvePath(filePath);
1649
2120
  let content;
@@ -1673,37 +2144,6 @@ var FilesystemBackend = class {
1673
2144
  }
1674
2145
  }
1675
2146
  /**
1676
- * Read file content as raw FileData.
1677
- *
1678
- * @param filePath - Absolute file path
1679
- * @returns Raw file content as FileData
1680
- */
1681
- async readRaw(filePath) {
1682
- const resolvedPath = this.resolvePath(filePath);
1683
- let content;
1684
- let stat;
1685
- if (SUPPORTS_NOFOLLOW) {
1686
- stat = await node_fs_promises.default.stat(resolvedPath);
1687
- if (!stat.isFile()) throw new Error(`File '${filePath}' not found`);
1688
- const fd = await node_fs_promises.default.open(resolvedPath, node_fs.default.constants.O_RDONLY | node_fs.default.constants.O_NOFOLLOW);
1689
- try {
1690
- content = await fd.readFile({ encoding: "utf-8" });
1691
- } finally {
1692
- await fd.close();
1693
- }
1694
- } else {
1695
- stat = await node_fs_promises.default.lstat(resolvedPath);
1696
- if (stat.isSymbolicLink()) throw new Error(`Symlinks are not allowed: ${filePath}`);
1697
- if (!stat.isFile()) throw new Error(`File '${filePath}' not found`);
1698
- content = await node_fs_promises.default.readFile(resolvedPath, "utf-8");
1699
- }
1700
- return {
1701
- content: content.split("\n"),
1702
- created_at: stat.ctime.toISOString(),
1703
- modified_at: stat.mtime.toISOString()
1704
- };
1705
- }
1706
- /**
1707
2147
  * Create a new file with content.
1708
2148
  * Returns WriteResult. External storage sets filesUpdate=null.
1709
2149
  */
@@ -2106,21 +2546,11 @@ var CompositeBackend = class {
2106
2546
  * @param limit - Maximum number of lines to read
2107
2547
  * @returns Formatted file content with line numbers, or error message
2108
2548
  */
2109
- async read(filePath, offset = 0, limit = 2e3) {
2549
+ async read(filePath, offset = 0, limit = 500) {
2110
2550
  const [backend, strippedKey] = this.getBackendAndKey(filePath);
2111
2551
  return await backend.read(strippedKey, offset, limit);
2112
2552
  }
2113
2553
  /**
2114
- * Read file content as raw FileData.
2115
- *
2116
- * @param filePath - Absolute file path
2117
- * @returns Raw file content as FileData
2118
- */
2119
- async readRaw(filePath) {
2120
- const [backend, strippedKey] = this.getBackendAndKey(filePath);
2121
- return await backend.readRaw(strippedKey);
2122
- }
2123
- /**
2124
2554
  * Structured search results or error string for invalid input.
2125
2555
  */
2126
2556
  async grepRaw(pattern, path$4 = "/", glob = null) {
@@ -2557,35 +2987,13 @@ var BaseSandbox = class {
2557
2987
  * @param limit - Maximum number of lines to read
2558
2988
  * @returns Formatted file content with line numbers, or error message
2559
2989
  */
2560
- async read(filePath, offset = 0, limit = 2e3) {
2990
+ async read(filePath, offset = 0, limit = 500) {
2561
2991
  const command = buildReadCommand(filePath, offset, limit);
2562
2992
  const result = await this.execute(command);
2563
2993
  if (result.exitCode !== 0) return `Error: File '${filePath}' not found`;
2564
2994
  return result.output;
2565
2995
  }
2566
2996
  /**
2567
- * Read file content as raw FileData.
2568
- *
2569
- * @param filePath - Absolute file path
2570
- * @returns Raw file content as FileData
2571
- */
2572
- async readRaw(filePath) {
2573
- const command = buildReadCommand(filePath, 0, Number.MAX_SAFE_INTEGER);
2574
- const result = await this.execute(command);
2575
- if (result.exitCode !== 0) throw new Error(`File '${filePath}' not found`);
2576
- const lines = [];
2577
- for (const line of result.output.split("\n")) {
2578
- const tabIndex = line.indexOf(" ");
2579
- if (tabIndex !== -1) lines.push(line.substring(tabIndex + 1));
2580
- }
2581
- const now = (/* @__PURE__ */ new Date()).toISOString();
2582
- return {
2583
- content: lines,
2584
- created_at: now,
2585
- modified_at: now
2586
- };
2587
- }
2588
- /**
2589
2997
  * Structured search results or error string for invalid input.
2590
2998
  */
2591
2999
  async grepRaw(pattern, path$4 = "/", glob = null) {
@@ -2691,7 +3099,7 @@ const BASE_PROMPT = `In order to complete the objective that the user asks of yo
2691
3099
  * ```
2692
3100
  */
2693
3101
  function createDeepAgent(params = {}) {
2694
- const { model = "claude-sonnet-4-5-20250929", tools = [], systemPrompt, middleware: customMiddleware = [], subagents = [], responseFormat, contextSchema, checkpointer, store, backend, interruptOn, name } = params;
3102
+ const { model = "claude-sonnet-4-5-20250929", tools = [], systemPrompt, middleware: customMiddleware = [], subagents = [], responseFormat, contextSchema, checkpointer, store, backend, interruptOn, name, memory, skills } = params;
2695
3103
  const finalSystemPrompt = systemPrompt ? typeof systemPrompt === "string" ? `${systemPrompt}\n\n${BASE_PROMPT}` : new langchain.SystemMessage({ content: [{
2696
3104
  type: "text",
2697
3105
  text: BASE_PROMPT
@@ -2700,14 +3108,20 @@ function createDeepAgent(params = {}) {
2700
3108
  text: systemPrompt.content
2701
3109
  }] : systemPrompt.content] }) : BASE_PROMPT;
2702
3110
  const filesystemBackend = backend ? backend : (config) => new StateBackend(config);
3111
+ const skillsMiddleware = skills != null && skills.length > 0 ? [createSkillsMiddleware({
3112
+ backend: filesystemBackend,
3113
+ sources: skills
3114
+ })] : [];
2703
3115
  const builtInMiddleware = [
2704
3116
  (0, langchain.todoListMiddleware)(),
3117
+ ...skillsMiddleware,
2705
3118
  createFilesystemMiddleware({ backend: filesystemBackend }),
2706
3119
  createSubAgentMiddleware({
2707
3120
  defaultModel: model,
2708
3121
  defaultTools: tools,
2709
3122
  defaultMiddleware: [
2710
3123
  (0, langchain.todoListMiddleware)(),
3124
+ ...skillsMiddleware,
2711
3125
  createFilesystemMiddleware({ backend: filesystemBackend }),
2712
3126
  (0, langchain.summarizationMiddleware)({
2713
3127
  model,
@@ -2727,7 +3141,11 @@ function createDeepAgent(params = {}) {
2727
3141
  keep: { messages: 6 }
2728
3142
  }),
2729
3143
  (0, langchain.anthropicPromptCachingMiddleware)({ unsupportedModelBehavior: "ignore" }),
2730
- createPatchToolCallsMiddleware()
3144
+ createPatchToolCallsMiddleware(),
3145
+ ...memory != null && memory.length > 0 ? [createMemoryMiddleware({
3146
+ backend: filesystemBackend,
3147
+ sources: memory
3148
+ })] : []
2731
3149
  ];
2732
3150
  if (interruptOn) builtInMiddleware.push((0, langchain.humanInTheLoopMiddleware)({ interruptOn }));
2733
3151
  return (0, langchain.createAgent)({
@@ -2837,6 +3255,206 @@ function createSettings(options = {}) {
2837
3255
  };
2838
3256
  }
2839
3257
 
3258
+ //#endregion
3259
+ //#region src/middleware/agent-memory.ts
3260
+ /**
3261
+ * Middleware for loading agent-specific long-term memory into the system prompt.
3262
+ *
3263
+ * This middleware loads the agent's long-term memory from agent.md files
3264
+ * and injects it into the system prompt. Memory is loaded from:
3265
+ * - User memory: ~/.deepagents/{agent_name}/agent.md
3266
+ * - Project memory: {project_root}/.deepagents/agent.md
3267
+ */
3268
+ /**
3269
+ * State schema for agent memory middleware.
3270
+ */
3271
+ const AgentMemoryStateSchema = zod.z.object({
3272
+ userMemory: zod.z.string().optional(),
3273
+ projectMemory: zod.z.string().optional()
3274
+ });
3275
+ /**
3276
+ * Default template for memory injection.
3277
+ */
3278
+ const DEFAULT_MEMORY_TEMPLATE = `<user_memory>
3279
+ {user_memory}
3280
+ </user_memory>
3281
+
3282
+ <project_memory>
3283
+ {project_memory}
3284
+ </project_memory>`;
3285
+ /**
3286
+ * Long-term Memory Documentation system prompt.
3287
+ */
3288
+ const LONGTERM_MEMORY_SYSTEM_PROMPT = `
3289
+
3290
+ ## Long-term Memory
3291
+
3292
+ Your long-term memory is stored in files on the filesystem and persists across sessions.
3293
+
3294
+ **User Memory Location**: \`{agent_dir_absolute}\` (displays as \`{agent_dir_display}\`)
3295
+ **Project Memory Location**: {project_memory_info}
3296
+
3297
+ Your system prompt is loaded from TWO sources at startup:
3298
+ 1. **User agent.md**: \`{agent_dir_absolute}/agent.md\` - Your personal preferences across all projects
3299
+ 2. **Project agent.md**: Loaded from project root if available - Project-specific instructions
3300
+
3301
+ Project-specific agent.md is loaded from these locations (both combined if both exist):
3302
+ - \`[project-root]/.deepagents/agent.md\` (preferred)
3303
+ - \`[project-root]/agent.md\` (fallback, but also included if both exist)
3304
+
3305
+ **When to CHECK/READ memories (CRITICAL - do this FIRST):**
3306
+ - **At the start of ANY new session**: Check both user and project memories
3307
+ - User: \`ls {agent_dir_absolute}\`
3308
+ - Project: \`ls {project_deepagents_dir}\` (if in a project)
3309
+ - **BEFORE answering questions**: If asked "what do you know about X?" or "how do I do Y?", check project memories FIRST, then user
3310
+ - **When user asks you to do something**: Check if you have project-specific guides or examples
3311
+ - **When user references past work**: Search project memory files for related context
3312
+
3313
+ **Memory-first response pattern:**
3314
+ 1. User asks a question → Check project directory first: \`ls {project_deepagents_dir}\`
3315
+ 2. If relevant files exist → Read them with \`read_file '{project_deepagents_dir}/[filename]'\`
3316
+ 3. Check user memory if needed → \`ls {agent_dir_absolute}\`
3317
+ 4. Base your answer on saved knowledge supplemented by general knowledge
3318
+
3319
+ **When to update memories:**
3320
+ - **IMMEDIATELY when the user describes your role or how you should behave**
3321
+ - **IMMEDIATELY when the user gives feedback on your work** - Update memories to capture what was wrong and how to do it better
3322
+ - When the user explicitly asks you to remember something
3323
+ - When patterns or preferences emerge (coding styles, conventions, workflows)
3324
+ - After significant work where context would help in future sessions
3325
+
3326
+ **Learning from feedback:**
3327
+ - When user says something is better/worse, capture WHY and encode it as a pattern
3328
+ - Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions
3329
+ - When user says "you should remember X" or "be careful about Y", treat this as HIGH PRIORITY - update memories IMMEDIATELY
3330
+ - Look for the underlying principle behind corrections, not just the specific mistake
3331
+
3332
+ ## Deciding Where to Store Memory
3333
+
3334
+ When writing or updating agent memory, decide whether each fact, configuration, or behavior belongs in:
3335
+
3336
+ ### User Agent File: \`{agent_dir_absolute}/agent.md\`
3337
+ → Describes the agent's **personality, style, and universal behavior** across all projects.
3338
+
3339
+ **Store here:**
3340
+ - Your general tone and communication style
3341
+ - Universal coding preferences (formatting, comment style, etc.)
3342
+ - General workflows and methodologies you follow
3343
+ - Tool usage patterns that apply everywhere
3344
+ - Personal preferences that don't change per-project
3345
+
3346
+ **Examples:**
3347
+ - "Be concise and direct in responses"
3348
+ - "Always use type hints in Python"
3349
+ - "Prefer functional programming patterns"
3350
+
3351
+ ### Project Agent File: \`{project_deepagents_dir}/agent.md\`
3352
+ → Describes **how this specific project works** and **how the agent should behave here only.**
3353
+
3354
+ **Store here:**
3355
+ - Project-specific architecture and design patterns
3356
+ - Coding conventions specific to this codebase
3357
+ - Project structure and organization
3358
+ - Testing strategies for this project
3359
+ - Deployment processes and workflows
3360
+ - Team conventions and guidelines
3361
+
3362
+ **Examples:**
3363
+ - "This project uses FastAPI with SQLAlchemy"
3364
+ - "Tests go in tests/ directory mirroring src/ structure"
3365
+ - "All API changes require updating OpenAPI spec"
3366
+
3367
+ ### Project Memory Files: \`{project_deepagents_dir}/*.md\`
3368
+ → Use for **project-specific reference information** and structured notes.
3369
+
3370
+ **Store here:**
3371
+ - API design documentation
3372
+ - Architecture decisions and rationale
3373
+ - Deployment procedures
3374
+ - Common debugging patterns
3375
+ - Onboarding information
3376
+
3377
+ **Examples:**
3378
+ - \`{project_deepagents_dir}/api-design.md\` - REST API patterns used
3379
+ - \`{project_deepagents_dir}/architecture.md\` - System architecture overview
3380
+ - \`{project_deepagents_dir}/deployment.md\` - How to deploy this project
3381
+
3382
+ ### File Operations:
3383
+
3384
+ **User memory:**
3385
+ \`\`\`
3386
+ ls {agent_dir_absolute} # List user memory files
3387
+ read_file '{agent_dir_absolute}/agent.md' # Read user preferences
3388
+ edit_file '{agent_dir_absolute}/agent.md' ... # Update user preferences
3389
+ \`\`\`
3390
+
3391
+ **Project memory (preferred for project-specific information):**
3392
+ \`\`\`
3393
+ ls {project_deepagents_dir} # List project memory files
3394
+ read_file '{project_deepagents_dir}/agent.md' # Read project instructions
3395
+ edit_file '{project_deepagents_dir}/agent.md' ... # Update project instructions
3396
+ write_file '{project_deepagents_dir}/agent.md' ... # Create project memory file
3397
+ \`\`\`
3398
+
3399
+ **Important**:
3400
+ - Project memory files are stored in \`.deepagents/\` inside the project root
3401
+ - Always use absolute paths for file operations
3402
+ - Check project memories BEFORE user when answering project-specific questions`;
3403
+ /**
3404
+ * Create middleware for loading agent-specific long-term memory.
3405
+ *
3406
+ * This middleware loads the agent's long-term memory from a file (agent.md)
3407
+ * and injects it into the system prompt. The memory is loaded once at the
3408
+ * start of the conversation and stored in state.
3409
+ *
3410
+ * @param options - Configuration options
3411
+ * @returns AgentMiddleware for memory loading and injection
3412
+ */
3413
+ function createAgentMemoryMiddleware(options) {
3414
+ const { settings, assistantId, systemPromptTemplate } = options;
3415
+ const agentDir = settings.getAgentDir(assistantId);
3416
+ const agentDirDisplay = `~/.deepagents/${assistantId}`;
3417
+ const agentDirAbsolute = agentDir;
3418
+ const projectRoot = settings.projectRoot;
3419
+ const projectMemoryInfo = projectRoot ? `\`${projectRoot}\` (detected)` : "None (not in a git project)";
3420
+ const projectDeepagentsDir = projectRoot ? `${projectRoot}/.deepagents` : "[project-root]/.deepagents (not in a project)";
3421
+ const template = systemPromptTemplate || DEFAULT_MEMORY_TEMPLATE;
3422
+ return (0, langchain.createMiddleware)({
3423
+ name: "AgentMemoryMiddleware",
3424
+ stateSchema: AgentMemoryStateSchema,
3425
+ beforeAgent(state) {
3426
+ const result = {};
3427
+ if (!("userMemory" in state)) {
3428
+ const userPath = settings.getUserAgentMdPath(assistantId);
3429
+ if (node_fs.default.existsSync(userPath)) try {
3430
+ result.userMemory = node_fs.default.readFileSync(userPath, "utf-8");
3431
+ } catch {}
3432
+ }
3433
+ if (!("projectMemory" in state)) {
3434
+ const projectPath = settings.getProjectAgentMdPath();
3435
+ if (projectPath && node_fs.default.existsSync(projectPath)) try {
3436
+ result.projectMemory = node_fs.default.readFileSync(projectPath, "utf-8");
3437
+ } catch {}
3438
+ }
3439
+ return Object.keys(result).length > 0 ? result : void 0;
3440
+ },
3441
+ wrapModelCall(request, handler) {
3442
+ const userMemory = request.state?.userMemory;
3443
+ const projectMemory = request.state?.projectMemory;
3444
+ const baseSystemPrompt = request.systemPrompt || "";
3445
+ const memorySection = template.replace("{user_memory}", userMemory || "(No user agent.md)").replace("{project_memory}", projectMemory || "(No project agent.md)");
3446
+ const memoryDocs = LONGTERM_MEMORY_SYSTEM_PROMPT.replaceAll("{agent_dir_absolute}", agentDirAbsolute).replaceAll("{agent_dir_display}", agentDirDisplay).replaceAll("{project_memory_info}", projectMemoryInfo).replaceAll("{project_deepagents_dir}", projectDeepagentsDir);
3447
+ let systemPrompt = memorySection;
3448
+ if (baseSystemPrompt) systemPrompt += "\n\n" + baseSystemPrompt;
3449
+ systemPrompt += "\n\n" + memoryDocs;
3450
+ return handler({
3451
+ ...request,
3452
+ systemPrompt
3453
+ });
3454
+ }
3455
+ });
3456
+ }
3457
+
2840
3458
  //#endregion
2841
3459
  //#region src/skills/loader.ts
2842
3460
  /**
@@ -2865,10 +3483,10 @@ function createSettings(options = {}) {
2865
3483
  * @see https://agentskills.io/specification
2866
3484
  */
2867
3485
  /** Maximum size for SKILL.md files (10MB) */
2868
- const MAX_SKILL_FILE_SIZE = 10 * 1024 * 1024;
3486
+ const MAX_SKILL_FILE_SIZE$1 = 10 * 1024 * 1024;
2869
3487
  /** Agent Skills spec constraints */
2870
- const MAX_SKILL_NAME_LENGTH = 64;
2871
- const MAX_SKILL_DESCRIPTION_LENGTH = 1024;
3488
+ const MAX_SKILL_NAME_LENGTH$1 = 64;
3489
+ const MAX_SKILL_DESCRIPTION_LENGTH$1 = 1024;
2872
3490
  /** Pattern for validating skill names per Agent Skills spec */
2873
3491
  const SKILL_NAME_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
2874
3492
  /** Pattern for extracting YAML frontmatter */
@@ -2912,7 +3530,7 @@ function validateSkillName(name, directoryName) {
2912
3530
  valid: false,
2913
3531
  error: "name is required"
2914
3532
  };
2915
- if (name.length > MAX_SKILL_NAME_LENGTH) return {
3533
+ if (name.length > MAX_SKILL_NAME_LENGTH$1) return {
2916
3534
  valid: false,
2917
3535
  error: "name exceeds 64 characters"
2918
3536
  };
@@ -2952,7 +3570,7 @@ function parseFrontmatter(content) {
2952
3570
  function parseSkillMetadata(skillMdPath, source) {
2953
3571
  try {
2954
3572
  const stats = node_fs.default.statSync(skillMdPath);
2955
- if (stats.size > MAX_SKILL_FILE_SIZE) {
3573
+ if (stats.size > MAX_SKILL_FILE_SIZE$1) {
2956
3574
  console.warn(`Skipping ${skillMdPath}: file too large (${stats.size} bytes)`);
2957
3575
  return null;
2958
3576
  }
@@ -2971,9 +3589,9 @@ function parseSkillMetadata(skillMdPath, source) {
2971
3589
  const validation = validateSkillName(String(name), directoryName);
2972
3590
  if (!validation.valid) console.warn(`Skill '${name}' in ${skillMdPath} does not follow Agent Skills spec: ${validation.error}. Consider renaming to be spec-compliant.`);
2973
3591
  let descriptionStr = String(description);
2974
- if (descriptionStr.length > MAX_SKILL_DESCRIPTION_LENGTH) {
2975
- console.warn(`Description exceeds ${MAX_SKILL_DESCRIPTION_LENGTH} chars in ${skillMdPath}, truncating`);
2976
- descriptionStr = descriptionStr.slice(0, MAX_SKILL_DESCRIPTION_LENGTH);
3592
+ if (descriptionStr.length > MAX_SKILL_DESCRIPTION_LENGTH$1) {
3593
+ console.warn(`Description exceeds ${MAX_SKILL_DESCRIPTION_LENGTH$1} chars in ${skillMdPath}, truncating`);
3594
+ descriptionStr = descriptionStr.slice(0, MAX_SKILL_DESCRIPTION_LENGTH$1);
2977
3595
  }
2978
3596
  return {
2979
3597
  name: String(name),
@@ -3060,375 +3678,6 @@ function listSkills(options) {
3060
3678
  return Array.from(allSkills.values());
3061
3679
  }
3062
3680
 
3063
- //#endregion
3064
- //#region src/middleware/skills.ts
3065
- /**
3066
- * Middleware for loading and exposing agent skills to the system prompt.
3067
- *
3068
- * This middleware implements Anthropic's "Agent Skills" pattern with progressive disclosure:
3069
- * 1. Parse YAML frontmatter from SKILL.md files at session start
3070
- * 2. Inject skills metadata (name + description) into system prompt
3071
- * 3. Agent reads full SKILL.md content when relevant to a task
3072
- *
3073
- * Skills directory structure (per-agent + project):
3074
- * User-level: ~/.deepagents/{AGENT_NAME}/skills/
3075
- * Project-level: {PROJECT_ROOT}/.deepagents/skills/
3076
- *
3077
- * @example
3078
- * ```
3079
- * ~/.deepagents/{AGENT_NAME}/skills/
3080
- * ├── web-research/
3081
- * │ ├── SKILL.md # Required: YAML frontmatter + instructions
3082
- * │ └── helper.py # Optional: supporting files
3083
- * ├── code-review/
3084
- * │ ├── SKILL.md
3085
- * │ └── checklist.md
3086
- *
3087
- * .deepagents/skills/
3088
- * ├── project-specific/
3089
- * │ └── SKILL.md # Project-specific skills
3090
- * ```
3091
- */
3092
- /**
3093
- * State schema for skills middleware.
3094
- */
3095
- const SkillsStateSchema = zod.z.object({ skillsMetadata: zod.z.array(zod.z.object({
3096
- name: zod.z.string(),
3097
- description: zod.z.string(),
3098
- path: zod.z.string(),
3099
- source: zod.z.enum(["user", "project"]),
3100
- license: zod.z.string().optional(),
3101
- compatibility: zod.z.string().optional(),
3102
- metadata: zod.z.record(zod.z.string(), zod.z.string()).optional(),
3103
- allowedTools: zod.z.string().optional()
3104
- })).optional() });
3105
- /**
3106
- * Skills System Documentation prompt template.
3107
- */
3108
- const SKILLS_SYSTEM_PROMPT = `
3109
-
3110
- ## Skills System
3111
-
3112
- You have access to a skills library that provides specialized capabilities and domain knowledge.
3113
-
3114
- {skills_locations}
3115
-
3116
- **Available Skills:**
3117
-
3118
- {skills_list}
3119
-
3120
- **How to Use Skills (Progressive Disclosure):**
3121
-
3122
- Skills follow a **progressive disclosure** pattern - you know they exist (name + description above), but you only read the full instructions when needed:
3123
-
3124
- 1. **Recognize when a skill applies**: Check if the user's task matches any skill's description
3125
- 2. **Read the skill's full instructions**: The skill list above shows the exact path to use with read_file
3126
- 3. **Follow the skill's instructions**: SKILL.md contains step-by-step workflows, best practices, and examples
3127
- 4. **Access supporting files**: Skills may include Python scripts, configs, or reference docs - use absolute paths
3128
-
3129
- **When to Use Skills:**
3130
- - When the user's request matches a skill's domain (e.g., "research X" → web-research skill)
3131
- - When you need specialized knowledge or structured workflows
3132
- - When a skill provides proven patterns for complex tasks
3133
-
3134
- **Skills are Self-Documenting:**
3135
- - Each SKILL.md tells you exactly what the skill does and how to use it
3136
- - The skill list above shows the full path for each skill's SKILL.md file
3137
-
3138
- **Executing Skill Scripts:**
3139
- Skills may contain Python scripts or other executable files. Always use absolute paths from the skill list.
3140
-
3141
- **Example Workflow:**
3142
-
3143
- User: "Can you research the latest developments in quantum computing?"
3144
-
3145
- 1. Check available skills above → See "web-research" skill with its full path
3146
- 2. Read the skill using the path shown in the list
3147
- 3. Follow the skill's research workflow (search → organize → synthesize)
3148
- 4. Use any helper scripts with absolute paths
3149
-
3150
- Remember: Skills are tools to make you more capable and consistent. When in doubt, check if a skill exists for the task!
3151
- `;
3152
- /**
3153
- * Format skills locations for display in system prompt.
3154
- */
3155
- function formatSkillsLocations(userSkillsDisplay, projectSkillsDir) {
3156
- const locations = [`**User Skills**: \`${userSkillsDisplay}\``];
3157
- if (projectSkillsDir) locations.push(`**Project Skills**: \`${projectSkillsDir}\` (overrides user skills)`);
3158
- return locations.join("\n");
3159
- }
3160
- /**
3161
- * Format skills metadata for display in system prompt.
3162
- */
3163
- function formatSkillsList(skills, userSkillsDisplay, projectSkillsDir) {
3164
- if (skills.length === 0) {
3165
- const locations = [userSkillsDisplay];
3166
- if (projectSkillsDir) locations.push(projectSkillsDir);
3167
- return `(No skills available yet. You can create skills in ${locations.join(" or ")})`;
3168
- }
3169
- const userSkills = skills.filter((s) => s.source === "user");
3170
- const projectSkills = skills.filter((s) => s.source === "project");
3171
- const lines = [];
3172
- if (userSkills.length > 0) {
3173
- lines.push("**User Skills:**");
3174
- for (const skill of userSkills) {
3175
- lines.push(`- **${skill.name}**: ${skill.description}`);
3176
- lines.push(` → Read \`${skill.path}\` for full instructions`);
3177
- }
3178
- lines.push("");
3179
- }
3180
- if (projectSkills.length > 0) {
3181
- lines.push("**Project Skills:**");
3182
- for (const skill of projectSkills) {
3183
- lines.push(`- **${skill.name}**: ${skill.description}`);
3184
- lines.push(` → Read \`${skill.path}\` for full instructions`);
3185
- }
3186
- }
3187
- return lines.join("\n");
3188
- }
3189
- /**
3190
- * Create middleware for loading and exposing agent skills.
3191
- *
3192
- * This middleware implements Anthropic's agent skills pattern:
3193
- * - Loads skills metadata (name, description) from YAML frontmatter at session start
3194
- * - Injects skills list into system prompt for discoverability
3195
- * - Agent reads full SKILL.md content when a skill is relevant (progressive disclosure)
3196
- *
3197
- * Supports both user-level and project-level skills:
3198
- * - User skills: ~/.deepagents/{AGENT_NAME}/skills/
3199
- * - Project skills: {PROJECT_ROOT}/.deepagents/skills/
3200
- * - Project skills override user skills with the same name
3201
- *
3202
- * @param options - Configuration options
3203
- * @returns AgentMiddleware for skills loading and injection
3204
- */
3205
- function createSkillsMiddleware(options) {
3206
- const { skillsDir, assistantId, projectSkillsDir } = options;
3207
- const userSkillsDisplay = `~/.deepagents/${assistantId}/skills`;
3208
- return (0, langchain.createMiddleware)({
3209
- name: "SkillsMiddleware",
3210
- stateSchema: SkillsStateSchema,
3211
- beforeAgent() {
3212
- return { skillsMetadata: listSkills({
3213
- userSkillsDir: skillsDir,
3214
- projectSkillsDir
3215
- }) };
3216
- },
3217
- wrapModelCall(request, handler) {
3218
- const skillsMetadata = request.state?.skillsMetadata || [];
3219
- const skillsLocations = formatSkillsLocations(userSkillsDisplay, projectSkillsDir);
3220
- const skillsList = formatSkillsList(skillsMetadata, userSkillsDisplay, projectSkillsDir);
3221
- const skillsSection = SKILLS_SYSTEM_PROMPT.replace("{skills_locations}", skillsLocations).replace("{skills_list}", skillsList);
3222
- const currentSystemPrompt = request.systemPrompt || "";
3223
- const newSystemPrompt = currentSystemPrompt ? `${currentSystemPrompt}\n\n${skillsSection}` : skillsSection;
3224
- return handler({
3225
- ...request,
3226
- systemPrompt: newSystemPrompt
3227
- });
3228
- }
3229
- });
3230
- }
3231
-
3232
- //#endregion
3233
- //#region src/middleware/agent-memory.ts
3234
- /**
3235
- * Middleware for loading agent-specific long-term memory into the system prompt.
3236
- *
3237
- * This middleware loads the agent's long-term memory from agent.md files
3238
- * and injects it into the system prompt. Memory is loaded from:
3239
- * - User memory: ~/.deepagents/{agent_name}/agent.md
3240
- * - Project memory: {project_root}/.deepagents/agent.md
3241
- */
3242
- /**
3243
- * State schema for agent memory middleware.
3244
- */
3245
- const AgentMemoryStateSchema = zod.z.object({
3246
- userMemory: zod.z.string().optional(),
3247
- projectMemory: zod.z.string().optional()
3248
- });
3249
- /**
3250
- * Default template for memory injection.
3251
- */
3252
- const DEFAULT_MEMORY_TEMPLATE = `<user_memory>
3253
- {user_memory}
3254
- </user_memory>
3255
-
3256
- <project_memory>
3257
- {project_memory}
3258
- </project_memory>`;
3259
- /**
3260
- * Long-term Memory Documentation system prompt.
3261
- */
3262
- const LONGTERM_MEMORY_SYSTEM_PROMPT = `
3263
-
3264
- ## Long-term Memory
3265
-
3266
- Your long-term memory is stored in files on the filesystem and persists across sessions.
3267
-
3268
- **User Memory Location**: \`{agent_dir_absolute}\` (displays as \`{agent_dir_display}\`)
3269
- **Project Memory Location**: {project_memory_info}
3270
-
3271
- Your system prompt is loaded from TWO sources at startup:
3272
- 1. **User agent.md**: \`{agent_dir_absolute}/agent.md\` - Your personal preferences across all projects
3273
- 2. **Project agent.md**: Loaded from project root if available - Project-specific instructions
3274
-
3275
- Project-specific agent.md is loaded from these locations (both combined if both exist):
3276
- - \`[project-root]/.deepagents/agent.md\` (preferred)
3277
- - \`[project-root]/agent.md\` (fallback, but also included if both exist)
3278
-
3279
- **When to CHECK/READ memories (CRITICAL - do this FIRST):**
3280
- - **At the start of ANY new session**: Check both user and project memories
3281
- - User: \`ls {agent_dir_absolute}\`
3282
- - Project: \`ls {project_deepagents_dir}\` (if in a project)
3283
- - **BEFORE answering questions**: If asked "what do you know about X?" or "how do I do Y?", check project memories FIRST, then user
3284
- - **When user asks you to do something**: Check if you have project-specific guides or examples
3285
- - **When user references past work**: Search project memory files for related context
3286
-
3287
- **Memory-first response pattern:**
3288
- 1. User asks a question → Check project directory first: \`ls {project_deepagents_dir}\`
3289
- 2. If relevant files exist → Read them with \`read_file '{project_deepagents_dir}/[filename]'\`
3290
- 3. Check user memory if needed → \`ls {agent_dir_absolute}\`
3291
- 4. Base your answer on saved knowledge supplemented by general knowledge
3292
-
3293
- **When to update memories:**
3294
- - **IMMEDIATELY when the user describes your role or how you should behave**
3295
- - **IMMEDIATELY when the user gives feedback on your work** - Update memories to capture what was wrong and how to do it better
3296
- - When the user explicitly asks you to remember something
3297
- - When patterns or preferences emerge (coding styles, conventions, workflows)
3298
- - After significant work where context would help in future sessions
3299
-
3300
- **Learning from feedback:**
3301
- - When user says something is better/worse, capture WHY and encode it as a pattern
3302
- - Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions
3303
- - When user says "you should remember X" or "be careful about Y", treat this as HIGH PRIORITY - update memories IMMEDIATELY
3304
- - Look for the underlying principle behind corrections, not just the specific mistake
3305
-
3306
- ## Deciding Where to Store Memory
3307
-
3308
- When writing or updating agent memory, decide whether each fact, configuration, or behavior belongs in:
3309
-
3310
- ### User Agent File: \`{agent_dir_absolute}/agent.md\`
3311
- → Describes the agent's **personality, style, and universal behavior** across all projects.
3312
-
3313
- **Store here:**
3314
- - Your general tone and communication style
3315
- - Universal coding preferences (formatting, comment style, etc.)
3316
- - General workflows and methodologies you follow
3317
- - Tool usage patterns that apply everywhere
3318
- - Personal preferences that don't change per-project
3319
-
3320
- **Examples:**
3321
- - "Be concise and direct in responses"
3322
- - "Always use type hints in Python"
3323
- - "Prefer functional programming patterns"
3324
-
3325
- ### Project Agent File: \`{project_deepagents_dir}/agent.md\`
3326
- → Describes **how this specific project works** and **how the agent should behave here only.**
3327
-
3328
- **Store here:**
3329
- - Project-specific architecture and design patterns
3330
- - Coding conventions specific to this codebase
3331
- - Project structure and organization
3332
- - Testing strategies for this project
3333
- - Deployment processes and workflows
3334
- - Team conventions and guidelines
3335
-
3336
- **Examples:**
3337
- - "This project uses FastAPI with SQLAlchemy"
3338
- - "Tests go in tests/ directory mirroring src/ structure"
3339
- - "All API changes require updating OpenAPI spec"
3340
-
3341
- ### Project Memory Files: \`{project_deepagents_dir}/*.md\`
3342
- → Use for **project-specific reference information** and structured notes.
3343
-
3344
- **Store here:**
3345
- - API design documentation
3346
- - Architecture decisions and rationale
3347
- - Deployment procedures
3348
- - Common debugging patterns
3349
- - Onboarding information
3350
-
3351
- **Examples:**
3352
- - \`{project_deepagents_dir}/api-design.md\` - REST API patterns used
3353
- - \`{project_deepagents_dir}/architecture.md\` - System architecture overview
3354
- - \`{project_deepagents_dir}/deployment.md\` - How to deploy this project
3355
-
3356
- ### File Operations:
3357
-
3358
- **User memory:**
3359
- \`\`\`
3360
- ls {agent_dir_absolute} # List user memory files
3361
- read_file '{agent_dir_absolute}/agent.md' # Read user preferences
3362
- edit_file '{agent_dir_absolute}/agent.md' ... # Update user preferences
3363
- \`\`\`
3364
-
3365
- **Project memory (preferred for project-specific information):**
3366
- \`\`\`
3367
- ls {project_deepagents_dir} # List project memory files
3368
- read_file '{project_deepagents_dir}/agent.md' # Read project instructions
3369
- edit_file '{project_deepagents_dir}/agent.md' ... # Update project instructions
3370
- write_file '{project_deepagents_dir}/agent.md' ... # Create project memory file
3371
- \`\`\`
3372
-
3373
- **Important**:
3374
- - Project memory files are stored in \`.deepagents/\` inside the project root
3375
- - Always use absolute paths for file operations
3376
- - Check project memories BEFORE user when answering project-specific questions`;
3377
- /**
3378
- * Create middleware for loading agent-specific long-term memory.
3379
- *
3380
- * This middleware loads the agent's long-term memory from a file (agent.md)
3381
- * and injects it into the system prompt. The memory is loaded once at the
3382
- * start of the conversation and stored in state.
3383
- *
3384
- * @param options - Configuration options
3385
- * @returns AgentMiddleware for memory loading and injection
3386
- */
3387
- function createAgentMemoryMiddleware(options) {
3388
- const { settings, assistantId, systemPromptTemplate } = options;
3389
- const agentDir = settings.getAgentDir(assistantId);
3390
- const agentDirDisplay = `~/.deepagents/${assistantId}`;
3391
- const agentDirAbsolute = agentDir;
3392
- const projectRoot = settings.projectRoot;
3393
- const projectMemoryInfo = projectRoot ? `\`${projectRoot}\` (detected)` : "None (not in a git project)";
3394
- const projectDeepagentsDir = projectRoot ? `${projectRoot}/.deepagents` : "[project-root]/.deepagents (not in a project)";
3395
- const template = systemPromptTemplate || DEFAULT_MEMORY_TEMPLATE;
3396
- return (0, langchain.createMiddleware)({
3397
- name: "AgentMemoryMiddleware",
3398
- stateSchema: AgentMemoryStateSchema,
3399
- beforeAgent(state) {
3400
- const result = {};
3401
- if (!("userMemory" in state)) {
3402
- const userPath = settings.getUserAgentMdPath(assistantId);
3403
- if (node_fs.default.existsSync(userPath)) try {
3404
- result.userMemory = node_fs.default.readFileSync(userPath, "utf-8");
3405
- } catch {}
3406
- }
3407
- if (!("projectMemory" in state)) {
3408
- const projectPath = settings.getProjectAgentMdPath();
3409
- if (projectPath && node_fs.default.existsSync(projectPath)) try {
3410
- result.projectMemory = node_fs.default.readFileSync(projectPath, "utf-8");
3411
- } catch {}
3412
- }
3413
- return Object.keys(result).length > 0 ? result : void 0;
3414
- },
3415
- wrapModelCall(request, handler) {
3416
- const userMemory = request.state?.userMemory;
3417
- const projectMemory = request.state?.projectMemory;
3418
- const baseSystemPrompt = request.systemPrompt || "";
3419
- const memorySection = template.replace("{user_memory}", userMemory || "(No user agent.md)").replace("{project_memory}", projectMemory || "(No project agent.md)");
3420
- const memoryDocs = LONGTERM_MEMORY_SYSTEM_PROMPT.replaceAll("{agent_dir_absolute}", agentDirAbsolute).replaceAll("{agent_dir_display}", agentDirDisplay).replaceAll("{project_memory_info}", projectMemoryInfo).replaceAll("{project_deepagents_dir}", projectDeepagentsDir);
3421
- let systemPrompt = memorySection;
3422
- if (baseSystemPrompt) systemPrompt += "\n\n" + baseSystemPrompt;
3423
- systemPrompt += "\n\n" + memoryDocs;
3424
- return handler({
3425
- ...request,
3426
- systemPrompt
3427
- });
3428
- }
3429
- });
3430
- }
3431
-
3432
3681
  //#endregion
3433
3682
  exports.BaseSandbox = BaseSandbox;
3434
3683
  exports.CompositeBackend = CompositeBackend;
@@ -3441,6 +3690,7 @@ exports.StoreBackend = StoreBackend;
3441
3690
  exports.createAgentMemoryMiddleware = createAgentMemoryMiddleware;
3442
3691
  exports.createDeepAgent = createDeepAgent;
3443
3692
  exports.createFilesystemMiddleware = createFilesystemMiddleware;
3693
+ exports.createMemoryMiddleware = createMemoryMiddleware;
3444
3694
  exports.createPatchToolCallsMiddleware = createPatchToolCallsMiddleware;
3445
3695
  exports.createSettings = createSettings;
3446
3696
  exports.createSkillsMiddleware = createSkillsMiddleware;