@promptbook/components 0.112.0-47 → 0.112.0-49

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 (51) hide show
  1. package/esm/index.es.js +1175 -167
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/src/avatars/AvatarOrImage.d.ts +5 -1
  4. package/esm/src/avatars/avatarAnimationScheduler.d.ts +16 -0
  5. package/esm/src/avatars/avatarInteractionUtils.d.ts +81 -0
  6. package/esm/src/avatars/avatarInteractionUtils.test.d.ts +1 -0
  7. package/esm/src/avatars/avatarPointerTracking.d.ts +33 -0
  8. package/esm/src/avatars/avatarRenderingUtils.d.ts +3 -2
  9. package/esm/src/avatars/avatarRenderingUtils.test.d.ts +1 -0
  10. package/esm/src/avatars/avatarVisibilityTracking.d.ts +17 -0
  11. package/esm/src/avatars/index.d.ts +1 -1
  12. package/esm/src/avatars/renderAvatarVisual.d.ts +29 -1
  13. package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +35 -0
  14. package/esm/src/avatars/visuals/octopusAvatarVisualShared.d.ts +34 -0
  15. package/esm/src/avatars/visuals/octopusAvatarVisualShared.test.d.ts +1 -0
  16. package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +3 -3
  17. package/esm/src/book-components/Chat/Chat/TeamToolCallModalContent.test.d.ts +2 -0
  18. package/esm/src/commitments/USE/USE.d.ts +1 -0
  19. package/esm/src/commitments/USE/aggregateUseCommitmentSystemMessages.d.ts +1 -1
  20. package/esm/src/commitments/USE_DEEPSEARCH/USE_DEEPSEARCH.d.ts +47 -0
  21. package/esm/src/commitments/USE_DEEPSEARCH/USE_DEEPSEARCH.test.d.ts +1 -0
  22. package/esm/src/commitments/_common/createSerpSearchToolFunction.d.ts +12 -0
  23. package/esm/src/commitments/index.d.ts +2 -1
  24. package/esm/src/llm-providers/openai/OpenAiAgentKitExecutionTools.test.d.ts +1 -0
  25. package/esm/src/version.d.ts +1 -1
  26. package/package.json +1 -1
  27. package/umd/index.umd.js +1174 -166
  28. package/umd/index.umd.js.map +1 -1
  29. package/umd/src/avatars/AvatarOrImage.d.ts +5 -1
  30. package/umd/src/avatars/avatarAnimationScheduler.d.ts +16 -0
  31. package/umd/src/avatars/avatarInteractionUtils.d.ts +81 -0
  32. package/umd/src/avatars/avatarInteractionUtils.test.d.ts +1 -0
  33. package/umd/src/avatars/avatarPointerTracking.d.ts +33 -0
  34. package/umd/src/avatars/avatarRenderingUtils.d.ts +3 -2
  35. package/umd/src/avatars/avatarRenderingUtils.test.d.ts +1 -0
  36. package/umd/src/avatars/avatarVisibilityTracking.d.ts +17 -0
  37. package/umd/src/avatars/index.d.ts +1 -1
  38. package/umd/src/avatars/renderAvatarVisual.d.ts +29 -1
  39. package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +35 -0
  40. package/umd/src/avatars/visuals/octopusAvatarVisualShared.d.ts +34 -0
  41. package/umd/src/avatars/visuals/octopusAvatarVisualShared.test.d.ts +1 -0
  42. package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +3 -3
  43. package/umd/src/book-components/Chat/Chat/TeamToolCallModalContent.test.d.ts +2 -0
  44. package/umd/src/commitments/USE/USE.d.ts +1 -0
  45. package/umd/src/commitments/USE/aggregateUseCommitmentSystemMessages.d.ts +1 -1
  46. package/umd/src/commitments/USE_DEEPSEARCH/USE_DEEPSEARCH.d.ts +47 -0
  47. package/umd/src/commitments/USE_DEEPSEARCH/USE_DEEPSEARCH.test.d.ts +1 -0
  48. package/umd/src/commitments/_common/createSerpSearchToolFunction.d.ts +12 -0
  49. package/umd/src/commitments/index.d.ts +2 -1
  50. package/umd/src/llm-providers/openai/OpenAiAgentKitExecutionTools.test.d.ts +1 -0
  51. package/umd/src/version.d.ts +1 -1
package/umd/index.umd.js CHANGED
@@ -30,7 +30,7 @@
30
30
  * @generated
31
31
  * @see https://github.com/webgptorg/promptbook
32
32
  */
33
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-47';
33
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-49';
34
34
  /**
35
35
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
36
36
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -1392,11 +1392,12 @@
1392
1392
  * Creates the shared derived palette used by every avatar visual.
1393
1393
  *
1394
1394
  * @param avatarDefinition Stable avatar definition.
1395
+ * @param surface Surface style used by the parent UI.
1395
1396
  * @returns Derived palette.
1396
1397
  *
1397
1398
  * @private utility of the avatar rendering system
1398
1399
  */
1399
- function createAvatarPalette(avatarDefinition) {
1400
+ function createAvatarPalette(avatarDefinition, surface = 'framed') {
1400
1401
  const normalizedAvatarDefinition = normalizeAvatarDefinition(avatarDefinition);
1401
1402
  const primaryColor = Color.fromSafe(normalizedAvatarDefinition.colors[0] || PROMPTBOOK_COLOR);
1402
1403
  const secondaryColor = Color.fromSafe(normalizedAvatarDefinition.colors[1] || primaryColor.then(lighten(0.12)).then(saturate(0.16)));
@@ -1406,8 +1407,8 @@
1406
1407
  const highlightColor = Color.fromSafe(accentColor.then(lighten(0.22)).then(saturate(0.08)));
1407
1408
  const shadowColor = Color.fromSafe(primaryColor.then(darken(0.46)).then(saturate(0.14)));
1408
1409
  return {
1409
- background: backgroundColor.toHex(),
1410
- backgroundSecondary: backgroundSecondaryColor.toHex(),
1410
+ background: surface === 'transparent' ? 'transparent' : backgroundColor.toHex(),
1411
+ backgroundSecondary: surface === 'transparent' ? 'transparent' : backgroundSecondaryColor.toHex(),
1411
1412
  primary: primaryColor.toHex(),
1412
1413
  secondary: secondaryColor.toHex(),
1413
1414
  accent: accentColor.toHex(),
@@ -1426,6 +1427,9 @@
1426
1427
  * @private utility of the avatar rendering system
1427
1428
  */
1428
1429
  function drawAvatarFrame(context, size, palette) {
1430
+ if (palette.background === 'transparent' && palette.backgroundSecondary === 'transparent') {
1431
+ return;
1432
+ }
1429
1433
  const gradient = context.createLinearGradient(0, 0, size, size);
1430
1434
  gradient.addColorStop(0, palette.background);
1431
1435
  gradient.addColorStop(1, palette.backgroundSecondary);
@@ -1505,10 +1509,22 @@
1505
1509
  */
1506
1510
  function prepareAvatarCanvas(canvas, context, size, devicePixelRatio) {
1507
1511
  const normalizedDevicePixelRatio = Math.max(1, Math.round(devicePixelRatio * 100) / 100);
1508
- canvas.width = Math.round(size * normalizedDevicePixelRatio);
1509
- canvas.height = Math.round(size * normalizedDevicePixelRatio);
1510
- canvas.style.width = `${size}px`;
1511
- canvas.style.height = `${size}px`;
1512
+ const nextCanvasWidth = Math.round(size * normalizedDevicePixelRatio);
1513
+ const nextCanvasHeight = Math.round(size * normalizedDevicePixelRatio);
1514
+ const nextCanvasStyleWidth = `${size}px`;
1515
+ const nextCanvasStyleHeight = `${size}px`;
1516
+ if (canvas.width !== nextCanvasWidth) {
1517
+ canvas.width = nextCanvasWidth;
1518
+ }
1519
+ if (canvas.height !== nextCanvasHeight) {
1520
+ canvas.height = nextCanvasHeight;
1521
+ }
1522
+ if (canvas.style.width !== nextCanvasStyleWidth) {
1523
+ canvas.style.width = nextCanvasStyleWidth;
1524
+ }
1525
+ if (canvas.style.height !== nextCanvasStyleHeight) {
1526
+ canvas.style.height = nextCanvasStyleHeight;
1527
+ }
1512
1528
  context.setTransform(normalizedDevicePixelRatio, 0, 0, normalizedDevicePixelRatio, 0, 0);
1513
1529
  context.clearRect(0, 0, size, size);
1514
1530
  }
@@ -1577,7 +1593,7 @@
1577
1593
  *
1578
1594
  * @private shared avatar contract
1579
1595
  */
1580
- const DEFAULT_AGENT_AVATAR_VISUAL_ID = 'octopus2';
1596
+ const DEFAULT_AGENT_AVATAR_VISUAL_ID = 'octopus3';
1581
1597
  /**
1582
1598
  * Resolve a base URL for relative images, preferring the provided base or browser location.
1583
1599
  *
@@ -11722,6 +11738,7 @@
11722
11738
  * Supported USE types:
11723
11739
  * - USE BROWSER: Enables the agent to use a web browser tool
11724
11740
  * - USE SEARCH ENGINE (future): Enables search engine access
11741
+ * - USE DEEPSEARCH: Enables deeper research-oriented search access
11725
11742
  * - USE FILE SYSTEM (future): Enables file system operations
11726
11743
  * - USE MCP (future): Enables MCP server connections
11727
11744
  *
@@ -11744,7 +11761,7 @@
11744
11761
  * Short one-line description of USE commitments.
11745
11762
  */
11746
11763
  get description() {
11747
- return 'Enable the agent to use specific tools or capabilities (BROWSER, SEARCH ENGINE, etc.).';
11764
+ return 'Enable the agent to use specific tools or capabilities (BROWSER, SEARCH ENGINE, DEEPSEARCH, etc.).';
11748
11765
  }
11749
11766
  /**
11750
11767
  * Icon for this commitment.
@@ -11765,6 +11782,7 @@
11765
11782
 
11766
11783
  - **USE BROWSER** - Enables the agent to use a web browser tool to access and retrieve information from the internet
11767
11784
  - **USE SEARCH ENGINE** (future) - Enables search engine access
11785
+ - **USE DEEPSEARCH** - Enables deeper research-oriented search access
11768
11786
  - **USE FILE SYSTEM** (future) - Enables file system operations
11769
11787
  - **USE MCP** (future) - Enables MCP server connections
11770
11788
 
@@ -11819,7 +11837,7 @@
11819
11837
  * Checks if this is a known USE type
11820
11838
  */
11821
11839
  isKnownUseType(useType) {
11822
- const knownTypes = ['BROWSER', 'SEARCH ENGINE', 'FILE SYSTEM', 'MCP'];
11840
+ const knownTypes = ['BROWSER', 'SEARCH ENGINE', 'DEEPSEARCH', 'FILE SYSTEM', 'MCP'];
11823
11841
  return knownTypes.includes(useType.toUpperCase());
11824
11842
  }
11825
11843
  }
@@ -11832,6 +11850,7 @@
11832
11850
  */
11833
11851
  const AGGREGATED_USE_COMMITMENT_TYPES = [
11834
11852
  'USE BROWSER',
11853
+ 'USE DEEPSEARCH',
11835
11854
  'USE SEARCH ENGINE',
11836
11855
  'USE TIME',
11837
11856
  ];
@@ -11911,6 +11930,15 @@
11911
11930
  - Do not tell the user you cannot search for information, YOU CAN.
11912
11931
  ${block(formatOptionalInstructionBlock('Search instructions', combinedAdditionalInstructions))}
11913
11932
  `);
11933
+ case 'USE DEEPSEARCH':
11934
+ return spacetrim.spaceTrim((block) => `
11935
+ Tool:
11936
+ - You have access to DeepSearch via the tool "deep_search".
11937
+ - Use it for broader research tasks that need multi-step investigation, comparison, or synthesis across multiple sources.
11938
+ - Prefer it over quick search when the user asks for a well-grounded brief, report, or deeper investigation.
11939
+ - Do not pretend you cannot research current information when this tool is available.
11940
+ ${block(formatOptionalInstructionBlock('DeepSearch instructions', combinedAdditionalInstructions))}
11941
+ `);
11914
11942
  }
11915
11943
  }
11916
11944
  /**
@@ -13460,6 +13488,207 @@
13460
13488
  }
13461
13489
  // Note: [💞] Ignore a discrepancy between file name and entity name
13462
13490
 
13491
+ /**
13492
+ * A search engine implementation that uses the SerpApi to fetch Google search results.
13493
+ *
13494
+ * @private <- TODO: !!!! Export via some package
13495
+ */
13496
+ class SerpSearchEngine {
13497
+ get title() {
13498
+ return 'SerpApi Search Engine';
13499
+ }
13500
+ get description() {
13501
+ return 'Search engine that uses SerpApi to fetch Google search results';
13502
+ }
13503
+ checkConfiguration() {
13504
+ if (!process.env.SERP_API_KEY) {
13505
+ throw new Error('SERP_API_KEY is not configured');
13506
+ }
13507
+ }
13508
+ async search(query, options = {}) {
13509
+ const apiKey = process.env.SERP_API_KEY;
13510
+ if (!apiKey) {
13511
+ throw new Error('SERP_API_KEY is not configured');
13512
+ }
13513
+ const url = new URL('https://serpapi.com/search');
13514
+ url.searchParams.set('api_key', apiKey);
13515
+ url.searchParams.set('engine', 'google');
13516
+ url.searchParams.set('q', query);
13517
+ for (const [key, value] of Object.entries(options)) {
13518
+ url.searchParams.set(key, String(value));
13519
+ }
13520
+ const response = await fetch(url.toString());
13521
+ if (!response.ok) {
13522
+ const body = await response.text();
13523
+ throw new Error(`SerpApi failed with status ${response.status}: ${response.statusText}\n${body}`);
13524
+ }
13525
+ const data = (await response.json());
13526
+ return (data.organic_results || []).map((item) => ({
13527
+ title: item.title,
13528
+ url: item.link,
13529
+ snippet: item.snippet || '',
13530
+ }));
13531
+ }
13532
+ }
13533
+
13534
+ /**
13535
+ * Creates one SERP-backed tool function used as a local fallback for search-like commitments.
13536
+ *
13537
+ * @param toolName - Technical tool name used for validation messages.
13538
+ * @param resultLabel - Human-readable label used in formatted results.
13539
+ * @returns Async tool function compatible with commitment tool registration.
13540
+ *
13541
+ * @private internal helper for search-like commitments
13542
+ */
13543
+ function createSerpSearchToolFunction(toolName, resultLabel) {
13544
+ return async (rawArgs) => {
13545
+ const { query, ...searchOptions } = rawArgs;
13546
+ if (typeof query !== 'string' || !query.trim()) {
13547
+ throw new Error(`${toolName} query is required`);
13548
+ }
13549
+ const searchEngine = new SerpSearchEngine();
13550
+ const results = await searchEngine.search(query, searchOptions);
13551
+ return spacetrim.spaceTrim((block) => `
13552
+ ${resultLabel} results for "${query}"${Object.keys(searchOptions).length === 0
13553
+ ? ''
13554
+ : ` with options ${JSON.stringify(searchOptions)}`}:
13555
+
13556
+ ${block(results
13557
+ .map((result) => spacetrim.spaceTrim(`
13558
+ - **${result.title}**
13559
+ ${result.url}
13560
+ ${result.snippet}
13561
+ `))
13562
+ .join('\n\n'))}
13563
+ `);
13564
+ };
13565
+ }
13566
+
13567
+ /**
13568
+ * USE DEEPSEARCH commitment definition
13569
+ *
13570
+ * The `USE DEEPSEARCH` commitment indicates that the agent should use a deeper research-oriented
13571
+ * search workflow instead of lightweight web search when it needs fresh information from the internet.
13572
+ *
13573
+ * The content following `USE DEEPSEARCH` is an arbitrary text that the agent should know
13574
+ * (e.g. search scope or research instructions).
13575
+ *
13576
+ * Example usage in agent source:
13577
+ *
13578
+ * ```book
13579
+ * USE DEEPSEARCH
13580
+ * USE DEEPSEARCH Compare official vendor documentation with independent benchmarks.
13581
+ * ```
13582
+ *
13583
+ * @private [🪔] Maybe export the commitments through some package
13584
+ */
13585
+ class UseDeepSearchCommitmentDefinition extends BaseCommitmentDefinition {
13586
+ constructor() {
13587
+ super('USE DEEPSEARCH');
13588
+ }
13589
+ get requiresContent() {
13590
+ return false;
13591
+ }
13592
+ /**
13593
+ * Short one-line description of USE DEEPSEARCH.
13594
+ */
13595
+ get description() {
13596
+ return 'Enable the agent to use DeepSearch for more thorough internet research.';
13597
+ }
13598
+ /**
13599
+ * Icon for this commitment.
13600
+ */
13601
+ get icon() {
13602
+ return '🔬';
13603
+ }
13604
+ /**
13605
+ * Markdown documentation for USE DEEPSEARCH commitment.
13606
+ */
13607
+ get documentation() {
13608
+ return spacetrim.spaceTrim(`
13609
+ # USE DEEPSEARCH
13610
+
13611
+ Enables the agent to use DeepSearch for broader, more thorough internet research than lightweight web search.
13612
+
13613
+ ## Key aspects
13614
+
13615
+ - The content following \`USE DEEPSEARCH\` is arbitrary guidance for the research workflow.
13616
+ - In Agents Server, the OpenAI Agents SDK runtime uses a nested deep-research agent for this tool.
13617
+ - Use this for investigations, comparisons, market scans, or other tasks that benefit from deeper synthesis.
13618
+ - Prefer regular \`USE SEARCH ENGINE\` when a quick factual lookup is enough.
13619
+
13620
+ ## Examples
13621
+
13622
+ \`\`\`book
13623
+ Due Diligence Researcher
13624
+
13625
+ GOAL Investigate vendors thoroughly before making recommendations.
13626
+ USE DEEPSEARCH Compare official sources with credible third-party analysis.
13627
+ RULE Cite the strongest supporting sources in the final answer.
13628
+ \`\`\`
13629
+
13630
+ \`\`\`book
13631
+ Market Analyst
13632
+
13633
+ GOAL Build concise but well-grounded research briefs.
13634
+ USE DEEPSEARCH Focus on recent public information and competing viewpoints.
13635
+ CLOSED
13636
+ \`\`\`
13637
+ `);
13638
+ }
13639
+ applyToAgentModelRequirements(requirements, content) {
13640
+ const existingTools = requirements.tools || [];
13641
+ const updatedTools = existingTools.some((tool) => tool.name === 'deep_search')
13642
+ ? existingTools
13643
+ : [
13644
+ ...existingTools,
13645
+ {
13646
+ name: 'deep_search',
13647
+ description: spacetrim.spaceTrim(`
13648
+ Research the internet deeply and synthesize a grounded answer.
13649
+ Use this tool for broader investigations, comparisons, and requests that need more than a quick search.
13650
+ `),
13651
+ parameters: {
13652
+ type: 'object',
13653
+ properties: {
13654
+ query: {
13655
+ type: 'string',
13656
+ description: 'The research question or investigation request.',
13657
+ },
13658
+ },
13659
+ required: ['query'],
13660
+ additionalProperties: false,
13661
+ },
13662
+ },
13663
+ ];
13664
+ return appendAggregatedUseCommitmentPlaceholder({
13665
+ ...requirements,
13666
+ tools: updatedTools,
13667
+ _metadata: {
13668
+ ...requirements._metadata,
13669
+ useDeepSearch: content || true,
13670
+ },
13671
+ }, this.type);
13672
+ }
13673
+ /**
13674
+ * Gets human-readable titles for tool functions provided by this commitment.
13675
+ */
13676
+ getToolTitles() {
13677
+ return {
13678
+ deep_search: 'DeepSearch',
13679
+ };
13680
+ }
13681
+ /**
13682
+ * Gets the local fallback implementation for the `deep_search` tool.
13683
+ */
13684
+ getToolFunctions() {
13685
+ return {
13686
+ deep_search: createSerpSearchToolFunction('deep_search', 'DeepSearch'),
13687
+ };
13688
+ }
13689
+ }
13690
+ // Note: [💞] Ignore a discrepancy between file name and entity name
13691
+
13463
13692
  /**
13464
13693
  * Lightweight email token matcher used for `USE EMAIL` first-line parsing.
13465
13694
  *
@@ -15691,49 +15920,6 @@
15691
15920
  }
15692
15921
  // Note: [💞] Ignore a discrepancy between file name and entity name
15693
15922
 
15694
- /**
15695
- * A search engine implementation that uses the SerpApi to fetch Google search results.
15696
- *
15697
- * @private <- TODO: !!!! Export via some package
15698
- */
15699
- class SerpSearchEngine {
15700
- get title() {
15701
- return 'SerpApi Search Engine';
15702
- }
15703
- get description() {
15704
- return 'Search engine that uses SerpApi to fetch Google search results';
15705
- }
15706
- checkConfiguration() {
15707
- if (!process.env.SERP_API_KEY) {
15708
- throw new Error('SERP_API_KEY is not configured');
15709
- }
15710
- }
15711
- async search(query, options = {}) {
15712
- const apiKey = process.env.SERP_API_KEY;
15713
- if (!apiKey) {
15714
- throw new Error('SERP_API_KEY is not configured');
15715
- }
15716
- const url = new URL('https://serpapi.com/search');
15717
- url.searchParams.set('api_key', apiKey);
15718
- url.searchParams.set('engine', 'google');
15719
- url.searchParams.set('q', query);
15720
- for (const [key, value] of Object.entries(options)) {
15721
- url.searchParams.set(key, String(value));
15722
- }
15723
- const response = await fetch(url.toString());
15724
- if (!response.ok) {
15725
- const body = await response.text();
15726
- throw new Error(`SerpApi failed with status ${response.status}: ${response.statusText}\n${body}`);
15727
- }
15728
- const data = (await response.json());
15729
- return (data.organic_results || []).map((item) => ({
15730
- title: item.title,
15731
- url: item.link,
15732
- snippet: item.snippet || '',
15733
- }));
15734
- }
15735
- }
15736
-
15737
15923
  /**
15738
15924
  * USE SEARCH ENGINE commitment definition
15739
15925
  *
@@ -15877,26 +16063,7 @@
15877
16063
  */
