@@ -22,7 +22,7 @@ import { ILogService, NullLogService } from '../../../../../../../platform/log/c
22
22
import { TextModelPromptParser } from '../../../../common/promptSyntax/parsers/textModelPromptParser.js' ;
23
23
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../../base/test/common/utils.js' ;
24
24
import { IInstantiationService } from '../../../../../../../platform/instantiation/common/instantiation.js' ;
25
- import { INSTRUCTIONS_LANGUAGE_ID , PROMPT_LANGUAGE_ID } from '../../../../common/promptSyntax/constants.js' ;
25
+ import { INSTRUCTIONS_LANGUAGE_ID , MODE_LANGUAGE_ID , PROMPT_LANGUAGE_ID } from '../../../../common/promptSyntax/constants.js' ;
26
26
import { InMemoryFileSystemProvider } from '../../../../../../../platform/files/common/inMemoryFilesystemProvider.js' ;
27
27
import { ExpectedDiagnosticError , ExpectedDiagnosticWarning , TExpectedDiagnostic } from '../testUtils/expectedDiagnostic.js' ;
28
28
import { TestInstantiationService } from '../../../../../../../platform/instantiation/test/common/instantiationServiceMock.js' ;
@@ -334,6 +334,62 @@ suite('TextModelPromptParser', () => {
334
334
'Must have empty metadata.' ,
335
335
) ;
336
336
} ) ;
337
+
338
+ test ( `• has correct 'instructions' metadata` , async ( ) => {
339
+ const test = createTest (
340
+ URI . file ( '/absolute/folder/and/a/filename.instructions.md' ) ,
341
+ [
342
+ /* 01 */ "---" ,
343
+ /* 02 */ "description: 'My prompt.'\t\t" ,
344
+ /* 03 */ " something: true" , /* unknown metadata record */
345
+ /* 04 */ " tools: [ 'tool_name1', \"tool_name2\", 'tool_name1', true, false, '', 'tool_name2' ]\t\t" ,
346
+ /* 05 */ " tools: [ 'tool_name3', \"tool_name4\" ]" , /* duplicate `tools` record is ignored */
347
+ /* 06 */ " tools: 'tool_name5'" , /* duplicate `tools` record with invalid value is ignored */
348
+ /* 07 */ " mode: 'agent'" ,
349
+ /* 07 */ " applyTo: 'frontend/**/*spec.ts'" ,
350
+ /* 08 */ "---" ,
351
+ /* 09 */ "The cactus on my desk has a thriving Instagram account." ,
352
+ /* 10 */ "Midnight snacks are the secret to eternal [text](./foo-bar-baz/another-file.ts) happiness." ,
353
+ /* 11 */ "In an alternate universe, pigeons deliver sushi by drone." ,
354
+ /* 12 */ "Lunar rainbows only appear when you sing in falsetto." ,
355
+ /* 13 */ "Carrots have secret telepathic abilities, but only on Tuesdays." ,
356
+ ] ,
357
+ INSTRUCTIONS_LANGUAGE_ID ,
358
+ ) ;
359
+
360
+ await test . validateReferences ( [
361
+ new ExpectedReference ( {
362
+ uri : URI . file ( '/absolute/folder/and/a/foo-bar-baz/another-file.ts' ) ,
363
+ text : '[text](./foo-bar-baz/another-file.ts)' ,
364
+ path : './foo-bar-baz/another-file.ts' ,
365
+ startLine : 11 ,
366
+ startColumn : 43 ,
367
+ pathStartColumn : 50 ,
368
+ childrenOrError : new OpenFailed ( URI . file ( '/absolute/folder/and/a/foo-bar-baz/another-file.ts' ) , 'File not found.' ) ,
369
+ } ) ,
370
+ ] ) ;
371
+
372
+ const { header, metadata } = test . parser ;
373
+ assertDefined (
374
+ header ,
375
+ 'Prompt header must be defined.' ,
376
+ ) ;
377
+
378
+ assert (
379
+ metadata ?. promptType === PromptsType . instructions ,
380
+ `Must be a 'instructions' metadata, got '${ JSON . stringify ( metadata ) } '.` ,
381
+ ) ;
382
+
383
+ assert . deepStrictEqual (
384
+ metadata ,
385
+ {
386
+ promptType : PromptsType . instructions ,
387
+ description : 'My prompt.' ,
388
+ applyTo : 'frontend/**/*spec.ts' ,
389
+ } ,
390
+ 'Must have correct metadata.' ,
391
+ ) ;
392
+ } ) ;
337
393
} ) ;
338
394
339
395
suite ( ' • prompts' , ( ) => {
@@ -379,12 +435,11 @@ suite('TextModelPromptParser', () => {
379
435
'Must have empty metadata.' ,
380
436
) ;
381
437
} ) ;
382
- } ) ;
383
438
384
- test ( `• has correct 'prompt' metadata` , async ( ) => {
385
- const test = createTest (
386
- URI . file ( '/absolute/folder/and/a/filename.txt' ) ,
387
- [
439
+ test ( `• has correct 'prompt' metadata` , async ( ) => {
440
+ const test = createTest (
441
+ URI . file ( '/absolute/folder/and/a/filename.txt' ) ,
442
+ [
388
443
/* 01 */ "---" ,
389
444
/* 02 */ "description: 'My prompt.'\t\t" ,
390
445
/* 03 */ " something: true" , /* unknown metadata record */
@@ -399,99 +454,140 @@ suite('TextModelPromptParser', () => {
399
454
/* 11 */ "In an alternate universe, pigeons deliver sushi by drone." ,
400
455
/* 12 */ "Lunar rainbows only appear when you sing in falsetto." ,
401
456
/* 13 */ "Carrots have secret telepathic abilities, but only on Tuesdays." ,
402
- ] ,
403
- PROMPT_LANGUAGE_ID ,
404
- ) ;
457
+ ] ,
458
+ PROMPT_LANGUAGE_ID ,
459
+ ) ;
405
460
406
- await test . validateReferences ( [
407
- new ExpectedReference ( {
408
- uri : URI . file ( '/absolute/folder/and/a/foo-bar-baz/another-file.ts' ) ,
409
- text : '[text](./foo-bar-baz/another-file.ts)' ,
410
- path : './foo-bar-baz/another-file.ts' ,
411
- startLine : 11 ,
412
- startColumn : 43 ,
413
- pathStartColumn : 50 ,
414
- childrenOrError : new OpenFailed ( URI . file ( '/absolute/folder/and/a/foo-bar-baz/another-file.ts' ) , 'File not found.' ) ,
415
- } ) ,
416
- ] ) ;
461
+ await test . validateReferences ( [
462
+ new ExpectedReference ( {
463
+ uri : URI . file ( '/absolute/folder/and/a/foo-bar-baz/another-file.ts' ) ,
464
+ text : '[text](./foo-bar-baz/another-file.ts)' ,
465
+ path : './foo-bar-baz/another-file.ts' ,
466
+ startLine : 11 ,
467
+ startColumn : 43 ,
468
+ pathStartColumn : 50 ,
469
+ childrenOrError : new OpenFailed ( URI . file ( '/absolute/folder/and/a/foo-bar-baz/another-file.ts' ) , 'File not found.' ) ,
470
+ } ) ,
471
+ ] ) ;
417
472
418
- const { header, metadata } = test . parser ;
419
- assertDefined (
420
- header ,
421
- 'Prompt header must be defined.' ,
422
- ) ;
473
+ const { header, metadata } = test . parser ;
474
+ assertDefined (
475
+ header ,
476
+ 'Prompt header must be defined.' ,
477
+ ) ;
423
478
424
- assert (
425
- metadata ?. promptType === PromptsType . prompt ,
426
- `Must be a 'prompt' metadata, got '${ JSON . stringify ( metadata ) } '.` ,
427
- ) ;
479
+ assert (
480
+ metadata ?. promptType === PromptsType . prompt ,
481
+ `Must be a 'prompt' metadata, got '${ JSON . stringify ( metadata ) } '.` ,
482
+ ) ;
428
483
429
- assert . deepStrictEqual (
430
- metadata ,
431
- {
432
- promptType : PromptsType . prompt ,
433
- mode : 'agent' ,
434
- description : 'My prompt.' ,
435
- tools : [ 'tool_name1' , 'tool_name2' ] ,
436
- } ,
437
- 'Must have correct metadata.' ,
438
- ) ;
484
+ assert . deepStrictEqual (
485
+ metadata ,
486
+ {
487
+ promptType : PromptsType . prompt ,
488
+ mode : 'agent' ,
489
+ description : 'My prompt.' ,
490
+ tools : [ 'tool_name1' , 'tool_name2' ] ,
491
+ } ,
492
+ 'Must have correct metadata.' ,
493
+ ) ;
494
+ } ) ;
439
495
} ) ;
440
496
441
- test ( `• has correct 'instructions' metadata` , async ( ) => {
442
- const test = createTest (
443
- URI . file ( '/absolute/folder/and/a/filename.instructions.md' ) ,
444
- [
497
+ suite ( ' • modes' , ( ) => {
498
+ test ( `• empty header` , async ( ) => {
499
+ const test = createTest (
500
+ URI . file ( '/absolute/folder/and/a/filename.txt' ) ,
501
+ [
445
502
/* 01 */ "---" ,
446
- /* 02 */ "description: 'My prompt.'\t\t" ,
503
+ /* 02 */ "" ,
504
+ /* 03 */ "---" ,
505
+ /* 04 */ "The cactus on my desk has a thriving Instagram account." ,
506
+ /* 05 */ "Midnight snacks are the secret to eternal [text](./foo-bar-baz/another-file.ts) happiness." ,
507
+ /* 06 */ "In an alternate universe, pigeons deliver sushi by drone." ,
508
+ /* 07 */ "Lunar rainbows only appear when you sing in falsetto." ,
509
+ /* 08 */ "Carrots have secret telepathic abilities, but only on Tuesdays." ,
510
+ ] ,
511
+ MODE_LANGUAGE_ID ,
512
+ ) ;
513
+
514
+ await test . validateReferences ( [
515
+ new ExpectedReference ( {
516
+ uri : URI . file ( '/absolute/folder/and/a/foo-bar-baz/another-file.ts' ) ,
517
+ text : '[text](./foo-bar-baz/another-file.ts)' ,
518
+ path : './foo-bar-baz/another-file.ts' ,
519
+ startLine : 5 ,
520
+ startColumn : 43 ,
521
+ pathStartColumn : 50 ,
522
+ childrenOrError : new OpenFailed ( URI . file ( '/absolute/folder/and/a/foo-bar-baz/another-file.ts' ) , 'File not found.' ) ,
523
+ } ) ,
524
+ ] ) ;
525
+
526
+ const { header, metadata } = test . parser ;
527
+ assertDefined (
528
+ header ,
529
+ 'Prompt header must be defined.' ,
530
+ ) ;
531
+
532
+ assert . deepStrictEqual (
533
+ metadata ,
534
+ {
535
+ promptType : PromptsType . mode ,
536
+ } ,
537
+ 'Must have empty metadata.' ,
538
+ ) ;
539
+ } ) ;
540
+
541
+ test ( `• has correct metadata` , async ( ) => {
542
+ const test = createTest (
543
+ URI . file ( '/absolute/folder/and/a/filename.txt' ) ,
544
+ [
545
+ /* 01 */ "---" ,
546
+ /* 02 */ "description: 'My mode.'\t\t" ,
447
547
/* 03 */ " something: true" , /* unknown metadata record */
448
548
/* 04 */ " tools: [ 'tool_name1', \"tool_name2\", 'tool_name1', true, false, '', 'tool_name2' ]\t\t" ,
449
549
/* 05 */ " tools: [ 'tool_name3', \"tool_name4\" ]" , /* duplicate `tools` record is ignored */
450
550
/* 06 */ " tools: 'tool_name5'" , /* duplicate `tools` record with invalid value is ignored */
451
- /* 07 */ " mode: 'agent'" ,
452
551
/* 07 */ " applyTo: 'frontend/**/*spec.ts'" ,
453
552
/* 08 */ "---" ,
454
553
/* 09 */ "The cactus on my desk has a thriving Instagram account." ,
455
554
/* 10 */ "Midnight snacks are the secret to eternal [text](./foo-bar-baz/another-file.ts) happiness." ,
456
555
/* 11 */ "In an alternate universe, pigeons deliver sushi by drone." ,
457
556
/* 12 */ "Lunar rainbows only appear when you sing in falsetto." ,
458
557
/* 13 */ "Carrots have secret telepathic abilities, but only on Tuesdays." ,
459
- ] ,
460
- INSTRUCTIONS_LANGUAGE_ID ,
461
- ) ;
462
-
463
- await test . validateReferences ( [
464
- new ExpectedReference ( {
465
- uri : URI . file ( '/absolute/folder/and/a/foo-bar-baz/another-file.ts' ) ,
466
- text : '[text](./foo-bar-baz/another-file.ts)' ,
467
- path : './foo-bar-baz/another-file.ts' ,
468
- startLine : 11 ,
469
- startColumn : 43 ,
470
- pathStartColumn : 50 ,
471
- childrenOrError : new OpenFailed ( URI . file ( '/absolute/folder/and/a/foo-bar-baz/another-file.ts' ) , 'File not found.' ) ,
472
- } ) ,
473
- ] ) ;
558
+ ] ,
559
+ MODE_LANGUAGE_ID ,
560
+ ) ;
474
561
475
- const { header, metadata } = test . parser ;
476
- assertDefined (
477
- header ,
478
- 'Prompt header must be defined.' ,
479
- ) ;
562
+ await test . validateReferences ( [
563
+ new ExpectedReference ( {
564
+ uri : URI . file ( '/absolute/folder/and/a/foo-bar-baz/another-file.ts' ) ,
565
+ text : '[text](./foo-bar-baz/another-file.ts)' ,
566
+ path : './foo-bar-baz/another-file.ts' ,
567
+ startLine : 10 ,
568
+ startColumn : 43 ,
569
+ pathStartColumn : 50 ,
570
+ childrenOrError : new OpenFailed ( URI . file ( '/absolute/folder/and/a/foo-bar-baz/another-file.ts' ) , 'File not found.' ) ,
571
+ } ) ,
572
+ ] ) ;
480
573
481
- assert (
482
- metadata ?. promptType === PromptsType . instructions ,
483
- `Must be a 'instructions' metadata, got '${ JSON . stringify ( metadata ) } '.` ,
484
- ) ;
574
+ const { header, metadata } = test . parser ;
575
+ assertDefined (
576
+ header ,
577
+ 'Mode header must be defined.' ,
578
+ ) ;
485
579
486
- assert . deepStrictEqual (
487
- metadata ,
488
- {
489
- promptType : PromptsType . instructions ,
490
- description : 'My prompt.' ,
491
- applyTo : 'frontend/**/*spec.ts' ,
492
- } ,
493
- 'Must have correct metadata.' ,
494
- ) ;
580
+ assert . deepStrictEqual (
581
+ metadata ,
582
+ {
583
+ promptType : PromptsType . mode ,
584
+ mode : 'agent' ,
585
+ description : 'My mode.' ,
586
+ tools : [ 'tool_name1' , 'tool_name2' ] ,
587
+ } ,
588
+ 'Must have correct metadata.' ,
589
+ ) ;
590
+ } ) ;
495
591
} ) ;
496
592
} ) ;
497
593
0 commit comments