compat: handle claude code 2.1.x tool renames (Task→Agent, new Task* tools)#82
Merged
Conversation
…tools) Claude Code 2.1.150 renamed the subagent-spawning tool from `Task` to `Agent`, added a per-session task-tracking suite (`TaskCreate`, `TaskUpdate`, `TaskList`, `TaskGet`, `TaskStop`, `TaskOutput`) that replaces `TodoWrite`, and introduced `ScheduleWakeup` for `/loop` dynamic mode. Without changes: - Sub-agent panels stopped opening (engine + UI only matched `Task`). - New `Task*` tool calls fell through to the generic block with no context-aware rendering. - The model could call `ScheduleWakeup`, which Nerve has no `/loop` skill to consume — dead-end turns. Backend: - Set `disallowed_tools=["ScheduleWakeup"]` so the CLI strips it from the model's tool list entirely. - Track sub-agent lifecycle for both `Task` (history back-compat) and `Agent` (current). Frontend: - Route `Agent` to `SubagentToolBlock` (keep `Task` for old history). - New `CCTaskToolBlock` renders the six `Task*` tools as compact cards. - `TodoPanel` now also displays Claude Code 2.1+ tasks (with id badges), reconciled live by an incremental parser in `helpers/ccTasks.ts` (TaskCreate input → placeholder row, TaskUpdate optimistic mutate, TaskList result → replace, TaskGet → upsert). - `chatStore` gains `currentCCTasks` state, restored on session switch and on mid-turn buffer replay. - `bufferReplay` recognises `Agent` for panel rebuild and exports history/buffer task extractors. - `BackgroundJobs` shows the Bot icon for both `Agent` and `Task`.
Drop ``disallowed_tools=["ScheduleWakeup"]`` and add a dedicated ``ScheduleWakeupBlock`` so the call surfaces in the UI with the parsed delay, scheduled wall-clock time, clamp marker, reason, and prompt. Claude Code persists wakeups in ``~/.claude/scheduled_tasks.json`` and fires past-due ones on the next CLI resume, so the tool isn't a hard no-op — Nerve just doesn't actively trigger them on a timer (no ``/loop`` skill). The card makes that contract clear with a small "stored by Claude Code; fires on next resume" note in the expanded view.
… timer)
Empirically tested in a live Nerve session:
* Scheduled at 02:05:24 for 02:07:00 (in 96s).
* 02:07:00 — JSONL records queue-op + user-meta entries (CLI scheduler
fired on time).
* 02:07:00 — zero Nerve engine log activity (no turn started).
* 02:07:26 — user typed "did it worked?" → Nerve called
``client.query()`` → SDK flushed the queued wakeup as a synthetic
user message BEFORE the user's input.
So the wakeup is not autonomous from Nerve's POV — it's a deferred
prompt that piggybacks on the next user turn. If no turn ever comes
before the idle client is reaped, the wakeup is lost (unless
``durable: true``, which the model rarely sets).
Rewrote the comments in engine.py and the inline note in
ScheduleWakeupBlock to reflect this.
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.
Summary
Claude Code 2.1.150 / claude-agent-sdk 0.2.87 changed three things that break Nerve's chat UI:
Task→Agent.TaskCreate/TaskUpdate/TaskList/TaskGet/TaskStop/TaskOutput) replacesTodoWrite. Tasks live per-session in~/.claude/tasks/<id>/; the panel of pending work is meant to drive an in-chat todo UI.ScheduleWakeupwas added for/loopdynamic mode — Nerve has no/loopskill, so the tool is a dead end if the model calls it.Without changes, sub-agent panels stopped opening, the new Task tools fell through to the generic block, and the model could still call
ScheduleWakeupand waste a turn.Changes
Backend (
nerve/agent/engine.py)ClaudeAgentOptionsnow passesdisallowed_tools=[\"ScheduleWakeup\"]so the CLI strips it from the model's tool list entirely.Task(legacy history) andAgent(current).Frontend
ToolCallBlockroutesAgent→SubagentToolBlock(alongsideTaskfor back-compat) and the six newTask*tools → a newCCTaskToolBlock.CCTaskToolBlock(new) — compact one-line cards per call, with expand-for-details, custom icons + summaries per tool variant.TodoPanelextended to also render Claude Code 2.1+ tasks (with#idbadges so they're distinguishable from legacy TodoWrite items).helpers/ccTasks.ts(new) — incremental panel reconciler:TaskCreateinput adds a placeholder row that's reconciled to the real id ontool_result;TaskUpdatemutates optimistically;TaskList/TaskGetresults replace/upsert.chatStoregainscurrentCCTasks, restored from message history on session switch and from buffered events on mid-turn reconnect.bufferReplayrecognisesAgentfor panel rebuild and exposesextractCCTasksFromMessages/extractCCTasksFromBuffer.BackgroundJobsshows the Bot icon for bothAgentandTask.Out of scope
TeamCreate/Agent(team_name=…)) — only triggered when explicitly using cross-session task lists; falls back to the generic block.CronCreate/CronList/CronDelete(the new kairos cron tools) — same shape of issue but not raised in this report.Test plan
pytest tests/ -x -q— 727/727 passnpm run build— clean (tsc + vite)#1/#2badges show.ScheduleWakeupis absent from the model's tool list (e.g.,/loopreferences go nowhere).