@@ -130,60 +130,6 @@ function isStalePendingApprovalFailureDetail(detail: string | null): boolean {
130130 ) ;
131131}
132132
133- function isStalePendingUserInputFailureDetail ( detail : string | null ) : boolean {
134- if ( detail === null ) {
135- return false ;
136- }
137- return (
138- detail . includes ( "stale pending user-input request" ) ||
139- detail . includes ( "unknown pending user-input request" ) ||
140- detail . includes ( "unknown pending user input request" ) ||
141- detail . includes ( "unknown pending codex user input request" )
142- ) ;
143- }
144-
145- function derivePendingUserInputCountFromActivities (
146- activities : ReadonlyArray < ProjectionThreadActivity > ,
147- ) : number {
148- const openRequestIds = new Set < string > ( ) ;
149- const ordered = [ ...activities ] . toSorted (
150- ( left , right ) =>
151- left . createdAt . localeCompare ( right . createdAt ) ||
152- left . activityId . localeCompare ( right . activityId ) ,
153- ) ;
154-
155- for ( const activity of ordered ) {
156- const requestId = extractActivityRequestId ( activity . payload ) ;
157- if ( requestId === null ) {
158- continue ;
159- }
160- const payload =
161- typeof activity . payload === "object" && activity . payload !== null
162- ? ( activity . payload as Record < string , unknown > )
163- : null ;
164- const detail = typeof payload ?. detail === "string" ? payload . detail . toLowerCase ( ) : null ;
165-
166- if ( activity . kind === "user-input.requested" ) {
167- openRequestIds . add ( requestId ) ;
168- continue ;
169- }
170-
171- if ( activity . kind === "user-input.resolved" ) {
172- openRequestIds . delete ( requestId ) ;
173- continue ;
174- }
175-
176- if (
177- activity . kind === "provider.user-input.respond.failed" &&
178- isStalePendingUserInputFailureDetail ( detail )
179- ) {
180- openRequestIds . delete ( requestId ) ;
181- }
182- }
183-
184- return openRequestIds . size ;
185- }
186-
187133function deriveHasActionableProposedPlan ( input : {
188134 readonly latestTurnId : string | null ;
189135 readonly proposedPlans : ReadonlyArray < ProjectionThreadProposedPlan > ;
@@ -570,27 +516,18 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
570516 return ;
571517 }
572518
573- const [ messages , proposedPlans , activities , pendingApprovals ] = yield * Effect . all ( [
574- projectionThreadMessageRepository . listByThreadId ( { threadId } ) ,
575- projectionThreadProposedPlanRepository . listByThreadId ( { threadId } ) ,
576- projectionThreadActivityRepository . listByThreadId ( { threadId } ) ,
577- projectionPendingApprovalRepository . listByThreadId ( { threadId } ) ,
578- ] ) ;
579-
580- let latestUserMessageAt : string | null = null ;
581- for ( const message of messages ) {
582- if (
583- message . role === "user" &&
584- ( latestUserMessageAt === null || message . createdAt > latestUserMessageAt )
585- ) {
586- latestUserMessageAt = message . createdAt ;
587- }
588- }
519+ const [ latestUserMessageAtOption , proposedPlans , pendingUserInputCount , pendingApprovals ] =
520+ yield * Effect . all ( [
521+ projectionThreadMessageRepository . getLatestUserMessageAtByThreadId ( { threadId } ) ,
522+ projectionThreadProposedPlanRepository . listByThreadId ( { threadId } ) ,
523+ projectionThreadActivityRepository . countPendingUserInputsByThreadId ( { threadId } ) ,
524+ projectionPendingApprovalRepository . listByThreadId ( { threadId } ) ,
525+ ] ) ;
589526
527+ const latestUserMessageAt = Option . getOrNull ( latestUserMessageAtOption ) ;
590528 const pendingApprovalCount = pendingApprovals . filter (
591529 ( approval ) => approval . status === "pending" ,
592530 ) . length ;
593- const pendingUserInputCount = derivePendingUserInputCountFromActivities ( activities ) ;
594531 const hasActionableProposedPlan = deriveHasActionableProposedPlan ( {
595532 latestTurnId : existingRow . value . latestTurnId ,
596533 proposedPlans,
@@ -877,20 +814,11 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
877814
878815 switch ( event . type ) {
879816 case "thread.message-sent" : {
880- if ( event . payload . role !== "user" ) {
881- break ;
882- }
883- const projectedMessage = yield * projectionThreadMessageRepository . getByMessageId ( {
884- messageId : event . payload . messageId ,
885- } ) ;
886- if (
887- Option . isSome ( projectedMessage ) &&
888- projectedMessage . value . role === "user" &&
889- ( latestUserMessageAt === null ||
890- projectedMessage . value . createdAt > latestUserMessageAt )
891- ) {
892- latestUserMessageAt = projectedMessage . value . createdAt ;
893- }
817+ latestUserMessageAt = Option . getOrNull (
818+ yield * projectionThreadMessageRepository . getLatestUserMessageAtByThreadId ( {
819+ threadId : event . payload . threadId ,
820+ } ) ,
821+ ) ;
894822 break ;
895823 }
896824
@@ -931,17 +859,10 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
931859 ) . length ;
932860 }
933861
934- if (
935- kind === "user-input.requested" ||
936- kind === "user-input.resolved" ||
937- ( kind === "provider.user-input.respond.failed" &&
938- isStalePendingUserInputFailureDetail ( detail ) )
939- ) {
940- pendingUserInputCount =
941- yield * projectionThreadActivityRepository . countPendingUserInputsByThreadId ( {
942- threadId : event . payload . threadId ,
943- } ) ;
944- }
862+ pendingUserInputCount =
863+ yield * projectionThreadActivityRepository . countPendingUserInputsByThreadId ( {
864+ threadId : event . payload . threadId ,
865+ } ) ;
945866 break ;
946867 }
947868
0 commit comments