15878
16064
  getToolFunctions() {
15879
16065
  return {
15880
- async web_search(args) {
15881
- console.log('!!!! [Tool] web_search called', { args });
15882
- const { query, ...options } = args;
15883
- if (!query) {
15884
- throw new Error('Search query is required');
15885
- }
15886
- const searchEngine = new SerpSearchEngine();
15887
- const results = await searchEngine.search(query, options);
15888
- return spacetrim.spaceTrim((block) => `
15889
- Search results for "${query}"${Object.keys(options).length === 0 ? '' : ` with options ${JSON.stringify(options)}`}:
15890
-
15891
- ${block(results
15892
- .map((result) => spacetrim.spaceTrim(`
15893
- - **${result.title}**
15894
- ${result.url}
15895
- ${result.snippet}
15896
- `))
15897
- .join('\n\n'))}
15898
- `);
15899
- },
16066
+ web_search: createSerpSearchToolFunction('web_search', 'Search'),
15900
16067
  };
15901
16068
  }
15902
16069
  }
@@ -17542,6 +17709,7 @@
17542
17709
  new ClosedCommitmentDefinition(),
17543
17710
  new TeamCommitmentDefinition(),
17544
17711
  new UseBrowserCommitmentDefinition(),
17712
+ new UseDeepSearchCommitmentDefinition(),
17545
17713
  new UseSearchEngineCommitmentDefinition(),
17546
17714
  new UseSpawnCommitmentDefinition(),
17547
17715
  new UseTimeoutCommitmentDefinition(),
@@ -17853,6 +18021,11 @@
17853
18021
  label: 'Internet',
17854
18022
  iconName: 'Search',
17855
18023
  },
18024
+ 'USE DEEPSEARCH': {
18025
+ type: 'search-engine',
18026
+ label: 'DeepSearch',
18027
+ iconName: 'Search',
18028
+ },
17856
18029
  'USE TIME': {
17857
18030
  type: 'time',
17858
18031
  label: 'Time',
@@ -25728,6 +25901,496 @@
25728
25901
  }), children: jsxRuntime.jsx(SendIcon, { size: 25 }) })] }), speechRecognition && (jsxRuntime.jsx(ChatInputAreaDictationPanel, { bubbleText: speechRecognitionUiDescriptor.bubbleText, bubbleTone: speechRecognitionUiDescriptor.bubbleTone, shouldShowPanel: shouldShowDictationPanel, isExpanded: isDictationPanelExpanded, interimText: dictationInterimText, error: dictationError, lastFinalChunk: dictationLastFinalChunk, editableChunk: dictationEditableChunk, canBacktrack: canBacktrack, dictationSettings: dictationSettings, isBrowserSpeechFallbackSupported: isBrowserSpeechFallbackSupported, canOpenBrowserSettings: canOpenBrowserSettings, onToggleExpanded: toggleDictationPanel, onExpand: expandDictationPanel, onEditableChunkChange: setDictationEditableChunk, onRetryPermissionRequest: handleRetryPermissionRequest, onOpenBrowserSettings: handleOpenBrowserSettings, onApplyCorrection: handleApplyCorrection, onBacktrackLastChunk: handleBacktrackLastChunk, onDictationSettingChange: handleDictationSettingChange })), isUploading && (jsxRuntime.jsxs("div", { className: styles$5.uploadProgress, children: [jsxRuntime.jsx("div", { className: styles$5.uploadProgressBar, children: jsxRuntime.jsx("div", { className: styles$5.uploadProgressFill }) }), jsxRuntime.jsx("span", { children: "Uploading files..." })] })), isDragOver && onFileUpload && (jsxRuntime.jsx("div", { className: styles$5.dragOverlay, children: jsxRuntime.jsxs("div", { className: styles$5.dragOverlayContent, children: [jsxRuntime.jsx(AttachmentIcon, { size: 48 }), jsxRuntime.jsx("span", { children: "Drop files here to upload" })] }) }))] }));
25729
25902
  }
25730
25903
 
25904
+ // Note: [💞] Ignore a discrepancy between file name and entity name
25905
+ /**
25906
+ * Maximum normalized eye travel used when the viewer moves across the viewport.
25907
+ *
25908
+ * @private utility of the avatar rendering system
25909
+ */
25910
+ const MAX_GAZE_OFFSET = 0.78;
25911
+ /**
25912
+ * Maximum normalized body lean used for subtle mantle response.
25913
+ *
25914
+ * @private utility of the avatar rendering system
25915
+ */
25916
+ const MAX_BODY_OFFSET = 0.28;
25917
+ /**
25918
+ * Smoothing window used while a live pointer or touch target is active.
25919
+ *
25920
+ * @private utility of the avatar rendering system
25921
+ */
25922
+ const ACTIVE_INTERACTION_SMOOTHING_MS = 90;
25923
+ /**
25924
+ * Slower smoothing window used when easing the avatar back to its idle state.
25925
+ *
25926
+ * @private utility of the avatar rendering system
25927
+ */
25928
+ const IDLE_INTERACTION_SMOOTHING_MS = 230;
25929
+ /**
25930
+ * Maximum frame delta allowed when smoothing interaction after tab stalls.
25931
+ *
25932
+ * @private utility of the avatar rendering system
25933
+ */
25934
+ const MAX_INTERACTION_FRAME_DELTA_MS = 64;
25935
+ /**
25936
+ * Extra damping used for the slower body lean compared with the quicker eye motion.
25937
+ *
25938
+ * @private utility of the avatar rendering system
25939
+ */
25940
+ const BODY_INTERACTION_SMOOTHING_MULTIPLIER = 1.2;
25941
+ /**
25942
+ * Stable zeroed interaction state used by non-interactive render paths.
25943
+ *
25944
+ * @private utility of the avatar rendering system
25945
+ */
25946
+ const IDLE_AVATAR_INTERACTION_STATE = {
25947
+ gazeX: 0,
25948
+ gazeY: 0,
25949
+ bodyOffsetX: 0,
25950
+ bodyOffsetY: 0,
25951
+ intensity: 0,
25952
+ isPointerActive: false,
25953
+ pointerType: 'idle',
25954
+ };
25955
+ /**
25956
+ * Creates one stable cache key from the meaningful avatar-definition fields.
25957
+ *
25958
+ * @param avatarDefinition Normalized or raw avatar definition.
25959
+ * @returns Stable cache key that ignores object identity churn.
25960
+ *
25961
+ * @private utility of the avatar rendering system
25962
+ */
25963
+ function createAvatarDefinitionKey(avatarDefinition) {
25964
+ const normalizedAvatarDefinition = normalizeAvatarDefinition(avatarDefinition);
25965
+ return [
25966
+ normalizedAvatarDefinition.agentName,
25967
+ normalizedAvatarDefinition.agentHash,
25968
+ normalizedAvatarDefinition.colors.join('|'),
25969
+ ].join('::');
25970
+ }
25971
+ /**
25972
+ * Returns the neutral interaction state used by static/server-side renders.
25973
+ *
25974
+ * @returns Zeroed interaction state.
25975
+ *
25976
+ * @private utility of the avatar rendering system
25977
+ */
25978
+ function createIdleAvatarInteractionState() {
25979
+ return IDLE_AVATAR_INTERACTION_STATE;
25980
+ }
25981
+ /**
25982
+ * Creates a fresh runtime state for the interactive animation loop.
25983
+ *
25984
+ * @returns Runtime interaction state with neutral values.
25985
+ *
25986
+ * @private utility of the avatar rendering system
25987
+ */
25988
+ function createAvatarInteractionRuntimeState() {
25989
+ return {
25990
+ ...IDLE_AVATAR_INTERACTION_STATE,
25991
+ lastFrameMs: null,
25992
+ };
25993
+ }
25994
+ /**
25995
+ * Converts the shared viewport pointer state into one avatar-local gaze target.
25996
+ *
25997
+ * @param avatarBounds Canvas bounds in viewport coordinates.
25998
+ * @param pointerSnapshot Latest shared pointer sample.
25999
+ * @returns Local target used to steer eyes and subtle body lean.
26000
+ *
26001
+ * @private utility of the avatar rendering system
26002
+ */
26003
+ function resolveAvatarPointerTarget(avatarBounds, pointerSnapshot) {
26004
+ if (!pointerSnapshot || !pointerSnapshot.isPointerActive) {
26005
+ return {
26006
+ ...IDLE_AVATAR_INTERACTION_STATE,
26007
+ };
26008
+ }
26009
+ const centerX = avatarBounds.left + avatarBounds.width / 2;
26010
+ const centerY = avatarBounds.top + avatarBounds.height / 2;
26011
+ const normalizedX = (pointerSnapshot.clientX - centerX) / Math.max(avatarBounds.width / 2, 1);
26012
+ const normalizedY = (pointerSnapshot.clientY - centerY) / Math.max(avatarBounds.height / 2, 1);
26013
+ const normalizedLength = Math.hypot(normalizedX, normalizedY) || 1;
26014
+ const clampedLength = Math.min(1, normalizedLength);
26015
+ const targetX = (normalizedX / normalizedLength) * clampedLength;
26016
+ const targetY = (normalizedY / normalizedLength) * clampedLength;
26017
+ const intensity = clamp01$1(clampedLength);
26018
+ return {
26019
+ gazeX: targetX * MAX_GAZE_OFFSET,
26020
+ gazeY: targetY * MAX_GAZE_OFFSET,
26021
+ bodyOffsetX: targetX * MAX_BODY_OFFSET,
26022
+ bodyOffsetY: targetY * MAX_BODY_OFFSET,
26023
+ intensity,
26024
+ isPointerActive: true,
26025
+ pointerType: pointerSnapshot.pointerType,
26026
+ };
26027
+ }
26028
+ /**
26029
+ * Advances the smoothed interaction state toward the latest pointer target.
26030
+ *
26031
+ * @param runtimeState Previous animation-frame state.
26032
+ * @param pointerTarget Latest local pointer target.
26033
+ * @param nowMs Current animation-frame timestamp.
26034
+ * @returns Next runtime state to keep in the animation loop.
26035
+ *
26036
+ * @private utility of the avatar rendering system
26037
+ */
26038
+ function stepAvatarInteractionRuntimeState(runtimeState, pointerTarget, nowMs) {
26039
+ const deltaMs = runtimeState.lastFrameMs === null
26040
+ ? 16
26041
+ : Math.min(MAX_INTERACTION_FRAME_DELTA_MS, Math.max(8, nowMs - runtimeState.lastFrameMs));
26042
+ const smoothingWindowMs = pointerTarget.isPointerActive
26043
+ ? ACTIVE_INTERACTION_SMOOTHING_MS
26044
+ : IDLE_INTERACTION_SMOOTHING_MS;
26045
+ // This exponential interpolation keeps the gaze response smooth regardless of fluctuating frame rates.
26046
+ return {
26047
+ gazeX: interpolateExponentially(runtimeState.gazeX, pointerTarget.gazeX, deltaMs, smoothingWindowMs),
26048
+ gazeY: interpolateExponentially(runtimeState.gazeY, pointerTarget.gazeY, deltaMs, smoothingWindowMs),
26049
+ bodyOffsetX: interpolateExponentially(runtimeState.bodyOffsetX, pointerTarget.bodyOffsetX, deltaMs, smoothingWindowMs * BODY_INTERACTION_SMOOTHING_MULTIPLIER),
26050
+ bodyOffsetY: interpolateExponentially(runtimeState.bodyOffsetY, pointerTarget.bodyOffsetY, deltaMs, smoothingWindowMs * BODY_INTERACTION_SMOOTHING_MULTIPLIER),
26051
+ intensity: interpolateExponentially(runtimeState.intensity, pointerTarget.intensity, deltaMs, smoothingWindowMs),
26052
+ isPointerActive: pointerTarget.isPointerActive,
26053
+ pointerType: pointerTarget.pointerType,
26054
+ lastFrameMs: nowMs,
26055
+ };
26056
+ }
26057
+ /**
26058
+ * Clamps a scalar into the inclusive `[0, 1]` range.
26059
+ *
26060
+ * @param value Arbitrary scalar.
26061
+ * @returns Clamped scalar.
26062
+ *
26063
+ * @private utility of the avatar rendering system
26064
+ */
26065
+ function clamp01$1(value) {
26066
+ return Math.min(1, Math.max(0, value));
26067
+ }
26068
+ /**
26069
+ * Interpolates between two values using frame-rate-independent exponential easing.
26070
+ *
26071
+ * @param currentValue Current smoothed value.
26072
+ * @param targetValue Target value.
26073
+ * @param deltaMs Elapsed milliseconds since the previous frame.
26074
+ * @param smoothingWindowMs Time constant controlling responsiveness.
26075
+ * @returns Smoothed next value.
26076
+ *
26077
+ * @private utility of the avatar rendering system
26078
+ */
26079
+ function interpolateExponentially(currentValue, targetValue, deltaMs, smoothingWindowMs) {
26080
+ const blend = 1 - Math.exp(-deltaMs / Math.max(1, smoothingWindowMs));
26081
+ return currentValue + (targetValue - currentValue) * blend;
26082
+ }
26083
+
26084
+ // Note: [💞] Ignore a discrepancy between file name and entity name
26085
+ /**
26086
+ * Next registration id used by the shared avatar animation scheduler.
26087
+ *
26088
+ * @private utility of the avatar rendering system
26089
+ */
26090
+ let nextAvatarAnimationListenerId = 1;
26091
+ /**
26092
+ * Active avatar animation callbacks keyed by their registration id.
26093
+ *
26094
+ * @private utility of the avatar rendering system
26095
+ */
26096
+ const avatarAnimationListeners = new Map();
26097
+ /**
26098
+ * Active shared animation-frame handle.
26099
+ *
26100
+ * @private utility of the avatar rendering system
26101
+ */
26102
+ let avatarAnimationFrameId = null;
26103
+ /**
26104
+ * Registers one avatar animation callback in the shared animation loop.
26105
+ *
26106
+ * @param avatarAnimationListener Frame callback invoked on every animation frame.
26107
+ * @returns Cleanup function that unregisters the callback.
26108
+ *
26109
+ * @private utility of the avatar rendering system
26110
+ */
26111
+ function retainAvatarAnimationListener(avatarAnimationListener) {
26112
+ if (typeof window === 'undefined') {
26113
+ return () => undefined;
26114
+ }
26115
+ const listenerId = nextAvatarAnimationListenerId++;
26116
+ avatarAnimationListeners.set(listenerId, avatarAnimationListener);
26117
+ ensureAvatarAnimationLoop();
26118
+ return () => {
26119
+ avatarAnimationListeners.delete(listenerId);
26120
+ if (avatarAnimationListeners.size === 0 && avatarAnimationFrameId !== null) {
26121
+ window.cancelAnimationFrame(avatarAnimationFrameId);
26122
+ avatarAnimationFrameId = null;
26123
+ }
26124
+ };
26125
+ }
26126
+ /**
26127
+ * Ensures the shared animation loop is running while at least one avatar listener is active.
26128
+ *
26129
+ * @private utility of the avatar rendering system
26130
+ */
26131
+ function ensureAvatarAnimationLoop() {
26132
+ if (avatarAnimationFrameId !== null || avatarAnimationListeners.size === 0 || typeof window === 'undefined') {
26133
+ return;
26134
+ }
26135
+ const runFrame = (now) => {
26136
+ avatarAnimationFrameId = null;
26137
+ for (const avatarAnimationListener of [...avatarAnimationListeners.values()]) {
26138
+ avatarAnimationListener(now);
26139
+ }
26140
+ ensureAvatarAnimationLoop();
26141
+ };
26142
+ avatarAnimationFrameId = window.requestAnimationFrame(runFrame);
26143
+ }
26144
+
26145
+ // Note: [💞] Ignore a discrepancy between file name and entity name
26146
+ /**
26147
+ * Shared `IntersectionObserver` callbacks grouped by observed element.
26148
+ *
26149
+ * @private utility of the avatar rendering system
26150
+ */
26151
+ const avatarVisibilityListeners = new Map();
26152
+ /**
26153
+ * Lazily created shared `IntersectionObserver` used by avatar canvases.
26154
+ *
26155
+ * @private utility of the avatar rendering system
26156
+ */
26157
+ let avatarVisibilityObserver = null;
26158
+ /**
26159
+ * Observes one avatar element and notifies the caller when it enters or leaves the viewport.
26160
+ *
26161
+ * @param element Observed avatar element.
26162
+ * @param avatarVisibilityListener Listener notified with the current visibility state.
26163
+ * @returns Cleanup function that stops observing the element.
26164
+ *
26165
+ * @private utility of the avatar rendering system
26166
+ */
26167
+ function observeAvatarVisibility(element, avatarVisibilityListener) {
26168
+ if (typeof window === 'undefined' || typeof IntersectionObserver === 'undefined') {
26169
+ avatarVisibilityListener(true);
26170
+ return () => undefined;
26171
+ }
26172
+ const observer = getAvatarVisibilityObserver();
26173
+ const elementListeners = avatarVisibilityListeners.get(element) || new Set();
26174
+ elementListeners.add(avatarVisibilityListener);
26175
+ avatarVisibilityListeners.set(element, elementListeners);
26176
+ observer.observe(element);
26177
+ return () => {
26178
+ const currentElementListeners = avatarVisibilityListeners.get(element);
26179
+ if (!currentElementListeners) {
26180
+ return;
26181
+ }
26182
+ currentElementListeners.delete(avatarVisibilityListener);
26183
+ if (currentElementListeners.size > 0) {
26184
+ return;
26185
+ }
26186
+ avatarVisibilityListeners.delete(element);
26187
+ observer.unobserve(element);
26188
+ };
26189
+ }
26190
+ /**
26191
+ * Creates the shared `IntersectionObserver` used by all avatar canvases.
26192
+ *
26193
+ * @returns Shared observer instance.
26194
+ *
26195
+ * @private utility of the avatar rendering system
26196
+ */
26197
+ function getAvatarVisibilityObserver() {
26198
+ if (avatarVisibilityObserver) {
26199
+ return avatarVisibilityObserver;
26200
+ }
26201
+ avatarVisibilityObserver = new IntersectionObserver((entries) => {
26202
+ for (const entry of entries) {
26203
+ const elementListeners = avatarVisibilityListeners.get(entry.target);
26204
+ if (!elementListeners) {
26205
+ continue;
26206
+ }
26207
+ const isVisible = entry.isIntersecting && entry.intersectionRatio > 0;
26208
+ for (const avatarVisibilityListener of elementListeners) {
26209
+ avatarVisibilityListener(isVisible);
26210
+ }
26211
+ }
26212
+ });
26213
+ return avatarVisibilityObserver;
26214
+ }
26215
+
26216
+ // Note: [💞] Ignore a discrepancy between file name and entity name
26217
+ /**
26218
+ * Active avatar instances currently consuming the shared pointer tracker.
26219
+ *
26220
+ * @private utility of the avatar rendering system
26221
+ */
26222
+ let avatarPointerTrackingConsumerCount = 0;
26223
+ /**
26224
+ * Latest shared viewport pointer sample.
26225
+ *
26226
+ * @private utility of the avatar rendering system
26227
+ */
26228
+ let currentAvatarPointerSnapshot = null;
26229
+ /**
26230
+ * Monotonic version incremented whenever the shared pointer snapshot changes.
26231
+ *
26232
+ * @private utility of the avatar rendering system
26233
+ */
26234
+ let currentAvatarPointerSnapshotVersion = 0;
26235
+ /**
26236
+ * Monotonic version incremented whenever scrolling or resizing may invalidate cached avatar bounds.
26237
+ *
26238
+ * @private utility of the avatar rendering system
26239
+ */
26240
+ let currentAvatarViewportLayoutVersion = 0;
26241
+ /**
26242
+ * Cleanup function for the lazily attached global listeners.
26243
+ *
26244
+ * @private utility of the avatar rendering system
26245
+ */
26246
+ let releaseAvatarPointerTrackingListeners = null;
26247
+ /**
26248
+ * Starts the shared pointer tracker and returns a disposer for the caller.
26249
+ *
26250
+ * @returns Cleanup function that releases one consumer.
26251
+ *
26252
+ * @private utility of the avatar rendering system
26253
+ */
26254
+ function retainAvatarPointerTracking() {
26255
+ avatarPointerTrackingConsumerCount++;
26256
+ if (avatarPointerTrackingConsumerCount === 1) {
26257
+ releaseAvatarPointerTrackingListeners = attachAvatarPointerTrackingListeners();
26258
+ }
26259
+ return () => {
26260
+ avatarPointerTrackingConsumerCount = Math.max(0, avatarPointerTrackingConsumerCount - 1);
26261
+ if (avatarPointerTrackingConsumerCount === 0) {
26262
+ currentAvatarPointerSnapshot = null;
26263
+ releaseAvatarPointerTrackingListeners === null || releaseAvatarPointerTrackingListeners === void 0 ? void 0 : releaseAvatarPointerTrackingListeners();
26264
+ releaseAvatarPointerTrackingListeners = null;
26265
+ }
26266
+ };
26267
+ }
26268
+ /**
26269
+ * Returns the latest shared viewport pointer sample when available.
26270
+ *
26271
+ * @returns Shared pointer snapshot or `null`.
26272
+ *
26273
+ * @private utility of the avatar rendering system
26274
+ */
26275
+ function getAvatarPointerSnapshot() {
26276
+ return currentAvatarPointerSnapshot;
26277
+ }
26278
+ /**
26279
+ * Returns the current pointer snapshot version.
26280
+ *
26281
+ * @returns Monotonic pointer snapshot version.
26282
+ *
26283
+ * @private utility of the avatar rendering system
26284
+ */
26285
+ function getAvatarPointerSnapshotVersion() {
26286
+ return currentAvatarPointerSnapshotVersion;
26287
+ }
26288
+ /**
26289
+ * Returns the current viewport-layout version used to invalidate cached avatar bounds.
26290
+ *
26291
+ * @returns Monotonic viewport-layout version.
26292
+ *
26293
+ * @private utility of the avatar rendering system
26294
+ */
26295
+ function getAvatarViewportLayoutVersion() {
26296
+ return currentAvatarViewportLayoutVersion;
26297
+ }
26298
+ /**
26299
+ * Attaches the global pointer/touch listeners used by all live avatar canvases.
26300
+ *
26301
+ * @returns Cleanup function for the attached listeners.
26302
+ *
26303
+ * @private utility of the avatar rendering system
26304
+ */
26305
+ function attachAvatarPointerTrackingListeners() {
26306
+ if (typeof window === 'undefined') {
26307
+ return () => undefined;
26308
+ }
26309
+ const clearPointerSnapshot = () => {
26310
+ if (currentAvatarPointerSnapshot === null) {
26311
+ return;
26312
+ }
26313
+ currentAvatarPointerSnapshot = null;
26314
+ currentAvatarPointerSnapshotVersion++;
26315
+ };
26316
+ const updatePointerSnapshot = (clientX, clientY, pointerType) => {
26317
+ currentAvatarPointerSnapshot = {
26318
+ clientX,
26319
+ clientY,
26320
+ isPointerActive: true,
26321
+ pointerType,
26322
+ };
26323
+ currentAvatarPointerSnapshotVersion++;
26324
+ };
26325
+ const invalidateViewportLayout = () => {
26326
+ currentAvatarViewportLayoutVersion++;
26327
+ };
26328
+ const handlePointerMove = (event) => {
26329
+ updatePointerSnapshot(event.clientX, event.clientY, normalizeAvatarPointerType(event.pointerType));
26330
+ };
26331
+ const handlePointerDown = (event) => {
26332
+ updatePointerSnapshot(event.clientX, event.clientY, normalizeAvatarPointerType(event.pointerType));
26333
+ };
26334
+ const handlePointerUp = (event) => {
26335
+ if (normalizeAvatarPointerType(event.pointerType) !== 'mouse') {
26336
+ clearPointerSnapshot();
26337
+ }
26338
+ };
26339
+ const handleMouseOut = (event) => {
26340
+ if (!event.relatedTarget) {
26341
+ clearPointerSnapshot();
26342
+ }
26343
+ };
26344
+ const handleTouchEvent = (event) => {
26345
+ const touch = event.touches[0] || event.changedTouches[0];
26346
+ if (!touch) {
26347
+ clearPointerSnapshot();
26348
+ return;
26349
+ }
26350
+ updatePointerSnapshot(touch.clientX, touch.clientY, 'touch');
26351
+ };
26352
+ window.addEventListener('pointermove', handlePointerMove, { passive: true });
26353
+ window.addEventListener('pointerdown', handlePointerDown, { passive: true });
26354
+ window.addEventListener('pointerup', handlePointerUp, { passive: true });
26355
+ window.addEventListener('pointercancel', clearPointerSnapshot, { passive: true });
26356
+ window.addEventListener('mouseout', handleMouseOut, { passive: true });
26357
+ window.addEventListener('blur', clearPointerSnapshot);
26358
+ window.addEventListener('touchstart', handleTouchEvent, { passive: true });
26359
+ window.addEventListener('touchmove', handleTouchEvent, { passive: true });
26360
+ window.addEventListener('touchend', clearPointerSnapshot, { passive: true });
26361
+ window.addEventListener('touchcancel', clearPointerSnapshot, { passive: true });
26362
+ window.addEventListener('scroll', invalidateViewportLayout, { passive: true, capture: true });
26363
+ window.addEventListener('resize', invalidateViewportLayout, { passive: true });
26364
+ return () => {
26365
+ window.removeEventListener('pointermove', handlePointerMove);
26366
+ window.removeEventListener('pointerdown', handlePointerDown);
26367
+ window.removeEventListener('pointerup', handlePointerUp);
26368
+ window.removeEventListener('pointercancel', clearPointerSnapshot);
26369
+ window.removeEventListener('mouseout', handleMouseOut);
26370
+ window.removeEventListener('blur', clearPointerSnapshot);
26371
+ window.removeEventListener('touchstart', handleTouchEvent);
26372
+ window.removeEventListener('touchmove', handleTouchEvent);
26373
+ window.removeEventListener('touchend', clearPointerSnapshot);
26374
+ window.removeEventListener('touchcancel', clearPointerSnapshot);
26375
+ window.removeEventListener('scroll', invalidateViewportLayout, true);
26376
+ window.removeEventListener('resize', invalidateViewportLayout);
26377
+ };
26378
+ }
26379
+ /**
26380
+ * Normalizes browser pointer-type strings into the shared avatar contract.
26381
+ *
26382
+ * @param pointerType Raw browser pointer type.
26383
+ * @returns Shared pointer type.
26384
+ *
26385
+ * @private utility of the avatar rendering system
26386
+ */
26387
+ function normalizeAvatarPointerType(pointerType) {
26388
+ if (pointerType === 'touch' || pointerType === 'pen') {
26389
+ return pointerType;
26390
+ }
26391
+ return 'mouse';
26392
+ }
26393
+
25731
26394
  /* eslint-disable no-magic-numbers */
25732
26395
  /**
25733
26396
  * Builds a smoothly morphing octopus-like silhouette from deterministic parameters.
@@ -25804,8 +26467,9 @@
25804
26467
  * @private shared geometry helper of `octopus3AvatarVisual` and `asciiOctopusAvatarVisual`
25805
26468
  */
25806
26469
  function createOrganicOctopusTentacleShapes(options) {
25807
- const { size, centerX, centerY, bodyRadius, horizontalStretch, tentacleCount, shapePhase, createRandom, timeMs, saltPrefix, } = options;
26470
+ const { size, centerX, centerY, bodyRadius, horizontalStretch, tentacleCount, shapePhase, createRandom, timeMs, saltPrefix, bodyPoints } = options;
25808
26471
  const baseY = centerY + bodyRadius * 0.74;
26472
+ const lowerBodyAnchorPoints = bodyPoints ? resolveTentacleBodyAnchorPoints(bodyPoints, centerY + bodyRadius * 0.04) : null;
25809
26473
  return Array.from({ length: tentacleCount }, (_, tentacleIndex) => {
25810
26474
  const tentacleRandom = createRandom(`${saltPrefix}-tentacle-${tentacleIndex}`);
25811
26475
  const spreadProgress = tentacleCount === 1 ? 0.5 : tentacleIndex / (tentacleCount - 1);
@@ -25817,10 +26481,21 @@
25817
26481
  const curlDirection = centeredProgress === 0 ? (tentacleRandom() < 0.5 ? -1 : 1) : Math.sign(centeredProgress);
25818
26482
  const lateralReach = centeredProgress * size * (0.1 + tentacleRandom() * 0.1) + temporalSway;
25819
26483
  const tipReach = curlDirection * size * (0.025 + tentacleRandom() * 0.07);
25820
- const startPoint = {
25821
- x: centerX + centeredProgress * bodyRadius * horizontalStretch * 1.52,
25822
- y: baseY + Math.abs(centeredProgress) * size * 0.012 + tentacleRandom() * size * 0.01,
25823
- };
26484
+ const startYOffset = Math.abs(centeredProgress) * size * 0.012 + tentacleRandom() * size * 0.01;
26485
+ const startPoint = lowerBodyAnchorPoints && lowerBodyAnchorPoints.length >= 2
26486
+ ? createInsetTentacleStartPoint({
26487
+ bodyPoints: lowerBodyAnchorPoints,
26488
+ anchorProgress: spreadProgress,
26489
+ centerX,
26490
+ centerY,
26491
+ bodyRadius,
26492
+ centeredProgress,
26493
+ startYOffset,
26494
+ })
26495
+ : {
26496
+ x: centerX + centeredProgress * bodyRadius * horizontalStretch * 1.52,
26497
+ y: baseY + startYOffset,
26498
+ };
25824
26499
  const controlPointOne = {
25825
26500
  x: startPoint.x + centeredProgress * size * 0.045 + temporalSway * 0.4,
25826
26501
  y: startPoint.y + flowLength * (0.21 + tentacleRandom() * 0.08),
@@ -25850,6 +26525,67 @@
25850
26525
  };
25851
26526
  });
25852
26527
  }
26528
+ /**
26529
+ * Narrows the body contour to lower anchor points that can safely host tentacle roots.
26530
+ *
26531
+ * @param bodyPoints Generated closed-loop body points.
26532
+ * @param lowerBodyThresholdY Minimum Y coordinate considered part of the lower mantle.
26533
+ * @returns Body points sorted from left to right across the lower silhouette.
26534
+ *
26535
+ * @private shared geometry helper of `octopus3AvatarVisual`
26536
+ */
26537
+ function resolveTentacleBodyAnchorPoints(bodyPoints, lowerBodyThresholdY) {
26538
+ const lowerBodyPoints = bodyPoints.filter((bodyPoint) => bodyPoint.y >= lowerBodyThresholdY).sort((leftPoint, rightPoint) => leftPoint.x - rightPoint.x);
26539
+ if (lowerBodyPoints.length >= 2) {
26540
+ return lowerBodyPoints;
26541
+ }
26542
+ return [...bodyPoints].sort((leftPoint, rightPoint) => leftPoint.x - rightPoint.x);
26543
+ }
26544
+ /**
26545
+ * Resolves one tentacle root from the provided lower body contour and nudges it inside the mantle.
26546
+ *
26547
+ * @param options Tentacle anchor options.
26548
+ * @returns Tentacle start point safely embedded inside the body silhouette.
26549
+ *
26550
+ * @private shared geometry helper of `octopus3AvatarVisual`
26551
+ */
26552
+ function createInsetTentacleStartPoint(options) {
26553
+ const { bodyPoints, anchorProgress, centerX, centerY, bodyRadius, centeredProgress, startYOffset } = options;
26554
+ const clampedAnchorProgress = Math.min(0.94, Math.max(0.06, anchorProgress));
26555
+ const bodyAnchorPoint = interpolatePointAlongTentacleAnchors(bodyPoints, clampedAnchorProgress);
26556
+ const inwardX = centerX - bodyAnchorPoint.x;
26557
+ const inwardY = centerY + bodyRadius * 0.08 - bodyAnchorPoint.y;
26558
+ const inwardLength = Math.hypot(inwardX, inwardY) || 1;
26559
+ const insetDistance = bodyRadius * (0.12 + Math.abs(centeredProgress) * 0.05) + startYOffset * 0.32;
26560
+ return {
26561
+ x: bodyAnchorPoint.x + (inwardX / inwardLength) * insetDistance,
26562
+ y: bodyAnchorPoint.y + (inwardY / inwardLength) * insetDistance,
26563
+ };
26564
+ }
26565
+ /**
26566
+ * Interpolates one left-to-right anchor point along the prepared lower body contour.
26567
+ *
26568
+ * @param bodyPoints Lower body contour points sorted from left to right.
26569
+ * @param progress Interpolation progress in the range `[0, 1]`.
26570
+ * @returns Interpolated anchor point.
26571
+ *
26572
+ * @private shared geometry helper of `octopus3AvatarVisual`
26573
+ */
26574
+ function interpolatePointAlongTentacleAnchors(bodyPoints, progress) {
26575
+ if (bodyPoints.length === 1) {
26576
+ return bodyPoints[0];
26577
+ }
26578
+ const anchorIndex = progress * (bodyPoints.length - 1);
26579
+ const startIndex = Math.floor(anchorIndex);
26580
+ const endIndex = Math.min(bodyPoints.length - 1, startIndex + 1);
26581
+ const blend = anchorIndex - startIndex;
26582
+ const startPoint = bodyPoints[startIndex];
26583
+ const endPoint = bodyPoints[endIndex];
26584
+ return {
26585
+ x: startPoint.x + (endPoint.x - startPoint.x) * blend,
26586
+ y: startPoint.y + (endPoint.y - startPoint.y) * blend,
26587
+ };
26588
+ }
25853
26589
  /**
25854
26590
  * Samples the cubic tentacle centerline and offsets normals to build a filled ribbon.
25855
26591
  *
@@ -25879,6 +26615,26 @@
25879
26615
  };
25880
26616
  });
25881
26617
  }
26618
+ /**
26619
+ * Resolves smooth pupil offsets that blend autonomous idle drift with live viewer tracking.
26620
+ *
26621
+ * @param options Eye motion options.
26622
+ * @returns Resolved pupil offsets.
26623
+ *
26624
+ * @private shared geometry helper of octopus avatar visuals
26625
+ */
26626
+ function resolveOrganicEyeMotion(options) {
26627
+ const { radiusX, radiusY, timeMs, phase, interaction, autonomousDriftRatioX = 0.12, autonomousDriftRatioY = 0.08, } = options;
26628
+ const autonomousOffsetX = Math.sin(timeMs / 1280 + phase) * radiusX * autonomousDriftRatioX;
26629
+ const autonomousOffsetY = Math.cos(timeMs / 940 + phase) * radiusY * autonomousDriftRatioY;
26630
+ const interactionBlend = Math.min(1, interaction.intensity * 0.9);
26631
+ return {
26632
+ pupilOffsetX: autonomousOffsetX * (1 - interactionBlend) +
26633
+ interaction.gazeX * radiusX * (0.18 + interactionBlend * 0.18),
26634
+ pupilOffsetY: autonomousOffsetY * (1 - interactionBlend) +
26635
+ interaction.gazeY * radiusY * (0.16 + interactionBlend * 0.16),
26636
+ };
26637
+ }
25882
26638
  /**
25883
26639
  * Samples one point on a cubic Bezier curve.
25884
26640
  *
@@ -25932,13 +26688,14 @@
25932
26688
  const asciiOctopusAvatarVisual = {
25933
26689
  id: 'ascii-octopus',
25934
26690
  title: 'AsciiOctopus',
25935
- description: 'Morphing alien octopus translated into animated ASCII glyphs with deterministic blob and tentacle geometry.',
26691
+ description: 'Morphing alien octopus translated into animated ASCII glyphs with responsive eyes and seeded geometry.',
25936
26692
  isAnimated: true,
25937
- render({ context, size, palette, createRandom, timeMs }) {
26693
+ supportsPointerTracking: true,
26694
+ render({ context, size, palette, createRandom, timeMs, interaction }) {
25938
26695
  const gridRandom = createRandom('ascii-octopus-grid');
25939
26696
  const staticRandom = createRandom('ascii-octopus-static');
25940
26697
  const gridMetrics = createAsciiGridMetrics(size, gridRandom);
25941
- const layout = createAsciiOctopusLayout(size, timeMs, createRandom, staticRandom);
26698
+ const layout = createAsciiOctopusLayout(size, timeMs, createRandom, staticRandom, interaction);
25942
26699
  drawAvatarFrame(context, size, palette);
25943
26700
  drawAsciiBackdrop(context, size, palette, layout, timeMs);
25944
26701
  context.save();
@@ -26012,7 +26769,8 @@
26012
26769
  */
26013
26770
  function resolveAsciiGlyph(options) {
26014
26771
  const { point, layout, palette, cellWidth, cellHeight, noise, timeMs } = options;
26015
- const eyeGlyphDescriptor = resolveEyeGlyph(point, layout.leftEye, palette, timeMs) || resolveEyeGlyph(point, layout.rightEye, palette, timeMs);
26772
+ const eyeGlyphDescriptor = resolveEyeGlyph(point, layout.leftEye, layout.interaction, palette, timeMs) ||
26773
+ resolveEyeGlyph(point, layout.rightEye, layout.interaction, palette, timeMs);
26016
26774
  if (eyeGlyphDescriptor) {
26017
26775
  return eyeGlyphDescriptor;
26018
26776
  }
@@ -26057,9 +26815,14 @@
26057
26815
  *
26058
26816
  * @private helper of `asciiOctopusAvatarVisual`
26059
26817
  */
26060
- function resolveEyeGlyph(point, eyeFeature, palette, timeMs) {
26061
- const pupilOffsetX = Math.sin(timeMs / 1280 + eyeFeature.phase) * eyeFeature.radiusX * 0.12;
26062
- const pupilOffsetY = Math.cos(timeMs / 940 + eyeFeature.phase) * eyeFeature.radiusY * 0.08;
26818
+ function resolveEyeGlyph(point, eyeFeature, interaction, palette, timeMs) {
26819
+ const { pupilOffsetX, pupilOffsetY } = resolveOrganicEyeMotion({
26820
+ radiusX: eyeFeature.radiusX,
26821
+ radiusY: eyeFeature.radiusY,
26822
+ timeMs,
26823
+ phase: eyeFeature.phase,
26824
+ interaction,
26825
+ });
26063
26826
  const scleraDistance = measureRotatedEllipseDistance(point, eyeFeature.centerX, eyeFeature.centerY, eyeFeature.radiusX, eyeFeature.radiusY, eyeFeature.rotation);
26064
26827
  if (scleraDistance > 1.08) {
26065
26828
  return null;
@@ -26233,9 +26996,9 @@
26233
26996
  *
26234
26997
  * @private helper of `asciiOctopusAvatarVisual`
26235
26998
  */
26236
- function createAsciiOctopusLayout(size, timeMs, createRandom, staticRandom) {
26237
- const centerX = size * (0.5 + (staticRandom() - 0.5) * 0.02);
26238
- const centerY = size * (0.41 + staticRandom() * 0.05);
26999
+ function createAsciiOctopusLayout(size, timeMs, createRandom, staticRandom, interaction) {
27000
+ const centerX = size * (0.5 + (staticRandom() - 0.5) * 0.02) + interaction.bodyOffsetX * size * 0.05;
27001
+ const centerY = size * (0.41 + staticRandom() * 0.05) + interaction.bodyOffsetY * size * 0.035;
26239
27002
  const bodyRadius = size * (0.195 + staticRandom() * 0.05);
26240
27003
  const horizontalStretch = 1.08 + staticRandom() * 0.22;
26241
27004
  const verticalStretch = 0.88 + staticRandom() * 0.14;
@@ -26275,6 +27038,7 @@
26275
27038
  createRandom,
26276
27039
  timeMs,
26277
27040
  saltPrefix: 'ascii-octopus',
27041
+ bodyPoints,
26278
27042
  });
26279
27043
  const sampledTentacles = tentacleShapes.map(sampleOrganicTentacleRibbonPoints);
26280
27044
  const leftEye = {
@@ -26295,7 +27059,7 @@
26295
27059
  };
26296
27060
  const mouthPoints = sampleQuadraticBezierPoints({ x: centerX - size * 0.074, y: centerY + size * 0.092 }, {
26297
27061
  x: centerX,
26298
- y: centerY + size * (0.142 + Math.sin(timeMs / 620 + shapePhase) * 0.016),
27062
+ y: centerY + size * (0.142 + Math.sin(timeMs / 620 + shapePhase) * 0.016) + interaction.gazeY * size * 0.012,
26299
27063
  }, { x: centerX + size * 0.074, y: centerY + size * 0.092 }, 12);
26300
27064
  let leftBound = Number.POSITIVE_INFINITY;
26301
27065
  let rightBound = Number.NEGATIVE_INFINITY;
@@ -26321,6 +27085,7 @@
26321
27085
  bodyRadius,
26322
27086
  horizontalStretch,
26323
27087
  shapePhase,
27088
+ interaction,
26324
27089
  bodyPoints,
26325
27090
  sampledTentacles,
26326
27091
  leftEye,
@@ -27041,15 +27806,16 @@
27041
27806
  const octopusAvatarVisual = {
27042
27807
  id: 'octopus',
27043
27808
  title: 'Octopus',
27044
- description: 'Playful underwater mascot with animated tentacles, bubbles, and seed-based markings.',
27809
+ description: 'Playful underwater mascot with cursor-following eyes, animated tentacles, bubbles, and seeded markings.',
27045
27810
  isAnimated: true,
27046
- render({ context, size, palette, createRandom, timeMs }) {
27811
+ supportsPointerTracking: true,
27812
+ render({ context, size, palette, createRandom, timeMs, interaction }) {
27047
27813
  const staticRandom = createRandom('octopus-static');
27048
27814
  const bubbleRandom = createRandom('octopus-bubbles');
27049
27815
  const bubbleCount = 8;
27050
27816
  const bubbleRadiusBase = size * 0.02;
27051
- const centerX = size * 0.5;
27052
- const centerY = size * 0.42;
27817
+ const centerX = size * 0.5 + interaction.bodyOffsetX * size * 0.035;
27818
+ const centerY = size * 0.42 + interaction.bodyOffsetY * size * 0.024;
27053
27819
  const headRadius = size * (0.19 + staticRandom() * 0.03);
27054
27820
  const mantleHeight = headRadius * 1.18;
27055
27821
  const tentacleLength = size * (0.18 + staticRandom() * 0.06);
@@ -27129,11 +27895,9 @@
27129
27895
  }
27130
27896
  const eyeOffsetX = headRadius * 0.42;
27131
27897
  const eyeY = centerY + headRadius * 0.04;
27132
- const pupilDriftX = Math.sin(timeMs / 850) * headRadius * 0.05;
27133
- const pupilDriftY = Math.cos(timeMs / 930) * headRadius * 0.03;
27134
27898
  const eyeRadius = headRadius * 0.22;
27135
- drawEye(context, centerX - eyeOffsetX, eyeY, eyeRadius, palette, pupilDriftX, pupilDriftY);
27136
- drawEye(context, centerX + eyeOffsetX, eyeY, eyeRadius, palette, pupilDriftX, pupilDriftY);
27899
+ drawEye(context, centerX - eyeOffsetX, eyeY, eyeRadius, palette, timeMs, interaction, 0);
27900
+ drawEye(context, centerX + eyeOffsetX, eyeY, eyeRadius, palette, timeMs, interaction, Math.PI / 5);
27137
27901
  context.beginPath();
27138
27902
  context.arc(centerX - headRadius * 0.28, centerY + headRadius * 0.3, headRadius * 0.12, 0, Math.PI * 2);
27139
27903
  context.arc(centerX + headRadius * 0.28, centerY + headRadius * 0.3, headRadius * 0.12, 0, Math.PI * 2);
@@ -27156,22 +27920,32 @@
27156
27920
  * @param centerY Eye center Y coordinate.
27157
27921
  * @param radius Eye radius.
27158
27922
  * @param palette Derived avatar palette.
27159
- * @param pupilDriftX Horizontal pupil drift.
27160
- * @param pupilDriftY Vertical pupil drift.
27923
+ * @param timeMs Current animation time in milliseconds.
27924
+ * @param interaction Smoothed avatar interaction state.
27925
+ * @param phase Seed-based phase offset.
27161
27926
  *
27162
27927
  * @private helper of `octopusAvatarVisual`
27163
27928
  */
27164
- function drawEye(context, centerX, centerY, radius, palette, pupilDriftX, pupilDriftY) {
27929
+ function drawEye(context, centerX, centerY, radius, palette, timeMs, interaction, phase) {
27930
+ const { pupilOffsetX, pupilOffsetY } = resolveOrganicEyeMotion({
27931
+ radiusX: radius,
27932
+ radiusY: radius,
27933
+ timeMs,
27934
+ phase,
27935
+ interaction,
27936
+ autonomousDriftRatioX: 0.05,
27937
+ autonomousDriftRatioY: 0.03,
27938
+ });
27165
27939
  context.beginPath();
27166
27940
  context.arc(centerX, centerY, radius, 0, Math.PI * 2);
27167
27941
  context.fillStyle = '#ffffff';
27168
27942
  context.fill();
27169
27943
  context.beginPath();
27170
- context.arc(centerX + pupilDriftX, centerY + pupilDriftY, radius * 0.45, 0, Math.PI * 2);
27944
+ context.arc(centerX + pupilOffsetX, centerY + pupilOffsetY, radius * 0.45, 0, Math.PI * 2);
27171
27945
  context.fillStyle = palette.ink;
27172
27946
  context.fill();
27173
27947
  context.beginPath();
27174
- context.arc(centerX + pupilDriftX - radius * 0.12, centerY + pupilDriftY - radius * 0.12, radius * 0.15, 0, Math.PI * 2);
27948
+ context.arc(centerX + pupilOffsetX - radius * 0.12, centerY + pupilOffsetY - radius * 0.12, radius * 0.15, 0, Math.PI * 2);
27175
27949
  context.fillStyle = '#ffffff';
27176
27950
  context.fill();
27177
27951
  context.beginPath();
@@ -27190,12 +27964,13 @@
27190
27964
  const octopus2AvatarVisual = {
27191
27965
  id: 'octopus2',
27192
27966
  title: 'Octopus2',
27193
- description: 'Organic alien octopus rendered as one continuously morphing blob with luminous eyes and soft inner motion.',
27967
+ description: 'Organic alien octopus rendered as one continuously morphing blob with responsive luminous eyes.',
27194
27968
  isAnimated: true,
27195
- render({ context, size, palette, createRandom, timeMs }) {
27969
+ supportsPointerTracking: true,
27970
+ render({ context, size, palette, createRandom, timeMs, interaction }) {
27196
27971
  const staticRandom = createRandom('octopus2-static');
27197
- const centerX = size * 0.5;
27198
- const centerY = size * (0.48 + staticRandom() * 0.03);
27972
+ const centerX = size * 0.5 + interaction.bodyOffsetX * size * 0.042;
27973
+ const centerY = size * (0.48 + staticRandom() * 0.03) + interaction.bodyOffsetY * size * 0.028;
27199
27974
  const bodyRadius = size * (0.25 + staticRandom() * 0.035);
27200
27975
  const horizontalStretch = 1.04 + staticRandom() * 0.16;
27201
27976
  const verticalStretch = 0.94 + staticRandom() * 0.12;
@@ -27266,11 +28041,11 @@
27266
28041
  const eyeCenterY = centerY - size * 0.02;
27267
28042
  const eyeRadiusX = size * 0.072;
27268
28043
  const eyeRadiusY = size * 0.086;
27269
- drawAlienEye(context, centerX - eyeOffsetX, eyeCenterY, eyeRadiusX, eyeRadiusY, palette, timeMs, shapePhase);
27270
- drawAlienEye(context, centerX + eyeOffsetX, eyeCenterY, eyeRadiusX, eyeRadiusY, palette, timeMs, shapePhase + Math.PI / 5);
28044
+ drawAlienEye(context, centerX - eyeOffsetX, eyeCenterY, eyeRadiusX, eyeRadiusY, palette, timeMs, shapePhase, interaction);
28045
+ drawAlienEye(context, centerX + eyeOffsetX, eyeCenterY, eyeRadiusX, eyeRadiusY, palette, timeMs, shapePhase + Math.PI / 5, interaction);
27271
28046
  context.beginPath();
27272
28047
  context.moveTo(centerX - size * 0.08, centerY + size * 0.12);
27273
- context.quadraticCurveTo(centerX, centerY + size * (0.175 + Math.sin(timeMs / 520 + shapePhase) * 0.012), centerX + size * 0.08, centerY + size * 0.12);
28048
+ context.quadraticCurveTo(centerX, centerY + size * (0.175 + Math.sin(timeMs / 520 + shapePhase) * 0.012) + interaction.gazeY * size * 0.01, centerX + size * 0.08, centerY + size * 0.12);
27274
28049
  context.strokeStyle = `${palette.ink}b3`;
27275
28050
  context.lineWidth = size * 0.013;
27276
28051
  context.lineCap = 'round';
@@ -27348,12 +28123,19 @@
27348
28123
  * @param palette Derived avatar palette.
27349
28124
  * @param timeMs Current animation time in milliseconds.
27350
28125
  * @param phase Seed-based animation phase.
28126
+ * @param interaction Smoothed avatar interaction state.
27351
28127
  *
27352
28128
  * @private helper of `octopus2AvatarVisual`
27353
28129
  */
27354
- function drawAlienEye(context, centerX, centerY, radiusX, radiusY, palette, timeMs, phase) {
27355
- const pupilOffsetX = Math.sin(timeMs / 1300 + phase) * radiusX * 0.12;
27356
- const pupilOffsetY = Math.cos(timeMs / 970 + phase) * radiusY * 0.1;
28130
+ function drawAlienEye(context, centerX, centerY, radiusX, radiusY, palette, timeMs, phase, interaction) {
28131
+ const { pupilOffsetX, pupilOffsetY } = resolveOrganicEyeMotion({
28132
+ radiusX,
28133
+ radiusY,
28134
+ timeMs,
28135
+ phase,
28136
+ interaction,
28137
+ autonomousDriftRatioY: 0.1,
28138
+ });
27357
28139
  context.save();
27358
28140
  context.beginPath();
27359
28141
  context.ellipse(centerX, centerY, radiusX, radiusY, 0, 0, Math.PI * 2);
@@ -27393,12 +28175,13 @@
27393
28175
  const octopus3AvatarVisual = {
27394
28176
  id: 'octopus3',
27395
28177
  title: 'Octopus3',
27396
- description: 'Gelatinous alien octopus with a morphing mantle, visible ribbon tentacles, and seeded facial features.',
28178
+ description: 'Gelatinous alien octopus with a morphing mantle, responsive eyes, and visible ribbon tentacles.',
27397
28179
  isAnimated: true,
27398
- render({ context, size, palette, createRandom, timeMs }) {
28180
+ supportsPointerTracking: true,
28181
+ render({ context, size, palette, createRandom, timeMs, interaction }) {
27399
28182
  const staticRandom = createRandom('octopus3-static');
27400
- const centerX = size * (0.5 + (staticRandom() - 0.5) * 0.02);
27401
- const centerY = size * (0.41 + staticRandom() * 0.05);
28183
+ const centerX = size * (0.5 + (staticRandom() - 0.5) * 0.02) + interaction.bodyOffsetX * size * 0.05;
28184
+ const centerY = size * (0.41 + staticRandom() * 0.05) + interaction.bodyOffsetY * size * 0.035;
27402
28185
  const bodyRadius = size * (0.2 + staticRandom() * 0.045);
27403
28186
  const horizontalStretch = 1.08 + staticRandom() * 0.22;
27404
28187
  const verticalStretch = 0.9 + staticRandom() * 0.12;
@@ -27438,6 +28221,7 @@
27438
28221
  createRandom,
27439
28222
  timeMs,
27440
28223
  saltPrefix: 'octopus3',
28224
+ bodyPoints,
27441
28225
  });
27442
28226
  drawAvatarFrame(context, size, palette);
27443
28227
  drawOctopus3Atmosphere(context, size, palette, centerX, centerY, timeMs, shapePhase);
@@ -27483,11 +28267,11 @@
27483
28267
  context.ellipse(centerX, centerY - size * 0.14, size * 0.18, size * 0.062, 0, Math.PI, Math.PI * 2);
27484
28268
  context.fillStyle = `${palette.highlight}3d`;
27485
28269
  context.fill();
27486
- drawSeededEye(context, centerX - eyeSpacing, centerY - size * 0.01, eyeRadiusX, eyeRadiusY, (staticRandom() - 0.5) * 0.28, palette, timeMs, shapePhase);
27487
- drawSeededEye(context, centerX + eyeSpacing, centerY - size * 0.01, eyeRadiusX, eyeRadiusY, (staticRandom() - 0.5) * 0.28, palette, timeMs, shapePhase + Math.PI / 4);
28270
+ drawSeededEye(context, centerX - eyeSpacing, centerY - size * 0.01, eyeRadiusX, eyeRadiusY, (staticRandom() - 0.5) * 0.28, palette, timeMs, shapePhase, interaction);
28271
+ drawSeededEye(context, centerX + eyeSpacing, centerY - size * 0.01, eyeRadiusX, eyeRadiusY, (staticRandom() - 0.5) * 0.28, palette, timeMs, shapePhase + Math.PI / 4, interaction);
27488
28272
  context.beginPath();
27489
28273
  context.moveTo(centerX - size * 0.07, centerY + size * 0.09);
27490
- context.quadraticCurveTo(centerX, centerY + size * (0.14 + Math.sin(timeMs / 620 + shapePhase) * 0.016), centerX + size * 0.07, centerY + size * 0.09);
28274
+ context.quadraticCurveTo(centerX, centerY + size * (0.14 + Math.sin(timeMs / 620 + shapePhase) * 0.016) + interaction.gazeY * size * 0.012, centerX + size * 0.07, centerY + size * 0.09);
27491
28275
  context.strokeStyle = `${palette.ink}b3`;
27492
28276
  context.lineWidth = size * 0.012;
27493
28277
  context.lineCap = 'round';
@@ -27675,12 +28459,18 @@
27675
28459
  * @param palette Derived avatar palette.
27676
28460
  * @param timeMs Current animation time in milliseconds.
27677
28461
  * @param phase Seed-based animation phase.
28462
+ * @param interaction Smoothed avatar interaction state.
27678
28463
  *
27679
28464
  * @private helper of `octopus3AvatarVisual`
27680
28465
  */
27681
- function drawSeededEye(context, centerX, centerY, radiusX, radiusY, rotation, palette, timeMs, phase) {
27682
- const pupilOffsetX = Math.sin(timeMs / 1280 + phase) * radiusX * 0.12;
27683
- const pupilOffsetY = Math.cos(timeMs / 940 + phase) * radiusY * 0.08;
28466
+ function drawSeededEye(context, centerX, centerY, radiusX, radiusY, rotation, palette, timeMs, phase, interaction) {
28467
+ const { pupilOffsetX, pupilOffsetY } = resolveOrganicEyeMotion({
28468
+ radiusX,
28469
+ radiusY,
28470
+ timeMs,
28471
+ phase,
28472
+ interaction,
28473
+ });
27684
28474
  context.save();
27685
28475
  context.translate(centerX, centerY);
27686
28476
  context.rotate(rotation);
@@ -27716,7 +28506,7 @@
27716
28506
  context.stroke();
27717
28507
  context.beginPath();
27718
28508
  context.moveTo(-radiusX * 0.88, -radiusY * 0.08);
27719
- context.quadraticCurveTo(0, -radiusY * 0.9, radiusX * 0.88, -radiusY * 0.08);
28509
+ context.quadraticCurveTo(0, -radiusY * (0.9 - interaction.gazeY * 0.16 + interaction.intensity * 0.08), radiusX * 0.88, -radiusY * 0.08);
27720
28510
  context.strokeStyle = `${palette.shadow}73`;
27721
28511
  context.lineWidth = radiusX * 0.16;
27722
28512
  context.lineCap = 'round';
@@ -27854,30 +28644,56 @@
27854
28644
  return avatarVisual;
27855
28645
  }
27856
28646
 
28647
+ /**
28648
+ * Resolves the stable avatar render inputs reused across multiple frames.
28649
+ *
28650
+ * @param options Avatar identity and visual selection.
28651
+ * @returns Stable render data ready to be used by `renderAvatarVisual`.
28652
+ *
28653
+ * @private shared helper for canvas avatar rendering
28654
+ */
28655
+ function resolveAvatarRenderDefinition(options) {
28656
+ const avatarDefinition = normalizeAvatarDefinition(options.avatarDefinition);
28657
+ const surface = options.surface || 'framed';
28658
+ return {
28659
+ avatarDefinition,
28660
+ avatarVisual: getAvatarVisualById(options.visualId),
28661
+ surface,
28662
+ palette: createAvatarPalette(avatarDefinition, surface),
28663
+ createRandom: createAvatarRandomFactory(avatarDefinition),
28664
+ };
28665
+ }
27857
28666
  /**
27858
28667
  * Renders one deterministic avatar frame into the provided canvas.
27859
28668
  *
27860
28669
  * @param options Rendering options.
28670
+ * @param resolvedAvatarRenderDefinition Optional stable render data reused between frames.
27861
28671
  *
27862
28672
  * @private shared helper for canvas avatar rendering
27863
28673
  */
27864
- function renderAvatarVisual(options) {
27865
- const normalizedAvatarDefinition = normalizeAvatarDefinition(options.avatarDefinition);
27866
- const avatarVisual = getAvatarVisualById(options.visualId);
28674
+ function renderAvatarVisual(options, resolvedAvatarRenderDefinition) {
28675
+ const resolvedRenderDefinition = resolvedAvatarRenderDefinition ||
28676
+ resolveAvatarRenderDefinition({
28677
+ avatarDefinition: options.avatarDefinition,
28678
+ visualId: options.visualId,
28679
+ surface: options.surface,
28680
+ });
27867
28681
  const context = options.canvas.getContext('2d');
27868
28682
  if (!context) {
27869
28683
  throw new Error('2D canvas rendering context is unavailable.');
27870
28684
  }
27871
28685
  prepareAvatarCanvas(options.canvas, context, options.size, options.devicePixelRatio || 1);
27872
- avatarVisual.render({
28686
+ resolvedRenderDefinition.avatarVisual.render({
27873
28687
  canvas: options.canvas,
27874
28688
  context,
27875
28689
  size: options.size,
27876
28690
  devicePixelRatio: options.devicePixelRatio || 1,
27877
28691
  timeMs: options.timeMs,
27878
- avatarDefinition: normalizedAvatarDefinition,
27879
- palette: createAvatarPalette(normalizedAvatarDefinition),
27880
- createRandom: createAvatarRandomFactory(normalizedAvatarDefinition),
28692
+ avatarDefinition: resolvedRenderDefinition.avatarDefinition,
28693
+ palette: resolvedRenderDefinition.palette,
28694
+ createRandom: resolvedRenderDefinition.createRandom,
28695
+ surface: resolvedRenderDefinition.surface,
28696
+ interaction: options.interaction || createIdleAvatarInteractionState(),
27881
28697
  });
27882
28698
  }
27883
28699
 
@@ -27887,48 +28703,136 @@
27887
28703
  * @private helper of `<Avatar/>`
27888
28704
  */
27889
28705
  const AVATAR_CANVAS_RADIUS_RATIO = 0.18;
28706
+ /**
28707
+ * Maximum time between layout-bound refreshes while pointer tracking is active.
28708
+ *
28709
+ * This keeps pointer-aware visuals aligned with chat/layout shifts without forcing a layout read every frame.
28710
+ *
28711
+ * @private helper of `<Avatar/>`
28712
+ */
28713
+ const ACTIVE_POINTER_BOUNDS_REFRESH_MS = 120;
27890
28714
  /**
27891
28715
  * Canvas-based deterministic avatar component.
27892
28716
  *
27893
28717
  * @private shared component for in-repository avatar previews
27894
28718
  */
27895
28719
  function Avatar(props) {
27896
- const { avatarDefinition, visualId, size = DEFAULT_AVATAR_SIZE, title, className, style } = props;
28720
+ const { avatarDefinition, visualId, surface = 'framed', size = DEFAULT_AVATAR_SIZE, title, className, style } = props;
27897
28721
  const canvasRef = react.useRef(null);
27898
- const normalizedAvatarDefinition = react.useMemo(() => normalizeAvatarDefinition(avatarDefinition), [avatarDefinition]);
27899
- const avatarVisual = react.useMemo(() => getAvatarVisualById(visualId), [visualId]);
28722
+ const animationStartRef = react.useRef(null);
28723
+ const interactionRuntimeStateRef = react.useRef(createAvatarInteractionRuntimeState());
28724
+ const avatarBoundsRef = react.useRef(null);
28725
+ const lastResolvedPointerVersionRef = react.useRef(-1);
28726
+ const lastResolvedViewportLayoutVersionRef = react.useRef(-1);
28727
+ const lastAvatarBoundsRefreshAtRef = react.useRef(0);
28728
+ const avatarColorsKey = avatarDefinition.colors.join('|');
28729
+ const resolvedAvatarRenderDefinition = react.useMemo(() => resolveAvatarRenderDefinition({
28730
+ avatarDefinition,
28731
+ visualId,
28732
+ surface,
28733
+ }), [avatarDefinition.agentHash, avatarDefinition.agentName, avatarColorsKey, surface, visualId]);
28734
+ const avatarDefinitionKey = react.useMemo(() => createAvatarDefinitionKey(resolvedAvatarRenderDefinition.avatarDefinition), [
28735
+ resolvedAvatarRenderDefinition.avatarDefinition.agentHash,
28736
+ resolvedAvatarRenderDefinition.avatarDefinition.agentName,
28737
+ resolvedAvatarRenderDefinition.avatarDefinition.colors.join('|'),
28738
+ ]);
28739
+ const [isVisible, setIsVisible] = react.useState(true);
27900
28740
  react.useEffect(() => {
27901
28741
  const canvas = canvasRef.current;
27902
28742
  if (!canvas) {
27903
28743
  throw new Error('Avatar canvas is not mounted.');
27904
28744
  }
27905
- let animationFrameId = null;
27906
- const animationStart = performance.now();
28745
+ return observeAvatarVisibility(canvas, setIsVisible);
28746
+ }, []);
28747
+ react.useEffect(() => {
28748
+ interactionRuntimeStateRef.current = createAvatarInteractionRuntimeState();
28749
+ avatarBoundsRef.current = null;
28750
+ lastResolvedPointerVersionRef.current = -1;
28751
+ lastResolvedViewportLayoutVersionRef.current = -1;
28752
+ lastAvatarBoundsRefreshAtRef.current = 0;
28753
+ }, [avatarDefinitionKey, isVisible, visualId]);
28754
+ react.useEffect(() => {
28755
+ const canvas = canvasRef.current;
28756
+ if (!canvas || typeof ResizeObserver === 'undefined') {
28757
+ return;
28758
+ }
28759
+ const resizeObserver = new ResizeObserver(() => {
28760
+ avatarBoundsRef.current = null;
28761
+ });
28762
+ resizeObserver.observe(canvas);
28763
+ return () => {
28764
+ resizeObserver.disconnect();
28765
+ };
28766
+ }, []);
28767
+ react.useEffect(() => {
28768
+ const canvas = canvasRef.current;
28769
+ if (!canvas) {
28770
+ throw new Error('Avatar canvas is not mounted.');
28771
+ }
28772
+ const avatarVisual = resolvedAvatarRenderDefinition.avatarVisual;
28773
+ const isDynamicAvatar = avatarVisual.isAnimated || avatarVisual.supportsPointerTracking === true;
28774
+ const shouldTrackPointer = avatarVisual.supportsPointerTracking === true && isVisible;
28775
+ const releasePointerTracking = shouldTrackPointer ? retainAvatarPointerTracking() : null;
28776
+ if (animationStartRef.current === null) {
28777
+ animationStartRef.current = performance.now();
28778
+ }
27907
28779
  const renderFrame = (now) => {
28780
+ const pointerSnapshot = avatarVisual.supportsPointerTracking ? getAvatarPointerSnapshot() : null;
28781
+ let interactionState = createIdleAvatarInteractionState();
28782
+ if (avatarVisual.supportsPointerTracking && pointerSnapshot) {
28783
+ const pointerSnapshotVersion = getAvatarPointerSnapshotVersion();
28784
+ const viewportLayoutVersion = getAvatarViewportLayoutVersion();
28785
+ if (avatarBoundsRef.current === null ||
28786
+ lastResolvedPointerVersionRef.current !== pointerSnapshotVersion ||
28787
+ lastResolvedViewportLayoutVersionRef.current !== viewportLayoutVersion ||
28788
+ now - lastAvatarBoundsRefreshAtRef.current >= ACTIVE_POINTER_BOUNDS_REFRESH_MS) {
28789
+ avatarBoundsRef.current = canvas.getBoundingClientRect();
28790
+ lastResolvedPointerVersionRef.current = pointerSnapshotVersion;
28791
+ lastResolvedViewportLayoutVersionRef.current = viewportLayoutVersion;
28792
+ lastAvatarBoundsRefreshAtRef.current = now;
28793
+ }
28794
+ interactionRuntimeStateRef.current = stepAvatarInteractionRuntimeState(interactionRuntimeStateRef.current, resolveAvatarPointerTarget(avatarBoundsRef.current, pointerSnapshot), now);
28795
+ interactionState = interactionRuntimeStateRef.current;
28796
+ }
28797
+ else if (avatarVisual.supportsPointerTracking) {
28798
+ interactionRuntimeStateRef.current = stepAvatarInteractionRuntimeState(interactionRuntimeStateRef.current, createIdleAvatarInteractionState(), now);
28799
+ interactionState = interactionRuntimeStateRef.current;
28800
+ }
27908
28801
  renderAvatarVisual({
27909
28802
  canvas,
27910
- avatarDefinition: normalizedAvatarDefinition,
28803
+ avatarDefinition: resolvedAvatarRenderDefinition.avatarDefinition,
27911
28804
  visualId,
28805
+ surface,
27912
28806
  size,
27913
- timeMs: now - animationStart,
28807
+ timeMs: now - animationStartRef.current,
27914
28808
  devicePixelRatio: window.devicePixelRatio || 1,
27915
- });
27916
- if (avatarVisual.isAnimated) {
27917
- animationFrameId = window.requestAnimationFrame(renderFrame);
27918
- }
28809
+ interaction: interactionState,
28810
+ }, resolvedAvatarRenderDefinition);
27919
28811
  };
27920
- renderFrame(animationStart);
28812
+ renderFrame(performance.now());
28813
+ if (!isDynamicAvatar || !isVisible) {
28814
+ return () => {
28815
+ releasePointerTracking === null || releasePointerTracking === void 0 ? void 0 : releasePointerTracking();
28816
+ };
28817
+ }
28818
+ const releaseAnimationListener = retainAvatarAnimationListener(renderFrame);
27921
28819
  return () => {
27922
- if (animationFrameId !== null) {
27923
- window.cancelAnimationFrame(animationFrameId);
27924
- }
28820
+ releaseAnimationListener();
28821
+ releasePointerTracking === null || releasePointerTracking === void 0 ? void 0 : releasePointerTracking();
27925
28822
  };
27926
- }, [avatarVisual.isAnimated, normalizedAvatarDefinition, size, visualId]);
27927
- return (jsxRuntime.jsx("canvas", { ref: canvasRef, title: title || `${normalizedAvatarDefinition.agentName} avatar`, className: className, style: {
28823
+ }, [
28824
+ avatarDefinitionKey,
28825
+ isVisible,
28826
+ resolvedAvatarRenderDefinition,
28827
+ size,
28828
+ surface,
28829
+ visualId,
28830
+ ]);
28831
+ return (jsxRuntime.jsx("canvas", { ref: canvasRef, title: title || `${resolvedAvatarRenderDefinition.avatarDefinition.agentName} avatar`, className: className, style: {
27928
28832
  width: size,
27929
28833
  height: size,
27930
28834
  display: 'block',
27931
- borderRadius: size * AVATAR_CANVAS_RADIUS_RATIO,
28835
+ borderRadius: surface === 'transparent' ? 0 : size * AVATAR_CANVAS_RADIUS_RATIO,
27932
28836
  ...style,
27933
28837
  } }));
27934
28838
  }
@@ -27939,9 +28843,9 @@
27939
28843
  * @private shared component for avatar media rendering
27940
28844
  */
27941
28845
  function AvatarOrImage(props) {
27942
- const { imageUrl, avatarDefinition, visualId, size, alt, className, style } = props;
28846
+ const { imageUrl, avatarDefinition, visualId, surface, size, alt, className, style } = props;
27943
28847
  if (avatarDefinition && visualId) {
27944
- return (jsxRuntime.jsx(Avatar, { avatarDefinition: avatarDefinition, visualId: visualId, size: size, title: alt, className: className, style: style }));
28848
+ return (jsxRuntime.jsx(Avatar, { avatarDefinition: avatarDefinition, visualId: visualId, surface: surface, size: size, title: alt, className: className, style: style }));
27945
28849
  }
27946
28850
  if (!imageUrl) {
27947
28851
  return null;
@@ -38549,6 +39453,14 @@
38549
39453
  * Constant for default agent kit model name.
38550
39454
  */
38551
39455
  const DEFAULT_AGENT_KIT_MODEL_NAME = 'gpt-5.4-mini';
39456
+ /**
39457
+ * Default model used for nested DeepSearch tool invocations.
39458
+ */
39459
+ const DEFAULT_DEEP_SEARCH_MODEL_NAME = 'o4-mini-deep-research';
39460
+ /**
39461
+ * Tool name used by the Book commitment-backed DeepSearch capability.
39462
+ */
39463
+ const DEEP_SEARCH_TOOL_NAME = 'deep_search';
38552
39464
  /**
38553
39465
  * Creates one structured log entry for streamed tool-call updates.
38554
39466
  *
@@ -38591,6 +39503,98 @@
38591
39503
  }
38592
39504
  return 'COMPLETE';
38593
39505
  }
39506
+ /**
39507
+ * Returns true when one tool definition represents the dedicated DeepSearch capability.
39508
+ *
39509
+ * @param toolDefinition - Tool definition from compiled model requirements.
39510
+ * @returns `true` when the tool should be backed by a nested deep-research agent.
39511
+ *
39512
+ * @private helper of `OpenAiAgentKitExecutionTools`
39513
+ */
39514
+ function isDeepSearchToolDefinition(toolDefinition) {
39515
+ return toolDefinition.name === DEEP_SEARCH_TOOL_NAME;
39516
+ }
39517
+ /**
39518
+ * Normalizes Promptbook JSON-schema tool parameters for AgentKit function tools.
39519
+ *
39520
+ * @param parameters - Promptbook tool parameters.
39521
+ * @returns AgentKit-compatible JSON schema or `undefined`.
39522
+ *
39523
+ * @private helper of `OpenAiAgentKitExecutionTools`
39524
+ */
39525
+ function normalizeAgentKitToolParameters(parameters) {
39526
+ var _a, _b;
39527
+ if (!parameters) {
39528
+ return undefined;
39529
+ }
39530
+ return {
39531
+ ...parameters,
39532
+ additionalProperties: (_a = parameters.additionalProperties) !== null && _a !== void 0 ? _a : false,
39533
+ required: (_b = parameters.required) !== null && _b !== void 0 ? _b : [],
39534
+ };
39535
+ }
39536
+ /**
39537
+ * Creates instructions for the nested DeepSearch specialist agent.
39538
+ *
39539
+ * @param toolDescription - Model-facing description from the original tool definition.
39540
+ * @returns System instructions for the nested deep-research agent.
39541
+ *
39542
+ * @private helper of `OpenAiAgentKitExecutionTools`
39543
+ */
39544
+ function createDeepSearchAgentInstructions(toolDescription) {
39545
+ const normalizedDescription = toolDescription.trim();
39546
+ return spacetrim.spaceTrim((block) => `
39547
+ You are a DeepSearch specialist working as a tool for another agent.
39548
+ Perform thorough, source-grounded public-web research based on the provided request.
39549
+ Use web search to gather current information, compare relevant viewpoints, and synthesize a concise research brief.
39550
+ Do not ask follow-up questions. If the request is not specific enough, state the assumptions you had to make.
39551
+ Include citations in the research brief whenever sources were used.
39552
+ ${block(normalizedDescription ? `Tool guidance:\n${normalizedDescription}` : '')}
39553
+ `);
39554
+ }
39555
+ /**
39556
+ * Builds the nested DeepSearch prompt from structured tool arguments.
39557
+ *
39558
+ * @param rawInput - Parsed function-tool arguments provided by the outer agent.
39559
+ * @returns Prompt text passed to the nested deep-research agent.
39560
+ *
39561
+ * @private helper of `OpenAiAgentKitExecutionTools`
39562
+ */
39563
+ function buildDeepSearchToolInput(rawInput) {
39564
+ const input = rawInput && typeof rawInput === 'object' ? rawInput : {};
39565
+ const query = typeof input.query === 'string' ? input.query.trim() : '';
39566
+ const additionalHints = Object.entries(input)
39567
+ .filter(([key, value]) => key !== 'query' && value !== undefined && value !== null && String(value).trim() !== '')
39568
+ .map(([key, value]) => `- ${key}: ${typeof value === 'string' ? value : JSON.stringify(value)}`);
39569
+ return spacetrim.spaceTrim((block) => `
39570
+ Research request:
39571
+ ${query || JSON.stringify(input)}
39572
+ ${block(additionalHints.length > 0 ? `Execution hints:\n${additionalHints.join('\n')}` : '')}
39573
+ `);
39574
+ }
39575
+ /**
39576
+ * Creates the native Agent SDK tool used for `USE DEEPSEARCH`.
39577
+ *
39578
+ * @param toolDefinition - Promptbook tool definition for `deep_search`.
39579
+ * @returns AgentKit tool backed by a nested deep-research agent.
39580
+ *
39581
+ * @private helper of `OpenAiAgentKitExecutionTools`
39582
+ */
39583
+ function createDeepSearchAgentKitTool(toolDefinition) {
39584
+ const deepSearchAgent = new agents.Agent({
39585
+ name: 'DeepSearch',
39586
+ model: DEFAULT_DEEP_SEARCH_MODEL_NAME,
39587
+ instructions: createDeepSearchAgentInstructions(toolDefinition.description),
39588
+ tools: [agents.webSearchTool({ searchContextSize: 'high' })],
39589
+ });
39590
+ return deepSearchAgent.asTool({
39591
+ toolName: toolDefinition.name,
39592
+ toolDescription: toolDefinition.description,
39593
+ parameters: normalizeAgentKitToolParameters(toolDefinition.parameters),
39594
+ inputBuilder: ({ params }) => buildDeepSearchToolInput(params),
39595
+ customOutputExtractor: (result) => { var _a; return typeof result.finalOutput === 'string' ? result.finalOutput : JSON.stringify((_a = result.finalOutput) !== null && _a !== void 0 ? _a : ''); },
39596
+ });
39597
+ }
38594
39598
  /**
38595
39599
  * Constant for default JSON schema name.
38596
39600
  */
@@ -38931,25 +39935,23 @@
38931
39935
  * Builds the tool list for AgentKit, including hosted file search when applicable.
38932
39936
  */
38933
39937
  buildAgentKitTools(options) {
38934
- var _a;
38935
39938
  const { tools, vectorStoreId } = options;
38936
39939
  const agentKitTools = [];
38937
39940
  if (vectorStoreId) {
38938
39941
  agentKitTools.push(agents.fileSearchTool(vectorStoreId));
38939
39942
  }
38940
39943
  if (tools && tools.length > 0) {
38941
- const scriptTools = this.resolveScriptTools();
39944
+ let scriptTools = null;
38942
39945
  for (const toolDefinition of tools) {
39946
+ if (isDeepSearchToolDefinition(toolDefinition)) {
39947
+ agentKitTools.push(createDeepSearchAgentKitTool(toolDefinition));
39948
+ continue;
39949
+ }
39950
+ scriptTools !== null && scriptTools !== void 0 ? scriptTools : (scriptTools = this.resolveScriptTools());
38943
39951
  agentKitTools.push(agents.tool({
38944
39952
  name: toolDefinition.name,
38945
39953
  description: toolDefinition.description,
38946
- parameters: toolDefinition.parameters
38947
- ? {
38948
- ...toolDefinition.parameters,
38949
- additionalProperties: false,
38950
- required: (_a = toolDefinition.parameters.required) !== null && _a !== void 0 ? _a : [],
38951
- }
38952
- : undefined,
39954
+ parameters: normalizeAgentKitToolParameters(toolDefinition.parameters),
38953
39955
  strict: false,
38954
39956
  execute: async (input, runContext, details) => {
38955
39957
  var _a, _b, _c, _d;
@@ -45136,6 +46138,7 @@
45136
46138
  delete_wallet_record: { title: 'Deleting wallet', emoji: '👛' },
45137
46139
  request_wallet_record: { title: 'Requesting wallet', emoji: '👛' },
45138
46140
  web_search: { title: 'Searching the web', emoji: '🔎' },
46141
+ deep_search: { title: 'Deep research', emoji: '🔬' },
45139
46142
  useSearchEngine: { title: 'Searching the web', emoji: '🔎' },
45140
46143
  search: { title: 'Searching the web', emoji: '🔎' },
45141
46144
  useBrowser: { title: 'Browsing the web', emoji: '🌐' },
@@ -48097,7 +49100,7 @@
48097
49100
  * @private function of ChatToolCallModal
48098
49101
  */
48099
49102
  function isSearchToolCallName(toolName) {
48100
- return toolName === 'web_search' || toolName === 'useSearchEngine' || toolName === 'search';
49103
+ return toolName === 'web_search' || toolName === 'deep_search' || toolName === 'useSearchEngine' || toolName === 'search';
48101
49104
  }
48102
49105
  /**
48103
49106
  * Checks whether a tool name should use the time renderer.
@@ -48833,7 +49836,12 @@
48833
49836
  avatarSrc: resolvedTeammateAvatar || undefined,
48834
49837
  },
48835
49838
  ];
48836
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: classNames(styles$5.searchModalHeader, styles$5.teamModalHeader), children: jsxRuntime.jsxs("div", { className: styles$5.teamHeaderParticipants, children: [jsxRuntime.jsx(TeamHeaderProfile, { label: resolvedAgentLabel, avatarSrc: resolvedAgentAvatar, avatarDefinition: resolvedAgentAvatarDefinition, avatarVisualId: resolvedAgentAvatarVisualId, fallbackColor: resolvedAgentHeaderColor }), jsxRuntime.jsx("span", { className: styles$5.teamHeaderDivider, children: "talking with" }), jsxRuntime.jsx(TeamHeaderProfile, { label: resolvedTeammateLabel, avatarSrc: resolvedTeammateAvatar, fallbackColor: "#0ea5e9", href: teammateLink })] }) }), jsxRuntime.jsxs("div", { className: styles$5.searchModalContent, children: [messages.length > 0 ? (jsxRuntime.jsx("div", { className: styles$5.teamChatContainer, children: jsxRuntime.jsx(MockedChat, { title: `Chat between ${resolvedAgentLabel} and ${resolvedTeammateLabel}`, messages: messages, participants: participants, isResettable: false, isPausable: false, isSaveButtonEnabled: false, isCopyButtonEnabled: false, visual: "STANDALONE", delayConfig: FAST_FLOW }) })) : (jsxRuntime.jsx("div", { className: styles$5.noResults, children: "No teammate conversation available." })), (hasTeamToolCalls || hasTeamCitations) && (jsxRuntime.jsxs("div", { className: styles$5.teamToolCallSection, children: [hasTeamToolCalls && (jsxRuntime.jsxs("div", { className: styles$5.teamToolCallGroup, children: [jsxRuntime.jsx("div", { className: styles$5.teamToolCallHeading, children: "Actions" }), jsxRuntime.jsx("div", { className: styles$5.teamToolCallChips, children: teamToolCalls.map((toolCallEntry, index) => {
49839
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: classNames(styles$5.searchModalHeader, styles$5.teamModalHeader), children: jsxRuntime.jsxs("div", { className: styles$5.teamHeaderParticipants, children: [jsxRuntime.jsx(TeamHeaderProfile, { label: resolvedAgentLabel, avatarSrc: resolvedAgentAvatar, avatarDefinition: resolvedAgentAvatarDefinition, avatarVisualId: resolvedAgentAvatarVisualId, fallbackColor: resolvedAgentHeaderColor }), jsxRuntime.jsx("span", { className: styles$5.teamHeaderDivider, children: "talking with" }), jsxRuntime.jsx(TeamHeaderProfile, { label: resolvedTeammateLabel, avatarSrc: resolvedTeammateAvatar, fallbackColor: "#0ea5e9", href: teammateLink })] }) }), jsxRuntime.jsxs("div", { className: styles$5.searchModalContent, children: [messages.length > 0 ? (jsxRuntime.jsx("div", { className: styles$5.teamChatContainer, children: jsxRuntime.jsx(MockedChat, { title: `Chat between ${resolvedAgentLabel} and ${resolvedTeammateLabel}`, messages: messages, participants: participants, isResettable: false, isPausable: false, isSaveButtonEnabled: false, isCopyButtonEnabled: false, layout: "STANDALONE", delayConfig: {
49840
+ // Note+TODO: For some strange reason, <MockedChat/> is not running and stays static on the initial frame, so doing this hack to force it to show the entire chat at once. Need to investigate why the animation is not running as expected and then just use `delayConfig={FAST_FLOW}`
49841
+ ...FAST_FLOW,
49842
+ beforeFirstMessage: 0,
49843
+ showIntermediateMessages: messages.length,
49844
+ }, visualMode: "BUBBLE_MODE" }) })) : (jsxRuntime.jsx("div", { className: styles$5.noResults, children: "No teammate conversation available." })), (hasTeamToolCalls || hasTeamCitations) && (jsxRuntime.jsxs("div", { className: styles$5.teamToolCallSection, children: [hasTeamToolCalls && (jsxRuntime.jsxs("div", { className: styles$5.teamToolCallGroup, children: [jsxRuntime.jsx("div", { className: styles$5.teamToolCallHeading, children: "Actions" }), jsxRuntime.jsx("div", { className: styles$5.teamToolCallChips, children: teamToolCalls.map((toolCallEntry, index) => {
48837
49845
  const chipletInfo = getToolCallChipletInfo(toolCallEntry.toolCall, undefined, toolTitles);
48838
49846
  const chipletText = buildToolCallChipText(chipletInfo);
48839
49847
  return (jsxRuntime.jsxs("button", { className: styles$5.completedToolCall, onClick: () => {
@@ -49772,7 +50780,7 @@
49772
50780
  * @public exported from `@promptbook/components`
49773
50781
  */
49774
50782
  function Chat(props) {
49775
- const { title = 'Chat', messages, onChange, onMessage, onActionButton, onQuickMessageButton, onReplyToMessage, onCancelReply, onReset, resetRequiresConfirmation = true, newChatButtonHref, onFeedback, feedbackMode = 'stars', feedbackTranslations, timingTranslations, onFileUpload, chatLocale, speechRecognition, placeholderMessageContent, defaultMessage, enterBehavior, resolveEnterBehavior, children, className, style, isAiTextHumanizedAndPromptbookified = true, isVoiceCalling = false, isFocusedOnLoad, participants = [], canReplyToMessage, replyingToMessage, extraActions, actionsContainer, saveFormats, isSaveButtonEnabled = true, isCopyButtonEnabled = true, buttonColor: buttonColorRaw, onUseTemplate, onCreateAgent, toolTitles, teammates, teamAgentProfiles, visual, visualMode = 'ARTICLE_MODE', effectConfigs, soundSystem, speechRecognitionLanguage, isSpeechPlaybackEnabled = true, elevenLabsVoiceId, chatUiTranslations, } = props;
50783
+ const { title = 'Chat', messages, onChange, onMessage, onActionButton, onQuickMessageButton, onReplyToMessage, onCancelReply, onReset, resetRequiresConfirmation = true, newChatButtonHref, onFeedback, feedbackMode = 'stars', feedbackTranslations, timingTranslations, onFileUpload, chatLocale, speechRecognition, placeholderMessageContent, defaultMessage, enterBehavior, resolveEnterBehavior, children, className, style, isAiTextHumanizedAndPromptbookified = true, isVoiceCalling = false, isFocusedOnLoad, participants = [], canReplyToMessage, replyingToMessage, extraActions, actionsContainer, saveFormats, isSaveButtonEnabled = true, isCopyButtonEnabled = true, buttonColor: buttonColorRaw, onUseTemplate, onCreateAgent, toolTitles, teammates, teamAgentProfiles, layout, visualMode = 'ARTICLE_MODE', effectConfigs, soundSystem, speechRecognitionLanguage, isSpeechPlaybackEnabled = true, elevenLabsVoiceId, chatUiTranslations, } = props;
49776
50784
  const buttonColor = react.useMemo(() => Color.from(buttonColorRaw || '#0066cc'), [buttonColorRaw]);
49777
50785
  const agentParticipant = react.useMemo(() => participants.find((participant) => participant.name === 'AGENT'), [participants]);
49778
50786
  const postprocessedMessages = useChatPostprocessedMessages({
@@ -49813,11 +50821,11 @@
49813
50821
  extraActions,
49814
50822
  isSaveButtonEnabled,
49815
50823
  });
49816
- const isConstrainedArticleMode = visualMode === 'ARTICLE_MODE' && visual === 'FULL_PAGE';
50824
+ const isConstrainedArticleMode = visualMode === 'ARTICLE_MODE' && layout === 'FULL_PAGE';
49817
50825
  useChatCompleteNotification(messages, soundSystem);
49818
50826
  return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [feedbackStatus && (jsxRuntime.jsx("div", { className: classNames(styles$5.feedbackStatus, feedbackStatus.variant === 'success'
49819
50827
  ? styles$5.feedbackStatusSuccess
49820
- : styles$5.feedbackStatusError), "aria-live": "polite", role: "status", children: feedbackStatus.message })), effectConfigs && effectConfigs.length > 0 && (jsxRuntime.jsx(ChatEffectsSystem, { messages: postprocessedMessages, effectConfigs: effectConfigs, soundSystem: soundSystem })), jsxRuntime.jsx("div", { className: classNames(className, styles$5.Chat, visual === 'STANDALONE' && styles$5.standaloneVisual, visual === 'FULL_PAGE' && styles$5.fullPageVisual, isConstrainedArticleMode && styles$5.constrainedArticleVisual, getChatCssClassName('Chat'), chatCssClassNames.chat), style, children: jsxRuntime.jsxs("div", { className: classNames(className, styles$5.chatMainFlow, getChatCssClassName('chatMainFlow'), chatCssClassNames.chatMainFlow), children: [children && jsxRuntime.jsx("div", { className: classNames(styles$5.chatChildren), children: children }), shouldShowScrollToBottom && (jsxRuntime.jsx("div", { className: styles$5.scrollToBottomContainer, children: jsxRuntime.jsxs("div", { className: styles$5.scrollToBottomWrapper, children: [jsxRuntime.jsx(SolidArrowButton, { "data-button-type": "custom", direction: "down", iconSize: 33, className: classNames(styles$5.scrollToBottom, scrollToBottomCssClassName), onClick: handleButtonClick(() => scrollToBottom()), "aria-label": ariaLabel, title: ariaLabel }), badgeLabel && (jsxRuntime.jsx("span", { className: styles$5.scrollToBottomBadge, "aria-live": "polite", role: "status", children: badgeLabel }))] }) })), isVoiceCalling && (jsxRuntime.jsx("div", { className: styles$5.voiceCallIndicatorBar, children: jsxRuntime.jsxs("div", { className: styles$5.voiceCallIndicator, children: [jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: jsxRuntime.jsx("path", { d: "M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z" }) }), jsxRuntime.jsx("span", { children: "Voice call active" }), jsxRuntime.jsx("div", { className: styles$5.voiceCallPulse })] }) })), jsxRuntime.jsx(ChatActionsBar, { actionsRef: actionsRef, actionsContainer: actionsContainer, messages: postprocessedMessages, participants: participants, title: title, onReset: onReset, resetRequiresConfirmation: resetRequiresConfirmation, newChatButtonHref: newChatButtonHref, onUseTemplate: onUseTemplate, extraActions: extraActions, saveFormats: saveFormats, isSaveButtonEnabled: isSaveButtonEnabled, shouldFadeActions: shouldFadeActions, shouldDisableActions: shouldDisableActions, chatUiTranslations: chatUiTranslations, onButtonClick: handleButtonClick }), jsxRuntime.jsx(ChatMessageList, { messages: postprocessedMessages, participants: participants, expandedMessageId: expandedMessageId, messageRatings: messageRatings, setExpandedMessageId: setExpandedMessageId, handleRating: handleRating, mode: mode, isCopyButtonEnabled: isCopyButtonEnabled, isFeedbackEnabled: isFeedbackEnabled, feedbackMode: feedbackMode, feedbackTranslations: feedbackTranslations, timingTranslations: timingTranslations, chatLocale: chatLocale, onCopy: handleCopy, onMessage: onMessage, onActionButton: onActionButton, onQuickMessageButton: onQuickMessageButton, onReplyToMessage: onReplyToMessage, canReplyToMessage: canReplyToMessage, onCreateAgent: onCreateAgent, toolTitles: toolTitles, teammates: teammates, teamAgentProfiles: teamAgentProfiles, visualMode: visualMode, soundSystem: soundSystem, onToolCallClick: openToolCall, onCitationClick: openCitation, setChatMessagesElement: setChatMessagesElement, onScroll: handleChatScroll, isSpeechPlaybackEnabled: isSpeechPlaybackEnabled, elevenLabsVoiceId: elevenLabsVoiceId, chatUiTranslations: chatUiTranslations, chatMessagesClassName: classNames(isConstrainedArticleMode && styles$5.articleModeChatMessages, getChatCssClassName('chatMessages'), chatCssClassNames.chatMessages), hasActions: hasActions }), onMessage && (jsxRuntime.jsx(ChatInputArea, { onMessage: onMessage, onChange: onChange, onFileUpload: onFileUpload, speechRecognition: speechRecognition, speechRecognitionLanguage: speechRecognitionLanguage, replyingToMessage: replyingToMessage, onCancelReply: onCancelReply, defaultMessage: defaultMessage, enterBehavior: enterBehavior, resolveEnterBehavior: resolveEnterBehavior, placeholderMessageContent: placeholderMessageContent || (chatUiTranslations === null || chatUiTranslations === void 0 ? void 0 : chatUiTranslations.inputPlaceholder), isFocusedOnLoad: isFocusedOnLoad, isMobile: isMobile, isVoiceCalling: isVoiceCalling, participants: participants, buttonColor: buttonColor, soundSystem: soundSystem, onButtonClick: handleButtonClick, chatUiTranslations: chatUiTranslations, chatInputClassName: classNames(isConstrainedArticleMode && styles$5.articleModeChatInput, getChatCssClassName('chatInput'), chatCssClassNames.chatInput) }))] }) }), jsxRuntime.jsx(ChatToolCallModal, { isOpen: toolCallModalOpen, toolCall: selectedToolCall, toolCallIdentity: selectedToolCallIdentity, onClose: closeToolCallModal, toolTitles: toolTitles, agentParticipant: agentParticipant, buttonColor: buttonColor, teamAgentProfiles: teamAgentProfiles, chatUiTranslations: chatUiTranslations, locale: chatLocale, availableTools: selectedMessageAvailableTools }), jsxRuntime.jsx(ChatCitationModal, { isOpen: citationModalOpen, citation: selectedCitation, participants: participants, soundSystem: soundSystem, onClose: closeCitationModal }), jsxRuntime.jsx(ChatRatingModal, { isOpen: ratingModalOpen, selectedMessage: selectedMessage, postprocessedMessages: postprocessedMessages, messages: messages, hoveredRating: hoveredRating, messageRatings: messageRatings, textRating: textRating, feedbackMode: feedbackMode, feedbackTranslations: feedbackTranslations, mode: mode, isMobile: isMobile, onClose: () => setRatingModalOpen(false), setHoveredRating: setHoveredRating, setMessageRatings: setMessageRatings, setSelectedMessage: setSelectedMessage, setTextRating: setTextRating, submitRating: submitRating })] }));
50828
+ : styles$5.feedbackStatusError), "aria-live": "polite", role: "status", children: feedbackStatus.message })), effectConfigs && effectConfigs.length > 0 && (jsxRuntime.jsx(ChatEffectsSystem, { messages: postprocessedMessages, effectConfigs: effectConfigs, soundSystem: soundSystem })), jsxRuntime.jsx("div", { className: classNames(className, styles$5.Chat, layout === 'STANDALONE' && styles$5.standaloneVisual, layout === 'FULL_PAGE' && styles$5.fullPageVisual, isConstrainedArticleMode && styles$5.constrainedArticleVisual, getChatCssClassName('Chat'), chatCssClassNames.chat), style, children: jsxRuntime.jsxs("div", { className: classNames(className, styles$5.chatMainFlow, getChatCssClassName('chatMainFlow'), chatCssClassNames.chatMainFlow), children: [children && jsxRuntime.jsx("div", { className: classNames(styles$5.chatChildren), children: children }), shouldShowScrollToBottom && (jsxRuntime.jsx("div", { className: styles$5.scrollToBottomContainer, children: jsxRuntime.jsxs("div", { className: styles$5.scrollToBottomWrapper, children: [jsxRuntime.jsx(SolidArrowButton, { "data-button-type": "custom", direction: "down", iconSize: 33, className: classNames(styles$5.scrollToBottom, scrollToBottomCssClassName), onClick: handleButtonClick(() => scrollToBottom()), "aria-label": ariaLabel, title: ariaLabel }), badgeLabel && (jsxRuntime.jsx("span", { className: styles$5.scrollToBottomBadge, "aria-live": "polite", role: "status", children: badgeLabel }))] }) })), isVoiceCalling && (jsxRuntime.jsx("div", { className: styles$5.voiceCallIndicatorBar, children: jsxRuntime.jsxs("div", { className: styles$5.voiceCallIndicator, children: [jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: jsxRuntime.jsx("path", { d: "M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z" }) }), jsxRuntime.jsx("span", { children: "Voice call active" }), jsxRuntime.jsx("div", { className: styles$5.voiceCallPulse })] }) })), jsxRuntime.jsx(ChatActionsBar, { actionsRef: actionsRef, actionsContainer: actionsContainer, messages: postprocessedMessages, participants: participants, title: title, onReset: onReset, resetRequiresConfirmation: resetRequiresConfirmation, newChatButtonHref: newChatButtonHref, onUseTemplate: onUseTemplate, extraActions: extraActions, saveFormats: saveFormats, isSaveButtonEnabled: isSaveButtonEnabled, shouldFadeActions: shouldFadeActions, shouldDisableActions: shouldDisableActions, chatUiTranslations: chatUiTranslations, onButtonClick: handleButtonClick }), jsxRuntime.jsx(ChatMessageList, { messages: postprocessedMessages, participants: participants, expandedMessageId: expandedMessageId, messageRatings: messageRatings, setExpandedMessageId: setExpandedMessageId, handleRating: handleRating, mode: mode, isCopyButtonEnabled: isCopyButtonEnabled, isFeedbackEnabled: isFeedbackEnabled, feedbackMode: feedbackMode, feedbackTranslations: feedbackTranslations, timingTranslations: timingTranslations, chatLocale: chatLocale, onCopy: handleCopy, onMessage: onMessage, onActionButton: onActionButton, onQuickMessageButton: onQuickMessageButton, onReplyToMessage: onReplyToMessage, canReplyToMessage: canReplyToMessage, onCreateAgent: onCreateAgent, toolTitles: toolTitles, teammates: teammates, teamAgentProfiles: teamAgentProfiles, visualMode: visualMode, soundSystem: soundSystem, onToolCallClick: openToolCall, onCitationClick: openCitation, setChatMessagesElement: setChatMessagesElement, onScroll: handleChatScroll, isSpeechPlaybackEnabled: isSpeechPlaybackEnabled, elevenLabsVoiceId: elevenLabsVoiceId, chatUiTranslations: chatUiTranslations, chatMessagesClassName: classNames(isConstrainedArticleMode && styles$5.articleModeChatMessages, getChatCssClassName('chatMessages'), chatCssClassNames.chatMessages), hasActions: hasActions }), onMessage && (jsxRuntime.jsx(ChatInputArea, { onMessage: onMessage, onChange: onChange, onFileUpload: onFileUpload, speechRecognition: speechRecognition, speechRecognitionLanguage: speechRecognitionLanguage, replyingToMessage: replyingToMessage, onCancelReply: onCancelReply, defaultMessage: defaultMessage, enterBehavior: enterBehavior, resolveEnterBehavior: resolveEnterBehavior, placeholderMessageContent: placeholderMessageContent || (chatUiTranslations === null || chatUiTranslations === void 0 ? void 0 : chatUiTranslations.inputPlaceholder), isFocusedOnLoad: isFocusedOnLoad, isMobile: isMobile, isVoiceCalling: isVoiceCalling, participants: participants, buttonColor: buttonColor, soundSystem: soundSystem, onButtonClick: handleButtonClick, chatUiTranslations: chatUiTranslations, chatInputClassName: classNames(isConstrainedArticleMode && styles$5.articleModeChatInput, getChatCssClassName('chatInput'), chatCssClassNames.chatInput) }))] }) }), jsxRuntime.jsx(ChatToolCallModal, { isOpen: toolCallModalOpen, toolCall: selectedToolCall, toolCallIdentity: selectedToolCallIdentity, onClose: closeToolCallModal, toolTitles: toolTitles, agentParticipant: agentParticipant, buttonColor: buttonColor, teamAgentProfiles: teamAgentProfiles, chatUiTranslations: chatUiTranslations, locale: chatLocale, availableTools: selectedMessageAvailableTools }), jsxRuntime.jsx(ChatCitationModal, { isOpen: citationModalOpen, citation: selectedCitation, participants: participants, soundSystem: soundSystem, onClose: closeCitationModal }), jsxRuntime.jsx(ChatRatingModal, { isOpen: ratingModalOpen, selectedMessage: selectedMessage, postprocessedMessages: postprocessedMessages, messages: messages, hoveredRating: hoveredRating, messageRatings: messageRatings, textRating: textRating, feedbackMode: feedbackMode, feedbackTranslations: feedbackTranslations, mode: mode, isMobile: isMobile, onClose: () => setRatingModalOpen(false), setHoveredRating: setHoveredRating, setMessageRatings: setMessageRatings, setSelectedMessage: setSelectedMessage, setTextRating: setTextRating, submitRating: submitRating })] }));
49821
50829
  }
49822
50830
 
49823
50831
  /**
@@ -51123,7 +52131,7 @@
51123
52131
  : styles.PromptbookAgentSeamlessIntegrationStatusPending) }), jsxRuntime.jsxs("div", { className: styles.PromptbookAgentSeamlessIntegrationText, children: [jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationLabel, children: "Chat" }), jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationHint, children: displayName })] }), jsxRuntime.jsx("span", { className: styles.PromptbookAgentSeamlessIntegrationScreenReaderOnly, children: connectionStatusText })] }), isOpen && (jsxRuntime.jsxs("div", { className: styles.PromptbookAgentSeamlessIntegrationWindow, id: windowId, children: [jsxRuntime.jsxs("div", { className: styles.PromptbookAgentSeamlessIntegrationHeader, style: { backgroundColor: color }, ref: setHeaderElement, children: [jsxRuntime.jsxs("div", { className: styles.PromptbookAgentSeamlessIntegrationTitleWrap, children: [jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationTitle, children: displayName }), jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationSubtitle, children: connectionStatusText })] }), isIframeUsed && (jsxRuntime.jsx("button", { className: styles.PromptbookAgentSeamlessIntegrationClose, onClick: () => setOpen(false), title: "Close", "aria-label": "Close chat", children: jsxRuntime.jsx(CloseIcon, {}) }))] }), jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationContent, children: isIframeUsed ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [!isIframeLoaded && (jsxRuntime.jsxs("div", { className: styles.PromptbookAgentSeamlessIntegrationLoading, children: [jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationLoadingShimmer }), jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationLoadingSpinner }), jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationLoadingTitle, children: "Preparing your chat" }), jsxRuntime.jsxs("div", { className: styles.PromptbookAgentSeamlessIntegrationLoadingText, children: ["Connecting to ", displayName, "..."] })] })), jsxRuntime.jsx("iframe", { src: agentUrl + '/chat?headless', className: styles.PromptbookAgentSeamlessIntegrationIframe, style: { opacity: isIframeLoaded ? 1 : 0 }, tabIndex: -1, onLoad: () => {
51124
52132
  setIsIframeLoaded(true);
51125
52133
  setIsChatConnected(true);
51126
- } })] })) : agent ? (jsxRuntime.jsx(AgentChat, { agent: agent, actionsContainer: headerElement, isFocusedOnLoad: isFocusedOnLoad, extraActions: jsxRuntime.jsx("button", { className: styles.PromptbookAgentSeamlessIntegrationClose, onClick: () => setOpen(false), title: "Close", "aria-label": "Close chat", children: jsxRuntime.jsx(CloseIcon, {}) }), visual: "STANDALONE" })) : error ? (jsxRuntime.jsxs("div", { className: styles.PromptbookAgentSeamlessIntegrationError, children: [jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationErrorTitle, children: "Failed to connect to the agent" }), jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationErrorMessage, children: error.message })] })) : (jsxRuntime.jsxs("div", { className: styles.PromptbookAgentSeamlessIntegrationLoading, children: [jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationLoadingShimmer }), jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationLoadingSpinner }), jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationLoadingTitle, children: "Preparing your chat" }), jsxRuntime.jsxs("div", { className: styles.PromptbookAgentSeamlessIntegrationLoadingText, children: ["Connecting to ", displayName, "..."] })] })) })] }))] }));
52134
+ } })] })) : agent ? (jsxRuntime.jsx(AgentChat, { agent: agent, actionsContainer: headerElement, isFocusedOnLoad: isFocusedOnLoad, extraActions: jsxRuntime.jsx("button", { className: styles.PromptbookAgentSeamlessIntegrationClose, onClick: () => setOpen(false), title: "Close", "aria-label": "Close chat", children: jsxRuntime.jsx(CloseIcon, {}) }), layout: "STANDALONE" })) : error ? (jsxRuntime.jsxs("div", { className: styles.PromptbookAgentSeamlessIntegrationError, children: [jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationErrorTitle, children: "Failed to connect to the agent" }), jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationErrorMessage, children: error.message })] })) : (jsxRuntime.jsxs("div", { className: styles.PromptbookAgentSeamlessIntegrationLoading, children: [jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationLoadingShimmer }), jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationLoadingSpinner }), jsxRuntime.jsx("div", { className: styles.PromptbookAgentSeamlessIntegrationLoadingTitle, children: "Preparing your chat" }), jsxRuntime.jsxs("div", { className: styles.PromptbookAgentSeamlessIntegrationLoadingText, children: ["Connecting to ", displayName, "..."] })] })) })] }))] }));
51127
52135
  }
51128
52136
 
51129
52137
  /**