@promptbook/cli 0.103.0-50 → 0.103.0-52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/apps/agents-server/package.json +1 -0
  2. package/apps/agents-server/src/app/AddAgentButton.tsx +7 -6
  3. package/apps/agents-server/src/app/{metadata → admin/metadata}/MetadataClient.tsx +5 -13
  4. package/apps/agents-server/src/app/{metadata → admin/metadata}/page.tsx +2 -2
  5. package/apps/agents-server/src/app/agents/[agentName]/AgentQrCode.tsx +3 -3
  6. package/apps/agents-server/src/app/agents/[agentName]/generateAgentMetadata.ts +1 -1
  7. package/apps/agents-server/src/app/agents/[agentName]/page.tsx +5 -2
  8. package/apps/agents-server/src/app/api/embed.js/route.ts +93 -0
  9. package/apps/agents-server/src/app/embed/page.tsx +24 -0
  10. package/apps/agents-server/src/app/page.tsx +48 -101
  11. package/apps/agents-server/src/components/Header/Header.tsx +28 -8
  12. package/apps/agents-server/src/components/Homepage/AgentCard.tsx +28 -0
  13. package/apps/agents-server/src/components/Homepage/Card.tsx +18 -0
  14. package/apps/agents-server/src/components/Homepage/ModelCard.tsx +29 -0
  15. package/apps/agents-server/src/components/Homepage/Section.tsx +17 -0
  16. package/apps/agents-server/src/components/Homepage/TechInfoCard.tsx +20 -0
  17. package/apps/agents-server/src/components/UsersList/UsersList.tsx +6 -6
  18. package/apps/agents-server/src/components/VercelDeploymentCard/VercelDeploymentCard.tsx +3 -8
  19. package/apps/agents-server/src/database/migrate.ts +131 -0
  20. package/apps/agents-server/src/database/{schema.sql → migrations/2025-11-0001-initial-schema.sql} +1 -17
  21. package/apps/agents-server/src/database/migrations/2025-11-0002-metadata-table.sql +16 -0
  22. package/apps/agents-server/src/middleware.ts +1 -1
  23. package/esm/index.es.js +192 -10
  24. package/esm/index.es.js.map +1 -1
  25. package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +1 -0
  26. package/esm/typings/src/book-2.0/agent-source/createCommitmentRegex.d.ts +2 -2
  27. package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +6 -0
  28. package/esm/typings/src/book-components/PromptbookAgent/PromptbookAgent.d.ts +10 -1
  29. package/esm/typings/src/commitments/META_COLOR/META_COLOR.d.ts +38 -0
  30. package/esm/typings/src/commitments/_base/BaseCommitmentDefinition.d.ts +2 -1
  31. package/esm/typings/src/commitments/index.d.ts +3 -1
  32. package/esm/typings/src/llm-providers/agent/Agent.d.ts +1 -0
  33. package/esm/typings/src/version.d.ts +1 -1
  34. package/package.json +1 -1
  35. package/umd/index.umd.js +192 -10
  36. package/umd/index.umd.js.map +1 -1
