@@ -42,11 +42,13 @@ import { getRoom } from '@cardstack/host/resources/room';
42
42
43
43
import type CardService from ' @cardstack/host/services/card-service' ;
44
44
import type CommandService from ' @cardstack/host/services/command-service' ;
45
+ import LoaderService from ' @cardstack/host/services/loader-service' ;
45
46
import type MatrixService from ' @cardstack/host/services/matrix-service' ;
46
47
import { type MonacoSDK } from ' @cardstack/host/services/monaco-service' ;
47
48
import type OperatorModeStateService from ' @cardstack/host/services/operator-mode-state-service' ;
48
49
49
50
import { type CardDef } from ' https://cardstack.com/base/card-api' ;
51
+ import * as FileAPI from ' https://cardstack.com/base/file-api' ;
50
52
import type { SkillCard } from ' https://cardstack.com/base/skill-card' ;
51
53
52
54
import AiAssistantAttachmentPicker from ' ../ai-assistant/attachment-picker' ;
@@ -139,8 +141,9 @@ export default class Room extends Component<Signature> {
139
141
@ cardsToAttach ={{this .cardsToAttach }}
140
142
@ chooseCard ={{this .chooseCard }}
141
143
@ removeCard ={{this .removeCard }}
142
- @ autoAttachedFiles ={{this .autoAttachedFiles }}
144
+ @ autoAttachedFile ={{this .autoAttachedFile }}
143
145
@ filesToAttach ={{this .filesToAttach }}
146
+ @ removeFile ={{this .excludeFile }}
144
147
/>
145
148
<LLMSelect
146
149
@ selected ={{this .roomResource.activeLLM }}
@@ -209,6 +212,9 @@ export default class Room extends Component<Signature> {
209
212
@service private declare commandService: CommandService ;
210
213
@service private declare matrixService: MatrixService ;
211
214
@service private declare operatorModeStateService: OperatorModeStateService ;
215
+ @service private declare loaderService: LoaderService ;
216
+ @tracked private fileAPI: typeof FileAPI | undefined ;
217
+ @tracked private filesToExclude: FileAPI .FileDef [] = [];
212
218
213
219
private roomResource = getRoom (
214
220
this ,
@@ -238,6 +244,7 @@ export default class Room extends Component<Signature> {
238
244
constructor (owner : Owner , args : Signature [' Args' ]) {
239
245
super (owner , args );
240
246
this .doMatrixEventFlush .perform ();
247
+ this .doLoadFileAPI .perform ();
241
248
registerDestructor (this , () => {
242
249
this .scrollState ().messageVisibilityObserver .disconnect ();
243
250
});
@@ -274,12 +281,46 @@ export default class Room extends Component<Signature> {
274
281
return state ;
275
282
}
276
283
277
- private get autoAttachedFiles() {
278
- return []; // TODO: implement
284
+ private get autoAttachedFileUrl() {
285
+ if (! this .fileAPI ) {
286
+ return undefined ;
287
+ }
288
+ return this .operatorModeStateService .state .codePath ?.href ;
289
+ }
290
+
291
+ private get autoAttachedFile() {
292
+ if (! this .autoAttachedFileUrl ) {
293
+ return undefined ;
294
+ }
295
+
296
+ if (! this .fileAPI ) {
297
+ return undefined ;
298
+ }
299
+
300
+ if (
301
+ this .filesToExclude .some (
302
+ (file ) => file .sourceUrl === this .autoAttachedFileUrl ,
303
+ )
304
+ ) {
305
+ return undefined ;
306
+ }
307
+
308
+ return new this .fileAPI .FileDef ({
309
+ sourceUrl: this .autoAttachedFileUrl ,
310
+ name: this .autoAttachedFileUrl .split (' /' ).pop (),
311
+ });
279
312
}
280
313
281
314
private get filesToAttach() {
282
- return []; // TODO: implement
315
+ if (! this .fileAPI ) {
316
+ return [];
317
+ }
318
+ // User will be eventually able to attach files manually (from the realm file system, or uploaded from the device),
319
+ // but for now we only support auto-attaching files from the operator mode code path
320
+ if (! this .autoAttachedFile ) {
321
+ return [];
322
+ }
323
+ return [this .autoAttachedFile ];
283
324
}
284
325
285
326
private get isScrolledToBottom() {
@@ -478,6 +519,10 @@ export default class Room extends Component<Signature> {
478
519
this .roomResource .toggleViewCode (message );
479
520
};
480
521
522
+ private excludeFile = (file : FileAPI .FileDef ) => {
523
+ this .filesToExclude = [... this .filesToExclude , file ];
524
+ };
525
+
481
526
private doMatrixEventFlush = restartableTask (async () => {
482
527
await this .matrixService .flushMembership ;
483
528
await this .matrixService .flushTimeline ;
@@ -630,10 +675,13 @@ export default class Room extends Component<Signature> {
630
675
.map ((stackItem ) => stackItem .card .id ),
631
676
};
632
677
try {
678
+ let files = await this .matrixService .uploadFiles (this .filesToAttach );
679
+
633
680
await this .matrixService .sendMessage (
634
681
this .args .roomId ,
635
682
message ,
636
683
cards ,
684
+ files ,
637
685
clientGeneratedId ,
638
686
context ,
639
687
);
@@ -698,6 +746,14 @@ export default class Room extends Component<Signature> {
698
746
skills: [card ],
699
747
});
700
748
});
749
+
750
+ private doLoadFileAPI = restartableTask (async () => {
751
+ let fileAPI = await this .loaderService .loader .import <typeof FileAPI >(
752
+ ' https://cardstack.com/base/file-api' ,
753
+ );
754
+
755
+ this .fileAPI = fileAPI ;
756
+ });
701
757
}
702
758
703
759
declare module ' @glint/environment-ember-loose/registry' {
0 commit comments