@promptbook/remote-server 0.112.0-64 → 0.112.0-66

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 (55) hide show
  1. package/esm/index.es.js +750 -252
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/src/_packages/components.index.d.ts +0 -2
  4. package/esm/src/_packages/core.index.d.ts +2 -2
  5. package/esm/src/_packages/types.index.d.ts +0 -2
  6. package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  7. package/esm/src/avatars/visuals/minecraft2AvatarVisual.d.ts +7 -0
  8. package/esm/src/avatars/visuals/minecraftAvatarVisualShared.d.ts +48 -0
  9. package/esm/src/book-2.0/book-language-documentation/BookLanguageDocumentationExample.d.ts +27 -0
  10. package/esm/src/book-2.0/book-language-documentation/bookLanguageCommonPitfalls.d.ts +25 -0
  11. package/esm/src/book-2.0/book-language-documentation/bookLanguageDocumentationExamples.d.ts +10 -0
  12. package/esm/src/book-2.0/book-language-documentation/createStandaloneBookLanguageMarkdown.d.ts +14 -0
  13. package/esm/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.d.ts +43 -0
  14. package/esm/src/book-components/Chat/types/ChatMessage.d.ts +0 -34
  15. package/esm/src/cli/cli-commands/coder/ensureCoderGitignoreFile.d.ts +1 -1
  16. package/esm/src/commitments/KNOWLEDGE/KNOWLEDGE.d.ts +0 -11
  17. package/esm/src/commitments/_common/toolRuntimeContext.d.ts +0 -6
  18. package/esm/src/config.d.ts +3 -3
  19. package/esm/src/formfactors/index.d.ts +2 -2
  20. package/esm/src/formfactors/matcher/MatcherFormfactorDefinition.d.ts +1 -1
  21. package/esm/src/formfactors/translator/TranslatorFormfactorDefinition.d.ts +1 -1
  22. package/esm/src/llm-providers/openai/OpenAiAgentKitExecutionTools.d.ts +0 -4
  23. package/esm/src/llm-providers/openai/OpenAiAgentKitExecutionToolsOptions.d.ts +0 -9
  24. package/esm/src/utils/files/getPromptbookTempPath.d.ts +24 -0
  25. package/esm/src/version.d.ts +1 -1
  26. package/package.json +2 -2
  27. package/umd/index.umd.js +749 -251
  28. package/umd/index.umd.js.map +1 -1
  29. package/umd/src/_packages/components.index.d.ts +0 -2
  30. package/umd/src/_packages/core.index.d.ts +2 -2
  31. package/umd/src/_packages/types.index.d.ts +0 -2
  32. package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  33. package/umd/src/avatars/visuals/minecraft2AvatarVisual.d.ts +7 -0
  34. package/umd/src/avatars/visuals/minecraftAvatarVisualShared.d.ts +48 -0
  35. package/umd/src/book-2.0/book-language-documentation/BookLanguageDocumentationExample.d.ts +27 -0
  36. package/umd/src/book-2.0/book-language-documentation/bookLanguageCommonPitfalls.d.ts +25 -0
  37. package/umd/src/book-2.0/book-language-documentation/bookLanguageDocumentationExamples.d.ts +10 -0
  38. package/umd/src/book-2.0/book-language-documentation/createStandaloneBookLanguageMarkdown.d.ts +14 -0
  39. package/umd/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.d.ts +43 -0
  40. package/umd/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.test.d.ts +1 -0
  41. package/umd/src/book-components/Chat/types/ChatMessage.d.ts +0 -34
  42. package/umd/src/cli/cli-commands/coder/ensureCoderGitignoreFile.d.ts +1 -1
  43. package/umd/src/commitments/KNOWLEDGE/KNOWLEDGE.d.ts +0 -11
  44. package/umd/src/commitments/_common/toolRuntimeContext.d.ts +0 -6
  45. package/umd/src/config.d.ts +3 -3
  46. package/umd/src/formfactors/index.d.ts +2 -2
  47. package/umd/src/formfactors/matcher/MatcherFormfactorDefinition.d.ts +1 -1
  48. package/umd/src/formfactors/translator/TranslatorFormfactorDefinition.d.ts +1 -1
  49. package/umd/src/llm-providers/openai/OpenAiAgentKitExecutionTools.d.ts +0 -4
  50. package/umd/src/llm-providers/openai/OpenAiAgentKitExecutionToolsOptions.d.ts +0 -9
  51. package/umd/src/utils/files/getPromptbookTempPath.d.ts +24 -0
  52. package/umd/src/utils/files/getPromptbookTempPath.test.d.ts +1 -0
  53. package/umd/src/version.d.ts +1 -1
  54. /package/esm/src/{commitments/KNOWLEDGE/KNOWLEDGE.test.d.ts → book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.test.d.ts} +0 -0
  55. /package/{umd/src/commitments/KNOWLEDGE/KNOWLEDGE.test.d.ts → esm/src/utils/files/getPromptbookTempPath.test.d.ts} +0 -0
package/umd/index.umd.js CHANGED
@@ -50,7 +50,7 @@
50
50
  * @generated
51
51
  * @see https://github.com/webgptorg/promptbook
52
52
  */
53
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-64';
53
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-66';
54
54
  /**
55
55
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
56
56
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -969,6 +969,29 @@
969
969
  }
970
970
  // TODO: Maybe implement by mix+hsl
971
971
 
972
+ /**
973
+ * Relative directory name without the `./` prefix for Git ignore rules and glob patterns.
974
+ *
975
+ * @private internal utility for Promptbook-owned temp files
976
+ */
977
+ const PROMPTBOOK_TEMP_DIRECTORY_NAME = '.promptbook';
978
+ /**
979
+ * Builds one project-relative path inside the shared Promptbook working directory.
980
+ *
981
+ * @private internal utility for Promptbook-owned temp files
982
+ */
983
+ function getPromptbookTempPath(...pathSegments) {
984
+ return `./${getPromptbookTempPosixPath(...pathSegments)}`;
985
+ }
986
+ /**
987
+ * Builds one POSIX path fragment inside the shared Promptbook working directory for globs and generated text files.
988
+ *
989
+ * @private internal utility for Promptbook-owned temp files
990
+ */
991
+ function getPromptbookTempPosixPath(...pathSegments) {
992
+ return path.posix.join(PROMPTBOOK_TEMP_DIRECTORY_NAME, ...pathSegments);
993
+ }
994
+
972
995
  /**
973
996
  * Returns the same value that is passed as argument.
974
997
  * No side effects.
@@ -1159,7 +1182,6 @@
1159
1182
  */
1160
1183
  const DEFAULT_MAX_EXECUTION_ATTEMPTS = 7; // <- TODO: [🤹‍♂️]
1161
1184
  // <- TODO: [🕝] Make also `AGENTS_DIRNAME_ALTERNATIVES`
1162
- // TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
1163
1185
  /**
1164
1186
  * Where to store the temporary downloads
1165
1187
  *
@@ -1167,7 +1189,15 @@
1167
1189
  *
1168
1190
  * @public exported from `@promptbook/core`
1169
1191
  */
1170
- const DEFAULT_DOWNLOAD_CACHE_DIRNAME = './.promptbook/download-cache';
1192
+ const DEFAULT_DOWNLOAD_CACHE_DIRNAME = getPromptbookTempPath('download-cache');
1193
+ /**
1194
+ * Where to store the cache of executions for promptbook CLI
1195
+ *
1196
+ * Note: When the folder does not exist, it is created recursively
1197
+ *
1198
+ * @public exported from `@promptbook/core`
1199
+ */
1200
+ getPromptbookTempPath('execution-cache');
1171
1201
  /**
1172
1202
  * Where to store the scrape cache
1173
1203
  *
@@ -1175,7 +1205,7 @@
1175
1205
  *
1176
1206
  * @public exported from `@promptbook/core`
1177
1207
  */
1178
- const DEFAULT_SCRAPE_CACHE_DIRNAME = './.promptbook/scrape-cache';
1208
+ const DEFAULT_SCRAPE_CACHE_DIRNAME = getPromptbookTempPath('scrape-cache');
1179
1209
  // <- TODO: [🧜‍♂️]
