fix(session): remove duplicated turn-end step

This commit is contained in:
_Kerman
2026-08-04 14:10:07 +08:00
parent e874910a76
commit ab441389b2
10 changed files with 46 additions and 46 deletions

View File

@@ -1516,7 +1516,7 @@ export function createFixtureApi(options: FixtureOptions = {}): ApiProxy {
},
})
append(sessionId, { type: 'step/end', data: { turn: scenario.turn, step: 1 } })
append(sessionId, { type: 'turn/end', data: { turn: scenario.turn, step: 1, reason: { kind: 'aborted', reason: { kind: 'user' } },
append(sessionId, { type: 'turn/end', data: { turn: scenario.turn, reason: { kind: 'aborted', reason: { kind: 'user' } },
} })
retryScenarios.delete(sessionId)
setRunning(sessionId, false)
@@ -1542,7 +1542,7 @@ export function createFixtureApi(options: FixtureOptions = {}): ApiProxy {
},
})
append(sessionId, { type: 'step/end', data: { turn: scenario.turn, step: 1 } })
append(sessionId, { type: 'turn/end', data: { turn: scenario.turn, step: 1, reason: { kind: 'completed' } } })
append(sessionId, { type: 'turn/end', data: { turn: scenario.turn, reason: { kind: 'completed' } } })
setRunning(sessionId, false)
},
/** Log append WITHOUT the mux emit: a frame lost in transit — history still serves it, the client must repull. */

View File

@@ -240,6 +240,7 @@ function promptChange(
function deriveRequests(events: readonly SessionEvent[]): readonly RequestView[] {
const requests: RequestView[] = []
const ordinaryByStep = new Map<string, number>()
const lastStepByTurn = new Map<number, string>()
let activeStep: string | undefined
let activePrompt: ConversationPromptSnapshot | undefined
let activeCompaction: number | undefined
@@ -266,6 +267,7 @@ function deriveRequests(events: readonly SessionEvent[]): readonly RequestView[]
const { turn, step } = sourceEvent.data
const key = requestKey(turn, step)
ordinaryByStep.set(key, requests.length)
lastStepByTurn.set(turn, key)
requests.push({
purpose: 'assistant',
startSeq: sourceEvent.seq,
@@ -358,12 +360,15 @@ function deriveRequests(events: readonly SessionEvent[]): readonly RequestView[]
})
continue
}
if (sourceEvent.type === 'turn/end' && sourceEvent.data.reason.kind === 'error') {
const reason = sourceEvent.data.reason
updateAssistant(ordinaryByStep.get(requestKey(sourceEvent.data.turn, sourceEvent.data.step)), {
status: 'error',
error: displayFailureMessage(reason.error),
})
if (sourceEvent.type === 'turn/end') {
const lastStep = lastStepByTurn.get(sourceEvent.data.turn)
if (sourceEvent.data.reason.kind === 'error') {
updateAssistant(lastStep === undefined ? undefined : ordinaryByStep.get(lastStep), {
status: 'error',
error: displayFailureMessage(sourceEvent.data.reason.error),
})
}
lastStepByTurn.delete(sourceEvent.data.turn)
continue
}

View File

@@ -98,6 +98,8 @@ export class Session implements SessionFace {
private readonly transcript = new TranscriptAdapter()
private partial: PartialAccumulator | null = null
private openCalls = new Map<string, RunningToolCall>()
/** Last entered step per turn, folded from step/start for terminal error placement. */
private lastStepByTurn = new Map<number, number>()
/** Operational notices and interrupted-turn terminal nodes merged into the flow by seq.
* Derived from window events and rebuilt with partial/openCalls; the transcript is
* seq-monotonic, so a plain seq merge preserves event order. */
@@ -796,6 +798,10 @@ export class Session implements SessionFace {
}
switch (event.type) {
case 'turn/start':
this.lastStepByTurn.set(event.data.turn, 0)
return
case 'step/start':
this.lastStepByTurn.set(event.data.turn, event.data.step)
return
case 'assistant/chunk': {
const { turn, step, chunk } = event.data
@@ -826,6 +832,7 @@ export class Session implements SessionFace {
return
}
case 'turn/end': {
const lastStep = this.lastStepByTurn.get(event.data.turn) ?? 0
this.turnEnds.set(event.data.turn, event.seq)
this.turnEndsRev++
if (event.data.reason.kind === 'aborted') {
@@ -841,7 +848,7 @@ export class Session implements SessionFace {
seq: event.seq,
time: event.time,
turn: event.data.turn,
step: event.data.step,
step: lastStep,
message: displayFailureMessage(failure),
code: failure.code,
})
@@ -882,6 +889,7 @@ export class Session implements SessionFace {
})
this.derivedRev++
}
this.lastStepByTurn.delete(event.data.turn)
return
}
default:
@@ -916,6 +924,7 @@ export class Session implements SessionFace {
private rebuildDerivedFromWindow(): void {
this.partial = null
this.openCalls.clear()
this.lastStepByTurn.clear()
this.callsRev++
this.derivedNodes = []
this.derivedRev++