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. C
Colin Francis committed
0971007ab2491e73eb1a78c5426ab934470d5620
Parent: 204cb27
Committed by GitHub <noreply@github.com>
on 6/18/2026, 1:27:35 PM