@@ -8,7 +8,13 @@ import { homedir } from 'os';
88import { mkdir , writeFile } from 'fs/promises' ;
99
1010import NavieService from '../services/navieService' ;
11- import { NavieEvent , NavieMessageEvent , PinnedItem , TimestampNavieEvent } from './events' ;
11+ import {
12+ NavieAddMessageAttachmentEvent ,
13+ NavieEvent ,
14+ NavieMessageEvent ,
15+ PinnedItem ,
16+ TimestampNavieEvent ,
17+ } from './events' ;
1218import { ThreadIndexService } from '../services/threadIndexService' ;
1319import { container } from 'tsyringe' ;
1420import { NavieRpc } from '@appland/rpc' ;
@@ -25,15 +31,26 @@ type EventListener = (...args: any[]) => void;
2531 */
2632function convertContext (
2733 context ?: NavieRpc . V1 . UserContext . ContextItem [ ]
28- ) : undefined | UserContext . Context {
29- return context ?. map ( ( item ) => {
34+ ) : UserContext . ContextItem [ ] {
35+ if ( ! context ) return [ ] ;
36+ return context . map ( ( item ) => {
3037 if ( item . type === 'static' ) {
3138 return { type : 'code-snippet' , content : item . content , location : item . id } ;
3239 }
3340 return { type : 'file' , location : item . uri } ;
3441 } ) ;
3542}
3643
44+ function convertMessageAttachmentToContextItem (
45+ attachment : NavieAddMessageAttachmentEvent
46+ ) : UserContext . ContextItem {
47+ return {
48+ type : 'code-snippet' ,
49+ content : attachment . content ?? '' ,
50+ location : attachment . uri ,
51+ } ;
52+ }
53+
3754export class Thread {
3855 private eventEmitter = new EventEmitter ( ) ;
3956 private listeners = new Map < string , EventListener [ ] > ( ) ;
@@ -236,10 +253,11 @@ export class Thread {
236253
237254 /**
238255 * Send a user message to the thread. This will emit a `message` event. This promise will resolve
239- * once the message has been acknowledged by the backend, before the message is completed.
256+ * once the message has been acknowledged by the backend, before the message is completed. Message
257+ * attachments need NOT be included in the `userContext` parameter.
240258 *
241259 * @param message the message to send
242- * @param codeSelection (optional) the code selection to send
260+ * @param codeSelection (optional) additional context to use, i.e., pinned items
243261 */
244262 async sendMessage (
245263 message : string ,
@@ -248,8 +266,10 @@ export class Thread {
248266 const [ navie , contextEvents ] = this . navieService . getNavie ( ) ;
249267
250268 let context = convertContext ( userContext ) ;
269+ context . push ( ...this . getMessageAttachments ( ) . map ( convertMessageAttachmentToContextItem ) ) ;
270+
251271 const { applied, userContext : newUserContext } = await handleReview ( message , context ) ;
252- if ( applied ) {
272+ if ( applied && newUserContext ) {
253273 context = newUserContext ;
254274 }
255275
@@ -296,6 +316,44 @@ export class Thread {
296316 } ) ;
297317 }
298318
319+ addMessageAttachment ( uri ?: string , content ?: string ) : string {
320+ const attachmentId = randomUUID ( ) ;
321+ this . logEvent ( {
322+ type : 'add-message-attachment' ,
323+ attachmentId,
324+ uri,
325+ content,
326+ } ) ;
327+ return attachmentId ;
328+ }
329+
330+ removeMessageAttachment ( attachmentId : string ) {
331+ this . logEvent ( { type : 'remove-message-attachment' , attachmentId } ) ;
332+ }
333+
334+ getMessageAttachments ( ) : NavieAddMessageAttachmentEvent [ ] {
335+ // Array.lastIndexOf is not supported until es2023.
336+ let lastUserMessageIndex = 0 ;
337+ for ( let i = lastUserMessageIndex ; i < this . log . length ; ++ i ) {
338+ const e = this . log [ i ] ;
339+ if ( e . type === 'message' && e . role === 'user' ) {
340+ lastUserMessageIndex = i ;
341+ }
342+ }
343+
344+ const attachments = new Map < string , NavieAddMessageAttachmentEvent > ( ) ;
345+ for ( let i = lastUserMessageIndex + 1 ; i < this . log . length ; ++ i ) {
346+ const e = this . log [ i ] ;
347+ if ( e . type === 'add-message-attachment' ) {
348+ attachments . set ( e . attachmentId , e ) ;
349+ } else if ( e . type === 'remove-message-attachment' ) {
350+ attachments . delete ( e . attachmentId ) ;
351+ }
352+ }
353+
354+ return Array . from ( attachments . values ( ) ) ;
355+ }
356+
299357 /**
300358 * Gets the events since the given nonce. If no nonce is given, it will return all events.
301359 *
0 commit comments