@@ -43,6 +43,7 @@ import { normalizeChatType } from "../../channels/chat-type.js";
4343import { resolveChannelModelOverride } from "../../channels/model-overrides.js" ;
4444import { shouldSuppressLocalExecApprovalPrompt } from "../../channels/plugins/exec-approval-local.js" ;
4545import { applyMergePatch } from "../../config/merge-patch.js" ;
46+ import { normalizeExplicitSessionKey } from "../../config/sessions/explicit-session-key-normalization.js" ;
4647import { resolveGroupSessionKey } from "../../config/sessions/group.js" ;
4748import {
4849 appendAssistantMessageToSessionTranscript ,
@@ -142,6 +143,7 @@ import type {
142143} from "./dispatch-from-config.types.js" ;
143144import { resolveEffectiveReplyRoute } from "./effective-reply-route.js" ;
144145import { withFullRuntimeReplyConfig } from "./get-reply-fast-path.js" ;
146+ import type { ReplySessionBinding } from "./get-reply.types.js" ;
145147import { claimInboundDedupe , commitInboundDedupe , releaseInboundDedupe } from "./inbound-dedupe.js" ;
146148import { hasInboundAudio } from "./inbound-media.js" ;
147149import { resolveOriginMessageProvider } from "./origin-routing.js" ;
@@ -180,6 +182,7 @@ type TranscriptMirror = SourceReplyTranscriptMirror & {
180182} ;
181183type InternalReplyResolverOptions = {
182184 onSessionMetadataChanges ?: ( changes : CommandSessionMetadataChange [ ] ) => void ;
185+ onSessionPrepared ?: ( binding : ReplySessionBinding ) => void ;
183186} ;
184187
185188class DispatchReplyOperationAbortedError extends Error {
@@ -1225,6 +1228,34 @@ export async function dispatchReplyFromConfig(
12251228 const sessionStoreEntry = boundAcpDispatchSessionKey
12261229 ? resolveSessionStoreLookup ( { ...ctx , SessionKey : boundAcpDispatchSessionKey } , cfg )
12271230 : initialSessionStoreEntry ;
1231+ let preparedSessionBinding : ReplySessionBinding | undefined =
1232+ sessionStoreEntry . sessionKey && sessionStoreEntry . entry ?. sessionId
1233+ ? {
1234+ sessionKey : sessionStoreEntry . sessionKey ,
1235+ sessionId : sessionStoreEntry . entry . sessionId ,
1236+ storePath : sessionStoreEntry . storePath ,
1237+ }
1238+ : undefined ;
1239+ const sessionKeysMatch = ( left ?: string , right ?: string ) =>
1240+ Boolean (
1241+ left &&
1242+ right &&
1243+ normalizeExplicitSessionKey ( left , ctx ) === normalizeExplicitSessionKey ( right , ctx ) ,
1244+ ) ;
1245+ const notePreparedSession = ( binding : ReplySessionBinding ) => {
1246+ if ( sessionKeysMatch ( binding . sessionKey , sessionStoreEntry . sessionKey ) ) {
1247+ preparedSessionBinding = binding ;
1248+ }
1249+ } ;
1250+ const resolvePreparedTranscriptBinding = ( mirrorSessionKey ?: string ) => {
1251+ if (
1252+ ! preparedSessionBinding ||
1253+ ! sessionKeysMatch ( mirrorSessionKey , preparedSessionBinding . sessionKey )
1254+ ) {
1255+ return undefined ;
1256+ }
1257+ return preparedSessionBinding ;
1258+ } ;
12281259 const sessionAgentId = resolveSessionAgentId ( {
12291260 sessionKey : acpDispatchSessionKey ,
12301261 config : cfg ,
@@ -2250,14 +2281,16 @@ export async function dispatchReplyFromConfig(
22502281 await flushPendingCommentaryProgress ( ) ;
22512282 throwIfFinalDeliveryAborted ( ) ;
22522283 const payloadMetadata = getReplyPayloadMetadata ( payload ) ;
2284+ const sourceReplySessionBinding = resolvePreparedTranscriptBinding (
2285+ payloadMetadata ?. sourceReplyTranscriptMirror ?. sessionKey ,
2286+ ) ;
22532287 const sourceReplyTranscriptMirror = payloadMetadata ?. sourceReplyTranscriptMirror
22542288 ? {
22552289 ...payloadMetadata . sourceReplyTranscriptMirror ,
2256- ...( payloadMetadata . sourceReplyTranscriptMirror . sessionKey ===
2257- sessionStoreEntry . sessionKey && sessionStoreEntry . entry ?. sessionId
2258- ? { expectedSessionId : sessionStoreEntry . entry . sessionId }
2290+ ...( sourceReplySessionBinding
2291+ ? { expectedSessionId : sourceReplySessionBinding . sessionId }
22592292 : { } ) ,
2260- storePath : sessionStoreEntry . storePath ,
2293+ storePath : sourceReplySessionBinding ?. storePath ?? sessionStoreEntry . storePath ,
22612294 }
22622295 : undefined ;
22632296 const hasTranscriptOwner =
@@ -2309,6 +2342,9 @@ export async function dispatchReplyFromConfig(
23092342 const transcriptMirrorSourceId =
23102343 normalizeOptionalString ( messageIdForHook ) ??
23112344 normalizeOptionalString ( params . replyOptions ?. runId ) ;
2345+ const transcriptMirrorSessionBinding = resolvePreparedTranscriptBinding (
2346+ transcriptMirrorSessionKey ,
2347+ ) ;
23122348 const transcriptMirror =
23132349 sourceReplyTranscriptMirror ??
23142350 ( ! hasTranscriptOwner &&
@@ -2319,11 +2355,10 @@ export async function dispatchReplyFromConfig(
23192355 {
23202356 sessionKey : transcriptMirrorSessionKey ,
23212357 agentId : sessionAgentId ,
2322- ...( transcriptMirrorSessionKey === sessionStoreEntry . sessionKey &&
2323- sessionStoreEntry . entry ?. sessionId
2324- ? { expectedSessionId : sessionStoreEntry . entry . sessionId }
2358+ ...( transcriptMirrorSessionBinding
2359+ ? { expectedSessionId : transcriptMirrorSessionBinding . sessionId }
23252360 : { } ) ,
2326- storePath : sessionStoreEntry . storePath ,
2361+ storePath : transcriptMirrorSessionBinding ?. storePath ?? sessionStoreEntry . storePath ,
23272362 preferText : true ,
23282363 idempotencyKey : transcriptMirrorSourceId
23292364 ? `channel-final:${ transcriptMirrorSourceId } :${ options . deliveryId ?? "single" } `
@@ -2795,6 +2830,7 @@ export async function dispatchReplyFromConfig(
27952830 sourceReplyDeliveryMode,
27962831 ...( {
27972832 onSessionMetadataChanges : notifySessionMetadataChanges ,
2833+ onSessionPrepared : notePreparedSession ,
27982834 } satisfies InternalReplyResolverOptions ) ,
27992835 onObservedReplyDelivery : markObservedReplyDelivery ,
28002836 suppressToolErrorWarnings,
0 commit comments