@@ -11,6 +11,28 @@ import type {
1111const CONVERSATIONS_OBJECT = 'ai_conversations' ;
1212const MESSAGES_OBJECT = 'ai_messages' ;
1313
14+ /** Database row shape for ai_conversations. */
15+ interface DbConversationRow {
16+ id : string ;
17+ title : string | null ;
18+ agent_id : string | null ;
19+ user_id : string | null ;
20+ metadata : string | null ;
21+ created_at : string ;
22+ updated_at : string ;
23+ }
24+
25+ /** Database row shape for ai_messages. */
26+ interface DbMessageRow {
27+ id : string ;
28+ conversation_id : string ;
29+ role : 'system' | 'user' | 'assistant' | 'tool' ;
30+ content : string ;
31+ tool_calls : string | null ;
32+ tool_call_id : string | null ;
33+ created_at : string ;
34+ }
35+
1436/**
1537 * ObjectQLConversationService — Persistent implementation of IAIConversationService.
1638 *
@@ -62,13 +84,13 @@ export class ObjectQLConversationService implements IAIConversationService {
6284 }
6385
6486 async get ( conversationId : string ) : Promise < AIConversation | null > {
65- const row = await this . engine . findOne ( CONVERSATIONS_OBJECT , {
87+ const row : DbConversationRow | null = await this . engine . findOne ( CONVERSATIONS_OBJECT , {
6688 where : { id : conversationId } ,
6789 } ) ;
6890
6991 if ( ! row ) return null ;
7092
71- const messages = await this . engine . find ( MESSAGES_OBJECT , {
93+ const messages : DbMessageRow [ ] = await this . engine . find ( MESSAGES_OBJECT , {
7294 where : { conversation_id : conversationId } ,
7395 orderBy : [ { field : 'created_at' , order : 'asc' } ] ,
7496 } ) ;
@@ -98,16 +120,17 @@ export class ObjectQLConversationService implements IAIConversationService {
98120 }
99121 }
100122
101- const rows = await this . engine . find ( CONVERSATIONS_OBJECT , {
123+ const rows : DbConversationRow [ ] = await this . engine . find ( CONVERSATIONS_OBJECT , {
102124 where : Object . keys ( where ) . length > 0 ? where : undefined ,
103125 orderBy : [ { field : 'created_at' , order : 'asc' } ] ,
104126 limit : options . limit && options . limit > 0 ? options . limit : undefined ,
105127 } ) ;
106128
107- // Batch-load messages for all conversations
129+ // Load messages per conversation.
130+ // N+1 is bounded by the pagination limit; driver-agnostic $in is not guaranteed.
108131 const conversations : AIConversation [ ] = [ ] ;
109132 for ( const row of rows ) {
110- const messages = await this . engine . find ( MESSAGES_OBJECT , {
133+ const messages : DbMessageRow [ ] = await this . engine . find ( MESSAGES_OBJECT , {
111134 where : { conversation_id : row . id } ,
112135 orderBy : [ { field : 'created_at' , order : 'asc' } ] ,
113136 } ) ;
@@ -119,7 +142,7 @@ export class ObjectQLConversationService implements IAIConversationService {
119142
120143 async addMessage ( conversationId : string , message : AIMessage ) : Promise < AIConversation > {
121144 // Verify conversation exists
122- const row = await this . engine . findOne ( CONVERSATIONS_OBJECT , {
145+ const row : DbConversationRow | null = await this . engine . findOne ( CONVERSATIONS_OBJECT , {
123146 where : { id : conversationId } ,
124147 } ) ;
125148 if ( ! row ) {
@@ -167,7 +190,7 @@ export class ObjectQLConversationService implements IAIConversationService {
167190 /**
168191 * Map a database row + message rows to an AIConversation.
169192 */
170- private toConversation ( row : any , messageRows : any [ ] ) : AIConversation {
193+ private toConversation ( row : DbConversationRow , messageRows : DbMessageRow [ ] ) : AIConversation {
171194 return {
172195 id : row . id ,
173196 title : row . title ?? undefined ,
@@ -183,7 +206,7 @@ export class ObjectQLConversationService implements IAIConversationService {
183206 /**
184207 * Map a database row to an AIMessage.
185208 */
186- private toMessage ( row : any ) : AIMessage {
209+ private toMessage ( row : DbMessageRow ) : AIMessage {
187210 const msg : AIMessage = {
188211 role : row . role ,
189212 content : row . content ,
0 commit comments