Skip to content

compat: handle claude code 2.1.x tool renames (Task→Agent, new Task* tools)#82

Merged
pufit merged 3 commits into
mainfrom
pufit/claude-code-2.1.150-compat
May 26, 2026
Merged

compat: handle claude code 2.1.x tool renames (Task→Agent, new Task* tools)#82
pufit merged 3 commits into
mainfrom
pufit/claude-code-2.1.150-compat

Conversation

@pufit

@pufit pufit commented May 26, 2026

Copy link
Copy Markdown
Member

Summary

Claude Code 2.1.150 / claude-agent-sdk 0.2.87 changed three things that break Nerve's chat UI:

  • The subagent-spawning tool was renamed TaskAgent.
  • A new task-tracking suite (TaskCreate/TaskUpdate/TaskList/TaskGet/TaskStop/TaskOutput) replaces TodoWrite. Tasks live per-session in ~/.claude/tasks/<id>/; the panel of pending work is meant to drive an in-chat todo UI.
  • ScheduleWakeup was added for /loop dynamic mode — Nerve has no /loop skill, 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 ScheduleWakeup and waste a turn.

Changes

Backend (nerve/agent/engine.py)

  • ClaudeAgentOptions now passes disallowed_tools=[\"ScheduleWakeup\"] so the CLI strips it from the model's tool list entirely.
  • Sub-agent lifecycle hook matches both Task (legacy history) and Agent (current).

Frontend

  • ToolCallBlock routes AgentSubagentToolBlock (alongside Task for back-compat) and the six new Task* tools → a new CCTaskToolBlock.
  • CCTaskToolBlock (new) — compact one-line cards per call, with expand-for-details, custom icons + summaries per tool variant.
  • TodoPanel extended to also render Claude Code 2.1+ tasks (with #id badges so they're distinguishable from legacy TodoWrite items).
  • helpers/ccTasks.ts (new) — incremental panel reconciler: TaskCreate input adds a placeholder row that's reconciled to the real id on tool_result; TaskUpdate mutates optimistically; TaskList/TaskGet results replace/upsert.
  • chatStore gains currentCCTasks, restored from message history on session switch and from buffered events on mid-turn reconnect.
  • bufferReplay recognises Agent for panel rebuild and exposes extractCCTasksFromMessages / extractCCTasksFromBuffer.
  • BackgroundJobs shows the Bot icon for both Agent and Task.

Out of scope

  • Multi-agent Teams (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 pass
  • npm run build — clean (tsc + vite)
  • eslint diff vs main — no new errors introduced
  • Manual: open a session, ask the agent to use TaskCreate + TaskUpdate + TaskList → verify the panel populates, status transitions render, the #1/#2 badges show.
  • Manual: ask the model to spawn an Agent subagent → verify the side panel opens (no longer falls through to generic block).
  • Manual: confirm ScheduleWakeup is absent from the model's tool list (e.g., /loop references go nowhere).

Generated by Nerve

pufit added 3 commits May 25, 2026 19:58
…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.
@pufit pufit merged commit c39280f into main May 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant