feat(deepagents): async agents experiments#299
feat(deepagents): async agents experiments#299Christian Bromann (christian-bromann) wants to merge 2 commits intomainfrom
Conversation
|
| ) { | ||
| res.statusCode = status; | ||
| res.setHeader("Content-Type", "application/json"); | ||
| res.end(JSON.stringify(body)); |
Check warning
Code scanning / CodeQL
Information exposure through a stack trace Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 4 days ago
In general, to fix information exposure through stack traces you should avoid sending raw exception data (messages, stacks, or entire error objects) back to clients. Instead, log the error server-side (where developers can inspect it) and respond to the client with a generic, non-sensitive error message and possibly a coarse error code.
For this codebase, the best minimal fix is to modify the /api/steer error handling so that it no longer returns error.message (or any other data derived from the original exception) to the client. Instead, it should:
- Log the full error (including stack) to the server console or logger.
- Return a fixed generic error payload, such as
{ error: "Invalid request payload" }or{ error: "Unable to process steer request" }, independent of the thrown error. - Keep all success responses unchanged and leave
sendJsonas a generic helper, since the issue here is how it’s used with error data, notJSON.stringifyitself.
Concretely, in libs/deepagents-ui/src/vite-server.ts, within the if (req.method === "POST" && url.pathname === "/api/steer") { ... } block, replace the catch block that builds the response from error.message with one that logs the error via console.error and sends a generic message. No new imports are needed, as console is globally available in Node.
| @@ -103,8 +103,10 @@ | ||
| const result = await attached.steer(input); | ||
| sendJson(res, 200, result); | ||
| } catch (error) { | ||
| // Log detailed error information on the server, but do not expose it to the client. | ||
| console.error("Error handling /api/steer request:", error); | ||
| sendJson(res, 400, { | ||
| error: error instanceof Error ? error.message : String(error), | ||
| error: "Unable to process steer request.", | ||
| }); | ||
| } | ||
| return; |
This PR adds an experimental observer/companion stack for long-running Deep Agents.
It introduces a session-scoped activity bus that lets external consumers inspect what a running agent is doing, plus an optional conversational companion agent that can answer questions about the run and queue lightweight steering commands.
Motivation
Long-running agents are hard to work with once they are in flight. Today, users can mostly do one of two things:
This change explores a middle ground:
The design is intentionally built around a shared session/event model rather than a single read-only observer abstraction, so it can later back UI tails, CLIs, websocket transports, and higher-level agent orchestration patterns.
What’s Included
Observer middleware
Adds
createObserverMiddleware()inlibs/deepagents/src/middleware/observer.ts.The middleware:
model_responseactivity events after model callstool_resultactivity events after tool callscontrol_appliedevents when commands are claimedThis is implemented as best-effort middleware so observation failures do not break the main run.
Session handle
Adds
createSessionHandle()inlibs/deepagents/src/observer/handle.ts.The session handle provides the non-LLM control/read API:
getSnapshot()for aggregated session/thread stategetEvents()for cursor-based activity pagingsend()for queueing steering commandsThis is the core primitive behind the feature.
Companion agent
Adds
createCompanionAgent()inlibs/deepagents/src/observer/agent.ts.The companion agent:
observe_agenttoolsteer_agenttool whenallowSteering: trueObserver tools
Adds
createObserveTool()andcreateSteerTool()inlibs/deepagents/src/observer/tool.ts.These tools expose:
Types and store helpers
Adds shared types and store helpers under
libs/deepagents/src/observer/.This includes:
ActivityEventControlCommandSessionSnapshotSessionEventPageSessionHandleExamples
Adds runnable examples in
examples/observer/:basic-companion.tsinteractive-companion.tsThese demonstrate:
API Overview
Middleware
Session handle
Companion agent
Current Limitations / Follow-ups
This implementation is a strong first slice, but a few areas are still follow-up work rather than fully complete behavior:
"active"targeting is currently lightweight and should become more precise once we have stronger active-thread tracking.thread_started,thread_completed,thread_failed) are defined in the model but not yet fully emitted, so running/idle inference can be improved.Why this direction
The important architectural choice here is making the primitive session-based and event-driven rather than coupling everything to a single observer agent.
That gives us:
Example Use Cases
Notes
This should be viewed as an experimental first pass at async observation + lightweight steering for Deep Agents, with the core abstractions now in place for follow-up work on subagent propagation, stronger control semantics, and more robust cross-thread concurrency handling.