@promptbook/core 0.112.0-115 → 0.112.0-118

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 (31) hide show
  1. package/esm/index.es.js +212 -57
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/src/_packages/components.index.d.ts +2 -0
  4. package/esm/src/_packages/node.index.d.ts +20 -0
  5. package/esm/src/book-3.0/BookNodeAgentSource.d.ts +1 -1
  6. package/esm/src/book-3.0/CliAgent.d.ts +15 -17
  7. package/esm/src/book-3.0/agentFolderPaths.d.ts +30 -0
  8. package/esm/src/book-3.0/cliAgentEnv.d.ts +33 -0
  9. package/esm/src/book-components/BookEditor/BookEditorBrowserConfig.d.ts +2 -0
  10. package/esm/src/book-components/BookEditor/BookEditorForClient.d.ts +7 -0
  11. package/esm/src/book-components/BookEditor/createDeprecatedCommitmentDiagnostics.browser.d.ts +9 -0
  12. package/esm/src/cli/cli-commands/agent-folder/agentProjectPaths.d.ts +2 -30
  13. package/esm/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +2 -18
  14. package/esm/src/scrapers/website/utils/createShowdownConverter.d.ts +2 -2
  15. package/esm/src/version.d.ts +1 -1
  16. package/package.json +1 -1
  17. package/umd/index.umd.js +215 -58
  18. package/umd/index.umd.js.map +1 -1
  19. package/umd/src/_packages/components.index.d.ts +2 -0
  20. package/umd/src/_packages/node.index.d.ts +20 -0
  21. package/umd/src/book-3.0/BookNodeAgentSource.d.ts +1 -1
  22. package/umd/src/book-3.0/CliAgent.d.ts +15 -17
  23. package/umd/src/book-3.0/agentFolderPaths.d.ts +30 -0
  24. package/umd/src/book-3.0/cliAgentEnv.d.ts +33 -0
  25. package/umd/src/book-components/BookEditor/BookEditorBrowserConfig.d.ts +2 -0
  26. package/umd/src/book-components/BookEditor/BookEditorForClient.d.ts +7 -0
  27. package/umd/src/book-components/BookEditor/createDeprecatedCommitmentDiagnostics.browser.d.ts +9 -0
  28. package/umd/src/cli/cli-commands/agent-folder/agentProjectPaths.d.ts +2 -30
  29. package/umd/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +2 -18
  30. package/umd/src/scrapers/website/utils/createShowdownConverter.d.ts +2 -2
  31. package/umd/src/version.d.ts +1 -1
package/esm/index.es.js CHANGED
@@ -1,14 +1,14 @@
1
- import { SHA256 } from 'crypto-js';
1
+ import CryptoJS from 'crypto-js';
2
2
  import hexEncoder from 'crypto-js/enc-hex';
3
3
  import { spaceTrim as spaceTrim$1 } from 'spacetrim';
4
- import { randomBytes } from 'crypto';
5
4
  import { Subject, BehaviorSubject } from 'rxjs';
6
5
  import { forTime } from 'waitasecond';
7
6
  import sha256 from 'crypto-js/sha256';
8
7
  import { basename, join, dirname, isAbsolute } from 'path';
9
8
  import { lookup, extension } from 'mime-types';
10
- import { parse, unparse } from 'papaparse';
9
+ import papaparse from 'papaparse';
11
10
  import moment from 'moment';
11
+ import { randomBytes } from 'crypto';
12
12
  import colors from 'colors';
13
13
  import { fileSearchTool, tool, Agent as Agent$1, webSearchTool, run, setDefaultOpenAIClient, setDefaultOpenAIKey } from '@openai/agents';
14
14
  import Bottleneck from 'bottleneck';
@@ -28,7 +28,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
28
28
  * @generated
29
29
  * @see https://github.com/webgptorg/promptbook
30
30
  */
