feat(cli): wire /tasks + /background on a session-scoped TaskManager#172
Merged
Conversation
The background-task infrastructure (TaskManager + TASK_TOOLS) existed but the manager was created per runAgent call (agent.ts), so tasks vanished after each turn and slash commands couldn't see them. Re-scope it to the REPL session so tasks persist and are visible to both the agent and the user. - core: TaskManager.setRunner() lets a host own a long-lived manager while the agent loop attaches its run-local sub-agent runner each turn (resolves named sub-agents + fires SubagentStop). Already-started tasks are unaffected. - core: RunAgentOptions.taskManager — when set, runAgent attaches its runner and exposes it on the tool context instead of making a per-run manager (the fallback, unchanged, keeps M1/headless/desktop behavior). - cli: REPL creates one session-scoped TaskManager (baseline runner handles /background started before the first turn) and threads it into every runAgent call + onto the slash-command SessionContext. - cli: /tasks lists this session's background tasks (id/status/description); /tasks <id> shows one's status + output. /background <prompt> (alias /bg) runs the prompt as a depth-1 background sub-agent via the manager. - docs: flip /background + /tasks to ✅ in BEHAVIOR_PARITY; /batch stays 🔄. Slice 1 (visibility) only. Moving the in-flight turn to the background (Ctrl+B parity) needs REPL concurrency and is scoped separately. Tests: setRunner re-targeting (core); /tasks + /background against a stub-backed TaskManager (cli, 10 cases). typecheck + lint + format:check + full suite green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Wires the
/tasksand/backgroundslash commands (both were 🔄 indocs/BEHAVIOR_PARITY.md) on top of the existing background-task infrastructure (TaskManager+TASK_TOOLS).The gap: the
TaskManagerwas constructed perrunAgentcall (agent.ts), so background tasks evaporated after each turn and nothing outside the agent loop (the REPL, slash commands) could see them. This re-scopes the manager to the REPL session so tasks persist across turns and are visible to both the agent and the user.This is slice 1 (visibility) — the foundation. Slice 2 (move the in-flight turn to the background,
Ctrl+Bparity) needs REPL concurrency and is scoped separately.How
@deepcode/coreTaskManager.setRunner()— lets a host own a long-lived (session-scoped) manager while the agent loop attaches its run-local sub-agent runner each turn. The rich runner resolves named sub-agents + firesSubagentStop. Tasks already started are unaffected (their handle is captured atcreate()time).RunAgentOptions.taskManager— when provided,runAgentcallssetRunner(...)on it and exposes it astoolCtx.tasksinstead of creating a per-run manager. When absent, the original per-run fallback is kept verbatim, so headless / desktop / library callers are unchanged.deepcode-cliTaskManagerfor the whole session and threads it into everyrunAgentcall (opts.taskManager) and onto the slash-commandSessionContext(ctx.tasks). Its baseline runner runs a prompt as a depth-1 sub-agent (clean context, no nested tasks; readsctx.model/ctx.modelive) — this only matters for/backgroundstarted before the first turn, after which the agent loop's richer runner takes over./tasks— lists this session's background tasks (id · status · description)./tasks <id>shows a single task's status + output./background <prompt>(alias/bg) — creates a background task that runs<prompt>as a sub-agent via the manager.docs — flip
/background+/tasksto ✅ inBEHAVIOR_PARITY.md;/batchstays 🔄 (batch-of-prompts not wired here — use/backgroundper prompt).Notes on behavior
TaskCreate) and tasks the user starts (via/background) show up in the same/taskslist.askUsercallback (matching the existing sub-agent path), so anask-verdict tool is returned to the sub-agent as a blocked tool result rather than blocking on the REPL prompt — no deadlock / interleaved prompts.AbortController, so it isn't tied to a turn's lifecycle and keeps running while the user is at the prompt (await rl.questionyields to the event loop).Testing
core:setRunnerre-targets the runner for subsequentcreate()calls.cli: newbackground-commands.test.ts(10 cases) drives/tasks+/backgroundagainst a stub-backedTaskManager— create / list /<id>output / aliases / usage / unavailable / runner-failure.format:check· core 643 · cli 155 · desktop 54 · lsp 8.CommandRegistryconfirms the rendered output for empty list, create,/bg, list-with-statuses,/tasks <id>, and usage.🤖 Generated with Claude Code