[PR #204] feat(deepagents): allow overriding default middleware for deepagent and subagents #208

Open
opened 2026-02-16 06:17:26 -05:00 by yindo · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/langchain-ai/deepagentsjs/pull/204
Author: @alvedder
Created: 2/8/2026
Status: 🔄 Open

Base: mainHead: alvedder/middleware-override


📝 Commits (2)

  • 5848e30 feat(deepagents): allow overriding default middleware for deepagent and subagents
  • 974d553 Merge branch 'langchain-ai:main' into alvedder/middleware-override

📊 Changes

4 files changed (+173 additions, -13 deletions)

View changed files

📝 libs/deepagents/src/agent.ts (+14 -11)
📝 libs/deepagents/src/middleware/subagents.ts (+2 -1)
📝 libs/deepagents/src/middleware/utils.test.ts (+114 -1)
📝 libs/deepagents/src/middleware/utils.ts (+43 -0)

📄 Description

Adds middleware override capability for DeepAgents and subagents, allowing users to replace specific default middleware by name while preserving the middleware execution order.

Motivation

Previously, middleware arrays were merged through simple concatenation ([...defaults, ...custom]), making it difficult to replace or customize default middleware behavior as langchain's createAgent throws an error if detects multiple same-named middleware.

Users who wanted to modify a specific middleware (e.g., filesystem, skills, memory) had to either:

  • Accept the default behavior entirely, or
  • Manually reconstruct the entire middleware chain

This commit introduces a smarter merge strategy that:

  • Allows overriding default middleware by matching the name property
  • Preserves the position of overridden middleware in the chain
  • Appends new custom middleware at the end (as it was previously)
  • Maintains backward compatibility for users who don't override anything

This gives users fine-grained control over agent behavior without requiring deep knowledge of the internal middleware ordering.

Changes

libs/deepagents/src/middleware/utils.ts

Added the mergeMiddleware function that implements the merge strategy:

  • Creates a map of custom middleware by name for efficient lookups
  • Replaces default middleware in-place when a custom override exists
  • Appends non-overriding custom middleware at the end
  • Returns a new array without mutating inputs

Example behavior:

const defaults = [mw1, mw2, mw3];
const custom = [mw2Override, mw4];
const result = mergeMiddleware(defaults, custom);
// Result: [mw1, mw2Override, mw3, mw4]

libs/deepagents/src/middleware/utils.test.ts

Added test coverage for mergeMiddleware with 10 test cases covering:

  • Empty array handling (both, either, or neither empty)
  • In-place replacement of named middleware
  • Appending new custom middleware
  • Mixed override and addition scenarios
  • Full replacement when all defaults are overridden
  • Order preservation for non-overridden middleware
  • Input array immutability

libs/deepagents/src/agent.ts

Updated createDeepAgent function:

  • Replaced array concatenation with mergeMiddleware for the main agent's runtime middleware
  • Applied the same pattern to subagent skills middleware processing
  • Maintained the same middleware execution order for backward compatibility

Before:

const runtimeMiddleware: AgentMiddleware[] = [
  ...builtInMiddleware,
  ...skillsMiddlewareArray,
  ...memoryMiddlewareArray,
  ...(interruptOn ? [humanInTheLoopMiddleware({ interruptOn })] : []),
  ...(customMiddleware as unknown as AgentMiddleware[]),
];

After:

const runtimeMiddleware: AgentMiddleware[] = mergeMiddleware(
  [
    ...builtInMiddleware,
    ...skillsMiddlewareArray,
    ...memoryMiddlewareArray,
    ...(interruptOn ? [humanInTheLoopMiddleware({ interruptOn })] : []),
  ],
  customMiddleware as unknown as AgentMiddleware[],
);

libs/deepagents/src/middleware/subagents.ts

Updated getSubagents function:

  • Replaced array concatenation with mergeMiddleware for subagent middleware
  • Imported the new utility function
  • Consistent behavior with main agent middleware merging

Before:

const middleware = agentParams.middleware
  ? [...defaultSubagentMiddleware, ...agentParams.middleware]
  : [...defaultSubagentMiddleware];

After:

const middleware = agentParams.middleware
  ? mergeMiddleware(defaultSubagentMiddleware, agentParams.middleware)
  : [...defaultSubagentMiddleware];

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/langchain-ai/deepagentsjs/pull/204 **Author:** [@alvedder](https://github.com/alvedder) **Created:** 2/8/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `alvedder/middleware-override` --- ### 📝 Commits (2) - [`5848e30`](https://github.com/langchain-ai/deepagentsjs/commit/5848e3060fa4bda1c3bd62a2fb30abda028b2eac) feat(deepagents): allow overriding default middleware for deepagent and subagents - [`974d553`](https://github.com/langchain-ai/deepagentsjs/commit/974d553eca34776cc1b6b076b93f159f59348d95) Merge branch 'langchain-ai:main' into alvedder/middleware-override ### 📊 Changes **4 files changed** (+173 additions, -13 deletions) <details> <summary>View changed files</summary> 📝 `libs/deepagents/src/agent.ts` (+14 -11) 📝 `libs/deepagents/src/middleware/subagents.ts` (+2 -1) 📝 `libs/deepagents/src/middleware/utils.test.ts` (+114 -1) 📝 `libs/deepagents/src/middleware/utils.ts` (+43 -0) </details> ### 📄 Description Adds middleware override capability for DeepAgents and subagents, allowing users to replace specific default middleware by name while preserving the middleware execution order. ## Motivation Previously, middleware arrays were merged through simple concatenation (`[...defaults, ...custom]`), making it difficult to replace or customize default middleware behavior as langchain's `createAgent` throws an error if detects multiple same-named middleware. Users who wanted to modify a specific middleware (e.g., filesystem, skills, memory) had to either: - Accept the default behavior entirely, or - Manually reconstruct the entire middleware chain This commit introduces a smarter merge strategy that: - Allows overriding default middleware by matching the `name` property - Preserves the position of overridden middleware in the chain - Appends new custom middleware at the end (as it was previously) - Maintains backward compatibility for users who don't override anything This gives users fine-grained control over agent behavior without requiring deep knowledge of the internal middleware ordering. ## Changes ### `libs/deepagents/src/middleware/utils.ts` Added the `mergeMiddleware` function that implements the merge strategy: - Creates a map of custom middleware by name for efficient lookups - Replaces default middleware in-place when a custom override exists - Appends non-overriding custom middleware at the end - Returns a new array without mutating inputs **Example behavior:** ```typescript const defaults = [mw1, mw2, mw3]; const custom = [mw2Override, mw4]; const result = mergeMiddleware(defaults, custom); // Result: [mw1, mw2Override, mw3, mw4] ``` ### `libs/deepagents/src/middleware/utils.test.ts` Added test coverage for `mergeMiddleware` with 10 test cases covering: - Empty array handling (both, either, or neither empty) - In-place replacement of named middleware - Appending new custom middleware - Mixed override and addition scenarios - Full replacement when all defaults are overridden - Order preservation for non-overridden middleware - Input array immutability ### `libs/deepagents/src/agent.ts` Updated `createDeepAgent` function: - Replaced array concatenation with `mergeMiddleware` for the main agent's runtime middleware - Applied the same pattern to subagent skills middleware processing - Maintained the same middleware execution order for backward compatibility **Before:** ```typescript const runtimeMiddleware: AgentMiddleware[] = [ ...builtInMiddleware, ...skillsMiddlewareArray, ...memoryMiddlewareArray, ...(interruptOn ? [humanInTheLoopMiddleware({ interruptOn })] : []), ...(customMiddleware as unknown as AgentMiddleware[]), ]; ``` **After:** ```typescript const runtimeMiddleware: AgentMiddleware[] = mergeMiddleware( [ ...builtInMiddleware, ...skillsMiddlewareArray, ...memoryMiddlewareArray, ...(interruptOn ? [humanInTheLoopMiddleware({ interruptOn })] : []), ], customMiddleware as unknown as AgentMiddleware[], ); ``` ### `libs/deepagents/src/middleware/subagents.ts` Updated `getSubagents` function: - Replaced array concatenation with `mergeMiddleware` for subagent middleware - Imported the new utility function - Consistent behavior with main agent middleware merging **Before:** ```typescript const middleware = agentParams.middleware ? [...defaultSubagentMiddleware, ...agentParams.middleware] : [...defaultSubagentMiddleware]; ``` **After:** ```typescript const middleware = agentParams.middleware ? mergeMiddleware(defaultSubagentMiddleware, agentParams.middleware) : [...defaultSubagentMiddleware]; ``` --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
yindo added the pull-request label 2026-02-16 06:17:26 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/deepagentsjs#208