@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/esm/index.es.js CHANGED
@@ -1,4 +1,4 @@
1
- import { join, basename, dirname, isAbsolute } from 'path';
1
+ import { posix, join, basename, dirname, isAbsolute } from 'path';
2
2
  import { spawn } from 'child_process';
3
3
  import colors from 'colors';
4
4
  import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
@@ -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-64';
43
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-66';
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
@@ -959,6 +959,29 @@ function saturate(amount) {
959
959
  }
960
960
  // TODO: Maybe implement by mix+hsl
961
961
 
962
+ /**
963
+ * Relative directory name without the `./` prefix for Git ignore rules and glob patterns.
964
+ *
965
+ * @private internal utility for Promptbook-owned temp files
966
+ */
967
+ const PROMPTBOOK_TEMP_DIRECTORY_NAME = '.promptbook';
968
+ /**
969
+ * Builds one project-relative path inside the shared Promptbook working directory.
970
+ *
971
+ * @private internal utility for Promptbook-owned temp files
972
+ */
973
+ function getPromptbookTempPath(...pathSegments) {
974
+ return `./${getPromptbookTempPosixPath(...pathSegments)}`;
975
+ }
976
+ /**
977
+ * Builds one POSIX path fragment inside the shared Promptbook working directory for globs and generated text files.
978
+ *
979
+ * @private internal utility for Promptbook-owned temp files
980
+ */
981
+ function getPromptbookTempPosixPath(...pathSegments) {
982
+ return posix.join(PROMPTBOOK_TEMP_DIRECTORY_NAME, ...pathSegments);
983
+ }
984
+
962
985
  /**
963
986
  * Returns the same value that is passed as argument.
964
987
  * No side effects.
@@ -1149,7 +1172,6 @@ const DEFAULT_MAX_PARALLEL_COUNT = 5; // <- TODO: [🤹‍♂️]
1149
1172
  */
1150
1173
  const DEFAULT_MAX_EXECUTION_ATTEMPTS = 7; // <- TODO: [🤹‍♂️]
1151
1174
  // <- TODO: [🕝] Make also `AGENTS_DIRNAME_ALTERNATIVES`
1152
- // TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
1153
1175
  /**
1154
1176
  * Where to store the temporary downloads
1155
1177
  *
@@ -1157,7 +1179,15 @@ const DEFAULT_MAX_EXECUTION_ATTEMPTS = 7; // <- TODO: [🤹‍♂️]
1157
1179
  *
1158
1180
  * @public exported from `@promptbook/core`
1159
1181
  */
1160
- const DEFAULT_DOWNLOAD_CACHE_DIRNAME = './.promptbook/download-cache';
1182
+ const DEFAULT_DOWNLOAD_CACHE_DIRNAME = getPromptbookTempPath('download-cache');
1183
+ /**
1184
+ * Where to store the cache of executions for promptbook CLI
1185
+ *
1186
+ * Note: When the folder does not exist, it is created recursively
1187
+ *
1188
+ * @public exported from `@promptbook/core`
1189
+ */
1190
+ getPromptbookTempPath('execution-cache');
1161
1191
  /**
1162
1192
  * Where to store the scrape cache
1163
1193
  *
@@ -1165,7 +1195,7 @@ const DEFAULT_DOWNLOAD_CACHE_DIRNAME = './.promptbook/download-cache';
1165
1195
  *
1166
1196
  * @public exported from `@promptbook/core`
1167
1197
  */
1168
- const DEFAULT_SCRAPE_CACHE_DIRNAME = './.promptbook/scrape-cache';
1198
+ const DEFAULT_SCRAPE_CACHE_DIRNAME = getPromptbookTempPath('scrape-cache');
1169
1199
  // <- TODO: [🧜‍♂️]
1170
1200
  /**
1171
1201
  * Default settings for parsing and generating CSV files in Promptbook.
@@ -12679,18 +12709,6 @@ function parseDataUrlKnowledgeSource(source) {
12679
12709
  }
12680
12710
  // Note: [💞] Ignore a discrepancy between file name and entity name
12681
12711
 
12682
- /**
12683
- * Name of the tool used by agents to search configured `KNOWLEDGE` sources.
12684
- *
12685
- * @public exported from `@promptbook/core`
12686
- */
12687
- const KNOWLEDGE_SEARCH_TOOL_NAME = 'knowledge_search';
12688
- /**
12689
- * Title of the system-message section generated for `KNOWLEDGE` commitments.
12690
- *
12691
- * @private constant of `KnowledgeCommitmentDefinition`
12692
- */
12693
- const KNOWLEDGE_SEARCH_SYSTEM_SECTION_TITLE = 'Knowledge Search';
12694
12712
  /**
12695
12713
  * KNOWLEDGE commitment definition
12696
12714
  *
@@ -12812,17 +12830,9 @@ class KnowledgeCommitmentDefinition extends BaseCommitmentDefinition {
12812
12830
  knowledgeInfoEntries.push(`Knowledge Source Inline: ${inlineSource.filename} (derived from inline content and processed for retrieval during chat)`);
12813
12831
  }
12814
12832
  if (knowledgeInfoEntries.length === 0) {
12815
- return addKnowledgeSearchToolAndSystemSection(nextRequirements);
12833
+ return nextRequirements;
12816
12834
  }
12817
- return addKnowledgeSearchToolAndSystemSection(nextRequirements);
12818
- }
12819
- /**
12820
- * Gets human-readable titles for tool functions provided by this commitment.
12821
- */
12822
- getToolTitles() {
12823
- return {
12824
- [KNOWLEDGE_SEARCH_TOOL_NAME]: 'Knowledge search',
12825
- };
12835
+ return this.appendToSystemMessage(nextRequirements, knowledgeInfoEntries.join('\n'), '\n\n');
12826
12836
  }
12827
12837
  }
