@promptbook/node 0.113.0-7 → 0.113.0-9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/book/scripts/import-markdown/increaseHeadings.d.ts +8 -0
- package/esm/index.es.js +1532 -1170
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/common/parseDuration.d.ts +19 -0
- package/esm/scripts/run-codex-prompts/runners/claude-code/ClaudeCodeRunner.d.ts +4 -0
- package/esm/scripts/run-codex-prompts/runners/claude-code/ClaudeCodeSessionResurrection.d.ts +37 -0
- package/esm/scripts/run-codex-prompts/runners/claude-code/parseClaudeCodeOutputEvents.d.ts +47 -0
- package/esm/src/_packages/types.index.d.ts +2 -2
- package/esm/src/avatars/renderAvatarVisualAsciiArt.d.ts +24 -1
- package/esm/src/avatars/visuals/octopus3dAvatarVisualShared.d.ts +1 -1
- package/esm/src/book-components/BookEditor/BookEditorMonacoUploadPanel.d.ts +1 -1
- package/esm/src/book-components/BookEditor/useBookEditorMonacoUploads/bookEditorMonacoUploadTypes.d.ts +120 -0
- package/esm/src/book-components/BookEditor/useBookEditorMonacoUploads/clearScheduledTimer.d.ts +6 -0
- package/esm/src/book-components/BookEditor/useBookEditorMonacoUploads/enqueueFilesForUpload.d.ts +26 -0
- package/esm/src/book-components/BookEditor/useBookEditorMonacoUploads/useBookEditorMonacoUploadEditorSync.d.ts +23 -0
- package/esm/src/book-components/BookEditor/useBookEditorMonacoUploads/useBookEditorMonacoUploadItemsState.d.ts +21 -0
- package/esm/src/book-components/BookEditor/useBookEditorMonacoUploads/useBookEditorMonacoUploadProgressQueue.d.ts +12 -0
- package/esm/src/book-components/BookEditor/useBookEditorMonacoUploads/useBookEditorMonacoUploadQueue.d.ts +27 -0
- package/esm/src/book-components/BookEditor/useBookEditorMonacoUploads/useCompletedUploadsAutoClear.d.ts +12 -0
- package/esm/src/book-components/BookEditor/useBookEditorMonacoUploads.d.ts +5 -58
- package/esm/src/book-components/Chat/Chat/ChatImageAttachmentModal.d.ts +25 -0
- package/esm/src/book-components/Chat/Chat/ChatInputArea.d.ts +3 -0
- package/esm/src/book-components/Chat/Chat/ChatMessageAttachments.d.ts +27 -0
- package/esm/src/book-components/Chat/Chat/ChatMessageItem.d.ts +1 -1
- package/esm/src/book-components/Chat/Chat/ChatMessageList.d.ts +1 -0
- package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +8 -0
- package/esm/src/book-components/Chat/Chat/useChatInputAreaComposer.d.ts +12 -0
- package/esm/src/book-components/Chat/Chat/useChatInputAreaComposer.draftMessage.test.d.ts +2 -0
- package/esm/src/book-components/Chat/utils/isVisibleChatToolCall.d.ts +1 -1
- package/esm/src/book-components/Chat/utils/parseMessageButtons.d.ts +16 -2
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/AGENTS_SERVER_BUILD_CACHE_FILENAME.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/AGENTS_SERVER_BUILD_CACHE_VERSION.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/AGENTS_SERVER_NEXT_BUILD_ID_FILENAME.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/AgentsServerBuildCache.d.ts +10 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/AgentsServerBuildCacheOptions.d.ts +10 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/NODE_MODULES_DIRECTORY_NAME.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/PreparedAgentsServerRuntime.d.ts +18 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/createAgentsServerBuildSourceFingerprint.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/createAgentsServerRuntimeEnvironment.d.ts +28 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/ensureAgentsServerBuild.d.ts +19 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/getAgentsServerBuildInputRelativePaths.d.ts +11 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/isAgentsServerAppPath.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/isAgentsServerAppPathMaterialized.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/isAgentsServerBuildCacheCurrent.d.ts +7 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/isAgentsServerBuildInputTestFile.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/isExcludedAgentsServerBuildInputDirectoryName.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/isExcludedAgentsServerBuildInputPath.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/isExcludedAgentsServerRuntimeSourcePath.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/isFile.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/isPathInsideNodeModules.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/normalizeAgentsServerBuildInputPath.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/prepareAgentsServerRuntime.d.ts +9 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/readAgentsServerBuildCache.d.ts +8 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/resolveAgentsServerAppPath.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/resolveAgentsServerBuildAppPath.d.ts +9 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/resolveAgentsServerBuildOutputPath.d.ts +7 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/resolveNextCliPath.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/resolveNodeModulesPath.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/runNextBuild.d.ts +12 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/shouldCopyAgentsServerRuntimePath.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/synchronizeMaterializedAgentsServerRuntime.d.ts +11 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/writeAgentsServerBuildCache.d.ts +7 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +8 -109
- package/esm/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.d.ts +1 -1
- package/esm/src/cli/cli-commands/agents-server/ensureAgentsServerGitignoreFile.d.ts +1 -1
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/AgentsServerChildEnvironment.d.ts +16 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/AgentsServerLogStreams.d.ts +30 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/AgentsServerRuntimePaths.d.ts +19 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/AgentsServerSupervisorState.d.ts +37 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/LocalAgentRunnerLimits.d.ts +9 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/PreparedAgentsServerLaunch.d.ts +13 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/StartAgentsServerOptions.d.ts +24 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/createInternalRouteErrorMessage.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/createLocalAgentRunOptions.d.ts +9 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/forwardChildOutput.d.ts +13 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/loadAgentsServerProjectEnvironment.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/prepareAgentsServerLaunch.d.ts +18 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/readInternalRouteErrorDetails.d.ts +6 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/resolveAgentsServerChildHostname.d.ts +7 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/startNextServer.d.ts +20 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/startUserChatJobWorkerPump.d.ts +15 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/stopChildProcess.d.ts +8 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/waitForLocalAgentRunnerLimits.d.ts +16 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +3 -30
- package/esm/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +1 -1
- package/esm/src/collection/agent-collection/CreateAgentInput.d.ts +1 -1
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/prepareAgentSourceForPersistence.d.ts +1 -1
- package/esm/src/commitments/META/META.d.ts +2 -2
- package/esm/src/commitments/META_AVATAR/META_AVATAR.d.ts +9 -4
- package/esm/src/commitments/index.d.ts +1 -1
- package/esm/src/conversion/validation/validatePipeline/createPipelineValidationContext.d.ts +16 -0
- package/esm/src/conversion/validation/validatePipeline/validatePipelineCollectionsStructure.d.ts +7 -0
- package/esm/src/conversion/validation/validatePipeline/validatePipelineDependencyResolution.d.ts +7 -0
- package/esm/src/conversion/validation/validatePipeline/validatePipelineMetadata.d.ts +7 -0
- package/esm/src/conversion/validation/validatePipeline/validatePipelineParameters.d.ts +7 -0
- package/esm/src/conversion/validation/validatePipeline/validatePipelineTasks.d.ts +7 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/RegisteredLlmToolsMessageContext.d.ts +46 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/USED_ENV_FILENAME.d.ts +11 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/createRegisteredLlmToolConfigurationStatusMessage.d.ts +7 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/createRegisteredLlmToolEntryKey.d.ts +7 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/createRegisteredLlmToolInstallationStatusMessage.d.ts +7 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/createRegisteredLlmToolStatus.d.ts +14 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/createRegisteredLlmToolsMessageContext.d.ts +7 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/getAvailableRegisteredLlmToolsEnvironmentVariables.d.ts +7 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/getRegisteredLlmToolRegisters.d.ts +7 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/hasRegisteredLlmToolEntry.d.ts +7 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/listRegisteredLlmToolEntries.d.ts +9 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/listRegisteredLlmToolStatuses.d.ts +7 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/renderAvailableRegisteredLlmTools.d.ts +7 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/renderNoRegisteredLlmToolsMessage.d.ts +7 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/renderRegisteredLlmToolsMessage.d.ts +8 -0
- package/esm/src/llm-providers/_common/register/$registeredLlmToolsMessage/renderRelevantRegisteredLlmToolsEnvironmentVariables.d.ts +7 -0
- package/esm/src/utils/agents/resolveAgentAvatarImageUrl.d.ts +2 -2
- package/esm/src/utils/color/Color.d.ts +1 -1
- package/esm/src/version.d.ts +1 -1
- package/package.json +2 -2
- package/umd/book/scripts/import-markdown/increaseHeadings.d.ts +8 -0
- package/umd/index.umd.js +1536 -1174
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/common/parseDuration.d.ts +19 -0
- package/umd/scripts/run-codex-prompts/runners/claude-code/ClaudeCodeRunner.d.ts +4 -0
- package/umd/scripts/run-codex-prompts/runners/claude-code/ClaudeCodeSessionResurrection.d.ts +37 -0
- package/umd/scripts/run-codex-prompts/runners/claude-code/parseClaudeCodeOutputEvents.d.ts +47 -0
- package/umd/src/_packages/types.index.d.ts +2 -2
- package/umd/src/avatars/renderAvatarVisualAsciiArt.d.ts +24 -1
- package/umd/src/avatars/visuals/octopus3dAvatarVisualShared.d.ts +1 -1
- package/umd/src/book-components/BookEditor/BookEditorMonacoUploadPanel.d.ts +1 -1
- package/umd/src/book-components/BookEditor/useBookEditorMonacoUploads/bookEditorMonacoUploadTypes.d.ts +120 -0
- package/umd/src/book-components/BookEditor/useBookEditorMonacoUploads/clearScheduledTimer.d.ts +6 -0
- package/umd/src/book-components/BookEditor/useBookEditorMonacoUploads/enqueueFilesForUpload.d.ts +26 -0
- package/umd/src/book-components/BookEditor/useBookEditorMonacoUploads/useBookEditorMonacoUploadEditorSync.d.ts +23 -0
- package/umd/src/book-components/BookEditor/useBookEditorMonacoUploads/useBookEditorMonacoUploadItemsState.d.ts +21 -0
- package/umd/src/book-components/BookEditor/useBookEditorMonacoUploads/useBookEditorMonacoUploadProgressQueue.d.ts +12 -0
- package/umd/src/book-components/BookEditor/useBookEditorMonacoUploads/useBookEditorMonacoUploadQueue.d.ts +27 -0
- package/umd/src/book-components/BookEditor/useBookEditorMonacoUploads/useCompletedUploadsAutoClear.d.ts +12 -0
- package/umd/src/book-components/BookEditor/useBookEditorMonacoUploads.d.ts +5 -58
- package/umd/src/book-components/Chat/Chat/ChatImageAttachmentModal.d.ts +25 -0
- package/umd/src/book-components/Chat/Chat/ChatInputArea.d.ts +3 -0
- package/umd/src/book-components/Chat/Chat/ChatMessageAttachments.d.ts +27 -0
- package/umd/src/book-components/Chat/Chat/ChatMessageItem.d.ts +1 -1
- package/umd/src/book-components/Chat/Chat/ChatMessageList.d.ts +1 -0
- package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +8 -0
- package/umd/src/book-components/Chat/Chat/useChatInputAreaComposer.d.ts +12 -0
- package/umd/src/book-components/Chat/Chat/useChatInputAreaComposer.draftMessage.test.d.ts +2 -0
- package/umd/src/book-components/Chat/utils/isVisibleChatToolCall.d.ts +1 -1
- package/umd/src/book-components/Chat/utils/parseMessageButtons.d.ts +16 -2
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/AGENTS_SERVER_BUILD_CACHE_FILENAME.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/AGENTS_SERVER_BUILD_CACHE_VERSION.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/AGENTS_SERVER_NEXT_BUILD_ID_FILENAME.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/AgentsServerBuildCache.d.ts +10 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/AgentsServerBuildCacheOptions.d.ts +10 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/NODE_MODULES_DIRECTORY_NAME.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/PreparedAgentsServerRuntime.d.ts +18 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/createAgentsServerBuildSourceFingerprint.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/createAgentsServerRuntimeEnvironment.d.ts +28 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/ensureAgentsServerBuild.d.ts +19 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/getAgentsServerBuildInputRelativePaths.d.ts +11 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/isAgentsServerAppPath.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/isAgentsServerAppPathMaterialized.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/isAgentsServerBuildCacheCurrent.d.ts +7 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/isAgentsServerBuildInputTestFile.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/isExcludedAgentsServerBuildInputDirectoryName.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/isExcludedAgentsServerBuildInputPath.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/isExcludedAgentsServerRuntimeSourcePath.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/isFile.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/isPathInsideNodeModules.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/normalizeAgentsServerBuildInputPath.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/prepareAgentsServerRuntime.d.ts +9 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/readAgentsServerBuildCache.d.ts +8 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/resolveAgentsServerAppPath.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/resolveAgentsServerBuildAppPath.d.ts +9 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/resolveAgentsServerBuildOutputPath.d.ts +7 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/resolveNextCliPath.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/resolveNodeModulesPath.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/runNextBuild.d.ts +12 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/shouldCopyAgentsServerRuntimePath.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/synchronizeMaterializedAgentsServerRuntime.d.ts +11 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/writeAgentsServerBuildCache.d.ts +7 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +8 -109
- package/umd/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.d.ts +1 -1
- package/umd/src/cli/cli-commands/agents-server/ensureAgentsServerGitignoreFile.d.ts +1 -1
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/AgentsServerChildEnvironment.d.ts +16 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/AgentsServerLogStreams.d.ts +30 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/AgentsServerRuntimePaths.d.ts +19 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/AgentsServerSupervisorState.d.ts +37 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/LocalAgentRunnerLimits.d.ts +9 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/PreparedAgentsServerLaunch.d.ts +13 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/StartAgentsServerOptions.d.ts +24 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/createInternalRouteErrorMessage.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/createLocalAgentRunOptions.d.ts +9 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/forwardChildOutput.d.ts +13 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/loadAgentsServerProjectEnvironment.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/prepareAgentsServerLaunch.d.ts +18 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/readInternalRouteErrorDetails.d.ts +6 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/resolveAgentsServerChildHostname.d.ts +7 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/startNextServer.d.ts +20 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/startUserChatJobWorkerPump.d.ts +15 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/stopChildProcess.d.ts +8 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/waitForLocalAgentRunnerLimits.d.ts +16 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +3 -30
- package/umd/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +1 -1
- package/umd/src/collection/agent-collection/CreateAgentInput.d.ts +1 -1
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/prepareAgentSourceForPersistence.d.ts +1 -1
- package/umd/src/commitments/META/META.d.ts +2 -2
- package/umd/src/commitments/META_AVATAR/META_AVATAR.d.ts +9 -4
- package/umd/src/commitments/index.d.ts +1 -1
- package/umd/src/conversion/validation/validatePipeline/createPipelineValidationContext.d.ts +16 -0
- package/umd/src/conversion/validation/validatePipeline/validatePipelineCollectionsStructure.d.ts +7 -0
- package/umd/src/conversion/validation/validatePipeline/validatePipelineDependencyResolution.d.ts +7 -0
- package/umd/src/conversion/validation/validatePipeline/validatePipelineMetadata.d.ts +7 -0
- package/umd/src/conversion/validation/validatePipeline/validatePipelineParameters.d.ts +7 -0
- package/umd/src/conversion/validation/validatePipeline/validatePipelineTasks.d.ts +7 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/RegisteredLlmToolsMessageContext.d.ts +46 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/USED_ENV_FILENAME.d.ts +11 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/createRegisteredLlmToolConfigurationStatusMessage.d.ts +7 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/createRegisteredLlmToolEntryKey.d.ts +7 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/createRegisteredLlmToolInstallationStatusMessage.d.ts +7 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/createRegisteredLlmToolStatus.d.ts +14 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/createRegisteredLlmToolsMessageContext.d.ts +7 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/getAvailableRegisteredLlmToolsEnvironmentVariables.d.ts +7 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/getRegisteredLlmToolRegisters.d.ts +7 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/hasRegisteredLlmToolEntry.d.ts +7 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/listRegisteredLlmToolEntries.d.ts +9 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/listRegisteredLlmToolStatuses.d.ts +7 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/renderAvailableRegisteredLlmTools.d.ts +7 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/renderNoRegisteredLlmToolsMessage.d.ts +7 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/renderRegisteredLlmToolsMessage.d.ts +8 -0
- package/umd/src/llm-providers/_common/register/$registeredLlmToolsMessage/renderRelevantRegisteredLlmToolsEnvironmentVariables.d.ts +7 -0
- package/umd/src/utils/agents/resolveAgentAvatarImageUrl.d.ts +2 -2
- package/umd/src/utils/color/Color.d.ts +1 -1
- package/umd/src/version.d.ts +1 -1
package/esm/index.es.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { join, dirname, basename, isAbsolute, resolve, relative } from 'path';
|
|
2
2
|
import { unlink, mkdir, appendFile, writeFile, readFile, stat, access, constants, readdir, watch, rm } from 'fs/promises';
|
|
3
|
+
import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
|
|
3
4
|
import colors from 'colors';
|
|
4
5
|
import { spawn } from 'child_process';
|
|
5
|
-
import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
|
|
6
6
|
import { fileSearchTool, tool, Agent as Agent$1, webSearchTool, run, setDefaultOpenAIClient, setDefaultOpenAIKey } from '@openai/agents';
|
|
7
7
|
import { fileURLToPath } from 'url';
|
|
8
8
|
import { Readability } from '@mozilla/readability';
|
|
@@ -36,7 +36,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
36
36
|
* @generated
|
|
37
37
|
* @see https://github.com/webgptorg/promptbook
|
|
38
38
|
*/
|
|
39
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.113.0-
|
|
39
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.113.0-9';
|
|
40
40
|
/**
|
|
41
41
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
42
42
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -381,6 +381,34 @@ function $randomToken(randomness) {
|
|
|
381
381
|
// TODO: [🤶] Maybe export through `@promptbook/utils` or `@promptbook/random` package
|
|
382
382
|
// TODO: Maybe use nanoid instead https://github.com/ai/nanoid
|
|
383
383
|
|
|
384
|
+
/**
|
|
385
|
+
* Increase the level of all headings in the markdown content
|
|
386
|
+
*
|
|
387
|
+
* @example h1 -> h2, h2 -> h3, ...
|
|
388
|
+
* @param content The markdown content
|
|
389
|
+
* @returns The markdown with increased headings
|
|
390
|
+
*/
|
|
391
|
+
function increaseHeadings(content) {
|
|
392
|
+
const lines = content.split(/\r?\n/);
|
|
393
|
+
let inCodeBlock = false;
|
|
394
|
+
for (let i = 0; i < lines.length; i++) {
|
|
395
|
+
const line = lines[i];
|
|
396
|
+
if (line.startsWith('```')) {
|
|
397
|
+
inCodeBlock = !inCodeBlock;
|
|
398
|
+
}
|
|
399
|
+
if (inCodeBlock) {
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
const headingMatch = line.match(/^(#+)(.*)/);
|
|
403
|
+
if (headingMatch) {
|
|
404
|
+
const headingLevel = headingMatch[1].length;
|
|
405
|
+
const headingText = headingMatch[2];
|
|
406
|
+
lines[i] = `${'#'.repeat(headingLevel + 1)}${headingText}`;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return lines.join('\n');
|
|
410
|
+
}
|
|
411
|
+
|
|
384
412
|
/**
|
|
385
413
|
* Appends optional coding context to a runner prompt.
|
|
386
414
|
*/
|
|
@@ -393,7 +421,13 @@ function appendCoderContext(prompt, context) {
|
|
|
393
421
|
if (normalizedPrompt === '') {
|
|
394
422
|
return normalizedContext;
|
|
395
423
|
}
|
|
396
|
-
return
|
|
424
|
+
return spaceTrim$1((block) => `
|
|
425
|
+
${block(normalizedPrompt)}
|
|
426
|
+
|
|
427
|
+
## Context
|
|
428
|
+
|
|
429
|
+
${block(increaseHeadings(normalizedContext))}
|
|
430
|
+
`);
|
|
397
431
|
}
|
|
398
432
|
|
|
399
433
|
/**
|
|
@@ -522,6 +556,127 @@ function take(initialValue) {
|
|
|
522
556
|
});
|
|
523
557
|
}
|
|
524
558
|
|
|
559
|
+
/**
|
|
560
|
+
* Validates that a channel value is a valid number within the range of 0 to 255.
|
|
561
|
+
* Throws an error if the value is not valid.
|
|
562
|
+
*
|
|
563
|
+
* @param channelName - The name of the channel being validated.
|
|
564
|
+
* @param value - The value of the channel to validate.
|
|
565
|
+
* @throws Will throw an error if the value is not a valid channel number.
|
|
566
|
+
*
|
|
567
|
+
* @private util of `@promptbook/color`
|
|
568
|
+
*/
|
|
569
|
+
function checkChannelValue(channelName, value) {
|
|
570
|
+
if (typeof value !== 'number') {
|
|
571
|
+
throw new Error(`${channelName} channel value is not number but ${typeof value}`);
|
|
572
|
+
}
|
|
573
|
+
if (isNaN(value)) {
|
|
574
|
+
throw new Error(`${channelName} channel value is NaN`);
|
|
575
|
+
}
|
|
576
|
+
if (Math.round(value) !== value) {
|
|
577
|
+
throw new Error(`${channelName} channel is not whole number, it is ${value}`);
|
|
578
|
+
}
|
|
579
|
+
if (value < 0) {
|
|
580
|
+
throw new Error(`${channelName} channel is lower than 0, it is ${value}`);
|
|
581
|
+
}
|
|
582
|
+
if (value > 255) {
|
|
583
|
+
throw new Error(`${channelName} channel is greater than 255, it is ${value}`);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Shared immutable channel storage and serialization helpers for `Color`.
|
|
589
|
+
*
|
|
590
|
+
* @private base class of Color
|
|
591
|
+
*/
|
|
592
|
+
class ColorValue {
|
|
593
|
+
constructor(red, green, blue, alpha = 255) {
|
|
594
|
+
this.red = red;
|
|
595
|
+
this.green = green;
|
|
596
|
+
this.blue = blue;
|
|
597
|
+
this.alpha = alpha;
|
|
598
|
+
checkChannelValue('Red', red);
|
|
599
|
+
checkChannelValue('Green', green);
|
|
600
|
+
checkChannelValue('Blue', blue);
|
|
601
|
+
checkChannelValue('Alpha', alpha);
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Shortcut for `red` property
|
|
605
|
+
* Number from 0 to 255
|
|
606
|
+
* @alias red
|
|
607
|
+
*/
|
|
608
|
+
get r() {
|
|
609
|
+
return this.red;
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Shortcut for `green` property
|
|
613
|
+
* Number from 0 to 255
|
|
614
|
+
* @alias green
|
|
615
|
+
*/
|
|
616
|
+
get g() {
|
|
617
|
+
return this.green;
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Shortcut for `blue` property
|
|
621
|
+
* Number from 0 to 255
|
|
622
|
+
* @alias blue
|
|
623
|
+
*/
|
|
624
|
+
get b() {
|
|
625
|
+
return this.blue;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Shortcut for `alpha` property
|
|
629
|
+
* Number from 0 (transparent) to 255 (opaque)
|
|
630
|
+
* @alias alpha
|
|
631
|
+
*/
|
|
632
|
+
get a() {
|
|
633
|
+
return this.alpha;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Shortcut for `alpha` property
|
|
637
|
+
* Number from 0 (transparent) to 255 (opaque)
|
|
638
|
+
* @alias alpha
|
|
639
|
+
*/
|
|
640
|
+
get opacity() {
|
|
641
|
+
return this.alpha;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Shortcut for 1-`alpha` property
|
|
645
|
+
*/
|
|
646
|
+
get transparency() {
|
|
647
|
+
return 255 - this.alpha;
|
|
648
|
+
}
|
|
649
|
+
clone() {
|
|
650
|
+
return take(this.createColor(this.red, this.green, this.blue, this.alpha));
|
|
651
|
+
}
|
|
652
|
+
toString() {
|
|
653
|
+
return this.toHex();
|
|
654
|
+
}
|
|
655
|
+
toHex() {
|
|
656
|
+
if (this.alpha === 255) {
|
|
657
|
+
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
658
|
+
.toString(16)
|
|
659
|
+
.padStart(2, '0')}`;
|
|
660
|
+
}
|
|
661
|
+
else {
|
|
662
|
+
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
663
|
+
.toString(16)
|
|
664
|
+
.padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
toRgb() {
|
|
668
|
+
if (this.alpha === 255) {
|
|
669
|
+
return `rgb(${this.red}, ${this.green}, ${this.blue})`;
|
|
670
|
+
}
|
|
671
|
+
else {
|
|
672
|
+
return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
toHsl() {
|
|
676
|
+
throw new Error(`Getting HSL is not implemented`);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
525
680
|
/**
|
|
526
681
|
* 🎨 List of all 140 color names which are supported by CSS
|
|
527
682
|
*
|
|
@@ -681,127 +836,6 @@ const CSS_COLORS = {
|
|
|
681
836
|
};
|
|
682
837
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
683
838
|
|
|
684
|
-
/**
|
|
685
|
-
* Validates that a channel value is a valid number within the range of 0 to 255.
|
|
686
|
-
* Throws an error if the value is not valid.
|
|
687
|
-
*
|
|
688
|
-
* @param channelName - The name of the channel being validated.
|
|
689
|
-
* @param value - The value of the channel to validate.
|
|
690
|
-
* @throws Will throw an error if the value is not a valid channel number.
|
|
691
|
-
*
|
|
692
|
-
* @private util of `@promptbook/color`
|
|
693
|
-
*/
|
|
694
|
-
function checkChannelValue(channelName, value) {
|
|
695
|
-
if (typeof value !== 'number') {
|
|
696
|
-
throw new Error(`${channelName} channel value is not number but ${typeof value}`);
|
|
697
|
-
}
|
|
698
|
-
if (isNaN(value)) {
|
|
699
|
-
throw new Error(`${channelName} channel value is NaN`);
|
|
700
|
-
}
|
|
701
|
-
if (Math.round(value) !== value) {
|
|
702
|
-
throw new Error(`${channelName} channel is not whole number, it is ${value}`);
|
|
703
|
-
}
|
|
704
|
-
if (value < 0) {
|
|
705
|
-
throw new Error(`${channelName} channel is lower than 0, it is ${value}`);
|
|
706
|
-
}
|
|
707
|
-
if (value > 255) {
|
|
708
|
-
throw new Error(`${channelName} channel is greater than 255, it is ${value}`);
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
/**
|
|
713
|
-
* Shared immutable channel storage and serialization helpers for `Color`.
|
|
714
|
-
*
|
|
715
|
-
* @private base class of Color
|
|
716
|
-
*/
|
|
717
|
-
class ColorValue {
|
|
718
|
-
constructor(red, green, blue, alpha = 255) {
|
|
719
|
-
this.red = red;
|
|
720
|
-
this.green = green;
|
|
721
|
-
this.blue = blue;
|
|
722
|
-
this.alpha = alpha;
|
|
723
|
-
checkChannelValue('Red', red);
|
|
724
|
-
checkChannelValue('Green', green);
|
|
725
|
-
checkChannelValue('Blue', blue);
|
|
726
|
-
checkChannelValue('Alpha', alpha);
|
|
727
|
-
}
|
|
728
|
-
/**
|
|
729
|
-
* Shortcut for `red` property
|
|
730
|
-
* Number from 0 to 255
|
|
731
|
-
* @alias red
|
|
732
|
-
*/
|
|
733
|
-
get r() {
|
|
734
|
-
return this.red;
|
|
735
|
-
}
|
|
736
|
-
/**
|
|
737
|
-
* Shortcut for `green` property
|
|
738
|
-
* Number from 0 to 255
|
|
739
|
-
* @alias green
|
|
740
|
-
*/
|
|
741
|
-
get g() {
|
|
742
|
-
return this.green;
|
|
743
|
-
}
|
|
744
|
-
/**
|
|
745
|
-
* Shortcut for `blue` property
|
|
746
|
-
* Number from 0 to 255
|
|
747
|
-
* @alias blue
|
|
748
|
-
*/
|
|
749
|
-
get b() {
|
|
750
|
-
return this.blue;
|
|
751
|
-
}
|
|
752
|
-
/**
|
|
753
|
-
* Shortcut for `alpha` property
|
|
754
|
-
* Number from 0 (transparent) to 255 (opaque)
|
|
755
|
-
* @alias alpha
|
|
756
|
-
*/
|
|
757
|
-
get a() {
|
|
758
|
-
return this.alpha;
|
|
759
|
-
}
|
|
760
|
-
/**
|
|
761
|
-
* Shortcut for `alpha` property
|
|
762
|
-
* Number from 0 (transparent) to 255 (opaque)
|
|
763
|
-
* @alias alpha
|
|
764
|
-
*/
|
|
765
|
-
get opacity() {
|
|
766
|
-
return this.alpha;
|
|
767
|
-
}
|
|
768
|
-
/**
|
|
769
|
-
* Shortcut for 1-`alpha` property
|
|
770
|
-
*/
|
|
771
|
-
get transparency() {
|
|
772
|
-
return 255 - this.alpha;
|
|
773
|
-
}
|
|
774
|
-
clone() {
|
|
775
|
-
return take(this.createColor(this.red, this.green, this.blue, this.alpha));
|
|
776
|
-
}
|
|
777
|
-
toString() {
|
|
778
|
-
return this.toHex();
|
|
779
|
-
}
|
|
780
|
-
toHex() {
|
|
781
|
-
if (this.alpha === 255) {
|
|
782
|
-
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
783
|
-
.toString(16)
|
|
784
|
-
.padStart(2, '0')}`;
|
|
785
|
-
}
|
|
786
|
-
else {
|
|
787
|
-
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
788
|
-
.toString(16)
|
|
789
|
-
.padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
toRgb() {
|
|
793
|
-
if (this.alpha === 255) {
|
|
794
|
-
return `rgb(${this.red}, ${this.green}, ${this.blue})`;
|
|
795
|
-
}
|
|
796
|
-
else {
|
|
797
|
-
return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
toHsl() {
|
|
801
|
-
throw new Error(`Getting HSL is not implemented`);
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
|
|
805
839
|
/**
|
|
806
840
|
* Checks if the given value is a valid hex color string
|
|
807
841
|
*
|
|
@@ -2775,6 +2809,31 @@ const OPENAI_MODELS = exportJson({
|
|
|
2775
2809
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
2776
2810
|
*/
|
|
2777
2811
|
|
|
2812
|
+
/**
|
|
2813
|
+
* Pattern that matches durations like "1h", "30m", "5s", "1h30m", "1h30m5s".
|
|
2814
|
+
*/
|
|
2815
|
+
/**
|
|
2816
|
+
* Formats a duration in milliseconds into a compact human-readable string.
|
|
2817
|
+
*
|
|
2818
|
+
* Examples: `3600000` → `"1h"`, `90000` → `"1m 30s"`, `5000` → `"5s"`.
|
|
2819
|
+
*
|
|
2820
|
+
* @private internal utility of `ptbk coder run`
|
|
2821
|
+
*/
|
|
2822
|
+
function formatDurationMs(ms) {
|
|
2823
|
+
const totalSeconds = Math.ceil(ms / 1000);
|
|
2824
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
2825
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
2826
|
+
const seconds = totalSeconds % 60;
|
|
2827
|
+
const parts = [];
|
|
2828
|
+
if (hours > 0)
|
|
2829
|
+
parts.push(`${hours}h`);
|
|
2830
|
+
if (minutes > 0)
|
|
2831
|
+
parts.push(`${minutes}m`);
|
|
2832
|
+
if (seconds > 0 || parts.length === 0)
|
|
2833
|
+
parts.push(`${seconds}s`);
|
|
2834
|
+
return parts.join(' ');
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2778
2837
|
/**
|
|
2779
2838
|
* Formats one unknown error-like value into readable text for logs and feedback.
|
|
2780
2839
|
*/
|
|
@@ -3012,14 +3071,209 @@ const CLAUDE_PROMPT_DELIMITER = 'CLAUDE_PROMPT';
|
|
|
3012
3071
|
function buildClaudeScript(options) {
|
|
3013
3072
|
const MODEL_ARGUMENT = options.model ? ` --model ${options.model}` : '';
|
|
3014
3073
|
const THINKING_LEVEL_ARGUMENT = options.thinkingLevel ? ` --effort ${options.thinkingLevel}` : '';
|
|
3074
|
+
const RESUME_SESSION_ARGUMENT = options.resumeSessionId
|
|
3075
|
+
? ` --resume ${quoteShellArgument(options.resumeSessionId)}`
|
|
3076
|
+
: '';
|
|
3015
3077
|
return spaceTrim((block) => `
|
|
3016
|
-
claude --allowedTools "Bash,Read,Edit,Write"${MODEL_ARGUMENT}${THINKING_LEVEL_ARGUMENT} --output-format stream-json --verbose --include-partial-messages --print <<'${CLAUDE_PROMPT_DELIMITER}'
|
|
3078
|
+
claude --allowedTools "Bash,Read,Edit,Write"${MODEL_ARGUMENT}${THINKING_LEVEL_ARGUMENT}${RESUME_SESSION_ARGUMENT} --output-format stream-json --verbose --include-partial-messages --print <<'${CLAUDE_PROMPT_DELIMITER}'
|
|
3017
3079
|
|
|
3018
3080
|
${block(options.prompt)}
|
|
3019
3081
|
|
|
3020
3082
|
${CLAUDE_PROMPT_DELIMITER}
|
|
3021
3083
|
`);
|
|
3022
3084
|
}
|
|
3085
|
+
/**
|
|
3086
|
+
* Quotes one shell argument for the generated Bash script.
|
|
3087
|
+
*/
|
|
3088
|
+
function quoteShellArgument(value) {
|
|
3089
|
+
return JSON.stringify(value);
|
|
3090
|
+
}
|
|
3091
|
+
|
|
3092
|
+
/**
|
|
3093
|
+
* Parses all JSON lines from Claude Code output while ignoring shell prefixes and stack traces.
|
|
3094
|
+
*/
|
|
3095
|
+
function parseClaudeCodeOutputEvents(output) {
|
|
3096
|
+
return output
|
|
3097
|
+
.split(/\r?\n/u)
|
|
3098
|
+
.map(parseClaudeCodeOutputLine)
|
|
3099
|
+
.filter((event) => event !== undefined);
|
|
3100
|
+
}
|
|
3101
|
+
/**
|
|
3102
|
+
* Finds the final Claude Code result event in a stream-json output blob.
|
|
3103
|
+
*/
|
|
3104
|
+
function findClaudeCodeResultEvent(output) {
|
|
3105
|
+
return parseClaudeCodeOutputEvents(output).find((event) => event.type === 'result');
|
|
3106
|
+
}
|
|
3107
|
+
/**
|
|
3108
|
+
* Parses one output line when it contains a JSON object.
|
|
3109
|
+
*/
|
|
3110
|
+
function parseClaudeCodeOutputLine(line) {
|
|
3111
|
+
const jsonStartIndex = line.indexOf('{');
|
|
3112
|
+
if (jsonStartIndex === -1) {
|
|
3113
|
+
return undefined;
|
|
3114
|
+
}
|
|
3115
|
+
const possibleJson = line.slice(jsonStartIndex).trim();
|
|
3116
|
+
try {
|
|
3117
|
+
const parsed = JSON.parse(possibleJson);
|
|
3118
|
+
if (isClaudeCodeOutputEvent(parsed)) {
|
|
3119
|
+
return parsed;
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
catch (_a) {
|
|
3123
|
+
return undefined;
|
|
3124
|
+
}
|
|
3125
|
+
return undefined;
|
|
3126
|
+
}
|
|
3127
|
+
/**
|
|
3128
|
+
* Checks whether an unknown parsed JSON value has the object shape expected from Claude Code events.
|
|
3129
|
+
*/
|
|
3130
|
+
function isClaudeCodeOutputEvent(value) {
|
|
3131
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3132
|
+
}
|
|
3133
|
+
|
|
3134
|
+
/**
|
|
3135
|
+
* Number of milliseconds added after Claude's reported reset timestamp before retrying.
|
|
3136
|
+
*/
|
|
3137
|
+
const CLAUDE_CODE_SESSION_LIMIT_RESET_BUFFER_MS = 30 * 1000;
|
|
3138
|
+
/**
|
|
3139
|
+
* Fallback delay used when Claude reports a session limit without a machine-readable reset timestamp.
|
|
3140
|
+
*/
|
|
3141
|
+
const DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS = 10 * 60 * 1000;
|
|
3142
|
+
/**
|
|
3143
|
+
* Extracts a Claude Code session-limit failure from a thrown runner error.
|
|
3144
|
+
*/
|
|
3145
|
+
function extractClaudeCodeSessionLimitFromError(error) {
|
|
3146
|
+
return extractClaudeCodeSessionLimitFromOutput(formatUnknownErrorDetails(error));
|
|
3147
|
+
}
|
|
3148
|
+
/**
|
|
3149
|
+
* Extracts a Claude Code session-limit failure from raw stream-json output.
|
|
3150
|
+
*/
|
|
3151
|
+
function extractClaudeCodeSessionLimitFromOutput(output) {
|
|
3152
|
+
var _a, _b, _c, _d, _e;
|
|
3153
|
+
const events = parseClaudeCodeOutputEvents(output);
|
|
3154
|
+
const rejectedRateLimitEvent = events.find(isRejectedRateLimitEvent);
|
|
3155
|
+
const sessionLimitResultEvent = events.find(isSessionLimitResultEvent);
|
|
3156
|
+
const sessionLimitTextEvent = events.find(isSessionLimitTextEvent);
|
|
3157
|
+
if (!sessionLimitResultEvent && !sessionLimitTextEvent) {
|
|
3158
|
+
return undefined;
|
|
3159
|
+
}
|
|
3160
|
+
const sessionId = findClaudeCodeSessionId(events);
|
|
3161
|
+
if (!sessionId) {
|
|
3162
|
+
return undefined;
|
|
3163
|
+
}
|
|
3164
|
+
const resetDate = extractResetDate(rejectedRateLimitEvent);
|
|
3165
|
+
const rateLimitType = (_b = (_a = rejectedRateLimitEvent === null || rejectedRateLimitEvent === void 0 ? void 0 : rejectedRateLimitEvent.rate_limit_info) === null || _a === void 0 ? void 0 : _a.rateLimitType) !== null && _b !== void 0 ? _b : (_c = sessionLimitResultEvent === null || sessionLimitResultEvent === void 0 ? void 0 : sessionLimitResultEvent.rate_limit_info) === null || _c === void 0 ? void 0 : _c.rateLimitType;
|
|
3166
|
+
const summary = (_e = (_d = extractSessionLimitSummary(sessionLimitResultEvent)) !== null && _d !== void 0 ? _d : extractSessionLimitSummary(sessionLimitTextEvent)) !== null && _e !== void 0 ? _e : 'Claude Code reported a session limit.';
|
|
3167
|
+
return {
|
|
3168
|
+
sessionId,
|
|
3169
|
+
resetDate,
|
|
3170
|
+
rateLimitType,
|
|
3171
|
+
summary,
|
|
3172
|
+
};
|
|
3173
|
+
}
|
|
3174
|
+
/**
|
|
3175
|
+
* Computes how long to wait before trying to resume the Claude Code session.
|
|
3176
|
+
*/
|
|
3177
|
+
function getClaudeCodeSessionLimitDelayMs(sessionLimit, nowMs = Date.now()) {
|
|
3178
|
+
if (!sessionLimit.resetDate) {
|
|
3179
|
+
return DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS;
|
|
3180
|
+
}
|
|
3181
|
+
return Math.max(0, sessionLimit.resetDate.getTime() - nowMs + CLAUDE_CODE_SESSION_LIMIT_RESET_BUFFER_MS);
|
|
3182
|
+
}
|
|
3183
|
+
/**
|
|
3184
|
+
* Builds the follow-up prompt sent into a resumed Claude Code session after its limit resets.
|
|
3185
|
+
*/
|
|
3186
|
+
function buildClaudeCodeSessionResurrectionPrompt(originalPrompt, sessionId) {
|
|
3187
|
+
return spaceTrim((block) => `
|
|
3188
|
+
## Claude Code session resurrection
|
|
3189
|
+
|
|
3190
|
+
You are resuming Claude Code session \`${sessionId}\` after Claude reported a session limit.
|
|
3191
|
+
Continue the same task from the existing repository and session state.
|
|
3192
|
+
Do not discard useful context, completed analysis, or file changes from the resumed session.
|
|
3193
|
+
|
|
3194
|
+
The original prompt is repeated below as reference in case the resumed session needs it.
|
|
3195
|
+
|
|
3196
|
+
## Original prompt
|
|
3197
|
+
|
|
3198
|
+
${block(originalPrompt)}
|
|
3199
|
+
`);
|
|
3200
|
+
}
|
|
3201
|
+
/**
|
|
3202
|
+
* Builds a compact one-line label for logs and terminal UI messages.
|
|
3203
|
+
*/
|
|
3204
|
+
function formatClaudeCodeSessionLimitForDisplay(sessionLimit) {
|
|
3205
|
+
const resetSuffix = sessionLimit.resetDate
|
|
3206
|
+
? `, resets at ${sessionLimit.resetDate.toISOString()}`
|
|
3207
|
+
: `, retrying every ${formatDurationMs(DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS)}`;
|
|
3208
|
+
const rateLimitSuffix = sessionLimit.rateLimitType ? ` (${sessionLimit.rateLimitType})` : '';
|
|
3209
|
+
return `${sessionLimit.summary}${rateLimitSuffix}${resetSuffix}`;
|
|
3210
|
+
}
|
|
3211
|
+
/**
|
|
3212
|
+
* Returns true when the event is an explicit rejected Claude Code rate-limit event.
|
|
3213
|
+
*/
|
|
3214
|
+
function isRejectedRateLimitEvent(event) {
|
|
3215
|
+
var _a;
|
|
3216
|
+
return event.type === 'rate_limit_event' && ((_a = event.rate_limit_info) === null || _a === void 0 ? void 0 : _a.status) === 'rejected';
|
|
3217
|
+
}
|
|
3218
|
+
/**
|
|
3219
|
+
* Returns true when the final result reports the Claude session limit.
|
|
3220
|
+
*/
|
|
3221
|
+
function isSessionLimitResultEvent(event) {
|
|
3222
|
+
return (event.type === 'result' &&
|
|
3223
|
+
event.is_error === true &&
|
|
3224
|
+
event.api_error_status === 429 &&
|
|
3225
|
+
isSessionLimitText(event.result));
|
|
3226
|
+
}
|
|
3227
|
+
/**
|
|
3228
|
+
* Returns true when any assistant event reports the Claude session limit in text.
|
|
3229
|
+
*/
|
|
3230
|
+
function isSessionLimitTextEvent(event) {
|
|
3231
|
+
if (event.error !== 'rate_limit') {
|
|
3232
|
+
return false;
|
|
3233
|
+
}
|
|
3234
|
+
return isSessionLimitText(extractSessionLimitSummary(event));
|
|
3235
|
+
}
|
|
3236
|
+
/**
|
|
3237
|
+
* Extracts the first session id reported by Claude Code.
|
|
3238
|
+
*/
|
|
3239
|
+
function findClaudeCodeSessionId(events) {
|
|
3240
|
+
return events.map((event) => event.session_id).find((sessionId) => Boolean(sessionId));
|
|
3241
|
+
}
|
|
3242
|
+
/**
|
|
3243
|
+
* Extracts Claude's reset timestamp from a rejected rate-limit event.
|
|
3244
|
+
*/
|
|
3245
|
+
function extractResetDate(event) {
|
|
3246
|
+
var _a;
|
|
3247
|
+
const resetsAt = (_a = event === null || event === void 0 ? void 0 : event.rate_limit_info) === null || _a === void 0 ? void 0 : _a.resetsAt;
|
|
3248
|
+
if (typeof resetsAt !== 'number' || !Number.isFinite(resetsAt)) {
|
|
3249
|
+
return undefined;
|
|
3250
|
+
}
|
|
3251
|
+
const resetDate = new Date(resetsAt * 1000);
|
|
3252
|
+
if (Number.isNaN(resetDate.getTime())) {
|
|
3253
|
+
return undefined;
|
|
3254
|
+
}
|
|
3255
|
+
return resetDate;
|
|
3256
|
+
}
|
|
3257
|
+
/**
|
|
3258
|
+
* Extracts a human-readable session-limit summary from an event.
|
|
3259
|
+
*/
|
|
3260
|
+
function extractSessionLimitSummary(event) {
|
|
3261
|
+
var _a, _b;
|
|
3262
|
+
if (!event) {
|
|
3263
|
+
return undefined;
|
|
3264
|
+
}
|
|
3265
|
+
if (typeof event.result === 'string' && event.result.trim()) {
|
|
3266
|
+
return event.result.trim();
|
|
3267
|
+
}
|
|
3268
|
+
const textContent = (_b = (_a = event.message) === null || _a === void 0 ? void 0 : _a.content) === null || _b === void 0 ? void 0 : _b.map((content) => { var _a; return (content.type === 'text' ? (_a = content.text) === null || _a === void 0 ? void 0 : _a.trim() : undefined); }).find((text) => Boolean(text));
|
|
3269
|
+
return textContent;
|
|
3270
|
+
}
|
|
3271
|
+
/**
|
|
3272
|
+
* Checks whether a text value names the Claude Code session limit.
|
|
3273
|
+
*/
|
|
3274
|
+
function isSessionLimitText(text) {
|
|
3275
|
+
return /\bsession\s+limit\b/iu.test(text !== null && text !== void 0 ? text : '');
|
|
3276
|
+
}
|
|
3023
3277
|
|
|
3024
3278
|
/**
|
|
3025
3279
|
* Represents the uncertain value
|
|
@@ -3095,14 +3349,8 @@ const UNCERTAIN_USAGE = $deepFreeze({
|
|
|
3095
3349
|
function parseClaudeCodeJsonOutput(output) {
|
|
3096
3350
|
var _a, _b, _c, _d;
|
|
3097
3351
|
try {
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
const jsonLine = lines.find((line) => line.trim().startsWith('{"type":"result"'));
|
|
3101
|
-
if (!jsonLine) {
|
|
3102
|
-
return UNCERTAIN_USAGE;
|
|
3103
|
-
}
|
|
3104
|
-
const parsed = JSON.parse(jsonLine);
|
|
3105
|
-
if (parsed.type !== 'result') {
|
|
3352
|
+
const parsed = findClaudeCodeResultEvent(output);
|
|
3353
|
+
if (!parsed) {
|
|
3106
3354
|
return UNCERTAIN_USAGE;
|
|
3107
3355
|
}
|
|
3108
3356
|
const totalInputTokens = (((_a = parsed.usage) === null || _a === void 0 ? void 0 : _a.input_tokens) || 0) +
|
|
@@ -3146,6 +3394,10 @@ function parseClaudeCodeJsonOutput(output) {
|
|
|
3146
3394
|
}
|
|
3147
3395
|
}
|
|
3148
3396
|
|
|
3397
|
+
/**
|
|
3398
|
+
* Polling interval used while waiting for Claude Code session limits to reset.
|
|
3399
|
+
*/
|
|
3400
|
+
const CLAUDE_CODE_SESSION_RESURRECTION_POLL_MS = 30 * 1000;
|
|
3149
3401
|
/**
|
|
3150
3402
|
* Runs prompts via the Claude Code CLI.
|
|
3151
3403
|
*/
|
|
@@ -3161,22 +3413,102 @@ class ClaudeCodeRunner {
|
|
|
3161
3413
|
* Runs the prompt using Claude Code and parses usage output.
|
|
3162
3414
|
*/
|
|
3163
3415
|
async runPrompt(options) {
|
|
3416
|
+
let resumeSessionId;
|
|
3417
|
+
let prompt = options.prompt;
|
|
3418
|
+
let resurrectionCount = 0;
|
|
3419
|
+
while (true) {
|
|
3420
|
+
const output = await this.runClaudeCodeOnce({
|
|
3421
|
+
...options,
|
|
3422
|
+
prompt,
|
|
3423
|
+
resumeSessionId,
|
|
3424
|
+
}).catch(async (error) => {
|
|
3425
|
+
const sessionLimit = extractClaudeCodeSessionLimitFromError(error);
|
|
3426
|
+
if (!sessionLimit) {
|
|
3427
|
+
throw error;
|
|
3428
|
+
}
|
|
3429
|
+
resurrectionCount++;
|
|
3430
|
+
await waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options);
|
|
3431
|
+
resumeSessionId = sessionLimit.sessionId;
|
|
3432
|
+
prompt = buildClaudeCodeSessionResurrectionPrompt(options.prompt, sessionLimit.sessionId);
|
|
3433
|
+
return undefined;
|
|
3434
|
+
});
|
|
3435
|
+
if (output === undefined) {
|
|
3436
|
+
continue;
|
|
3437
|
+
}
|
|
3438
|
+
const sessionLimit = extractClaudeCodeSessionLimitFromOutput(output);
|
|
3439
|
+
if (sessionLimit) {
|
|
3440
|
+
resurrectionCount++;
|
|
3441
|
+
await waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options);
|
|
3442
|
+
resumeSessionId = sessionLimit.sessionId;
|
|
3443
|
+
prompt = buildClaudeCodeSessionResurrectionPrompt(options.prompt, sessionLimit.sessionId);
|
|
3444
|
+
continue;
|
|
3445
|
+
}
|
|
3446
|
+
const usage = parseClaudeCodeJsonOutput(output);
|
|
3447
|
+
return { usage };
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
/**
|
|
3451
|
+
* Runs one Claude Code CLI process and returns its raw output.
|
|
3452
|
+
*/
|
|
3453
|
+
async runClaudeCodeOnce(options) {
|
|
3164
3454
|
const scriptContent = buildClaudeScript({
|
|
3165
3455
|
prompt: options.prompt,
|
|
3166
3456
|
model: this.options.model,
|
|
3167
3457
|
thinkingLevel: this.options.thinkingLevel,
|
|
3458
|
+
resumeSessionId: options.resumeSessionId,
|
|
3168
3459
|
});
|
|
3169
|
-
|
|
3460
|
+
return await $runGoScriptWithOutput({
|
|
3170
3461
|
scriptPath: options.scriptPath,
|
|
3171
3462
|
scriptContent,
|
|
3172
3463
|
logPath: options.logPath,
|
|
3173
3464
|
shouldPrintLiveOutput: options.shouldPrintLiveOutput,
|
|
3174
3465
|
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
3175
3466
|
});
|
|
3176
|
-
const usage = parseClaudeCodeJsonOutput(output);
|
|
3177
|
-
return { usage };
|
|
3178
3467
|
}
|
|
3179
3468
|
}
|
|
3469
|
+
/**
|
|
3470
|
+
* Waits until the Claude Code session can be resumed, keeping terminal status clear.
|
|
3471
|
+
*/
|
|
3472
|
+
async function waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options) {
|
|
3473
|
+
var _a, _b, _c;
|
|
3474
|
+
const delayMs = getClaudeCodeSessionLimitDelayMs(sessionLimit);
|
|
3475
|
+
const sessionLabel = formatClaudeCodeSessionIdForDisplay(sessionLimit.sessionId);
|
|
3476
|
+
const resetSummary = formatClaudeCodeSessionLimitForDisplay(sessionLimit);
|
|
3477
|
+
if ((_a = options.shouldPrintLiveOutput) !== null && _a !== void 0 ? _a : true) {
|
|
3478
|
+
console.warn(colors.yellow(`[claude-code] Session limit detected for ${sessionLimit.sessionId}. Resurrection #${resurrectionCount} will resume with --resume after ${formatDurationMs(delayMs)}. ${resetSummary}`));
|
|
3479
|
+
}
|
|
3480
|
+
let remainingDelayMs = delayMs;
|
|
3481
|
+
while (remainingDelayMs > 0) {
|
|
3482
|
+
await ((_b = options.waitForPauseCheckpoint) === null || _b === void 0 ? void 0 : _b.call(options, {
|
|
3483
|
+
checkpointLabel: 'the Claude Code session limit reset',
|
|
3484
|
+
phase: 'waiting',
|
|
3485
|
+
statusMessage: `Claude Code session ${sessionLabel} hit its limit; resurrection #${resurrectionCount} resumes in ${formatDurationMs(remainingDelayMs)}`,
|
|
3486
|
+
}));
|
|
3487
|
+
const currentDelayMs = Math.min(CLAUDE_CODE_SESSION_RESURRECTION_POLL_MS, remainingDelayMs);
|
|
3488
|
+
await waitFor$1(currentDelayMs);
|
|
3489
|
+
remainingDelayMs -= currentDelayMs;
|
|
3490
|
+
}
|
|
3491
|
+
await ((_c = options.waitForPauseCheckpoint) === null || _c === void 0 ? void 0 : _c.call(options, {
|
|
3492
|
+
checkpointLabel: 'resurrecting the Claude Code session with --resume',
|
|
3493
|
+
phase: 'running',
|
|
3494
|
+
statusMessage: `Resurrecting Claude Code session ${sessionLabel} with --resume`,
|
|
3495
|
+
}));
|
|
3496
|
+
}
|
|
3497
|
+
/**
|
|
3498
|
+
* Waits for a fixed amount of milliseconds.
|
|
3499
|
+
*/
|
|
3500
|
+
async function waitFor$1(delayMs) {
|
|
3501
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
3502
|
+
}
|
|
3503
|
+
/**
|
|
3504
|
+
* Formats a Claude Code session id for compact terminal status lines.
|
|
3505
|
+
*/
|
|
3506
|
+
function formatClaudeCodeSessionIdForDisplay(sessionId) {
|
|
3507
|
+
if (sessionId.length <= 8) {
|
|
3508
|
+
return sessionId;
|
|
3509
|
+
}
|
|
3510
|
+
return `${sessionId.slice(0, 8)}...`;
|
|
3511
|
+
}
|
|
3180
3512
|
|
|
3181
3513
|
/**
|
|
3182
3514
|
* Creates a temporary script file, runs it, and cleans it up unless preservation is requested or the run fails.
|
|
@@ -5072,6 +5404,95 @@ function pipelineJsonToString(pipelineJson) {
|
|
|
5072
5404
|
// TODO: [🏛] Escape all
|
|
5073
5405
|
// TODO: [🧠] Should be in generated .book.md file GENERATOR_WARNING
|
|
5074
5406
|
|
|
5407
|
+
/**
|
|
5408
|
+
* This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
|
|
5409
|
+
*
|
|
5410
|
+
* @public exported from `@promptbook/core`
|
|
5411
|
+
*/
|
|
5412
|
+
class PipelineLogicError extends Error {
|
|
5413
|
+
constructor(message) {
|
|
5414
|
+
super(message);
|
|
5415
|
+
this.name = 'PipelineLogicError';
|
|
5416
|
+
Object.setPrototypeOf(this, PipelineLogicError.prototype);
|
|
5417
|
+
}
|
|
5418
|
+
}
|
|
5419
|
+
|
|
5420
|
+
/**
|
|
5421
|
+
* Creates the shared validation context for one pipeline.
|
|
5422
|
+
*
|
|
5423
|
+
* @private function of `validatePipeline`
|
|
5424
|
+
*/
|
|
5425
|
+
function createPipelineValidationContext(pipeline) {
|
|
5426
|
+
return {
|
|
5427
|
+
pipeline,
|
|
5428
|
+
pipelineIdentification: getPipelineIdentification$1(pipeline),
|
|
5429
|
+
};
|
|
5430
|
+
}
|
|
5431
|
+
/**
|
|
5432
|
+
* Builds a short file/url identification block for validation errors.
|
|
5433
|
+
*
|
|
5434
|
+
* @private internal utility of `validatePipeline`
|
|
5435
|
+
*/
|
|
5436
|
+
function getPipelineIdentification$1(pipeline) {
|
|
5437
|
+
// Note: This is a 😐 implementation of [🚞]
|
|
5438
|
+
const pipelineIdentificationParts = [];
|
|
5439
|
+
if (pipeline.sourceFile !== undefined) {
|
|
5440
|
+
pipelineIdentificationParts.push(`File: ${pipeline.sourceFile}`);
|
|
5441
|
+
}
|
|
5442
|
+
if (pipeline.pipelineUrl !== undefined) {
|
|
5443
|
+
pipelineIdentificationParts.push(`Url: ${pipeline.pipelineUrl}`);
|
|
5444
|
+
}
|
|
5445
|
+
return pipelineIdentificationParts.join('\n');
|
|
5446
|
+
}
|
|
5447
|
+
|
|
5448
|
+
/**
|
|
5449
|
+
* Validates that the expected top-level collections have array structure.
|
|
5450
|
+
*
|
|
5451
|
+
* @private function of `validatePipeline`
|
|
5452
|
+
*/
|
|
5453
|
+
function validatePipelineCollectionsStructure({ pipeline, pipelineIdentification, }) {
|
|
5454
|
+
validatePipelineParametersCollection(pipeline, pipelineIdentification);
|
|
5455
|
+
validatePipelineTasksCollection(pipeline, pipelineIdentification);
|
|
5456
|
+
}
|
|
5457
|
+
/**
|
|
5458
|
+
* Validates that `pipeline.parameters` is an array.
|
|
5459
|
+
*
|
|
5460
|
+
* @private internal utility of `validatePipelineCollectionsStructure`
|
|
5461
|
+
*/
|
|
5462
|
+
function validatePipelineParametersCollection(pipeline, pipelineIdentification) {
|
|
5463
|
+
// TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
|
|
5464
|
+
if (Array.isArray(pipeline.parameters)) {
|
|
5465
|
+
return;
|
|
5466
|
+
}
|
|
5467
|
+
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5468
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
5469
|
+
Pipeline is valid JSON but with wrong structure
|
|
5470
|
+
|
|
5471
|
+
\`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
|
|
5472
|
+
|
|
5473
|
+
${block(pipelineIdentification)}
|
|
5474
|
+
`));
|
|
5475
|
+
}
|
|
5476
|
+
/**
|
|
5477
|
+
* Validates that `pipeline.tasks` is an array.
|
|
5478
|
+
*
|
|
5479
|
+
* @private internal utility of `validatePipelineCollectionsStructure`
|
|
5480
|
+
*/
|
|
5481
|
+
function validatePipelineTasksCollection(pipeline, pipelineIdentification) {
|
|
5482
|
+
// TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
|
|
5483
|
+
if (Array.isArray(pipeline.tasks)) {
|
|
5484
|
+
return;
|
|
5485
|
+
}
|
|
5486
|
+
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5487
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
5488
|
+
Pipeline is valid JSON but with wrong structure
|
|
5489
|
+
|
|
5490
|
+
\`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
|
|
5491
|
+
|
|
5492
|
+
${block(pipelineIdentification)}
|
|
5493
|
+
`));
|
|
5494
|
+
}
|
|
5495
|
+
|
|
5075
5496
|
/**
|
|
5076
5497
|
* Order of keys in the pipeline JSON
|
|
5077
5498
|
*
|
|
@@ -5184,16 +5605,137 @@ const LIMITS = {
|
|
|
5184
5605
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
5185
5606
|
|
|
5186
5607
|
/**
|
|
5187
|
-
*
|
|
5608
|
+
* Validates that task dependencies can be resolved without cycles or missing definitions.
|
|
5188
5609
|
*
|
|
5189
|
-
* @
|
|
5610
|
+
* @private function of `validatePipeline`
|
|
5190
5611
|
*/
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5612
|
+
function validatePipelineDependencyResolution({ pipeline, pipelineIdentification, }) {
|
|
5613
|
+
let dependencyResolutionState = createInitialDependencyResolutionState(pipeline);
|
|
5614
|
+
let loopLimit = LOOP_LIMIT;
|
|
5615
|
+
while (hasUnresolvedTasks(dependencyResolutionState)) {
|
|
5616
|
+
if (loopLimit-- < 0) {
|
|
5617
|
+
throw createDependencyResolutionLoopLimitError(pipelineIdentification);
|
|
5618
|
+
}
|
|
5619
|
+
dependencyResolutionState = resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification);
|
|
5620
|
+
}
|
|
5621
|
+
}
|
|
5622
|
+
/**
|
|
5623
|
+
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
5624
|
+
*
|
|
5625
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5626
|
+
*/
|
|
5627
|
+
function createInitialDependencyResolutionState(pipeline) {
|
|
5628
|
+
return {
|
|
5629
|
+
resolvedParameterNames: createInitiallyResolvedParameterNames(pipeline),
|
|
5630
|
+
unresolvedTasks: [...pipeline.tasks],
|
|
5631
|
+
};
|
|
5632
|
+
}
|
|
5633
|
+
/**
|
|
5634
|
+
* Checks whether dependency resolution still has tasks left to process.
|
|
5635
|
+
*
|
|
5636
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5637
|
+
*/
|
|
5638
|
+
function hasUnresolvedTasks({ unresolvedTasks }) {
|
|
5639
|
+
return unresolvedTasks.length > 0;
|
|
5640
|
+
}
|
|
5641
|
+
/**
|
|
5642
|
+
* Resolves the next batch of currently satisfiable tasks.
|
|
5643
|
+
*
|
|
5644
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5645
|
+
*/
|
|
5646
|
+
function resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification) {
|
|
5647
|
+
const currentlyResolvedTasks = getCurrentlyResolvedTasks(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames);
|
|
5648
|
+
if (currentlyResolvedTasks.length === 0) {
|
|
5649
|
+
throw createUnresolvedTasksError(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames, pipelineIdentification);
|
|
5196
5650
|
}
|
|
5651
|
+
return {
|
|
5652
|
+
resolvedParameterNames: appendResolvedTaskParameterNames(dependencyResolutionState.resolvedParameterNames, currentlyResolvedTasks),
|
|
5653
|
+
unresolvedTasks: dependencyResolutionState.unresolvedTasks.filter((task) => !currentlyResolvedTasks.includes(task)),
|
|
5654
|
+
};
|
|
5655
|
+
}
|
|
5656
|
+
/**
|
|
5657
|
+
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
5658
|
+
*
|
|
5659
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5660
|
+
*/
|
|
5661
|
+
function createInitiallyResolvedParameterNames(pipeline) {
|
|
5662
|
+
let resolvedParameterNames = pipeline.parameters
|
|
5663
|
+
.filter(({ isInput }) => isInput)
|
|
5664
|
+
.map(({ name }) => name);
|
|
5665
|
+
for (const reservedParameterName of RESERVED_PARAMETER_NAMES) {
|
|
5666
|
+
resolvedParameterNames = [...resolvedParameterNames, reservedParameterName];
|
|
5667
|
+
}
|
|
5668
|
+
return resolvedParameterNames;
|
|
5669
|
+
}
|
|
5670
|
+
/**
|
|
5671
|
+
* Adds newly resolved task outputs to the resolved parameter list.
|
|
5672
|
+
*
|
|
5673
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5674
|
+
*/
|
|
5675
|
+
function appendResolvedTaskParameterNames(resolvedParameterNames, currentlyResolvedTasks) {
|
|
5676
|
+
return [
|
|
5677
|
+
...resolvedParameterNames,
|
|
5678
|
+
...currentlyResolvedTasks.map(({ resultingParameterName }) => resultingParameterName),
|
|
5679
|
+
];
|
|
5680
|
+
}
|
|
5681
|
+
/**
|
|
5682
|
+
* Selects tasks whose dependencies are already resolved.
|
|
5683
|
+
*
|
|
5684
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5685
|
+
*/
|
|
5686
|
+
function getCurrentlyResolvedTasks(unresolvedTasks, resolvedParameterNames) {
|
|
5687
|
+
return unresolvedTasks.filter((task) => task.dependentParameterNames.every((name) => resolvedParameterNames.includes(name)));
|
|
5688
|
+
}
|
|
5689
|
+
/**
|
|
5690
|
+
* Creates the unexpected loop-limit error for dependency resolution.
|
|
5691
|
+
*
|
|
5692
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5693
|
+
*/
|
|
5694
|
+
function createDependencyResolutionLoopLimitError(pipelineIdentification) {
|
|
5695
|
+
// Note: Really UnexpectedError not LimitReachedError - this should not happen and be caught below
|
|
5696
|
+
return new UnexpectedError(spaceTrim$1((block) => `
|
|
5697
|
+
Loop limit reached during detection of circular dependencies in \`validatePipeline\`
|
|
5698
|
+
|
|
5699
|
+
${block(pipelineIdentification)}
|
|
5700
|
+
`));
|
|
5701
|
+
}
|
|
5702
|
+
/**
|
|
5703
|
+
* Creates the detailed error for unresolved or circular task dependencies.
|
|
5704
|
+
*
|
|
5705
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5706
|
+
*/
|
|
5707
|
+
function createUnresolvedTasksError(unresolvedTasks, resolvedParameterNames, pipelineIdentification) {
|
|
5708
|
+
return new PipelineLogicError(
|
|
5709
|
+
// TODO: [🐎] DRY
|
|
5710
|
+
spaceTrim$1((block) => `
|
|
5711
|
+
|
|
5712
|
+
Can not resolve some parameters:
|
|
5713
|
+
Either you are using a parameter that is not defined, or there are some circular dependencies.
|
|
5714
|
+
|
|
5715
|
+
${block(pipelineIdentification)}
|
|
5716
|
+
|
|
5717
|
+
**Can not resolve:**
|
|
5718
|
+
${block(unresolvedTasks
|
|
5719
|
+
.map(({ resultingParameterName, dependentParameterNames }) => `- Parameter \`{${resultingParameterName}}\` which depends on ${dependentParameterNames
|
|
5720
|
+
.map((dependentParameterName) => `\`{${dependentParameterName}}\``)
|
|
5721
|
+
.join(' and ')}`)
|
|
5722
|
+
.join('\n'))}
|
|
5723
|
+
|
|
5724
|
+
**Resolved:**
|
|
5725
|
+
${block(resolvedParameterNames
|
|
5726
|
+
.filter((name) => !RESERVED_PARAMETER_NAMES.includes(name))
|
|
5727
|
+
.map((name) => `- Parameter \`{${name}}\``)
|
|
5728
|
+
.join('\n'))}
|
|
5729
|
+
|
|
5730
|
+
|
|
5731
|
+
**Reserved (which are available):**
|
|
5732
|
+
${block(resolvedParameterNames
|
|
5733
|
+
.filter((name) => RESERVED_PARAMETER_NAMES.includes(name))
|
|
5734
|
+
.map((name) => `- Parameter \`{${name}}\``)
|
|
5735
|
+
.join('\n'))}
|
|
5736
|
+
|
|
5737
|
+
|
|
5738
|
+
`));
|
|
5197
5739
|
}
|
|
5198
5740
|
|
|
5199
5741
|
/**
|
|
@@ -5270,168 +5812,19 @@ function isValidPipelineUrl(url) {
|
|
|
5270
5812
|
}
|
|
5271
5813
|
// TODO: [🐠] Maybe more info why the URL is invalid
|
|
5272
5814
|
|
|
5273
|
-
/**
|
|
5274
|
-
* Validates PipelineJson if it is logically valid
|
|
5275
|
-
*
|
|
5276
|
-
* It checks:
|
|
5277
|
-
* - if it has correct parameters dependency
|
|
5278
|
-
*
|
|
5279
|
-
* It does NOT check:
|
|
5280
|
-
* - if it is valid json
|
|
5281
|
-
* - if it is meaningful
|
|
5282
|
-
*
|
|
5283
|
-
* Note: [🔂] This function is idempotent.
|
|
5284
|
-
*
|
|
5285
|
-
* @param pipeline valid or invalid PipelineJson
|
|
5286
|
-
* @returns the same pipeline if it is logically valid
|
|
5287
|
-
* @throws {PipelineLogicError} on logical error in the pipeline
|
|
5288
|
-
*
|
|
5289
|
-
* @public exported from `@promptbook/core`
|
|
5290
|
-
*/
|
|
5291
|
-
function validatePipeline(pipeline) {
|
|
5292
|
-
if (IS_PIPELINE_LOGIC_VALIDATED) {
|
|
5293
|
-
validatePipeline_InnerFunction(pipeline);
|
|
5294
|
-
}
|
|
5295
|
-
else {
|
|
5296
|
-
try {
|
|
5297
|
-
validatePipeline_InnerFunction(pipeline);
|
|
5298
|
-
}
|
|
5299
|
-
catch (error) {
|
|
5300
|
-
if (!(error instanceof PipelineLogicError)) {
|
|
5301
|
-
throw error;
|
|
5302
|
-
}
|
|
5303
|
-
console.error(spaceTrim$1((block) => `
|
|
5304
|
-
Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
|
|
5305
|
-
|
|
5306
|
-
${block(error.message)}
|
|
5307
|
-
`));
|
|
5308
|
-
}
|
|
5309
|
-
}
|
|
5310
|
-
return pipeline;
|
|
5311
|
-
}
|
|
5312
|
-
/**
|
|
5313
|
-
* Validates pipeline inner function.
|
|
5314
|
-
*
|
|
5315
|
-
* @private internal function for `validatePipeline`
|
|
5316
|
-
*/
|
|
5317
|
-
function validatePipeline_InnerFunction(pipeline) {
|
|
5318
|
-
// TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
|
|
5319
|
-
const context = createPipelineValidationContext(pipeline);
|
|
5320
|
-
validatePipelineMetadata(context);
|
|
5321
|
-
validatePipelineCollectionsStructure(context);
|
|
5322
|
-
validatePipelineParameters(context);
|
|
5323
|
-
validatePipelineTasks(context);
|
|
5324
|
-
validatePipelineDependencyResolution(context);
|
|
5325
|
-
// Note: Check that formfactor is corresponding to the pipeline interface
|
|
5326
|
-
// TODO: !!6 Implement this
|
|
5327
|
-
// pipeline.formfactorName
|
|
5328
|
-
}
|
|
5329
|
-
/**
|
|
5330
|
-
* Creates the shared validation context for one pipeline.
|
|
5331
|
-
*
|
|
5332
|
-
* @private internal utility of `validatePipeline`
|
|
5333
|
-
*/
|
|
5334
|
-
function createPipelineValidationContext(pipeline) {
|
|
5335
|
-
return {
|
|
5336
|
-
pipeline,
|
|
5337
|
-
pipelineIdentification: getPipelineIdentification$1(pipeline),
|
|
5338
|
-
};
|
|
5339
|
-
}
|
|
5340
|
-
/**
|
|
5341
|
-
* Builds a short file/url identification block for validation errors.
|
|
5342
|
-
*
|
|
5343
|
-
* @private internal utility of `validatePipeline`
|
|
5344
|
-
*/
|
|
5345
|
-
function getPipelineIdentification$1(pipeline) {
|
|
5346
|
-
// Note: This is a 😐 implementation of [🚞]
|
|
5347
|
-
const pipelineIdentificationParts = [];
|
|
5348
|
-
if (pipeline.sourceFile !== undefined) {
|
|
5349
|
-
pipelineIdentificationParts.push(`File: ${pipeline.sourceFile}`);
|
|
5350
|
-
}
|
|
5351
|
-
if (pipeline.pipelineUrl !== undefined) {
|
|
5352
|
-
pipelineIdentificationParts.push(`Url: ${pipeline.pipelineUrl}`);
|
|
5353
|
-
}
|
|
5354
|
-
return pipelineIdentificationParts.join('\n');
|
|
5355
|
-
}
|
|
5356
5815
|
/**
|
|
5357
5816
|
* Validates pipeline-level metadata fields.
|
|
5358
5817
|
*
|
|
5359
|
-
* @private
|
|
5818
|
+
* @private function of `validatePipeline`
|
|
5360
5819
|
*/
|
|
5361
5820
|
function validatePipelineMetadata({ pipeline, pipelineIdentification }) {
|
|
5362
5821
|
validatePipelineUrl(pipeline, pipelineIdentification);
|
|
5363
5822
|
validatePipelineBookVersion(pipeline, pipelineIdentification);
|
|
5364
5823
|
}
|
|
5365
|
-
/**
|
|
5366
|
-
* Validates that the expected top-level collections have array structure.
|
|
5367
|
-
*
|
|
5368
|
-
* @private internal step of `validatePipeline`
|
|
5369
|
-
*/
|
|
5370
|
-
function validatePipelineCollectionsStructure({ pipeline, pipelineIdentification }) {
|
|
5371
|
-
validatePipelineParametersCollection(pipeline, pipelineIdentification);
|
|
5372
|
-
validatePipelineTasksCollection(pipeline, pipelineIdentification);
|
|
5373
|
-
}
|
|
5374
|
-
/**
|
|
5375
|
-
* Validates all pipeline parameter declarations.
|
|
5376
|
-
*
|
|
5377
|
-
* @private internal step of `validatePipeline`
|
|
5378
|
-
*/
|
|
5379
|
-
function validatePipelineParameters({ pipeline, pipelineIdentification }) {
|
|
5380
|
-
for (const parameter of pipeline.parameters) {
|
|
5381
|
-
validatePipelineParameter(parameter, pipeline, pipelineIdentification);
|
|
5382
|
-
}
|
|
5383
|
-
}
|
|
5384
|
-
/**
|
|
5385
|
-
* Validates all pipeline tasks and their per-task invariants.
|
|
5386
|
-
*
|
|
5387
|
-
* @private internal step of `validatePipeline`
|
|
5388
|
-
*/
|
|
5389
|
-
function validatePipelineTasks({ pipeline, pipelineIdentification }) {
|
|
5390
|
-
// Note: All input parameters are defined - so that they can be used as result of some task
|
|
5391
|
-
const definedParameters = createInitiallyDefinedParameters(pipeline);
|
|
5392
|
-
for (const task of pipeline.tasks) {
|
|
5393
|
-
validatePipelineTask(task, definedParameters, pipelineIdentification);
|
|
5394
|
-
}
|
|
5395
|
-
}
|
|
5396
|
-
/**
|
|
5397
|
-
* Validates that task dependencies can be resolved without cycles or missing definitions.
|
|
5398
|
-
*
|
|
5399
|
-
* @private internal step of `validatePipeline`
|
|
5400
|
-
*/
|
|
5401
|
-
function validatePipelineDependencyResolution({ pipeline, pipelineIdentification }) {
|
|
5402
|
-
let dependencyResolutionState = createInitialDependencyResolutionState(pipeline);
|
|
5403
|
-
let loopLimit = LOOP_LIMIT;
|
|
5404
|
-
while (hasUnresolvedTasks(dependencyResolutionState)) {
|
|
5405
|
-
if (loopLimit-- < 0) {
|
|
5406
|
-
throw createDependencyResolutionLoopLimitError(pipelineIdentification);
|
|
5407
|
-
}
|
|
5408
|
-
dependencyResolutionState = resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification);
|
|
5409
|
-
}
|
|
5410
|
-
}
|
|
5411
|
-
/**
|
|
5412
|
-
* Validates one pipeline parameter declaration.
|
|
5413
|
-
*
|
|
5414
|
-
* @private internal step of `validatePipeline`
|
|
5415
|
-
*/
|
|
5416
|
-
function validatePipelineParameter(parameter, pipeline, pipelineIdentification) {
|
|
5417
|
-
validateParameterDirection(parameter, pipelineIdentification);
|
|
5418
|
-
validateParameterUsage(parameter, pipeline, pipelineIdentification);
|
|
5419
|
-
validateParameterDefinition(parameter, pipeline, pipelineIdentification);
|
|
5420
|
-
}
|
|
5421
|
-
/**
|
|
5422
|
-
* Validates one pipeline task and its invariants.
|
|
5423
|
-
*
|
|
5424
|
-
* @private internal step of `validatePipeline`
|
|
5425
|
-
*/
|
|
5426
|
-
function validatePipelineTask(task, definedParameters, pipelineIdentification) {
|
|
5427
|
-
validateTaskResultingParameter(task, definedParameters, pipelineIdentification);
|
|
5428
|
-
validateTaskJokers(task, pipelineIdentification);
|
|
5429
|
-
validateTaskExpectations(task, pipelineIdentification);
|
|
5430
|
-
}
|
|
5431
5824
|
/**
|
|
5432
5825
|
* Validates the pipeline URL, when present.
|
|
5433
5826
|
*
|
|
5434
|
-
* @private internal utility of `
|
|
5827
|
+
* @private internal utility of `validatePipelineMetadata`
|
|
5435
5828
|
*/
|
|
5436
5829
|
function validatePipelineUrl(pipeline, pipelineIdentification) {
|
|
5437
5830
|
if (pipeline.pipelineUrl === undefined || isValidPipelineUrl(pipeline.pipelineUrl)) {
|
|
@@ -5447,7 +5840,7 @@ function validatePipelineUrl(pipeline, pipelineIdentification) {
|
|
|
5447
5840
|
/**
|
|
5448
5841
|
* Validates the Promptbook version, when present.
|
|
5449
5842
|
*
|
|
5450
|
-
* @private internal utility of `
|
|
5843
|
+
* @private internal utility of `validatePipelineMetadata`
|
|
5451
5844
|
*/
|
|
5452
5845
|
function validatePipelineBookVersion(pipeline, pipelineIdentification) {
|
|
5453
5846
|
if (pipeline.bookVersion === undefined || isValidPromptbookVersion(pipeline.bookVersion)) {
|
|
@@ -5460,48 +5853,31 @@ function validatePipelineBookVersion(pipeline, pipelineIdentification) {
|
|
|
5460
5853
|
${block(pipelineIdentification)}
|
|
5461
5854
|
`));
|
|
5462
5855
|
}
|
|
5856
|
+
|
|
5463
5857
|
/**
|
|
5464
|
-
* Validates
|
|
5858
|
+
* Validates all pipeline parameter declarations.
|
|
5465
5859
|
*
|
|
5466
|
-
* @private
|
|
5860
|
+
* @private function of `validatePipeline`
|
|
5467
5861
|
*/
|
|
5468
|
-
function
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
return;
|
|
5862
|
+
function validatePipelineParameters({ pipeline, pipelineIdentification }) {
|
|
5863
|
+
for (const parameter of pipeline.parameters) {
|
|
5864
|
+
validatePipelineParameter(parameter, pipeline, pipelineIdentification);
|
|
5472
5865
|
}
|
|
5473
|
-
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5474
|
-
throw new ParseError(spaceTrim$1((block) => `
|
|
5475
|
-
Pipeline is valid JSON but with wrong structure
|
|
5476
|
-
|
|
5477
|
-
\`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
|
|
5478
|
-
|
|
5479
|
-
${block(pipelineIdentification)}
|
|
5480
|
-
`));
|
|
5481
5866
|
}
|
|
5482
5867
|
/**
|
|
5483
|
-
* Validates
|
|
5868
|
+
* Validates one pipeline parameter declaration.
|
|
5484
5869
|
*
|
|
5485
|
-
* @private internal utility of `
|
|
5870
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5486
5871
|
*/
|
|
5487
|
-
function
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
}
|
|
5492
|
-
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5493
|
-
throw new ParseError(spaceTrim$1((block) => `
|
|
5494
|
-
Pipeline is valid JSON but with wrong structure
|
|
5495
|
-
|
|
5496
|
-
\`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
|
|
5497
|
-
|
|
5498
|
-
${block(pipelineIdentification)}
|
|
5499
|
-
`));
|
|
5872
|
+
function validatePipelineParameter(parameter, pipeline, pipelineIdentification) {
|
|
5873
|
+
validateParameterDirection(parameter, pipelineIdentification);
|
|
5874
|
+
validateParameterUsage(parameter, pipeline, pipelineIdentification);
|
|
5875
|
+
validateParameterDefinition(parameter, pipeline, pipelineIdentification);
|
|
5500
5876
|
}
|
|
5501
5877
|
/**
|
|
5502
5878
|
* Validates that one parameter does not declare incompatible directions.
|
|
5503
5879
|
*
|
|
5504
|
-
* @private internal utility of `
|
|
5880
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5505
5881
|
*/
|
|
5506
5882
|
function validateParameterDirection(parameter, pipelineIdentification) {
|
|
5507
5883
|
if (!parameter.isInput || !parameter.isOutput) {
|
|
@@ -5518,7 +5894,7 @@ function validateParameterDirection(parameter, pipelineIdentification) {
|
|
|
5518
5894
|
/**
|
|
5519
5895
|
* Validates that one intermediate parameter is actually consumed by at least one task.
|
|
5520
5896
|
*
|
|
5521
|
-
* @private internal utility of `
|
|
5897
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5522
5898
|
*/
|
|
5523
5899
|
function validateParameterUsage(parameter, pipeline, pipelineIdentification) {
|
|
5524
5900
|
if (parameter.isInput || parameter.isOutput || isParameterUsedByAnyTask(parameter, pipeline.tasks)) {
|
|
@@ -5537,7 +5913,7 @@ function validateParameterUsage(parameter, pipeline, pipelineIdentification) {
|
|
|
5537
5913
|
/**
|
|
5538
5914
|
* Validates that one non-input parameter is produced by at least one task.
|
|
5539
5915
|
*
|
|
5540
|
-
* @private internal utility of `
|
|
5916
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5541
5917
|
*/
|
|
5542
5918
|
function validateParameterDefinition(parameter, pipeline, pipelineIdentification) {
|
|
5543
5919
|
if (parameter.isInput || isParameterDefinedByAnyTask(parameter, pipeline.tasks)) {
|
|
@@ -5556,7 +5932,7 @@ function validateParameterDefinition(parameter, pipeline, pipelineIdentification
|
|
|
5556
5932
|
/**
|
|
5557
5933
|
* Checks whether one parameter is consumed by at least one task dependency list.
|
|
5558
5934
|
*
|
|
5559
|
-
* @private internal utility of `
|
|
5935
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5560
5936
|
*/
|
|
5561
5937
|
function isParameterUsedByAnyTask(parameter, tasks) {
|
|
5562
5938
|
return tasks.some((task) => task.dependentParameterNames.includes(parameter.name));
|
|
@@ -5564,23 +5940,46 @@ function isParameterUsedByAnyTask(parameter, tasks) {
|
|
|
5564
5940
|
/**
|
|
5565
5941
|
* Checks whether one parameter is produced by at least one task.
|
|
5566
5942
|
*
|
|
5567
|
-
* @private internal utility of `
|
|
5943
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5568
5944
|
*/
|
|
5569
5945
|
function isParameterDefinedByAnyTask(parameter, tasks) {
|
|
5570
5946
|
return tasks.some((task) => task.resultingParameterName === parameter.name);
|
|
5571
5947
|
}
|
|
5948
|
+
|
|
5949
|
+
/**
|
|
5950
|
+
* Validates all pipeline tasks and their per-task invariants.
|
|
5951
|
+
*
|
|
5952
|
+
* @private function of `validatePipeline`
|
|
5953
|
+
*/
|
|
5954
|
+
function validatePipelineTasks({ pipeline, pipelineIdentification }) {
|
|
5955
|
+
// Note: All input parameters are defined - so that they can be used as result of some task
|
|
5956
|
+
const definedParameters = createInitiallyDefinedParameters(pipeline);
|
|
5957
|
+
for (const task of pipeline.tasks) {
|
|
5958
|
+
validatePipelineTask(task, definedParameters, pipelineIdentification);
|
|
5959
|
+
}
|
|
5960
|
+
}
|
|
5572
5961
|
/**
|
|
5573
5962
|
* Collects the parameter names that are already defined before task validation starts.
|
|
5574
5963
|
*
|
|
5575
|
-
* @private internal utility of `
|
|
5964
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5576
5965
|
*/
|
|
5577
5966
|
function createInitiallyDefinedParameters(pipeline) {
|
|
5578
5967
|
return new Set(pipeline.parameters.filter(({ isInput }) => isInput).map(({ name }) => name));
|
|
5579
5968
|
}
|
|
5969
|
+
/**
|
|
5970
|
+
* Validates one pipeline task and its invariants.
|
|
5971
|
+
*
|
|
5972
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5973
|
+
*/
|
|
5974
|
+
function validatePipelineTask(task, definedParameters, pipelineIdentification) {
|
|
5975
|
+
validateTaskResultingParameter(task, definedParameters, pipelineIdentification);
|
|
5976
|
+
validateTaskJokers(task, pipelineIdentification);
|
|
5977
|
+
validateTaskExpectations(task, pipelineIdentification);
|
|
5978
|
+
}
|
|
5580
5979
|
/**
|
|
5581
5980
|
* Validates one task result parameter declaration and marks it as defined.
|
|
5582
5981
|
*
|
|
5583
|
-
* @private internal utility of `
|
|
5982
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5584
5983
|
*/
|
|
5585
5984
|
function validateTaskResultingParameter(task, definedParameters, pipelineIdentification) {
|
|
5586
5985
|
if (definedParameters.has(task.resultingParameterName)) {
|
|
@@ -5602,7 +6001,7 @@ function validateTaskResultingParameter(task, definedParameters, pipelineIdentif
|
|
|
5602
6001
|
/**
|
|
5603
6002
|
* Validates joker parameters for one task.
|
|
5604
6003
|
*
|
|
5605
|
-
* @private internal utility of `
|
|
6004
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5606
6005
|
*/
|
|
5607
6006
|
function validateTaskJokers(task, pipelineIdentification) {
|
|
5608
6007
|
if (!hasTaskJokers(task)) {
|
|
@@ -5614,7 +6013,7 @@ function validateTaskJokers(task, pipelineIdentification) {
|
|
|
5614
6013
|
/**
|
|
5615
6014
|
* Checks whether one task declares any joker parameters.
|
|
5616
6015
|
*
|
|
5617
|
-
* @private internal utility of `
|
|
6016
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5618
6017
|
*/
|
|
5619
6018
|
function hasTaskJokers(task) {
|
|
5620
6019
|
return !!task.jokerParameterNames && task.jokerParameterNames.length > 0;
|
|
@@ -5622,7 +6021,7 @@ function hasTaskJokers(task) {
|
|
|
5622
6021
|
/**
|
|
5623
6022
|
* Validates that a task has the required supporting features when using jokers.
|
|
5624
6023
|
*
|
|
5625
|
-
* @private internal utility of `
|
|
6024
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5626
6025
|
*/
|
|
5627
6026
|
function validateTaskSupportsJokers(task, pipelineIdentification) {
|
|
5628
6027
|
if (task.format || task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
|
|
@@ -5637,7 +6036,7 @@ function validateTaskSupportsJokers(task, pipelineIdentification) {
|
|
|
5637
6036
|
/**
|
|
5638
6037
|
* Validates that every joker parameter is also listed among task dependencies.
|
|
5639
6038
|
*
|
|
5640
|
-
* @private internal utility of `
|
|
6039
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5641
6040
|
*/
|
|
5642
6041
|
function validateTaskJokerDependencies(task, pipelineIdentification) {
|
|
5643
6042
|
for (const joker of task.jokerParameterNames) {
|
|
@@ -5654,7 +6053,7 @@ function validateTaskJokerDependencies(task, pipelineIdentification) {
|
|
|
5654
6053
|
/**
|
|
5655
6054
|
* Validates all expectation bounds configured on one task.
|
|
5656
6055
|
*
|
|
5657
|
-
* @private internal utility of `
|
|
6056
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5658
6057
|
*/
|
|
5659
6058
|
function validateTaskExpectations(task, pipelineIdentification) {
|
|
5660
6059
|
if (!task.expectations) {
|
|
@@ -5669,7 +6068,7 @@ function validateTaskExpectations(task, pipelineIdentification) {
|
|
|
5669
6068
|
/**
|
|
5670
6069
|
* Validates the minimum and maximum expectation ordering for one unit.
|
|
5671
6070
|
*
|
|
5672
|
-
* @private internal utility of `
|
|
6071
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5673
6072
|
*/
|
|
5674
6073
|
function validateTaskExpectationRange(unit, min, max, pipelineIdentification) {
|
|
5675
6074
|
if (min === undefined || max === undefined || min <= max) {
|
|
@@ -5684,7 +6083,7 @@ function validateTaskExpectationRange(unit, min, max, pipelineIdentification) {
|
|
|
5684
6083
|
/**
|
|
5685
6084
|
* Validates the minimum expectation bound for one unit.
|
|
5686
6085
|
*
|
|
5687
|
-
* @private internal utility of `
|
|
6086
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5688
6087
|
*/
|
|
5689
6088
|
function validateTaskExpectationMin(unit, min, pipelineIdentification) {
|
|
5690
6089
|
if (min === undefined || min >= 0) {
|
|
@@ -5699,7 +6098,7 @@ function validateTaskExpectationMin(unit, min, pipelineIdentification) {
|
|
|
5699
6098
|
/**
|
|
5700
6099
|
* Validates the maximum expectation bound for one unit.
|
|
5701
6100
|
*
|
|
5702
|
-
* @private internal utility of `
|
|
6101
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5703
6102
|
*/
|
|
5704
6103
|
function validateTaskExpectationMax(unit, max, pipelineIdentification) {
|
|
5705
6104
|
if (max === undefined || max > 0) {
|
|
@@ -5711,123 +6110,62 @@ function validateTaskExpectationMax(unit, max, pipelineIdentification) {
|
|
|
5711
6110
|
${block(pipelineIdentification)}
|
|
5712
6111
|
`));
|
|
5713
6112
|
}
|
|
6113
|
+
|
|
5714
6114
|
/**
|
|
5715
|
-
*
|
|
5716
|
-
*
|
|
5717
|
-
* @private internal utility of `validatePipeline`
|
|
5718
|
-
*/
|
|
5719
|
-
function createInitialDependencyResolutionState(pipeline) {
|
|
5720
|
-
return {
|
|
5721
|
-
resolvedParameterNames: createInitiallyResolvedParameterNames(pipeline),
|
|
5722
|
-
unresolvedTasks: [...pipeline.tasks],
|
|
5723
|
-
};
|
|
5724
|
-
}
|
|
5725
|
-
/**
|
|
5726
|
-
* Checks whether dependency resolution still has tasks left to process.
|
|
5727
|
-
*
|
|
5728
|
-
* @private internal utility of `validatePipeline`
|
|
5729
|
-
*/
|
|
5730
|
-
function hasUnresolvedTasks({ unresolvedTasks }) {
|
|
5731
|
-
return unresolvedTasks.length > 0;
|
|
5732
|
-
}
|
|
5733
|
-
/**
|
|
5734
|
-
* Resolves the next batch of currently satisfiable tasks.
|
|
6115
|
+
* Validates PipelineJson if it is logically valid
|
|
5735
6116
|
*
|
|
5736
|
-
*
|
|
5737
|
-
|
|
5738
|
-
function resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification) {
|
|
5739
|
-
const currentlyResolvedTasks = getCurrentlyResolvedTasks(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames);
|
|
5740
|
-
if (currentlyResolvedTasks.length === 0) {
|
|
5741
|
-
throw createUnresolvedTasksError(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames, pipelineIdentification);
|
|
5742
|
-
}
|
|
5743
|
-
return {
|
|
5744
|
-
resolvedParameterNames: appendResolvedTaskParameterNames(dependencyResolutionState.resolvedParameterNames, currentlyResolvedTasks),
|
|
5745
|
-
unresolvedTasks: dependencyResolutionState.unresolvedTasks.filter((task) => !currentlyResolvedTasks.includes(task)),
|
|
5746
|
-
};
|
|
5747
|
-
}
|
|
5748
|
-
/**
|
|
5749
|
-
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
6117
|
+
* It checks:
|
|
6118
|
+
* - if it has correct parameters dependency
|
|
5750
6119
|
*
|
|
5751
|
-
*
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
let resolvedParameterNames = pipeline.parameters
|
|
5755
|
-
.filter(({ isInput }) => isInput)
|
|
5756
|
-
.map(({ name }) => name);
|
|
5757
|
-
for (const reservedParameterName of RESERVED_PARAMETER_NAMES) {
|
|
5758
|
-
resolvedParameterNames = [...resolvedParameterNames, reservedParameterName];
|
|
5759
|
-
}
|
|
5760
|
-
return resolvedParameterNames;
|
|
5761
|
-
}
|
|
5762
|
-
/**
|
|
5763
|
-
* Adds newly resolved task outputs to the resolved parameter list.
|
|
6120
|
+
* It does NOT check:
|
|
6121
|
+
* - if it is valid json
|
|
6122
|
+
* - if it is meaningful
|
|
5764
6123
|
*
|
|
5765
|
-
*
|
|
5766
|
-
*/
|
|
5767
|
-
function appendResolvedTaskParameterNames(resolvedParameterNames, currentlyResolvedTasks) {
|
|
5768
|
-
return [
|
|
5769
|
-
...resolvedParameterNames,
|
|
5770
|
-
...currentlyResolvedTasks.map(({ resultingParameterName }) => resultingParameterName),
|
|
5771
|
-
];
|
|
5772
|
-
}
|
|
5773
|
-
/**
|
|
5774
|
-
* Selects tasks whose dependencies are already resolved.
|
|
6124
|
+
* Note: [🔂] This function is idempotent.
|
|
5775
6125
|
*
|
|
5776
|
-
* @
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
return unresolvedTasks.filter((task) => task.dependentParameterNames.every((name) => resolvedParameterNames.includes(name)));
|
|
5780
|
-
}
|
|
5781
|
-
/**
|
|
5782
|
-
* Creates the unexpected loop-limit error for dependency resolution.
|
|
6126
|
+
* @param pipeline valid or invalid PipelineJson
|
|
6127
|
+
* @returns the same pipeline if it is logically valid
|
|
6128
|
+
* @throws {PipelineLogicError} on logical error in the pipeline
|
|
5783
6129
|
*
|
|
5784
|
-
* @
|
|
6130
|
+
* @public exported from `@promptbook/core`
|
|
5785
6131
|
*/
|
|
5786
|
-
function
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
6132
|
+
function validatePipeline(pipeline) {
|
|
6133
|
+
if (IS_PIPELINE_LOGIC_VALIDATED) {
|
|
6134
|
+
validatePipeline_InnerFunction(pipeline);
|
|
6135
|
+
}
|
|
6136
|
+
else {
|
|
6137
|
+
try {
|
|
6138
|
+
validatePipeline_InnerFunction(pipeline);
|
|
6139
|
+
}
|
|
6140
|
+
catch (error) {
|
|
6141
|
+
if (!(error instanceof PipelineLogicError)) {
|
|
6142
|
+
throw error;
|
|
6143
|
+
}
|
|
6144
|
+
console.error(spaceTrim$1((block) => `
|
|
6145
|
+
Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
|
|
5790
6146
|
|
|
5791
|
-
|
|
5792
|
-
|
|
6147
|
+
${block(error.message)}
|
|
6148
|
+
`));
|
|
6149
|
+
}
|
|
6150
|
+
}
|
|
6151
|
+
return pipeline;
|
|
5793
6152
|
}
|
|
5794
6153
|
/**
|
|
5795
|
-
*
|
|
6154
|
+
* Validates pipeline inner function.
|
|
5796
6155
|
*
|
|
5797
|
-
* @private internal
|
|
6156
|
+
* @private internal function for `validatePipeline`
|
|
5798
6157
|
*/
|
|
5799
|
-
function
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
${block(unresolvedTasks
|
|
5811
|
-
.map(({ resultingParameterName, dependentParameterNames }) => `- Parameter \`{${resultingParameterName}}\` which depends on ${dependentParameterNames
|
|
5812
|
-
.map((dependentParameterName) => `\`{${dependentParameterName}}\``)
|
|
5813
|
-
.join(' and ')}`)
|
|
5814
|
-
.join('\n'))}
|
|
5815
|
-
|
|
5816
|
-
**Resolved:**
|
|
5817
|
-
${block(resolvedParameterNames
|
|
5818
|
-
.filter((name) => !RESERVED_PARAMETER_NAMES.includes(name))
|
|
5819
|
-
.map((name) => `- Parameter \`{${name}}\``)
|
|
5820
|
-
.join('\n'))}
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
**Reserved (which are available):**
|
|
5824
|
-
${block(resolvedParameterNames
|
|
5825
|
-
.filter((name) => RESERVED_PARAMETER_NAMES.includes(name))
|
|
5826
|
-
.map((name) => `- Parameter \`{${name}}\``)
|
|
5827
|
-
.join('\n'))}
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
`));
|
|
6158
|
+
function validatePipeline_InnerFunction(pipeline) {
|
|
6159
|
+
// TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
|
|
6160
|
+
const context = createPipelineValidationContext(pipeline);
|
|
6161
|
+
validatePipelineMetadata(context);
|
|
6162
|
+
validatePipelineCollectionsStructure(context);
|
|
6163
|
+
validatePipelineParameters(context);
|
|
6164
|
+
validatePipelineTasks(context);
|
|
6165
|
+
validatePipelineDependencyResolution(context);
|
|
6166
|
+
// Note: Check that formfactor is corresponding to the pipeline interface
|
|
6167
|
+
// TODO: !!6 Implement this
|
|
6168
|
+
// pipeline.formfactorName
|
|
5831
6169
|
}
|
|
5832
6170
|
/**
|
|
5833
6171
|
* TODO: [🧞♀️] Do not allow joker + foreach
|
|
@@ -14147,7 +14485,7 @@ class MessageSuffixCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
14147
14485
|
* META commitment definition
|
|
14148
14486
|
*
|
|
14149
14487
|
* The META commitment handles all meta-information about the agent such as:
|
|
14150
|
-
* - META AVATAR: Sets the agent's built-in default avatar visual
|
|
14488
|
+
* - META AVATAR / META VISUAL: Sets the agent's built-in default avatar visual
|
|
14151
14489
|
* - META IMAGE: Sets the agent's avatar/profile image URL
|
|
14152
14490
|
* - META LINK: Provides profile/source links for the person the agent models
|
|
14153
14491
|
* - META DOMAIN: Sets the canonical custom domain/host of the agent
|
|
@@ -14162,7 +14500,7 @@ class MessageSuffixCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
14162
14500
|
* Example usage in agent source:
|
|
14163
14501
|
*
|
|
14164
14502
|
* ```book
|
|
14165
|
-
* META
|
|
14503
|
+
* META VISUAL pixel-art
|
|
14166
14504
|
* META IMAGE https://example.com/avatar.jpg
|
|
14167
14505
|
* META LINK https://twitter.com/username
|
|
14168
14506
|
* META DOMAIN my-agent.com
|
|
@@ -14202,7 +14540,7 @@ class MetaCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
14202
14540
|
|
|
14203
14541
|
## Supported META types
|
|
14204
14542
|
|
|
14205
|
-
- **META AVATAR** - Sets the agent's built-in default avatar visual
|
|
14543
|
+
- **META AVATAR** / **META VISUAL** - Sets the agent's built-in default avatar visual
|
|
14206
14544
|
- **META IMAGE** - Sets the agent's avatar/profile image URL
|
|
14207
14545
|
- **META LINK** - Provides profile/source links for the person the agent models
|
|
14208
14546
|
- **META DOMAIN** - Sets the canonical custom domain/host of the agent
|
|
@@ -14226,7 +14564,7 @@ class MetaCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
14226
14564
|
\`\`\`book
|
|
14227
14565
|
Professional Assistant
|
|
14228
14566
|
|
|
14229
|
-
META
|
|
14567
|
+
META VISUAL octopus3
|
|
14230
14568
|
META IMAGE https://example.com/professional-avatar.jpg
|
|
14231
14569
|
META TITLE Senior Business Consultant
|
|
14232
14570
|
META DESCRIPTION Specialized in strategic planning and project management
|
|
@@ -17397,452 +17735,13 @@ function formatAlphaHex$1(opacity) {
|
|
|
17397
17735
|
.padStart(2, '0');
|
|
17398
17736
|
}
|
|
17399
17737
|
|
|
17400
|
-
/* eslint-disable no-magic-numbers */
|
|
17401
|
-
/**
|
|
17402
|
-
* Light direction used by the organic 3D octopus shading.
|
|
17403
|
-
*
|
|
17404
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17405
|
-
*/
|
|
17406
|
-
const LIGHT_DIRECTION$3 = normalizeVector3({
|
|
17407
|
-
x: 0.48,
|
|
17408
|
-
y: -0.62,
|
|
17409
|
-
z: 0.94,
|
|
17410
|
-
});
|
|
17411
|
-
/**
|
|
17412
|
-
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
17413
|
-
*
|
|
17414
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17415
|
-
*/
|
|
17416
|
-
const octopus3dStableStateCache = new WeakMap();
|
|
17417
|
-
/**
|
|
17418
|
-
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
17419
|
-
*
|
|
17420
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17421
|
-
*/
|
|
17422
|
-
function getOctopus3dStableState(createRandom) {
|
|
17423
|
-
const cached = octopus3dStableStateCache.get(createRandom);
|
|
17424
|
-
if (cached !== undefined) {
|
|
17425
|
-
return cached;
|
|
17426
|
-
}
|
|
17427
|
-
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
17428
|
-
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
17429
|
-
const leftEyePhaseOffset = eyeRandom() * 0.6;
|
|
17430
|
-
const rightEyePhaseOffset = eyeRandom() * 0.6;
|
|
17431
|
-
const state = {
|
|
17432
|
-
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
17433
|
-
animationPhase: animationRandom() * Math.PI * 2,
|
|
17434
|
-
leftEyePhaseOffset,
|
|
17435
|
-
rightEyePhaseOffset,
|
|
17436
|
-
};
|
|
17437
|
-
octopus3dStableStateCache.set(createRandom, state);
|
|
17438
|
-
return state;
|
|
17439
|
-
}
|
|
17440
|
-
/**
|
|
17441
|
-
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
17442
|
-
*
|
|
17443
|
-
* @private built-in avatar visual
|
|
17444
|
-
*/
|
|
17445
|
-
const octopus3dAvatarVisual = {
|
|
17446
|
-
id: 'octopus3d',
|
|
17447
|
-
title: 'Octopus 3D',
|
|
17448
|
-
description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
|
|
17449
|
-
isAnimated: true,
|
|
17450
|
-
supportsPointerTracking: true,
|
|
17451
|
-
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
17452
|
-
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
|
|
17453
|
-
const sceneCenterX = size * 0.5;
|
|
17454
|
-
const sceneCenterY = size * 0.56;
|
|
17455
|
-
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
17456
|
-
const mantleCenter = {
|
|
17457
|
-
x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
|
|
17458
|
-
y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
17459
|
-
z: interaction.intensity * size * 0.012,
|
|
17460
|
-
};
|
|
17461
|
-
const underbodyCenter = {
|
|
17462
|
-
x: mantleCenter.x * 0.86,
|
|
17463
|
-
y: mantleCenter.y + size * 0.168,
|
|
17464
|
-
z: mantleCenter.z - size * 0.018,
|
|
17465
|
-
};
|
|
17466
|
-
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
17467
|
-
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
17468
|
-
const mantleRadiusZ = size *
|
|
17469
|
-
morphologyProfile.body.bodyRadiusRatio *
|
|
17470
|
-
(0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
17471
|
-
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
17472
|
-
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
17473
|
-
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
17474
|
-
const bodyYaw = -0.18 +
|
|
17475
|
-
Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
|
|
17476
|
-
interaction.bodyOffsetX * 0.18 +
|
|
17477
|
-
interaction.gazeX * 0.22;
|
|
17478
|
-
const bodyPitch = -0.08 +
|
|
17479
|
-
Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
|
|
17480
|
-
interaction.bodyOffsetY * 0.08 -
|
|
17481
|
-
interaction.gazeY * 0.08;
|
|
17482
|
-
const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
|
|
17483
|
-
const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
|
|
17484
|
-
const mantlePatches = resolveVisibleEllipsoidPatches({
|
|
17485
|
-
center: mantleCenter,
|
|
17486
|
-
radiusX: mantleRadiusX,
|
|
17487
|
-
radiusY: mantleRadiusY,
|
|
17488
|
-
radiusZ: mantleRadiusZ,
|
|
17489
|
-
rotationX: headPitch,
|
|
17490
|
-
rotationY: headYaw,
|
|
17491
|
-
sceneCenterX,
|
|
17492
|
-
sceneCenterY,
|
|
17493
|
-
size,
|
|
17494
|
-
palette,
|
|
17495
|
-
verticalColorBias: 0,
|
|
17496
|
-
outlineColor: `${palette.highlight}7a`,
|
|
17497
|
-
});
|
|
17498
|
-
const underbodyPatches = resolveVisibleEllipsoidPatches({
|
|
17499
|
-
center: underbodyCenter,
|
|
17500
|
-
radiusX: underbodyRadiusX,
|
|
17501
|
-
radiusY: underbodyRadiusY,
|
|
17502
|
-
radiusZ: underbodyRadiusZ,
|
|
17503
|
-
rotationX: bodyPitch,
|
|
17504
|
-
rotationY: bodyYaw,
|
|
17505
|
-
sceneCenterX,
|
|
17506
|
-
sceneCenterY,
|
|
17507
|
-
size,
|
|
17508
|
-
palette,
|
|
17509
|
-
verticalColorBias: 0.18,
|
|
17510
|
-
outlineColor: `${palette.shadow}8f`,
|
|
17511
|
-
});
|
|
17512
|
-
const tentacleStrokes = createOctopusTentacleStrokes({
|
|
17513
|
-
createRandom,
|
|
17514
|
-
morphologyProfile,
|
|
17515
|
-
timeMs,
|
|
17516
|
-
size,
|
|
17517
|
-
center: underbodyCenter,
|
|
17518
|
-
radiusX: underbodyRadiusX,
|
|
17519
|
-
radiusY: underbodyRadiusY,
|
|
17520
|
-
radiusZ: underbodyRadiusZ,
|
|
17521
|
-
rotationX: bodyPitch,
|
|
17522
|
-
rotationY: bodyYaw,
|
|
17523
|
-
sceneCenterX,
|
|
17524
|
-
sceneCenterY,
|
|
17525
|
-
animationPhase,
|
|
17526
|
-
});
|
|
17527
|
-
const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
|
|
17528
|
-
const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
|
|
17529
|
-
const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
|
|
17530
|
-
const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
|
|
17531
|
-
const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
|
|
17532
|
-
const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
|
|
17533
|
-
drawAvatarFrame(context, size, palette);
|
|
17534
|
-
drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
17535
|
-
drawOctopus3dShadow(context, size, palette, interaction, timeMs);
|
|
17536
|
-
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
|
|
17537
|
-
drawTentacleStroke(context, tentacleStroke, palette);
|
|
17538
|
-
}
|
|
17539
|
-
for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
17540
|
-
drawSurfacePatch(context, surfacePatch);
|
|
17541
|
-
}
|
|
17542
|
-
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
17543
|
-
drawTentacleStroke(context, tentacleStroke, palette);
|
|
17544
|
-
}
|
|
17545
|
-
drawProjectedOrganicEye(context, {
|
|
17546
|
-
x: -faceEyeSpacing,
|
|
17547
|
-
y: faceEyeYOffset,
|
|
17548
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
17549
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
17550
|
-
drawProjectedOrganicEye(context, {
|
|
17551
|
-
x: faceEyeSpacing,
|
|
17552
|
-
y: faceEyeYOffset,
|
|
17553
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
17554
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
17555
|
-
drawProjectedOrganicMouth(context, [
|
|
17556
|
-
{
|
|
17557
|
-
x: -mouthHalfWidth,
|
|
17558
|
-
y: mouthY,
|
|
17559
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY),
|
|
17560
|
-
},
|
|
17561
|
-
{
|
|
17562
|
-
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
17563
|
-
y: mouthY +
|
|
17564
|
-
size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
|
|
17565
|
-
Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
|
|
17566
|
-
interaction.gazeY * size * 0.01,
|
|
17567
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
17568
|
-
},
|
|
17569
|
-
{
|
|
17570
|
-
x: mouthHalfWidth,
|
|
17571
|
-
y: mouthY,
|
|
17572
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY),
|
|
17573
|
-
},
|
|
17574
|
-
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
17575
|
-
},
|
|
17576
|
-
};
|
|
17577
|
-
/**
|
|
17578
|
-
* Draws the atmospheric underwater glow behind the octopus mesh.
|
|
17579
|
-
*
|
|
17580
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17581
|
-
*/
|
|
17582
|
-
function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
17583
|
-
const glowGradient = context.createRadialGradient(sceneCenterX + interaction.gazeX * size * 0.1, sceneCenterY - size * 0.2 + interaction.gazeY * size * 0.05, size * 0.04, sceneCenterX, sceneCenterY - size * 0.04, size * 0.62);
|
|
17584
|
-
glowGradient.addColorStop(0, `${palette.highlight}5c`);
|
|
17585
|
-
glowGradient.addColorStop(0.36, `${palette.accent}24`);
|
|
17586
|
-
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
17587
|
-
context.fillStyle = glowGradient;
|
|
17588
|
-
context.fillRect(0, 0, size, size);
|
|
17589
|
-
const lowerGradient = context.createRadialGradient(sceneCenterX + Math.sin(timeMs / 1700) * size * 0.05, sceneCenterY + size * 0.23, size * 0.08, sceneCenterX, sceneCenterY + size * 0.28, size * 0.5);
|
|
17590
|
-
lowerGradient.addColorStop(0, `${palette.secondary}1d`);
|
|
17591
|
-
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
17592
|
-
context.fillStyle = lowerGradient;
|
|
17593
|
-
context.fillRect(0, 0, size, size);
|
|
17594
|
-
}
|
|
17595
|
-
/**
|
|
17596
|
-
* Draws the soft ground shadow below the octopus.
|
|
17597
|
-
*
|
|
17598
|
-
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
17599
|
-
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
17600
|
-
*
|
|
17601
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17602
|
-
*/
|
|
17603
|
-
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
17604
|
-
const cx = size * 0.5 + interaction.gazeX * size * 0.04;
|
|
17605
|
-
const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
|
|
17606
|
-
const rx = size * (0.18 + interaction.intensity * 0.02);
|
|
17607
|
-
const ry = size * 0.06;
|
|
17608
|
-
context.save();
|
|
17609
|
-
context.translate(cx, cy);
|
|
17610
|
-
context.scale(1, ry / rx);
|
|
17611
|
-
const blurRadius = rx * 1.4;
|
|
17612
|
-
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
17613
|
-
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
17614
|
-
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
17615
|
-
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
17616
|
-
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
17617
|
-
context.fillStyle = shadowGradient;
|
|
17618
|
-
context.beginPath();
|
|
17619
|
-
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
17620
|
-
context.fill();
|
|
17621
|
-
context.restore();
|
|
17622
|
-
}
|
|
17623
|
-
/**
|
|
17624
|
-
* Resolves visible projected patches for one rotated ellipsoid mesh.
|
|
17625
|
-
*
|
|
17626
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17627
|
-
*/
|
|
17628
|
-
function resolveVisibleEllipsoidPatches(options) {
|
|
17629
|
-
const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
|
|
17630
|
-
const latitudePatchCount = 10;
|
|
17631
|
-
const longitudePatchCount = 18;
|
|
17632
|
-
const surfacePatches = [];
|
|
17633
|
-
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
17634
|
-
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
17635
|
-
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
17636
|
-
const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
|
|
17637
|
-
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
17638
|
-
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
17639
|
-
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
17640
|
-
const localCorners = [
|
|
17641
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
|
|
17642
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
|
|
17643
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
|
|
17644
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
|
|
17645
|
-
];
|
|
17646
|
-
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
17647
|
-
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
17648
|
-
if (surfaceNormal.z <= 0.01) {
|
|
17649
|
-
continue;
|
|
17650
|
-
}
|
|
17651
|
-
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
17652
|
-
surfacePatches.push({
|
|
17653
|
-
corners: projectedCorners,
|
|
17654
|
-
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
17655
|
-
transformedCorners.length,
|
|
17656
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$3), -1, 1),
|
|
17657
|
-
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
17658
|
-
outlineColor,
|
|
17659
|
-
});
|
|
17660
|
-
}
|
|
17661
|
-
}
|
|
17662
|
-
return surfacePatches;
|
|
17663
|
-
}
|
|
17664
|
-
/**
|
|
17665
|
-
* Samples one point on an ellipsoid aligned to the local axes.
|
|
17666
|
-
*
|
|
17667
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17668
|
-
*/
|
|
17669
|
-
function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
|
|
17670
|
-
const cosineLatitude = Math.cos(latitude);
|
|
17671
|
-
return {
|
|
17672
|
-
x: Math.sin(longitude) * cosineLatitude * radiusX,
|
|
17673
|
-
y: Math.sin(latitude) * radiusY,
|
|
17674
|
-
z: Math.cos(longitude) * cosineLatitude * radiusZ,
|
|
17675
|
-
};
|
|
17676
|
-
}
|
|
17677
|
-
/**
|
|
17678
|
-
* Resolves one base fill tone for a surface patch across the octopus body.
|
|
17679
|
-
*
|
|
17680
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17681
|
-
*/
|
|
17682
|
-
function resolveSurfacePatchFillStyle(palette, verticalProgress) {
|
|
17683
|
-
const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
|
|
17684
|
-
if (clampedVerticalProgress < 0.2) {
|
|
17685
|
-
return palette.highlight;
|
|
17686
|
-
}
|
|
17687
|
-
if (clampedVerticalProgress < 0.45) {
|
|
17688
|
-
return palette.secondary;
|
|
17689
|
-
}
|
|
17690
|
-
if (clampedVerticalProgress < 0.8) {
|
|
17691
|
-
return palette.primary;
|
|
17692
|
-
}
|
|
17693
|
-
return `${palette.shadow}f2`;
|
|
17694
|
-
}
|
|
17695
|
-
/**
|
|
17696
|
-
* Draws one projected mesh patch with organic shading.
|
|
17697
|
-
*
|
|
17698
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17699
|
-
*/
|
|
17700
|
-
function drawSurfacePatch(context, surfacePatch) {
|
|
17701
|
-
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
17702
|
-
if (surfacePatch.lightIntensity > 0) {
|
|
17703
|
-
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
|
|
17704
|
-
}
|
|
17705
|
-
else if (surfacePatch.lightIntensity < 0) {
|
|
17706
|
-
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
17707
|
-
}
|
|
17708
|
-
context.save();
|
|
17709
|
-
context.beginPath();
|
|
17710
|
-
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
17711
|
-
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
17712
|
-
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
17713
|
-
}
|
|
17714
|
-
context.closePath();
|
|
17715
|
-
context.strokeStyle = surfacePatch.outlineColor;
|
|
17716
|
-
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
|
|
17717
|
-
context.lineJoin = 'round';
|
|
17718
|
-
context.stroke();
|
|
17719
|
-
context.restore();
|
|
17720
|
-
}
|
|
17721
|
-
/**
|
|
17722
|
-
* Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
|
|
17723
|
-
*
|
|
17724
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17725
|
-
*/
|
|
17726
|
-
function createOctopusTentacleStrokes(options) {
|
|
17727
|
-
const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
|
|
17728
|
-
return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
|
|
17729
|
-
const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
|
|
17730
|
-
const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
|
|
17731
|
-
const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
|
|
17732
|
-
const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
|
|
17733
|
-
const lateralReach = size *
|
|
17734
|
-
(0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
|
|
17735
|
-
const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
|
|
17736
|
-
const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
|
|
17737
|
-
const anchorPoint = {
|
|
17738
|
-
x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
|
|
17739
|
-
y: radiusY * (0.22 + tentacleRandom() * 0.18),
|
|
17740
|
-
z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
|
|
17741
|
-
};
|
|
17742
|
-
const controlPointOne = {
|
|
17743
|
-
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
|
|
17744
|
-
y: anchorPoint.y + flowLength * 0.26,
|
|
17745
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
17746
|
-
};
|
|
17747
|
-
const controlPointTwo = {
|
|
17748
|
-
x: anchorPoint.x +
|
|
17749
|
-
Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
17750
|
-
y: anchorPoint.y + flowLength * 0.66,
|
|
17751
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
17752
|
-
};
|
|
17753
|
-
const endPoint = {
|
|
17754
|
-
x: anchorPoint.x +
|
|
17755
|
-
Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
|
|
17756
|
-
sway * size * 0.028,
|
|
17757
|
-
y: anchorPoint.y + flowLength,
|
|
17758
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
|
|
17759
|
-
};
|
|
17760
|
-
const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
|
|
17761
|
-
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
17762
|
-
const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
|
|
17763
|
-
return {
|
|
17764
|
-
projectedPoints,
|
|
17765
|
-
averageDepth,
|
|
17766
|
-
isFrontFacing: averageDepth >= center.z - size * 0.006,
|
|
17767
|
-
baseWidth: size *
|
|
17768
|
-
(0.019 +
|
|
17769
|
-
morphologyProfile.tentacles.baseWidthScale * 0.007 +
|
|
17770
|
-
tentacleRandom() * 0.003 +
|
|
17771
|
-
Math.abs(Math.sin(orbitAngle)) * 0.002),
|
|
17772
|
-
tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
|
|
17773
|
-
colorBias: tentacleRandom(),
|
|
17774
|
-
};
|
|
17775
|
-
});
|
|
17776
|
-
}
|
|
17777
|
-
/**
|
|
17778
|
-
* Samples one point on a cubic Bezier curve in 3D.
|
|
17779
|
-
*
|
|
17780
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17781
|
-
*/
|
|
17782
|
-
function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
|
|
17783
|
-
const inverseProgress = 1 - progress;
|
|
17784
|
-
return {
|
|
17785
|
-
x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
|
|
17786
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
|
|
17787
|
-
3 * inverseProgress * progress * progress * controlPointTwo.x +
|
|
17788
|
-
progress * progress * progress * endPoint.x,
|
|
17789
|
-
y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
|
|
17790
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
|
|
17791
|
-
3 * inverseProgress * progress * progress * controlPointTwo.y +
|
|
17792
|
-
progress * progress * progress * endPoint.y,
|
|
17793
|
-
z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
|
|
17794
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
|
|
17795
|
-
3 * inverseProgress * progress * progress * controlPointTwo.z +
|
|
17796
|
-
progress * progress * progress * endPoint.z,
|
|
17797
|
-
};
|
|
17798
|
-
}
|
|
17799
|
-
/**
|
|
17800
|
-
* Draws one projected tentacle stroke with a slim highlight ridge.
|
|
17801
|
-
*
|
|
17802
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17803
|
-
*/
|
|
17804
|
-
function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
17805
|
-
const projectedSegments = tentacleStroke.projectedPoints.length - 1;
|
|
17806
|
-
for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
|
|
17807
|
-
const startPoint = tentacleStroke.projectedPoints[segmentIndex];
|
|
17808
|
-
const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
|
|
17809
|
-
const progress = segmentIndex / projectedSegments;
|
|
17810
|
-
const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
|
|
17811
|
-
context.beginPath();
|
|
17812
|
-
context.moveTo(startPoint.x, startPoint.y);
|
|
17813
|
-
context.lineTo(endPoint.x, endPoint.y);
|
|
17814
|
-
context.strokeStyle = tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
17815
|
-
context.lineWidth = width;
|
|
17816
|
-
context.lineCap = 'round';
|
|
17817
|
-
context.stroke();
|
|
17818
|
-
context.beginPath();
|
|
17819
|
-
context.moveTo(startPoint.x, startPoint.y);
|
|
17820
|
-
context.lineTo(endPoint.x, endPoint.y);
|
|
17821
|
-
context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
|
|
17822
|
-
context.lineWidth = Math.max(1, width * 0.34);
|
|
17823
|
-
context.lineCap = 'round';
|
|
17824
|
-
context.stroke();
|
|
17825
|
-
}
|
|
17826
|
-
}
|
|
17827
|
-
/**
|
|
17828
|
-
* Resolves the front surface depth on an ellipsoid for one local face point.
|
|
17829
|
-
*
|
|
17830
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17831
|
-
*/
|
|
17832
|
-
function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
17833
|
-
const normalizedX = x / radiusX;
|
|
17834
|
-
const normalizedY = y / radiusY;
|
|
17835
|
-
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
17836
|
-
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
17837
|
-
}
|
|
17838
|
-
|
|
17839
17738
|
/* eslint-disable no-magic-numbers */
|
|
17840
17739
|
/**
|
|
17841
17740
|
* Light direction used by the single-mesh octopus shading.
|
|
17842
17741
|
*
|
|
17843
17742
|
* @private helper of `octopus3d2AvatarVisual`
|
|
17844
17743
|
*/
|
|
17845
|
-
const LIGHT_DIRECTION$
|
|
17744
|
+
const LIGHT_DIRECTION$3 = normalizeVector3({
|
|
17846
17745
|
x: 0.38,
|
|
17847
17746
|
y: -0.6,
|
|
17848
17747
|
z: 0.98,
|
|
@@ -18081,7 +17980,7 @@ function resolveVisibleBlobbyOctopusPatches(options) {
|
|
|
18081
17980
|
transformedCorners[2].z +
|
|
18082
17981
|
transformedCorners[3].z) /
|
|
18083
17982
|
4,
|
|
18084
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$
|
|
17983
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$3), -1, 1),
|
|
18085
17984
|
fillStyle: resolveBlobbySurfacePatchFillStyle$1(palette, verticalProgress, Math.max(0, Math.cos(centerLongitude)), resolveLowerLobeWave(centerLongitude, morphologyProfile, animationPhase, timeMs)),
|
|
18086
17985
|
outlineColor: verticalProgress < 0.58 ? `${palette.highlight}73` : `${palette.shadow}8a`,
|
|
18087
17986
|
});
|
|
@@ -18196,7 +18095,7 @@ function drawBlobbySurfacePatch(context, surfacePatch) {
|
|
|
18196
18095
|
*
|
|
18197
18096
|
* @private helper of `octopus3d3AvatarVisual`
|
|
18198
18097
|
*/
|
|
18199
|
-
const LIGHT_DIRECTION$
|
|
18098
|
+
const LIGHT_DIRECTION$2 = normalizeVector3({
|
|
18200
18099
|
x: 0.34,
|
|
18201
18100
|
y: -0.62,
|
|
18202
18101
|
z: 1,
|
|
@@ -18503,7 +18402,7 @@ function resolveVisibleContinuousOctopusPatches(options) {
|
|
|
18503
18402
|
transformedCorners[2].z +
|
|
18504
18403
|
transformedCorners[3].z) /
|
|
18505
18404
|
4,
|
|
18506
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$
|
|
18405
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$2), -1, 1),
|
|
18507
18406
|
fillStyle: resolveContinuousSurfacePatchFillStyle(palette, verticalProgress, cachedCosByPatchCenterLongitude[longitudeIndex], cachedTentacleInfluencesByPatchCenterLongitude[longitudeIndex].core, cachedLobeWavesByPatchCenterLongitude[longitudeIndex]),
|
|
18508
18407
|
outlineColor: verticalProgress < 0.54 ? `${palette.highlight}69` : `${palette.shadow}78`,
|
|
18509
18408
|
});
|
|
@@ -18818,7 +18717,7 @@ function smoothStep$1(edgeStart, edgeEnd, value) {
|
|
|
18818
18717
|
*
|
|
18819
18718
|
* @private helper of `octopus3d4AvatarVisual`
|
|
18820
18719
|
*/
|
|
18821
|
-
const LIGHT_DIRECTION = normalizeVector3({
|
|
18720
|
+
const LIGHT_DIRECTION$1 = normalizeVector3({
|
|
18822
18721
|
x: 0.32,
|
|
18823
18722
|
y: -0.66,
|
|
18824
18723
|
z: 1,
|
|
@@ -19164,7 +19063,7 @@ function resolveVisibleBlobbyContinuousPatches(options) {
|
|
|
19164
19063
|
projectScenePoint(transformedCorners[2], size, sceneCenterX, sceneCenterY),
|
|
19165
19064
|
projectScenePoint(transformedCorners[3], size, sceneCenterX, sceneCenterY),
|
|
19166
19065
|
];
|
|
19167
|
-
const lightIntensity = clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1);
|
|
19066
|
+
const lightIntensity = clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$1), -1, 1);
|
|
19168
19067
|
const rimLightIntensity = Math.pow(clampNumber$1(dotProduct3D(surfaceNormal, RIM_LIGHT_DIRECTION), 0, 1), 2.6);
|
|
19169
19068
|
surfacePatches.push({
|
|
19170
19069
|
corners: projectedCorners,
|
|
@@ -19563,6 +19462,445 @@ function formatAlphaHex(opacity) {
|
|
|
19563
19462
|
.padStart(2, '0');
|
|
19564
19463
|
}
|
|
19565
19464
|
|
|
19465
|
+
/* eslint-disable no-magic-numbers */
|
|
19466
|
+
/**
|
|
19467
|
+
* Light direction used by the organic 3D octopus shading.
|
|
19468
|
+
*
|
|
19469
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19470
|
+
*/
|
|
19471
|
+
const LIGHT_DIRECTION = normalizeVector3({
|
|
19472
|
+
x: 0.48,
|
|
19473
|
+
y: -0.62,
|
|
19474
|
+
z: 0.94,
|
|
19475
|
+
});
|
|
19476
|
+
/**
|
|
19477
|
+
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
19478
|
+
*
|
|
19479
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19480
|
+
*/
|
|
19481
|
+
const octopus3dStableStateCache = new WeakMap();
|
|
19482
|
+
/**
|
|
19483
|
+
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
19484
|
+
*
|
|
19485
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19486
|
+
*/
|
|
19487
|
+
function getOctopus3dStableState(createRandom) {
|
|
19488
|
+
const cached = octopus3dStableStateCache.get(createRandom);
|
|
19489
|
+
if (cached !== undefined) {
|
|
19490
|
+
return cached;
|
|
19491
|
+
}
|
|
19492
|
+
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
19493
|
+
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
19494
|
+
const leftEyePhaseOffset = eyeRandom() * 0.6;
|
|
19495
|
+
const rightEyePhaseOffset = eyeRandom() * 0.6;
|
|
19496
|
+
const state = {
|
|
19497
|
+
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
19498
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
19499
|
+
leftEyePhaseOffset,
|
|
19500
|
+
rightEyePhaseOffset,
|
|
19501
|
+
};
|
|
19502
|
+
octopus3dStableStateCache.set(createRandom, state);
|
|
19503
|
+
return state;
|
|
19504
|
+
}
|
|
19505
|
+
/**
|
|
19506
|
+
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
19507
|
+
*
|
|
19508
|
+
* @private built-in avatar visual
|
|
19509
|
+
*/
|
|
19510
|
+
const octopus3dAvatarVisual = {
|
|
19511
|
+
id: 'octopus3d',
|
|
19512
|
+
title: 'Octopus 3D',
|
|
19513
|
+
description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
|
|
19514
|
+
isAnimated: true,
|
|
19515
|
+
supportsPointerTracking: true,
|
|
19516
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
19517
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
|
|
19518
|
+
const sceneCenterX = size * 0.5;
|
|
19519
|
+
const sceneCenterY = size * 0.56;
|
|
19520
|
+
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
19521
|
+
const mantleCenter = {
|
|
19522
|
+
x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
|
|
19523
|
+
y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
19524
|
+
z: interaction.intensity * size * 0.012,
|
|
19525
|
+
};
|
|
19526
|
+
const underbodyCenter = {
|
|
19527
|
+
x: mantleCenter.x * 0.86,
|
|
19528
|
+
y: mantleCenter.y + size * 0.168,
|
|
19529
|
+
z: mantleCenter.z - size * 0.018,
|
|
19530
|
+
};
|
|
19531
|
+
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
19532
|
+
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
19533
|
+
const mantleRadiusZ = size *
|
|
19534
|
+
morphologyProfile.body.bodyRadiusRatio *
|
|
19535
|
+
(0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
19536
|
+
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
19537
|
+
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
19538
|
+
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
19539
|
+
const bodyYaw = -0.18 +
|
|
19540
|
+
Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
|
|
19541
|
+
interaction.bodyOffsetX * 0.18 +
|
|
19542
|
+
interaction.gazeX * 0.22;
|
|
19543
|
+
const bodyPitch = -0.08 +
|
|
19544
|
+
Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
|
|
19545
|
+
interaction.bodyOffsetY * 0.08 -
|
|
19546
|
+
interaction.gazeY * 0.08;
|
|
19547
|
+
const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
|
|
19548
|
+
const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
|
|
19549
|
+
const mantlePatches = resolveVisibleEllipsoidPatches({
|
|
19550
|
+
center: mantleCenter,
|
|
19551
|
+
radiusX: mantleRadiusX,
|
|
19552
|
+
radiusY: mantleRadiusY,
|
|
19553
|
+
radiusZ: mantleRadiusZ,
|
|
19554
|
+
rotationX: headPitch,
|
|
19555
|
+
rotationY: headYaw,
|
|
19556
|
+
sceneCenterX,
|
|
19557
|
+
sceneCenterY,
|
|
19558
|
+
size,
|
|
19559
|
+
palette,
|
|
19560
|
+
verticalColorBias: 0,
|
|
19561
|
+
outlineColor: `${palette.highlight}7a`,
|
|
19562
|
+
});
|
|
19563
|
+
const underbodyPatches = resolveVisibleEllipsoidPatches({
|
|
19564
|
+
center: underbodyCenter,
|
|
19565
|
+
radiusX: underbodyRadiusX,
|
|
19566
|
+
radiusY: underbodyRadiusY,
|
|
19567
|
+
radiusZ: underbodyRadiusZ,
|
|
19568
|
+
rotationX: bodyPitch,
|
|
19569
|
+
rotationY: bodyYaw,
|
|
19570
|
+
sceneCenterX,
|
|
19571
|
+
sceneCenterY,
|
|
19572
|
+
size,
|
|
19573
|
+
palette,
|
|
19574
|
+
verticalColorBias: 0.18,
|
|
19575
|
+
outlineColor: `${palette.shadow}8f`,
|
|
19576
|
+
});
|
|
19577
|
+
const tentacleStrokes = createOctopusTentacleStrokes({
|
|
19578
|
+
createRandom,
|
|
19579
|
+
morphologyProfile,
|
|
19580
|
+
timeMs,
|
|
19581
|
+
size,
|
|
19582
|
+
center: underbodyCenter,
|
|
19583
|
+
radiusX: underbodyRadiusX,
|
|
19584
|
+
radiusY: underbodyRadiusY,
|
|
19585
|
+
radiusZ: underbodyRadiusZ,
|
|
19586
|
+
rotationX: bodyPitch,
|
|
19587
|
+
rotationY: bodyYaw,
|
|
19588
|
+
sceneCenterX,
|
|
19589
|
+
sceneCenterY,
|
|
19590
|
+
animationPhase,
|
|
19591
|
+
});
|
|
19592
|
+
const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
|
|
19593
|
+
const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
|
|
19594
|
+
const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
|
|
19595
|
+
const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
|
|
19596
|
+
const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
|
|
19597
|
+
const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
|
|
19598
|
+
drawAvatarFrame(context, size, palette);
|
|
19599
|
+
drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
19600
|
+
drawOctopus3dShadow(context, size, palette, interaction, timeMs);
|
|
19601
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
|
|
19602
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
19603
|
+
}
|
|
19604
|
+
for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
19605
|
+
drawSurfacePatch(context, surfacePatch);
|
|
19606
|
+
}
|
|
19607
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
19608
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
19609
|
+
}
|
|
19610
|
+
drawProjectedOrganicEye(context, {
|
|
19611
|
+
x: -faceEyeSpacing,
|
|
19612
|
+
y: faceEyeYOffset,
|
|
19613
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
19614
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
19615
|
+
drawProjectedOrganicEye(context, {
|
|
19616
|
+
x: faceEyeSpacing,
|
|
19617
|
+
y: faceEyeYOffset,
|
|
19618
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
19619
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
19620
|
+
drawProjectedOrganicMouth(context, [
|
|
19621
|
+
{
|
|
19622
|
+
x: -mouthHalfWidth,
|
|
19623
|
+
y: mouthY,
|
|
19624
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY),
|
|
19625
|
+
},
|
|
19626
|
+
{
|
|
19627
|
+
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
19628
|
+
y: mouthY +
|
|
19629
|
+
size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
|
|
19630
|
+
Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
|
|
19631
|
+
interaction.gazeY * size * 0.01,
|
|
19632
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
19633
|
+
},
|
|
19634
|
+
{
|
|
19635
|
+
x: mouthHalfWidth,
|
|
19636
|
+
y: mouthY,
|
|
19637
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY),
|
|
19638
|
+
},
|
|
19639
|
+
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
19640
|
+
},
|
|
19641
|
+
};
|
|
19642
|
+
/**
|
|
19643
|
+
* Draws the atmospheric underwater glow behind the octopus mesh.
|
|
19644
|
+
*
|
|
19645
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19646
|
+
*/
|
|
19647
|
+
function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
19648
|
+
const glowGradient = context.createRadialGradient(sceneCenterX + interaction.gazeX * size * 0.1, sceneCenterY - size * 0.2 + interaction.gazeY * size * 0.05, size * 0.04, sceneCenterX, sceneCenterY - size * 0.04, size * 0.62);
|
|
19649
|
+
glowGradient.addColorStop(0, `${palette.highlight}5c`);
|
|
19650
|
+
glowGradient.addColorStop(0.36, `${palette.accent}24`);
|
|
19651
|
+
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
19652
|
+
context.fillStyle = glowGradient;
|
|
19653
|
+
context.fillRect(0, 0, size, size);
|
|
19654
|
+
const lowerGradient = context.createRadialGradient(sceneCenterX + Math.sin(timeMs / 1700) * size * 0.05, sceneCenterY + size * 0.23, size * 0.08, sceneCenterX, sceneCenterY + size * 0.28, size * 0.5);
|
|
19655
|
+
lowerGradient.addColorStop(0, `${palette.secondary}1d`);
|
|
19656
|
+
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
19657
|
+
context.fillStyle = lowerGradient;
|
|
19658
|
+
context.fillRect(0, 0, size, size);
|
|
19659
|
+
}
|
|
19660
|
+
/**
|
|
19661
|
+
* Draws the soft ground shadow below the octopus.
|
|
19662
|
+
*
|
|
19663
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
19664
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
19665
|
+
*
|
|
19666
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19667
|
+
*/
|
|
19668
|
+
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
19669
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.04;
|
|
19670
|
+
const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
|
|
19671
|
+
const rx = size * (0.18 + interaction.intensity * 0.02);
|
|
19672
|
+
const ry = size * 0.06;
|
|
19673
|
+
context.save();
|
|
19674
|
+
context.translate(cx, cy);
|
|
19675
|
+
context.scale(1, ry / rx);
|
|
19676
|
+
const blurRadius = rx * 1.4;
|
|
19677
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
19678
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
19679
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
19680
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
19681
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
19682
|
+
context.fillStyle = shadowGradient;
|
|
19683
|
+
context.beginPath();
|
|
19684
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
19685
|
+
context.fill();
|
|
19686
|
+
context.restore();
|
|
19687
|
+
}
|
|
19688
|
+
/**
|
|
19689
|
+
* Resolves visible projected patches for one rotated ellipsoid mesh.
|
|
19690
|
+
*
|
|
19691
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19692
|
+
*/
|
|
19693
|
+
function resolveVisibleEllipsoidPatches(options) {
|
|
19694
|
+
const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
|
|
19695
|
+
const latitudePatchCount = 10;
|
|
19696
|
+
const longitudePatchCount = 18;
|
|
19697
|
+
const surfacePatches = [];
|
|
19698
|
+
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
19699
|
+
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
19700
|
+
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
19701
|
+
const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
|
|
19702
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
19703
|
+
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
19704
|
+
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
19705
|
+
const localCorners = [
|
|
19706
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
|
|
19707
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
|
|
19708
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
|
|
19709
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
|
|
19710
|
+
];
|
|
19711
|
+
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
19712
|
+
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
19713
|
+
if (surfaceNormal.z <= 0.01) {
|
|
19714
|
+
continue;
|
|
19715
|
+
}
|
|
19716
|
+
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
19717
|
+
surfacePatches.push({
|
|
19718
|
+
corners: projectedCorners,
|
|
19719
|
+
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
19720
|
+
transformedCorners.length,
|
|
19721
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
19722
|
+
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
19723
|
+
outlineColor,
|
|
19724
|
+
});
|
|
19725
|
+
}
|
|
19726
|
+
}
|
|
19727
|
+
return surfacePatches;
|
|
19728
|
+
}
|
|
19729
|
+
/**
|
|
19730
|
+
* Samples one point on an ellipsoid aligned to the local axes.
|
|
19731
|
+
*
|
|
19732
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19733
|
+
*/
|
|
19734
|
+
function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
|
|
19735
|
+
const cosineLatitude = Math.cos(latitude);
|
|
19736
|
+
return {
|
|
19737
|
+
x: Math.sin(longitude) * cosineLatitude * radiusX,
|
|
19738
|
+
y: Math.sin(latitude) * radiusY,
|
|
19739
|
+
z: Math.cos(longitude) * cosineLatitude * radiusZ,
|
|
19740
|
+
};
|
|
19741
|
+
}
|
|
19742
|
+
/**
|
|
19743
|
+
* Resolves one base fill tone for a surface patch across the octopus body.
|
|
19744
|
+
*
|
|
19745
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19746
|
+
*/
|
|
19747
|
+
function resolveSurfacePatchFillStyle(palette, verticalProgress) {
|
|
19748
|
+
const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
|
|
19749
|
+
if (clampedVerticalProgress < 0.2) {
|
|
19750
|
+
return palette.highlight;
|
|
19751
|
+
}
|
|
19752
|
+
if (clampedVerticalProgress < 0.45) {
|
|
19753
|
+
return palette.secondary;
|
|
19754
|
+
}
|
|
19755
|
+
if (clampedVerticalProgress < 0.8) {
|
|
19756
|
+
return palette.primary;
|
|
19757
|
+
}
|
|
19758
|
+
return `${palette.shadow}f2`;
|
|
19759
|
+
}
|
|
19760
|
+
/**
|
|
19761
|
+
* Draws one projected mesh patch with organic shading.
|
|
19762
|
+
*
|
|
19763
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19764
|
+
*/
|
|
19765
|
+
function drawSurfacePatch(context, surfacePatch) {
|
|
19766
|
+
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
19767
|
+
if (surfacePatch.lightIntensity > 0) {
|
|
19768
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
|
|
19769
|
+
}
|
|
19770
|
+
else if (surfacePatch.lightIntensity < 0) {
|
|
19771
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
19772
|
+
}
|
|
19773
|
+
context.save();
|
|
19774
|
+
context.beginPath();
|
|
19775
|
+
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
19776
|
+
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
19777
|
+
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
19778
|
+
}
|
|
19779
|
+
context.closePath();
|
|
19780
|
+
context.strokeStyle = surfacePatch.outlineColor;
|
|
19781
|
+
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
|
|
19782
|
+
context.lineJoin = 'round';
|
|
19783
|
+
context.stroke();
|
|
19784
|
+
context.restore();
|
|
19785
|
+
}
|
|
19786
|
+
/**
|
|
19787
|
+
* Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
|
|
19788
|
+
*
|
|
19789
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19790
|
+
*/
|
|
19791
|
+
function createOctopusTentacleStrokes(options) {
|
|
19792
|
+
const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
|
|
19793
|
+
return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
|
|
19794
|
+
const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
|
|
19795
|
+
const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
|
|
19796
|
+
const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
|
|
19797
|
+
const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
|
|
19798
|
+
const lateralReach = size *
|
|
19799
|
+
(0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
|
|
19800
|
+
const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
|
|
19801
|
+
const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
|
|
19802
|
+
const anchorPoint = {
|
|
19803
|
+
x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
|
|
19804
|
+
y: radiusY * (0.22 + tentacleRandom() * 0.18),
|
|
19805
|
+
z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
|
|
19806
|
+
};
|
|
19807
|
+
const controlPointOne = {
|
|
19808
|
+
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
|
|
19809
|
+
y: anchorPoint.y + flowLength * 0.26,
|
|
19810
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
19811
|
+
};
|
|
19812
|
+
const controlPointTwo = {
|
|
19813
|
+
x: anchorPoint.x +
|
|
19814
|
+
Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
19815
|
+
y: anchorPoint.y + flowLength * 0.66,
|
|
19816
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
19817
|
+
};
|
|
19818
|
+
const endPoint = {
|
|
19819
|
+
x: anchorPoint.x +
|
|
19820
|
+
Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
|
|
19821
|
+
sway * size * 0.028,
|
|
19822
|
+
y: anchorPoint.y + flowLength,
|
|
19823
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
|
|
19824
|
+
};
|
|
19825
|
+
const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
|
|
19826
|
+
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
19827
|
+
const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
|
|
19828
|
+
return {
|
|
19829
|
+
projectedPoints,
|
|
19830
|
+
averageDepth,
|
|
19831
|
+
isFrontFacing: averageDepth >= center.z - size * 0.006,
|
|
19832
|
+
baseWidth: size *
|
|
19833
|
+
(0.019 +
|
|
19834
|
+
morphologyProfile.tentacles.baseWidthScale * 0.007 +
|
|
19835
|
+
tentacleRandom() * 0.003 +
|
|
19836
|
+
Math.abs(Math.sin(orbitAngle)) * 0.002),
|
|
19837
|
+
tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
|
|
19838
|
+
colorBias: tentacleRandom(),
|
|
19839
|
+
};
|
|
19840
|
+
});
|
|
19841
|
+
}
|
|
19842
|
+
/**
|
|
19843
|
+
* Samples one point on a cubic Bezier curve in 3D.
|
|
19844
|
+
*
|
|
19845
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19846
|
+
*/
|
|
19847
|
+
function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
|
|
19848
|
+
const inverseProgress = 1 - progress;
|
|
19849
|
+
return {
|
|
19850
|
+
x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
|
|
19851
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
|
|
19852
|
+
3 * inverseProgress * progress * progress * controlPointTwo.x +
|
|
19853
|
+
progress * progress * progress * endPoint.x,
|
|
19854
|
+
y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
|
|
19855
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
|
|
19856
|
+
3 * inverseProgress * progress * progress * controlPointTwo.y +
|
|
19857
|
+
progress * progress * progress * endPoint.y,
|
|
19858
|
+
z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
|
|
19859
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
|
|
19860
|
+
3 * inverseProgress * progress * progress * controlPointTwo.z +
|
|
19861
|
+
progress * progress * progress * endPoint.z,
|
|
19862
|
+
};
|
|
19863
|
+
}
|
|
19864
|
+
/**
|
|
19865
|
+
* Draws one projected tentacle stroke with a slim highlight ridge.
|
|
19866
|
+
*
|
|
19867
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19868
|
+
*/
|
|
19869
|
+
function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
19870
|
+
const projectedSegments = tentacleStroke.projectedPoints.length - 1;
|
|
19871
|
+
for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
|
|
19872
|
+
const startPoint = tentacleStroke.projectedPoints[segmentIndex];
|
|
19873
|
+
const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
|
|
19874
|
+
const progress = segmentIndex / projectedSegments;
|
|
19875
|
+
const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
|
|
19876
|
+
context.beginPath();
|
|
19877
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
19878
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
19879
|
+
context.strokeStyle = tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
19880
|
+
context.lineWidth = width;
|
|
19881
|
+
context.lineCap = 'round';
|
|
19882
|
+
context.stroke();
|
|
19883
|
+
context.beginPath();
|
|
19884
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
19885
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
19886
|
+
context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
|
|
19887
|
+
context.lineWidth = Math.max(1, width * 0.34);
|
|
19888
|
+
context.lineCap = 'round';
|
|
19889
|
+
context.stroke();
|
|
19890
|
+
}
|
|
19891
|
+
}
|
|
19892
|
+
/**
|
|
19893
|
+
* Resolves the front surface depth on an ellipsoid for one local face point.
|
|
19894
|
+
*
|
|
19895
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19896
|
+
*/
|
|
19897
|
+
function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
19898
|
+
const normalizedX = x / radiusX;
|
|
19899
|
+
const normalizedY = y / radiusY;
|
|
19900
|
+
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
19901
|
+
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
19902
|
+
}
|
|
19903
|
+
|
|
19566
19904
|
/* eslint-disable no-magic-numbers */
|
|
19567
19905
|
/**
|
|
19568
19906
|
* Octopus avatar visual.
|
|
@@ -20383,14 +20721,14 @@ function resolveAvatarVisualId(value) {
|
|
|
20383
20721
|
/**
|
|
20384
20722
|
* META AVATAR commitment definition
|
|
20385
20723
|
*
|
|
20386
|
-
* The `META AVATAR`
|
|
20387
|
-
* the agent does not provide an explicit `META IMAGE`.
|
|
20724
|
+
* The `META AVATAR` and `META VISUAL` commitments set the built-in default avatar visual
|
|
20725
|
+
* used when the agent does not provide an explicit `META IMAGE`.
|
|
20388
20726
|
*
|
|
20389
20727
|
* @private [🪔] Maybe export the commitments through some package
|
|
20390
20728
|
*/
|
|
20391
20729
|
class MetaAvatarCommitmentDefinition extends BaseCommitmentDefinition {
|
|
20392
|
-
constructor() {
|
|
20393
|
-
super(
|
|
20730
|
+
constructor(type = 'META AVATAR') {
|
|
20731
|
+
super(type);
|
|
20394
20732
|
}
|
|
20395
20733
|
/**
|
|
20396
20734
|
* Short one-line description of META AVATAR.
|
|
@@ -20410,14 +20748,15 @@ class MetaAvatarCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
20410
20748
|
get documentation() {
|
|
20411
20749
|
const supportedVisuals = AVATAR_VISUALS.map((avatarVisual) => `\`${avatarVisual.id}\``).join(', ');
|
|
20412
20750
|
return spaceTrim$1(`
|
|
20413
|
-
#
|
|
20751
|
+
# ${this.type}
|
|
20414
20752
|
|
|
20415
20753
|
Sets the built-in avatar visual used for the agent when no explicit \`META IMAGE\` is provided.
|
|
20754
|
+
\`META AVATAR\` and \`META VISUAL\` are equivalent.
|
|
20416
20755
|
|
|
20417
20756
|
## Key aspects
|
|
20418
20757
|
|
|
20419
20758
|
- Does not modify the agent's behavior or responses.
|
|
20420
|
-
- Only one \`META AVATAR\` should be used per agent.
|
|
20759
|
+
- Only one \`META AVATAR\` or \`META VISUAL\` should be used per agent.
|
|
20421
20760
|
- If multiple are specified, the last one takes precedence.
|
|
20422
20761
|
- Values are matched case-insensitively and spaces, hyphens, and underscores are normalized.
|
|
20423
20762
|
- Supported visuals are derived from the shared avatar registry: ${supportedVisuals}.
|
|
@@ -20432,15 +20771,15 @@ class MetaAvatarCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
20432
20771
|
\`\`\`
|
|
20433
20772
|
|
|
20434
20773
|
\`\`\`book
|
|
20435
|
-
|
|
20774
|
+
Minecraft Assistant
|
|
20436
20775
|
|
|
20437
|
-
META
|
|
20776
|
+
META VISUAL Minecraft2
|
|
20438
20777
|
GOAL Answer in a calm and focused way.
|
|
20439
20778
|
\`\`\`
|
|
20440
20779
|
`);
|
|
20441
20780
|
}
|
|
20442
20781
|
applyToAgentModelRequirements(requirements, content) {
|
|
20443
|
-
// META AVATAR
|
|
20782
|
+
// META AVATAR and META VISUAL don't modify the system message or model requirements.
|
|
20444
20783
|
// It's handled separately in the parsing logic for profile avatar resolution.
|
|
20445
20784
|
return requirements;
|
|
20446
20785
|
}
|
|
@@ -29628,6 +29967,7 @@ const COMMITMENT_REGISTRY = [
|
|
|
29628
29967
|
new ActionCommitmentDefinition('ACTIONS'),
|
|
29629
29968
|
new ComponentCommitmentDefinition(),
|
|
29630
29969
|
new MetaAvatarCommitmentDefinition(),
|
|
29970
|
+
new MetaAvatarCommitmentDefinition('META VISUAL'),
|
|
29631
29971
|
new MetaImageCommitmentDefinition(),
|
|
29632
29972
|
new MetaColorCommitmentDefinition(),
|
|
29633
29973
|
new MetaFontCommitmentDefinition(),
|
|
@@ -30979,6 +31319,7 @@ function hasHttpProtocol(value) {
|
|
|
30979
31319
|
*/
|
|
30980
31320
|
const META_COMMITMENT_APPLIERS = {
|
|
30981
31321
|
'META AVATAR': applyMetaAvatarContent,
|
|
31322
|
+
'META VISUAL': applyMetaAvatarContent,
|
|
30982
31323
|
'META LINK': applyMetaLinkContent,
|
|
30983
31324
|
'META DOMAIN': applyMetaDomainContent,
|
|
30984
31325
|
'META IMAGE': applyMetaImageContent,
|
|
@@ -31027,7 +31368,7 @@ function applyGenericMetaCommitment(state, content) {
|
|
|
31027
31368
|
state.meta[metaType] = metaValue;
|
|
31028
31369
|
}
|
|
31029
31370
|
/**
|
|
31030
|
-
* Applies META AVATAR content into the canonical `meta.avatar` field.
|
|
31371
|
+
* Applies META AVATAR / META VISUAL content into the canonical `meta.avatar` field.
|
|
31031
31372
|
*/
|
|
31032
31373
|
function applyMetaAvatarContent(state, content) {
|
|
31033
31374
|
const avatarVisualId = resolveAvatarVisualId(content);
|
|
@@ -32091,6 +32432,78 @@ function normalizeCliAgentFileSegment(value) {
|
|
|
32091
32432
|
.replace(/^[._-]+|[._-]+$/gu, '');
|
|
32092
32433
|
}
|
|
32093
32434
|
|
|
32435
|
+
/**
|
|
32436
|
+
* Helper of usage compute
|
|
32437
|
+
*
|
|
32438
|
+
* @param content the content of prompt or response
|
|
32439
|
+
* @returns part of UsageCounts
|
|
32440
|
+
*
|
|
32441
|
+
* @private internal utility of LlmExecutionTools
|
|
32442
|
+
*/
|
|
32443
|
+
function computeUsageCounts(content) {
|
|
32444
|
+
return {
|
|
32445
|
+
charactersCount: { value: countCharacters(content) },
|
|
32446
|
+
wordsCount: { value: countWords(content) },
|
|
32447
|
+
sentencesCount: { value: countSentences(content) },
|
|
32448
|
+
linesCount: { value: countLines(content) },
|
|
32449
|
+
paragraphsCount: { value: countParagraphs(content) },
|
|
32450
|
+
pagesCount: { value: countPages(content) },
|
|
32451
|
+
};
|
|
32452
|
+
}
|
|
32453
|
+
|
|
32454
|
+
/**
|
|
32455
|
+
* Computes the usage of the OpenAI API based on the response from OpenAI
|
|
32456
|
+
*
|
|
32457
|
+
* @param promptContent The content of the prompt
|
|
32458
|
+
* @param resultContent The content of the result (for embedding prompts or failed prompts pass empty string)
|
|
32459
|
+
* @param rawResponse The raw response from OpenAI API
|
|
32460
|
+
* @param duration The duration of the execution
|
|
32461
|
+
* @throws {PipelineExecutionError} If the usage is not defined in the response from OpenAI
|
|
32462
|
+
*
|
|
32463
|
+
* @private internal utility of `OpenAiExecutionTools`
|
|
32464
|
+
*/
|
|
32465
|
+
function computeOpenAiUsage(promptContent, // <- Note: Intentionally using [] to access type properties to bring jsdoc from Prompt/PromptResult to consumer
|
|
32466
|
+
resultContent, rawResponse, duration = ZERO_VALUE) {
|
|
32467
|
+
var _a, _b;
|
|
32468
|
+
if (rawResponse.usage === undefined) {
|
|
32469
|
+
throw new PipelineExecutionError('The usage is not defined in the response from OpenAI');
|
|
32470
|
+
}
|
|
32471
|
+
if (((_a = rawResponse.usage) === null || _a === void 0 ? void 0 : _a.prompt_tokens) === undefined) {
|
|
32472
|
+
throw new PipelineExecutionError('In OpenAI response `usage.prompt_tokens` not defined');
|
|
32473
|
+
}
|
|
32474
|
+
const inputTokens = rawResponse.usage.prompt_tokens;
|
|
32475
|
+
const outputTokens = ((_b = rawResponse.usage) === null || _b === void 0 ? void 0 : _b.completion_tokens) || 0;
|
|
32476
|
+
let isUncertain = false;
|
|
32477
|
+
let modelInfo = OPENAI_MODELS.find((model) => model.modelName === rawResponse.model);
|
|
32478
|
+
if (modelInfo === undefined) {
|
|
32479
|
+
// Note: Model is not in the list of known models, fallback to the family of the models and mark price as uncertain
|
|
32480
|
+
modelInfo = OPENAI_MODELS.find((model) => (rawResponse.model || SALT_NONCE).startsWith(model.modelName));
|
|
32481
|
+
if (modelInfo !== undefined) {
|
|
32482
|
+
isUncertain = true;
|
|
32483
|
+
}
|
|
32484
|
+
}
|
|
32485
|
+
let price;
|
|
32486
|
+
if (modelInfo === undefined || modelInfo.pricing === undefined) {
|
|
32487
|
+
price = uncertainNumber();
|
|
32488
|
+
}
|
|
32489
|
+
else {
|
|
32490
|
+
price = uncertainNumber(inputTokens * modelInfo.pricing.prompt + outputTokens * modelInfo.pricing.output, isUncertain);
|
|
32491
|
+
}
|
|
32492
|
+
return {
|
|
32493
|
+
price,
|
|
32494
|
+
duration,
|
|
32495
|
+
input: {
|
|
32496
|
+
tokensCount: uncertainNumber(rawResponse.usage.prompt_tokens),
|
|
32497
|
+
...computeUsageCounts(promptContent),
|
|
32498
|
+
},
|
|
32499
|
+
output: {
|
|
32500
|
+
tokensCount: uncertainNumber(outputTokens),
|
|
32501
|
+
...computeUsageCounts(resultContent),
|
|
32502
|
+
},
|
|
32503
|
+
};
|
|
32504
|
+
}
|
|
32505
|
+
// TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
|
|
32506
|
+
|
|
32094
32507
|
/**
|
|
32095
32508
|
* Simple wrapper `new Date().toISOString()`
|
|
32096
32509
|
*
|
|
@@ -32499,78 +32912,6 @@ class OpenAiAgentKitExecutionToolsToolBuilder {
|
|
|
32499
32912
|
}
|
|
32500
32913
|
}
|
|
32501
32914
|
|
|
32502
|
-
/**
|
|
32503
|
-
* Helper of usage compute
|
|
32504
|
-
*
|
|
32505
|
-
* @param content the content of prompt or response
|
|
32506
|
-
* @returns part of UsageCounts
|
|
32507
|
-
*
|
|
32508
|
-
* @private internal utility of LlmExecutionTools
|
|
32509
|
-
*/
|
|
32510
|
-
function computeUsageCounts(content) {
|
|
32511
|
-
return {
|
|
32512
|
-
charactersCount: { value: countCharacters(content) },
|
|
32513
|
-
wordsCount: { value: countWords(content) },
|
|
32514
|
-
sentencesCount: { value: countSentences(content) },
|
|
32515
|
-
linesCount: { value: countLines(content) },
|
|
32516
|
-
paragraphsCount: { value: countParagraphs(content) },
|
|
32517
|
-
pagesCount: { value: countPages(content) },
|
|
32518
|
-
};
|
|
32519
|
-
}
|
|
32520
|
-
|
|
32521
|
-
/**
|
|
32522
|
-
* Computes the usage of the OpenAI API based on the response from OpenAI
|
|
32523
|
-
*
|
|
32524
|
-
* @param promptContent The content of the prompt
|
|
32525
|
-
* @param resultContent The content of the result (for embedding prompts or failed prompts pass empty string)
|
|
32526
|
-
* @param rawResponse The raw response from OpenAI API
|
|
32527
|
-
* @param duration The duration of the execution
|
|
32528
|
-
* @throws {PipelineExecutionError} If the usage is not defined in the response from OpenAI
|
|
32529
|
-
*
|
|
32530
|
-
* @private internal utility of `OpenAiExecutionTools`
|
|
32531
|
-
*/
|
|
32532
|
-
function computeOpenAiUsage(promptContent, // <- Note: Intentionally using [] to access type properties to bring jsdoc from Prompt/PromptResult to consumer
|
|
32533
|
-
resultContent, rawResponse, duration = ZERO_VALUE) {
|
|
32534
|
-
var _a, _b;
|
|
32535
|
-
if (rawResponse.usage === undefined) {
|
|
32536
|
-
throw new PipelineExecutionError('The usage is not defined in the response from OpenAI');
|
|
32537
|
-
}
|
|
32538
|
-
if (((_a = rawResponse.usage) === null || _a === void 0 ? void 0 : _a.prompt_tokens) === undefined) {
|
|
32539
|
-
throw new PipelineExecutionError('In OpenAI response `usage.prompt_tokens` not defined');
|
|
32540
|
-
}
|
|
32541
|
-
const inputTokens = rawResponse.usage.prompt_tokens;
|
|
32542
|
-
const outputTokens = ((_b = rawResponse.usage) === null || _b === void 0 ? void 0 : _b.completion_tokens) || 0;
|
|
32543
|
-
let isUncertain = false;
|
|
32544
|
-
let modelInfo = OPENAI_MODELS.find((model) => model.modelName === rawResponse.model);
|
|
32545
|
-
if (modelInfo === undefined) {
|
|
32546
|
-
// Note: Model is not in the list of known models, fallback to the family of the models and mark price as uncertain
|
|
32547
|
-
modelInfo = OPENAI_MODELS.find((model) => (rawResponse.model || SALT_NONCE).startsWith(model.modelName));
|
|
32548
|
-
if (modelInfo !== undefined) {
|
|
32549
|
-
isUncertain = true;
|
|
32550
|
-
}
|
|
32551
|
-
}
|
|
32552
|
-
let price;
|
|
32553
|
-
if (modelInfo === undefined || modelInfo.pricing === undefined) {
|
|
32554
|
-
price = uncertainNumber();
|
|
32555
|
-
}
|
|
32556
|
-
else {
|
|
32557
|
-
price = uncertainNumber(inputTokens * modelInfo.pricing.prompt + outputTokens * modelInfo.pricing.output, isUncertain);
|
|
32558
|
-
}
|
|
32559
|
-
return {
|
|
32560
|
-
price,
|
|
32561
|
-
duration,
|
|
32562
|
-
input: {
|
|
32563
|
-
tokensCount: uncertainNumber(rawResponse.usage.prompt_tokens),
|
|
32564
|
-
...computeUsageCounts(promptContent),
|
|
32565
|
-
},
|
|
32566
|
-
output: {
|
|
32567
|
-
tokensCount: uncertainNumber(outputTokens),
|
|
32568
|
-
...computeUsageCounts(resultContent),
|
|
32569
|
-
},
|
|
32570
|
-
};
|
|
32571
|
-
}
|
|
32572
|
-
// TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
|
|
32573
|
-
|
|
32574
32915
|
/**
|
|
32575
32916
|
* Finds the best hardcoded-model match for one API-listed model identifier.
|
|
32576
32917
|
*/
|
|
@@ -43028,18 +43369,6 @@ async function $provideExecutablesForNode(options) {
|
|
|
43028
43369
|
const $llmToolsMetadataRegister = new $Register('llm_tools_metadata');
|
|
43029
43370
|
// TODO: [®] DRY Register logic
|
|
43030
43371
|
|
|
43031
|
-
/**
|
|
43032
|
-
* Register for LLM tools.
|
|
43033
|
-
*
|
|
43034
|
-
* Note: `$` is used to indicate that this interacts with the global scope
|
|
43035
|
-
*
|
|
43036
|
-
* @singleton Only one instance of each register is created per build, but there can be more instances across different builds or environments.
|
|
43037
|
-
*
|
|
43038
|
-
* @public exported from `@promptbook/core`
|
|
43039
|
-
*/
|
|
43040
|
-
const $llmToolsRegister = new $Register('llm_execution_tools_constructors');
|
|
43041
|
-
// TODO: [®] DRY Register logic
|
|
43042
|
-
|
|
43043
43372
|
/**
|
|
43044
43373
|
* Path to the `.env` file which was used to configure LLM tools
|
|
43045
43374
|
*
|
|
@@ -43047,61 +43376,53 @@ const $llmToolsRegister = new $Register('llm_execution_tools_constructors');
|
|
|
43047
43376
|
*/
|
|
43048
43377
|
let $usedEnvFilename = null;
|
|
43049
43378
|
/**
|
|
43050
|
-
*
|
|
43051
|
-
*
|
|
43052
|
-
* Note: `$` is used to indicate that this variable is making side effect
|
|
43053
|
-
*
|
|
43054
|
-
* @private internal log of `$provideLlmToolsConfigurationFromEnv` and `$registeredLlmToolsMessage`
|
|
43055
|
-
*/
|
|
43056
|
-
function $setUsedEnvFilename(filepath) {
|
|
43057
|
-
$usedEnvFilename = filepath;
|
|
43058
|
-
}
|
|
43059
|
-
/**
|
|
43060
|
-
* Creates a message with all registered LLM tools
|
|
43061
|
-
*
|
|
43062
|
-
* Note: This function is used to create a (error) message when there is no constructor for some LLM provider
|
|
43063
|
-
*
|
|
43064
|
-
* @private internal function of `createLlmToolsFromConfiguration` and `$provideLlmToolsFromEnv`
|
|
43065
|
-
*/
|
|
43066
|
-
function $registeredLlmToolsMessage() {
|
|
43067
|
-
const registeredLlmToolsMessageContext = createRegisteredLlmToolsMessageContext();
|
|
43068
|
-
if (registeredLlmToolsMessageContext.llmToolStatuses.length === 0) {
|
|
43069
|
-
return renderNoRegisteredLlmToolsMessage(registeredLlmToolsMessageContext.usedEnvMessage);
|
|
43070
|
-
}
|
|
43071
|
-
return renderRegisteredLlmToolsMessage(registeredLlmToolsMessageContext);
|
|
43072
|
-
}
|
|
43073
|
-
/**
|
|
43074
|
-
* Collects all state needed to render the provider summary.
|
|
43379
|
+
* Shared state for the `.env` file used to configure LLM tools.
|
|
43075
43380
|
*
|
|
43076
|
-
* @private internal
|
|
43381
|
+
* @private internal state of `$registeredLlmToolsMessage`
|
|
43077
43382
|
*/
|
|
43078
|
-
|
|
43079
|
-
|
|
43080
|
-
|
|
43081
|
-
|
|
43082
|
-
|
|
43083
|
-
|
|
43084
|
-
|
|
43085
|
-
|
|
43086
|
-
|
|
43087
|
-
|
|
43088
|
-
|
|
43383
|
+
const USED_ENV_FILENAME = {
|
|
43384
|
+
set(filepath) {
|
|
43385
|
+
$usedEnvFilename = filepath;
|
|
43386
|
+
},
|
|
43387
|
+
createMessage() {
|
|
43388
|
+
return $usedEnvFilename === null
|
|
43389
|
+
? `Unknown \`.env\` file`
|
|
43390
|
+
: spaceTrim$1(`
|
|
43391
|
+
Used \`.env\` file:
|
|
43392
|
+
${$usedEnvFilename}
|
|
43393
|
+
`);
|
|
43394
|
+
},
|
|
43395
|
+
};
|
|
43396
|
+
|
|
43089
43397
|
/**
|
|
43090
43398
|
* Reads environment variables relevant for provider configuration.
|
|
43091
43399
|
*
|
|
43092
|
-
* @private
|
|
43400
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43093
43401
|
*/
|
|
43094
|
-
function
|
|
43402
|
+
function getAvailableRegisteredLlmToolsEnvironmentVariables(isRunningInNode) {
|
|
43095
43403
|
if (isRunningInNode) {
|
|
43096
43404
|
return process.env;
|
|
43097
43405
|
// <- TODO: [⚛] Some DRY way how to get to `process.env` and pass it into functions - ACRY search for `env`
|
|
43098
43406
|
}
|
|
43099
43407
|
return {};
|
|
43100
43408
|
}
|
|
43409
|
+
|
|
43410
|
+
/**
|
|
43411
|
+
* Register for LLM tools.
|
|
43412
|
+
*
|
|
43413
|
+
* Note: `$` is used to indicate that this interacts with the global scope
|
|
43414
|
+
*
|
|
43415
|
+
* @singleton Only one instance of each register is created per build, but there can be more instances across different builds or environments.
|
|
43416
|
+
*
|
|
43417
|
+
* @public exported from `@promptbook/core`
|
|
43418
|
+
*/
|
|
43419
|
+
const $llmToolsRegister = new $Register('llm_execution_tools_constructors');
|
|
43420
|
+
// TODO: [®] DRY Register logic
|
|
43421
|
+
|
|
43101
43422
|
/**
|
|
43102
43423
|
* Takes stable snapshots of both LLM provider registers.
|
|
43103
43424
|
*
|
|
43104
|
-
* @private
|
|
43425
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43105
43426
|
*/
|
|
43106
43427
|
function getRegisteredLlmToolRegisters() {
|
|
43107
43428
|
return {
|
|
@@ -43109,62 +43430,30 @@ function getRegisteredLlmToolRegisters() {
|
|
|
43109
43430
|
registeredTools: $llmToolsRegister.list(),
|
|
43110
43431
|
};
|
|
43111
43432
|
}
|
|
43112
|
-
|
|
43113
|
-
* Lists provider entries enriched with installation and configuration state.
|
|
43114
|
-
*
|
|
43115
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43116
|
-
*/
|
|
43117
|
-
function listRegisteredLlmToolStatuses({ registeredMetadata, registeredTools }, env) {
|
|
43118
|
-
return listRegisteredLlmToolEntries(registeredMetadata, registeredTools).map((registeredLlmToolEntry) => createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env }));
|
|
43119
|
-
}
|
|
43120
|
-
/**
|
|
43121
|
-
* Merges provider entries from the metadata and constructor registers.
|
|
43122
|
-
*
|
|
43123
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43124
|
-
*/
|
|
43125
|
-
function listRegisteredLlmToolEntries(registeredMetadata, registeredTools) {
|
|
43126
|
-
const registeredLlmToolEntries = new Map();
|
|
43127
|
-
for (const { title, packageName, className, envVariables } of registeredMetadata) {
|
|
43128
|
-
addRegisteredLlmToolEntry(registeredLlmToolEntries, { title, packageName, className, envVariables });
|
|
43129
|
-
}
|
|
43130
|
-
for (const { packageName, className } of registeredTools) {
|
|
43131
|
-
addRegisteredLlmToolEntry(registeredLlmToolEntries, { packageName, className });
|
|
43132
|
-
}
|
|
43133
|
-
return [...registeredLlmToolEntries.values()];
|
|
43134
|
-
}
|
|
43135
|
-
/**
|
|
43136
|
-
* Adds a provider entry only when the provider is not already present.
|
|
43137
|
-
*
|
|
43138
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43139
|
-
*/
|
|
43140
|
-
function addRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43141
|
-
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43142
|
-
if (registeredLlmToolEntries.has(registeredLlmToolEntryKey)) {
|
|
43143
|
-
return;
|
|
43144
|
-
}
|
|
43145
|
-
registeredLlmToolEntries.set(registeredLlmToolEntryKey, registeredLlmToolEntry);
|
|
43146
|
-
}
|
|
43433
|
+
|
|
43147
43434
|
/**
|
|
43148
43435
|
* Creates a deduplication key for a provider entry.
|
|
43149
43436
|
*
|
|
43150
|
-
* @private
|
|
43437
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43151
43438
|
*/
|
|
43152
43439
|
function createRegisteredLlmToolEntryKey({ packageName, className }) {
|
|
43153
43440
|
return `${packageName}::${className}`;
|
|
43154
43441
|
}
|
|
43442
|
+
|
|
43155
43443
|
/**
|
|
43156
43444
|
* Checks whether the given provider entry already exists in the target register list.
|
|
43157
43445
|
*
|
|
43158
|
-
* @private
|
|
43446
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43159
43447
|
*/
|
|
43160
43448
|
function hasRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43161
43449
|
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43162
43450
|
return registeredLlmToolEntries.some((listedRegisteredLlmToolEntry) => createRegisteredLlmToolEntryKey(listedRegisteredLlmToolEntry) === registeredLlmToolEntryKey);
|
|
43163
43451
|
}
|
|
43452
|
+
|
|
43164
43453
|
/**
|
|
43165
43454
|
* Builds the runtime status for one provider entry.
|
|
43166
43455
|
*
|
|
43167
|
-
* @private
|
|
43456
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43168
43457
|
*/
|
|
43169
43458
|
function createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env, }) {
|
|
43170
43459
|
const availabilityStatus = createRegisteredLlmToolAvailabilityStatus(registeredLlmToolEntry, registeredMetadata, registeredTools);
|
|
@@ -43178,7 +43467,7 @@ function createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetad
|
|
|
43178
43467
|
/**
|
|
43179
43468
|
* Resolves whether the provider has metadata and a registered constructor.
|
|
43180
43469
|
*
|
|
43181
|
-
* @private
|
|
43470
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43182
43471
|
*/
|
|
43183
43472
|
function createRegisteredLlmToolAvailabilityStatus(registeredLlmToolEntry, registeredMetadata, registeredTools) {
|
|
43184
43473
|
return {
|
|
@@ -43189,7 +43478,7 @@ function createRegisteredLlmToolAvailabilityStatus(registeredLlmToolEntry, regis
|
|
|
43189
43478
|
/**
|
|
43190
43479
|
* Resolves whether the provider has enough environment variables to be configured.
|
|
43191
43480
|
*
|
|
43192
|
-
* @private
|
|
43481
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43193
43482
|
*/
|
|
43194
43483
|
function createRegisteredLlmToolConfigurationStatus({ envVariables }, env) {
|
|
43195
43484
|
return {
|
|
@@ -43200,7 +43489,7 @@ function createRegisteredLlmToolConfigurationStatus({ envVariables }, env) {
|
|
|
43200
43489
|
/**
|
|
43201
43490
|
* Checks whether all required environment variables are present for a provider.
|
|
43202
43491
|
*
|
|
43203
|
-
* @private
|
|
43492
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43204
43493
|
*/
|
|
43205
43494
|
function isRegisteredLlmToolFullyConfigured(envVariables, env) {
|
|
43206
43495
|
if (envVariables === undefined || envVariables === null) {
|
|
@@ -43211,7 +43500,7 @@ function isRegisteredLlmToolFullyConfigured(envVariables, env) {
|
|
|
43211
43500
|
/**
|
|
43212
43501
|
* Checks whether at least one required environment variable is present for a provider.
|
|
43213
43502
|
*
|
|
43214
|
-
* @private
|
|
43503
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43215
43504
|
*/
|
|
43216
43505
|
function isRegisteredLlmToolPartiallyConfigured(envVariables, env) {
|
|
43217
43506
|
if (envVariables === undefined || envVariables === null) {
|
|
@@ -43219,109 +43508,128 @@ function isRegisteredLlmToolPartiallyConfigured(envVariables, env) {
|
|
|
43219
43508
|
}
|
|
43220
43509
|
return envVariables.some((envVariableName) => env[envVariableName] !== undefined);
|
|
43221
43510
|
}
|
|
43511
|
+
|
|
43222
43512
|
/**
|
|
43223
|
-
*
|
|
43513
|
+
* Merges provider entries from the metadata and constructor registers.
|
|
43224
43514
|
*
|
|
43225
|
-
* @private
|
|
43515
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43226
43516
|
*/
|
|
43227
|
-
function
|
|
43228
|
-
|
|
43229
|
-
|
|
43230
|
-
|
|
43231
|
-
|
|
43232
|
-
|
|
43517
|
+
function listRegisteredLlmToolEntries(registeredMetadata, registeredTools) {
|
|
43518
|
+
const registeredLlmToolEntries = new Map();
|
|
43519
|
+
for (const { title, packageName, className, envVariables } of registeredMetadata) {
|
|
43520
|
+
addRegisteredLlmToolEntry(registeredLlmToolEntries, { title, packageName, className, envVariables });
|
|
43521
|
+
}
|
|
43522
|
+
for (const { packageName, className } of registeredTools) {
|
|
43523
|
+
addRegisteredLlmToolEntry(registeredLlmToolEntries, { packageName, className });
|
|
43524
|
+
}
|
|
43525
|
+
return [...registeredLlmToolEntries.values()];
|
|
43233
43526
|
}
|
|
43234
43527
|
/**
|
|
43235
|
-
*
|
|
43528
|
+
* Adds a provider entry only when the provider is not already present.
|
|
43236
43529
|
*
|
|
43237
|
-
* @private
|
|
43530
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43238
43531
|
*/
|
|
43239
|
-
function
|
|
43240
|
-
|
|
43241
|
-
|
|
43242
|
-
|
|
43243
|
-
|
|
43244
|
-
|
|
43245
|
-
${block(renderRelevantEnvironmentVariables(env, llmToolStatuses))}
|
|
43246
|
-
|
|
43247
|
-
Available LLM providers are:
|
|
43248
|
-
${block(renderAvailableProviders(llmToolStatuses, env, isRunningInNode))}
|
|
43249
|
-
`);
|
|
43532
|
+
function addRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43533
|
+
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43534
|
+
if (registeredLlmToolEntries.has(registeredLlmToolEntryKey)) {
|
|
43535
|
+
return;
|
|
43536
|
+
}
|
|
43537
|
+
registeredLlmToolEntries.set(registeredLlmToolEntryKey, registeredLlmToolEntry);
|
|
43250
43538
|
}
|
|
43539
|
+
|
|
43251
43540
|
/**
|
|
43252
|
-
*
|
|
43541
|
+
* Lists provider entries enriched with installation and configuration state.
|
|
43253
43542
|
*
|
|
43254
|
-
* @private
|
|
43543
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43255
43544
|
*/
|
|
43256
|
-
function
|
|
43257
|
-
return
|
|
43258
|
-
.map((envVariableName) => `- \`${envVariableName}\``)
|
|
43259
|
-
.join('\n');
|
|
43545
|
+
function listRegisteredLlmToolStatuses({ registeredMetadata, registeredTools }, env) {
|
|
43546
|
+
return listRegisteredLlmToolEntries(registeredMetadata, registeredTools).map((registeredLlmToolEntry) => createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env }));
|
|
43260
43547
|
}
|
|
43548
|
+
|
|
43261
43549
|
/**
|
|
43262
|
-
*
|
|
43550
|
+
* Collects all state needed to render the provider summary.
|
|
43263
43551
|
*
|
|
43264
|
-
* @private
|
|
43552
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43265
43553
|
*/
|
|
43266
|
-
function
|
|
43267
|
-
|
|
43554
|
+
function createRegisteredLlmToolsMessageContext() {
|
|
43555
|
+
const isRunningInNode = $isRunningInNode();
|
|
43556
|
+
const env = getAvailableRegisteredLlmToolsEnvironmentVariables(isRunningInNode);
|
|
43557
|
+
const registeredLlmToolRegisters = getRegisteredLlmToolRegisters();
|
|
43558
|
+
return {
|
|
43559
|
+
env,
|
|
43560
|
+
llmToolStatuses: listRegisteredLlmToolStatuses(registeredLlmToolRegisters, env),
|
|
43561
|
+
usedEnvMessage: USED_ENV_FILENAME.createMessage(),
|
|
43562
|
+
isRunningInNode,
|
|
43563
|
+
};
|
|
43268
43564
|
}
|
|
43565
|
+
|
|
43269
43566
|
/**
|
|
43270
|
-
* Renders
|
|
43567
|
+
* Renders the fallback message for environments with no registered providers.
|
|
43271
43568
|
*
|
|
43272
|
-
* @private
|
|
43569
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43273
43570
|
*/
|
|
43274
|
-
function
|
|
43275
|
-
return
|
|
43276
|
-
|
|
43277
|
-
|
|
43571
|
+
function renderNoRegisteredLlmToolsMessage(usedEnvMessage) {
|
|
43572
|
+
return spaceTrim$1((block) => `
|
|
43573
|
+
No LLM providers are available.
|
|
43574
|
+
|
|
43575
|
+
${block(usedEnvMessage)}
|
|
43576
|
+
`);
|
|
43278
43577
|
}
|
|
43578
|
+
|
|
43279
43579
|
/**
|
|
43280
|
-
*
|
|
43580
|
+
* Creates the configuration-status sentence for one provider.
|
|
43281
43581
|
*
|
|
43282
|
-
* @private
|
|
43582
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43283
43583
|
*/
|
|
43284
|
-
function
|
|
43285
|
-
|
|
43286
|
-
|
|
43287
|
-
|
|
43584
|
+
function createRegisteredLlmToolConfigurationStatusMessage({ envVariables, isFullyConfigured, isPartiallyConfigured }, env) {
|
|
43585
|
+
if (isFullyConfigured) {
|
|
43586
|
+
return `Configured`;
|
|
43587
|
+
}
|
|
43588
|
+
if (isPartiallyConfigured) {
|
|
43589
|
+
return createPartiallyConfiguredStatusMessage(envVariables, env);
|
|
43590
|
+
}
|
|
43591
|
+
if (envVariables !== null) {
|
|
43592
|
+
return createNotConfiguredStatusMessage(envVariables);
|
|
43288
43593
|
}
|
|
43289
|
-
return
|
|
43594
|
+
return `Not configured`;
|
|
43595
|
+
// <- Note: Can not be configured via environment variables
|
|
43290
43596
|
}
|
|
43291
43597
|
/**
|
|
43292
|
-
* Creates the
|
|
43598
|
+
* Creates the partial-configuration sentence including missing variables.
|
|
43293
43599
|
*
|
|
43294
|
-
* @private
|
|
43600
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43295
43601
|
*/
|
|
43296
|
-
function
|
|
43297
|
-
|
|
43298
|
-
const providerStatusMessages = createProviderStatusMessages(llmToolStatus, env);
|
|
43299
|
-
return spaceTrim$1(`
|
|
43300
|
-
${index + 1}) **${title}** \`${className}\` from \`${packageName}\`
|
|
43301
|
-
${providerStatusMessages.join('; ')}
|
|
43302
|
-
`);
|
|
43602
|
+
function createPartiallyConfiguredStatusMessage(envVariables, env) {
|
|
43603
|
+
return `Partially confugured, missing ${listMissingEnvironmentVariables(envVariables, env).join(' + ')}`;
|
|
43303
43604
|
}
|
|
43304
43605
|
/**
|
|
43305
|
-
* Creates the
|
|
43606
|
+
* Creates the not-configured sentence including the expected environment variables.
|
|
43306
43607
|
*
|
|
43307
|
-
* @private
|
|
43608
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43308
43609
|
*/
|
|
43309
|
-
function
|
|
43310
|
-
return
|
|
43610
|
+
function createNotConfiguredStatusMessage(envVariables) {
|
|
43611
|
+
return `Not configured, to configure set env ${envVariables === null || envVariables === void 0 ? void 0 : envVariables.join(' + ')}`;
|
|
43612
|
+
}
|
|
43613
|
+
/**
|
|
43614
|
+
* Lists environment variables that are required but currently missing.
|
|
43615
|
+
*
|
|
43616
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43617
|
+
*/
|
|
43618
|
+
function listMissingEnvironmentVariables(envVariables, env) {
|
|
43619
|
+
return (envVariables === null || envVariables === void 0 ? void 0 : envVariables.filter((envVariable) => env[envVariable] === undefined)) || [];
|
|
43311
43620
|
}
|
|
43621
|
+
|
|
43312
43622
|
/**
|
|
43313
43623
|
* Creates the installation-status sentence for one provider.
|
|
43314
43624
|
*
|
|
43315
|
-
* @private
|
|
43625
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43316
43626
|
*/
|
|
43317
|
-
function
|
|
43318
|
-
const installationStatusKey =
|
|
43627
|
+
function createRegisteredLlmToolInstallationStatusMessage({ isMetadataAvailable, isInstalled, }) {
|
|
43628
|
+
const installationStatusKey = createRegisteredLlmToolInstallationStatusKey(isMetadataAvailable, isInstalled);
|
|
43319
43629
|
switch (installationStatusKey) {
|
|
43320
43630
|
case 'missing-metadata-and-installation':
|
|
43321
|
-
// TODO: [�][�] Maybe do allow to do auto-install if package not registered and not found
|
|
43322
43631
|
return `Not installed and no metadata, looks like a unexpected behavior`;
|
|
43323
43632
|
case 'metadata-without-installation':
|
|
43324
|
-
// TODO: [�][�]
|
|
43325
43633
|
return `Not installed`;
|
|
43326
43634
|
case 'installation-without-metadata':
|
|
43327
43635
|
return `No metadata but installed, looks like a unexpected behavior`;
|
|
@@ -43334,9 +43642,9 @@ function createInstallationStatusMessage({ isMetadataAvailable, isInstalled, })
|
|
|
43334
43642
|
/**
|
|
43335
43643
|
* Creates a stable installation-state key from metadata and constructor availability.
|
|
43336
43644
|
*
|
|
43337
|
-
* @private
|
|
43645
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43338
43646
|
*/
|
|
43339
|
-
function
|
|
43647
|
+
function createRegisteredLlmToolInstallationStatusKey(isMetadataAvailable, isInstalled) {
|
|
43340
43648
|
if (!isMetadataAvailable && !isInstalled) {
|
|
43341
43649
|
return 'missing-metadata-and-installation';
|
|
43342
43650
|
}
|
|
@@ -43351,54 +43659,59 @@ function createInstallationStatusKey(isMetadataAvailable, isInstalled) {
|
|
|
43351
43659
|
}
|
|
43352
43660
|
return 'unknown';
|
|
43353
43661
|
}
|
|
43662
|
+
|
|
43354
43663
|
/**
|
|
43355
|
-
*
|
|
43664
|
+
* Renders all provider lines in the status summary.
|
|
43356
43665
|
*
|
|
43357
|
-
* @private
|
|
43666
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43358
43667
|
*/
|
|
43359
|
-
function
|
|
43360
|
-
|
|
43361
|
-
|
|
43362
|
-
|
|
43363
|
-
if (isPartiallyConfigured) {
|
|
43364
|
-
return createPartiallyConfiguredStatusMessage(envVariables, env);
|
|
43365
|
-
}
|
|
43366
|
-
if (envVariables !== null) {
|
|
43367
|
-
return createNotConfiguredStatusMessage(envVariables);
|
|
43368
|
-
}
|
|
43369
|
-
return `Not configured`;
|
|
43370
|
-
// <- Note: Can not be configured via environment variables
|
|
43668
|
+
function renderAvailableRegisteredLlmTools(llmToolStatuses, env, isRunningInNode) {
|
|
43669
|
+
return llmToolStatuses
|
|
43670
|
+
.map((llmToolStatus, index) => renderAvailableRegisteredLlmTool(llmToolStatus, index, env, isRunningInNode))
|
|
43671
|
+
.join('\n');
|
|
43371
43672
|
}
|
|
43372
43673
|
/**
|
|
43373
|
-
*
|
|
43674
|
+
* Renders one provider line in the status summary.
|
|
43374
43675
|
*
|
|
43375
|
-
* @private
|
|
43676
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43376
43677
|
*/
|
|
43377
|
-
function
|
|
43378
|
-
|
|
43678
|
+
function renderAvailableRegisteredLlmTool(llmToolStatus, index, env, isRunningInNode) {
|
|
43679
|
+
const providerMessage = createAvailableRegisteredLlmToolMessage(llmToolStatus, index, env);
|
|
43680
|
+
if (!isRunningInNode) {
|
|
43681
|
+
return providerMessage;
|
|
43682
|
+
}
|
|
43683
|
+
return colorizeAvailableRegisteredLlmToolMessage(providerMessage, llmToolStatus);
|
|
43379
43684
|
}
|
|
43380
43685
|
/**
|
|
43381
|
-
* Creates the
|
|
43686
|
+
* Creates the plain-text provider line before optional colorization.
|
|
43382
43687
|
*
|
|
43383
|
-
* @private
|
|
43688
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43384
43689
|
*/
|
|
43385
|
-
function
|
|
43386
|
-
|
|
43690
|
+
function createAvailableRegisteredLlmToolMessage(llmToolStatus, index, env) {
|
|
43691
|
+
const { title, packageName, className } = llmToolStatus;
|
|
43692
|
+
const providerStatusMessages = createRegisteredLlmToolStatusMessages(llmToolStatus, env);
|
|
43693
|
+
return spaceTrim$1(`
|
|
43694
|
+
${index + 1}) **${title}** \`${className}\` from \`${packageName}\`
|
|
43695
|
+
${providerStatusMessages.join('; ')}
|
|
43696
|
+
`);
|
|
43387
43697
|
}
|
|
43388
43698
|
/**
|
|
43389
|
-
*
|
|
43699
|
+
* Creates the install and configuration fragments for one provider line.
|
|
43390
43700
|
*
|
|
43391
|
-
* @private
|
|
43701
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43392
43702
|
*/
|
|
43393
|
-
function
|
|
43394
|
-
return
|
|
43703
|
+
function createRegisteredLlmToolStatusMessages(llmToolStatus, env) {
|
|
43704
|
+
return [
|
|
43705
|
+
createRegisteredLlmToolInstallationStatusMessage(llmToolStatus),
|
|
43706
|
+
createRegisteredLlmToolConfigurationStatusMessage(llmToolStatus, env),
|
|
43707
|
+
];
|
|
43395
43708
|
}
|
|
43396
43709
|
/**
|
|
43397
43710
|
* Applies the same terminal coloring rules as the original summary renderer.
|
|
43398
43711
|
*
|
|
43399
|
-
* @private
|
|
43712
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43400
43713
|
*/
|
|
43401
|
-
function
|
|
43714
|
+
function colorizeAvailableRegisteredLlmToolMessage(providerMessage, { isInstalled, isFullyConfigured, isPartiallyConfigured }) {
|
|
43402
43715
|
if (isInstalled && isFullyConfigured) {
|
|
43403
43716
|
return colors.green(providerMessage);
|
|
43404
43717
|
}
|
|
@@ -43407,18 +43720,67 @@ function colorizeAvailableProviderMessage(providerMessage, { isInstalled, isFull
|
|
|
43407
43720
|
}
|
|
43408
43721
|
return colors.gray(providerMessage);
|
|
43409
43722
|
}
|
|
43723
|
+
|
|
43410
43724
|
/**
|
|
43411
|
-
*
|
|
43725
|
+
* Renders the list of environment variables used by at least one registered provider.
|
|
43412
43726
|
*
|
|
43413
|
-
* @private
|
|
43727
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43414
43728
|
*/
|
|
43415
|
-
function
|
|
43416
|
-
return
|
|
43417
|
-
|
|
43418
|
-
|
|
43419
|
-
|
|
43420
|
-
|
|
43421
|
-
|
|
43729
|
+
function renderRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses) {
|
|
43730
|
+
return listRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses)
|
|
43731
|
+
.map((envVariableName) => `- \`${envVariableName}\``)
|
|
43732
|
+
.join('\n');
|
|
43733
|
+
}
|
|
43734
|
+
/**
|
|
43735
|
+
* Lists environment variables that are both present and used by at least one provider.
|
|
43736
|
+
*
|
|
43737
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43738
|
+
*/
|
|
43739
|
+
function listRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses) {
|
|
43740
|
+
return Object.keys(env).filter((envVariableName) => llmToolStatuses.some(({ envVariables }) => envVariables === null || envVariables === void 0 ? void 0 : envVariables.includes(envVariableName)));
|
|
43741
|
+
}
|
|
43742
|
+
|
|
43743
|
+
/**
|
|
43744
|
+
* Renders the full provider status summary.
|
|
43745
|
+
*
|
|
43746
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43747
|
+
*/
|
|
43748
|
+
function renderRegisteredLlmToolsMessage({ env, llmToolStatuses, usedEnvMessage, isRunningInNode, }) {
|
|
43749
|
+
return spaceTrim$1((block) => `
|
|
43750
|
+
|
|
43751
|
+
${block(usedEnvMessage)}
|
|
43752
|
+
|
|
43753
|
+
Relevant environment variables:
|
|
43754
|
+
${block(renderRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses))}
|
|
43755
|
+
|
|
43756
|
+
Available LLM providers are:
|
|
43757
|
+
${block(renderAvailableRegisteredLlmTools(llmToolStatuses, env, isRunningInNode))}
|
|
43758
|
+
`);
|
|
43759
|
+
}
|
|
43760
|
+
|
|
43761
|
+
/**
|
|
43762
|
+
* Pass the `.env` file which was used to configure LLM tools
|
|
43763
|
+
*
|
|
43764
|
+
* Note: `$` is used to indicate that this variable is making side effect
|
|
43765
|
+
*
|
|
43766
|
+
* @private internal log of `$provideLlmToolsConfigurationFromEnv` and `$registeredLlmToolsMessage`
|
|
43767
|
+
*/
|
|
43768
|
+
function $setUsedEnvFilename(filepath) {
|
|
43769
|
+
USED_ENV_FILENAME.set(filepath);
|
|
43770
|
+
}
|
|
43771
|
+
/**
|
|
43772
|
+
* Creates a message with all registered LLM tools
|
|
43773
|
+
*
|
|
43774
|
+
* Note: This function is used to create a (error) message when there is no constructor for some LLM provider
|
|
43775
|
+
*
|
|
43776
|
+
* @private internal function of `createLlmToolsFromConfiguration` and `$provideLlmToolsFromEnv`
|
|
43777
|
+
*/
|
|
43778
|
+
function $registeredLlmToolsMessage() {
|
|
43779
|
+
const registeredLlmToolsMessageContext = createRegisteredLlmToolsMessageContext();
|
|
43780
|
+
if (registeredLlmToolsMessageContext.llmToolStatuses.length === 0) {
|
|
43781
|
+
return renderNoRegisteredLlmToolsMessage(registeredLlmToolsMessageContext.usedEnvMessage);
|
|
43782
|
+
}
|
|
43783
|
+
return renderRegisteredLlmToolsMessage(registeredLlmToolsMessageContext);
|
|
43422
43784
|
}
|
|
43423
43785
|
// TODO: [®] DRY Register logic
|
|
43424
43786
|
// TODO: [🧠][⚛] Maybe pass env as argument
|