Allow failed agent turns to be forked (#2063)
* fix(chat): allow failed turns to be forked Failed turns can end in Paseo-generated timeline items without provider message IDs. Anchor forks to canonical timeline positions while retaining legacy boundaries for compatibility. Place the fork summary before the new prompt and delimit it as structured chat history. * fix(chat): tighten fork boundary handling
This commit is contained in:
@@ -9,7 +9,7 @@ import {
|
||||
collectAssistantTurnContentForStreamRenderStrategy,
|
||||
type StreamStrategy,
|
||||
} from "./strategy";
|
||||
import { resolveAssistantTurnBoundaryMessageId } from "./turn-boundary";
|
||||
import { resolveAssistantTurnForkBoundary, type AssistantTurnForkBoundary } from "./turn-boundary";
|
||||
import {
|
||||
AssistantTurnFooter,
|
||||
LiveElapsed,
|
||||
@@ -31,7 +31,7 @@ const workingIndicatorColorMapping = (theme: Theme) => ({
|
||||
export type TurnContentStrategy = StreamStrategy;
|
||||
export type AssistantTurnForkHandler = (input: {
|
||||
target: AssistantForkTarget;
|
||||
boundaryMessageId?: string;
|
||||
boundary: AssistantTurnForkBoundary;
|
||||
}) => Promise<void> | void;
|
||||
|
||||
export const TurnFooter = memo(function TurnFooter({
|
||||
@@ -39,12 +39,14 @@ export const TurnFooter = memo(function TurnFooter({
|
||||
inFlightTurnStartedAt,
|
||||
host,
|
||||
strategy,
|
||||
supportsTimelineCursor,
|
||||
onForkAssistantTurn,
|
||||
}: {
|
||||
isRunning: boolean;
|
||||
inFlightTurnStartedAt: Date | null;
|
||||
host: TurnFooterHost | null;
|
||||
strategy: TurnContentStrategy;
|
||||
supportsTimelineCursor: boolean;
|
||||
onForkAssistantTurn?: AssistantTurnForkHandler;
|
||||
}) {
|
||||
if (isRunning) {
|
||||
@@ -63,6 +65,7 @@ export const TurnFooter = memo(function TurnFooter({
|
||||
items={host.items}
|
||||
timing={host.timing}
|
||||
startIndex={host.startIndex}
|
||||
supportsTimelineCursor={supportsTimelineCursor}
|
||||
onForkAssistantTurn={onForkAssistantTurn}
|
||||
/>
|
||||
);
|
||||
@@ -73,12 +76,14 @@ export const CompletedTurnFooterRow = memo(function CompletedTurnFooterRow({
|
||||
items,
|
||||
timing,
|
||||
startIndex,
|
||||
supportsTimelineCursor,
|
||||
onForkAssistantTurn,
|
||||
}: {
|
||||
strategy: TurnContentStrategy;
|
||||
items: StreamItem[];
|
||||
timing?: TurnTiming;
|
||||
startIndex: number;
|
||||
supportsTimelineCursor: boolean;
|
||||
onForkAssistantTurn?: AssistantTurnForkHandler;
|
||||
}) {
|
||||
return (
|
||||
@@ -88,6 +93,7 @@ export const CompletedTurnFooterRow = memo(function CompletedTurnFooterRow({
|
||||
items={items}
|
||||
timing={timing}
|
||||
startIndex={startIndex}
|
||||
supportsTimelineCursor={supportsTimelineCursor}
|
||||
onForkAssistantTurn={onForkAssistantTurn}
|
||||
/>
|
||||
</TurnFooterRow>
|
||||
@@ -130,12 +136,14 @@ function CompletedTurnFooter({
|
||||
items,
|
||||
timing,
|
||||
startIndex,
|
||||
supportsTimelineCursor,
|
||||
onForkAssistantTurn,
|
||||
}: {
|
||||
strategy: TurnContentStrategy;
|
||||
items: StreamItem[];
|
||||
timing?: TurnTiming;
|
||||
startIndex: number;
|
||||
supportsTimelineCursor: boolean;
|
||||
onForkAssistantTurn?: AssistantTurnForkHandler;
|
||||
}) {
|
||||
const getContent = useCallback(
|
||||
@@ -147,18 +155,27 @@ function CompletedTurnFooter({
|
||||
}),
|
||||
[strategy, items, startIndex],
|
||||
);
|
||||
const boundaryMessageId = resolveAssistantTurnBoundaryMessageId({
|
||||
const boundary = resolveAssistantTurnForkBoundary({
|
||||
items,
|
||||
startIndex,
|
||||
supportsTimelineCursor,
|
||||
});
|
||||
const handleFork = useCallback(
|
||||
(target: AssistantForkTarget) => {
|
||||
if (!boundary) {
|
||||
return;
|
||||
}
|
||||
return onForkAssistantTurn?.({ target, boundary });
|
||||
},
|
||||
[boundary, onForkAssistantTurn],
|
||||
);
|
||||
return (
|
||||
<View style={stylesheet.turnFooterSlot}>
|
||||
<AssistantTurnFooter
|
||||
getContent={getContent}
|
||||
completedAt={timing?.completedAt}
|
||||
durationMs={timing?.durationMs}
|
||||
forkBoundaryMessageId={boundaryMessageId}
|
||||
onFork={onForkAssistantTurn}
|
||||
onFork={boundary && onForkAssistantTurn ? handleFork : undefined}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user