12828
12838
  /**
@@ -12836,128 +12846,6 @@ function hasMeaningfulNonUrlText(content, urls) {
12836
12846
  const significantText = contentWithoutUrls.replace(/[\s.,!?;:'"`()[\]{}<>/-]+/g, '');
12837
12847
  return significantText.length > 0;
12838
12848
  }
12839
- /**
12840
- * Adds the shared `knowledge_search` tool definition and the consolidated system-message section.
12841
- *
12842
- * @param requirements - Requirements after one `KNOWLEDGE` commitment was applied.
12843
- * @returns Requirements with the knowledge search instructions and tool definition.
12844
- *
12845
- * @private internal utility of `KnowledgeCommitmentDefinition`
12846
- */
12847
- function addKnowledgeSearchToolAndSystemSection(requirements) {
12848
- const nextRequirements = addKnowledgeSearchTool(requirements);
12849
- const section = createKnowledgeSearchSystemSection(nextRequirements);
12850
- const sectionHeader = `## ${KNOWLEDGE_SEARCH_SYSTEM_SECTION_TITLE}`;
12851
- if (nextRequirements.systemMessage.includes(sectionHeader)) {
12852
- return {
12853
- ...nextRequirements,
12854
- systemMessage: nextRequirements.systemMessage.replace(new RegExp(`## ${KNOWLEDGE_SEARCH_SYSTEM_SECTION_TITLE.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\s\\S]*?(?=\\n\\n##|$)`), section),
12855
- };
12856
- }
12857
- return {
12858
- ...nextRequirements,
12859
- systemMessage: nextRequirements.systemMessage.trim()
12860
- ? `${nextRequirements.systemMessage}\n\n${section}`
12861
- : section,
12862
- };
12863
- }
12864
- /**
12865
- * Adds the `knowledge_search` model tool when it is not already present.
12866
- *
12867
- * @param requirements - Current model requirements.
12868
- * @returns Requirements with the tool definition available to the model.
12869
- *
12870
- * @private internal utility of `KnowledgeCommitmentDefinition`
12871
- */
12872
- function addKnowledgeSearchTool(requirements) {
12873
- const existingTools = requirements.tools || [];
12874
- if (existingTools.some((tool) => tool.name === KNOWLEDGE_SEARCH_TOOL_NAME)) {
12875
- return requirements;
12876
- }
12877
- return {
12878
- ...requirements,
12879
- tools: [
12880
- ...existingTools,
12881
- {
12882
- name: KNOWLEDGE_SEARCH_TOOL_NAME,
12883
- description: spaceTrim$1(`
12884
- Search the agent's configured knowledge sources and return relevant excerpts with citation ids.
12885
- Use this before answering questions that may depend on the agent's KNOWLEDGE commitments.
12886
- `),
12887
- parameters: {
12888
- type: 'object',
12889
- properties: {
12890
- query: {
12891
- type: 'string',
12892
- description: 'The natural-language search query for the knowledge base.',
12893
- },
12894
- limit: {
12895
- type: 'integer',
12896
- description: 'Maximum number of matching source excerpts to return.',
12897
- },
12898
- },
12899
- required: ['query'],
12900
- },
12901
- },
12902
- ],
12903
- };
12904
- }
12905
- /**
12906
- * Creates the model-facing system-message section for knowledge search.
12907
- *
12908
- * @param requirements - Current model requirements.
12909
- * @returns Markdown system-message section.
12910
- *
12911
- * @private internal utility of `KnowledgeCommitmentDefinition`
12912
- */
12913
- function createKnowledgeSearchSystemSection(requirements) {
12914
- const sourceEntries = createKnowledgeSourceSystemEntries(requirements);
12915
- const sourceList = sourceEntries.length > 0 ? sourceEntries.map((entry) => `- ${entry}`).join('\n') : '- None';
12916
- return spaceTrim$1(`
12917
- ## ${KNOWLEDGE_SEARCH_SYSTEM_SECTION_TITLE}
12918
-
12919
- - Use \`${KNOWLEDGE_SEARCH_TOOL_NAME}\` to search the configured knowledge sources before answering questions that depend on this agent's knowledge base.
12920
- - Base source-backed factual answers on the returned excerpts.
12921
- - When you use a returned excerpt, include its citation marker in the answer body, for example \`[0:0]\`.
12922
- - If the search returns no relevant information, say that the knowledge base did not contain the answer instead of inventing it.
12923
-
12924
- Configured knowledge sources:
12925
- ${sourceList}
12926
- `);
12927
- }
12928
- /**
12929
- * Builds a stable list of configured knowledge sources for system-message diagnostics.
12930
- *
12931
- * @param requirements - Current model requirements.
12932
- * @returns Human-readable source entries.
12933
- *
12934
- * @private internal utility of `KnowledgeCommitmentDefinition`
12935
- */
12936
- function createKnowledgeSourceSystemEntries(requirements) {
12937
- var _a;
12938
- const entries = [];
12939
- const seenEntries = new Set();
12940
- for (const source of requirements.knowledgeSources || []) {
12941
- const entry = `Source URL: ${source} (processed for retrieval during chat)`;
12942
- if (seenEntries.has(entry)) {
12943
- continue;
12944
- }
12945
- seenEntries.add(entry);
12946
- entries.push(entry);
12947
- }
12948
- const inlineSources = (((_a = requirements._metadata) === null || _a === void 0 ? void 0 : _a.inlineKnowledgeSources) || [])
12949
- .map((source) => source.filename)
12950
- .filter(Boolean);
12951
- for (const filename of inlineSources) {
12952
- const entry = `Knowledge Source Inline: ${filename} (Inline source: processed for retrieval during chat)`;
12953
- if (seenEntries.has(entry)) {
12954
- continue;
12955
- }
12956
- seenEntries.add(entry);
12957
- entries.push(entry);
12958
- }
12959
- return entries;
12960
- }
12961
12849
 
