@promptbook/node 0.113.0-8 → 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/umd/index.umd.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('path'), require('fs/promises'), require('
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports', 'path', 'fs/promises', '
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-node"] = {}, global.path, global.promises, global.
|
|
5
|
-
})(this, (function (exports, path, promises, colors, child_process,
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('path'), require('fs/promises'), require('spacetrim'), require('colors'), require('child_process'), require('@openai/agents'), require('url'), require('@mozilla/readability'), require('jsdom'), require('crypto-js'), require('crypto-js/enc-hex'), require('showdown'), require('jszip'), require('waitasecond'), require('dotenv'), require('crypto-js/sha256'), require('rxjs'), require('crypto'), require('moment'), require('mime-types'), require('papaparse'), require('bottleneck'), require('openai')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', 'path', 'fs/promises', 'spacetrim', 'colors', 'child_process', '@openai/agents', 'url', '@mozilla/readability', 'jsdom', 'crypto-js', 'crypto-js/enc-hex', 'showdown', 'jszip', 'waitasecond', 'dotenv', 'crypto-js/sha256', 'rxjs', 'crypto', 'moment', 'mime-types', 'papaparse', 'bottleneck', 'openai'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-node"] = {}, global.path, global.promises, global._spaceTrim, global.colors, global.child_process, global.agents, global.url, global.readability, global.jsdom, global.CryptoJS, global.hexEncoder, global.showdown, global.JSZip, global.waitasecond, global.dotenv, global.sha256, global.rxjs, null, global.moment, global.mimeTypes, global.papaparse, global.Bottleneck, global.OpenAI));
|
|
5
|
+
})(this, (function (exports, path, promises, _spaceTrim, colors, child_process, agents, url, readability, jsdom, CryptoJS, hexEncoder, showdown, JSZip, waitasecond, dotenv, sha256, rxjs, crypto, moment, mimeTypes, papaparse, Bottleneck, OpenAI) { 'use strict';
|
|
6
6
|
|
|
7
7
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
8
|
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
return Object.freeze(n);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
var colors__default = /*#__PURE__*/_interopDefaultLegacy(colors);
|
|
28
27
|
var _spaceTrim__default = /*#__PURE__*/_interopDefaultLegacy(_spaceTrim);
|
|
28
|
+
var colors__default = /*#__PURE__*/_interopDefaultLegacy(colors);
|
|
29
29
|
var CryptoJS__default = /*#__PURE__*/_interopDefaultLegacy(CryptoJS);
|
|
30
30
|
var hexEncoder__default = /*#__PURE__*/_interopDefaultLegacy(hexEncoder);
|
|
31
31
|
var showdown__default = /*#__PURE__*/_interopDefaultLegacy(showdown);
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
* @generated
|
|
52
52
|
* @see https://github.com/webgptorg/promptbook
|
|
53
53
|
*/
|
|
54
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.113.0-
|
|
54
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.113.0-9';
|
|
55
55
|
/**
|
|
56
56
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
57
57
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -396,6 +396,34 @@
|
|
|
396
396
|
// TODO: [🤶] Maybe export through `@promptbook/utils` or `@promptbook/random` package
|
|
397
397
|
// TODO: Maybe use nanoid instead https://github.com/ai/nanoid
|
|
398
398
|
|
|
399
|
+
/**
|
|
400
|
+
* Increase the level of all headings in the markdown content
|
|
401
|
+
*
|
|
402
|
+
* @example h1 -> h2, h2 -> h3, ...
|
|
403
|
+
* @param content The markdown content
|
|
404
|
+
* @returns The markdown with increased headings
|
|
405
|
+
*/
|
|
406
|
+
function increaseHeadings(content) {
|
|
407
|
+
const lines = content.split(/\r?\n/);
|
|
408
|
+
let inCodeBlock = false;
|
|
409
|
+
for (let i = 0; i < lines.length; i++) {
|
|
410
|
+
const line = lines[i];
|
|
411
|
+
if (line.startsWith('```')) {
|
|
412
|
+
inCodeBlock = !inCodeBlock;
|
|
413
|
+
}
|
|
414
|
+
if (inCodeBlock) {
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
const headingMatch = line.match(/^(#+)(.*)/);
|
|
418
|
+
if (headingMatch) {
|
|
419
|
+
const headingLevel = headingMatch[1].length;
|
|
420
|
+
const headingText = headingMatch[2];
|
|
421
|
+
lines[i] = `${'#'.repeat(headingLevel + 1)}${headingText}`;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return lines.join('\n');
|
|
425
|
+
}
|
|
426
|
+
|
|
399
427
|
/**
|
|
400
428
|
* Appends optional coding context to a runner prompt.
|
|
401
429
|
*/
|
|
@@ -408,7 +436,13 @@
|
|
|
408
436
|
if (normalizedPrompt === '') {
|
|
409
437
|
return normalizedContext;
|
|
410
438
|
}
|
|
411
|
-
return
|
|
439
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
440
|
+
${block(normalizedPrompt)}
|
|
441
|
+
|
|
442
|
+
## Context
|
|
443
|
+
|
|
444
|
+
${block(increaseHeadings(normalizedContext))}
|
|
445
|
+
`);
|
|
412
446
|
}
|
|
413
447
|
|
|
414
448
|
/**
|
|
@@ -537,6 +571,127 @@
|
|
|
537
571
|
});
|
|
538
572
|
}
|
|
539
573
|
|
|
574
|
+
/**
|
|
575
|
+
* Validates that a channel value is a valid number within the range of 0 to 255.
|
|
576
|
+
* Throws an error if the value is not valid.
|
|
577
|
+
*
|
|
578
|
+
* @param channelName - The name of the channel being validated.
|
|
579
|
+
* @param value - The value of the channel to validate.
|
|
580
|
+
* @throws Will throw an error if the value is not a valid channel number.
|
|
581
|
+
*
|
|
582
|
+
* @private util of `@promptbook/color`
|
|
583
|
+
*/
|
|
584
|
+
function checkChannelValue(channelName, value) {
|
|
585
|
+
if (typeof value !== 'number') {
|
|
586
|
+
throw new Error(`${channelName} channel value is not number but ${typeof value}`);
|
|
587
|
+
}
|
|
588
|
+
if (isNaN(value)) {
|
|
589
|
+
throw new Error(`${channelName} channel value is NaN`);
|
|
590
|
+
}
|
|
591
|
+
if (Math.round(value) !== value) {
|
|
592
|
+
throw new Error(`${channelName} channel is not whole number, it is ${value}`);
|
|
593
|
+
}
|
|
594
|
+
if (value < 0) {
|
|
595
|
+
throw new Error(`${channelName} channel is lower than 0, it is ${value}`);
|
|
596
|
+
}
|
|
597
|
+
if (value > 255) {
|
|
598
|
+
throw new Error(`${channelName} channel is greater than 255, it is ${value}`);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Shared immutable channel storage and serialization helpers for `Color`.
|
|
604
|
+
*
|
|
605
|
+
* @private base class of Color
|
|
606
|
+
*/
|
|
607
|
+
class ColorValue {
|
|
608
|
+
constructor(red, green, blue, alpha = 255) {
|
|
609
|
+
this.red = red;
|
|
610
|
+
this.green = green;
|
|
611
|
+
this.blue = blue;
|
|
612
|
+
this.alpha = alpha;
|
|
613
|
+
checkChannelValue('Red', red);
|
|
614
|
+
checkChannelValue('Green', green);
|
|
615
|
+
checkChannelValue('Blue', blue);
|
|
616
|
+
checkChannelValue('Alpha', alpha);
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Shortcut for `red` property
|
|
620
|
+
* Number from 0 to 255
|
|
621
|
+
* @alias red
|
|
622
|
+
*/
|
|
623
|
+
get r() {
|
|
624
|
+
return this.red;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Shortcut for `green` property
|
|
628
|
+
* Number from 0 to 255
|
|
629
|
+
* @alias green
|
|
630
|
+
*/
|
|
631
|
+
get g() {
|
|
632
|
+
return this.green;
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Shortcut for `blue` property
|
|
636
|
+
* Number from 0 to 255
|
|
637
|
+
* @alias blue
|
|
638
|
+
*/
|
|
639
|
+
get b() {
|
|
640
|
+
return this.blue;
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Shortcut for `alpha` property
|
|
644
|
+
* Number from 0 (transparent) to 255 (opaque)
|
|
645
|
+
* @alias alpha
|
|
646
|
+
*/
|
|
647
|
+
get a() {
|
|
648
|
+
return this.alpha;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Shortcut for `alpha` property
|
|
652
|
+
* Number from 0 (transparent) to 255 (opaque)
|
|
653
|
+
* @alias alpha
|
|
654
|
+
*/
|
|
655
|
+
get opacity() {
|
|
656
|
+
return this.alpha;
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Shortcut for 1-`alpha` property
|
|
660
|
+
*/
|
|
661
|
+
get transparency() {
|
|
662
|
+
return 255 - this.alpha;
|
|
663
|
+
}
|
|
664
|
+
clone() {
|
|
665
|
+
return take(this.createColor(this.red, this.green, this.blue, this.alpha));
|
|
666
|
+
}
|
|
667
|
+
toString() {
|
|
668
|
+
return this.toHex();
|
|
669
|
+
}
|
|
670
|
+
toHex() {
|
|
671
|
+
if (this.alpha === 255) {
|
|
672
|
+
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
673
|
+
.toString(16)
|
|
674
|
+
.padStart(2, '0')}`;
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
678
|
+
.toString(16)
|
|
679
|
+
.padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
toRgb() {
|
|
683
|
+
if (this.alpha === 255) {
|
|
684
|
+
return `rgb(${this.red}, ${this.green}, ${this.blue})`;
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
toHsl() {
|
|
691
|
+
throw new Error(`Getting HSL is not implemented`);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
540
695
|
/**
|
|
541
696
|
* 🎨 List of all 140 color names which are supported by CSS
|
|
542
697
|
*
|
|
@@ -696,127 +851,6 @@
|
|
|
696
851
|
};
|
|
697
852
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
698
853
|
|
|
699
|
-
/**
|
|
700
|
-
* Validates that a channel value is a valid number within the range of 0 to 255.
|
|
701
|
-
* Throws an error if the value is not valid.
|
|
702
|
-
*
|
|
703
|
-
* @param channelName - The name of the channel being validated.
|
|
704
|
-
* @param value - The value of the channel to validate.
|
|
705
|
-
* @throws Will throw an error if the value is not a valid channel number.
|
|
706
|
-
*
|
|
707
|
-
* @private util of `@promptbook/color`
|
|
708
|
-
*/
|
|
709
|
-
function checkChannelValue(channelName, value) {
|
|
710
|
-
if (typeof value !== 'number') {
|
|
711
|
-
throw new Error(`${channelName} channel value is not number but ${typeof value}`);
|
|
712
|
-
}
|
|
713
|
-
if (isNaN(value)) {
|
|
714
|
-
throw new Error(`${channelName} channel value is NaN`);
|
|
715
|
-
}
|
|
716
|
-
if (Math.round(value) !== value) {
|
|
717
|
-
throw new Error(`${channelName} channel is not whole number, it is ${value}`);
|
|
718
|
-
}
|
|
719
|
-
if (value < 0) {
|
|
720
|
-
throw new Error(`${channelName} channel is lower than 0, it is ${value}`);
|
|
721
|
-
}
|
|
722
|
-
if (value > 255) {
|
|
723
|
-
throw new Error(`${channelName} channel is greater than 255, it is ${value}`);
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
/**
|
|
728
|
-
* Shared immutable channel storage and serialization helpers for `Color`.
|
|
729
|
-
*
|
|
730
|
-
* @private base class of Color
|
|
731
|
-
*/
|
|
732
|
-
class ColorValue {
|
|
733
|
-
constructor(red, green, blue, alpha = 255) {
|
|
734
|
-
this.red = red;
|
|
735
|
-
this.green = green;
|
|
736
|
-
this.blue = blue;
|
|
737
|
-
this.alpha = alpha;
|
|
738
|
-
checkChannelValue('Red', red);
|
|
739
|
-
checkChannelValue('Green', green);
|
|
740
|
-
checkChannelValue('Blue', blue);
|
|
741
|
-
checkChannelValue('Alpha', alpha);
|
|
742
|
-
}
|
|
743
|
-
/**
|
|
744
|
-
* Shortcut for `red` property
|
|
745
|
-
* Number from 0 to 255
|
|
746
|
-
* @alias red
|
|
747
|
-
*/
|
|
748
|
-
get r() {
|
|
749
|
-
return this.red;
|
|
750
|
-
}
|
|
751
|
-
/**
|
|
752
|
-
* Shortcut for `green` property
|
|
753
|
-
* Number from 0 to 255
|
|
754
|
-
* @alias green
|
|
755
|
-
*/
|
|
756
|
-
get g() {
|
|
757
|
-
return this.green;
|
|
758
|
-
}
|
|
759
|
-
/**
|
|
760
|
-
* Shortcut for `blue` property
|
|
761
|
-
* Number from 0 to 255
|
|
762
|
-
* @alias blue
|
|
763
|
-
*/
|
|
764
|
-
get b() {
|
|
765
|
-
return this.blue;
|
|
766
|
-
}
|
|
767
|
-
/**
|
|
768
|
-
* Shortcut for `alpha` property
|
|
769
|
-
* Number from 0 (transparent) to 255 (opaque)
|
|
770
|
-
* @alias alpha
|
|
771
|
-
*/
|
|
772
|
-
get a() {
|
|
773
|
-
return this.alpha;
|
|
774
|
-
}
|
|
775
|
-
/**
|
|
776
|
-
* Shortcut for `alpha` property
|
|
777
|
-
* Number from 0 (transparent) to 255 (opaque)
|
|
778
|
-
* @alias alpha
|
|
779
|
-
*/
|
|
780
|
-
get opacity() {
|
|
781
|
-
return this.alpha;
|
|
782
|
-
}
|
|
783
|
-
/**
|
|
784
|
-
* Shortcut for 1-`alpha` property
|
|
785
|
-
*/
|
|
786
|
-
get transparency() {
|
|
787
|
-
return 255 - this.alpha;
|
|
788
|
-
}
|
|
789
|
-
clone() {
|
|
790
|
-
return take(this.createColor(this.red, this.green, this.blue, this.alpha));
|
|
791
|
-
}
|
|
792
|
-
toString() {
|
|
793
|
-
return this.toHex();
|
|
794
|
-
}
|
|
795
|
-
toHex() {
|
|
796
|
-
if (this.alpha === 255) {
|
|
797
|
-
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
798
|
-
.toString(16)
|
|
799
|
-
.padStart(2, '0')}`;
|
|
800
|
-
}
|
|
801
|
-
else {
|
|
802
|
-
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
803
|
-
.toString(16)
|
|
804
|
-
.padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
toRgb() {
|
|
808
|
-
if (this.alpha === 255) {
|
|
809
|
-
return `rgb(${this.red}, ${this.green}, ${this.blue})`;
|
|
810
|
-
}
|
|
811
|
-
else {
|
|
812
|
-
return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
toHsl() {
|
|
816
|
-
throw new Error(`Getting HSL is not implemented`);
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
|
|
820
854
|
/**
|
|
821
855
|
* Checks if the given value is a valid hex color string
|
|
822
856
|
*
|
|
@@ -2790,6 +2824,31 @@
|
|
|
2790
2824
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
2791
2825
|
*/
|
|
2792
2826
|
|
|
2827
|
+
/**
|
|
2828
|
+
* Pattern that matches durations like "1h", "30m", "5s", "1h30m", "1h30m5s".
|
|
2829
|
+
*/
|
|
2830
|
+
/**
|
|
2831
|
+
* Formats a duration in milliseconds into a compact human-readable string.
|
|
2832
|
+
*
|
|
2833
|
+
* Examples: `3600000` → `"1h"`, `90000` → `"1m 30s"`, `5000` → `"5s"`.
|
|
2834
|
+
*
|
|
2835
|
+
* @private internal utility of `ptbk coder run`
|
|
2836
|
+
*/
|
|
2837
|
+
function formatDurationMs(ms) {
|
|
2838
|
+
const totalSeconds = Math.ceil(ms / 1000);
|
|
2839
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
2840
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
2841
|
+
const seconds = totalSeconds % 60;
|
|
2842
|
+
const parts = [];
|
|
2843
|
+
if (hours > 0)
|
|
2844
|
+
parts.push(`${hours}h`);
|
|
2845
|
+
if (minutes > 0)
|
|
2846
|
+
parts.push(`${minutes}m`);
|
|
2847
|
+
if (seconds > 0 || parts.length === 0)
|
|
2848
|
+
parts.push(`${seconds}s`);
|
|
2849
|
+
return parts.join(' ');
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2793
2852
|
/**
|
|
2794
2853
|
* Formats one unknown error-like value into readable text for logs and feedback.
|
|
2795
2854
|
*/
|
|
@@ -3027,14 +3086,209 @@
|
|
|
3027
3086
|
function buildClaudeScript(options) {
|
|
3028
3087
|
const MODEL_ARGUMENT = options.model ? ` --model ${options.model}` : '';
|
|
3029
3088
|
const THINKING_LEVEL_ARGUMENT = options.thinkingLevel ? ` --effort ${options.thinkingLevel}` : '';
|
|
3089
|
+
const RESUME_SESSION_ARGUMENT = options.resumeSessionId
|
|
3090
|
+
? ` --resume ${quoteShellArgument(options.resumeSessionId)}`
|
|
3091
|
+
: '';
|
|
3030
3092
|
return spaceTrim((block) => `
|
|
3031
|
-
claude --allowedTools "Bash,Read,Edit,Write"${MODEL_ARGUMENT}${THINKING_LEVEL_ARGUMENT} --output-format stream-json --verbose --include-partial-messages --print <<'${CLAUDE_PROMPT_DELIMITER}'
|
|
3093
|
+
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}'
|
|
3032
3094
|
|
|
3033
3095
|
${block(options.prompt)}
|
|
3034
3096
|
|
|
3035
3097
|
${CLAUDE_PROMPT_DELIMITER}
|
|
3036
3098
|
`);
|
|
3037
3099
|
}
|
|
3100
|
+
/**
|
|
3101
|
+
* Quotes one shell argument for the generated Bash script.
|
|
3102
|
+
*/
|
|
3103
|
+
function quoteShellArgument(value) {
|
|
3104
|
+
return JSON.stringify(value);
|
|
3105
|
+
}
|
|
3106
|
+
|
|
3107
|
+
/**
|
|
3108
|
+
* Parses all JSON lines from Claude Code output while ignoring shell prefixes and stack traces.
|
|
3109
|
+
*/
|
|
3110
|
+
function parseClaudeCodeOutputEvents(output) {
|
|
3111
|
+
return output
|
|
3112
|
+
.split(/\r?\n/u)
|
|
3113
|
+
.map(parseClaudeCodeOutputLine)
|
|
3114
|
+
.filter((event) => event !== undefined);
|
|
3115
|
+
}
|
|
3116
|
+
/**
|
|
3117
|
+
* Finds the final Claude Code result event in a stream-json output blob.
|
|
3118
|
+
*/
|
|
3119
|
+
function findClaudeCodeResultEvent(output) {
|
|
3120
|
+
return parseClaudeCodeOutputEvents(output).find((event) => event.type === 'result');
|
|
3121
|
+
}
|
|
3122
|
+
/**
|
|
3123
|
+
* Parses one output line when it contains a JSON object.
|
|
3124
|
+
*/
|
|
3125
|
+
function parseClaudeCodeOutputLine(line) {
|
|
3126
|
+
const jsonStartIndex = line.indexOf('{');
|
|
3127
|
+
if (jsonStartIndex === -1) {
|
|
3128
|
+
return undefined;
|
|
3129
|
+
}
|
|
3130
|
+
const possibleJson = line.slice(jsonStartIndex).trim();
|
|
3131
|
+
try {
|
|
3132
|
+
const parsed = JSON.parse(possibleJson);
|
|
3133
|
+
if (isClaudeCodeOutputEvent(parsed)) {
|
|
3134
|
+
return parsed;
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
catch (_a) {
|
|
3138
|
+
return undefined;
|
|
3139
|
+
}
|
|
3140
|
+
return undefined;
|
|
3141
|
+
}
|
|
3142
|
+
/**
|
|
3143
|
+
* Checks whether an unknown parsed JSON value has the object shape expected from Claude Code events.
|
|
3144
|
+
*/
|
|
3145
|
+
function isClaudeCodeOutputEvent(value) {
|
|
3146
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3147
|
+
}
|
|
3148
|
+
|
|
3149
|
+
/**
|
|
3150
|
+
* Number of milliseconds added after Claude's reported reset timestamp before retrying.
|
|
3151
|
+
*/
|
|
3152
|
+
const CLAUDE_CODE_SESSION_LIMIT_RESET_BUFFER_MS = 30 * 1000;
|
|
3153
|
+
/**
|
|
3154
|
+
* Fallback delay used when Claude reports a session limit without a machine-readable reset timestamp.
|
|
3155
|
+
*/
|
|
3156
|
+
const DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS = 10 * 60 * 1000;
|
|
3157
|
+
/**
|
|
3158
|
+
* Extracts a Claude Code session-limit failure from a thrown runner error.
|
|
3159
|
+
*/
|
|
3160
|
+
function extractClaudeCodeSessionLimitFromError(error) {
|
|
3161
|
+
return extractClaudeCodeSessionLimitFromOutput(formatUnknownErrorDetails(error));
|
|
3162
|
+
}
|
|
3163
|
+
/**
|
|
3164
|
+
* Extracts a Claude Code session-limit failure from raw stream-json output.
|
|
3165
|
+
*/
|
|
3166
|
+
function extractClaudeCodeSessionLimitFromOutput(output) {
|
|
3167
|
+
var _a, _b, _c, _d, _e;
|
|
3168
|
+
const events = parseClaudeCodeOutputEvents(output);
|
|
3169
|
+
const rejectedRateLimitEvent = events.find(isRejectedRateLimitEvent);
|
|
3170
|
+
const sessionLimitResultEvent = events.find(isSessionLimitResultEvent);
|
|
3171
|
+
const sessionLimitTextEvent = events.find(isSessionLimitTextEvent);
|
|
3172
|
+
if (!sessionLimitResultEvent && !sessionLimitTextEvent) {
|
|
3173
|
+
return undefined;
|
|
3174
|
+
}
|
|
3175
|
+
const sessionId = findClaudeCodeSessionId(events);
|
|
3176
|
+
if (!sessionId) {
|
|
3177
|
+
return undefined;
|
|
3178
|
+
}
|
|
3179
|
+
const resetDate = extractResetDate(rejectedRateLimitEvent);
|
|
3180
|
+
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;
|
|
3181
|
+
const summary = (_e = (_d = extractSessionLimitSummary(sessionLimitResultEvent)) !== null && _d !== void 0 ? _d : extractSessionLimitSummary(sessionLimitTextEvent)) !== null && _e !== void 0 ? _e : 'Claude Code reported a session limit.';
|
|
3182
|
+
return {
|
|
3183
|
+
sessionId,
|
|
3184
|
+
resetDate,
|
|
3185
|
+
rateLimitType,
|
|
3186
|
+
summary,
|
|
3187
|
+
};
|
|
3188
|
+
}
|
|
3189
|
+
/**
|
|
3190
|
+
* Computes how long to wait before trying to resume the Claude Code session.
|
|
3191
|
+
*/
|
|
3192
|
+
function getClaudeCodeSessionLimitDelayMs(sessionLimit, nowMs = Date.now()) {
|
|
3193
|
+
if (!sessionLimit.resetDate) {
|
|
3194
|
+
return DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS;
|
|
3195
|
+
}
|
|
3196
|
+
return Math.max(0, sessionLimit.resetDate.getTime() - nowMs + CLAUDE_CODE_SESSION_LIMIT_RESET_BUFFER_MS);
|
|
3197
|
+
}
|
|
3198
|
+
/**
|
|
3199
|
+
* Builds the follow-up prompt sent into a resumed Claude Code session after its limit resets.
|
|
3200
|
+
*/
|
|
3201
|
+
function buildClaudeCodeSessionResurrectionPrompt(originalPrompt, sessionId) {
|
|
3202
|
+
return spaceTrim((block) => `
|
|
3203
|
+
## Claude Code session resurrection
|
|
3204
|
+
|
|
3205
|
+
You are resuming Claude Code session \`${sessionId}\` after Claude reported a session limit.
|
|
3206
|
+
Continue the same task from the existing repository and session state.
|
|
3207
|
+
Do not discard useful context, completed analysis, or file changes from the resumed session.
|
|
3208
|
+
|
|
3209
|
+
The original prompt is repeated below as reference in case the resumed session needs it.
|
|
3210
|
+
|
|
3211
|
+
## Original prompt
|
|
3212
|
+
|
|
3213
|
+
${block(originalPrompt)}
|
|
3214
|
+
`);
|
|
3215
|
+
}
|
|
3216
|
+
/**
|
|
3217
|
+
* Builds a compact one-line label for logs and terminal UI messages.
|
|
3218
|
+
*/
|
|
3219
|
+
function formatClaudeCodeSessionLimitForDisplay(sessionLimit) {
|
|
3220
|
+
const resetSuffix = sessionLimit.resetDate
|
|
3221
|
+
? `, resets at ${sessionLimit.resetDate.toISOString()}`
|
|
3222
|
+
: `, retrying every ${formatDurationMs(DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS)}`;
|
|
3223
|
+
const rateLimitSuffix = sessionLimit.rateLimitType ? ` (${sessionLimit.rateLimitType})` : '';
|
|
3224
|
+
return `${sessionLimit.summary}${rateLimitSuffix}${resetSuffix}`;
|
|
3225
|
+
}
|
|
3226
|
+
/**
|
|
3227
|
+
* Returns true when the event is an explicit rejected Claude Code rate-limit event.
|
|
3228
|
+
*/
|
|
3229
|
+
function isRejectedRateLimitEvent(event) {
|
|
3230
|
+
var _a;
|
|
3231
|
+
return event.type === 'rate_limit_event' && ((_a = event.rate_limit_info) === null || _a === void 0 ? void 0 : _a.status) === 'rejected';
|
|
3232
|
+
}
|
|
3233
|
+
/**
|
|
3234
|
+
* Returns true when the final result reports the Claude session limit.
|
|
3235
|
+
*/
|
|
3236
|
+
function isSessionLimitResultEvent(event) {
|
|
3237
|
+
return (event.type === 'result' &&
|
|
3238
|
+
event.is_error === true &&
|
|
3239
|
+
event.api_error_status === 429 &&
|
|
3240
|
+
isSessionLimitText(event.result));
|
|
3241
|
+
}
|
|
3242
|
+
/**
|
|
3243
|
+
* Returns true when any assistant event reports the Claude session limit in text.
|
|
3244
|
+
*/
|
|
3245
|
+
function isSessionLimitTextEvent(event) {
|
|
3246
|
+
if (event.error !== 'rate_limit') {
|
|
3247
|
+
return false;
|
|
3248
|
+
}
|
|
3249
|
+
return isSessionLimitText(extractSessionLimitSummary(event));
|
|
3250
|
+
}
|
|
3251
|
+
/**
|
|
3252
|
+
* Extracts the first session id reported by Claude Code.
|
|
3253
|
+
*/
|
|
3254
|
+
function findClaudeCodeSessionId(events) {
|
|
3255
|
+
return events.map((event) => event.session_id).find((sessionId) => Boolean(sessionId));
|
|
3256
|
+
}
|
|
3257
|
+
/**
|
|
3258
|
+
* Extracts Claude's reset timestamp from a rejected rate-limit event.
|
|
3259
|
+
*/
|
|
3260
|
+
function extractResetDate(event) {
|
|
3261
|
+
var _a;
|
|
3262
|
+
const resetsAt = (_a = event === null || event === void 0 ? void 0 : event.rate_limit_info) === null || _a === void 0 ? void 0 : _a.resetsAt;
|
|
3263
|
+
if (typeof resetsAt !== 'number' || !Number.isFinite(resetsAt)) {
|
|
3264
|
+
return undefined;
|
|
3265
|
+
}
|
|
3266
|
+
const resetDate = new Date(resetsAt * 1000);
|
|
3267
|
+
if (Number.isNaN(resetDate.getTime())) {
|
|
3268
|
+
return undefined;
|
|
3269
|
+
}
|
|
3270
|
+
return resetDate;
|
|
3271
|
+
}
|
|
3272
|
+
/**
|
|
3273
|
+
* Extracts a human-readable session-limit summary from an event.
|
|
3274
|
+
*/
|
|
3275
|
+
function extractSessionLimitSummary(event) {
|
|
3276
|
+
var _a, _b;
|
|
3277
|
+
if (!event) {
|
|
3278
|
+
return undefined;
|
|
3279
|
+
}
|
|
3280
|
+
if (typeof event.result === 'string' && event.result.trim()) {
|
|
3281
|
+
return event.result.trim();
|
|
3282
|
+
}
|
|
3283
|
+
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));
|
|
3284
|
+
return textContent;
|
|
3285
|
+
}
|
|
3286
|
+
/**
|
|
3287
|
+
* Checks whether a text value names the Claude Code session limit.
|
|
3288
|
+
*/
|
|
3289
|
+
function isSessionLimitText(text) {
|
|
3290
|
+
return /\bsession\s+limit\b/iu.test(text !== null && text !== void 0 ? text : '');
|
|
3291
|
+
}
|
|
3038
3292
|
|
|
3039
3293
|
/**
|
|
3040
3294
|
* Represents the uncertain value
|
|
@@ -3110,14 +3364,8 @@
|
|
|
3110
3364
|
function parseClaudeCodeJsonOutput(output) {
|
|
3111
3365
|
var _a, _b, _c, _d;
|
|
3112
3366
|
try {
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
const jsonLine = lines.find((line) => line.trim().startsWith('{"type":"result"'));
|
|
3116
|
-
if (!jsonLine) {
|
|
3117
|
-
return UNCERTAIN_USAGE;
|
|
3118
|
-
}
|
|
3119
|
-
const parsed = JSON.parse(jsonLine);
|
|
3120
|
-
if (parsed.type !== 'result') {
|
|
3367
|
+
const parsed = findClaudeCodeResultEvent(output);
|
|
3368
|
+
if (!parsed) {
|
|
3121
3369
|
return UNCERTAIN_USAGE;
|
|
3122
3370
|
}
|
|
3123
3371
|
const totalInputTokens = (((_a = parsed.usage) === null || _a === void 0 ? void 0 : _a.input_tokens) || 0) +
|
|
@@ -3161,6 +3409,10 @@
|
|
|
3161
3409
|
}
|
|
3162
3410
|
}
|
|
3163
3411
|
|
|
3412
|
+
/**
|
|
3413
|
+
* Polling interval used while waiting for Claude Code session limits to reset.
|
|
3414
|
+
*/
|
|
3415
|
+
const CLAUDE_CODE_SESSION_RESURRECTION_POLL_MS = 30 * 1000;
|
|
3164
3416
|
/**
|
|
3165
3417
|
* Runs prompts via the Claude Code CLI.
|
|
3166
3418
|
*/
|
|
@@ -3176,22 +3428,102 @@
|
|
|
3176
3428
|
* Runs the prompt using Claude Code and parses usage output.
|
|
3177
3429
|
*/
|
|
3178
3430
|
async runPrompt(options) {
|
|
3431
|
+
let resumeSessionId;
|
|
3432
|
+
let prompt = options.prompt;
|
|
3433
|
+
let resurrectionCount = 0;
|
|
3434
|
+
while (true) {
|
|
3435
|
+
const output = await this.runClaudeCodeOnce({
|
|
3436
|
+
...options,
|
|
3437
|
+
prompt,
|
|
3438
|
+
resumeSessionId,
|
|
3439
|
+
}).catch(async (error) => {
|
|
3440
|
+
const sessionLimit = extractClaudeCodeSessionLimitFromError(error);
|
|
3441
|
+
if (!sessionLimit) {
|
|
3442
|
+
throw error;
|
|
3443
|
+
}
|
|
3444
|
+
resurrectionCount++;
|
|
3445
|
+
await waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options);
|
|
3446
|
+
resumeSessionId = sessionLimit.sessionId;
|
|
3447
|
+
prompt = buildClaudeCodeSessionResurrectionPrompt(options.prompt, sessionLimit.sessionId);
|
|
3448
|
+
return undefined;
|
|
3449
|
+
});
|
|
3450
|
+
if (output === undefined) {
|
|
3451
|
+
continue;
|
|
3452
|
+
}
|
|
3453
|
+
const sessionLimit = extractClaudeCodeSessionLimitFromOutput(output);
|
|
3454
|
+
if (sessionLimit) {
|
|
3455
|
+
resurrectionCount++;
|
|
3456
|
+
await waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options);
|
|
3457
|
+
resumeSessionId = sessionLimit.sessionId;
|
|
3458
|
+
prompt = buildClaudeCodeSessionResurrectionPrompt(options.prompt, sessionLimit.sessionId);
|
|
3459
|
+
continue;
|
|
3460
|
+
}
|
|
3461
|
+
const usage = parseClaudeCodeJsonOutput(output);
|
|
3462
|
+
return { usage };
|
|
3463
|
+
}
|
|
3464
|
+
}
|
|
3465
|
+
/**
|
|
3466
|
+
* Runs one Claude Code CLI process and returns its raw output.
|
|
3467
|
+
*/
|
|
3468
|
+
async runClaudeCodeOnce(options) {
|
|
3179
3469
|
const scriptContent = buildClaudeScript({
|
|
3180
3470
|
prompt: options.prompt,
|
|
3181
3471
|
model: this.options.model,
|
|
3182
3472
|
thinkingLevel: this.options.thinkingLevel,
|
|
3473
|
+
resumeSessionId: options.resumeSessionId,
|
|
3183
3474
|
});
|
|
3184
|
-
|
|
3475
|
+
return await $runGoScriptWithOutput({
|
|
3185
3476
|
scriptPath: options.scriptPath,
|
|
3186
3477
|
scriptContent,
|
|
3187
3478
|
logPath: options.logPath,
|
|
3188
3479
|
shouldPrintLiveOutput: options.shouldPrintLiveOutput,
|
|
3189
3480
|
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
3190
3481
|
});
|
|
3191
|
-
const usage = parseClaudeCodeJsonOutput(output);
|
|
3192
|
-
return { usage };
|
|
3193
3482
|
}
|
|
3194
3483
|
}
|
|
3484
|
+
/**
|
|
3485
|
+
* Waits until the Claude Code session can be resumed, keeping terminal status clear.
|
|
3486
|
+
*/
|
|
3487
|
+
async function waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options) {
|
|
3488
|
+
var _a, _b, _c;
|
|
3489
|
+
const delayMs = getClaudeCodeSessionLimitDelayMs(sessionLimit);
|
|
3490
|
+
const sessionLabel = formatClaudeCodeSessionIdForDisplay(sessionLimit.sessionId);
|
|
3491
|
+
const resetSummary = formatClaudeCodeSessionLimitForDisplay(sessionLimit);
|
|
3492
|
+
if ((_a = options.shouldPrintLiveOutput) !== null && _a !== void 0 ? _a : true) {
|
|
3493
|
+
console.warn(colors__default["default"].yellow(`[claude-code] Session limit detected for ${sessionLimit.sessionId}. Resurrection #${resurrectionCount} will resume with --resume after ${formatDurationMs(delayMs)}. ${resetSummary}`));
|
|
3494
|
+
}
|
|
3495
|
+
let remainingDelayMs = delayMs;
|
|
3496
|
+
while (remainingDelayMs > 0) {
|
|
3497
|
+
await ((_b = options.waitForPauseCheckpoint) === null || _b === void 0 ? void 0 : _b.call(options, {
|
|
3498
|
+
checkpointLabel: 'the Claude Code session limit reset',
|
|
3499
|
+
phase: 'waiting',
|
|
3500
|
+
statusMessage: `Claude Code session ${sessionLabel} hit its limit; resurrection #${resurrectionCount} resumes in ${formatDurationMs(remainingDelayMs)}`,
|
|
3501
|
+
}));
|
|
3502
|
+
const currentDelayMs = Math.min(CLAUDE_CODE_SESSION_RESURRECTION_POLL_MS, remainingDelayMs);
|
|
3503
|
+
await waitFor$1(currentDelayMs);
|
|
3504
|
+
remainingDelayMs -= currentDelayMs;
|
|
3505
|
+
}
|
|
3506
|
+
await ((_c = options.waitForPauseCheckpoint) === null || _c === void 0 ? void 0 : _c.call(options, {
|
|
3507
|
+
checkpointLabel: 'resurrecting the Claude Code session with --resume',
|
|
3508
|
+
phase: 'running',
|
|
3509
|
+
statusMessage: `Resurrecting Claude Code session ${sessionLabel} with --resume`,
|
|
3510
|
+
}));
|
|
3511
|
+
}
|
|
3512
|
+
/**
|
|
3513
|
+
* Waits for a fixed amount of milliseconds.
|
|
3514
|
+
*/
|
|
3515
|
+
async function waitFor$1(delayMs) {
|
|
3516
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
3517
|
+
}
|
|
3518
|
+
/**
|
|
3519
|
+
* Formats a Claude Code session id for compact terminal status lines.
|
|
3520
|
+
*/
|
|
3521
|
+
function formatClaudeCodeSessionIdForDisplay(sessionId) {
|
|
3522
|
+
if (sessionId.length <= 8) {
|
|
3523
|
+
return sessionId;
|
|
3524
|
+
}
|
|
3525
|
+
return `${sessionId.slice(0, 8)}...`;
|
|
3526
|
+
}
|
|
3195
3527
|
|
|
3196
3528
|
/**
|
|
3197
3529
|
* Creates a temporary script file, runs it, and cleans it up unless preservation is requested or the run fails.
|
|
@@ -5087,6 +5419,95 @@
|
|
|
5087
5419
|
// TODO: [🏛] Escape all
|
|
5088
5420
|
// TODO: [🧠] Should be in generated .book.md file GENERATOR_WARNING
|
|
5089
5421
|
|
|
5422
|
+
/**
|
|
5423
|
+
* This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
|
|
5424
|
+
*
|
|
5425
|
+
* @public exported from `@promptbook/core`
|
|
5426
|
+
*/
|
|
5427
|
+
class PipelineLogicError extends Error {
|
|
5428
|
+
constructor(message) {
|
|
5429
|
+
super(message);
|
|
5430
|
+
this.name = 'PipelineLogicError';
|
|
5431
|
+
Object.setPrototypeOf(this, PipelineLogicError.prototype);
|
|
5432
|
+
}
|
|
5433
|
+
}
|
|
5434
|
+
|
|
5435
|
+
/**
|
|
5436
|
+
* Creates the shared validation context for one pipeline.
|
|
5437
|
+
*
|
|
5438
|
+
* @private function of `validatePipeline`
|
|
5439
|
+
*/
|
|
5440
|
+
function createPipelineValidationContext(pipeline) {
|
|
5441
|
+
return {
|
|
5442
|
+
pipeline,
|
|
5443
|
+
pipelineIdentification: getPipelineIdentification$1(pipeline),
|
|
5444
|
+
};
|
|
5445
|
+
}
|
|
5446
|
+
/**
|
|
5447
|
+
* Builds a short file/url identification block for validation errors.
|
|
5448
|
+
*
|
|
5449
|
+
* @private internal utility of `validatePipeline`
|
|
5450
|
+
*/
|
|
5451
|
+
function getPipelineIdentification$1(pipeline) {
|
|
5452
|
+
// Note: This is a 😐 implementation of [🚞]
|
|
5453
|
+
const pipelineIdentificationParts = [];
|
|
5454
|
+
if (pipeline.sourceFile !== undefined) {
|
|
5455
|
+
pipelineIdentificationParts.push(`File: ${pipeline.sourceFile}`);
|
|
5456
|
+
}
|
|
5457
|
+
if (pipeline.pipelineUrl !== undefined) {
|
|
5458
|
+
pipelineIdentificationParts.push(`Url: ${pipeline.pipelineUrl}`);
|
|
5459
|
+
}
|
|
5460
|
+
return pipelineIdentificationParts.join('\n');
|
|
5461
|
+
}
|
|
5462
|
+
|
|
5463
|
+
/**
|
|
5464
|
+
* Validates that the expected top-level collections have array structure.
|
|
5465
|
+
*
|
|
5466
|
+
* @private function of `validatePipeline`
|
|
5467
|
+
*/
|
|
5468
|
+
function validatePipelineCollectionsStructure({ pipeline, pipelineIdentification, }) {
|
|
5469
|
+
validatePipelineParametersCollection(pipeline, pipelineIdentification);
|
|
5470
|
+
validatePipelineTasksCollection(pipeline, pipelineIdentification);
|
|
5471
|
+
}
|
|
5472
|
+
/**
|
|
5473
|
+
* Validates that `pipeline.parameters` is an array.
|
|
5474
|
+
*
|
|
5475
|
+
* @private internal utility of `validatePipelineCollectionsStructure`
|
|
5476
|
+
*/
|
|
5477
|
+
function validatePipelineParametersCollection(pipeline, pipelineIdentification) {
|
|
5478
|
+
// TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
|
|
5479
|
+
if (Array.isArray(pipeline.parameters)) {
|
|
5480
|
+
return;
|
|
5481
|
+
}
|
|
5482
|
+
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5483
|
+
throw new ParseError(_spaceTrim.spaceTrim((block) => `
|
|
5484
|
+
Pipeline is valid JSON but with wrong structure
|
|
5485
|
+
|
|
5486
|
+
\`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
|
|
5487
|
+
|
|
5488
|
+
${block(pipelineIdentification)}
|
|
5489
|
+
`));
|
|
5490
|
+
}
|
|
5491
|
+
/**
|
|
5492
|
+
* Validates that `pipeline.tasks` is an array.
|
|
5493
|
+
*
|
|
5494
|
+
* @private internal utility of `validatePipelineCollectionsStructure`
|
|
5495
|
+
*/
|
|
5496
|
+
function validatePipelineTasksCollection(pipeline, pipelineIdentification) {
|
|
5497
|
+
// TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
|
|
5498
|
+
if (Array.isArray(pipeline.tasks)) {
|
|
5499
|
+
return;
|
|
5500
|
+
}
|
|
5501
|
+
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5502
|
+
throw new ParseError(_spaceTrim.spaceTrim((block) => `
|
|
5503
|
+
Pipeline is valid JSON but with wrong structure
|
|
5504
|
+
|
|
5505
|
+
\`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
|
|
5506
|
+
|
|
5507
|
+
${block(pipelineIdentification)}
|
|
5508
|
+
`));
|
|
5509
|
+
}
|
|
5510
|
+
|
|
5090
5511
|
/**
|
|
5091
5512
|
* Order of keys in the pipeline JSON
|
|
5092
5513
|
*
|
|
@@ -5199,16 +5620,137 @@
|
|
|
5199
5620
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
5200
5621
|
|
|
5201
5622
|
/**
|
|
5202
|
-
*
|
|
5623
|
+
* Validates that task dependencies can be resolved without cycles or missing definitions.
|
|
5203
5624
|
*
|
|
5204
|
-
* @
|
|
5625
|
+
* @private function of `validatePipeline`
|
|
5205
5626
|
*/
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5627
|
+
function validatePipelineDependencyResolution({ pipeline, pipelineIdentification, }) {
|
|
5628
|
+
let dependencyResolutionState = createInitialDependencyResolutionState(pipeline);
|
|
5629
|
+
let loopLimit = LOOP_LIMIT;
|
|
5630
|
+
while (hasUnresolvedTasks(dependencyResolutionState)) {
|
|
5631
|
+
if (loopLimit-- < 0) {
|
|
5632
|
+
throw createDependencyResolutionLoopLimitError(pipelineIdentification);
|
|
5633
|
+
}
|
|
5634
|
+
dependencyResolutionState = resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification);
|
|
5635
|
+
}
|
|
5636
|
+
}
|
|
5637
|
+
/**
|
|
5638
|
+
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
5639
|
+
*
|
|
5640
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5641
|
+
*/
|
|
5642
|
+
function createInitialDependencyResolutionState(pipeline) {
|
|
5643
|
+
return {
|
|
5644
|
+
resolvedParameterNames: createInitiallyResolvedParameterNames(pipeline),
|
|
5645
|
+
unresolvedTasks: [...pipeline.tasks],
|
|
5646
|
+
};
|
|
5647
|
+
}
|
|
5648
|
+
/**
|
|
5649
|
+
* Checks whether dependency resolution still has tasks left to process.
|
|
5650
|
+
*
|
|
5651
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5652
|
+
*/
|
|
5653
|
+
function hasUnresolvedTasks({ unresolvedTasks }) {
|
|
5654
|
+
return unresolvedTasks.length > 0;
|
|
5655
|
+
}
|
|
5656
|
+
/**
|
|
5657
|
+
* Resolves the next batch of currently satisfiable tasks.
|
|
5658
|
+
*
|
|
5659
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5660
|
+
*/
|
|
5661
|
+
function resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification) {
|
|
5662
|
+
const currentlyResolvedTasks = getCurrentlyResolvedTasks(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames);
|
|
5663
|
+
if (currentlyResolvedTasks.length === 0) {
|
|
5664
|
+
throw createUnresolvedTasksError(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames, pipelineIdentification);
|
|
5211
5665
|
}
|
|
5666
|
+
return {
|
|
5667
|
+
resolvedParameterNames: appendResolvedTaskParameterNames(dependencyResolutionState.resolvedParameterNames, currentlyResolvedTasks),
|
|
5668
|
+
unresolvedTasks: dependencyResolutionState.unresolvedTasks.filter((task) => !currentlyResolvedTasks.includes(task)),
|
|
5669
|
+
};
|
|
5670
|
+
}
|
|
5671
|
+
/**
|
|
5672
|
+
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
5673
|
+
*
|
|
5674
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5675
|
+
*/
|
|
5676
|
+
function createInitiallyResolvedParameterNames(pipeline) {
|
|
5677
|
+
let resolvedParameterNames = pipeline.parameters
|
|
5678
|
+
.filter(({ isInput }) => isInput)
|
|
5679
|
+
.map(({ name }) => name);
|
|
5680
|
+
for (const reservedParameterName of RESERVED_PARAMETER_NAMES) {
|
|
5681
|
+
resolvedParameterNames = [...resolvedParameterNames, reservedParameterName];
|
|
5682
|
+
}
|
|
5683
|
+
return resolvedParameterNames;
|
|
5684
|
+
}
|
|
5685
|
+
/**
|
|
5686
|
+
* Adds newly resolved task outputs to the resolved parameter list.
|
|
5687
|
+
*
|
|
5688
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5689
|
+
*/
|
|
5690
|
+
function appendResolvedTaskParameterNames(resolvedParameterNames, currentlyResolvedTasks) {
|
|
5691
|
+
return [
|
|
5692
|
+
...resolvedParameterNames,
|
|
5693
|
+
...currentlyResolvedTasks.map(({ resultingParameterName }) => resultingParameterName),
|
|
5694
|
+
];
|
|
5695
|
+
}
|
|
5696
|
+
/**
|
|
5697
|
+
* Selects tasks whose dependencies are already resolved.
|
|
5698
|
+
*
|
|
5699
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5700
|
+
*/
|
|
5701
|
+
function getCurrentlyResolvedTasks(unresolvedTasks, resolvedParameterNames) {
|
|
5702
|
+
return unresolvedTasks.filter((task) => task.dependentParameterNames.every((name) => resolvedParameterNames.includes(name)));
|
|
5703
|
+
}
|
|
5704
|
+
/**
|
|
5705
|
+
* Creates the unexpected loop-limit error for dependency resolution.
|
|
5706
|
+
*
|
|
5707
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5708
|
+
*/
|
|
5709
|
+
function createDependencyResolutionLoopLimitError(pipelineIdentification) {
|
|
5710
|
+
// Note: Really UnexpectedError not LimitReachedError - this should not happen and be caught below
|
|
5711
|
+
return new UnexpectedError(_spaceTrim.spaceTrim((block) => `
|
|
5712
|
+
Loop limit reached during detection of circular dependencies in \`validatePipeline\`
|
|
5713
|
+
|
|
5714
|
+
${block(pipelineIdentification)}
|
|
5715
|
+
`));
|
|
5716
|
+
}
|
|
5717
|
+
/**
|
|
5718
|
+
* Creates the detailed error for unresolved or circular task dependencies.
|
|
5719
|
+
*
|
|
5720
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5721
|
+
*/
|
|
5722
|
+
function createUnresolvedTasksError(unresolvedTasks, resolvedParameterNames, pipelineIdentification) {
|
|
5723
|
+
return new PipelineLogicError(
|
|
5724
|
+
// TODO: [🐎] DRY
|
|
5725
|
+
_spaceTrim.spaceTrim((block) => `
|
|
5726
|
+
|
|
5727
|
+
Can not resolve some parameters:
|
|
5728
|
+
Either you are using a parameter that is not defined, or there are some circular dependencies.
|
|
5729
|
+
|
|
5730
|
+
${block(pipelineIdentification)}
|
|
5731
|
+
|
|
5732
|
+
**Can not resolve:**
|
|
5733
|
+
${block(unresolvedTasks
|
|
5734
|
+
.map(({ resultingParameterName, dependentParameterNames }) => `- Parameter \`{${resultingParameterName}}\` which depends on ${dependentParameterNames
|
|
5735
|
+
.map((dependentParameterName) => `\`{${dependentParameterName}}\``)
|
|
5736
|
+
.join(' and ')}`)
|
|
5737
|
+
.join('\n'))}
|
|
5738
|
+
|
|
5739
|
+
**Resolved:**
|
|
5740
|
+
${block(resolvedParameterNames
|
|
5741
|
+
.filter((name) => !RESERVED_PARAMETER_NAMES.includes(name))
|
|
5742
|
+
.map((name) => `- Parameter \`{${name}}\``)
|
|
5743
|
+
.join('\n'))}
|
|
5744
|
+
|
|
5745
|
+
|
|
5746
|
+
**Reserved (which are available):**
|
|
5747
|
+
${block(resolvedParameterNames
|
|
5748
|
+
.filter((name) => RESERVED_PARAMETER_NAMES.includes(name))
|
|
5749
|
+
.map((name) => `- Parameter \`{${name}}\``)
|
|
5750
|
+
.join('\n'))}
|
|
5751
|
+
|
|
5752
|
+
|
|
5753
|
+
`));
|
|
5212
5754
|
}
|
|
5213
5755
|
|
|
5214
5756
|
/**
|
|
@@ -5285,168 +5827,19 @@
|
|
|
5285
5827
|
}
|
|
5286
5828
|
// TODO: [🐠] Maybe more info why the URL is invalid
|
|
5287
5829
|
|
|
5288
|
-
/**
|
|
5289
|
-
* Validates PipelineJson if it is logically valid
|
|
5290
|
-
*
|
|
5291
|
-
* It checks:
|
|
5292
|
-
* - if it has correct parameters dependency
|
|
5293
|
-
*
|
|
5294
|
-
* It does NOT check:
|
|
5295
|
-
* - if it is valid json
|
|
5296
|
-
* - if it is meaningful
|
|
5297
|
-
*
|
|
5298
|
-
* Note: [🔂] This function is idempotent.
|
|
5299
|
-
*
|
|
5300
|
-
* @param pipeline valid or invalid PipelineJson
|
|
5301
|
-
* @returns the same pipeline if it is logically valid
|
|
5302
|
-
* @throws {PipelineLogicError} on logical error in the pipeline
|
|
5303
|
-
*
|
|
5304
|
-
* @public exported from `@promptbook/core`
|
|
5305
|
-
*/
|
|
5306
|
-
function validatePipeline(pipeline) {
|
|
5307
|
-
if (IS_PIPELINE_LOGIC_VALIDATED) {
|
|
5308
|
-
validatePipeline_InnerFunction(pipeline);
|
|
5309
|
-
}
|
|
5310
|
-
else {
|
|
5311
|
-
try {
|
|
5312
|
-
validatePipeline_InnerFunction(pipeline);
|
|
5313
|
-
}
|
|
5314
|
-
catch (error) {
|
|
5315
|
-
if (!(error instanceof PipelineLogicError)) {
|
|
5316
|
-
throw error;
|
|
5317
|
-
}
|
|
5318
|
-
console.error(_spaceTrim.spaceTrim((block) => `
|
|
5319
|
-
Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
|
|
5320
|
-
|
|
5321
|
-
${block(error.message)}
|
|
5322
|
-
`));
|
|
5323
|
-
}
|
|
5324
|
-
}
|
|
5325
|
-
return pipeline;
|
|
5326
|
-
}
|
|
5327
|
-
/**
|
|
5328
|
-
* Validates pipeline inner function.
|
|
5329
|
-
*
|
|
5330
|
-
* @private internal function for `validatePipeline`
|
|
5331
|
-
*/
|
|
5332
|
-
function validatePipeline_InnerFunction(pipeline) {
|
|
5333
|
-
// TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
|
|
5334
|
-
const context = createPipelineValidationContext(pipeline);
|
|
5335
|
-
validatePipelineMetadata(context);
|
|
5336
|
-
validatePipelineCollectionsStructure(context);
|
|
5337
|
-
validatePipelineParameters(context);
|
|
5338
|
-
validatePipelineTasks(context);
|
|
5339
|
-
validatePipelineDependencyResolution(context);
|
|
5340
|
-
// Note: Check that formfactor is corresponding to the pipeline interface
|
|
5341
|
-
// TODO: !!6 Implement this
|
|
5342
|
-
// pipeline.formfactorName
|
|
5343
|
-
}
|
|
5344
|
-
/**
|
|
5345
|
-
* Creates the shared validation context for one pipeline.
|
|
5346
|
-
*
|
|
5347
|
-
* @private internal utility of `validatePipeline`
|
|
5348
|
-
*/
|
|
5349
|
-
function createPipelineValidationContext(pipeline) {
|
|
5350
|
-
return {
|
|
5351
|
-
pipeline,
|
|
5352
|
-
pipelineIdentification: getPipelineIdentification$1(pipeline),
|
|
5353
|
-
};
|
|
5354
|
-
}
|
|
5355
|
-
/**
|
|
5356
|
-
* Builds a short file/url identification block for validation errors.
|
|
5357
|
-
*
|
|
5358
|
-
* @private internal utility of `validatePipeline`
|
|
5359
|
-
*/
|
|
5360
|
-
function getPipelineIdentification$1(pipeline) {
|
|
5361
|
-
// Note: This is a 😐 implementation of [🚞]
|
|
5362
|
-
const pipelineIdentificationParts = [];
|
|
5363
|
-
if (pipeline.sourceFile !== undefined) {
|
|
5364
|
-
pipelineIdentificationParts.push(`File: ${pipeline.sourceFile}`);
|
|
5365
|
-
}
|
|
5366
|
-
if (pipeline.pipelineUrl !== undefined) {
|
|
5367
|
-
pipelineIdentificationParts.push(`Url: ${pipeline.pipelineUrl}`);
|
|
5368
|
-
}
|
|
5369
|
-
return pipelineIdentificationParts.join('\n');
|
|
5370
|
-
}
|
|
5371
5830
|
/**
|
|
5372
5831
|
* Validates pipeline-level metadata fields.
|
|
5373
5832
|
*
|
|
5374
|
-
* @private
|
|
5833
|
+
* @private function of `validatePipeline`
|
|
5375
5834
|
*/
|
|
5376
5835
|
function validatePipelineMetadata({ pipeline, pipelineIdentification }) {
|
|
5377
5836
|
validatePipelineUrl(pipeline, pipelineIdentification);
|
|
5378
5837
|
validatePipelineBookVersion(pipeline, pipelineIdentification);
|
|
5379
5838
|
}
|
|
5380
|
-
/**
|
|
5381
|
-
* Validates that the expected top-level collections have array structure.
|
|
5382
|
-
*
|
|
5383
|
-
* @private internal step of `validatePipeline`
|
|
5384
|
-
*/
|
|
5385
|
-
function validatePipelineCollectionsStructure({ pipeline, pipelineIdentification }) {
|
|
5386
|
-
validatePipelineParametersCollection(pipeline, pipelineIdentification);
|
|
5387
|
-
validatePipelineTasksCollection(pipeline, pipelineIdentification);
|
|
5388
|
-
}
|
|
5389
|
-
/**
|
|
5390
|
-
* Validates all pipeline parameter declarations.
|
|
5391
|
-
*
|
|
5392
|
-
* @private internal step of `validatePipeline`
|
|
5393
|
-
*/
|
|
5394
|
-
function validatePipelineParameters({ pipeline, pipelineIdentification }) {
|
|
5395
|
-
for (const parameter of pipeline.parameters) {
|
|
5396
|
-
validatePipelineParameter(parameter, pipeline, pipelineIdentification);
|
|
5397
|
-
}
|
|
5398
|
-
}
|
|
5399
|
-
/**
|
|
5400
|
-
* Validates all pipeline tasks and their per-task invariants.
|
|
5401
|
-
*
|
|
5402
|
-
* @private internal step of `validatePipeline`
|
|
5403
|
-
*/
|
|
5404
|
-
function validatePipelineTasks({ pipeline, pipelineIdentification }) {
|
|
5405
|
-
// Note: All input parameters are defined - so that they can be used as result of some task
|
|
5406
|
-
const definedParameters = createInitiallyDefinedParameters(pipeline);
|
|
5407
|
-
for (const task of pipeline.tasks) {
|
|
5408
|
-
validatePipelineTask(task, definedParameters, pipelineIdentification);
|
|
5409
|
-
}
|
|
5410
|
-
}
|
|
5411
|
-
/**
|
|
5412
|
-
* Validates that task dependencies can be resolved without cycles or missing definitions.
|
|
5413
|
-
*
|
|
5414
|
-
* @private internal step of `validatePipeline`
|
|
5415
|
-
*/
|
|
5416
|
-
function validatePipelineDependencyResolution({ pipeline, pipelineIdentification }) {
|
|
5417
|
-
let dependencyResolutionState = createInitialDependencyResolutionState(pipeline);
|
|
5418
|
-
let loopLimit = LOOP_LIMIT;
|
|
5419
|
-
while (hasUnresolvedTasks(dependencyResolutionState)) {
|
|
5420
|
-
if (loopLimit-- < 0) {
|
|
5421
|
-
throw createDependencyResolutionLoopLimitError(pipelineIdentification);
|
|
5422
|
-
}
|
|
5423
|
-
dependencyResolutionState = resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification);
|
|
5424
|
-
}
|
|
5425
|
-
}
|
|
5426
|
-
/**
|
|
5427
|
-
* Validates one pipeline parameter declaration.
|
|
5428
|
-
*
|
|
5429
|
-
* @private internal step of `validatePipeline`
|
|
5430
|
-
*/
|
|
5431
|
-
function validatePipelineParameter(parameter, pipeline, pipelineIdentification) {
|
|
5432
|
-
validateParameterDirection(parameter, pipelineIdentification);
|
|
5433
|
-
validateParameterUsage(parameter, pipeline, pipelineIdentification);
|
|
5434
|
-
validateParameterDefinition(parameter, pipeline, pipelineIdentification);
|
|
5435
|
-
}
|
|
5436
|
-
/**
|
|
5437
|
-
* Validates one pipeline task and its invariants.
|
|
5438
|
-
*
|
|
5439
|
-
* @private internal step of `validatePipeline`
|
|
5440
|
-
*/
|
|
5441
|
-
function validatePipelineTask(task, definedParameters, pipelineIdentification) {
|
|
5442
|
-
validateTaskResultingParameter(task, definedParameters, pipelineIdentification);
|
|
5443
|
-
validateTaskJokers(task, pipelineIdentification);
|
|
5444
|
-
validateTaskExpectations(task, pipelineIdentification);
|
|
5445
|
-
}
|
|
5446
5839
|
/**
|
|
5447
5840
|
* Validates the pipeline URL, when present.
|
|
5448
5841
|
*
|
|
5449
|
-
* @private internal utility of `
|
|
5842
|
+
* @private internal utility of `validatePipelineMetadata`
|
|
5450
5843
|
*/
|
|
5451
5844
|
function validatePipelineUrl(pipeline, pipelineIdentification) {
|
|
5452
5845
|
if (pipeline.pipelineUrl === undefined || isValidPipelineUrl(pipeline.pipelineUrl)) {
|
|
@@ -5462,7 +5855,7 @@
|
|
|
5462
5855
|
/**
|
|
5463
5856
|
* Validates the Promptbook version, when present.
|
|
5464
5857
|
*
|
|
5465
|
-
* @private internal utility of `
|
|
5858
|
+
* @private internal utility of `validatePipelineMetadata`
|
|
5466
5859
|
*/
|
|
5467
5860
|
function validatePipelineBookVersion(pipeline, pipelineIdentification) {
|
|
5468
5861
|
if (pipeline.bookVersion === undefined || isValidPromptbookVersion(pipeline.bookVersion)) {
|
|
@@ -5475,48 +5868,31 @@
|
|
|
5475
5868
|
${block(pipelineIdentification)}
|
|
5476
5869
|
`));
|
|
5477
5870
|
}
|
|
5871
|
+
|
|
5478
5872
|
/**
|
|
5479
|
-
* Validates
|
|
5873
|
+
* Validates all pipeline parameter declarations.
|
|
5480
5874
|
*
|
|
5481
|
-
* @private
|
|
5875
|
+
* @private function of `validatePipeline`
|
|
5482
5876
|
*/
|
|
5483
|
-
function
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
return;
|
|
5877
|
+
function validatePipelineParameters({ pipeline, pipelineIdentification }) {
|
|
5878
|
+
for (const parameter of pipeline.parameters) {
|
|
5879
|
+
validatePipelineParameter(parameter, pipeline, pipelineIdentification);
|
|
5487
5880
|
}
|
|
5488
|
-
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5489
|
-
throw new ParseError(_spaceTrim.spaceTrim((block) => `
|
|
5490
|
-
Pipeline is valid JSON but with wrong structure
|
|
5491
|
-
|
|
5492
|
-
\`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
|
|
5493
|
-
|
|
5494
|
-
${block(pipelineIdentification)}
|
|
5495
|
-
`));
|
|
5496
5881
|
}
|
|
5497
5882
|
/**
|
|
5498
|
-
* Validates
|
|
5883
|
+
* Validates one pipeline parameter declaration.
|
|
5499
5884
|
*
|
|
5500
|
-
* @private internal utility of `
|
|
5885
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5501
5886
|
*/
|
|
5502
|
-
function
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
}
|
|
5507
|
-
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5508
|
-
throw new ParseError(_spaceTrim.spaceTrim((block) => `
|
|
5509
|
-
Pipeline is valid JSON but with wrong structure
|
|
5510
|
-
|
|
5511
|
-
\`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
|
|
5512
|
-
|
|
5513
|
-
${block(pipelineIdentification)}
|
|
5514
|
-
`));
|
|
5887
|
+
function validatePipelineParameter(parameter, pipeline, pipelineIdentification) {
|
|
5888
|
+
validateParameterDirection(parameter, pipelineIdentification);
|
|
5889
|
+
validateParameterUsage(parameter, pipeline, pipelineIdentification);
|
|
5890
|
+
validateParameterDefinition(parameter, pipeline, pipelineIdentification);
|
|
5515
5891
|
}
|
|
5516
5892
|
/**
|
|
5517
5893
|
* Validates that one parameter does not declare incompatible directions.
|
|
5518
5894
|
*
|
|
5519
|
-
* @private internal utility of `
|
|
5895
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5520
5896
|
*/
|
|
5521
5897
|
function validateParameterDirection(parameter, pipelineIdentification) {
|
|
5522
5898
|
if (!parameter.isInput || !parameter.isOutput) {
|
|
@@ -5533,7 +5909,7 @@
|
|
|
5533
5909
|
/**
|
|
5534
5910
|
* Validates that one intermediate parameter is actually consumed by at least one task.
|
|
5535
5911
|
*
|
|
5536
|
-
* @private internal utility of `
|
|
5912
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5537
5913
|
*/
|
|
5538
5914
|
function validateParameterUsage(parameter, pipeline, pipelineIdentification) {
|
|
5539
5915
|
if (parameter.isInput || parameter.isOutput || isParameterUsedByAnyTask(parameter, pipeline.tasks)) {
|
|
@@ -5552,7 +5928,7 @@
|
|
|
5552
5928
|
/**
|
|
5553
5929
|
* Validates that one non-input parameter is produced by at least one task.
|
|
5554
5930
|
*
|
|
5555
|
-
* @private internal utility of `
|
|
5931
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5556
5932
|
*/
|
|
5557
5933
|
function validateParameterDefinition(parameter, pipeline, pipelineIdentification) {
|
|
5558
5934
|
if (parameter.isInput || isParameterDefinedByAnyTask(parameter, pipeline.tasks)) {
|
|
@@ -5571,7 +5947,7 @@
|
|
|
5571
5947
|
/**
|
|
5572
5948
|
* Checks whether one parameter is consumed by at least one task dependency list.
|
|
5573
5949
|
*
|
|
5574
|
-
* @private internal utility of `
|
|
5950
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5575
5951
|
*/
|
|
5576
5952
|
function isParameterUsedByAnyTask(parameter, tasks) {
|
|
5577
5953
|
return tasks.some((task) => task.dependentParameterNames.includes(parameter.name));
|
|
@@ -5579,23 +5955,46 @@
|
|
|
5579
5955
|
/**
|
|
5580
5956
|
* Checks whether one parameter is produced by at least one task.
|
|
5581
5957
|
*
|
|
5582
|
-
* @private internal utility of `
|
|
5958
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5583
5959
|
*/
|
|
5584
5960
|
function isParameterDefinedByAnyTask(parameter, tasks) {
|
|
5585
5961
|
return tasks.some((task) => task.resultingParameterName === parameter.name);
|
|
5586
5962
|
}
|
|
5963
|
+
|
|
5964
|
+
/**
|
|
5965
|
+
* Validates all pipeline tasks and their per-task invariants.
|
|
5966
|
+
*
|
|
5967
|
+
* @private function of `validatePipeline`
|
|
5968
|
+
*/
|
|
5969
|
+
function validatePipelineTasks({ pipeline, pipelineIdentification }) {
|
|
5970
|
+
// Note: All input parameters are defined - so that they can be used as result of some task
|
|
5971
|
+
const definedParameters = createInitiallyDefinedParameters(pipeline);
|
|
5972
|
+
for (const task of pipeline.tasks) {
|
|
5973
|
+
validatePipelineTask(task, definedParameters, pipelineIdentification);
|
|
5974
|
+
}
|
|
5975
|
+
}
|
|
5587
5976
|
/**
|
|
5588
5977
|
* Collects the parameter names that are already defined before task validation starts.
|
|
5589
5978
|
*
|
|
5590
|
-
* @private internal utility of `
|
|
5979
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5591
5980
|
*/
|
|
5592
5981
|
function createInitiallyDefinedParameters(pipeline) {
|
|
5593
5982
|
return new Set(pipeline.parameters.filter(({ isInput }) => isInput).map(({ name }) => name));
|
|
5594
5983
|
}
|
|
5984
|
+
/**
|
|
5985
|
+
* Validates one pipeline task and its invariants.
|
|
5986
|
+
*
|
|
5987
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5988
|
+
*/
|
|
5989
|
+
function validatePipelineTask(task, definedParameters, pipelineIdentification) {
|
|
5990
|
+
validateTaskResultingParameter(task, definedParameters, pipelineIdentification);
|
|
5991
|
+
validateTaskJokers(task, pipelineIdentification);
|
|
5992
|
+
validateTaskExpectations(task, pipelineIdentification);
|
|
5993
|
+
}
|
|
5595
5994
|
/**
|
|
5596
5995
|
* Validates one task result parameter declaration and marks it as defined.
|
|
5597
5996
|
*
|
|
5598
|
-
* @private internal utility of `
|
|
5997
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5599
5998
|
*/
|
|
5600
5999
|
function validateTaskResultingParameter(task, definedParameters, pipelineIdentification) {
|
|
5601
6000
|
if (definedParameters.has(task.resultingParameterName)) {
|
|
@@ -5617,7 +6016,7 @@
|
|
|
5617
6016
|
/**
|
|
5618
6017
|
* Validates joker parameters for one task.
|
|
5619
6018
|
*
|
|
5620
|
-
* @private internal utility of `
|
|
6019
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5621
6020
|
*/
|
|
5622
6021
|
function validateTaskJokers(task, pipelineIdentification) {
|
|
5623
6022
|
if (!hasTaskJokers(task)) {
|
|
@@ -5629,7 +6028,7 @@
|
|
|
5629
6028
|
/**
|
|
5630
6029
|
* Checks whether one task declares any joker parameters.
|
|
5631
6030
|
*
|
|
5632
|
-
* @private internal utility of `
|
|
6031
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5633
6032
|
*/
|
|
5634
6033
|
function hasTaskJokers(task) {
|
|
5635
6034
|
return !!task.jokerParameterNames && task.jokerParameterNames.length > 0;
|
|
@@ -5637,7 +6036,7 @@
|
|
|
5637
6036
|
/**
|
|
5638
6037
|
* Validates that a task has the required supporting features when using jokers.
|
|
5639
6038
|
*
|
|
5640
|
-
* @private internal utility of `
|
|
6039
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5641
6040
|
*/
|
|
5642
6041
|
function validateTaskSupportsJokers(task, pipelineIdentification) {
|
|
5643
6042
|
if (task.format || task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
|
|
@@ -5652,7 +6051,7 @@
|
|
|
5652
6051
|
/**
|
|
5653
6052
|
* Validates that every joker parameter is also listed among task dependencies.
|
|
5654
6053
|
*
|
|
5655
|
-
* @private internal utility of `
|
|
6054
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5656
6055
|
*/
|
|
5657
6056
|
function validateTaskJokerDependencies(task, pipelineIdentification) {
|
|
5658
6057
|
for (const joker of task.jokerParameterNames) {
|
|
@@ -5669,7 +6068,7 @@
|
|
|
5669
6068
|
/**
|
|
5670
6069
|
* Validates all expectation bounds configured on one task.
|
|
5671
6070
|
*
|
|
5672
|
-
* @private internal utility of `
|
|
6071
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5673
6072
|
*/
|
|
5674
6073
|
function validateTaskExpectations(task, pipelineIdentification) {
|
|
5675
6074
|
if (!task.expectations) {
|
|
@@ -5684,7 +6083,7 @@
|
|
|
5684
6083
|
/**
|
|
5685
6084
|
* Validates the minimum and maximum expectation ordering for one unit.
|
|
5686
6085
|
*
|
|
5687
|
-
* @private internal utility of `
|
|
6086
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5688
6087
|
*/
|
|
5689
6088
|
function validateTaskExpectationRange(unit, min, max, pipelineIdentification) {
|
|
5690
6089
|
if (min === undefined || max === undefined || min <= max) {
|
|
@@ -5699,7 +6098,7 @@
|
|
|
5699
6098
|
/**
|
|
5700
6099
|
* Validates the minimum expectation bound for one unit.
|
|
5701
6100
|
*
|
|
5702
|
-
* @private internal utility of `
|
|
6101
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5703
6102
|
*/
|
|
5704
6103
|
function validateTaskExpectationMin(unit, min, pipelineIdentification) {
|
|
5705
6104
|
if (min === undefined || min >= 0) {
|
|
@@ -5714,7 +6113,7 @@
|
|
|
5714
6113
|
/**
|
|
5715
6114
|
* Validates the maximum expectation bound for one unit.
|
|
5716
6115
|
*
|
|
5717
|
-
* @private internal utility of `
|
|
6116
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5718
6117
|
*/
|
|
5719
6118
|
function validateTaskExpectationMax(unit, max, pipelineIdentification) {
|
|
5720
6119
|
if (max === undefined || max > 0) {
|
|
@@ -5726,123 +6125,62 @@
|
|
|
5726
6125
|
${block(pipelineIdentification)}
|
|
5727
6126
|
`));
|
|
5728
6127
|
}
|
|
6128
|
+
|
|
5729
6129
|
/**
|
|
5730
|
-
*
|
|
5731
|
-
*
|
|
5732
|
-
* @private internal utility of `validatePipeline`
|
|
5733
|
-
*/
|
|
5734
|
-
function createInitialDependencyResolutionState(pipeline) {
|
|
5735
|
-
return {
|
|
5736
|
-
resolvedParameterNames: createInitiallyResolvedParameterNames(pipeline),
|
|
5737
|
-
unresolvedTasks: [...pipeline.tasks],
|
|
5738
|
-
};
|
|
5739
|
-
}
|
|
5740
|
-
/**
|
|
5741
|
-
* Checks whether dependency resolution still has tasks left to process.
|
|
5742
|
-
*
|
|
5743
|
-
* @private internal utility of `validatePipeline`
|
|
5744
|
-
*/
|
|
5745
|
-
function hasUnresolvedTasks({ unresolvedTasks }) {
|
|
5746
|
-
return unresolvedTasks.length > 0;
|
|
5747
|
-
}
|
|
5748
|
-
/**
|
|
5749
|
-
* Resolves the next batch of currently satisfiable tasks.
|
|
6130
|
+
* Validates PipelineJson if it is logically valid
|
|
5750
6131
|
*
|
|
5751
|
-
*
|
|
5752
|
-
|
|
5753
|
-
function resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification) {
|
|
5754
|
-
const currentlyResolvedTasks = getCurrentlyResolvedTasks(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames);
|
|
5755
|
-
if (currentlyResolvedTasks.length === 0) {
|
|
5756
|
-
throw createUnresolvedTasksError(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames, pipelineIdentification);
|
|
5757
|
-
}
|
|
5758
|
-
return {
|
|
5759
|
-
resolvedParameterNames: appendResolvedTaskParameterNames(dependencyResolutionState.resolvedParameterNames, currentlyResolvedTasks),
|
|
5760
|
-
unresolvedTasks: dependencyResolutionState.unresolvedTasks.filter((task) => !currentlyResolvedTasks.includes(task)),
|
|
5761
|
-
};
|
|
5762
|
-
}
|
|
5763
|
-
/**
|
|
5764
|
-
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
6132
|
+
* It checks:
|
|
6133
|
+
* - if it has correct parameters dependency
|
|
5765
6134
|
*
|
|
5766
|
-
*
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
let resolvedParameterNames = pipeline.parameters
|
|
5770
|
-
.filter(({ isInput }) => isInput)
|
|
5771
|
-
.map(({ name }) => name);
|
|
5772
|
-
for (const reservedParameterName of RESERVED_PARAMETER_NAMES) {
|
|
5773
|
-
resolvedParameterNames = [...resolvedParameterNames, reservedParameterName];
|
|
5774
|
-
}
|
|
5775
|
-
return resolvedParameterNames;
|
|
5776
|
-
}
|
|
5777
|
-
/**
|
|
5778
|
-
* Adds newly resolved task outputs to the resolved parameter list.
|
|
6135
|
+
* It does NOT check:
|
|
6136
|
+
* - if it is valid json
|
|
6137
|
+
* - if it is meaningful
|
|
5779
6138
|
*
|
|
5780
|
-
*
|
|
5781
|
-
*/
|
|
5782
|
-
function appendResolvedTaskParameterNames(resolvedParameterNames, currentlyResolvedTasks) {
|
|
5783
|
-
return [
|
|
5784
|
-
...resolvedParameterNames,
|
|
5785
|
-
...currentlyResolvedTasks.map(({ resultingParameterName }) => resultingParameterName),
|
|
5786
|
-
];
|
|
5787
|
-
}
|
|
5788
|
-
/**
|
|
5789
|
-
* Selects tasks whose dependencies are already resolved.
|
|
6139
|
+
* Note: [🔂] This function is idempotent.
|
|
5790
6140
|
*
|
|
5791
|
-
* @
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
return unresolvedTasks.filter((task) => task.dependentParameterNames.every((name) => resolvedParameterNames.includes(name)));
|
|
5795
|
-
}
|
|
5796
|
-
/**
|
|
5797
|
-
* Creates the unexpected loop-limit error for dependency resolution.
|
|
6141
|
+
* @param pipeline valid or invalid PipelineJson
|
|
6142
|
+
* @returns the same pipeline if it is logically valid
|
|
6143
|
+
* @throws {PipelineLogicError} on logical error in the pipeline
|
|
5798
6144
|
*
|
|
5799
|
-
* @
|
|
6145
|
+
* @public exported from `@promptbook/core`
|
|
5800
6146
|
*/
|
|
5801
|
-
function
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
6147
|
+
function validatePipeline(pipeline) {
|
|
6148
|
+
if (IS_PIPELINE_LOGIC_VALIDATED) {
|
|
6149
|
+
validatePipeline_InnerFunction(pipeline);
|
|
6150
|
+
}
|
|
6151
|
+
else {
|
|
6152
|
+
try {
|
|
6153
|
+
validatePipeline_InnerFunction(pipeline);
|
|
6154
|
+
}
|
|
6155
|
+
catch (error) {
|
|
6156
|
+
if (!(error instanceof PipelineLogicError)) {
|
|
6157
|
+
throw error;
|
|
6158
|
+
}
|
|
6159
|
+
console.error(_spaceTrim.spaceTrim((block) => `
|
|
6160
|
+
Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
|
|
5805
6161
|
|
|
5806
|
-
|
|
5807
|
-
|
|
6162
|
+
${block(error.message)}
|
|
6163
|
+
`));
|
|
6164
|
+
}
|
|
6165
|
+
}
|
|
6166
|
+
return pipeline;
|
|
5808
6167
|
}
|
|
5809
6168
|
/**
|
|
5810
|
-
*
|
|
6169
|
+
* Validates pipeline inner function.
|
|
5811
6170
|
*
|
|
5812
|
-
* @private internal
|
|
6171
|
+
* @private internal function for `validatePipeline`
|
|
5813
6172
|
*/
|
|
5814
|
-
function
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
${block(unresolvedTasks
|
|
5826
|
-
.map(({ resultingParameterName, dependentParameterNames }) => `- Parameter \`{${resultingParameterName}}\` which depends on ${dependentParameterNames
|
|
5827
|
-
.map((dependentParameterName) => `\`{${dependentParameterName}}\``)
|
|
5828
|
-
.join(' and ')}`)
|
|
5829
|
-
.join('\n'))}
|
|
5830
|
-
|
|
5831
|
-
**Resolved:**
|
|
5832
|
-
${block(resolvedParameterNames
|
|
5833
|
-
.filter((name) => !RESERVED_PARAMETER_NAMES.includes(name))
|
|
5834
|
-
.map((name) => `- Parameter \`{${name}}\``)
|
|
5835
|
-
.join('\n'))}
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
**Reserved (which are available):**
|
|
5839
|
-
${block(resolvedParameterNames
|
|
5840
|
-
.filter((name) => RESERVED_PARAMETER_NAMES.includes(name))
|
|
5841
|
-
.map((name) => `- Parameter \`{${name}}\``)
|
|
5842
|
-
.join('\n'))}
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
`));
|
|
6173
|
+
function validatePipeline_InnerFunction(pipeline) {
|
|
6174
|
+
// TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
|
|
6175
|
+
const context = createPipelineValidationContext(pipeline);
|
|
6176
|
+
validatePipelineMetadata(context);
|
|
6177
|
+
validatePipelineCollectionsStructure(context);
|
|
6178
|
+
validatePipelineParameters(context);
|
|
6179
|
+
validatePipelineTasks(context);
|
|
6180
|
+
validatePipelineDependencyResolution(context);
|
|
6181
|
+
// Note: Check that formfactor is corresponding to the pipeline interface
|
|
6182
|
+
// TODO: !!6 Implement this
|
|
6183
|
+
// pipeline.formfactorName
|
|
5846
6184
|
}
|
|
5847
6185
|
/**
|
|
5848
6186
|
* TODO: [🧞♀️] Do not allow joker + foreach
|
|
@@ -14162,7 +14500,7 @@
|
|
|
14162
14500
|
* META commitment definition
|
|
14163
14501
|
*
|
|
14164
14502
|
* The META commitment handles all meta-information about the agent such as:
|
|
14165
|
-
* - META AVATAR: Sets the agent's built-in default avatar visual
|
|
14503
|
+
* - META AVATAR / META VISUAL: Sets the agent's built-in default avatar visual
|
|
14166
14504
|
* - META IMAGE: Sets the agent's avatar/profile image URL
|
|
14167
14505
|
* - META LINK: Provides profile/source links for the person the agent models
|
|
14168
14506
|
* - META DOMAIN: Sets the canonical custom domain/host of the agent
|
|
@@ -14177,7 +14515,7 @@
|
|
|
14177
14515
|
* Example usage in agent source:
|
|
14178
14516
|
*
|
|
14179
14517
|
* ```book
|
|
14180
|
-
* META
|
|
14518
|
+
* META VISUAL pixel-art
|
|
14181
14519
|
* META IMAGE https://example.com/avatar.jpg
|
|
14182
14520
|
* META LINK https://twitter.com/username
|
|
14183
14521
|
* META DOMAIN my-agent.com
|
|
@@ -14217,7 +14555,7 @@
|
|
|
14217
14555
|
|
|
14218
14556
|
## Supported META types
|
|
14219
14557
|
|
|
14220
|
-
- **META AVATAR** - Sets the agent's built-in default avatar visual
|
|
14558
|
+
- **META AVATAR** / **META VISUAL** - Sets the agent's built-in default avatar visual
|
|
14221
14559
|
- **META IMAGE** - Sets the agent's avatar/profile image URL
|
|
14222
14560
|
- **META LINK** - Provides profile/source links for the person the agent models
|
|
14223
14561
|
- **META DOMAIN** - Sets the canonical custom domain/host of the agent
|
|
@@ -14241,7 +14579,7 @@
|
|
|
14241
14579
|
\`\`\`book
|
|
14242
14580
|
Professional Assistant
|
|
14243
14581
|
|
|
14244
|
-
META
|
|
14582
|
+
META VISUAL octopus3
|
|
14245
14583
|
META IMAGE https://example.com/professional-avatar.jpg
|
|
14246
14584
|
META TITLE Senior Business Consultant
|
|
14247
14585
|
META DESCRIPTION Specialized in strategic planning and project management
|
|
@@ -17412,452 +17750,13 @@
|
|
|
17412
17750
|
.padStart(2, '0');
|
|
17413
17751
|
}
|
|
17414
17752
|
|
|
17415
|
-
/* eslint-disable no-magic-numbers */
|
|
17416
|
-
/**
|
|
17417
|
-
* Light direction used by the organic 3D octopus shading.
|
|
17418
|
-
*
|
|
17419
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17420
|
-
*/
|
|
17421
|
-
const LIGHT_DIRECTION$3 = normalizeVector3({
|
|
17422
|
-
x: 0.48,
|
|
17423
|
-
y: -0.62,
|
|
17424
|
-
z: 0.94,
|
|
17425
|
-
});
|
|
17426
|
-
/**
|
|
17427
|
-
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
17428
|
-
*
|
|
17429
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17430
|
-
*/
|
|
17431
|
-
const octopus3dStableStateCache = new WeakMap();
|
|
17432
|
-
/**
|
|
17433
|
-
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
17434
|
-
*
|
|
17435
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17436
|
-
*/
|
|
17437
|
-
function getOctopus3dStableState(createRandom) {
|
|
17438
|
-
const cached = octopus3dStableStateCache.get(createRandom);
|
|
17439
|
-
if (cached !== undefined) {
|
|
17440
|
-
return cached;
|
|
17441
|
-
}
|
|
17442
|
-
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
17443
|
-
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
17444
|
-
const leftEyePhaseOffset = eyeRandom() * 0.6;
|
|
17445
|
-
const rightEyePhaseOffset = eyeRandom() * 0.6;
|
|
17446
|
-
const state = {
|
|
17447
|
-
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
17448
|
-
animationPhase: animationRandom() * Math.PI * 2,
|
|
17449
|
-
leftEyePhaseOffset,
|
|
17450
|
-
rightEyePhaseOffset,
|
|
17451
|
-
};
|
|
17452
|
-
octopus3dStableStateCache.set(createRandom, state);
|
|
17453
|
-
return state;
|
|
17454
|
-
}
|
|
17455
|
-
/**
|
|
17456
|
-
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
17457
|
-
*
|
|
17458
|
-
* @private built-in avatar visual
|
|
17459
|
-
*/
|
|
17460
|
-
const octopus3dAvatarVisual = {
|
|
17461
|
-
id: 'octopus3d',
|
|
17462
|
-
title: 'Octopus 3D',
|
|
17463
|
-
description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
|
|
17464
|
-
isAnimated: true,
|
|
17465
|
-
supportsPointerTracking: true,
|
|
17466
|
-
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
17467
|
-
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
|
|
17468
|
-
const sceneCenterX = size * 0.5;
|
|
17469
|
-
const sceneCenterY = size * 0.56;
|
|
17470
|
-
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
17471
|
-
const mantleCenter = {
|
|
17472
|
-
x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
|
|
17473
|
-
y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
17474
|
-
z: interaction.intensity * size * 0.012,
|
|
17475
|
-
};
|
|
17476
|
-
const underbodyCenter = {
|
|
17477
|
-
x: mantleCenter.x * 0.86,
|
|
17478
|
-
y: mantleCenter.y + size * 0.168,
|
|
17479
|
-
z: mantleCenter.z - size * 0.018,
|
|
17480
|
-
};
|
|
17481
|
-
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
17482
|
-
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
17483
|
-
const mantleRadiusZ = size *
|
|
17484
|
-
morphologyProfile.body.bodyRadiusRatio *
|
|
17485
|
-
(0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
17486
|
-
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
17487
|
-
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
17488
|
-
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
17489
|
-
const bodyYaw = -0.18 +
|
|
17490
|
-
Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
|
|
17491
|
-
interaction.bodyOffsetX * 0.18 +
|
|
17492
|
-
interaction.gazeX * 0.22;
|
|
17493
|
-
const bodyPitch = -0.08 +
|
|
17494
|
-
Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
|
|
17495
|
-
interaction.bodyOffsetY * 0.08 -
|
|
17496
|
-
interaction.gazeY * 0.08;
|
|
17497
|
-
const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
|
|
17498
|
-
const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
|
|
17499
|
-
const mantlePatches = resolveVisibleEllipsoidPatches({
|
|
17500
|
-
center: mantleCenter,
|
|
17501
|
-
radiusX: mantleRadiusX,
|
|
17502
|
-
radiusY: mantleRadiusY,
|
|
17503
|
-
radiusZ: mantleRadiusZ,
|
|
17504
|
-
rotationX: headPitch,
|
|
17505
|
-
rotationY: headYaw,
|
|
17506
|
-
sceneCenterX,
|
|
17507
|
-
sceneCenterY,
|
|
17508
|
-
size,
|
|
17509
|
-
palette,
|
|
17510
|
-
verticalColorBias: 0,
|
|
17511
|
-
outlineColor: `${palette.highlight}7a`,
|
|
17512
|
-
});
|
|
17513
|
-
const underbodyPatches = resolveVisibleEllipsoidPatches({
|
|
17514
|
-
center: underbodyCenter,
|
|
17515
|
-
radiusX: underbodyRadiusX,
|
|
17516
|
-
radiusY: underbodyRadiusY,
|
|
17517
|
-
radiusZ: underbodyRadiusZ,
|
|
17518
|
-
rotationX: bodyPitch,
|
|
17519
|
-
rotationY: bodyYaw,
|
|
17520
|
-
sceneCenterX,
|
|
17521
|
-
sceneCenterY,
|
|
17522
|
-
size,
|
|
17523
|
-
palette,
|
|
17524
|
-
verticalColorBias: 0.18,
|
|
17525
|
-
outlineColor: `${palette.shadow}8f`,
|
|
17526
|
-
});
|
|
17527
|
-
const tentacleStrokes = createOctopusTentacleStrokes({
|
|
17528
|
-
createRandom,
|
|
17529
|
-
morphologyProfile,
|
|
17530
|
-
timeMs,
|
|
17531
|
-
size,
|
|
17532
|
-
center: underbodyCenter,
|
|
17533
|
-
radiusX: underbodyRadiusX,
|
|
17534
|
-
radiusY: underbodyRadiusY,
|
|
17535
|
-
radiusZ: underbodyRadiusZ,
|
|
17536
|
-
rotationX: bodyPitch,
|
|
17537
|
-
rotationY: bodyYaw,
|
|
17538
|
-
sceneCenterX,
|
|
17539
|
-
sceneCenterY,
|
|
17540
|
-
animationPhase,
|
|
17541
|
-
});
|
|
17542
|
-
const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
|
|
17543
|
-
const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
|
|
17544
|
-
const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
|
|
17545
|
-
const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
|
|
17546
|
-
const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
|
|
17547
|
-
const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
|
|
17548
|
-
drawAvatarFrame(context, size, palette);
|
|
17549
|
-
drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
17550
|
-
drawOctopus3dShadow(context, size, palette, interaction, timeMs);
|
|
17551
|
-
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
|
|
17552
|
-
drawTentacleStroke(context, tentacleStroke, palette);
|
|
17553
|
-
}
|
|
17554
|
-
for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
17555
|
-
drawSurfacePatch(context, surfacePatch);
|
|
17556
|
-
}
|
|
17557
|
-
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
17558
|
-
drawTentacleStroke(context, tentacleStroke, palette);
|
|
17559
|
-
}
|
|
17560
|
-
drawProjectedOrganicEye(context, {
|
|
17561
|
-
x: -faceEyeSpacing,
|
|
17562
|
-
y: faceEyeYOffset,
|
|
17563
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
17564
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
17565
|
-
drawProjectedOrganicEye(context, {
|
|
17566
|
-
x: faceEyeSpacing,
|
|
17567
|
-
y: faceEyeYOffset,
|
|
17568
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
17569
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
17570
|
-
drawProjectedOrganicMouth(context, [
|
|
17571
|
-
{
|
|
17572
|
-
x: -mouthHalfWidth,
|
|
17573
|
-
y: mouthY,
|
|
17574
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY),
|
|
17575
|
-
},
|
|
17576
|
-
{
|
|
17577
|
-
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
17578
|
-
y: mouthY +
|
|
17579
|
-
size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
|
|
17580
|
-
Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
|
|
17581
|
-
interaction.gazeY * size * 0.01,
|
|
17582
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
17583
|
-
},
|
|
17584
|
-
{
|
|
17585
|
-
x: mouthHalfWidth,
|
|
17586
|
-
y: mouthY,
|
|
17587
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY),
|
|
17588
|
-
},
|
|
17589
|
-
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
17590
|
-
},
|
|
17591
|
-
};
|
|
17592
|
-
/**
|
|
17593
|
-
* Draws the atmospheric underwater glow behind the octopus mesh.
|
|
17594
|
-
*
|
|
17595
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17596
|
-
*/
|
|
17597
|
-
function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
17598
|
-
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);
|
|
17599
|
-
glowGradient.addColorStop(0, `${palette.highlight}5c`);
|
|
17600
|
-
glowGradient.addColorStop(0.36, `${palette.accent}24`);
|
|
17601
|
-
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
17602
|
-
context.fillStyle = glowGradient;
|
|
17603
|
-
context.fillRect(0, 0, size, size);
|
|
17604
|
-
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);
|
|
17605
|
-
lowerGradient.addColorStop(0, `${palette.secondary}1d`);
|
|
17606
|
-
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
17607
|
-
context.fillStyle = lowerGradient;
|
|
17608
|
-
context.fillRect(0, 0, size, size);
|
|
17609
|
-
}
|
|
17610
|
-
/**
|
|
17611
|
-
* Draws the soft ground shadow below the octopus.
|
|
17612
|
-
*
|
|
17613
|
-
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
17614
|
-
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
17615
|
-
*
|
|
17616
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17617
|
-
*/
|
|
17618
|
-
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
17619
|
-
const cx = size * 0.5 + interaction.gazeX * size * 0.04;
|
|
17620
|
-
const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
|
|
17621
|
-
const rx = size * (0.18 + interaction.intensity * 0.02);
|
|
17622
|
-
const ry = size * 0.06;
|
|
17623
|
-
context.save();
|
|
17624
|
-
context.translate(cx, cy);
|
|
17625
|
-
context.scale(1, ry / rx);
|
|
17626
|
-
const blurRadius = rx * 1.4;
|
|
17627
|
-
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
17628
|
-
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
17629
|
-
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
17630
|
-
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
17631
|
-
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
17632
|
-
context.fillStyle = shadowGradient;
|
|
17633
|
-
context.beginPath();
|
|
17634
|
-
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
17635
|
-
context.fill();
|
|
17636
|
-
context.restore();
|
|
17637
|
-
}
|
|
17638
|
-
/**
|
|
17639
|
-
* Resolves visible projected patches for one rotated ellipsoid mesh.
|
|
17640
|
-
*
|
|
17641
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17642
|
-
*/
|
|
17643
|
-
function resolveVisibleEllipsoidPatches(options) {
|
|
17644
|
-
const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
|
|
17645
|
-
const latitudePatchCount = 10;
|
|
17646
|
-
const longitudePatchCount = 18;
|
|
17647
|
-
const surfacePatches = [];
|
|
17648
|
-
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
17649
|
-
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
17650
|
-
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
17651
|
-
const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
|
|
17652
|
-
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
17653
|
-
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
17654
|
-
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
17655
|
-
const localCorners = [
|
|
17656
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
|
|
17657
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
|
|
17658
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
|
|
17659
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
|
|
17660
|
-
];
|
|
17661
|
-
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
17662
|
-
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
17663
|
-
if (surfaceNormal.z <= 0.01) {
|
|
17664
|
-
continue;
|
|
17665
|
-
}
|
|
17666
|
-
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
17667
|
-
surfacePatches.push({
|
|
17668
|
-
corners: projectedCorners,
|
|
17669
|
-
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
17670
|
-
transformedCorners.length,
|
|
17671
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$3), -1, 1),
|
|
17672
|
-
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
17673
|
-
outlineColor,
|
|
17674
|
-
});
|
|
17675
|
-
}
|
|
17676
|
-
}
|
|
17677
|
-
return surfacePatches;
|
|
17678
|
-
}
|
|
17679
|
-
/**
|
|
17680
|
-
* Samples one point on an ellipsoid aligned to the local axes.
|
|
17681
|
-
*
|
|
17682
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17683
|
-
*/
|
|
17684
|
-
function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
|
|
17685
|
-
const cosineLatitude = Math.cos(latitude);
|
|
17686
|
-
return {
|
|
17687
|
-
x: Math.sin(longitude) * cosineLatitude * radiusX,
|
|
17688
|
-
y: Math.sin(latitude) * radiusY,
|
|
17689
|
-
z: Math.cos(longitude) * cosineLatitude * radiusZ,
|
|
17690
|
-
};
|
|
17691
|
-
}
|
|
17692
|
-
/**
|
|
17693
|
-
* Resolves one base fill tone for a surface patch across the octopus body.
|
|
17694
|
-
*
|
|
17695
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17696
|
-
*/
|
|
17697
|
-
function resolveSurfacePatchFillStyle(palette, verticalProgress) {
|
|
17698
|
-
const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
|
|
17699
|
-
if (clampedVerticalProgress < 0.2) {
|
|
17700
|
-
return palette.highlight;
|
|
17701
|
-
}
|
|
17702
|
-
if (clampedVerticalProgress < 0.45) {
|
|
17703
|
-
return palette.secondary;
|
|
17704
|
-
}
|
|
17705
|
-
if (clampedVerticalProgress < 0.8) {
|
|
17706
|
-
return palette.primary;
|
|
17707
|
-
}
|
|
17708
|
-
return `${palette.shadow}f2`;
|
|
17709
|
-
}
|
|
17710
|
-
/**
|
|
17711
|
-
* Draws one projected mesh patch with organic shading.
|
|
17712
|
-
*
|
|
17713
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17714
|
-
*/
|
|
17715
|
-
function drawSurfacePatch(context, surfacePatch) {
|
|
17716
|
-
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
17717
|
-
if (surfacePatch.lightIntensity > 0) {
|
|
17718
|
-
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
|
|
17719
|
-
}
|
|
17720
|
-
else if (surfacePatch.lightIntensity < 0) {
|
|
17721
|
-
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
17722
|
-
}
|
|
17723
|
-
context.save();
|
|
17724
|
-
context.beginPath();
|
|
17725
|
-
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
17726
|
-
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
17727
|
-
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
17728
|
-
}
|
|
17729
|
-
context.closePath();
|
|
17730
|
-
context.strokeStyle = surfacePatch.outlineColor;
|
|
17731
|
-
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
|
|
17732
|
-
context.lineJoin = 'round';
|
|
17733
|
-
context.stroke();
|
|
17734
|
-
context.restore();
|
|
17735
|
-
}
|
|
17736
|
-
/**
|
|
17737
|
-
* Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
|
|
17738
|
-
*
|
|
17739
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17740
|
-
*/
|
|
17741
|
-
function createOctopusTentacleStrokes(options) {
|
|
17742
|
-
const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
|
|
17743
|
-
return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
|
|
17744
|
-
const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
|
|
17745
|
-
const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
|
|
17746
|
-
const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
|
|
17747
|
-
const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
|
|
17748
|
-
const lateralReach = size *
|
|
17749
|
-
(0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
|
|
17750
|
-
const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
|
|
17751
|
-
const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
|
|
17752
|
-
const anchorPoint = {
|
|
17753
|
-
x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
|
|
17754
|
-
y: radiusY * (0.22 + tentacleRandom() * 0.18),
|
|
17755
|
-
z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
|
|
17756
|
-
};
|
|
17757
|
-
const controlPointOne = {
|
|
17758
|
-
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
|
|
17759
|
-
y: anchorPoint.y + flowLength * 0.26,
|
|
17760
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
17761
|
-
};
|
|
17762
|
-
const controlPointTwo = {
|
|
17763
|
-
x: anchorPoint.x +
|
|
17764
|
-
Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
17765
|
-
y: anchorPoint.y + flowLength * 0.66,
|
|
17766
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
17767
|
-
};
|
|
17768
|
-
const endPoint = {
|
|
17769
|
-
x: anchorPoint.x +
|
|
17770
|
-
Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
|
|
17771
|
-
sway * size * 0.028,
|
|
17772
|
-
y: anchorPoint.y + flowLength,
|
|
17773
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
|
|
17774
|
-
};
|
|
17775
|
-
const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
|
|
17776
|
-
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
17777
|
-
const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
|
|
17778
|
-
return {
|
|
17779
|
-
projectedPoints,
|
|
17780
|
-
averageDepth,
|
|
17781
|
-
isFrontFacing: averageDepth >= center.z - size * 0.006,
|
|
17782
|
-
baseWidth: size *
|
|
17783
|
-
(0.019 +
|
|
17784
|
-
morphologyProfile.tentacles.baseWidthScale * 0.007 +
|
|
17785
|
-
tentacleRandom() * 0.003 +
|
|
17786
|
-
Math.abs(Math.sin(orbitAngle)) * 0.002),
|
|
17787
|
-
tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
|
|
17788
|
-
colorBias: tentacleRandom(),
|
|
17789
|
-
};
|
|
17790
|
-
});
|
|
17791
|
-
}
|
|
17792
|
-
/**
|
|
17793
|
-
* Samples one point on a cubic Bezier curve in 3D.
|
|
17794
|
-
*
|
|
17795
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17796
|
-
*/
|
|
17797
|
-
function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
|
|
17798
|
-
const inverseProgress = 1 - progress;
|
|
17799
|
-
return {
|
|
17800
|
-
x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
|
|
17801
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
|
|
17802
|
-
3 * inverseProgress * progress * progress * controlPointTwo.x +
|
|
17803
|
-
progress * progress * progress * endPoint.x,
|
|
17804
|
-
y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
|
|
17805
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
|
|
17806
|
-
3 * inverseProgress * progress * progress * controlPointTwo.y +
|
|
17807
|
-
progress * progress * progress * endPoint.y,
|
|
17808
|
-
z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
|
|
17809
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
|
|
17810
|
-
3 * inverseProgress * progress * progress * controlPointTwo.z +
|
|
17811
|
-
progress * progress * progress * endPoint.z,
|
|
17812
|
-
};
|
|
17813
|
-
}
|
|
17814
|
-
/**
|
|
17815
|
-
* Draws one projected tentacle stroke with a slim highlight ridge.
|
|
17816
|
-
*
|
|
17817
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17818
|
-
*/
|
|
17819
|
-
function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
17820
|
-
const projectedSegments = tentacleStroke.projectedPoints.length - 1;
|
|
17821
|
-
for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
|
|
17822
|
-
const startPoint = tentacleStroke.projectedPoints[segmentIndex];
|
|
17823
|
-
const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
|
|
17824
|
-
const progress = segmentIndex / projectedSegments;
|
|
17825
|
-
const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
|
|
17826
|
-
context.beginPath();
|
|
17827
|
-
context.moveTo(startPoint.x, startPoint.y);
|
|
17828
|
-
context.lineTo(endPoint.x, endPoint.y);
|
|
17829
|
-
context.strokeStyle = tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
17830
|
-
context.lineWidth = width;
|
|
17831
|
-
context.lineCap = 'round';
|
|
17832
|
-
context.stroke();
|
|
17833
|
-
context.beginPath();
|
|
17834
|
-
context.moveTo(startPoint.x, startPoint.y);
|
|
17835
|
-
context.lineTo(endPoint.x, endPoint.y);
|
|
17836
|
-
context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
|
|
17837
|
-
context.lineWidth = Math.max(1, width * 0.34);
|
|
17838
|
-
context.lineCap = 'round';
|
|
17839
|
-
context.stroke();
|
|
17840
|
-
}
|
|
17841
|
-
}
|
|
17842
|
-
/**
|
|
17843
|
-
* Resolves the front surface depth on an ellipsoid for one local face point.
|
|
17844
|
-
*
|
|
17845
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17846
|
-
*/
|
|
17847
|
-
function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
17848
|
-
const normalizedX = x / radiusX;
|
|
17849
|
-
const normalizedY = y / radiusY;
|
|
17850
|
-
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
17851
|
-
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
17852
|
-
}
|
|
17853
|
-
|
|
17854
17753
|
/* eslint-disable no-magic-numbers */
|
|
17855
17754
|
/**
|
|
17856
17755
|
* Light direction used by the single-mesh octopus shading.
|
|
17857
17756
|
*
|
|
17858
17757
|
* @private helper of `octopus3d2AvatarVisual`
|
|
17859
17758
|
*/
|
|
17860
|
-
const LIGHT_DIRECTION$
|
|
17759
|
+
const LIGHT_DIRECTION$3 = normalizeVector3({
|
|
17861
17760
|
x: 0.38,
|
|
17862
17761
|
y: -0.6,
|
|
17863
17762
|
z: 0.98,
|
|
@@ -18096,7 +17995,7 @@
|
|
|
18096
17995
|
transformedCorners[2].z +
|
|
18097
17996
|
transformedCorners[3].z) /
|
|
18098
17997
|
4,
|
|
18099
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$
|
|
17998
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$3), -1, 1),
|
|
18100
17999
|
fillStyle: resolveBlobbySurfacePatchFillStyle$1(palette, verticalProgress, Math.max(0, Math.cos(centerLongitude)), resolveLowerLobeWave(centerLongitude, morphologyProfile, animationPhase, timeMs)),
|
|
18101
18000
|
outlineColor: verticalProgress < 0.58 ? `${palette.highlight}73` : `${palette.shadow}8a`,
|
|
18102
18001
|
});
|
|
@@ -18211,7 +18110,7 @@
|
|
|
18211
18110
|
*
|
|
18212
18111
|
* @private helper of `octopus3d3AvatarVisual`
|
|
18213
18112
|
*/
|
|
18214
|
-
const LIGHT_DIRECTION$
|
|
18113
|
+
const LIGHT_DIRECTION$2 = normalizeVector3({
|
|
18215
18114
|
x: 0.34,
|
|
18216
18115
|
y: -0.62,
|
|
18217
18116
|
z: 1,
|
|
@@ -18518,7 +18417,7 @@
|
|
|
18518
18417
|
transformedCorners[2].z +
|
|
18519
18418
|
transformedCorners[3].z) /
|
|
18520
18419
|
4,
|
|
18521
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$
|
|
18420
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$2), -1, 1),
|
|
18522
18421
|
fillStyle: resolveContinuousSurfacePatchFillStyle(palette, verticalProgress, cachedCosByPatchCenterLongitude[longitudeIndex], cachedTentacleInfluencesByPatchCenterLongitude[longitudeIndex].core, cachedLobeWavesByPatchCenterLongitude[longitudeIndex]),
|
|
18523
18422
|
outlineColor: verticalProgress < 0.54 ? `${palette.highlight}69` : `${palette.shadow}78`,
|
|
18524
18423
|
});
|
|
@@ -18833,7 +18732,7 @@
|
|
|
18833
18732
|
*
|
|
18834
18733
|
* @private helper of `octopus3d4AvatarVisual`
|
|
18835
18734
|
*/
|
|
18836
|
-
const LIGHT_DIRECTION = normalizeVector3({
|
|
18735
|
+
const LIGHT_DIRECTION$1 = normalizeVector3({
|
|
18837
18736
|
x: 0.32,
|
|
18838
18737
|
y: -0.66,
|
|
18839
18738
|
z: 1,
|
|
@@ -19179,7 +19078,7 @@
|
|
|
19179
19078
|
projectScenePoint(transformedCorners[2], size, sceneCenterX, sceneCenterY),
|
|
19180
19079
|
projectScenePoint(transformedCorners[3], size, sceneCenterX, sceneCenterY),
|
|
19181
19080
|
];
|
|
19182
|
-
const lightIntensity = clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1);
|
|
19081
|
+
const lightIntensity = clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$1), -1, 1);
|
|
19183
19082
|
const rimLightIntensity = Math.pow(clampNumber$1(dotProduct3D(surfaceNormal, RIM_LIGHT_DIRECTION), 0, 1), 2.6);
|
|
19184
19083
|
surfacePatches.push({
|
|
19185
19084
|
corners: projectedCorners,
|
|
@@ -19578,6 +19477,445 @@
|
|
|
19578
19477
|
.padStart(2, '0');
|
|
19579
19478
|
}
|
|
19580
19479
|
|
|
19480
|
+
/* eslint-disable no-magic-numbers */
|
|
19481
|
+
/**
|
|
19482
|
+
* Light direction used by the organic 3D octopus shading.
|
|
19483
|
+
*
|
|
19484
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19485
|
+
*/
|
|
19486
|
+
const LIGHT_DIRECTION = normalizeVector3({
|
|
19487
|
+
x: 0.48,
|
|
19488
|
+
y: -0.62,
|
|
19489
|
+
z: 0.94,
|
|
19490
|
+
});
|
|
19491
|
+
/**
|
|
19492
|
+
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
19493
|
+
*
|
|
19494
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19495
|
+
*/
|
|
19496
|
+
const octopus3dStableStateCache = new WeakMap();
|
|
19497
|
+
/**
|
|
19498
|
+
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
19499
|
+
*
|
|
19500
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19501
|
+
*/
|
|
19502
|
+
function getOctopus3dStableState(createRandom) {
|
|
19503
|
+
const cached = octopus3dStableStateCache.get(createRandom);
|
|
19504
|
+
if (cached !== undefined) {
|
|
19505
|
+
return cached;
|
|
19506
|
+
}
|
|
19507
|
+
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
19508
|
+
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
19509
|
+
const leftEyePhaseOffset = eyeRandom() * 0.6;
|
|
19510
|
+
const rightEyePhaseOffset = eyeRandom() * 0.6;
|
|
19511
|
+
const state = {
|
|
19512
|
+
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
19513
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
19514
|
+
leftEyePhaseOffset,
|
|
19515
|
+
rightEyePhaseOffset,
|
|
19516
|
+
};
|
|
19517
|
+
octopus3dStableStateCache.set(createRandom, state);
|
|
19518
|
+
return state;
|
|
19519
|
+
}
|
|
19520
|
+
/**
|
|
19521
|
+
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
19522
|
+
*
|
|
19523
|
+
* @private built-in avatar visual
|
|
19524
|
+
*/
|
|
19525
|
+
const octopus3dAvatarVisual = {
|
|
19526
|
+
id: 'octopus3d',
|
|
19527
|
+
title: 'Octopus 3D',
|
|
19528
|
+
description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
|
|
19529
|
+
isAnimated: true,
|
|
19530
|
+
supportsPointerTracking: true,
|
|
19531
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
19532
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
|
|
19533
|
+
const sceneCenterX = size * 0.5;
|
|
19534
|
+
const sceneCenterY = size * 0.56;
|
|
19535
|
+
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
19536
|
+
const mantleCenter = {
|
|
19537
|
+
x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
|
|
19538
|
+
y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
19539
|
+
z: interaction.intensity * size * 0.012,
|
|
19540
|
+
};
|
|
19541
|
+
const underbodyCenter = {
|
|
19542
|
+
x: mantleCenter.x * 0.86,
|
|
19543
|
+
y: mantleCenter.y + size * 0.168,
|
|
19544
|
+
z: mantleCenter.z - size * 0.018,
|
|
19545
|
+
};
|
|
19546
|
+
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
19547
|
+
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
19548
|
+
const mantleRadiusZ = size *
|
|
19549
|
+
morphologyProfile.body.bodyRadiusRatio *
|
|
19550
|
+
(0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
19551
|
+
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
19552
|
+
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
19553
|
+
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
19554
|
+
const bodyYaw = -0.18 +
|
|
19555
|
+
Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
|
|
19556
|
+
interaction.bodyOffsetX * 0.18 +
|
|
19557
|
+
interaction.gazeX * 0.22;
|
|
19558
|
+
const bodyPitch = -0.08 +
|
|
19559
|
+
Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
|
|
19560
|
+
interaction.bodyOffsetY * 0.08 -
|
|
19561
|
+
interaction.gazeY * 0.08;
|
|
19562
|
+
const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
|
|
19563
|
+
const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
|
|
19564
|
+
const mantlePatches = resolveVisibleEllipsoidPatches({
|
|
19565
|
+
center: mantleCenter,
|
|
19566
|
+
radiusX: mantleRadiusX,
|
|
19567
|
+
radiusY: mantleRadiusY,
|
|
19568
|
+
radiusZ: mantleRadiusZ,
|
|
19569
|
+
rotationX: headPitch,
|
|
19570
|
+
rotationY: headYaw,
|
|
19571
|
+
sceneCenterX,
|
|
19572
|
+
sceneCenterY,
|
|
19573
|
+
size,
|
|
19574
|
+
palette,
|
|
19575
|
+
verticalColorBias: 0,
|
|
19576
|
+
outlineColor: `${palette.highlight}7a`,
|
|
19577
|
+
});
|
|
19578
|
+
const underbodyPatches = resolveVisibleEllipsoidPatches({
|
|
19579
|
+
center: underbodyCenter,
|
|
19580
|
+
radiusX: underbodyRadiusX,
|
|
19581
|
+
radiusY: underbodyRadiusY,
|
|
19582
|
+
radiusZ: underbodyRadiusZ,
|
|
19583
|
+
rotationX: bodyPitch,
|
|
19584
|
+
rotationY: bodyYaw,
|
|
19585
|
+
sceneCenterX,
|
|
19586
|
+
sceneCenterY,
|
|
19587
|
+
size,
|
|
19588
|
+
palette,
|
|
19589
|
+
verticalColorBias: 0.18,
|
|
19590
|
+
outlineColor: `${palette.shadow}8f`,
|
|
19591
|
+
});
|
|
19592
|
+
const tentacleStrokes = createOctopusTentacleStrokes({
|
|
19593
|
+
createRandom,
|
|
19594
|
+
morphologyProfile,
|
|
19595
|
+
timeMs,
|
|
19596
|
+
size,
|
|
19597
|
+
center: underbodyCenter,
|
|
19598
|
+
radiusX: underbodyRadiusX,
|
|
19599
|
+
radiusY: underbodyRadiusY,
|
|
19600
|
+
radiusZ: underbodyRadiusZ,
|
|
19601
|
+
rotationX: bodyPitch,
|
|
19602
|
+
rotationY: bodyYaw,
|
|
19603
|
+
sceneCenterX,
|
|
19604
|
+
sceneCenterY,
|
|
19605
|
+
animationPhase,
|
|
19606
|
+
});
|
|
19607
|
+
const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
|
|
19608
|
+
const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
|
|
19609
|
+
const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
|
|
19610
|
+
const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
|
|
19611
|
+
const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
|
|
19612
|
+
const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
|
|
19613
|
+
drawAvatarFrame(context, size, palette);
|
|
19614
|
+
drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
19615
|
+
drawOctopus3dShadow(context, size, palette, interaction, timeMs);
|
|
19616
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
|
|
19617
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
19618
|
+
}
|
|
19619
|
+
for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
19620
|
+
drawSurfacePatch(context, surfacePatch);
|
|
19621
|
+
}
|
|
19622
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
19623
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
19624
|
+
}
|
|
19625
|
+
drawProjectedOrganicEye(context, {
|
|
19626
|
+
x: -faceEyeSpacing,
|
|
19627
|
+
y: faceEyeYOffset,
|
|
19628
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
19629
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
19630
|
+
drawProjectedOrganicEye(context, {
|
|
19631
|
+
x: faceEyeSpacing,
|
|
19632
|
+
y: faceEyeYOffset,
|
|
19633
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
19634
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
19635
|
+
drawProjectedOrganicMouth(context, [
|
|
19636
|
+
{
|
|
19637
|
+
x: -mouthHalfWidth,
|
|
19638
|
+
y: mouthY,
|
|
19639
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY),
|
|
19640
|
+
},
|
|
19641
|
+
{
|
|
19642
|
+
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
19643
|
+
y: mouthY +
|
|
19644
|
+
size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
|
|
19645
|
+
Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
|
|
19646
|
+
interaction.gazeY * size * 0.01,
|
|
19647
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
19648
|
+
},
|
|
19649
|
+
{
|
|
19650
|
+
x: mouthHalfWidth,
|
|
19651
|
+
y: mouthY,
|
|
19652
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY),
|
|
19653
|
+
},
|
|
19654
|
+
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
19655
|
+
},
|
|
19656
|
+
};
|
|
19657
|
+
/**
|
|
19658
|
+
* Draws the atmospheric underwater glow behind the octopus mesh.
|
|
19659
|
+
*
|
|
19660
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19661
|
+
*/
|
|
19662
|
+
function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
19663
|
+
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);
|
|
19664
|
+
glowGradient.addColorStop(0, `${palette.highlight}5c`);
|
|
19665
|
+
glowGradient.addColorStop(0.36, `${palette.accent}24`);
|
|
19666
|
+
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
19667
|
+
context.fillStyle = glowGradient;
|
|
19668
|
+
context.fillRect(0, 0, size, size);
|
|
19669
|
+
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);
|
|
19670
|
+
lowerGradient.addColorStop(0, `${palette.secondary}1d`);
|
|
19671
|
+
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
19672
|
+
context.fillStyle = lowerGradient;
|
|
19673
|
+
context.fillRect(0, 0, size, size);
|
|
19674
|
+
}
|
|
19675
|
+
/**
|
|
19676
|
+
* Draws the soft ground shadow below the octopus.
|
|
19677
|
+
*
|
|
19678
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
19679
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
19680
|
+
*
|
|
19681
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19682
|
+
*/
|
|
19683
|
+
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
19684
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.04;
|
|
19685
|
+
const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
|
|
19686
|
+
const rx = size * (0.18 + interaction.intensity * 0.02);
|
|
19687
|
+
const ry = size * 0.06;
|
|
19688
|
+
context.save();
|
|
19689
|
+
context.translate(cx, cy);
|
|
19690
|
+
context.scale(1, ry / rx);
|
|
19691
|
+
const blurRadius = rx * 1.4;
|
|
19692
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
19693
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
19694
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
19695
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
19696
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
19697
|
+
context.fillStyle = shadowGradient;
|
|
19698
|
+
context.beginPath();
|
|
19699
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
19700
|
+
context.fill();
|
|
19701
|
+
context.restore();
|
|
19702
|
+
}
|
|
19703
|
+
/**
|
|
19704
|
+
* Resolves visible projected patches for one rotated ellipsoid mesh.
|
|
19705
|
+
*
|
|
19706
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19707
|
+
*/
|
|
19708
|
+
function resolveVisibleEllipsoidPatches(options) {
|
|
19709
|
+
const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
|
|
19710
|
+
const latitudePatchCount = 10;
|
|
19711
|
+
const longitudePatchCount = 18;
|
|
19712
|
+
const surfacePatches = [];
|
|
19713
|
+
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
19714
|
+
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
19715
|
+
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
19716
|
+
const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
|
|
19717
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
19718
|
+
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
19719
|
+
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
19720
|
+
const localCorners = [
|
|
19721
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
|
|
19722
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
|
|
19723
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
|
|
19724
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
|
|
19725
|
+
];
|
|
19726
|
+
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
19727
|
+
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
19728
|
+
if (surfaceNormal.z <= 0.01) {
|
|
19729
|
+
continue;
|
|
19730
|
+
}
|
|
19731
|
+
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
19732
|
+
surfacePatches.push({
|
|
19733
|
+
corners: projectedCorners,
|
|
19734
|
+
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
19735
|
+
transformedCorners.length,
|
|
19736
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
19737
|
+
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
19738
|
+
outlineColor,
|
|
19739
|
+
});
|
|
19740
|
+
}
|
|
19741
|
+
}
|
|
19742
|
+
return surfacePatches;
|
|
19743
|
+
}
|
|
19744
|
+
/**
|
|
19745
|
+
* Samples one point on an ellipsoid aligned to the local axes.
|
|
19746
|
+
*
|
|
19747
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19748
|
+
*/
|
|
19749
|
+
function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
|
|
19750
|
+
const cosineLatitude = Math.cos(latitude);
|
|
19751
|
+
return {
|
|
19752
|
+
x: Math.sin(longitude) * cosineLatitude * radiusX,
|
|
19753
|
+
y: Math.sin(latitude) * radiusY,
|
|
19754
|
+
z: Math.cos(longitude) * cosineLatitude * radiusZ,
|
|
19755
|
+
};
|
|
19756
|
+
}
|
|
19757
|
+
/**
|
|
19758
|
+
* Resolves one base fill tone for a surface patch across the octopus body.
|
|
19759
|
+
*
|
|
19760
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19761
|
+
*/
|
|
19762
|
+
function resolveSurfacePatchFillStyle(palette, verticalProgress) {
|
|
19763
|
+
const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
|
|
19764
|
+
if (clampedVerticalProgress < 0.2) {
|
|
19765
|
+
return palette.highlight;
|
|
19766
|
+
}
|
|
19767
|
+
if (clampedVerticalProgress < 0.45) {
|
|
19768
|
+
return palette.secondary;
|
|
19769
|
+
}
|
|
19770
|
+
if (clampedVerticalProgress < 0.8) {
|
|
19771
|
+
return palette.primary;
|
|
19772
|
+
}
|
|
19773
|
+
return `${palette.shadow}f2`;
|
|
19774
|
+
}
|
|
19775
|
+
/**
|
|
19776
|
+
* Draws one projected mesh patch with organic shading.
|
|
19777
|
+
*
|
|
19778
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19779
|
+
*/
|
|
19780
|
+
function drawSurfacePatch(context, surfacePatch) {
|
|
19781
|
+
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
19782
|
+
if (surfacePatch.lightIntensity > 0) {
|
|
19783
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
|
|
19784
|
+
}
|
|
19785
|
+
else if (surfacePatch.lightIntensity < 0) {
|
|
19786
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
19787
|
+
}
|
|
19788
|
+
context.save();
|
|
19789
|
+
context.beginPath();
|
|
19790
|
+
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
19791
|
+
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
19792
|
+
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
19793
|
+
}
|
|
19794
|
+
context.closePath();
|
|
19795
|
+
context.strokeStyle = surfacePatch.outlineColor;
|
|
19796
|
+
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
|
|
19797
|
+
context.lineJoin = 'round';
|
|
19798
|
+
context.stroke();
|
|
19799
|
+
context.restore();
|
|
19800
|
+
}
|
|
19801
|
+
/**
|
|
19802
|
+
* Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
|
|
19803
|
+
*
|
|
19804
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19805
|
+
*/
|
|
19806
|
+
function createOctopusTentacleStrokes(options) {
|
|
19807
|
+
const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
|
|
19808
|
+
return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
|
|
19809
|
+
const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
|
|
19810
|
+
const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
|
|
19811
|
+
const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
|
|
19812
|
+
const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
|
|
19813
|
+
const lateralReach = size *
|
|
19814
|
+
(0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
|
|
19815
|
+
const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
|
|
19816
|
+
const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
|
|
19817
|
+
const anchorPoint = {
|
|
19818
|
+
x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
|
|
19819
|
+
y: radiusY * (0.22 + tentacleRandom() * 0.18),
|
|
19820
|
+
z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
|
|
19821
|
+
};
|
|
19822
|
+
const controlPointOne = {
|
|
19823
|
+
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
|
|
19824
|
+
y: anchorPoint.y + flowLength * 0.26,
|
|
19825
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
19826
|
+
};
|
|
19827
|
+
const controlPointTwo = {
|
|
19828
|
+
x: anchorPoint.x +
|
|
19829
|
+
Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
19830
|
+
y: anchorPoint.y + flowLength * 0.66,
|
|
19831
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
19832
|
+
};
|
|
19833
|
+
const endPoint = {
|
|
19834
|
+
x: anchorPoint.x +
|
|
19835
|
+
Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
|
|
19836
|
+
sway * size * 0.028,
|
|
19837
|
+
y: anchorPoint.y + flowLength,
|
|
19838
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
|
|
19839
|
+
};
|
|
19840
|
+
const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
|
|
19841
|
+
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
19842
|
+
const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
|
|
19843
|
+
return {
|
|
19844
|
+
projectedPoints,
|
|
19845
|
+
averageDepth,
|
|
19846
|
+
isFrontFacing: averageDepth >= center.z - size * 0.006,
|
|
19847
|
+
baseWidth: size *
|
|
19848
|
+
(0.019 +
|
|
19849
|
+
morphologyProfile.tentacles.baseWidthScale * 0.007 +
|
|
19850
|
+
tentacleRandom() * 0.003 +
|
|
19851
|
+
Math.abs(Math.sin(orbitAngle)) * 0.002),
|
|
19852
|
+
tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
|
|
19853
|
+
colorBias: tentacleRandom(),
|
|
19854
|
+
};
|
|
19855
|
+
});
|
|
19856
|
+
}
|
|
19857
|
+
/**
|
|
19858
|
+
* Samples one point on a cubic Bezier curve in 3D.
|
|
19859
|
+
*
|
|
19860
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19861
|
+
*/
|
|
19862
|
+
function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
|
|
19863
|
+
const inverseProgress = 1 - progress;
|
|
19864
|
+
return {
|
|
19865
|
+
x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
|
|
19866
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
|
|
19867
|
+
3 * inverseProgress * progress * progress * controlPointTwo.x +
|
|
19868
|
+
progress * progress * progress * endPoint.x,
|
|
19869
|
+
y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
|
|
19870
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
|
|
19871
|
+
3 * inverseProgress * progress * progress * controlPointTwo.y +
|
|
19872
|
+
progress * progress * progress * endPoint.y,
|
|
19873
|
+
z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
|
|
19874
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
|
|
19875
|
+
3 * inverseProgress * progress * progress * controlPointTwo.z +
|
|
19876
|
+
progress * progress * progress * endPoint.z,
|
|
19877
|
+
};
|
|
19878
|
+
}
|
|
19879
|
+
/**
|
|
19880
|
+
* Draws one projected tentacle stroke with a slim highlight ridge.
|
|
19881
|
+
*
|
|
19882
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19883
|
+
*/
|
|
19884
|
+
function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
19885
|
+
const projectedSegments = tentacleStroke.projectedPoints.length - 1;
|
|
19886
|
+
for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
|
|
19887
|
+
const startPoint = tentacleStroke.projectedPoints[segmentIndex];
|
|
19888
|
+
const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
|
|
19889
|
+
const progress = segmentIndex / projectedSegments;
|
|
19890
|
+
const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
|
|
19891
|
+
context.beginPath();
|
|
19892
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
19893
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
19894
|
+
context.strokeStyle = tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
19895
|
+
context.lineWidth = width;
|
|
19896
|
+
context.lineCap = 'round';
|
|
19897
|
+
context.stroke();
|
|
19898
|
+
context.beginPath();
|
|
19899
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
19900
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
19901
|
+
context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
|
|
19902
|
+
context.lineWidth = Math.max(1, width * 0.34);
|
|
19903
|
+
context.lineCap = 'round';
|
|
19904
|
+
context.stroke();
|
|
19905
|
+
}
|
|
19906
|
+
}
|
|
19907
|
+
/**
|
|
19908
|
+
* Resolves the front surface depth on an ellipsoid for one local face point.
|
|
19909
|
+
*
|
|
19910
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19911
|
+
*/
|
|
19912
|
+
function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
19913
|
+
const normalizedX = x / radiusX;
|
|
19914
|
+
const normalizedY = y / radiusY;
|
|
19915
|
+
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
19916
|
+
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
19917
|
+
}
|
|
19918
|
+
|
|
19581
19919
|
/* eslint-disable no-magic-numbers */
|
|
19582
19920
|
/**
|
|
19583
19921
|
* Octopus avatar visual.
|
|
@@ -20398,14 +20736,14 @@
|
|
|
20398
20736
|
/**
|
|
20399
20737
|
* META AVATAR commitment definition
|
|
20400
20738
|
*
|
|
20401
|
-
* The `META AVATAR`
|
|
20402
|
-
* the agent does not provide an explicit `META IMAGE`.
|
|
20739
|
+
* The `META AVATAR` and `META VISUAL` commitments set the built-in default avatar visual
|
|
20740
|
+
* used when the agent does not provide an explicit `META IMAGE`.
|
|
20403
20741
|
*
|
|
20404
20742
|
* @private [🪔] Maybe export the commitments through some package
|
|
20405
20743
|
*/
|
|
20406
20744
|
class MetaAvatarCommitmentDefinition extends BaseCommitmentDefinition {
|
|
20407
|
-
constructor() {
|
|
20408
|
-
super(
|
|
20745
|
+
constructor(type = 'META AVATAR') {
|
|
20746
|
+
super(type);
|
|
20409
20747
|
}
|
|
20410
20748
|
/**
|
|
20411
20749
|
* Short one-line description of META AVATAR.
|
|
@@ -20425,14 +20763,15 @@
|
|
|
20425
20763
|
get documentation() {
|
|
20426
20764
|
const supportedVisuals = AVATAR_VISUALS.map((avatarVisual) => `\`${avatarVisual.id}\``).join(', ');
|
|
20427
20765
|
return _spaceTrim.spaceTrim(`
|
|
20428
|
-
#
|
|
20766
|
+
# ${this.type}
|
|
20429
20767
|
|
|
20430
20768
|
Sets the built-in avatar visual used for the agent when no explicit \`META IMAGE\` is provided.
|
|
20769
|
+
\`META AVATAR\` and \`META VISUAL\` are equivalent.
|
|
20431
20770
|
|
|
20432
20771
|
## Key aspects
|
|
20433
20772
|
|
|
20434
20773
|
- Does not modify the agent's behavior or responses.
|
|
20435
|
-
- Only one \`META AVATAR\` should be used per agent.
|
|
20774
|
+
- Only one \`META AVATAR\` or \`META VISUAL\` should be used per agent.
|
|
20436
20775
|
- If multiple are specified, the last one takes precedence.
|
|
20437
20776
|
- Values are matched case-insensitively and spaces, hyphens, and underscores are normalized.
|
|
20438
20777
|
- Supported visuals are derived from the shared avatar registry: ${supportedVisuals}.
|
|
@@ -20447,15 +20786,15 @@
|
|
|
20447
20786
|
\`\`\`
|
|
20448
20787
|
|
|
20449
20788
|
\`\`\`book
|
|
20450
|
-
|
|
20789
|
+
Minecraft Assistant
|
|
20451
20790
|
|
|
20452
|
-
META
|
|
20791
|
+
META VISUAL Minecraft2
|
|
20453
20792
|
GOAL Answer in a calm and focused way.
|
|
20454
20793
|
\`\`\`
|
|
20455
20794
|
`);
|
|
20456
20795
|
}
|
|
20457
20796
|
applyToAgentModelRequirements(requirements, content) {
|
|
20458
|
-
// META AVATAR
|
|
20797
|
+
// META AVATAR and META VISUAL don't modify the system message or model requirements.
|
|
20459
20798
|
// It's handled separately in the parsing logic for profile avatar resolution.
|
|
20460
20799
|
return requirements;
|
|
20461
20800
|
}
|
|
@@ -29643,6 +29982,7 @@
|
|
|
29643
29982
|
new ActionCommitmentDefinition('ACTIONS'),
|
|
29644
29983
|
new ComponentCommitmentDefinition(),
|
|
29645
29984
|
new MetaAvatarCommitmentDefinition(),
|
|
29985
|
+
new MetaAvatarCommitmentDefinition('META VISUAL'),
|
|
29646
29986
|
new MetaImageCommitmentDefinition(),
|
|
29647
29987
|
new MetaColorCommitmentDefinition(),
|
|
29648
29988
|
new MetaFontCommitmentDefinition(),
|
|
@@ -30994,6 +31334,7 @@
|
|
|
30994
31334
|
*/
|
|
30995
31335
|
const META_COMMITMENT_APPLIERS = {
|
|
30996
31336
|
'META AVATAR': applyMetaAvatarContent,
|
|
31337
|
+
'META VISUAL': applyMetaAvatarContent,
|
|
30997
31338
|
'META LINK': applyMetaLinkContent,
|
|
30998
31339
|
'META DOMAIN': applyMetaDomainContent,
|
|
30999
31340
|
'META IMAGE': applyMetaImageContent,
|
|
@@ -31042,7 +31383,7 @@
|
|
|
31042
31383
|
state.meta[metaType] = metaValue;
|
|
31043
31384
|
}
|
|
31044
31385
|
/**
|
|
31045
|
-
* Applies META AVATAR content into the canonical `meta.avatar` field.
|
|
31386
|
+
* Applies META AVATAR / META VISUAL content into the canonical `meta.avatar` field.
|
|
31046
31387
|
*/
|
|
31047
31388
|
function applyMetaAvatarContent(state, content) {
|
|
31048
31389
|
const avatarVisualId = resolveAvatarVisualId(content);
|
|
@@ -32106,6 +32447,78 @@
|
|
|
32106
32447
|
.replace(/^[._-]+|[._-]+$/gu, '');
|
|
32107
32448
|
}
|
|
32108
32449
|
|
|
32450
|
+
/**
|
|
32451
|
+
* Helper of usage compute
|
|
32452
|
+
*
|
|
32453
|
+
* @param content the content of prompt or response
|
|
32454
|
+
* @returns part of UsageCounts
|
|
32455
|
+
*
|
|
32456
|
+
* @private internal utility of LlmExecutionTools
|
|
32457
|
+
*/
|
|
32458
|
+
function computeUsageCounts(content) {
|
|
32459
|
+
return {
|
|
32460
|
+
charactersCount: { value: countCharacters(content) },
|
|
32461
|
+
wordsCount: { value: countWords(content) },
|
|
32462
|
+
sentencesCount: { value: countSentences(content) },
|
|
32463
|
+
linesCount: { value: countLines(content) },
|
|
32464
|
+
paragraphsCount: { value: countParagraphs(content) },
|
|
32465
|
+
pagesCount: { value: countPages(content) },
|
|
32466
|
+
};
|
|
32467
|
+
}
|
|
32468
|
+
|
|
32469
|
+
/**
|
|
32470
|
+
* Computes the usage of the OpenAI API based on the response from OpenAI
|
|
32471
|
+
*
|
|
32472
|
+
* @param promptContent The content of the prompt
|
|
32473
|
+
* @param resultContent The content of the result (for embedding prompts or failed prompts pass empty string)
|
|
32474
|
+
* @param rawResponse The raw response from OpenAI API
|
|
32475
|
+
* @param duration The duration of the execution
|
|
32476
|
+
* @throws {PipelineExecutionError} If the usage is not defined in the response from OpenAI
|
|
32477
|
+
*
|
|
32478
|
+
* @private internal utility of `OpenAiExecutionTools`
|
|
32479
|
+
*/
|
|
32480
|
+
function computeOpenAiUsage(promptContent, // <- Note: Intentionally using [] to access type properties to bring jsdoc from Prompt/PromptResult to consumer
|
|
32481
|
+
resultContent, rawResponse, duration = ZERO_VALUE) {
|
|
32482
|
+
var _a, _b;
|
|
32483
|
+
if (rawResponse.usage === undefined) {
|
|
32484
|
+
throw new PipelineExecutionError('The usage is not defined in the response from OpenAI');
|
|
32485
|
+
}
|
|
32486
|
+
if (((_a = rawResponse.usage) === null || _a === void 0 ? void 0 : _a.prompt_tokens) === undefined) {
|
|
32487
|
+
throw new PipelineExecutionError('In OpenAI response `usage.prompt_tokens` not defined');
|
|
32488
|
+
}
|
|
32489
|
+
const inputTokens = rawResponse.usage.prompt_tokens;
|
|
32490
|
+
const outputTokens = ((_b = rawResponse.usage) === null || _b === void 0 ? void 0 : _b.completion_tokens) || 0;
|
|
32491
|
+
let isUncertain = false;
|
|
32492
|
+
let modelInfo = OPENAI_MODELS.find((model) => model.modelName === rawResponse.model);
|
|
32493
|
+
if (modelInfo === undefined) {
|
|
32494
|
+
// Note: Model is not in the list of known models, fallback to the family of the models and mark price as uncertain
|
|
32495
|
+
modelInfo = OPENAI_MODELS.find((model) => (rawResponse.model || SALT_NONCE).startsWith(model.modelName));
|
|
32496
|
+
if (modelInfo !== undefined) {
|
|
32497
|
+
isUncertain = true;
|
|
32498
|
+
}
|
|
32499
|
+
}
|
|
32500
|
+
let price;
|
|
32501
|
+
if (modelInfo === undefined || modelInfo.pricing === undefined) {
|
|
32502
|
+
price = uncertainNumber();
|
|
32503
|
+
}
|
|
32504
|
+
else {
|
|
32505
|
+
price = uncertainNumber(inputTokens * modelInfo.pricing.prompt + outputTokens * modelInfo.pricing.output, isUncertain);
|
|
32506
|
+
}
|
|
32507
|
+
return {
|
|
32508
|
+
price,
|
|
32509
|
+
duration,
|
|
32510
|
+
input: {
|
|
32511
|
+
tokensCount: uncertainNumber(rawResponse.usage.prompt_tokens),
|
|
32512
|
+
...computeUsageCounts(promptContent),
|
|
32513
|
+
},
|
|
32514
|
+
output: {
|
|
32515
|
+
tokensCount: uncertainNumber(outputTokens),
|
|
32516
|
+
...computeUsageCounts(resultContent),
|
|
32517
|
+
},
|
|
32518
|
+
};
|
|
32519
|
+
}
|
|
32520
|
+
// TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
|
|
32521
|
+
|
|
32109
32522
|
/**
|
|
32110
32523
|
* Simple wrapper `new Date().toISOString()`
|
|
32111
32524
|
*
|
|
@@ -32514,78 +32927,6 @@
|
|
|
32514
32927
|
}
|
|
32515
32928
|
}
|
|
32516
32929
|
|
|
32517
|
-
/**
|
|
32518
|
-
* Helper of usage compute
|
|
32519
|
-
*
|
|
32520
|
-
* @param content the content of prompt or response
|
|
32521
|
-
* @returns part of UsageCounts
|
|
32522
|
-
*
|
|
32523
|
-
* @private internal utility of LlmExecutionTools
|
|
32524
|
-
*/
|
|
32525
|
-
function computeUsageCounts(content) {
|
|
32526
|
-
return {
|
|
32527
|
-
charactersCount: { value: countCharacters(content) },
|
|
32528
|
-
wordsCount: { value: countWords(content) },
|
|
32529
|
-
sentencesCount: { value: countSentences(content) },
|
|
32530
|
-
linesCount: { value: countLines(content) },
|
|
32531
|
-
paragraphsCount: { value: countParagraphs(content) },
|
|
32532
|
-
pagesCount: { value: countPages(content) },
|
|
32533
|
-
};
|
|
32534
|
-
}
|
|
32535
|
-
|
|
32536
|
-
/**
|
|
32537
|
-
* Computes the usage of the OpenAI API based on the response from OpenAI
|
|
32538
|
-
*
|
|
32539
|
-
* @param promptContent The content of the prompt
|
|
32540
|
-
* @param resultContent The content of the result (for embedding prompts or failed prompts pass empty string)
|
|
32541
|
-
* @param rawResponse The raw response from OpenAI API
|
|
32542
|
-
* @param duration The duration of the execution
|
|
32543
|
-
* @throws {PipelineExecutionError} If the usage is not defined in the response from OpenAI
|
|
32544
|
-
*
|
|
32545
|
-
* @private internal utility of `OpenAiExecutionTools`
|
|
32546
|
-
*/
|
|
32547
|
-
function computeOpenAiUsage(promptContent, // <- Note: Intentionally using [] to access type properties to bring jsdoc from Prompt/PromptResult to consumer
|
|
32548
|
-
resultContent, rawResponse, duration = ZERO_VALUE) {
|
|
32549
|
-
var _a, _b;
|
|
32550
|
-
if (rawResponse.usage === undefined) {
|
|
32551
|
-
throw new PipelineExecutionError('The usage is not defined in the response from OpenAI');
|
|
32552
|
-
}
|
|
32553
|
-
if (((_a = rawResponse.usage) === null || _a === void 0 ? void 0 : _a.prompt_tokens) === undefined) {
|
|
32554
|
-
throw new PipelineExecutionError('In OpenAI response `usage.prompt_tokens` not defined');
|
|
32555
|
-
}
|
|
32556
|
-
const inputTokens = rawResponse.usage.prompt_tokens;
|
|
32557
|
-
const outputTokens = ((_b = rawResponse.usage) === null || _b === void 0 ? void 0 : _b.completion_tokens) || 0;
|
|
32558
|
-
let isUncertain = false;
|
|
32559
|
-
let modelInfo = OPENAI_MODELS.find((model) => model.modelName === rawResponse.model);
|
|
32560
|
-
if (modelInfo === undefined) {
|
|
32561
|
-
// Note: Model is not in the list of known models, fallback to the family of the models and mark price as uncertain
|
|
32562
|
-
modelInfo = OPENAI_MODELS.find((model) => (rawResponse.model || SALT_NONCE).startsWith(model.modelName));
|
|
32563
|
-
if (modelInfo !== undefined) {
|
|
32564
|
-
isUncertain = true;
|
|
32565
|
-
}
|
|
32566
|
-
}
|
|
32567
|
-
let price;
|
|
32568
|
-
if (modelInfo === undefined || modelInfo.pricing === undefined) {
|
|
32569
|
-
price = uncertainNumber();
|
|
32570
|
-
}
|
|
32571
|
-
else {
|
|
32572
|
-
price = uncertainNumber(inputTokens * modelInfo.pricing.prompt + outputTokens * modelInfo.pricing.output, isUncertain);
|
|
32573
|
-
}
|
|
32574
|
-
return {
|
|
32575
|
-
price,
|
|
32576
|
-
duration,
|
|
32577
|
-
input: {
|
|
32578
|
-
tokensCount: uncertainNumber(rawResponse.usage.prompt_tokens),
|
|
32579
|
-
...computeUsageCounts(promptContent),
|
|
32580
|
-
},
|
|
32581
|
-
output: {
|
|
32582
|
-
tokensCount: uncertainNumber(outputTokens),
|
|
32583
|
-
...computeUsageCounts(resultContent),
|
|
32584
|
-
},
|
|
32585
|
-
};
|
|
32586
|
-
}
|
|
32587
|
-
// TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
|
|
32588
|
-
|
|
32589
32930
|
/**
|
|
32590
32931
|
* Finds the best hardcoded-model match for one API-listed model identifier.
|
|
32591
32932
|
*/
|
|
@@ -43043,18 +43384,6 @@
|
|
|
43043
43384
|
const $llmToolsMetadataRegister = new $Register('llm_tools_metadata');
|
|
43044
43385
|
// TODO: [®] DRY Register logic
|
|
43045
43386
|
|
|
43046
|
-
/**
|
|
43047
|
-
* Register for LLM tools.
|
|
43048
|
-
*
|
|
43049
|
-
* Note: `$` is used to indicate that this interacts with the global scope
|
|
43050
|
-
*
|
|
43051
|
-
* @singleton Only one instance of each register is created per build, but there can be more instances across different builds or environments.
|
|
43052
|
-
*
|
|
43053
|
-
* @public exported from `@promptbook/core`
|
|
43054
|
-
*/
|
|
43055
|
-
const $llmToolsRegister = new $Register('llm_execution_tools_constructors');
|
|
43056
|
-
// TODO: [®] DRY Register logic
|
|
43057
|
-
|
|
43058
43387
|
/**
|
|
43059
43388
|
* Path to the `.env` file which was used to configure LLM tools
|
|
43060
43389
|
*
|
|
@@ -43062,61 +43391,53 @@
|
|
|
43062
43391
|
*/
|
|
43063
43392
|
let $usedEnvFilename = null;
|
|
43064
43393
|
/**
|
|
43065
|
-
*
|
|
43066
|
-
*
|
|
43067
|
-
* Note: `$` is used to indicate that this variable is making side effect
|
|
43068
|
-
*
|
|
43069
|
-
* @private internal log of `$provideLlmToolsConfigurationFromEnv` and `$registeredLlmToolsMessage`
|
|
43070
|
-
*/
|
|
43071
|
-
function $setUsedEnvFilename(filepath) {
|
|
43072
|
-
$usedEnvFilename = filepath;
|
|
43073
|
-
}
|
|
43074
|
-
/**
|
|
43075
|
-
* Creates a message with all registered LLM tools
|
|
43076
|
-
*
|
|
43077
|
-
* Note: This function is used to create a (error) message when there is no constructor for some LLM provider
|
|
43078
|
-
*
|
|
43079
|
-
* @private internal function of `createLlmToolsFromConfiguration` and `$provideLlmToolsFromEnv`
|
|
43080
|
-
*/
|
|
43081
|
-
function $registeredLlmToolsMessage() {
|
|
43082
|
-
const registeredLlmToolsMessageContext = createRegisteredLlmToolsMessageContext();
|
|
43083
|
-
if (registeredLlmToolsMessageContext.llmToolStatuses.length === 0) {
|
|
43084
|
-
return renderNoRegisteredLlmToolsMessage(registeredLlmToolsMessageContext.usedEnvMessage);
|
|
43085
|
-
}
|
|
43086
|
-
return renderRegisteredLlmToolsMessage(registeredLlmToolsMessageContext);
|
|
43087
|
-
}
|
|
43088
|
-
/**
|
|
43089
|
-
* Collects all state needed to render the provider summary.
|
|
43394
|
+
* Shared state for the `.env` file used to configure LLM tools.
|
|
43090
43395
|
*
|
|
43091
|
-
* @private internal
|
|
43396
|
+
* @private internal state of `$registeredLlmToolsMessage`
|
|
43092
43397
|
*/
|
|
43093
|
-
|
|
43094
|
-
|
|
43095
|
-
|
|
43096
|
-
|
|
43097
|
-
|
|
43098
|
-
|
|
43099
|
-
|
|
43100
|
-
|
|
43101
|
-
|
|
43102
|
-
|
|
43103
|
-
|
|
43398
|
+
const USED_ENV_FILENAME = {
|
|
43399
|
+
set(filepath) {
|
|
43400
|
+
$usedEnvFilename = filepath;
|
|
43401
|
+
},
|
|
43402
|
+
createMessage() {
|
|
43403
|
+
return $usedEnvFilename === null
|
|
43404
|
+
? `Unknown \`.env\` file`
|
|
43405
|
+
: _spaceTrim.spaceTrim(`
|
|
43406
|
+
Used \`.env\` file:
|
|
43407
|
+
${$usedEnvFilename}
|
|
43408
|
+
`);
|
|
43409
|
+
},
|
|
43410
|
+
};
|
|
43411
|
+
|
|
43104
43412
|
/**
|
|
43105
43413
|
* Reads environment variables relevant for provider configuration.
|
|
43106
43414
|
*
|
|
43107
|
-
* @private
|
|
43415
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43108
43416
|
*/
|
|
43109
|
-
function
|
|
43417
|
+
function getAvailableRegisteredLlmToolsEnvironmentVariables(isRunningInNode) {
|
|
43110
43418
|
if (isRunningInNode) {
|
|
43111
43419
|
return process.env;
|
|
43112
43420
|
// <- TODO: [⚛] Some DRY way how to get to `process.env` and pass it into functions - ACRY search for `env`
|
|
43113
43421
|
}
|
|
43114
43422
|
return {};
|
|
43115
43423
|
}
|
|
43424
|
+
|
|
43425
|
+
/**
|
|
43426
|
+
* Register for LLM tools.
|
|
43427
|
+
*
|
|
43428
|
+
* Note: `$` is used to indicate that this interacts with the global scope
|
|
43429
|
+
*
|
|
43430
|
+
* @singleton Only one instance of each register is created per build, but there can be more instances across different builds or environments.
|
|
43431
|
+
*
|
|
43432
|
+
* @public exported from `@promptbook/core`
|
|
43433
|
+
*/
|
|
43434
|
+
const $llmToolsRegister = new $Register('llm_execution_tools_constructors');
|
|
43435
|
+
// TODO: [®] DRY Register logic
|
|
43436
|
+
|
|
43116
43437
|
/**
|
|
43117
43438
|
* Takes stable snapshots of both LLM provider registers.
|
|
43118
43439
|
*
|
|
43119
|
-
* @private
|
|
43440
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43120
43441
|
*/
|
|
43121
43442
|
function getRegisteredLlmToolRegisters() {
|
|
43122
43443
|
return {
|
|
@@ -43124,62 +43445,30 @@
|
|
|
43124
43445
|
registeredTools: $llmToolsRegister.list(),
|
|
43125
43446
|
};
|
|
43126
43447
|
}
|
|
43127
|
-
|
|
43128
|
-
* Lists provider entries enriched with installation and configuration state.
|
|
43129
|
-
*
|
|
43130
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43131
|
-
*/
|
|
43132
|
-
function listRegisteredLlmToolStatuses({ registeredMetadata, registeredTools }, env) {
|
|
43133
|
-
return listRegisteredLlmToolEntries(registeredMetadata, registeredTools).map((registeredLlmToolEntry) => createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env }));
|
|
43134
|
-
}
|
|
43135
|
-
/**
|
|
43136
|
-
* Merges provider entries from the metadata and constructor registers.
|
|
43137
|
-
*
|
|
43138
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43139
|
-
*/
|
|
43140
|
-
function listRegisteredLlmToolEntries(registeredMetadata, registeredTools) {
|
|
43141
|
-
const registeredLlmToolEntries = new Map();
|
|
43142
|
-
for (const { title, packageName, className, envVariables } of registeredMetadata) {
|
|
43143
|
-
addRegisteredLlmToolEntry(registeredLlmToolEntries, { title, packageName, className, envVariables });
|
|
43144
|
-
}
|
|
43145
|
-
for (const { packageName, className } of registeredTools) {
|
|
43146
|
-
addRegisteredLlmToolEntry(registeredLlmToolEntries, { packageName, className });
|
|
43147
|
-
}
|
|
43148
|
-
return [...registeredLlmToolEntries.values()];
|
|
43149
|
-
}
|
|
43150
|
-
/**
|
|
43151
|
-
* Adds a provider entry only when the provider is not already present.
|
|
43152
|
-
*
|
|
43153
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43154
|
-
*/
|
|
43155
|
-
function addRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43156
|
-
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43157
|
-
if (registeredLlmToolEntries.has(registeredLlmToolEntryKey)) {
|
|
43158
|
-
return;
|
|
43159
|
-
}
|
|
43160
|
-
registeredLlmToolEntries.set(registeredLlmToolEntryKey, registeredLlmToolEntry);
|
|
43161
|
-
}
|
|
43448
|
+
|
|
43162
43449
|
/**
|
|
43163
43450
|
* Creates a deduplication key for a provider entry.
|
|
43164
43451
|
*
|
|
43165
|
-
* @private
|
|
43452
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43166
43453
|
*/
|
|
43167
43454
|
function createRegisteredLlmToolEntryKey({ packageName, className }) {
|
|
43168
43455
|
return `${packageName}::${className}`;
|
|
43169
43456
|
}
|
|
43457
|
+
|
|
43170
43458
|
/**
|
|
43171
43459
|
* Checks whether the given provider entry already exists in the target register list.
|
|
43172
43460
|
*
|
|
43173
|
-
* @private
|
|
43461
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43174
43462
|
*/
|
|
43175
43463
|
function hasRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43176
43464
|
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43177
43465
|
return registeredLlmToolEntries.some((listedRegisteredLlmToolEntry) => createRegisteredLlmToolEntryKey(listedRegisteredLlmToolEntry) === registeredLlmToolEntryKey);
|
|
43178
43466
|
}
|
|
43467
|
+
|
|
43179
43468
|
/**
|
|
43180
43469
|
* Builds the runtime status for one provider entry.
|
|
43181
43470
|
*
|
|
43182
|
-
* @private
|
|
43471
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43183
43472
|
*/
|
|
43184
43473
|
function createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env, }) {
|
|
43185
43474
|
const availabilityStatus = createRegisteredLlmToolAvailabilityStatus(registeredLlmToolEntry, registeredMetadata, registeredTools);
|
|
@@ -43193,7 +43482,7 @@
|
|
|
43193
43482
|
/**
|
|
43194
43483
|
* Resolves whether the provider has metadata and a registered constructor.
|
|
43195
43484
|
*
|
|
43196
|
-
* @private
|
|
43485
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43197
43486
|
*/
|
|
43198
43487
|
function createRegisteredLlmToolAvailabilityStatus(registeredLlmToolEntry, registeredMetadata, registeredTools) {
|
|
43199
43488
|
return {
|
|
@@ -43204,7 +43493,7 @@
|
|
|
43204
43493
|
/**
|
|
43205
43494
|
* Resolves whether the provider has enough environment variables to be configured.
|
|
43206
43495
|
*
|
|
43207
|
-
* @private
|
|
43496
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43208
43497
|
*/
|
|
43209
43498
|
function createRegisteredLlmToolConfigurationStatus({ envVariables }, env) {
|
|
43210
43499
|
return {
|
|
@@ -43215,7 +43504,7 @@
|
|
|
43215
43504
|
/**
|
|
43216
43505
|
* Checks whether all required environment variables are present for a provider.
|
|
43217
43506
|
*
|
|
43218
|
-
* @private
|
|
43507
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43219
43508
|
*/
|
|
43220
43509
|
function isRegisteredLlmToolFullyConfigured(envVariables, env) {
|
|
43221
43510
|
if (envVariables === undefined || envVariables === null) {
|
|
@@ -43226,7 +43515,7 @@
|
|
|
43226
43515
|
/**
|
|
43227
43516
|
* Checks whether at least one required environment variable is present for a provider.
|
|
43228
43517
|
*
|
|
43229
|
-
* @private
|
|
43518
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43230
43519
|
*/
|
|
43231
43520
|
function isRegisteredLlmToolPartiallyConfigured(envVariables, env) {
|
|
43232
43521
|
if (envVariables === undefined || envVariables === null) {
|
|
@@ -43234,109 +43523,128 @@
|
|
|
43234
43523
|
}
|
|
43235
43524
|
return envVariables.some((envVariableName) => env[envVariableName] !== undefined);
|
|
43236
43525
|
}
|
|
43526
|
+
|
|
43237
43527
|
/**
|
|
43238
|
-
*
|
|
43528
|
+
* Merges provider entries from the metadata and constructor registers.
|
|
43239
43529
|
*
|
|
43240
|
-
* @private
|
|
43530
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43241
43531
|
*/
|
|
43242
|
-
function
|
|
43243
|
-
|
|
43244
|
-
|
|
43245
|
-
|
|
43246
|
-
|
|
43247
|
-
|
|
43532
|
+
function listRegisteredLlmToolEntries(registeredMetadata, registeredTools) {
|
|
43533
|
+
const registeredLlmToolEntries = new Map();
|
|
43534
|
+
for (const { title, packageName, className, envVariables } of registeredMetadata) {
|
|
43535
|
+
addRegisteredLlmToolEntry(registeredLlmToolEntries, { title, packageName, className, envVariables });
|
|
43536
|
+
}
|
|
43537
|
+
for (const { packageName, className } of registeredTools) {
|
|
43538
|
+
addRegisteredLlmToolEntry(registeredLlmToolEntries, { packageName, className });
|
|
43539
|
+
}
|
|
43540
|
+
return [...registeredLlmToolEntries.values()];
|
|
43248
43541
|
}
|
|
43249
43542
|
/**
|
|
43250
|
-
*
|
|
43543
|
+
* Adds a provider entry only when the provider is not already present.
|
|
43251
43544
|
*
|
|
43252
|
-
* @private
|
|
43545
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43253
43546
|
*/
|
|
43254
|
-
function
|
|
43255
|
-
|
|
43256
|
-
|
|
43257
|
-
|
|
43258
|
-
|
|
43259
|
-
|
|
43260
|
-
${block(renderRelevantEnvironmentVariables(env, llmToolStatuses))}
|
|
43261
|
-
|
|
43262
|
-
Available LLM providers are:
|
|
43263
|
-
${block(renderAvailableProviders(llmToolStatuses, env, isRunningInNode))}
|
|
43264
|
-
`);
|
|
43547
|
+
function addRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43548
|
+
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43549
|
+
if (registeredLlmToolEntries.has(registeredLlmToolEntryKey)) {
|
|
43550
|
+
return;
|
|
43551
|
+
}
|
|
43552
|
+
registeredLlmToolEntries.set(registeredLlmToolEntryKey, registeredLlmToolEntry);
|
|
43265
43553
|
}
|
|
43554
|
+
|
|
43266
43555
|
/**
|
|
43267
|
-
*
|
|
43556
|
+
* Lists provider entries enriched with installation and configuration state.
|
|
43268
43557
|
*
|
|
43269
|
-
* @private
|
|
43558
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43270
43559
|
*/
|
|
43271
|
-
function
|
|
43272
|
-
return
|
|
43273
|
-
.map((envVariableName) => `- \`${envVariableName}\``)
|
|
43274
|
-
.join('\n');
|
|
43560
|
+
function listRegisteredLlmToolStatuses({ registeredMetadata, registeredTools }, env) {
|
|
43561
|
+
return listRegisteredLlmToolEntries(registeredMetadata, registeredTools).map((registeredLlmToolEntry) => createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env }));
|
|
43275
43562
|
}
|
|
43563
|
+
|
|
43276
43564
|
/**
|
|
43277
|
-
*
|
|
43565
|
+
* Collects all state needed to render the provider summary.
|
|
43278
43566
|
*
|
|
43279
|
-
* @private
|
|
43567
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43280
43568
|
*/
|
|
43281
|
-
function
|
|
43282
|
-
|
|
43569
|
+
function createRegisteredLlmToolsMessageContext() {
|
|
43570
|
+
const isRunningInNode = $isRunningInNode();
|
|
43571
|
+
const env = getAvailableRegisteredLlmToolsEnvironmentVariables(isRunningInNode);
|
|
43572
|
+
const registeredLlmToolRegisters = getRegisteredLlmToolRegisters();
|
|
43573
|
+
return {
|
|
43574
|
+
env,
|
|
43575
|
+
llmToolStatuses: listRegisteredLlmToolStatuses(registeredLlmToolRegisters, env),
|
|
43576
|
+
usedEnvMessage: USED_ENV_FILENAME.createMessage(),
|
|
43577
|
+
isRunningInNode,
|
|
43578
|
+
};
|
|
43283
43579
|
}
|
|
43580
|
+
|
|
43284
43581
|
/**
|
|
43285
|
-
* Renders
|
|
43582
|
+
* Renders the fallback message for environments with no registered providers.
|
|
43286
43583
|
*
|
|
43287
|
-
* @private
|
|
43584
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43288
43585
|
*/
|
|
43289
|
-
function
|
|
43290
|
-
return
|
|
43291
|
-
|
|
43292
|
-
|
|
43586
|
+
function renderNoRegisteredLlmToolsMessage(usedEnvMessage) {
|
|
43587
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
43588
|
+
No LLM providers are available.
|
|
43589
|
+
|
|
43590
|
+
${block(usedEnvMessage)}
|
|
43591
|
+
`);
|
|
43293
43592
|
}
|
|
43593
|
+
|
|
43294
43594
|
/**
|
|
43295
|
-
*
|
|
43595
|
+
* Creates the configuration-status sentence for one provider.
|
|
43296
43596
|
*
|
|
43297
|
-
* @private
|
|
43597
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43298
43598
|
*/
|
|
43299
|
-
function
|
|
43300
|
-
|
|
43301
|
-
|
|
43302
|
-
|
|
43599
|
+
function createRegisteredLlmToolConfigurationStatusMessage({ envVariables, isFullyConfigured, isPartiallyConfigured }, env) {
|
|
43600
|
+
if (isFullyConfigured) {
|
|
43601
|
+
return `Configured`;
|
|
43602
|
+
}
|
|
43603
|
+
if (isPartiallyConfigured) {
|
|
43604
|
+
return createPartiallyConfiguredStatusMessage(envVariables, env);
|
|
43605
|
+
}
|
|
43606
|
+
if (envVariables !== null) {
|
|
43607
|
+
return createNotConfiguredStatusMessage(envVariables);
|
|
43303
43608
|
}
|
|
43304
|
-
return
|
|
43609
|
+
return `Not configured`;
|
|
43610
|
+
// <- Note: Can not be configured via environment variables
|
|
43305
43611
|
}
|
|
43306
43612
|
/**
|
|
43307
|
-
* Creates the
|
|
43613
|
+
* Creates the partial-configuration sentence including missing variables.
|
|
43308
43614
|
*
|
|
43309
|
-
* @private
|
|
43615
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43310
43616
|
*/
|
|
43311
|
-
function
|
|
43312
|
-
|
|
43313
|
-
const providerStatusMessages = createProviderStatusMessages(llmToolStatus, env);
|
|
43314
|
-
return _spaceTrim.spaceTrim(`
|
|
43315
|
-
${index + 1}) **${title}** \`${className}\` from \`${packageName}\`
|
|
43316
|
-
${providerStatusMessages.join('; ')}
|
|
43317
|
-
`);
|
|
43617
|
+
function createPartiallyConfiguredStatusMessage(envVariables, env) {
|
|
43618
|
+
return `Partially confugured, missing ${listMissingEnvironmentVariables(envVariables, env).join(' + ')}`;
|
|
43318
43619
|
}
|
|
43319
43620
|
/**
|
|
43320
|
-
* Creates the
|
|
43621
|
+
* Creates the not-configured sentence including the expected environment variables.
|
|
43321
43622
|
*
|
|
43322
|
-
* @private
|
|
43623
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43323
43624
|
*/
|
|
43324
|
-
function
|
|
43325
|
-
return
|
|
43625
|
+
function createNotConfiguredStatusMessage(envVariables) {
|
|
43626
|
+
return `Not configured, to configure set env ${envVariables === null || envVariables === void 0 ? void 0 : envVariables.join(' + ')}`;
|
|
43627
|
+
}
|
|
43628
|
+
/**
|
|
43629
|
+
* Lists environment variables that are required but currently missing.
|
|
43630
|
+
*
|
|
43631
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43632
|
+
*/
|
|
43633
|
+
function listMissingEnvironmentVariables(envVariables, env) {
|
|
43634
|
+
return (envVariables === null || envVariables === void 0 ? void 0 : envVariables.filter((envVariable) => env[envVariable] === undefined)) || [];
|
|
43326
43635
|
}
|
|
43636
|
+
|
|
43327
43637
|
/**
|
|
43328
43638
|
* Creates the installation-status sentence for one provider.
|
|
43329
43639
|
*
|
|
43330
|
-
* @private
|
|
43640
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43331
43641
|
*/
|
|
43332
|
-
function
|
|
43333
|
-
const installationStatusKey =
|
|
43642
|
+
function createRegisteredLlmToolInstallationStatusMessage({ isMetadataAvailable, isInstalled, }) {
|
|
43643
|
+
const installationStatusKey = createRegisteredLlmToolInstallationStatusKey(isMetadataAvailable, isInstalled);
|
|
43334
43644
|
switch (installationStatusKey) {
|
|
43335
43645
|
case 'missing-metadata-and-installation':
|
|
43336
|
-
// TODO: [�][�] Maybe do allow to do auto-install if package not registered and not found
|
|
43337
43646
|
return `Not installed and no metadata, looks like a unexpected behavior`;
|
|
43338
43647
|
case 'metadata-without-installation':
|
|
43339
|
-
// TODO: [�][�]
|
|
43340
43648
|
return `Not installed`;
|
|
43341
43649
|
case 'installation-without-metadata':
|
|
43342
43650
|
return `No metadata but installed, looks like a unexpected behavior`;
|
|
@@ -43349,9 +43657,9 @@
|
|
|
43349
43657
|
/**
|
|
43350
43658
|
* Creates a stable installation-state key from metadata and constructor availability.
|
|
43351
43659
|
*
|
|
43352
|
-
* @private
|
|
43660
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43353
43661
|
*/
|
|
43354
|
-
function
|
|
43662
|
+
function createRegisteredLlmToolInstallationStatusKey(isMetadataAvailable, isInstalled) {
|
|
43355
43663
|
if (!isMetadataAvailable && !isInstalled) {
|
|
43356
43664
|
return 'missing-metadata-and-installation';
|
|
43357
43665
|
}
|
|
@@ -43366,54 +43674,59 @@
|
|
|
43366
43674
|
}
|
|
43367
43675
|
return 'unknown';
|
|
43368
43676
|
}
|
|
43677
|
+
|
|
43369
43678
|
/**
|
|
43370
|
-
*
|
|
43679
|
+
* Renders all provider lines in the status summary.
|
|
43371
43680
|
*
|
|
43372
|
-
* @private
|
|
43681
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43373
43682
|
*/
|
|
43374
|
-
function
|
|
43375
|
-
|
|
43376
|
-
|
|
43377
|
-
|
|
43378
|
-
if (isPartiallyConfigured) {
|
|
43379
|
-
return createPartiallyConfiguredStatusMessage(envVariables, env);
|
|
43380
|
-
}
|
|
43381
|
-
if (envVariables !== null) {
|
|
43382
|
-
return createNotConfiguredStatusMessage(envVariables);
|
|
43383
|
-
}
|
|
43384
|
-
return `Not configured`;
|
|
43385
|
-
// <- Note: Can not be configured via environment variables
|
|
43683
|
+
function renderAvailableRegisteredLlmTools(llmToolStatuses, env, isRunningInNode) {
|
|
43684
|
+
return llmToolStatuses
|
|
43685
|
+
.map((llmToolStatus, index) => renderAvailableRegisteredLlmTool(llmToolStatus, index, env, isRunningInNode))
|
|
43686
|
+
.join('\n');
|
|
43386
43687
|
}
|
|
43387
43688
|
/**
|
|
43388
|
-
*
|
|
43689
|
+
* Renders one provider line in the status summary.
|
|
43389
43690
|
*
|
|
43390
|
-
* @private
|
|
43691
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43391
43692
|
*/
|
|
43392
|
-
function
|
|
43393
|
-
|
|
43693
|
+
function renderAvailableRegisteredLlmTool(llmToolStatus, index, env, isRunningInNode) {
|
|
43694
|
+
const providerMessage = createAvailableRegisteredLlmToolMessage(llmToolStatus, index, env);
|
|
43695
|
+
if (!isRunningInNode) {
|
|
43696
|
+
return providerMessage;
|
|
43697
|
+
}
|
|
43698
|
+
return colorizeAvailableRegisteredLlmToolMessage(providerMessage, llmToolStatus);
|
|
43394
43699
|
}
|
|
43395
43700
|
/**
|
|
43396
|
-
* Creates the
|
|
43701
|
+
* Creates the plain-text provider line before optional colorization.
|
|
43397
43702
|
*
|
|
43398
|
-
* @private
|
|
43703
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43399
43704
|
*/
|
|
43400
|
-
function
|
|
43401
|
-
|
|
43705
|
+
function createAvailableRegisteredLlmToolMessage(llmToolStatus, index, env) {
|
|
43706
|
+
const { title, packageName, className } = llmToolStatus;
|
|
43707
|
+
const providerStatusMessages = createRegisteredLlmToolStatusMessages(llmToolStatus, env);
|
|
43708
|
+
return _spaceTrim.spaceTrim(`
|
|
43709
|
+
${index + 1}) **${title}** \`${className}\` from \`${packageName}\`
|
|
43710
|
+
${providerStatusMessages.join('; ')}
|
|
43711
|
+
`);
|
|
43402
43712
|
}
|
|
43403
43713
|
/**
|
|
43404
|
-
*
|
|
43714
|
+
* Creates the install and configuration fragments for one provider line.
|
|
43405
43715
|
*
|
|
43406
|
-
* @private
|
|
43716
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43407
43717
|
*/
|
|
43408
|
-
function
|
|
43409
|
-
return
|
|
43718
|
+
function createRegisteredLlmToolStatusMessages(llmToolStatus, env) {
|
|
43719
|
+
return [
|
|
43720
|
+
createRegisteredLlmToolInstallationStatusMessage(llmToolStatus),
|
|
43721
|
+
createRegisteredLlmToolConfigurationStatusMessage(llmToolStatus, env),
|
|
43722
|
+
];
|
|
43410
43723
|
}
|
|
43411
43724
|
/**
|
|
43412
43725
|
* Applies the same terminal coloring rules as the original summary renderer.
|
|
43413
43726
|
*
|
|
43414
|
-
* @private
|
|
43727
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43415
43728
|
*/
|
|
43416
|
-
function
|
|
43729
|
+
function colorizeAvailableRegisteredLlmToolMessage(providerMessage, { isInstalled, isFullyConfigured, isPartiallyConfigured }) {
|
|
43417
43730
|
if (isInstalled && isFullyConfigured) {
|
|
43418
43731
|
return colors__default["default"].green(providerMessage);
|
|
43419
43732
|
}
|
|
@@ -43422,18 +43735,67 @@
|
|
|
43422
43735
|
}
|
|
43423
43736
|
return colors__default["default"].gray(providerMessage);
|
|
43424
43737
|
}
|
|
43738
|
+
|
|
43425
43739
|
/**
|
|
43426
|
-
*
|
|
43740
|
+
* Renders the list of environment variables used by at least one registered provider.
|
|
43427
43741
|
*
|
|
43428
|
-
* @private
|
|
43742
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43429
43743
|
*/
|
|
43430
|
-
function
|
|
43431
|
-
return
|
|
43432
|
-
|
|
43433
|
-
|
|
43434
|
-
|
|
43435
|
-
|
|
43436
|
-
|
|
43744
|
+
function renderRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses) {
|
|
43745
|
+
return listRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses)
|
|
43746
|
+
.map((envVariableName) => `- \`${envVariableName}\``)
|
|
43747
|
+
.join('\n');
|
|
43748
|
+
}
|
|
43749
|
+
/**
|
|
43750
|
+
* Lists environment variables that are both present and used by at least one provider.
|
|
43751
|
+
*
|
|
43752
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43753
|
+
*/
|
|
43754
|
+
function listRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses) {
|
|
43755
|
+
return Object.keys(env).filter((envVariableName) => llmToolStatuses.some(({ envVariables }) => envVariables === null || envVariables === void 0 ? void 0 : envVariables.includes(envVariableName)));
|
|
43756
|
+
}
|
|
43757
|
+
|
|
43758
|
+
/**
|
|
43759
|
+
* Renders the full provider status summary.
|
|
43760
|
+
*
|
|
43761
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43762
|
+
*/
|
|
43763
|
+
function renderRegisteredLlmToolsMessage({ env, llmToolStatuses, usedEnvMessage, isRunningInNode, }) {
|
|
43764
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
43765
|
+
|
|
43766
|
+
${block(usedEnvMessage)}
|
|
43767
|
+
|
|
43768
|
+
Relevant environment variables:
|
|
43769
|
+
${block(renderRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses))}
|
|
43770
|
+
|
|
43771
|
+
Available LLM providers are:
|
|
43772
|
+
${block(renderAvailableRegisteredLlmTools(llmToolStatuses, env, isRunningInNode))}
|
|
43773
|
+
`);
|
|
43774
|
+
}
|
|
43775
|
+
|
|
43776
|
+
/**
|
|
43777
|
+
* Pass the `.env` file which was used to configure LLM tools
|
|
43778
|
+
*
|
|
43779
|
+
* Note: `$` is used to indicate that this variable is making side effect
|
|
43780
|
+
*
|
|
43781
|
+
* @private internal log of `$provideLlmToolsConfigurationFromEnv` and `$registeredLlmToolsMessage`
|
|
43782
|
+
*/
|
|
43783
|
+
function $setUsedEnvFilename(filepath) {
|
|
43784
|
+
USED_ENV_FILENAME.set(filepath);
|
|
43785
|
+
}
|
|
43786
|
+
/**
|
|
43787
|
+
* Creates a message with all registered LLM tools
|
|
43788
|
+
*
|
|
43789
|
+
* Note: This function is used to create a (error) message when there is no constructor for some LLM provider
|
|
43790
|
+
*
|
|
43791
|
+
* @private internal function of `createLlmToolsFromConfiguration` and `$provideLlmToolsFromEnv`
|
|
43792
|
+
*/
|
|
43793
|
+
function $registeredLlmToolsMessage() {
|
|
43794
|
+
const registeredLlmToolsMessageContext = createRegisteredLlmToolsMessageContext();
|
|
43795
|
+
if (registeredLlmToolsMessageContext.llmToolStatuses.length === 0) {
|
|
43796
|
+
return renderNoRegisteredLlmToolsMessage(registeredLlmToolsMessageContext.usedEnvMessage);
|
|
43797
|
+
}
|
|
43798
|
+
return renderRegisteredLlmToolsMessage(registeredLlmToolsMessageContext);
|
|
43437
43799
|
}
|
|
43438
43800
|
// TODO: [®] DRY Register logic
|
|
43439
43801
|
// TODO: [🧠][⚛] Maybe pass env as argument
|