Skip to content

fix(server): show OpenCode task progress in the composer - #178

Open
rynfar wants to merge 1 commit into
pylonfrom
fix/opencode-plan-parity
Open

fix(server): show OpenCode task progress in the composer#178
rynfar wants to merge 1 commit into
pylonfrom
fix/opencode-plan-parity

Conversation

@rynfar

@rynfar rynfar commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

Problem

OpenCode threads never showed task progress. The composer Tasks tab, the turn plan summary, and the sidebar working line were all permanently empty — OpenCode was the only provider in Pylon without plan parity:

Adapter Plan surface
Codex native turn/plan/updated
Claude TodoWrite input + Claude Tasks ✅
Cursor ACP ext cursor/update_todos
Grok ACP PlanUpdated
Prime (ACP + managed daemon)
OpenCode none

Two causes, both in OpenCodeAdapter.ts:

  1. OpenCode emits a structured todo.updated event that was already arriving at the adapter and already passing the parent-session gate — it just fell off the end of the event switch, which has no default. No turn.plan.updated was ever emitted.
  2. toToolLifecycleItemType matched todowrite on its write branch and classified it as file_change, so every todo update was filed into the edit tool group and counted toward the edit total. OpenCode threads over-reported file edits.

Found while reviewing upstream pingdotgg/t3code#5760, which diagnoses the same bug in T3. That issue is still open with no upstream fix, so this is Pylon's own.

Fix

Handle todo.updated and classify todo tools ahead of the write branch. Entirely within the adapter boundary — no contract, decider, projector, or migration changes, since turn.plan.updated already flows end to end for five other providers.

Notes on the choices:

  • Uses the v2 SDK's todo.updated event, not the tool-call input the upstream issue suggests sniffing. The event is structured, already in the subscribed Event union, and survives OpenCode changing its tool internals.
  • Cancelled todos are dropped, not reported completed. Pylon's plan contract has no cancelled state, and claiming finished work that was abandoned is worse than omitting it.
  • Unknown statuses settle to pending — the SDK types Todo.status as a bare string.
  • A fingerprint suppresses duplicates. OpenCode re-emits todo.updated on every mutation; without this each step transition would write a redundant plan activity. Same approach Grok and Prime already use.
  • Only the parent session's todos count. A delegated child session would otherwise overwrite the thread's plan.

Verification

vp test run apps/server/src/provider/Layers/OpenCodeAdapter.test.ts84 passed, including 4 new.

Each new test was mutation-tested rather than trusted for going green:

  • Disabling the todo.updated case → the 3 plan tests fail.
  • Removing the todo branch from classification → the classification test fails.

vp run -F t3 typecheck — 0 errors. vp lint clean on both changed files, verified live with a debugger probe rather than inferred from a silent exit 0.


Claude Opus 5 in Pylon.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

OpenCode threads never populated the Tasks tab, the turn plan summary, or the
sidebar working line. The adapter dropped OpenCode's `todo.updated` event off
the end of its event switch, so no `turn.plan.updated` was ever emitted --
OpenCode was the only provider without plan parity. Separately, `todowrite`
matched the `write` branch of tool classification and was filed as a file
change, inflating the work log's edit count.

Handle `todo.updated` from the v2 SDK, which already reaches the adapter and
already passes the parent-session gate, and classify todo tools ahead of the
write branch. Cancelled todos are dropped rather than reported completed, and
a fingerprint suppresses the duplicate emissions OpenCode sends on every
mutation.
@github-actions github-actions Bot added size:M vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Aug 29, 2026
@github-actions

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.3 KiB 13.2 KiB −121 B (−0.9%) 15.1 KiB
Codex Thread snapshot wire 6.9 KiB 6.9 KiB −2 B (−0.0%) 7.3 KiB
Codex Live turn WebSocket wire 6.4 KiB 6.3 KiB −119 B (−1.8%) 7.8 KiB
Codex Live turn WebSocket decoded 55.5 KiB 54.7 KiB −822 B (−1.4%) 66.4 KiB
Codex Live turn messages 9 9 0 (0.0%) 21
Claude Total thread wire 13.3 KiB 13.3 KiB −7 B (−0.1%) 15.1 KiB
Claude Thread snapshot wire 6.9 KiB 6.9 KiB −8 B (−0.1%) 7.3 KiB
Claude Live turn WebSocket wire 6.4 KiB 6.4 KiB +1 B (+0.0%) 7.8 KiB
Claude Live turn WebSocket decoded 56.4 KiB 56.4 KiB 0 B (0.0%) 66.4 KiB
Claude Live turn messages 10 10 0 (0.0%) 21

Baseline: abe70a7 · PR result: 0e0afd0 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

rynfar added a commit that referenced this pull request Aug 30, 2026
Also note in WATCH-1 that Pylon's own OpenCode task-progress fix is open as #178, so the row stays listed only because upstream #5760 is still open.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant