Skip to content

[P1][0.5] Standardize agent progress commentary and one final answer #85

Description

@mightnent

Outcome

Give every LemmaComputer agent one consistent, release-qualified turn lifecycle for user-visible progress, final answers, retries, input requests, failures, cancellation, reconnect, and resumption.

The product contract applies to every enabled agent adapter—currently Claude, Codex, and Hermes—and to future adapters before they can be registered for employee use. Each agent may use a different CLI, provider API, streaming format, tool loop, approval mechanism, and vendor-session model. Those differences must end at the adapter boundary. Control, Web Chat, Activity, and conversation persistence must receive the same normalized semantics regardless of which agent runs the turn.

While any agent works, meaningful user-visible commentary should stream into one expandable Thinking surface rather than being appended to the final answer. When the turn reaches a terminal outcome, that surface collapses and exactly one concise durable answer follows it.

This is not a request to expose hidden chain-of-thought. Thinking is the product name for model-authored commentary that is intentionally safe to show the employee, together with sanitized plans, milestones, tool states, and failure summaries. It remains visually and structurally separate from the terminal answer.

Current evidence

The defect was first reproduced through Hermes during a synthetic artifact-generation request while qualifying #80. No customer content was involved. Hermes emitted intermediate assistant text during its tool loop, the adapter forwarded each delta as ordinary chat text, and Control accumulated those deltas into the same assistant content as the final response. The employee therefore saw repeated promises and progress paragraphs before the actual answer.

Hermes is the original reproduction, not the product boundary. Claude, Codex, and future agents expose different native event streams and execution mechanisms, but all can produce the same class of defect if commentary, retries, tool-loop text, and final output are not normalized explicitly.

The required fix is an agent-neutral lifecycle contract plus adapter-specific translation—not a Hermes-only text filter and not identical internal implementations across agents.

Execution

Scope

1. Define one normalized lifecycle for every agent

  • Define versioned Control-owned semantics for user-visible commentary, sanitized activity/tool state, exactly one final answer, needs_input, failed, and cancelled.
  • Make event type, run identity, message identity, sequence, and terminality explicit. Do not infer them from prose, silence, timing, or provider-specific event names.
  • Emit user-visible interim commentary independently from the terminal answer. If a native event is ambiguous, the adapter must buffer it until it can classify it safely.
  • Allow at most one terminal outcome per logical run. Late, repeated, or replayed provider events must be idempotent.
  • Preserve one logical run and stable identifiers across provider retry, tool retry, reconnect, browser refresh, Control restart, and supported agent-session resumption.
  • Treat needs_input, failed, and cancelled as terminal outcomes with one concise, actionable durable message.
  • Keep raw provider payloads, hidden reasoning, unrestricted tool arguments/results, credentials, and private paths out of chat messages and Activity records.

2. Keep native mechanisms inside each adapter

  • Require every registered adapter to translate its native provider or CLI events into the normalized lifecycle.
  • Keep native parsing, tool-loop behavior, approval handling, retry mechanics, cancellation, and vendor-session resumption adapter-local.
  • Do not hard-code product behavior to Hermes, Claude, Codex, or any other agent name.
  • Add a provider-independent conformance suite that runs against every enabled adapter.
  • Cover commentary, tool activity, final answers, input or approval requests, cancellation, deterministic failure, transient retry, reconnect, and resumed sessions.
  • Prove that Claude, Codex, and Hermes produce the same normalized employee-visible outcome for equivalent scripted event sequences even though their native streams differ.
  • If an adapter has no native user-visible commentary, show only real sanitized lifecycle or tool milestones; do not fabricate model commentary.
  • Keep vendor session bindings separate. Changing agents between turns must not merge proprietary session state or reclassify prior commentary as a new final answer.
  • Reject registration or release qualification for an adapter that cannot prove lifecycle conformance.

3. Stream and coalesce commentary consistently in Web Chat

  • While a turn is active, render one live, expanded Thinking surface in the conversation regardless of the selected agent.
  • Stream distinct model-authored commentary and sanitized milestones into that surface as they occur; do not reduce the experience to a spinner or one static status label.
  • Update the same surface in place, preserve useful order, and coalesce semantically equivalent statements that add no new milestone or outcome.
  • Show the newest meaningful update prominently while allowing the employee to review earlier visible updates.
  • When the run reaches a terminal outcome, collapse the surface to a compact summary such as Thought for 1m 22s; keep it expandable and render exactly one terminal assistant answer beneath it.
  • Keep View activity as the deeper sanitized operational trace owned by [P0][Demo] Add a versioned, sanitized Activity event protocol and replay API #6 and [P0][Demo] Build the streaming Activity, Sources & Actions side panel #16. The Thinking surface is the conversational summary; Activity is the structured plan/progress/tool timeline.
  • Avoid redundant UI rows such as separate low-value Work complete, Turn completed, and repeated final-answer milestones for the same transition.
  • Meet keyboard, screen-reader, reduced-motion, narrow viewport, and long-running-turn requirements.
  • Rate-limit live-region announcements so token-level streaming does not overwhelm assistive technology.

4. Make retries, reconnect, and persistence idempotent

  • Store or derive user-visible commentary separately from canonical final-answer text.
  • Reconstruct the same active or collapsed Thinking surface after browser refresh, reconnect, workspace restart, Control restart, and later conversation reload without duplicating content.
  • Do not create a second progress surface, final answer, artifact card, or durable message when a provider, tool, transport, or client retries.
  • Classify deterministic failures once and do not retry them as transient failures.
  • Bound transient retry and backoff without changing the logical run or restarting visible progress.
  • Preserve completed commentary and the terminal answer when the workspace later stops, through the durable boundary owned by [P1][Post-0.5] Make conversations and generated artifacts durable outside workspace runtimes #80.
  • Define the normalized lifecycle records and identifiers consumed by [P1][Post-0.5] Make conversations and generated artifacts durable outside workspace runtimes #80 without making workspace paths, provider payloads, or vendor session files the long-term conversation authority.

5. Define deterministic terminal UI and data semantics

  • final: collapse Thinking, retain it as expandable history, and show exactly one final answer.
  • needs_input: stop active progress and show one actionable request without also presenting a success answer.
  • failed: stop active progress and show one sanitized failure summary without replaying recovered internal errors as separate terminal messages.
  • cancelled: stop active progress and show one cancellation outcome without later provider events reviving the run.
  • Reconnect or replay after any terminal outcome must reconstruct that same outcome rather than emit another terminal message.

Non-goals

  • Displaying or storing hidden chain-of-thought.
  • Persisting unrestricted provider streams or raw tool results as chat history.
  • Replacing streamed commentary with only a spinner or static Working… label.
  • Making Claude, Codex, Hermes, or future agents use the same native execution or streaming mechanism.
  • Implementing equivalent UI, deduplication, or persistence behavior separately inside each agent.
  • Office document generation, PowerPoint/Word/Excel runtime qualification, visual artifact inspection, or agent-specific Office tooling.
  • Adding packages, browser runtimes, or agent-specific execution capabilities.
  • Replacing the governed routing layer, Activity, or the durable conversation/artifact architecture in [P1][Post-0.5] Make conversations and generated artifacts durable outside workspace runtimes #80.
  • Treating a larger timeout or higher tool-iteration budget as the lifecycle fix.

Definition of success

All-agent protocol behavior

  • Claude, Codex, Hermes, and every other enabled adapter pass the same normalized lifecycle conformance suite.
  • An equivalent multi-tool turn from each adapter produces multiple distinct updates in one Thinking surface followed by exactly one terminal assistant answer.
  • Native provider events never reach Control or Web Chat as ambiguous untyped assistant text.
  • Completed, failed, cancelled, and needs-input outcomes each have deterministic agent-independent protocol, UI, and persistence semantics.
  • Provider, tool, transport, and client retries do not duplicate commentary, the progress surface, terminal answer, artifact references, or durable messages.
  • Adding or upgrading an adapter cannot bypass the conformance gate.

