@@ -9,6 +9,7 @@ import { resolveContextTokensForModel } from "../../agents/context.js";
99import { DEFAULT_CONTEXT_TOKENS } from "../../agents/defaults.js" ;
1010import { resolveModelAuthMode } from "../../agents/model-auth.js" ;
1111import { isCliProvider } from "../../agents/model-selection.js" ;
12+ import type { MessagingToolSend } from "../../agents/pi-embedded-messaging.types.js" ;
1213import {
1314 formatEmbeddedPiQueueFailureSummary ,
1415 queueEmbeddedPiMessageWithOutcomeAsync ,
@@ -37,7 +38,10 @@ import { enqueueSystemEvent } from "../../infra/system-events.js";
3738import { CommandLaneClearedError , GatewayDrainingError } from "../../process/command-queue.js" ;
3839import { shouldPreserveUserFacingSessionStateForInputProvenance } from "../../sessions/input-provenance.js" ;
3940import { resolveSendPolicy } from "../../sessions/send-policy.js" ;
40- import { normalizeOptionalString } from "../../shared/string-coerce.js" ;
41+ import {
42+ normalizeOptionalString ,
43+ normalizeOptionalStringifiedId ,
44+ } from "../../shared/string-coerce.js" ;
4145import {
4246 estimateUsageCost ,
4347 formatTokenCount ,
@@ -95,6 +99,7 @@ import {
9599 type QueueSettings ,
96100} from "./queue.js" ;
97101import { createReplyMediaContext } from "./reply-media-paths.js" ;
102+ import { getMatchingMessagingToolReplyTargets } from "./reply-payloads-dedupe.js" ;
98103import { replyRunRegistry , type ReplyOperation } from "./reply-run-registry.js" ;
99104import { createReplyToModeFilterForChannel , resolveReplyToMode } from "./reply-threading.js" ;
100105import { admitReplyTurn , resolveReplyTurnKind } from "./reply-turn-admission.js" ;
@@ -170,8 +175,18 @@ function isAcknowledgedLongworkMessagingText(value: string): boolean {
170175 }
171176 // Keep this guard conservative: a generic checkpoint is only helpful when the
172177 // earlier message looks like an ACK/progress commitment, not a final result.
178+ if (
179+ / \b (?: d o n e | f i n i s h e d | c o m p l e t e d | c o m p l e t e | r e a d y | r e s o l v e d | f i x e d | p a s s e d | s u c c e s s (?: f u l l y ) ? | s e n t | d e l i v e r e d ) \b / . test (
180+ normalized ,
181+ ) &&
182+ / \b (?: i (?: ' | ’ ) ? m | i a m | i (?: ' | ’ ) ? v e | i h a v e | t e s t s ? | c h e c k s ? | p a t c h | r e s u l t | s u m m a r y | r e p o r t | f i n a l | r e p l y | m e s s a g e ) \b / . test (
183+ normalized ,
184+ )
185+ ) {
186+ return false ;
187+ }
173188 return (
174- / \b ( i (?: ' | ’ ) ? l l | i w i l l | i a m | i ' m | w o r k i n g | s t a r t i n g | c h e c k i n g | i n v e s t i g a t i n g | c o n t i n u e | h a n d l e | l o o k i n t o | g o i n g t o | d e t a c h i n g ) \b / . test (
189+ / \b ( i (?: ' | ’ ) ? l l | i w i l l | w o r k i n g | s t a r t i n g | c h e c k i n g | i n v e s t i g a t i n g | c o n t i n u (?: e | i n g ) | h a n d l i n g | h a n d l e | l o o k i n t o | g o i n g t o | d e t a c h i n g ) \b / . test (
175190 normalized ,
176191 ) || / 收 到 | 我 会 | 我 先 | 继 续 | 处 理 | 处 理 中 | 开 始 | 稍 后 | 马 上 | 先 .* [ 看 查 做 ] / . test ( value )
177192 ) ;
@@ -201,12 +216,42 @@ function hasAcknowledgedLongworkMessagingText(params: {
201216 } ) ;
202217}
203218
219+ function resolveAcknowledgedLongworkRouteTexts ( params : {
220+ followupRun : FollowupRun ;
221+ sessionCtx : TemplateContext ;
222+ messagingToolSentTargets ?: MessagingToolSend [ ] ;
223+ } ) : string [ ] {
224+ const sentTargets = params . messagingToolSentTargets ?? [ ] ;
225+ const matchingTargets = getMatchingMessagingToolReplyTargets ( {
226+ messageProvider : resolveOriginMessageProvider ( {
227+ originatingChannel : params . sessionCtx . OriginatingChannel ,
228+ provider : params . followupRun . run . messageProvider ,
229+ } ) ,
230+ messagingToolSentTargets : sentTargets ,
231+ originatingTo : resolveOriginMessageTo ( {
232+ originatingTo : params . sessionCtx . OriginatingTo ,
233+ to : params . sessionCtx . To ,
234+ } ) ,
235+ accountId : params . sessionCtx . AccountId ,
236+ } ) . filter ( ( target ) => {
237+ const originThreadId = normalizeOptionalStringifiedId ( params . sessionCtx . MessageThreadId ) ;
238+ const targetThreadId = normalizeOptionalStringifiedId ( target . threadId ) ;
239+ if ( ! originThreadId ) {
240+ return ! targetThreadId ;
241+ }
242+ return targetThreadId === originThreadId ;
243+ } ) ;
244+ return matchingTargets . flatMap ( ( target ) =>
245+ typeof target . text === "string" && target . text . trim ( ) ? [ target . text ] : [ ] ,
246+ ) ;
247+ }
248+
204249function hasSuccessfulSideEffectDelivery ( params : {
205250 blockReplyPipeline : { didStream : ( ) => boolean ; isAborted : ( ) => boolean } | null ;
206251 directlySentBlockKeys ?: Set < string > ;
207252 messagingToolSentTexts ?: string [ ] ;
208253 messagingToolSentMediaUrls ?: string [ ] ;
209- messagingToolSentTargets ?: unknown [ ] ;
254+ messagingToolSentTargets ?: MessagingToolSend [ ] ;
210255 successfulCronAdds ?: number ;
211256 didSendDeterministicApprovalPrompt ?: boolean ;
212257} ) : boolean {
@@ -248,7 +293,7 @@ function shouldSurfaceAcknowledgedLongworkCheckpoint(params: {
248293 toolActivityAfterMessagingToolDelivery ?: boolean ;
249294 messagingToolSentTexts ?: string [ ] ;
250295 messagingToolSentMediaUrls ?: string [ ] ;
251- messagingToolSentTargets ?: unknown [ ] ;
296+ messagingToolSentTargets ?: MessagingToolSend [ ] ;
252297 successfulCronAdds ?: number ;
253298 didSendDeterministicApprovalPrompt ?: boolean ;
254299} ) : boolean {
@@ -263,10 +308,14 @@ function shouldSurfaceAcknowledgedLongworkCheckpoint(params: {
263308 ) {
264309 return false ;
265310 }
266- return hasAcknowledgedLongworkMessagingText ( {
267- messagingToolSentTexts : params . messagingToolSentTexts ,
311+ const routeSentTexts = resolveAcknowledgedLongworkRouteTexts ( {
312+ followupRun : params . followupRun ,
313+ sessionCtx : params . sessionCtx ,
268314 messagingToolSentTargets : params . messagingToolSentTargets ,
269315 } ) ;
316+ return hasAcknowledgedLongworkMessagingText ( {
317+ messagingToolSentTexts : routeSentTexts ,
318+ } ) ;
270319}
271320
272321function resolveConfiguredFallbackModel ( params : {
0 commit comments