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.js CHANGED
@@ -5,14 +5,14 @@ import micromatch from "micromatch";
5
5
  import { basename } from "path";
6
6
  import { z as z$1 } from "zod/v3";
7
7
  import { HumanMessage, RemoveMessage } from "@langchain/core/messages";
8
+ import { z as z$2 } from "zod";
9
+ import yaml from "yaml";
8
10
  import fs from "node:fs/promises";
9
11
  import fs$1 from "node:fs";
10
12
  import path from "node:path";
11
13
  import { spawn } from "node:child_process";
12
14
  import fg from "fast-glob";
13
15
  import os from "node:os";
14
- import { z as z$2 } from "zod";
15
- import yaml from "yaml";
16
16
 
17
17
  //#region src/backends/protocol.ts
18
18
  /**
@@ -328,23 +328,12 @@ var StateBackend = class {
328
328
  * @param limit - Maximum number of lines to read
329
329
  * @returns Formatted file content with line numbers, or error message
330
330
  */
331
- read(filePath, offset = 0, limit = 2e3) {
331
+ read(filePath, offset = 0, limit = 500) {
332
332
  const fileData = this.getFiles()[filePath];
333
333
  if (!fileData) return `Error: File '${filePath}' not found`;
334
334
  return formatReadResponse(fileData, offset, limit);
335
335
  }
336
336
  /**
337
- * Read file content as raw FileData.
338
- *
339
- * @param filePath - Absolute file path
340
- * @returns Raw file content as FileData
341
- */
342
- readRaw(filePath) {
343
- const fileData = this.getFiles()[filePath];
344
- if (!fileData) throw new Error(`File '${filePath}' not found`);
345
- return fileData;
346
- }
347
- /**
348
337
  * Create a new file with content.
349
338
  * Returns WriteResult with filesUpdate to update LangGraph state.
350
339
  */
@@ -585,7 +574,7 @@ function createReadFileTool(backend, options) {
585
574
  state: getCurrentTaskInput(config),
586
575
  store: config.store
587
576
  });
588
- const { file_path, offset = 0, limit = 2e3 } = input;
577
+ const { file_path, offset = 0, limit = 500 } = input;
589
578
  return await resolvedBackend.read(file_path, offset, limit);
590
579
  }, {
591
580
  name: "read_file",
@@ -593,7 +582,7 @@ function createReadFileTool(backend, options) {
593
582
  schema: z.object({
594
583
  file_path: z.string().describe("Absolute path to the file to read"),
595
584
  offset: z.coerce.number().optional().default(0).describe("Line offset to start reading from (0-indexed)"),
596
- limit: z.coerce.number().optional().default(2e3).describe("Maximum number of lines to read")
585
+ limit: z.coerce.number().optional().default(500).describe("Maximum number of lines to read")
597
586
  })
598
587
  });
599
588
  }
@@ -849,7 +838,7 @@ const DEFAULT_SUBAGENT_PROMPT = "In order to complete the objective that the use
849
838
  const EXCLUDED_STATE_KEYS = [
850
839
  "messages",
851
840
  "todos",
852
- "jumpTo",
841
+ "structuredResponse",
853
842
  "files"
854
843
  ];
855
844
  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.";
@@ -1107,14 +1096,10 @@ function createSubAgentMiddleware(options) {
1107
1096
  taskDescription
1108
1097
  })],
1109
1098
  wrapModelCall: async (request, handler) => {
1110
- if (systemPrompt !== null) {
1111
- const currentPrompt = request.systemPrompt || "";
1112
- const newPrompt = currentPrompt ? `${currentPrompt}\n\n${systemPrompt}` : systemPrompt;
1113
- return handler({
1114
- ...request,
1115
- systemPrompt: newPrompt
1116
- });
1117
- }
1099
+ if (systemPrompt !== null) return handler({
1100
+ ...request,
1101
+ systemMessage: request.systemMessage.concat(new SystemMessage({ content: systemPrompt }))
1102
+ });
1118
1103
  return handler(request);
1119
1104
  }
1120
1105
  });
@@ -1168,6 +1153,501 @@ function createPatchToolCallsMiddleware() {
1168
1153
  });
1169
1154
  }
1170
1155
 