Web Chat behavior

  • The Thinking surface updates in place, preserves useful milestone order, and coalesces near-duplicate statements without hiding genuinely new progress.
  • On a terminal outcome, the surface collapses to a compact duration or summary row, remains expandable, and stays visually separate from the terminal answer.
  • Refresh, reconnect, workspace restart, Control restart, conversation reload, and supported agent handoff reconstruct the same state without duplicated content.
  • The thought surface and Activity view contain only intentionally user-visible commentary and sanitized lifecycle records, never hidden reasoning or raw provider/tool payloads.
  • Keyboard, screen-reader, reduced-motion, narrow viewport, live-region, and long-running-turn behavior pass focused browser coverage.

Regression evidence

  • A Hermes regression fixture proves tool-loop assistant deltas no longer accumulate into the final answer.
  • Adapter-specific fixtures prove Claude, Codex, and Hermes native streams normalize to the same commentary/final/input/failure/cancellation semantics.
  • A provider-independent fixture covers transient retry, deterministic failure, cancellation, reconnect, replay, and resumption and proves each transition is bounded and idempotent.
  • Persistence coverage proves user-visible commentary is separate from the normalized terminal answer and artifact references.
  • Browser coverage switches among enabled agents and verifies live updates, coalescing, refresh during work, automatic collapse, expansion, terminal outcomes, and conversation reload.
  • npm run verify:quick, the smallest relevant Playwright chat flow, and focused adapter conformance tests pass on the exact candidate SHA.

Related issues

Done when

  • The Control protocol documents commentary, activity, final, needs-input, failure, cancellation, retry, reconnect, replay, and resumption semantics independently of any agent vendor.
  • Every enabled agent adapter has passing conformance evidence against that protocol.
  • Web Chat renders one coalesced, accessible Thinking surface and exactly one deterministic terminal answer for every adapter.
  • Conversation and Activity boundaries retain only normalized, tenant-scoped records and reconstruct turns without duplication.
  • Documentation explains how an adapter maps native events to the shared lifecycle and how to diagnose a failed conformance fixture from sanitized evidence.
  • The final handoff records exact commands/results, adapter-matrix results, deployment-profile impact, residual limitations, and the integration-eligible commit SHA.

Workpad — commit review, 2026-09-08

Status: Hermes mitigation implemented; #85 remains open. Reviewed 9d45fc31a4fb20bfab702356e037185d91aac725, which changes only the workspace Python adapter, adds five Hermes regression tests, and adds a qualification record. No blocking regression was identified in the reviewed Hermes slice. This is not completion of the all-agent definition of success.

Verified implementation

  • Hermes drops every native assistant.delta, because that stream mixes intermediate commentary and final-answer tokens. It does not classify prose or preserve those deltas as commentary.
  • It buffers assistant.completed.content and emits that text once only after run.completed.completed === true and clean stream completion. Repeated completion messages in one stream do not append duplicate answers.
  • It rejects partial/interrupted assistant completions and a missing explicit final answer. Existing native-error, unsuccessful-run, truncated-stream, and provider-failure handling remains; none falls back to mixed deltas.
  • An explicit empty final remains valid for artifact-only turns. Cancellation before publication propagates without flushing the buffered answer. The shared needs-input marker still works when present at the beginning of the final reply.
  • Existing sanitized tool activity remains live; existing source extraction, artifact collection, approvals, vendor-session bindings, and detached replay paths are retained.
  • Trade-off: Hermes answer text appears at completion; this does not reduce model calls or tool-loop latency. Old saved transcripts are not rewritten.
  • Claude, Codex, shared protocol, Control accumulation, Web rendering, and persistence were not changed by this commit. There is no schema/migration or deployment-profile divergence.

Sources: adapter change, Hermes regression tests, qualification record.

