an answer that goes nowhere now says so, and one that lands says that too

Second half of the AskUserQuestion report: "when I answer, the agent does not react — I see the bubble
for a long time and end up sending a message anyway", intermittently and not reproducible.

Two different causes, both invisible from the outside.

A DROPPED answer was silent at every step. user-instance discarded the boolean, sendFire does nothing
when no sidecar is connected, and the lookup returns undefined for both "no such session" and "not
yours". So a lost answer and a slow agent looked identical: a card that does not change. It now warns
with the reason, and where a session exists it emits an error into the durable log — the same channel a
successful answer uses, so a second pane sees it too, rather than confirming to the browser that
clicked.

A LANDED answer had the opposite problem. The card goes read-only the moment you pick, but `sent` is
local and optimistic while `message.output` only arrives once the harness has produced something. In
between there is a real gap, and nothing filled it — so an answered card looked exactly like one that
had timed out. It now says "Answer sent — waiting for the agent", which makes the two states different
without pretending to know when the agent will speak.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-21 15:31:25 +00:00
co-authored by Claude Opus 5
parent 1a215dcfee
commit 8d476129ea
3 changed files with 48 additions and 2 deletions
@@ -1,5 +1,5 @@
import { useState } from 'react';
import { MessageCircleQuestion, Check } from 'lucide-react';
import { MessageCircleQuestion, Check, Loader2 } from 'lucide-react';
import type { ChatMessage } from '../types';
type ToolMessage = Extract<ChatMessage, { role: 'tool' }>;
@@ -113,8 +113,28 @@ export const QuestionActivity = ({ message, onAnswer }: QuestionActivityProps) =
});
};
/*
Answered, and the agent has not spoken yet.
`sent` is local and optimistic; `message.output` is the tool result, which only arrives once the
harness has taken the answer and produced something. Between the two there is a real gap — the agent
may be thinking for a while — and until now nothing filled it: the card simply went read-only, which
looks exactly like a card that TIMED OUT. Reported as "I answer and it does not react, so I send
another message".
Saying so costs one line and removes the ambiguity: an answered card now looks different from an
abandoned one, without pretending to know when the agent will speak.
*/
const awaitingAgent = sent && message.output === undefined;
return (
<div className="my-1 space-y-3">
{awaitingAgent && (
<div className="flex items-center gap-2 px-1 text-xs text-muted-foreground">
<Loader2 className="h-3 w-3 animate-spin" />
<span>Answer sent — waiting for the agent</span>
</div>
)}
{questions.map((q, qi) => {
const multi = isMulti(q);
const answer = answers[qi];