31
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-115';
31
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-118';
32
32
  /**
33
33
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
34
34
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -1653,7 +1653,7 @@ function valueToString(value) {
1653
1653
  * @public exported from `@promptbook/utils`
1654
1654
  */
1655
1655
  function computeHash(value) {
1656
- return SHA256(hexEncoder.parse(spaceTrim$1(valueToString(value)))).toString( /* hex */);
1656
+ return CryptoJS.SHA256(hexEncoder.parse(spaceTrim$1(valueToString(value)))).toString( /* hex */);
1657
1657
  }
1658
1658
  // TODO: [🥬][🥬] Use this ACRY
1659
1659
 
@@ -3773,7 +3773,7 @@ class NotYetImplementedError extends Error {
3773
3773
  * @private internal helper function
3774
3774
  */
3775
3775
  function $randomToken(randomness) {
3776
- return randomBytes(randomness).toString('hex');
3776
+ return CryptoJS.lib.WordArray.random(randomness).toString(CryptoJS.enc.Hex);
3777
3777
  }
3778
3778
  // TODO: [🤶] Maybe export through `@promptbook/utils` or `@promptbook/random` package
3779
3779
  // TODO: Maybe use nanoid instead https://github.com/ai/nanoid
@@ -5457,7 +5457,7 @@ function normalizeToKebabCase(text) {
5457
5457
  * @public exported from `@promptbook/editable`
5458
5458
  */
5459
5459
  function knowledgeSourceContentToName(knowledgeSourceContent) {
5460
- const hash = SHA256(hexEncoder.parse(JSON.stringify(knowledgeSourceContent)))
5460
+ const hash = CryptoJS.SHA256(hexEncoder.parse(JSON.stringify(knowledgeSourceContent)))
5461
5461
  // <- TODO: [🥬] Encapsulate sha256 to some private utility function
5462
5462
  .toString( /* hex */)
5463
5463
  .substring(0, 20);
@@ -6370,7 +6370,7 @@ function csvParse(value /* <- TODO: string_csv */, settings, schema /* <- TODO:
6370
6370
  console.warn('CSV string contains carriage return characters, but in the CSV settings the `newline` setting does not include them. Autohealing the CSV string.');
6371
6371
  value = value.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
6372
6372
  }
6373
- const csv = parse(value, settings);
6373
+ const csv = papaparse.parse(value, settings);
6374
6374
  return csv;
6375
6375
  }
6376
6376
 
@@ -6455,10 +6455,10 @@ const CsvFormatParser = {
6455
6455
  i > index ? { ...row, [outputParameterName]: PENDING_VALUE_PLACEHOLDER } : row,
6456
6456
  );
6457
6457
  */
6458
- await onProgress(unparse(mappedData, { ...settings, ...MANDATORY_CSV_SETTINGS }));
6458
+ await onProgress(papaparse.unparse(mappedData, { ...settings, ...MANDATORY_CSV_SETTINGS }));
6459
6459
  }
6460
6460
  }
6461
- return unparse(mappedData, { ...settings, ...MANDATORY_CSV_SETTINGS });
6461
+ return papaparse.unparse(mappedData, { ...settings, ...MANDATORY_CSV_SETTINGS });
6462
6462
  },
6463
6463
  },
6464
6464
  {
@@ -6486,7 +6486,7 @@ const CsvFormatParser = {
6486
6486
  return /* not await */ mapCallback({ [key]: value }, index, array.length);
6487
6487
  }));
6488
6488
  }));
6489
- return unparse(mappedData, { ...settings, ...MANDATORY_CSV_SETTINGS });
6489
+ return papaparse.unparse(mappedData, { ...settings, ...MANDATORY_CSV_SETTINGS });
6490
6490
  },
6491
6491
  },
6492
6492
  ],
