33 * Licensed under the MIT License. See License.txt in the project root for license information.
44 *--------------------------------------------------------------------------------------------*/
55
6+ import { CancelablePromise , createCancelablePromise } from '../../../../../base/common/async.js' ;
67import { Emitter } from '../../../../../base/common/event.js' ;
78import { Disposable } from '../../../../../base/common/lifecycle.js' ;
89import { ResourceMap } from '../../../../../base/common/map.js' ;
10+ import { URI } from '../../../../../base/common/uri.js' ;
911import { ILanguageService } from '../../../../../editor/common/languages/language.js' ;
1012import { IModelService } from '../../../../../editor/common/services/model.js' ;
11- import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js' ;
1213import { IChatRequestVariableEntry , IPromptFileVariableEntry , toPromptFileVariableEntry } from '../../common/chatVariableEntries.js' ;
13-
14- import { ChatPromptAttachmentModel } from './chatPromptAttachmentModel.js' ;
14+ import { IPromptParserResult , IPromptsService } from '../../common/promptSyntax/service/promptsService.js' ;
1515
1616/**
1717 * Model for a collection of prompt instruction attachments.
18- * See { @linkcode ChatPromptAttachmentModel} for individual attachment.
18+ * Starts
1919 */
2020export class ChatPromptAttachmentsCollection extends Disposable {
2121 /**
@@ -24,29 +24,38 @@ export class ChatPromptAttachmentsCollection extends Disposable {
2424 * See {@linkcode onUpdate}.
2525 */
2626 protected _onUpdate = this . _register ( new Emitter < IPromptFileVariableEntry > ( ) ) ;
27+
2728 /**
2829 * Subscribe to the `onUpdate` event.
2930 */
3031 public onUpdate = this . _onUpdate . event ;
3132
32-
3333 /**
3434 * List of all prompt instruction attachments.
3535 */
36- private _attachments : ResourceMap < ChatPromptAttachmentModel > = new ResourceMap < ChatPromptAttachmentModel > ( ) ;
36+ private _attachments = new ResourceMap < CancelablePromise < IPromptParserResult > > ( ) ;
37+
38+
39+ constructor (
40+ @ILanguageService private readonly languageService : ILanguageService ,
41+ @IModelService private readonly modelService : IModelService ,
42+ @IPromptsService private readonly promptsService : IPromptsService ,
43+ ) {
44+ super ( ) ;
45+ }
3746
3847 /**
3948 * Check if any of the attachments is a prompt file.
4049 */
4150 public hasPromptFiles ( promptFileLanguageId : string ) : boolean {
42- const hasLanguage = ( { uri } : ChatPromptAttachmentModel ) => {
51+ const hasLanguage = ( uri : URI ) => {
4352 const model = this . modelService . getModel ( uri ) ;
4453 const languageId = model ? model . getLanguageId ( ) : this . languageService . guessLanguageIdByFilepathOrFirstLine ( uri ) ;
4554 return languageId === promptFileLanguageId ;
4655 } ;
4756
48- for ( const child of this . _attachments . values ( ) ) {
49- if ( hasLanguage ( child ) ) {
57+ for ( const uri of this . _attachments . keys ( ) ) {
58+ if ( hasLanguage ( uri ) ) {
5059 return true ;
5160 }
5261 }
@@ -58,51 +67,25 @@ export class ChatPromptAttachmentsCollection extends Disposable {
5867 * nested child references of each attachment explicitly attached by user.
5968 */
6069 public async getAttachments ( ) : Promise < readonly IChatRequestVariableEntry [ ] > {
61- await this . allSettled ( ) ;
62-
6370 const result = [ ] ;
6471 const attachments = [ ...this . _attachments . values ( ) ] ;
6572
66- for ( const attachment of attachments ) {
67- const { reference } = attachment ;
73+ for ( const parseResultPromise of attachments ) {
74+ const parseResult = await parseResultPromise ;
6875
6976 // the usual URIs list of prompt instructions is `bottom-up`, therefore
7077 // we do the same here - first add all child references of the model
71- result . push (
72- ...reference . allValidReferences . map ( ( link ) => {
73- return toPromptFileVariableEntry ( link . uri , false ) ;
74- } ) ,
75- ) ;
78+ for ( const uri of parseResult . allValidReferences ) {
79+ result . push ( toPromptFileVariableEntry ( uri , false ) ) ;
80+ }
7681
7782 // then add the root reference of the model itself
78- result . push ( toPromptFileVariableEntry ( reference . uri , true ) ) ;
83+ result . push ( toPromptFileVariableEntry ( parseResult . uri , true ) ) ;
7984 }
8085
8186 return result ;
8287 }
8388
84- /**
85- * Promise that resolves when parsing of all attached prompt instruction
86- * files completes, including parsing of all its possible child references.
87- */
88- async allSettled ( ) : Promise < void > {
89- const attachments = [ ...this . _attachments . values ( ) ] ;
90-
91- await Promise . allSettled (
92- attachments . map ( ( attachment ) => {
93- return attachment . allSettled ;
94- } ) ,
95- ) ;
96- }
97-
98- constructor (
99- @IInstantiationService private readonly instantiationService : IInstantiationService ,
100- @ILanguageService private readonly languageService : ILanguageService ,
101- @IModelService private readonly modelService : IModelService ,
102- ) {
103- super ( ) ;
104- }
105-
10689 /**
10790 * Add prompt instruction attachment instances
10891 */
@@ -115,8 +98,15 @@ export class ChatPromptAttachmentsCollection extends Disposable {
11598 continue ;
11699 }
117100
118- const instruction = this . instantiationService . createInstance ( ChatPromptAttachmentModel , uri , ( ) => this . _onUpdate . fire ( entry ) ) ;
119- this . _attachments . set ( uri , instruction ) ;
101+ const parseResult = createCancelablePromise ( token => this . promptsService . parse ( uri , token ) ) ;
102+ parseResult . then ( ( ) => {
103+ this . _onUpdate . fire ( entry ) ;
104+ } ) . catch ( ( error ) => {
105+ // if parsing fails, we still create an attachment model
106+ // to allow the user to see the error and fix it
107+ console . error ( `Failed to parse prompt file ${ uri . toString ( ) } :` , error ) ;
108+ } ) ;
109+ this . _attachments . set ( uri , parseResult ) ;
120110 }
121111 }
122112
@@ -129,7 +119,7 @@ export class ChatPromptAttachmentsCollection extends Disposable {
129119 const attachment = this . _attachments . get ( uri ) ;
130120 if ( attachment ) {
131121 this . _attachments . delete ( uri ) ;
132- attachment . dispose ( ) ;
122+ attachment . cancel ( ) ;
133123 }
134124
135125 return this ;
@@ -140,7 +130,7 @@ export class ChatPromptAttachmentsCollection extends Disposable {
140130 */
141131 public clear ( ) : this {
142132 for ( const attachment of this . _attachments . values ( ) ) {
143- attachment . dispose ( ) ;
133+ attachment . cancel ( ) ;
144134 }
145135 this . _attachments . clear ( ) ;
146136
0 commit comments