@@ -49,6 +49,7 @@ export type AgentBasicInformation = {
49
49
  * When there are multiple meta commitments of the same type, later overrides earlier
50
50
  */
51
51
  meta: {
52
+ fullname?: string;
52
53
  image?: string_url_image;
53
54
  color?: string_color;
54
55
  [key: string]: string | undefined;
@@ -7,7 +7,7 @@ import type { BookCommitment } from '../../commitments/_base/BookCommitment';
7
7
  *
8
8
  * @private - TODO: [🧠] Maybe should be public?
9
9
  */
10
- export declare function createCommitmentRegex(commitment: BookCommitment): RegExp;
10
+ export declare function createCommitmentRegex(commitment: BookCommitment, aliases?: BookCommitment[]): RegExp;
11
11
  /**
12
12
  * Generates a regex pattern to match a specific commitment type
13
13
  *
@@ -17,4 +17,4 @@ export declare function createCommitmentRegex(commitment: BookCommitment): RegEx
17
17
  *
18
18
  * @private
19
19
  */
20
- export declare function createCommitmentTypeRegex(commitment: BookCommitment): RegExp;
20
+ export declare function createCommitmentTypeRegex(commitment: BookCommitment, aliases?: BookCommitment[]): RegExp;
@@ -77,6 +77,12 @@ export type ChatProps = {
77
77
  * adding feature–specific controls (e.g. Pause / Resume in MockedChat).
78
78
  */
79
79
  readonly extraActions?: ReactNode;
80
+ /**
81
+ * Optional container to render the actions into (using React Portal).
82
+ * If provided, the actions toolbar will be rendered inside this element
83
+ * instead of its default position within the chat.
84
+ */
85
+ readonly actionsContainer?: HTMLElement | null;
80
86
  /**
81
87
  * Optional CSS class name which will be added to root <div/> element
82
88
  */
@@ -1,4 +1,4 @@
1
- import './PromptbookAgent.css';
1
+ import type { AgentBasicInformation } from '../../book-2.0/agent-source/AgentBasicInformation';
2
2
  type PromptbookAgentProps = {
3
3
  /**
4
4
  * URL of the agent to connect to
@@ -6,6 +6,15 @@ type PromptbookAgentProps = {
6
6
  * @example "http://s6.ptbk.io/benjamin-white"
7
7
  */
8
8
  agentUrl: string;
9
+ /**
10
+ * Optional metadata to show before the agent is connected
11
+ * Or to override the agent metadata if the agent does not provide it
12
+ */
13
+ meta?: Partial<AgentBasicInformation['meta']>;
14
+ /**
15
+ * Callback when the window is opened or closed
16
+ */
17
+ onOpenChange?: (isOpen: boolean) => void;
9
18
  };
10
19
  /**
11
20
  * Renders a floating agent button that opens a chat window with the remote agent.
@@ -0,0 +1,38 @@
1
+ import type { AgentModelRequirements } from '../../book-2.0/agent-source/AgentModelRequirements';
2
+ import { BaseCommitmentDefinition } from '../_base/BaseCommitmentDefinition';
3
+ /**
4
+ * META COLOR commitment definition
5
+ *
6
+ * The META COLOR commitment sets the agent's accent color.
7
+ * This commitment is special because it doesn't affect the system message,
8
+ * but is handled separately in the parsing logic.
9
+ *
10
+ * Example usage in agent source:
11
+ *
12
+ * ```book
13
+ * META COLOR #ff0000
14
+ * META COLOR #00ff00
15
+ * ```
16
+ *
17
+ * @private [🪔] Maybe export the commitments through some package
18
+ */
19
+ export declare class MetaColorCommitmentDefinition extends BaseCommitmentDefinition<'META COLOR'> {
20
+ constructor();
21
+ /**
22
+ * Short one-line description of META COLOR.
23
+ */
24
+ get description(): string;
25
+ /**
26
+ * Markdown documentation for META COLOR commitment.
27
+ */
28
+ get documentation(): string;
29
+ applyToAgentModelRequirements(requirements: AgentModelRequirements, content: string): AgentModelRequirements;
30
+ /**
31
+ * Extracts the profile color from the content
32
+ * This is used by the parsing logic
33
+ */
34
+ extractProfileColor(content: string): string | null;
35
+ }
36
+ /**
37
+ * Note: [💞] Ignore a discrepancy between file name and entity name
38
+ */
@@ -8,7 +8,8 @@ import type { CommitmentDefinition } from './CommitmentDefinition';
8
8
  */
9
9
  export declare abstract class BaseCommitmentDefinition<TBookCommitment extends string> implements CommitmentDefinition {
10
10
  readonly type: TBookCommitment;
11
- constructor(type: TBookCommitment);
11
+ readonly aliases: string[];
12
+ constructor(type: TBookCommitment, aliases?: string[]);
12
13
  /**
13
14
  * Short one-line markdown description; concise, may use inline **markdown**.
14
15
  * Must be implemented by each concrete commitment.
@@ -9,6 +9,8 @@ import { MemoryCommitmentDefinition } from './MEMORY/MEMORY';
9
9
  import { InitialMessageCommitmentDefinition } from './MESSAGE/InitialMessageCommitmentDefinition';
10
10
  import { MessageCommitmentDefinition } from './MESSAGE/MESSAGE';
11
11
  import { MetaCommitmentDefinition } from './META/META';
12
+ import { MetaColorCommitmentDefinition } from './META_COLOR/META_COLOR';
13
+ import { MetaImageCommitmentDefinition } from './META_IMAGE/META_IMAGE';
12
14
  import { ModelCommitmentDefinition } from './MODEL/MODEL';
13
15
  import { NoteCommitmentDefinition } from './NOTE/NOTE';
14
16
  import { PersonaCommitmentDefinition } from './PERSONA/PERSONA';
@@ -24,7 +26,7 @@ import { NotYetImplementedCommitmentDefinition } from './_base/NotYetImplemented
24
26
  *
25
27
  * @private Use functions to access commitments instead of this array directly
26
28
  */
27
- export declare const COMMITMENT_REGISTRY: readonly [PersonaCommitmentDefinition, PersonaCommitmentDefinition, KnowledgeCommitmentDefinition, MemoryCommitmentDefinition, MemoryCommitmentDefinition, StyleCommitmentDefinition, StyleCommitmentDefinition, RuleCommitmentDefinition, RuleCommitmentDefinition, SampleCommitmentDefinition, SampleCommitmentDefinition, FormatCommitmentDefinition, FormatCommitmentDefinition, ModelCommitmentDefinition, ModelCommitmentDefinition, ActionCommitmentDefinition, ActionCommitmentDefinition, MetaCommitmentDefinition, NoteCommitmentDefinition, NoteCommitmentDefinition, NoteCommitmentDefinition, NoteCommitmentDefinition, GoalCommitmentDefinition, GoalCommitmentDefinition, InitialMessageCommitmentDefinition, MessageCommitmentDefinition, MessageCommitmentDefinition, ScenarioCommitmentDefinition, ScenarioCommitmentDefinition, DeleteCommitmentDefinition, DeleteCommitmentDefinition, DeleteCommitmentDefinition, DeleteCommitmentDefinition, NotYetImplementedCommitmentDefinition<"EXPECT">, NotYetImplementedCommitmentDefinition<"BEHAVIOUR">, NotYetImplementedCommitmentDefinition<"BEHAVIOURS">, NotYetImplementedCommitmentDefinition<"AVOID">, NotYetImplementedCommitmentDefinition<"AVOIDANCE">, NotYetImplementedCommitmentDefinition<"CONTEXT">];
29
+ export declare const COMMITMENT_REGISTRY: readonly [PersonaCommitmentDefinition, PersonaCommitmentDefinition, KnowledgeCommitmentDefinition, MemoryCommitmentDefinition, MemoryCommitmentDefinition, StyleCommitmentDefinition, StyleCommitmentDefinition, RuleCommitmentDefinition, RuleCommitmentDefinition, SampleCommitmentDefinition, SampleCommitmentDefinition, FormatCommitmentDefinition, FormatCommitmentDefinition, ModelCommitmentDefinition, ModelCommitmentDefinition, ActionCommitmentDefinition, ActionCommitmentDefinition, MetaImageCommitmentDefinition, MetaColorCommitmentDefinition, MetaCommitmentDefinition, NoteCommitmentDefinition, NoteCommitmentDefinition, NoteCommitmentDefinition, NoteCommitmentDefinition, GoalCommitmentDefinition, GoalCommitmentDefinition, InitialMessageCommitmentDefinition, MessageCommitmentDefinition, MessageCommitmentDefinition, ScenarioCommitmentDefinition, ScenarioCommitmentDefinition, DeleteCommitmentDefinition, DeleteCommitmentDefinition, DeleteCommitmentDefinition, DeleteCommitmentDefinition, NotYetImplementedCommitmentDefinition<"EXPECT">, NotYetImplementedCommitmentDefinition<"BEHAVIOUR">, NotYetImplementedCommitmentDefinition<"BEHAVIOURS">, NotYetImplementedCommitmentDefinition<"AVOID">, NotYetImplementedCommitmentDefinition<"AVOIDANCE">, NotYetImplementedCommitmentDefinition<"CONTEXT">];
28
30
  /**
29
31
  * Gets a commitment definition by its type
30
32
  * @param type The commitment type to look up
@@ -45,6 +45,7 @@ export declare class Agent extends AgentLlmExecutionTools implements LlmExecutio
45
45
  * Metadata like image or color
46
46
  */
47
47
  meta: {
48
+ fullname?: string;
48
49
  image?: string_url_image;
49
50
  link?: string;
50
51
  title?: string;
@@ -15,7 +15,7 @@ export declare const BOOK_LANGUAGE_VERSION: string_semantic_version;
15
15
  export declare const PROMPTBOOK_ENGINE_VERSION: string_promptbook_version;
16
16
  /**
17
17
  * Represents the version string of the Promptbook engine.
18
- * It follows semantic versioning (e.g., `0.103.0-49`).
18
+ * It follows semantic versioning (e.g., `0.103.0-51`).
19
19
  *
20
20
  * @generated
21
21
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promptbook/cli",
3
- "version": "0.103.0-50",
3
+ "version": "0.103.0-52",
4
4
  "description": "Promptbook: Turn your company's scattered knowledge into AI ready books",
5
5
  "private": false,
6
6
  "sideEffects": false,
package/umd/index.umd.js CHANGED
@@ -56,7 +56,7 @@
56
56
  * @generated
57
57
  * @see https://github.com/webgptorg/promptbook
58
58
  */
59
- const PROMPTBOOK_ENGINE_VERSION = '0.103.0-50';
59
+ const PROMPTBOOK_ENGINE_VERSION = '0.103.0-52';
60
60
  /**
61
61
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
62
62
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -22404,9 +22404,13 @@
22404
22404
  *
22405
22405
  * @private - TODO: [🧠] Maybe should be public?
22406
22406
  */
22407
- function createCommitmentRegex(commitment) {
22408
- const escapedCommitment = commitment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
22409
- const keywordPattern = escapedCommitment.split(/\s+/).join('\\s+');
22407
+ function createCommitmentRegex(commitment, aliases = []) {
22408
+ const allCommitments = [commitment, ...aliases];
22409
+ const patterns = allCommitments.map((c) => {
22410
+ const escapedCommitment = c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
22411
+ return escapedCommitment.split(/\s+/).join('\\s+');
22412
+ });
22413
+ const keywordPattern = patterns.join('|');
22410
22414
  const regex = new RegExp(`^\\s*(?<type>${keywordPattern})\\b\\s+(?<contents>.+)$`, 'gim');
22411
22415
  return regex;
22412
22416
  }
@@ -22419,9 +22423,13 @@
22419
22423
  *
22420
22424
  * @private
22421
22425
  */
22422
- function createCommitmentTypeRegex(commitment) {
22423
- const escapedCommitment = commitment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
22424
- const keywordPattern = escapedCommitment.split(/\s+/).join('\\s+');
22426
+ function createCommitmentTypeRegex(commitment, aliases = []) {
22427
+ const allCommitments = [commitment, ...aliases];
22428
+ const patterns = allCommitments.map((c) => {
22429
+ const escapedCommitment = c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
22430
+ return escapedCommitment.split(/\s+/).join('\\s+');
22431
+ });
22432
+ const keywordPattern = patterns.join('|');
22425
22433
  const regex = new RegExp(`^\\s*(?<type>${keywordPattern})\\b`, 'gim');
22426
22434
  return regex;
22427
22435
  }
@@ -22433,22 +22441,23 @@
22433
22441
  * @private
22434
22442
  */
22435
22443
  class BaseCommitmentDefinition {
22436
- constructor(type) {
22444
+ constructor(type, aliases = []) {
22437
22445
  this.type = type;
22446
+ this.aliases = aliases;
22438
22447
  }
22439
22448
  /**
22440
22449
  * Creates a regex pattern to match this commitment in agent source
22441
22450
  * Uses the existing createCommitmentRegex function as internal helper
22442
22451
  */
22443
22452
  createRegex() {
22444
- return createCommitmentRegex(this.type);
22453
+ return createCommitmentRegex(this.type, this.aliases);
22445
22454
  }
22446
22455
  /**
22447
22456
  * Creates a regex pattern to match just the commitment type
22448
22457
  * Uses the existing createCommitmentTypeRegex function as internal helper
22449
22458
  */
22450
22459
  createTypeRegex() {
22451
- return createCommitmentTypeRegex(this.type);
22460
+ return createCommitmentTypeRegex(this.type, this.aliases);
22452
22461
  }
22453
22462
  /**
22454
22463
  * Helper method to create a new requirements object with updated system message
@@ -23360,6 +23369,165 @@
23360
23369
  * Note: [💞] Ignore a discrepancy between file name and entity name
23361
23370
  */
23362
23371
 
23372
+ /**
23373
+ * META COLOR commitment definition
23374
+ *
23375
+ * The META COLOR commitment sets the agent's accent color.
23376
+ * This commitment is special because it doesn't affect the system message,
23377
+ * but is handled separately in the parsing logic.
23378
+ *
23379
+ * Example usage in agent source:
23380
+ *
23381
+ * ```book
23382
+ * META COLOR #ff0000
23383
+ * META COLOR #00ff00
23384
+ * ```
23385
+ *
23386
+ * @private [🪔] Maybe export the commitments through some package
23387
+ */
23388
+ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
23389
+ constructor() {
23390
+ super('META COLOR', ['COLOR']);
23391
+ }
23392
+ /**
23393
+ * Short one-line description of META COLOR.
23394
+ */
23395
+ get description() {
23396
+ return "Set the agent's accent color.";
23397
+ }
23398
+ /**
23399
+ * Markdown documentation for META COLOR commitment.
23400
+ */
23401
+ get documentation() {
23402
+ return spaceTrim.spaceTrim(`
23403
+ # META COLOR
23404
+
23405
+ Sets the agent's accent color.
23406
+
23407
+ ## Key aspects
23408
+
23409
+ - Does not modify the agent's behavior or responses.
23410
+ - Only one \`META COLOR\` should be used per agent.
23411
+ - If multiple are specified, the last one takes precedence.
23412
+ - Used for visual representation in user interfaces.
23413
+
23414
+ ## Examples
23415
+
23416
+ \`\`\`book
23417
+ Professional Assistant
23418
+
23419
+ META COLOR #3498db
23420
+ PERSONA You are a professional business assistant
23421
+ \`\`\`
23422
+
23423
+ \`\`\`book
23424
+ Creative Helper
23425
+
23426
+ META COLOR #e74c3c
23427
+ PERSONA You are a creative and inspiring assistant
23428
+ \`\`\`
23429
+ `);
23430
+ }
23431
+ applyToAgentModelRequirements(requirements, content) {
23432
+ // META COLOR doesn't modify the system message or model requirements
23433
+ // It's handled separately in the parsing logic for profile color extraction
23434
+ // This method exists for consistency with the CommitmentDefinition interface
23435
+ return requirements;
23436
+ }
23437
+ /**
23438
+ * Extracts the profile color from the content
23439
+ * This is used by the parsing logic
23440
+ */
23441
+ extractProfileColor(content) {
23442
+ const trimmedContent = content.trim();
23443
+ return trimmedContent || null;
23444
+ }
23445
+ }
23446
+ /**
23447
+ * Note: [💞] Ignore a discrepancy between file name and entity name
23448
+ */
23449
+
23450
+ /**
23451
+ * META IMAGE commitment definition
23452
+ *
23453
+ * The META IMAGE commitment sets the agent's avatar/profile image URL.
23454
+ * This commitment is special because it doesn't affect the system message,
23455
+ * but is handled separately in the parsing logic.
23456
+ *
23457
+ * Example usage in agent source:
23458
+ *
23459
+ * ```book
23460
+ * META IMAGE https://example.com/avatar.jpg
23461
+ * META IMAGE /assets/agent-avatar.png
23462
+ * ```
23463
+ *
23464
+ * @private [🪔] Maybe export the commitments through some package
23465
+ */
23466
+ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
23467
+ constructor() {
23468
+ super('META IMAGE', ['IMAGE']);
23469
+ }
23470
+ /**
23471
+ * Short one-line description of META IMAGE.
23472
+ */
23473
+ get description() {
23474
+ return "Set the agent's profile image URL.";
23475
+ }
23476
+ /**
23477
+ * Markdown documentation for META IMAGE commitment.
23478
+ */
23479
+ get documentation() {
23480
+ return spaceTrim.spaceTrim(`
23481
+ # META IMAGE
23482
+
23483
+ Sets the agent's avatar/profile image URL.
23484
+
23485
+ ## Key aspects
23486
+
23487
+ - Does not modify the agent's behavior or responses.
23488
+ - Only one \`META IMAGE\` should be used per agent.
23489
+ - If multiple are specified, the last one takes precedence.
23490
+ - Used for visual representation in user interfaces.
23491
+
23492
+ ## Examples
23493
+
23494
+ \`\`\`book
23495
+ Professional Assistant
23496
+
23497
+ META IMAGE https://example.com/professional-avatar.jpg
23498
+ PERSONA You are a professional business assistant
23499
+ STYLE Maintain a formal and courteous tone
23500
+ \`\`\`
23501
+
23502
+ \`\`\`book
23503
+ Creative Helper
23504
+
23505
+ META IMAGE /assets/creative-bot-avatar.png
23506
+ PERSONA You are a creative and inspiring assistant
23507
+ STYLE Be enthusiastic and encouraging
23508
+ ACTION Can help with brainstorming and ideation
23509
+ \`\`\`
23510
+ `);
23511
+ }
23512
+ applyToAgentModelRequirements(requirements, content) {
23513
+ // META IMAGE doesn't modify the system message or model requirements
23514
+ // It's handled separately in the parsing logic for profile image extraction
23515
+ // This method exists for consistency with the CommitmentDefinition interface
23516
+ return requirements;
23517
+ }
23518
+ /**
23519
+ * Extracts the profile image URL from the content
23520
+ * This is used by the parsing logic
23521
+ */
23522
+ extractProfileImageUrl(content) {
23523
+ const trimmedContent = content.trim();
23524
+ return trimmedContent || null;
23525
+ }
23526
+ }
23527
+ /**
23528
+ * Note: [💞] Ignore a discrepancy between file name and entity name
23529
+ */
23530
+
23363
23531
  /**
23364
23532
  * MODEL commitment definition
23365
23533
  *
@@ -24267,6 +24435,8 @@
24267
24435
  new ModelCommitmentDefinition('MODELS'),
24268
24436
  new ActionCommitmentDefinition('ACTION'),
24269
24437
  new ActionCommitmentDefinition('ACTIONS'),
24438
+ new MetaImageCommitmentDefinition(),
24439
+ new MetaColorCommitmentDefinition(),
24270
24440
  new MetaCommitmentDefinition(),
24271
24441
  new NoteCommitmentDefinition('NOTE'),
24272
24442
  new NoteCommitmentDefinition('NOTES'),
@@ -24719,6 +24889,14 @@
24719
24889
  links.push(spaceTrim__default["default"](commitment.content));
24720
24890
  continue;
24721
24891
  }
24892
+ if (commitment.type === 'META IMAGE') {
24893
+ meta.image = spaceTrim__default["default"](commitment.content);
24894
+ continue;
24895
+ }
24896
+ if (commitment.type === 'META COLOR') {
24897
+ meta.color = spaceTrim__default["default"](commitment.content);
24898
+ continue;
24899
+ }
24722
24900
  if (commitment.type !== 'META') {
24723
24901
  continue;
24724
24902
  }
@@ -24734,6 +24912,10 @@
24734
24912
  if (!meta.image) {
24735
24913
  meta.image = generatePlaceholderAgentProfileImageUrl(parseResult.agentName || '!!');
24736
24914
  }
24915
+ // Generate fullname fallback if no meta fullname specified
24916
+ if (!meta.fullname) {
24917
+ meta.fullname = parseResult.agentName || createDefaultAgentName(agentSource);
24918
+ }
24737
24919
  // Parse parameters using unified approach - both @Parameter and {parameter} notations
24738
24920
  // are treated as the same syntax feature with unified representation
24739
24921
  const parameters = parseParameters(agentSource);