fix(app): stop completed turns from appearing stuck

Turn activity was inferred from a user-message row flag, so a stale duplicate row could keep the working footer active after the turn ended. Track submission lifecycle separately and route every send path through the shared submission flow.
This commit is contained in:
Mohamed Boudra
2026-07-27 12:44:32 +02:00
parent b97d6d13f3
commit d17aa098a6
30 changed files with 2246 additions and 681 deletions
@@ -49,6 +49,25 @@ describe("MockLoadTestAgentClient", () => {
});
});
test("rejects the configured number of prompts before starting a retry", async () => {
const client = new MockLoadTestAgentClient();
const session = await client.createSession({
provider: "mock",
cwd: process.cwd(),
model: "ten-second-stream",
featureValues: { mockPromptRejections: 1 },
});
await expect(session.startTurn("Reject this prompt.")).rejects.toThrow(
"Requested mock prompt rejection",
);
await expect(session.startTurn("Accept this retry.")).resolves.toEqual({
turnId: expect.any(String),
});
await session.interrupt();
});
test("returns schema-shaped JSON for structured branch-name generation", async () => {
vi.useFakeTimers();
const client = new MockLoadTestAgentClient();
@@ -583,6 +583,7 @@ export class MockLoadTestAgentSession implements AgentSession {
private modeId: string | null;
private modelId: string | null;
private readonly rewindError: string | null;
private remainingPromptRejections: number;
constructor(options: { config: AgentSessionConfig; sessionId: string; logger?: Logger }) {
this.id = options.sessionId;
@@ -593,6 +594,13 @@ export class MockLoadTestAgentSession implements AgentSession {
typeof options.config.featureValues?.mockRewindError === "string"
? options.config.featureValues.mockRewindError
: null;
const requestedPromptRejections = options.config.featureValues?.mockPromptRejections;
this.remainingPromptRejections =
typeof requestedPromptRejections === "number" &&
Number.isSafeInteger(requestedPromptRejections) &&
requestedPromptRejections > 0
? requestedPromptRejections
: 0;
}
async run(prompt: AgentPromptInput, options?: AgentRunOptions): Promise<AgentRunResult> {
@@ -611,6 +619,10 @@ export class MockLoadTestAgentSession implements AgentSession {
if (this.activeTurn) {
throw new Error("Mock load-test provider already has an active turn");
}
if (this.remainingPromptRejections > 0) {
this.remainingPromptRejections -= 1;
throw new Error("Requested mock prompt rejection");
}
const profile = resolveModelProfile(this.modelId);
const turnId = randomUUID();