Skip to content

feat(sdk): add subagent_model param to create_deep_agent#1369

Open
Harrison Chase (hwchase17) wants to merge 78 commits intomainfrom
open-swe/1b4b174d-c1a7-7012-920e-48174f57add2
Open

feat(sdk): add subagent_model param to create_deep_agent#1369
Harrison Chase (hwchase17) wants to merge 78 commits intomainfrom
open-swe/1b4b174d-c1a7-7012-920e-48174f57add2

Conversation

@hwchase17
Copy link
Contributor

@hwchase17 Harrison Chase (hwchase17) commented Feb 17, 2026

Summary

Allow users to override the default general-purpose subagent configuration in create_deep_agent by passing a subagent with the name "general-purpose" in the subagents list.

Previously, the built-in general-purpose subagent was always prepended, making it impossible to customize its model, system prompt, or other settings. Now, if a user-provided subagent shares the "general-purpose" name, it replaces the default instead of duplicating it.

Changes

  • libs/deepagents/deepagents/graph.py: Check whether processed_subagents already contains a "general-purpose" entry before prepending the default spec. Also inlines the base agent prompt and adds a minor noqa annotation.
  • libs/deepagents/tests/unit_tests/test_subagents.py: Adds test_general_purpose_subagent_override to verify that a user-supplied general-purpose subagent fully replaces the default.

@github-actions github-actions bot added deepagents Related to the `deepagents` SDK / agent harness internal User is a member of the `langchain-ai` GitHub organization feature New feature/enhancement or request for one labels Feb 17, 2026
system_prompt: str | SystemMessage | None = None,
middleware: Sequence[AgentMiddleware] = (),
subagents: list[SubAgent | CompiledSubAgent] | None = None,
subagent_model: str | BaseChatModel | None = None,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a way to specify t his through subagents instead?

General agent is forcing this arg to appear at top level of API, but it spreads subagent configuration into multiple locations

Fixes #1289 

Pressing Escape while the slash-command or file-mention dropdown was
open would skip the popup and immediately interrupt the running agent
(or reject an approval). Gives the completion popup its own dismissal
step in the `action_interrupt` priority chain.

Before (Pressing `Esc` did not close the completion dropdown) :
<img width="847" height="691" alt="Screenshot 2026-02-17 142557"
src="https://github.com/user-attachments/assets/6309d245-3e87-43fe-951e-19e25d849eec"
/>

After (Pressing `Esc` cleanly hides the dropdown):
<img width="844" height="688" alt="Screenshot 2026-02-17 145510"
src="https://github.com/user-attachments/assets/ecc2ce6f-32ce-4056-8b1c-3e5565fe0a3e"
/>

---------