1180
1210
  /**
1181
1211
  * Default settings for parsing and generating CSV files in Promptbook.
@@ -12689,18 +12719,6 @@
12689
12719
  }
12690
12720
  // Note: [💞] Ignore a discrepancy between file name and entity name
12691
12721
 
12692
- /**
12693
- * Name of the tool used by agents to search configured `KNOWLEDGE` sources.
12694
- *
12695
- * @public exported from `@promptbook/core`
12696
- */
12697
- const KNOWLEDGE_SEARCH_TOOL_NAME = 'knowledge_search';
12698
- /**
12699
- * Title of the system-message section generated for `KNOWLEDGE` commitments.
12700
- *
12701
- * @private constant of `KnowledgeCommitmentDefinition`
12702
- */
12703
- const KNOWLEDGE_SEARCH_SYSTEM_SECTION_TITLE = 'Knowledge Search';
12704
12722
  /**
12705
12723
  * KNOWLEDGE commitment definition
12706
12724
  *
@@ -12822,17 +12840,9 @@
12822
12840
  knowledgeInfoEntries.push(`Knowledge Source Inline: ${inlineSource.filename} (derived from inline content and processed for retrieval during chat)`);
12823
12841
  }
12824
12842
  if (knowledgeInfoEntries.length === 0) {
12825
- return addKnowledgeSearchToolAndSystemSection(nextRequirements);
12843
+ return nextRequirements;
12826
12844
  }
12827
- return addKnowledgeSearchToolAndSystemSection(nextRequirements);
12828
- }
12829
- /**
12830
- * Gets human-readable titles for tool functions provided by this commitment.
12831
- */
12832
- getToolTitles() {
12833
- return {
12834
- [KNOWLEDGE_SEARCH_TOOL_NAME]: 'Knowledge search',
12835
- };
12845
+ return this.appendToSystemMessage(nextRequirements, knowledgeInfoEntries.join('\n'), '\n\n');
12836
12846
  }
12837
12847
  }
12838
12848
  /**
@@ -12846,128 +12856,6 @@
12846
12856
  const significantText = contentWithoutUrls.replace(/[\s.,!?;:'"`()[\]{}<>/-]+/g, '');
12847
12857
  return significantText.length > 0;
12848
12858
  }
12849
- /**
12850
- * Adds the shared `knowledge_search` tool definition and the consolidated system-message section.
12851
- *
12852
- * @param requirements - Requirements after one `KNOWLEDGE` commitment was applied.
12853
- * @returns Requirements with the knowledge search instructions and tool definition.
12854
- *
12855
- * @private internal utility of `KnowledgeCommitmentDefinition`
12856
- */
12857
- function addKnowledgeSearchToolAndSystemSection(requirements) {
12858
- const nextRequirements = addKnowledgeSearchTool(requirements);
12859
- const section = createKnowledgeSearchSystemSection(nextRequirements);
12860
- const sectionHeader = `## ${KNOWLEDGE_SEARCH_SYSTEM_SECTION_TITLE}`;
12861
- if (nextRequirements.systemMessage.includes(sectionHeader)) {
12862
- return {
12863
- ...nextRequirements,
12864
- systemMessage: nextRequirements.systemMessage.replace(new RegExp(`## ${KNOWLEDGE_SEARCH_SYSTEM_SECTION_TITLE.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\s\\S]*?(?=\\n\\n##|$)`), section),
12865
- };
12866
- }
12867
- return {
12868
- ...nextRequirements,
12869
- systemMessage: nextRequirements.systemMessage.trim()
12870
- ? `${nextRequirements.systemMessage}\n\n${section}`
12871
- : section,
12872
- };
12873
- }
12874
- /**
12875
- * Adds the `knowledge_search` model tool when it is not already present.
12876
- *
12877
- * @param requirements - Current model requirements.
12878
- * @returns Requirements with the tool definition available to the model.
12879
- *
12880
- * @private internal utility of `KnowledgeCommitmentDefinition`
12881
- */
12882
- function addKnowledgeSearchTool(requirements) {
12883
- const existingTools = requirements.tools || [];
12884
- if (existingTools.some((tool) => tool.name === KNOWLEDGE_SEARCH_TOOL_NAME)) {
12885
- return requirements;
12886
- }
12887
- return {
12888
- ...requirements,
12889
- tools: [
12890
- ...existingTools,
12891
- {
12892
- name: KNOWLEDGE_SEARCH_TOOL_NAME,
12893
- description: _spaceTrim.spaceTrim(`
12894
- Search the agent's configured knowledge sources and return relevant excerpts with citation ids.
12895
- Use this before answering questions that may depend on the agent's KNOWLEDGE commitments.
12896
- `),
12897
- parameters: {
12898
- type: 'object',
12899
- properties: {
12900
- query: {
12901
- type: 'string',
12902
- description: 'The natural-language search query for the knowledge base.',
12903
- },
12904
- limit: {
12905
- type: 'integer',
12906
- description: 'Maximum number of matching source excerpts to return.',
12907
- },
12908
- },
12909
- required: ['query'],
12910
- },
12911
- },
12912
- ],
12913
- };
12914
- }
12915
- /**
12916
- * Creates the model-facing system-message section for knowledge search.
12917
- *
12918
- * @param requirements - Current model requirements.
12919
- * @returns Markdown system-message section.
12920
- *
12921
- * @private internal utility of `KnowledgeCommitmentDefinition`
12922
- */
12923
- function createKnowledgeSearchSystemSection(requirements) {
12924
- const sourceEntries = createKnowledgeSourceSystemEntries(requirements);
12925
- const sourceList = sourceEntries.length > 0 ? sourceEntries.map((entry) => `- ${entry}`).join('\n') : '- None';
12926
- return _spaceTrim.spaceTrim(`
12927
- ## ${KNOWLEDGE_SEARCH_SYSTEM_SECTION_TITLE}
12928
-
12929
- - Use \`${KNOWLEDGE_SEARCH_TOOL_NAME}\` to search the configured knowledge sources before answering questions that depend on this agent's knowledge base.
12930
- - Base source-backed factual answers on the returned excerpts.
12931
- - When you use a returned excerpt, include its citation marker in the answer body, for example \`[0:0]\`.
12932
- - If the search returns no relevant information, say that the knowledge base did not contain the answer instead of inventing it.
12933
-
12934
- Configured knowledge sources:
12935
- ${sourceList}
12936
- `);
12937
- }
12938
- /**
12939
- * Builds a stable list of configured knowledge sources for system-message diagnostics.
12940
- *
12941
- * @param requirements - Current model requirements.
12942
- * @returns Human-readable source entries.
12943
- *
12944
- * @private internal utility of `KnowledgeCommitmentDefinition`
12945
- */
12946
- function createKnowledgeSourceSystemEntries(requirements) {
12947
- var _a;
12948
- const entries = [];
12949
- const seenEntries = new Set();
12950
- for (const source of requirements.knowledgeSources || []) {
12951
- const entry = `Source URL: ${source} (processed for retrieval during chat)`;
12952
- if (seenEntries.has(entry)) {
12953
- continue;
12954
- }
12955
- seenEntries.add(entry);
12956
- entries.push(entry);
12957
- }
12958
- const inlineSources = (((_a = requirements._metadata) === null || _a === void 0 ? void 0 : _a.inlineKnowledgeSources) || [])
12959
- .map((source) => source.filename)
12960
- .filter(Boolean);
12961
- for (const filename of inlineSources) {
12962
- const entry = `Knowledge Source Inline: ${filename} (Inline source: processed for retrieval during chat)`;
12963
- if (seenEntries.has(entry)) {
12964
- continue;
12965
- }
12966
- seenEntries.add(entry);
12967
- entries.push(entry);
12968
- }
12969
- return entries;
12970
- }
12971
12859
 