1156
+ //#endregion
1157
+ //#region src/middleware/memory.ts
1158
+ /**
1159
+ * Middleware for loading agent memory/context from AGENTS.md files.
1160
+ *
1161
+ * This module implements support for the AGENTS.md specification (https://agents.md/),
1162
+ * loading memory/context from configurable sources and injecting into the system prompt.
1163
+ *
1164
+ * ## Overview
1165
+ *
1166
+ * AGENTS.md files provide project-specific context and instructions to help AI agents
1167
+ * work effectively. Unlike skills (which are on-demand workflows), memory is always
1168
+ * loaded and provides persistent context.
1169
+ *
1170
+ * ## Usage
1171
+ *
1172
+ * ```typescript
1173
+ * import { createMemoryMiddleware } from "@anthropic/deepagents";
1174
+ * import { FilesystemBackend } from "@anthropic/deepagents";
1175
+ *
1176
+ * // Security: FilesystemBackend allows reading/writing from the entire filesystem.
1177
+ * // Either ensure the agent is running within a sandbox OR add human-in-the-loop (HIL)
1178
+ * // approval to file operations.
1179
+ * const backend = new FilesystemBackend({ rootDir: "/" });
1180
+ *
1181
+ * const middleware = createMemoryMiddleware({
1182
+ * backend,
1183
+ * sources: [
1184
+ * "~/.deepagents/AGENTS.md",
1185
+ * "./.deepagents/AGENTS.md",
1186
+ * ],
1187
+ * });
1188
+ *
1189
+ * const agent = createDeepAgent({ middleware: [middleware] });
1190
+ * ```
1191
+ *
1192
+ * ## Memory Sources
1193
+ *
1194
+ * Sources are simply paths to AGENTS.md files that are loaded in order and combined.
1195
+ * Multiple sources are concatenated in order, with all content included.
1196
+ * Later sources appear after earlier ones in the combined prompt.
1197
+ *
1198
+ * ## File Format
1199
+ *
1200
+ * AGENTS.md files are standard Markdown with no required structure.
1201
+ * Common sections include:
1202
+ * - Project overview
1203
+ * - Build/test commands
1204
+ * - Code style guidelines
1205
+ * - Architecture notes
1206
+ */
1207
+ /**
1208
+ * State schema for memory middleware.
1209
+ */
1210
+ const MemoryStateSchema = z$2.object({ memoryContents: z$2.record(z$2.string(), z$2.string()).optional() });
1211
+ /**
1212
+ * Default system prompt template for memory.
1213
+ * Ported from Python's comprehensive memory guidelines.
1214
+ */
1215
+ const MEMORY_SYSTEM_PROMPT = `<agent_memory>
1216
+ {memory_contents}
1217
+ </agent_memory>
1218
+
1219
+ <memory_guidelines>
1220
+ 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.
1221
+
1222
+ **Learning from feedback:**
1223
+ - 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.
1224
+ - 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.
1225
+ - When user says something is better/worse, capture WHY and encode it as a pattern.
1226
+ - Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions.
1227
+ - 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.
1228
+ - Look for the underlying principle behind corrections, not just the specific mistake.
1229
+ - 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.
1230
+
1231
+ **Asking for information:**
1232
+ - 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.
1233
+ - It is preferred for you to ask for information, don't assume anything that you do not know!
1234
+ - When the user provides information that is useful for future use, you should update your memories immediately.
1235
+
1236
+ **When to update memories:**
1237
+ - When the user explicitly asks you to remember something (e.g., "remember my email", "save this preference")
1238
+ - When the user describes your role or how you should behave (e.g., "you are a web researcher", "always do X")
1239
+ - When the user gives feedback on your work - capture what was wrong and how to improve
1240
+ - When the user provides information required for tool use (e.g., slack channel ID, email addresses)
1241
+ - When the user provides context useful for future tasks, such as how to use tools, or which actions to take in a particular situation
1242
+ - When you discover new patterns or preferences (coding styles, conventions, workflows)
1243
+
1244
+ **When to NOT update memories:**
1245
+ - When the information is temporary or transient (e.g., "I'm running late", "I'm on my phone right now")
1246
+ - When the information is a one-time task request (e.g., "Find me a recipe", "What's 25 * 4?")
1247
+ - When the information is a simple question that doesn't reveal lasting preferences (e.g., "What day is it?", "Can you explain X?")
1248
+ - When the information is an acknowledgment or small talk (e.g., "Sounds good!", "Hello", "Thanks for that")
1249
+ - When the information is stale or irrelevant in future conversations
1250
+ - Never store API keys, access tokens, passwords, or any other credentials in any file, memory, or system prompt.
1251
+ - If the user asks where to put API keys or provides an API key, do NOT echo or save it.
1252
+
1253
+ **Examples:**
1254
+ Example 1 (remembering user information):
1255
+ User: Can you connect to my google account?
1256
+ Agent: Sure, I'll connect to your google account, what's your google account email?
1257
+ User: john@example.com
1258
+ Agent: Let me save this to my memory.
1259
+ Tool Call: edit_file(...) -> remembers that the user's google account email is john@example.com
1260
+
1261
+ Example 2 (remembering implicit user preferences):
1262
+ User: Can you write me an example for creating a deep agent in LangChain?
1263
+ Agent: Sure, I'll write you an example for creating a deep agent in LangChain <example code in Python>
1264
+ User: Can you do this in JavaScript
1265
+ Agent: Let me save this to my memory.
1266
+ Tool Call: edit_file(...) -> remembers that the user prefers to get LangChain code examples in JavaScript
1267
+ Agent: Sure, here is the JavaScript example<example code in JavaScript>
1268
+
1269
+ Example 3 (do not remember transient information):
1270
+ User: I'm going to play basketball tonight so I will be offline for a few hours.
1271
+ Agent: Okay I'll add a block to your calendar.
1272
+ Tool Call: create_calendar_event(...) -> just calls a tool, does not commit anything to memory, as it is transient information
1273
+ </memory_guidelines>`;
1274
+ /**
1275
+ * Format loaded memory contents for injection into prompt.
1276
+ * Pairs memory locations with their contents for clarity.
1277
+ */
1278
+ function formatMemoryContents(contents, sources) {
1279
+ if (Object.keys(contents).length === 0) return "(No memory loaded)";
1280
+ const sections = [];
1281
+ for (const path$1 of sources) if (contents[path$1]) sections.push(`${path$1}\n${contents[path$1]}`);
1282
+ if (sections.length === 0) return "(No memory loaded)";
1283
+ return sections.join("\n\n");
1284
+ }
1285
+ /**
1286
+ * Load memory content from a backend path.
1287
+ *
1288
+ * @param backend - Backend to load from.
1289
+ * @param path - Path to the AGENTS.md file.
1290
+ * @returns File content if found, null otherwise.
1291
+ */
1292
+ async function loadMemoryFromBackend(backend, path$1) {
1293
+ const results = await backend.downloadFiles([path$1]);
1294
+ if (results.length !== 1) throw new Error(`Expected 1 response for path ${path$1}, got ${results.length}`);
1295
+ const response = results[0];
1296
+ if (response.error != null) {
1297
+ if (response.error === "file_not_found") return null;
1298
+ throw new Error(`Failed to download ${path$1}: ${response.error}`);
1299
+ }
1300
+ if (response.content != null) return new TextDecoder().decode(response.content);
1301
+ return null;
1302
+ }
1303
+ /**
1304
+ * Create middleware for loading agent memory from AGENTS.md files.
1305
+ *
1306
+ * Loads memory content from configured sources and injects into the system prompt.
1307
+ * Supports multiple sources that are combined together.
1308
+ *
1309
+ * @param options - Configuration options
1310
+ * @returns AgentMiddleware for memory loading and injection
1311
+ *
1312
+ * @example
1313
+ * ```typescript
1314
+ * const middleware = createMemoryMiddleware({
1315
+ * backend: new FilesystemBackend({ rootDir: "/" }),
1316
+ * sources: [
1317
+ * "~/.deepagents/AGENTS.md",
1318
+ * "./.deepagents/AGENTS.md",
1319
+ * ],
1320
+ * });
1321
+ * ```
1322
+ */
1323
+ function createMemoryMiddleware(options) {
1324
+ const { backend, sources } = options;
1325
+ /**
1326
+ * Resolve backend from instance or factory.
1327
+ */
1328
+ function getBackend$1(state) {
1329
+ if (typeof backend === "function") return backend({ state });
1330
+ return backend;
1331
+ }
1332
+ return createMiddleware({
1333
+ name: "MemoryMiddleware",
1334
+ stateSchema: MemoryStateSchema,
1335
+ async beforeAgent(state) {
1336
+ if ("memoryContents" in state && state.memoryContents != null) return;
1337
+ const resolvedBackend = getBackend$1(state);
1338
+ const contents = {};
1339
+ for (const path$1 of sources) try {
1340
+ const content = await loadMemoryFromBackend(resolvedBackend, path$1);
1341
+ if (content) contents[path$1] = content;
1342
+ } catch (error) {
1343
+ console.debug(`Failed to load memory from ${path$1}:`, error);
1344
+ }
1345
+ return { memoryContents: contents };
1346
+ },
1347
+ wrapModelCall(request, handler) {
1348
+ const formattedContents = formatMemoryContents(request.state?.memoryContents || {}, sources);
1349
+ const memorySection = MEMORY_SYSTEM_PROMPT.replace("{memory_contents}", formattedContents);
1350
+ const currentSystemPrompt = request.systemPrompt || "";
1351
+ const newSystemPrompt = currentSystemPrompt ? `${memorySection}\n\n${currentSystemPrompt}` : memorySection;
1352
+ return handler({
1353
+ ...request,
1354
+ systemPrompt: newSystemPrompt
1355
+ });
1356
+ }
1357
+ });
1358
+ }
1359
+
1360
+ //#endregion
1361
+ //#region src/middleware/skills.ts
1362
+ /**
1363
+ * Backend-agnostic skills middleware for loading agent skills from any backend.
1364
+ *
1365
+ * This middleware implements Anthropic's agent skills pattern with progressive disclosure,
1366
+ * loading skills from backend storage via configurable sources.
1367
+ *
1368
+ * ## Architecture
1369
+ *
1370
+ * Skills are loaded from one or more **sources** - paths in a backend where skills are
1371
+ * organized. Sources are loaded in order, with later sources overriding earlier ones
1372
+ * when skills have the same name (last one wins). This enables layering: base -> user
1373
+ * -> project -> team skills.
1374
+ *
1375
+ * The middleware uses backend APIs exclusively (no direct filesystem access), making it
1376
+ * portable across different storage backends (filesystem, state, remote storage, etc.).
1377
+ *
1378
+ * ## Usage
1379
+ *
1380
+ * ```typescript
1381
+ * import { createSkillsMiddleware, FilesystemBackend } from "@anthropic/deepagents";
1382
+ *
1383
+ * const middleware = createSkillsMiddleware({
1384
+ * backend: new FilesystemBackend({ rootDir: "/" }),
1385
+ * sources: [
1386
+ * "/skills/user/",
1387
+ * "/skills/project/",
1388
+ * ],
1389
+ * });
1390
+ *
1391
+ * const agent = createDeepAgent({ middleware: [middleware] });
1392
+ * ```
1393
+ *
1394
+ * Or use the `skills` parameter on createDeepAgent:
1395
+ *
1396
+ * ```typescript
1397
+ * const agent = createDeepAgent({
1398
+ * skills: ["/skills/user/", "/skills/project/"],
1399
+ * });
1400
+ * ```
1401
+ */
1402
+ const MAX_SKILL_FILE_SIZE = 10 * 1024 * 1024;
1403
+ const MAX_SKILL_NAME_LENGTH = 64;
1404
+ const MAX_SKILL_DESCRIPTION_LENGTH = 1024;
1405
+ /**
1406
+ * State schema for skills middleware.
1407
+ */
1408
+ const SkillsStateSchema = z$2.object({ skillsMetadata: z$2.array(z$2.object({
1409
+ name: z$2.string(),
1410
+ description: z$2.string(),
1411
+ path: z$2.string(),
1412
+ license: z$2.string().nullable().optional(),
1413
+ compatibility: z$2.string().nullable().optional(),
1414
+ metadata: z$2.record(z$2.string(), z$2.string()).optional(),
1415
+ allowedTools: z$2.array(z$2.string()).optional()
1416
+ })).optional() });
1417
+ /**
1418
+ * Skills System Documentation prompt template.
1419
+ */
1420
+ const SKILLS_SYSTEM_PROMPT = `
1421
+ ## Skills System
1422
+
1423
+ You have access to a skills library that provides specialized capabilities and domain knowledge.
1424
+
1425
+ {skills_locations}
1426
+
1427
+ **Available Skills:**
1428
+
1429
+ {skills_list}
1430
+
1431
+ **How to Use Skills (Progressive Disclosure):**
1432
+
1433
+ Skills follow a **progressive disclosure** pattern - you know they exist (name + description above), but you only read the full instructions when needed:
1434
+
1435
+ 1. **Recognize when a skill applies**: Check if the user's task matches any skill's description
1436
+ 2. **Read the skill's full instructions**: The skill list above shows the exact path to use with read_file
1437
+ 3. **Follow the skill's instructions**: SKILL.md contains step-by-step workflows, best practices, and examples
1438
+ 4. **Access supporting files**: Skills may include Python scripts, configs, or reference docs - use absolute paths
1439
+
1440
+ **When to Use Skills:**
1441
+ - When the user's request matches a skill's domain (e.g., "research X" → web-research skill)
1442
+ - When you need specialized knowledge or structured workflows
1443
+ - When a skill provides proven patterns for complex tasks
1444
+
1445
+ **Skills are Self-Documenting:**
1446
+ - Each SKILL.md tells you exactly what the skill does and how to use it
1447
+ - The skill list above shows the full path for each skill's SKILL.md file
1448
+
1449
+ **Executing Skill Scripts:**
1450
+ Skills may contain Python scripts or other executable files. Always use absolute paths from the skill list.
1451
+
1452
+ **Example Workflow:**
1453
+
1454
+ User: "Can you research the latest developments in quantum computing?"
1455
+
1456
+ 1. Check available skills above → See "web-research" skill with its full path
1457
+ 2. Read the skill using the path shown in the list
1458
+ 3. Follow the skill's research workflow (search → organize → synthesize)
1459
+ 4. Use any helper scripts with absolute paths
1460
+
1461
+ Remember: Skills are tools to make you more capable and consistent. When in doubt, check if a skill exists for the task!
1462
+ `;
1463
+ /**
1464
+ * Validate skill name per Agent Skills specification.
1465
+ */
1466
+ function validateSkillName$1(name, directoryName) {
1467
+ if (!name) return {
1468
+ valid: false,
1469
+ error: "name is required"
1470
+ };
1471
+ if (name.length > MAX_SKILL_NAME_LENGTH) return {
1472
+ valid: false,
1473
+ error: "name exceeds 64 characters"
1474
+ };
1475
+ if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) return {
1476
+ valid: false,
1477
+ error: "name must be lowercase alphanumeric with single hyphens only"
1478
+ };
1479
+ if (name !== directoryName) return {
1480
+ valid: false,
1481
+ error: `name '${name}' must match directory name '${directoryName}'`
1482
+ };
1483
+ return {
1484
+ valid: true,
1485
+ error: ""
1486
+ };
1487
+ }
1488
+ /**
1489
+ * Parse YAML frontmatter from SKILL.md content.
1490
+ */
1491
+ function parseSkillMetadataFromContent(content, skillPath, directoryName) {
1492
+ if (content.length > MAX_SKILL_FILE_SIZE) {
1493
+ console.warn(`Skipping ${skillPath}: content too large (${content.length} bytes)`);
1494
+ return null;
1495
+ }
1496
+ const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
1497
+ if (!match) {
1498
+ console.warn(`Skipping ${skillPath}: no valid YAML frontmatter found`);
1499
+ return null;
1500
+ }
1501
+ const frontmatterStr = match[1];
1502
+ let frontmatterData;
1503
+ try {
1504
+ frontmatterData = yaml.parse(frontmatterStr);
1505
+ } catch (e) {
1506
+ console.warn(`Invalid YAML in ${skillPath}:`, e);
1507
+ return null;
1508
+ }
1509
+ if (!frontmatterData || typeof frontmatterData !== "object") {
1510
+ console.warn(`Skipping ${skillPath}: frontmatter is not a mapping`);
1511
+ return null;
1512
+ }
1513
+ const name = frontmatterData.name;
1514
+ const description = frontmatterData.description;
1515
+ if (!name || !description) {
1516
+ console.warn(`Skipping ${skillPath}: missing required 'name' or 'description'`);
1517
+ return null;
1518
+ }
1519
+ const validation = validateSkillName$1(String(name), directoryName);
1520
+ if (!validation.valid) console.warn(`Skill '${name}' in ${skillPath} does not follow Agent Skills specification: ${validation.error}. Consider renaming for spec compliance.`);
1521
+ let descriptionStr = String(description).trim();
1522
+ if (descriptionStr.length > MAX_SKILL_DESCRIPTION_LENGTH) {
1523
+ console.warn(`Description exceeds ${MAX_SKILL_DESCRIPTION_LENGTH} characters in ${skillPath}, truncating`);
1524
+ descriptionStr = descriptionStr.slice(0, MAX_SKILL_DESCRIPTION_LENGTH);
1525
+ }
1526
+ const allowedToolsStr = frontmatterData["allowed-tools"];
1527
+ const allowedTools = allowedToolsStr ? allowedToolsStr.split(" ") : [];
1528
+ return {
1529
+ name: String(name),
1530
+ description: descriptionStr,
1531
+ path: skillPath,
1532
+ metadata: frontmatterData.metadata || {},
1533
+ license: typeof frontmatterData.license === "string" ? frontmatterData.license.trim() || null : null,
1534
+ compatibility: typeof frontmatterData.compatibility === "string" ? frontmatterData.compatibility.trim() || null : null,
1535
+ allowedTools
1536
+ };
1537
+ }
1538
+ /**
1539
+ * List all skills from a backend source.
1540
+ */
1541
+ async function listSkillsFromBackend(backend, sourcePath) {
1542
+ const skills = [];
1543
+ const normalizedPath = sourcePath.endsWith("/") ? sourcePath : `${sourcePath}/`;
1544
+ let fileInfos;
1545
+ try {
1546
+ fileInfos = await backend.lsInfo(normalizedPath);
1547
+ } catch {
1548
+ return [];
1549
+ }
1550
+ const entries = fileInfos.map((info) => ({
1551
+ name: info.path.replace(/\/$/, "").split("/").pop() || "",
1552
+ type: info.is_dir ? "directory" : "file"
1553
+ }));
1554
+ for (const entry of entries) {
1555
+ if (entry.type !== "directory") continue;
1556
+ const skillMdPath = `${normalizedPath}${entry.name}/SKILL.md`;
1557
+ const results = await backend.downloadFiles([skillMdPath]);
1558
+ if (results.length !== 1) continue;
1559
+ const response = results[0];
1560
+ if (response.error != null || response.content == null) continue;
1561
+ const metadata = parseSkillMetadataFromContent(new TextDecoder().decode(response.content), skillMdPath, entry.name);
1562
+ if (metadata) skills.push(metadata);
1563
+ }
1564
+ return skills;
1565
+ }
1566
+ /**
1567
+ * Format skills locations for display in system prompt.
1568
+ */
1569
+ function formatSkillsLocations(sources) {
1570
+ if (sources.length === 0) return "**Skills Sources:** None configured";
1571
+ const lines = ["**Skills Sources:**"];
1572
+ for (const source of sources) lines.push(`- \`${source}\``);
1573
+ return lines.join("\n");
1574
+ }
1575
+ /**
1576
+ * Format skills metadata for display in system prompt.
1577
+ */
1578
+ function formatSkillsList(skills, sources) {
1579
+ if (skills.length === 0) return `(No skills available yet. Skills can be created in ${sources.join(" or ")})`;
1580
+ const lines = [];
1581
+ for (const skill of skills) {
1582
+ lines.push(`- **${skill.name}**: ${skill.description}`);
1583
+ lines.push(` → Read \`${skill.path}\` for full instructions`);
1584
+ }
1585
+ return lines.join("\n");
1586
+ }
1587
+ /**
1588
+ * Create backend-agnostic middleware for loading and exposing agent skills.
1589
+ *
1590
+ * This middleware loads skills from configurable backend sources and injects
1591
+ * skill metadata into the system prompt. It implements the progressive disclosure
1592
+ * pattern: skill names and descriptions are shown in the prompt, but the agent
1593
+ * reads full SKILL.md content only when needed.
1594
+ *
1595
+ * @param options - Configuration options
1596
+ * @returns AgentMiddleware for skills loading and injection
1597
+ *
1598
+ * @example
1599
+ * ```typescript
1600
+ * const middleware = createSkillsMiddleware({
1601
+ * backend: new FilesystemBackend({ rootDir: "/" }),
1602
+ * sources: ["/skills/user/", "/skills/project/"],
1603
+ * });
1604
+ * ```
1605
+ */
1606
+ function createSkillsMiddleware(options) {
1607
+ const { backend, sources } = options;
1608
+ let loadedSkills = [];
1609
+ /**
1610
+ * Resolve backend from instance or factory.
1611
+ */
1612
+ function getBackend$1(state) {
1613
+ if (typeof backend === "function") return backend({ state });
1614
+ return backend;
1615
+ }
1616
+ return createMiddleware({
1617
+ name: "SkillsMiddleware",
1618
+ stateSchema: SkillsStateSchema,
1619
+ async beforeAgent(state) {
1620
+ if (loadedSkills.length > 0) return;
1621
+ if ("skillsMetadata" in state && state.skillsMetadata != null) {
1622
+ loadedSkills = state.skillsMetadata;
1623
+ return;
1624
+ }
1625
+ const resolvedBackend = getBackend$1(state);
1626
+ const allSkills = /* @__PURE__ */ new Map();
1627
+ for (const sourcePath of sources) try {
1628
+ const skills = await listSkillsFromBackend(resolvedBackend, sourcePath);
1629
+ for (const skill of skills) allSkills.set(skill.name, skill);
1630
+ } catch (error) {
1631
+ console.debug(`[BackendSkillsMiddleware] Failed to load skills from ${sourcePath}:`, error);
1632
+ }
1633
+ loadedSkills = Array.from(allSkills.values());
1634
+ return { skillsMetadata: loadedSkills };
1635
+ },
1636
+ wrapModelCall(request, handler) {
1637
+ const skillsMetadata = loadedSkills.length > 0 ? loadedSkills : request.state?.skillsMetadata || [];
1638
+ const skillsLocations = formatSkillsLocations(sources);
1639
+ const skillsList = formatSkillsList(skillsMetadata, sources);
1640
+ const skillsSection = SKILLS_SYSTEM_PROMPT.replace("{skills_locations}", skillsLocations).replace("{skills_list}", skillsList);
1641
+ const currentSystemPrompt = request.systemPrompt || "";
1642
+ const newSystemPrompt = currentSystemPrompt ? `${currentSystemPrompt}\n\n${skillsSection}` : skillsSection;
1643
+ return handler({
1644
+ ...request,
1645
+ systemPrompt: newSystemPrompt
1646
+ });
1647
+ }
1648
+ });
1649
+ }
1650
+
1171
1651
  //#endregion