Co-authored-by: Mason Daugherty <mason@langchain.dev>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
…h` (#1370)

Following #918

- Log skipped paths in `FilesystemBackend` virtual mode instead of
silently
  continuing (DEBUG for outside-root, WARNING for OS errors)
- Rename `_validate_path` to `validate_path` since used cross-module,
not private
Give the chat input box visual feedback when the user enters bash or
command mode. The prompt character, border color, and prompt color all
update to reflect the active mode.
<img width="720" height="137" alt="Screenshot 19"
src="https://github.com/user-attachments/assets/c949ef79-21bb-42b2-80b7-f6a82cb53192"
/>
<img width="716" height="327" alt="Screenshot 10"
src="https://github.com/user-attachments/assets/1f3a91f2-9118-45b6-9313-d196f2d14c6f"
/>
<img width="713" height="138" alt="Screenshot 9"
src="https://github.com/user-attachments/assets/9cc6ec3a-45bb-4854-9430-efde45b8aa94"
/>
Strip mode-trigger characters (`!`, `/`) from the text area after they
switch the input mode, so users see clean input (e.g. `ls` instead of
`!ls`) while the mode indicator badge communicates the active mode
visually.

<img width="298" height="127" alt="Screenshot 9"
src="https://github.com/user-attachments/assets/369a67a9-181b-450e-b90c-47cb0dd70395"
/>
<img width="316" height="137" alt="Screenshot 8"
src="https://github.com/user-attachments/assets/c4fc57cd-0123-4381-9fd1-645a5e4c2342"
/>

Also shows in history:

<img width="587" height="437" alt="Screenshot"
src="https://github.com/user-attachments/assets/e1f7afed-f0e2-4757-97c3-2599e849e3cf"
/>
The `/version` slash command and `--version` CLI flag previously only
showed the `deepagents-cli` package version. Now both surfaces display
the SDK (`deepagents`) version alongside the CLI version, making it
easier to triage issues.
…ort (#1295)

Rewrite `LocalContextMiddleware` to run environment detection as a bash
script via `backend.execute()` instead of Python's
`subprocess`/`pathlib` calls. The old implementation only worked locally
— running detection through the backend means the same context-gathering
logic works in remote sandboxes too.

## Changes
- Replace all previous Python-based detection methods with a single bash
script built from composable section functions
- `LocalContextMiddleware` now requires a `backend` argument
implementing the `_ExecutableBackend` protocol
- Move middleware registration in `create_cli_agent` outside the
local/remote branch so it activates for any backend that supports shell
execution, gated by `isinstance(backend, _ExecutableBackend)`
- Add new detection capabilities not in the old implementation: runtime
version reporting (Python/Node versions), uncommitted change count, and
`npm test` command detection via `package.json` scripts

The loop detection middleware is ported from the Harbor benchmark
harness where it ran across 445 TB2 trials, adapted for CLI's
human-in-the-loop context.

---------

Co-authored-by: Mason Daugherty <github@mdrxy.com>
)

Fixes #1351
Fixes #1006

---

When tool results contain base64-encoded images (e.g. from screenshot or
vision tools), the raw data would flood the terminal with thousands of
characters of noise. This replaces those payloads with a compact
`[Image: mime/type, ~NKB]` placeholder. Also fixes a separate issue
where `_escape_markup` was doing a bracket replacement (`\[`, `\]`) that
caused visible backslashes in tool output — now delegates to Rich's
[`escape`](https://rich.readthedocs.io/en/latest/markup.html#escaping)
which only targets actual markup patterns.
Switch the CLI's unit test runner from sequential to parallel execution
via `pytest-xdist` (`-n auto`). Cuts total test time by ~75%
Restrict prompt history navigation to true input boundaries — up arrow
only triggers at cursor position `(0, 0)`, down arrow only at the end of
input. Previously, being anywhere on the first or last line was enough,
which hijacked normal cursor movement while editing multi-character or
multiline prompts. When already browsing history (`_in_history`),
navigation is allowed from either boundary so cycling through entries
still works naturally.
Add drag-and-drop image attachment to the CLI chat input. 

Dropping image files onto the terminal (or pasting their paths) encodes
them as base64 and inserts `[image N]` placeholder tokens into the
composer, treating each placeholder as an atomic unit for editing.
Defer heavy third-party imports out of module-level scope so the CLI
loads faster. Every function that needs these libraries now imports them
at call time. Also adds a fast-path version check – `deepagents -v` /
`--version` now prints and exits before any heavy imports are loaded.
Add a small test suite for evals. These are more of "short-horizon"
tasks to make sure that the agent can be efficient at specific tasks. if
all the context is in place.
🤖 I have created a release *beep* *boop*
---


##
[0.0.23](deepagents-cli==0.0.22...deepagents-cli==0.0.23)
(2026-02-18)


### Features

* **cli:** add drag-and-drop image attachment to chat input
([#1386](#1386))
([cd3d89b](cd3d89b))
* **cli:** add skill deletion command
([#580](#580))
([40a8d86](40a8d86))
* **cli:** add visual mode indicators to chat input
([#1371](#1371))
([1ea6159](1ea6159))
* **cli:** dismiss completion dropdown on `esc`
([#1362](#1362))
([961b7fc](961b7fc))
* **cli:** expand local context & implement via bash for sandbox support
([#1295](#1295))
([de8bc7c](de8bc7c))
* **cli:** show sdk version alongside cli version
([#1378](#1378))
([e99b4c8](e99b4c8))
* **cli:** strip mode-trigger prefix from chat input text
([#1373](#1373))
([6879eff](6879eff))


### Bug Fixes

* **cli,sdk:** harden path hardening
([#918](#918))
([fc34a14](fc34a14))
* **cli:** only navigate prompt history at input boundaries
([#1385](#1385))
([6d82d6d](6d82d6d))
* **cli:** substitute image base64 for placeholder in result block
([#1381](#1381))
([54f4d8e](54f4d8e))


### Performance Improvements

* **cli:** defer more heavy imports to speed up startup
([#1389](#1389))
([4dd10d5](4dd10d5))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* Parametrizing the system message for exec vs. no exec.
* In a separate PR we'll deal with the custom system message.
Fixes a rendering crash when shell commands contain literal `Rich`
tag-like text (for example `[/dim]`), which was being interpreted as
markup instead of plain text.

**Before**  
`ApprovalMenu._get_command_display()` built a Rich-marked string by
interpolating raw command text:

```python
f"[bold #f59e0b]{command}[/bold #f59e0b]"
```

If `command` contained `[` or `]` tag sequences, Rich parsed them.  

Example input:

```text
echo [/dim] [literal]
```

could raise:

```text
... closing tag '[/dim]' does not match any open tag
```

**After**  
`command` (and truncated command) is escaped before insertion into
markup:

```python
f"[bold #f59e0b]{escape_markup(command)}[/bold #f59e0b]"
```

Result: Rich renders the command text literally, including bracket
sequences, with no parse error.
Replace hand-maintained help targets across all `Makefile`s

The manual echo blocks were already drifting out of sync with actual
targets
…1484)

`BaseSandbox.ls_info()` and `_READ_COMMAND_TEMPLATE` interpolate
`path`/`file_path` directly into Python code strings using raw
`'{path}'` formatting. A crafted path containing single quotes can break
out of the string literal and execute arbitrary code inside the sandbox.

This applies the same base64-encoding pattern already used by
`_GLOB_COMMAND_TEMPLATE`, `_WRITE_COMMAND_TEMPLATE`, and
`_EDIT_COMMAND_TEMPLATE` in the same file.

Fixes #1483

## Areas requiring careful review

- The `_READ_COMMAND_TEMPLATE` now takes `file_path_b64` instead of
`file_path`, and `BaseSandbox.read()` encodes it before calling
`.format()`. This is the same pattern as `glob_info()`.
- The `ls_info()` inline command now encodes `path` the same way.
- Two new tests verify that malicious paths do not appear in the
generated command strings.

## How was this verified?

- Ran `make format`, `make lint`, and `make test` from
`libs/deepagents/`
- Added `test_sandbox_ls_info_path_is_sanitized` and
`test_sandbox_read_path_is_sanitized` to confirm malicious paths are not
interpolated raw
- Updated `test_read_command_template_format` to use the new base64
interface
- Verified `write()`, `edit()`, `glob_info()`, and `grep_raw()` already
use safe patterns (base64 or `shlex.quote()`) and are unchanged

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
## Summary

Fixed issue #1348 where glob patterns containing `**` silently return
zero results when ripgrep is unavailable.

## Problem

The `_python_search` fallback method had two bugs:
1. Used `fp.name` (filename only) instead of relative path for glob
matching
2. Missing `GLOBSTAR` flag, so `**` wasn't treated as recursive wildcard

## Fix

```python
# Before (broken):
if include_glob and not wcglob.globmatch(fp.name, include_glob, flags=wcglob.BRACE):
    continue

