1- import crypto from "node:crypto" ;
21import fs from "node:fs/promises" ;
32import {
43 hasSessionAutoModelFallbackProvenance ,
@@ -103,7 +102,6 @@ import {
103102 type ReplyOperation ,
104103} from "./reply-run-registry.js" ;
105104import { createReplyToModeFilterForChannel , resolveReplyToMode } from "./reply-threading.js" ;
106- import { clearSessionResetRuntimeState } from "./session-reset-cleanup.js" ;
107105import { incrementRunCompactionCount , persistRunSessionUsage } from "./session-run-accounting.js" ;
108106import { resolveSourceReplyVisibilityPolicy } from "./source-reply-delivery-mode.js" ;
109107import { createTypingSignaler } from "./typing-mode.js" ;
@@ -115,54 +113,6 @@ function isReplayInvalidAgentRunError(error: unknown): boolean {
115113 return classifyProviderRuntimeFailureKind ( formatErrorMessage ( error ) ) === "replay_invalid" ;
116114}
117115
118- function buildReplayInvalidSessionResetPatch ( now : number ) : Partial < SessionEntry > {
119- return {
120- sessionId : crypto . randomUUID ( ) ,
121- sessionFile : undefined ,
122- updatedAt : now ,
123- sessionStartedAt : now ,
124- lastInteractionAt : now ,
125- systemSent : false ,
126- abortedLastRun : false ,
127- status : undefined ,
128- startedAt : undefined ,
129- endedAt : undefined ,
130- runtimeMs : undefined ,
131- totalTokens : undefined ,
132- inputTokens : undefined ,
133- outputTokens : undefined ,
134- totalTokensFresh : undefined ,
135- estimatedCostUsd : undefined ,
136- cacheRead : undefined ,
137- cacheWrite : undefined ,
138- contextTokens : undefined ,
139- responseUsage : undefined ,
140- modelProvider : undefined ,
141- model : undefined ,
142- agentHarnessId : undefined ,
143- fallbackNoticeSelectedModel : undefined ,
144- fallbackNoticeActiveModel : undefined ,
145- fallbackNoticeReason : undefined ,
146- compactionCount : 0 ,
147- memoryFlushAt : undefined ,
148- memoryFlushCompactionCount : undefined ,
149- memoryFlushContextHash : undefined ,
150- pendingFinalDelivery : undefined ,
151- pendingFinalDeliveryCreatedAt : undefined ,
152- pendingFinalDeliveryLastAttemptAt : undefined ,
153- pendingFinalDeliveryAttemptCount : undefined ,
154- pendingFinalDeliveryLastError : undefined ,
155- pendingFinalDeliveryText : undefined ,
156- pendingFinalDeliveryContext : undefined ,
157- pendingFinalDeliveryIntentId : undefined ,
158- cliSessionIds : undefined ,
159- cliSessionBindings : undefined ,
160- claudeCliSessionId : undefined ,
161- skillsSnapshot : undefined ,
162- systemPromptReport : undefined ,
163- } ;
164- }
165-
166116function markBeforeAgentRunBlockedPayloads ( payloads : ReplyPayload [ ] ) : ReplyPayload [ ] {
167117 return payloads . map ( ( payload ) =>
168118 setReplyPayloadMetadata ( payload , { beforeAgentRunBlocked : true } ) ,
@@ -1209,52 +1159,44 @@ export async function runReplyAgent(params: {
12091159 } ) ;
12101160 }
12111161 } ;
1212- const resetSessionAfterReplayInvalid = async ( reason : string ) : Promise < boolean > => {
1213- if ( ! sessionKey ) {
1214- return false ;
1215- }
1216- const oldSessionId = activeSessionEntry ?. sessionId ;
1217- const patch = buildReplayInvalidSessionResetPatch ( Date . now ( ) ) ;
1218- let didReset = false ;
1219- if ( activeSessionStore && activeSessionEntry ) {
1220- const nextEntry = { ...activeSessionEntry , ...patch } as SessionEntry ;
1221- activeSessionStore [ sessionKey ] = nextEntry ;
1222- activeSessionEntry = nextEntry ;
1223- didReset = true ;
1224- }
1225- if ( storePath ) {
1226- try {
1227- const updated = await updateSessionStoreEntry ( {
1228- storePath,
1229- sessionKey,
1230- update : async ( ) => patch ,
1231- } ) ;
1232- if ( updated ) {
1233- activeSessionEntry = updated ;
1234- if ( activeSessionStore ) {
1235- activeSessionStore [ sessionKey ] = updated ;
1236- }
1237- didReset = true ;
1238- }
1239- } catch ( resetError ) {
1240- logVerbose (
1241- `failed to reset replay-invalid session ${ sessionKey } : ${ formatErrorMessage ( resetError ) } ` ,
1242- ) ;
1243- }
1244- }
1245- if ( ! didReset ) {
1246- return false ;
1247- }
1248- followupRun . run . sessionId = String ( patch . sessionId ) ;
1249- activeIsNewSession = true ;
1250- clearSessionResetRuntimeState ( [ sessionKey , oldSessionId ] ) ;
1251- logVerbose (
1252- `reset replay-invalid session ${ sessionKey } ` +
1253- ( oldSessionId ? ` (${ oldSessionId } -> ${ String ( patch . sessionId ) } )` : "" ) +
1254- ` after ${ reason } ` ,
1255- ) ;
1256- return true ;
1162+ type SessionResetOptions = {
1163+ failureLabel : string ;
1164+ buildLogMessage : ( nextSessionId : string ) => string ;
1165+ cleanupTranscripts ?: boolean ;
12571166 } ;
1167+ const resetSession = async ( {
1168+ failureLabel,
1169+ buildLogMessage,
1170+ cleanupTranscripts,
1171+ } : SessionResetOptions ) : Promise < boolean > =>
1172+ await resetReplyRunSession ( {
1173+ options : {
1174+ failureLabel,
1175+ buildLogMessage,
1176+ cleanupTranscripts,
1177+ } ,
1178+ sessionKey,
1179+ queueKey,
1180+ activeSessionEntry,
1181+ activeSessionStore,
1182+ storePath,
1183+ messageThreadId :
1184+ typeof sessionCtx . MessageThreadId === "string" ? sessionCtx . MessageThreadId : undefined ,
1185+ followupRun,
1186+ onActiveSessionEntry : ( nextEntry ) => {
1187+ activeSessionEntry = nextEntry ;
1188+ } ,
1189+ onNewSession : ( ) => {
1190+ activeIsNewSession = true ;
1191+ } ,
1192+ } ) ;
1193+ const resetSessionAfterReplayInvalid = async ( reason : string ) : Promise < boolean > =>
1194+ resetSession ( {
1195+ failureLabel : "replay-invalid session state" ,
1196+ buildLogMessage : ( nextSessionId ) =>
1197+ `Replay-invalid session state (${ reason } ). Restarting session ${ sessionKey } -> ${ nextSessionId } .` ,
1198+ cleanupTranscripts : true ,
1199+ } ) ;
12581200
12591201 if ( effectiveShouldSteer && isStreaming ) {
12601202 const steerSessionId =
@@ -1508,37 +1450,6 @@ export async function runReplyAgent(params: {
15081450 } ) ;
15091451
15101452 let responseUsageLine : string | undefined ;
1511- type SessionResetOptions = {
1512- failureLabel : string ;
1513- buildLogMessage : ( nextSessionId : string ) => string ;
1514- cleanupTranscripts ?: boolean ;
1515- } ;
1516- const resetSession = async ( {
1517- failureLabel,
1518- buildLogMessage,
1519- cleanupTranscripts,
1520- } : SessionResetOptions ) : Promise < boolean > =>
1521- await resetReplyRunSession ( {
1522- options : {
1523- failureLabel,
1524- buildLogMessage,
1525- cleanupTranscripts,
1526- } ,
1527- sessionKey,
1528- queueKey,
1529- activeSessionEntry,
1530- activeSessionStore,
1531- storePath,
1532- messageThreadId :
1533- typeof sessionCtx . MessageThreadId === "string" ? sessionCtx . MessageThreadId : undefined ,
1534- followupRun,
1535- onActiveSessionEntry : ( nextEntry ) => {
1536- activeSessionEntry = nextEntry ;
1537- } ,
1538- onNewSession : ( ) => {
1539- activeIsNewSession = true ;
1540- } ,
1541- } ) ;
15421453 const resetSessionAfterRoleOrderingConflict = async ( reason : string ) : Promise < boolean > =>
15431454 resetSession ( {
15441455 failureLabel : "role ordering conflict" ,
0 commit comments