Verification and evidence limits

  • Re-ran node --import tsx --test tests/hermes-final-answer.test.ts tests/agent-chat.test.ts on review HEAD b29fa3eb5a0408d6b03dfd45b947b518e096f939: 25 passed, zero failures/skips. Initial sandbox execution blocked three localhost fixture listeners with EPERM; rerun with localhost permission passed.
  • The Python adapter and Hermes regression test are byte-for-byte unchanged between the reviewed commit and review HEAD. The shared agent-chat test has subsequent schedule-executor assertions, so this is current-HEAD focused verification, not a fresh full gate on the historical SHA.
  • The committed qualification record reports the earlier quick gate (891 passed, 39 database/optional skips), four browser fixture tests, and a live Lite Hermes multi-tool turn whose saved answer matched the native final reply, plus refresh and cancellation checks. These are recorded historical results, not rerun live during this review.
  • The test named “Hermes, Claude, and Codex satisfy the same ordered owned stream contract” uses already-normalized fixture frames for each catalog ID. It proves shared transport/UI mapping, not native three-adapter lifecycle conformance.
  • Local main contains the reviewed commit. No current deployment, workspace-image rollout, external-channel qualification, or issue closure is asserted by this review. Deployment requires the updated workspace adapter image/runtime; a Web-only update is insufficient.

Remaining adapter work

Adapter Verified current gap Recommended next slice
Claude Every StreamEvent text delta is forwarded as answer text. Once any text streams, ResultMessage.result is not published as the authoritative answer. Intermediate tool-loop text can therefore remain in the answer, matching the original class of Hermes defect. Keep tool/approval events live; buffer ambiguous assistant text and publish the authoritative result only after a successful, non-aborted terminal result. Qualify the pinned SDK's result semantics, missing/empty result behavior, and cancellation before adopting this path. Preserve the input marker, sources, artifacts and session binding.
Codex Every item/agentMessage/delta is forwarded without item/phase classification. Completed items inspect phase == final_answer, but any earlier delta suppresses publication of that selected final. The fallback also accepts the first unclassified/commentary message when no final has been selected. Track native item IDs and phases; select an explicit final-answer item and commit it only on successful turn/completed. Never promote the first commentary item to final merely because no final exists. Buffer missing/unknown phases until safely classified; qualify the pinned SDK's fallback semantics. Interrupted/failed turns must not flush a success answer.

Native paths: Claude, Codex. These are source-confirmed gaps in unchanged code, not new regressions introduced by this commit. Live Claude/Codex reproductions were not run during this review.

Proposed execution order and remaining shared contract

  • Hermes final-answer contamination regression fixture and completion-only mitigation.
  • Add Python-backed native Claude fixtures and implement its bounded final-answer mitigation.
  • Add Python-backed native Codex fixtures and implement item/phase-aware final-answer selection.
  • For each adapter, prove multi-tool commentary exclusion, final-only replies, missing/empty finals, needs-input and approvals, failure after partial output, cancellation, repeated/late terminal events, sources/artifacts, and resumed sessions. Confirm empty text is valid only under the agreed artifact/output contract; never use interim chatter as a fallback.
  • Extend the existing versioned Control-owned protocol (which already has run/session identity, sequence, tool/progress events and terminal states) with explicit commentary/final semantics. Retain existing tenant-scoped persistence and Activity boundaries; add separate normalized commentary records and replay/idempotency coverage rather than rebuilding [P1][Post-0.5] Make conversations and generated artifacts durable outside workspace runtimes #80.
  • Map intentionally user-visible native commentary into that shared contract. Codex can use verified item phases; Claude needs verified message/tool/result boundaries; Hermes needs a reliable native boundary before its discarded mixed deltas can become visible commentary. Keep ambiguous text buffered and hidden reasoning excluded.
  • Implement one shared coalescing, expandable Thinking surface, terminal collapse, accessibility, and refresh/reconnect/reload reconstruction for all adapters.
  • Make actual native-adapter conformance a registration/release gate; run the relevant browser matrix and live small-model qualification, then record exact candidate SHA and rollout evidence separately.

