1313// 
1414// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 
1515// ***************************************************************************** 
16- import  {  Agent ,  AgentService ,  CommunicationRecordingService ,  CommunicationRequestEntry ,  CommunicationResponseEntry  }  from  '@theia/ai-core' ; 
16+ import  {  Agent ,  AgentService ,  LanguageModelService ,  SessionEvent  }  from  '@theia/ai-core' ; 
17+ import  {  AiSemanticRequest  }  from  '@theia/ai-core/lib/common/language-model-interaction-model' ; 
1718import  {  codicon ,  ReactWidget ,  StatefulWidget  }  from  '@theia/core/lib/browser' ; 
1819import  {  inject ,  injectable ,  postConstruct  }  from  '@theia/core/shared/inversify' ; 
1920import  *  as  React  from  '@theia/core/shared/react' ; 
20- import  {  CommunicationCard  }  from  './ai-history-communication -card' ; 
21+ import  {  SemanticRequestCard  }  from  './ai-history-semantic-request -card' ; 
2122import  {  SelectComponent ,  SelectOption  }  from  '@theia/core/lib/browser/widgets/select-component' ; 
2223import  {  deepClone ,  nls  }  from  '@theia/core' ; 
2324
2425namespace  AIHistoryView  { 
2526    export  interface  State  { 
2627        chronological : boolean ; 
28+         selectedAgentId ?: string ; 
2729    } 
2830} 
2931
3032@injectable ( ) 
3133export  class  AIHistoryView  extends  ReactWidget  implements  StatefulWidget  { 
32-     @inject ( CommunicationRecordingService ) 
33-     protected  recordingService :  CommunicationRecordingService ; 
34+     @inject ( LanguageModelService ) 
35+     protected  languageModelService :  LanguageModelService ; 
3436    @inject ( AgentService ) 
3537    protected  readonly  agentService : AgentService ; 
3638
3739    public  static  ID  =  'ai-history-widget' ; 
3840    static  LABEL  =  nls . localize ( 'theia/ai/history/view/label' ,  'AI Agent History [Alpha]' ) ; 
3941
40-     protected  selectedAgent ?: Agent ; 
41- 
4242    protected  _state : AIHistoryView . State  =  {  chronological : false  } ; 
4343
4444    constructor ( )  { 
@@ -74,27 +74,21 @@ export class AIHistoryView extends ReactWidget implements StatefulWidget {
7474    @postConstruct ( ) 
7575    protected  init ( ) : void { 
7676        this . update ( ) ; 
77-         this . toDispose . push ( this . recordingService . onDidRecordRequest ( entry  =>  this . historyContentUpdated ( entry ) ) ) ; 
78-         this . toDispose . push ( this . recordingService . onDidRecordResponse ( entry  =>  this . historyContentUpdated ( entry ) ) ) ; 
79-         this . toDispose . push ( this . recordingService . onStructuralChange ( ( )  =>  this . update ( ) ) ) ; 
77+         this . toDispose . push ( this . languageModelService . onSessionChanged ( ( event : SessionEvent )  =>  this . historyContentUpdated ( event ) ) ) ; 
8078        this . selectAgent ( this . agentService . getAllAgents ( ) [ 0 ] ) ; 
8179    } 
8280
8381    protected  selectAgent ( agent : Agent  |  undefined ) : void { 
84-         this . selectedAgent  =  agent ; 
85-         this . update ( ) ; 
82+         this . state  =  {  ...this . state ,  selectedAgentId : agent ?. id  } ; 
8683    } 
8784
88-     protected  historyContentUpdated ( entry : CommunicationRequestEntry  |  CommunicationResponseEntry ) : void { 
89-         if  ( entry . agentId  ===  this . selectedAgent ?. id )  { 
90-             this . update ( ) ; 
91-         } 
85+     protected  historyContentUpdated ( event : SessionEvent ) : void { 
86+         this . update ( ) ; 
9287    } 
9388
9489    render ( ) : React . ReactNode  { 
9590        const  selectionChange  =  ( value : SelectOption )  =>  { 
96-             this . selectedAgent  =  this . agentService . getAllAgents ( ) . find ( agent  =>  agent . id  ===  value . value ) ; 
97-             this . update ( ) ; 
91+             this . selectAgent ( this . agentService . getAllAgents ( ) . find ( agent  =>  agent . id  ===  value . value ) ) ; 
9892        } ; 
9993        const  agents  =  this . agentService . getAllAgents ( ) ; 
10094        if  ( agents . length  ===  0 )  { 
@@ -112,7 +106,7 @@ export class AIHistoryView extends ReactWidget implements StatefulWidget {
112106                        description : agent . description  ||  '' 
113107                    } ) ) } 
114108                    onChange = { selectionChange } 
115-                     defaultValue = { this . selectedAgent ?. id }  /> 
109+                     defaultValue = { this . state . selectedAgentId }  /> 
116110                < div  className = 'agent-history' > 
117111                    { this . renderHistory ( ) } 
118112                </ div > 
@@ -121,24 +115,41 @@ export class AIHistoryView extends ReactWidget implements StatefulWidget {
121115    } 
122116
123117    protected  renderHistory ( ) : React . ReactNode  { 
124-         if  ( ! this . selectedAgent )  { 
118+         if  ( ! this . state . selectedAgentId )  { 
125119            return  < div  className = 'theia-card no-content' > { nls . localize ( 'theia/ai/history/view/noAgentSelected' ,  'No agent selected.' ) } </ div > ; 
126120        } 
127-         const  history  =  [ ...this . recordingService . getHistory ( this . selectedAgent . id ) ] ; 
128-         if  ( history . length  ===  0 )  { 
121+ 
122+         const  semanticRequests  =  this . getSemanticRequestsByAgent ( this . state . selectedAgentId ) ; 
123+ 
124+         if  ( semanticRequests . length  ===  0 )  { 
125+             const  selectedAgent  =  this . agentService . getAllAgents ( ) . find ( agent  =>  agent . id  ===  this . state . selectedAgentId ) ; 
129126            return  < div  className = 'theia-card no-content' > 
130-                 { nls . localize ( 'theia/ai/history/view/noHistoryForAgent' ,  'No history available for the selected agent \'{0}\'' ,  this . selectedAgent . name ) } 
127+                 { nls . localize ( 'theia/ai/history/view/noHistoryForAgent' ,  'No history available for the selected agent \'{0}\'' ,  selectedAgent ? .name   ||   this . state . selectedAgentId ) } 
131128            </ div > ; 
132129        } 
133-         if  ( ! this . state . chronological )  { 
134-             history . reverse ( ) ; 
135-         } 
136-         return  history . map ( entry  =>  < CommunicationCard  key = { entry . requestId }  entry = { entry }  /> ) ; 
130+ 
131+         // Sort requests by timestamp (using the first sub-request's timestamp) 
132+         const  sortedRequests  =  [ ...semanticRequests ] . sort ( ( a ,  b )  =>  { 
133+             const  aTimestamp  =  a . requests [ 0 ] ?. metadata . timestamp  as  number  ||  0 ; 
134+             const  bTimestamp  =  b . requests [ 0 ] ?. metadata . timestamp  as  number  ||  0 ; 
135+             return  this . state . chronological  ? aTimestamp  -  bTimestamp  : bTimestamp  -  aTimestamp ; 
136+         } ) ; 
137+ 
138+         return  sortedRequests . map ( request  =>  < SemanticRequestCard  key = { request . id }  semanticRequest = { request }  selectedAgentId = { this . state . selectedAgentId }  /> ) ; 
137139    } 
138140
139-     protected  onClick ( e : React . MouseEvent < HTMLDivElement > ,  agent : Agent ) : void { 
140-         e . stopPropagation ( ) ; 
141-         this . selectAgent ( agent ) ; 
141+     /** 
142+      * Get all semantic requests for a specific agent. 
143+      * Includes all requests in which the agent is involved, either as the main request or as a sub-request. 
144+      * @param  agentId The agent ID to filter by 
145+      */ 
146+     protected  getSemanticRequestsByAgent ( agentId : string ) : AiSemanticRequest [ ]  { 
147+         return  this . languageModelService . sessions . flatMap ( session  => 
148+             session . requests . filter ( request  => 
149+                 request . metadata . agent  ===  agentId  || 
150+                 request . requests . some ( subRequest  =>  subRequest . metadata . agent  ===  agentId ) 
151+             ) 
152+         ) ; 
142153    } 
143154
144155    public  sortHistory ( chronological : boolean ) : void { 
0 commit comments