12972
12860
  /**
12973
12861
  * LANGUAGE commitment definition
@@ -15619,6 +15507,177 @@
15619
15507
  context.restore();
15620
15508
  }
15621
15509
 
15510
+ /* eslint-disable no-magic-numbers */
15511
+ /**
15512
+ * Builds the seeded six-face texture pack used by the Minecraft-style head cuboid.
15513
+ *
15514
+ * @param random Seeded random generator.
15515
+ * @param palette Derived avatar palette.
15516
+ * @param hasHeadband Whether the generated avatar should include a colored headband.
15517
+ * @returns Head cuboid textures.
15518
+ *
15519
+ * @private helper of the Minecraft avatar visuals
15520
+ */
15521
+ function createMinecraftHeadTextures(random, palette, hasHeadband) {
15522
+ const faceTexture = createMinecraftFaceTexture(random, palette, hasHeadband);
15523
+ const hairColor = random() < 0.5 ? palette.primary : palette.secondary;
15524
+ const skinColor = palette.highlight;
15525
+ const headbandColor = hasHeadband ? palette.accent : hairColor;
15526
+ const sideTexture = createFilledTexture(skinColor);
15527
+ const backTexture = createFilledTexture(skinColor);
15528
+ const topTexture = createFilledTexture(hairColor);
15529
+ const bottomTexture = createFilledTexture(`${palette.shadow}cc`);
15530
+ fillTextureRect(sideTexture, 0, 0, 8, 3, hairColor);
15531
+ fillTextureRect(backTexture, 0, 0, 8, 5, hairColor);
15532
+ fillTextureRect(backTexture, 1, 5, 6, 1, hairColor);
15533
+ if (hasHeadband) {
15534
+ fillTextureRect(sideTexture, 0, 2, 8, 1, headbandColor);
15535
+ fillTextureRect(backTexture, 0, 2, 8, 1, headbandColor);
15536
+ fillTextureRect(topTexture, 0, 4, 8, 1, headbandColor);
15537
+ }
15538
+ sideTexture[4][4] = `${palette.shadow}99`;
15539
+ sideTexture[5][4] = `${palette.shadow}cc`;
15540
+ backTexture[6][2] = `${palette.shadow}99`;
15541
+ backTexture[6][5] = `${palette.shadow}99`;
15542
+ return {
15543
+ front: faceTexture,
15544
+ back: backTexture,
15545
+ left: sideTexture,
15546
+ right: mirrorMinecraftTexture(sideTexture),
15547
+ top: topTexture,
15548
+ bottom: bottomTexture,
15549
+ };
15550
+ }
15551
+ /**
15552
+ * Builds the seeded six-face texture pack used by the Minecraft-style torso cuboid.
15553
+ *
15554
+ * @param random Seeded random generator.
15555
+ * @param palette Derived avatar palette.
15556
+ * @returns Torso cuboid textures.
15557
+ *
15558
+ * @private helper of the Minecraft avatar visuals
15559
+ */
15560
+ function createMinecraftTorsoTextures(random, palette) {
15561
+ const frontTexture = createMinecraftShirtTexture(random, palette);
15562
+ const sideTexture = createFilledTexture(palette.primary);
15563
+ const backTexture = createFilledTexture(palette.primary);
15564
+ const topTexture = createFilledTexture(`${palette.highlight}dd`);
15565
+ const bottomTexture = createFilledTexture(`${palette.shadow}dd`);
15566
+ const stripeColor = random() < 0.5 ? palette.secondary : palette.highlight;
15567
+ fillTextureRect(sideTexture, 0, 0, 8, 2, palette.shadow);
15568
+ fillTextureRect(backTexture, 0, 0, 8, 2, palette.shadow);
15569
+ fillTextureRect(backTexture, 3, 2, 2, 6, stripeColor);
15570
+ fillTextureRect(sideTexture, 4, 2, 1, 6, stripeColor);
15571
+ fillTextureRect(topTexture, 0, 0, 8, 2, palette.shadow);
15572
+ fillTextureRect(topTexture, 2, 2, 4, 4, stripeColor);
15573
+ return {
15574
+ front: frontTexture,
15575
+ back: backTexture,
15576
+ left: sideTexture,
15577
+ right: mirrorMinecraftTexture(sideTexture),
15578
+ top: topTexture,
15579
+ bottom: bottomTexture,
15580
+ };
15581
+ }
15582
+ /**
15583
+ * Mirrors one Minecraft texture horizontally.
15584
+ *
15585
+ * @param texture Source texture.
15586
+ * @returns Mirrored texture copy.
15587
+ *
15588
+ * @private helper of the Minecraft avatar visuals
15589
+ */
15590
+ function mirrorMinecraftTexture(texture) {
15591
+ return texture.map((row) => [...row].reverse());
15592
+ }
15593
+ /**
15594
+ * Creates the front-face pixel texture for the cube head.
15595
+ *
15596
+ * @param random Seeded random generator.
15597
+ * @param palette Derived avatar palette.
15598
+ * @param hasHeadband Whether the avatar should render a headband row.
15599
+ * @returns 8x8 pixel texture.
15600
+ *
15601
+ * @private helper of the Minecraft avatar visuals
15602
+ */
15603
+ function createMinecraftFaceTexture(random, palette, hasHeadband) {
15604
+ const texture = createFilledTexture(palette.highlight);
15605
+ const hairlineColor = random() < 0.5 ? palette.primary : palette.secondary;
15606
+ const cheekColor = random() < 0.5 ? `${palette.accent}bb` : `${palette.secondary}bb`;
15607
+ fillTextureRect(texture, 0, 0, 8, 2, hairlineColor);
15608
+ texture[2][0] = hairlineColor;
15609
+ texture[2][7] = hairlineColor;
15610
+ texture[3][0] = hairlineColor;
15611
+ texture[3][7] = hairlineColor;
15612
+ if (hasHeadband) {
15613
+ fillTextureRect(texture, 0, 2, 8, 1, palette.accent);
15614
+ }
15615
+ texture[3][2] = palette.ink;
15616
+ texture[3][5] = palette.ink;
15617
+ texture[4][2] = '#ffffff';
15618
+ texture[4][5] = '#ffffff';
15619
+ texture[5][1] = cheekColor;
15620
+ texture[5][6] = cheekColor;
15621
+ texture[5][3] = palette.shadow;
15622
+ texture[5][4] = palette.shadow;
15623
+ texture[6][3] = palette.shadow;
15624
+ texture[6][4] = palette.shadow;
15625
+ return texture;
15626
+ }
15627
+ /**
15628
+ * Creates the front-face pixel texture for the torso.
15629
+ *
15630
+ * @param random Seeded random generator.
15631
+ * @param palette Derived avatar palette.
15632
+ * @returns 8x8 torso texture.
15633
+ *
15634
+ * @private helper of the Minecraft avatar visuals
15635
+ */
15636
+ function createMinecraftShirtTexture(random, palette) {
15637
+ const texture = createFilledTexture(palette.primary);
15638
+ const stripeColor = random() < 0.5 ? palette.secondary : palette.highlight;
15639
+ fillTextureRect(texture, 0, 0, 8, 2, palette.shadow);
15640
+ for (let rowIndex = 2; rowIndex < 8; rowIndex++) {
15641
+ texture[rowIndex][3] = stripeColor;
15642
+ texture[rowIndex][4] = stripeColor;
15643
+ }
15644
+ texture[4][1] = palette.accent;
15645
+ texture[4][6] = palette.accent;
15646
+ texture[5][2] = palette.highlight;
15647
+ texture[5][5] = palette.highlight;
15648
+ return texture;
15649
+ }
15650
+ /**
15651
+ * Creates one solid-color 8x8 Minecraft texture.
15652
+ *
15653
+ * @param color Fill color.
15654
+ * @returns Filled 8x8 texture.
15655
+ *
15656
+ * @private helper of the Minecraft avatar visuals
15657
+ */
15658
+ function createFilledTexture(color) {
15659
+ return Array.from({ length: 8 }, () => Array.from({ length: 8 }, () => color));
15660
+ }
15661
+ /**
15662
+ * Fills one rectangular area inside a mutable Minecraft texture.
15663
+ *
15664
+ * @param texture Mutable target texture.
15665
+ * @param x Left texture coordinate.
15666
+ * @param y Top texture coordinate.
15667
+ * @param width Rectangle width.
15668
+ * @param height Rectangle height.
15669
+ * @param color Fill color.
15670
+ *
15671
+ * @private helper of the Minecraft avatar visuals
15672
+ */
15673
+ function fillTextureRect(texture, x, y, width, height, color) {
15674
+ for (let rowIndex = y; rowIndex < y + height; rowIndex++) {
15675
+ for (let columnIndex = x; columnIndex < x + width; columnIndex++) {
15676
+ texture[rowIndex][columnIndex] = color;
15677
+ }
15678
+ }
15679
+ }
15680
+
15622
15681
  /* eslint-disable no-magic-numbers */
