mirror of
https://github.com/alphaXiv/OpenResearch.git
synced 2026-11-11 09:59:34 +08:00
* Fix harness prompt bugs: AskUserQuestion double-card + hang, resolved-card rendering
- plan_auto_policy auto-allows AskUserQuestion: the bridge no longer fronts
the question card with a redundant permission card whose held request also
deadlocked the end-turn resume (answer rejected as busy until interrupt).
- respond() resolves a card only after its answer is delivered, so a rejected
send leaves the card actionable instead of resolved-with-the-answer-dropped.
- Resolved cards mirror Claude Code: permission cards vanish, plan/question
cards collapse to compact inline expandable rows with an answer echo
(answers/approved/note stamped on resolve, carried through turn flushes).
* Review round 1 fixes: doc split, echo-preserving adopt, neutral outcome, read-only class rename
* Review round 2 fixes: PendingGuard doc, best-effort resolve folded into helper, neutral question echo
* Post-review nits: doc wording, dedupe question text in collapsed body, word-break on collapsed rows
* Plan-mode AskUserQuestion truly blocks: bridge holds the call as the question card
Auto-allowing AskUserQuestion was wrong: headless the tool returns no
answer, so the model guessed and kept planning instead of waiting. The
bridge now surfaces the QUESTION itself as a held mid-turn card (like
ExitPlanMode's plan card); the answer settles the held call as a denial
whose message is the answer, so the model continues the same turn with
the user's actual choice. The turn-status line says 'Waiting for your
input…' instead of 'Working…' while a card holds the turn open.
* Post-review nits: deny-message hardening, question cards don't suppress plan-synth, empty-options fallback, held-card status via nativeId, comment accuracy
* Polish: no tool row for bridge-held calls (deny-with-answer painted them red), plan pane gets padding + plain background
The bridged AskUserQuestion/ExitPlanMode tool_use now renders nothing —
the held card is the representation, and the denial that carries the
user's answer back made the CLI report the tool as errored, painting a
successful Q&A as a red error row. The right-pane plan tab had no CSS
at all: flush text on the panel tint; it's a markdown document, so it
gets a padded, plain reading surface.
* PlanStrip: Claude-desktop shape — title line, real buttons in a row below
The strip's buttons used .btn-primary/.btn-ghost, which are only styled
inside .prompt-actions — in the strip they rendered as bare text crammed
next to the title. The actions row now reuses .prompt-actions (same
buttons as every card) and sits on its own line under the title.
* PlanStrip buttons: monochrome — black text/borders, no brand red
* PlanStrip split button: single internal divider (caret drops its own left border)
* PlanStrip split button: flat inner corners (radius reset must out-rank .prompt-actions shorthand)
* Composer: attention bell instead of Stop while a held card awaits the user
A blocked-on-input turn is busy, so the composer showed the Stop X — a
loading/cancel affordance while the agent is actually waiting on an
answer. When the session is busy AND a held card (nativeId) is
unresolved, show a pulsing bell that scrolls to the pending card; Esc
still interrupts. The transcript status line shares the same
awaitingInput signal.
* Composer: two states only — Send by default, Stop X only while actively streaming
Drop the bell experiment. A turn held on an unanswered card shows the
idle Send button; the card and the status line are the waiting
affordance. Esc still interrupts a held turn.
* Composer answers the pending card (Claude-desktop): typed text = plan revision feedback / custom question answer
- send() routes plain typed text to the newest unresolved plan/question
card (respond with note) instead of racing the held turn with a new
message the busy guard would drop; placeholder says so. Questions
route only on Claude sessions (opencode rejects note-only replies).
- Rail busy-dot stops pulsing when the turn is held waiting on the user
(steady dot; same awaitingInput signal as the status line).
- Note-only question answers echo the note in the collapsed row.
* PlanStrip: Claude-desktop parity actions + popovers above the strip
Reject / Revise… / Accept / Accept-and-auto-mode (+ bypass in the caret),
Open plan as a title-row link. Reject is a true rejection: the note-less
plan denial now tells the model to stop and wait (was 'keep refining',
which made it improvise revisions/questions); collapsed rows echo
'Rejected' vs 'Revision requested' by note presence. Accept resumes
under accept-edits (guarded), Accept-and-auto under Auto — the primary
is the solid dark button, not brand red. The strip moved inside
.composer so the mode/model picker popovers (z 50 in that stacking
context) layer above it — as a sibling, .composer's z-index:4 capped
them below the strip.
* PlanStrip: single Accept-and-auto-mode primary, drop the plan excerpt
Matches the desktop reference exactly: [Reject] [Revise…] on the left,
one primary button on the right whose caret menu holds the two guarded
tiers (Accept = accept-edits, Accept and bypass all). The separate
outline Accept button and the plan-title excerpt next to the header
are gone — plan.excerpt/plan prop was fully unused after removal.
* PlanStrip: self-contained Revise mode (Claude-desktop parity)
Swaps the strip into its own textarea + [Back] [Revise ↵] footer
instead of routing through the main composer — matches the desktop
reference exactly. Enter submits, Shift+Enter newlines, Esc cancels
back to the action row. The main-composer typed-text routing
(pendingPrompt) is now question-only; plans have their own dedicated
UI and no longer need it.
* PlanStrip: drop the plain accept-edits Accept option
We have no partial-approval story (edits-only, everything else still
gated) — the caret now holds only Accept and bypass all.
* Plan revision: visible feedback + never silently dead-end
- Submitting a revision now swaps the strip to a 'Revising the plan…'
placeholder until the revised card arrives (or the turn ends) —
previously the strip snapped back to an identical-looking action row
and the submit read as a no-op.
- An empty revise note maps to a generic 'Please revise the plan.'
instead of riding the note-less wire shape, which the backend reads
as a hard rejection ('stop and wait') — the '(optional)' field was
accidentally a Reject.
- respond() reconciles messages AND busy state from the server after
every answer: a stale card (e.g. resolved by the bridge timeout while
the tab's SSE was dropped) previously stayed actionable forever and
swallowed every answer.
* PlanStrip: drop the 'Revising the plan…' placeholder
The transcript's Working… spinner already communicates it. The strip
still hides while a submitted revision is in flight (the outgoing card
must not look actionable) and the revised card swaps in on arrival.
* Review round 1 fixes: zombie-card recovery, honest composer button, reject-loop fix
Blockers:
- A held card orphaned by a process restart (PendingGuard never ran)
permanently captured typed input: the composer routed every message to
it and errors were swallowed. Now the backend collapses the zombie on
the first answer attempt, and the composer only routes typed text to a
question card that is actually answerable (live turn for native cards).
- The Send/Stop swap keyed on awaitingInput while send() could only
service question cards — a held plan/permission card showed a lying
Send (silent no-op) with no Stop control. Now keyed on pendingQuestion.
Also: note-less Reject on an end-turn/synthesized plan card resolves
with no resume (resuming just to say 'stop' re-synthesized a card — an
un-dismissable strip); the bridge plan-deny arm reuses synthesize_resume
verbatim; respond() reconciles busy for its own session only and reports
failure so the question route can restore a consumed draft; revising
clear gated to its session; un-docked plan card fallback matches the
strip's semantics; Rejected gets its own outcome class; note-only
answers echo once; split-button CSS consolidated; dead CSS/union
removed; test pins the reject wording.
* Post-clean-round nits: keep optimistic busy on failed reconcile fetch, sweep zombie held cards at claude turn entry
- respond()'s busy reconcile no longer clears busy when the sessions
fetch fails — during a Handled resume nothing re-asserts busy
mid-stream, so a transient fetch failure would hide Working…/Stop for
the rest of the turn.
- claude run_turn sweeps unresolved native_id cards at turn entry
(resolve_stale_prompts gains a native_only mode; codex keeps sweeping
everything). A held card can never outlive its process, so one left
unresolved is a crash artifact — previously it could capture the
composer's typed-text routing once the new turn made the session busy.
* Bump version to 0.1.61