Commit Graph

177 Commits

Author SHA1 Message Date
github-actions[bot] a9e1ba1b89 chore: version packages (#605)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## deepagents-acp@0.1.15

### Patch Changes

- Updated dependencies
[[`7c4a11e`](https://github.com/langchain-ai/deepagentsjs/commit/7c4a11eacc11c3720b70d802068300ac3b4d8651)]:
  - deepagents@1.10.5
## deepagents@1.10.5

### Patch Changes

- [#598](https://github.com/langchain-ai/deepagentsjs/pull/598)
[`7c4a11e`](https://github.com/langchain-ai/deepagentsjs/commit/7c4a11eacc11c3720b70d802068300ac3b4d8651)
Thanks [@christian-bromann](https://github.com/christian-bromann)! -
refactor(stream): use langchain `run.subagents` instead of bespoke
transformer

Remove deepagents' custom `createSubagentTransformer` and rely on the
native
  subagent stream that `createAgent` registers (langchain#37739). Keep
`DeepAgentRunStream` as a compile-time overlay that narrows
`run.subagents` to
declared subagent specs. Update streaming tests for `cause` and
per-subagent
  message coverage.
## @langchain/quickjs@0.5.1

### Patch Changes

- [#602](https://github.com/langchain-ai/deepagentsjs/pull/602)
[`204cb27`](https://github.com/langchain-ai/deepagentsjs/commit/204cb27414c82c34a0c681c7e5a5336e1834f058)
Thanks [@colifran](https://github.com/colifran)! - chore(quickjs):
refine dynamic subagent prompt to trigger on workflow keyword and to
improve iterative eval behavior

- [#604](https://github.com/langchain-ai/deepagentsjs/pull/604)
[`0971007`](https://github.com/langchain-ai/deepagentsjs/commit/0971007ab2491e73eb1a78c5426ab934470d5620)
Thanks [@colifran](https://github.com/colifran)! - fix(quickjs): unwrap
Command/ToolMessage envelopes from tool and subagent results
## @deepagents/evals@0.0.14

### Patch Changes

- Updated dependencies
[[`7c4a11e`](https://github.com/langchain-ai/deepagentsjs/commit/7c4a11eacc11c3720b70d802068300ac3b4d8651)]:
  - deepagents@1.10.5

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-18 09:38:18 -07:00
Christian Bromann 7c4a11eacc fix(deepagents): use langchain run.subagents instead of bespoke transformer (#598)
## Summary
- Remove deepagents' bespoke `createSubagentTransformer` (~460 lines)
and wire `createDeepAgent` to langchain's native `run.subagents`
projection from `createAgent` (langchain#37739).
- Slim `stream.ts` to type-only exports: re-export `SubagentRunStream`
from langchain and keep `DeepAgentRunStream` as a compile-time narrowing
over declared subagent specs.
- Update streaming tests for `sub.cause` (replacing `taskInput`), add
single-subagent `sub.messages` coverage, and document parallel-subagent
streaming behavior.
- Pin `langchain@1.4.6-dev-1781497519109` and `@langchain/langgraph` /
`@langchain/langgraph-checkpoint` to `d2312cf` dev builds (root
`pnpm.overrides`) for end-to-end verification until published releases
are available.
- Clarify `streamTransformers` docs: custom transformers surface on
`run.extensions`; built-in streams like `run.subagents` and
`run.toolCalls` are separate.

fixes #560
2026-06-18 09:36:50 -07:00
Colin Francis 0971007ab2 fix(quickjs): unwrap Command/ToolMessage envelopes from tool and subagent results (#604)
### Summary

The deepagents `task` tool resolves to a LangGraph `Command` (and some
tools return a `ToolMessage` or a list of messages), but the quickjs
bridges passed these envelopes straight to the REPL so `task(...)` and
PTC `tools.*` calls handed the model the wrapper instead of the
subagent's actual output, breaking the contract that a `responseSchema`
dispatch resolves to a typed value.

This PR adds `unwrapToolEnvelope`: a duck-typed unwrap of `Command` /
`ToolMessage` / message-list shapes that reverse-scans `update.messages`
for the last message with content and reads both live and serialized
forms. Non-envelope values pass through unchanged.

`unwrapToolEnvelope` is wired into both bridges, i.e., the `task()`
dispatch and the PTC `tools.*` bridge.

Inspired by the Python's
[`coerce_tool_output_for_ptc`](https://github.com/langchain-ai/deepagents/blob/4c347603162e181c721e5e2a5ca8bbff6828e23c/libs/partners/quickjs/langchain_quickjs/_format.py#L93-L119).

### Tests

- `coerce.test.ts` provide unit test coverage for `unwrapToolEnvelope`:
string/null/undefined passthrough, `Command` (single + multi-message),
reverse-scan past empty trailing messages, serialized `kwargs.content`,
bare `ToolMessage`, message lists, content-block arrays and plain `{
content }` objects left untouched.
- `middleware.test.ts` provides an integration test that the `task()`
bridge returns the parsed structured value from a `Command` result.
2026-06-18 06:27:35 -07:00
Colin Francis 204cb27414 chore(quickjs): refine dynamic subagent prompt to trigger on workflow keyword and to improve iterative eval behavior (#602)
### Summary

Prompt change only, no runtime behavior change.

Reworks the quickjs code-interpreter subagent prompt to steer the
orchestrator toward an explore-then-distribute workflow. It explores
with its own tools first, hands subagents file paths instead of pasted
contents, reuses persisted REPL variables rather than re-pasting prior
eval output, and returns results via the last expression instead of
`console.log`. Also gates the REPL sandbox note so it only mentions the
`tools.*` namespace when PTC is actually exposed.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 06:27:18 -07:00
github-actions[bot] 750d69c024 chore: version packages (#568)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @langchain/node-vfs@0.2.0

### Minor Changes

- [#575](https://github.com/langchain-ai/deepagentsjs/pull/575)
[`5d266a2`](https://github.com/langchain-ai/deepagentsjs/commit/5d266a213d8d3d15c2281e2e00ab71ee30ca3ffe)
Thanks [@hntrl](https://github.com/hntrl)! - BREAKING: remove shell
execution from the VFS provider

`VfsBackend` now operates as a filesystem-only `BackendProtocolV2`
implementation and no longer exposes command execution.

The provider now implements `read`, `ls`, `grep`, and `glob` directly
against the in-memory VFS, path resolution is confined to the virtual
workspace root, and legacy `VfsSandbox` / `createVfsSandboxFactory*`
aliases are removed.
## @langchain/quickjs@0.5.0

### Minor Changes

- [#590](https://github.com/langchain-ai/deepagentsjs/pull/590)
[`7ee3feb`](https://github.com/langchain-ai/deepagentsjs/commit/7ee3feb674c361305b2a031db9132253e3d0543b)
Thanks [@colifran](https://github.com/colifran)! - chore(quickjs):
remove skills backend and associated plumbing

- [#592](https://github.com/langchain-ai/deepagentsjs/pull/592)
[`72cfb0c`](https://github.com/langchain-ai/deepagentsjs/commit/72cfb0c0384b30059b5e8028139a2e167c1be882)
Thanks [@colifran](https://github.com/colifran)! - feat(quickjs):
implement default subagent primitive in code interpreter for
programmatic subagent calling

### Patch Changes

- [#594](https://github.com/langchain-ai/deepagentsjs/pull/594)
[`61db938`](https://github.com/langchain-ai/deepagentsjs/commit/61db9381494f61b4548cd80b715e5af72fdde381)
Thanks [@colifran](https://github.com/colifran)! - chore(quickjs):
remove configurable concurrency and add subagents option with true
default

- [#546](https://github.com/langchain-ai/deepagentsjs/pull/546)
[`b7a5f26`](https://github.com/langchain-ai/deepagentsjs/commit/b7a5f26fd9cba992b11e1a4cf18607d64533503b)
Thanks [@open-swe](https://github.com/apps/open-swe)! - fix(quickjs):
scope `CodeInterpreterMiddleware` REPL prompt sandbox bullet to the
runtime
## deepagents-acp@0.1.14

### Patch Changes

- Updated dependencies
[[`18557db`](https://github.com/langchain-ai/deepagentsjs/commit/18557db7bbdf92052ed5f994512fb70e11989e69),
[`773cac5`](https://github.com/langchain-ai/deepagentsjs/commit/773cac5dc7efc7843dd882642d91f7d64d6fde81),
[`1ca6dc9`](https://github.com/langchain-ai/deepagentsjs/commit/1ca6dc92fd40a6d845d24b95ba14b8f2643db394),
[`03df237`](https://github.com/langchain-ai/deepagentsjs/commit/03df237385fbdfefd862076c5588eb39cb6e43c3),
[`84f3c0c`](https://github.com/langchain-ai/deepagentsjs/commit/84f3c0c2f1cad271191bcc138b84ba5b9c9205c9),
[`72cfb0c`](https://github.com/langchain-ai/deepagentsjs/commit/72cfb0c0384b30059b5e8028139a2e167c1be882),
[`04cc3fc`](https://github.com/langchain-ai/deepagentsjs/commit/04cc3fc26001ee566ed94de44c2dda2cf6adecc4),
[`18fbb48`](https://github.com/langchain-ai/deepagentsjs/commit/18fbb4839050e98ae3cfd36ec69b11f0725ad6d6),
[`e3d4b53`](https://github.com/langchain-ai/deepagentsjs/commit/e3d4b5367b1825df56c919b483ec4a3e117d631f)]:
  - deepagents@1.10.4
## deepagents@1.10.4

### Patch Changes

- [#551](https://github.com/langchain-ai/deepagentsjs/pull/551)
[`18557db`](https://github.com/langchain-ai/deepagentsjs/commit/18557db7bbdf92052ed5f994512fb70e11989e69)
Thanks [@antonnak](https://github.com/antonnak)! - fix(deepagents): gate
cache_control writes on per-call request.model

`createCacheBreakpointMiddleware` and `createMemoryMiddleware` were
gating
the Anthropic-specific `cache_control` write at agent-creation time
only.
When `modelFallbackMiddleware` swapped `request.model` to a
non-Anthropic
  provider mid-flight (e.g. on Anthropic 5xx), the marker leaked through
  and the fallback provider rejected the request with
  `400 Unknown parameter: 'cache_control'`. Both middlewares now also
check `isAnthropicModel(request.model)` inside `wrapModelCall`. Fixes
[#550](https://github.com/langchain-ai/deepagentsjs/issues/550).

- [#591](https://github.com/langchain-ai/deepagentsjs/pull/591)
[`773cac5`](https://github.com/langchain-ai/deepagentsjs/commit/773cac5dc7efc7843dd882642d91f7d64d6fde81)
Thanks [@colifran](https://github.com/colifran)! - chore(deepagents):
expose createSubAgent

- [#541](https://github.com/langchain-ai/deepagentsjs/pull/541)
[`1ca6dc9`](https://github.com/langchain-ai/deepagentsjs/commit/1ca6dc92fd40a6d845d24b95ba14b8f2643db394)
Thanks [@ixchio](https://github.com/ixchio)! - fix getMimeType to return
application/octet-stream for unknown file extensions instead of
text/plain

- [#572](https://github.com/langchain-ai/deepagentsjs/pull/572)
[`03df237`](https://github.com/langchain-ai/deepagentsjs/commit/03df237385fbdfefd862076c5588eb39cb6e43c3)
Thanks [@hntrl](https://github.com/hntrl)! - fix: scope CompositeBackend
grep/glob route fanout by search path

CompositeBackend now limits fallback route fanout to routes mounted
under the requested search path, instead of querying all routed backends
unconditionally.

This avoids unrelated routed backend calls (and side-effect errors) for
scoped searches like `path="/workspace"`, while preserving full fanout
behavior at root (`path="/"`).

- [#574](https://github.com/langchain-ai/deepagentsjs/pull/574)
[`84f3c0c`](https://github.com/langchain-ai/deepagentsjs/commit/84f3c0c2f1cad271191bcc138b84ba5b9c9205c9)
Thanks [@hntrl](https://github.com/hntrl)! - fix(deepagents): add
explicit browser and node entrypoints
  - add `deepagents/browser` and `deepagents/node` subpath exports
- route browser bundlers to the browser-safe bundle via the root
`browser` export condition
- avoid named Node builtin imports in backend utils that can break
browser builds
  - document browser guidance to import from `deepagents/browser`

- [#592](https://github.com/langchain-ai/deepagentsjs/pull/592)
[`72cfb0c`](https://github.com/langchain-ai/deepagentsjs/commit/72cfb0c0384b30059b5e8028139a2e167c1be882)
Thanks [@colifran](https://github.com/colifran)! - feat(quickjs):
implement default subagent primitive in code interpreter for
programmatic subagent calling

- [#566](https://github.com/langchain-ai/deepagentsjs/pull/566)
[`04cc3fc`](https://github.com/langchain-ai/deepagentsjs/commit/04cc3fc26001ee566ed94de44c2dda2cf6adecc4)
Thanks [@hntrl](https://github.com/hntrl)! - fix(deepagents): propagate
subagent `lc_agent_name` during task delegation
- Ensure `task` tool subagent invocations override
`metadata.lc_agent_name` with the selected `subagent_type`.
- Add regression coverage for both compiled subagents (`runnable`) and
standard subagent specs to verify tool-time metadata reflects the active
subagent.
- Update the `langsmith` peer dependency range in `deepagents` to
`^0.7.1`.

- [#595](https://github.com/langchain-ai/deepagentsjs/pull/595)
[`18fbb48`](https://github.com/langchain-ai/deepagentsjs/commit/18fbb4839050e98ae3cfd36ec69b11f0725ad6d6)
Thanks [@christian-bromann](https://github.com/christian-bromann)! -
fix(deepagents): count tokens once per model call in summarization
middleware

`createSummarizationMiddleware` counted tokens twice on every model
call—once
inside `truncateArgs` and again for the should-summarize check—even when
nothing was truncated or summarized. Count once and pass the total into
`truncateArgs`; recount only when truncation actually modifies messages.

- [#242](https://github.com/langchain-ai/deepagentsjs/pull/242)
[`e3d4b53`](https://github.com/langchain-ai/deepagentsjs/commit/e3d4b5367b1825df56c919b483ec4a3e117d631f)
Thanks [@alvedder](https://github.com/alvedder)! - feat(deepagents):
support direct skill paths as sources in createSkillsMiddleware
## @deepagents/evals@0.0.13

### Patch Changes

- Updated dependencies
[[`18557db`](https://github.com/langchain-ai/deepagentsjs/commit/18557db7bbdf92052ed5f994512fb70e11989e69),
[`773cac5`](https://github.com/langchain-ai/deepagentsjs/commit/773cac5dc7efc7843dd882642d91f7d64d6fde81),
[`1ca6dc9`](https://github.com/langchain-ai/deepagentsjs/commit/1ca6dc92fd40a6d845d24b95ba14b8f2643db394),
[`03df237`](https://github.com/langchain-ai/deepagentsjs/commit/03df237385fbdfefd862076c5588eb39cb6e43c3),
[`84f3c0c`](https://github.com/langchain-ai/deepagentsjs/commit/84f3c0c2f1cad271191bcc138b84ba5b9c9205c9),
[`72cfb0c`](https://github.com/langchain-ai/deepagentsjs/commit/72cfb0c0384b30059b5e8028139a2e167c1be882),
[`04cc3fc`](https://github.com/langchain-ai/deepagentsjs/commit/04cc3fc26001ee566ed94de44c2dda2cf6adecc4),
[`18fbb48`](https://github.com/langchain-ai/deepagentsjs/commit/18fbb4839050e98ae3cfd36ec69b11f0725ad6d6),
[`e3d4b53`](https://github.com/langchain-ai/deepagentsjs/commit/e3d4b5367b1825df56c919b483ec4a3e117d631f)]:
  - deepagents@1.10.4

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-17 15:05:26 -07:00
Christian Bromann 18fbb48390 fix(deepagents): count tokens once per model call in summarization middleware (#595)
## Summary
- Port
[langchain-ai/deepagents#3877](https://github.com/langchain-ai/deepagents/pull/3877):
`createSummarizationMiddleware` now counts tokens once per model call
instead of twice on the common pass-through path.
- Pass the precomputed total into `truncateArgs` via an optional
`totalTokens` parameter; recount only when truncation modifies messages.
- Add a regression test asserting `countTokensApproximately` runs
exactly once when nothing is truncated or summarized.
2026-06-12 17:26:50 -07:00
Colin Francis 61db938149 chore(quickjs): remove configurable concurrency and add subagents option with true default (#594)
### Summary

This PR remove the configurable concurrency option from code interpreter
middleware options and adds a subagents option that is true by default
2026-06-11 16:10:15 -07:00
Colin Francis 72cfb0c038 feat(quickjs): implement default task primitive in code interpreter for programmatic subagent calling (#592)
### Summary

This PR adds a default task primitive to the code interpreter that
allows the agent to natively write code to programmatically dispatch
subagents. The task primitive supports passing response schemas for
dynamic structured output that helps with more complex orchestration
patterns.

This PR also removes the swarm task tool in favor of the task primitive.

---------

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
2026-06-11 15:36:01 -07:00
Colin Francis 773cac5dc7 chore(deepagents): expose createSubAgent (#591)
### Summary

Exposes `createSubAgent` as a dedicated function which allows us to
reuse the inner subagent factory outside of the middleware (e.g. using
it as the single source of truth for defining subagents in quickjs).

Port of similar implementation from
https://github.com/langchain-ai/deepagents/pull/3846
2026-06-10 17:16:05 -07:00
Colin Francis 7ee3feb674 chore(quickjs): remove skills backend and associated plumbing (#590)
### Summary

Removes skills backend and associated plumbing from code interpreter
middleware and options
2026-06-10 11:53:13 -07:00
Alexei Vedernikov e3d4b5367b feat(deepagents): support direct skill paths as sources in createSkillsMiddleware (#242)
## Description

Previously, sources had to be parent directories (e.g. `/skills/`) whose
subdirectories each contained a SKILL.md. Passing a direct skill path
(e.g. `/skills/my-skill/`) had no effect because `listSkillsFromBackend`
scanned for subdirectories inside the source, found none, and returned
an empty list.

## Real case

The motivating scenario is when a curated list of skills organised as
individual directories under a shared directory. Each skill has a clear
responsibility, and different skills are intentionally assigned to the
orchestrator agent vs. subagents:

```typescript
// Desired: pass individual skill paths — one per capability
const SHARED_SKILLS = ['/skills/web-research/'];

const ORCHESTRATOR_SKILLS = [
  '/skills/requirement-completeness-validator/',
  '/skills/diff-risk-analyzer/',
];

createDeepAgent({
  skills: [...SHARED_SKILLS, ...ORCHESTRATOR_SKILLS],
  subagents: subagentsConfig.map(agentConfig => ({
    skills: [
      ...SHARED_SKILLS,
      ...agentConfig.skills,
    ]
  }))
});
```

The workaround would be to create nested directories like this:
```
skills/
  web-research/
    web-research/
      SKILL.md
  equirement-completeness-validator/
    equirement-completeness-validator/
      SKILL.md
  ...and so on
```

## What's done

Detection is done by inspecting the lsInfo() result of the source
directory: if a SKILL.md file appears directly in the listing, the
source itself is treated as the skill directory. Otherwise the existing
parent-directory scan runs unchanged.

The two modes can be freely mixed in the sources array:
```ts
sources: [
  '/skills/',               // parent dir: all subdirs with SKILL.md
  '/skills/my-skill/',      // direct path: SKILL.md at its root
 ]
 ```

---------

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
2026-06-07 14:08:52 -07:00
Anton Nak 18557db7bb fix(deepagents): gate cache_control writes on per-call request.model (#551)
Fixes #550.

## Problem

`createCacheBreakpointMiddleware` and `createMemoryMiddleware` write
Anthropic-specific `cache_control: { type: "ephemeral" }` markers into
the request payload. Both gate the write at **agent-creation time** in
`createDeepAgent` (whether the *primary* model is Anthropic). When
`modelFallbackMiddleware` swaps `request.model` to a non-Anthropic
provider at request time, the markers leak through and the fallback
provider rejects the request:

```
400 Unknown parameter: 'messages[0].content[N].cache_control'
```

Full root-cause writeup, production trace, and reproduction in #550.

## Fix

Move the model classification from boot-time to **per-call**, using the
existing `isAnthropicModel` helper (`src/utils.ts:9`).

- **`src/middleware/cache.ts`** — bail at the top of `wrapModelCall`
when `request.model` isn't Anthropic.
- **`src/middleware/memory.ts`** — AND the existing `addCacheControl`
flag with the same per-call check. `addCacheControl` keeps its current
public meaning (opt-in switch); the per-call gate is an additional
safety net.
- **`src/agent.ts`** — left untouched. The boot-time install gate stays
(small perf win when primary is non-Anthropic — middleware isn't
installed at all). The new per-call check handles the fallback case
where the middleware *is* installed but the model has been swapped.

## Tests

Each middleware's `.test.ts` got a `per-call provider gating` block.
They build a request with a `ChatAnthropic`-shaped stub vs a
`ChatOpenAI`-shaped stub on `request.model`, run `wrapModelCall`, and
assert `cache_control` is/isn't written. Also covers `ConfigurableModel`
with `modelProvider: "anthropic"` and the string forms
(`"anthropic:claude-..."`, `"openai:gpt-5"`).

Existing fixtures that didn't set `request.model` now pass a
`ChatAnthropic` stub so they keep exercising the write path — they were
previously relying on the unconditional behavior. No behavioral
assertions changed; only the fixture got more explicit.

31/31 tests pass on `libs/deepagents` (`cache.test.ts` +
`memory.test.ts`).

## Compatibility

- **No public API change.** `addCacheControl?: boolean` on
`MemoryMiddlewareOptions` keeps its existing semantics.
- **Anthropic-primary happy path unchanged** — same writes, same cache
hits.
- **Per-call cost:** one `getName()` / string check inside
`wrapModelCall`. Sub-microsecond.
- **Failure mode improvement:** users running `createDeepAgent` with an
Anthropic primary + non-Anthropic fallback no longer get a 400 from the
fallback provider on swap.

## Changeset

`patch` bump on `deepagents`.

## Out of scope

`request.modelSettings.cache_control` (written by LangChain core's
`anthropicPromptCachingMiddleware`) can also leak across the swap.
Mentioned in #550 for tracking — that's a LangChain-side fix, not
deepagents.

---------

Co-authored-by: Anton Nakaliuzhnyi <anakaliuzhnyi@gipartners.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 14:04:23 -07:00
Aman Pandey 1ca6dc92fd fix(deepagents): return application/octet-stream for unknown MIME types (#541)
Fixes #542.

`getMimeType()` falls back to `"text/plain"` for any extension not in
the `MIME_TYPES` lookup table. Since `isTextMimeType("text/plain")`
returns `true`, this means binary files (.zip, .exe, .wasm, .sqlite,
.pyc, .class, .jar, etc.) get treated as text everywhere downstream —
grep searches through them and returns garbage, read_file splits their
content on newlines and paginates it, and StateBackend can silently
corrupt binary data stored via createFileData().

The fix is straightforward: change the default to
`"application/octet-stream"`, which is what unknown binary data should
be. `isTextMimeType()` already returns `false` for it, so binary files
stop getting mangled.

To avoid breaking existing behavior for actual text files that were
previously relying on the fallback (like .txt, .ts, .py, .json, .js —
none of which had explicit entries), this also adds those to the
MIME_TYPES map directly. Covers ~67 common text/code extensions.

All 386 backend tests pass (10 files). The updated test expectations in
utils.test.ts verify both sides: known text extensions still resolve
correctly, and unknown/binary extensions now get
`application/octet-stream` instead of being misidentified as text.

---------

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
2026-06-02 13:44:48 -07:00
Hunter Lovell 5d266a213d refactor(node-vfs): make VfsSandbox filesystem-only (#575)
## Summary

This PR removes command-execution semantics from `@langchain/node-vfs`
and aligns `VfsSandbox` with `BackendProtocolV2` as a filesystem-only
backend.

The provider no longer uses sandbox execution abstractions and now
performs core file operations directly against the in-memory VFS.

## Changes

### Protocol alignment

- `VfsSandbox` now implements `BackendProtocolV2` directly instead of
extending sandbox/base-execution abstractions.
- Removed command execution from the provider surface (`execute` is no
longer part of this backend implementation).
- Removed `timeout` from `VfsSandboxOptions` and corresponding docs.

### Runtime behavior

- Added native backend implementations for:
  - `read`
  - `readRaw`
  - `write`
  - `edit`
  - `ls`
  - `grep`
  - `glob`
- Kept upload/download support and added path confinement handling for
invalid traversal paths.
- Continued in-memory VFS-only operation (no temp-dir shell sync path).

### Tests and docs

- Updated unit and integration tests to remove execute-focused
assertions and validate filesystem behavior.
- Updated package docs to describe `BackendProtocolV2` usage and removed
execute/timeout references.
- Added changeset for `@langchain/node-vfs`.
2026-06-02 19:47:14 +00:00
open-swe[bot] b7a5f26fd9 fix(quickjs): scope REPL prompt sandbox bullet to the runtime (#546)
Ports langchain-ai/deepagents#3528 to deepagentsjs.

The base `CodeInterpreterMiddleware` REPL prompt asserted "no
filesystem, no stdlib, no network, no real clock, no `fetch`, no
`require`". When `ptc` is configured, the same system prompt also
exposes a `tools.*` namespace whose members can include things like web
fetch, file I/O, or shell access — directly contradicting the sandbox
bullet.

A model reading both sections sees "no network" *and* `await
tools.webFetch({...})` in the same prompt. With PTC disabled it's even
worse: exposed tools are still reachable through the normal tool-calling
path *outside* `eval`, and the model could interpret the bullet as a
statement about the agent's capabilities rather than the REPL's.

This rewords the bullet to scope it to the QuickJS runtime, and notes
that external side effects from inside the REPL flow through `tools.*`
when it's exposed (otherwise the REPL is pure computation).
`@langchain/quickjs` middleware unit tests, lint, and format all pass
locally.

_Opened collaboratively by Mason Daugherty and open-swe._

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Mason Daugherty <61371264+mdrxy@users.noreply.github.com>
2026-06-02 10:41:20 -07:00
Hunter Lovell 84f3c0c2f1 fix(deepagents): add browser and node entrypoints (#574)
## Summary

Fixes #292, #543

This updates `deepagents` packaging to split environment-specific
exports and avoid browser build failures caused by Node-only imports in
the default bundle. Browser consumers now have an explicit
`deepagents/browser` entrypoint, while Node consumers can keep using
`deepagents` (or optionally `deepagents/node`) for the full runtime API.

## Changes

### `deepagents` package exports and entrypoints

- Added `src/browser.ts` as a browser-safe public barrel that excludes
Node-only APIs.
- Added `src/node.ts` as an explicit Node entrypoint that re-exports the
full API.
- Updated `package.json` exports to:
  - route the root `browser` condition to `./dist/browser.js`
  - expose `./browser` and `./node` subpath exports (ESM + CJS + types).
- Updated `tsdown` config to build `index`, `browser`, and `node`
outputs.

### Runtime import graph hardening

- Updated `createDeepAgent` to import `StateBackend` directly from
`backends/state` so it no longer pulls in the full Node-oriented
backends barrel.
- Updated `types.ts` to import `AnyBackendProtocol` from
`backends/protocol` instead of `backends/index`.
- Removed named Node builtin path imports from `backends/utils.ts` by
replacing `path.basename`/`path.extname` with local helpers.

### Documentation and release notes

- Added a README section documenting import guidance: browser apps
should use `deepagents/browser`, and Node apps can continue to use
`deepagents`.
- Added a patch changeset for `deepagents` describing the entrypoint and
packaging fix.
2026-06-02 10:32:55 -07:00
Hunter Lovell 03df237385 fix(deepagents): scope composite route search fanout by path (#572)
## Summary

Fixes #241.

This updates `CompositeBackend` search routing so scoped `grep`/`glob`
requests only fan out to routed backends mounted under the requested
path. Previously, non-route paths (for example `/workspace`) still
queried all routes, which could trigger unrelated backend errors.

## Changes

### `libs/deepagents/src/backends/composite.ts`

- Added route/path helper predicates to distinguish:
  - when a search path is inside a route,
  - when a route is a descendant of the requested search path.
- Updated `grep` fallback behavior to query the default backend plus
only descendant routes (instead of unconditional all-route fanout).
- Updated `glob` fallback behavior to use the same descendant-route
filtering.
- Normalized `grep` path handling to accept `null` and treat it as root
(`/`).
- Reused the same route-matching helper in `ls` for consistent prefix
matching semantics.

### `libs/deepagents/src/backends/composite.test.ts`

- Added regression test to ensure `grep("...", "/workspace")` does not
call unrelated routes (for example `/skills/`) while still searching
relevant descendant routes.
- Added regression test for equivalent `glob` behavior.

Co-authored-by: Christian Bromann <731337+christian-bromann@users.noreply.github.com>
2026-06-02 10:12:26 -07:00
github-actions[bot] c524561ad0 chore: version packages (#538)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## deepagents-acp@0.1.13

### Patch Changes

- Updated dependencies
\[[`bfb6eec`](https://github.com/langchain-ai/deepagentsjs/commit/bfb6eecdfe617645b3bdebf9a60d4b08e575cef7),
[`9c666ba`](https://github.com/langchain-ai/deepagentsjs/commit/9c666ba44adc1f8b428546c2191ea71d88b03998),
[`04cc3fc`](https://github.com/langchain-ai/deepagentsjs/commit/04cc3fc26001ee566ed94de44c2dda2cf6adecc4),
[`9221c8a`](https://github.com/langchain-ai/deepagentsjs/commit/9221c8a2b5236954f674e30f3ef0e2962f54fb56),
[`f6d3f13`](https://github.com/langchain-ai/deepagentsjs/commit/f6d3f13559bd2d9dfad63e379b59ad7577e828be)]:
    -   deepagents@1.10.3

## deepagents@1.10.3

### Patch Changes

- [#500](https://github.com/langchain-ai/deepagentsjs/pull/500)
[`bfb6eec`](https://github.com/langchain-ai/deepagentsjs/commit/bfb6eecdfe617645b3bdebf9a60d4b08e575cef7)
Thanks [@colifran](https://github.com/colifran)! - feat(quickjs): add
swarm task tool

- [#288](https://github.com/langchain-ai/deepagentsjs/pull/288)
[`9c666ba`](https://github.com/langchain-ai/deepagentsjs/commit/9c666ba44adc1f8b428546c2191ea71d88b03998)
Thanks [@christian-bromann](https://github.com/christian-bromann)! -
fix(deepagents): handle non-string content blocks in tool result
sizechecking

- [#566](https://github.com/langchain-ai/deepagentsjs/pull/566)
[`04cc3fc`](https://github.com/langchain-ai/deepagentsjs/commit/04cc3fc26001ee566ed94de44c2dda2cf6adecc4)
Thanks [@hntrl](https://github.com/hntrl)! - fix(deepagents): propagate
subagent `lc_agent_name` during task delegation
- Ensure `task` tool subagent invocations override
`metadata.lc_agent_name` with the selected `subagent_type`.
- Add regression coverage for both compiled subagents (`runnable`) and
standard subagent specs to verify tool-time metadata reflects the active
subagent.
- Update the `langsmith` peer dependency range in `deepagents` to
`^0.7.1`.

- [#549](https://github.com/langchain-ai/deepagentsjs/pull/549)
[`9221c8a`](https://github.com/langchain-ai/deepagentsjs/commit/9221c8a2b5236954f674e30f3ef0e2962f54fb56)
Thanks [@colifran](https://github.com/colifran)! - chore(deepagents):
move required ptc tools to metadata

- [#537](https://github.com/langchain-ai/deepagentsjs/pull/537)
[`f6d3f13`](https://github.com/langchain-ai/deepagentsjs/commit/f6d3f13559bd2d9dfad63e379b59ad7577e828be)
Thanks [@hntrl](https://github.com/hntrl)! - bump langsmith sdk version

## @langchain/quickjs@0.4.1

### Patch Changes

- [#545](https://github.com/langchain-ai/deepagentsjs/pull/545)
[`b3f0d6e`](https://github.com/langchain-ai/deepagentsjs/commit/b3f0d6e8fa2980652123e0053c116fc9945720ac)
Thanks [@colifran](https://github.com/colifran)! - chore(quickjs):
update swarm task tool to use withStructuredOutput

- [#500](https://github.com/langchain-ai/deepagentsjs/pull/500)
[`bfb6eec`](https://github.com/langchain-ai/deepagentsjs/commit/bfb6eecdfe617645b3bdebf9a60d4b08e575cef7)
Thanks [@colifran](https://github.com/colifran)! - feat(quickjs): add
swarm task tool

- [#549](https://github.com/langchain-ai/deepagentsjs/pull/549)
[`9221c8a`](https://github.com/langchain-ai/deepagentsjs/commit/9221c8a2b5236954f674e30f3ef0e2962f54fb56)
Thanks [@colifran](https://github.com/colifran)! - chore(deepagents):
move required ptc tools to metadata

## @deepagents/evals@0.0.12

### Patch Changes

- Updated dependencies
\[[`bfb6eec`](https://github.com/langchain-ai/deepagentsjs/commit/bfb6eecdfe617645b3bdebf9a60d4b08e575cef7),
[`9c666ba`](https://github.com/langchain-ai/deepagentsjs/commit/9c666ba44adc1f8b428546c2191ea71d88b03998),
[`04cc3fc`](https://github.com/langchain-ai/deepagentsjs/commit/04cc3fc26001ee566ed94de44c2dda2cf6adecc4),
[`9221c8a`](https://github.com/langchain-ai/deepagentsjs/commit/9221c8a2b5236954f674e30f3ef0e2962f54fb56),
[`f6d3f13`](https://github.com/langchain-ai/deepagentsjs/commit/f6d3f13559bd2d9dfad63e379b59ad7577e828be)]:
    -   deepagents@1.10.3

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Colin Francis <colin.francis@langchain.dev>
2026-06-01 14:09:00 -07:00
Hunter Lovell 04cc3fc260 fix(deepagents): propagate subagent lc_agent_name for delegated tasks (#566)
## Summary

Fixes #206.

This updates deepagents subagent delegation so tool executions can
reliably identify the active subagent via
`config.metadata.lc_agent_name` instead of inheriting the parent agent
name. It also adds focused regression tests that validate both compiled
subagents and standard subagent specs follow the same metadata behavior.

## Changes

### `libs/deepagents` subagent metadata propagation

- Updated `createTaskTool` subagent invocation config to explicitly set:
  - `metadata.lc_agent_name = subagent_type`
- existing `configurable.ls_agent_type = "subagent"` behavior remains
unchanged
- Added new regression coverage in `subagent.test.ts`:
  - compiled subagent (`runnable`) path
  - standard subagent spec (`systemPrompt/tools/model`) path
- Tests assert tool-time metadata receives the delegated subagent name
(`worker`), preventing parent-name leakage.

### `libs/deepagents` dependency range update

- Bumped `langsmith` peer dependency range in
`libs/deepagents/package.json` from `>=0.6.0 <1.0.0` to `^0.7.1`.
- Updated `pnpm-lock.yaml` accordingly.
2026-06-01 12:54:59 -07:00
Christian Bromann 9c666ba44a fix(deepagents): handle non-string content blocks in tool result sizechecking (#288)
Fixes #277

The tool result eviction logic in `processToolMessage` only checked
`content` when it was a plain string (`typeof msg.content ===
"string"`), which meant array-based content blocks (e.g. `[{ type:
"text", text: "..." }]`) bypassed the size limit entirely and were sent
back to the agent untruncated.

The fix uses the existing `BaseMessage.text` getter from
`@langchain/core`, which already handles both content formats:
- **String content**: returned as-is
- **Array content blocks**: joins all blocks with `type === "text"` into
a single string

This avoids introducing any new utility functions — the upstream API
already solves this.

## Changes

- Updated `processToolMessage()` in `fs.ts` to use `msg.text` instead of
directly checking `msg.content`
- Added 2 unit tests covering array-based content block eviction (large
and small)
2026-06-01 11:32:05 -07:00
Colin Francis 9221c8a2b5 chore(deepagents): move required ptc tools to metadata (#549)
This PR aligns SkillMetadata with the agent skills spec by removing the
top level required ptc tools field and keeps it contained within
metadata
2026-05-22 16:36:51 -07:00
Colin Francis b3f0d6e8fa chore(quickjs): update swarm task tool to use withStructuredOutput (#545)
### Summary

Switch JS swarm task tool to use withStructuredOutput instead of
hand-rolled bindTools + tool_calls extraction.

### Tests

- All 202 unit tests pass
- Removed normalizeSchema tests and bindTools-specific tests, replaced
with withStructuredOutput test using FakeToolCallingModel
2026-05-21 15:38:18 -07:00
Colin Francis bfb6eecdfe feat(quickjs): add swarm task tool (#500)
### Summary

Adds the swarm task tool to @langchain/quickjs and fixes skill module
loading for the agentskills.io spec, enabling parallel subagent dispatch
from inside the QuickJS code interpreter.

Swarm task tool (tools/swarm-task.ts) is a PTC-only tool that bridges
the code interpreter to the host runtime for subagent dispatch. It
supports two modes:
1. Direct model calls with structured output (invoke mode) for
classification/extraction tasks
2. Full agentic loops with tools (agent mode) for multi-step reasoning.
It handles schema normalization, model variant caching with TTL-based
sweeping, and structured output binding.

Spec-compliant entrypoint resolution — loadSkill() now resolves the
entrypoint from metadata.entrypoint (the agentskills.io extension point)
first, falling back to the legacy top-level module field. This lets
skills use spec-compliant frontmatter without a top-level module key.

Subdirectory entrypoint support — the QuickJS module normalizer now uses
the entrypoint's directory (not the skill root) when resolving relative
imports from a bare specifier. This fixes import { ... } from
"./sibling.js" when the entrypoint lives in a subdirectory like
scripts/index.ts.

Supporting changes include wiring skills metadata through the middleware
and session layers, extending the transform pipeline to strip import
type/export type declarations, adding requiredPtcTools validation, and
session improvements (extractToolText, stripLineNumbers, __sessionId__).

The swarm skill itself (table management, batching, filtering,
interpolation) is distributed separately and not included here.

### Tests
- 41 tests for the swarm task tool covering both dispatch modes, schema
normalization, variant caching and TTL sweeping, error handling, and
edge cases around model binding
- 3 new tests for entrypoint resolution (metadata.entrypoint preferred
over module, subdirectory relative imports)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-19 11:43:04 -07:00
Hunter Lovell f6d3f13559 chore(deepagents): bump langsmith sdk version (#537) 2026-05-15 16:00:10 -07:00
github-actions[bot] 163ee4949e chore: version packages (#532)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## deepagents-acp@0.1.12

### Patch Changes

- Updated dependencies
\[[`f088089`](https://github.com/langchain-ai/deepagentsjs/commit/f0880899ea6726b7320b0888d0f6a10a7749e1bf),
[`7c33a86`](https://github.com/langchain-ai/deepagentsjs/commit/7c33a8695f2e16217779bef5c6fca28230f18815)]:
    -   deepagents@1.10.2

## deepagents@1.10.2

### Patch Changes

- [#533](https://github.com/langchain-ai/deepagentsjs/pull/533)
[`f088089`](https://github.com/langchain-ai/deepagentsjs/commit/f0880899ea6726b7320b0888d0f6a10a7749e1bf)
Thanks [@vishnu-ssuresh](https://github.com/vishnu-ssuresh)! -
feat(deepagents): add `ContextHubBackend` for LangSmith Hub agent repos

- [#526](https://github.com/langchain-ai/deepagentsjs/pull/526)
[`7c33a86`](https://github.com/langchain-ai/deepagentsjs/commit/7c33a8695f2e16217779bef5c6fca28230f18815)
Thanks [@colifran](https://github.com/colifran)! - feat(deepagents):
implement harness profiles

## @deepagents/evals@0.0.11

### Patch Changes

- Updated dependencies
\[[`f088089`](https://github.com/langchain-ai/deepagentsjs/commit/f0880899ea6726b7320b0888d0f6a10a7749e1bf),
[`7c33a86`](https://github.com/langchain-ai/deepagentsjs/commit/7c33a8695f2e16217779bef5c6fca28230f18815)]:
    -   deepagents@1.10.2

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Colin Francis <colin.francis@langchain.dev>
2026-05-13 06:38:37 -07:00
Vishnu Suresh f0880899ea feat(deepagents): add ContextHubBackend backend (#533)
This ports Python deepagents PR #3338 behavior into the JS SDK by
introducing a new first-class backend: `ContextHubBackend`.

Why:
- Context Hub repo persistence is now available as an SDK backend in JS,
matching the Python backend architecture.
- This gives JS users a canonical LangSmith Hub-backed file backend with
the same operational semantics (lazy pull, commit chaining, cache
invalidation, batch upload behavior).

What changed:
- Added `ContextHubBackend` in
`libs/deepagents/src/backends/context-hub.ts`.
- Exported it from backend and root package exports.
- Added parity-focused unit tests in `context-hub.test.ts`.
- Added integration contract tests in `context-hub.int.test.ts` (gated
by `LANGSMITH_API_KEY`).
- Updated `deepagents` peer dependency on `langsmith` from `>=0.5.20` to
`>=0.6.0` to rely on Hub directory APIs (`pullAgent` / `pushAgent`).
- Added a changeset for release notes.

Behavior highlights:
- Missing repo on pull is treated as empty and lazily created on first
write.
- In-memory file cache with linked-entry tracking (`getLinkedEntries`).
- Commit hash tracking with optimistic `parentCommit` chaining.
- Cache invalidation on mutating Hub failures.
- `uploadFiles` commits all valid UTF-8 files in a single batch commit
and returns per-file success/error.

Validation run:
- `pnpm install`
- `pnpm exec oxfmt --write ...` (touched files)
- `pnpm --filter deepagents exec oxlint ...` (touched files)
- `pnpm --filter deepagents exec vitest run
src/backends/context-hub.test.ts` (33 passed)
- `pnpm --filter deepagents exec vitest run --mode int
src/backends/context-hub.int.test.ts` (skipped without
`LANGSMITH_API_KEY`)
2026-05-12 09:47:52 -07:00
Colin Francis 7c33a8695f feat(deepagents): implement harness profiles (#526)
### Summary

Introduces harness profiles which is a way to declaratively control how
agents behave at runtime without changing which model is used. A profile
can override the system prompt, hide tools, add or remove middleware,
and configure the general-purpose subagent. Profiles are registered by
provider or model key ("anthropic", "openai:gpt-5.4") and looked up
automatically when `createDeepAgent` is called.

The system ships with built-in profiles for Anthropic Opus 4.7, Sonnet
4.6, Haiku 4.5, and OpenAI Codex that include vendor-recommended
prompting guidance. Users can register their own profiles on top and
registrations merge additively so provider-wide defaults compose with
model-specific overrides.

Profiles are plain frozen objects with Zod schemas for parsing from
JSON/YAML config files, including prototype-pollution protection for
untrusted input.

### Tests

Unit tests cover key validation, profile construction and freezing,
serialization round-trips, poison-key rejection, merge semantics across
all field types, registry lookup with provider fallback, and prompt
overlay behavior. Built-in profiles are tested for correct registration
and expected content.

Also verified end-to-end via a standalone script against LangSmith and
confirmed the custom suffix appears in the system prompt and excluded
tools are absent from the model call.
  
### Usage Example
```ts
import { HumanMessage } from "@langchain/core/messages";
import { createDeepAgent, registerHarnessProfile } from "deepagents";

registerHarnessProfile("anthropic:claude-sonnet-4-6", {
  systemPromptSuffix: "Always respond in exactly one sentence.",
  excludedTools: ["grep"],
  generalPurposeSubagent: {
    description: "A customized GP subagent via harness profile.",
  },
});

const agent = createDeepAgent({
  model: "anthropic:claude-sonnet-4-6",
});

const result = await agent.invoke({
  messages: [new HumanMessage("What is the capital of France?")],
});

const lastMessage = result.messages[result.messages.length - 1];
console.log("Response:", lastMessage.content);
```
2026-05-11 14:57:29 -07:00
github-actions[bot] c231aed3ee chore: version packages (#525)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @langchain/quickjs@0.4.0

### Minor Changes

- [#531](https://github.com/langchain-ai/deepagentsjs/pull/531)
[`a76b7df`](https://github.com/langchain-ai/deepagentsjs/commit/a76b7df62310e7f2dd49bb1ea5f1b3ee6c8590b6)
Thanks [@colifran](https://github.com/colifran)! - chore(quickjs):
update `REPLMiddleware` to be named `CodeInterpreterMiddleware`

### Patch Changes

- [#524](https://github.com/langchain-ai/deepagentsjs/pull/524)
[`2cbd524`](https://github.com/langchain-ai/deepagentsjs/commit/2cbd5245a43fb1ba97fa532c1942a8903e090cfa)
Thanks [@colifran](https://github.com/colifran)! - fix(quickjs):
individual repl sessions use individual wasm module causing inefficient
memory usage

## deepagents-acp@0.1.11

### Patch Changes

- Updated dependencies
\[[`f164f99`](https://github.com/langchain-ai/deepagentsjs/commit/f164f992e06a157573612fb2640232f44d9daa18)]:
    -   deepagents@1.10.1

## deepagents@1.10.1

### Patch Changes

- [#479](https://github.com/langchain-ai/deepagentsjs/pull/479)
[`f164f99`](https://github.com/langchain-ai/deepagentsjs/commit/f164f992e06a157573612fb2640232f44d9daa18)
Thanks [@ramon-langchain](https://github.com/ramon-langchain)! -
feat(deepagents): add snapshot/start/stop lifecycle to LangSmithSandbox

## @deepagents/evals@0.0.10

### Patch Changes

- Updated dependencies
\[[`f164f99`](https://github.com/langchain-ai/deepagentsjs/commit/f164f992e06a157573612fb2640232f44d9daa18)]:
    -   deepagents@1.10.1

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Colin Francis <colin.francis@langchain.dev>
2026-05-11 14:32:28 -07:00
Colin Francis a76b7df623 chore(quickjs): update REPLMiddleware to be named CodeInterpreterMiddleware (#531)
### Summary

This PR updates `REPLMiddleware` to `CodeInterpreterMiddleware`
2026-05-11 13:02:54 -07:00
Ramon Nogueira f164f992e0 feat(deepagents): add snapshot/start/stop lifecycle to LangSmithSandbox (#479)
## Summary

Expose the new LangSmith sandbox snapshot and lifecycle APIs (landed in
`langsmith@0.5.20`) through the `LangSmithSandbox` wrapper.

- New methods on `LangSmithSandbox`: `start()`, `stop()`,
`captureSnapshot()`
- `LangSmithSandbox.create()` now accepts `snapshotId` (preferred) or
`templateName` (deprecated); throws if neither is provided
- Re-export upstream types as `LangSmithSnapshot`,
`LangSmithCaptureSnapshotOptions`, `LangSmithStartSandboxOptions`
- Bump `langsmith` peer dep to `>=0.5.20`
- Update the example to boot from `LANGSMITH_SANDBOX_SNAPSHOT_ID`

## Test plan

- [x] Unit tests: added coverage for `start()`, `stop()`,
`captureSnapshot()`; 41/41 pass
- [x] Type-check clean
- [x] Dev smoke test against `dev.api.smith.langchain.com` — create from
snapshot, execute, stop, start, execute after restart all working

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Ramon Nogueira <270434257+ramon-langchain@users.noreply.github.com>
Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
2026-05-08 18:36:11 +00:00
Colin Francis 2cbd5245a4 fix(quickjs): individual repl sessions use individual wasm module causing inefficient memory usage (#524)
### Summary

This PR optimizes memory usage by allowing us to use a single WASM
module. To do this we needed to fix two failure modes that occur when
multiple sessions share a single WASM module. Both are caused by the
async module loader creating asyncify suspensions (unwind/rewind cycles
on a module-global stack buffer) during import resolution.

__Failure 1__: Concurrent eval crash. The asyncify variant allows only
one async operation per module at a time. If two sessions eval
simultaneously and both hit an import, the second eval tries to suspend
asyncify while the first is already suspended. This crashes with
QuickJSAsyncifySuspended: Already suspended.
Fix: AsyncEvalQueue queues evalCodeAsync calls so only one runs at a
time.

__Failure 2__: Silent disposal corruption. When a session imports a
multi-file skill (e.g. an entry point that imports greet.js and
shout.js), each import causes an asyncify unwind/rewind cycle. The eval
succeeds. But when the session's runtime is disposed, the disposal does
not fully reset the module's asyncify stack buffer and the unwind/rewind
cycles left residual state (saved stack frames, rewind pointers) that
emscripten manages at the module level, not the runtime level. The next
session creates a fresh runtime on the same module, but the corrupted
asyncify state causes module loader callbacks to silently never fire.
Fix: synchronous module loader. Skill files are preloaded into a Map
before eval starts. The loader callback does a plain map.get(). No
await, no asyncify suspension, no residual state on disposal.

Note: The eval queue alone does not fix failure 2. The corruption
happens at runtime disposal, which runs outside the queue. Both fixes
are required.

#### What This PR Adds
- Replaces per-session WASM module instantiation with a process-global
singleton shared by all sessions. Each session still gets its own
runtime and context (full isolation); only the underlying WASM module is
shared. Reduces WASM memory from ~16 MB per session to ~16 MB total.
- Adds AsyncEvalQueue to serialize evalCodeAsync calls across sessions,
enforcing the asyncify one-concurrent-async-call-per-module constraint.
- Makes the module loader synchronous by preloading skill files into an
in-memory cache before eval (preloadReferencedSkills). Why is this
needed? An async module loader causes asyncify suspensions on each
import. Disposing a runtime after multi-file skill imports corrupts the
shared module's asyncify state and silently breaks the loader for all
subsequent sessions. The sync loader eliminates asyncify suspensions
from imports entirely.

#### Synchronous Module Loading

As stated above, synchronous module loading is a necessary change due to
async module loading causing asyncify suspensions on each import which
corrupts the singleton WASM module's asyncify state which silently
breaks the loader for all subsequent sessions. The following
demonstrates the before and after regarding this change:

__Before__:
User code: `import { run } from "@/skills/demo"`

1. eval() is called
2. evalCodeAsync() runs the code
3. QuickJS hits the import, calls the module loader callback
4. The callback is async: await ensureSkillLoaded("demo")
   → fetches /skills/demo/index.js from the backend (network I/O)
   → this await causes the first asyncify suspension in the WASM module
5. index.js has: import { greet } from "./greet.js"
6. QuickJS calls the loader again for greet.js
   → await ensureSkillLoaded() → network fetch
   → The second asyncify suspension in the WASM module is hit
7. index.js has: import { shout } from "./shout.js"
8. QuickJS calls the loader again for shout.js
   → await ensureSkillLoaded() → network fetch
   → third asyncify suspension in the WASM module is hit
9. eval completes, runtime is disposed
10. runtime.dispose() is called to clean up the session
11. The runtime disposal does NOT fully reset the module's asyncify
stack buffer. The 3 unwind/rewind cycles left residual state (saved
stack frames, rewind pointers, etc.) that the dispose path doesn't know
to clean up, because asyncify bookkeeping is managed by emscripten at
the module level, not by QuickJS at the runtime level.
12. Next session creates a fresh runtime on the same module, but the
module's asyncify machinery is corrupted. When QuickJS tries to call the
new session's module loader, the stale asyncify state causes the
callback to silently not fire. No crash, no error. Imports just resolve
to nothing.

__After__:
User code: `import { run } from "@/skills/demo"`

1. eval() is called
2. preloadReferencedSkills() runs BEFORE evalCodeAsync():
   → scans source code for "@/skills/*" specifiers
   → finds "demo"
   → fetches all 3 files from the backend into a Map:
     "@/skills/demo"          → source code
     "@/skills/demo/greet.js" → source code
     "@/skills/demo/shout.js" → source code
   → (this is async but happens OUTSIDE the WASM module so no asyncify)
3. evalCodeAsync() runs the code
4. QuickJS hits the import, calls the module loader callback
5. The callback is sync: map.get("@/skills/demo") → returns source
immediately
   → NO asyncify suspension
6. QuickJS resolves greet.js → map.get("@/skills/demo/greet.js") →
immediate
   → NO asyncify suspension
7. QuickJS resolves shout.js → map.get("@/skills/demo/shout.js") →
immediate
   → NO asyncify suspension
8. eval completes, runtime is disposed
9. Zero asyncify suspensions occurred → no residual state → module is
clean
10. Next session works perfectly

### Tests

- 4 new AsyncEvalQueue unit tests: serialization (no interleaving of
concurrent ops), return values, error isolation (rejected op doesn't
break queue), insertion order preservation
- All 160 existing tests pass (session, skills, middleware, transform,
utils, eval queue)

### Memory Benchmarking

#### Per-session module (before)

| Sessions | RSS Delta (MB) | Per-Session RSS (MB) | WASM Memory (MB) |
Module Init (ms) | Setup (ms) |

|----------|----------------|----------------------|------------------|------------------|------------|
| 1 | 0.53 | 0.53 | 16 | 11.4 | 15.9 |
| 5 | 2.13 | 0.43 | 80 | 30.2 | 37.9 |
| 10 | 5.28 | 0.53 | 160 | 31.1 | 42.8 |
| 15 | 5.53 | 0.37 | 240 | 57.4 | 72.1 |
| 20 | 6.80 | 0.34 | 320 | 73.6 | 91.1 |

---

#### Singleton (after)

| Sessions | RSS Delta (MB) | Per-Session RSS (MB) | WASM Memory (MB) |
Module Init (ms) | Setup (ms) |

|----------|----------------|----------------------|------------------|------------------|------------|
| 1 | 0.61 | 0.61 | 16 | 6.7 | 9.1 |
| 5 | 0.59 | 0.12 | 16 | 12.5 | 28.5 |
| 10 | 0.91 | 0.09 | 16 | 12.2 | 37.0 |
| 15 | 1.81 | 0.12 | 16 | 12.0 | 45.1 |
| 20 | 1.70 | 0.09 | 16 | 10.4 | 50.4 |

---

#### Comparison at 20 sessions (realistic workload)

| Metric                 | Before  | After  | Improvement     |
|------------------------|---------|--------|-----------------|
| WASM virtual memory    | 320 MB  | 16 MB  | 20x reduction   |
| RSS delta              | 6.80 MB | 1.70 MB| 4x reduction    |
| Module instantiation   | 73.6 ms | 10.4 ms| 7x reduction    |
| Setup time             | 91.1 ms | 50.4 ms| 1.8x reduction  |
2026-05-06 15:43:23 -07:00
github-actions[bot] 6da7007e52 chore: version packages (#521)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## deepagents@1.10.0

### Minor Changes

- [#458](https://github.com/langchain-ai/deepagentsjs/pull/458)
[`b1e1b7b`](https://github.com/langchain-ai/deepagentsjs/commit/b1e1b7bd3bcc3bd5b03dd461e72559ed69c77e22)
Thanks [@christian-bromann](https://github.com/christian-bromann)! -
feat(deepagents): new events streaming

## @langchain/quickjs@0.3.0

### Minor Changes

- [#520](https://github.com/langchain-ai/deepagentsjs/pull/520)
[`2548954`](https://github.com/langchain-ai/deepagentsjs/commit/254895457fce2de7df4547ebcf825d60868bacce)
Thanks [@colifran](https://github.com/colifran)! - chore(quickjs):
rename to REPLMiddleware and adjust defaults

## deepagents-acp@0.1.10

### Patch Changes

- Updated dependencies
\[[`b1e1b7b`](https://github.com/langchain-ai/deepagentsjs/commit/b1e1b7bd3bcc3bd5b03dd461e72559ed69c77e22)]:
    -   deepagents@1.10.0

## @deepagents/evals@0.0.9

### Patch Changes

- Updated dependencies
\[[`b1e1b7b`](https://github.com/langchain-ai/deepagentsjs/commit/b1e1b7bd3bcc3bd5b03dd461e72559ed69c77e22)]:
    -   deepagents@1.10.0

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-05 16:00:39 -07:00
Christian Bromann b1e1b7bd3b feat(deepagents): support new streaming features (currently experimental in LG.js) (#458)
This patch adopts the new streaming primitives we have implemented in
LangGraph.js for Deep Agent.

LangGraph.js PR: https://github.com/langchain-ai/langgraphjs/pull/2312
LangChain.js PR: https://github.com/langchain-ai/langchainjs/pull/10697
2026-05-05 15:59:20 -07:00
Colin Francis 254895457f chore(quickjs): rename to REPLMiddleware and adjust defaults (#520)
### Summary

- Rename `createQuickJSMiddleware` → `createREPLMiddleware` and
`QuickJSMiddlewareOptions` → `REPLMiddlewareOptions` to match the Python
`REPLMiddleware` naming
- Rename middleware registration from `"QuickJSMiddleware"` →
`"REPLMiddleware"`
- Rename default tool name from `"js_eval"` → `"eval"`, now configurable
via `toolName` option
- Add `captureConsole` option (default `true`) to toggle console output
capture
- Align default memory limit to 64 MiB (was 50 MiB) and timeout to 5s
(was 30s) to match Python

### Tests

- All 156 existing unit tests pass with updated references
- Updated `middleware.test.ts`, `middleware.int.test.ts`, and example
files to use new names

---------

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
2026-05-04 15:33:17 -07:00
github-actions[bot] 9a8ff1941a chore: version packages (#444)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## deepagents-acp@0.1.9

### Patch Changes

- [#501](https://github.com/langchain-ai/deepagentsjs/pull/501)
[`5b0eaea`](https://github.com/langchain-ai/deepagentsjs/commit/5b0eaea7b20461414983b71ba08d26d078b49214)
Thanks [@sukhmanghotraa](https://github.com/sukhmanghotraa)! - fix: bump
@langchain/core to ^1.1.42 across all workspace packages

- Updated dependencies
\[[`5b0eaea`](https://github.com/langchain-ai/deepagentsjs/commit/5b0eaea7b20461414983b71ba08d26d078b49214),
[`e90171a`](https://github.com/langchain-ai/deepagentsjs/commit/e90171abe4bcc76767246be470a7b17b94692f41),
[`8fd575f`](https://github.com/langchain-ai/deepagentsjs/commit/8fd575f06ca27cb0bef1a649aa34124a2c04ddd3),
[`3657941`](https://github.com/langchain-ai/deepagentsjs/commit/3657941ea36b21b9b512c1eb68a250ae79124383),
[`998d772`](https://github.com/langchain-ai/deepagentsjs/commit/998d772a07acc76fcc0d419e65b3c74a64d9ac52),
[`55f3bd8`](https://github.com/langchain-ai/deepagentsjs/commit/55f3bd8d74cac22d124fd6d1b11538dc2c2c2aec),
[`79e20e1`](https://github.com/langchain-ai/deepagentsjs/commit/79e20e18082a19b65094b953cd857908a7525801),
[`2442d7d`](https://github.com/langchain-ai/deepagentsjs/commit/2442d7d080c8a1008197eda526de52400303dd72),
[`43cd121`](https://github.com/langchain-ai/deepagentsjs/commit/43cd121133562abf0dee76c6db01f2bde0eb3fd3),
[`2994444`](https://github.com/langchain-ai/deepagentsjs/commit/2994444f32a6c0503defa6157652e742361abb00)]:
    -   deepagents@1.9.1

## deepagents@1.9.1

### Patch Changes

- [#501](https://github.com/langchain-ai/deepagentsjs/pull/501)
[`5b0eaea`](https://github.com/langchain-ai/deepagentsjs/commit/5b0eaea7b20461414983b71ba08d26d078b49214)
Thanks [@sukhmanghotraa](https://github.com/sukhmanghotraa)! - fix: bump
@langchain/core to ^1.1.42 across all workspace packages

- [#442](https://github.com/langchain-ai/deepagentsjs/pull/442)
[`e90171a`](https://github.com/langchain-ai/deepagentsjs/commit/e90171abe4bcc76767246be470a7b17b94692f41)
Thanks [@christian-bromann](https://github.com/christian-bromann)! -
fix(deepagents): closer align store backend with Python

- [#496](https://github.com/langchain-ai/deepagentsjs/pull/496)
[`8fd575f`](https://github.com/langchain-ai/deepagentsjs/commit/8fd575f06ca27cb0bef1a649aa34124a2c04ddd3)
Thanks [@colifran](https://github.com/colifran)! - feat(deepagents):
implement functional skills for quickjs middleware

- [#448](https://github.com/langchain-ai/deepagentsjs/pull/448)
[`3657941`](https://github.com/langchain-ai/deepagentsjs/commit/3657941ea36b21b9b512c1eb68a250ae79124383)
Thanks [@ItayCoCo](https://github.com/ItayCoCo)! - fix: follow symlinks
in sandbox find commands by adding -L flag to find invocations in
buildLsCommand, buildFindCommand, and buildGrepCommand

- [#486](https://github.com/langchain-ai/deepagentsjs/pull/486)
[`998d772`](https://github.com/langchain-ai/deepagentsjs/commit/998d772a07acc76fcc0d419e65b3c74a64d9ac52)
Thanks [@colifran](https://github.com/colifran)! - feat(quickjs): remove
built-in VFS globals, add PTC instance injection and StateBackend
read-your-writes

- [#470](https://github.com/langchain-ai/deepagentsjs/pull/470)
[`55f3bd8`](https://github.com/langchain-ai/deepagentsjs/commit/55f3bd8d74cac22d124fd6d1b11538dc2c2c2aec)
Thanks [@jacoblee93](https://github.com/jacoblee93)! - Adds agent type
metadata prop to configurable

- [#451](https://github.com/langchain-ai/deepagentsjs/pull/451)
[`79e20e1`](https://github.com/langchain-ai/deepagentsjs/commit/79e20e18082a19b65094b953cd857908a7525801)
Thanks [@JadenKim-dev](https://github.com/JadenKim-dev)! - remove
unconditional @langchain/anthropic import

- [#465](https://github.com/langchain-ai/deepagentsjs/pull/465)
[`2442d7d`](https://github.com/langchain-ai/deepagentsjs/commit/2442d7d080c8a1008197eda526de52400303dd72)
Thanks [@hntrl](https://github.com/hntrl)! - fix(deepagents): route
summarization through active request model

- [#492](https://github.com/langchain-ai/deepagentsjs/pull/492)
[`43cd121`](https://github.com/langchain-ai/deepagentsjs/commit/43cd121133562abf0dee76c6db01f2bde0eb3fd3)
Thanks [@colifran](https://github.com/colifran)! - implement file system
permissions for fs middleware tools

- [#459](https://github.com/langchain-ai/deepagentsjs/pull/459)
[`2994444`](https://github.com/langchain-ai/deepagentsjs/commit/2994444f32a6c0503defa6157652e742361abb00)
Thanks [@open-swe](https://github.com/apps/open-swe)! - fix(deepagents):
skill loading should default to 1000 lines

## @langchain/quickjs@0.2.6

### Patch Changes

- [#501](https://github.com/langchain-ai/deepagentsjs/pull/501)
[`5b0eaea`](https://github.com/langchain-ai/deepagentsjs/commit/5b0eaea7b20461414983b71ba08d26d078b49214)
Thanks [@sukhmanghotraa](https://github.com/sukhmanghotraa)! - fix: bump
@langchain/core to ^1.1.42 across all workspace packages

- [#496](https://github.com/langchain-ai/deepagentsjs/pull/496)
[`8fd575f`](https://github.com/langchain-ai/deepagentsjs/commit/8fd575f06ca27cb0bef1a649aa34124a2c04ddd3)
Thanks [@colifran](https://github.com/colifran)! - feat(deepagents):
implement functional skills for quickjs middleware

- [#486](https://github.com/langchain-ai/deepagentsjs/pull/486)
[`998d772`](https://github.com/langchain-ai/deepagentsjs/commit/998d772a07acc76fcc0d419e65b3c74a64d9ac52)
Thanks [@colifran](https://github.com/colifran)! - feat(quickjs): remove
built-in VFS globals, add PTC instance injection and StateBackend
read-your-writes

- [#498](https://github.com/langchain-ai/deepagentsjs/pull/498)
[`192bbd7`](https://github.com/langchain-ai/deepagentsjs/commit/192bbd7109817a826aa6bd982e16b54b5a5c8cb5)
Thanks [@colifran](https://github.com/colifran)! - fix(quickjs): bound
console buffering at capture time

- [#497](https://github.com/langchain-ai/deepagentsjs/pull/497)
[`79dcf9a`](https://github.com/langchain-ai/deepagentsjs/commit/79dcf9ae4567fcce71ea7e529f332baf6a3d6dcd)
Thanks [@colifran](https://github.com/colifran)! - feat(quickjs): add
maxPtcCallsbudget for ptc calls

- [#492](https://github.com/langchain-ai/deepagentsjs/pull/492)
[`43cd121`](https://github.com/langchain-ai/deepagentsjs/commit/43cd121133562abf0dee76c6db01f2bde0eb3fd3)
Thanks [@colifran](https://github.com/colifran)! - implement file system
permissions for fs middleware tools

- [#494](https://github.com/langchain-ai/deepagentsjs/pull/494)
[`e64c7e3`](https://github.com/langchain-ai/deepagentsjs/commit/e64c7e31a7e62929d5d2a9048ad7df3315a546cd)
Thanks [@colifran](https://github.com/colifran)! - feat(quickjs):
implement delete session in after agent hook to clean up completed repl
sessions

- [#499](https://github.com/langchain-ai/deepagentsjs/pull/499)
[`352e487`](https://github.com/langchain-ai/deepagentsjs/commit/352e4876679fb708d9690ffeab82363ba02677dc)
Thanks [@hntrl](https://github.com/hntrl)! - fix(quickjs): add
ls_code_input_language metadata to js_eval tool

## @deepagents/evals@0.0.8

### Patch Changes

- Updated dependencies
\[[`5b0eaea`](https://github.com/langchain-ai/deepagentsjs/commit/5b0eaea7b20461414983b71ba08d26d078b49214),
[`e90171a`](https://github.com/langchain-ai/deepagentsjs/commit/e90171abe4bcc76767246be470a7b17b94692f41),
[`8fd575f`](https://github.com/langchain-ai/deepagentsjs/commit/8fd575f06ca27cb0bef1a649aa34124a2c04ddd3),
[`3657941`](https://github.com/langchain-ai/deepagentsjs/commit/3657941ea36b21b9b512c1eb68a250ae79124383),
[`998d772`](https://github.com/langchain-ai/deepagentsjs/commit/998d772a07acc76fcc0d419e65b3c74a64d9ac52),
[`55f3bd8`](https://github.com/langchain-ai/deepagentsjs/commit/55f3bd8d74cac22d124fd6d1b11538dc2c2c2aec),
[`79e20e1`](https://github.com/langchain-ai/deepagentsjs/commit/79e20e18082a19b65094b953cd857908a7525801),
[`2442d7d`](https://github.com/langchain-ai/deepagentsjs/commit/2442d7d080c8a1008197eda526de52400303dd72),
[`43cd121`](https://github.com/langchain-ai/deepagentsjs/commit/43cd121133562abf0dee76c6db01f2bde0eb3fd3),
[`2994444`](https://github.com/langchain-ai/deepagentsjs/commit/2994444f32a6c0503defa6157652e742361abb00)]:
    -   deepagents@1.9.1

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Hunter Lovell <hunter@hntrl.io>
2026-05-04 09:43:36 -07:00
sukh 5b0eaea7b2 fix: bump @langchain/core to ^1.1.42 across all workspace packages (#501)
## Problem

When using `@langchain/google` as a model provider in the examples
workspace, the server crashes immediately with:

1. Runtime crash on startup:

    ```bash
    ERR_PACKAGE_PATH_NOT_EXPORTED: Package subpath './utils/uuid' is not
    defined by "exports" in @langchain/core/package.json
    ```

`@langchain/google` imports `@langchain/core/utils/uuid`, a subpath
added in `@langchain/core@1.1.42`. Both the examples workspace and
`libs/deepagents` were pinned to `^1.1.40` which does not export this
path.

 2. TypeScript type error after fixing the runtime crash:
 
    ```bash
Type 'ChatGoogle' is not assignable to type 'BaseLanguageModel<any,
BaseLanguageModelCallOptions>'
    ```
Even after bumping `@langchain/core` in `examples/` only, pnpm kept two
separate copies in its store - `1.1.40` for `deepagents` and `1.1.42`
for `@langchain/google`. TypeScript treats them as structurally
incompatible types because the type import paths differ.

## Fix

- Bump `@langchain/core` from `^1.1.40` → `^1.1.42` in all
`../package.json` files

## Testing

```bash
cd examples/research
pnpm dlx @langchain/langgraph-cli dev
# -> No ERR_PACKAGE_PATH_NOT_EXPORTED and agent starts correctly

---------

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
2026-05-01 15:41:53 -07:00
Hunter Lovell 352e487667 fix(quickjs): add ls_code_input_language metadata to js_eval tool (#499)
## Summary

Adds LangSmith code-language metadata to the QuickJS REPL evaluation
tool so tool inputs are correctly interpreted as JavaScript in traces.

## Changes

### @langchain/quickjs

- Added `metadata: { ls_code_input_language: "javascript" }` to the
`js_eval` tool definition in `createQuickJSMiddleware`.
- Extended middleware tool-registration tests to assert that `js_eval`
exposes `ls_code_input_language` metadata.
- Verified behavior with quickjs unit tests (`src/middleware.test.ts`).
2026-05-01 00:24:41 +00:00
Colin Francis 192bbd7109 fix(quickjs): bound console buffering at capture time (#498)
Port of https://github.com/langchain-ai/deepagents/pull/2999
2026-04-30 15:56:59 -07:00
Colin Francis 79dcf9ae45 feat(quickjs): add maxPtcCallsbudget for ptc calls (#497)
Port of https://github.com/langchain-ai/deepagents/pull/2994
2026-04-30 15:24:20 -07:00
Colin Francis 8fd575f06c feat(deepagents): implement functional skills for quickjs middleware (#496)
### Summary

Adds functional skill modules to the QuickJS REPL. Skills can now ship
JS/TS entrypoints via a module: frontmatter key on SKILL.md, which the
model dynamically imports at eval time with await
import("@/skills/<name>").

When skillsBackend is passed to createQuickJSMiddleware, the middleware
reads skillsMetadata from the current task state before each eval, scans
the source for skill references, and pushes the metadata + backend into
the session. The session wires a QuickJS module loader that lazily
fetches skill files from the backend, strips TypeScript syntax, and
caches the result for the lifetime of the session. Skills that are
referenced but not available on the agent short-circuit with a clear
error before evaluation starts.

On the deepagents side, SkillMetadata gains an optional module field
(validated and normalized from frontmatter), and formatSkillsList now
advertises importable skills in the system prompt with an await
import(...) hint.

```ts
const backend = new FilesystemBackend({ rootDir: "/project", virtualMode: true });

const agent = createDeepAgent({
  model: "claude-sonnet-4-6",
  backend,
  skills: ["/skills/"],
  middleware: [
    createQuickJSMiddleware({ skillsBackend: backend }),
  ],
});
```

### Tests

- Unit tests cover module path validation, TS syntax stripping, skill
loading (single/multi-file, error cases, bundle size cap), skill
reference scanning, module loader resolution and caching, and system
prompt formatting
- Ran an E2E eval that exercised the full pipeline from SKILL.md parse
through dynamic import and function call in the REPL, with a LangSmith
trace

### Benchmarks

#### memory: console_log concurrent
- Total time: 15820ms

| name | hz | min | max | mean | p75 | p99 | p995 | p999 | rme | samples
|

|--------------------------|---------|--------|--------|--------|--------|--------|--------|--------|--------|---------|
| 1 concurrent sessions | 145.91 | 1.8263 | 27.7702| 6.8536 | 9.1753 |
21.1492| 25.0420| 27.7702| ±5.30% | 730 |
| 8 concurrent sessions | 39.1773 | 15.5854| 61.5015| 25.5250| 27.8461|
49.0536| 61.5015| 61.5015| ±3.58% | 196 |
| 32 concurrent sessions | 13.9753 | 48.5504| 110.40 | 71.5547| 76.6394|
110.40 | 110.40 | 110.40 | ±3.72% | 70 |

---

#### memory: ptc_tools concurrent
- Total time: 16755ms

| name | hz | min | max | mean | p75 | p99 | p995 | p999 | rme | samples
|

|--------------------------|---------|--------|--------|--------|--------|--------|--------|--------|--------|---------|
| 1 concurrent sessions | 86.9205 | 4.1809 | 32.1833| 11.5048| 15.3222|
25.2676| 28.2697| 32.1833| ±4.76% | 435 |
| 8 concurrent sessions | 21.8310 | 33.5598| 69.0041| 45.8065| 50.8740|
60.2001| 69.0041| 69.0041| ±2.77% | 110 |
| 32 concurrent sessions | 7.0269 | 137.88 | 148.90 | 142.31 | 144.05 |
148.90 | 148.90 | 148.90 | ±0.70% | 36 |

---

#### throughput: single thread many iterations
- Total time: 31656ms

| name | hz | min | max | mean | p75 | p99 | p995 | p999 | rme | samples
|

|-------------------------------------------|--------|--------|--------|--------|--------|--------|--------|--------|--------|---------|
| 200 sequential evals (ptc + console.log) | 3.5897 | 240.92 | 347.19 |
278.58 | 289.81 | 341.02 | 347.19 | 347.19 | ±1.44% | 108 |
2026-04-30 13:13:40 -07:00
Colin Francis e64c7e31a7 feat(quickjs): implement delete session in after agent hook to clean up completed repl sessions (#494)
### Summary

ReplSession uses a static map to preserve QuickJS WASM runtime state
across js_eval calls within a run. Previously sessions were never
cleaned up, causing unbounded memory growth as each thread_id
accumulated a live WASM runtime for the lifetime of the process.

- Added ReplSession.deleteSession(key) to dispose of the QuickJS runtime
and removes the entry from the session map
- Added an afterAgent hook in createQuickJSMiddleware that calls
deleteSession for the current thread's session key at the end of each
agent run

Sessions still persist across all js_eval calls within a single run. The
map remains for correct concurrent thread isolation. Without it,
simultaneous runs from different threads would share a runtime.

### Tests

Unit tests covering the following scenarios:
- ReplSession.deleteSession disposes and removes an existing session
- ReplSession.deleteSession is a no-op for a key that does not exist
- afterAgent disposes the session for the finished thread
- afterAgent on a thread with no session does not throw
- afterAgent only removes the session for the finished thread, leaving
other active threads intact
2026-04-28 16:34:34 -07:00
Colin Francis 998d772a07 feat(quickjs): remove built-in VFS globals, add PTC instance injection and StateBackend read-your-writes (#486)
### Summary
- Removed built-in readFile/writeFile globals from the QuickJS REPL.
File I/O is now exclusively through PTC tools, keeping the REPL a pure
JS sandbox with no implicit side effects
- ptc now accepts StructuredToolInterface instances directly alongside
tool name strings. Custom tools can be injected into the REPL without
being registered on the agent
- StateBackend now provides read-your-writes semantics within a single
js_eval superstep by reading via __pregel_read with fresh=true. Pregel
already tracks pending sends in task.writes; asking for a fresh read
applies them through the reducer, removing the need for a manual write
buffer
- Removed ptc: boolean shorthand from QuickJSMiddlewareOptions; use the
array or object forms instead

### Tests
- Added 12 unit tests to state.test.ts covering write-then-read, chained
edits, ls/grep/glob/readRaw visibility, upload/download, duplicate write
error, edit-nonexistent, and superstep boundary behavior
(commitSends/clearPending)
- Expanded middleware.test.ts with PTC instance injection coverage
- Verified end-to-end with createDeepAgent + createQuickJSMiddleware
across 7 scenarios (write-read, write-edit-read, write-ls, write-grep,
write-glob, cross-eval, upload-download); traces confirmed in LangSmith

---------

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
2026-04-28 14:23:08 -07:00
Colin Francis 43cd121133 feat(deepagents): implement file system permissions for fs middleware tools (#492)
### Summary

- Adds a FilesystemPermission class and a permissions parameter to
createDeepAgent and SubAgent that controls which filesystem operations
each agent is allowed to perform
- Rules are evaluated first-match-wins with a permissive default; mode:
"deny" blocks the operation before any backend call
- Permissions are closed over at tool-creation time — no runtime config
threading, no ToolPolicy in langchain-core
- ls, glob, and grep enforce permissions in two passes: the base path
check throws early; results are post-filtered to strip entries the
caller can't read
- Subagents receive the parent agent's permissions by default; setting
permissions on a SubAgent is a full replacement, not a merge
- FilesystemPermission, FilesystemPermissionOptions,
FilesystemOperation, and PermissionMode are exported from the top-level
package entry point

### Tests

- permissions/types.test.ts — FilesystemPermission construction,
validation (rejects relative paths, .., ~), defaults
- permissions/enforce.test.ts — validatePath, globMatch (wildcards,
brace expansion, dotfiles), decidePathAccess (first-match-wins,
operation mismatch, multiple ops/paths)
- middleware/fs.permissions.test.ts — each fs tool (read, write, edit,
ls, glob, grep) with allow/deny rules and mock backends; verifies
backend is never called on a denied path; verifies execute is unaffected
- permissions/agent.permissions.test.ts —
CreateDeepAgentParams.permissions type and default; wiring to
createFilesystemMiddleware
- middleware/subagents.permissions.test.ts — SubAgent.permissions type;
?? resolution (inherit vs override vs own deny);
createFilesystemMiddleware behavior for each resolved-permissions case

---------

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
2026-04-28 14:13:00 -07:00
Jacob Lee 55f3bd8d74 feat(deepagents): Adds agent type metadata prop to configurable (#470)
Will be useful for trace display features

Python: https://github.com/langchain-ai/deepagents/pull/2788

---------

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
2026-04-17 22:03:59 -07:00
Hunter Lovell 2442d7d080 fix(deepagents): align summarization with active request model (#465)
## Summary

Fixes #398

Align deepagents summarization with the active request-time model path
instead of relying on a separate middleware-specific model resolution
path. This keeps summarization behavior consistent with the main agent
model selection flow and avoids divergence in provider/model handling
during middleware execution. The update also simplifies runtime behavior
by removing unnecessary explicit config threading for summary calls.

## Changes

### `deepagents` middleware/model routing

- Updated summarization middleware to prefer `request.model` as the
resolved model used for profile-derived limits and summary generation.
- Kept fallback model resolution support for cases where a request model
is not present.
- Removed explicit runtime config plumb-through in summary invocation,
relying on LangChain runnable context propagation.

### `deepagents` agent wiring

- Updated `createDeepAgent` built-in and subagent middleware wiring to
construct summarization middleware without explicitly passing a separate
model option, so summarization follows the active request model path.

### `deepagents` tests

- Added/updated summarization tests to cover request-model-based
summarization behavior and ensure middleware behavior remains stable
with the new routing path.
- Simplified test request construction to keep request-model assumptions
explicit.
2026-04-14 17:43:56 -07:00
ItayCoCo 3657941ea3 fix: follow symlinks in sandbox find commands (#448)
## Summary

- Add `-L` flag to `find` in `buildLsCommand`, `buildFindCommand`, and
`buildGrepCommand` so that symlinks are followed
- Fixes #447

## Problem

`BaseSandbox` helper functions use `find` without `-L`, which means
symbolic links are not dereferenced. On Modal (and potentially other
providers), volumes are mounted as symlinks, so the `ls`, `glob`, and
`grep` sandbox tools all return empty results when pointed at symlinked
paths.

## Fix

The `-L` flag tells `find` to follow symbolic links. This is a one-line
change in each of the three helper functions:

```diff
- find ${quotedPath} -maxdepth 1 ...
+ find -L ${quotedPath} -maxdepth 1 ...
```

This matches user expectations — filesystem exploration tools should
transparently follow symlinks, just like `ls` and `find -L` do in a
normal shell.

## Test plan

- [ ] Verify `ls` tool returns files when the target path is a symlink
- [ ] Verify `glob` tool traverses symlinked directories
- [ ] Verify `grep` tool searches inside symlinked directories
- [ ] Confirm no regression on non-symlinked paths (behavior is
identical when no symlinks are present)

---------

Co-authored-by: Itay Cohen <itaycohen@Itays-MacBook-Pro.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:36:01 -07:00
open-swe[bot] 2994444f32 fix: skill loading should default to 1000 lines (#459)
## Description
Ports the skill loading fix from the Python SDK
(langchain-ai/deepagents#2721) to JS. The system prompt now instructs
agents to pass `limit=1000` when reading skill files via `read_file`,
since the default of 100 lines is too small for most skill files.

## Test Plan
- [ ] Verify skill loading prompt includes `limit=1000` instruction

_Opened collaboratively by Sydney Runkle and open-swe._

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
2026-04-14 15:15:10 -07:00
Youngho Kim 79e20e1808 fix(deepagents): remove unconditional @langchain/anthropic import (#451)
## Summary

Fixes #443

- Removed static `import { ChatAnthropic } from "@langchain/anthropic"`
at module level
- Changed default `model` parameter from `new
ChatAnthropic("claude-sonnet-4-6")` to the string `"claude-sonnet-4-6"`

## Problem

`deepagents@1.9.0` unconditionally imported `@langchain/anthropic` at
the top of `agent.ts`. Bundlers follow static imports regardless of
which model the user actually uses, causing builds to fail for users who
only use other providers (e.g. `ChatOpenAI`) and don't have
`@langchain/anthropic` installed.

## Solution

`createAgent` from `langchain` natively accepts a model name string
(`string | AgentLanguageModelLike`), so no `ChatAnthropic` instantiation
is needed at the library level. With a string default, bundlers have no
static reference to `@langchain/anthropic` and can tree-shake it
entirely.

Users who want Anthropic models can either:
- Pass `new ChatAnthropic(...)` explicitly (requires
`@langchain/anthropic` in their own `package.json`)
- Rely on the `"claude-sonnet-4-6"` string default (also requires
`@langchain/anthropic` at runtime, but no longer breaks builds for
non-Anthropic users)

---------

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
2026-04-13 21:46:24 -07:00
Christian Bromann e90171abe4 fix(deepagents): closer align store backend with Python (#442)
Aligned `StoreBackend` in `libs/deepagents/src/backends/store.ts` more
closely with the Python version while keeping the current TS behavior
working:

- `namespace` now supports either a static `string[]` or a dynamic
factory, so callers can derive store namespaces from runtime
state/config instead of hardcoding them.
- Legacy namespace fallback now checks config metadata for
`assistant_id` / `assistantId` first, then falls back to the existing
injected `assistantId`, and finally to `["filesystem"]`.
- Added exported types for the new namespace factory context in
`libs/deepagents/src/backends/index.ts` and
`libs/deepagents/src/index.ts`.
2026-04-09 09:05:33 -07:00
github-actions[bot] 02c1c7fa38 chore: version packages (#433)
* chore: version packages

* cr

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Hunter Lovell <hunter@hntrl.io>
2026-04-07 08:48:53 -07:00