15623
15682
  /**
15624
15683
  * Minecraft-style 3D avatar visual.
@@ -15643,8 +15702,8 @@
15643
15702
  const bodyX = size * 0.33;
15644
15703
  const bodyY = headY + headSize * 0.96;
15645
15704
  const hasHeadband = random() < 0.5;
15646
- const faceTexture = createMinecraftFaceTexture(createRandom('minecraft-face'), palette, hasHeadband);
15647
- const shirtTexture = createMinecraftShirtTexture(createRandom('minecraft-shirt'), palette);
15705
+ const headTextures = createMinecraftHeadTextures(createRandom('minecraft-face'), palette, hasHeadband);
15706
+ const torsoTextures = createMinecraftTorsoTextures(createRandom('minecraft-shirt'), palette);
15648
15707
  drawAvatarFrame(context, size, palette);
15649
15708
  const spotlight = context.createRadialGradient(size * 0.5, size * 0.18, size * 0.05, size * 0.5, size * 0.18, size * 0.5);
15650
15709
  spotlight.addColorStop(0, `${palette.highlight}66`);
@@ -15664,7 +15723,7 @@
15664
15723
  width: bodyWidth,
15665
15724
  height: bodyHeight,
15666
15725
  depth: bodyDepth,
15667
- frontTexture: shirtTexture,
15726
+ frontTexture: torsoTextures.front,
15668
15727
  topColor: `${palette.highlight}cc`,
15669
15728
  sideColor: `${palette.secondary}dd`,
15670
15729
  outlineColor: `${palette.shadow}aa`,
@@ -15675,7 +15734,7 @@
15675
15734
  width: headSize,
15676
15735
  height: headSize,
15677
15736
  depth,
15678
- frontTexture: faceTexture,
15737
+ frontTexture: headTextures.front,
15679
15738
  topColor: `${palette.highlight}ee`,
15680
15739
  sideColor: `${palette.secondary}ee`,
15681
15740
  outlineColor: `${palette.shadow}cc`,
@@ -15740,72 +15799,505 @@
15740
15799
  context.closePath();
15741
15800
  context.stroke();
15742
15801
  }
15802
+
15803
+ /* eslint-disable no-magic-numbers */
15743
15804
  /**
15744
- * Creates the front-face pixel texture for the cube head.
15805
+ * Fixed scene camera distance used for the proper-3D projection.
15745
15806
  *
15746
- * @param random Seeded random generator.
15807
+ * @private helper of `minecraft2AvatarVisual`
15808
+ */
15809
+ const CAMERA_DISTANCE_RATIO = 1.4;
15810
+ /**
15811
+ * Shared light direction used to shade projected cuboid faces.
15812
+ *
15813
+ * @private helper of `minecraft2AvatarVisual`
15814
+ */
15815
+ const LIGHT_DIRECTION = normalizeVector3({
15816
+ x: 0.4,
15817
+ y: -0.65,
15818
+ z: 0.92,
15819
+ });
15820
+ /**
15821
+ * Minecraft 3D 2 avatar visual.
15822
+ *
15823
+ * @private built-in avatar visual
15824
+ */
15825
+ const minecraft2AvatarVisual = {
15826
+ id: 'minecraft2',
15827
+ title: 'Minecraft 3D 2',
15828
+ description: 'Proper 3D Minecraft-style portrait with textured cuboids and pointer-driven head turns.',
15829
+ isAnimated: true,
15830
+ supportsPointerTracking: true,
15831
+ render({ context, size, palette, createRandom, timeMs, interaction }) {
15832
+ const spotlightY = size * 0.22;
15833
+ const headRandom = createRandom('minecraft2-head');
15834
+ const hasHeadband = headRandom() < 0.5;
15835
+ const headTextures = createMinecraftHeadTextures(createRandom('minecraft2-head-textures'), palette, hasHeadband);
15836
+ const torsoTextures = createMinecraftTorsoTextures(createRandom('minecraft2-body-textures'), palette);
15837
+ const bob = Math.sin(timeMs / 880) * size * 0.014;
15838
+ const bodyYaw = -0.24 + Math.sin(timeMs / 2300) * 0.06 + interaction.bodyOffsetX * 0.16;
15839
+ const bodyPitch = -0.12 + Math.cos(timeMs / 2800) * 0.02 - interaction.bodyOffsetY * 0.06;
15840
+ const headYaw = -0.18 + Math.sin(timeMs / 1900 + 0.6) * 0.05 + interaction.gazeX * 0.62;
15841
+ const headPitch = -0.12 + Math.cos(timeMs / 2400 + 1.1) * 0.03 - interaction.gazeY * 0.38;
15842
+ const sceneCenterX = size * 0.5;
15843
+ const sceneCenterY = size * 0.57;
15844
+ const bodyWidth = size * 0.225;
15845
+ const bodyHeight = size * 0.245;
15846
+ const bodyDepth = size * 0.145;
15847
+ const headSize = size * 0.24;
15848
+ const headLift = size * 0.205;
15849
+ const headForwardShift = interaction.intensity * size * 0.018;
15850
+ const sceneCuboids = [
15851
+ {
15852
+ center: {
15853
+ x: interaction.bodyOffsetX * size * 0.026,
15854
+ y: size * 0.05 + interaction.bodyOffsetY * size * 0.018 + bob,
15855
+ z: 0,
15856
+ },
15857
+ width: bodyWidth,
15858
+ height: bodyHeight,
15859
+ depth: bodyDepth,
15860
+ rotationX: bodyPitch,
15861
+ rotationY: bodyYaw,
15862
+ textures: torsoTextures,
15863
+ outlineColor: `${palette.shadow}cc`,
15864
+ },
15865
+ {
15866
+ center: {
15867
+ x: interaction.bodyOffsetX * size * 0.018 + interaction.gazeX * size * 0.016,
15868
+ y: -headLift + bob * 1.15,
15869
+ z: headForwardShift,
15870
+ },
15871
+ width: headSize,
15872
+ height: headSize,
15873
+ depth: headSize,
15874
+ rotationX: headPitch,
15875
+ rotationY: headYaw,
15876
+ textures: headTextures,
15877
+ outlineColor: `${palette.shadow}dd`,
15878
+ },
15879
+ ];
15880
+ const visibleFaces = sceneCuboids
15881
+ .flatMap((cuboid) => resolveVisibleCuboidFaces(cuboid, size, sceneCenterX, sceneCenterY))
15882
+ .sort((firstFace, secondFace) => firstFace.averageDepth - secondFace.averageDepth);
15883
+ drawAvatarFrame(context, size, palette);
15884
+ drawMinecraftBackdrop(context, size, palette, sceneCenterX, spotlightY, interaction, timeMs);
15885
+ drawMinecraftShadow(context, size, palette, interaction, timeMs);
15886
+ for (const visibleFace of visibleFaces) {
15887
+ drawTexturedProjectedFace(context, visibleFace);
15888
+ }
15889
+ },
15890
+ };
15891
+ /**
15892
+ * Draws the shared background atmosphere behind the Minecraft 3D 2 portrait.
15893
+ *
15894
+ * @param context Canvas 2D context.
15895
+ * @param size Canvas size in CSS pixels.
15747
15896
  * @param palette Derived avatar palette.
15748
- * @param hasHeadband Whether the avatar should render a headband row.
15749
- * @returns 8x8 pixel texture.
15897
+ * @param sceneCenterX Horizontal scene center.
15898
+ * @param spotlightY Vertical spotlight anchor.
15899
+ * @param interaction Smoothed pointer-aware interaction state.
15900
+ * @param timeMs Current animation time in milliseconds.
15750
15901
  *
15751
- * @private helper of `minecraftAvatarVisual`
15902
+ * @private helper of `minecraft2AvatarVisual`
15752
15903
  */
