@promptbook/node 0.113.0-1 → 0.113.0-11
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/README.md +1 -17
- package/esm/book/scripts/import-markdown/increaseHeadings.d.ts +8 -0
- package/esm/index.es.js +1630 -1222
- 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/common/waitUntilWorldTimeDeadline.d.ts +17 -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 +98 -0
- 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/CitationIframePreview.d.ts +1 -1
- package/esm/src/book-components/Chat/Chat/CitationIframePreview.test.d.ts +2 -0
- package/esm/src/book-components/Chat/Chat/insertDictationChunk.d.ts +1 -1
- package/esm/src/book-components/Chat/Chat/insertDictationChunk.test.d.ts +1 -0
- package/esm/src/book-components/Chat/Chat/learnDictationDictionary.test.d.ts +1 -0
- package/esm/src/book-components/Chat/Chat/refineFinalDictationChunk.test.d.ts +1 -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/createPositiveIntegerOptionParser.d.ts +10 -0
- 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/agent-message-runtime/agentMessageRuntimePaths.d.ts +24 -0
- package/esm/src/utils/agents/resolveAgentAvatarImageUrl.d.ts +2 -2
- package/esm/src/utils/agents/terminalAgentAvatarVisual.d.ts +94 -0
- package/esm/src/utils/agents/terminalAgentAvatarVisual.test.d.ts +1 -0
- package/esm/src/utils/ascii-art/$detectTerminalAnsiColorDepth.d.ts +15 -0
- package/esm/src/utils/ascii-art/convertImageDataToAsciiArt.d.ts +80 -0
- 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 +1634 -1226
- 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/common/waitUntilWorldTimeDeadline.d.ts +17 -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 +98 -0
- 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/CitationIframePreview.d.ts +1 -1
- package/umd/src/book-components/Chat/Chat/CitationIframePreview.test.d.ts +2 -0
- package/umd/src/book-components/Chat/Chat/insertDictationChunk.d.ts +1 -1
- package/umd/src/book-components/Chat/Chat/insertDictationChunk.test.d.ts +1 -0
- package/umd/src/book-components/Chat/Chat/learnDictationDictionary.test.d.ts +1 -0
- package/umd/src/book-components/Chat/Chat/refineFinalDictationChunk.test.d.ts +1 -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/createPositiveIntegerOptionParser.d.ts +10 -0
- 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/agent-message-runtime/agentMessageRuntimePaths.d.ts +24 -0
- package/umd/src/utils/agents/resolveAgentAvatarImageUrl.d.ts +2 -2
- package/umd/src/utils/agents/terminalAgentAvatarVisual.d.ts +94 -0
- package/umd/src/utils/agents/terminalAgentAvatarVisual.test.d.ts +1 -0
- package/umd/src/utils/ascii-art/$detectTerminalAnsiColorDepth.d.ts +15 -0
- package/umd/src/utils/ascii-art/convertImageDataToAsciiArt.d.ts +80 -0
- package/umd/src/utils/color/Color.d.ts +1 -1
- package/umd/src/version.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/common/runGoScript/buildTemporaryPromptScriptPath.d.ts +0 -14
- package/esm/src/book-components/Chat/utils/livePagePreviewConstants.d.ts +0 -12
- package/umd/scripts/run-codex-prompts/common/runGoScript/buildTemporaryPromptScriptPath.d.ts +0 -14
- package/umd/src/book-components/Chat/utils/livePagePreviewConstants.d.ts +0 -12
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-11';
|
|
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
|
*/
|
|
@@ -3017,6 +3076,47 @@
|
|
|
3017
3076
|
});
|
|
3018
3077
|
}
|
|
3019
3078
|
|
|
3079
|
+
/**
|
|
3080
|
+
* Minimum timer duration used to avoid a zero-millisecond polling loop.
|
|
3081
|
+
*/
|
|
3082
|
+
const MINIMUM_WORLD_TIME_WAIT_POLL_INTERVAL_MS = 1;
|
|
3083
|
+
/**
|
|
3084
|
+
* Waits until one wall-clock deadline has passed.
|
|
3085
|
+
*
|
|
3086
|
+
* The remaining time is recalculated from `Date.now()` after every poll and after every tick callback.
|
|
3087
|
+
* This makes waits elapse while the process is paused at a checkpoint or the computer is asleep.
|
|
3088
|
+
*
|
|
3089
|
+
* @private internal utility of `ptbk coder` wait handling
|
|
3090
|
+
*/
|
|
3091
|
+
async function waitUntilWorldTimeDeadline(options) {
|
|
3092
|
+
const { deadlineTimeMs, pollIntervalMs, onTick } = options;
|
|
3093
|
+
const normalizedPollIntervalMs = Math.max(MINIMUM_WORLD_TIME_WAIT_POLL_INTERVAL_MS, pollIntervalMs);
|
|
3094
|
+
while (true) {
|
|
3095
|
+
const remainingDurationMs = getRemainingDurationMs(deadlineTimeMs);
|
|
3096
|
+
if (remainingDurationMs <= 0) {
|
|
3097
|
+
return;
|
|
3098
|
+
}
|
|
3099
|
+
await (onTick === null || onTick === void 0 ? void 0 : onTick(remainingDurationMs));
|
|
3100
|
+
const remainingDurationAfterTickMs = getRemainingDurationMs(deadlineTimeMs);
|
|
3101
|
+
if (remainingDurationAfterTickMs <= 0) {
|
|
3102
|
+
return;
|
|
3103
|
+
}
|
|
3104
|
+
await waitForMilliseconds(Math.min(normalizedPollIntervalMs, remainingDurationAfterTickMs));
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
/**
|
|
3108
|
+
* Returns the remaining wall-clock duration until a timestamp.
|
|
3109
|
+
*/
|
|
3110
|
+
function getRemainingDurationMs(deadlineTimeMs) {
|
|
3111
|
+
return Math.max(0, deadlineTimeMs - Date.now());
|
|
3112
|
+
}
|
|
3113
|
+
/**
|
|
3114
|
+
* Waits for one short polling interval.
|
|
3115
|
+
*/
|
|
3116
|
+
async function waitForMilliseconds(durationMs) {
|
|
3117
|
+
await new Promise((resolve) => setTimeout(resolve, durationMs));
|
|
3118
|
+
}
|
|
3119
|
+
|
|
3020
3120
|
/**
|
|
3021
3121
|
* Base delimiter used for passing large prompts through stdin.
|
|
3022
3122
|
*/
|
|
@@ -3025,15 +3125,211 @@
|
|
|
3025
3125
|
* Builds the shell script that runs Claude Code with the prompt and coding context.
|
|
3026
3126
|
*/
|
|
3027
3127
|
function buildClaudeScript(options) {
|
|
3128
|
+
const MODEL_ARGUMENT = options.model ? ` --model ${options.model}` : '';
|
|
3028
3129
|
const THINKING_LEVEL_ARGUMENT = options.thinkingLevel ? ` --effort ${options.thinkingLevel}` : '';
|
|
3130
|
+
const RESUME_SESSION_ARGUMENT = options.resumeSessionId
|
|
3131
|
+
? ` --resume ${quoteShellArgument(options.resumeSessionId)}`
|
|
3132
|
+
: '';
|
|
3029
3133
|
return spaceTrim((block) => `
|
|
3030
|
-
claude --allowedTools "Bash,Read,Edit,Write"${THINKING_LEVEL_ARGUMENT} --output-format json --print <<'${CLAUDE_PROMPT_DELIMITER}'
|
|
3134
|
+
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}'
|
|
3031
3135
|
|
|
3032
3136
|
${block(options.prompt)}
|
|
3033
3137
|
|
|
3034
3138
|
${CLAUDE_PROMPT_DELIMITER}
|
|
3035
3139
|
`);
|
|
3036
3140
|
}
|
|
3141
|
+
/**
|
|
3142
|
+
* Quotes one shell argument for the generated Bash script.
|
|
3143
|
+
*/
|
|
3144
|
+
function quoteShellArgument(value) {
|
|
3145
|
+
return JSON.stringify(value);
|
|
3146
|
+
}
|
|
3147
|
+
|
|
3148
|
+
/**
|
|
3149
|
+
* Parses all JSON lines from Claude Code output while ignoring shell prefixes and stack traces.
|
|
3150
|
+
*/
|
|
3151
|
+
function parseClaudeCodeOutputEvents(output) {
|
|
3152
|
+
return output
|
|
3153
|
+
.split(/\r?\n/u)
|
|
3154
|
+
.map(parseClaudeCodeOutputLine)
|
|
3155
|
+
.filter((event) => event !== undefined);
|
|
3156
|
+
}
|
|
3157
|
+
/**
|
|
3158
|
+
* Finds the final Claude Code result event in a stream-json output blob.
|
|
3159
|
+
*/
|
|
3160
|
+
function findClaudeCodeResultEvent(output) {
|
|
3161
|
+
return parseClaudeCodeOutputEvents(output).find((event) => event.type === 'result');
|
|
3162
|
+
}
|
|
3163
|
+
/**
|
|
3164
|
+
* Parses one output line when it contains a JSON object.
|
|
3165
|
+
*/
|
|
3166
|
+
function parseClaudeCodeOutputLine(line) {
|
|
3167
|
+
const jsonStartIndex = line.indexOf('{');
|
|
3168
|
+
if (jsonStartIndex === -1) {
|
|
3169
|
+
return undefined;
|
|
3170
|
+
}
|
|
3171
|
+
const possibleJson = line.slice(jsonStartIndex).trim();
|
|
3172
|
+
try {
|
|
3173
|
+
const parsed = JSON.parse(possibleJson);
|
|
3174
|
+
if (isClaudeCodeOutputEvent(parsed)) {
|
|
3175
|
+
return parsed;
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
catch (_a) {
|
|
3179
|
+
return undefined;
|
|
3180
|
+
}
|
|
3181
|
+
return undefined;
|
|
3182
|
+
}
|
|
3183
|
+
/**
|
|
3184
|
+
* Checks whether an unknown parsed JSON value has the object shape expected from Claude Code events.
|
|
3185
|
+
*/
|
|
3186
|
+
function isClaudeCodeOutputEvent(value) {
|
|
3187
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
/**
|
|
3191
|
+
* Number of milliseconds added after Claude's reported reset timestamp before retrying.
|
|
3192
|
+
*/
|
|
3193
|
+
const CLAUDE_CODE_SESSION_LIMIT_RESET_BUFFER_MS = 30 * 1000;
|
|
3194
|
+
/**
|
|
3195
|
+
* Fallback delay used when Claude reports a session limit without a machine-readable reset timestamp.
|
|
3196
|
+
*/
|
|
3197
|
+
const DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS = 10 * 60 * 1000;
|
|
3198
|
+
/**
|
|
3199
|
+
* Extracts a Claude Code session-limit failure from a thrown runner error.
|
|
3200
|
+
*/
|
|
3201
|
+
function extractClaudeCodeSessionLimitFromError(error) {
|
|
3202
|
+
return extractClaudeCodeSessionLimitFromOutput(formatUnknownErrorDetails(error));
|
|
3203
|
+
}
|
|
3204
|
+
/**
|
|
3205
|
+
* Extracts a Claude Code session-limit failure from raw stream-json output.
|
|
3206
|
+
*/
|
|
3207
|
+
function extractClaudeCodeSessionLimitFromOutput(output) {
|
|
3208
|
+
var _a, _b, _c, _d, _e;
|
|
3209
|
+
const events = parseClaudeCodeOutputEvents(output);
|
|
3210
|
+
const rejectedRateLimitEvent = events.find(isRejectedRateLimitEvent);
|
|
3211
|
+
const sessionLimitResultEvent = events.find(isSessionLimitResultEvent);
|
|
3212
|
+
const sessionLimitTextEvent = events.find(isSessionLimitTextEvent);
|
|
3213
|
+
if (!sessionLimitResultEvent && !sessionLimitTextEvent) {
|
|
3214
|
+
return undefined;
|
|
3215
|
+
}
|
|
3216
|
+
const sessionId = findClaudeCodeSessionId(events);
|
|
3217
|
+
if (!sessionId) {
|
|
3218
|
+
return undefined;
|
|
3219
|
+
}
|
|
3220
|
+
const resetDate = extractResetDate(rejectedRateLimitEvent);
|
|
3221
|
+
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;
|
|
3222
|
+
const summary = (_e = (_d = extractSessionLimitSummary(sessionLimitResultEvent)) !== null && _d !== void 0 ? _d : extractSessionLimitSummary(sessionLimitTextEvent)) !== null && _e !== void 0 ? _e : 'Claude Code reported a session limit.';
|
|
3223
|
+
return {
|
|
3224
|
+
sessionId,
|
|
3225
|
+
resetDate,
|
|
3226
|
+
rateLimitType,
|
|
3227
|
+
summary,
|
|
3228
|
+
};
|
|
3229
|
+
}
|
|
3230
|
+
/**
|
|
3231
|
+
* Computes how long to wait before trying to resume the Claude Code session.
|
|
3232
|
+
*/
|
|
3233
|
+
function getClaudeCodeSessionLimitDelayMs(sessionLimit, nowMs = Date.now()) {
|
|
3234
|
+
if (!sessionLimit.resetDate) {
|
|
3235
|
+
return DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS;
|
|
3236
|
+
}
|
|
3237
|
+
return Math.max(0, sessionLimit.resetDate.getTime() - nowMs + CLAUDE_CODE_SESSION_LIMIT_RESET_BUFFER_MS);
|
|
3238
|
+
}
|
|
3239
|
+
/**
|
|
3240
|
+
* Builds the follow-up prompt sent into a resumed Claude Code session after its limit resets.
|
|
3241
|
+
*/
|
|
3242
|
+
function buildClaudeCodeSessionResurrectionPrompt(originalPrompt, sessionId) {
|
|
3243
|
+
return spaceTrim((block) => `
|
|
3244
|
+
## Claude Code session resurrection
|
|
3245
|
+
|
|
3246
|
+
You are resuming Claude Code session \`${sessionId}\` after Claude reported a session limit.
|
|
3247
|
+
Continue the same task from the existing repository and session state.
|
|
3248
|
+
Do not discard useful context, completed analysis, or file changes from the resumed session.
|
|
3249
|
+
|
|
3250
|
+
The original prompt is repeated below as reference in case the resumed session needs it.
|
|
3251
|
+
|
|
3252
|
+
## Original prompt
|
|
3253
|
+
|
|
3254
|
+
${block(originalPrompt)}
|
|
3255
|
+
`);
|
|
3256
|
+
}
|
|
3257
|
+
/**
|
|
3258
|
+
* Builds a compact one-line label for logs and terminal UI messages.
|
|
3259
|
+
*/
|
|
3260
|
+
function formatClaudeCodeSessionLimitForDisplay(sessionLimit) {
|
|
3261
|
+
const resetSuffix = sessionLimit.resetDate
|
|
3262
|
+
? `, resets at ${sessionLimit.resetDate.toISOString()}`
|
|
3263
|
+
: `, retrying every ${formatDurationMs(DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS)}`;
|
|
3264
|
+
const rateLimitSuffix = sessionLimit.rateLimitType ? ` (${sessionLimit.rateLimitType})` : '';
|
|
3265
|
+
return `${sessionLimit.summary}${rateLimitSuffix}${resetSuffix}`;
|
|
3266
|
+
}
|
|
3267
|
+
/**
|
|
3268
|
+
* Returns true when the event is an explicit rejected Claude Code rate-limit event.
|
|
3269
|
+
*/
|
|
3270
|
+
function isRejectedRateLimitEvent(event) {
|
|
3271
|
+
var _a;
|
|
3272
|
+
return event.type === 'rate_limit_event' && ((_a = event.rate_limit_info) === null || _a === void 0 ? void 0 : _a.status) === 'rejected';
|
|
3273
|
+
}
|
|
3274
|
+
/**
|
|
3275
|
+
* Returns true when the final result reports the Claude session limit.
|
|
3276
|
+
*/
|
|
3277
|
+
function isSessionLimitResultEvent(event) {
|
|
3278
|
+
return (event.type === 'result' &&
|
|
3279
|
+
event.is_error === true &&
|
|
3280
|
+
event.api_error_status === 429 &&
|
|
3281
|
+
isSessionLimitText(event.result));
|
|
3282
|
+
}
|
|
3283
|
+
/**
|
|
3284
|
+
* Returns true when any assistant event reports the Claude session limit in text.
|
|
3285
|
+
*/
|
|
3286
|
+
function isSessionLimitTextEvent(event) {
|
|
3287
|
+
if (event.error !== 'rate_limit') {
|
|
3288
|
+
return false;
|
|
3289
|
+
}
|
|
3290
|
+
return isSessionLimitText(extractSessionLimitSummary(event));
|
|
3291
|
+
}
|
|
3292
|
+
/**
|
|
3293
|
+
* Extracts the first session id reported by Claude Code.
|
|
3294
|
+
*/
|
|
3295
|
+
function findClaudeCodeSessionId(events) {
|
|
3296
|
+
return events.map((event) => event.session_id).find((sessionId) => Boolean(sessionId));
|
|
3297
|
+
}
|
|
3298
|
+
/**
|
|
3299
|
+
* Extracts Claude's reset timestamp from a rejected rate-limit event.
|
|
3300
|
+
*/
|
|
3301
|
+
function extractResetDate(event) {
|
|
3302
|
+
var _a;
|
|
3303
|
+
const resetsAt = (_a = event === null || event === void 0 ? void 0 : event.rate_limit_info) === null || _a === void 0 ? void 0 : _a.resetsAt;
|
|
3304
|
+
if (typeof resetsAt !== 'number' || !Number.isFinite(resetsAt)) {
|
|
3305
|
+
return undefined;
|
|
3306
|
+
}
|
|
3307
|
+
const resetDate = new Date(resetsAt * 1000);
|
|
3308
|
+
if (Number.isNaN(resetDate.getTime())) {
|
|
3309
|
+
return undefined;
|
|
3310
|
+
}
|
|
3311
|
+
return resetDate;
|
|
3312
|
+
}
|
|
3313
|
+
/**
|
|
3314
|
+
* Extracts a human-readable session-limit summary from an event.
|
|
3315
|
+
*/
|
|
3316
|
+
function extractSessionLimitSummary(event) {
|
|
3317
|
+
var _a, _b;
|
|
3318
|
+
if (!event) {
|
|
3319
|
+
return undefined;
|
|
3320
|
+
}
|
|
3321
|
+
if (typeof event.result === 'string' && event.result.trim()) {
|
|
3322
|
+
return event.result.trim();
|
|
3323
|
+
}
|
|
3324
|
+
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));
|
|
3325
|
+
return textContent;
|
|
3326
|
+
}
|
|
3327
|
+
/**
|
|
3328
|
+
* Checks whether a text value names the Claude Code session limit.
|
|
3329
|
+
*/
|
|
3330
|
+
function isSessionLimitText(text) {
|
|
3331
|
+
return /\bsession\s+limit\b/iu.test(text !== null && text !== void 0 ? text : '');
|
|
3332
|
+
}
|
|
3037
3333
|
|
|
3038
3334
|
/**
|
|
3039
3335
|
* Represents the uncertain value
|
|
@@ -3109,14 +3405,8 @@
|
|
|
3109
3405
|
function parseClaudeCodeJsonOutput(output) {
|
|
3110
3406
|
var _a, _b, _c, _d;
|
|
3111
3407
|
try {
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
const jsonLine = lines.find((line) => line.trim().startsWith('{"type":"result"'));
|
|
3115
|
-
if (!jsonLine) {
|
|
3116
|
-
return UNCERTAIN_USAGE;
|
|
3117
|
-
}
|
|
3118
|
-
const parsed = JSON.parse(jsonLine);
|
|
3119
|
-
if (parsed.type !== 'result') {
|
|
3408
|
+
const parsed = findClaudeCodeResultEvent(output);
|
|
3409
|
+
if (!parsed) {
|
|
3120
3410
|
return UNCERTAIN_USAGE;
|
|
3121
3411
|
}
|
|
3122
3412
|
const totalInputTokens = (((_a = parsed.usage) === null || _a === void 0 ? void 0 : _a.input_tokens) || 0) +
|
|
@@ -3160,6 +3450,10 @@
|
|
|
3160
3450
|
}
|
|
3161
3451
|
}
|
|
3162
3452
|
|
|
3453
|
+
/**
|
|
3454
|
+
* Polling interval used while waiting for Claude Code session limits to reset.
|
|
3455
|
+
*/
|
|
3456
|
+
const CLAUDE_CODE_SESSION_RESURRECTION_POLL_MS = 30 * 1000;
|
|
3163
3457
|
/**
|
|
3164
3458
|
* Runs prompts via the Claude Code CLI.
|
|
3165
3459
|
*/
|
|
@@ -3175,21 +3469,98 @@
|
|
|
3175
3469
|
* Runs the prompt using Claude Code and parses usage output.
|
|
3176
3470
|
*/
|
|
3177
3471
|
async runPrompt(options) {
|
|
3472
|
+
let resumeSessionId;
|
|
3473
|
+
let prompt = options.prompt;
|
|
3474
|
+
let resurrectionCount = 0;
|
|
3475
|
+
while (true) {
|
|
3476
|
+
const output = await this.runClaudeCodeOnce({
|
|
3477
|
+
...options,
|
|
3478
|
+
prompt,
|
|
3479
|
+
resumeSessionId,
|
|
3480
|
+
}).catch(async (error) => {
|
|
3481
|
+
const sessionLimit = extractClaudeCodeSessionLimitFromError(error);
|
|
3482
|
+
if (!sessionLimit) {
|
|
3483
|
+
throw error;
|
|
3484
|
+
}
|
|
3485
|
+
resurrectionCount++;
|
|
3486
|
+
await waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options);
|
|
3487
|
+
resumeSessionId = sessionLimit.sessionId;
|
|
3488
|
+
prompt = buildClaudeCodeSessionResurrectionPrompt(options.prompt, sessionLimit.sessionId);
|
|
3489
|
+
return undefined;
|
|
3490
|
+
});
|
|
3491
|
+
if (output === undefined) {
|
|
3492
|
+
continue;
|
|
3493
|
+
}
|
|
3494
|
+
const sessionLimit = extractClaudeCodeSessionLimitFromOutput(output);
|
|
3495
|
+
if (sessionLimit) {
|
|
3496
|
+
resurrectionCount++;
|
|
3497
|
+
await waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options);
|
|
3498
|
+
resumeSessionId = sessionLimit.sessionId;
|
|
3499
|
+
prompt = buildClaudeCodeSessionResurrectionPrompt(options.prompt, sessionLimit.sessionId);
|
|
3500
|
+
continue;
|
|
3501
|
+
}
|
|
3502
|
+
const usage = parseClaudeCodeJsonOutput(output);
|
|
3503
|
+
return { usage };
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
/**
|
|
3507
|
+
* Runs one Claude Code CLI process and returns its raw output.
|
|
3508
|
+
*/
|
|
3509
|
+
async runClaudeCodeOnce(options) {
|
|
3178
3510
|
const scriptContent = buildClaudeScript({
|
|
3179
3511
|
prompt: options.prompt,
|
|
3512
|
+
model: this.options.model,
|
|
3180
3513
|
thinkingLevel: this.options.thinkingLevel,
|
|
3514
|
+
resumeSessionId: options.resumeSessionId,
|
|
3181
3515
|
});
|
|
3182
|
-
|
|
3516
|
+
return await $runGoScriptWithOutput({
|
|
3183
3517
|
scriptPath: options.scriptPath,
|
|
3184
3518
|
scriptContent,
|
|
3185
3519
|
logPath: options.logPath,
|
|
3186
3520
|
shouldPrintLiveOutput: options.shouldPrintLiveOutput,
|
|
3187
3521
|
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
3188
3522
|
});
|
|
3189
|
-
const usage = parseClaudeCodeJsonOutput(output);
|
|
3190
|
-
return { usage };
|
|
3191
3523
|
}
|
|
3192
3524
|
}
|
|
3525
|
+
/**
|
|
3526
|
+
* Waits until the Claude Code session can be resumed, keeping terminal status clear.
|
|
3527
|
+
*/
|
|
3528
|
+
async function waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options) {
|
|
3529
|
+
var _a, _b;
|
|
3530
|
+
const delayMs = getClaudeCodeSessionLimitDelayMs(sessionLimit);
|
|
3531
|
+
const resetDeadlineTimeMs = Date.now() + delayMs;
|
|
3532
|
+
const sessionLabel = formatClaudeCodeSessionIdForDisplay(sessionLimit.sessionId);
|
|
3533
|
+
const resetSummary = formatClaudeCodeSessionLimitForDisplay(sessionLimit);
|
|
3534
|
+
if ((_a = options.shouldPrintLiveOutput) !== null && _a !== void 0 ? _a : true) {
|
|
3535
|
+
console.warn(colors__default["default"].yellow(`[claude-code] Session limit detected for ${sessionLimit.sessionId}. Resurrection #${resurrectionCount} will resume with --resume after ${formatDurationMs(delayMs)}. ${resetSummary}`));
|
|
3536
|
+
}
|
|
3537
|
+
await waitUntilWorldTimeDeadline({
|
|
3538
|
+
deadlineTimeMs: resetDeadlineTimeMs,
|
|
3539
|
+
pollIntervalMs: CLAUDE_CODE_SESSION_RESURRECTION_POLL_MS,
|
|
3540
|
+
onTick: async (remainingDelayMs) => {
|
|
3541
|
+
var _a;
|
|
3542
|
+
await ((_a = options.waitForPauseCheckpoint) === null || _a === void 0 ? void 0 : _a.call(options, {
|
|
3543
|
+
checkpointLabel: 'the Claude Code session limit reset',
|
|
3544
|
+
phase: 'waiting',
|
|
3545
|
+
statusMessage: `Claude Code session ${sessionLabel} hit its limit; resurrection #${resurrectionCount} resumes in ${formatDurationMs(Math.min(remainingDelayMs, delayMs))}`,
|
|
3546
|
+
}));
|
|
3547
|
+
},
|
|
3548
|
+
});
|
|
3549
|
+
await ((_b = options.waitForPauseCheckpoint) === null || _b === void 0 ? void 0 : _b.call(options, {
|
|
3550
|
+
checkpointLabel: 'resurrecting the Claude Code session with --resume',
|
|
3551
|
+
phase: 'running',
|
|
3552
|
+
statusMessage: `Resurrecting Claude Code session ${sessionLabel} with --resume`,
|
|
3553
|
+
}));
|
|
3554
|
+
}
|
|
3555
|
+
/**
|
|
3556
|
+
* Formats a Claude Code session id for compact terminal status lines.
|
|
3557
|
+
*/
|
|
3558
|
+
function formatClaudeCodeSessionIdForDisplay(sessionId) {
|
|
3559
|
+
if (sessionId.length <= 8) {
|
|
3560
|
+
return sessionId;
|
|
3561
|
+
}
|
|
3562
|
+
return `${sessionId.slice(0, 8)}...`;
|
|
3563
|
+
}
|
|
3193
3564
|
|
|
3194
3565
|
/**
|
|
3195
3566
|
* Creates a temporary script file, runs it, and cleans it up unless preservation is requested or the run fails.
|
|
@@ -4141,12 +4512,6 @@
|
|
|
4141
4512
|
* Randomized delay proportion added/subtracted for retry jitter.
|
|
4142
4513
|
*/
|
|
4143
4514
|
const RATE_LIMIT_BACKOFF_JITTER_RATIO = 0.15;
|
|
4144
|
-
/**
|
|
4145
|
-
* Waits for one given amount of milliseconds.
|
|
4146
|
-
*/
|
|
4147
|
-
async function waitFor(delayMs) {
|
|
4148
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
4149
|
-
}
|
|
4150
4515
|
/**
|
|
4151
4516
|
* Formats a delay value into a concise `xh ym zs` style label.
|
|
4152
4517
|
*/
|
|
@@ -4236,13 +4601,18 @@
|
|
|
4236
4601
|
throw error;
|
|
4237
4602
|
}
|
|
4238
4603
|
const delayMs = this.rateLimitBackoff.nextDelayMs();
|
|
4239
|
-
const
|
|
4604
|
+
const retryDeadlineTimeMs = Date.now() + delayMs;
|
|
4605
|
+
const retryAt = new Date(retryDeadlineTimeMs).toISOString();
|
|
4240
4606
|
const retryIndex = this.rateLimitBackoff.retryCount;
|
|
4241
4607
|
const summary = extractFailureSummary(details);
|
|
4242
4608
|
if ((_b = options.shouldPrintLiveOutput) !== null && _b !== void 0 ? _b : true) {
|
|
4243
4609
|
console.warn(colors__default["default"].yellow(`[codex] Rate limit/quota detected (${summary}). Retry #${retryIndex} in ${formatDelay(delayMs)} at ${retryAt}.`));
|
|
4244
4610
|
}
|
|
4245
|
-
await waitForRetryDelay(
|
|
4611
|
+
await waitForRetryDelay({
|
|
4612
|
+
delayMs,
|
|
4613
|
+
retryDeadlineTimeMs,
|
|
4614
|
+
promptRunOptions: options,
|
|
4615
|
+
});
|
|
4246
4616
|
}
|
|
4247
4617
|
}
|
|
4248
4618
|
}
|
|
@@ -4250,20 +4620,21 @@
|
|
|
4250
4620
|
/**
|
|
4251
4621
|
* Waits for the next Codex retry while polling for requested pause checkpoints.
|
|
4252
4622
|
*/
|
|
4253
|
-
async function waitForRetryDelay(
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4623
|
+
async function waitForRetryDelay(options) {
|
|
4624
|
+
const { delayMs, retryDeadlineTimeMs, promptRunOptions } = options;
|
|
4625
|
+
await waitUntilWorldTimeDeadline({
|
|
4626
|
+
deadlineTimeMs: retryDeadlineTimeMs,
|
|
4627
|
+
pollIntervalMs: RATE_LIMIT_BACKOFF_POLL_MS,
|
|
4628
|
+
onTick: async (remainingDelayMs) => {
|
|
4629
|
+
var _a;
|
|
4630
|
+
const remainingDelayLabel = formatDelay(Math.min(remainingDelayMs, delayMs));
|
|
4631
|
+
await ((_a = promptRunOptions.waitForPauseCheckpoint) === null || _a === void 0 ? void 0 : _a.call(promptRunOptions, {
|
|
4632
|
+
checkpointLabel: 'the next OpenAI Codex retry after rate limit',
|
|
4633
|
+
phase: 'running',
|
|
4634
|
+
statusMessage: `Waiting ${remainingDelayLabel} before retrying OpenAI Codex`,
|
|
4635
|
+
}));
|
|
4636
|
+
},
|
|
4637
|
+
});
|
|
4267
4638
|
}
|
|
4268
4639
|
|
|
4269
4640
|
/**
|
|
@@ -4437,8 +4808,9 @@
|
|
|
4437
4808
|
}
|
|
4438
4809
|
if (agentName === 'claude-code') {
|
|
4439
4810
|
return createRunnerResolution(options, new ClaudeCodeRunner({
|
|
4811
|
+
model: options.model,
|
|
4440
4812
|
thinkingLevel: options.thinkingLevel,
|
|
4441
|
-
}));
|
|
4813
|
+
}), options.model);
|
|
4442
4814
|
}
|
|
4443
4815
|
if (agentName === 'opencode') {
|
|
4444
4816
|
return createRunnerResolution(options, new OpencodeRunner({
|
|
@@ -4512,7 +4884,7 @@
|
|
|
4512
4884
|
if (options.agentName === 'cline') {
|
|
4513
4885
|
return { runnerName, modelName: CLINE_MODEL };
|
|
4514
4886
|
}
|
|
4515
|
-
if (options.agentName === 'opencode') {
|
|
4887
|
+
if (options.agentName === 'opencode' || options.agentName === 'claude-code') {
|
|
4516
4888
|
return { runnerName, modelName: options.model };
|
|
4517
4889
|
}
|
|
4518
4890
|
return { runnerName };
|
|
@@ -4589,9 +4961,10 @@
|
|
|
4589
4961
|
|
|
4590
4962
|
[Up to 50,000 CZK](?message=We are posting an order up to 50,000 CZK)
|
|
4591
4963
|
[Up to 100,000 CZK](?message=We are posting an order up to 100,000 CZK)
|
|
4592
|
-
[Over 100,000 CZK](?
|
|
4964
|
+
[Over 100,000 CZK](?messageDraft=We are posting an order over 100,000 CZK)
|
|
4593
4965
|
\`\`\`
|
|
4594
4966
|
|
|
4967
|
+
- You can use \`message\` for message that will be sent immediately after clicking the button, or \`messageDraft\` for message that will be prefilled in the input field for editing before sending.
|
|
4595
4968
|
|
|
4596
4969
|
## This is how you should behave
|
|
4597
4970
|
|
|
@@ -4599,28 +4972,38 @@
|
|
|
4599
4972
|
`);
|
|
4600
4973
|
}
|
|
4601
4974
|
|
|
4602
|
-
/**
|
|
4603
|
-
* Builds a normalized temporary shell script path for prompt runners.
|
|
4604
|
-
*/
|
|
4605
|
-
function buildTemporaryPromptScriptPath(options) {
|
|
4606
|
-
const sourceFileName = path.basename(options.sourceFileName);
|
|
4607
|
-
const scriptFileName = `${sourceFileName.replace(/\.[^.]+$/u, '')}${options.suffix || ''}.sh`;
|
|
4608
|
-
return resolvePromptbookTemporaryPath(options.projectPath, options.scriptDirectoryName, scriptFileName);
|
|
4609
|
-
}
|
|
4610
|
-
|
|
4611
4975
|
/**
|
|
4612
4976
|
* Temporary subdirectory used for agent-message runner shell scripts.
|
|
4977
|
+
*
|
|
4978
|
+
* @private internal constant of agent-message runtime paths
|
|
4613
4979
|
*/
|
|
4614
4980
|
const AGENT_MESSAGE_SCRIPT_DIRECTORY_NAME = 'agent-messages';
|
|
4981
|
+
/**
|
|
4982
|
+
* File extension used for temporary prompt-runner shell scripts.
|
|
4983
|
+
*
|
|
4984
|
+
* @private internal constant of agent-message runtime paths
|
|
4985
|
+
*/
|
|
4986
|
+
const AGENT_MESSAGE_SCRIPT_EXTENSION = '.sh';
|
|
4987
|
+
/**
|
|
4988
|
+
* Builds the temporary shell script path used by one queued agent-message harness run.
|
|
4989
|
+
*
|
|
4990
|
+
* @param projectPath - Local agent project path containing the message queue.
|
|
4991
|
+
* @param sourceFileName - Queued message filename used to name the temporary shell script.
|
|
4992
|
+
* @returns Temporary shell script path.
|
|
4993
|
+
* @private internal utility of agent-message runners
|
|
4994
|
+
*/
|
|
4995
|
+
function buildAgentMessageScriptPathFromFileName(projectPath, sourceFileName) {
|
|
4996
|
+
const sourceFileBasename = path.basename(sourceFileName);
|
|
4997
|
+
const scriptFileName = `${sourceFileBasename.replace(/\.[^.]+$/u, '')}${AGENT_MESSAGE_SCRIPT_EXTENSION}`;
|
|
4998
|
+
return resolvePromptbookTemporaryPath(projectPath, AGENT_MESSAGE_SCRIPT_DIRECTORY_NAME, scriptFileName);
|
|
4999
|
+
}
|
|
5000
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
5001
|
+
|
|
4615
5002
|
/**
|
|
4616
5003
|
* Builds a temporary script path for one agent message runner invocation.
|
|
4617
5004
|
*/
|
|
4618
5005
|
function buildAgentMessageScriptPath(projectPath, messageFile) {
|
|
4619
|
-
return
|
|
4620
|
-
projectPath,
|
|
4621
|
-
scriptDirectoryName: AGENT_MESSAGE_SCRIPT_DIRECTORY_NAME,
|
|
4622
|
-
sourceFileName: messageFile.fileName,
|
|
4623
|
-
});
|
|
5006
|
+
return buildAgentMessageScriptPathFromFileName(projectPath, messageFile.fileName);
|
|
4624
5007
|
}
|
|
4625
5008
|
|
|
4626
5009
|
var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book",formfactorName:"GENERIC",parameters:[{name:"knowledgeContent",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledgePieces",description:"The knowledge JSON object",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}",resultingParameterName:"knowledgePieces",dependentParameterNames:["knowledgeContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge from Markdown\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book`\n- INPUT PARAMETER `{knowledgeContent}` Markdown document content\n- OUTPUT PARAMETER `{knowledgePieces}` The knowledge JSON object\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}\n```\n\n`-> {knowledgePieces}`\n"}],sourceFile:"./books/prepare-knowledge-from-markdown.book"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}",resultingParameterName:"keywords",dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Keywords\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-keywords.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{keywords}` Keywords separated by comma\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}\n```\n\n`-> {keywords}`\n"}],sourceFile:"./books/prepare-knowledge-keywords.book"},{title:"Prepare Knowledge-piece Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"title",description:"The title of the document",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}",resultingParameterName:"title",expectations:{words:{min:1,max:8}},dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge-piece Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-title.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{title}` The title of the document\n\n## Knowledge\n\n- EXPECT MIN 1 WORD\n- EXPECT MAX 8 WORDS\n\n```markdown\nYou are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-knowledge-title.book"},{title:"Prepare Persona",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.book",formfactorName:"GENERIC",parameters:[{name:"availableModels",description:"List of available model names together with their descriptions as JSON",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelsRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-model-requirements",title:"Make modelRequirements",content:"You are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n```json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpful assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n```\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nHere are the available models:\n\n```json\n{availableModels}\n```\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}",resultingParameterName:"modelsRequirements",format:"JSON",dependentParameterNames:["availableModels","personaDescription"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Persona\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-persona.book`\n- INPUT PARAMETER `{availableModels}` List of available model names together with their descriptions as JSON\n- INPUT PARAMETER `{personaDescription}` Description of the persona\n- OUTPUT PARAMETER `{modelsRequirements}` Specific requirements for the model\n\n## Make modelRequirements\n\n- FORMAT JSON\n\n```markdown\nYou are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n\\`\\`\\`json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpful assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n\\`\\`\\`\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nHere are the available models:\n\n\\`\\`\\`json\n{availableModels}\n\\`\\`\\`\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}\n```\n\n`-> {modelsRequirements}`\n"}],sourceFile:"./books/prepare-persona.book"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-title.book",formfactorName:"GENERIC",parameters:[{name:"book",description:"The book to prepare the title for",isInput:true,isOutput:false},{name:"title",description:"Best title for the book",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-title",title:"Make title",content:"Make best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}",resultingParameterName:"title",expectations:{words:{min:1,max:8},lines:{min:1,max:1}},dependentParameterNames:["book"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-title.book`\n- INPUT PARAMETER `{book}` The book to prepare the title for\n- OUTPUT PARAMETER `{title}` Best title for the book\n\n## Make title\n\n- EXPECT MIN 1 Word\n- EXPECT MAX 8 Words\n- EXPECT EXACTLY 1 Line\n\n```markdown\nMake best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-title.book"}];
|
|
@@ -5083,6 +5466,95 @@
|
|
|
5083
5466
|
// TODO: [🏛] Escape all
|
|
5084
5467
|
// TODO: [🧠] Should be in generated .book.md file GENERATOR_WARNING
|
|
5085
5468
|
|
|
5469
|
+
/**
|
|
5470
|
+
* This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
|
|
5471
|
+
*
|
|
5472
|
+
* @public exported from `@promptbook/core`
|
|
5473
|
+
*/
|
|
5474
|
+
class PipelineLogicError extends Error {
|
|
5475
|
+
constructor(message) {
|
|
5476
|
+
super(message);
|
|
5477
|
+
this.name = 'PipelineLogicError';
|
|
5478
|
+
Object.setPrototypeOf(this, PipelineLogicError.prototype);
|
|
5479
|
+
}
|
|
5480
|
+
}
|
|
5481
|
+
|
|
5482
|
+
/**
|
|
5483
|
+
* Creates the shared validation context for one pipeline.
|
|
5484
|
+
*
|
|
5485
|
+
* @private function of `validatePipeline`
|
|
5486
|
+
*/
|
|
5487
|
+
function createPipelineValidationContext(pipeline) {
|
|
5488
|
+
return {
|
|
5489
|
+
pipeline,
|
|
5490
|
+
pipelineIdentification: getPipelineIdentification$1(pipeline),
|
|
5491
|
+
};
|
|
5492
|
+
}
|
|
5493
|
+
/**
|
|
5494
|
+
* Builds a short file/url identification block for validation errors.
|
|
5495
|
+
*
|
|
5496
|
+
* @private internal utility of `validatePipeline`
|
|
5497
|
+
*/
|
|
5498
|
+
function getPipelineIdentification$1(pipeline) {
|
|
5499
|
+
// Note: This is a 😐 implementation of [🚞]
|
|
5500
|
+
const pipelineIdentificationParts = [];
|
|
5501
|
+
if (pipeline.sourceFile !== undefined) {
|
|
5502
|
+
pipelineIdentificationParts.push(`File: ${pipeline.sourceFile}`);
|
|
5503
|
+
}
|
|
5504
|
+
if (pipeline.pipelineUrl !== undefined) {
|
|
5505
|
+
pipelineIdentificationParts.push(`Url: ${pipeline.pipelineUrl}`);
|
|
5506
|
+
}
|
|
5507
|
+
return pipelineIdentificationParts.join('\n');
|
|
5508
|
+
}
|
|
5509
|
+
|
|
5510
|
+
/**
|
|
5511
|
+
* Validates that the expected top-level collections have array structure.
|
|
5512
|
+
*
|
|
5513
|
+
* @private function of `validatePipeline`
|
|
5514
|
+
*/
|
|
5515
|
+
function validatePipelineCollectionsStructure({ pipeline, pipelineIdentification, }) {
|
|
5516
|
+
validatePipelineParametersCollection(pipeline, pipelineIdentification);
|
|
5517
|
+
validatePipelineTasksCollection(pipeline, pipelineIdentification);
|
|
5518
|
+
}
|
|
5519
|
+
/**
|
|
5520
|
+
* Validates that `pipeline.parameters` is an array.
|
|
5521
|
+
*
|
|
5522
|
+
* @private internal utility of `validatePipelineCollectionsStructure`
|
|
5523
|
+
*/
|
|
5524
|
+
function validatePipelineParametersCollection(pipeline, pipelineIdentification) {
|
|
5525
|
+
// TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
|
|
5526
|
+
if (Array.isArray(pipeline.parameters)) {
|
|
5527
|
+
return;
|
|
5528
|
+
}
|
|
5529
|
+
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5530
|
+
throw new ParseError(_spaceTrim.spaceTrim((block) => `
|
|
5531
|
+
Pipeline is valid JSON but with wrong structure
|
|
5532
|
+
|
|
5533
|
+
\`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
|
|
5534
|
+
|
|
5535
|
+
${block(pipelineIdentification)}
|
|
5536
|
+
`));
|
|
5537
|
+
}
|
|
5538
|
+
/**
|
|
5539
|
+
* Validates that `pipeline.tasks` is an array.
|
|
5540
|
+
*
|
|
5541
|
+
* @private internal utility of `validatePipelineCollectionsStructure`
|
|
5542
|
+
*/
|
|
5543
|
+
function validatePipelineTasksCollection(pipeline, pipelineIdentification) {
|
|
5544
|
+
// TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
|
|
5545
|
+
if (Array.isArray(pipeline.tasks)) {
|
|
5546
|
+
return;
|
|
5547
|
+
}
|
|
5548
|
+
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5549
|
+
throw new ParseError(_spaceTrim.spaceTrim((block) => `
|
|
5550
|
+
Pipeline is valid JSON but with wrong structure
|
|
5551
|
+
|
|
5552
|
+
\`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
|
|
5553
|
+
|
|
5554
|
+
${block(pipelineIdentification)}
|
|
5555
|
+
`));
|
|
5556
|
+
}
|
|
5557
|
+
|
|
5086
5558
|
/**
|
|
5087
5559
|
* Order of keys in the pipeline JSON
|
|
5088
5560
|
*
|
|
@@ -5195,16 +5667,137 @@
|
|
|
5195
5667
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
5196
5668
|
|
|
5197
5669
|
/**
|
|
5198
|
-
*
|
|
5670
|
+
* Validates that task dependencies can be resolved without cycles or missing definitions.
|
|
5199
5671
|
*
|
|
5200
|
-
* @
|
|
5672
|
+
* @private function of `validatePipeline`
|
|
5201
5673
|
*/
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5674
|
+
function validatePipelineDependencyResolution({ pipeline, pipelineIdentification, }) {
|
|
5675
|
+
let dependencyResolutionState = createInitialDependencyResolutionState(pipeline);
|
|
5676
|
+
let loopLimit = LOOP_LIMIT;
|
|
5677
|
+
while (hasUnresolvedTasks(dependencyResolutionState)) {
|
|
5678
|
+
if (loopLimit-- < 0) {
|
|
5679
|
+
throw createDependencyResolutionLoopLimitError(pipelineIdentification);
|
|
5680
|
+
}
|
|
5681
|
+
dependencyResolutionState = resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification);
|
|
5682
|
+
}
|
|
5683
|
+
}
|
|
5684
|
+
/**
|
|
5685
|
+
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
5686
|
+
*
|
|
5687
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5688
|
+
*/
|
|
5689
|
+
function createInitialDependencyResolutionState(pipeline) {
|
|
5690
|
+
return {
|
|
5691
|
+
resolvedParameterNames: createInitiallyResolvedParameterNames(pipeline),
|
|
5692
|
+
unresolvedTasks: [...pipeline.tasks],
|
|
5693
|
+
};
|
|
5694
|
+
}
|
|
5695
|
+
/**
|
|
5696
|
+
* Checks whether dependency resolution still has tasks left to process.
|
|
5697
|
+
*
|
|
5698
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5699
|
+
*/
|
|
5700
|
+
function hasUnresolvedTasks({ unresolvedTasks }) {
|
|
5701
|
+
return unresolvedTasks.length > 0;
|
|
5702
|
+
}
|
|
5703
|
+
/**
|
|
5704
|
+
* Resolves the next batch of currently satisfiable tasks.
|
|
5705
|
+
*
|
|
5706
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5707
|
+
*/
|
|
5708
|
+
function resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification) {
|
|
5709
|
+
const currentlyResolvedTasks = getCurrentlyResolvedTasks(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames);
|
|
5710
|
+
if (currentlyResolvedTasks.length === 0) {
|
|
5711
|
+
throw createUnresolvedTasksError(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames, pipelineIdentification);
|
|
5207
5712
|
}
|
|
5713
|
+
return {
|
|
5714
|
+
resolvedParameterNames: appendResolvedTaskParameterNames(dependencyResolutionState.resolvedParameterNames, currentlyResolvedTasks),
|
|
5715
|
+
unresolvedTasks: dependencyResolutionState.unresolvedTasks.filter((task) => !currentlyResolvedTasks.includes(task)),
|
|
5716
|
+
};
|
|
5717
|
+
}
|
|
5718
|
+
/**
|
|
5719
|
+
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
5720
|
+
*
|
|
5721
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5722
|
+
*/
|
|
5723
|
+
function createInitiallyResolvedParameterNames(pipeline) {
|
|
5724
|
+
let resolvedParameterNames = pipeline.parameters
|
|
5725
|
+
.filter(({ isInput }) => isInput)
|
|
5726
|
+
.map(({ name }) => name);
|
|
5727
|
+
for (const reservedParameterName of RESERVED_PARAMETER_NAMES) {
|
|
5728
|
+
resolvedParameterNames = [...resolvedParameterNames, reservedParameterName];
|
|
5729
|
+
}
|
|
5730
|
+
return resolvedParameterNames;
|
|
5731
|
+
}
|
|
5732
|
+
/**
|
|
5733
|
+
* Adds newly resolved task outputs to the resolved parameter list.
|
|
5734
|
+
*
|
|
5735
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5736
|
+
*/
|
|
5737
|
+
function appendResolvedTaskParameterNames(resolvedParameterNames, currentlyResolvedTasks) {
|
|
5738
|
+
return [
|
|
5739
|
+
...resolvedParameterNames,
|
|
5740
|
+
...currentlyResolvedTasks.map(({ resultingParameterName }) => resultingParameterName),
|
|
5741
|
+
];
|
|
5742
|
+
}
|
|
5743
|
+
/**
|
|
5744
|
+
* Selects tasks whose dependencies are already resolved.
|
|
5745
|
+
*
|
|
5746
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5747
|
+
*/
|
|
5748
|
+
function getCurrentlyResolvedTasks(unresolvedTasks, resolvedParameterNames) {
|
|
5749
|
+
return unresolvedTasks.filter((task) => task.dependentParameterNames.every((name) => resolvedParameterNames.includes(name)));
|
|
5750
|
+
}
|
|
5751
|
+
/**
|
|
5752
|
+
* Creates the unexpected loop-limit error for dependency resolution.
|
|
5753
|
+
*
|
|
5754
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5755
|
+
*/
|
|
5756
|
+
function createDependencyResolutionLoopLimitError(pipelineIdentification) {
|
|
5757
|
+
// Note: Really UnexpectedError not LimitReachedError - this should not happen and be caught below
|
|
5758
|
+
return new UnexpectedError(_spaceTrim.spaceTrim((block) => `
|
|
5759
|
+
Loop limit reached during detection of circular dependencies in \`validatePipeline\`
|
|
5760
|
+
|
|
5761
|
+
${block(pipelineIdentification)}
|
|
5762
|
+
`));
|
|
5763
|
+
}
|
|
5764
|
+
/**
|
|
5765
|
+
* Creates the detailed error for unresolved or circular task dependencies.
|
|
5766
|
+
*
|
|
5767
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5768
|
+
*/
|
|
5769
|
+
function createUnresolvedTasksError(unresolvedTasks, resolvedParameterNames, pipelineIdentification) {
|
|
5770
|
+
return new PipelineLogicError(
|
|
5771
|
+
// TODO: [🐎] DRY
|
|
5772
|
+
_spaceTrim.spaceTrim((block) => `
|
|
5773
|
+
|
|
5774
|
+
Can not resolve some parameters:
|
|
5775
|
+
Either you are using a parameter that is not defined, or there are some circular dependencies.
|
|
5776
|
+
|
|
5777
|
+
${block(pipelineIdentification)}
|
|
5778
|
+
|
|
5779
|
+
**Can not resolve:**
|
|
5780
|
+
${block(unresolvedTasks
|
|
5781
|
+
.map(({ resultingParameterName, dependentParameterNames }) => `- Parameter \`{${resultingParameterName}}\` which depends on ${dependentParameterNames
|
|
5782
|
+
.map((dependentParameterName) => `\`{${dependentParameterName}}\``)
|
|
5783
|
+
.join(' and ')}`)
|
|
5784
|
+
.join('\n'))}
|
|
5785
|
+
|
|
5786
|
+
**Resolved:**
|
|
5787
|
+
${block(resolvedParameterNames
|
|
5788
|
+
.filter((name) => !RESERVED_PARAMETER_NAMES.includes(name))
|
|
5789
|
+
.map((name) => `- Parameter \`{${name}}\``)
|
|
5790
|
+
.join('\n'))}
|
|
5791
|
+
|
|
5792
|
+
|
|
5793
|
+
**Reserved (which are available):**
|
|
5794
|
+
${block(resolvedParameterNames
|
|
5795
|
+
.filter((name) => RESERVED_PARAMETER_NAMES.includes(name))
|
|
5796
|
+
.map((name) => `- Parameter \`{${name}}\``)
|
|
5797
|
+
.join('\n'))}
|
|
5798
|
+
|
|
5799
|
+
|
|
5800
|
+
`));
|
|
5208
5801
|
}
|
|
5209
5802
|
|
|
5210
5803
|
/**
|
|
@@ -5281,168 +5874,19 @@
|
|
|
5281
5874
|
}
|
|
5282
5875
|
// TODO: [🐠] Maybe more info why the URL is invalid
|
|
5283
5876
|
|
|
5284
|
-
/**
|
|
5285
|
-
* Validates PipelineJson if it is logically valid
|
|
5286
|
-
*
|
|
5287
|
-
* It checks:
|
|
5288
|
-
* - if it has correct parameters dependency
|
|
5289
|
-
*
|
|
5290
|
-
* It does NOT check:
|
|
5291
|
-
* - if it is valid json
|
|
5292
|
-
* - if it is meaningful
|
|
5293
|
-
*
|
|
5294
|
-
* Note: [🔂] This function is idempotent.
|
|
5295
|
-
*
|
|
5296
|
-
* @param pipeline valid or invalid PipelineJson
|
|
5297
|
-
* @returns the same pipeline if it is logically valid
|
|
5298
|
-
* @throws {PipelineLogicError} on logical error in the pipeline
|
|
5299
|
-
*
|
|
5300
|
-
* @public exported from `@promptbook/core`
|
|
5301
|
-
*/
|
|
5302
|
-
function validatePipeline(pipeline) {
|
|
5303
|
-
if (IS_PIPELINE_LOGIC_VALIDATED) {
|
|
5304
|
-
validatePipeline_InnerFunction(pipeline);
|
|
5305
|
-
}
|
|
5306
|
-
else {
|
|
5307
|
-
try {
|
|
5308
|
-
validatePipeline_InnerFunction(pipeline);
|
|
5309
|
-
}
|
|
5310
|
-
catch (error) {
|
|
5311
|
-
if (!(error instanceof PipelineLogicError)) {
|
|
5312
|
-
throw error;
|
|
5313
|
-
}
|
|
5314
|
-
console.error(_spaceTrim.spaceTrim((block) => `
|
|
5315
|
-
Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
|
|
5316
|
-
|
|
5317
|
-
${block(error.message)}
|
|
5318
|
-
`));
|
|
5319
|
-
}
|
|
5320
|
-
}
|
|
5321
|
-
return pipeline;
|
|
5322
|
-
}
|
|
5323
|
-
/**
|
|
5324
|
-
* Validates pipeline inner function.
|
|
5325
|
-
*
|
|
5326
|
-
* @private internal function for `validatePipeline`
|
|
5327
|
-
*/
|
|
5328
|
-
function validatePipeline_InnerFunction(pipeline) {
|
|
5329
|
-
// TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
|
|
5330
|
-
const context = createPipelineValidationContext(pipeline);
|
|
5331
|
-
validatePipelineMetadata(context);
|
|
5332
|
-
validatePipelineCollectionsStructure(context);
|
|
5333
|
-
validatePipelineParameters(context);
|
|
5334
|
-
validatePipelineTasks(context);
|
|
5335
|
-
validatePipelineDependencyResolution(context);
|
|
5336
|
-
// Note: Check that formfactor is corresponding to the pipeline interface
|
|
5337
|
-
// TODO: !!6 Implement this
|
|
5338
|
-
// pipeline.formfactorName
|
|
5339
|
-
}
|
|
5340
|
-
/**
|
|
5341
|
-
* Creates the shared validation context for one pipeline.
|
|
5342
|
-
*
|
|
5343
|
-
* @private internal utility of `validatePipeline`
|
|
5344
|
-
*/
|
|
5345
|
-
function createPipelineValidationContext(pipeline) {
|
|
5346
|
-
return {
|
|
5347
|
-
pipeline,
|
|
5348
|
-
pipelineIdentification: getPipelineIdentification$1(pipeline),
|
|
5349
|
-
};
|
|
5350
|
-
}
|
|
5351
|
-
/**
|
|
5352
|
-
* Builds a short file/url identification block for validation errors.
|
|
5353
|
-
*
|
|
5354
|
-
* @private internal utility of `validatePipeline`
|
|
5355
|
-
*/
|
|
5356
|
-
function getPipelineIdentification$1(pipeline) {
|
|
5357
|
-
// Note: This is a 😐 implementation of [🚞]
|
|
5358
|
-
const pipelineIdentificationParts = [];
|
|
5359
|
-
if (pipeline.sourceFile !== undefined) {
|
|
5360
|
-
pipelineIdentificationParts.push(`File: ${pipeline.sourceFile}`);
|
|
5361
|
-
}
|
|
5362
|
-
if (pipeline.pipelineUrl !== undefined) {
|
|
5363
|
-
pipelineIdentificationParts.push(`Url: ${pipeline.pipelineUrl}`);
|
|
5364
|
-
}
|
|
5365
|
-
return pipelineIdentificationParts.join('\n');
|
|
5366
|
-
}
|
|
5367
5877
|
/**
|
|
5368
5878
|
* Validates pipeline-level metadata fields.
|
|
5369
5879
|
*
|
|
5370
|
-
* @private
|
|
5880
|
+
* @private function of `validatePipeline`
|
|
5371
5881
|
*/
|
|
5372
5882
|
function validatePipelineMetadata({ pipeline, pipelineIdentification }) {
|
|
5373
5883
|
validatePipelineUrl(pipeline, pipelineIdentification);
|
|
5374
5884
|
validatePipelineBookVersion(pipeline, pipelineIdentification);
|
|
5375
5885
|
}
|
|
5376
|
-
/**
|
|
5377
|
-
* Validates that the expected top-level collections have array structure.
|
|
5378
|
-
*
|
|
5379
|
-
* @private internal step of `validatePipeline`
|
|
5380
|
-
*/
|
|
5381
|
-
function validatePipelineCollectionsStructure({ pipeline, pipelineIdentification }) {
|
|
5382
|
-
validatePipelineParametersCollection(pipeline, pipelineIdentification);
|
|
5383
|
-
validatePipelineTasksCollection(pipeline, pipelineIdentification);
|
|
5384
|
-
}
|
|
5385
|
-
/**
|
|
5386
|
-
* Validates all pipeline parameter declarations.
|
|
5387
|
-
*
|
|
5388
|
-
* @private internal step of `validatePipeline`
|
|
5389
|
-
*/
|
|
5390
|
-
function validatePipelineParameters({ pipeline, pipelineIdentification }) {
|
|
5391
|
-
for (const parameter of pipeline.parameters) {
|
|
5392
|
-
validatePipelineParameter(parameter, pipeline, pipelineIdentification);
|
|
5393
|
-
}
|
|
5394
|
-
}
|
|
5395
|
-
/**
|
|
5396
|
-
* Validates all pipeline tasks and their per-task invariants.
|
|
5397
|
-
*
|
|
5398
|
-
* @private internal step of `validatePipeline`
|
|
5399
|
-
*/
|
|
5400
|
-
function validatePipelineTasks({ pipeline, pipelineIdentification }) {
|
|
5401
|
-
// Note: All input parameters are defined - so that they can be used as result of some task
|
|
5402
|
-
const definedParameters = createInitiallyDefinedParameters(pipeline);
|
|
5403
|
-
for (const task of pipeline.tasks) {
|
|
5404
|
-
validatePipelineTask(task, definedParameters, pipelineIdentification);
|
|
5405
|
-
}
|
|
5406
|
-
}
|
|
5407
|
-
/**
|
|
5408
|
-
* Validates that task dependencies can be resolved without cycles or missing definitions.
|
|
5409
|
-
*
|
|
5410
|
-
* @private internal step of `validatePipeline`
|
|
5411
|
-
*/
|
|
5412
|
-
function validatePipelineDependencyResolution({ pipeline, pipelineIdentification }) {
|
|
5413
|
-
let dependencyResolutionState = createInitialDependencyResolutionState(pipeline);
|
|
5414
|
-
let loopLimit = LOOP_LIMIT;
|
|
5415
|
-
while (hasUnresolvedTasks(dependencyResolutionState)) {
|
|
5416
|
-
if (loopLimit-- < 0) {
|
|
5417
|
-
throw createDependencyResolutionLoopLimitError(pipelineIdentification);
|
|
5418
|
-
}
|
|
5419
|
-
dependencyResolutionState = resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification);
|
|
5420
|
-
}
|
|
5421
|
-
}
|
|
5422
|
-
/**
|
|
5423
|
-
* Validates one pipeline parameter declaration.
|
|
5424
|
-
*
|
|
5425
|
-
* @private internal step of `validatePipeline`
|
|
5426
|
-
*/
|
|
5427
|
-
function validatePipelineParameter(parameter, pipeline, pipelineIdentification) {
|
|
5428
|
-
validateParameterDirection(parameter, pipelineIdentification);
|
|
5429
|
-
validateParameterUsage(parameter, pipeline, pipelineIdentification);
|
|
5430
|
-
validateParameterDefinition(parameter, pipeline, pipelineIdentification);
|
|
5431
|
-
}
|
|
5432
|
-
/**
|
|
5433
|
-
* Validates one pipeline task and its invariants.
|
|
5434
|
-
*
|
|
5435
|
-
* @private internal step of `validatePipeline`
|
|
5436
|
-
*/
|
|
5437
|
-
function validatePipelineTask(task, definedParameters, pipelineIdentification) {
|
|
5438
|
-
validateTaskResultingParameter(task, definedParameters, pipelineIdentification);
|
|
5439
|
-
validateTaskJokers(task, pipelineIdentification);
|
|
5440
|
-
validateTaskExpectations(task, pipelineIdentification);
|
|
5441
|
-
}
|
|
5442
5886
|
/**
|
|
5443
5887
|
* Validates the pipeline URL, when present.
|
|
5444
5888
|
*
|
|
5445
|
-
* @private internal utility of `
|
|
5889
|
+
* @private internal utility of `validatePipelineMetadata`
|
|
5446
5890
|
*/
|
|
5447
5891
|
function validatePipelineUrl(pipeline, pipelineIdentification) {
|
|
5448
5892
|
if (pipeline.pipelineUrl === undefined || isValidPipelineUrl(pipeline.pipelineUrl)) {
|
|
@@ -5458,7 +5902,7 @@
|
|
|
5458
5902
|
/**
|
|
5459
5903
|
* Validates the Promptbook version, when present.
|
|
5460
5904
|
*
|
|
5461
|
-
* @private internal utility of `
|
|
5905
|
+
* @private internal utility of `validatePipelineMetadata`
|
|
5462
5906
|
*/
|
|
5463
5907
|
function validatePipelineBookVersion(pipeline, pipelineIdentification) {
|
|
5464
5908
|
if (pipeline.bookVersion === undefined || isValidPromptbookVersion(pipeline.bookVersion)) {
|
|
@@ -5471,48 +5915,31 @@
|
|
|
5471
5915
|
${block(pipelineIdentification)}
|
|
5472
5916
|
`));
|
|
5473
5917
|
}
|
|
5918
|
+
|
|
5474
5919
|
/**
|
|
5475
|
-
* Validates
|
|
5920
|
+
* Validates all pipeline parameter declarations.
|
|
5476
5921
|
*
|
|
5477
|
-
* @private
|
|
5922
|
+
* @private function of `validatePipeline`
|
|
5478
5923
|
*/
|
|
5479
|
-
function
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
return;
|
|
5924
|
+
function validatePipelineParameters({ pipeline, pipelineIdentification }) {
|
|
5925
|
+
for (const parameter of pipeline.parameters) {
|
|
5926
|
+
validatePipelineParameter(parameter, pipeline, pipelineIdentification);
|
|
5483
5927
|
}
|
|
5484
|
-
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5485
|
-
throw new ParseError(_spaceTrim.spaceTrim((block) => `
|
|
5486
|
-
Pipeline is valid JSON but with wrong structure
|
|
5487
|
-
|
|
5488
|
-
\`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
|
|
5489
|
-
|
|
5490
|
-
${block(pipelineIdentification)}
|
|
5491
|
-
`));
|
|
5492
5928
|
}
|
|
5493
5929
|
/**
|
|
5494
|
-
* Validates
|
|
5930
|
+
* Validates one pipeline parameter declaration.
|
|
5495
5931
|
*
|
|
5496
|
-
* @private internal utility of `
|
|
5932
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5497
5933
|
*/
|
|
5498
|
-
function
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
}
|
|
5503
|
-
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5504
|
-
throw new ParseError(_spaceTrim.spaceTrim((block) => `
|
|
5505
|
-
Pipeline is valid JSON but with wrong structure
|
|
5506
|
-
|
|
5507
|
-
\`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
|
|
5508
|
-
|
|
5509
|
-
${block(pipelineIdentification)}
|
|
5510
|
-
`));
|
|
5934
|
+
function validatePipelineParameter(parameter, pipeline, pipelineIdentification) {
|
|
5935
|
+
validateParameterDirection(parameter, pipelineIdentification);
|
|
5936
|
+
validateParameterUsage(parameter, pipeline, pipelineIdentification);
|
|
5937
|
+
validateParameterDefinition(parameter, pipeline, pipelineIdentification);
|
|
5511
5938
|
}
|
|
5512
5939
|
/**
|
|
5513
5940
|
* Validates that one parameter does not declare incompatible directions.
|
|
5514
5941
|
*
|
|
5515
|
-
* @private internal utility of `
|
|
5942
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5516
5943
|
*/
|
|
5517
5944
|
function validateParameterDirection(parameter, pipelineIdentification) {
|
|
5518
5945
|
if (!parameter.isInput || !parameter.isOutput) {
|
|
@@ -5529,7 +5956,7 @@
|
|
|
5529
5956
|
/**
|
|
5530
5957
|
* Validates that one intermediate parameter is actually consumed by at least one task.
|
|
5531
5958
|
*
|
|
5532
|
-
* @private internal utility of `
|
|
5959
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5533
5960
|
*/
|
|
5534
5961
|
function validateParameterUsage(parameter, pipeline, pipelineIdentification) {
|
|
5535
5962
|
if (parameter.isInput || parameter.isOutput || isParameterUsedByAnyTask(parameter, pipeline.tasks)) {
|
|
@@ -5548,7 +5975,7 @@
|
|
|
5548
5975
|
/**
|
|
5549
5976
|
* Validates that one non-input parameter is produced by at least one task.
|
|
5550
5977
|
*
|
|
5551
|
-
* @private internal utility of `
|
|
5978
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5552
5979
|
*/
|
|
5553
5980
|
function validateParameterDefinition(parameter, pipeline, pipelineIdentification) {
|
|
5554
5981
|
if (parameter.isInput || isParameterDefinedByAnyTask(parameter, pipeline.tasks)) {
|
|
@@ -5567,7 +5994,7 @@
|
|
|
5567
5994
|
/**
|
|
5568
5995
|
* Checks whether one parameter is consumed by at least one task dependency list.
|
|
5569
5996
|
*
|
|
5570
|
-
* @private internal utility of `
|
|
5997
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5571
5998
|
*/
|
|
5572
5999
|
function isParameterUsedByAnyTask(parameter, tasks) {
|
|
5573
6000
|
return tasks.some((task) => task.dependentParameterNames.includes(parameter.name));
|
|
@@ -5575,23 +6002,46 @@
|
|
|
5575
6002
|
/**
|
|
5576
6003
|
* Checks whether one parameter is produced by at least one task.
|
|
5577
6004
|
*
|
|
5578
|
-
* @private internal utility of `
|
|
6005
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5579
6006
|
*/
|
|
5580
6007
|
function isParameterDefinedByAnyTask(parameter, tasks) {
|
|
5581
6008
|
return tasks.some((task) => task.resultingParameterName === parameter.name);
|
|
5582
6009
|
}
|
|
6010
|
+
|
|
6011
|
+
/**
|
|
6012
|
+
* Validates all pipeline tasks and their per-task invariants.
|
|
6013
|
+
*
|
|
6014
|
+
* @private function of `validatePipeline`
|
|
6015
|
+
*/
|
|
6016
|
+
function validatePipelineTasks({ pipeline, pipelineIdentification }) {
|
|
6017
|
+
// Note: All input parameters are defined - so that they can be used as result of some task
|
|
6018
|
+
const definedParameters = createInitiallyDefinedParameters(pipeline);
|
|
6019
|
+
for (const task of pipeline.tasks) {
|
|
6020
|
+
validatePipelineTask(task, definedParameters, pipelineIdentification);
|
|
6021
|
+
}
|
|
6022
|
+
}
|
|
5583
6023
|
/**
|
|
5584
6024
|
* Collects the parameter names that are already defined before task validation starts.
|
|
5585
6025
|
*
|
|
5586
|
-
* @private internal utility of `
|
|
6026
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5587
6027
|
*/
|
|
5588
6028
|
function createInitiallyDefinedParameters(pipeline) {
|
|
5589
6029
|
return new Set(pipeline.parameters.filter(({ isInput }) => isInput).map(({ name }) => name));
|
|
5590
6030
|
}
|
|
6031
|
+
/**
|
|
6032
|
+
* Validates one pipeline task and its invariants.
|
|
6033
|
+
*
|
|
6034
|
+
* @private internal utility of `validatePipelineTasks`
|
|
6035
|
+
*/
|
|
6036
|
+
function validatePipelineTask(task, definedParameters, pipelineIdentification) {
|
|
6037
|
+
validateTaskResultingParameter(task, definedParameters, pipelineIdentification);
|
|
6038
|
+
validateTaskJokers(task, pipelineIdentification);
|
|
6039
|
+
validateTaskExpectations(task, pipelineIdentification);
|
|
6040
|
+
}
|
|
5591
6041
|
/**
|
|
5592
6042
|
* Validates one task result parameter declaration and marks it as defined.
|
|
5593
6043
|
*
|
|
5594
|
-
* @private internal utility of `
|
|
6044
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5595
6045
|
*/
|
|
5596
6046
|
function validateTaskResultingParameter(task, definedParameters, pipelineIdentification) {
|
|
5597
6047
|
if (definedParameters.has(task.resultingParameterName)) {
|
|
@@ -5613,7 +6063,7 @@
|
|
|
5613
6063
|
/**
|
|
5614
6064
|
* Validates joker parameters for one task.
|
|
5615
6065
|
*
|
|
5616
|
-
* @private internal utility of `
|
|
6066
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5617
6067
|
*/
|
|
5618
6068
|
function validateTaskJokers(task, pipelineIdentification) {
|
|
5619
6069
|
if (!hasTaskJokers(task)) {
|
|
@@ -5625,7 +6075,7 @@
|
|
|
5625
6075
|
/**
|
|
5626
6076
|
* Checks whether one task declares any joker parameters.
|
|
5627
6077
|
*
|
|
5628
|
-
* @private internal utility of `
|
|
6078
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5629
6079
|
*/
|
|
5630
6080
|
function hasTaskJokers(task) {
|
|
5631
6081
|
return !!task.jokerParameterNames && task.jokerParameterNames.length > 0;
|
|
@@ -5633,7 +6083,7 @@
|
|
|
5633
6083
|
/**
|
|
5634
6084
|
* Validates that a task has the required supporting features when using jokers.
|
|
5635
6085
|
*
|
|
5636
|
-
* @private internal utility of `
|
|
6086
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5637
6087
|
*/
|
|
5638
6088
|
function validateTaskSupportsJokers(task, pipelineIdentification) {
|
|
5639
6089
|
if (task.format || task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
|
|
@@ -5648,7 +6098,7 @@
|
|
|
5648
6098
|
/**
|
|
5649
6099
|
* Validates that every joker parameter is also listed among task dependencies.
|
|
5650
6100
|
*
|
|
5651
|
-
* @private internal utility of `
|
|
6101
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5652
6102
|
*/
|
|
5653
6103
|
function validateTaskJokerDependencies(task, pipelineIdentification) {
|
|
5654
6104
|
for (const joker of task.jokerParameterNames) {
|
|
@@ -5665,7 +6115,7 @@
|
|
|
5665
6115
|
/**
|
|
5666
6116
|
* Validates all expectation bounds configured on one task.
|
|
5667
6117
|
*
|
|
5668
|
-
* @private internal utility of `
|
|
6118
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5669
6119
|
*/
|
|
5670
6120
|
function validateTaskExpectations(task, pipelineIdentification) {
|
|
5671
6121
|
if (!task.expectations) {
|
|
@@ -5680,7 +6130,7 @@
|
|
|
5680
6130
|
/**
|
|
5681
6131
|
* Validates the minimum and maximum expectation ordering for one unit.
|
|
5682
6132
|
*
|
|
5683
|
-
* @private internal utility of `
|
|
6133
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5684
6134
|
*/
|
|
5685
6135
|
function validateTaskExpectationRange(unit, min, max, pipelineIdentification) {
|
|
5686
6136
|
if (min === undefined || max === undefined || min <= max) {
|
|
@@ -5695,7 +6145,7 @@
|
|
|
5695
6145
|
/**
|
|
5696
6146
|
* Validates the minimum expectation bound for one unit.
|
|
5697
6147
|
*
|
|
5698
|
-
* @private internal utility of `
|
|
6148
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5699
6149
|
*/
|
|
5700
6150
|
function validateTaskExpectationMin(unit, min, pipelineIdentification) {
|
|
5701
6151
|
if (min === undefined || min >= 0) {
|
|
@@ -5710,7 +6160,7 @@
|
|
|
5710
6160
|
/**
|
|
5711
6161
|
* Validates the maximum expectation bound for one unit.
|
|
5712
6162
|
*
|
|
5713
|
-
* @private internal utility of `
|
|
6163
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5714
6164
|
*/
|
|
5715
6165
|
function validateTaskExpectationMax(unit, max, pipelineIdentification) {
|
|
5716
6166
|
if (max === undefined || max > 0) {
|
|
@@ -5722,123 +6172,62 @@
|
|
|
5722
6172
|
${block(pipelineIdentification)}
|
|
5723
6173
|
`));
|
|
5724
6174
|
}
|
|
6175
|
+
|
|
5725
6176
|
/**
|
|
5726
|
-
*
|
|
5727
|
-
*
|
|
5728
|
-
* @private internal utility of `validatePipeline`
|
|
5729
|
-
*/
|
|
5730
|
-
function createInitialDependencyResolutionState(pipeline) {
|
|
5731
|
-
return {
|
|
5732
|
-
resolvedParameterNames: createInitiallyResolvedParameterNames(pipeline),
|
|
5733
|
-
unresolvedTasks: [...pipeline.tasks],
|
|
5734
|
-
};
|
|
5735
|
-
}
|
|
5736
|
-
/**
|
|
5737
|
-
* Checks whether dependency resolution still has tasks left to process.
|
|
5738
|
-
*
|
|
5739
|
-
* @private internal utility of `validatePipeline`
|
|
5740
|
-
*/
|
|
5741
|
-
function hasUnresolvedTasks({ unresolvedTasks }) {
|
|
5742
|
-
return unresolvedTasks.length > 0;
|
|
5743
|
-
}
|
|
5744
|
-
/**
|
|
5745
|
-
* Resolves the next batch of currently satisfiable tasks.
|
|
6177
|
+
* Validates PipelineJson if it is logically valid
|
|
5746
6178
|
*
|
|
5747
|
-
*
|
|
5748
|
-
|
|
5749
|
-
function resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification) {
|
|
5750
|
-
const currentlyResolvedTasks = getCurrentlyResolvedTasks(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames);
|
|
5751
|
-
if (currentlyResolvedTasks.length === 0) {
|
|
5752
|
-
throw createUnresolvedTasksError(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames, pipelineIdentification);
|
|
5753
|
-
}
|
|
5754
|
-
return {
|
|
5755
|
-
resolvedParameterNames: appendResolvedTaskParameterNames(dependencyResolutionState.resolvedParameterNames, currentlyResolvedTasks),
|
|
5756
|
-
unresolvedTasks: dependencyResolutionState.unresolvedTasks.filter((task) => !currentlyResolvedTasks.includes(task)),
|
|
5757
|
-
};
|
|
5758
|
-
}
|
|
5759
|
-
/**
|
|
5760
|
-
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
6179
|
+
* It checks:
|
|
6180
|
+
* - if it has correct parameters dependency
|
|
5761
6181
|
*
|
|
5762
|
-
*
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
let resolvedParameterNames = pipeline.parameters
|
|
5766
|
-
.filter(({ isInput }) => isInput)
|
|
5767
|
-
.map(({ name }) => name);
|
|
5768
|
-
for (const reservedParameterName of RESERVED_PARAMETER_NAMES) {
|
|
5769
|
-
resolvedParameterNames = [...resolvedParameterNames, reservedParameterName];
|
|
5770
|
-
}
|
|
5771
|
-
return resolvedParameterNames;
|
|
5772
|
-
}
|
|
5773
|
-
/**
|
|
5774
|
-
* Adds newly resolved task outputs to the resolved parameter list.
|
|
6182
|
+
* It does NOT check:
|
|
6183
|
+
* - if it is valid json
|
|
6184
|
+
* - if it is meaningful
|
|
5775
6185
|
*
|
|
5776
|
-
*
|
|
5777
|
-
*/
|
|
5778
|
-
function appendResolvedTaskParameterNames(resolvedParameterNames, currentlyResolvedTasks) {
|
|
5779
|
-
return [
|
|
5780
|
-
...resolvedParameterNames,
|
|
5781
|
-
...currentlyResolvedTasks.map(({ resultingParameterName }) => resultingParameterName),
|
|
5782
|
-
];
|
|
5783
|
-
}
|
|
5784
|
-
/**
|
|
5785
|
-
* Selects tasks whose dependencies are already resolved.
|
|
6186
|
+
* Note: [🔂] This function is idempotent.
|
|
5786
6187
|
*
|
|
5787
|
-
* @
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
return unresolvedTasks.filter((task) => task.dependentParameterNames.every((name) => resolvedParameterNames.includes(name)));
|
|
5791
|
-
}
|
|
5792
|
-
/**
|
|
5793
|
-
* Creates the unexpected loop-limit error for dependency resolution.
|
|
6188
|
+
* @param pipeline valid or invalid PipelineJson
|
|
6189
|
+
* @returns the same pipeline if it is logically valid
|
|
6190
|
+
* @throws {PipelineLogicError} on logical error in the pipeline
|
|
5794
6191
|
*
|
|
5795
|
-
* @
|
|
6192
|
+
* @public exported from `@promptbook/core`
|
|
5796
6193
|
*/
|
|
5797
|
-
function
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
6194
|
+
function validatePipeline(pipeline) {
|
|
6195
|
+
if (IS_PIPELINE_LOGIC_VALIDATED) {
|
|
6196
|
+
validatePipeline_InnerFunction(pipeline);
|
|
6197
|
+
}
|
|
6198
|
+
else {
|
|
6199
|
+
try {
|
|
6200
|
+
validatePipeline_InnerFunction(pipeline);
|
|
6201
|
+
}
|
|
6202
|
+
catch (error) {
|
|
6203
|
+
if (!(error instanceof PipelineLogicError)) {
|
|
6204
|
+
throw error;
|
|
6205
|
+
}
|
|
6206
|
+
console.error(_spaceTrim.spaceTrim((block) => `
|
|
6207
|
+
Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
|
|
5801
6208
|
|
|
5802
|
-
|
|
5803
|
-
|
|
6209
|
+
${block(error.message)}
|
|
6210
|
+
`));
|
|
6211
|
+
}
|
|
6212
|
+
}
|
|
6213
|
+
return pipeline;
|
|
5804
6214
|
}
|
|
5805
6215
|
/**
|
|
5806
|
-
*
|
|
6216
|
+
* Validates pipeline inner function.
|
|
5807
6217
|
*
|
|
5808
|
-
* @private internal
|
|
6218
|
+
* @private internal function for `validatePipeline`
|
|
5809
6219
|
*/
|
|
5810
|
-
function
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
${block(unresolvedTasks
|
|
5822
|
-
.map(({ resultingParameterName, dependentParameterNames }) => `- Parameter \`{${resultingParameterName}}\` which depends on ${dependentParameterNames
|
|
5823
|
-
.map((dependentParameterName) => `\`{${dependentParameterName}}\``)
|
|
5824
|
-
.join(' and ')}`)
|
|
5825
|
-
.join('\n'))}
|
|
5826
|
-
|
|
5827
|
-
**Resolved:**
|
|
5828
|
-
${block(resolvedParameterNames
|
|
5829
|
-
.filter((name) => !RESERVED_PARAMETER_NAMES.includes(name))
|
|
5830
|
-
.map((name) => `- Parameter \`{${name}}\``)
|
|
5831
|
-
.join('\n'))}
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
**Reserved (which are available):**
|
|
5835
|
-
${block(resolvedParameterNames
|
|
5836
|
-
.filter((name) => RESERVED_PARAMETER_NAMES.includes(name))
|
|
5837
|
-
.map((name) => `- Parameter \`{${name}}\``)
|
|
5838
|
-
.join('\n'))}
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
`));
|
|
6220
|
+
function validatePipeline_InnerFunction(pipeline) {
|
|
6221
|
+
// TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
|
|
6222
|
+
const context = createPipelineValidationContext(pipeline);
|
|
6223
|
+
validatePipelineMetadata(context);
|
|
6224
|
+
validatePipelineCollectionsStructure(context);
|
|
6225
|
+
validatePipelineParameters(context);
|
|
6226
|
+
validatePipelineTasks(context);
|
|
6227
|
+
validatePipelineDependencyResolution(context);
|
|
6228
|
+
// Note: Check that formfactor is corresponding to the pipeline interface
|
|
6229
|
+
// TODO: !!6 Implement this
|
|
6230
|
+
// pipeline.formfactorName
|
|
5842
6231
|
}
|
|
5843
6232
|
/**
|
|
5844
6233
|
* TODO: [🧞♀️] Do not allow joker + foreach
|
|
@@ -14158,7 +14547,7 @@
|
|
|
14158
14547
|
* META commitment definition
|
|
14159
14548
|
*
|
|
14160
14549
|
* The META commitment handles all meta-information about the agent such as:
|
|
14161
|
-
* - META AVATAR: Sets the agent's built-in default avatar visual
|
|
14550
|
+
* - META AVATAR / META VISUAL: Sets the agent's built-in default avatar visual
|
|
14162
14551
|
* - META IMAGE: Sets the agent's avatar/profile image URL
|
|
14163
14552
|
* - META LINK: Provides profile/source links for the person the agent models
|
|
14164
14553
|
* - META DOMAIN: Sets the canonical custom domain/host of the agent
|
|
@@ -14173,7 +14562,7 @@
|
|
|
14173
14562
|
* Example usage in agent source:
|
|
14174
14563
|
*
|
|
14175
14564
|
* ```book
|
|
14176
|
-
* META
|
|
14565
|
+
* META VISUAL pixel-art
|
|
14177
14566
|
* META IMAGE https://example.com/avatar.jpg
|
|
14178
14567
|
* META LINK https://twitter.com/username
|
|
14179
14568
|
* META DOMAIN my-agent.com
|
|
@@ -14213,7 +14602,7 @@
|
|
|
14213
14602
|
|
|
14214
14603
|
## Supported META types
|
|
14215
14604
|
|
|
14216
|
-
- **META AVATAR** - Sets the agent's built-in default avatar visual
|
|
14605
|
+
- **META AVATAR** / **META VISUAL** - Sets the agent's built-in default avatar visual
|
|
14217
14606
|
- **META IMAGE** - Sets the agent's avatar/profile image URL
|
|
14218
14607
|
- **META LINK** - Provides profile/source links for the person the agent models
|
|
14219
14608
|
- **META DOMAIN** - Sets the canonical custom domain/host of the agent
|
|
@@ -14237,7 +14626,7 @@
|
|
|
14237
14626
|
\`\`\`book
|
|
14238
14627
|
Professional Assistant
|
|
14239
14628
|
|
|
14240
|
-
META
|
|
14629
|
+
META VISUAL octopus3
|
|
14241
14630
|
META IMAGE https://example.com/professional-avatar.jpg
|
|
14242
14631
|
META TITLE Senior Business Consultant
|
|
14243
14632
|
META DESCRIPTION Specialized in strategic planning and project management
|
|
@@ -17408,452 +17797,13 @@
|
|
|
17408
17797
|
.padStart(2, '0');
|
|
17409
17798
|
}
|
|
17410
17799
|
|
|
17411
|
-
/* eslint-disable no-magic-numbers */
|
|
17412
|
-
/**
|
|
17413
|
-
* Light direction used by the organic 3D octopus shading.
|
|
17414
|
-
*
|
|
17415
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17416
|
-
*/
|
|
17417
|
-
const LIGHT_DIRECTION$3 = normalizeVector3({
|
|
17418
|
-
x: 0.48,
|
|
17419
|
-
y: -0.62,
|
|
17420
|
-
z: 0.94,
|
|
17421
|
-
});
|
|
17422
|
-
/**
|
|
17423
|
-
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
17424
|
-
*
|
|
17425
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17426
|
-
*/
|
|
17427
|
-
const octopus3dStableStateCache = new WeakMap();
|
|
17428
|
-
/**
|
|
17429
|
-
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
17430
|
-
*
|
|
17431
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17432
|
-
*/
|
|
17433
|
-
function getOctopus3dStableState(createRandom) {
|
|
17434
|
-
const cached = octopus3dStableStateCache.get(createRandom);
|
|
17435
|
-
if (cached !== undefined) {
|
|
17436
|
-
return cached;
|
|
17437
|
-
}
|
|
17438
|
-
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
17439
|
-
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
17440
|
-
const leftEyePhaseOffset = eyeRandom() * 0.6;
|
|
17441
|
-
const rightEyePhaseOffset = eyeRandom() * 0.6;
|
|
17442
|
-
const state = {
|
|
17443
|
-
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
17444
|
-
animationPhase: animationRandom() * Math.PI * 2,
|
|
17445
|
-
leftEyePhaseOffset,
|
|
17446
|
-
rightEyePhaseOffset,
|
|
17447
|
-
};
|
|
17448
|
-
octopus3dStableStateCache.set(createRandom, state);
|
|
17449
|
-
return state;
|
|
17450
|
-
}
|
|
17451
|
-
/**
|
|
17452
|
-
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
17453
|
-
*
|
|
17454
|
-
* @private built-in avatar visual
|
|
17455
|
-
*/
|
|
17456
|
-
const octopus3dAvatarVisual = {
|
|
17457
|
-
id: 'octopus3d',
|
|
17458
|
-
title: 'Octopus 3D',
|
|
17459
|
-
description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
|
|
17460
|
-
isAnimated: true,
|
|
17461
|
-
supportsPointerTracking: true,
|
|
17462
|
-
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
17463
|
-
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
|
|
17464
|
-
const sceneCenterX = size * 0.5;
|
|
17465
|
-
const sceneCenterY = size * 0.56;
|
|
17466
|
-
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
17467
|
-
const mantleCenter = {
|
|
17468
|
-
x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
|
|
17469
|
-
y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
17470
|
-
z: interaction.intensity * size * 0.012,
|
|
17471
|
-
};
|
|
17472
|
-
const underbodyCenter = {
|
|
17473
|
-
x: mantleCenter.x * 0.86,
|
|
17474
|
-
y: mantleCenter.y + size * 0.168,
|
|
17475
|
-
z: mantleCenter.z - size * 0.018,
|
|
17476
|
-
};
|
|
17477
|
-
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
17478
|
-
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
17479
|
-
const mantleRadiusZ = size *
|
|
17480
|
-
morphologyProfile.body.bodyRadiusRatio *
|
|
17481
|
-
(0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
17482
|
-
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
17483
|
-
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
17484
|
-
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
17485
|
-
const bodyYaw = -0.18 +
|
|
17486
|
-
Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
|
|
17487
|
-
interaction.bodyOffsetX * 0.18 +
|
|
17488
|
-
interaction.gazeX * 0.22;
|
|
17489
|
-
const bodyPitch = -0.08 +
|
|
17490
|
-
Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
|
|
17491
|
-
interaction.bodyOffsetY * 0.08 -
|
|
17492
|
-
interaction.gazeY * 0.08;
|
|
17493
|
-
const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
|
|
17494
|
-
const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
|
|
17495
|
-
const mantlePatches = resolveVisibleEllipsoidPatches({
|
|
17496
|
-
center: mantleCenter,
|
|
17497
|
-
radiusX: mantleRadiusX,
|
|
17498
|
-
radiusY: mantleRadiusY,
|
|
17499
|
-
radiusZ: mantleRadiusZ,
|
|
17500
|
-
rotationX: headPitch,
|
|
17501
|
-
rotationY: headYaw,
|
|
17502
|
-
sceneCenterX,
|
|
17503
|
-
sceneCenterY,
|
|
17504
|
-
size,
|
|
17505
|
-
palette,
|
|
17506
|
-
verticalColorBias: 0,
|
|
17507
|
-
outlineColor: `${palette.highlight}7a`,
|
|
17508
|
-
});
|
|
17509
|
-
const underbodyPatches = resolveVisibleEllipsoidPatches({
|
|
17510
|
-
center: underbodyCenter,
|
|
17511
|
-
radiusX: underbodyRadiusX,
|
|
17512
|
-
radiusY: underbodyRadiusY,
|
|
17513
|
-
radiusZ: underbodyRadiusZ,
|
|
17514
|
-
rotationX: bodyPitch,
|
|
17515
|
-
rotationY: bodyYaw,
|
|
17516
|
-
sceneCenterX,
|
|
17517
|
-
sceneCenterY,
|
|
17518
|
-
size,
|
|
17519
|
-
palette,
|
|
17520
|
-
verticalColorBias: 0.18,
|
|
17521
|
-
outlineColor: `${palette.shadow}8f`,
|
|
17522
|
-
});
|
|
17523
|
-
const tentacleStrokes = createOctopusTentacleStrokes({
|
|
17524
|
-
createRandom,
|
|
17525
|
-
morphologyProfile,
|
|
17526
|
-
timeMs,
|
|
17527
|
-
size,
|
|
17528
|
-
center: underbodyCenter,
|
|
17529
|
-
radiusX: underbodyRadiusX,
|
|
17530
|
-
radiusY: underbodyRadiusY,
|
|
17531
|
-
radiusZ: underbodyRadiusZ,
|
|
17532
|
-
rotationX: bodyPitch,
|
|
17533
|
-
rotationY: bodyYaw,
|
|
17534
|
-
sceneCenterX,
|
|
17535
|
-
sceneCenterY,
|
|
17536
|
-
animationPhase,
|
|
17537
|
-
});
|
|
17538
|
-
const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
|
|
17539
|
-
const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
|
|
17540
|
-
const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
|
|
17541
|
-
const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
|
|
17542
|
-
const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
|
|
17543
|
-
const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
|
|
17544
|
-
drawAvatarFrame(context, size, palette);
|
|
17545
|
-
drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
17546
|
-
drawOctopus3dShadow(context, size, palette, interaction, timeMs);
|
|
17547
|
-
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
|
|
17548
|
-
drawTentacleStroke(context, tentacleStroke, palette);
|
|
17549
|
-
}
|
|
17550
|
-
for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
17551
|
-
drawSurfacePatch(context, surfacePatch);
|
|
17552
|
-
}
|
|
17553
|
-
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
17554
|
-
drawTentacleStroke(context, tentacleStroke, palette);
|
|
17555
|
-
}
|
|
17556
|
-
drawProjectedOrganicEye(context, {
|
|
17557
|
-
x: -faceEyeSpacing,
|
|
17558
|
-
y: faceEyeYOffset,
|
|
17559
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
17560
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
17561
|
-
drawProjectedOrganicEye(context, {
|
|
17562
|
-
x: faceEyeSpacing,
|
|
17563
|
-
y: faceEyeYOffset,
|
|
17564
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
17565
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
17566
|
-
drawProjectedOrganicMouth(context, [
|
|
17567
|
-
{
|
|
17568
|
-
x: -mouthHalfWidth,
|
|
17569
|
-
y: mouthY,
|
|
17570
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY),
|
|
17571
|
-
},
|
|
17572
|
-
{
|
|
17573
|
-
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
17574
|
-
y: mouthY +
|
|
17575
|
-
size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
|
|
17576
|
-
Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
|
|
17577
|
-
interaction.gazeY * size * 0.01,
|
|
17578
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
17579
|
-
},
|
|
17580
|
-
{
|
|
17581
|
-
x: mouthHalfWidth,
|
|
17582
|
-
y: mouthY,
|
|
17583
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY),
|
|
17584
|
-
},
|
|
17585
|
-
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
17586
|
-
},
|
|
17587
|
-
};
|
|
17588
|
-
/**
|
|
17589
|
-
* Draws the atmospheric underwater glow behind the octopus mesh.
|
|
17590
|
-
*
|
|
17591
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17592
|
-
*/
|
|
17593
|
-
function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
17594
|
-
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);
|
|
17595
|
-
glowGradient.addColorStop(0, `${palette.highlight}5c`);
|
|
17596
|
-
glowGradient.addColorStop(0.36, `${palette.accent}24`);
|
|
17597
|
-
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
17598
|
-
context.fillStyle = glowGradient;
|
|
17599
|
-
context.fillRect(0, 0, size, size);
|
|
17600
|
-
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);
|
|
17601
|
-
lowerGradient.addColorStop(0, `${palette.secondary}1d`);
|
|
17602
|
-
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
17603
|
-
context.fillStyle = lowerGradient;
|
|
17604
|
-
context.fillRect(0, 0, size, size);
|
|
17605
|
-
}
|
|
17606
|
-
/**
|
|
17607
|
-
* Draws the soft ground shadow below the octopus.
|
|
17608
|
-
*
|
|
17609
|
-
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
17610
|
-
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
17611
|
-
*
|
|
17612
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17613
|
-
*/
|
|
17614
|
-
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
17615
|
-
const cx = size * 0.5 + interaction.gazeX * size * 0.04;
|
|
17616
|
-
const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
|
|
17617
|
-
const rx = size * (0.18 + interaction.intensity * 0.02);
|
|
17618
|
-
const ry = size * 0.06;
|
|
17619
|
-
context.save();
|
|
17620
|
-
context.translate(cx, cy);
|
|
17621
|
-
context.scale(1, ry / rx);
|
|
17622
|
-
const blurRadius = rx * 1.4;
|
|
17623
|
-
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
17624
|
-
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
17625
|
-
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
17626
|
-
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
17627
|
-
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
17628
|
-
context.fillStyle = shadowGradient;
|
|
17629
|
-
context.beginPath();
|
|
17630
|
-
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
17631
|
-
context.fill();
|
|
17632
|
-
context.restore();
|
|
17633
|
-
}
|
|
17634
|
-
/**
|
|
17635
|
-
* Resolves visible projected patches for one rotated ellipsoid mesh.
|
|
17636
|
-
*
|
|
17637
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17638
|
-
*/
|
|
17639
|
-
function resolveVisibleEllipsoidPatches(options) {
|
|
17640
|
-
const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
|
|
17641
|
-
const latitudePatchCount = 10;
|
|
17642
|
-
const longitudePatchCount = 18;
|
|
17643
|
-
const surfacePatches = [];
|
|
17644
|
-
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
17645
|
-
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
17646
|
-
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
17647
|
-
const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
|
|
17648
|
-
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
17649
|
-
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
17650
|
-
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
17651
|
-
const localCorners = [
|
|
17652
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
|
|
17653
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
|
|
17654
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
|
|
17655
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
|
|
17656
|
-
];
|
|
17657
|
-
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
17658
|
-
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
17659
|
-
if (surfaceNormal.z <= 0.01) {
|
|
17660
|
-
continue;
|
|
17661
|
-
}
|
|
17662
|
-
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
17663
|
-
surfacePatches.push({
|
|
17664
|
-
corners: projectedCorners,
|
|
17665
|
-
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
17666
|
-
transformedCorners.length,
|
|
17667
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$3), -1, 1),
|
|
17668
|
-
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
17669
|
-
outlineColor,
|
|
17670
|
-
});
|
|
17671
|
-
}
|
|
17672
|
-
}
|
|
17673
|
-
return surfacePatches;
|
|
17674
|
-
}
|
|
17675
|
-
/**
|
|
17676
|
-
* Samples one point on an ellipsoid aligned to the local axes.
|
|
17677
|
-
*
|
|
17678
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17679
|
-
*/
|
|
17680
|
-
function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
|
|
17681
|
-
const cosineLatitude = Math.cos(latitude);
|
|
17682
|
-
return {
|
|
17683
|
-
x: Math.sin(longitude) * cosineLatitude * radiusX,
|
|
17684
|
-
y: Math.sin(latitude) * radiusY,
|
|
17685
|
-
z: Math.cos(longitude) * cosineLatitude * radiusZ,
|
|
17686
|
-
};
|
|
17687
|
-
}
|
|
17688
|
-
/**
|
|
17689
|
-
* Resolves one base fill tone for a surface patch across the octopus body.
|
|
17690
|
-
*
|
|
17691
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17692
|
-
*/
|
|
17693
|
-
function resolveSurfacePatchFillStyle(palette, verticalProgress) {
|
|
17694
|
-
const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
|
|
17695
|
-
if (clampedVerticalProgress < 0.2) {
|
|
17696
|
-
return palette.highlight;
|
|
17697
|
-
}
|
|
17698
|
-
if (clampedVerticalProgress < 0.45) {
|
|
17699
|
-
return palette.secondary;
|
|
17700
|
-
}
|
|
17701
|
-
if (clampedVerticalProgress < 0.8) {
|
|
17702
|
-
return palette.primary;
|
|
17703
|
-
}
|
|
17704
|
-
return `${palette.shadow}f2`;
|
|
17705
|
-
}
|
|
17706
|
-
/**
|
|
17707
|
-
* Draws one projected mesh patch with organic shading.
|
|
17708
|
-
*
|
|
17709
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17710
|
-
*/
|
|
17711
|
-
function drawSurfacePatch(context, surfacePatch) {
|
|
17712
|
-
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
17713
|
-
if (surfacePatch.lightIntensity > 0) {
|
|
17714
|
-
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
|
|
17715
|
-
}
|
|
17716
|
-
else if (surfacePatch.lightIntensity < 0) {
|
|
17717
|
-
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
17718
|
-
}
|
|
17719
|
-
context.save();
|
|
17720
|
-
context.beginPath();
|
|
17721
|
-
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
17722
|
-
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
17723
|
-
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
17724
|
-
}
|
|
17725
|
-
context.closePath();
|
|
17726
|
-
context.strokeStyle = surfacePatch.outlineColor;
|
|
17727
|
-
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
|
|
17728
|
-
context.lineJoin = 'round';
|
|
17729
|
-
context.stroke();
|
|
17730
|
-
context.restore();
|
|
17731
|
-
}
|
|
17732
|
-
/**
|
|
17733
|
-
* Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
|
|
17734
|
-
*
|
|
17735
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17736
|
-
*/
|
|
17737
|
-
function createOctopusTentacleStrokes(options) {
|
|
17738
|
-
const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
|
|
17739
|
-
return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
|
|
17740
|
-
const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
|
|
17741
|
-
const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
|
|
17742
|
-
const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
|
|
17743
|
-
const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
|
|
17744
|
-
const lateralReach = size *
|
|
17745
|
-
(0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
|
|
17746
|
-
const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
|
|
17747
|
-
const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
|
|
17748
|
-
const anchorPoint = {
|
|
17749
|
-
x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
|
|
17750
|
-
y: radiusY * (0.22 + tentacleRandom() * 0.18),
|
|
17751
|
-
z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
|
|
17752
|
-
};
|
|
17753
|
-
const controlPointOne = {
|
|
17754
|
-
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
|
|
17755
|
-
y: anchorPoint.y + flowLength * 0.26,
|
|
17756
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
17757
|
-
};
|
|
17758
|
-
const controlPointTwo = {
|
|
17759
|
-
x: anchorPoint.x +
|
|
17760
|
-
Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
17761
|
-
y: anchorPoint.y + flowLength * 0.66,
|
|
17762
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
17763
|
-
};
|
|
17764
|
-
const endPoint = {
|
|
17765
|
-
x: anchorPoint.x +
|
|
17766
|
-
Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
|
|
17767
|
-
sway * size * 0.028,
|
|
17768
|
-
y: anchorPoint.y + flowLength,
|
|
17769
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
|
|
17770
|
-
};
|
|
17771
|
-
const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
|
|
17772
|
-
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
17773
|
-
const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
|
|
17774
|
-
return {
|
|
17775
|
-
projectedPoints,
|
|
17776
|
-
averageDepth,
|
|
17777
|
-
isFrontFacing: averageDepth >= center.z - size * 0.006,
|
|
17778
|
-
baseWidth: size *
|
|
17779
|
-
(0.019 +
|
|
17780
|
-
morphologyProfile.tentacles.baseWidthScale * 0.007 +
|
|
17781
|
-
tentacleRandom() * 0.003 +
|
|
17782
|
-
Math.abs(Math.sin(orbitAngle)) * 0.002),
|
|
17783
|
-
tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
|
|
17784
|
-
colorBias: tentacleRandom(),
|
|
17785
|
-
};
|
|
17786
|
-
});
|
|
17787
|
-
}
|
|
17788
|
-
/**
|
|
17789
|
-
* Samples one point on a cubic Bezier curve in 3D.
|
|
17790
|
-
*
|
|
17791
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17792
|
-
*/
|
|
17793
|
-
function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
|
|
17794
|
-
const inverseProgress = 1 - progress;
|
|
17795
|
-
return {
|
|
17796
|
-
x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
|
|
17797
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
|
|
17798
|
-
3 * inverseProgress * progress * progress * controlPointTwo.x +
|
|
17799
|
-
progress * progress * progress * endPoint.x,
|
|
17800
|
-
y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
|
|
17801
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
|
|
17802
|
-
3 * inverseProgress * progress * progress * controlPointTwo.y +
|
|
17803
|
-
progress * progress * progress * endPoint.y,
|
|
17804
|
-
z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
|
|
17805
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
|
|
17806
|
-
3 * inverseProgress * progress * progress * controlPointTwo.z +
|
|
17807
|
-
progress * progress * progress * endPoint.z,
|
|
17808
|
-
};
|
|
17809
|
-
}
|
|
17810
|
-
/**
|
|
17811
|
-
* Draws one projected tentacle stroke with a slim highlight ridge.
|
|
17812
|
-
*
|
|
17813
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17814
|
-
*/
|
|
17815
|
-
function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
17816
|
-
const projectedSegments = tentacleStroke.projectedPoints.length - 1;
|
|
17817
|
-
for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
|
|
17818
|
-
const startPoint = tentacleStroke.projectedPoints[segmentIndex];
|
|
17819
|
-
const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
|
|
17820
|
-
const progress = segmentIndex / projectedSegments;
|
|
17821
|
-
const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
|
|
17822
|
-
context.beginPath();
|
|
17823
|
-
context.moveTo(startPoint.x, startPoint.y);
|
|
17824
|
-
context.lineTo(endPoint.x, endPoint.y);
|
|
17825
|
-
context.strokeStyle = tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
17826
|
-
context.lineWidth = width;
|
|
17827
|
-
context.lineCap = 'round';
|
|
17828
|
-
context.stroke();
|
|
17829
|
-
context.beginPath();
|
|
17830
|
-
context.moveTo(startPoint.x, startPoint.y);
|
|
17831
|
-
context.lineTo(endPoint.x, endPoint.y);
|
|
17832
|
-
context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
|
|
17833
|
-
context.lineWidth = Math.max(1, width * 0.34);
|
|
17834
|
-
context.lineCap = 'round';
|
|
17835
|
-
context.stroke();
|
|
17836
|
-
}
|
|
17837
|
-
}
|
|
17838
|
-
/**
|
|
17839
|
-
* Resolves the front surface depth on an ellipsoid for one local face point.
|
|
17840
|
-
*
|
|
17841
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17842
|
-
*/
|
|
17843
|
-
function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
17844
|
-
const normalizedX = x / radiusX;
|
|
17845
|
-
const normalizedY = y / radiusY;
|
|
17846
|
-
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
17847
|
-
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
17848
|
-
}
|
|
17849
|
-
|
|
17850
17800
|
/* eslint-disable no-magic-numbers */
|
|
17851
17801
|
/**
|
|
17852
17802
|
* Light direction used by the single-mesh octopus shading.
|
|
17853
17803
|
*
|
|
17854
17804
|
* @private helper of `octopus3d2AvatarVisual`
|
|
17855
17805
|
*/
|
|
17856
|
-
const LIGHT_DIRECTION$
|
|
17806
|
+
const LIGHT_DIRECTION$3 = normalizeVector3({
|
|
17857
17807
|
x: 0.38,
|
|
17858
17808
|
y: -0.6,
|
|
17859
17809
|
z: 0.98,
|
|
@@ -18092,7 +18042,7 @@
|
|
|
18092
18042
|
transformedCorners[2].z +
|
|
18093
18043
|
transformedCorners[3].z) /
|
|
18094
18044
|
4,
|
|
18095
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$
|
|
18045
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$3), -1, 1),
|
|
18096
18046
|
fillStyle: resolveBlobbySurfacePatchFillStyle$1(palette, verticalProgress, Math.max(0, Math.cos(centerLongitude)), resolveLowerLobeWave(centerLongitude, morphologyProfile, animationPhase, timeMs)),
|
|
18097
18047
|
outlineColor: verticalProgress < 0.58 ? `${palette.highlight}73` : `${palette.shadow}8a`,
|
|
18098
18048
|
});
|
|
@@ -18207,7 +18157,7 @@
|
|
|
18207
18157
|
*
|
|
18208
18158
|
* @private helper of `octopus3d3AvatarVisual`
|
|
18209
18159
|
*/
|
|
18210
|
-
const LIGHT_DIRECTION$
|
|
18160
|
+
const LIGHT_DIRECTION$2 = normalizeVector3({
|
|
18211
18161
|
x: 0.34,
|
|
18212
18162
|
y: -0.62,
|
|
18213
18163
|
z: 1,
|
|
@@ -18514,7 +18464,7 @@
|
|
|
18514
18464
|
transformedCorners[2].z +
|
|
18515
18465
|
transformedCorners[3].z) /
|
|
18516
18466
|
4,
|
|
18517
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$
|
|
18467
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$2), -1, 1),
|
|
18518
18468
|
fillStyle: resolveContinuousSurfacePatchFillStyle(palette, verticalProgress, cachedCosByPatchCenterLongitude[longitudeIndex], cachedTentacleInfluencesByPatchCenterLongitude[longitudeIndex].core, cachedLobeWavesByPatchCenterLongitude[longitudeIndex]),
|
|
18519
18469
|
outlineColor: verticalProgress < 0.54 ? `${palette.highlight}69` : `${palette.shadow}78`,
|
|
18520
18470
|
});
|
|
@@ -18829,7 +18779,7 @@
|
|
|
18829
18779
|
*
|
|
18830
18780
|
* @private helper of `octopus3d4AvatarVisual`
|
|
18831
18781
|
*/
|
|
18832
|
-
const LIGHT_DIRECTION = normalizeVector3({
|
|
18782
|
+
const LIGHT_DIRECTION$1 = normalizeVector3({
|
|
18833
18783
|
x: 0.32,
|
|
18834
18784
|
y: -0.66,
|
|
18835
18785
|
z: 1,
|
|
@@ -18900,7 +18850,7 @@
|
|
|
18900
18850
|
isAnimated: true,
|
|
18901
18851
|
supportsPointerTracking: true,
|
|
18902
18852
|
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
18903
|
-
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset, tentacleProfiles, skinSpots } = getOctopus3d4StableState(createRandom);
|
|
18853
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset, tentacleProfiles, skinSpots, } = getOctopus3d4StableState(createRandom);
|
|
18904
18854
|
const sceneCenterX = size * 0.5;
|
|
18905
18855
|
const sceneCenterY = size * 0.535;
|
|
18906
18856
|
const bob = Math.sin(timeMs / 980 + animationPhase) * size * 0.013;
|
|
@@ -19175,7 +19125,7 @@
|
|
|
19175
19125
|
projectScenePoint(transformedCorners[2], size, sceneCenterX, sceneCenterY),
|
|
19176
19126
|
projectScenePoint(transformedCorners[3], size, sceneCenterX, sceneCenterY),
|
|
19177
19127
|
];
|
|
19178
|
-
const lightIntensity = clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1);
|
|
19128
|
+
const lightIntensity = clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$1), -1, 1);
|
|
19179
19129
|
const rimLightIntensity = Math.pow(clampNumber$1(dotProduct3D(surfaceNormal, RIM_LIGHT_DIRECTION), 0, 1), 2.6);
|
|
19180
19130
|
surfacePatches.push({
|
|
19181
19131
|
corners: projectedCorners,
|
|
@@ -19248,10 +19198,7 @@
|
|
|
19248
19198
|
Math.max(0, Math.cos(effectiveLongitude)) * 0.12 +
|
|
19249
19199
|
lowerBlend * tentacleInfluence.core * (0.12 + tentacleInfluence.depthScale * 0.07) -
|
|
19250
19200
|
Math.max(0, -Math.cos(effectiveLongitude)) * 0.05;
|
|
19251
|
-
const tentacleTubeRadius = lowerBlend *
|
|
19252
|
-
tentacleInfluence.core *
|
|
19253
|
-
(0.12 + tipBlend * 0.07 + tentacleInfluence.widthScale * 0.028) *
|
|
19254
|
-
radiusX;
|
|
19201
|
+
const tentacleTubeRadius = lowerBlend * tentacleInfluence.core * (0.12 + tipBlend * 0.07 + tentacleInfluence.widthScale * 0.028) * radiusX;
|
|
19255
19202
|
const planarRadiusX = cosineLatitude * radiusX * horizontalScale + tentacleTubeRadius;
|
|
19256
19203
|
const planarRadiusZ = cosineLatitude * radiusZ * depthScale + tentacleTubeRadius * 0.74;
|
|
19257
19204
|
const lowerDrop = lowerBlend *
|
|
@@ -19263,9 +19210,7 @@
|
|
|
19263
19210
|
(morphologyProfile.tentacles.flowLengthScale - 1) * 0.1));
|
|
19264
19211
|
const combinedTentacleSway = (primaryTentacleWave + secondaryTentacleWave) * radiusX * (0.06 + tipBlend * 0.06);
|
|
19265
19212
|
return {
|
|
19266
|
-
x: Math.sin(effectiveLongitude) * planarRadiusX +
|
|
19267
|
-
combinedTentacleSway +
|
|
19268
|
-
tentacleCurl * radiusX * 0.18,
|
|
19213
|
+
x: Math.sin(effectiveLongitude) * planarRadiusX + combinedTentacleSway + tentacleCurl * radiusX * 0.18,
|
|
19269
19214
|
y: Math.sin(latitude) * radiusY * (1 + upperBlend * 0.14) -
|
|
19270
19215
|
upperBlend * radiusY * 0.12 +
|
|
19271
19216
|
lowerDrop +
|
|
@@ -19579,6 +19524,445 @@
|
|
|
19579
19524
|
.padStart(2, '0');
|
|
19580
19525
|
}
|
|
19581
19526
|
|
|
19527
|
+
/* eslint-disable no-magic-numbers */
|
|
19528
|
+
/**
|
|
19529
|
+
* Light direction used by the organic 3D octopus shading.
|
|
19530
|
+
*
|
|
19531
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19532
|
+
*/
|
|
19533
|
+
const LIGHT_DIRECTION = normalizeVector3({
|
|
19534
|
+
x: 0.48,
|
|
19535
|
+
y: -0.62,
|
|
19536
|
+
z: 0.94,
|
|
19537
|
+
});
|
|
19538
|
+
/**
|
|
19539
|
+
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
19540
|
+
*
|
|
19541
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19542
|
+
*/
|
|
19543
|
+
const octopus3dStableStateCache = new WeakMap();
|
|
19544
|
+
/**
|
|
19545
|
+
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
19546
|
+
*
|
|
19547
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19548
|
+
*/
|
|
19549
|
+
function getOctopus3dStableState(createRandom) {
|
|
19550
|
+
const cached = octopus3dStableStateCache.get(createRandom);
|
|
19551
|
+
if (cached !== undefined) {
|
|
19552
|
+
return cached;
|
|
19553
|
+
}
|
|
19554
|
+
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
19555
|
+
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
19556
|
+
const leftEyePhaseOffset = eyeRandom() * 0.6;
|
|
19557
|
+
const rightEyePhaseOffset = eyeRandom() * 0.6;
|
|
19558
|
+
const state = {
|
|
19559
|
+
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
19560
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
19561
|
+
leftEyePhaseOffset,
|
|
19562
|
+
rightEyePhaseOffset,
|
|
19563
|
+
};
|
|
19564
|
+
octopus3dStableStateCache.set(createRandom, state);
|
|
19565
|
+
return state;
|
|
19566
|
+
}
|
|
19567
|
+
/**
|
|
19568
|
+
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
19569
|
+
*
|
|
19570
|
+
* @private built-in avatar visual
|
|
19571
|
+
*/
|
|
19572
|
+
const octopus3dAvatarVisual = {
|
|
19573
|
+
id: 'octopus3d',
|
|
19574
|
+
title: 'Octopus 3D',
|
|
19575
|
+
description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
|
|
19576
|
+
isAnimated: true,
|
|
19577
|
+
supportsPointerTracking: true,
|
|
19578
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
19579
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
|
|
19580
|
+
const sceneCenterX = size * 0.5;
|
|
19581
|
+
const sceneCenterY = size * 0.56;
|
|
19582
|
+
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
19583
|
+
const mantleCenter = {
|
|
19584
|
+
x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
|
|
19585
|
+
y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
19586
|
+
z: interaction.intensity * size * 0.012,
|
|
19587
|
+
};
|
|
19588
|
+
const underbodyCenter = {
|
|
19589
|
+
x: mantleCenter.x * 0.86,
|
|
19590
|
+
y: mantleCenter.y + size * 0.168,
|
|
19591
|
+
z: mantleCenter.z - size * 0.018,
|
|
19592
|
+
};
|
|
19593
|
+
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
19594
|
+
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
19595
|
+
const mantleRadiusZ = size *
|
|
19596
|
+
morphologyProfile.body.bodyRadiusRatio *
|
|
19597
|
+
(0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
19598
|
+
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
19599
|
+
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
19600
|
+
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
19601
|
+
const bodyYaw = -0.18 +
|
|
19602
|
+
Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
|
|
19603
|
+
interaction.bodyOffsetX * 0.18 +
|
|
19604
|
+
interaction.gazeX * 0.22;
|
|
19605
|
+
const bodyPitch = -0.08 +
|
|
19606
|
+
Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
|
|
19607
|
+
interaction.bodyOffsetY * 0.08 -
|
|
19608
|
+
interaction.gazeY * 0.08;
|
|
19609
|
+
const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
|
|
19610
|
+
const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
|
|
19611
|
+
const mantlePatches = resolveVisibleEllipsoidPatches({
|
|
19612
|
+
center: mantleCenter,
|
|
19613
|
+
radiusX: mantleRadiusX,
|
|
19614
|
+
radiusY: mantleRadiusY,
|
|
19615
|
+
radiusZ: mantleRadiusZ,
|
|
19616
|
+
rotationX: headPitch,
|
|
19617
|
+
rotationY: headYaw,
|
|
19618
|
+
sceneCenterX,
|
|
19619
|
+
sceneCenterY,
|
|
19620
|
+
size,
|
|
19621
|
+
palette,
|
|
19622
|
+
verticalColorBias: 0,
|
|
19623
|
+
outlineColor: `${palette.highlight}7a`,
|
|
19624
|
+
});
|
|
19625
|
+
const underbodyPatches = resolveVisibleEllipsoidPatches({
|
|
19626
|
+
center: underbodyCenter,
|
|
19627
|
+
radiusX: underbodyRadiusX,
|
|
19628
|
+
radiusY: underbodyRadiusY,
|
|
19629
|
+
radiusZ: underbodyRadiusZ,
|
|
19630
|
+
rotationX: bodyPitch,
|
|
19631
|
+
rotationY: bodyYaw,
|
|
19632
|
+
sceneCenterX,
|
|
19633
|
+
sceneCenterY,
|
|
19634
|
+
size,
|
|
19635
|
+
palette,
|
|
19636
|
+
verticalColorBias: 0.18,
|
|
19637
|
+
outlineColor: `${palette.shadow}8f`,
|
|
19638
|
+
});
|
|
19639
|
+
const tentacleStrokes = createOctopusTentacleStrokes({
|
|
19640
|
+
createRandom,
|
|
19641
|
+
morphologyProfile,
|
|
19642
|
+
timeMs,
|
|
19643
|
+
size,
|
|
19644
|
+
center: underbodyCenter,
|
|
19645
|
+
radiusX: underbodyRadiusX,
|
|
19646
|
+
radiusY: underbodyRadiusY,
|
|
19647
|
+
radiusZ: underbodyRadiusZ,
|
|
19648
|
+
rotationX: bodyPitch,
|
|
19649
|
+
rotationY: bodyYaw,
|
|
19650
|
+
sceneCenterX,
|
|
19651
|
+
sceneCenterY,
|
|
19652
|
+
animationPhase,
|
|
19653
|
+
});
|
|
19654
|
+
const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
|
|
19655
|
+
const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
|
|
19656
|
+
const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
|
|
19657
|
+
const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
|
|
19658
|
+
const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
|
|
19659
|
+
const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
|
|
19660
|
+
drawAvatarFrame(context, size, palette);
|
|
19661
|
+
drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
19662
|
+
drawOctopus3dShadow(context, size, palette, interaction, timeMs);
|
|
19663
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
|
|
19664
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
19665
|
+
}
|
|
19666
|
+
for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
19667
|
+
drawSurfacePatch(context, surfacePatch);
|
|
19668
|
+
}
|
|
19669
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
19670
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
19671
|
+
}
|
|
19672
|
+
drawProjectedOrganicEye(context, {
|
|
19673
|
+
x: -faceEyeSpacing,
|
|
19674
|
+
y: faceEyeYOffset,
|
|
19675
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
19676
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
19677
|
+
drawProjectedOrganicEye(context, {
|
|
19678
|
+
x: faceEyeSpacing,
|
|
19679
|
+
y: faceEyeYOffset,
|
|
19680
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
19681
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
19682
|
+
drawProjectedOrganicMouth(context, [
|
|
19683
|
+
{
|
|
19684
|
+
x: -mouthHalfWidth,
|
|
19685
|
+
y: mouthY,
|
|
19686
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY),
|
|
19687
|
+
},
|
|
19688
|
+
{
|
|
19689
|
+
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
19690
|
+
y: mouthY +
|
|
19691
|
+
size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
|
|
19692
|
+
Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
|
|
19693
|
+
interaction.gazeY * size * 0.01,
|
|
19694
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
19695
|
+
},
|
|
19696
|
+
{
|
|
19697
|
+
x: mouthHalfWidth,
|
|
19698
|
+
y: mouthY,
|
|
19699
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY),
|
|
19700
|
+
},
|
|
19701
|
+
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
19702
|
+
},
|
|
19703
|
+
};
|
|
19704
|
+
/**
|
|
19705
|
+
* Draws the atmospheric underwater glow behind the octopus mesh.
|
|
19706
|
+
*
|
|
19707
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19708
|
+
*/
|
|
19709
|
+
function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
19710
|
+
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);
|
|
19711
|
+
glowGradient.addColorStop(0, `${palette.highlight}5c`);
|
|
19712
|
+
glowGradient.addColorStop(0.36, `${palette.accent}24`);
|
|
19713
|
+
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
19714
|
+
context.fillStyle = glowGradient;
|
|
19715
|
+
context.fillRect(0, 0, size, size);
|
|
19716
|
+
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);
|
|
19717
|
+
lowerGradient.addColorStop(0, `${palette.secondary}1d`);
|
|
19718
|
+
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
19719
|
+
context.fillStyle = lowerGradient;
|
|
19720
|
+
context.fillRect(0, 0, size, size);
|
|
19721
|
+
}
|
|
19722
|
+
/**
|
|
19723
|
+
* Draws the soft ground shadow below the octopus.
|
|
19724
|
+
*
|
|
19725
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
19726
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
19727
|
+
*
|
|
19728
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19729
|
+
*/
|
|
19730
|
+
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
19731
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.04;
|
|
19732
|
+
const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
|
|
19733
|
+
const rx = size * (0.18 + interaction.intensity * 0.02);
|
|
19734
|
+
const ry = size * 0.06;
|
|
19735
|
+
context.save();
|
|
19736
|
+
context.translate(cx, cy);
|
|
19737
|
+
context.scale(1, ry / rx);
|
|
19738
|
+
const blurRadius = rx * 1.4;
|
|
19739
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
19740
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
19741
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
19742
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
19743
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
19744
|
+
context.fillStyle = shadowGradient;
|
|
19745
|
+
context.beginPath();
|
|
19746
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
19747
|
+
context.fill();
|
|
19748
|
+
context.restore();
|
|
19749
|
+
}
|
|
19750
|
+
/**
|
|
19751
|
+
* Resolves visible projected patches for one rotated ellipsoid mesh.
|
|
19752
|
+
*
|
|
19753
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19754
|
+
*/
|
|
19755
|
+
function resolveVisibleEllipsoidPatches(options) {
|
|
19756
|
+
const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
|
|
19757
|
+
const latitudePatchCount = 10;
|
|
19758
|
+
const longitudePatchCount = 18;
|
|
19759
|
+
const surfacePatches = [];
|
|
19760
|
+
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
19761
|
+
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
19762
|
+
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
19763
|
+
const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
|
|
19764
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
19765
|
+
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
19766
|
+
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
19767
|
+
const localCorners = [
|
|
19768
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
|
|
19769
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
|
|
19770
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
|
|
19771
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
|
|
19772
|
+
];
|
|
19773
|
+
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
19774
|
+
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
19775
|
+
if (surfaceNormal.z <= 0.01) {
|
|
19776
|
+
continue;
|
|
19777
|
+
}
|
|
19778
|
+
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
19779
|
+
surfacePatches.push({
|
|
19780
|
+
corners: projectedCorners,
|
|
19781
|
+
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
19782
|
+
transformedCorners.length,
|
|
19783
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
19784
|
+
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
19785
|
+
outlineColor,
|
|
19786
|
+
});
|
|
19787
|
+
}
|
|
19788
|
+
}
|
|
19789
|
+
return surfacePatches;
|
|
19790
|
+
}
|
|
19791
|
+
/**
|
|
19792
|
+
* Samples one point on an ellipsoid aligned to the local axes.
|
|
19793
|
+
*
|
|
19794
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19795
|
+
*/
|
|
19796
|
+
function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
|
|
19797
|
+
const cosineLatitude = Math.cos(latitude);
|
|
19798
|
+
return {
|
|
19799
|
+
x: Math.sin(longitude) * cosineLatitude * radiusX,
|
|
19800
|
+
y: Math.sin(latitude) * radiusY,
|
|
19801
|
+
z: Math.cos(longitude) * cosineLatitude * radiusZ,
|
|
19802
|
+
};
|
|
19803
|
+
}
|
|
19804
|
+
/**
|
|
19805
|
+
* Resolves one base fill tone for a surface patch across the octopus body.
|
|
19806
|
+
*
|
|
19807
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19808
|
+
*/
|
|
19809
|
+
function resolveSurfacePatchFillStyle(palette, verticalProgress) {
|
|
19810
|
+
const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
|
|
19811
|
+
if (clampedVerticalProgress < 0.2) {
|
|
19812
|
+
return palette.highlight;
|
|
19813
|
+
}
|
|
19814
|
+
if (clampedVerticalProgress < 0.45) {
|
|
19815
|
+
return palette.secondary;
|
|
19816
|
+
}
|
|
19817
|
+
if (clampedVerticalProgress < 0.8) {
|
|
19818
|
+
return palette.primary;
|
|
19819
|
+
}
|
|
19820
|
+
return `${palette.shadow}f2`;
|
|
19821
|
+
}
|
|
19822
|
+
/**
|
|
19823
|
+
* Draws one projected mesh patch with organic shading.
|
|
19824
|
+
*
|
|
19825
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19826
|
+
*/
|
|
19827
|
+
function drawSurfacePatch(context, surfacePatch) {
|
|
19828
|
+
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
19829
|
+
if (surfacePatch.lightIntensity > 0) {
|
|
19830
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
|
|
19831
|
+
}
|
|
19832
|
+
else if (surfacePatch.lightIntensity < 0) {
|
|
19833
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
19834
|
+
}
|
|
19835
|
+
context.save();
|
|
19836
|
+
context.beginPath();
|
|
19837
|
+
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
19838
|
+
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
19839
|
+
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
19840
|
+
}
|
|
19841
|
+
context.closePath();
|
|
19842
|
+
context.strokeStyle = surfacePatch.outlineColor;
|
|
19843
|
+
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
|
|
19844
|
+
context.lineJoin = 'round';
|
|
19845
|
+
context.stroke();
|
|
19846
|
+
context.restore();
|
|
19847
|
+
}
|
|
19848
|
+
/**
|
|
19849
|
+
* Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
|
|
19850
|
+
*
|
|
19851
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19852
|
+
*/
|
|
19853
|
+
function createOctopusTentacleStrokes(options) {
|
|
19854
|
+
const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
|
|
19855
|
+
return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
|
|
19856
|
+
const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
|
|
19857
|
+
const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
|
|
19858
|
+
const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
|
|
19859
|
+
const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
|
|
19860
|
+
const lateralReach = size *
|
|
19861
|
+
(0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
|
|
19862
|
+
const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
|
|
19863
|
+
const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
|
|
19864
|
+
const anchorPoint = {
|
|
19865
|
+
x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
|
|
19866
|
+
y: radiusY * (0.22 + tentacleRandom() * 0.18),
|
|
19867
|
+
z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
|
|
19868
|
+
};
|
|
19869
|
+
const controlPointOne = {
|
|
19870
|
+
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
|
|
19871
|
+
y: anchorPoint.y + flowLength * 0.26,
|
|
19872
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
19873
|
+
};
|
|
19874
|
+
const controlPointTwo = {
|
|
19875
|
+
x: anchorPoint.x +
|
|
19876
|
+
Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
19877
|
+
y: anchorPoint.y + flowLength * 0.66,
|
|
19878
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
19879
|
+
};
|
|
19880
|
+
const endPoint = {
|
|
19881
|
+
x: anchorPoint.x +
|
|
19882
|
+
Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
|
|
19883
|
+
sway * size * 0.028,
|
|
19884
|
+
y: anchorPoint.y + flowLength,
|
|
19885
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
|
|
19886
|
+
};
|
|
19887
|
+
const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
|
|
19888
|
+
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
19889
|
+
const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
|
|
19890
|
+
return {
|
|
19891
|
+
projectedPoints,
|
|
19892
|
+
averageDepth,
|
|
19893
|
+
isFrontFacing: averageDepth >= center.z - size * 0.006,
|
|
19894
|
+
baseWidth: size *
|
|
19895
|
+
(0.019 +
|
|
19896
|
+
morphologyProfile.tentacles.baseWidthScale * 0.007 +
|
|
19897
|
+
tentacleRandom() * 0.003 +
|
|
19898
|
+
Math.abs(Math.sin(orbitAngle)) * 0.002),
|
|
19899
|
+
tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
|
|
19900
|
+
colorBias: tentacleRandom(),
|
|
19901
|
+
};
|
|
19902
|
+
});
|
|
19903
|
+
}
|
|
19904
|
+
/**
|
|
19905
|
+
* Samples one point on a cubic Bezier curve in 3D.
|
|
19906
|
+
*
|
|
19907
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19908
|
+
*/
|
|
19909
|
+
function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
|
|
19910
|
+
const inverseProgress = 1 - progress;
|
|
19911
|
+
return {
|
|
19912
|
+
x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
|
|
19913
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
|
|
19914
|
+
3 * inverseProgress * progress * progress * controlPointTwo.x +
|
|
19915
|
+
progress * progress * progress * endPoint.x,
|
|
19916
|
+
y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
|
|
19917
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
|
|
19918
|
+
3 * inverseProgress * progress * progress * controlPointTwo.y +
|
|
19919
|
+
progress * progress * progress * endPoint.y,
|
|
19920
|
+
z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
|
|
19921
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
|
|
19922
|
+
3 * inverseProgress * progress * progress * controlPointTwo.z +
|
|
19923
|
+
progress * progress * progress * endPoint.z,
|
|
19924
|
+
};
|
|
19925
|
+
}
|
|
19926
|
+
/**
|
|
19927
|
+
* Draws one projected tentacle stroke with a slim highlight ridge.
|
|
19928
|
+
*
|
|
19929
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19930
|
+
*/
|
|
19931
|
+
function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
19932
|
+
const projectedSegments = tentacleStroke.projectedPoints.length - 1;
|
|
19933
|
+
for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
|
|
19934
|
+
const startPoint = tentacleStroke.projectedPoints[segmentIndex];
|
|
19935
|
+
const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
|
|
19936
|
+
const progress = segmentIndex / projectedSegments;
|
|
19937
|
+
const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
|
|
19938
|
+
context.beginPath();
|
|
19939
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
19940
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
19941
|
+
context.strokeStyle = tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
19942
|
+
context.lineWidth = width;
|
|
19943
|
+
context.lineCap = 'round';
|
|
19944
|
+
context.stroke();
|
|
19945
|
+
context.beginPath();
|
|
19946
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
19947
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
19948
|
+
context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
|
|
19949
|
+
context.lineWidth = Math.max(1, width * 0.34);
|
|
19950
|
+
context.lineCap = 'round';
|
|
19951
|
+
context.stroke();
|
|
19952
|
+
}
|
|
19953
|
+
}
|
|
19954
|
+
/**
|
|
19955
|
+
* Resolves the front surface depth on an ellipsoid for one local face point.
|
|
19956
|
+
*
|
|
19957
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19958
|
+
*/
|
|
19959
|
+
function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
19960
|
+
const normalizedX = x / radiusX;
|
|
19961
|
+
const normalizedY = y / radiusY;
|
|
19962
|
+
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
19963
|
+
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
19964
|
+
}
|
|
19965
|
+
|
|
19582
19966
|
/* eslint-disable no-magic-numbers */
|
|
19583
19967
|
/**
|
|
19584
19968
|
* Octopus avatar visual.
|
|
@@ -20399,14 +20783,14 @@
|
|
|
20399
20783
|
/**
|
|
20400
20784
|
* META AVATAR commitment definition
|
|
20401
20785
|
*
|
|
20402
|
-
* The `META AVATAR`
|
|
20403
|
-
* the agent does not provide an explicit `META IMAGE`.
|
|
20786
|
+
* The `META AVATAR` and `META VISUAL` commitments set the built-in default avatar visual
|
|
20787
|
+
* used when the agent does not provide an explicit `META IMAGE`.
|
|
20404
20788
|
*
|
|
20405
20789
|
* @private [🪔] Maybe export the commitments through some package
|
|
20406
20790
|
*/
|
|
20407
20791
|
class MetaAvatarCommitmentDefinition extends BaseCommitmentDefinition {
|
|
20408
|
-
constructor() {
|
|
20409
|
-
super(
|
|
20792
|
+
constructor(type = 'META AVATAR') {
|
|
20793
|
+
super(type);
|
|
20410
20794
|
}
|
|
20411
20795
|
/**
|
|
20412
20796
|
* Short one-line description of META AVATAR.
|
|
@@ -20426,14 +20810,15 @@
|
|
|
20426
20810
|
get documentation() {
|
|
20427
20811
|
const supportedVisuals = AVATAR_VISUALS.map((avatarVisual) => `\`${avatarVisual.id}\``).join(', ');
|
|
20428
20812
|
return _spaceTrim.spaceTrim(`
|
|
20429
|
-
#
|
|
20813
|
+
# ${this.type}
|
|
20430
20814
|
|
|
20431
20815
|
Sets the built-in avatar visual used for the agent when no explicit \`META IMAGE\` is provided.
|
|
20816
|
+
\`META AVATAR\` and \`META VISUAL\` are equivalent.
|
|
20432
20817
|
|
|
20433
20818
|
## Key aspects
|
|
20434
20819
|
|
|
20435
20820
|
- Does not modify the agent's behavior or responses.
|
|
20436
|
-
- Only one \`META AVATAR\` should be used per agent.
|
|
20821
|
+
- Only one \`META AVATAR\` or \`META VISUAL\` should be used per agent.
|
|
20437
20822
|
- If multiple are specified, the last one takes precedence.
|
|
20438
20823
|
- Values are matched case-insensitively and spaces, hyphens, and underscores are normalized.
|
|
20439
20824
|
- Supported visuals are derived from the shared avatar registry: ${supportedVisuals}.
|
|
@@ -20448,15 +20833,15 @@
|
|
|
20448
20833
|
\`\`\`
|
|
20449
20834
|
|
|
20450
20835
|
\`\`\`book
|
|
20451
|
-
|
|
20836
|
+
Minecraft Assistant
|
|
20452
20837
|
|
|
20453
|
-
META
|
|
20838
|
+
META VISUAL Minecraft2
|
|
20454
20839
|
GOAL Answer in a calm and focused way.
|
|
20455
20840
|
\`\`\`
|
|
20456
20841
|
`);
|
|
20457
20842
|
}
|
|
20458
20843
|
applyToAgentModelRequirements(requirements, content) {
|
|
20459
|
-
// META AVATAR
|
|
20844
|
+
// META AVATAR and META VISUAL don't modify the system message or model requirements.
|
|
20460
20845
|
// It's handled separately in the parsing logic for profile avatar resolution.
|
|
20461
20846
|
return requirements;
|
|
20462
20847
|
}
|
|
@@ -22435,10 +22820,10 @@
|
|
|
22435
22820
|
*
|
|
22436
22821
|
* @private
|
|
22437
22822
|
*/
|
|
22438
|
-
const
|
|
22439
|
-
|
|
22440
|
-
|
|
22441
|
-
|
|
22823
|
+
const TEAM_SYSTEM_MESSAGE_GUIDANCE = _spaceTrim.spaceTrim(`
|
|
22824
|
+
- If a teammate is relevant to the request, consult that teammate using the matching tool.
|
|
22825
|
+
- Do not ask the user for information that a listed teammate can provide directly.
|
|
22826
|
+
`);
|
|
22442
22827
|
/**
|
|
22443
22828
|
* Constant for remote agents by Url.
|
|
22444
22829
|
*/
|
|
@@ -22620,7 +23005,7 @@
|
|
|
22620
23005
|
`);
|
|
22621
23006
|
});
|
|
22622
23007
|
return _spaceTrim.spaceTrim((block) => `
|
|
22623
|
-
${block(
|
|
23008
|
+
${block(TEAM_SYSTEM_MESSAGE_GUIDANCE)}
|
|
22624
23009
|
|
|
22625
23010
|
${block(teammateSections.join('\n\n'))}
|
|
22626
23011
|
`);
|
|
@@ -29644,6 +30029,7 @@
|
|
|
29644
30029
|
new ActionCommitmentDefinition('ACTIONS'),
|
|
29645
30030
|
new ComponentCommitmentDefinition(),
|
|
29646
30031
|
new MetaAvatarCommitmentDefinition(),
|
|
30032
|
+
new MetaAvatarCommitmentDefinition('META VISUAL'),
|
|
29647
30033
|
new MetaImageCommitmentDefinition(),
|
|
29648
30034
|
new MetaColorCommitmentDefinition(),
|
|
29649
30035
|
new MetaFontCommitmentDefinition(),
|
|
@@ -30995,6 +31381,7 @@
|
|
|
30995
31381
|
*/
|
|
30996
31382
|
const META_COMMITMENT_APPLIERS = {
|
|
30997
31383
|
'META AVATAR': applyMetaAvatarContent,
|
|
31384
|
+
'META VISUAL': applyMetaAvatarContent,
|
|
30998
31385
|
'META LINK': applyMetaLinkContent,
|
|
30999
31386
|
'META DOMAIN': applyMetaDomainContent,
|
|
31000
31387
|
'META IMAGE': applyMetaImageContent,
|
|
@@ -31043,7 +31430,7 @@
|
|
|
31043
31430
|
state.meta[metaType] = metaValue;
|
|
31044
31431
|
}
|
|
31045
31432
|
/**
|
|
31046
|
-
* Applies META AVATAR content into the canonical `meta.avatar` field.
|
|
31433
|
+
* Applies META AVATAR / META VISUAL content into the canonical `meta.avatar` field.
|
|
31047
31434
|
*/
|
|
31048
31435
|
function applyMetaAvatarContent(state, content) {
|
|
31049
31436
|
const avatarVisualId = resolveAvatarVisualId(content);
|
|
@@ -32107,6 +32494,78 @@
|
|
|
32107
32494
|
.replace(/^[._-]+|[._-]+$/gu, '');
|
|
32108
32495
|
}
|
|
32109
32496
|
|
|
32497
|
+
/**
|
|
32498
|
+
* Helper of usage compute
|
|
32499
|
+
*
|
|
32500
|
+
* @param content the content of prompt or response
|
|
32501
|
+
* @returns part of UsageCounts
|
|
32502
|
+
*
|
|
32503
|
+
* @private internal utility of LlmExecutionTools
|
|
32504
|
+
*/
|
|
32505
|
+
function computeUsageCounts(content) {
|
|
32506
|
+
return {
|
|
32507
|
+
charactersCount: { value: countCharacters(content) },
|
|
32508
|
+
wordsCount: { value: countWords(content) },
|
|
32509
|
+
sentencesCount: { value: countSentences(content) },
|
|
32510
|
+
linesCount: { value: countLines(content) },
|
|
32511
|
+
paragraphsCount: { value: countParagraphs(content) },
|
|
32512
|
+
pagesCount: { value: countPages(content) },
|
|
32513
|
+
};
|
|
32514
|
+
}
|
|
32515
|
+
|
|
32516
|
+
/**
|
|
32517
|
+
* Computes the usage of the OpenAI API based on the response from OpenAI
|
|
32518
|
+
*
|
|
32519
|
+
* @param promptContent The content of the prompt
|
|
32520
|
+
* @param resultContent The content of the result (for embedding prompts or failed prompts pass empty string)
|
|
32521
|
+
* @param rawResponse The raw response from OpenAI API
|
|
32522
|
+
* @param duration The duration of the execution
|
|
32523
|
+
* @throws {PipelineExecutionError} If the usage is not defined in the response from OpenAI
|
|
32524
|
+
*
|
|
32525
|
+
* @private internal utility of `OpenAiExecutionTools`
|
|
32526
|
+
*/
|
|
32527
|
+
function computeOpenAiUsage(promptContent, // <- Note: Intentionally using [] to access type properties to bring jsdoc from Prompt/PromptResult to consumer
|
|
32528
|
+
resultContent, rawResponse, duration = ZERO_VALUE) {
|
|
32529
|
+
var _a, _b;
|
|
32530
|
+
if (rawResponse.usage === undefined) {
|
|
32531
|
+
throw new PipelineExecutionError('The usage is not defined in the response from OpenAI');
|
|
32532
|
+
}
|
|
32533
|
+
if (((_a = rawResponse.usage) === null || _a === void 0 ? void 0 : _a.prompt_tokens) === undefined) {
|
|
32534
|
+
throw new PipelineExecutionError('In OpenAI response `usage.prompt_tokens` not defined');
|
|
32535
|
+
}
|
|
32536
|
+
const inputTokens = rawResponse.usage.prompt_tokens;
|
|
32537
|
+
const outputTokens = ((_b = rawResponse.usage) === null || _b === void 0 ? void 0 : _b.completion_tokens) || 0;
|
|
32538
|
+
let isUncertain = false;
|
|
32539
|
+
let modelInfo = OPENAI_MODELS.find((model) => model.modelName === rawResponse.model);
|
|
32540
|
+
if (modelInfo === undefined) {
|
|
32541
|
+
// Note: Model is not in the list of known models, fallback to the family of the models and mark price as uncertain
|
|
32542
|
+
modelInfo = OPENAI_MODELS.find((model) => (rawResponse.model || SALT_NONCE).startsWith(model.modelName));
|
|
32543
|
+
if (modelInfo !== undefined) {
|
|
32544
|
+
isUncertain = true;
|
|
32545
|
+
}
|
|
32546
|
+
}
|
|
32547
|
+
let price;
|
|
32548
|
+
if (modelInfo === undefined || modelInfo.pricing === undefined) {
|
|
32549
|
+
price = uncertainNumber();
|
|
32550
|
+
}
|
|
32551
|
+
else {
|
|
32552
|
+
price = uncertainNumber(inputTokens * modelInfo.pricing.prompt + outputTokens * modelInfo.pricing.output, isUncertain);
|
|
32553
|
+
}
|
|
32554
|
+
return {
|
|
32555
|
+
price,
|
|
32556
|
+
duration,
|
|
32557
|
+
input: {
|
|
32558
|
+
tokensCount: uncertainNumber(rawResponse.usage.prompt_tokens),
|
|
32559
|
+
...computeUsageCounts(promptContent),
|
|
32560
|
+
},
|
|
32561
|
+
output: {
|
|
32562
|
+
tokensCount: uncertainNumber(outputTokens),
|
|
32563
|
+
...computeUsageCounts(resultContent),
|
|
32564
|
+
},
|
|
32565
|
+
};
|
|
32566
|
+
}
|
|
32567
|
+
// TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
|
|
32568
|
+
|
|
32110
32569
|
/**
|
|
32111
32570
|
* Simple wrapper `new Date().toISOString()`
|
|
32112
32571
|
*
|
|
@@ -32515,78 +32974,6 @@
|
|
|
32515
32974
|
}
|
|
32516
32975
|
}
|
|
32517
32976
|
|
|
32518
|
-
/**
|
|
32519
|
-
* Helper of usage compute
|
|
32520
|
-
*
|
|
32521
|
-
* @param content the content of prompt or response
|
|
32522
|
-
* @returns part of UsageCounts
|
|
32523
|
-
*
|
|
32524
|
-
* @private internal utility of LlmExecutionTools
|
|
32525
|
-
*/
|
|
32526
|
-
function computeUsageCounts(content) {
|
|
32527
|
-
return {
|
|
32528
|
-
charactersCount: { value: countCharacters(content) },
|
|
32529
|
-
wordsCount: { value: countWords(content) },
|
|
32530
|
-
sentencesCount: { value: countSentences(content) },
|
|
32531
|
-
linesCount: { value: countLines(content) },
|
|
32532
|
-
paragraphsCount: { value: countParagraphs(content) },
|
|
32533
|
-
pagesCount: { value: countPages(content) },
|
|
32534
|
-
};
|
|
32535
|
-
}
|
|
32536
|
-
|
|
32537
|
-
/**
|
|
32538
|
-
* Computes the usage of the OpenAI API based on the response from OpenAI
|
|
32539
|
-
*
|
|
32540
|
-
* @param promptContent The content of the prompt
|
|
32541
|
-
* @param resultContent The content of the result (for embedding prompts or failed prompts pass empty string)
|
|
32542
|
-
* @param rawResponse The raw response from OpenAI API
|
|
32543
|
-
* @param duration The duration of the execution
|
|
32544
|
-
* @throws {PipelineExecutionError} If the usage is not defined in the response from OpenAI
|
|
32545
|
-
*
|
|
32546
|
-
* @private internal utility of `OpenAiExecutionTools`
|
|
32547
|
-
*/
|
|
32548
|
-
function computeOpenAiUsage(promptContent, // <- Note: Intentionally using [] to access type properties to bring jsdoc from Prompt/PromptResult to consumer
|
|
32549
|
-
resultContent, rawResponse, duration = ZERO_VALUE) {
|
|
32550
|
-
var _a, _b;
|
|
32551
|
-
if (rawResponse.usage === undefined) {
|
|
32552
|
-
throw new PipelineExecutionError('The usage is not defined in the response from OpenAI');
|
|
32553
|
-
}
|
|
32554
|
-
if (((_a = rawResponse.usage) === null || _a === void 0 ? void 0 : _a.prompt_tokens) === undefined) {
|
|
32555
|
-
throw new PipelineExecutionError('In OpenAI response `usage.prompt_tokens` not defined');
|
|
32556
|
-
}
|
|
32557
|
-
const inputTokens = rawResponse.usage.prompt_tokens;
|
|
32558
|
-
const outputTokens = ((_b = rawResponse.usage) === null || _b === void 0 ? void 0 : _b.completion_tokens) || 0;
|
|
32559
|
-
let isUncertain = false;
|
|
32560
|
-
let modelInfo = OPENAI_MODELS.find((model) => model.modelName === rawResponse.model);
|
|
32561
|
-
if (modelInfo === undefined) {
|
|
32562
|
-
// Note: Model is not in the list of known models, fallback to the family of the models and mark price as uncertain
|
|
32563
|
-
modelInfo = OPENAI_MODELS.find((model) => (rawResponse.model || SALT_NONCE).startsWith(model.modelName));
|
|
32564
|
-
if (modelInfo !== undefined) {
|
|
32565
|
-
isUncertain = true;
|
|
32566
|
-
}
|
|
32567
|
-
}
|
|
32568
|
-
let price;
|
|
32569
|
-
if (modelInfo === undefined || modelInfo.pricing === undefined) {
|
|
32570
|
-
price = uncertainNumber();
|
|
32571
|
-
}
|
|
32572
|
-
else {
|
|
32573
|
-
price = uncertainNumber(inputTokens * modelInfo.pricing.prompt + outputTokens * modelInfo.pricing.output, isUncertain);
|
|
32574
|
-
}
|
|
32575
|
-
return {
|
|
32576
|
-
price,
|
|
32577
|
-
duration,
|
|
32578
|
-
input: {
|
|
32579
|
-
tokensCount: uncertainNumber(rawResponse.usage.prompt_tokens),
|
|
32580
|
-
...computeUsageCounts(promptContent),
|
|
32581
|
-
},
|
|
32582
|
-
output: {
|
|
32583
|
-
tokensCount: uncertainNumber(outputTokens),
|
|
32584
|
-
...computeUsageCounts(resultContent),
|
|
32585
|
-
},
|
|
32586
|
-
};
|
|
32587
|
-
}
|
|
32588
|
-
// TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
|
|
32589
|
-
|
|
32590
32977
|
/**
|
|
32591
32978
|
* Finds the best hardcoded-model match for one API-listed model identifier.
|
|
32592
32979
|
*/
|
|
@@ -43044,18 +43431,6 @@
|
|
|
43044
43431
|
const $llmToolsMetadataRegister = new $Register('llm_tools_metadata');
|
|
43045
43432
|
// TODO: [®] DRY Register logic
|
|
43046
43433
|
|
|
43047
|
-
/**
|
|
43048
|
-
* Register for LLM tools.
|
|
43049
|
-
*
|
|
43050
|
-
* Note: `$` is used to indicate that this interacts with the global scope
|
|
43051
|
-
*
|
|
43052
|
-
* @singleton Only one instance of each register is created per build, but there can be more instances across different builds or environments.
|
|
43053
|
-
*
|
|
43054
|
-
* @public exported from `@promptbook/core`
|
|
43055
|
-
*/
|
|
43056
|
-
const $llmToolsRegister = new $Register('llm_execution_tools_constructors');
|
|
43057
|
-
// TODO: [®] DRY Register logic
|
|
43058
|
-
|
|
43059
43434
|
/**
|
|
43060
43435
|
* Path to the `.env` file which was used to configure LLM tools
|
|
43061
43436
|
*
|
|
@@ -43063,61 +43438,53 @@
|
|
|
43063
43438
|
*/
|
|
43064
43439
|
let $usedEnvFilename = null;
|
|
43065
43440
|
/**
|
|
43066
|
-
*
|
|
43067
|
-
*
|
|
43068
|
-
* Note: `$` is used to indicate that this variable is making side effect
|
|
43069
|
-
*
|
|
43070
|
-
* @private internal log of `$provideLlmToolsConfigurationFromEnv` and `$registeredLlmToolsMessage`
|
|
43071
|
-
*/
|
|
43072
|
-
function $setUsedEnvFilename(filepath) {
|
|
43073
|
-
$usedEnvFilename = filepath;
|
|
43074
|
-
}
|
|
43075
|
-
/**
|
|
43076
|
-
* Creates a message with all registered LLM tools
|
|
43077
|
-
*
|
|
43078
|
-
* Note: This function is used to create a (error) message when there is no constructor for some LLM provider
|
|
43079
|
-
*
|
|
43080
|
-
* @private internal function of `createLlmToolsFromConfiguration` and `$provideLlmToolsFromEnv`
|
|
43081
|
-
*/
|
|
43082
|
-
function $registeredLlmToolsMessage() {
|
|
43083
|
-
const registeredLlmToolsMessageContext = createRegisteredLlmToolsMessageContext();
|
|
43084
|
-
if (registeredLlmToolsMessageContext.llmToolStatuses.length === 0) {
|
|
43085
|
-
return renderNoRegisteredLlmToolsMessage(registeredLlmToolsMessageContext.usedEnvMessage);
|
|
43086
|
-
}
|
|
43087
|
-
return renderRegisteredLlmToolsMessage(registeredLlmToolsMessageContext);
|
|
43088
|
-
}
|
|
43089
|
-
/**
|
|
43090
|
-
* Collects all state needed to render the provider summary.
|
|
43441
|
+
* Shared state for the `.env` file used to configure LLM tools.
|
|
43091
43442
|
*
|
|
43092
|
-
* @private internal
|
|
43443
|
+
* @private internal state of `$registeredLlmToolsMessage`
|
|
43093
43444
|
*/
|
|
43094
|
-
|
|
43095
|
-
|
|
43096
|
-
|
|
43097
|
-
|
|
43098
|
-
|
|
43099
|
-
|
|
43100
|
-
|
|
43101
|
-
|
|
43102
|
-
|
|
43103
|
-
|
|
43104
|
-
|
|
43445
|
+
const USED_ENV_FILENAME = {
|
|
43446
|
+
set(filepath) {
|
|
43447
|
+
$usedEnvFilename = filepath;
|
|
43448
|
+
},
|
|
43449
|
+
createMessage() {
|
|
43450
|
+
return $usedEnvFilename === null
|
|
43451
|
+
? `Unknown \`.env\` file`
|
|
43452
|
+
: _spaceTrim.spaceTrim(`
|
|
43453
|
+
Used \`.env\` file:
|
|
43454
|
+
${$usedEnvFilename}
|
|
43455
|
+
`);
|
|
43456
|
+
},
|
|
43457
|
+
};
|
|
43458
|
+
|
|
43105
43459
|
/**
|
|
43106
43460
|
* Reads environment variables relevant for provider configuration.
|
|
43107
43461
|
*
|
|
43108
|
-
* @private
|
|
43462
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43109
43463
|
*/
|
|
43110
|
-
function
|
|
43464
|
+
function getAvailableRegisteredLlmToolsEnvironmentVariables(isRunningInNode) {
|
|
43111
43465
|
if (isRunningInNode) {
|
|
43112
43466
|
return process.env;
|
|
43113
43467
|
// <- TODO: [⚛] Some DRY way how to get to `process.env` and pass it into functions - ACRY search for `env`
|
|
43114
43468
|
}
|
|
43115
43469
|
return {};
|
|
43116
43470
|
}
|
|
43471
|
+
|
|
43472
|
+
/**
|
|
43473
|
+
* Register for LLM tools.
|
|
43474
|
+
*
|
|
43475
|
+
* Note: `$` is used to indicate that this interacts with the global scope
|
|
43476
|
+
*
|
|
43477
|
+
* @singleton Only one instance of each register is created per build, but there can be more instances across different builds or environments.
|
|
43478
|
+
*
|
|
43479
|
+
* @public exported from `@promptbook/core`
|
|
43480
|
+
*/
|
|
43481
|
+
const $llmToolsRegister = new $Register('llm_execution_tools_constructors');
|
|
43482
|
+
// TODO: [®] DRY Register logic
|
|
43483
|
+
|
|
43117
43484
|
/**
|
|
43118
43485
|
* Takes stable snapshots of both LLM provider registers.
|
|
43119
43486
|
*
|
|
43120
|
-
* @private
|
|
43487
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43121
43488
|
*/
|
|
43122
43489
|
function getRegisteredLlmToolRegisters() {
|
|
43123
43490
|
return {
|
|
@@ -43125,62 +43492,30 @@
|
|
|
43125
43492
|
registeredTools: $llmToolsRegister.list(),
|
|
43126
43493
|
};
|
|
43127
43494
|
}
|
|
43128
|
-
|
|
43129
|
-
* Lists provider entries enriched with installation and configuration state.
|
|
43130
|
-
*
|
|
43131
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43132
|
-
*/
|
|
43133
|
-
function listRegisteredLlmToolStatuses({ registeredMetadata, registeredTools }, env) {
|
|
43134
|
-
return listRegisteredLlmToolEntries(registeredMetadata, registeredTools).map((registeredLlmToolEntry) => createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env }));
|
|
43135
|
-
}
|
|
43136
|
-
/**
|
|
43137
|
-
* Merges provider entries from the metadata and constructor registers.
|
|
43138
|
-
*
|
|
43139
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43140
|
-
*/
|
|
43141
|
-
function listRegisteredLlmToolEntries(registeredMetadata, registeredTools) {
|
|
43142
|
-
const registeredLlmToolEntries = new Map();
|
|
43143
|
-
for (const { title, packageName, className, envVariables } of registeredMetadata) {
|
|
43144
|
-
addRegisteredLlmToolEntry(registeredLlmToolEntries, { title, packageName, className, envVariables });
|
|
43145
|
-
}
|
|
43146
|
-
for (const { packageName, className } of registeredTools) {
|
|
43147
|
-
addRegisteredLlmToolEntry(registeredLlmToolEntries, { packageName, className });
|
|
43148
|
-
}
|
|
43149
|
-
return [...registeredLlmToolEntries.values()];
|
|
43150
|
-
}
|
|
43151
|
-
/**
|
|
43152
|
-
* Adds a provider entry only when the provider is not already present.
|
|
43153
|
-
*
|
|
43154
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43155
|
-
*/
|
|
43156
|
-
function addRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43157
|
-
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43158
|
-
if (registeredLlmToolEntries.has(registeredLlmToolEntryKey)) {
|
|
43159
|
-
return;
|
|
43160
|
-
}
|
|
43161
|
-
registeredLlmToolEntries.set(registeredLlmToolEntryKey, registeredLlmToolEntry);
|
|
43162
|
-
}
|
|
43495
|
+
|
|
43163
43496
|
/**
|
|
43164
43497
|
* Creates a deduplication key for a provider entry.
|
|
43165
43498
|
*
|
|
43166
|
-
* @private
|
|
43499
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43167
43500
|
*/
|
|
43168
43501
|
function createRegisteredLlmToolEntryKey({ packageName, className }) {
|
|
43169
43502
|
return `${packageName}::${className}`;
|
|
43170
43503
|
}
|
|
43504
|
+
|
|
43171
43505
|
/**
|
|
43172
43506
|
* Checks whether the given provider entry already exists in the target register list.
|
|
43173
43507
|
*
|
|
43174
|
-
* @private
|
|
43508
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43175
43509
|
*/
|
|
43176
43510
|
function hasRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43177
43511
|
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43178
43512
|
return registeredLlmToolEntries.some((listedRegisteredLlmToolEntry) => createRegisteredLlmToolEntryKey(listedRegisteredLlmToolEntry) === registeredLlmToolEntryKey);
|
|
43179
43513
|
}
|
|
43514
|
+
|
|
43180
43515
|
/**
|
|
43181
43516
|
* Builds the runtime status for one provider entry.
|
|
43182
43517
|
*
|
|
43183
|
-
* @private
|
|
43518
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43184
43519
|
*/
|
|
43185
43520
|
function createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env, }) {
|
|
43186
43521
|
const availabilityStatus = createRegisteredLlmToolAvailabilityStatus(registeredLlmToolEntry, registeredMetadata, registeredTools);
|
|
@@ -43194,7 +43529,7 @@
|
|
|
43194
43529
|
/**
|
|
43195
43530
|
* Resolves whether the provider has metadata and a registered constructor.
|
|
43196
43531
|
*
|
|
43197
|
-
* @private
|
|
43532
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43198
43533
|
*/
|
|
43199
43534
|
function createRegisteredLlmToolAvailabilityStatus(registeredLlmToolEntry, registeredMetadata, registeredTools) {
|
|
43200
43535
|
return {
|
|
@@ -43205,7 +43540,7 @@
|
|
|
43205
43540
|
/**
|
|
43206
43541
|
* Resolves whether the provider has enough environment variables to be configured.
|
|
43207
43542
|
*
|
|
43208
|
-
* @private
|
|
43543
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43209
43544
|
*/
|
|
43210
43545
|
function createRegisteredLlmToolConfigurationStatus({ envVariables }, env) {
|
|
43211
43546
|
return {
|
|
@@ -43216,7 +43551,7 @@
|
|
|
43216
43551
|
/**
|
|
43217
43552
|
* Checks whether all required environment variables are present for a provider.
|
|
43218
43553
|
*
|
|
43219
|
-
* @private
|
|
43554
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43220
43555
|
*/
|
|
43221
43556
|
function isRegisteredLlmToolFullyConfigured(envVariables, env) {
|
|
43222
43557
|
if (envVariables === undefined || envVariables === null) {
|
|
@@ -43227,7 +43562,7 @@
|
|
|
43227
43562
|
/**
|
|
43228
43563
|
* Checks whether at least one required environment variable is present for a provider.
|
|
43229
43564
|
*
|
|
43230
|
-
* @private
|
|
43565
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43231
43566
|
*/
|
|
43232
43567
|
function isRegisteredLlmToolPartiallyConfigured(envVariables, env) {
|
|
43233
43568
|
if (envVariables === undefined || envVariables === null) {
|
|
@@ -43235,109 +43570,128 @@
|
|
|
43235
43570
|
}
|
|
43236
43571
|
return envVariables.some((envVariableName) => env[envVariableName] !== undefined);
|
|
43237
43572
|
}
|
|
43573
|
+
|
|
43238
43574
|
/**
|
|
43239
|
-
*
|
|
43575
|
+
* Merges provider entries from the metadata and constructor registers.
|
|
43240
43576
|
*
|
|
43241
|
-
* @private
|
|
43577
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43242
43578
|
*/
|
|
43243
|
-
function
|
|
43244
|
-
|
|
43245
|
-
|
|
43246
|
-
|
|
43247
|
-
|
|
43248
|
-
|
|
43579
|
+
function listRegisteredLlmToolEntries(registeredMetadata, registeredTools) {
|
|
43580
|
+
const registeredLlmToolEntries = new Map();
|
|
43581
|
+
for (const { title, packageName, className, envVariables } of registeredMetadata) {
|
|
43582
|
+
addRegisteredLlmToolEntry(registeredLlmToolEntries, { title, packageName, className, envVariables });
|
|
43583
|
+
}
|
|
43584
|
+
for (const { packageName, className } of registeredTools) {
|
|
43585
|
+
addRegisteredLlmToolEntry(registeredLlmToolEntries, { packageName, className });
|
|
43586
|
+
}
|
|
43587
|
+
return [...registeredLlmToolEntries.values()];
|
|
43249
43588
|
}
|
|
43250
43589
|
/**
|
|
43251
|
-
*
|
|
43590
|
+
* Adds a provider entry only when the provider is not already present.
|
|
43252
43591
|
*
|
|
43253
|
-
* @private
|
|
43592
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43254
43593
|
*/
|
|
43255
|
-
function
|
|
43256
|
-
|
|
43257
|
-
|
|
43258
|
-
|
|
43259
|
-
|
|
43260
|
-
|
|
43261
|
-
${block(renderRelevantEnvironmentVariables(env, llmToolStatuses))}
|
|
43262
|
-
|
|
43263
|
-
Available LLM providers are:
|
|
43264
|
-
${block(renderAvailableProviders(llmToolStatuses, env, isRunningInNode))}
|
|
43265
|
-
`);
|
|
43594
|
+
function addRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43595
|
+
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43596
|
+
if (registeredLlmToolEntries.has(registeredLlmToolEntryKey)) {
|
|
43597
|
+
return;
|
|
43598
|
+
}
|
|
43599
|
+
registeredLlmToolEntries.set(registeredLlmToolEntryKey, registeredLlmToolEntry);
|
|
43266
43600
|
}
|
|
43601
|
+
|
|
43267
43602
|
/**
|
|
43268
|
-
*
|
|
43603
|
+
* Lists provider entries enriched with installation and configuration state.
|
|
43269
43604
|
*
|
|
43270
|
-
* @private
|
|
43605
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43271
43606
|
*/
|
|
43272
|
-
function
|
|
43273
|
-
return
|
|
43274
|
-
.map((envVariableName) => `- \`${envVariableName}\``)
|
|
43275
|
-
.join('\n');
|
|
43607
|
+
function listRegisteredLlmToolStatuses({ registeredMetadata, registeredTools }, env) {
|
|
43608
|
+
return listRegisteredLlmToolEntries(registeredMetadata, registeredTools).map((registeredLlmToolEntry) => createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env }));
|
|
43276
43609
|
}
|
|
43610
|
+
|
|
43277
43611
|
/**
|
|
43278
|
-
*
|
|
43612
|
+
* Collects all state needed to render the provider summary.
|
|
43279
43613
|
*
|
|
43280
|
-
* @private
|
|
43614
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43281
43615
|
*/
|
|
43282
|
-
function
|
|
43283
|
-
|
|
43616
|
+
function createRegisteredLlmToolsMessageContext() {
|
|
43617
|
+
const isRunningInNode = $isRunningInNode();
|
|
43618
|
+
const env = getAvailableRegisteredLlmToolsEnvironmentVariables(isRunningInNode);
|
|
43619
|
+
const registeredLlmToolRegisters = getRegisteredLlmToolRegisters();
|
|
43620
|
+
return {
|
|
43621
|
+
env,
|
|
43622
|
+
llmToolStatuses: listRegisteredLlmToolStatuses(registeredLlmToolRegisters, env),
|
|
43623
|
+
usedEnvMessage: USED_ENV_FILENAME.createMessage(),
|
|
43624
|
+
isRunningInNode,
|
|
43625
|
+
};
|
|
43284
43626
|
}
|
|
43627
|
+
|
|
43285
43628
|
/**
|
|
43286
|
-
* Renders
|
|
43629
|
+
* Renders the fallback message for environments with no registered providers.
|
|
43287
43630
|
*
|
|
43288
|
-
* @private
|
|
43631
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43289
43632
|
*/
|
|
43290
|
-
function
|
|
43291
|
-
return
|
|
43292
|
-
|
|
43293
|
-
|
|
43633
|
+
function renderNoRegisteredLlmToolsMessage(usedEnvMessage) {
|
|
43634
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
43635
|
+
No LLM providers are available.
|
|
43636
|
+
|
|
43637
|
+
${block(usedEnvMessage)}
|
|
43638
|
+
`);
|
|
43294
43639
|
}
|
|
43640
|
+
|
|
43295
43641
|
/**
|
|
43296
|
-
*
|
|
43642
|
+
* Creates the configuration-status sentence for one provider.
|
|
43297
43643
|
*
|
|
43298
|
-
* @private
|
|
43644
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43299
43645
|
*/
|
|
43300
|
-
function
|
|
43301
|
-
|
|
43302
|
-
|
|
43303
|
-
|
|
43646
|
+
function createRegisteredLlmToolConfigurationStatusMessage({ envVariables, isFullyConfigured, isPartiallyConfigured }, env) {
|
|
43647
|
+
if (isFullyConfigured) {
|
|
43648
|
+
return `Configured`;
|
|
43649
|
+
}
|
|
43650
|
+
if (isPartiallyConfigured) {
|
|
43651
|
+
return createPartiallyConfiguredStatusMessage(envVariables, env);
|
|
43652
|
+
}
|
|
43653
|
+
if (envVariables !== null) {
|
|
43654
|
+
return createNotConfiguredStatusMessage(envVariables);
|
|
43304
43655
|
}
|
|
43305
|
-
return
|
|
43656
|
+
return `Not configured`;
|
|
43657
|
+
// <- Note: Can not be configured via environment variables
|
|
43306
43658
|
}
|
|
43307
43659
|
/**
|
|
43308
|
-
* Creates the
|
|
43660
|
+
* Creates the partial-configuration sentence including missing variables.
|
|
43309
43661
|
*
|
|
43310
|
-
* @private
|
|
43662
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43311
43663
|
*/
|
|
43312
|
-
function
|
|
43313
|
-
|
|
43314
|
-
const providerStatusMessages = createProviderStatusMessages(llmToolStatus, env);
|
|
43315
|
-
return _spaceTrim.spaceTrim(`
|
|
43316
|
-
${index + 1}) **${title}** \`${className}\` from \`${packageName}\`
|
|
43317
|
-
${providerStatusMessages.join('; ')}
|
|
43318
|
-
`);
|
|
43664
|
+
function createPartiallyConfiguredStatusMessage(envVariables, env) {
|
|
43665
|
+
return `Partially confugured, missing ${listMissingEnvironmentVariables(envVariables, env).join(' + ')}`;
|
|
43319
43666
|
}
|
|
43320
43667
|
/**
|
|
43321
|
-
* Creates the
|
|
43668
|
+
* Creates the not-configured sentence including the expected environment variables.
|
|
43322
43669
|
*
|
|
43323
|
-
* @private
|
|
43670
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43324
43671
|
*/
|
|
43325
|
-
function
|
|
43326
|
-
return
|
|
43672
|
+
function createNotConfiguredStatusMessage(envVariables) {
|
|
43673
|
+
return `Not configured, to configure set env ${envVariables === null || envVariables === void 0 ? void 0 : envVariables.join(' + ')}`;
|
|
43674
|
+
}
|
|
43675
|
+
/**
|
|
43676
|
+
* Lists environment variables that are required but currently missing.
|
|
43677
|
+
*
|
|
43678
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43679
|
+
*/
|
|
43680
|
+
function listMissingEnvironmentVariables(envVariables, env) {
|
|
43681
|
+
return (envVariables === null || envVariables === void 0 ? void 0 : envVariables.filter((envVariable) => env[envVariable] === undefined)) || [];
|
|
43327
43682
|
}
|
|
43683
|
+
|
|
43328
43684
|
/**
|
|
43329
43685
|
* Creates the installation-status sentence for one provider.
|
|
43330
43686
|
*
|
|
43331
|
-
* @private
|
|
43687
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43332
43688
|
*/
|
|
43333
|
-
function
|
|
43334
|
-
const installationStatusKey =
|
|
43689
|
+
function createRegisteredLlmToolInstallationStatusMessage({ isMetadataAvailable, isInstalled, }) {
|
|
43690
|
+
const installationStatusKey = createRegisteredLlmToolInstallationStatusKey(isMetadataAvailable, isInstalled);
|
|
43335
43691
|
switch (installationStatusKey) {
|
|
43336
43692
|
case 'missing-metadata-and-installation':
|
|
43337
|
-
// TODO: [�][�] Maybe do allow to do auto-install if package not registered and not found
|
|
43338
43693
|
return `Not installed and no metadata, looks like a unexpected behavior`;
|
|
43339
43694
|
case 'metadata-without-installation':
|
|
43340
|
-
// TODO: [�][�]
|
|
43341
43695
|
return `Not installed`;
|
|
43342
43696
|
case 'installation-without-metadata':
|
|
43343
43697
|
return `No metadata but installed, looks like a unexpected behavior`;
|
|
@@ -43350,9 +43704,9 @@
|
|
|
43350
43704
|
/**
|
|
43351
43705
|
* Creates a stable installation-state key from metadata and constructor availability.
|
|
43352
43706
|
*
|
|
43353
|
-
* @private
|
|
43707
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43354
43708
|
*/
|
|
43355
|
-
function
|
|
43709
|
+
function createRegisteredLlmToolInstallationStatusKey(isMetadataAvailable, isInstalled) {
|
|
43356
43710
|
if (!isMetadataAvailable && !isInstalled) {
|
|
43357
43711
|
return 'missing-metadata-and-installation';
|
|
43358
43712
|
}
|
|
@@ -43367,54 +43721,59 @@
|
|
|
43367
43721
|
}
|
|
43368
43722
|
return 'unknown';
|
|
43369
43723
|
}
|
|
43724
|
+
|
|
43370
43725
|
/**
|
|
43371
|
-
*
|
|
43726
|
+
* Renders all provider lines in the status summary.
|
|
43372
43727
|
*
|
|
43373
|
-
* @private
|
|
43728
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43374
43729
|
*/
|
|
43375
|
-
function
|
|
43376
|
-
|
|
43377
|
-
|
|
43378
|
-
|
|
43379
|
-
if (isPartiallyConfigured) {
|
|
43380
|
-
return createPartiallyConfiguredStatusMessage(envVariables, env);
|
|
43381
|
-
}
|
|
43382
|
-
if (envVariables !== null) {
|
|
43383
|
-
return createNotConfiguredStatusMessage(envVariables);
|
|
43384
|
-
}
|
|
43385
|
-
return `Not configured`;
|
|
43386
|
-
// <- Note: Can not be configured via environment variables
|
|
43730
|
+
function renderAvailableRegisteredLlmTools(llmToolStatuses, env, isRunningInNode) {
|
|
43731
|
+
return llmToolStatuses
|
|
43732
|
+
.map((llmToolStatus, index) => renderAvailableRegisteredLlmTool(llmToolStatus, index, env, isRunningInNode))
|
|
43733
|
+
.join('\n');
|
|
43387
43734
|
}
|
|
43388
43735
|
/**
|
|
43389
|
-
*
|
|
43736
|
+
* Renders one provider line in the status summary.
|
|
43390
43737
|
*
|
|
43391
|
-
* @private
|
|
43738
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43392
43739
|
*/
|
|
43393
|
-
function
|
|
43394
|
-
|
|
43740
|
+
function renderAvailableRegisteredLlmTool(llmToolStatus, index, env, isRunningInNode) {
|
|
43741
|
+
const providerMessage = createAvailableRegisteredLlmToolMessage(llmToolStatus, index, env);
|
|
43742
|
+
if (!isRunningInNode) {
|
|
43743
|
+
return providerMessage;
|
|
43744
|
+
}
|
|
43745
|
+
return colorizeAvailableRegisteredLlmToolMessage(providerMessage, llmToolStatus);
|
|
43395
43746
|
}
|
|
43396
43747
|
/**
|
|
43397
|
-
* Creates the
|
|
43748
|
+
* Creates the plain-text provider line before optional colorization.
|
|
43398
43749
|
*
|
|
43399
|
-
* @private
|
|
43750
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43400
43751
|
*/
|
|
43401
|
-
function
|
|
43402
|
-
|
|
43752
|
+
function createAvailableRegisteredLlmToolMessage(llmToolStatus, index, env) {
|
|
43753
|
+
const { title, packageName, className } = llmToolStatus;
|
|
43754
|
+
const providerStatusMessages = createRegisteredLlmToolStatusMessages(llmToolStatus, env);
|
|
43755
|
+
return _spaceTrim.spaceTrim(`
|
|
43756
|
+
${index + 1}) **${title}** \`${className}\` from \`${packageName}\`
|
|
43757
|
+
${providerStatusMessages.join('; ')}
|
|
43758
|
+
`);
|
|
43403
43759
|
}
|
|
43404
43760
|
/**
|
|
43405
|
-
*
|
|
43761
|
+
* Creates the install and configuration fragments for one provider line.
|
|
43406
43762
|
*
|
|
43407
|
-
* @private
|
|
43763
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43408
43764
|
*/
|
|
43409
|
-
function
|
|
43410
|
-
return
|
|
43765
|
+
function createRegisteredLlmToolStatusMessages(llmToolStatus, env) {
|
|
43766
|
+
return [
|
|
43767
|
+
createRegisteredLlmToolInstallationStatusMessage(llmToolStatus),
|
|
43768
|
+
createRegisteredLlmToolConfigurationStatusMessage(llmToolStatus, env),
|
|
43769
|
+
];
|
|
43411
43770
|
}
|
|
43412
43771
|
/**
|
|
43413
43772
|
* Applies the same terminal coloring rules as the original summary renderer.
|
|
43414
43773
|
*
|
|
43415
|
-
* @private
|
|
43774
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43416
43775
|
*/
|
|
43417
|
-
function
|
|
43776
|
+
function colorizeAvailableRegisteredLlmToolMessage(providerMessage, { isInstalled, isFullyConfigured, isPartiallyConfigured }) {
|
|
43418
43777
|
if (isInstalled && isFullyConfigured) {
|
|
43419
43778
|
return colors__default["default"].green(providerMessage);
|
|
43420
43779
|
}
|
|
@@ -43423,18 +43782,67 @@
|
|
|
43423
43782
|
}
|
|
43424
43783
|
return colors__default["default"].gray(providerMessage);
|
|
43425
43784
|
}
|
|
43785
|
+
|
|
43426
43786
|
/**
|
|
43427
|
-
*
|
|
43787
|
+
* Renders the list of environment variables used by at least one registered provider.
|
|
43428
43788
|
*
|
|
43429
|
-
* @private
|
|
43789
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43430
43790
|
*/
|
|
43431
|
-
function
|
|
43432
|
-
return
|
|
43433
|
-
|
|
43434
|
-
|
|
43435
|
-
|
|
43436
|
-
|
|
43437
|
-
|
|
43791
|
+
function renderRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses) {
|
|
43792
|
+
return listRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses)
|
|
43793
|
+
.map((envVariableName) => `- \`${envVariableName}\``)
|
|
43794
|
+
.join('\n');
|
|
43795
|
+
}
|
|
43796
|
+
/**
|
|
43797
|
+
* Lists environment variables that are both present and used by at least one provider.
|
|
43798
|
+
*
|
|
43799
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43800
|
+
*/
|
|
43801
|
+
function listRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses) {
|
|
43802
|
+
return Object.keys(env).filter((envVariableName) => llmToolStatuses.some(({ envVariables }) => envVariables === null || envVariables === void 0 ? void 0 : envVariables.includes(envVariableName)));
|
|
43803
|
+
}
|
|
43804
|
+
|
|
43805
|
+
/**
|
|
43806
|
+
* Renders the full provider status summary.
|
|
43807
|
+
*
|
|
43808
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43809
|
+
*/
|
|
43810
|
+
function renderRegisteredLlmToolsMessage({ env, llmToolStatuses, usedEnvMessage, isRunningInNode, }) {
|
|
43811
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
43812
|
+
|
|
43813
|
+
${block(usedEnvMessage)}
|
|
43814
|
+
|
|
43815
|
+
Relevant environment variables:
|
|
43816
|
+
${block(renderRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses))}
|
|
43817
|
+
|
|
43818
|
+
Available LLM providers are:
|
|
43819
|
+
${block(renderAvailableRegisteredLlmTools(llmToolStatuses, env, isRunningInNode))}
|
|
43820
|
+
`);
|
|
43821
|
+
}
|
|
43822
|
+
|
|
43823
|
+
/**
|
|
43824
|
+
* Pass the `.env` file which was used to configure LLM tools
|
|
43825
|
+
*
|
|
43826
|
+
* Note: `$` is used to indicate that this variable is making side effect
|
|
43827
|
+
*
|
|
43828
|
+
* @private internal log of `$provideLlmToolsConfigurationFromEnv` and `$registeredLlmToolsMessage`
|
|
43829
|
+
*/
|
|
43830
|
+
function $setUsedEnvFilename(filepath) {
|
|
43831
|
+
USED_ENV_FILENAME.set(filepath);
|
|
43832
|
+
}
|
|
43833
|
+
/**
|
|
43834
|
+
* Creates a message with all registered LLM tools
|
|
43835
|
+
*
|
|
43836
|
+
* Note: This function is used to create a (error) message when there is no constructor for some LLM provider
|
|
43837
|
+
*
|
|
43838
|
+
* @private internal function of `createLlmToolsFromConfiguration` and `$provideLlmToolsFromEnv`
|
|
43839
|
+
*/
|
|
43840
|
+
function $registeredLlmToolsMessage() {
|
|
43841
|
+
const registeredLlmToolsMessageContext = createRegisteredLlmToolsMessageContext();
|
|
43842
|
+
if (registeredLlmToolsMessageContext.llmToolStatuses.length === 0) {
|
|
43843
|
+
return renderNoRegisteredLlmToolsMessage(registeredLlmToolsMessageContext.usedEnvMessage);
|
|
43844
|
+
}
|
|
43845
|
+
return renderRegisteredLlmToolsMessage(registeredLlmToolsMessageContext);
|
|
43438
43846
|
}
|
|
43439
43847
|
// TODO: [®] DRY Register logic
|
|
43440
43848
|
// TODO: [🧠][⚛] Maybe pass env as argument
|