12962
12850
  /**
12963
12851
  * LANGUAGE commitment definition
@@ -15609,6 +15497,177 @@ function drawFractalCore(context, size, palette, timeMs, corePhase) {
15609
15497
  context.restore();
15610
15498
  }
15611
15499
 
15500
+ /* eslint-disable no-magic-numbers */
15501
+ /**
15502
+ * Builds the seeded six-face texture pack used by the Minecraft-style head cuboid.
15503
+ *
15504
+ * @param random Seeded random generator.
15505
+ * @param palette Derived avatar palette.
15506
+ * @param hasHeadband Whether the generated avatar should include a colored headband.
15507
+ * @returns Head cuboid textures.
15508
+ *
15509
+ * @private helper of the Minecraft avatar visuals
15510
+ */
15511
+ function createMinecraftHeadTextures(random, palette, hasHeadband) {
15512
+ const faceTexture = createMinecraftFaceTexture(random, palette, hasHeadband);
15513
+ const hairColor = random() < 0.5 ? palette.primary : palette.secondary;
15514
+ const skinColor = palette.highlight;
15515
+ const headbandColor = hasHeadband ? palette.accent : hairColor;
15516
+ const sideTexture = createFilledTexture(skinColor);
15517
+ const backTexture = createFilledTexture(skinColor);
15518
+ const topTexture = createFilledTexture(hairColor);
15519
+ const bottomTexture = createFilledTexture(`${palette.shadow}cc`);
15520
+ fillTextureRect(sideTexture, 0, 0, 8, 3, hairColor);
15521
+ fillTextureRect(backTexture, 0, 0, 8, 5, hairColor);
15522
+ fillTextureRect(backTexture, 1, 5, 6, 1, hairColor);
15523
+ if (hasHeadband) {
15524
+ fillTextureRect(sideTexture, 0, 2, 8, 1, headbandColor);
15525
+ fillTextureRect(backTexture, 0, 2, 8, 1, headbandColor);
15526
+ fillTextureRect(topTexture, 0, 4, 8, 1, headbandColor);
15527
+ }
15528
+ sideTexture[4][4] = `${palette.shadow}99`;
15529
+ sideTexture[5][4] = `${palette.shadow}cc`;
15530
+ backTexture[6][2] = `${palette.shadow}99`;
15531
+ backTexture[6][5] = `${palette.shadow}99`;
15532
+ return {
15533
+ front: faceTexture,
15534
+ back: backTexture,
15535
+ left: sideTexture,
15536
+ right: mirrorMinecraftTexture(sideTexture),
15537
+ top: topTexture,
15538
+ bottom: bottomTexture,
15539
+ };
15540
+ }
15541
+ /**
15542
+ * Builds the seeded six-face texture pack used by the Minecraft-style torso cuboid.
15543
+ *
15544
+ * @param random Seeded random generator.
15545
+ * @param palette Derived avatar palette.
15546
+ * @returns Torso cuboid textures.
15547
+ *
15548
+ * @private helper of the Minecraft avatar visuals
15549
+ */
15550
+ function createMinecraftTorsoTextures(random, palette) {
15551
+ const frontTexture = createMinecraftShirtTexture(random, palette);
15552
+ const sideTexture = createFilledTexture(palette.primary);
15553
+ const backTexture = createFilledTexture(palette.primary);
15554
+ const topTexture = createFilledTexture(`${palette.highlight}dd`);
15555
+ const bottomTexture = createFilledTexture(`${palette.shadow}dd`);
15556
+ const stripeColor = random() < 0.5 ? palette.secondary : palette.highlight;
15557
+ fillTextureRect(sideTexture, 0, 0, 8, 2, palette.shadow);
15558
+ fillTextureRect(backTexture, 0, 0, 8, 2, palette.shadow);
15559
+ fillTextureRect(backTexture, 3, 2, 2, 6, stripeColor);
15560
+ fillTextureRect(sideTexture, 4, 2, 1, 6, stripeColor);
15561
+ fillTextureRect(topTexture, 0, 0, 8, 2, palette.shadow);
15562
+ fillTextureRect(topTexture, 2, 2, 4, 4, stripeColor);
15563
+ return {
15564
+ front: frontTexture,
15565
+ back: backTexture,
15566
+ left: sideTexture,
15567
+ right: mirrorMinecraftTexture(sideTexture),
15568
+ top: topTexture,
15569
+ bottom: bottomTexture,
15570
+ };
15571
+ }
15572
+ /**
15573
+ * Mirrors one Minecraft texture horizontally.
15574
+ *
15575
+ * @param texture Source texture.
15576
+ * @returns Mirrored texture copy.
15577
+ *
15578
+ * @private helper of the Minecraft avatar visuals
15579
+ */
15580
+ function mirrorMinecraftTexture(texture) {
15581
+ return texture.map((row) => [...row].reverse());
15582
+ }
15583
+ /**
15584
+ * Creates the front-face pixel texture for the cube head.
15585
+ *
15586
+ * @param random Seeded random generator.
15587
+ * @param palette Derived avatar palette.
15588
+ * @param hasHeadband Whether the avatar should render a headband row.
15589
+ * @returns 8x8 pixel texture.
15590
+ *
15591
+ * @private helper of the Minecraft avatar visuals
15592
+ */
15593
+ function createMinecraftFaceTexture(random, palette, hasHeadband) {
15594
+ const texture = createFilledTexture(palette.highlight);
15595
+ const hairlineColor = random() < 0.5 ? palette.primary : palette.secondary;
15596
+ const cheekColor = random() < 0.5 ? `${palette.accent}bb` : `${palette.secondary}bb`;
15597
+ fillTextureRect(texture, 0, 0, 8, 2, hairlineColor);
15598
+ texture[2][0] = hairlineColor;
15599
+ texture[2][7] = hairlineColor;
15600
+ texture[3][0] = hairlineColor;
15601
+ texture[3][7] = hairlineColor;
15602
+ if (hasHeadband) {
15603
+ fillTextureRect(texture, 0, 2, 8, 1, palette.accent);
15604
+ }
15605
+ texture[3][2] = palette.ink;
15606
+ texture[3][5] = palette.ink;
15607
+ texture[4][2] = '#ffffff';
15608
+ texture[4][5] = '#ffffff';
15609
+ texture[5][1] = cheekColor;
15610
+ texture[5][6] = cheekColor;
15611
+ texture[5][3] = palette.shadow;
15612
+ texture[5][4] = palette.shadow;
15613
+ texture[6][3] = palette.shadow;
15614
+ texture[6][4] = palette.shadow;
15615
+ return texture;
15616
+ }
15617
+ /**
15618
+ * Creates the front-face pixel texture for the torso.
15619
+ *
15620
+ * @param random Seeded random generator.
15621
+ * @param palette Derived avatar palette.
15622
+ * @returns 8x8 torso texture.
15623
+ *
15624
+ * @private helper of the Minecraft avatar visuals
15625
+ */
15626
+ function createMinecraftShirtTexture(random, palette) {
15627
+ const texture = createFilledTexture(palette.primary);
15628
+ const stripeColor = random() < 0.5 ? palette.secondary : palette.highlight;
15629
+ fillTextureRect(texture, 0, 0, 8, 2, palette.shadow);
15630
+ for (let rowIndex = 2; rowIndex < 8; rowIndex++) {
15631
+ texture[rowIndex][3] = stripeColor;
15632
+ texture[rowIndex][4] = stripeColor;
15633
+ }
15634
+ texture[4][1] = palette.accent;
15635
+ texture[4][6] = palette.accent;
15636
+ texture[5][2] = palette.highlight;
15637
+ texture[5][5] = palette.highlight;
15638
+ return texture;
15639
+ }
15640
+ /**
15641
+ * Creates one solid-color 8x8 Minecraft texture.
15642
+ *
15643
+ * @param color Fill color.
15644
+ * @returns Filled 8x8 texture.
15645
+ *
15646
+ * @private helper of the Minecraft avatar visuals
15647
+ */
15648
+ function createFilledTexture(color) {
15649
+ return Array.from({ length: 8 }, () => Array.from({ length: 8 }, () => color));
15650
+ }
15651
+ /**
15652
+ * Fills one rectangular area inside a mutable Minecraft texture.
15653
+ *
15654
+ * @param texture Mutable target texture.
15655
+ * @param x Left texture coordinate.
15656
+ * @param y Top texture coordinate.
15657
+ * @param width Rectangle width.
15658
+ * @param height Rectangle height.
15659
+ * @param color Fill color.
15660
+ *
15661
+ * @private helper of the Minecraft avatar visuals
15662
+ */
15663
+ function fillTextureRect(texture, x, y, width, height, color) {
15664
+ for (let rowIndex = y; rowIndex < y + height; rowIndex++) {
15665
+ for (let columnIndex = x; columnIndex < x + width; columnIndex++) {
15666
+ texture[rowIndex][columnIndex] = color;
15667
+ }
15668
+ }
15669
+ }
15670
+
15612
15671
  /* eslint-disable no-magic-numbers */
