@promptbook/cli 0.112.0-102 → 0.112.0-104
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/agents-server/README.md +0 -6
- package/apps/agents-server/src/app/AddAgentButton.tsx +0 -5
- package/apps/agents-server/src/app/actions.ts +50 -0
- package/apps/agents-server/src/app/admin/image-generator-test/ImageAttachmentsEditor.tsx +11 -6
- package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +13 -15
- package/apps/agents-server/src/app/admin/servers/useCreateServerWizard.ts +13 -14
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +3 -4
- package/apps/agents-server/src/app/api/health/route.ts +18 -0
- package/apps/agents-server/src/app/api/upload/route.ts +110 -383
- package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +1 -4
- package/apps/agents-server/src/components/Header/Header.tsx +0 -11
- package/apps/agents-server/src/components/Header/useHeaderAgentMenus.tsx +0 -5
- package/apps/agents-server/src/components/NewAgentDialog/useNewAgentDialog.tsx +39 -16
- package/apps/agents-server/src/constants/defaultAgentAvatarVisual.ts +1 -1
- package/apps/agents-server/src/database/migrations/2026-06-0200-default-agent-avatar-visual-octopus3d3.sql +16 -0
- package/apps/agents-server/src/middleware.ts +2 -1
- package/apps/agents-server/src/tools/$provideCdnForServer.ts +87 -49
- package/apps/agents-server/src/utils/agentRouting/resolveAgentRouteTarget.ts +27 -4
- package/apps/agents-server/src/utils/cdn/classes/DigitalOceanSpaces.ts +17 -49
- package/apps/agents-server/src/utils/cdn/classes/TrackedFilesStorage.ts +5 -2
- package/apps/agents-server/src/utils/cdn/interfaces/IFilesStorage.ts +5 -0
- package/apps/agents-server/src/utils/defaultAgents/defaultAgents.ts +168 -0
- package/apps/agents-server/src/utils/defaultAgents/installDefaultAgents.ts +139 -0
- package/apps/agents-server/src/utils/shareTargetPayloads.ts +15 -63
- package/apps/agents-server/src/utils/upload/createBookEditorUploadHandler.ts +23 -150
- package/apps/agents-server/src/utils/upload/uploadFileToServer.ts +113 -0
- package/esm/index.es.js +711 -41
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/common/waitForPause.d.ts +12 -0
- package/esm/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -1
- package/esm/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +1 -0
- package/esm/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +1 -1
- package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/esm/src/avatars/visuals/octopus3d3AvatarVisual.d.ts +7 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/avatars/types/AvatarVisualDefinition.ts +1 -0
- package/src/avatars/visuals/avatarVisualRegistry.ts +2 -0
- package/src/avatars/visuals/octopus3d3AvatarVisual.ts +903 -0
- package/src/book-components/Chat/MarkdownContent/MarkdownContent.tsx +1 -3
- package/src/other/templates/getTemplatesPipelineCollection.ts +799 -809
- package/src/utils/agents/resolveAgentAvatarImageUrl.ts +1 -1
- package/src/version.ts +2 -2
- package/src/versions.txt +1 -0
- package/umd/index.umd.js +711 -41
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/common/waitForPause.d.ts +12 -0
- package/umd/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -1
- package/umd/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +1 -0
- package/umd/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +1 -1
- package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/umd/src/avatars/visuals/octopus3d3AvatarVisual.d.ts +7 -0
- package/umd/src/version.d.ts +1 -1
- package/apps/agents-server/src/utils/cdn/resolveCdnStorageProvider.ts +0 -40
package/esm/index.es.js
CHANGED
|
@@ -58,7 +58,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
58
58
|
* @generated
|
|
59
59
|
* @see https://github.com/webgptorg/promptbook
|
|
60
60
|
*/
|
|
61
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
61
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-104';
|
|
62
62
|
/**
|
|
63
63
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
64
64
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -3615,16 +3615,30 @@ function resolveNextCliPath() {
|
|
|
3615
3615
|
// Note: [🟡] Code for CLI runtime [buildAgentsServer](src/cli/cli-commands/agents-server/buildAgentsServer.ts) should never be published outside of `@promptbook/cli`
|
|
3616
3616
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
3617
3617
|
|
|
3618
|
+
/**
|
|
3619
|
+
* Default label used before the next pause checkpoint is known.
|
|
3620
|
+
*/
|
|
3621
|
+
const DEFAULT_PAUSE_TARGET_LABEL = 'the next task';
|
|
3618
3622
|
/**
|
|
3619
3623
|
* Current pause state.
|
|
3620
3624
|
*/
|
|
3621
3625
|
let pauseState = 'RUNNING';
|
|
3626
|
+
/**
|
|
3627
|
+
* Label of the next checkpoint where the requested pause will take effect.
|
|
3628
|
+
*/
|
|
3629
|
+
let pauseTargetLabel = DEFAULT_PAUSE_TARGET_LABEL;
|
|
3622
3630
|
/**
|
|
3623
3631
|
* Stores one new pause state in the shared runner controller.
|
|
3624
3632
|
*/
|
|
3625
3633
|
function setPauseState(nextPauseState) {
|
|
3626
3634
|
pauseState = nextPauseState;
|
|
3627
3635
|
}
|
|
3636
|
+
/**
|
|
3637
|
+
* Stores one new pause target label in the shared runner controller.
|
|
3638
|
+
*/
|
|
3639
|
+
function setPauseTargetLabel(nextPauseTargetLabel) {
|
|
3640
|
+
pauseTargetLabel = nextPauseTargetLabel.trim() || DEFAULT_PAUSE_TARGET_LABEL;
|
|
3641
|
+
}
|
|
3628
3642
|
/**
|
|
3629
3643
|
* Applies the same three-state toggle used by the `P` hotkey.
|
|
3630
3644
|
*/
|
|
@@ -3635,9 +3649,11 @@ function togglePauseState() {
|
|
|
3635
3649
|
}
|
|
3636
3650
|
if (pauseState === 'PAUSING') {
|
|
3637
3651
|
setPauseState('RUNNING');
|
|
3652
|
+
resetPauseTargetLabel();
|
|
3638
3653
|
return 'CANCELLED_PAUSE';
|
|
3639
3654
|
}
|
|
3640
3655
|
setPauseState('RUNNING');
|
|
3656
|
+
resetPauseTargetLabel();
|
|
3641
3657
|
return 'RESUMED';
|
|
3642
3658
|
}
|
|
3643
3659
|
/**
|
|
@@ -3678,7 +3694,8 @@ async function checkPause(options) {
|
|
|
3678
3694
|
if (pauseState === 'PAUSING') {
|
|
3679
3695
|
setPauseState('PAUSED');
|
|
3680
3696
|
if (!(options === null || options === void 0 ? void 0 : options.silent)) {
|
|
3681
|
-
console.log(colors.bgWhite.black(
|
|
3697
|
+
console.log(colors.bgWhite.black(`Paused before ${getPauseTargetLabel()}`) +
|
|
3698
|
+
colors.gray(' (Press "p" to resume)'));
|
|
3682
3699
|
}
|
|
3683
3700
|
(_a = options === null || options === void 0 ? void 0 : options.onPaused) === null || _a === void 0 ? void 0 : _a.call(options);
|
|
3684
3701
|
while (getPauseState() === 'PAUSED') {
|
|
@@ -3696,6 +3713,24 @@ async function checkPause(options) {
|
|
|
3696
3713
|
function getPauseState() {
|
|
3697
3714
|
return pauseState;
|
|
3698
3715
|
}
|
|
3716
|
+
/**
|
|
3717
|
+
* Returns the label of the next checkpoint where pausing will take effect.
|
|
3718
|
+
*/
|
|
3719
|
+
function getPauseTargetLabel() {
|
|
3720
|
+
return pauseTargetLabel;
|
|
3721
|
+
}
|
|
3722
|
+
/**
|
|
3723
|
+
* Updates the label of the next pause checkpoint.
|
|
3724
|
+
*/
|
|
3725
|
+
function announcePauseTargetLabel(nextPauseTargetLabel) {
|
|
3726
|
+
setPauseTargetLabel(nextPauseTargetLabel);
|
|
3727
|
+
}
|
|
3728
|
+
/**
|
|
3729
|
+
* Restores the default generic pause target label.
|
|
3730
|
+
*/
|
|
3731
|
+
function resetPauseTargetLabel() {
|
|
3732
|
+
setPauseTargetLabel(DEFAULT_PAUSE_TARGET_LABEL);
|
|
3733
|
+
}
|
|
3699
3734
|
|
|
3700
3735
|
/**
|
|
3701
3736
|
* Just says that the variable is not used but should be kept
|
|
@@ -3933,18 +3968,18 @@ function buildScriptPathSessionRows(scriptPaths, bodyWidth) {
|
|
|
3933
3968
|
/**
|
|
3934
3969
|
* Builds the colored phase badge shown in the session box.
|
|
3935
3970
|
*/
|
|
3936
|
-
function buildPausePresentation(phase, pauseState, statusMessage) {
|
|
3971
|
+
function buildPausePresentation(phase, pauseState, pauseTargetLabel, statusMessage) {
|
|
3937
3972
|
if (pauseState === 'PAUSING') {
|
|
3938
3973
|
return {
|
|
3939
3974
|
badge: colors.bgYellow.black(' PAUSING '),
|
|
3940
|
-
stateMessage:
|
|
3975
|
+
stateMessage: `Pausing before ${pauseTargetLabel}`,
|
|
3941
3976
|
pauseControl: colors.bgMagenta.white(' P ') + colors.white(' Cancel pause'),
|
|
3942
3977
|
};
|
|
3943
3978
|
}
|
|
3944
3979
|
if (pauseState === 'PAUSED') {
|
|
3945
3980
|
return {
|
|
3946
3981
|
badge: colors.bgWhite.black(' PAUSED '),
|
|
3947
|
-
stateMessage:
|
|
3982
|
+
stateMessage: `Paused before ${pauseTargetLabel}`,
|
|
3948
3983
|
pauseControl: colors.bgGreen.black(' P ') + colors.white(' Resume'),
|
|
3949
3984
|
};
|
|
3950
3985
|
}
|
|
@@ -4076,7 +4111,7 @@ function buildCoderRunUiFrame(options) {
|
|
|
4076
4111
|
const octopusAnimationFrame = isCoderRunUiAutoRefreshing(options.phase, options.pauseState)
|
|
4077
4112
|
? options.animationFrame
|
|
4078
4113
|
: 0;
|
|
4079
|
-
const pausePresentation = buildPausePresentation(options.phase, options.pauseState, options.statusMessage);
|
|
4114
|
+
const pausePresentation = buildPausePresentation(options.phase, options.pauseState, options.pauseTargetLabel, options.statusMessage);
|
|
4080
4115
|
const sessionLines = buildSessionLines$1(options, totalWidth, pausePresentation);
|
|
4081
4116
|
const currentTaskLines = options.currentPromptLabel
|
|
4082
4117
|
? [
|
|
@@ -4704,6 +4739,7 @@ function renderCoderRunUi(startTime, options = {}) {
|
|
|
4704
4739
|
animationFrame: spinnerFrame,
|
|
4705
4740
|
spinner: SPINNER_FRAMES[spinnerFrame],
|
|
4706
4741
|
pauseState: getPauseState(),
|
|
4742
|
+
pauseTargetLabel: getPauseTargetLabel(),
|
|
4707
4743
|
config: state.config,
|
|
4708
4744
|
phase: state.phase,
|
|
4709
4745
|
currentPromptLabel: state.currentPromptLabel,
|
|
@@ -11005,7 +11041,7 @@ function fillTextureRect(texture, x, y, width, height, color) {
|
|
|
11005
11041
|
*
|
|
11006
11042
|
* @private helper of `minecraft2AvatarVisual`
|
|
11007
11043
|
*/
|
|
11008
|
-
const LIGHT_DIRECTION$
|
|
11044
|
+
const LIGHT_DIRECTION$3 = normalizeVector3({
|
|
11009
11045
|
x: 0.4,
|
|
11010
11046
|
y: -0.65,
|
|
11011
11047
|
z: 0.92,
|
|
@@ -11217,7 +11253,7 @@ function resolveVisibleCuboidFaces(cuboid, size, sceneCenterX, sceneCenterY) {
|
|
|
11217
11253
|
corners: projectedCorners,
|
|
11218
11254
|
texture: faceDefinition.texture,
|
|
11219
11255
|
averageDepth: transformedCorners.reduce((depthSum, corner) => depthSum + corner.z, 0) / transformedCorners.length,
|
|
11220
|
-
lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION$
|
|
11256
|
+
lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION$3), -1, 1),
|
|
11221
11257
|
outlineColor: cuboid.outlineColor,
|
|
11222
11258
|
};
|
|
11223
11259
|
});
|
|
@@ -12408,7 +12444,7 @@ function formatAlphaHex(opacity) {
|
|
|
12408
12444
|
*
|
|
12409
12445
|
* @private helper of `octopus3dAvatarVisual`
|
|
12410
12446
|
*/
|
|
12411
|
-
const LIGHT_DIRECTION$
|
|
12447
|
+
const LIGHT_DIRECTION$2 = normalizeVector3({
|
|
12412
12448
|
x: 0.48,
|
|
12413
12449
|
y: -0.62,
|
|
12414
12450
|
z: 0.94,
|
|
@@ -12618,7 +12654,7 @@ function resolveVisibleEllipsoidPatches(options) {
|
|
|
12618
12654
|
corners: projectedCorners,
|
|
12619
12655
|
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
12620
12656
|
transformedCorners.length,
|
|
12621
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$
|
|
12657
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$2), -1, 1),
|
|
12622
12658
|
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
12623
12659
|
outlineColor,
|
|
12624
12660
|
});
|
|
@@ -12807,7 +12843,7 @@ function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
|
12807
12843
|
*
|
|
12808
12844
|
* @private helper of `octopus3d2AvatarVisual`
|
|
12809
12845
|
*/
|
|
12810
|
-
const LIGHT_DIRECTION = normalizeVector3({
|
|
12846
|
+
const LIGHT_DIRECTION$1 = normalizeVector3({
|
|
12811
12847
|
x: 0.38,
|
|
12812
12848
|
y: -0.6,
|
|
12813
12849
|
z: 0.98,
|
|
@@ -12956,7 +12992,7 @@ function resolveVisibleBlobbyOctopusPatches(options) {
|
|
|
12956
12992
|
corners: projectedCorners,
|
|
12957
12993
|
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
12958
12994
|
transformedCorners.length,
|
|
12959
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
12995
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$1), -1, 1),
|
|
12960
12996
|
fillStyle: resolveBlobbySurfacePatchFillStyle(palette, verticalProgress, Math.max(0, Math.cos(centerLongitude)), resolveLowerLobeWave(centerLongitude, morphologyProfile, animationPhase, timeMs)),
|
|
12961
12997
|
outlineColor: verticalProgress < 0.58 ? `${palette.highlight}73` : `${palette.shadow}8a`,
|
|
12962
12998
|
});
|
|
@@ -13056,6 +13092,516 @@ function drawBlobbySurfacePatch(context, surfacePatch) {
|
|
|
13056
13092
|
context.restore();
|
|
13057
13093
|
}
|
|
13058
13094
|
|
|
13095
|
+
/* eslint-disable no-magic-numbers */
|
|
13096
|
+
/**
|
|
13097
|
+
* Light direction used by the continuous octopus mesh shading.
|
|
13098
|
+
*
|
|
13099
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13100
|
+
*/
|
|
13101
|
+
const LIGHT_DIRECTION = normalizeVector3({
|
|
13102
|
+
x: 0.34,
|
|
13103
|
+
y: -0.62,
|
|
13104
|
+
z: 1,
|
|
13105
|
+
});
|
|
13106
|
+
/**
|
|
13107
|
+
* Real-octopus tentacle count used by the continuous lower mesh.
|
|
13108
|
+
*
|
|
13109
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13110
|
+
*/
|
|
13111
|
+
const OCTOPUS_TENTACLE_COUNT = 8;
|
|
13112
|
+
/**
|
|
13113
|
+
* Octopus 3D 3 avatar visual.
|
|
13114
|
+
*
|
|
13115
|
+
* @private built-in avatar visual
|
|
13116
|
+
*/
|
|
13117
|
+
const octopus3d3AvatarVisual = {
|
|
13118
|
+
id: 'octopus3d3',
|
|
13119
|
+
title: 'Octopus 3D 3',
|
|
13120
|
+
description: 'Cute continuous 3D octopus with a blobby single mesh, waving tentacle lobes, rich shading, and cursor-aware eyes.',
|
|
13121
|
+
isAnimated: true,
|
|
13122
|
+
supportsPointerTracking: true,
|
|
13123
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
13124
|
+
const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
|
|
13125
|
+
const animationRandom = createRandom('octopus3d3-animation-profile');
|
|
13126
|
+
const eyeRandom = createRandom('octopus3d3-eye-profile');
|
|
13127
|
+
const animationPhase = animationRandom() * Math.PI * 2;
|
|
13128
|
+
const tentacleProfiles = createContinuousTentacleProfiles(createRandom, morphologyProfile);
|
|
13129
|
+
const sceneCenterX = size * 0.5;
|
|
13130
|
+
const sceneCenterY = size * 0.535;
|
|
13131
|
+
const bob = Math.sin(timeMs / 960 + animationPhase) * size * 0.012;
|
|
13132
|
+
const meshCenter = {
|
|
13133
|
+
x: interaction.bodyOffsetX * size * 0.048 + size * morphologyProfile.body.centerXJitterRatio * 0.44,
|
|
13134
|
+
y: -size * 0.07 + interaction.bodyOffsetY * size * 0.026 + bob,
|
|
13135
|
+
z: interaction.intensity * size * 0.018,
|
|
13136
|
+
};
|
|
13137
|
+
const rotationY = -0.1 +
|
|
13138
|
+
Math.sin(timeMs / 2700 + animationPhase) * 0.035 +
|
|
13139
|
+
interaction.bodyOffsetX * 0.22 +
|
|
13140
|
+
interaction.gazeX * 0.88;
|
|
13141
|
+
const rotationX = -0.07 +
|
|
13142
|
+
Math.cos(timeMs / 3100 + animationPhase * 0.7) * 0.018 -
|
|
13143
|
+
interaction.bodyOffsetY * 0.08 -
|
|
13144
|
+
interaction.gazeY * 0.38;
|
|
13145
|
+
const surfaceOptions = {
|
|
13146
|
+
radiusX: size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch * 1.1,
|
|
13147
|
+
radiusY: size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.08,
|
|
13148
|
+
radiusZ: size *
|
|
13149
|
+
morphologyProfile.body.bodyRadiusRatio *
|
|
13150
|
+
(1.02 + (morphologyProfile.body.horizontalStretch - 1) * 0.18),
|
|
13151
|
+
morphologyProfile,
|
|
13152
|
+
timeMs,
|
|
13153
|
+
animationPhase,
|
|
13154
|
+
tentacleProfiles,
|
|
13155
|
+
};
|
|
13156
|
+
const surfacePatches = resolveVisibleContinuousOctopusPatches({
|
|
13157
|
+
...surfaceOptions,
|
|
13158
|
+
center: meshCenter,
|
|
13159
|
+
rotationX,
|
|
13160
|
+
rotationY,
|
|
13161
|
+
sceneCenterX,
|
|
13162
|
+
sceneCenterY,
|
|
13163
|
+
size,
|
|
13164
|
+
palette,
|
|
13165
|
+
});
|
|
13166
|
+
const eyeLatitude = clampNumber$1(morphologyProfile.face.eyeCenterYOffsetRatio * 4.2 - 0.03, -0.22, 0.08);
|
|
13167
|
+
const eyeLongitude = clampNumber$1(morphologyProfile.face.eyeSpacingRatio * 3.1, 0.18, 0.32);
|
|
13168
|
+
const mouthLatitude = clampNumber$1(eyeLatitude + 0.2 + morphologyProfile.face.mouthYOffsetRatio, 0.08, 0.34);
|
|
13169
|
+
const mouthCenterLongitude = clampNumber$1(morphologyProfile.face.mouthCenterOffsetRatio * 5.6, -0.08, 0.08);
|
|
13170
|
+
const mouthHalfLongitude = clampNumber$1(eyeLongitude * 0.78, 0.15, 0.28);
|
|
13171
|
+
const mouthCurveLatitude = clampNumber$1(mouthLatitude + morphologyProfile.face.mouthCurveDepthRatio * 0.78, mouthLatitude + 0.03, 0.42);
|
|
13172
|
+
const eyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.76;
|
|
13173
|
+
const eyeRadiusY = eyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.9;
|
|
13174
|
+
drawAvatarFrame(context, size, palette);
|
|
13175
|
+
drawContinuousOctopusAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
13176
|
+
drawContinuousOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile);
|
|
13177
|
+
for (const surfacePatch of surfacePatches.sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
13178
|
+
drawContinuousSurfacePatch(context, surfacePatch);
|
|
13179
|
+
}
|
|
13180
|
+
drawProjectedSurfaceCurrents({
|
|
13181
|
+
context,
|
|
13182
|
+
surfaceOptions,
|
|
13183
|
+
center: meshCenter,
|
|
13184
|
+
rotationX,
|
|
13185
|
+
rotationY,
|
|
13186
|
+
sceneCenterX,
|
|
13187
|
+
sceneCenterY,
|
|
13188
|
+
size,
|
|
13189
|
+
palette,
|
|
13190
|
+
morphologyProfile,
|
|
13191
|
+
timeMs,
|
|
13192
|
+
animationPhase,
|
|
13193
|
+
});
|
|
13194
|
+
drawProjectedTentacleSuckers({
|
|
13195
|
+
context,
|
|
13196
|
+
surfaceOptions,
|
|
13197
|
+
center: meshCenter,
|
|
13198
|
+
rotationX,
|
|
13199
|
+
rotationY,
|
|
13200
|
+
sceneCenterX,
|
|
13201
|
+
sceneCenterY,
|
|
13202
|
+
size,
|
|
13203
|
+
palette,
|
|
13204
|
+
});
|
|
13205
|
+
drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, -eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + eyeRandom() * 0.7, interaction, morphologyProfile.face.eyeStyle);
|
|
13206
|
+
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);
|
|
13207
|
+
drawProjectedOrganicMouth(context, [
|
|
13208
|
+
sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
|
|
13209
|
+
sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
|
|
13210
|
+
sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude + mouthHalfLongitude),
|
|
13211
|
+
], meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, palette, size);
|
|
13212
|
+
},
|
|
13213
|
+
};
|
|
13214
|
+
/**
|
|
13215
|
+
* Creates seeded tentacle-lobe profiles around the visible lower octopus body.
|
|
13216
|
+
*
|
|
13217
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13218
|
+
*/
|
|
13219
|
+
function createContinuousTentacleProfiles(createRandom, morphologyProfile) {
|
|
13220
|
+
return Array.from({ length: OCTOPUS_TENTACLE_COUNT }, (_, tentacleIndex) => {
|
|
13221
|
+
const tentacleRandom = createRandom(`octopus3d3-tentacle-${tentacleIndex}`);
|
|
13222
|
+
const progress = tentacleIndex / (OCTOPUS_TENTACLE_COUNT - 1);
|
|
13223
|
+
return {
|
|
13224
|
+
centerLongitude: -Math.PI * 0.86 +
|
|
13225
|
+
progress * Math.PI * 1.72 +
|
|
13226
|
+
(tentacleRandom() - 0.5) * (0.08 + morphologyProfile.tentacles.rootSpreadScale * 0.03),
|
|
13227
|
+
widthScale: 0.86 + tentacleRandom() * 0.34 + (morphologyProfile.tentacles.baseWidthScale - 1) * 0.16,
|
|
13228
|
+
lengthScale: 0.86 + tentacleRandom() * 0.36 + (morphologyProfile.tentacles.flowLengthScale - 1) * 0.22,
|
|
13229
|
+
swayScale: 0.82 + tentacleRandom() * 0.38 + (morphologyProfile.tentacles.swayScale - 1) * 0.2,
|
|
13230
|
+
depthScale: 0.86 + tentacleRandom() * 0.32 + (morphologyProfile.tentacles.tipReachScale - 1) * 0.2,
|
|
13231
|
+
phase: tentacleRandom() * Math.PI * 2,
|
|
13232
|
+
suckerSide: tentacleRandom() > 0.5 ? 1 : -1,
|
|
13233
|
+
};
|
|
13234
|
+
});
|
|
13235
|
+
}
|
|
13236
|
+
/**
|
|
13237
|
+
* Draws the soft underwater atmosphere behind the continuous octopus mesh.
|
|
13238
|
+
*
|
|
13239
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13240
|
+
*/
|
|
13241
|
+
function drawContinuousOctopusAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
13242
|
+
const glowGradient = context.createRadialGradient(sceneCenterX + interaction.gazeX * size * 0.11, sceneCenterY - size * 0.17 + interaction.gazeY * size * 0.05, size * 0.04, sceneCenterX, sceneCenterY, size * (0.66 + interaction.intensity * 0.02));
|
|
13243
|
+
glowGradient.addColorStop(0, `${palette.highlight}66`);
|
|
13244
|
+
glowGradient.addColorStop(0.34, `${palette.accent}2e`);
|
|
13245
|
+
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
13246
|
+
context.fillStyle = glowGradient;
|
|
13247
|
+
context.fillRect(0, 0, size, size);
|
|
13248
|
+
const lowerGradient = context.createRadialGradient(sceneCenterX + Math.sin(timeMs / 1550) * size * 0.05, sceneCenterY + size * 0.29, size * 0.06, sceneCenterX, sceneCenterY + size * 0.3, size * 0.54);
|
|
13249
|
+
lowerGradient.addColorStop(0, `${palette.secondary}25`);
|
|
13250
|
+
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
13251
|
+
context.fillStyle = lowerGradient;
|
|
13252
|
+
context.fillRect(0, 0, size, size);
|
|
13253
|
+
}
|
|
13254
|
+
/**
|
|
13255
|
+
* Draws the soft lower shadow that anchors the octopus in the avatar frame.
|
|
13256
|
+
*
|
|
13257
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13258
|
+
*/
|
|
13259
|
+
function drawContinuousOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
|
|
13260
|
+
context.save();
|
|
13261
|
+
context.fillStyle = `${palette.shadow}66`;
|
|
13262
|
+
context.filter = `blur(${size * 0.025}px)`;
|
|
13263
|
+
context.beginPath();
|
|
13264
|
+
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);
|
|
13265
|
+
context.fill();
|
|
13266
|
+
context.restore();
|
|
13267
|
+
}
|
|
13268
|
+
/**
|
|
13269
|
+
* Resolves visible projected patches for the continuous octopus mesh.
|
|
13270
|
+
*
|
|
13271
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13272
|
+
*/
|
|
13273
|
+
function resolveVisibleContinuousOctopusPatches(options) {
|
|
13274
|
+
const { center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette } = options;
|
|
13275
|
+
const latitudePatchCount = 16;
|
|
13276
|
+
const longitudePatchCount = 40;
|
|
13277
|
+
const surfacePatches = [];
|
|
13278
|
+
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
13279
|
+
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
13280
|
+
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
13281
|
+
const centerLatitude = (startLatitude + endLatitude) / 2;
|
|
13282
|
+
const verticalProgress = (Math.sin(centerLatitude) + 1) / 2;
|
|
13283
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
13284
|
+
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
13285
|
+
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
13286
|
+
const centerLongitude = (startLongitude + endLongitude) / 2;
|
|
13287
|
+
const localCorners = [
|
|
13288
|
+
sampleContinuousOctopusSurfacePoint(options, startLatitude, startLongitude),
|
|
13289
|
+
sampleContinuousOctopusSurfacePoint(options, startLatitude, endLongitude),
|
|
13290
|
+
sampleContinuousOctopusSurfacePoint(options, endLatitude, endLongitude),
|
|
13291
|
+
sampleContinuousOctopusSurfacePoint(options, endLatitude, startLongitude),
|
|
13292
|
+
];
|
|
13293
|
+
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
13294
|
+
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
13295
|
+
if (surfaceNormal.z <= 0.008) {
|
|
13296
|
+
continue;
|
|
13297
|
+
}
|
|
13298
|
+
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
13299
|
+
const tentacleInfluence = resolveContinuousTentacleInfluence(options, centerLongitude);
|
|
13300
|
+
const lowerLobeWave = resolveContinuousLobeWave(options, centerLongitude);
|
|
13301
|
+
surfacePatches.push({
|
|
13302
|
+
corners: projectedCorners,
|
|
13303
|
+
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
13304
|
+
transformedCorners.length,
|
|
13305
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
13306
|
+
fillStyle: resolveContinuousSurfacePatchFillStyle(palette, verticalProgress, Math.max(0, Math.cos(centerLongitude)), tentacleInfluence.core, lowerLobeWave),
|
|
13307
|
+
outlineColor: verticalProgress < 0.54 ? `${palette.highlight}69` : `${palette.shadow}78`,
|
|
13308
|
+
});
|
|
13309
|
+
}
|
|
13310
|
+
}
|
|
13311
|
+
return surfacePatches;
|
|
13312
|
+
}
|
|
13313
|
+
/**
|
|
13314
|
+
* Samples one point on the continuous Octopus 3D 3 surface.
|
|
13315
|
+
*
|
|
13316
|
+
* The lower hemisphere is pulled into eight seeded waving lobes, so the portrait reads as
|
|
13317
|
+
* tentacled while still being rendered as one connected blobby mesh.
|
|
13318
|
+
*
|
|
13319
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13320
|
+
*/
|
|
13321
|
+
function sampleContinuousOctopusSurfacePoint(options, latitude, longitude) {
|
|
13322
|
+
const { radiusX, radiusY, radiusZ, morphologyProfile, timeMs, animationPhase } = options;
|
|
13323
|
+
const cosineLatitude = Math.max(0, Math.cos(latitude));
|
|
13324
|
+
const verticalProgress = (Math.sin(latitude) + 1) / 2;
|
|
13325
|
+
const upperBlend = Math.pow(1 - verticalProgress, 1.28);
|
|
13326
|
+
const lowerBlend = smoothStep(0.38, 1, verticalProgress);
|
|
13327
|
+
const tipBlend = smoothStep(0.68, 1, verticalProgress);
|
|
13328
|
+
const tentacleInfluence = resolveContinuousTentacleInfluence(options, longitude);
|
|
13329
|
+
const centerPull = resolveSignedAngularDistance(longitude, tentacleInfluence.centerLongitude);
|
|
13330
|
+
const effectiveLongitude = longitude + centerPull * lowerBlend * tentacleInfluence.core * (0.24 + tipBlend * 0.2);
|
|
13331
|
+
const lowerLobeWave = resolveContinuousLobeWave(options, longitude);
|
|
13332
|
+
const mantleRipple = Math.sin(longitude * morphologyProfile.body.lobeCount +
|
|
13333
|
+
animationPhase * 0.6 +
|
|
13334
|
+
timeMs / (1750 + morphologyProfile.body.lobeCount * 30)) *
|
|
13335
|
+
(0.018 + morphologyProfile.body.wobbleAmplitudeRatio * 0.8) *
|
|
13336
|
+
(0.3 + lowerBlend * 0.7);
|
|
13337
|
+
const tentacleWave = Math.sin(timeMs / 760 + tentacleInfluence.phase + verticalProgress * 2.4) *
|
|
13338
|
+
lowerBlend *
|
|
13339
|
+
tentacleInfluence.core *
|
|
13340
|
+
tentacleInfluence.swayScale;
|
|
13341
|
+
const horizontalScale = 1.04 +
|
|
13342
|
+
mantleRipple +
|
|
13343
|
+
lowerBlend * (0.16 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.1) +
|
|
13344
|
+
lowerBlend * tentacleInfluence.core * (0.2 + lowerLobeWave * 0.12) -
|
|
13345
|
+
upperBlend * 0.08;
|
|
13346
|
+
const depthScale = 1.06 +
|
|
13347
|
+
upperBlend * 0.16 +
|
|
13348
|
+
Math.max(0, Math.cos(effectiveLongitude)) * 0.1 +
|
|
13349
|
+
lowerBlend * tentacleInfluence.core * (0.1 + tentacleInfluence.depthScale * 0.06) -
|
|
13350
|
+
Math.max(0, -Math.cos(effectiveLongitude)) * 0.05;
|
|
13351
|
+
const tentacleTubeRadius = lowerBlend *
|
|
13352
|
+
tentacleInfluence.core *
|
|
13353
|
+
(0.11 + tipBlend * 0.06 + tentacleInfluence.widthScale * 0.025) *
|
|
13354
|
+
radiusX;
|
|
13355
|
+
const planarRadiusX = cosineLatitude * radiusX * horizontalScale + tentacleTubeRadius;
|
|
13356
|
+
const planarRadiusZ = cosineLatitude * radiusZ * depthScale + tentacleTubeRadius * 0.72;
|
|
13357
|
+
const lowerDrop = lowerBlend *
|
|
13358
|
+
radiusY *
|
|
13359
|
+
(0.18 +
|
|
13360
|
+
tentacleInfluence.core *
|
|
13361
|
+
(0.38 +
|
|
13362
|
+
tentacleInfluence.lengthScale * 0.22 +
|
|
13363
|
+
(morphologyProfile.tentacles.flowLengthScale - 1) * 0.08));
|
|
13364
|
+
return {
|
|
13365
|
+
x: Math.sin(effectiveLongitude) * planarRadiusX +
|
|
13366
|
+
tentacleWave * radiusX * (0.052 + tipBlend * 0.05),
|
|
13367
|
+
y: Math.sin(latitude) * radiusY * (1 + upperBlend * 0.12) -
|
|
13368
|
+
upperBlend * radiusY * 0.1 +
|
|
13369
|
+
lowerDrop +
|
|
13370
|
+
Math.sin(timeMs / 1420 + animationPhase + latitude * 1.6) * lowerBlend * radiusY * 0.018 +
|
|
13371
|
+
Math.cos(timeMs / 880 + tentacleInfluence.phase) *
|
|
13372
|
+
lowerBlend *
|
|
13373
|
+
tipBlend *
|
|
13374
|
+
tentacleInfluence.core *
|
|
13375
|
+
radiusY *
|
|
13376
|
+
0.034,
|
|
13377
|
+
z: Math.cos(effectiveLongitude) * planarRadiusZ +
|
|
13378
|
+
Math.cos(timeMs / 980 + tentacleInfluence.phase + verticalProgress) *
|
|
13379
|
+
lowerBlend *
|
|
13380
|
+
tentacleInfluence.core *
|
|
13381
|
+
radiusZ *
|
|
13382
|
+
0.04,
|
|
13383
|
+
};
|
|
13384
|
+
}
|
|
13385
|
+
/**
|
|
13386
|
+
* Blends nearby seeded tentacle profiles at one mesh longitude.
|
|
13387
|
+
*
|
|
13388
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13389
|
+
*/
|
|
13390
|
+
function resolveContinuousTentacleInfluence(options, longitude) {
|
|
13391
|
+
let totalWeight = 0;
|
|
13392
|
+
let weightedSin = 0;
|
|
13393
|
+
let weightedCos = 0;
|
|
13394
|
+
let weightedWidthScale = 0;
|
|
13395
|
+
let weightedLengthScale = 0;
|
|
13396
|
+
let weightedSwayScale = 0;
|
|
13397
|
+
let weightedDepthScale = 0;
|
|
13398
|
+
let weightedPhase = 0;
|
|
13399
|
+
for (const tentacleProfile of options.tentacleProfiles) {
|
|
13400
|
+
const distance = Math.abs(resolveSignedAngularDistance(longitude, tentacleProfile.centerLongitude));
|
|
13401
|
+
const width = 0.2 * tentacleProfile.widthScale;
|
|
13402
|
+
const weight = Math.exp(-(distance * distance) / (width * width));
|
|
13403
|
+
totalWeight += weight;
|
|
13404
|
+
weightedSin += Math.sin(tentacleProfile.centerLongitude) * weight;
|
|
13405
|
+
weightedCos += Math.cos(tentacleProfile.centerLongitude) * weight;
|
|
13406
|
+
weightedWidthScale += tentacleProfile.widthScale * weight;
|
|
13407
|
+
weightedLengthScale += tentacleProfile.lengthScale * weight;
|
|
13408
|
+
weightedSwayScale += tentacleProfile.swayScale * weight;
|
|
13409
|
+
weightedDepthScale += tentacleProfile.depthScale * weight;
|
|
13410
|
+
weightedPhase += tentacleProfile.phase * weight;
|
|
13411
|
+
}
|
|
13412
|
+
if (totalWeight < 0.0001) {
|
|
13413
|
+
return {
|
|
13414
|
+
core: 0,
|
|
13415
|
+
centerLongitude: longitude,
|
|
13416
|
+
widthScale: 1,
|
|
13417
|
+
lengthScale: 1,
|
|
13418
|
+
swayScale: 1,
|
|
13419
|
+
depthScale: 1,
|
|
13420
|
+
phase: 0,
|
|
13421
|
+
};
|
|
13422
|
+
}
|
|
13423
|
+
return {
|
|
13424
|
+
core: clampNumber$1(totalWeight, 0, 1),
|
|
13425
|
+
centerLongitude: Math.atan2(weightedSin / totalWeight, weightedCos / totalWeight),
|
|
13426
|
+
widthScale: weightedWidthScale / totalWeight,
|
|
13427
|
+
lengthScale: weightedLengthScale / totalWeight,
|
|
13428
|
+
swayScale: weightedSwayScale / totalWeight,
|
|
13429
|
+
depthScale: weightedDepthScale / totalWeight,
|
|
13430
|
+
phase: weightedPhase / totalWeight,
|
|
13431
|
+
};
|
|
13432
|
+
}
|
|
13433
|
+
/**
|
|
13434
|
+
* Resolves the soft lower wave that makes the continuous mesh read as a set of tentacles.
|
|
13435
|
+
*
|
|
13436
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13437
|
+
*/
|
|
13438
|
+
function resolveContinuousLobeWave(options, longitude) {
|
|
13439
|
+
const { morphologyProfile, animationPhase, timeMs } = options;
|
|
13440
|
+
return (Math.cos(longitude * OCTOPUS_TENTACLE_COUNT + animationPhase + timeMs / (980 + morphologyProfile.body.lobeCount * 18)) +
|
|
13441
|
+
1) / 2;
|
|
13442
|
+
}
|
|
13443
|
+
/**
|
|
13444
|
+
* Resolves one base fill tone for a patch on the continuous octopus mesh.
|
|
13445
|
+
*
|
|
13446
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13447
|
+
*/
|
|
13448
|
+
function resolveContinuousSurfacePatchFillStyle(palette, verticalProgress, forwardness, tentacleCore, lowerLobeWave) {
|
|
13449
|
+
const tonalProgress = clampNumber$1(verticalProgress + lowerLobeWave * 0.1 + tentacleCore * 0.08 - forwardness * 0.08, 0, 1);
|
|
13450
|
+
if (tonalProgress < 0.14) {
|
|
13451
|
+
return palette.highlight;
|
|
13452
|
+
}
|
|
13453
|
+
if (tonalProgress < 0.32) {
|
|
13454
|
+
return palette.secondary;
|
|
13455
|
+
}
|
|
13456
|
+
if (tonalProgress < 0.72) {
|
|
13457
|
+
return forwardness > 0.55 ? palette.secondary : palette.primary;
|
|
13458
|
+
}
|
|
13459
|
+
return tentacleCore > 0.44 ? `${palette.primary}f4` : `${palette.shadow}ee`;
|
|
13460
|
+
}
|
|
13461
|
+
/**
|
|
13462
|
+
* Draws one projected mesh patch with soft shading and a subtle edge.
|
|
13463
|
+
*
|
|
13464
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13465
|
+
*/
|
|
13466
|
+
function drawContinuousSurfacePatch(context, surfacePatch) {
|
|
13467
|
+
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
13468
|
+
if (surfacePatch.lightIntensity > 0) {
|
|
13469
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.18 * surfacePatch.lightIntensity})`);
|
|
13470
|
+
}
|
|
13471
|
+
else if (surfacePatch.lightIntensity < 0) {
|
|
13472
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.25 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
13473
|
+
}
|
|
13474
|
+
context.save();
|
|
13475
|
+
context.beginPath();
|
|
13476
|
+
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
13477
|
+
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
13478
|
+
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
13479
|
+
}
|
|
13480
|
+
context.closePath();
|
|
13481
|
+
context.strokeStyle = surfacePatch.outlineColor;
|
|
13482
|
+
context.lineWidth = Math.max(0.7, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0032);
|
|
13483
|
+
context.lineJoin = 'round';
|
|
13484
|
+
context.stroke();
|
|
13485
|
+
context.restore();
|
|
13486
|
+
}
|
|
13487
|
+
/**
|
|
13488
|
+
* Draws projected mantle-current lines on the front of the mesh.
|
|
13489
|
+
*
|
|
13490
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13491
|
+
*/
|
|
13492
|
+
function drawProjectedSurfaceCurrents(options) {
|
|
13493
|
+
const { context, surfaceOptions, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, morphologyProfile, timeMs, animationPhase, } = options;
|
|
13494
|
+
const currentCount = Math.min(6, morphologyProfile.details.mantleCurrentCount);
|
|
13495
|
+
const centerIndex = (currentCount - 1) / 2;
|
|
13496
|
+
context.save();
|
|
13497
|
+
context.lineCap = 'round';
|
|
13498
|
+
context.lineJoin = 'round';
|
|
13499
|
+
for (let currentIndex = 0; currentIndex < currentCount; currentIndex++) {
|
|
13500
|
+
const baseLongitude = (currentIndex - centerIndex) * 0.15;
|
|
13501
|
+
const projectedPoints = [];
|
|
13502
|
+
for (let sampleIndex = 0; sampleIndex < 8; sampleIndex++) {
|
|
13503
|
+
const progress = sampleIndex / 7;
|
|
13504
|
+
const latitude = -0.46 + progress * 0.74;
|
|
13505
|
+
const longitude = baseLongitude +
|
|
13506
|
+
Math.sin(timeMs / 1160 + animationPhase + currentIndex * 0.7 + progress * 2) * 0.035;
|
|
13507
|
+
const scenePoint = transformScenePoint(sampleContinuousOctopusSurfacePoint(surfaceOptions, latitude, longitude), center, rotationX, rotationY);
|
|
13508
|
+
if (scenePoint.z > center.z - size * 0.016) {
|
|
13509
|
+
projectedPoints.push(projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
13510
|
+
}
|
|
13511
|
+
}
|
|
13512
|
+
if (projectedPoints.length < 3) {
|
|
13513
|
+
continue;
|
|
13514
|
+
}
|
|
13515
|
+
context.beginPath();
|
|
13516
|
+
context.moveTo(projectedPoints[0].x, projectedPoints[0].y);
|
|
13517
|
+
for (const projectedPoint of projectedPoints.slice(1)) {
|
|
13518
|
+
context.lineTo(projectedPoint.x, projectedPoint.y);
|
|
13519
|
+
}
|
|
13520
|
+
context.strokeStyle = currentIndex % 2 === 0 ? `${palette.highlight}3d` : `${palette.accent}33`;
|
|
13521
|
+
context.lineWidth = size * (0.0055 + currentIndex * 0.00045);
|
|
13522
|
+
context.stroke();
|
|
13523
|
+
}
|
|
13524
|
+
context.restore();
|
|
13525
|
+
}
|
|
13526
|
+
/**
|
|
13527
|
+
* Draws small projected sucker highlights on the waving lower mesh lobes.
|
|
13528
|
+
*
|
|
13529
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13530
|
+
*/
|
|
13531
|
+
function drawProjectedTentacleSuckers(options) {
|
|
13532
|
+
const { surfaceOptions, size } = options;
|
|
13533
|
+
const { timeMs } = surfaceOptions;
|
|
13534
|
+
for (const tentacleProfile of surfaceOptions.tentacleProfiles) {
|
|
13535
|
+
if (Math.cos(tentacleProfile.centerLongitude) < -0.12) {
|
|
13536
|
+
continue;
|
|
13537
|
+
}
|
|
13538
|
+
for (let suckerIndex = 0; suckerIndex < 3; suckerIndex++) {
|
|
13539
|
+
const latitude = 0.52 + suckerIndex * 0.14;
|
|
13540
|
+
const sideOffset = tentacleProfile.suckerSide * (0.035 + suckerIndex * 0.012) * tentacleProfile.widthScale;
|
|
13541
|
+
const waveOffset = Math.sin(timeMs / 900 + tentacleProfile.phase + suckerIndex * 0.8) * 0.018;
|
|
13542
|
+
drawProjectedSurfaceSpot({
|
|
13543
|
+
...options,
|
|
13544
|
+
latitude,
|
|
13545
|
+
longitude: tentacleProfile.centerLongitude + sideOffset + waveOffset,
|
|
13546
|
+
radiusScale: size * (0.0065 - suckerIndex * 0.0007),
|
|
13547
|
+
});
|
|
13548
|
+
}
|
|
13549
|
+
}
|
|
13550
|
+
}
|
|
13551
|
+
/**
|
|
13552
|
+
* Draws one tiny projected surface spot by sampling local mesh tangents.
|
|
13553
|
+
*
|
|
13554
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13555
|
+
*/
|
|
13556
|
+
function drawProjectedSurfaceSpot(options) {
|
|
13557
|
+
const { context, surfaceOptions, center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, latitude, longitude, radiusScale, } = options;
|
|
13558
|
+
const localCenter = sampleContinuousOctopusSurfacePoint(surfaceOptions, latitude, longitude);
|
|
13559
|
+
const localHorizontal = sampleContinuousOctopusSurfacePoint(surfaceOptions, latitude, longitude + 0.018);
|
|
13560
|
+
const localVertical = sampleContinuousOctopusSurfacePoint(surfaceOptions, latitude + 0.018, longitude);
|
|
13561
|
+
const sceneCenterPoint = transformScenePoint(localCenter, center, rotationX, rotationY);
|
|
13562
|
+
if (sceneCenterPoint.z <= center.z - size * 0.012) {
|
|
13563
|
+
return;
|
|
13564
|
+
}
|
|
13565
|
+
const projectedCenterPoint = projectScenePoint(sceneCenterPoint, size, sceneCenterX, sceneCenterY);
|
|
13566
|
+
const projectedHorizontalPoint = projectScenePoint(transformScenePoint(localHorizontal, center, rotationX, rotationY), size, sceneCenterX, sceneCenterY);
|
|
13567
|
+
const projectedVerticalPoint = projectScenePoint(transformScenePoint(localVertical, center, rotationX, rotationY), size, sceneCenterX, sceneCenterY);
|
|
13568
|
+
const horizontalRadius = clampNumber$1(Math.hypot(projectedHorizontalPoint.x - projectedCenterPoint.x, projectedHorizontalPoint.y - projectedCenterPoint.y) *
|
|
13569
|
+
radiusScale *
|
|
13570
|
+
0.74, size * 0.003, size * 0.018);
|
|
13571
|
+
const verticalRadius = clampNumber$1(Math.hypot(projectedVerticalPoint.x - projectedCenterPoint.x, projectedVerticalPoint.y - projectedCenterPoint.y) *
|
|
13572
|
+
radiusScale *
|
|
13573
|
+
0.52, size * 0.0024, size * 0.014);
|
|
13574
|
+
const rotation = Math.atan2(projectedHorizontalPoint.y - projectedCenterPoint.y, projectedHorizontalPoint.x - projectedCenterPoint.x);
|
|
13575
|
+
context.save();
|
|
13576
|
+
context.translate(projectedCenterPoint.x, projectedCenterPoint.y);
|
|
13577
|
+
context.rotate(rotation);
|
|
13578
|
+
context.beginPath();
|
|
13579
|
+
context.ellipse(0, 0, horizontalRadius, verticalRadius, 0, 0, Math.PI * 2);
|
|
13580
|
+
context.fillStyle = `${palette.highlight}73`;
|
|
13581
|
+
context.fill();
|
|
13582
|
+
context.strokeStyle = `${palette.highlight}99`;
|
|
13583
|
+
context.lineWidth = Math.max(0.7, size * 0.0028);
|
|
13584
|
+
context.stroke();
|
|
13585
|
+
context.restore();
|
|
13586
|
+
}
|
|
13587
|
+
/**
|
|
13588
|
+
* Resolves a signed angular distance from the source longitude to the target longitude.
|
|
13589
|
+
*
|
|
13590
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13591
|
+
*/
|
|
13592
|
+
function resolveSignedAngularDistance(sourceLongitude, targetLongitude) {
|
|
13593
|
+
return Math.atan2(Math.sin(targetLongitude - sourceLongitude), Math.cos(targetLongitude - sourceLongitude));
|
|
13594
|
+
}
|
|
13595
|
+
/**
|
|
13596
|
+
* Smoothly maps a value between two bounds into `[0, 1]`.
|
|
13597
|
+
*
|
|
13598
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13599
|
+
*/
|
|
13600
|
+
function smoothStep(edgeStart, edgeEnd, value) {
|
|
13601
|
+
const progress = clampNumber$1((value - edgeStart) / (edgeEnd - edgeStart), 0, 1);
|
|
13602
|
+
return progress * progress * (3 - 2 * progress);
|
|
13603
|
+
}
|
|
13604
|
+
|
|
13059
13605
|
/* eslint-disable no-magic-numbers */
|
|
13060
13606
|
/**
|
|
13061
13607
|
* Octopus avatar visual.
|
|
@@ -13826,6 +14372,7 @@ const AVATAR_VISUALS = [
|
|
|
13826
14372
|
octopus3AvatarVisual,
|
|
13827
14373
|
octopus3dAvatarVisual,
|
|
13828
14374
|
octopus3d2AvatarVisual,
|
|
14375
|
+
octopus3d3AvatarVisual,
|
|
13829
14376
|
asciiOctopusAvatarVisual,
|
|
13830
14377
|
minecraftAvatarVisual,
|
|
13831
14378
|
minecraft2AvatarVisual,
|
|
@@ -33837,6 +34384,14 @@ const CODEX_COMPLETION_LINE = /^\s*tokens used\b/i;
|
|
|
33837
34384
|
* Idle timeout after completion marker to capture trailing output.
|
|
33838
34385
|
*/
|
|
33839
34386
|
const CODEX_COMPLETION_IDLE_MS = 60 * 1000;
|
|
34387
|
+
/**
|
|
34388
|
+
* Number of seconds in one hour.
|
|
34389
|
+
*/
|
|
34390
|
+
const SECONDS_PER_HOUR = 60 * 60;
|
|
34391
|
+
/**
|
|
34392
|
+
* Poll interval used while waiting for the next rate-limit retry so pause requests can be honored promptly.
|
|
34393
|
+
*/
|
|
34394
|
+
const RATE_LIMIT_BACKOFF_POLL_MS = 1000;
|
|
33840
34395
|
/**
|
|
33841
34396
|
* Maximum delay between retries while rate-limited.
|
|
33842
34397
|
*/
|
|
@@ -33856,8 +34411,8 @@ async function waitFor(delayMs) {
|
|
|
33856
34411
|
*/
|
|
33857
34412
|
function formatDelay(delayMs) {
|
|
33858
34413
|
const totalSeconds = Math.max(0, Math.round(delayMs / 1000));
|
|
33859
|
-
const hours = Math.floor(totalSeconds /
|
|
33860
|
-
const minutes = Math.floor((totalSeconds %
|
|
34414
|
+
const hours = Math.floor(totalSeconds / SECONDS_PER_HOUR);
|
|
34415
|
+
const minutes = Math.floor((totalSeconds % SECONDS_PER_HOUR) / 60);
|
|
33861
34416
|
const seconds = totalSeconds % 60;
|
|
33862
34417
|
const parts = [];
|
|
33863
34418
|
if (hours > 0) {
|
|
@@ -33898,6 +34453,7 @@ class OpenAiCodexRunner {
|
|
|
33898
34453
|
* Runs the Codex prompt in a temporary script and waits for completion output.
|
|
33899
34454
|
*/
|
|
33900
34455
|
async runPrompt(options) {
|
|
34456
|
+
var _a;
|
|
33901
34457
|
const scriptContent = buildCodexScript({
|
|
33902
34458
|
prompt: options.prompt,
|
|
33903
34459
|
projectPath: options.projectPath,
|
|
@@ -33908,7 +34464,14 @@ class OpenAiCodexRunner {
|
|
|
33908
34464
|
allowCredits: this.options.allowCredits,
|
|
33909
34465
|
codexCommand: this.options.codexCommand,
|
|
33910
34466
|
});
|
|
33911
|
-
|
|
34467
|
+
for (let retryIndex = 0;; retryIndex++) {
|
|
34468
|
+
if (retryIndex > 0) {
|
|
34469
|
+
await ((_a = options.waitForPauseCheckpoint) === null || _a === void 0 ? void 0 : _a.call(options, {
|
|
34470
|
+
checkpointLabel: 'retrying the OpenAI Codex model call after rate limit',
|
|
34471
|
+
phase: 'running',
|
|
34472
|
+
statusMessage: 'Retrying OpenAI Codex after rate limit',
|
|
34473
|
+
}));
|
|
34474
|
+
}
|
|
33912
34475
|
try {
|
|
33913
34476
|
const output = await $runGoScriptUntilMarkerIdle({
|
|
33914
34477
|
scriptPath: options.scriptPath,
|
|
@@ -33935,11 +34498,29 @@ class OpenAiCodexRunner {
|
|
|
33935
34498
|
const retryIndex = this.rateLimitBackoff.retryCount;
|
|
33936
34499
|
const summary = extractFailureSummary(details);
|
|
33937
34500
|
console.warn(colors.yellow(`[codex] Rate limit/quota detected (${summary}). Retry #${retryIndex} in ${formatDelay(delayMs)} at ${retryAt}.`));
|
|
33938
|
-
await
|
|
34501
|
+
await waitForRetryDelay(delayMs, options);
|
|
33939
34502
|
}
|
|
33940
34503
|
}
|
|
33941
34504
|
}
|
|
33942
34505
|
}
|
|
34506
|
+
/**
|
|
34507
|
+
* Waits for the next Codex retry while polling for requested pause checkpoints.
|
|
34508
|
+
*/
|
|
34509
|
+
async function waitForRetryDelay(delayMs, options) {
|
|
34510
|
+
var _a;
|
|
34511
|
+
let remainingDelayMs = delayMs;
|
|
34512
|
+
while (remainingDelayMs > 0) {
|
|
34513
|
+
const remainingDelayLabel = formatDelay(remainingDelayMs);
|
|
34514
|
+
await ((_a = options.waitForPauseCheckpoint) === null || _a === void 0 ? void 0 : _a.call(options, {
|
|
34515
|
+
checkpointLabel: 'the next OpenAI Codex retry after rate limit',
|
|
34516
|
+
phase: 'running',
|
|
34517
|
+
statusMessage: `Waiting ${remainingDelayLabel} before retrying OpenAI Codex`,
|
|
34518
|
+
}));
|
|
34519
|
+
const currentDelayMs = Math.min(RATE_LIMIT_BACKOFF_POLL_MS, remainingDelayMs);
|
|
34520
|
+
await waitFor(currentDelayMs);
|
|
34521
|
+
remainingDelayMs -= currentDelayMs;
|
|
34522
|
+
}
|
|
34523
|
+
}
|
|
33943
34524
|
|
|
33944
34525
|
/**
|
|
33945
34526
|
* Builds the shell script that runs Opencode with the prompt and coding context.
|
|
@@ -34260,6 +34841,10 @@ const MAX_PROMPT_TEST_ATTEMPTS = 3;
|
|
|
34260
34841
|
* Maximum amount of verification output sent back to the coding agent as retry feedback.
|
|
34261
34842
|
*/
|
|
34262
34843
|
const MAX_TEST_FEEDBACK_OUTPUT_CHARS = 12000;
|
|
34844
|
+
/**
|
|
34845
|
+
* File extension used by generated shell scripts.
|
|
34846
|
+
*/
|
|
34847
|
+
const SHELL_SCRIPT_EXTENSION = '.sh';
|
|
34263
34848
|
/**
|
|
34264
34849
|
* Runs one coding prompt and, when configured, verifies it with a shell command that can feed failures back.
|
|
34265
34850
|
*/
|
|
@@ -34268,12 +34853,14 @@ async function runPromptWithTestFeedback(options) {
|
|
|
34268
34853
|
const normalizedTestCommand = (_a = options.testCommand) === null || _a === void 0 ? void 0 : _a.trim();
|
|
34269
34854
|
if (!normalizedTestCommand) {
|
|
34270
34855
|
(_b = options.onAttemptStarted) === null || _b === void 0 ? void 0 : _b.call(options, 1);
|
|
34856
|
+
await waitForPromptAttemptPauseCheckpoint(options.waitForPauseCheckpoint, options.runner.name, 1);
|
|
34271
34857
|
const result = await options.runner.runPrompt({
|
|
34272
34858
|
prompt: options.prompt,
|
|
34273
34859
|
scriptPath: options.scriptPath,
|
|
34274
34860
|
projectPath: options.projectPath,
|
|
34275
34861
|
logPath: options.logPath,
|
|
34276
34862
|
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
34863
|
+
waitForPauseCheckpoint: options.waitForPauseCheckpoint,
|
|
34277
34864
|
});
|
|
34278
34865
|
return { ...result, attemptCount: 1 };
|
|
34279
34866
|
}
|
|
@@ -34281,13 +34868,16 @@ async function runPromptWithTestFeedback(options) {
|
|
|
34281
34868
|
let promptForCurrentAttempt = options.prompt;
|
|
34282
34869
|
for (let attemptCount = 1; attemptCount <= MAX_PROMPT_TEST_ATTEMPTS; attemptCount++) {
|
|
34283
34870
|
(_d = options.onAttemptStarted) === null || _d === void 0 ? void 0 : _d.call(options, attemptCount);
|
|
34871
|
+
await waitForPromptAttemptPauseCheckpoint(options.waitForPauseCheckpoint, options.runner.name, attemptCount);
|
|
34284
34872
|
const result = await options.runner.runPrompt({
|
|
34285
34873
|
prompt: promptForCurrentAttempt,
|
|
34286
34874
|
scriptPath: options.scriptPath,
|
|
34287
34875
|
projectPath: options.projectPath,
|
|
34288
34876
|
logPath: options.logPath,
|
|
34289
34877
|
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
34878
|
+
waitForPauseCheckpoint: options.waitForPauseCheckpoint,
|
|
34290
34879
|
});
|
|
34880
|
+
await waitForVerificationPauseCheckpoint(options.waitForPauseCheckpoint, normalizedTestCommand, attemptCount);
|
|
34291
34881
|
console.info(colors.gray(`Running verification command after attempt #${attemptCount}: ${normalizedTestCommand}`));
|
|
34292
34882
|
try {
|
|
34293
34883
|
await runPromptTestCommandExecutor({
|
|
@@ -34321,6 +34911,44 @@ async function runPromptWithTestFeedback(options) {
|
|
|
34321
34911
|
}
|
|
34322
34912
|
throw new Error('Unexpected prompt verification state.');
|
|
34323
34913
|
}
|
|
34914
|
+
/**
|
|
34915
|
+
* Waits for a pause checkpoint immediately before one model attempt begins.
|
|
34916
|
+
*/
|
|
34917
|
+
async function waitForPromptAttemptPauseCheckpoint(waitForPauseCheckpoint, runnerName, attemptCount) {
|
|
34918
|
+
await (waitForPauseCheckpoint === null || waitForPauseCheckpoint === void 0 ? void 0 : waitForPauseCheckpoint({
|
|
34919
|
+
checkpointLabel: buildPromptAttemptPauseLabel(runnerName, attemptCount),
|
|
34920
|
+
phase: 'running',
|
|
34921
|
+
statusMessage: buildPromptAttemptStatusMessage(runnerName, attemptCount),
|
|
34922
|
+
}));
|
|
34923
|
+
}
|
|
34924
|
+
/**
|
|
34925
|
+
* Waits for a pause checkpoint immediately before one verification command begins.
|
|
34926
|
+
*/
|
|
34927
|
+
async function waitForVerificationPauseCheckpoint(waitForPauseCheckpoint, testCommand, attemptCount) {
|
|
34928
|
+
await (waitForPauseCheckpoint === null || waitForPauseCheckpoint === void 0 ? void 0 : waitForPauseCheckpoint({
|
|
34929
|
+
checkpointLabel: buildVerificationPauseLabel(attemptCount),
|
|
34930
|
+
phase: 'verifying',
|
|
34931
|
+
statusMessage: `Running verification after attempt #${attemptCount}: ${testCommand}`,
|
|
34932
|
+
}));
|
|
34933
|
+
}
|
|
34934
|
+
/**
|
|
34935
|
+
* Builds the human-readable pause label used before one runner attempt begins.
|
|
34936
|
+
*/
|
|
34937
|
+
function buildPromptAttemptPauseLabel(runnerName, attemptCount) {
|
|
34938
|
+
return `calling ${runnerName} (attempt ${attemptCount})`;
|
|
34939
|
+
}
|
|
34940
|
+
/**
|
|
34941
|
+
* Builds the status line shown while one runner attempt is about to start.
|
|
34942
|
+
*/
|
|
34943
|
+
function buildPromptAttemptStatusMessage(runnerName, attemptCount) {
|
|
34944
|
+
return `Calling ${runnerName} (attempt ${attemptCount})`;
|
|
34945
|
+
}
|
|
34946
|
+
/**
|
|
34947
|
+
* Builds the human-readable pause label used before one verification command begins.
|
|
34948
|
+
*/
|
|
34949
|
+
function buildVerificationPauseLabel(attemptCount) {
|
|
34950
|
+
return `running verification after attempt #${attemptCount}`;
|
|
34951
|
+
}
|
|
34324
34952
|
/**
|
|
34325
34953
|
* Builds one feedback block appended to the next coding attempt after tests fail.
|
|
34326
34954
|
*/
|
|
@@ -34370,8 +34998,8 @@ function limitVerificationOutputForFeedback(verificationOutput) {
|
|
|
34370
34998
|
* Derives a dedicated temp-script path for verification commands.
|
|
34371
34999
|
*/
|
|
34372
35000
|
function buildPromptTestScriptPath(scriptPath) {
|
|
34373
|
-
if (scriptPath.toLowerCase().endsWith(
|
|
34374
|
-
return `${scriptPath.slice(0, -
|
|
35001
|
+
if (scriptPath.toLowerCase().endsWith(SHELL_SCRIPT_EXTENSION)) {
|
|
35002
|
+
return `${scriptPath.slice(0, -SHELL_SCRIPT_EXTENSION.length)}.test.sh`;
|
|
34375
35003
|
}
|
|
34376
35004
|
return `${scriptPath}.test.sh`;
|
|
34377
35005
|
}
|
|
@@ -34562,7 +35190,7 @@ function buildAgentRunUiFrame(options) {
|
|
|
34562
35190
|
const totalWidth = Math.max(MIN_FRAME_WIDTH, Math.min(options.terminalWidth, MAX_FRAME_WIDTH));
|
|
34563
35191
|
const isPromptActive = options.phase === 'running' || options.phase === 'verifying' || options.phase === 'loading';
|
|
34564
35192
|
const promptStatusPrefix = isPromptActive ? `${colors.yellow(`${options.spinner} `)}` : '';
|
|
34565
|
-
const pausePresentation = buildPausePresentation(options.phase, options.pauseState, options.statusMessage);
|
|
35193
|
+
const pausePresentation = buildPausePresentation(options.phase, options.pauseState, options.pauseTargetLabel, options.statusMessage);
|
|
34566
35194
|
const sessionLines = buildSessionLines(options, totalWidth, pausePresentation);
|
|
34567
35195
|
const agentStatusLines = buildAgentStatusTableLines(options, totalWidth);
|
|
34568
35196
|
const currentTaskLines = options.currentPromptLabel
|
|
@@ -68802,8 +69430,12 @@ async function runPromptRound({ options, runner, runnerMetadata, nextPrompt, pro
|
|
|
68802
69430
|
const commitMessage = buildCommitMessage(nextPrompt.file, nextPrompt.section);
|
|
68803
69431
|
const codexPrompt = appendCoderContext(buildCodexPrompt(nextPrompt.file, nextPrompt.section), resolvedCoderContext);
|
|
68804
69432
|
const scriptPath = buildScriptPath(nextPrompt.file, nextPrompt.section);
|
|
68805
|
-
await waitForRequestedPause();
|
|
68806
69433
|
setPromptRoundRunningState({ isRichUiEnabled, promptLabel, scriptPath, uiHandle });
|
|
69434
|
+
await waitForRequestedPause({
|
|
69435
|
+
checkpointLabel: 'preparing the current prompt execution',
|
|
69436
|
+
phase: 'running',
|
|
69437
|
+
statusMessage: 'Preparing prompt execution',
|
|
69438
|
+
});
|
|
68807
69439
|
const promptExecutionStartedDate = moment();
|
|
68808
69440
|
let attemptCount = 1;
|
|
68809
69441
|
const roundChangedFilesSnapshot = options.normalizeLineEndings
|
|
@@ -68824,11 +69456,8 @@ async function runPromptRound({ options, runner, runnerMetadata, nextPrompt, pro
|
|
|
68824
69456
|
onAttemptStarted: (nextAttemptCount) => {
|
|
68825
69457
|
attemptCount = nextAttemptCount;
|
|
68826
69458
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setAttempt(nextAttemptCount);
|
|
68827
|
-
if (nextAttemptCount > 1) {
|
|
68828
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Retrying (attempt ${nextAttemptCount})`);
|
|
68829
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('verifying');
|
|
68830
|
-
}
|
|
68831
69459
|
},
|
|
69460
|
+
waitForPauseCheckpoint: waitForRequestedPause,
|
|
68832
69461
|
});
|
|
68833
69462
|
await finalizeSuccessfulPromptRound({
|
|
68834
69463
|
options,
|
|
@@ -68842,6 +69471,7 @@ async function runPromptRound({ options, runner, runnerMetadata, nextPrompt, pro
|
|
|
68842
69471
|
isRichUiEnabled,
|
|
68843
69472
|
progressDisplay,
|
|
68844
69473
|
uiHandle,
|
|
69474
|
+
waitForRequestedPause,
|
|
68845
69475
|
});
|
|
68846
69476
|
}
|
|
68847
69477
|
catch (error) {
|
|
@@ -68854,6 +69484,7 @@ async function runPromptRound({ options, runner, runnerMetadata, nextPrompt, pro
|
|
|
68854
69484
|
options,
|
|
68855
69485
|
roundChangedFilesSnapshot,
|
|
68856
69486
|
uiHandle,
|
|
69487
|
+
waitForRequestedPause,
|
|
68857
69488
|
});
|
|
68858
69489
|
throw error;
|
|
68859
69490
|
}
|
|
@@ -68877,9 +69508,13 @@ function setPromptRoundRunningState(options) {
|
|
|
68877
69508
|
* Finalizes a successful prompt round, including prompt bookkeeping and commit flow.
|
|
68878
69509
|
*/
|
|
68879
69510
|
async function finalizeSuccessfulPromptRound(options) {
|
|
68880
|
-
const { options: runOptions, nextPrompt, runnerMetadata, promptExecutionStartedDate, result, commitMessage, logPath, roundChangedFilesSnapshot, isRichUiEnabled, progressDisplay, uiHandle, } = options;
|
|
69511
|
+
const { options: runOptions, nextPrompt, runnerMetadata, promptExecutionStartedDate, result, commitMessage, logPath, roundChangedFilesSnapshot, isRichUiEnabled, progressDisplay, uiHandle, waitForRequestedPause, } = options;
|
|
68881
69512
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
68882
|
-
|
|
69513
|
+
await waitForRequestedPause({
|
|
69514
|
+
checkpointLabel: 'recording the successful prompt result',
|
|
69515
|
+
phase: 'running',
|
|
69516
|
+
statusMessage: 'Recording prompt result',
|
|
69517
|
+
});
|
|
68883
69518
|
markPromptDone(nextPrompt.file, nextPrompt.section, result.usage, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, result.attemptCount);
|
|
68884
69519
|
await writePromptFile(nextPrompt.file);
|
|
68885
69520
|
await normalizeLineEndingsForCurrentRound(runOptions, roundChangedFilesSnapshot);
|
|
@@ -68891,22 +69526,42 @@ async function finalizeSuccessfulPromptRound(options) {
|
|
|
68891
69526
|
progressDisplay,
|
|
68892
69527
|
uiHandle,
|
|
68893
69528
|
});
|
|
69529
|
+
await waitForRequestedPause({
|
|
69530
|
+
checkpointLabel: 'committing the successful changes',
|
|
69531
|
+
phase: 'running',
|
|
69532
|
+
statusMessage: 'Committing changes',
|
|
69533
|
+
});
|
|
68894
69534
|
await commitChanges(commitMessage, {
|
|
68895
69535
|
autoPush: runOptions.autoPush,
|
|
68896
69536
|
// Keep the live runtime log out of default commits because it is deleted after a successful round.
|
|
68897
69537
|
excludePaths: runOptions.preserveLogs ? undefined : [logPath],
|
|
68898
69538
|
});
|
|
68899
69539
|
}
|
|
69540
|
+
else {
|
|
69541
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Leaving changes uncommitted');
|
|
69542
|
+
}
|
|
69543
|
+
if (runOptions.autoMigrate) {
|
|
69544
|
+
await waitForRequestedPause({
|
|
69545
|
+
checkpointLabel: 'running testing-server auto-migration',
|
|
69546
|
+
phase: 'running',
|
|
69547
|
+
statusMessage: 'Running testing-server auto-migration',
|
|
69548
|
+
});
|
|
69549
|
+
}
|
|
68900
69550
|
await runPostPromptAutoMigrationIfEnabled(runOptions);
|
|
68901
69551
|
}
|
|
68902
69552
|
/**
|
|
68903
69553
|
* Finalizes a failed prompt round, persisting prompt failure metadata before rethrowing.
|
|
68904
69554
|
*/
|
|
68905
69555
|
async function finalizeFailedPromptRound(options) {
|
|
68906
|
-
const { nextPrompt, runnerMetadata, promptExecutionStartedDate, attemptCount, error, options: runOptions, roundChangedFilesSnapshot, uiHandle, } = options;
|
|
69556
|
+
const { nextPrompt, runnerMetadata, promptExecutionStartedDate, attemptCount, error, options: runOptions, roundChangedFilesSnapshot, uiHandle, waitForRequestedPause, } = options;
|
|
68907
69557
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
68908
69558
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('error');
|
|
68909
69559
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(error instanceof Error ? error.message : String(error));
|
|
69560
|
+
await waitForRequestedPause({
|
|
69561
|
+
checkpointLabel: 'recording the prompt failure',
|
|
69562
|
+
phase: 'error',
|
|
69563
|
+
statusMessage: 'Recording prompt failure',
|
|
69564
|
+
});
|
|
68910
69565
|
markPromptFailed(nextPrompt.file, nextPrompt.section, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, attemptCount);
|
|
68911
69566
|
await writePromptFile(nextPrompt.file);
|
|
68912
69567
|
await writePromptErrorLog({
|
|
@@ -68941,6 +69596,8 @@ async function waitForCommitConfirmationIfNeeded(options) {
|
|
|
68941
69596
|
}
|
|
68942
69597
|
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.resumeTimer();
|
|
68943
69598
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
69599
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('running');
|
|
69600
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Committing changes');
|
|
68944
69601
|
}
|
|
68945
69602
|
/**
|
|
68946
69603
|
* Formats commit preview lines for the rich terminal UI.
|
|
@@ -69013,11 +69670,21 @@ async function runCodexPrompts(providedOptions) {
|
|
|
69013
69670
|
let hasShownUpcomingTasks = false;
|
|
69014
69671
|
let hasWaitedForStart = false;
|
|
69015
69672
|
while (just(true)) {
|
|
69016
|
-
|
|
69673
|
+
if (options.autoPull && !options.dryRun) {
|
|
69674
|
+
await waitForRequestedPause({
|
|
69675
|
+
checkpointLabel: 'pulling the latest repository changes',
|
|
69676
|
+
phase: 'loading',
|
|
69677
|
+
statusMessage: 'Pulling latest changes...',
|
|
69678
|
+
});
|
|
69679
|
+
}
|
|
69017
69680
|
await pullLatestChangesIfEnabled({
|
|
69018
69681
|
options,
|
|
69019
69682
|
isRichUiEnabled,
|
|
69020
|
-
|
|
69683
|
+
});
|
|
69684
|
+
await waitForRequestedPause({
|
|
69685
|
+
checkpointLabel: 'loading prompts',
|
|
69686
|
+
phase: 'loading',
|
|
69687
|
+
statusMessage: 'Loading prompts...',
|
|
69021
69688
|
});
|
|
69022
69689
|
const promptQueueSnapshot = await loadPromptQueueSnapshot({
|
|
69023
69690
|
options,
|
|
@@ -69047,6 +69714,11 @@ async function runCodexPrompts(providedOptions) {
|
|
|
69047
69714
|
uiHandle,
|
|
69048
69715
|
});
|
|
69049
69716
|
if (!options.ignoreGitChanges) {
|
|
69717
|
+
await waitForRequestedPause({
|
|
69718
|
+
checkpointLabel: 'checking the git working tree',
|
|
69719
|
+
phase: 'loading',
|
|
69720
|
+
statusMessage: 'Checking the working tree...',
|
|
69721
|
+
});
|
|
69050
69722
|
await ensureWorkingTreeClean();
|
|
69051
69723
|
}
|
|
69052
69724
|
await runPromptRound({
|
|
@@ -69095,12 +69767,10 @@ function validateRunCodexPromptOptions(options) {
|
|
|
69095
69767
|
* Pulls the latest repository state before loading prompts when the feature is enabled.
|
|
69096
69768
|
*/
|
|
69097
69769
|
async function pullLatestChangesIfEnabled(options) {
|
|
69098
|
-
const { options: runOptions, isRichUiEnabled
|
|
69770
|
+
const { options: runOptions, isRichUiEnabled } = options;
|
|
69099
69771
|
if (!runOptions.autoPull || runOptions.dryRun) {
|
|
69100
69772
|
return;
|
|
69101
69773
|
}
|
|
69102
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('loading');
|
|
69103
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Pulling latest changes...');
|
|
69104
69774
|
if (!isRichUiEnabled) {
|
|
69105
69775
|
console.info(colors.gray('Pulling latest changes before the next prompt...'));
|
|
69106
69776
|
}
|
|
@@ -69124,22 +69794,26 @@ function createRunDisplays(options, runStartDate) {
|
|
|
69124
69794
|
*/
|
|
69125
69795
|
function createPauseWaiter(options) {
|
|
69126
69796
|
const { isRichUiEnabled, progressDisplay, uiHandle } = options;
|
|
69127
|
-
return async () => {
|
|
69797
|
+
return async (checkpoint) => {
|
|
69798
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase(checkpoint.phase);
|
|
69799
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(checkpoint.statusMessage);
|
|
69800
|
+
announcePauseTargetLabel(checkpoint.checkpointLabel);
|
|
69128
69801
|
await checkPause({
|
|
69129
69802
|
silent: isRichUiEnabled,
|
|
69130
69803
|
onPaused: () => {
|
|
69131
69804
|
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.pauseTimer();
|
|
69132
69805
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
69133
69806
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('paused');
|
|
69134
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(
|
|
69807
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Paused before ${checkpoint.checkpointLabel}`);
|
|
69135
69808
|
},
|
|
69136
69809
|
onResumed: () => {
|
|
69137
69810
|
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.resumeTimer();
|
|
69138
69811
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
69139
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase(
|
|
69140
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(
|
|
69812
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase(checkpoint.phase);
|
|
69813
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(checkpoint.statusMessage);
|
|
69141
69814
|
},
|
|
69142
69815
|
});
|
|
69816
|
+
resetPauseTargetLabel();
|
|
69143
69817
|
};
|
|
69144
69818
|
}
|
|
69145
69819
|
/**
|
|
@@ -69184,11 +69858,7 @@ function initializeRunUi(uiHandle, runnerName, actualRunnerModel, options) {
|
|
|
69184
69858
|
*/
|
|
69185
69859
|
async function loadPromptQueueSnapshot(options) {
|
|
69186
69860
|
const { options: runOptions, isRichUiEnabled, progressDisplay, uiHandle } = options;
|
|
69187
|
-
|
|
69188
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentScriptPath(undefined);
|
|
69189
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('loading');
|
|
69190
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Loading prompts...');
|
|
69191
|
-
}
|
|
69861
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentScriptPath(undefined);
|
|
69192
69862
|
const promptFiles = await loadPromptFiles(PROMPTS_DIR$1);
|
|
69193
69863
|
const stats = summarizePrompts(promptFiles, runOptions.priority);
|
|
69194
69864
|
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.update(stats);
|