Carry forward the arbiter verdict too, not just the owner final
When a paired task ends on an arbiter ESCALATE (asking the user to choose), the user's next reply was carried into the fresh task with the owner's earlier final as context — not the arbiter message they were actually responding to. Generalize the carry-forward to the latest user-facing final (owner final OR arbiter verdict, whichever the task ended on), so the user can choose based on the last arbiter message without the new turn re-reading the whole prior conversation. The carried-forward guidance marker is now matched by a shared prefix so it triggers for both. Adds tests for the arbiter-escalation carry and the prefix guidance. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -251,20 +251,28 @@ function isIntermediateStepOutput(outputText: string): boolean {
|
||||
return /^\s*STEP_DONE\b/.test(outputText);
|
||||
}
|
||||
|
||||
function getLatestOwnerFinalOutput(taskId: string): PairedTurnOutput | null {
|
||||
const ownerOutputs = [...getPairedTurnOutputs(taskId)]
|
||||
function getLatestUserFacingFinalOutput(
|
||||
taskId: string,
|
||||
): PairedTurnOutput | null {
|
||||
// The user only ever sees owner finals and arbiter verdicts (reviewer turns
|
||||
// are internal). Whichever of those the previous task ended on is what the
|
||||
// user is replying to next — e.g. an arbiter ESCALATE asking them to choose.
|
||||
// So carry the chronologically-latest owner/arbiter final forward.
|
||||
const userFacingOutputs = [...getPairedTurnOutputs(taskId)]
|
||||
.reverse()
|
||||
.filter((output) => output.role === 'owner');
|
||||
.filter(
|
||||
(output) => output.role === 'owner' || output.role === 'arbiter',
|
||||
);
|
||||
return (
|
||||
ownerOutputs.find(
|
||||
userFacingOutputs.find(
|
||||
(output) => !isIntermediateStepOutput(output.output_text),
|
||||
) ??
|
||||
ownerOutputs[0] ??
|
||||
userFacingOutputs[0] ??
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
function carryForwardLatestOwnerFinal(args: {
|
||||
function carryForwardLatestFinal(args: {
|
||||
sourceTask: PairedTask;
|
||||
targetTask: PairedTask;
|
||||
}): void {
|
||||
@@ -272,29 +280,34 @@ function carryForwardLatestOwnerFinal(args: {
|
||||
return;
|
||||
}
|
||||
|
||||
const latestOwnerFinal = getLatestOwnerFinalOutput(args.sourceTask.id);
|
||||
if (!latestOwnerFinal) {
|
||||
const latestFinal = getLatestUserFacingFinalOutput(args.sourceTask.id);
|
||||
if (!latestFinal) {
|
||||
return;
|
||||
}
|
||||
|
||||
const label =
|
||||
latestFinal.role === 'arbiter'
|
||||
? 'latest arbiter verdict'
|
||||
: 'latest owner final';
|
||||
insertPairedTurnOutput(
|
||||
args.targetTask.id,
|
||||
0,
|
||||
'owner',
|
||||
`[Carried forward context from the previous task: latest owner final]\n${latestOwnerFinal.output_text}`,
|
||||
`[Carried forward context from the previous task: ${label}]\n${latestFinal.output_text}`,
|
||||
{
|
||||
createdAt: latestOwnerFinal.created_at,
|
||||
attachments: latestOwnerFinal.attachments,
|
||||
createdAt: latestFinal.created_at,
|
||||
attachments: latestFinal.attachments,
|
||||
},
|
||||
);
|
||||
logger.info(
|
||||
{
|
||||
sourceTaskId: args.sourceTask.id,
|
||||
targetTaskId: args.targetTask.id,
|
||||
carriedChars: latestOwnerFinal.output_text.length,
|
||||
attachmentCount: latestOwnerFinal.attachments?.length ?? 0,
|
||||
carriedRole: latestFinal.role,
|
||||
carriedChars: latestFinal.output_text.length,
|
||||
attachmentCount: latestFinal.attachments?.length ?? 0,
|
||||
},
|
||||
'Carried forward latest owner final into superseding paired task',
|
||||
'Carried forward latest user-facing final into superseding paired task',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -328,7 +341,7 @@ export function resolveOwnerTaskForHumanMessage(args: {
|
||||
// fresh task with the previous task's latest owner final so the owner keeps
|
||||
// continuity across sessions instead of answering with "no context".
|
||||
if (newTask && previousTask) {
|
||||
carryForwardLatestOwnerFinal({
|
||||
carryForwardLatestFinal({
|
||||
sourceTask: previousTask,
|
||||
targetTask: newTask,
|
||||
});
|
||||
@@ -373,7 +386,7 @@ export function resolveOwnerTaskForHumanMessage(args: {
|
||||
canonicalWorkDir,
|
||||
roomRoleContext: args.roomRoleContext,
|
||||
});
|
||||
carryForwardLatestOwnerFinal({
|
||||
carryForwardLatestFinal({
|
||||
sourceTask: existing,
|
||||
targetTask: newTask,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user