15613
15672
  /**
15614
15673
  * Minecraft-style 3D avatar visual.
@@ -15633,8 +15692,8 @@ const minecraftAvatarVisual = {
15633
15692
  const bodyX = size * 0.33;
15634
15693
  const bodyY = headY + headSize * 0.96;
15635
15694
  const hasHeadband = random() < 0.5;
15636
- const faceTexture = createMinecraftFaceTexture(createRandom('minecraft-face'), palette, hasHeadband);
15637
- const shirtTexture = createMinecraftShirtTexture(createRandom('minecraft-shirt'), palette);
15695
+ const headTextures = createMinecraftHeadTextures(createRandom('minecraft-face'), palette, hasHeadband);
15696
+ const torsoTextures = createMinecraftTorsoTextures(createRandom('minecraft-shirt'), palette);
15638
15697
  drawAvatarFrame(context, size, palette);
15639
15698
  const spotlight = context.createRadialGradient(size * 0.5, size * 0.18, size * 0.05, size * 0.5, size * 0.18, size * 0.5);
15640
15699
  spotlight.addColorStop(0, `${palette.highlight}66`);
@@ -15654,7 +15713,7 @@ const minecraftAvatarVisual = {
15654
15713
  width: bodyWidth,
15655
15714
  height: bodyHeight,
15656
15715
  depth: bodyDepth,
15657
- frontTexture: shirtTexture,
15716
+ frontTexture: torsoTextures.front,
15658
15717
  topColor: `${palette.highlight}cc`,
15659
15718
  sideColor: `${palette.secondary}dd`,
15660
15719
  outlineColor: `${palette.shadow}aa`,
@@ -15665,7 +15724,7 @@ const minecraftAvatarVisual = {
15665
15724
  width: headSize,
15666
15725
  height: headSize,
15667
15726
  depth,
15668
- frontTexture: faceTexture,
15727
+ frontTexture: headTextures.front,
15669
15728
  topColor: `${palette.highlight}ee`,
15670
15729
  sideColor: `${palette.secondary}ee`,
15671
15730
  outlineColor: `${palette.shadow}cc`,
@@ -15730,72 +15789,505 @@ function drawVoxelCuboid(context, cuboid) {
15730
15789
  context.closePath();
15731
15790
  context.stroke();
15732
15791
  }
15792
+
15793
+ /* eslint-disable no-magic-numbers */
15733
15794
  /**
15734
- * Creates the front-face pixel texture for the cube head.
15795
+ * Fixed scene camera distance used for the proper-3D projection.
15735
15796
  *
15736
- * @param random Seeded random generator.
15797
+ * @private helper of `minecraft2AvatarVisual`
15798
+ */
15799
+ const CAMERA_DISTANCE_RATIO = 1.4;
15800
+ /**
15801
+ * Shared light direction used to shade projected cuboid faces.
15802
+ *
15803
+ * @private helper of `minecraft2AvatarVisual`
15804
+ */
15805
+ const LIGHT_DIRECTION = normalizeVector3({
15806
+ x: 0.4,
15807
+ y: -0.65,
15808
+ z: 0.92,
15809
+ });
15810
+ /**
15811
+ * Minecraft 3D 2 avatar visual.
15812
+ *
15813
+ * @private built-in avatar visual
15814
+ */
15815
+ const minecraft2AvatarVisual = {
15816
+ id: 'minecraft2',
15817
+ title: 'Minecraft 3D 2',
15818
+ description: 'Proper 3D Minecraft-style portrait with textured cuboids and pointer-driven head turns.',
15819
+ isAnimated: true,
15820
+ supportsPointerTracking: true,
15821
+ render({ context, size, palette, createRandom, timeMs, interaction }) {
15822
+ const spotlightY = size * 0.22;
15823
+ const headRandom = createRandom('minecraft2-head');
15824
+ const hasHeadband = headRandom() < 0.5;
15825
+ const headTextures = createMinecraftHeadTextures(createRandom('minecraft2-head-textures'), palette, hasHeadband);
15826
+ const torsoTextures = createMinecraftTorsoTextures(createRandom('minecraft2-body-textures'), palette);
15827
+ const bob = Math.sin(timeMs / 880) * size * 0.014;
15828
+ const bodyYaw = -0.24 + Math.sin(timeMs / 2300) * 0.06 + interaction.bodyOffsetX * 0.16;
15829
+ const bodyPitch = -0.12 + Math.cos(timeMs / 2800) * 0.02 - interaction.bodyOffsetY * 0.06;
15830
+ const headYaw = -0.18 + Math.sin(timeMs / 1900 + 0.6) * 0.05 + interaction.gazeX * 0.62;
15831
+ const headPitch = -0.12 + Math.cos(timeMs / 2400 + 1.1) * 0.03 - interaction.gazeY * 0.38;
15832
+ const sceneCenterX = size * 0.5;
15833
+ const sceneCenterY = size * 0.57;
15834
+ const bodyWidth = size * 0.225;
15835
+ const bodyHeight = size * 0.245;
15836
+ const bodyDepth = size * 0.145;
15837
+ const headSize = size * 0.24;
15838
+ const headLift = size * 0.205;
15839
+ const headForwardShift = interaction.intensity * size * 0.018;
15840
+ const sceneCuboids = [
15841
+ {
15842
+ center: {
15843
+ x: interaction.bodyOffsetX * size * 0.026,
15844
+ y: size * 0.05 + interaction.bodyOffsetY * size * 0.018 + bob,
15845
+ z: 0,
15846
+ },
15847
+ width: bodyWidth,
15848
+ height: bodyHeight,
15849
+ depth: bodyDepth,
15850
+ rotationX: bodyPitch,
15851
+ rotationY: bodyYaw,
15852
+ textures: torsoTextures,
15853
+ outlineColor: `${palette.shadow}cc`,
15854
+ },
15855
+ {
15856
+ center: {
15857
+ x: interaction.bodyOffsetX * size * 0.018 + interaction.gazeX * size * 0.016,
15858
+ y: -headLift + bob * 1.15,
15859
+ z: headForwardShift,
15860
+ },
15861
+ width: headSize,
15862
+ height: headSize,
15863
+ depth: headSize,
15864
+ rotationX: headPitch,
15865
+ rotationY: headYaw,
15866
+ textures: headTextures,
15867
+ outlineColor: `${palette.shadow}dd`,
15868
+ },
15869
+ ];
15870
+ const visibleFaces = sceneCuboids
15871
+ .flatMap((cuboid) => resolveVisibleCuboidFaces(cuboid, size, sceneCenterX, sceneCenterY))
15872
+ .sort((firstFace, secondFace) => firstFace.averageDepth - secondFace.averageDepth);
15873
+ drawAvatarFrame(context, size, palette);
15874
+ drawMinecraftBackdrop(context, size, palette, sceneCenterX, spotlightY, interaction, timeMs);
15875
+ drawMinecraftShadow(context, size, palette, interaction, timeMs);
15876
+ for (const visibleFace of visibleFaces) {
15877
+ drawTexturedProjectedFace(context, visibleFace);
15878
+ }
15879
+ },
15880
+ };
15881
+ /**
15882
+ * Draws the shared background atmosphere behind the Minecraft 3D 2 portrait.
15883
+ *
15884
+ * @param context Canvas 2D context.
15885
+ * @param size Canvas size in CSS pixels.
15737
15886
  * @param palette Derived avatar palette.
15738
- * @param hasHeadband Whether the avatar should render a headband row.
15739
- * @returns 8x8 pixel texture.
15887
+ * @param sceneCenterX Horizontal scene center.
15888
+ * @param spotlightY Vertical spotlight anchor.
15889
+ * @param interaction Smoothed pointer-aware interaction state.
15890
+ * @param timeMs Current animation time in milliseconds.
15740
15891
  *
15741
- * @private helper of `minecraftAvatarVisual`
15892
+ * @private helper of `minecraft2AvatarVisual`
15742
15893
  */
