Skip to content

fix(goals): route /goal through the bridge-driven loop so clients see goal progress - #181

Open
samuelchanx wants to merge 1 commit into
william0wang:mainfrom
samuelchanx:fix/goal-client-rendering
Open

fix(goals): route /goal through the bridge-driven loop so clients see goal progress#181
samuelchanx wants to merge 1 commit into
william0wang:mainfrom
samuelchanx:fix/goal-client-rendering

Conversation

@samuelchanx

Copy link
Copy Markdown

Fixes #178

Problem

/goal kept the legacy backend goal mode (session/goal). Those backend-internal turns must be dropped by the per-prompt translator (skippingForeignTurn, the ghost-completed guard), so ACP clients never saw goal progress — only the goal set acknowledgement plus a few untyped leaked events that clients render as generic "Other" rows. Repro and evidence in #178.

Fix

/goal now shares the /auto bridge-driven GoalLoopDriver machinery (autoFlow()), which runs rounds through the normal runOneTurn dispatch — every round's tool calls and text stream to clients live.

  • /goal <objective> starts the loop (full objective, same first-word subcommand rules as /auto)
  • /goal pause|stop|resume|status — same subcommands as /auto
  • /goal clear — stop alias (backend action=clear parity)
  • /goal with no argument — shows status from the live driver or saved state
  • Escape hatch: ZCODE_ACP_GOAL_MODE=backend restores the legacy backend goal mode
  • The raw session/goal extension method is untouched (protocol-level show/state still works)

Verification

Unit: full suite green — 84 files / 1163 tests; tests/goal-slash.test.ts updated to pin the new routing (driver start, subcommands, clear alias, no-arg status, env escape hatch).

E2E against the real backend (scripts/goal-e2e-check.mjs, included — a minimal stdio ACP client that logs every session/update):

Published 0.35.2 (reproduces #178):

<- text: ✓ goal set: …
-- prompt finished: stopReason=end_turn (rounds keep running)
-- waiting for goal round activity (max 5min)...
== RESULT: 4 session/update events, 0 tool_call(s)
== FAIL: no round events reached the client (issue #178 symptom)

This branch:

<- text: 🎯 goal loop started: …
<- text: ✓ goal set: …
-- prompt finished: stopReason=end_turn (rounds keep running)
<- config_option_update, current_mode_update, agent_thought_chunk …
== RESULT: 12 session/update events
== PASS: goal round streamed to client

Note for reviewers

One UX delta vs the backend mode: the loop's objective lives in bridge state (goal-loop/state.ts), not backend goal state — so clients that render the backend goal banner read empty during a loop. The trade-off is the live progress stream, which the backend mode cannot offer (its turns are invisible by construction). Happy to also emit a typed goal-status notification if there's a preferred shape.

… goal progress

/goal kept the legacy backend goal mode (session/goal), whose
backend-internal turns the translator must drop (ghost-completed
guard) — so ACP clients never saw goal progress: only "goal set"
plus untyped leaked events that clients render as "Other"
(william0wanggh-178).

/goal now shares the /auto GoalLoopDriver machinery, streaming every
round's tool calls and text to clients live. ZCODE_ACP_GOAL_MODE=
backend restores the legacy behavior; /goal clear is a stop alias for
backend action=clear parity; no-arg /goal shows loop status from the
live driver or saved state.

Also adds scripts/goal-e2e-check.mjs, a minimal stdio ACP client that
verifies goal rounds stream to the client (A/B: 0.35.2 streams zero
events after goal set; this change streams round activity).
@samuelchanx

Copy link
Copy Markdown
Author

Added a second commit addressing two adjacent host-config gaps found while testing in Paseo (which renders no ACP config-option picker at all):

  • ZCODE_ACP_MODE — ACP-created sessions hardcoded mode: "yolo"; now a validated env override (plan/build/edit/yolo/auto, invalid → yolo). This doubles as the host-side permission-config surface: build/edit let the backend's permission requests flow to clients that support session/requestPermission.
  • ZCODE_ACP_THOUGHT_LEVEL — applied once via session/setThoughtLevel after materialization; a rejected token logs and keeps the model default.

Pending-session modes/configOptions advertise the same defaults so a client's dropdown matches what create will actually use. +4 tests (38 total in session-lazy), full suite green (84 files / 1167 tests). Both knobs are plain env, e.g. Paseo's providers.zcode.env block.

@samuelchanx
samuelchanx force-pushed the fix/goal-client-rendering branch 2 times, most recently from d389ae8 to 475db16 Compare September 12, 2026 22:00
@samuelchanx

Copy link
Copy Markdown
Author

Trimmed this PR to just the goal-routing fix to keep the diff focused. Two adjacent fixes (ZCODE_ACP_MODE / ZCODE_ACP_THOUGHT_LEVEL host env knobs, and stripping the $ skill prefix for Paseo clients) are no longer part of this PR — they live on the paseo-extras branch of my fork if useful.

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.

Goal loop events are dropped — ACP clients see no progress (or untyped "Other" entries) during /goal turns

1 participant