@@ -350,36 +350,38 @@ private async Task<string> SearchTextAsync(string userQuestion, ChatHistoryMemor
350350 string ? userId = searchScope . UserId ;
351351 string ? sessionId = searchScope . SessionId ;
352352
353- Expression < Func < Dictionary < string , object ? > , bool > > ? filter = null ;
353+ // Build a combined filter using a single shared parameter to avoid expression tree
354+ // scoping issues when multiple filters are combined with AndAlso.
355+ ParameterExpression parameter = Expression . Parameter ( typeof ( Dictionary < string , object ? > ) , "x" ) ;
356+ Expression ? filterBody = null ;
357+
354358 if ( applicationId != null )
355359 {
356- filter = x => ( string ? ) x [ ApplicationIdField ] == applicationId ;
360+ filterBody = RebindFilterBody ( x => ( string ? ) x [ ApplicationIdField ] == applicationId , parameter ) ;
357361 }
358362
359363 if ( agentId != null )
360364 {
361- Expression < Func < Dictionary < string , object ? > , bool > > agentIdFilter = x => ( string ? ) x [ AgentIdField ] == agentId ;
362- filter = filter == null ? agentIdFilter : Expression . Lambda < Func < Dictionary < string , object ? > , bool > > (
363- Expression . AndAlso ( filter . Body , agentIdFilter . Body ) ,
364- filter . Parameters ) ;
365+ Expression body = RebindFilterBody ( x => ( string ? ) x [ AgentIdField ] == agentId , parameter ) ;
366+ filterBody = filterBody == null ? body : Expression . AndAlso ( filterBody , body ) ;
365367 }
366368
367369 if ( userId != null )
368370 {
369- Expression < Func < Dictionary < string , object ? > , bool > > userIdFilter = x => ( string ? ) x [ UserIdField ] == userId ;
370- filter = filter == null ? userIdFilter : Expression . Lambda < Func < Dictionary < string , object ? > , bool > > (
371- Expression . AndAlso ( filter . Body , userIdFilter . Body ) ,
372- filter . Parameters ) ;
371+ Expression body = RebindFilterBody ( x => ( string ? ) x [ UserIdField ] == userId , parameter ) ;
372+ filterBody = filterBody == null ? body : Expression . AndAlso ( filterBody , body ) ;
373373 }
374374
375375 if ( sessionId != null )
376376 {
377- Expression < Func < Dictionary < string , object ? > , bool > > sessionIdFilter = x => ( string ? ) x [ SessionIdField ] == sessionId ;
378- filter = filter == null ? sessionIdFilter : Expression . Lambda < Func < Dictionary < string , object ? > , bool > > (
379- Expression . AndAlso ( filter . Body , sessionIdFilter . Body ) ,
380- filter . Parameters ) ;
377+ Expression body = RebindFilterBody ( x => ( string ? ) x [ SessionIdField ] == sessionId , parameter ) ;
378+ filterBody = filterBody == null ? body : Expression . AndAlso ( filterBody , body ) ;
381379 }
382380
381+ Expression < Func < Dictionary < string , object ? > , bool > > ? filter = filterBody != null
382+ ? Expression . Lambda < Func < Dictionary < string , object ? > , bool > > ( filterBody , parameter )
383+ : null ;
384+
383385 // Use search to find relevant messages
384386 var searchResults = collection . SearchAsync (
385387 queryText ,
@@ -467,6 +469,27 @@ public void Dispose()
467469
468470 private string ? SanitizeLogData ( string ? data ) => this . _enableSensitiveTelemetryData ? data : "<redacted>" ;
469471
472+ /// <summary>
473+ /// Rebinds a filter expression's body to use the specified shared parameter,
474+ /// replacing the original lambda parameter so that multiple filters can be safely
475+ /// combined with <see cref="Expression.AndAlso(Expression, Expression)"/>.
476+ /// </summary>
477+ private static Expression RebindFilterBody (
478+ Expression < Func < Dictionary < string , object ? > , bool > > filter ,
479+ ParameterExpression sharedParameter )
480+ {
481+ return new ParameterReplacer ( filter . Parameters [ 0 ] , sharedParameter ) . Visit ( filter . Body ) ;
482+ }
483+
484+ /// <summary>
485+ /// An <see cref="ExpressionVisitor"/> that replaces one <see cref="ParameterExpression"/> with another.
486+ /// </summary>
487+ private sealed class ParameterReplacer ( ParameterExpression original , ParameterExpression replacement ) : ExpressionVisitor
488+ {
489+ protected override Expression VisitParameter ( ParameterExpression node )
490+ => node == original ? replacement : base . VisitParameter ( node ) ;
491+ }
492+
470493 /// <summary>
471494 /// Represents the state of a <see cref="ChatHistoryMemoryProvider"/> stored in the <see cref="AgentSession.StateBag"/>.
472495 /// </summary>
0 commit comments