fix(rectification): bind collect-denial follow-up to the asked turn
Saying no to a spoken collect left the next stem only on current_question, so the preparing spinner never cleared. Persist the ack, link asked_turn_id, and emit run.completed with turnId (BUG-525). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import { decideFromDossier, rectificationFollowupCatalog } from "@/lib/rectifica
|
||||
import {
|
||||
applyRectificationChoice,
|
||||
applyCollectFocusDenial,
|
||||
persistCollectDenialTurn,
|
||||
persistNextInterviewIfIdle,
|
||||
} from "@/lib/rectification-agentic/v9/answer-choice";
|
||||
import { createAdoptNarrationWriter } from "@/lib/rectification-agentic/v9/adopt-narration-agent";
|
||||
@@ -52,10 +53,18 @@ import {
|
||||
export const runtime = "nodejs";
|
||||
export const maxDuration = 240;
|
||||
|
||||
function completedMessageResponse(text: string, requestId: string, caseId: string) {
|
||||
function completedMessageResponse(
|
||||
text: string,
|
||||
requestId: string,
|
||||
caseId: string,
|
||||
turnId?: string | null,
|
||||
) {
|
||||
const completed = turnId
|
||||
? { type: "run.completed", turnId }
|
||||
: { type: "run.completed" };
|
||||
const body = [
|
||||
JSON.stringify({ type: "answer.delta", text }),
|
||||
JSON.stringify({ type: "run.completed" }),
|
||||
JSON.stringify(completed),
|
||||
"",
|
||||
].join("\n");
|
||||
return new Response(body, {
|
||||
@@ -363,12 +372,12 @@ export async function POST(request: Request) {
|
||||
}
|
||||
if (!classified || classified.intent === "unclear") {
|
||||
const narration = RECTIFICATION_USER_COPY.unclearFocusReply;
|
||||
await persistV9DeterministicTurn(accounting, userId, caseId, {
|
||||
const turn = await persistV9DeterministicTurn(accounting, userId, caseId, {
|
||||
requestId,
|
||||
userMessage: parsed.data.message ?? null,
|
||||
assistantMessage: narration,
|
||||
});
|
||||
return completedMessageResponse(narration, requestId, caseId);
|
||||
return completedMessageResponse(narration, requestId, caseId, turn.turnId);
|
||||
}
|
||||
if (classified.intent === "answer_current_focus") {
|
||||
if (!classified.answer_class) {
|
||||
@@ -398,7 +407,7 @@ export async function POST(request: Request) {
|
||||
narrateAdopt,
|
||||
});
|
||||
if (!continueToAgent) {
|
||||
return completedMessageResponse(applied.narration, requestId, caseId);
|
||||
return completedMessageResponse(applied.narration, requestId, caseId, applied.turnId);
|
||||
}
|
||||
}
|
||||
if (classified.intent === "stop_rectification") {
|
||||
@@ -419,7 +428,7 @@ export async function POST(request: Request) {
|
||||
userDisplay: parsed.data.message ?? null,
|
||||
});
|
||||
await transitionV9CaseStatus(accounting, userId, caseId, "paused");
|
||||
return completedMessageResponse(applied.narration, requestId, caseId);
|
||||
return completedMessageResponse(applied.narration, requestId, caseId, applied.turnId);
|
||||
}
|
||||
} else if (focus && isCollectFocusSchema(focus.expectedAnswerSchema)) {
|
||||
let classified = null;
|
||||
@@ -443,12 +452,15 @@ export async function POST(request: Request) {
|
||||
narrateAdopt,
|
||||
});
|
||||
if (!continueToAgent) {
|
||||
await persistV9DeterministicTurn(accounting, userId, caseId, {
|
||||
const finished = await persistCollectDenialTurn({
|
||||
accounting,
|
||||
userId,
|
||||
caseId,
|
||||
requestId,
|
||||
userMessage: parsed.data.message ?? null,
|
||||
assistantMessage: applied.narration,
|
||||
applied,
|
||||
});
|
||||
return completedMessageResponse(applied.narration, requestId, caseId);
|
||||
return completedMessageResponse(finished.streamText, requestId, caseId, finished.turnId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -468,12 +480,12 @@ export async function POST(request: Request) {
|
||||
narrateAdopt,
|
||||
});
|
||||
const assistantMessage = idle.hostNarration || nonConvergingRangeNarration(decision);
|
||||
await persistV9DeterministicTurn(accounting, userId, caseId, {
|
||||
const turn = await persistV9DeterministicTurn(accounting, userId, caseId, {
|
||||
requestId,
|
||||
userMessage: parsed.data.message ?? null,
|
||||
assistantMessage,
|
||||
});
|
||||
return completedMessageResponse(assistantMessage, requestId, caseId);
|
||||
return completedMessageResponse(assistantMessage, requestId, caseId, turn.turnId);
|
||||
}
|
||||
if (decision.nextAction === "ask_candidate_discriminator") {
|
||||
const catalog = rectificationFollowupCatalog(
|
||||
@@ -529,16 +541,16 @@ export async function POST(request: Request) {
|
||||
expectedRevision: previous?.revision ?? 0,
|
||||
userDisplay: parsed.data.message ?? null,
|
||||
});
|
||||
return completedMessageResponse(applied.narration, requestId, caseId);
|
||||
return completedMessageResponse(applied.narration, requestId, caseId, applied.turnId);
|
||||
}
|
||||
}
|
||||
const narration = RECTIFICATION_USER_COPY.choicePrompt;
|
||||
await persistV9DeterministicTurn(accounting, userId, caseId, {
|
||||
const turn = await persistV9DeterministicTurn(accounting, userId, caseId, {
|
||||
requestId,
|
||||
userMessage: parsed.data.message ?? null,
|
||||
assistantMessage: narration,
|
||||
});
|
||||
return completedMessageResponse(narration, requestId, caseId);
|
||||
return completedMessageResponse(narration, requestId, caseId, turn.turnId);
|
||||
}
|
||||
if (!plan.next_followup) {
|
||||
const idle = await persistNextInterviewIfIdle({
|
||||
@@ -548,12 +560,12 @@ export async function POST(request: Request) {
|
||||
narrateAdopt,
|
||||
});
|
||||
const assistantMessage = idle.hostNarration || nonConvergingRangeNarration(decision);
|
||||
await persistV9DeterministicTurn(accounting, userId, caseId, {
|
||||
const turn = await persistV9DeterministicTurn(accounting, userId, caseId, {
|
||||
requestId,
|
||||
userMessage: parsed.data.message ?? null,
|
||||
assistantMessage,
|
||||
});
|
||||
return completedMessageResponse(assistantMessage, requestId, caseId);
|
||||
return completedMessageResponse(assistantMessage, requestId, caseId, turn.turnId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user