The two adapter mitigations can ship as bounded slices using the current transport. They reduce answer contamination but do not satisfy streamed commentary or the complete #85 lifecycle. Full completion still requires shared protocol/UI/persistence work and qualification of all three adapters.

Live Claude Lite follow-up — 2026-09-08

The product goal remains an expandable, live user-visible progress trace separate from the final answer. Completion-only output is a bounded mitigation, not the desired end-state. This review does not establish the historical reason AI SDK was originally adopted; current source confirms useChat/DefaultChatTransport carry our mapped UI messages, and the installed AI SDK supports typed stream parts. The application must supply the semantic separation.

Test environment: existing isolated local development owner mike/local-stateful-test, clean commit cf165fa86bd334acb507feffa984df127940de52, passed npm run dev:doctor. Created a new product workspace Issue 85 Lite Traces (d249aa93-65de-458f-8a5d-64b6078fbd04) with Claude CLI only, Internet workspace mode, no desktop applications/channels, and three synthetic fixture files. Existing workspaces were not modified. Native Claude SDK 0.2.128; configured CLI 2.1.215. The live adapter SHA256 is 23511036177579d4d4bc16740b7fbcb43119e354fd996505ad3b8a9dc537cc93, matching this worktree. Its Claude/Codex functions are unchanged from the reviewed main; the local runtime does not contain the separate Hermes final-answer mitigation, so these tests assert nothing about deployed Hermes behavior.

Live conversation: 1be2927f-81bc-4f4b-9f76-e1b04e2bf85a. Both persisted Control run records confirm requested_service_class=lite and status=completed.

Test Native evidence Product outcome
Multi-tool synthetic CSV calculation (about 24 seconds) Three visible progress text messages had distinct message IDs and stop_reason=tool_use; final text had a separate ID and stop_reason=end_turn. Four Read attempts included a recovered page-argument error. Final arithmetic was correct: total 76, highest item beta at 22. Real Chrome showed progress text accumulating in the answer during work. The saved assistant text joined all three progress messages and the final table with no message separators, breaking the table rendering.
Same-conversation follow-up after reload (about 10 seconds) One visible rechecking message ended with tool_use; the separate final was “The south.csv subtotal is 33.” with end_turn. Native history remained in the same session. Chat again persisted progress plus final as one text part: …verify its subtotal.The south.csv subtotal is 33.

Reload reconstructed the first completed answer without an extra assistant message; the contamination remained because it is persisted. The composer recovered and the follow-up ran in the same conversation. The expanded Activity view retained the initial Approach and successful file actions, but did not move the repeated progress paragraphs out of the final-answer body. Raw native thinking content was not read or copied into this evidence; only visible text, block types, message IDs, and stop reasons were inspected.

Conclusion for Claude: the tested SDK/runtime exposes useful native boundaries. The problem is demonstrably in our translation/accumulation, not evidence that Claude cannot support the requested experience. The installed SDK's AssistantMessage exposes message_id and stop_reason; StreamEvent exposes the native event and parent_tool_use_id; ResultMessage exposes final result and terminal reason. Use these boundaries to normalize tool-loop commentary separately, exclude subagent/hidden reasoning as appropriate, buffer text while its role is ambiguous, and finalize only against the successful terminal result. Then add the shared expandable commentary UI and persisted commentary records. These two successful live turns do not establish failure/cancellation/retry conformance.

Codex blocker: the current Web agentChoices hard-codes Codex CLI as “Coming soon / awaiting governance qualification” with no selectable catalog ID, although the runtime package/adapter exists. Its governed reasoning registration also remains discovery. No Codex provider request was made and no Lite capability conclusion is claimed. The user explicitly chose to report the Claude results and this blocker rather than stage an isolated Codex exposure branch. Codex still needs that separate qualification setup and the equivalent native/UI live tests before any capability claim or availability promotion.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions