@promptbook/components 0.112.0-47 → 0.112.0-48
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.
- package/esm/index.es.js +885 -143
- package/esm/index.es.js.map +1 -1
- package/esm/src/avatars/AvatarOrImage.d.ts +5 -1
- package/esm/src/avatars/avatarInteractionUtils.d.ts +81 -0
- package/esm/src/avatars/avatarInteractionUtils.test.d.ts +1 -0
- package/esm/src/avatars/avatarPointerTracking.d.ts +17 -0
- package/esm/src/avatars/avatarRenderingUtils.d.ts +3 -2
- package/esm/src/avatars/avatarRenderingUtils.test.d.ts +1 -0
- package/esm/src/avatars/index.d.ts +1 -1
- package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +35 -0
- package/esm/src/avatars/visuals/octopusAvatarVisualShared.d.ts +34 -0
- package/esm/src/avatars/visuals/octopusAvatarVisualShared.test.d.ts +1 -0
- package/esm/src/book-components/Chat/Chat/TeamToolCallModalContent.test.d.ts +2 -0
- package/esm/src/commitments/USE/USE.d.ts +1 -0
- package/esm/src/commitments/USE/aggregateUseCommitmentSystemMessages.d.ts +1 -1
- package/esm/src/commitments/USE_DEEPSEARCH/USE_DEEPSEARCH.d.ts +47 -0
- package/esm/src/commitments/USE_DEEPSEARCH/USE_DEEPSEARCH.test.d.ts +1 -0
- package/esm/src/commitments/_common/createSerpSearchToolFunction.d.ts +12 -0
- package/esm/src/commitments/index.d.ts +2 -1
- package/esm/src/llm-providers/openai/OpenAiAgentKitExecutionTools.test.d.ts +1 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +884 -142
- package/umd/index.umd.js.map +1 -1
- package/umd/src/avatars/AvatarOrImage.d.ts +5 -1
- package/umd/src/avatars/avatarInteractionUtils.d.ts +81 -0
- package/umd/src/avatars/avatarInteractionUtils.test.d.ts +1 -0
- package/umd/src/avatars/avatarPointerTracking.d.ts +17 -0
- package/umd/src/avatars/avatarRenderingUtils.d.ts +3 -2
- package/umd/src/avatars/avatarRenderingUtils.test.d.ts +1 -0
- package/umd/src/avatars/index.d.ts +1 -1
- package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +35 -0
- package/umd/src/avatars/visuals/octopusAvatarVisualShared.d.ts +34 -0
- package/umd/src/avatars/visuals/octopusAvatarVisualShared.test.d.ts +1 -0
- package/umd/src/book-components/Chat/Chat/TeamToolCallModalContent.test.d.ts +2 -0
- package/umd/src/commitments/USE/USE.d.ts +1 -0
- package/umd/src/commitments/USE/aggregateUseCommitmentSystemMessages.d.ts +1 -1
- package/umd/src/commitments/USE_DEEPSEARCH/USE_DEEPSEARCH.d.ts +47 -0
- package/umd/src/commitments/USE_DEEPSEARCH/USE_DEEPSEARCH.test.d.ts +1 -0
- package/umd/src/commitments/_common/createSerpSearchToolFunction.d.ts +12 -0
- package/umd/src/commitments/index.d.ts +2 -1
- package/umd/src/llm-providers/openai/OpenAiAgentKitExecutionTools.test.d.ts +1 -0
- package/umd/src/version.d.ts +1 -1
package/esm/index.es.js
CHANGED
|
@@ -21,7 +21,7 @@ import { forTime } from 'waitasecond';
|
|
|
21
21
|
import sha256 from 'crypto-js/sha256';
|
|
22
22
|
import { parse, unparse } from 'papaparse';
|
|
23
23
|
import colors from 'colors';
|
|
24
|
-
import { Agent as Agent$1, setDefaultOpenAIClient, setDefaultOpenAIKey, fileSearchTool, tool, run } from '@openai/agents';
|
|
24
|
+
import { Agent as Agent$1, setDefaultOpenAIClient, setDefaultOpenAIKey, fileSearchTool, tool, run, webSearchTool } from '@openai/agents';
|
|
25
25
|
import Bottleneck from 'bottleneck';
|
|
26
26
|
import OpenAI from 'openai';
|
|
27
27
|
import QRCode from 'qrcode';
|
|
@@ -40,7 +40,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
40
40
|
* @generated
|
|
41
41
|
* @see https://github.com/webgptorg/promptbook
|
|
42
42
|
*/
|
|
43
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
43
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-48';
|
|
44
44
|
/**
|
|
45
45
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
46
46
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -1402,11 +1402,12 @@ function createAvatarDefinitionFromAgentBasicInformation(agentBasicInformation)
|
|
|
1402
1402
|
* Creates the shared derived palette used by every avatar visual.
|
|
1403
1403
|
*
|
|
1404
1404
|
* @param avatarDefinition Stable avatar definition.
|
|
1405
|
+
* @param surface Surface style used by the parent UI.
|
|
1405
1406
|
* @returns Derived palette.
|
|
1406
1407
|
*
|
|
1407
1408
|
* @private utility of the avatar rendering system
|
|
1408
1409
|
*/
|
|
1409
|
-
function createAvatarPalette(avatarDefinition) {
|
|
1410
|
+
function createAvatarPalette(avatarDefinition, surface = 'framed') {
|
|
1410
1411
|
const normalizedAvatarDefinition = normalizeAvatarDefinition(avatarDefinition);
|
|
1411
1412
|
const primaryColor = Color.fromSafe(normalizedAvatarDefinition.colors[0] || PROMPTBOOK_COLOR);
|
|
1412
1413
|
const secondaryColor = Color.fromSafe(normalizedAvatarDefinition.colors[1] || primaryColor.then(lighten(0.12)).then(saturate(0.16)));
|
|
@@ -1416,8 +1417,8 @@ function createAvatarPalette(avatarDefinition) {
|
|
|
1416
1417
|
const highlightColor = Color.fromSafe(accentColor.then(lighten(0.22)).then(saturate(0.08)));
|
|
1417
1418
|
const shadowColor = Color.fromSafe(primaryColor.then(darken(0.46)).then(saturate(0.14)));
|
|
1418
1419
|
return {
|
|
1419
|
-
background: backgroundColor.toHex(),
|
|
1420
|
-
backgroundSecondary: backgroundSecondaryColor.toHex(),
|
|
1420
|
+
background: surface === 'transparent' ? 'transparent' : backgroundColor.toHex(),
|
|
1421
|
+
backgroundSecondary: surface === 'transparent' ? 'transparent' : backgroundSecondaryColor.toHex(),
|
|
1421
1422
|
primary: primaryColor.toHex(),
|
|
1422
1423
|
secondary: secondaryColor.toHex(),
|
|
1423
1424
|
accent: accentColor.toHex(),
|
|
@@ -1436,6 +1437,9 @@ function createAvatarPalette(avatarDefinition) {
|
|
|
1436
1437
|
* @private utility of the avatar rendering system
|
|
1437
1438
|
*/
|
|
1438
1439
|
function drawAvatarFrame(context, size, palette) {
|
|
1440
|
+
if (palette.background === 'transparent' && palette.backgroundSecondary === 'transparent') {
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1439
1443
|
const gradient = context.createLinearGradient(0, 0, size, size);
|
|
1440
1444
|
gradient.addColorStop(0, palette.background);
|
|
1441
1445
|
gradient.addColorStop(1, palette.backgroundSecondary);
|
|
@@ -1587,7 +1591,7 @@ function generatePlaceholderAgentProfileImageUrl(agentIdOrName, agentsServerUrl)
|
|
|
1587
1591
|
*
|
|
1588
1592
|
* @private shared avatar contract
|
|
1589
1593
|
*/
|
|
1590
|
-
const DEFAULT_AGENT_AVATAR_VISUAL_ID = '
|
|
1594
|
+
const DEFAULT_AGENT_AVATAR_VISUAL_ID = 'octopus3';
|
|
1591
1595
|
/**
|
|
1592
1596
|
* Resolve a base URL for relative images, preferring the provided base or browser location.
|
|
1593
1597
|
*
|
|
@@ -11732,6 +11736,7 @@ class TemplateCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
11732
11736
|
* Supported USE types:
|
|
11733
11737
|
* - USE BROWSER: Enables the agent to use a web browser tool
|
|
11734
11738
|
* - USE SEARCH ENGINE (future): Enables search engine access
|
|
11739
|
+
* - USE DEEPSEARCH: Enables deeper research-oriented search access
|
|
11735
11740
|
* - USE FILE SYSTEM (future): Enables file system operations
|
|
11736
11741
|
* - USE MCP (future): Enables MCP server connections
|
|
11737
11742
|
*
|
|
@@ -11754,7 +11759,7 @@ class UseCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
11754
11759
|
* Short one-line description of USE commitments.
|
|
11755
11760
|
*/
|
|
11756
11761
|
get description() {
|
|
11757
|
-
return 'Enable the agent to use specific tools or capabilities (BROWSER, SEARCH ENGINE, etc.).';
|
|
11762
|
+
return 'Enable the agent to use specific tools or capabilities (BROWSER, SEARCH ENGINE, DEEPSEARCH, etc.).';
|
|
11758
11763
|
}
|
|
11759
11764
|
/**
|
|
11760
11765
|
* Icon for this commitment.
|
|
@@ -11775,6 +11780,7 @@ class UseCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
11775
11780
|
|
|
11776
11781
|
- **USE BROWSER** - Enables the agent to use a web browser tool to access and retrieve information from the internet
|
|
11777
11782
|
- **USE SEARCH ENGINE** (future) - Enables search engine access
|
|
11783
|
+
- **USE DEEPSEARCH** - Enables deeper research-oriented search access
|
|
11778
11784
|
- **USE FILE SYSTEM** (future) - Enables file system operations
|
|
11779
11785
|
- **USE MCP** (future) - Enables MCP server connections
|
|
11780
11786
|
|
|
@@ -11829,7 +11835,7 @@ class UseCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
11829
11835
|
* Checks if this is a known USE type
|
|
11830
11836
|
*/
|
|
11831
11837
|
isKnownUseType(useType) {
|
|
11832
|
-
const knownTypes = ['BROWSER', 'SEARCH ENGINE', 'FILE SYSTEM', 'MCP'];
|
|
11838
|
+
const knownTypes = ['BROWSER', 'SEARCH ENGINE', 'DEEPSEARCH', 'FILE SYSTEM', 'MCP'];
|
|
11833
11839
|
return knownTypes.includes(useType.toUpperCase());
|
|
11834
11840
|
}
|
|
11835
11841
|
}
|
|
@@ -11842,6 +11848,7 @@ class UseCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
11842
11848
|
*/
|
|
11843
11849
|
const AGGREGATED_USE_COMMITMENT_TYPES = [
|
|
11844
11850
|
'USE BROWSER',
|
|
11851
|
+
'USE DEEPSEARCH',
|
|
11845
11852
|
'USE SEARCH ENGINE',
|
|
11846
11853
|
'USE TIME',
|
|
11847
11854
|
];
|
|
@@ -11921,6 +11928,15 @@ function createAggregatedUseCommitmentSystemMessage(type, additionalInstructions
|
|
|
11921
11928
|
- Do not tell the user you cannot search for information, YOU CAN.
|
|
11922
11929
|
${block(formatOptionalInstructionBlock('Search instructions', combinedAdditionalInstructions))}
|
|
11923
11930
|
`);
|
|
11931
|
+
case 'USE DEEPSEARCH':
|
|
11932
|
+
return spaceTrim$1((block) => `
|
|
11933
|
+
Tool:
|
|
11934
|
+
- You have access to DeepSearch via the tool "deep_search".
|
|
11935
|
+
- Use it for broader research tasks that need multi-step investigation, comparison, or synthesis across multiple sources.
|
|
11936
|
+
- Prefer it over quick search when the user asks for a well-grounded brief, report, or deeper investigation.
|
|
11937
|
+
- Do not pretend you cannot research current information when this tool is available.
|
|
11938
|
+
${block(formatOptionalInstructionBlock('DeepSearch instructions', combinedAdditionalInstructions))}
|
|
11939
|
+
`);
|
|
11924
11940
|
}
|
|
11925
11941
|
}
|
|
11926
11942
|
/**
|
|
@@ -13470,6 +13486,207 @@ function addConfiguredCalendarIfMissing(configuredCalendars, calendarReference)
|
|
|
13470
13486
|
}
|
|
13471
13487
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
13472
13488
|
|
|
13489
|
+
/**
|
|
13490
|
+
* A search engine implementation that uses the SerpApi to fetch Google search results.
|
|
13491
|
+
*
|
|
13492
|
+
* @private <- TODO: !!!! Export via some package
|
|
13493
|
+
*/
|
|
13494
|
+
class SerpSearchEngine {
|
|
13495
|
+
get title() {
|
|
13496
|
+
return 'SerpApi Search Engine';
|
|
13497
|
+
}
|
|
13498
|
+
get description() {
|
|
13499
|
+
return 'Search engine that uses SerpApi to fetch Google search results';
|
|
13500
|
+
}
|
|
13501
|
+
checkConfiguration() {
|
|
13502
|
+
if (!process.env.SERP_API_KEY) {
|
|
13503
|
+
throw new Error('SERP_API_KEY is not configured');
|
|
13504
|
+
}
|
|
13505
|
+
}
|
|
13506
|
+
async search(query, options = {}) {
|
|
13507
|
+
const apiKey = process.env.SERP_API_KEY;
|
|
13508
|
+
if (!apiKey) {
|
|
13509
|
+
throw new Error('SERP_API_KEY is not configured');
|
|
13510
|
+
}
|
|
13511
|
+
const url = new URL('https://serpapi.com/search');
|
|
13512
|
+
url.searchParams.set('api_key', apiKey);
|
|
13513
|
+
url.searchParams.set('engine', 'google');
|
|
13514
|
+
url.searchParams.set('q', query);
|
|
13515
|
+
for (const [key, value] of Object.entries(options)) {
|
|
13516
|
+
url.searchParams.set(key, String(value));
|
|
13517
|
+
}
|
|
13518
|
+
const response = await fetch(url.toString());
|
|
13519
|
+
if (!response.ok) {
|
|
13520
|
+
const body = await response.text();
|
|
13521
|
+
throw new Error(`SerpApi failed with status ${response.status}: ${response.statusText}\n${body}`);
|
|
13522
|
+
}
|
|
13523
|
+
const data = (await response.json());
|
|
13524
|
+
return (data.organic_results || []).map((item) => ({
|
|
13525
|
+
title: item.title,
|
|
13526
|
+
url: item.link,
|
|
13527
|
+
snippet: item.snippet || '',
|
|
13528
|
+
}));
|
|
13529
|
+
}
|
|
13530
|
+
}
|
|
13531
|
+
|
|
13532
|
+
/**
|
|
13533
|
+
* Creates one SERP-backed tool function used as a local fallback for search-like commitments.
|
|
13534
|
+
*
|
|
13535
|
+
* @param toolName - Technical tool name used for validation messages.
|
|
13536
|
+
* @param resultLabel - Human-readable label used in formatted results.
|
|
13537
|
+
* @returns Async tool function compatible with commitment tool registration.
|
|
13538
|
+
*
|
|
13539
|
+
* @private internal helper for search-like commitments
|
|
13540
|
+
*/
|
|
13541
|
+
function createSerpSearchToolFunction(toolName, resultLabel) {
|
|
13542
|
+
return async (rawArgs) => {
|
|
13543
|
+
const { query, ...searchOptions } = rawArgs;
|
|
13544
|
+
if (typeof query !== 'string' || !query.trim()) {
|
|
13545
|
+
throw new Error(`${toolName} query is required`);
|
|
13546
|
+
}
|
|
13547
|
+
const searchEngine = new SerpSearchEngine();
|
|
13548
|
+
const results = await searchEngine.search(query, searchOptions);
|
|
13549
|
+
return spaceTrim$1((block) => `
|
|
13550
|
+
${resultLabel} results for "${query}"${Object.keys(searchOptions).length === 0
|
|
13551
|
+
? ''
|
|
13552
|
+
: ` with options ${JSON.stringify(searchOptions)}`}:
|
|
13553
|
+
|
|
13554
|
+
${block(results
|
|
13555
|
+
.map((result) => spaceTrim$1(`
|
|
13556
|
+
- **${result.title}**
|
|
13557
|
+
${result.url}
|
|
13558
|
+
${result.snippet}
|
|
13559
|
+
`))
|
|
13560
|
+
.join('\n\n'))}
|
|
13561
|
+
`);
|
|
13562
|
+
};
|
|
13563
|
+
}
|
|
13564
|
+
|
|
13565
|
+
/**
|
|
13566
|
+
* USE DEEPSEARCH commitment definition
|
|
13567
|
+
*
|
|
13568
|
+
* The `USE DEEPSEARCH` commitment indicates that the agent should use a deeper research-oriented
|
|
13569
|
+
* search workflow instead of lightweight web search when it needs fresh information from the internet.
|
|
13570
|
+
*
|
|
13571
|
+
* The content following `USE DEEPSEARCH` is an arbitrary text that the agent should know
|
|
13572
|
+
* (e.g. search scope or research instructions).
|
|
13573
|
+
*
|
|
13574
|
+
* Example usage in agent source:
|
|
13575
|
+
*
|
|
13576
|
+
* ```book
|
|
13577
|
+
* USE DEEPSEARCH
|
|
13578
|
+
* USE DEEPSEARCH Compare official vendor documentation with independent benchmarks.
|
|
13579
|
+
* ```
|
|
13580
|
+
*
|
|
13581
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
13582
|
+
*/
|
|
13583
|
+
class UseDeepSearchCommitmentDefinition extends BaseCommitmentDefinition {
|
|
13584
|
+
constructor() {
|
|
13585
|
+
super('USE DEEPSEARCH');
|
|
13586
|
+
}
|
|
13587
|
+
get requiresContent() {
|
|
13588
|
+
return false;
|
|
13589
|
+
}
|
|
13590
|
+
/**
|
|
13591
|
+
* Short one-line description of USE DEEPSEARCH.
|
|
13592
|
+
*/
|
|
13593
|
+
get description() {
|
|
13594
|
+
return 'Enable the agent to use DeepSearch for more thorough internet research.';
|
|
13595
|
+
}
|
|
13596
|
+
/**
|
|
13597
|
+
* Icon for this commitment.
|
|
13598
|
+
*/
|
|
13599
|
+
get icon() {
|
|
13600
|
+
return '🔬';
|
|
13601
|
+
}
|
|
13602
|
+
/**
|
|
13603
|
+
* Markdown documentation for USE DEEPSEARCH commitment.
|
|
13604
|
+
*/
|
|
13605
|
+
get documentation() {
|
|
13606
|
+
return spaceTrim$1(`
|
|
13607
|
+
# USE DEEPSEARCH
|
|
13608
|
+
|
|
13609
|
+
Enables the agent to use DeepSearch for broader, more thorough internet research than lightweight web search.
|
|
13610
|
+
|
|
13611
|
+
## Key aspects
|
|
13612
|
+
|
|
13613
|
+
- The content following \`USE DEEPSEARCH\` is arbitrary guidance for the research workflow.
|
|
13614
|
+
- In Agents Server, the OpenAI Agents SDK runtime uses a nested deep-research agent for this tool.
|
|
13615
|
+
- Use this for investigations, comparisons, market scans, or other tasks that benefit from deeper synthesis.
|
|
13616
|
+
- Prefer regular \`USE SEARCH ENGINE\` when a quick factual lookup is enough.
|
|
13617
|
+
|
|
13618
|
+
## Examples
|
|
13619
|
+
|
|
13620
|
+
\`\`\`book
|
|
13621
|
+
Due Diligence Researcher
|
|
13622
|
+
|
|
13623
|
+
GOAL Investigate vendors thoroughly before making recommendations.
|
|
13624
|
+
USE DEEPSEARCH Compare official sources with credible third-party analysis.
|
|
13625
|
+
RULE Cite the strongest supporting sources in the final answer.
|
|
13626
|
+
\`\`\`
|
|
13627
|
+
|
|
13628
|
+
\`\`\`book
|
|
13629
|
+
Market Analyst
|
|
13630
|
+
|
|
13631
|
+
GOAL Build concise but well-grounded research briefs.
|
|
13632
|
+
USE DEEPSEARCH Focus on recent public information and competing viewpoints.
|
|
13633
|
+
CLOSED
|
|
13634
|
+
\`\`\`
|
|
13635
|
+
`);
|
|
13636
|
+
}
|
|
13637
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
13638
|
+
const existingTools = requirements.tools || [];
|
|
13639
|
+
const updatedTools = existingTools.some((tool) => tool.name === 'deep_search')
|
|
13640
|
+
? existingTools
|
|
13641
|
+
: [
|
|
13642
|
+
...existingTools,
|
|
13643
|
+
{
|
|
13644
|
+
name: 'deep_search',
|
|
13645
|
+
description: spaceTrim$1(`
|
|
13646
|
+
Research the internet deeply and synthesize a grounded answer.
|
|
13647
|
+
Use this tool for broader investigations, comparisons, and requests that need more than a quick search.
|
|
13648
|
+
`),
|
|
13649
|
+
parameters: {
|
|
13650
|
+
type: 'object',
|
|
13651
|
+
properties: {
|
|
13652
|
+
query: {
|
|
13653
|
+
type: 'string',
|
|
13654
|
+
description: 'The research question or investigation request.',
|
|
13655
|
+
},
|
|
13656
|
+
},
|
|
13657
|
+
required: ['query'],
|
|
13658
|
+
additionalProperties: false,
|
|
13659
|
+
},
|
|
13660
|
+
},
|
|
13661
|
+
];
|
|
13662
|
+
return appendAggregatedUseCommitmentPlaceholder({
|
|
13663
|
+
...requirements,
|
|
13664
|
+
tools: updatedTools,
|
|
13665
|
+
_metadata: {
|
|
13666
|
+
...requirements._metadata,
|
|
13667
|
+
useDeepSearch: content || true,
|
|
13668
|
+
},
|
|
13669
|
+
}, this.type);
|
|
13670
|
+
}
|
|
13671
|
+
/**
|
|
13672
|
+
* Gets human-readable titles for tool functions provided by this commitment.
|
|
13673
|
+
*/
|
|
13674
|
+
getToolTitles() {
|
|
13675
|
+
return {
|
|
13676
|
+
deep_search: 'DeepSearch',
|
|
13677
|
+
};
|
|
13678
|
+
}
|
|
13679
|
+
/**
|
|
13680
|
+
* Gets the local fallback implementation for the `deep_search` tool.
|
|
13681
|
+
*/
|
|
13682
|
+
getToolFunctions() {
|
|
13683
|
+
return {
|
|
13684
|
+
deep_search: createSerpSearchToolFunction('deep_search', 'DeepSearch'),
|
|
13685
|
+
};
|
|
13686
|
+
}
|
|
13687
|
+
}
|
|
13688
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
13689
|
+
|
|
13473
13690
|
/**
|
|
13474
13691
|
* Lightweight email token matcher used for `USE EMAIL` first-line parsing.
|
|
13475
13692
|
*
|
|
@@ -15701,49 +15918,6 @@ function addConfiguredProjectIfMissing(configuredProjects, repositoryReference)
|
|
|
15701
15918
|
}
|
|
15702
15919
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
15703
15920
|
|
|
15704
|
-
/**
|
|
15705
|
-
* A search engine implementation that uses the SerpApi to fetch Google search results.
|
|
15706
|
-
*
|
|
15707
|
-
* @private <- TODO: !!!! Export via some package
|
|
15708
|
-
*/
|
|
15709
|
-
class SerpSearchEngine {
|
|
15710
|
-
get title() {
|
|
15711
|
-
return 'SerpApi Search Engine';
|
|
15712
|
-
}
|
|
15713
|
-
get description() {
|
|
15714
|
-
return 'Search engine that uses SerpApi to fetch Google search results';
|
|
15715
|
-
}
|
|
15716
|
-
checkConfiguration() {
|
|
15717
|
-
if (!process.env.SERP_API_KEY) {
|
|
15718
|
-
throw new Error('SERP_API_KEY is not configured');
|
|
15719
|
-
}
|
|
15720
|
-
}
|
|
15721
|
-
async search(query, options = {}) {
|
|
15722
|
-
const apiKey = process.env.SERP_API_KEY;
|
|
15723
|
-
if (!apiKey) {
|
|
15724
|
-
throw new Error('SERP_API_KEY is not configured');
|
|
15725
|
-
}
|
|
15726
|
-
const url = new URL('https://serpapi.com/search');
|
|
15727
|
-
url.searchParams.set('api_key', apiKey);
|
|
15728
|
-
url.searchParams.set('engine', 'google');
|
|
15729
|
-
url.searchParams.set('q', query);
|
|
15730
|
-
for (const [key, value] of Object.entries(options)) {
|
|
15731
|
-
url.searchParams.set(key, String(value));
|
|
15732
|
-
}
|
|
15733
|
-
const response = await fetch(url.toString());
|
|
15734
|
-
if (!response.ok) {
|
|
15735
|
-
const body = await response.text();
|
|
15736
|
-
throw new Error(`SerpApi failed with status ${response.status}: ${response.statusText}\n${body}`);
|
|
15737
|
-
}
|
|
15738
|
-
const data = (await response.json());
|
|
15739
|
-
return (data.organic_results || []).map((item) => ({
|
|
15740
|
-
title: item.title,
|
|
15741
|
-
url: item.link,
|
|
15742
|
-
snippet: item.snippet || '',
|
|
15743
|
-
}));
|
|
15744
|
-
}
|
|
15745
|
-
}
|
|
15746
|
-
|
|
15747
15921
|
/**
|
|
15748
15922
|
* USE SEARCH ENGINE commitment definition
|
|
15749
15923
|
*
|
|
@@ -15887,26 +16061,7 @@ class UseSearchEngineCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
15887
16061
|
*/
|
|
15888
16062
|
getToolFunctions() {
|
|
15889
16063
|
return {
|
|
15890
|
-
|
|
15891
|
-
console.log('!!!! [Tool] web_search called', { args });
|
|
15892
|
-
const { query, ...options } = args;
|
|
15893
|
-
if (!query) {
|
|
15894
|
-
throw new Error('Search query is required');
|
|
15895
|
-
}
|
|
15896
|
-
const searchEngine = new SerpSearchEngine();
|
|
15897
|
-
const results = await searchEngine.search(query, options);
|
|
15898
|
-
return spaceTrim$1((block) => `
|
|
15899
|
-
Search results for "${query}"${Object.keys(options).length === 0 ? '' : ` with options ${JSON.stringify(options)}`}:
|
|
15900
|
-
|
|
15901
|
-
${block(results
|
|
15902
|
-
.map((result) => spaceTrim$1(`
|
|
15903
|
-
- **${result.title}**
|
|
15904
|
-
${result.url}
|
|
15905
|
-
${result.snippet}
|
|
15906
|
-
`))
|
|
15907
|
-
.join('\n\n'))}
|
|
15908
|
-
`);
|
|
15909
|
-
},
|
|
16064
|
+
web_search: createSerpSearchToolFunction('web_search', 'Search'),
|
|
15910
16065
|
};
|
|
15911
16066
|
}
|
|
15912
16067
|
}
|
|
@@ -17552,6 +17707,7 @@ const COMMITMENT_REGISTRY = [
|
|
|
17552
17707
|
new ClosedCommitmentDefinition(),
|
|
17553
17708
|
new TeamCommitmentDefinition(),
|
|
17554
17709
|
new UseBrowserCommitmentDefinition(),
|
|
17710
|
+
new UseDeepSearchCommitmentDefinition(),
|
|
17555
17711
|
new UseSearchEngineCommitmentDefinition(),
|
|
17556
17712
|
new UseSpawnCommitmentDefinition(),
|
|
17557
17713
|
new UseTimeoutCommitmentDefinition(),
|
|
@@ -17863,6 +18019,11 @@ const SIMPLE_CAPABILITY_BY_COMMITMENT_TYPE = {
|
|
|
17863
18019
|
label: 'Internet',
|
|
17864
18020
|
iconName: 'Search',
|
|
17865
18021
|
},
|
|
18022
|
+
'USE DEEPSEARCH': {
|
|
18023
|
+
type: 'search-engine',
|
|
18024
|
+
label: 'DeepSearch',
|
|
18025
|
+
iconName: 'Search',
|
|
18026
|
+
},
|
|
17866
18027
|
'USE TIME': {
|
|
17867
18028
|
type: 'time',
|
|
17868
18029
|
label: 'Time',
|
|
@@ -25738,6 +25899,320 @@ function ChatInputArea(props) {
|
|
|
25738
25899
|
}), children: jsx(SendIcon, { size: 25 }) })] }), speechRecognition && (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 && (jsxs("div", { className: styles$5.uploadProgress, children: [jsx("div", { className: styles$5.uploadProgressBar, children: jsx("div", { className: styles$5.uploadProgressFill }) }), jsx("span", { children: "Uploading files..." })] })), isDragOver && onFileUpload && (jsx("div", { className: styles$5.dragOverlay, children: jsxs("div", { className: styles$5.dragOverlayContent, children: [jsx(AttachmentIcon, { size: 48 }), jsx("span", { children: "Drop files here to upload" })] }) }))] }));
|
|
25739
25900
|
}
|
|
25740
25901
|
|
|
25902
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
25903
|
+
/**
|
|
25904
|
+
* Maximum normalized eye travel used when the viewer moves across the viewport.
|
|
25905
|
+
*
|
|
25906
|
+
* @private utility of the avatar rendering system
|
|
25907
|
+
*/
|
|
25908
|
+
const MAX_GAZE_OFFSET = 0.78;
|
|
25909
|
+
/**
|
|
25910
|
+
* Maximum normalized body lean used for subtle mantle response.
|
|
25911
|
+
*
|
|
25912
|
+
* @private utility of the avatar rendering system
|
|
25913
|
+
*/
|
|
25914
|
+
const MAX_BODY_OFFSET = 0.28;
|
|
25915
|
+
/**
|
|
25916
|
+
* Smoothing window used while a live pointer or touch target is active.
|
|
25917
|
+
*
|
|
25918
|
+
* @private utility of the avatar rendering system
|
|
25919
|
+
*/
|
|
25920
|
+
const ACTIVE_INTERACTION_SMOOTHING_MS = 90;
|
|
25921
|
+
/**
|
|
25922
|
+
* Slower smoothing window used when easing the avatar back to its idle state.
|
|
25923
|
+
*
|
|
25924
|
+
* @private utility of the avatar rendering system
|
|
25925
|
+
*/
|
|
25926
|
+
const IDLE_INTERACTION_SMOOTHING_MS = 230;
|
|
25927
|
+
/**
|
|
25928
|
+
* Maximum frame delta allowed when smoothing interaction after tab stalls.
|
|
25929
|
+
*
|
|
25930
|
+
* @private utility of the avatar rendering system
|
|
25931
|
+
*/
|
|
25932
|
+
const MAX_INTERACTION_FRAME_DELTA_MS = 64;
|
|
25933
|
+
/**
|
|
25934
|
+
* Extra damping used for the slower body lean compared with the quicker eye motion.
|
|
25935
|
+
*
|
|
25936
|
+
* @private utility of the avatar rendering system
|
|
25937
|
+
*/
|
|
25938
|
+
const BODY_INTERACTION_SMOOTHING_MULTIPLIER = 1.2;
|
|
25939
|
+
/**
|
|
25940
|
+
* Stable zeroed interaction state used by non-interactive render paths.
|
|
25941
|
+
*
|
|
25942
|
+
* @private utility of the avatar rendering system
|
|
25943
|
+
*/
|
|
25944
|
+
const IDLE_AVATAR_INTERACTION_STATE = {
|
|
25945
|
+
gazeX: 0,
|
|
25946
|
+
gazeY: 0,
|
|
25947
|
+
bodyOffsetX: 0,
|
|
25948
|
+
bodyOffsetY: 0,
|
|
25949
|
+
intensity: 0,
|
|
25950
|
+
isPointerActive: false,
|
|
25951
|
+
pointerType: 'idle',
|
|
25952
|
+
};
|
|
25953
|
+
/**
|
|
25954
|
+
* Creates one stable cache key from the meaningful avatar-definition fields.
|
|
25955
|
+
*
|
|
25956
|
+
* @param avatarDefinition Normalized or raw avatar definition.
|
|
25957
|
+
* @returns Stable cache key that ignores object identity churn.
|
|
25958
|
+
*
|
|
25959
|
+
* @private utility of the avatar rendering system
|
|
25960
|
+
*/
|
|
25961
|
+
function createAvatarDefinitionKey(avatarDefinition) {
|
|
25962
|
+
const normalizedAvatarDefinition = normalizeAvatarDefinition(avatarDefinition);
|
|
25963
|
+
return [
|
|
25964
|
+
normalizedAvatarDefinition.agentName,
|
|
25965
|
+
normalizedAvatarDefinition.agentHash,
|
|
25966
|
+
normalizedAvatarDefinition.colors.join('|'),
|
|
25967
|
+
].join('::');
|
|
25968
|
+
}
|
|
25969
|
+
/**
|
|
25970
|
+
* Returns the neutral interaction state used by static/server-side renders.
|
|
25971
|
+
*
|
|
25972
|
+
* @returns Zeroed interaction state.
|
|
25973
|
+
*
|
|
25974
|
+
* @private utility of the avatar rendering system
|
|
25975
|
+
*/
|
|
25976
|
+
function createIdleAvatarInteractionState() {
|
|
25977
|
+
return IDLE_AVATAR_INTERACTION_STATE;
|
|
25978
|
+
}
|
|
25979
|
+
/**
|
|
25980
|
+
* Creates a fresh runtime state for the interactive animation loop.
|
|
25981
|
+
*
|
|
25982
|
+
* @returns Runtime interaction state with neutral values.
|
|
25983
|
+
*
|
|
25984
|
+
* @private utility of the avatar rendering system
|
|
25985
|
+
*/
|
|
25986
|
+
function createAvatarInteractionRuntimeState() {
|
|
25987
|
+
return {
|
|
25988
|
+
...IDLE_AVATAR_INTERACTION_STATE,
|
|
25989
|
+
lastFrameMs: null,
|
|
25990
|
+
};
|
|
25991
|
+
}
|
|
25992
|
+
/**
|
|
25993
|
+
* Converts the shared viewport pointer state into one avatar-local gaze target.
|
|
25994
|
+
*
|
|
25995
|
+
* @param avatarBounds Canvas bounds in viewport coordinates.
|
|
25996
|
+
* @param pointerSnapshot Latest shared pointer sample.
|
|
25997
|
+
* @returns Local target used to steer eyes and subtle body lean.
|
|
25998
|
+
*
|
|
25999
|
+
* @private utility of the avatar rendering system
|
|
26000
|
+
*/
|
|
26001
|
+
function resolveAvatarPointerTarget(avatarBounds, pointerSnapshot) {
|
|
26002
|
+
if (!pointerSnapshot || !pointerSnapshot.isPointerActive) {
|
|
26003
|
+
return {
|
|
26004
|
+
...IDLE_AVATAR_INTERACTION_STATE,
|
|
26005
|
+
};
|
|
26006
|
+
}
|
|
26007
|
+
const centerX = avatarBounds.left + avatarBounds.width / 2;
|
|
26008
|
+
const centerY = avatarBounds.top + avatarBounds.height / 2;
|
|
26009
|
+
const normalizedX = (pointerSnapshot.clientX - centerX) / Math.max(avatarBounds.width / 2, 1);
|
|
26010
|
+
const normalizedY = (pointerSnapshot.clientY - centerY) / Math.max(avatarBounds.height / 2, 1);
|
|
26011
|
+
const normalizedLength = Math.hypot(normalizedX, normalizedY) || 1;
|
|
26012
|
+
const clampedLength = Math.min(1, normalizedLength);
|
|
26013
|
+
const targetX = (normalizedX / normalizedLength) * clampedLength;
|
|
26014
|
+
const targetY = (normalizedY / normalizedLength) * clampedLength;
|
|
26015
|
+
const intensity = clamp01$1(clampedLength);
|
|
26016
|
+
return {
|
|
26017
|
+
gazeX: targetX * MAX_GAZE_OFFSET,
|
|
26018
|
+
gazeY: targetY * MAX_GAZE_OFFSET,
|
|
26019
|
+
bodyOffsetX: targetX * MAX_BODY_OFFSET,
|
|
26020
|
+
bodyOffsetY: targetY * MAX_BODY_OFFSET,
|
|
26021
|
+
intensity,
|
|
26022
|
+
isPointerActive: true,
|
|
26023
|
+
pointerType: pointerSnapshot.pointerType,
|
|
26024
|
+
};
|
|
26025
|
+
}
|
|
26026
|
+
/**
|
|
26027
|
+
* Advances the smoothed interaction state toward the latest pointer target.
|
|
26028
|
+
*
|
|
26029
|
+
* @param runtimeState Previous animation-frame state.
|
|
26030
|
+
* @param pointerTarget Latest local pointer target.
|
|
26031
|
+
* @param nowMs Current animation-frame timestamp.
|
|
26032
|
+
* @returns Next runtime state to keep in the animation loop.
|
|
26033
|
+
*
|
|
26034
|
+
* @private utility of the avatar rendering system
|
|
26035
|
+
*/
|
|
26036
|
+
function stepAvatarInteractionRuntimeState(runtimeState, pointerTarget, nowMs) {
|
|
26037
|
+
const deltaMs = runtimeState.lastFrameMs === null
|
|
26038
|
+
? 16
|
|
26039
|
+
: Math.min(MAX_INTERACTION_FRAME_DELTA_MS, Math.max(8, nowMs - runtimeState.lastFrameMs));
|
|
26040
|
+
const smoothingWindowMs = pointerTarget.isPointerActive
|
|
26041
|
+
? ACTIVE_INTERACTION_SMOOTHING_MS
|
|
26042
|
+
: IDLE_INTERACTION_SMOOTHING_MS;
|
|
26043
|
+
// This exponential interpolation keeps the gaze response smooth regardless of fluctuating frame rates.
|
|
26044
|
+
return {
|
|
26045
|
+
gazeX: interpolateExponentially(runtimeState.gazeX, pointerTarget.gazeX, deltaMs, smoothingWindowMs),
|
|
26046
|
+
gazeY: interpolateExponentially(runtimeState.gazeY, pointerTarget.gazeY, deltaMs, smoothingWindowMs),
|
|
26047
|
+
bodyOffsetX: interpolateExponentially(runtimeState.bodyOffsetX, pointerTarget.bodyOffsetX, deltaMs, smoothingWindowMs * BODY_INTERACTION_SMOOTHING_MULTIPLIER),
|
|
26048
|
+
bodyOffsetY: interpolateExponentially(runtimeState.bodyOffsetY, pointerTarget.bodyOffsetY, deltaMs, smoothingWindowMs * BODY_INTERACTION_SMOOTHING_MULTIPLIER),
|
|
26049
|
+
intensity: interpolateExponentially(runtimeState.intensity, pointerTarget.intensity, deltaMs, smoothingWindowMs),
|
|
26050
|
+
isPointerActive: pointerTarget.isPointerActive,
|
|
26051
|
+
pointerType: pointerTarget.pointerType,
|
|
26052
|
+
lastFrameMs: nowMs,
|
|
26053
|
+
};
|
|
26054
|
+
}
|
|
26055
|
+
/**
|
|
26056
|
+
* Clamps a scalar into the inclusive `[0, 1]` range.
|
|
26057
|
+
*
|
|
26058
|
+
* @param value Arbitrary scalar.
|
|
26059
|
+
* @returns Clamped scalar.
|
|
26060
|
+
*
|
|
26061
|
+
* @private utility of the avatar rendering system
|
|
26062
|
+
*/
|
|
26063
|
+
function clamp01$1(value) {
|
|
26064
|
+
return Math.min(1, Math.max(0, value));
|
|
26065
|
+
}
|
|
26066
|
+
/**
|
|
26067
|
+
* Interpolates between two values using frame-rate-independent exponential easing.
|
|
26068
|
+
*
|
|
26069
|
+
* @param currentValue Current smoothed value.
|
|
26070
|
+
* @param targetValue Target value.
|
|
26071
|
+
* @param deltaMs Elapsed milliseconds since the previous frame.
|
|
26072
|
+
* @param smoothingWindowMs Time constant controlling responsiveness.
|
|
26073
|
+
* @returns Smoothed next value.
|
|
26074
|
+
*
|
|
26075
|
+
* @private utility of the avatar rendering system
|
|
26076
|
+
*/
|
|
26077
|
+
function interpolateExponentially(currentValue, targetValue, deltaMs, smoothingWindowMs) {
|
|
26078
|
+
const blend = 1 - Math.exp(-deltaMs / Math.max(1, smoothingWindowMs));
|
|
26079
|
+
return currentValue + (targetValue - currentValue) * blend;
|
|
26080
|
+
}
|
|
26081
|
+
|
|
26082
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
26083
|
+
/**
|
|
26084
|
+
* Active avatar instances currently consuming the shared pointer tracker.
|
|
26085
|
+
*
|
|
26086
|
+
* @private utility of the avatar rendering system
|
|
26087
|
+
*/
|
|
26088
|
+
let avatarPointerTrackingConsumerCount = 0;
|
|
26089
|
+
/**
|
|
26090
|
+
* Latest shared viewport pointer sample.
|
|
26091
|
+
*
|
|
26092
|
+
* @private utility of the avatar rendering system
|
|
26093
|
+
*/
|
|
26094
|
+
let currentAvatarPointerSnapshot = null;
|
|
26095
|
+
/**
|
|
26096
|
+
* Cleanup function for the lazily attached global listeners.
|
|
26097
|
+
*
|
|
26098
|
+
* @private utility of the avatar rendering system
|
|
26099
|
+
*/
|
|
26100
|
+
let releaseAvatarPointerTrackingListeners = null;
|
|
26101
|
+
/**
|
|
26102
|
+
* Starts the shared pointer tracker and returns a disposer for the caller.
|
|
26103
|
+
*
|
|
26104
|
+
* @returns Cleanup function that releases one consumer.
|
|
26105
|
+
*
|
|
26106
|
+
* @private utility of the avatar rendering system
|
|
26107
|
+
*/
|
|
26108
|
+
function retainAvatarPointerTracking() {
|
|
26109
|
+
avatarPointerTrackingConsumerCount++;
|
|
26110
|
+
if (avatarPointerTrackingConsumerCount === 1) {
|
|
26111
|
+
releaseAvatarPointerTrackingListeners = attachAvatarPointerTrackingListeners();
|
|
26112
|
+
}
|
|
26113
|
+
return () => {
|
|
26114
|
+
avatarPointerTrackingConsumerCount = Math.max(0, avatarPointerTrackingConsumerCount - 1);
|
|
26115
|
+
if (avatarPointerTrackingConsumerCount === 0) {
|
|
26116
|
+
currentAvatarPointerSnapshot = null;
|
|
26117
|
+
releaseAvatarPointerTrackingListeners === null || releaseAvatarPointerTrackingListeners === void 0 ? void 0 : releaseAvatarPointerTrackingListeners();
|
|
26118
|
+
releaseAvatarPointerTrackingListeners = null;
|
|
26119
|
+
}
|
|
26120
|
+
};
|
|
26121
|
+
}
|
|
26122
|
+
/**
|
|
26123
|
+
* Returns the latest shared viewport pointer sample when available.
|
|
26124
|
+
*
|
|
26125
|
+
* @returns Shared pointer snapshot or `null`.
|
|
26126
|
+
*
|
|
26127
|
+
* @private utility of the avatar rendering system
|
|
26128
|
+
*/
|
|
26129
|
+
function getAvatarPointerSnapshot() {
|
|
26130
|
+
return currentAvatarPointerSnapshot;
|
|
26131
|
+
}
|
|
26132
|
+
/**
|
|
26133
|
+
* Attaches the global pointer/touch listeners used by all live avatar canvases.
|
|
26134
|
+
*
|
|
26135
|
+
* @returns Cleanup function for the attached listeners.
|
|
26136
|
+
*
|
|
26137
|
+
* @private utility of the avatar rendering system
|
|
26138
|
+
*/
|
|
26139
|
+
function attachAvatarPointerTrackingListeners() {
|
|
26140
|
+
if (typeof window === 'undefined') {
|
|
26141
|
+
return () => undefined;
|
|
26142
|
+
}
|
|
26143
|
+
const clearPointerSnapshot = () => {
|
|
26144
|
+
currentAvatarPointerSnapshot = null;
|
|
26145
|
+
};
|
|
26146
|
+
const updatePointerSnapshot = (clientX, clientY, pointerType) => {
|
|
26147
|
+
currentAvatarPointerSnapshot = {
|
|
26148
|
+
clientX,
|
|
26149
|
+
clientY,
|
|
26150
|
+
isPointerActive: true,
|
|
26151
|
+
pointerType,
|
|
26152
|
+
};
|
|
26153
|
+
};
|
|
26154
|
+
const handlePointerMove = (event) => {
|
|
26155
|
+
updatePointerSnapshot(event.clientX, event.clientY, normalizeAvatarPointerType(event.pointerType));
|
|
26156
|
+
};
|
|
26157
|
+
const handlePointerDown = (event) => {
|
|
26158
|
+
updatePointerSnapshot(event.clientX, event.clientY, normalizeAvatarPointerType(event.pointerType));
|
|
26159
|
+
};
|
|
26160
|
+
const handlePointerUp = (event) => {
|
|
26161
|
+
if (normalizeAvatarPointerType(event.pointerType) !== 'mouse') {
|
|
26162
|
+
clearPointerSnapshot();
|
|
26163
|
+
}
|
|
26164
|
+
};
|
|
26165
|
+
const handleMouseOut = (event) => {
|
|
26166
|
+
if (!event.relatedTarget) {
|
|
26167
|
+
clearPointerSnapshot();
|
|
26168
|
+
}
|
|
26169
|
+
};
|
|
26170
|
+
const handleTouchEvent = (event) => {
|
|
26171
|
+
const touch = event.touches[0] || event.changedTouches[0];
|
|
26172
|
+
if (!touch) {
|
|
26173
|
+
clearPointerSnapshot();
|
|
26174
|
+
return;
|
|
26175
|
+
}
|
|
26176
|
+
updatePointerSnapshot(touch.clientX, touch.clientY, 'touch');
|
|
26177
|
+
};
|
|
26178
|
+
window.addEventListener('pointermove', handlePointerMove, { passive: true });
|
|
26179
|
+
window.addEventListener('pointerdown', handlePointerDown, { passive: true });
|
|
26180
|
+
window.addEventListener('pointerup', handlePointerUp, { passive: true });
|
|
26181
|
+
window.addEventListener('pointercancel', clearPointerSnapshot, { passive: true });
|
|
26182
|
+
window.addEventListener('mouseout', handleMouseOut, { passive: true });
|
|
26183
|
+
window.addEventListener('blur', clearPointerSnapshot);
|
|
26184
|
+
window.addEventListener('touchstart', handleTouchEvent, { passive: true });
|
|
26185
|
+
window.addEventListener('touchmove', handleTouchEvent, { passive: true });
|
|
26186
|
+
window.addEventListener('touchend', clearPointerSnapshot, { passive: true });
|
|
26187
|
+
window.addEventListener('touchcancel', clearPointerSnapshot, { passive: true });
|
|
26188
|
+
return () => {
|
|
26189
|
+
window.removeEventListener('pointermove', handlePointerMove);
|
|
26190
|
+
window.removeEventListener('pointerdown', handlePointerDown);
|
|
26191
|
+
window.removeEventListener('pointerup', handlePointerUp);
|
|
26192
|
+
window.removeEventListener('pointercancel', clearPointerSnapshot);
|
|
26193
|
+
window.removeEventListener('mouseout', handleMouseOut);
|
|
26194
|
+
window.removeEventListener('blur', clearPointerSnapshot);
|
|
26195
|
+
window.removeEventListener('touchstart', handleTouchEvent);
|
|
26196
|
+
window.removeEventListener('touchmove', handleTouchEvent);
|
|
26197
|
+
window.removeEventListener('touchend', clearPointerSnapshot);
|
|
26198
|
+
window.removeEventListener('touchcancel', clearPointerSnapshot);
|
|
26199
|
+
};
|
|
26200
|
+
}
|
|
26201
|
+
/**
|
|
26202
|
+
* Normalizes browser pointer-type strings into the shared avatar contract.
|
|
26203
|
+
*
|
|
26204
|
+
* @param pointerType Raw browser pointer type.
|
|
26205
|
+
* @returns Shared pointer type.
|
|
26206
|
+
*
|
|
26207
|
+
* @private utility of the avatar rendering system
|
|
26208
|
+
*/
|
|
26209
|
+
function normalizeAvatarPointerType(pointerType) {
|
|
26210
|
+
if (pointerType === 'touch' || pointerType === 'pen') {
|
|
26211
|
+
return pointerType;
|
|
26212
|
+
}
|
|
26213
|
+
return 'mouse';
|
|
26214
|
+
}
|
|
26215
|
+
|
|
25741
26216
|
/* eslint-disable no-magic-numbers */
|
|
25742
26217
|
/**
|
|
25743
26218
|
* Builds a smoothly morphing octopus-like silhouette from deterministic parameters.
|
|
@@ -25814,8 +26289,9 @@ function traceSmoothClosedPath(context, points) {
|
|
|
25814
26289
|
* @private shared geometry helper of `octopus3AvatarVisual` and `asciiOctopusAvatarVisual`
|
|
25815
26290
|
*/
|
|
25816
26291
|
function createOrganicOctopusTentacleShapes(options) {
|
|
25817
|
-
const { size, centerX, centerY, bodyRadius, horizontalStretch, tentacleCount, shapePhase, createRandom, timeMs, saltPrefix, } = options;
|
|
26292
|
+
const { size, centerX, centerY, bodyRadius, horizontalStretch, tentacleCount, shapePhase, createRandom, timeMs, saltPrefix, bodyPoints } = options;
|
|
25818
26293
|
const baseY = centerY + bodyRadius * 0.74;
|
|
26294
|
+
const lowerBodyAnchorPoints = bodyPoints ? resolveTentacleBodyAnchorPoints(bodyPoints, centerY + bodyRadius * 0.04) : null;
|
|
25819
26295
|
return Array.from({ length: tentacleCount }, (_, tentacleIndex) => {
|
|
25820
26296
|
const tentacleRandom = createRandom(`${saltPrefix}-tentacle-${tentacleIndex}`);
|
|
25821
26297
|
const spreadProgress = tentacleCount === 1 ? 0.5 : tentacleIndex / (tentacleCount - 1);
|
|
@@ -25827,10 +26303,21 @@ function createOrganicOctopusTentacleShapes(options) {
|
|
|
25827
26303
|
const curlDirection = centeredProgress === 0 ? (tentacleRandom() < 0.5 ? -1 : 1) : Math.sign(centeredProgress);
|
|
25828
26304
|
const lateralReach = centeredProgress * size * (0.1 + tentacleRandom() * 0.1) + temporalSway;
|
|
25829
26305
|
const tipReach = curlDirection * size * (0.025 + tentacleRandom() * 0.07);
|
|
25830
|
-
const
|
|
25831
|
-
|
|
25832
|
-
|
|
25833
|
-
|
|
26306
|
+
const startYOffset = Math.abs(centeredProgress) * size * 0.012 + tentacleRandom() * size * 0.01;
|
|
26307
|
+
const startPoint = lowerBodyAnchorPoints && lowerBodyAnchorPoints.length >= 2
|
|
26308
|
+
? createInsetTentacleStartPoint({
|
|
26309
|
+
bodyPoints: lowerBodyAnchorPoints,
|
|
26310
|
+
anchorProgress: spreadProgress,
|
|
26311
|
+
centerX,
|
|
26312
|
+
centerY,
|
|
26313
|
+
bodyRadius,
|
|
26314
|
+
centeredProgress,
|
|
26315
|
+
startYOffset,
|
|
26316
|
+
})
|
|
26317
|
+
: {
|
|
26318
|
+
x: centerX + centeredProgress * bodyRadius * horizontalStretch * 1.52,
|
|
26319
|
+
y: baseY + startYOffset,
|
|
26320
|
+
};
|
|
25834
26321
|
const controlPointOne = {
|
|
25835
26322
|
x: startPoint.x + centeredProgress * size * 0.045 + temporalSway * 0.4,
|
|
25836
26323
|
y: startPoint.y + flowLength * (0.21 + tentacleRandom() * 0.08),
|
|
@@ -25860,6 +26347,67 @@ function createOrganicOctopusTentacleShapes(options) {
|
|
|
25860
26347
|
};
|
|
25861
26348
|
});
|
|
25862
26349
|
}
|
|
26350
|
+
/**
|
|
26351
|
+
* Narrows the body contour to lower anchor points that can safely host tentacle roots.
|
|
26352
|
+
*
|
|
26353
|
+
* @param bodyPoints Generated closed-loop body points.
|
|
26354
|
+
* @param lowerBodyThresholdY Minimum Y coordinate considered part of the lower mantle.
|
|
26355
|
+
* @returns Body points sorted from left to right across the lower silhouette.
|
|
26356
|
+
*
|
|
26357
|
+
* @private shared geometry helper of `octopus3AvatarVisual`
|
|
26358
|
+
*/
|
|
26359
|
+
function resolveTentacleBodyAnchorPoints(bodyPoints, lowerBodyThresholdY) {
|
|
26360
|
+
const lowerBodyPoints = bodyPoints.filter((bodyPoint) => bodyPoint.y >= lowerBodyThresholdY).sort((leftPoint, rightPoint) => leftPoint.x - rightPoint.x);
|
|
26361
|
+
if (lowerBodyPoints.length >= 2) {
|
|
26362
|
+
return lowerBodyPoints;
|
|
26363
|
+
}
|
|
26364
|
+
return [...bodyPoints].sort((leftPoint, rightPoint) => leftPoint.x - rightPoint.x);
|
|
26365
|
+
}
|
|
26366
|
+
/**
|
|
26367
|
+
* Resolves one tentacle root from the provided lower body contour and nudges it inside the mantle.
|
|
26368
|
+
*
|
|
26369
|
+
* @param options Tentacle anchor options.
|
|
26370
|
+
* @returns Tentacle start point safely embedded inside the body silhouette.
|
|
26371
|
+
*
|
|
26372
|
+
* @private shared geometry helper of `octopus3AvatarVisual`
|
|
26373
|
+
*/
|
|
26374
|
+
function createInsetTentacleStartPoint(options) {
|
|
26375
|
+
const { bodyPoints, anchorProgress, centerX, centerY, bodyRadius, centeredProgress, startYOffset } = options;
|
|
26376
|
+
const clampedAnchorProgress = Math.min(0.94, Math.max(0.06, anchorProgress));
|
|
26377
|
+
const bodyAnchorPoint = interpolatePointAlongTentacleAnchors(bodyPoints, clampedAnchorProgress);
|
|
26378
|
+
const inwardX = centerX - bodyAnchorPoint.x;
|
|
26379
|
+
const inwardY = centerY + bodyRadius * 0.08 - bodyAnchorPoint.y;
|
|
26380
|
+
const inwardLength = Math.hypot(inwardX, inwardY) || 1;
|
|
26381
|
+
const insetDistance = bodyRadius * (0.12 + Math.abs(centeredProgress) * 0.05) + startYOffset * 0.32;
|
|
26382
|
+
return {
|
|
26383
|
+
x: bodyAnchorPoint.x + (inwardX / inwardLength) * insetDistance,
|
|
26384
|
+
y: bodyAnchorPoint.y + (inwardY / inwardLength) * insetDistance,
|
|
26385
|
+
};
|
|
26386
|
+
}
|
|
26387
|
+
/**
|
|
26388
|
+
* Interpolates one left-to-right anchor point along the prepared lower body contour.
|
|
26389
|
+
*
|
|
26390
|
+
* @param bodyPoints Lower body contour points sorted from left to right.
|
|
26391
|
+
* @param progress Interpolation progress in the range `[0, 1]`.
|
|
26392
|
+
* @returns Interpolated anchor point.
|
|
26393
|
+
*
|
|
26394
|
+
* @private shared geometry helper of `octopus3AvatarVisual`
|
|
26395
|
+
*/
|
|
26396
|
+
function interpolatePointAlongTentacleAnchors(bodyPoints, progress) {
|
|
26397
|
+
if (bodyPoints.length === 1) {
|
|
26398
|
+
return bodyPoints[0];
|
|
26399
|
+
}
|
|
26400
|
+
const anchorIndex = progress * (bodyPoints.length - 1);
|
|
26401
|
+
const startIndex = Math.floor(anchorIndex);
|
|
26402
|
+
const endIndex = Math.min(bodyPoints.length - 1, startIndex + 1);
|
|
26403
|
+
const blend = anchorIndex - startIndex;
|
|
26404
|
+
const startPoint = bodyPoints[startIndex];
|
|
26405
|
+
const endPoint = bodyPoints[endIndex];
|
|
26406
|
+
return {
|
|
26407
|
+
x: startPoint.x + (endPoint.x - startPoint.x) * blend,
|
|
26408
|
+
y: startPoint.y + (endPoint.y - startPoint.y) * blend,
|
|
26409
|
+
};
|
|
26410
|
+
}
|
|
25863
26411
|
/**
|
|
25864
26412
|
* Samples the cubic tentacle centerline and offsets normals to build a filled ribbon.
|
|
25865
26413
|
*
|
|
@@ -25889,6 +26437,26 @@ function sampleOrganicTentacleRibbonPoints(tentacleShape) {
|
|
|
25889
26437
|
};
|
|
25890
26438
|
});
|
|
25891
26439
|
}
|
|
26440
|
+
/**
|
|
26441
|
+
* Resolves smooth pupil offsets that blend autonomous idle drift with live viewer tracking.
|
|
26442
|
+
*
|
|
26443
|
+
* @param options Eye motion options.
|
|
26444
|
+
* @returns Resolved pupil offsets.
|
|
26445
|
+
*
|
|
26446
|
+
* @private shared geometry helper of octopus avatar visuals
|
|
26447
|
+
*/
|
|
26448
|
+
function resolveOrganicEyeMotion(options) {
|
|
26449
|
+
const { radiusX, radiusY, timeMs, phase, interaction, autonomousDriftRatioX = 0.12, autonomousDriftRatioY = 0.08, } = options;
|
|
26450
|
+
const autonomousOffsetX = Math.sin(timeMs / 1280 + phase) * radiusX * autonomousDriftRatioX;
|
|
26451
|
+
const autonomousOffsetY = Math.cos(timeMs / 940 + phase) * radiusY * autonomousDriftRatioY;
|
|
26452
|
+
const interactionBlend = Math.min(1, interaction.intensity * 0.9);
|
|
26453
|
+
return {
|
|
26454
|
+
pupilOffsetX: autonomousOffsetX * (1 - interactionBlend) +
|
|
26455
|
+
interaction.gazeX * radiusX * (0.18 + interactionBlend * 0.18),
|
|
26456
|
+
pupilOffsetY: autonomousOffsetY * (1 - interactionBlend) +
|
|
26457
|
+
interaction.gazeY * radiusY * (0.16 + interactionBlend * 0.16),
|
|
26458
|
+
};
|
|
26459
|
+
}
|
|
25892
26460
|
/**
|
|
25893
26461
|
* Samples one point on a cubic Bezier curve.
|
|
25894
26462
|
*
|
|
@@ -25942,13 +26510,14 @@ const ATMOSPHERE_GLYPHS = ['.', ':', '\'', '`'];
|
|
|
25942
26510
|
const asciiOctopusAvatarVisual = {
|
|
25943
26511
|
id: 'ascii-octopus',
|
|
25944
26512
|
title: 'AsciiOctopus',
|
|
25945
|
-
description: 'Morphing alien octopus translated into animated ASCII glyphs with
|
|
26513
|
+
description: 'Morphing alien octopus translated into animated ASCII glyphs with responsive eyes and seeded geometry.',
|
|
25946
26514
|
isAnimated: true,
|
|
25947
|
-
|
|
26515
|
+
supportsPointerTracking: true,
|
|
26516
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
25948
26517
|
const gridRandom = createRandom('ascii-octopus-grid');
|
|
25949
26518
|
const staticRandom = createRandom('ascii-octopus-static');
|
|
25950
26519
|
const gridMetrics = createAsciiGridMetrics(size, gridRandom);
|
|
25951
|
-
const layout = createAsciiOctopusLayout(size, timeMs, createRandom, staticRandom);
|
|
26520
|
+
const layout = createAsciiOctopusLayout(size, timeMs, createRandom, staticRandom, interaction);
|
|
25952
26521
|
drawAvatarFrame(context, size, palette);
|
|
25953
26522
|
drawAsciiBackdrop(context, size, palette, layout, timeMs);
|
|
25954
26523
|
context.save();
|
|
@@ -26022,7 +26591,8 @@ function drawAsciiBackdrop(context, size, palette, layout, timeMs) {
|
|
|
26022
26591
|
*/
|
|
26023
26592
|
function resolveAsciiGlyph(options) {
|
|
26024
26593
|
const { point, layout, palette, cellWidth, cellHeight, noise, timeMs } = options;
|
|
26025
|
-
const eyeGlyphDescriptor = resolveEyeGlyph(point, layout.leftEye,
|
|
26594
|
+
const eyeGlyphDescriptor = resolveEyeGlyph(point, layout.leftEye, layout.interaction, palette, timeMs) ||
|
|
26595
|
+
resolveEyeGlyph(point, layout.rightEye, layout.interaction, palette, timeMs);
|
|
26026
26596
|
if (eyeGlyphDescriptor) {
|
|
26027
26597
|
return eyeGlyphDescriptor;
|
|
26028
26598
|
}
|
|
@@ -26067,9 +26637,14 @@ function resolveAsciiGlyph(options) {
|
|
|
26067
26637
|
*
|
|
26068
26638
|
* @private helper of `asciiOctopusAvatarVisual`
|
|
26069
26639
|
*/
|
|
26070
|
-
function resolveEyeGlyph(point, eyeFeature, palette, timeMs) {
|
|
26071
|
-
const pupilOffsetX =
|
|
26072
|
-
|
|
26640
|
+
function resolveEyeGlyph(point, eyeFeature, interaction, palette, timeMs) {
|
|
26641
|
+
const { pupilOffsetX, pupilOffsetY } = resolveOrganicEyeMotion({
|
|
26642
|
+
radiusX: eyeFeature.radiusX,
|
|
26643
|
+
radiusY: eyeFeature.radiusY,
|
|
26644
|
+
timeMs,
|
|
26645
|
+
phase: eyeFeature.phase,
|
|
26646
|
+
interaction,
|
|
26647
|
+
});
|
|
26073
26648
|
const scleraDistance = measureRotatedEllipseDistance(point, eyeFeature.centerX, eyeFeature.centerY, eyeFeature.radiusX, eyeFeature.radiusY, eyeFeature.rotation);
|
|
26074
26649
|
if (scleraDistance > 1.08) {
|
|
26075
26650
|
return null;
|
|
@@ -26243,9 +26818,9 @@ function createAsciiGridMetrics(size, staticRandom) {
|
|
|
26243
26818
|
*
|
|
26244
26819
|
* @private helper of `asciiOctopusAvatarVisual`
|
|
26245
26820
|
*/
|
|
26246
|
-
function createAsciiOctopusLayout(size, timeMs, createRandom, staticRandom) {
|
|
26247
|
-
const centerX = size * (0.5 + (staticRandom() - 0.5) * 0.02);
|
|
26248
|
-
const centerY = size * (0.41 + staticRandom() * 0.05);
|
|
26821
|
+
function createAsciiOctopusLayout(size, timeMs, createRandom, staticRandom, interaction) {
|
|
26822
|
+
const centerX = size * (0.5 + (staticRandom() - 0.5) * 0.02) + interaction.bodyOffsetX * size * 0.05;
|
|
26823
|
+
const centerY = size * (0.41 + staticRandom() * 0.05) + interaction.bodyOffsetY * size * 0.035;
|
|
26249
26824
|
const bodyRadius = size * (0.195 + staticRandom() * 0.05);
|
|
26250
26825
|
const horizontalStretch = 1.08 + staticRandom() * 0.22;
|
|
26251
26826
|
const verticalStretch = 0.88 + staticRandom() * 0.14;
|
|
@@ -26285,6 +26860,7 @@ function createAsciiOctopusLayout(size, timeMs, createRandom, staticRandom) {
|
|
|
26285
26860
|
createRandom,
|
|
26286
26861
|
timeMs,
|
|
26287
26862
|
saltPrefix: 'ascii-octopus',
|
|
26863
|
+
bodyPoints,
|
|
26288
26864
|
});
|
|
26289
26865
|
const sampledTentacles = tentacleShapes.map(sampleOrganicTentacleRibbonPoints);
|
|
26290
26866
|
const leftEye = {
|
|
@@ -26305,7 +26881,7 @@ function createAsciiOctopusLayout(size, timeMs, createRandom, staticRandom) {
|
|
|
26305
26881
|
};
|
|
26306
26882
|
const mouthPoints = sampleQuadraticBezierPoints({ x: centerX - size * 0.074, y: centerY + size * 0.092 }, {
|
|
26307
26883
|
x: centerX,
|
|
26308
|
-
y: centerY + size * (0.142 + Math.sin(timeMs / 620 + shapePhase) * 0.016),
|
|
26884
|
+
y: centerY + size * (0.142 + Math.sin(timeMs / 620 + shapePhase) * 0.016) + interaction.gazeY * size * 0.012,
|
|
26309
26885
|
}, { x: centerX + size * 0.074, y: centerY + size * 0.092 }, 12);
|
|
26310
26886
|
let leftBound = Number.POSITIVE_INFINITY;
|
|
26311
26887
|
let rightBound = Number.NEGATIVE_INFINITY;
|
|
@@ -26331,6 +26907,7 @@ function createAsciiOctopusLayout(size, timeMs, createRandom, staticRandom) {
|
|
|
26331
26907
|
bodyRadius,
|
|
26332
26908
|
horizontalStretch,
|
|
26333
26909
|
shapePhase,
|
|
26910
|
+
interaction,
|
|
26334
26911
|
bodyPoints,
|
|
26335
26912
|
sampledTentacles,
|
|
26336
26913
|
leftEye,
|
|
@@ -27051,15 +27628,16 @@ function createMinecraftShirtTexture(random, palette) {
|
|
|
27051
27628
|
const octopusAvatarVisual = {
|
|
27052
27629
|
id: 'octopus',
|
|
27053
27630
|
title: 'Octopus',
|
|
27054
|
-
description: 'Playful underwater mascot with animated tentacles, bubbles, and
|
|
27631
|
+
description: 'Playful underwater mascot with cursor-following eyes, animated tentacles, bubbles, and seeded markings.',
|
|
27055
27632
|
isAnimated: true,
|
|
27056
|
-
|
|
27633
|
+
supportsPointerTracking: true,
|
|
27634
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
27057
27635
|
const staticRandom = createRandom('octopus-static');
|
|
27058
27636
|
const bubbleRandom = createRandom('octopus-bubbles');
|
|
27059
27637
|
const bubbleCount = 8;
|
|
27060
27638
|
const bubbleRadiusBase = size * 0.02;
|
|
27061
|
-
const centerX = size * 0.5;
|
|
27062
|
-
const centerY = size * 0.42;
|
|
27639
|
+
const centerX = size * 0.5 + interaction.bodyOffsetX * size * 0.035;
|
|
27640
|
+
const centerY = size * 0.42 + interaction.bodyOffsetY * size * 0.024;
|
|
27063
27641
|
const headRadius = size * (0.19 + staticRandom() * 0.03);
|
|
27064
27642
|
const mantleHeight = headRadius * 1.18;
|
|
27065
27643
|
const tentacleLength = size * (0.18 + staticRandom() * 0.06);
|
|
@@ -27139,11 +27717,9 @@ const octopusAvatarVisual = {
|
|
|
27139
27717
|
}
|
|
27140
27718
|
const eyeOffsetX = headRadius * 0.42;
|
|
27141
27719
|
const eyeY = centerY + headRadius * 0.04;
|
|
27142
|
-
const pupilDriftX = Math.sin(timeMs / 850) * headRadius * 0.05;
|
|
27143
|
-
const pupilDriftY = Math.cos(timeMs / 930) * headRadius * 0.03;
|
|
27144
27720
|
const eyeRadius = headRadius * 0.22;
|
|
27145
|
-
drawEye(context, centerX - eyeOffsetX, eyeY, eyeRadius, palette,
|
|
27146
|
-
drawEye(context, centerX + eyeOffsetX, eyeY, eyeRadius, palette,
|
|
27721
|
+
drawEye(context, centerX - eyeOffsetX, eyeY, eyeRadius, palette, timeMs, interaction, 0);
|
|
27722
|
+
drawEye(context, centerX + eyeOffsetX, eyeY, eyeRadius, palette, timeMs, interaction, Math.PI / 5);
|
|
27147
27723
|
context.beginPath();
|
|
27148
27724
|
context.arc(centerX - headRadius * 0.28, centerY + headRadius * 0.3, headRadius * 0.12, 0, Math.PI * 2);
|
|
27149
27725
|
context.arc(centerX + headRadius * 0.28, centerY + headRadius * 0.3, headRadius * 0.12, 0, Math.PI * 2);
|
|
@@ -27166,22 +27742,32 @@ const octopusAvatarVisual = {
|
|
|
27166
27742
|
* @param centerY Eye center Y coordinate.
|
|
27167
27743
|
* @param radius Eye radius.
|
|
27168
27744
|
* @param palette Derived avatar palette.
|
|
27169
|
-
* @param
|
|
27170
|
-
* @param
|
|
27745
|
+
* @param timeMs Current animation time in milliseconds.
|
|
27746
|
+
* @param interaction Smoothed avatar interaction state.
|
|
27747
|
+
* @param phase Seed-based phase offset.
|
|
27171
27748
|
*
|
|
27172
27749
|
* @private helper of `octopusAvatarVisual`
|
|
27173
27750
|
*/
|
|
27174
|
-
function drawEye(context, centerX, centerY, radius, palette,
|
|
27751
|
+
function drawEye(context, centerX, centerY, radius, palette, timeMs, interaction, phase) {
|
|
27752
|
+
const { pupilOffsetX, pupilOffsetY } = resolveOrganicEyeMotion({
|
|
27753
|
+
radiusX: radius,
|
|
27754
|
+
radiusY: radius,
|
|
27755
|
+
timeMs,
|
|
27756
|
+
phase,
|
|
27757
|
+
interaction,
|
|
27758
|
+
autonomousDriftRatioX: 0.05,
|
|
27759
|
+
autonomousDriftRatioY: 0.03,
|
|
27760
|
+
});
|
|
27175
27761
|
context.beginPath();
|
|
27176
27762
|
context.arc(centerX, centerY, radius, 0, Math.PI * 2);
|
|
27177
27763
|
context.fillStyle = '#ffffff';
|
|
27178
27764
|
context.fill();
|
|
27179
27765
|
context.beginPath();
|
|
27180
|
-
context.arc(centerX +
|
|
27766
|
+
context.arc(centerX + pupilOffsetX, centerY + pupilOffsetY, radius * 0.45, 0, Math.PI * 2);
|
|
27181
27767
|
context.fillStyle = palette.ink;
|
|
27182
27768
|
context.fill();
|
|
27183
27769
|
context.beginPath();
|
|
27184
|
-
context.arc(centerX +
|
|
27770
|
+
context.arc(centerX + pupilOffsetX - radius * 0.12, centerY + pupilOffsetY - radius * 0.12, radius * 0.15, 0, Math.PI * 2);
|
|
27185
27771
|
context.fillStyle = '#ffffff';
|
|
27186
27772
|
context.fill();
|
|
27187
27773
|
context.beginPath();
|
|
@@ -27200,12 +27786,13 @@ function drawEye(context, centerX, centerY, radius, palette, pupilDriftX, pupilD
|
|
|
27200
27786
|
const octopus2AvatarVisual = {
|
|
27201
27787
|
id: 'octopus2',
|
|
27202
27788
|
title: 'Octopus2',
|
|
27203
|
-
description: 'Organic alien octopus rendered as one continuously morphing blob with luminous eyes
|
|
27789
|
+
description: 'Organic alien octopus rendered as one continuously morphing blob with responsive luminous eyes.',
|
|
27204
27790
|
isAnimated: true,
|
|
27205
|
-
|
|
27791
|
+
supportsPointerTracking: true,
|
|
27792
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
27206
27793
|
const staticRandom = createRandom('octopus2-static');
|
|
27207
|
-
const centerX = size * 0.5;
|
|
27208
|
-
const centerY = size * (0.48 + staticRandom() * 0.03);
|
|
27794
|
+
const centerX = size * 0.5 + interaction.bodyOffsetX * size * 0.042;
|
|
27795
|
+
const centerY = size * (0.48 + staticRandom() * 0.03) + interaction.bodyOffsetY * size * 0.028;
|
|
27209
27796
|
const bodyRadius = size * (0.25 + staticRandom() * 0.035);
|
|
27210
27797
|
const horizontalStretch = 1.04 + staticRandom() * 0.16;
|
|
27211
27798
|
const verticalStretch = 0.94 + staticRandom() * 0.12;
|
|
@@ -27276,11 +27863,11 @@ const octopus2AvatarVisual = {
|
|
|
27276
27863
|
const eyeCenterY = centerY - size * 0.02;
|
|
27277
27864
|
const eyeRadiusX = size * 0.072;
|
|
27278
27865
|
const eyeRadiusY = size * 0.086;
|
|
27279
|
-
drawAlienEye(context, centerX - eyeOffsetX, eyeCenterY, eyeRadiusX, eyeRadiusY, palette, timeMs, shapePhase);
|
|
27280
|
-
drawAlienEye(context, centerX + eyeOffsetX, eyeCenterY, eyeRadiusX, eyeRadiusY, palette, timeMs, shapePhase + Math.PI / 5);
|
|
27866
|
+
drawAlienEye(context, centerX - eyeOffsetX, eyeCenterY, eyeRadiusX, eyeRadiusY, palette, timeMs, shapePhase, interaction);
|
|
27867
|
+
drawAlienEye(context, centerX + eyeOffsetX, eyeCenterY, eyeRadiusX, eyeRadiusY, palette, timeMs, shapePhase + Math.PI / 5, interaction);
|
|
27281
27868
|
context.beginPath();
|
|
27282
27869
|
context.moveTo(centerX - size * 0.08, centerY + size * 0.12);
|
|
27283
|
-
context.quadraticCurveTo(centerX, centerY + size * (0.175 + Math.sin(timeMs / 520 + shapePhase) * 0.012), centerX + size * 0.08, centerY + size * 0.12);
|
|
27870
|
+
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);
|
|
27284
27871
|
context.strokeStyle = `${palette.ink}b3`;
|
|
27285
27872
|
context.lineWidth = size * 0.013;
|
|
27286
27873
|
context.lineCap = 'round';
|
|
@@ -27358,12 +27945,19 @@ function drawLowerSuckers(context, centerX, centerY, size, palette, createRandom
|
|
|
27358
27945
|
* @param palette Derived avatar palette.
|
|
27359
27946
|
* @param timeMs Current animation time in milliseconds.
|
|
27360
27947
|
* @param phase Seed-based animation phase.
|
|
27948
|
+
* @param interaction Smoothed avatar interaction state.
|
|
27361
27949
|
*
|
|
27362
27950
|
* @private helper of `octopus2AvatarVisual`
|
|
27363
27951
|
*/
|
|
27364
|
-
function drawAlienEye(context, centerX, centerY, radiusX, radiusY, palette, timeMs, phase) {
|
|
27365
|
-
const pupilOffsetX =
|
|
27366
|
-
|
|
27952
|
+
function drawAlienEye(context, centerX, centerY, radiusX, radiusY, palette, timeMs, phase, interaction) {
|
|
27953
|
+
const { pupilOffsetX, pupilOffsetY } = resolveOrganicEyeMotion({
|
|
27954
|
+
radiusX,
|
|
27955
|
+
radiusY,
|
|
27956
|
+
timeMs,
|
|
27957
|
+
phase,
|
|
27958
|
+
interaction,
|
|
27959
|
+
autonomousDriftRatioY: 0.1,
|
|
27960
|
+
});
|
|
27367
27961
|
context.save();
|
|
27368
27962
|
context.beginPath();
|
|
27369
27963
|
context.ellipse(centerX, centerY, radiusX, radiusY, 0, 0, Math.PI * 2);
|
|
@@ -27403,12 +27997,13 @@ function drawAlienEye(context, centerX, centerY, radiusX, radiusY, palette, time
|
|
|
27403
27997
|
const octopus3AvatarVisual = {
|
|
27404
27998
|
id: 'octopus3',
|
|
27405
27999
|
title: 'Octopus3',
|
|
27406
|
-
description: 'Gelatinous alien octopus with a morphing mantle,
|
|
28000
|
+
description: 'Gelatinous alien octopus with a morphing mantle, responsive eyes, and visible ribbon tentacles.',
|
|
27407
28001
|
isAnimated: true,
|
|
27408
|
-
|
|
28002
|
+
supportsPointerTracking: true,
|
|
28003
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
27409
28004
|
const staticRandom = createRandom('octopus3-static');
|
|
27410
|
-
const centerX = size * (0.5 + (staticRandom() - 0.5) * 0.02);
|
|
27411
|
-
const centerY = size * (0.41 + staticRandom() * 0.05);
|
|
28005
|
+
const centerX = size * (0.5 + (staticRandom() - 0.5) * 0.02) + interaction.bodyOffsetX * size * 0.05;
|
|
28006
|
+
const centerY = size * (0.41 + staticRandom() * 0.05) + interaction.bodyOffsetY * size * 0.035;
|
|
27412
28007
|
const bodyRadius = size * (0.2 + staticRandom() * 0.045);
|
|
27413
28008
|
const horizontalStretch = 1.08 + staticRandom() * 0.22;
|
|
27414
28009
|
const verticalStretch = 0.9 + staticRandom() * 0.12;
|
|
@@ -27448,6 +28043,7 @@ const octopus3AvatarVisual = {
|
|
|
27448
28043
|
createRandom,
|
|
27449
28044
|
timeMs,
|
|
27450
28045
|
saltPrefix: 'octopus3',
|
|
28046
|
+
bodyPoints,
|
|
27451
28047
|
});
|
|
27452
28048
|
drawAvatarFrame(context, size, palette);
|
|
27453
28049
|
drawOctopus3Atmosphere(context, size, palette, centerX, centerY, timeMs, shapePhase);
|
|
@@ -27493,11 +28089,11 @@ const octopus3AvatarVisual = {
|
|
|
27493
28089
|
context.ellipse(centerX, centerY - size * 0.14, size * 0.18, size * 0.062, 0, Math.PI, Math.PI * 2);
|
|
27494
28090
|
context.fillStyle = `${palette.highlight}3d`;
|
|
27495
28091
|
context.fill();
|
|
27496
|
-
drawSeededEye(context, centerX - eyeSpacing, centerY - size * 0.01, eyeRadiusX, eyeRadiusY, (staticRandom() - 0.5) * 0.28, palette, timeMs, shapePhase);
|
|
27497
|
-
drawSeededEye(context, centerX + eyeSpacing, centerY - size * 0.01, eyeRadiusX, eyeRadiusY, (staticRandom() - 0.5) * 0.28, palette, timeMs, shapePhase + Math.PI / 4);
|
|
28092
|
+
drawSeededEye(context, centerX - eyeSpacing, centerY - size * 0.01, eyeRadiusX, eyeRadiusY, (staticRandom() - 0.5) * 0.28, palette, timeMs, shapePhase, interaction);
|
|
28093
|
+
drawSeededEye(context, centerX + eyeSpacing, centerY - size * 0.01, eyeRadiusX, eyeRadiusY, (staticRandom() - 0.5) * 0.28, palette, timeMs, shapePhase + Math.PI / 4, interaction);
|
|
27498
28094
|
context.beginPath();
|
|
27499
28095
|
context.moveTo(centerX - size * 0.07, centerY + size * 0.09);
|
|
27500
|
-
context.quadraticCurveTo(centerX, centerY + size * (0.14 + Math.sin(timeMs / 620 + shapePhase) * 0.016), centerX + size * 0.07, centerY + size * 0.09);
|
|
28096
|
+
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);
|
|
27501
28097
|
context.strokeStyle = `${palette.ink}b3`;
|
|
27502
28098
|
context.lineWidth = size * 0.012;
|
|
27503
28099
|
context.lineCap = 'round';
|
|
@@ -27685,12 +28281,18 @@ function drawMantleNodes(context, centerX, centerY, size, palette, createRandom)
|
|
|
27685
28281
|
* @param palette Derived avatar palette.
|
|
27686
28282
|
* @param timeMs Current animation time in milliseconds.
|
|
27687
28283
|
* @param phase Seed-based animation phase.
|
|
28284
|
+
* @param interaction Smoothed avatar interaction state.
|
|
27688
28285
|
*
|
|
27689
28286
|
* @private helper of `octopus3AvatarVisual`
|
|
27690
28287
|
*/
|
|
27691
|
-
function drawSeededEye(context, centerX, centerY, radiusX, radiusY, rotation, palette, timeMs, phase) {
|
|
27692
|
-
const pupilOffsetX =
|
|
27693
|
-
|
|
28288
|
+
function drawSeededEye(context, centerX, centerY, radiusX, radiusY, rotation, palette, timeMs, phase, interaction) {
|
|
28289
|
+
const { pupilOffsetX, pupilOffsetY } = resolveOrganicEyeMotion({
|
|
28290
|
+
radiusX,
|
|
28291
|
+
radiusY,
|
|
28292
|
+
timeMs,
|
|
28293
|
+
phase,
|
|
28294
|
+
interaction,
|
|
28295
|
+
});
|
|
27694
28296
|
context.save();
|
|
27695
28297
|
context.translate(centerX, centerY);
|
|
27696
28298
|
context.rotate(rotation);
|
|
@@ -27726,7 +28328,7 @@ function drawSeededEye(context, centerX, centerY, radiusX, radiusY, rotation, pa
|
|
|
27726
28328
|
context.stroke();
|
|
27727
28329
|
context.beginPath();
|
|
27728
28330
|
context.moveTo(-radiusX * 0.88, -radiusY * 0.08);
|
|
27729
|
-
context.quadraticCurveTo(0, -radiusY * 0.9, radiusX * 0.88, -radiusY * 0.08);
|
|
28331
|
+
context.quadraticCurveTo(0, -radiusY * (0.9 - interaction.gazeY * 0.16 + interaction.intensity * 0.08), radiusX * 0.88, -radiusY * 0.08);
|
|
27730
28332
|
context.strokeStyle = `${palette.shadow}73`;
|
|
27731
28333
|
context.lineWidth = radiusX * 0.16;
|
|
27732
28334
|
context.lineCap = 'round';
|
|
@@ -27874,6 +28476,7 @@ function getAvatarVisualById(visualId) {
|
|
|
27874
28476
|
function renderAvatarVisual(options) {
|
|
27875
28477
|
const normalizedAvatarDefinition = normalizeAvatarDefinition(options.avatarDefinition);
|
|
27876
28478
|
const avatarVisual = getAvatarVisualById(options.visualId);
|
|
28479
|
+
const surface = options.surface || 'framed';
|
|
27877
28480
|
const context = options.canvas.getContext('2d');
|
|
27878
28481
|
if (!context) {
|
|
27879
28482
|
throw new Error('2D canvas rendering context is unavailable.');
|
|
@@ -27886,8 +28489,10 @@ function renderAvatarVisual(options) {
|
|
|
27886
28489
|
devicePixelRatio: options.devicePixelRatio || 1,
|
|
27887
28490
|
timeMs: options.timeMs,
|
|
27888
28491
|
avatarDefinition: normalizedAvatarDefinition,
|
|
27889
|
-
palette: createAvatarPalette(normalizedAvatarDefinition),
|
|
28492
|
+
palette: createAvatarPalette(normalizedAvatarDefinition, surface),
|
|
27890
28493
|
createRandom: createAvatarRandomFactory(normalizedAvatarDefinition),
|
|
28494
|
+
surface,
|
|
28495
|
+
interaction: options.interaction || createIdleAvatarInteractionState(),
|
|
27891
28496
|
});
|
|
27892
28497
|
}
|
|
27893
28498
|
|
|
@@ -27903,42 +28508,74 @@ const AVATAR_CANVAS_RADIUS_RATIO = 0.18;
|
|
|
27903
28508
|
* @private shared component for in-repository avatar previews
|
|
27904
28509
|
*/
|
|
27905
28510
|
function Avatar(props) {
|
|
27906
|
-
const { avatarDefinition, visualId, size = DEFAULT_AVATAR_SIZE, title, className, style } = props;
|
|
28511
|
+
const { avatarDefinition, visualId, surface = 'framed', size = DEFAULT_AVATAR_SIZE, title, className, style } = props;
|
|
27907
28512
|
const canvasRef = useRef(null);
|
|
27908
|
-
const
|
|
28513
|
+
const animationStartRef = useRef(null);
|
|
28514
|
+
const interactionRuntimeStateRef = useRef(createAvatarInteractionRuntimeState());
|
|
28515
|
+
const avatarColorsKey = avatarDefinition.colors.join('|');
|
|
28516
|
+
const normalizedAvatarDefinition = useMemo(() => normalizeAvatarDefinition(avatarDefinition), [avatarDefinition.agentHash, avatarDefinition.agentName, avatarColorsKey]);
|
|
28517
|
+
const avatarDefinitionKey = useMemo(() => createAvatarDefinitionKey(normalizedAvatarDefinition), [normalizedAvatarDefinition.agentHash, normalizedAvatarDefinition.agentName, normalizedAvatarDefinition.colors.join('|')]);
|
|
27909
28518
|
const avatarVisual = useMemo(() => getAvatarVisualById(visualId), [visualId]);
|
|
28519
|
+
useEffect(() => {
|
|
28520
|
+
interactionRuntimeStateRef.current = createAvatarInteractionRuntimeState();
|
|
28521
|
+
}, [avatarDefinitionKey, visualId]);
|
|
27910
28522
|
useEffect(() => {
|
|
27911
28523
|
const canvas = canvasRef.current;
|
|
27912
28524
|
if (!canvas) {
|
|
27913
28525
|
throw new Error('Avatar canvas is not mounted.');
|
|
27914
28526
|
}
|
|
28527
|
+
const isDynamicAvatar = avatarVisual.isAnimated || avatarVisual.supportsPointerTracking === true;
|
|
28528
|
+
const releasePointerTracking = avatarVisual.supportsPointerTracking ? retainAvatarPointerTracking() : null;
|
|
27915
28529
|
let animationFrameId = null;
|
|
27916
|
-
|
|
28530
|
+
if (animationStartRef.current === null) {
|
|
28531
|
+
animationStartRef.current = performance.now();
|
|
28532
|
+
}
|
|
27917
28533
|
const renderFrame = (now) => {
|
|
28534
|
+
const pointerSnapshot = avatarVisual.supportsPointerTracking ? getAvatarPointerSnapshot() : null;
|
|
28535
|
+
let interactionState = createIdleAvatarInteractionState();
|
|
28536
|
+
if (avatarVisual.supportsPointerTracking && pointerSnapshot) {
|
|
28537
|
+
interactionRuntimeStateRef.current = stepAvatarInteractionRuntimeState(interactionRuntimeStateRef.current, resolveAvatarPointerTarget(canvas.getBoundingClientRect(), pointerSnapshot), now);
|
|
28538
|
+
interactionState = interactionRuntimeStateRef.current;
|
|
28539
|
+
}
|
|
28540
|
+
else if (avatarVisual.supportsPointerTracking) {
|
|
28541
|
+
interactionRuntimeStateRef.current = stepAvatarInteractionRuntimeState(interactionRuntimeStateRef.current, createIdleAvatarInteractionState(), now);
|
|
28542
|
+
interactionState = interactionRuntimeStateRef.current;
|
|
28543
|
+
}
|
|
27918
28544
|
renderAvatarVisual({
|
|
27919
28545
|
canvas,
|
|
27920
28546
|
avatarDefinition: normalizedAvatarDefinition,
|
|
27921
28547
|
visualId,
|
|
28548
|
+
surface,
|
|
27922
28549
|
size,
|
|
27923
|
-
timeMs: now -
|
|
28550
|
+
timeMs: now - animationStartRef.current,
|
|
27924
28551
|
devicePixelRatio: window.devicePixelRatio || 1,
|
|
28552
|
+
interaction: interactionState,
|
|
27925
28553
|
});
|
|
27926
|
-
if (
|
|
28554
|
+
if (isDynamicAvatar) {
|
|
27927
28555
|
animationFrameId = window.requestAnimationFrame(renderFrame);
|
|
27928
28556
|
}
|
|
27929
28557
|
};
|
|
27930
|
-
renderFrame(
|
|
28558
|
+
renderFrame(performance.now());
|
|
27931
28559
|
return () => {
|
|
27932
28560
|
if (animationFrameId !== null) {
|
|
27933
28561
|
window.cancelAnimationFrame(animationFrameId);
|
|
27934
28562
|
}
|
|
28563
|
+
releasePointerTracking === null || releasePointerTracking === void 0 ? void 0 : releasePointerTracking();
|
|
27935
28564
|
};
|
|
27936
|
-
}, [
|
|
28565
|
+
}, [
|
|
28566
|
+
avatarDefinitionKey,
|
|
28567
|
+
avatarVisual.isAnimated,
|
|
28568
|
+
avatarVisual.supportsPointerTracking,
|
|
28569
|
+
normalizedAvatarDefinition,
|
|
28570
|
+
size,
|
|
28571
|
+
surface,
|
|
28572
|
+
visualId,
|
|
28573
|
+
]);
|
|
27937
28574
|
return (jsx("canvas", { ref: canvasRef, title: title || `${normalizedAvatarDefinition.agentName} avatar`, className: className, style: {
|
|
27938
28575
|
width: size,
|
|
27939
28576
|
height: size,
|
|
27940
28577
|
display: 'block',
|
|
27941
|
-
borderRadius: size * AVATAR_CANVAS_RADIUS_RATIO,
|
|
28578
|
+
borderRadius: surface === 'transparent' ? 0 : size * AVATAR_CANVAS_RADIUS_RATIO,
|
|
27942
28579
|
...style,
|
|
27943
28580
|
} }));
|
|
27944
28581
|
}
|
|
@@ -27949,9 +28586,9 @@ function Avatar(props) {
|
|
|
27949
28586
|
* @private shared component for avatar media rendering
|
|
27950
28587
|
*/
|
|
27951
28588
|
function AvatarOrImage(props) {
|
|
27952
|
-
const { imageUrl, avatarDefinition, visualId, size, alt, className, style } = props;
|
|
28589
|
+
const { imageUrl, avatarDefinition, visualId, surface, size, alt, className, style } = props;
|
|
27953
28590
|
if (avatarDefinition && visualId) {
|
|
27954
|
-
return (jsx(Avatar, { avatarDefinition: avatarDefinition, visualId: visualId, size: size, title: alt, className: className, style: style }));
|
|
28591
|
+
return (jsx(Avatar, { avatarDefinition: avatarDefinition, visualId: visualId, surface: surface, size: size, title: alt, className: className, style: style }));
|
|
27955
28592
|
}
|
|
27956
28593
|
if (!imageUrl) {
|
|
27957
28594
|
return null;
|
|
@@ -38559,6 +39196,14 @@ class OpenAiVectorStoreHandler extends OpenAiExecutionTools {
|
|
|
38559
39196
|
* Constant for default agent kit model name.
|
|
38560
39197
|
*/
|
|
38561
39198
|
const DEFAULT_AGENT_KIT_MODEL_NAME = 'gpt-5.4-mini';
|
|
39199
|
+
/**
|
|
39200
|
+
* Default model used for nested DeepSearch tool invocations.
|
|
39201
|
+
*/
|
|
39202
|
+
const DEFAULT_DEEP_SEARCH_MODEL_NAME = 'o4-mini-deep-research';
|
|
39203
|
+
/**
|
|
39204
|
+
* Tool name used by the Book commitment-backed DeepSearch capability.
|
|
39205
|
+
*/
|
|
39206
|
+
const DEEP_SEARCH_TOOL_NAME = 'deep_search';
|
|
38562
39207
|
/**
|
|
38563
39208
|
* Creates one structured log entry for streamed tool-call updates.
|
|
38564
39209
|
*
|
|
@@ -38601,6 +39246,98 @@ function resolveFinalToolCallState$1(options) {
|
|
|
38601
39246
|
}
|
|
38602
39247
|
return 'COMPLETE';
|
|
38603
39248
|
}
|
|
39249
|
+
/**
|
|
39250
|
+
* Returns true when one tool definition represents the dedicated DeepSearch capability.
|
|
39251
|
+
*
|
|
39252
|
+
* @param toolDefinition - Tool definition from compiled model requirements.
|
|
39253
|
+
* @returns `true` when the tool should be backed by a nested deep-research agent.
|
|
39254
|
+
*
|
|
39255
|
+
* @private helper of `OpenAiAgentKitExecutionTools`
|
|
39256
|
+
*/
|
|
39257
|
+
function isDeepSearchToolDefinition(toolDefinition) {
|
|
39258
|
+
return toolDefinition.name === DEEP_SEARCH_TOOL_NAME;
|
|
39259
|
+
}
|
|
39260
|
+
/**
|
|
39261
|
+
* Normalizes Promptbook JSON-schema tool parameters for AgentKit function tools.
|
|
39262
|
+
*
|
|
39263
|
+
* @param parameters - Promptbook tool parameters.
|
|
39264
|
+
* @returns AgentKit-compatible JSON schema or `undefined`.
|
|
39265
|
+
*
|
|
39266
|
+
* @private helper of `OpenAiAgentKitExecutionTools`
|
|
39267
|
+
*/
|
|
39268
|
+
function normalizeAgentKitToolParameters(parameters) {
|
|
39269
|
+
var _a, _b;
|
|
39270
|
+
if (!parameters) {
|
|
39271
|
+
return undefined;
|
|
39272
|
+
}
|
|
39273
|
+
return {
|
|
39274
|
+
...parameters,
|
|
39275
|
+
additionalProperties: (_a = parameters.additionalProperties) !== null && _a !== void 0 ? _a : false,
|
|
39276
|
+
required: (_b = parameters.required) !== null && _b !== void 0 ? _b : [],
|
|
39277
|
+
};
|
|
39278
|
+
}
|
|
39279
|
+
/**
|
|
39280
|
+
* Creates instructions for the nested DeepSearch specialist agent.
|
|
39281
|
+
*
|
|
39282
|
+
* @param toolDescription - Model-facing description from the original tool definition.
|
|
39283
|
+
* @returns System instructions for the nested deep-research agent.
|
|
39284
|
+
*
|
|
39285
|
+
* @private helper of `OpenAiAgentKitExecutionTools`
|
|
39286
|
+
*/
|
|
39287
|
+
function createDeepSearchAgentInstructions(toolDescription) {
|
|
39288
|
+
const normalizedDescription = toolDescription.trim();
|
|
39289
|
+
return spaceTrim$1((block) => `
|
|
39290
|
+
You are a DeepSearch specialist working as a tool for another agent.
|
|
39291
|
+
Perform thorough, source-grounded public-web research based on the provided request.
|
|
39292
|
+
Use web search to gather current information, compare relevant viewpoints, and synthesize a concise research brief.
|
|
39293
|
+
Do not ask follow-up questions. If the request is not specific enough, state the assumptions you had to make.
|
|
39294
|
+
Include citations in the research brief whenever sources were used.
|
|
39295
|
+
${block(normalizedDescription ? `Tool guidance:\n${normalizedDescription}` : '')}
|
|
39296
|
+
`);
|
|
39297
|
+
}
|
|
39298
|
+
/**
|
|
39299
|
+
* Builds the nested DeepSearch prompt from structured tool arguments.
|
|
39300
|
+
*
|
|
39301
|
+
* @param rawInput - Parsed function-tool arguments provided by the outer agent.
|
|
39302
|
+
* @returns Prompt text passed to the nested deep-research agent.
|
|
39303
|
+
*
|
|
39304
|
+
* @private helper of `OpenAiAgentKitExecutionTools`
|
|
39305
|
+
*/
|
|
39306
|
+
function buildDeepSearchToolInput(rawInput) {
|
|
39307
|
+
const input = rawInput && typeof rawInput === 'object' ? rawInput : {};
|
|
39308
|
+
const query = typeof input.query === 'string' ? input.query.trim() : '';
|
|
39309
|
+
const additionalHints = Object.entries(input)
|
|
39310
|
+
.filter(([key, value]) => key !== 'query' && value !== undefined && value !== null && String(value).trim() !== '')
|
|
39311
|
+
.map(([key, value]) => `- ${key}: ${typeof value === 'string' ? value : JSON.stringify(value)}`);
|
|
39312
|
+
return spaceTrim$1((block) => `
|
|
39313
|
+
Research request:
|
|
39314
|
+
${query || JSON.stringify(input)}
|
|
39315
|
+
${block(additionalHints.length > 0 ? `Execution hints:\n${additionalHints.join('\n')}` : '')}
|
|
39316
|
+
`);
|
|
39317
|
+
}
|
|
39318
|
+
/**
|
|
39319
|
+
* Creates the native Agent SDK tool used for `USE DEEPSEARCH`.
|
|
39320
|
+
*
|
|
39321
|
+
* @param toolDefinition - Promptbook tool definition for `deep_search`.
|
|
39322
|
+
* @returns AgentKit tool backed by a nested deep-research agent.
|
|
39323
|
+
*
|
|
39324
|
+
* @private helper of `OpenAiAgentKitExecutionTools`
|
|
39325
|
+
*/
|
|
39326
|
+
function createDeepSearchAgentKitTool(toolDefinition) {
|
|
39327
|
+
const deepSearchAgent = new Agent$1({
|
|
39328
|
+
name: 'DeepSearch',
|
|
39329
|
+
model: DEFAULT_DEEP_SEARCH_MODEL_NAME,
|
|
39330
|
+
instructions: createDeepSearchAgentInstructions(toolDefinition.description),
|
|
39331
|
+
tools: [webSearchTool({ searchContextSize: 'high' })],
|
|
39332
|
+
});
|
|
39333
|
+
return deepSearchAgent.asTool({
|
|
39334
|
+
toolName: toolDefinition.name,
|
|
39335
|
+
toolDescription: toolDefinition.description,
|
|
39336
|
+
parameters: normalizeAgentKitToolParameters(toolDefinition.parameters),
|
|
39337
|
+
inputBuilder: ({ params }) => buildDeepSearchToolInput(params),
|
|
39338
|
+
customOutputExtractor: (result) => { var _a; return typeof result.finalOutput === 'string' ? result.finalOutput : JSON.stringify((_a = result.finalOutput) !== null && _a !== void 0 ? _a : ''); },
|
|
39339
|
+
});
|
|
39340
|
+
}
|
|
38604
39341
|
/**
|
|
38605
39342
|
* Constant for default JSON schema name.
|
|
38606
39343
|
*/
|
|
@@ -38941,25 +39678,23 @@ class OpenAiAgentKitExecutionTools extends OpenAiVectorStoreHandler {
|
|
|
38941
39678
|
* Builds the tool list for AgentKit, including hosted file search when applicable.
|
|
38942
39679
|
*/
|
|
38943
39680
|
buildAgentKitTools(options) {
|
|
38944
|
-
var _a;
|
|
38945
39681
|
const { tools, vectorStoreId } = options;
|
|
38946
39682
|
const agentKitTools = [];
|
|
38947
39683
|
if (vectorStoreId) {
|
|
38948
39684
|
agentKitTools.push(fileSearchTool(vectorStoreId));
|
|
38949
39685
|
}
|
|
38950
39686
|
if (tools && tools.length > 0) {
|
|
38951
|
-
|
|
39687
|
+
let scriptTools = null;
|
|
38952
39688
|
for (const toolDefinition of tools) {
|
|
39689
|
+
if (isDeepSearchToolDefinition(toolDefinition)) {
|
|
39690
|
+
agentKitTools.push(createDeepSearchAgentKitTool(toolDefinition));
|
|
39691
|
+
continue;
|
|
39692
|
+
}
|
|
39693
|
+
scriptTools !== null && scriptTools !== void 0 ? scriptTools : (scriptTools = this.resolveScriptTools());
|
|
38953
39694
|
agentKitTools.push(tool({
|
|
38954
39695
|
name: toolDefinition.name,
|
|
38955
39696
|
description: toolDefinition.description,
|
|
38956
|
-
parameters: toolDefinition.parameters
|
|
38957
|
-
? {
|
|
38958
|
-
...toolDefinition.parameters,
|
|
38959
|
-
additionalProperties: false,
|
|
38960
|
-
required: (_a = toolDefinition.parameters.required) !== null && _a !== void 0 ? _a : [],
|
|
38961
|
-
}
|
|
38962
|
-
: undefined,
|
|
39697
|
+
parameters: normalizeAgentKitToolParameters(toolDefinition.parameters),
|
|
38963
39698
|
strict: false,
|
|
38964
39699
|
execute: async (input, runContext, details) => {
|
|
38965
39700
|
var _a, _b, _c, _d;
|
|
@@ -45146,6 +45881,7 @@ const TOOL_TITLES = {
|
|
|
45146
45881
|
delete_wallet_record: { title: 'Deleting wallet', emoji: '👛' },
|
|
45147
45882
|
request_wallet_record: { title: 'Requesting wallet', emoji: '👛' },
|
|
45148
45883
|
web_search: { title: 'Searching the web', emoji: '🔎' },
|
|
45884
|
+
deep_search: { title: 'Deep research', emoji: '🔬' },
|
|
45149
45885
|
useSearchEngine: { title: 'Searching the web', emoji: '🔎' },
|
|
45150
45886
|
search: { title: 'Searching the web', emoji: '🔎' },
|
|
45151
45887
|
useBrowser: { title: 'Browsing the web', emoji: '🌐' },
|
|
@@ -48107,7 +48843,7 @@ function renderGenericToolCallDetails(options) {
|
|
|
48107
48843
|
* @private function of ChatToolCallModal
|
|
48108
48844
|
*/
|
|
48109
48845
|
function isSearchToolCallName(toolName) {
|
|
48110
|
-
return toolName === 'web_search' || toolName === 'useSearchEngine' || toolName === 'search';
|
|
48846
|
+
return toolName === 'web_search' || toolName === 'deep_search' || toolName === 'useSearchEngine' || toolName === 'search';
|
|
48111
48847
|
}
|
|
48112
48848
|
/**
|
|
48113
48849
|
* Checks whether a tool name should use the time renderer.
|
|
@@ -48807,6 +49543,12 @@ function TeamToolCallModalContent(options) {
|
|
|
48807
49543
|
});
|
|
48808
49544
|
}
|
|
48809
49545
|
}
|
|
49546
|
+
const staticConversationDelayConfig = {
|
|
49547
|
+
...FAST_FLOW,
|
|
49548
|
+
beforeFirstMessage: 0,
|
|
49549
|
+
// Show the full internal exchange immediately so the modal never opens as a blank panel.
|
|
49550
|
+
showIntermediateMessages: messages.length,
|
|
49551
|
+
};
|
|
48810
49552
|
const agentName = ((_c = (_b = teamResult.conversation) === null || _b === void 0 ? void 0 : _b.find((entry) => entry.sender === 'AGENT' || entry.role === 'AGENT')) === null || _c === void 0 ? void 0 : _c.name) || 'Agent';
|
|
48811
49553
|
const teammateConversationName = ((_e = (_d = teamResult.conversation) === null || _d === void 0 ? void 0 : _d.find((entry) => entry.sender === 'TEAMMATE' || entry.role === 'TEAMMATE')) === null || _e === void 0 ? void 0 : _e.name) || '';
|
|
48812
49554
|
const teammateProfile = teammateUrl ? teamProfiles[teammateUrl] : undefined;
|
|
@@ -48843,7 +49585,7 @@ function TeamToolCallModalContent(options) {
|
|
|
48843
49585
|
avatarSrc: resolvedTeammateAvatar || undefined,
|
|
48844
49586
|
},
|
|
48845
49587
|
];
|
|
48846
|
-
return (jsxs(Fragment, { children: [jsx("div", { className: classNames(styles$5.searchModalHeader, styles$5.teamModalHeader), children: jsxs("div", { className: styles$5.teamHeaderParticipants, children: [jsx(TeamHeaderProfile, { label: resolvedAgentLabel, avatarSrc: resolvedAgentAvatar, avatarDefinition: resolvedAgentAvatarDefinition, avatarVisualId: resolvedAgentAvatarVisualId, fallbackColor: resolvedAgentHeaderColor }), jsx("span", { className: styles$5.teamHeaderDivider, children: "talking with" }), jsx(TeamHeaderProfile, { label: resolvedTeammateLabel, avatarSrc: resolvedTeammateAvatar, fallbackColor: "#0ea5e9", href: teammateLink })] }) }), jsxs("div", { className: styles$5.searchModalContent, children: [messages.length > 0 ? (jsx("div", { className: styles$5.teamChatContainer, children: jsx(MockedChat, { title: `Chat between ${resolvedAgentLabel} and ${resolvedTeammateLabel}`, messages: messages, participants: participants, isResettable: false, isPausable: false, isSaveButtonEnabled: false, isCopyButtonEnabled: false, visual: "STANDALONE", delayConfig:
|
|
49588
|
+
return (jsxs(Fragment, { children: [jsx("div", { className: classNames(styles$5.searchModalHeader, styles$5.teamModalHeader), children: jsxs("div", { className: styles$5.teamHeaderParticipants, children: [jsx(TeamHeaderProfile, { label: resolvedAgentLabel, avatarSrc: resolvedAgentAvatar, avatarDefinition: resolvedAgentAvatarDefinition, avatarVisualId: resolvedAgentAvatarVisualId, fallbackColor: resolvedAgentHeaderColor }), jsx("span", { className: styles$5.teamHeaderDivider, children: "talking with" }), jsx(TeamHeaderProfile, { label: resolvedTeammateLabel, avatarSrc: resolvedTeammateAvatar, fallbackColor: "#0ea5e9", href: teammateLink })] }) }), jsxs("div", { className: styles$5.searchModalContent, children: [messages.length > 0 ? (jsx("div", { className: styles$5.teamChatContainer, children: jsx(MockedChat, { title: `Chat between ${resolvedAgentLabel} and ${resolvedTeammateLabel}`, messages: messages, participants: participants, isResettable: false, isPausable: false, isSaveButtonEnabled: false, isCopyButtonEnabled: false, visual: "STANDALONE", delayConfig: staticConversationDelayConfig }) })) : (jsx("div", { className: styles$5.noResults, children: "No teammate conversation available." })), (hasTeamToolCalls || hasTeamCitations) && (jsxs("div", { className: styles$5.teamToolCallSection, children: [hasTeamToolCalls && (jsxs("div", { className: styles$5.teamToolCallGroup, children: [jsx("div", { className: styles$5.teamToolCallHeading, children: "Actions" }), jsx("div", { className: styles$5.teamToolCallChips, children: teamToolCalls.map((toolCallEntry, index) => {
|
|
48847
49589
|
const chipletInfo = getToolCallChipletInfo(toolCallEntry.toolCall, undefined, toolTitles);
|
|
48848
49590
|
const chipletText = buildToolCallChipText(chipletInfo);
|
|
48849
49591
|
return (jsxs("button", { className: styles$5.completedToolCall, onClick: () => {
|