@@ -13063,21 +13063,22 @@ function getPointBounds(points) {
13063
13063
  * @private helper of `fractalAvatarVisual`
13064
13064
  */
13065
13065
  function drawDragonCurveLayer(context, points, options) {
13066
- const { size, primaryColor, secondaryColor, tertiaryColor, shadowColor, strokeWidth, timeMs, layerIndex } = options;
13066
+ const { primaryColor, secondaryColor, tertiaryColor, shadowColor, strokeWidth, timeMs, layerIndex } = options;
13067
13067
  const firstPoint = points[0];
13068
13068
  const lastPoint = points[points.length - 1];
13069
13069
  const ribbonGradient = context.createLinearGradient(firstPoint.x, firstPoint.y, lastPoint.x, lastPoint.y);
13070
13070
  ribbonGradient.addColorStop(0, `${primaryColor}f2`);
13071
13071
  ribbonGradient.addColorStop(0.5, `${secondaryColor}e6`);
13072
13072
  ribbonGradient.addColorStop(1, `${tertiaryColor}f2`);
13073
+ // Approximate the blurred shadow stroke with a wider semi-transparent stroke instead of
13074
+ // context.filter blur, which triggers a costly software rasterization pass every frame.
13073
13075
  context.save();
13074
13076
  context.beginPath();
13075
13077
  tracePolyline(context, points);
13076
- context.strokeStyle = `${shadowColor}82`;
13077
- context.lineWidth = strokeWidth * 1.8;
13078
+ context.strokeStyle = `${shadowColor}48`;
13079
+ context.lineWidth = strokeWidth * 4.5;
13078
13080
  context.lineJoin = 'round';
13079
13081
  context.lineCap = 'round';
13080
- context.filter = `blur(${size * 0.022}px)`;
13081
13082
  context.stroke();
13082
13083
  context.restore();
13083
13084
  context.beginPath();
@@ -13661,11 +13662,23 @@ function drawMinecraftBackdrop(context, size, palette, sceneCenterX, spotlightY,
13661
13662
  * @private helper of `minecraft2AvatarVisual`
13662
13663
  */
13663
13664
  function drawMinecraftShadow(context, size, palette, interaction, timeMs) {
13665
+ const cx = size * 0.5 + interaction.gazeX * size * 0.03;
13666
+ const cy = size * 0.85 + Math.sin(timeMs / 880) * size * 0.01;
13667
+ const rx = size * (0.16 + interaction.intensity * 0.015);
13668
+ const ry = size * 0.055;
13669
+ // Radial gradient approximates the blurry ellipse shadow without context.filter blur.
13664
13670
  context.save();
13665
- context.fillStyle = `${palette.shadow}66`;
13666
- context.filter = `blur(${size * 0.02}px)`;
13671
+ context.translate(cx, cy);
13672
+ context.scale(1, ry / rx);
13673
+ const blurRadius = rx * 1.4;
13674
+ const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
13675
+ shadowGradient.addColorStop(0, `${palette.shadow}7a`);
13676
+ shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
13677
+ shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
13678
+ shadowGradient.addColorStop(1, `${palette.shadow}00`);
13679
+ context.fillStyle = shadowGradient;
13667
13680
  context.beginPath();
13668
- 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);
13681
+ context.arc(0, 0, blurRadius, 0, Math.PI * 2);
13669
13682
  context.fill();
13670
13683
  context.restore();
13671
13684
  }
@@ -13889,13 +13902,27 @@ const minecraftAvatarVisual = {
13889
13902
  spotlight.addColorStop(1, `${palette.highlight}00`);
13890
13903
  context.fillStyle = spotlight;
13891
13904
  context.fillRect(0, 0, size, size);
13892
- context.save();
13893
- context.fillStyle = 'rgba(0, 0, 0, 0.22)';
13894
- context.filter = `blur(${size * 0.018}px)`;
13895
- context.beginPath();
13896
- context.ellipse(size * 0.5, size * 0.86, size * 0.2, size * 0.06, 0, 0, Math.PI * 2);
13897
- context.fill();
13898
- context.restore();
13905
+ {
13906
+ // Radial gradient approximates the blurry ellipse shadow without context.filter blur.
13907
+ const cx = size * 0.5;
13908
+ const cy = size * 0.86;
13909
+ const rx = size * 0.2;
13910
+ const ry = size * 0.06;
13911
+ const blurRadius = rx * 1.4;
13912
+ const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
13913
+ shadowGradient.addColorStop(0, 'rgba(0,0,0,0.28)');
13914
+ shadowGradient.addColorStop(0.45, 'rgba(0,0,0,0.14)');
13915
+ shadowGradient.addColorStop(0.8, 'rgba(0,0,0,0.05)');
13916
+ shadowGradient.addColorStop(1, 'rgba(0,0,0,0)');
13917
+ context.save();
13918
+ context.translate(cx, cy);
13919
+ context.scale(1, ry / rx);
13920
+ context.fillStyle = shadowGradient;
13921
+ context.beginPath();
13922
+ context.arc(0, 0, blurRadius, 0, Math.PI * 2);
13923
+ context.fill();
13924
+ context.restore();
13925
+ }
13899
13926
  drawVoxelCuboid(context, {
13900
13927
  x: bodyX,
13901
13928
  y: bodyY,
@@ -14947,6 +14974,35 @@ const LIGHT_DIRECTION$2 = normalizeVector3({
14947
14974
  y: -0.62,
14948
14975
  z: 0.94,
14949
14976
  });
14977
+ /**
14978
+ * Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
14979
+ *
14980
+ * @private helper of `octopus3dAvatarVisual`
14981
+ */
14982
+ const octopus3dStableStateCache = new WeakMap();
14983
+ /**
14984
+ * Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
14985
+ *
14986
+ * @private helper of `octopus3dAvatarVisual`
14987
+ */
14988
+ function getOctopus3dStableState(createRandom) {
14989
+ const cached = octopus3dStableStateCache.get(createRandom);
14990
+ if (cached !== undefined) {
14991
+ return cached;
14992
+ }
14993
+ const animationRandom = createRandom('octopus3d-animation-profile');
14994
+ const eyeRandom = createRandom('octopus3d-eye-profile');
14995
+ const leftEyePhaseOffset = eyeRandom() * 0.6;
14996
+ const rightEyePhaseOffset = eyeRandom() * 0.6;
14997
+ const state = {
14998
+ morphologyProfile: createOctopus3MorphologyProfile(createRandom),
14999
+ animationPhase: animationRandom() * Math.PI * 2,
15000
+ leftEyePhaseOffset,
15001
+ rightEyePhaseOffset,
15002
+ };
15003
+ octopus3dStableStateCache.set(createRandom, state);
15004
+ return state;
15005
+ }
14950
15006
  /**
14951
15007
  * Proper 3D Octopus visual built from projected organic meshes and tentacles.
14952
15008
  *
@@ -14959,10 +15015,7 @@ const octopus3dAvatarVisual = {
14959
15015
  isAnimated: true,
14960
15016
  supportsPointerTracking: true,
14961
15017
  render({ context, size, palette, createRandom, timeMs, interaction }) {
14962
- const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
14963
- const animationRandom = createRandom('octopus3d-animation-profile');
14964
- const eyeRandom = createRandom('octopus3d-eye-profile');
14965
- const animationPhase = animationRandom() * Math.PI * 2;
15018
+ const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
14966
15019
  const sceneCenterX = size * 0.5;
14967
15020
  const sceneCenterY = size * 0.56;
14968
15021
  const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
@@ -15059,12 +15112,12 @@ const octopus3dAvatarVisual = {
15059
15112
  x: -faceEyeSpacing,
15060
15113
  y: faceEyeYOffset,
15061
15114
  z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
15062
- }, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
15115
+ }, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
15063
15116
  drawProjectedOrganicEye(context, {
15064
15117
  x: faceEyeSpacing,
15065
15118
  y: faceEyeYOffset,
15066
15119
  z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
15067
- }, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
15120
+ }, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
15068
15121
  drawProjectedOrganicMouth(context, [
15069
15122
  {
15070
15123
  x: -mouthHalfWidth,
@@ -15108,14 +15161,28 @@ function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCent
15108
15161
  /**
15109
15162
  * Draws the soft ground shadow below the octopus.
15110
15163
  *
15164
+ * Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
15165
+ * blurry ellipse without triggering a costly software rasterization pass on every frame.
15166
+ *
15111
15167
  * @private helper of `octopus3dAvatarVisual`
15112
15168
  */
15113
15169
  function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
15170
+ const cx = size * 0.5 + interaction.gazeX * size * 0.04;
15171
+ const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
15172
+ const rx = size * (0.18 + interaction.intensity * 0.02);
15173
+ const ry = size * 0.06;
15114
15174
  context.save();
15115
- context.fillStyle = `${palette.shadow}66`;
15116
- context.filter = `blur(${size * 0.022}px)`;
15175
+ context.translate(cx, cy);
15176
+ context.scale(1, ry / rx);
15177
+ const blurRadius = rx * 1.4;
15178
+ const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
15179
+ shadowGradient.addColorStop(0, `${palette.shadow}7a`);
15180
+ shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
15181
+ shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
15182
+ shadowGradient.addColorStop(1, `${palette.shadow}00`);
15183
+ context.fillStyle = shadowGradient;
15117
15184
  context.beginPath();
15118
- context.ellipse(size * 0.5 + interaction.gazeX * size * 0.04, size * 0.87 + Math.sin(timeMs / 920) * size * 0.008, size * (0.18 + interaction.intensity * 0.02), size * 0.06, 0, 0, Math.PI * 2);
15185
+ context.arc(0, 0, blurRadius, 0, Math.PI * 2);
15119
15186
  context.fill();
15120
15187
  context.restore();
15121
15188
  }
@@ -15346,6 +15413,35 @@ const LIGHT_DIRECTION$1 = normalizeVector3({
15346
15413
  y: -0.6,
15347
15414
  z: 0.98,
15348
15415
  });
15416
+ /**
15417
+ * Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
15418
+ *
15419
+ * @private helper of `octopus3d2AvatarVisual`
15420
+ */
15421
+ const octopus3d2StableStateCache = new WeakMap();
15422
+ /**
15423
+ * Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
15424
+ *
15425
+ * @private helper of `octopus3d2AvatarVisual`
15426
+ */
15427
+ function getOctopus3d2StableState(createRandom) {
15428
+ const cached = octopus3d2StableStateCache.get(createRandom);
15429
+ if (cached !== undefined) {
15430
+ return cached;
15431
+ }
15432
+ const animationRandom = createRandom('octopus3d2-animation-profile');
15433
+ const eyeRandom = createRandom('octopus3d2-eye-profile');
15434
+ const leftEyePhaseOffset = eyeRandom() * 0.7;
15435
+ const rightEyePhaseOffset = eyeRandom() * 0.7;
15436
+ const state = {
15437
+ morphologyProfile: createOctopus3MorphologyProfile(createRandom),
15438
+ animationPhase: animationRandom() * Math.PI * 2,
15439
+ leftEyePhaseOffset,
15440
+ rightEyePhaseOffset,
15441
+ };
15442
+ octopus3d2StableStateCache.set(createRandom, state);
15443
+ return state;
15444
+ }
15349
15445
  /**
15350
15446
  * Octopus 3D 2 avatar visual.
15351
15447
  *
@@ -15358,10 +15454,7 @@ const octopus3d2AvatarVisual = {
15358
15454
  isAnimated: true,
15359
15455
  supportsPointerTracking: true,
15360
15456
  render({ context, size, palette, createRandom, timeMs, interaction }) {
15361
- const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
15362
- const animationRandom = createRandom('octopus3d2-animation-profile');
15363
- const eyeRandom = createRandom('octopus3d2-eye-profile');
15364
- const animationPhase = animationRandom() * Math.PI * 2;
15457
+ const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3d2StableState(createRandom);
15365
15458
  const sceneCenterX = size * 0.5;
15366
15459
  const sceneCenterY = size * 0.575;
15367
15460
  const bob = Math.sin(timeMs / 940 + animationPhase) * size * 0.013;
@@ -15414,8 +15507,8 @@ const octopus3d2AvatarVisual = {
15414
15507
  const rightEyeLocalCenter = sampleBlobbyOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude);
15415
15508
  const eyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.78;
15416
15509
  const eyeRadiusY = eyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.92;
15417
- drawProjectedOrganicEye(context, leftEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.7, interaction, morphologyProfile.face.eyeStyle);
15418
- drawProjectedOrganicEye(context, rightEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.9 + eyeRandom() * 0.7, interaction, morphologyProfile.face.eyeStyle);
15510
+ drawProjectedOrganicEye(context, leftEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
15511
+ drawProjectedOrganicEye(context, rightEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.9 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
15419
15512
  drawProjectedOrganicMouth(context, [
15420
15513
  sampleBlobbyOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
15421
15514
  sampleBlobbyOctopusSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
@@ -15444,14 +15537,28 @@ function drawBlobbyOctopusAtmosphere(context, size, palette, sceneCenterX, scene
15444
15537
  /**
15445
15538
  * Draws the soft floor shadow that anchors the single mesh in the frame.
15446
15539
  *
15540
+ * Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
15541
+ * blurry ellipse without triggering a costly software rasterization pass on every frame.
15542
+ *
15447
15543
  * @private helper of `octopus3d2AvatarVisual`
15448
15544
  */
15449
15545
  function drawBlobbyOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
15546
+ const cx = size * 0.5 + interaction.gazeX * size * 0.045;
15547
+ const cy = size * 0.88 + Math.sin(timeMs / 940) * size * 0.008;
15548
+ const rx = size * (0.18 + (morphologyProfile.body.horizontalStretch - 1) * 0.04 + interaction.intensity * 0.018);
15549
+ const ry = size * 0.062;
15450
15550
  context.save();
15451
- context.fillStyle = `${palette.shadow}66`;
15452
- context.filter = `blur(${size * 0.024}px)`;
15551
+ context.translate(cx, cy);
15552
+ context.scale(1, ry / rx);
15553
+ const blurRadius = rx * 1.4;
15554
+ const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
15555
+ shadowGradient.addColorStop(0, `${palette.shadow}7a`);
15556
+ shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
15557
+ shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
15558
+ shadowGradient.addColorStop(1, `${palette.shadow}00`);
15559
+ context.fillStyle = shadowGradient;
15453
15560
  context.beginPath();
15454
- context.ellipse(size * 0.5 + interaction.gazeX * size * 0.045, size * 0.88 + Math.sin(timeMs / 940) * size * 0.008, size * (0.18 + (morphologyProfile.body.horizontalStretch - 1) * 0.04 + interaction.intensity * 0.018), size * 0.062, 0, 0, Math.PI * 2);
15561
+ context.arc(0, 0, blurRadius, 0, Math.PI * 2);
15455
15562
  context.fill();
15456
15563
  context.restore();
15457
15564
  }
@@ -15607,6 +15714,40 @@ const LIGHT_DIRECTION = normalizeVector3({
15607
15714
  * @private helper of `octopus3d3AvatarVisual`
15608
15715
  */
15609
15716
  const OCTOPUS_TENTACLE_COUNT = 8;
15717
+ /**
15718
+ * Cache keyed by the `createRandom` factory reference, which is stable for the lifetime of one
15719
+ * mounted `<Avatar/>` component (created inside `resolveAvatarRenderDefinition` and held in a
15720
+ * React `useMemo`). Using a `WeakMap` ensures the entry is collected when the component unmounts.
15721
+ *
15722
+ * @private helper of `octopus3d3AvatarVisual`
15723
+ */
15724
+ const stableStateCache = new WeakMap();
15725
+ /**
15726
+ * Returns the stable per-avatar state, computing it on first access and returning the cached
15727
+ * result on every subsequent call within the same `<Avatar/>` mount.
15728
+ *
15729
+ * @private helper of `octopus3d3AvatarVisual`
15730
+ */
15731
+ function getOctopus3d3StableState(createRandom) {
15732
+ const cached = stableStateCache.get(createRandom);
15733
+ if (cached !== undefined) {
15734
+ return cached;
15735
+ }
15736
+ const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
15737
+ const animationRandom = createRandom('octopus3d3-animation-profile');
15738
+ const eyeRandom = createRandom('octopus3d3-eye-profile');
15739
+ const leftEyePhaseOffset = eyeRandom() * 0.7;
15740
+ const rightEyePhaseOffset = eyeRandom() * 0.7;
15741
+ const state = {
15742
+ morphologyProfile,
15743
+ animationPhase: animationRandom() * Math.PI * 2,
15744
+ leftEyePhaseOffset,
15745
+ rightEyePhaseOffset,
15746
+ tentacleProfiles: createContinuousTentacleProfiles(createRandom, morphologyProfile),
15747
+ };
15748
+ stableStateCache.set(createRandom, state);
15749
+ return state;
15750
+ }
15610
15751
  /**
15611
15752
  * Octopus 3D 3 avatar visual.
15612
15753
  *
@@ -15619,11 +15760,7 @@ const octopus3d3AvatarVisual = {
15619
15760
  isAnimated: true,
15620
15761
  supportsPointerTracking: true,
15621
15762
  render({ context, size, palette, createRandom, timeMs, interaction }) {
15622
- const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
15623
- const animationRandom = createRandom('octopus3d3-animation-profile');
15624
- const eyeRandom = createRandom('octopus3d3-eye-profile');
15625
- const animationPhase = animationRandom() * Math.PI * 2;
15626
- const tentacleProfiles = createContinuousTentacleProfiles(createRandom, morphologyProfile);
15763
+ const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset, tentacleProfiles } = getOctopus3d3StableState(createRandom);
15627
15764
  const sceneCenterX = size * 0.5;
15628
15765
  const sceneCenterY = size * 0.535;
15629
15766
  const bob = Math.sin(timeMs / 960 + animationPhase) * size * 0.012;
@@ -15700,8 +15837,8 @@ const octopus3d3AvatarVisual = {
15700
15837
  size,
15701
15838
  palette,
15702
15839
  });
15703
- drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, -eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.7, interaction, morphologyProfile.face.eyeStyle);
15704
- drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.85 + eyeRandom() * 0.7, interaction, morphologyProfile.face.eyeStyle);
15840
+ drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, -eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
15841
+ drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.85 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
15705
15842
  drawProjectedOrganicMouth(context, [
15706
15843
  sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
15707
15844
  sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
@@ -15752,14 +15889,30 @@ function drawContinuousOctopusAtmosphere(context, size, palette, sceneCenterX, s
15752
15889
  /**
15753
15890
  * Draws the soft lower shadow that anchors the octopus in the avatar frame.
15754
15891
  *
15892
+ * Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
15893
+ * blurry ellipse without triggering a costly software rasterization pass on every frame.
15894
+ *
15755
15895
  * @private helper of `octopus3d3AvatarVisual`
15756
15896
  */
15757
15897
  function drawContinuousOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
15898
+ const cx = size * 0.5 + interaction.gazeX * size * 0.045;
15899
+ const cy = size * 0.9 + Math.sin(timeMs / 980) * size * 0.007;
15900
+ const rx = size * (0.19 + morphologyProfile.tentacles.rootSpreadScale * 0.022 + interaction.intensity * 0.02);
15901
+ const ry = size * 0.06;
15902
+ // Scale the context so that drawing a circle produces the correct ellipse aspect ratio,
15903
+ // then fill with a radial gradient that approximates the blurry edge without context.filter.
15758
15904
  context.save();
15759
- context.fillStyle = `${palette.shadow}66`;
15760
- context.filter = `blur(${size * 0.025}px)`;
15905
+ context.translate(cx, cy);
15906
+ context.scale(1, ry / rx);
15907
+ const blurRadius = rx * 1.4;
15908
+ const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
15909
+ shadowGradient.addColorStop(0, `${palette.shadow}7a`);
15910
+ shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
15911
+ shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
15912
+ shadowGradient.addColorStop(1, `${palette.shadow}00`);
15913
+ context.fillStyle = shadowGradient;
15761
15914
  context.beginPath();
15762
- context.ellipse(size * 0.5 + interaction.gazeX * size * 0.045, size * 0.9 + Math.sin(timeMs / 980) * size * 0.007, size * (0.19 + morphologyProfile.tentacles.rootSpreadScale * 0.022 + interaction.intensity * 0.02), size * 0.06, 0, 0, Math.PI * 2);
15915
+ context.arc(0, 0, blurRadius, 0, Math.PI * 2);
15763
15916
  context.fill();
15764
15917
  context.restore();
15765
15918
  }
@@ -29164,7 +29317,9 @@ function parseBookMessageHeader(line) {
29164
29317
  * @private internal utility of `Book`
29165
29318
  */
29166
29319
  function parseCommitmentHeader(line) {
29167
- const match = /^([A-Z][A-Z0-9]*(?: [A-Z0-9]+)*)(?:\s+(.*))?$/u.exec(line);
29320
+ // Require at least 2 characters in the first keyword word to avoid treating common
29321
+ // single-letter words (e.g. "V" in Czech, "I" or "A" in English) as commitment headers.
29322
+ const match = /^([A-Z][A-Z0-9]+(?: [A-Z0-9]+)*)(?:\s+(.*))?$/u.exec(line);
29168
29323
  if (!match) {
29169
29324
  return null;
29170
29325
  }
@@ -41118,7 +41273,7 @@ function emitAgentLlmExecutionToolsAssistantPreparationProgress(options) {
41118
41273
  * Computes one stable hash from a JSON-serializable value.
41119
41274
  */
41120
41275
  function computeJsonHash$1(value) {
41121
- return SHA256(JSON.stringify(value)).toString();
41276
+ return CryptoJS.SHA256(JSON.stringify(value)).toString();
41122
41277
  }
41123
41278
  /**
41124
41279
  * Handles OpenAI AgentKit-backed executions for `AgentLlmExecutionTools`.
@@ -41276,7 +41431,7 @@ AgentLlmExecutionToolsAgentKitRunner.vectorStoreCache = new Map();
41276
41431
  * Computes one stable hash from a JSON-serializable value.
41277
41432
  */
41278
41433
  function computeJsonHash(value) {
41279
- return SHA256(JSON.stringify(value)).toString();
41434
+ return CryptoJS.SHA256(JSON.stringify(value)).toString();
41280
41435
  }
41281
41436
  /**
41282
41437
  * Removes assistant-managed requirements before the prompt is executed via OpenAI Assistants.
@@ -42132,7 +42287,7 @@ class AgentLlmExecutionTools {
42132
42287
  * Returns a virtual model name representing the agent behavior.
42133
42288
  */
42134
42289
  get modelName() {
42135
- const hash = SHA256(hexEncoder.parse(this.options.agentSource)).toString( /* hex */);
42290
+ const hash = CryptoJS.SHA256(hexEncoder.parse(this.options.agentSource)).toString( /* hex */);
42136
42291
  const agentId = hash.substring(0, 10);
42137
42292
  return (normalizeToKebabCase(this.title) + '-' + agentId);
42138
42293
  }