fix(web): keep editor disabled during STARTING so quick-chat sends don't race
My previous fix made submit no longer block on isStarting, with the
goal of keeping local quick-chat sessions from silently dropping
messages. The trace from CI showed it traded one failure for another:
the editor became contenteditable while the session was still
STARTING, the e2e suite pressed Cmd+Enter immediately, and the
backend rejected with "Failed to send message to agent" because the
agent process wasn't ready yet.
Restore the original semantics — STARTING blocks both editor and
submit — but keep `isPreparingEnvironment` as the narrower trigger for
the "agent still being set up" tooltip. Net behaviour:
- STARTING transition: editor disabled, no tooltip (signal is the
disabled state itself)
- container/sandbox prepare: editor disabled + tooltip explaining why
- quick-chat sessions: editor stays disabled until RUNNING, no race
This commit is contained in:
@@ -33,9 +33,25 @@ function renderInputState(overrides: Partial<Parameters<typeof useChatInputConta
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("useChatInputContainer", () => {
|
describe("useChatInputContainer", () => {
|
||||||
it("keeps the editor enabled while setup is still blocking submit", () => {
|
it("disables the editor while the session is still STARTING", () => {
|
||||||
|
// The editor must stay uneditable until the agent reaches RUNNING — if
|
||||||
|
// the user can press Cmd+Enter mid-startup, the backend rejects with
|
||||||
|
// "Failed to send message to agent" because the agent process isn't
|
||||||
|
// ready yet. This is the regression from earlier rounds where the e2e
|
||||||
|
// quick-chat suite kept failing on race conditions.
|
||||||
const { result } = renderInputState({ isStarting: true });
|
const { result } = renderInputState({ isStarting: true });
|
||||||
|
|
||||||
expect(result.current.isDisabled).toBe(false);
|
expect(result.current.isDisabled).toBe(true);
|
||||||
|
expect(result.current.submitDisabled).toBe(true);
|
||||||
|
expect(result.current.submitDisabledReason).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("surfaces the setup tooltip only while a container/sandbox is preparing", () => {
|
||||||
|
const { result } = renderInputState({
|
||||||
|
isStarting: true,
|
||||||
|
isPreparingEnvironment: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.current.submitDisabledReason).toBe("The agent is still being set up.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -102,18 +102,23 @@ function computeDerivedState(params: {
|
|||||||
isAgentBusy: boolean;
|
isAgentBusy: boolean;
|
||||||
hasAgentCommands: boolean;
|
hasAgentCommands: boolean;
|
||||||
}) {
|
}) {
|
||||||
|
// STARTING is included so the editor itself stays uneditable until the
|
||||||
|
// session reaches RUNNING. Without this, the e2e suite's wait-for-
|
||||||
|
// contenteditable would fire mid-STARTING, the test would press Cmd+Enter,
|
||||||
|
// and the backend would reject with "Failed to send message to agent"
|
||||||
|
// before the agent process is ready to receive prompts.
|
||||||
const isDisabled =
|
const isDisabled =
|
||||||
|
params.isStarting ||
|
||||||
params.isMoving ||
|
params.isMoving ||
|
||||||
params.isSending ||
|
params.isSending ||
|
||||||
params.isFailed ||
|
params.isFailed ||
|
||||||
params.needsRecovery ||
|
params.needsRecovery ||
|
||||||
params.executorUnavailable;
|
params.executorUnavailable;
|
||||||
// Only an active container/sandbox prepare blocks the submit and surfaces
|
const submitDisabled = isDisabled;
|
||||||
// the "agent still being set up" tooltip. The brief STARTING transition
|
// The "agent still being set up" tooltip is only meaningful while a
|
||||||
// every session passes through (including local quick-chat) intentionally
|
// container/sandbox is actively bootstrapping. The brief STARTING
|
||||||
// does NOT block — the e2e suite presses Cmd+Enter as soon as the editor
|
// transition for local quick-chat sessions doesn't deserve its own
|
||||||
// becomes editable, and a STARTING-only block silently dropped messages.
|
// tooltip — the editor is disabled, that's the signal.
|
||||||
const submitDisabled = params.isPreparingEnvironment || isDisabled;
|
|
||||||
const submitDisabledReason = params.isPreparingEnvironment
|
const submitDisabledReason = params.isPreparingEnvironment
|
||||||
? "The agent is still being set up."
|
? "The agent is still being set up."
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|||||||
Reference in New Issue
Block a user