15743
- function createMinecraftFaceTexture(random, palette, hasHeadband) {
15744
- const texture = Array.from({ length: 8 }, () => Array.from({ length: 8 }, () => palette.highlight));
15745
- const hairlineColor = random() < 0.5 ? palette.primary : palette.secondary;
15746
- const cheekColor = random() < 0.5 ? `${palette.accent}bb` : `${palette.secondary}bb`;
15747
- for (let rowIndex = 0; rowIndex < 2; rowIndex++) {
15748
- for (let columnIndex = 0; columnIndex < 8; columnIndex++) {
15749
- texture[rowIndex][columnIndex] = hairlineColor;
15894
+ function drawMinecraftBackdrop(context, size, palette, sceneCenterX, spotlightY, interaction, timeMs) {
15895
+ const spotlightGradient = context.createRadialGradient(sceneCenterX + interaction.gazeX * size * 0.08, spotlightY + interaction.gazeY * size * 0.05, size * 0.03, sceneCenterX, spotlightY, size * 0.52);
15896
+ spotlightGradient.addColorStop(0, `${palette.highlight}66`);
15897
+ spotlightGradient.addColorStop(0.42, `${palette.accent}1d`);
15898
+ spotlightGradient.addColorStop(1, `${palette.highlight}00`);
15899
+ context.fillStyle = spotlightGradient;
15900
+ context.fillRect(0, 0, size, size);
15901
+ const rimGradient = context.createLinearGradient(0, size * 0.14, 0, size * 0.92);
15902
+ rimGradient.addColorStop(0, `${palette.highlight}12`);
15903
+ rimGradient.addColorStop(0.55, `${palette.secondary}0a`);
15904
+ rimGradient.addColorStop(1, `${palette.shadow}00`);
15905
+ context.fillStyle = rimGradient;
15906
+ context.fillRect(0, 0, size, size);
15907
+ context.save();
15908
+ context.globalAlpha = 0.08 + interaction.intensity * 0.04;
15909
+ context.fillStyle = palette.highlight;
15910
+ context.beginPath();
15911
+ 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);
15912
+ context.fill();
15913
+ context.restore();
15914
+ }
15915
+ /**
15916
+ * Draws the soft floor shadow used to anchor the cuboids in the frame.
15917
+ *
15918
+ * @param context Canvas 2D context.
15919
+ * @param size Canvas size in CSS pixels.
15920
+ * @param palette Derived avatar palette.
15921
+ * @param interaction Smoothed pointer-aware interaction state.
15922
+ * @param timeMs Current animation time in milliseconds.
15923
+ *
15924
+ * @private helper of `minecraft2AvatarVisual`
15925
+ */
15926
+ function drawMinecraftShadow(context, size, palette, interaction, timeMs) {
15927
+ context.save();
15928
+ context.fillStyle = `${palette.shadow}66`;
15929
+ context.filter = `blur(${size * 0.02}px)`;
15930
+ context.beginPath();
15931
+ 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);
15932
+ context.fill();
15933
+ context.restore();
15934
+ }
15935
+ /**
15936
+ * Resolves all visible projected faces for one scene cuboid.
15937
+ *
15938
+ * @param cuboid Scene cuboid definition.
15939
+ * @param size Canvas size in CSS pixels.
15940
+ * @param sceneCenterX Horizontal scene center.
15941
+ * @param sceneCenterY Vertical scene center.
15942
+ * @returns Visible faces sorted later by depth.
15943
+ *
15944
+ * @private helper of `minecraft2AvatarVisual`
15945
+ */
15946
+ function resolveVisibleCuboidFaces(cuboid, size, sceneCenterX, sceneCenterY) {
15947
+ const halfWidth = cuboid.width / 2;
15948
+ const halfHeight = cuboid.height / 2;
15949
+ const halfDepth = cuboid.depth / 2;
15950
+ const faceDefinitions = [
15951
+ {
15952
+ texture: cuboid.textures.front,
15953
+ corners: [
15954
+ { x: -halfWidth, y: -halfHeight, z: halfDepth },
15955
+ { x: halfWidth, y: -halfHeight, z: halfDepth },
15956
+ { x: halfWidth, y: halfHeight, z: halfDepth },
15957
+ { x: -halfWidth, y: halfHeight, z: halfDepth },
15958
+ ],
15959
+ },
15960
+ {
15961
+ texture: cuboid.textures.back,
15962
+ corners: [
15963
+ { x: halfWidth, y: -halfHeight, z: -halfDepth },
15964
+ { x: -halfWidth, y: -halfHeight, z: -halfDepth },
15965
+ { x: -halfWidth, y: halfHeight, z: -halfDepth },
15966
+ { x: halfWidth, y: halfHeight, z: -halfDepth },
15967
+ ],
15968
+ },
15969
+ {
15970
+ texture: cuboid.textures.right,
15971
+ corners: [
15972
+ { x: halfWidth, y: -halfHeight, z: halfDepth },
15973
+ { x: halfWidth, y: -halfHeight, z: -halfDepth },
15974
+ { x: halfWidth, y: halfHeight, z: -halfDepth },
15975
+ { x: halfWidth, y: halfHeight, z: halfDepth },
15976
+ ],
15977
+ },
15978
+ {
15979
+ texture: cuboid.textures.left,
15980
+ corners: [
15981
+ { x: -halfWidth, y: -halfHeight, z: -halfDepth },
15982
+ { x: -halfWidth, y: -halfHeight, z: halfDepth },
15983
+ { x: -halfWidth, y: halfHeight, z: halfDepth },
15984
+ { x: -halfWidth, y: halfHeight, z: -halfDepth },
15985
+ ],
15986
+ },
15987
+ {
15988
+ texture: cuboid.textures.top,
15989
+ corners: [
15990
+ { x: -halfWidth, y: -halfHeight, z: -halfDepth },
15991
+ { x: halfWidth, y: -halfHeight, z: -halfDepth },
15992
+ { x: halfWidth, y: -halfHeight, z: halfDepth },
15993
+ { x: -halfWidth, y: -halfHeight, z: halfDepth },
15994
+ ],
15995
+ },
15996
+ {
15997
+ texture: cuboid.textures.bottom,
15998
+ corners: [
15999
+ { x: -halfWidth, y: halfHeight, z: halfDepth },
16000
+ { x: halfWidth, y: halfHeight, z: halfDepth },
16001
+ { x: halfWidth, y: halfHeight, z: -halfDepth },
16002
+ { x: -halfWidth, y: halfHeight, z: -halfDepth },
16003
+ ],
16004
+ },
16005
+ ];
16006
+ const visibleFaces = faceDefinitions
16007
+ .map((faceDefinition) => {
16008
+ const transformedCorners = faceDefinition.corners.map((corner) => transformScenePoint(corner, cuboid.center, cuboid.rotationX, cuboid.rotationY));
16009
+ const faceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
16010
+ if (faceNormal.z <= 0.02) {
16011
+ return null;
15750
16012
  }
16013
+ const projectedCorners = transformedCorners.map((corner) => projectScenePoint(corner, size, sceneCenterX, sceneCenterY));
16014
+ return {
16015
+ corners: projectedCorners,
16016
+ texture: faceDefinition.texture,
16017
+ averageDepth: transformedCorners.reduce((depthSum, corner) => depthSum + corner.z, 0) / transformedCorners.length,
16018
+ lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION), -1, 1),
16019
+ outlineColor: cuboid.outlineColor,
16020
+ };
16021
+ });
16022
+ return visibleFaces.filter((visibleFace) => visibleFace !== null);
16023
+ }
16024
+ /**
16025
+ * Draws one projected textured face by tessellating its texture cells into quads.
16026
+ *
16027
+ * @param context Canvas 2D context.
16028
+ * @param face Visible projected face.
16029
+ *
16030
+ * @private helper of `minecraft2AvatarVisual`
16031
+ */
16032
+ function drawTexturedProjectedFace(context, face) {
16033
+ var _a;
16034
+ const rows = face.texture.length;
16035
+ const columns = ((_a = face.texture[0]) === null || _a === void 0 ? void 0 : _a.length) || 0;
16036
+ if (rows === 0 || columns === 0) {
16037
+ return;
15751
16038
  }
15752
- texture[2][0] = hairlineColor;
15753
- texture[2][7] = hairlineColor;
15754
- texture[3][0] = hairlineColor;
15755
- texture[3][7] = hairlineColor;
15756
- if (hasHeadband) {
15757
- for (let columnIndex = 0; columnIndex < 8; columnIndex++) {
15758
- texture[2][columnIndex] = palette.accent;
16039
+ for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
16040
+ for (let columnIndex = 0; columnIndex < columns; columnIndex++) {
16041
+ const startX = columnIndex / columns;
16042
+ const endX = (columnIndex + 1) / columns;
16043
+ const startY = rowIndex / rows;
16044
+ const endY = (rowIndex + 1) / rows;
16045
+ drawProjectedQuad(context, [
16046
+ interpolateProjectedQuad(face.corners, startX, startY),
16047
+ interpolateProjectedQuad(face.corners, endX, startY),
16048
+ interpolateProjectedQuad(face.corners, endX, endY),
16049
+ interpolateProjectedQuad(face.corners, startX, endY),
16050
+ ], face.texture[rowIndex][columnIndex]);
15759
16051
  }
15760
16052
  }
15761
- texture[3][2] = palette.ink;
15762
- texture[3][5] = palette.ink;
15763
- texture[4][2] = '#ffffff';
15764
- texture[4][5] = '#ffffff';
15765
- texture[5][1] = cheekColor;
15766
- texture[5][6] = cheekColor;
15767
- texture[5][3] = palette.shadow;
15768
- texture[5][4] = palette.shadow;
15769
- texture[6][3] = palette.shadow;
15770
- texture[6][4] = palette.shadow;
15771
- return texture;
16053
+ if (face.lightIntensity > 0) {
16054
+ drawProjectedQuad(context, face.corners, `rgba(255, 255, 255, ${0.15 * face.lightIntensity})`);
16055
+ }
16056
+ else if (face.lightIntensity < 0) {
16057
+ drawProjectedQuad(context, face.corners, `rgba(0, 0, 0, ${0.22 * Math.abs(face.lightIntensity)})`);
16058
+ }
16059
+ context.save();
16060
+ context.beginPath();
16061
+ context.moveTo(face.corners[0].x, face.corners[0].y);
16062
+ for (let cornerIndex = 1; cornerIndex < face.corners.length; cornerIndex++) {
16063
+ context.lineTo(face.corners[cornerIndex].x, face.corners[cornerIndex].y);
16064
+ }
16065
+ context.closePath();
16066
+ context.strokeStyle = face.outlineColor;
16067
+ context.lineWidth = Math.max(1.1, getProjectedQuadPerimeter(face.corners) * 0.0045);
16068
+ context.lineJoin = 'round';
16069
+ context.stroke();
16070
+ context.restore();
15772
16071
  }
15773
16072
  /**
15774
- * Creates the front-face pixel texture for the torso.
16073
+ * Draws one filled projected quad.
15775
16074
  *
15776
- * @param random Seeded random generator.
15777
- * @param palette Derived avatar palette.
15778
- * @returns 8x8 torso texture.
16075
+ * @param context Canvas 2D context.
16076
+ * @param corners Quad corners in clockwise order.
16077
+ * @param fillStyle CSS fill style.
15779
16078
  *
15780
- * @private helper of `minecraftAvatarVisual`
16079
+ * @private helper of `minecraft2AvatarVisual`
15781
16080
  */
15782
- function createMinecraftShirtTexture(random, palette) {
15783
- const texture = Array.from({ length: 8 }, () => Array.from({ length: 8 }, () => palette.primary));
15784
- const stripeColor = random() < 0.5 ? palette.secondary : palette.highlight;
15785
- for (let rowIndex = 0; rowIndex < 2; rowIndex++) {
15786
- for (let columnIndex = 0; columnIndex < 8; columnIndex++) {
15787
- texture[rowIndex][columnIndex] = palette.shadow;
15788
- }
16081
+ function drawProjectedQuad(context, corners, fillStyle) {
16082
+ context.beginPath();
16083
+ context.moveTo(corners[0].x, corners[0].y);
16084
+ context.lineTo(corners[1].x, corners[1].y);
16085
+ context.lineTo(corners[2].x, corners[2].y);
16086
+ context.lineTo(corners[3].x, corners[3].y);
16087
+ context.closePath();
16088
+ context.fillStyle = fillStyle;
16089
+ context.fill();
16090
+ }
16091
+ /**
16092
+ * Interpolates one point inside a projected quad across both quad axes.
16093
+ *
16094
+ * @param corners Quad corners in clockwise order.
16095
+ * @param horizontalRatio Horizontal ratio in the range `[0, 1]`.
16096
+ * @param verticalRatio Vertical ratio in the range `[0, 1]`.
16097
+ * @returns Interpolated projected point.
16098
+ *
16099
+ * @private helper of `minecraft2AvatarVisual`
16100
+ */
16101
+ function interpolateProjectedQuad(corners, horizontalRatio, verticalRatio) {
16102
+ const topPoint = interpolateProjectedPoint(corners[0], corners[1], horizontalRatio);
16103
+ const bottomPoint = interpolateProjectedPoint(corners[3], corners[2], horizontalRatio);
16104
+ return interpolateProjectedPoint(topPoint, bottomPoint, verticalRatio);
16105
+ }
16106
+ /**
16107
+ * Interpolates between two projected points.
16108
+ *
16109
+ * @param startPoint Start point.
16110
+ * @param endPoint End point.
16111
+ * @param ratio Interpolation ratio in the range `[0, 1]`.
16112
+ * @returns Interpolated projected point.
16113
+ *
16114
+ * @private helper of `minecraft2AvatarVisual`
16115
+ */
16116
+ function interpolateProjectedPoint(startPoint, endPoint, ratio) {
16117
+ return {
16118
+ x: startPoint.x + (endPoint.x - startPoint.x) * ratio,
16119
+ y: startPoint.y + (endPoint.y - startPoint.y) * ratio,
16120
+ z: startPoint.z + (endPoint.z - startPoint.z) * ratio,
16121
+ };
16122
+ }
16123
+ /**
16124
+ * Projects one rotated scene point into canvas coordinates.
16125
+ *
16126
+ * @param point Scene point.
16127
+ * @param size Canvas size in CSS pixels.
16128
+ * @param sceneCenterX Horizontal scene center.
16129
+ * @param sceneCenterY Vertical scene center.
16130
+ * @returns Projected point.
16131
+ *
16132
+ * @private helper of `minecraft2AvatarVisual`
16133
+ */
16134
+ function projectScenePoint(point, size, sceneCenterX, sceneCenterY) {
16135
+ const cameraDistance = size * CAMERA_DISTANCE_RATIO;
16136
+ const perspectiveScale = cameraDistance / Math.max(cameraDistance - point.z, cameraDistance * 0.35);
16137
+ return {
16138
+ x: sceneCenterX + point.x * perspectiveScale,
16139
+ y: sceneCenterY + point.y * perspectiveScale,
16140
+ z: point.z,
16141
+ };
16142
+ }
16143
+ /**
16144
+ * Applies the local cuboid rotations and translation to one scene point.
16145
+ *
16146
+ * @param localPoint Point in cuboid-local space.
16147
+ * @param center Cuboid center in scene space.
16148
+ * @param rotationX Cuboid pitch in radians.
16149
+ * @param rotationY Cuboid yaw in radians.
16150
+ * @returns Transformed scene-space point.
16151
+ *
16152
+ * @private helper of `minecraft2AvatarVisual`
16153
+ */
16154
+ function transformScenePoint(localPoint, center, rotationX, rotationY) {
16155
+ const yawedPoint = rotatePointAroundY(localPoint, rotationY);
16156
+ const pitchedPoint = rotatePointAroundX(yawedPoint, rotationX);
16157
+ return {
16158
+ x: center.x + pitchedPoint.x,
16159
+ y: center.y + pitchedPoint.y,
16160
+ z: center.z + pitchedPoint.z,
16161
+ };
16162
+ }
16163
+ /**
16164
+ * Rotates one point around the local Y axis.
16165
+ *
16166
+ * @param point Source point.
16167
+ * @param angle Rotation angle in radians.
16168
+ * @returns Rotated point.
16169
+ *
16170
+ * @private helper of `minecraft2AvatarVisual`
16171
+ */
16172
+ function rotatePointAroundY(point, angle) {
16173
+ const cosine = Math.cos(angle);
16174
+ const sine = Math.sin(angle);
16175
+ return {
16176
+ x: point.x * cosine + point.z * sine,
16177
+ y: point.y,
16178
+ z: -point.x * sine + point.z * cosine,
16179
+ };
16180
+ }
16181
+ /**
16182
+ * Rotates one point around the local X axis.
16183
+ *
16184
+ * @param point Source point.
16185
+ * @param angle Rotation angle in radians.
16186
+ * @returns Rotated point.
16187
+ *
16188
+ * @private helper of `minecraft2AvatarVisual`
16189
+ */
16190
+ function rotatePointAroundX(point, angle) {
16191
+ const cosine = Math.cos(angle);
16192
+ const sine = Math.sin(angle);
16193
+ return {
16194
+ x: point.x,
16195
+ y: point.y * cosine - point.z * sine,
16196
+ z: point.y * sine + point.z * cosine,
16197
+ };
16198
+ }
16199
+ /**
16200
+ * Subtracts one 3D point from another.
16201
+ *
16202
+ * @param leftPoint Left point.
16203
+ * @param rightPoint Right point.
16204
+ * @returns Difference vector.
16205
+ *
16206
+ * @private helper of `minecraft2AvatarVisual`
16207
+ */
16208
+ function subtractPoint3D(leftPoint, rightPoint) {
16209
+ return {
16210
+ x: leftPoint.x - rightPoint.x,
16211
+ y: leftPoint.y - rightPoint.y,
16212
+ z: leftPoint.z - rightPoint.z,
16213
+ };
16214
+ }
16215
+ /**
16216
+ * Computes the 3D cross product of two vectors.
16217
+ *
16218
+ * @param leftVector Left vector.
16219
+ * @param rightVector Right vector.
16220
+ * @returns Cross product.
16221
+ *
16222
+ * @private helper of `minecraft2AvatarVisual`
16223
+ */
16224
+ function crossProduct3D(leftVector, rightVector) {
16225
+ return {
16226
+ x: leftVector.y * rightVector.z - leftVector.z * rightVector.y,
16227
+ y: leftVector.z * rightVector.x - leftVector.x * rightVector.z,
16228
+ z: leftVector.x * rightVector.y - leftVector.y * rightVector.x,
16229
+ };
16230
+ }
16231
+ /**
16232
+ * Computes the 3D dot product of two vectors.
16233
+ *
16234
+ * @param leftVector Left vector.
16235
+ * @param rightVector Right vector.
16236
+ * @returns Dot product.
16237
+ *
16238
+ * @private helper of `minecraft2AvatarVisual`
16239
+ */
16240
+ function dotProduct3D(leftVector, rightVector) {
16241
+ return leftVector.x * rightVector.x + leftVector.y * rightVector.y + leftVector.z * rightVector.z;
16242
+ }
16243
+ /**
16244
+ * Normalizes one 3D vector while keeping zero vectors stable.
16245
+ *
16246
+ * @param vector Source vector.
16247
+ * @returns Normalized vector.
16248
+ *
16249
+ * @private helper of `minecraft2AvatarVisual`
16250
+ */
16251
+ function normalizeVector3(vector) {
16252
+ const length = Math.hypot(vector.x, vector.y, vector.z);
16253
+ if (length === 0) {
16254
+ return vector;
15789
16255
  }
15790
- for (let rowIndex = 2; rowIndex < 8; rowIndex++) {
15791
- texture[rowIndex][3] = stripeColor;
15792
- texture[rowIndex][4] = stripeColor;
16256
+ return {
16257
+ x: vector.x / length,
16258
+ y: vector.y / length,
16259
+ z: vector.z / length,
16260
+ };
16261
+ }
16262
+ /**
16263
+ * Clamps one number into the provided range.
16264
+ *
16265
+ * @param value Input value.
16266
+ * @param minimumValue Inclusive lower bound.
16267
+ * @param maximumValue Inclusive upper bound.
16268
+ * @returns Clamped value.
16269
+ *
16270
+ * @private helper of `minecraft2AvatarVisual`
16271
+ */
16272
+ function clampNumber$1(value, minimumValue, maximumValue) {
16273
+ return Math.min(maximumValue, Math.max(minimumValue, value));
16274
+ }
16275
+ /**
16276
+ * Measures the perimeter of one projected quad.
16277
+ *
16278
+ * @param corners Quad corners.
16279
+ * @returns Perimeter length.
16280
+ *
16281
+ * @private helper of `minecraft2AvatarVisual`
16282
+ */
16283
+ function getProjectedQuadPerimeter(corners) {
16284
+ let perimeter = 0;
16285
+ for (let cornerIndex = 0; cornerIndex < corners.length; cornerIndex++) {
16286
+ const currentCorner = corners[cornerIndex];
16287
+ const nextCorner = corners[(cornerIndex + 1) % corners.length];
16288
+ perimeter += Math.hypot(nextCorner.x - currentCorner.x, nextCorner.y - currentCorner.y);
15793
16289
  }
15794
- texture[4][1] = palette.accent;
15795
- texture[4][6] = palette.accent;
15796
- texture[5][2] = palette.highlight;
15797
- texture[5][5] = palette.highlight;
15798
- return texture;
16290
+ return perimeter;
15799
16291
  }
15800
16292
 
15801
16293
  /* eslint-disable no-magic-numbers */
@@ -17400,6 +17892,7 @@ const AVATAR_VISUALS = [
17400
17892
  octopus3AvatarVisual,
17401
17893
  asciiOctopusAvatarVisual,
17402
17894
  minecraftAvatarVisual,
17895
+ minecraft2AvatarVisual,
17403
17896
  fractalAvatarVisual,
17404
17897
  orbAvatarVisual,
17405
17898
  ];
@@ -18702,7 +19195,11 @@ class PersonaCommitmentDefinition extends BaseCommitmentDefinition {
18702
19195
  // Create new system message with persona at the beginning
18703
19196
  // Format: "You are {agentName}\n{personaContent}"
18704
19197
  // The # PERSONA comment will be removed later by removeCommentsFromSystemMessage
18705
- const personaSection = `# PERSONA\nYou are ${agentName}\n${mergedPersonaContent}`; // <- TODO: Use spaceTrim
19198
+ const personaSection = spaceTrim$1((block) => `
19199
+ # PERSONA
19200
+ You are ${agentName}
19201
+ ${block(mergedPersonaContent)}
19202
+ `);
18706
19203
  const newSystemMessage = cleanedMessage ? `${personaSection}\n\n${cleanedMessage}` : personaSection;
18707
19204
  return {
18708
19205
  ...requirements,
@@ -19604,7 +20101,10 @@ function buildTeamSystemMessageBody(teamEntries) {
19604
20101
  */
19605
20102
  function buildTeamToolDescription(entry) {
19606
20103
  const detailLines = collectTeamEntryDetails(entry).map(({ label, content }) => `${label}: ${content}`);
19607
- return [`Consult teammate ${entry.teammate.label}`, ...detailLines].join('\n');
20104
+ return spaceTrim$1((block) => `
20105
+ Consult teammate ${entry.teammate.label}
20106
+ ${block(detailLines.join('\n'))}
20107
+ `);
19608
20108
  }
19609
20109
  /**
19610
20110
  * Collects structured teammate details that should stay visible to the model.
@@ -25101,7 +25601,10 @@ function createListedTimeoutsAssistantMessage(options) {
25101
25601
  if (hiddenCount > 0) {
25102
25602
  summaryRows.push(`...and ${hiddenCount} more.`);
25103
25603
  }
25104
- return [`Found ${options.total} ${options.total === 1 ? 'timeout' : 'timeouts'}:`, ...summaryRows].join('\n');
25604
+ return spaceTrim$1((block) => `
25605
+ Found ${options.total} ${options.total === 1 ? 'timeout' : 'timeouts'}:
25606
+ ${block(summaryRows.join('\n'))}
25607
+ `);
25105
25608
  }
25106
25609
  /**
25107
25610
  * Formats one timeout row for assistant-visible timeout listings.
@@ -28070,8 +28573,10 @@ async function renderMarkdownServerIndex(runtime) {
28070
28573
  **Application mode:** ${serverInfo.isApplicationModeAllowed ? 'enabled' : 'disabled'}
28071
28574
  ${block(!runtime.configuration.isApplicationModeAllowed || runtime.configuration.collection === null
28072
28575
  ? ''
28073
- : '**Pipelines in collection:**\n' +
28074
- serverInfo.pipelines.map((pipelineUrl) => `- ${pipelineUrl}`).join('\n'))}
28576
+ : spaceTrim$1((nestedBlock) => `
28577
+ **Pipelines in collection:**
28578
+ ${nestedBlock(serverInfo.pipelines.map((pipelineUrl) => `- ${pipelineUrl}`).join('\n'))}
28579
+ `))}
28075
28580
  **Running executions:** ${serverInfo.runningExecutions}
28076
28581
 
28077
28582
  ---
@@ -31065,11 +31570,11 @@ function formatChatAttachmentContext(attachments) {
31065
31570
  if (attachments.length === 0) {
31066
31571
  return '';
31067
31572
  }
31068
- return [
31069
- CHAT_ATTACHMENTS_HEADING,
31070
- ...attachments.map((attachment) => formatChatAttachmentLine(attachment)),
31071
- CHAT_ATTACHMENTS_INSTRUCTION,
31072
- ].join('\n');
31573
+ return spaceTrim$1((block) => `
31574
+ ${CHAT_ATTACHMENTS_HEADING}
31575
+ ${block(attachments.map((attachment) => formatChatAttachmentLine(attachment)).join('\n'))}
31576
+ ${CHAT_ATTACHMENTS_INSTRUCTION}
31577
+ `);
31073
31578
  }
31074
31579
 
31075
31580
  /**
@@ -31310,24 +31815,24 @@ function formatResolvedChatAttachmentContent(contentResolution) {
31310
31815
  : ''}`
31311
31816
  : null;
31312
31817
  const warningsLine = contentResolution.warnings.length > 0 ? `Warnings: ${contentResolution.warnings.join(' | ')}` : null;
31313
- if (!contentResolution.content) {
31818
+ const metadataLines = [decodingLine, warningsLine].filter((line) => Boolean(line)).join('\n');
31819
+ const resolvedContent = contentResolution.content;
31820
+ if (!resolvedContent) {
31314
31821
  const reason = contentResolution.reason || 'content unavailable';
31315
- return [`- ${attachmentLabel}: ${reason}. URL: ${contentResolution.attachment.url}`, decodingLine, warningsLine]
31316
- .filter(Boolean)
31317
- .join('\n');
31822
+ return spaceTrim$1((block) => `
31823
+ - ${attachmentLabel}: ${reason}. URL: ${contentResolution.attachment.url}
31824
+ ${block(metadataLines)}
31825
+ `);
31318
31826
  }
31319
31827
  const truncatedLabel = contentResolution.isTruncated ? ' [truncated]' : '';
31320
- return [
31321
- `File: ${attachmentLabel}${truncatedLabel}`,
31322
- `URL: ${contentResolution.attachment.url}`,
31323
- decodingLine,
31324
- warningsLine,
31325
- '```text',
31326
- contentResolution.content,
31327
- '```',
31328
- ]
31329
- .filter(Boolean)
31330
- .join('\n');
31828
+ return spaceTrim$1((block) => `
31829
+ File: ${attachmentLabel}${truncatedLabel}
31830
+ URL: ${contentResolution.attachment.url}
31831
+ ${block(metadataLines)}
31832
+ \`\`\`text
31833
+ ${block(resolvedContent)}
31834
+ \`\`\`
31835
+ `);
31331
31836
  }
31332
31837
  /**
31333
31838
  * Formats inline attachment-content context section for the model.
@@ -31341,11 +31846,14 @@ function formatChatAttachmentContentContext(resolvedContents) {
31341
31846
  if (resolvedContents.length === 0) {
31342
31847
  return '';
31343
31848
  }
31344
- return [
31345
- CHAT_ATTACHMENT_CONTENT_HEADING,
31346
- CHAT_ATTACHMENT_CONTENT_INSTRUCTION,
31347
- ...resolvedContents.map((resolvedContent) => formatResolvedChatAttachmentContent(resolvedContent)),
31348
- ].join('\n\n');
31849
+ return spaceTrim$1((block) => `
31850
+ ${CHAT_ATTACHMENT_CONTENT_HEADING}
31851
+ ${CHAT_ATTACHMENT_CONTENT_INSTRUCTION}
31852
+
31853
+ ${block(resolvedContents
31854
+ .map((resolvedContent) => formatResolvedChatAttachmentContent(resolvedContent))
31855
+ .join('\n\n'))}
31856
+ `);
31349
31857
  }
31350
31858
 
31351
31859
  /**
@@ -32490,9 +32998,11 @@ class OpenAiCompatibleUnsupportedParameterRetrier {
32490
32998
  * Creates the retry-history error message shared by all OpenAI-compatible model variants.
32491
32999
  */
32492
33000
  createAttemptHistoryError(finalErrorMessage) {
32493
- return new PipelineExecutionError(`All attempts failed. Attempt history:\n` +
32494
- formatUnsupportedParameterAttemptHistory(this.attemptStack) +
32495
- `\nFinal error: ${finalErrorMessage}`);
33001
+ return new PipelineExecutionError(spaceTrim$1((block) => `
33002
+ All attempts failed. Attempt history:
33003
+ ${block(formatUnsupportedParameterAttemptHistory(this.attemptStack))}
33004
+ Final error: ${finalErrorMessage}
33005
+ `));
32496
33006
  }
32497
33007
  }
32498
33008
 
@@ -35086,7 +35596,7 @@ class OpenAiAgentKitExecutionTools extends OpenAiVectorStoreHandler {
35086
35596
  });
35087
35597
  }
35088
35598
  let vectorStoreId = cachedVectorStoreId;
35089
- if (this.isNativeKnowledgeSearchEnabled && !vectorStoreId && knowledgeSources && knowledgeSources.length > 0) {
35599
+ if (!vectorStoreId && knowledgeSources && knowledgeSources.length > 0) {
35090
35600
  const vectorStoreResult = await this.createVectorStoreWithKnowledgeSources({
35091
35601
  client: await this.getClient(),
35092
35602
  name,
@@ -35095,19 +35605,13 @@ class OpenAiAgentKitExecutionTools extends OpenAiVectorStoreHandler {
35095
35605
  });
35096
35606
  vectorStoreId = vectorStoreResult.vectorStoreId;
35097
35607
  }
35098
- else if (this.isNativeKnowledgeSearchEnabled && vectorStoreId && this.options.isVerbose) {
35608
+ else if (vectorStoreId && this.options.isVerbose) {
35099
35609
  console.info('[🤰]', 'Using cached vector store for AgentKit agent', {
35100
35610
  name,
35101
35611
  vectorStoreId,
35102
35612
  });
35103
35613
  }
35104
- if (!this.isNativeKnowledgeSearchEnabled) {
35105
- vectorStoreId = undefined;
35106
- }
35107
- const agentKitTools = this.buildAgentKitTools({
35108
- tools,
35109
- vectorStoreId,
35110
- });
35614
+ const agentKitTools = this.buildAgentKitTools({ tools, vectorStoreId });
35111
35615
  const openAiAgentKitAgent = new Agent$1({
35112
35616
  name,
35113
35617
  model: this.agentKitModelName,
@@ -35126,7 +35630,7 @@ class OpenAiAgentKitExecutionTools extends OpenAiVectorStoreHandler {
35126
35630
  name,
35127
35631
  model: this.agentKitModelName,
35128
35632
  toolCount: agentKitTools.length,
35129
- hasVectorStore: this.isNativeKnowledgeSearchEnabled && Boolean(vectorStoreId),
35633
+ hasVectorStore: Boolean(vectorStoreId),
35130
35634
  });
35131
35635
  }
35132
35636
  return preparedAgent;
@@ -35625,12 +36129,6 @@ class OpenAiAgentKitExecutionTools extends OpenAiVectorStoreHandler {
35625
36129
  get agentKitOptions() {
35626
36130
  return this.options;
35627
36131
  }
35628
- /**
35629
- * Returns true when hosted OpenAI vector-store search should back `knowledgeSources`.
35630
- */
35631
- get isNativeKnowledgeSearchEnabled() {
35632
- return this.agentKitOptions.isNativeKnowledgeSearchEnabled !== false;
35633
- }
35634
36132
  /**
35635
36133
  * Discriminant for type guards.
35636
36134
  */