# After (fixed):
if include_glob:
    rel_path = str(fp.relative_to(root))
    if not wcglob.globmatch(
        rel_path, include_glob, flags=wcglob.BRACE | wcglob.GLOBSTAR
    ):
        continue
```

Now matches against relative path and adds GLOBSTAR flag for proper `**`
matching.

## Testing

- Reproduced the bug with test case from issue
- Verified fix works with glob patterns like `**/*.py`

AI assistance used for code review and implementation

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
Co-authored-by: Eugene Yurtsev <eugene@langchain.dev>
…tputs (#1482)

## Summary
Fixes data loss when large `ToolMessage` content is evicted to
`/large_tool_results/...`.

Before this change, eviction rebuilt the message with only
`content/tool_call_id/name`, which dropped runtime fields like
`artifact`.

This patch preserves the original message metadata when generating the
evicted replacement message:
- `artifact`
- `id`
- `status`
- `additional_kwargs`
- `response_metadata`

## Why this matters
`artifact` is not model-facing text, but it is part of runtime semantics
for downstream tooling, tracing, and replay/debug flows. Dropping it
caused structured tool metadata to disappear after middleware
processing.

## Tests
Added regression coverage for both sync and async interception paths:
- `test_intercept_long_toolmessage_preserves_artifact_and_metadata`
- `test_store_backend_aintercept_large_tool_result_async` (extended)

Local validation:
- `uv run --all-groups ruff check deepagents/middleware/filesystem.py
tests/unit_tests/test_middleware.py
tests/unit_tests/backends/test_store_backend_async.py`
- `uv run --all-groups ty check deepagents/middleware/filesystem.py`
- `uv run --all-groups ty check
tests/unit_tests/backends/test_store_backend_async.py`
- `uv run --group test pytest -q tests/unit_tests/test_middleware.py -k
"preserves_artifact_and_metadata or preserves_name"`
- `uv run --group test pytest -q
tests/unit_tests/backends/test_store_backend_async.py -k
"aintercept_large_tool_result_async"`

Additionally verified via `trace` that the new preservation lines are
executed in both sync and async code paths.

Closes #1450.

---
AI assistance disclosure: AI support was limited to unit-test drafting,
code review pass, and style/lint checks. Final code decisions and edits
were manually validated.
## Summary

- Refactors `_READ_COMMAND_TEMPLATE` to receive `file_path`, `offset`,
and `limit` as a single base64-encoded JSON payload via stdin heredoc
- Matches the pattern already used by `_WRITE_COMMAND_TEMPLATE` and
`_EDIT_COMMAND_TEMPLATE` in the same file
- Eliminates all raw parameter interpolation from the read command
string

Follow-up to reviewer feedback from @eyurtsev in #1484.

Fixes #1499

## Areas requiring careful review

- The `_READ_COMMAND_TEMPLATE` now reads a JSON payload from stdin
instead of using `.format()` placeholders for `file_path`, `offset`, and
`limit`
- `BaseSandbox.read()` now constructs and encodes the payload before
formatting
@github-actions github-actions bot added cli Related to `deepagents-cli` dependencies Pull requests that update a dependency file acp Agent Client Protocol harbor Benchmarks github_actions PR touching `.github` labels Feb 24, 2026
@github-actions github-actions bot added feature New feature/enhancement or request for one and removed feature New feature/enhancement or request for one labels Feb 25, 2026
Copy link
Collaborator

@eyurtsev Eugene Yurtsev (eyurtsev) left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine for now, we will likely be able to support this later using a more general overrides argument. Mind documenting this in the api ref itself in create_deep_agents?

@mdrxy Mason Daugherty (mdrxy) changed the title feat: add subagent_model param to create_deep_agent [closes LC-480] feat(sdk): add subagent_model param to create_deep_agent Mar 5, 2026
@github-actions github-actions bot added feature New feature/enhancement or request for one and removed feature New feature/enhancement or request for one labels Mar 5, 2026
@mdrxy Mason Daugherty (mdrxy) removed cli Related to `deepagents-cli` dependencies Pull requests that update a dependency file acp Agent Client Protocol harbor Benchmarks github_actions PR touching `.github` labels Mar 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

deepagents Related to the `deepagents` SDK / agent harness feature New feature/enhancement or request for one internal User is a member of the `langchain-ai` GitHub organization

Projects

None yet

Development

Successfully merging this pull request may close these issues.