1172
1652
  //#region src/backends/store.ts
1173
1653
  /**
@@ -1315,27 +1795,18 @@ var StoreBackend = class {
1315
1795
  * @param limit - Maximum number of lines to read
1316
1796
  * @returns Formatted file content with line numbers, or error message
1317
1797
  */
1318
- async read(filePath, offset = 0, limit = 2e3) {
1798
+ async read(filePath, offset = 0, limit = 500) {
1319
1799
  try {
1320
- return formatReadResponse(await this.readRaw(filePath), offset, limit);
1800
+ const store = this.getStore();
1801
+ const namespace = this.getNamespace();
1802
+ const item = await store.get(namespace, filePath);
1803
+ if (!item) return `Error: File '${filePath}' not found`;
1804
+ return formatReadResponse(this.convertStoreItemToFileData(item), offset, limit);
1321
1805
  } catch (e) {
1322
1806
  return `Error: ${e.message}`;
1323
1807
  }
1324
1808
  }
1325
1809
  /**
1326
- * Read file content as raw FileData.
1327
- *
1328
- * @param filePath - Absolute file path
1329
- * @returns Raw file content as FileData
1330
- */
1331
- async readRaw(filePath) {
1332
- const store = this.getStore();
1333
- const namespace = this.getNamespace();
1334
- const item = await store.get(namespace, filePath);
1335
- if (!item) throw new Error(`File '${filePath}' not found`);
1336
- return this.convertStoreItemToFileData(item);
1337
- }
1338
- /**
1339
1810
  * Create a new file with content.
1340
1811
  * Returns WriteResult. External storage sets filesUpdate=null.
1341
1812
  */
@@ -1609,7 +2080,7 @@ var FilesystemBackend = class {
1609
2080
  * @param limit - Maximum number of lines to read
1610
2081
  * @returns Formatted file content with line numbers, or error message
1611
2082
  */
1612
- async read(filePath, offset = 0, limit = 2e3) {
2083
+ async read(filePath, offset = 0, limit = 500) {
1613
2084
  try {
1614
2085
  const resolvedPath = this.resolvePath(filePath);
1615
2086
  let content;
@@ -1639,37 +2110,6 @@ var FilesystemBackend = class {
1639
2110
  }
1640
2111
  }
1641
2112
  /**
1642
- * Read file content as raw FileData.
1643
- *
1644
- * @param filePath - Absolute file path
1645
- * @returns Raw file content as FileData
1646
- */
1647
- async readRaw(filePath) {
1648
- const resolvedPath = this.resolvePath(filePath);
1649
- let content;
1650
- let stat;
1651
- if (SUPPORTS_NOFOLLOW) {
1652
- stat = await fs.stat(resolvedPath);
1653
- if (!stat.isFile()) throw new Error(`File '${filePath}' not found`);
1654
- const fd = await fs.open(resolvedPath, fs$1.constants.O_RDONLY | fs$1.constants.O_NOFOLLOW);
1655
- try {
1656
- content = await fd.readFile({ encoding: "utf-8" });
1657
- } finally {
1658
- await fd.close();
1659
- }
1660
- } else {
1661
- stat = await fs.lstat(resolvedPath);
1662
- if (stat.isSymbolicLink()) throw new Error(`Symlinks are not allowed: ${filePath}`);
1663
- if (!stat.isFile()) throw new Error(`File '${filePath}' not found`);
1664
- content = await fs.readFile(resolvedPath, "utf-8");
1665
- }
1666
- return {
1667
- content: content.split("\n"),
1668
- created_at: stat.ctime.toISOString(),
1669
- modified_at: stat.mtime.toISOString()
1670
- };
1671
- }
1672
- /**
1673
2113
  * Create a new file with content.
1674
2114
  * Returns WriteResult. External storage sets filesUpdate=null.
1675
2115
  */
@@ -2072,21 +2512,11 @@ var CompositeBackend = class {
2072
2512
  * @param limit - Maximum number of lines to read
2073
2513
  * @returns Formatted file content with line numbers, or error message
2074
2514
  */
2075
- async read(filePath, offset = 0, limit = 2e3) {
2515
+ async read(filePath, offset = 0, limit = 500) {
2076
2516
  const [backend, strippedKey] = this.getBackendAndKey(filePath);
2077
2517
  return await backend.read(strippedKey, offset, limit);
2078
2518
  }
2079
2519
  /**
2080
- * Read file content as raw FileData.
2081
- *
2082
- * @param filePath - Absolute file path
2083
- * @returns Raw file content as FileData
2084
- */
2085
- async readRaw(filePath) {
2086
- const [backend, strippedKey] = this.getBackendAndKey(filePath);
2087
- return await backend.readRaw(strippedKey);
2088
- }
2089
- /**
2090
2520
  * Structured search results or error string for invalid input.
2091
2521
  */
2092
2522
  async grepRaw(pattern, path$1 = "/", glob = null) {
@@ -2523,36 +2953,14 @@ var BaseSandbox = class {
2523
2953
  * @param limit - Maximum number of lines to read
2524
2954
  * @returns Formatted file content with line numbers, or error message
2525
2955
  */
2526
- async read(filePath, offset = 0, limit = 2e3) {
2956
+ async read(filePath, offset = 0, limit = 500) {
2527
2957
  const command = buildReadCommand(filePath, offset, limit);
2528
2958
  const result = await this.execute(command);
2529
2959
  if (result.exitCode !== 0) return `Error: File '${filePath}' not found`;
2530
2960
  return result.output;
2531
2961
  }
2532
2962
  /**
2533
- * Read file content as raw FileData.
2534
- *
2535
- * @param filePath - Absolute file path
2536
- * @returns Raw file content as FileData
2537
- */
2538
- async readRaw(filePath) {
2539
- const command = buildReadCommand(filePath, 0, Number.MAX_SAFE_INTEGER);
2540
- const result = await this.execute(command);
2541
- if (result.exitCode !== 0) throw new Error(`File '${filePath}' not found`);
2542
- const lines = [];
2543
- for (const line of result.output.split("\n")) {
2544
- const tabIndex = line.indexOf(" ");
2545
- if (tabIndex !== -1) lines.push(line.substring(tabIndex + 1));
2546
- }
2547
- const now = (/* @__PURE__ */ new Date()).toISOString();
2548
- return {
2549
- content: lines,
2550
- created_at: now,
2551
- modified_at: now
2552
- };
2553
- }
2554
- /**
2555
- * Structured search results or error string for invalid input.
2963
+ * Structured search results or error string for invalid input.
2556
2964
  */
2557
2965
  async grepRaw(pattern, path$1 = "/", glob = null) {
2558
2966
  const command = buildGrepCommand(pattern, path$1, glob);
@@ -2657,7 +3065,7 @@ const BASE_PROMPT = `In order to complete the objective that the user asks of yo
2657
3065
  * ```
2658
3066
  */
2659
3067
  function createDeepAgent(params = {}) {
2660
- const { model = "claude-sonnet-4-5-20250929", tools = [], systemPrompt, middleware: customMiddleware = [], subagents = [], responseFormat, contextSchema, checkpointer, store, backend, interruptOn, name } = params;
3068
+ const { model = "claude-sonnet-4-5-20250929", tools = [], systemPrompt, middleware: customMiddleware = [], subagents = [], responseFormat, contextSchema, checkpointer, store, backend, interruptOn, name, memory, skills } = params;
2661
3069
  const finalSystemPrompt = systemPrompt ? typeof systemPrompt === "string" ? `${systemPrompt}\n\n${BASE_PROMPT}` : new SystemMessage({ content: [{
2662
3070
  type: "text",
2663
3071
  text: BASE_PROMPT
@@ -2666,14 +3074,20 @@ function createDeepAgent(params = {}) {
2666
3074
  text: systemPrompt.content
2667
3075
  }] : systemPrompt.content] }) : BASE_PROMPT;
2668
3076
  const filesystemBackend = backend ? backend : (config) => new StateBackend(config);
3077
+ const skillsMiddleware = skills != null && skills.length > 0 ? [createSkillsMiddleware({
3078
+ backend: filesystemBackend,
3079
+ sources: skills
3080
+ })] : [];
2669
3081
  const builtInMiddleware = [
2670
3082
  todoListMiddleware(),
3083
+ ...skillsMiddleware,
2671
3084
  createFilesystemMiddleware({ backend: filesystemBackend }),
2672
3085
  createSubAgentMiddleware({
2673
3086
  defaultModel: model,
2674
3087
  defaultTools: tools,
2675
3088
  defaultMiddleware: [
2676
3089
  todoListMiddleware(),
3090
+ ...skillsMiddleware,
2677
3091
  createFilesystemMiddleware({ backend: filesystemBackend }),
2678
3092
  summarizationMiddleware({
2679
3093
  model,
@@ -2693,7 +3107,11 @@ function createDeepAgent(params = {}) {
2693
3107
  keep: { messages: 6 }
2694
3108
  }),
2695
3109
  anthropicPromptCachingMiddleware({ unsupportedModelBehavior: "ignore" }),
2696
- createPatchToolCallsMiddleware()
3110
+ createPatchToolCallsMiddleware(),
3111
+ ...memory != null && memory.length > 0 ? [createMemoryMiddleware({
3112
+ backend: filesystemBackend,
3113
+ sources: memory
3114
+ })] : []
2697
3115
  ];
2698
3116
  if (interruptOn) builtInMiddleware.push(humanInTheLoopMiddleware({ interruptOn }));
2699
3117
  return createAgent({
@@ -2803,6 +3221,206 @@ function createSettings(options = {}) {
2803
3221
  };
2804
3222
  }
2805
3223
 
3224
+ //#endregion
3225
+ //#region src/middleware/agent-memory.ts
3226
+ /**
3227
+ * Middleware for loading agent-specific long-term memory into the system prompt.
3228
+ *
3229
+ * This middleware loads the agent's long-term memory from agent.md files
3230
+ * and injects it into the system prompt. Memory is loaded from:
3231
+ * - User memory: ~/.deepagents/{agent_name}/agent.md
3232
+ * - Project memory: {project_root}/.deepagents/agent.md
3233
+ */
3234
+ /**
3235
+ * State schema for agent memory middleware.
3236
+ */
3237
+ const AgentMemoryStateSchema = z$2.object({
3238
+ userMemory: z$2.string().optional(),
3239
+ projectMemory: z$2.string().optional()
3240
+ });
3241
+ /**
3242
+ * Default template for memory injection.
3243
+ */
3244
+ const DEFAULT_MEMORY_TEMPLATE = `<user_memory>
3245
+ {user_memory}
3246
+ </user_memory>
3247
+
3248
+ <project_memory>
3249
+ {project_memory}
3250
+ </project_memory>`;
3251
+ /**
3252
+ * Long-term Memory Documentation system prompt.
3253
+ */
3254
+ const LONGTERM_MEMORY_SYSTEM_PROMPT = `
3255
+
3256
+ ## Long-term Memory
3257
+
3258
+ Your long-term memory is stored in files on the filesystem and persists across sessions.
3259
+
3260
+ **User Memory Location**: \`{agent_dir_absolute}\` (displays as \`{agent_dir_display}\`)
3261
+ **Project Memory Location**: {project_memory_info}
3262
+
3263
+ Your system prompt is loaded from TWO sources at startup:
3264
+ 1. **User agent.md**: \`{agent_dir_absolute}/agent.md\` - Your personal preferences across all projects
3265
+ 2. **Project agent.md**: Loaded from project root if available - Project-specific instructions
3266
+
3267
+ Project-specific agent.md is loaded from these locations (both combined if both exist):
3268
+ - \`[project-root]/.deepagents/agent.md\` (preferred)
3269
+ - \`[project-root]/agent.md\` (fallback, but also included if both exist)
3270
+
3271
+ **When to CHECK/READ memories (CRITICAL - do this FIRST):**
3272
+ - **At the start of ANY new session**: Check both user and project memories
3273
+ - User: \`ls {agent_dir_absolute}\`
3274
+ - Project: \`ls {project_deepagents_dir}\` (if in a project)
3275
+ - **BEFORE answering questions**: If asked "what do you know about X?" or "how do I do Y?", check project memories FIRST, then user
3276
+ - **When user asks you to do something**: Check if you have project-specific guides or examples
3277
+ - **When user references past work**: Search project memory files for related context
3278
+
3279
+ **Memory-first response pattern:**
3280
+ 1. User asks a question → Check project directory first: \`ls {project_deepagents_dir}\`
3281
+ 2. If relevant files exist → Read them with \`read_file '{project_deepagents_dir}/[filename]'\`
3282
+ 3. Check user memory if needed → \`ls {agent_dir_absolute}\`
3283
+ 4. Base your answer on saved knowledge supplemented by general knowledge
3284
+
3285
+ **When to update memories:**
3286
+ - **IMMEDIATELY when the user describes your role or how you should behave**
3287
+ - **IMMEDIATELY when the user gives feedback on your work** - Update memories to capture what was wrong and how to do it better
3288
+ - When the user explicitly asks you to remember something
3289
+ - When patterns or preferences emerge (coding styles, conventions, workflows)
3290
+ - After significant work where context would help in future sessions
3291
+
3292
+ **Learning from feedback:**
3293
+ - When user says something is better/worse, capture WHY and encode it as a pattern
3294
+ - Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions
3295
+ - When user says "you should remember X" or "be careful about Y", treat this as HIGH PRIORITY - update memories IMMEDIATELY
3296
+ - Look for the underlying principle behind corrections, not just the specific mistake
3297
+
3298
+ ## Deciding Where to Store Memory
3299
+
3300
+ When writing or updating agent memory, decide whether each fact, configuration, or behavior belongs in:
3301
+
3302
+ ### User Agent File: \`{agent_dir_absolute}/agent.md\`
3303
+ → Describes the agent's **personality, style, and universal behavior** across all projects.
3304
+
3305
+ **Store here:**
3306
+ - Your general tone and communication style
3307
+ - Universal coding preferences (formatting, comment style, etc.)
3308
+ - General workflows and methodologies you follow
3309
+ - Tool usage patterns that apply everywhere
3310
+ - Personal preferences that don't change per-project
3311
+
3312
+ **Examples:**
3313
+ - "Be concise and direct in responses"
3314
+ - "Always use type hints in Python"
3315
+ - "Prefer functional programming patterns"
3316
+
3317
+ ### Project Agent File: \`{project_deepagents_dir}/agent.md\`
3318
+ → Describes **how this specific project works** and **how the agent should behave here only.**
3319
+
3320
+ **Store here:**
3321
+ - Project-specific architecture and design patterns
3322
+ - Coding conventions specific to this codebase
3323
+ - Project structure and organization
3324
+ - Testing strategies for this project
3325
+ - Deployment processes and workflows
3326
+ - Team conventions and guidelines
3327
+
3328
+ **Examples:**
3329
+ - "This project uses FastAPI with SQLAlchemy"
3330
+ - "Tests go in tests/ directory mirroring src/ structure"
3331
+ - "All API changes require updating OpenAPI spec"
3332
+
3333
+ ### Project Memory Files: \`{project_deepagents_dir}/*.md\`
3334
+ → Use for **project-specific reference information** and structured notes.
3335
+
3336
+ **Store here:**
3337
+ - API design documentation
3338
+ - Architecture decisions and rationale
3339
+ - Deployment procedures
3340
+ - Common debugging patterns
3341
+ - Onboarding information
3342
+
3343
+ **Examples:**
3344
+ - \`{project_deepagents_dir}/api-design.md\` - REST API patterns used
3345
+ - \`{project_deepagents_dir}/architecture.md\` - System architecture overview
3346
+ - \`{project_deepagents_dir}/deployment.md\` - How to deploy this project
3347
+
3348
+ ### File Operations:
3349
+
3350
+ **User memory:**
3351
+ \`\`\`
3352
+ ls {agent_dir_absolute} # List user memory files
3353
+ read_file '{agent_dir_absolute}/agent.md' # Read user preferences
3354
+ edit_file '{agent_dir_absolute}/agent.md' ... # Update user preferences
3355
+ \`\`\`
3356
+
3357
+ **Project memory (preferred for project-specific information):**
3358
+ \`\`\`
3359
+ ls {project_deepagents_dir} # List project memory files
3360
+ read_file '{project_deepagents_dir}/agent.md' # Read project instructions
3361
+ edit_file '{project_deepagents_dir}/agent.md' ... # Update project instructions
3362
+ write_file '{project_deepagents_dir}/agent.md' ... # Create project memory file
3363
+ \`\`\`
3364
+
3365
+ **Important**:
3366
+ - Project memory files are stored in \`.deepagents/\` inside the project root
3367
+ - Always use absolute paths for file operations
3368
+ - Check project memories BEFORE user when answering project-specific questions`;
3369
+ /**
3370
+ * Create middleware for loading agent-specific long-term memory.
3371
+ *
3372
+ * This middleware loads the agent's long-term memory from a file (agent.md)
3373
+ * and injects it into the system prompt. The memory is loaded once at the
3374
+ * start of the conversation and stored in state.
3375
+ *
3376
+ * @param options - Configuration options
3377
+ * @returns AgentMiddleware for memory loading and injection
3378
+ */
3379
+ function createAgentMemoryMiddleware(options) {
3380
+ const { settings, assistantId, systemPromptTemplate } = options;
3381
+ const agentDir = settings.getAgentDir(assistantId);
3382
+ const agentDirDisplay = `~/.deepagents/${assistantId}`;
3383
+ const agentDirAbsolute = agentDir;
3384
+ const projectRoot = settings.projectRoot;
3385
+ const projectMemoryInfo = projectRoot ? `\`${projectRoot}\` (detected)` : "None (not in a git project)";
3386
+ const projectDeepagentsDir = projectRoot ? `${projectRoot}/.deepagents` : "[project-root]/.deepagents (not in a project)";
3387
+ const template = systemPromptTemplate || DEFAULT_MEMORY_TEMPLATE;
3388
+ return createMiddleware({
3389
+ name: "AgentMemoryMiddleware",
3390
+ stateSchema: AgentMemoryStateSchema,
3391
+ beforeAgent(state) {
3392
+ const result = {};
3393
+ if (!("userMemory" in state)) {
3394
+ const userPath = settings.getUserAgentMdPath(assistantId);
3395
+ if (fs$1.existsSync(userPath)) try {
3396
+ result.userMemory = fs$1.readFileSync(userPath, "utf-8");
3397
+ } catch {}
3398
+ }
3399
+ if (!("projectMemory" in state)) {
3400
+ const projectPath = settings.getProjectAgentMdPath();
3401
+ if (projectPath && fs$1.existsSync(projectPath)) try {
3402
+ result.projectMemory = fs$1.readFileSync(projectPath, "utf-8");
3403
+ } catch {}
3404
+ }
3405
+ return Object.keys(result).length > 0 ? result : void 0;
3406
+ },
3407
+ wrapModelCall(request, handler) {
3408
+ const userMemory = request.state?.userMemory;
3409
+ const projectMemory = request.state?.projectMemory;
3410
+ const baseSystemPrompt = request.systemPrompt || "";
3411
+ const memorySection = template.replace("{user_memory}", userMemory || "(No user agent.md)").replace("{project_memory}", projectMemory || "(No project agent.md)");
3412
+ 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);
3413
+ let systemPrompt = memorySection;
3414
+ if (baseSystemPrompt) systemPrompt += "\n\n" + baseSystemPrompt;
3415
+ systemPrompt += "\n\n" + memoryDocs;
3416
+ return handler({
3417
+ ...request,
3418
+ systemPrompt
3419
+ });
3420
+ }
3421
+ });
3422
+ }
3423
+
2806
3424
  //#endregion
2807
3425
  //#region src/skills/loader.ts
2808
3426
  /**
@@ -2831,10 +3449,10 @@ function createSettings(options = {}) {
2831
3449
  * @see https://agentskills.io/specification
2832
3450
  */
2833
3451
  /** Maximum size for SKILL.md files (10MB) */
2834
- const MAX_SKILL_FILE_SIZE = 10 * 1024 * 1024;
3452
+ const MAX_SKILL_FILE_SIZE$1 = 10 * 1024 * 1024;
2835
3453
  /** Agent Skills spec constraints */
2836
- const MAX_SKILL_NAME_LENGTH = 64;
2837
- const MAX_SKILL_DESCRIPTION_LENGTH = 1024;
3454
+ const MAX_SKILL_NAME_LENGTH$1 = 64;
3455
+ const MAX_SKILL_DESCRIPTION_LENGTH$1 = 1024;
2838
3456
  /** Pattern for validating skill names per Agent Skills spec */
2839
3457
  const SKILL_NAME_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
2840
3458
  /** Pattern for extracting YAML frontmatter */
@@ -2878,7 +3496,7 @@ function validateSkillName(name, directoryName) {
2878
3496
  valid: false,
2879
3497
  error: "name is required"
2880
3498
  };
2881
- if (name.length > MAX_SKILL_NAME_LENGTH) return {
3499
+ if (name.length > MAX_SKILL_NAME_LENGTH$1) return {
2882
3500
  valid: false,
2883
3501
  error: "name exceeds 64 characters"
2884
3502
  };
@@ -2918,7 +3536,7 @@ function parseFrontmatter(content) {
2918
3536
  function parseSkillMetadata(skillMdPath, source) {
2919
3537
  try {
2920
3538
  const stats = fs$1.statSync(skillMdPath);
2921
- if (stats.size > MAX_SKILL_FILE_SIZE) {
3539
+ if (stats.size > MAX_SKILL_FILE_SIZE$1) {
2922
3540
  console.warn(`Skipping ${skillMdPath}: file too large (${stats.size} bytes)`);
2923
3541
  return null;
2924
3542
  }
@@ -2937,9 +3555,9 @@ function parseSkillMetadata(skillMdPath, source) {
2937
3555
  const validation = validateSkillName(String(name), directoryName);
2938
3556
  if (!validation.valid) console.warn(`Skill '${name}' in ${skillMdPath} does not follow Agent Skills spec: ${validation.error}. Consider renaming to be spec-compliant.`);
2939
3557
  let descriptionStr = String(description);
2940
- if (descriptionStr.length > MAX_SKILL_DESCRIPTION_LENGTH) {
2941
- console.warn(`Description exceeds ${MAX_SKILL_DESCRIPTION_LENGTH} chars in ${skillMdPath}, truncating`);
2942
- descriptionStr = descriptionStr.slice(0, MAX_SKILL_DESCRIPTION_LENGTH);
3558
+ if (descriptionStr.length > MAX_SKILL_DESCRIPTION_LENGTH$1) {
3559
+ console.warn(`Description exceeds ${MAX_SKILL_DESCRIPTION_LENGTH$1} chars in ${skillMdPath}, truncating`);
3560
+ descriptionStr = descriptionStr.slice(0, MAX_SKILL_DESCRIPTION_LENGTH$1);
2943
3561
  }
2944
3562
  return {
2945
3563
  name: String(name),
@@ -3027,374 +3645,5 @@ function listSkills(options) {
3027
3645
  }
3028
3646
 
3029
3647
  //#endregion
3030
- //#region src/middleware/skills.ts
3031
- /**
3032
- * Middleware for loading and exposing agent skills to the system prompt.
3033
- *
3034
- * This middleware implements Anthropic's "Agent Skills" pattern with progressive disclosure:
3035
- * 1. Parse YAML frontmatter from SKILL.md files at session start
3036
- * 2. Inject skills metadata (name + description) into system prompt
3037
- * 3. Agent reads full SKILL.md content when relevant to a task
3038
- *
3039
- * Skills directory structure (per-agent + project):
3040
- * User-level: ~/.deepagents/{AGENT_NAME}/skills/
3041
- * Project-level: {PROJECT_ROOT}/.deepagents/skills/
3042
- *
3043
- * @example
3044
- * ```
3045
- * ~/.deepagents/{AGENT_NAME}/skills/
3046
- * ├── web-research/
3047
- * │ ├── SKILL.md # Required: YAML frontmatter + instructions
3048
- * │ └── helper.py # Optional: supporting files
3049
- * ├── code-review/
3050
- * │ ├── SKILL.md
3051
- * │ └── checklist.md
3052
- *
3053
- * .deepagents/skills/
3054
- * ├── project-specific/
3055
- * │ └── SKILL.md # Project-specific skills
3056
- * ```
3057
- */
3058
- /**
3059
- * State schema for skills middleware.
3060
- */
3061
- const SkillsStateSchema = z$2.object({ skillsMetadata: z$2.array(z$2.object({
3062
- name: z$2.string(),
3063
- description: z$2.string(),
3064
- path: z$2.string(),
3065
- source: z$2.enum(["user", "project"]),
3066
- license: z$2.string().optional(),
3067
- compatibility: z$2.string().optional(),
3068
- metadata: z$2.record(z$2.string(), z$2.string()).optional(),
3069
- allowedTools: z$2.string().optional()
3070
- })).optional() });
3071
- /**
3072
- * Skills System Documentation prompt template.
3073
- */
3074
- const SKILLS_SYSTEM_PROMPT = `
3075
-
3076
- ## Skills System
3077
-
3078
- You have access to a skills library that provides specialized capabilities and domain knowledge.
3079
-
3080
- {skills_locations}
3081
-
3082
- **Available Skills:**
3083
-
3084
- {skills_list}
3085
-
3086
- **How to Use Skills (Progressive Disclosure):**
3087
-
3088
- Skills follow a **progressive disclosure** pattern - you know they exist (name + description above), but you only read the full instructions when needed:
3089
-
3090
- 1. **Recognize when a skill applies**: Check if the user's task matches any skill's description
3091
- 2. **Read the skill's full instructions**: The skill list above shows the exact path to use with read_file
3092
- 3. **Follow the skill's instructions**: SKILL.md contains step-by-step workflows, best practices, and examples
3093
- 4. **Access supporting files**: Skills may include Python scripts, configs, or reference docs - use absolute paths
3094
-
3095
- **When to Use Skills:**
3096
- - When the user's request matches a skill's domain (e.g., "research X" → web-research skill)
3097
- - When you need specialized knowledge or structured workflows
3098
- - When a skill provides proven patterns for complex tasks
3099
-
3100
- **Skills are Self-Documenting:**
3101
- - Each SKILL.md tells you exactly what the skill does and how to use it
3102
- - The skill list above shows the full path for each skill's SKILL.md file
3103
-
3104
- **Executing Skill Scripts:**
3105
- Skills may contain Python scripts or other executable files. Always use absolute paths from the skill list.
3106
-
3107
- **Example Workflow:**
3108
-
3109
- User: "Can you research the latest developments in quantum computing?"
3110
-
3111
- 1. Check available skills above → See "web-research" skill with its full path
3112
- 2. Read the skill using the path shown in the list
3113
- 3. Follow the skill's research workflow (search → organize → synthesize)
3114
- 4. Use any helper scripts with absolute paths
3115
-
3116
- Remember: Skills are tools to make you more capable and consistent. When in doubt, check if a skill exists for the task!
3117
- `;
3118
- /**
3119
- * Format skills locations for display in system prompt.
3120
- */
3121
- function formatSkillsLocations(userSkillsDisplay, projectSkillsDir) {
3122
- const locations = [`**User Skills**: \`${userSkillsDisplay}\``];
3123
- if (projectSkillsDir) locations.push(`**Project Skills**: \`${projectSkillsDir}\` (overrides user skills)`);
3124
- return locations.join("\n");
3125
- }
3126
- /**
3127
- * Format skills metadata for display in system prompt.
3128
- */
3129
- function formatSkillsList(skills, userSkillsDisplay, projectSkillsDir) {
3130
- if (skills.length === 0) {
3131
- const locations = [userSkillsDisplay];
3132
- if (projectSkillsDir) locations.push(projectSkillsDir);
3133
- return `(No skills available yet. You can create skills in ${locations.join(" or ")})`;
3134
- }
3135
- const userSkills = skills.filter((s) => s.source === "user");
3136
- const projectSkills = skills.filter((s) => s.source === "project");
3137
- const lines = [];
3138
- if (userSkills.length > 0) {
3139
- lines.push("**User Skills:**");
3140
- for (const skill of userSkills) {
3141
- lines.push(`- **${skill.name}**: ${skill.description}`);
3142
- lines.push(` → Read \`${skill.path}\` for full instructions`);
3143
- }
3144
- lines.push("");
3145
- }
3146
- if (projectSkills.length > 0) {
3147
- lines.push("**Project Skills:**");
3148
- for (const skill of projectSkills) {
3149
- lines.push(`- **${skill.name}**: ${skill.description}`);
3150
- lines.push(` → Read \`${skill.path}\` for full instructions`);
3151
- }
3152
- }
3153
- return lines.join("\n");
3154
- }
3155
- /**
3156
- * Create middleware for loading and exposing agent skills.
3157
- *
3158
- * This middleware implements Anthropic's agent skills pattern:
3159
- * - Loads skills metadata (name, description) from YAML frontmatter at session start
3160
- * - Injects skills list into system prompt for discoverability
3161
- * - Agent reads full SKILL.md content when a skill is relevant (progressive disclosure)
3162
- *
3163
- * Supports both user-level and project-level skills:
3164
- * - User skills: ~/.deepagents/{AGENT_NAME}/skills/
3165
- * - Project skills: {PROJECT_ROOT}/.deepagents/skills/
3166
- * - Project skills override user skills with the same name
3167
- *
3168
- * @param options - Configuration options
3169
- * @returns AgentMiddleware for skills loading and injection
3170
- */
3171
- function createSkillsMiddleware(options) {
3172
- const { skillsDir, assistantId, projectSkillsDir } = options;
3173
- const userSkillsDisplay = `~/.deepagents/${assistantId}/skills`;
3174
- return createMiddleware({
3175
- name: "SkillsMiddleware",
3176
- stateSchema: SkillsStateSchema,
3177
- beforeAgent() {
3178
- return { skillsMetadata: listSkills({
3179
- userSkillsDir: skillsDir,
3180
- projectSkillsDir
3181
- }) };
3182
- },
3183
- wrapModelCall(request, handler) {
3184
- const skillsMetadata = request.state?.skillsMetadata || [];
3185
- const skillsLocations = formatSkillsLocations(userSkillsDisplay, projectSkillsDir);
3186
- const skillsList = formatSkillsList(skillsMetadata, userSkillsDisplay, projectSkillsDir);
3187
- const skillsSection = SKILLS_SYSTEM_PROMPT.replace("{skills_locations}", skillsLocations).replace("{skills_list}", skillsList);
3188
- const currentSystemPrompt = request.systemPrompt || "";
3189
- const newSystemPrompt = currentSystemPrompt ? `${currentSystemPrompt}\n\n${skillsSection}` : skillsSection;
3190
- return handler({
3191
- ...request,
3192
- systemPrompt: newSystemPrompt
3193
- });
3194
- }
3195
- });
3196
- }
3197
-
3198
- //#endregion
3199
- //#region src/middleware/agent-memory.ts
3200
- /**
3201
- * Middleware for loading agent-specific long-term memory into the system prompt.
3202
- *
3203
- * This middleware loads the agent's long-term memory from agent.md files
3204
- * and injects it into the system prompt. Memory is loaded from:
3205
- * - User memory: ~/.deepagents/{agent_name}/agent.md
3206
- * - Project memory: {project_root}/.deepagents/agent.md
3207
- */
3208
- /**
3209
- * State schema for agent memory middleware.
3210
- */
3211
- const AgentMemoryStateSchema = z$2.object({
3212
- userMemory: z$2.string().optional(),
3213
- projectMemory: z$2.string().optional()
3214
- });
3215
- /**
3216
- * Default template for memory injection.
3217
- */
3218
- const DEFAULT_MEMORY_TEMPLATE = `<user_memory>
3219
- {user_memory}
3220
- </user_memory>
3221
-
3222
- <project_memory>
3223
- {project_memory}
3224
- </project_memory>`;
3225
- /**
3226
- * Long-term Memory Documentation system prompt.
3227
- */
3228
- const LONGTERM_MEMORY_SYSTEM_PROMPT = `
3229
-
3230
- ## Long-term Memory
3231
-
3232
- Your long-term memory is stored in files on the filesystem and persists across sessions.
3233
-
3234
- **User Memory Location**: \`{agent_dir_absolute}\` (displays as \`{agent_dir_display}\`)
3235
- **Project Memory Location**: {project_memory_info}
3236
-
3237
- Your system prompt is loaded from TWO sources at startup:
3238
- 1. **User agent.md**: \`{agent_dir_absolute}/agent.md\` - Your personal preferences across all projects
3239
- 2. **Project agent.md**: Loaded from project root if available - Project-specific instructions
3240
-
3241
- Project-specific agent.md is loaded from these locations (both combined if both exist):
3242
- - \`[project-root]/.deepagents/agent.md\` (preferred)
3243
- - \`[project-root]/agent.md\` (fallback, but also included if both exist)
3244
-
3245
- **When to CHECK/READ memories (CRITICAL - do this FIRST):**
3246
- - **At the start of ANY new session**: Check both user and project memories
3247
- - User: \`ls {agent_dir_absolute}\`
3248
- - Project: \`ls {project_deepagents_dir}\` (if in a project)
3249
- - **BEFORE answering questions**: If asked "what do you know about X?" or "how do I do Y?", check project memories FIRST, then user
3250
- - **When user asks you to do something**: Check if you have project-specific guides or examples
3251
- - **When user references past work**: Search project memory files for related context
3252
-
3253
- **Memory-first response pattern:**
3254
- 1. User asks a question → Check project directory first: \`ls {project_deepagents_dir}\`
3255
- 2. If relevant files exist → Read them with \`read_file '{project_deepagents_dir}/[filename]'\`
3256
- 3. Check user memory if needed → \`ls {agent_dir_absolute}\`
3257
- 4. Base your answer on saved knowledge supplemented by general knowledge
3258
-
3259
- **When to update memories:**
3260
- - **IMMEDIATELY when the user describes your role or how you should behave**
3261
- - **IMMEDIATELY when the user gives feedback on your work** - Update memories to capture what was wrong and how to do it better
3262
- - When the user explicitly asks you to remember something
3263
- - When patterns or preferences emerge (coding styles, conventions, workflows)
3264
- - After significant work where context would help in future sessions
3265
-
3266
- **Learning from feedback:**
3267
- - When user says something is better/worse, capture WHY and encode it as a pattern
3268
- - Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions
3269
- - When user says "you should remember X" or "be careful about Y", treat this as HIGH PRIORITY - update memories IMMEDIATELY
3270
- - Look for the underlying principle behind corrections, not just the specific mistake
3271
-
3272
- ## Deciding Where to Store Memory
3273
-
3274
- When writing or updating agent memory, decide whether each fact, configuration, or behavior belongs in:
3275
-
3276
- ### User Agent File: \`{agent_dir_absolute}/agent.md\`
3277
- → Describes the agent's **personality, style, and universal behavior** across all projects.
3278
-
3279
- **Store here:**
3280
- - Your general tone and communication style
3281
- - Universal coding preferences (formatting, comment style, etc.)
3282
- - General workflows and methodologies you follow
3283
- - Tool usage patterns that apply everywhere
3284
- - Personal preferences that don't change per-project
3285
-
3286
- **Examples:**
3287
- - "Be concise and direct in responses"
3288
- - "Always use type hints in Python"
3289
- - "Prefer functional programming patterns"
3290
-
3291
- ### Project Agent File: \`{project_deepagents_dir}/agent.md\`
3292
- → Describes **how this specific project works** and **how the agent should behave here only.**
3293
-
3294
- **Store here:**
3295
- - Project-specific architecture and design patterns
3296
- - Coding conventions specific to this codebase
3297
- - Project structure and organization
3298
- - Testing strategies for this project
3299
- - Deployment processes and workflows
3300
- - Team conventions and guidelines
3301
-
3302
- **Examples:**
3303
- - "This project uses FastAPI with SQLAlchemy"
3304
- - "Tests go in tests/ directory mirroring src/ structure"
3305
- - "All API changes require updating OpenAPI spec"
3306
-
3307
- ### Project Memory Files: \`{project_deepagents_dir}/*.md\`
3308
- → Use for **project-specific reference information** and structured notes.
3309
-
3310
- **Store here:**
3311
- - API design documentation
3312
- - Architecture decisions and rationale
3313
- - Deployment procedures
3314
- - Common debugging patterns
3315
- - Onboarding information
3316
-
3317
- **Examples:**
3318
- - \`{project_deepagents_dir}/api-design.md\` - REST API patterns used
3319
- - \`{project_deepagents_dir}/architecture.md\` - System architecture overview
3320
- - \`{project_deepagents_dir}/deployment.md\` - How to deploy this project
3321
-
3322
- ### File Operations:
3323
-
3324
- **User memory:**
3325
- \`\`\`
3326
- ls {agent_dir_absolute} # List user memory files
3327
- read_file '{agent_dir_absolute}/agent.md' # Read user preferences
3328
- edit_file '{agent_dir_absolute}/agent.md' ... # Update user preferences
3329
- \`\`\`
3330
-
3331
- **Project memory (preferred for project-specific information):**
3332
- \`\`\`
3333
- ls {project_deepagents_dir} # List project memory files
3334
- read_file '{project_deepagents_dir}/agent.md' # Read project instructions
3335
- edit_file '{project_deepagents_dir}/agent.md' ... # Update project instructions
3336
- write_file '{project_deepagents_dir}/agent.md' ... # Create project memory file
3337
- \`\`\`
3338
-
3339
- **Important**:
3340
- - Project memory files are stored in \`.deepagents/\` inside the project root
3341
- - Always use absolute paths for file operations
3342
- - Check project memories BEFORE user when answering project-specific questions`;
3343
- /**
3344
- * Create middleware for loading agent-specific long-term memory.
3345
- *
3346
- * This middleware loads the agent's long-term memory from a file (agent.md)
3347
- * and injects it into the system prompt. The memory is loaded once at the
3348
- * start of the conversation and stored in state.
3349
- *
3350
- * @param options - Configuration options
3351
- * @returns AgentMiddleware for memory loading and injection
3352
- */
3353
- function createAgentMemoryMiddleware(options) {
3354
- const { settings, assistantId, systemPromptTemplate } = options;
3355
- const agentDir = settings.getAgentDir(assistantId);
3356
- const agentDirDisplay = `~/.deepagents/${assistantId}`;
3357
- const agentDirAbsolute = agentDir;
3358
- const projectRoot = settings.projectRoot;
3359
- const projectMemoryInfo = projectRoot ? `\`${projectRoot}\` (detected)` : "None (not in a git project)";
3360
- const projectDeepagentsDir = projectRoot ? `${projectRoot}/.deepagents` : "[project-root]/.deepagents (not in a project)";
3361
- const template = systemPromptTemplate || DEFAULT_MEMORY_TEMPLATE;
3362
- return createMiddleware({
3363
- name: "AgentMemoryMiddleware",
3364
- stateSchema: AgentMemoryStateSchema,
3365
- beforeAgent(state) {
3366
- const result = {};
3367
- if (!("userMemory" in state)) {
3368
- const userPath = settings.getUserAgentMdPath(assistantId);
3369
- if (fs$1.existsSync(userPath)) try {
3370
- result.userMemory = fs$1.readFileSync(userPath, "utf-8");
3371
- } catch {}
3372
- }
3373
- if (!("projectMemory" in state)) {
3374
- const projectPath = settings.getProjectAgentMdPath();
3375
- if (projectPath && fs$1.existsSync(projectPath)) try {
3376
- result.projectMemory = fs$1.readFileSync(projectPath, "utf-8");
3377
- } catch {}
3378
- }
3379
- return Object.keys(result).length > 0 ? result : void 0;
3380
- },
3381
- wrapModelCall(request, handler) {
3382
- const userMemory = request.state?.userMemory;
3383
- const projectMemory = request.state?.projectMemory;
3384
- const baseSystemPrompt = request.systemPrompt || "";
3385
- const memorySection = template.replace("{user_memory}", userMemory || "(No user agent.md)").replace("{project_memory}", projectMemory || "(No project agent.md)");
3386
- 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);
3387
- let systemPrompt = memorySection;
3388
- if (baseSystemPrompt) systemPrompt += "\n\n" + baseSystemPrompt;
3389
- systemPrompt += "\n\n" + memoryDocs;
3390
- return handler({
3391
- ...request,
3392
- systemPrompt
3393
- });
3394
- }
3395
- });
3396
- }
3397
-
3398
- //#endregion
3399
- export { BaseSandbox, CompositeBackend, FilesystemBackend, MAX_SKILL_DESCRIPTION_LENGTH, MAX_SKILL_FILE_SIZE, MAX_SKILL_NAME_LENGTH, StateBackend, StoreBackend, createAgentMemoryMiddleware, createDeepAgent, createFilesystemMiddleware, createPatchToolCallsMiddleware, createSettings, createSkillsMiddleware, createSubAgentMiddleware, findProjectRoot, isSandboxBackend, listSkills, parseSkillMetadata };
3648
+ export { BaseSandbox, CompositeBackend, FilesystemBackend, MAX_SKILL_DESCRIPTION_LENGTH, MAX_SKILL_FILE_SIZE, MAX_SKILL_NAME_LENGTH, StateBackend, StoreBackend, createAgentMemoryMiddleware, createDeepAgent, createFilesystemMiddleware, createMemoryMiddleware, createPatchToolCallsMiddleware, createSettings, createSkillsMiddleware, createSubAgentMiddleware, findProjectRoot, isSandboxBackend, listSkills, parseSkillMetadata };
3400
3649
  //# sourceMappingURL=index.js.map