15753
- function createMinecraftFaceTexture(random, palette, hasHeadband) {
15754
- const texture = Array.from({ length: 8 }, () => Array.from({ length: 8 }, () => palette.highlight));
15755
- const hairlineColor = random() < 0.5 ? palette.primary : palette.secondary;
15756
- const cheekColor = random() < 0.5 ? `${palette.accent}bb` : `${palette.secondary}bb`;
15757
- for (let rowIndex = 0; rowIndex < 2; rowIndex++) {
15758
- for (let columnIndex = 0; columnIndex < 8; columnIndex++) {
15759
- texture[rowIndex][columnIndex] = hairlineColor;
15904
+ function drawMinecraftBackdrop(context, size, palette, sceneCenterX, spotlightY, interaction, timeMs) {
15905
+ const spotlightGradient = context.createRadialGradient(sceneCenterX + interaction.gazeX * size * 0.08, spotlightY + interaction.gazeY * size * 0.05, size * 0.03, sceneCenterX, spotlightY, size * 0.52);
15906
+ spotlightGradient.addColorStop(0, `${palette.highlight}66`);
15907
+ spotlightGradient.addColorStop(0.42, `${palette.accent}1d`);
15908
+ spotlightGradient.addColorStop(1, `${palette.highlight}00`);
15909
+ context.fillStyle = spotlightGradient;
15910
+ context.fillRect(0, 0, size, size);
15911
+ const rimGradient = context.createLinearGradient(0, size * 0.14, 0, size * 0.92);
15912
+ rimGradient.addColorStop(0, `${palette.highlight}12`);
15913
+ rimGradient.addColorStop(0.55, `${palette.secondary}0a`);
15914
+ rimGradient.addColorStop(1, `${palette.shadow}00`);
15915
+ context.fillStyle = rimGradient;
15916
+ context.fillRect(0, 0, size, size);
15917
+ context.save();
15918
+ context.globalAlpha = 0.08 + interaction.intensity * 0.04;
15919
+ context.fillStyle = palette.highlight;
15920
+ context.beginPath();
15921
+ context.arc(size * 0.72 + Math.sin(timeMs / 1600) * size * 0.03, size * 0.2 + Math.cos(timeMs / 1400) * size * 0.018, size * 0.025, 0, Math.PI * 2);
15922
+ context.fill();
15923
+ context.restore();
15924
+ }
15925
+ /**
15926
+ * Draws the soft floor shadow used to anchor the cuboids in the frame.
15927
+ *
15928
+ * @param context Canvas 2D context.
15929
+ * @param size Canvas size in CSS pixels.
15930
+ * @param palette Derived avatar palette.
15931
+ * @param interaction Smoothed pointer-aware interaction state.
15932
+ * @param timeMs Current animation time in milliseconds.
15933
+ *
15934
+ * @private helper of `minecraft2AvatarVisual`
15935
+ */
15936
+ function drawMinecraftShadow(context, size, palette, interaction, timeMs) {
15937
+ context.save();
15938
+ context.fillStyle = `${palette.shadow}66`;
15939
+ context.filter = `blur(${size * 0.02}px)`;
15940
+ context.beginPath();
15941
+ context.ellipse(size * 0.5 + interaction.gazeX * size * 0.03, size * 0.85 + Math.sin(timeMs / 880) * size * 0.01, size * (0.16 + interaction.intensity * 0.015), size * 0.055, 0, 0, Math.PI * 2);
15942
+ context.fill();
15943
+ context.restore();
15944
+ }
15945
+ /**
15946
+ * Resolves all visible projected faces for one scene cuboid.
15947
+ *
15948
+ * @param cuboid Scene cuboid definition.
15949
+ * @param size Canvas size in CSS pixels.
15950
+ * @param sceneCenterX Horizontal scene center.
15951
+ * @param sceneCenterY Vertical scene center.
15952
+ * @returns Visible faces sorted later by depth.
15953
+ *
15954
+ * @private helper of `minecraft2AvatarVisual`
15955
+ */
15956
+ function resolveVisibleCuboidFaces(cuboid, size, sceneCenterX, sceneCenterY) {
15957
+ const halfWidth = cuboid.width / 2;
15958
+ const halfHeight = cuboid.height / 2;
15959
+ const halfDepth = cuboid.depth / 2;
15960
+ const faceDefinitions = [
15961
+ {
15962
+ texture: cuboid.textures.front,
15963
+ corners: [
15964
+ { x: -halfWidth, y: -halfHeight, z: halfDepth },
15965
+ { x: halfWidth, y: -halfHeight, z: halfDepth },
15966
+ { x: halfWidth, y: halfHeight, z: halfDepth },
15967
+ { x: -halfWidth, y: halfHeight, z: halfDepth },
15968
+ ],
15969
+ },
15970
+ {
15971
+ texture: cuboid.textures.back,
15972
+ corners: [
15973
+ { x: halfWidth, y: -halfHeight, z: -halfDepth },
15974
+ { x: -halfWidth, y: -halfHeight, z: -halfDepth },
15975
+ { x: -halfWidth, y: halfHeight, z: -halfDepth },
15976
+ { x: halfWidth, y: halfHeight, z: -halfDepth },
15977
+ ],
15978
+ },
15979
+ {
15980
+ texture: cuboid.textures.right,
15981
+ corners: [
15982
+ { x: halfWidth, y: -halfHeight, z: halfDepth },
15983
+ { x: halfWidth, y: -halfHeight, z: -halfDepth },
15984
+ { x: halfWidth, y: halfHeight, z: -halfDepth },
15985
+ { x: halfWidth, y: halfHeight, z: halfDepth },
15986
+ ],
15987
+ },
15988
+ {
15989
+ texture: cuboid.textures.left,
15990
+ corners: [
15991
+ { x: -halfWidth, y: -halfHeight, z: -halfDepth },
15992
+ { x: -halfWidth, y: -halfHeight, z: halfDepth },
15993
+ { x: -halfWidth, y: halfHeight, z: halfDepth },
15994
+ { x: -halfWidth, y: halfHeight, z: -halfDepth },
15995
+ ],
15996
+ },
15997
+ {
15998
+ texture: cuboid.textures.top,
15999
+ corners: [
16000
+ { x: -halfWidth, y: -halfHeight, z: -halfDepth },
16001
+ { x: halfWidth, y: -halfHeight, z: -halfDepth },
16002
+ { x: halfWidth, y: -halfHeight, z: halfDepth },
16003
+ { x: -halfWidth, y: -halfHeight, z: halfDepth },
16004
+ ],
16005
+ },
16006
+ {
16007
+ texture: cuboid.textures.bottom,
16008
+ corners: [
16009
+ { x: -halfWidth, y: halfHeight, z: halfDepth },
16010
+ { x: halfWidth, y: halfHeight, z: halfDepth },
16011
+ { x: halfWidth, y: halfHeight, z: -halfDepth },
16012
+ { x: -halfWidth, y: halfHeight, z: -halfDepth },
16013
+ ],
16014
+ },
16015
+ ];
16016
+ const visibleFaces = faceDefinitions
16017
+ .map((faceDefinition) => {
16018
+ const transformedCorners = faceDefinition.corners.map((corner) => transformScenePoint(corner, cuboid.center, cuboid.rotationX, cuboid.rotationY));
16019
+ const faceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
16020
+ if (faceNormal.z <= 0.02) {
16021
+ return null;
15760
16022
  }
16023
+ const projectedCorners = transformedCorners.map((corner) => projectScenePoint(corner, size, sceneCenterX, sceneCenterY));
16024
+ return {
16025
+ corners: projectedCorners,
16026
+ texture: faceDefinition.texture,
16027
+ averageDepth: transformedCorners.reduce((depthSum, corner) => depthSum + corner.z, 0) / transformedCorners.length,
16028
+ lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION), -1, 1),
16029
+ outlineColor: cuboid.outlineColor,
16030
+ };
16031
+ });
16032
+ return visibleFaces.filter((visibleFace) => visibleFace !== null);
16033
+ }
16034
+ /**
16035
+ * Draws one projected textured face by tessellating its texture cells into quads.
16036
+ *
16037
+ * @param context Canvas 2D context.
16038
+ * @param face Visible projected face.
16039
+ *
16040
+ * @private helper of `minecraft2AvatarVisual`
16041
+ */
16042
+ function drawTexturedProjectedFace(context, face) {
16043
+ var _a;
16044
+ const rows = face.texture.length;
16045
+ const columns = ((_a = face.texture[0]) === null || _a === void 0 ? void 0 : _a.length) || 0;
16046
+ if (rows === 0 || columns === 0) {
16047
+ return;
15761
16048
  }
15762
- texture[2][0] = hairlineColor;
15763
- texture[2][7] = hairlineColor;
15764
- texture[3][0] = hairlineColor;
15765
- texture[3][7] = hairlineColor;
15766
- if (hasHeadband) {
15767
- for (let columnIndex = 0; columnIndex < 8; columnIndex++) {
15768
- texture[2][columnIndex] = palette.accent;
16049
+ for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
16050
+ for (let columnIndex = 0; columnIndex < columns; columnIndex++) {
16051
+ const startX = columnIndex / columns;
16052
+ const endX = (columnIndex + 1) / columns;
16053
+ const startY = rowIndex / rows;
16054
+ const endY = (rowIndex + 1) / rows;
16055
+ drawProjectedQuad(context, [
16056
+ interpolateProjectedQuad(face.corners, startX, startY),
16057
+ interpolateProjectedQuad(face.corners, endX, startY),
16058
+ interpolateProjectedQuad(face.corners, endX, endY),
16059
+ interpolateProjectedQuad(face.corners, startX, endY),
16060
+ ], face.texture[rowIndex][columnIndex]);
15769
16061
  }
15770
16062
  }
15771
- texture[3][2] = palette.ink;
15772
- texture[3][5] = palette.ink;
15773
- texture[4][2] = '#ffffff';
15774
- texture[4][5] = '#ffffff';
15775
- texture[5][1] = cheekColor;
15776
- texture[5][6] = cheekColor;
15777
- texture[5][3] = palette.shadow;
15778
- texture[5][4] = palette.shadow;
15779
- texture[6][3] = palette.shadow;
15780
- texture[6][4] = palette.shadow;
15781
- return texture;
16063
+ if (face.lightIntensity > 0) {
16064
+ drawProjectedQuad(context, face.corners, `rgba(255, 255, 255, ${0.15 * face.lightIntensity})`);
16065
+ }
16066
+ else if (face.lightIntensity < 0) {
16067
+ drawProjectedQuad(context, face.corners, `rgba(0, 0, 0, ${0.22 * Math.abs(face.lightIntensity)})`);
16068
+ }
16069
+ context.save();
16070
+ context.beginPath();
16071
+ context.moveTo(face.corners[0].x, face.corners[0].y);
16072
+ for (let cornerIndex = 1; cornerIndex < face.corners.length; cornerIndex++) {
16073
+ context.lineTo(face.corners[cornerIndex].x, face.corners[cornerIndex].y);
16074
+ }
16075
+ context.closePath();
16076
+ context.strokeStyle = face.outlineColor;
16077
+ context.lineWidth = Math.max(1.1, getProjectedQuadPerimeter(face.corners) * 0.0045);
16078
+ context.lineJoin = 'round';
16079
+ context.stroke();
16080
+ context.restore();
15782
16081
  }
15783
16082
  /**
15784
- * Creates the front-face pixel texture for the torso.
16083
+ * Draws one filled projected quad.
15785
16084
  *
15786
- * @param random Seeded random generator.
15787
- * @param palette Derived avatar palette.
15788
- * @returns 8x8 torso texture.
16085
+ * @param context Canvas 2D context.
16086
+ * @param corners Quad corners in clockwise order.
16087
+ * @param fillStyle CSS fill style.
15789
16088
  *
15790
- * @private helper of `minecraftAvatarVisual`
16089
+ * @private helper of `minecraft2AvatarVisual`
15791
16090
  */
15792
- function createMinecraftShirtTexture(random, palette) {
15793
- const texture = Array.from({ length: 8 }, () => Array.from({ length: 8 }, () => palette.primary));
15794
- const stripeColor = random() < 0.5 ? palette.secondary : palette.highlight;
15795
- for (let rowIndex = 0; rowIndex < 2; rowIndex++) {
15796
- for (let columnIndex = 0; columnIndex < 8; columnIndex++) {
15797
- texture[rowIndex][columnIndex] = palette.shadow;
15798
- }
16091
+ function drawProjectedQuad(context, corners, fillStyle) {
16092
+ context.beginPath();
16093
+ context.moveTo(corners[0].x, corners[0].y);
16094
+ context.lineTo(corners[1].x, corners[1].y);
16095
+ context.lineTo(corners[2].x, corners[2].y);
16096
+ context.lineTo(corners[3].x, corners[3].y);
16097
+ context.closePath();
16098
+ context.fillStyle = fillStyle;
16099
+ context.fill();
16100
+ }
16101
+ /**
16102
+ * Interpolates one point inside a projected quad across both quad axes.
16103
+ *
16104
+ * @param corners Quad corners in clockwise order.
16105
+ * @param horizontalRatio Horizontal ratio in the range `[0, 1]`.
16106
+ * @param verticalRatio Vertical ratio in the range `[0, 1]`.
16107
+ * @returns Interpolated projected point.
16108
+ *
16109
+ * @private helper of `minecraft2AvatarVisual`
16110
+ */
16111
+ function interpolateProjectedQuad(corners, horizontalRatio, verticalRatio) {
16112
+ const topPoint = interpolateProjectedPoint(corners[0], corners[1], horizontalRatio);
16113
+ const bottomPoint = interpolateProjectedPoint(corners[3], corners[2], horizontalRatio);
16114
+ return interpolateProjectedPoint(topPoint, bottomPoint, verticalRatio);
16115
+ }
16116
+ /**
16117
+ * Interpolates between two projected points.
16118
+ *
16119
+ * @param startPoint Start point.
16120
+ * @param endPoint End point.
16121
+ * @param ratio Interpolation ratio in the range `[0, 1]`.
16122
+ * @returns Interpolated projected point.
16123
+ *
16124
+ * @private helper of `minecraft2AvatarVisual`
16125
+ */
16126
+ function interpolateProjectedPoint(startPoint, endPoint, ratio) {
16127
+ return {
16128
+ x: startPoint.x + (endPoint.x - startPoint.x) * ratio,
16129
+ y: startPoint.y + (endPoint.y - startPoint.y) * ratio,
16130
+ z: startPoint.z + (endPoint.z - startPoint.z) * ratio,
16131
+ };
16132
+ }
16133
+ /**
16134
+ * Projects one rotated scene point into canvas coordinates.
16135
+ *
16136
+ * @param point Scene point.
16137
+ * @param size Canvas size in CSS pixels.
16138
+ * @param sceneCenterX Horizontal scene center.
16139
+ * @param sceneCenterY Vertical scene center.
16140
+ * @returns Projected point.
16141
+ *
16142
+ * @private helper of `minecraft2AvatarVisual`
16143
+ */
16144
+ function projectScenePoint(point, size, sceneCenterX, sceneCenterY) {
16145
+ const cameraDistance = size * CAMERA_DISTANCE_RATIO;
16146
+ const perspectiveScale = cameraDistance / Math.max(cameraDistance - point.z, cameraDistance * 0.35);
16147
+ return {
16148
+ x: sceneCenterX + point.x * perspectiveScale,
16149
+ y: sceneCenterY + point.y * perspectiveScale,
16150
+ z: point.z,
16151
+ };
16152
+ }
16153
+ /**
16154
+ * Applies the local cuboid rotations and translation to one scene point.
16155
+ *
16156
+ * @param localPoint Point in cuboid-local space.
16157
+ * @param center Cuboid center in scene space.
16158
+ * @param rotationX Cuboid pitch in radians.
16159
+ * @param rotationY Cuboid yaw in radians.
16160
+ * @returns Transformed scene-space point.
16161
+ *
16162
+ * @private helper of `minecraft2AvatarVisual`
16163
+ */
16164
+ function transformScenePoint(localPoint, center, rotationX, rotationY) {
16165
+ const yawedPoint = rotatePointAroundY(localPoint, rotationY);
16166
+ const pitchedPoint = rotatePointAroundX(yawedPoint, rotationX);
16167
+ return {
16168
+ x: center.x + pitchedPoint.x,
16169
+ y: center.y + pitchedPoint.y,
16170
+ z: center.z + pitchedPoint.z,
16171
+ };
16172
+ }
16173
+ /**
16174
+ * Rotates one point around the local Y axis.
16175
+ *
16176
+ * @param point Source point.
16177
+ * @param angle Rotation angle in radians.
16178
+ * @returns Rotated point.
16179
+ *
16180
+ * @private helper of `minecraft2AvatarVisual`
16181
+ */
16182
+ function rotatePointAroundY(point, angle) {
16183
+ const cosine = Math.cos(angle);
16184
+ const sine = Math.sin(angle);
16185
+ return {
16186
+ x: point.x * cosine + point.z * sine,
16187
+ y: point.y,
16188
+ z: -point.x * sine + point.z * cosine,
16189
+ };
16190
+ }
16191
+ /**
16192
+ * Rotates one point around the local X axis.
16193
+ *
16194
+ * @param point Source point.
16195
+ * @param angle Rotation angle in radians.
16196
+ * @returns Rotated point.
16197
+ *
16198
+ * @private helper of `minecraft2AvatarVisual`
16199
+ */
16200
+ function rotatePointAroundX(point, angle) {
16201
+ const cosine = Math.cos(angle);
16202
+ const sine = Math.sin(angle);
16203
+ return {
16204
+ x: point.x,
16205
+ y: point.y * cosine - point.z * sine,
16206
+ z: point.y * sine + point.z * cosine,
16207
+ };
16208
+ }
16209
+ /**
16210
+ * Subtracts one 3D point from another.
16211
+ *
16212
+ * @param leftPoint Left point.
16213
+ * @param rightPoint Right point.
16214
+ * @returns Difference vector.
16215
+ *
16216
+ * @private helper of `minecraft2AvatarVisual`
16217
+ */
16218
+ function subtractPoint3D(leftPoint, rightPoint) {
16219
+ return {
16220
+ x: leftPoint.x - rightPoint.x,
16221
+ y: leftPoint.y - rightPoint.y,
16222
+ z: leftPoint.z - rightPoint.z,
16223
+ };
16224
+ }
16225
+ /**
16226
+ * Computes the 3D cross product of two vectors.
16227
+ *
16228
+ * @param leftVector Left vector.
16229
+ * @param rightVector Right vector.
16230
+ * @returns Cross product.
16231
+ *
16232
+ * @private helper of `minecraft2AvatarVisual`
16233
+ */
16234
+ function crossProduct3D(leftVector, rightVector) {
16235
+ return {
16236
+ x: leftVector.y * rightVector.z - leftVector.z * rightVector.y,
16237
+ y: leftVector.z * rightVector.x - leftVector.x * rightVector.z,
16238
+ z: leftVector.x * rightVector.y - leftVector.y * rightVector.x,
16239
+ };
16240
+ }
16241
+ /**
16242
+ * Computes the 3D dot product of two vectors.
16243
+ *
16244
+ * @param leftVector Left vector.
16245
+ * @param rightVector Right vector.
16246
+ * @returns Dot product.
16247
+ *
16248
+ * @private helper of `minecraft2AvatarVisual`
16249
+ */
16250
+ function dotProduct3D(leftVector, rightVector) {
16251
+ return leftVector.x * rightVector.x + leftVector.y * rightVector.y + leftVector.z * rightVector.z;
16252
+ }
16253
+ /**
16254
+ * Normalizes one 3D vector while keeping zero vectors stable.
16255
+ *
16256
+ * @param vector Source vector.
16257
+ * @returns Normalized vector.
16258
+ *
16259
+ * @private helper of `minecraft2AvatarVisual`
16260
+ */
16261
+ function normalizeVector3(vector) {
16262
+ const length = Math.hypot(vector.x, vector.y, vector.z);
16263
+ if (length === 0) {
16264
+ return vector;
15799
16265
  }
15800
- for (let rowIndex = 2; rowIndex < 8; rowIndex++) {
15801
- texture[rowIndex][3] = stripeColor;
15802
- texture[rowIndex][4] = stripeColor;
16266
+ return {
16267
+ x: vector.x / length,
16268
+ y: vector.y / length,
16269
+ z: vector.z / length,
16270
+ };
16271
+ }
16272
+ /**
16273
+ * Clamps one number into the provided range.
16274
+ *
16275
+ * @param value Input value.
16276
+ * @param minimumValue Inclusive lower bound.
16277
+ * @param maximumValue Inclusive upper bound.
16278
+ * @returns Clamped value.
16279
+ *
16280
+ * @private helper of `minecraft2AvatarVisual`
16281
+ */
16282
+ function clampNumber$1(value, minimumValue, maximumValue) {
16283
+ return Math.min(maximumValue, Math.max(minimumValue, value));
16284
+ }
16285
+ /**
16286
+ * Measures the perimeter of one projected quad.
16287
+ *
16288
+ * @param corners Quad corners.
16289
+ * @returns Perimeter length.
16290
+ *
16291
+ * @private helper of `minecraft2AvatarVisual`
16292
+ */
16293
+ function getProjectedQuadPerimeter(corners) {
16294
+ let perimeter = 0;
16295
+ for (let cornerIndex = 0; cornerIndex < corners.length; cornerIndex++) {
16296
+ const currentCorner = corners[cornerIndex];
16297
+ const nextCorner = corners[(cornerIndex + 1) % corners.length];
16298
+ perimeter += Math.hypot(nextCorner.x - currentCorner.x, nextCorner.y - currentCorner.y);
15803
16299
  }
15804
- texture[4][1] = palette.accent;
15805
- texture[4][6] = palette.accent;
15806
- texture[5][2] = palette.highlight;
15807
- texture[5][5] = palette.highlight;
15808
- return texture;
16300
+ return perimeter;
15809
16301
  }
15810
16302
 
15811
16303
  /* eslint-disable no-magic-numbers */
@@ -17410,6 +17902,7 @@
17410
17902
  octopus3AvatarVisual,
17411
17903
  asciiOctopusAvatarVisual,
17412
17904
  minecraftAvatarVisual,
17905
+ minecraft2AvatarVisual,
17413
17906
  fractalAvatarVisual,
17414
17907
  orbAvatarVisual,
17415
17908
  ];
@@ -18712,7 +19205,11 @@
18712
19205
  // Create new system message with persona at the beginning
18713
19206
  // Format: "You are {agentName}\n{personaContent}"
18714
19207
  // The # PERSONA comment will be removed later by removeCommentsFromSystemMessage
18715
- const personaSection = `# PERSONA\nYou are ${agentName}\n${mergedPersonaContent}`; // <- TODO: Use spaceTrim
19208
+ const personaSection = _spaceTrim.spaceTrim((block) => `
19209
+ # PERSONA
19210
+ You are ${agentName}
19211
+ ${block(mergedPersonaContent)}
19212
+ `);
18716
19213
  const newSystemMessage = cleanedMessage ? `${personaSection}\n\n${cleanedMessage}` : personaSection;
18717
19214
  return {
18718
19215
  ...requirements,
@@ -19614,7 +20111,10 @@
19614
20111
  */
19615
20112
  function buildTeamToolDescription(entry) {
19616
20113
  const detailLines = collectTeamEntryDetails(entry).map(({ label, content }) => `${label}: ${content}`);
19617
- return [`Consult teammate ${entry.teammate.label}`, ...detailLines].join('\n');
20114
+ return _spaceTrim.spaceTrim((block) => `
20115
+ Consult teammate ${entry.teammate.label}
20116
+ ${block(detailLines.join('\n'))}
20117
+ `);
19618
20118
  }
19619
20119
  /**
19620
20120
  * Collects structured teammate details that should stay visible to the model.
@@ -25111,7 +25611,10 @@
25111
25611
  if (hiddenCount > 0) {
25112
25612
  summaryRows.push(`...and ${hiddenCount} more.`);
25113
25613
  }
25114
- return [`Found ${options.total} ${options.total === 1 ? 'timeout' : 'timeouts'}:`, ...summaryRows].join('\n');
25614
+ return _spaceTrim.spaceTrim((block) => `
25615
+ Found ${options.total} ${options.total === 1 ? 'timeout' : 'timeouts'}:
25616
+ ${block(summaryRows.join('\n'))}
25617
+ `);
25115
25618
  }
25116
25619
  /**
25117
25620
  * Formats one timeout row for assistant-visible timeout listings.
@@ -28080,8 +28583,10 @@
28080
28583
  **Application mode:** ${serverInfo.isApplicationModeAllowed ? 'enabled' : 'disabled'}
28081
28584
  ${block(!runtime.configuration.isApplicationModeAllowed || runtime.configuration.collection === null
28082
28585
  ? ''
28083
- : '**Pipelines in collection:**\n' +
28084
- serverInfo.pipelines.map((pipelineUrl) => `- ${pipelineUrl}`).join('\n'))}
28586
+ : _spaceTrim.spaceTrim((nestedBlock) => `
28587
+ **Pipelines in collection:**
28588
+ ${nestedBlock(serverInfo.pipelines.map((pipelineUrl) => `- ${pipelineUrl}`).join('\n'))}
28589
+ `))}
28085
28590
  **Running executions:** ${serverInfo.runningExecutions}
28086
28591
 
28087
28592
  ---
@@ -31075,11 +31580,11 @@
31075
31580
  if (attachments.length === 0) {
31076
31581
  return '';
31077
31582
  }
31078
- return [
31079
- CHAT_ATTACHMENTS_HEADING,
31080
- ...attachments.map((attachment) => formatChatAttachmentLine(attachment)),
31081
- CHAT_ATTACHMENTS_INSTRUCTION,
31082
- ].join('\n');
31583
+ return _spaceTrim.spaceTrim((block) => `
31584
+ ${CHAT_ATTACHMENTS_HEADING}
31585
+ ${block(attachments.map((attachment) => formatChatAttachmentLine(attachment)).join('\n'))}
31586
+ ${CHAT_ATTACHMENTS_INSTRUCTION}
31587
+ `);
31083
31588
  }
31084
31589
 
31085
31590
  /**
@@ -31320,24 +31825,24 @@
31320
31825
  : ''}`
31321
31826
  : null;
31322
31827
  const warningsLine = contentResolution.warnings.length > 0 ? `Warnings: ${contentResolution.warnings.join(' | ')}` : null;
31323
- if (!contentResolution.content) {
31828
+ const metadataLines = [decodingLine, warningsLine].filter((line) => Boolean(line)).join('\n');
31829
+ const resolvedContent = contentResolution.content;
31830
+ if (!resolvedContent) {
31324
31831
  const reason = contentResolution.reason || 'content unavailable';
31325
- return [`- ${attachmentLabel}: ${reason}. URL: ${contentResolution.attachment.url}`, decodingLine, warningsLine]
31326
- .filter(Boolean)
31327
- .join('\n');
31832
+ return _spaceTrim.spaceTrim((block) => `
31833
+ - ${attachmentLabel}: ${reason}. URL: ${contentResolution.attachment.url}
31834
+ ${block(metadataLines)}
31835
+ `);
31328
31836
  }
31329
31837
  const truncatedLabel = contentResolution.isTruncated ? ' [truncated]' : '';
31330
- return [
31331
- `File: ${attachmentLabel}${truncatedLabel}`,
31332
- `URL: ${contentResolution.attachment.url}`,
31333
- decodingLine,
31334
- warningsLine,
31335
- '```text',
31336
- contentResolution.content,
31337
- '```',
31338
- ]
31339
- .filter(Boolean)
31340
- .join('\n');
31838
+ return _spaceTrim.spaceTrim((block) => `
31839
+ File: ${attachmentLabel}${truncatedLabel}
31840
+ URL: ${contentResolution.attachment.url}
31841
+ ${block(metadataLines)}
31842
+ \`\`\`text
31843
+ ${block(resolvedContent)}
31844
+ \`\`\`
31845
+ `);
31341
31846
  }
31342
31847
  /**
31343
31848
  * Formats inline attachment-content context section for the model.
@@ -31351,11 +31856,14 @@
31351
31856
  if (resolvedContents.length === 0) {
31352
31857
  return '';
31353
31858
  }
31354
- return [
31355
- CHAT_ATTACHMENT_CONTENT_HEADING,
31356
- CHAT_ATTACHMENT_CONTENT_INSTRUCTION,
31357
- ...resolvedContents.map((resolvedContent) => formatResolvedChatAttachmentContent(resolvedContent)),
31358
- ].join('\n\n');
31859
+ return _spaceTrim.spaceTrim((block) => `
31860
+ ${CHAT_ATTACHMENT_CONTENT_HEADING}
31861
+ ${CHAT_ATTACHMENT_CONTENT_INSTRUCTION}
31862
+
31863
+ ${block(resolvedContents
31864
+ .map((resolvedContent) => formatResolvedChatAttachmentContent(resolvedContent))
31865
+ .join('\n\n'))}
31866
+ `);
31359
31867
  }
31360
31868
 
31361
31869
  /**
@@ -32500,9 +33008,11 @@
32500
33008
  * Creates the retry-history error message shared by all OpenAI-compatible model variants.
32501
33009
  */
32502
33010
  createAttemptHistoryError(finalErrorMessage) {
32503
- return new PipelineExecutionError(`All attempts failed. Attempt history:\n` +
32504
- formatUnsupportedParameterAttemptHistory(this.attemptStack) +
32505
- `\nFinal error: ${finalErrorMessage}`);
33011
+ return new PipelineExecutionError(_spaceTrim.spaceTrim((block) => `
33012
+ All attempts failed. Attempt history:
33013
+ ${block(formatUnsupportedParameterAttemptHistory(this.attemptStack))}
33014
+ Final error: ${finalErrorMessage}
33015
+ `));
32506
33016
  }
32507
33017
  }
32508
33018
 
@@ -35096,7 +35606,7 @@
35096
35606
  });
35097
35607
  }
35098
35608
  let vectorStoreId = cachedVectorStoreId;
35099
- if (this.isNativeKnowledgeSearchEnabled && !vectorStoreId && knowledgeSources && knowledgeSources.length > 0) {
35609
+ if (!vectorStoreId && knowledgeSources && knowledgeSources.length > 0) {
35100
35610
  const vectorStoreResult = await this.createVectorStoreWithKnowledgeSources({
35101
35611
  client: await this.getClient(),
35102
35612
  name,
@@ -35105,19 +35615,13 @@
35105
35615
  });
35106
35616
  vectorStoreId = vectorStoreResult.vectorStoreId;
35107
35617
  }
35108
- else if (this.isNativeKnowledgeSearchEnabled && vectorStoreId && this.options.isVerbose) {
35618
+ else if (vectorStoreId && this.options.isVerbose) {
35109
35619
  console.info('[🤰]', 'Using cached vector store for AgentKit agent', {
35110
35620
  name,
35111
35621
  vectorStoreId,
35112
35622
  });
35113
35623
  }
35114
- if (!this.isNativeKnowledgeSearchEnabled) {
35115
- vectorStoreId = undefined;
35116
- }
35117
- const agentKitTools = this.buildAgentKitTools({
35118
- tools,
35119
- vectorStoreId,
35120
- });
35624
+ const agentKitTools = this.buildAgentKitTools({ tools, vectorStoreId });
35121
35625
  const openAiAgentKitAgent = new agents.Agent({
35122
35626
  name,
35123
35627
  model: this.agentKitModelName,
@@ -35136,7 +35640,7 @@
35136
35640
  name,
35137
35641
  model: this.agentKitModelName,
35138
35642
  toolCount: agentKitTools.length,
35139
- hasVectorStore: this.isNativeKnowledgeSearchEnabled && Boolean(vectorStoreId),
35643
+ hasVectorStore: Boolean(vectorStoreId),
35140
35644
  });
35141
35645
  }
35142
35646
  return preparedAgent;
@@ -35635,12 +36139,6 @@
35635
36139
  get agentKitOptions() {
35636
36140
  return this.options;
35637
36141
  }
35638
- /**
35639
- * Returns true when hosted OpenAI vector-store search should back `knowledgeSources`.
35640
- */
35641
- get isNativeKnowledgeSearchEnabled() {
35642
- return this.agentKitOptions.isNativeKnowledgeSearchEnabled !== false;
35643
- }
35644
36142
  /**
35645
36143
  * Discriminant for type guards.
35646
36144
  */