@promptbook/node 0.113.0-8 → 0.114.0-0
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 +4 -3
- package/esm/book/scripts/import-markdown/increaseHeadings.d.ts +8 -0
- package/esm/index.es.js +1975 -1267
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-agent-messages/messages/buildAgentMessagePrompt.d.ts +6 -1
- package/esm/scripts/run-agent-messages/messages/buildAgentProjectsPromptSection.d.ts +39 -0
- package/esm/scripts/run-codex-prompts/common/parseDuration.d.ts +19 -0
- package/esm/scripts/run-codex-prompts/common/waitUntilWorldTimeDeadline.d.ts +27 -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/scripts/run-codex-prompts/runners/openai-codex/parseCodexLoginMethodFromOutput.d.ts +10 -0
- package/esm/src/_packages/components.index.d.ts +8 -0
- package/esm/src/_packages/core.index.d.ts +4 -0
- package/esm/src/_packages/types.index.d.ts +14 -2
- package/esm/src/avatars/renderAvatarVisualAsciiArt.d.ts +24 -1
- package/esm/src/avatars/visuals/octopus3dAvatarVisualShared.d.ts +1 -1
- package/esm/src/book-2.0/agent-source/AgentBasicInformation.d.ts +7 -0
- package/esm/src/book-2.0/agent-source/parseAgentSource/ParsedAgentProfile.d.ts +1 -1
- package/esm/src/book-2.0/book-language-documentation/BookLanguageDocumentationExample.d.ts +5 -13
- package/esm/src/book-2.0/book-language-documentation/BookLanguageManualDictionary.d.ts +195 -0
- package/esm/src/book-2.0/book-language-documentation/bookLanguageDocumentationExamples.d.ts +2 -1
- package/esm/src/book-2.0/book-language-documentation/createStandaloneBookLanguageMarkdown.d.ts +43 -1
- package/esm/src/book-2.0/book-language-documentation/czechBookLanguageManualDictionary.d.ts +10 -0
- package/esm/src/book-2.0/book-language-documentation/englishBookLanguageManualDictionary.d.ts +10 -0
- package/esm/src/book-2.0/book-language-documentation/getBookLanguageManualCommitmentGroups.d.ts +33 -0
- package/esm/src/book-2.0/book-language-documentation/getBookLanguageManualDictionary.d.ts +15 -0
- package/esm/src/book-2.0/book-language-documentation/getSafeCodeBlock.d.ts +10 -0
- package/esm/src/book-2.0/book-language-documentation/renderCommitmentCatalogSection.d.ts +30 -0
- package/esm/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.d.ts +2 -1
- package/esm/src/book-2.0/book-language-documentation/toStableAnchorId.d.ts +12 -0
- package/esm/src/book-3.0/AgentMessageRunReport.d.ts +78 -0
- package/esm/src/book-3.0/agentFolderPaths.d.ts +9 -0
- package/esm/src/book-3.0/codexLoginMethod.d.ts +38 -0
- package/esm/src/book-components/BookEditor/BookEditorMonacoUploadPanel.d.ts +1 -1
- package/esm/src/book-components/BookEditor/BookEditorSyntaxTokenStyles.d.ts +39 -0
- package/esm/src/book-components/BookEditor/createBookSourceHighlightStyles.d.ts +12 -0
- package/esm/src/book-components/BookEditor/highlightBookSourceToHtml.d.ts +20 -0
- 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/ChatCitationModal.d.ts +5 -0
- package/esm/src/book-components/Chat/Chat/ChatCitationModal.test.d.ts +2 -0
- package/esm/src/book-components/Chat/Chat/ChatFeedbackStar.d.ts +37 -0
- 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 +5 -1
- package/esm/src/book-components/Chat/Chat/ChatMessageList.d.ts +5 -0
- package/esm/src/book-components/Chat/Chat/ChatMessageRichContent.d.ts +5 -0
- package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +21 -0
- package/esm/src/book-components/Chat/Chat/ChatRatingModal.test.d.ts +2 -0
- package/esm/src/book-components/Chat/Chat/CitationIframePreview.d.ts +25 -2
- package/esm/src/book-components/Chat/Chat/pagePreview/LiveBrowserPreview.d.ts +39 -0
- package/esm/src/book-components/Chat/Chat/pagePreview/LiveBrowserPreview.test.d.ts +2 -0
- package/esm/src/book-components/Chat/Chat/pagePreview/LiveBrowserPreviewToolbar.d.ts +71 -0
- package/esm/src/book-components/Chat/Chat/pagePreview/PagePreviewInputEvent.d.ts +72 -0
- package/esm/src/book-components/Chat/Chat/pagePreview/PagePreviewInputQueue.d.ts +64 -0
- package/esm/src/book-components/Chat/Chat/pagePreview/PagePreviewInputQueue.test.d.ts +1 -0
- package/esm/src/book-components/Chat/Chat/pagePreview/PagePreviewSessionState.d.ts +14 -0
- package/esm/src/book-components/Chat/Chat/pagePreview/PagePreviewViewport.d.ts +37 -0
- package/esm/src/book-components/Chat/Chat/pagePreview/createPagePreviewSessionId.d.ts +20 -0
- package/esm/src/book-components/Chat/Chat/pagePreview/normalizePagePreviewInputEvent.d.ts +13 -0
- package/esm/src/book-components/Chat/Chat/pagePreview/normalizePagePreviewInputEvent.test.d.ts +1 -0
- package/esm/src/book-components/Chat/Chat/resolveChatRatingMessageKey.d.ts +8 -0
- package/esm/src/book-components/Chat/Chat/useChatInputAreaComposer.d.ts +12 -0
- package/esm/src/book-components/Chat/Chat/useChatInputAreaComposer.draftMessage.test.d.ts +2 -0
- package/esm/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +2 -0
- package/esm/src/book-components/Chat/SourceChip/SourceChip.test.d.ts +2 -0
- package/esm/src/book-components/Chat/hooks/useResolvedCitationLabel.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/book-components/Chat/utils/renderMarkdown.d.ts +78 -0
- package/esm/src/book-components/Chat/utils/resolveCitationSourceDisplay.d.ts +149 -0
- package/esm/src/book-components/Chat/utils/thinkingMessageVariants.d.ts +9 -0
- package/esm/src/cli/cli-commands/agent-folder/agentProjectPaths.d.ts +2 -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 +17 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer/AgentsServerChildEnvironment.test.d.ts +1 -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/coder/add.d.ts +36 -0
- package/esm/src/cli/cli-commands/coder/add.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/coder/boilerplateTemplates.d.ts +24 -0
- package/esm/src/cli/cli-commands/coder.d.ts +1 -0
- package/esm/src/cli/cli-commands/common/createNonNegativeIntegerOptionParser.d.ts +10 -0
- package/esm/src/cli/cli-commands/common/harness/$applyHarnessInstallationStatus.d.ts +9 -0
- package/esm/src/cli/cli-commands/common/harness/$askForHarnessInstallationApproval.d.ts +9 -0
- package/esm/src/cli/cli-commands/common/harness/$checkHarnessInstallation.d.ts +10 -0
- package/esm/src/cli/cli-commands/common/harness/$ensureHarnessInstallations.d.ts +13 -0
- package/esm/src/cli/cli-commands/common/harness/$installHarness.d.ts +13 -0
- package/esm/src/cli/cli-commands/common/harness/$resolveInstalledHarnessVersion.d.ts +10 -0
- package/esm/src/cli/cli-commands/common/harness/$resolveLatestHarnessVersion.d.ts +10 -0
- package/esm/src/cli/cli-commands/common/harness/HarnessDefinition.d.ts +40 -0
- package/esm/src/cli/cli-commands/common/harness/HarnessDefinition.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/common/harness/HarnessInstallationStatus.d.ts +35 -0
- package/esm/src/cli/cli-commands/common/harness/buildHarnessInstallCommand.d.ts +10 -0
- package/esm/src/cli/cli-commands/common/harness/extractHarnessVersionFromOutput.d.ts +11 -0
- package/esm/src/cli/cli-commands/common/harness/extractHarnessVersionFromOutput.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/common/harness/formatHarnessInstallationWarning.d.ts +7 -0
- package/esm/src/cli/cli-commands/common/harness/isHarnessVersionOutdated.d.ts +9 -0
- package/esm/src/cli/cli-commands/common/harness/isHarnessVersionOutdated.test.d.ts +1 -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/buildAgentNameOrPermanentIdFilter.d.ts +18 -0
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/buildAgentNameOrPermanentIdFilter.test.d.ts +1 -0
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/prepareAgentSourceForPersistence.d.ts +1 -1
- package/esm/src/commitments/META/META.d.ts +4 -2
- package/esm/src/commitments/META_AVATAR/META_AVATAR.d.ts +9 -4
- package/esm/src/commitments/META_THINKING_MESSAGE/META_THINKING_MESSAGE.d.ts +26 -0
- package/esm/src/commitments/index.d.ts +2 -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/execution/utils/formatUsagePrice.d.ts +12 -0
- package/esm/src/execution/utils/formatUsagePrice.test.d.ts +1 -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/agent-message-runtime/resolveAgentMessageRuntimeActivity.d.ts +16 -0
- package/esm/src/utils/agent-message-runtime/resolveAgentMessageRuntimeActivity.test.d.ts +1 -0
- package/esm/src/utils/agents/resolveAgentAvatarImageUrl.d.ts +2 -2
- package/esm/src/utils/agents/terminalAgentAvatarVisual.d.ts +104 -0
- package/esm/src/utils/agents/terminalAgentAvatarVisual.test.d.ts +1 -0
- package/esm/src/utils/color/Color.d.ts +1 -1
- package/esm/src/utils/html/escapeHtml.d.ts +9 -0
- package/esm/src/utils/markdown/shiftMarkdownHeadingLevels.d.ts +15 -0
- 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 +1979 -1271
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-agent-messages/messages/buildAgentMessagePrompt.d.ts +6 -1
- package/umd/scripts/run-agent-messages/messages/buildAgentProjectsPromptSection.d.ts +39 -0
- package/umd/scripts/run-codex-prompts/common/parseDuration.d.ts +19 -0
- package/umd/scripts/run-codex-prompts/common/waitUntilWorldTimeDeadline.d.ts +27 -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/scripts/run-codex-prompts/runners/openai-codex/parseCodexLoginMethodFromOutput.d.ts +10 -0
- package/umd/src/_packages/components.index.d.ts +8 -0
- package/umd/src/_packages/core.index.d.ts +4 -0
- package/umd/src/_packages/types.index.d.ts +14 -2
- package/umd/src/avatars/renderAvatarVisualAsciiArt.d.ts +24 -1
- package/umd/src/avatars/visuals/octopus3dAvatarVisualShared.d.ts +1 -1
- package/umd/src/book-2.0/agent-source/AgentBasicInformation.d.ts +7 -0
- package/umd/src/book-2.0/agent-source/parseAgentSource/ParsedAgentProfile.d.ts +1 -1
- package/umd/src/book-2.0/book-language-documentation/BookLanguageDocumentationExample.d.ts +5 -13
- package/umd/src/book-2.0/book-language-documentation/BookLanguageManualDictionary.d.ts +195 -0
- package/umd/src/book-2.0/book-language-documentation/bookLanguageDocumentationExamples.d.ts +2 -1
- package/umd/src/book-2.0/book-language-documentation/createStandaloneBookLanguageMarkdown.d.ts +43 -1
- package/umd/src/book-2.0/book-language-documentation/createStandaloneBookLanguageMarkdown.test.d.ts +1 -0
- package/umd/src/book-2.0/book-language-documentation/czechBookLanguageManualDictionary.d.ts +10 -0
- package/umd/src/book-2.0/book-language-documentation/englishBookLanguageManualDictionary.d.ts +10 -0
- package/umd/src/book-2.0/book-language-documentation/getBookLanguageManualCommitmentGroups.d.ts +33 -0
- package/umd/src/book-2.0/book-language-documentation/getBookLanguageManualDictionary.d.ts +15 -0
- package/umd/src/book-2.0/book-language-documentation/getSafeCodeBlock.d.ts +10 -0
- package/umd/src/book-2.0/book-language-documentation/renderCommitmentCatalogSection.d.ts +30 -0
- package/umd/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.d.ts +2 -1
- package/umd/src/book-2.0/book-language-documentation/toStableAnchorId.d.ts +12 -0
- package/umd/src/book-3.0/AgentMessageRunReport.d.ts +78 -0
- package/umd/src/book-3.0/AgentMessageRunReport.test.d.ts +1 -0
- package/umd/src/book-3.0/agentFolderPaths.d.ts +9 -0
- package/umd/src/book-3.0/codexLoginMethod.d.ts +38 -0
- package/umd/src/book-components/BookEditor/BookEditorMonacoUploadPanel.d.ts +1 -1
- package/umd/src/book-components/BookEditor/BookEditorSyntaxTokenStyles.d.ts +39 -0
- package/umd/src/book-components/BookEditor/createBookSourceHighlightStyles.d.ts +12 -0
- package/umd/src/book-components/BookEditor/highlightBookSourceToHtml.d.ts +20 -0
- 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/ChatCitationModal.d.ts +5 -0
- package/umd/src/book-components/Chat/Chat/ChatCitationModal.test.d.ts +2 -0
- package/umd/src/book-components/Chat/Chat/ChatFeedbackStar.d.ts +37 -0
- 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 +5 -1
- package/umd/src/book-components/Chat/Chat/ChatMessageList.d.ts +5 -0
- package/umd/src/book-components/Chat/Chat/ChatMessageRichContent.d.ts +5 -0
- package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +21 -0
- package/umd/src/book-components/Chat/Chat/ChatRatingModal.test.d.ts +2 -0
- package/umd/src/book-components/Chat/Chat/CitationIframePreview.d.ts +25 -2
- package/umd/src/book-components/Chat/Chat/pagePreview/LiveBrowserPreview.d.ts +39 -0
- package/umd/src/book-components/Chat/Chat/pagePreview/LiveBrowserPreview.test.d.ts +2 -0
- package/umd/src/book-components/Chat/Chat/pagePreview/LiveBrowserPreviewToolbar.d.ts +71 -0
- package/umd/src/book-components/Chat/Chat/pagePreview/PagePreviewInputEvent.d.ts +72 -0
- package/umd/src/book-components/Chat/Chat/pagePreview/PagePreviewInputQueue.d.ts +64 -0
- package/umd/src/book-components/Chat/Chat/pagePreview/PagePreviewInputQueue.test.d.ts +1 -0
- package/umd/src/book-components/Chat/Chat/pagePreview/PagePreviewSessionState.d.ts +14 -0
- package/umd/src/book-components/Chat/Chat/pagePreview/PagePreviewViewport.d.ts +37 -0
- package/umd/src/book-components/Chat/Chat/pagePreview/createPagePreviewSessionId.d.ts +20 -0
- package/umd/src/book-components/Chat/Chat/pagePreview/normalizePagePreviewInputEvent.d.ts +13 -0
- package/umd/src/book-components/Chat/Chat/pagePreview/normalizePagePreviewInputEvent.test.d.ts +1 -0
- package/umd/src/book-components/Chat/Chat/resolveChatRatingMessageKey.d.ts +8 -0
- package/umd/src/book-components/Chat/Chat/useChatInputAreaComposer.d.ts +12 -0
- package/umd/src/book-components/Chat/Chat/useChatInputAreaComposer.draftMessage.test.d.ts +2 -0
- package/umd/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +2 -0
- package/umd/src/book-components/Chat/SourceChip/SourceChip.test.d.ts +2 -0
- package/umd/src/book-components/Chat/hooks/useResolvedCitationLabel.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/book-components/Chat/utils/renderMarkdown.d.ts +78 -0
- package/umd/src/book-components/Chat/utils/resolveCitationSourceDisplay.d.ts +149 -0
- package/umd/src/book-components/Chat/utils/thinkingMessageVariants.d.ts +9 -0
- package/umd/src/cli/cli-commands/agent-folder/agentProjectPaths.d.ts +2 -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 +17 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer/AgentsServerChildEnvironment.test.d.ts +1 -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/coder/add.d.ts +36 -0
- package/umd/src/cli/cli-commands/coder/add.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/coder/boilerplateTemplates.d.ts +24 -0
- package/umd/src/cli/cli-commands/coder.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/createNonNegativeIntegerOptionParser.d.ts +10 -0
- package/umd/src/cli/cli-commands/common/harness/$applyHarnessInstallationStatus.d.ts +9 -0
- package/umd/src/cli/cli-commands/common/harness/$askForHarnessInstallationApproval.d.ts +9 -0
- package/umd/src/cli/cli-commands/common/harness/$checkHarnessInstallation.d.ts +10 -0
- package/umd/src/cli/cli-commands/common/harness/$ensureHarnessInstallations.d.ts +13 -0
- package/umd/src/cli/cli-commands/common/harness/$installHarness.d.ts +13 -0
- package/umd/src/cli/cli-commands/common/harness/$resolveInstalledHarnessVersion.d.ts +10 -0
- package/umd/src/cli/cli-commands/common/harness/$resolveLatestHarnessVersion.d.ts +10 -0
- package/umd/src/cli/cli-commands/common/harness/HarnessDefinition.d.ts +40 -0
- package/umd/src/cli/cli-commands/common/harness/HarnessDefinition.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/harness/HarnessInstallationStatus.d.ts +35 -0
- package/umd/src/cli/cli-commands/common/harness/buildHarnessInstallCommand.d.ts +10 -0
- package/umd/src/cli/cli-commands/common/harness/extractHarnessVersionFromOutput.d.ts +11 -0
- package/umd/src/cli/cli-commands/common/harness/extractHarnessVersionFromOutput.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/harness/formatHarnessInstallationWarning.d.ts +7 -0
- package/umd/src/cli/cli-commands/common/harness/isHarnessVersionOutdated.d.ts +9 -0
- package/umd/src/cli/cli-commands/common/harness/isHarnessVersionOutdated.test.d.ts +1 -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/buildAgentNameOrPermanentIdFilter.d.ts +18 -0
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/buildAgentNameOrPermanentIdFilter.test.d.ts +1 -0
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/prepareAgentSourceForPersistence.d.ts +1 -1
- package/umd/src/commitments/META/META.d.ts +4 -2
- package/umd/src/commitments/META_AVATAR/META_AVATAR.d.ts +9 -4
- package/umd/src/commitments/META_THINKING_MESSAGE/META_THINKING_MESSAGE.d.ts +26 -0
- package/umd/src/commitments/index.d.ts +2 -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/execution/utils/formatUsagePrice.d.ts +12 -0
- package/umd/src/execution/utils/formatUsagePrice.test.d.ts +1 -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/agent-message-runtime/resolveAgentMessageRuntimeActivity.d.ts +16 -0
- package/umd/src/utils/agent-message-runtime/resolveAgentMessageRuntimeActivity.test.d.ts +1 -0
- package/umd/src/utils/agents/resolveAgentAvatarImageUrl.d.ts +2 -2
- package/umd/src/utils/agents/terminalAgentAvatarVisual.d.ts +104 -0
- package/umd/src/utils/agents/terminalAgentAvatarVisual.test.d.ts +1 -0
- package/umd/src/utils/color/Color.d.ts +1 -1
- package/umd/src/utils/html/escapeHtml.d.ts +9 -0
- package/umd/src/utils/markdown/shiftMarkdownHeadingLevels.d.ts +15 -0
- 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-2.0/book-language-documentation/bookLanguageCommonPitfalls.d.ts +0 -25
- package/esm/src/book-components/_common/react-utils/escapeHtml.d.ts +0 -6
- package/umd/scripts/run-codex-prompts/common/runGoScript/buildTemporaryPromptScriptPath.d.ts +0 -14
- package/umd/src/book-2.0/book-language-documentation/bookLanguageCommonPitfalls.d.ts +0 -25
- package/umd/src/book-components/_common/react-utils/escapeHtml.d.ts +0 -6
- /package/esm/src/{executables/browsers/locateInternetExplorer.test.d.ts → book-2.0/book-language-documentation/createStandaloneBookLanguageMarkdown.test.d.ts} +0 -0
- /package/{umd/src/executables/browsers/locateInternetExplorer.test.d.ts → esm/src/book-3.0/AgentMessageRunReport.test.d.ts} +0 -0
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.
|
|
54
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-0';
|
|
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
|
|
@@ -88,6 +88,15 @@
|
|
|
88
88
|
* @public exported from `@promptbook/node`
|
|
89
89
|
*/
|
|
90
90
|
const AGENT_FAILED_MESSAGES_DIRECTORY_PATH = path.join(AGENT_MESSAGES_DIRECTORY_PATH, 'failed');
|
|
91
|
+
/**
|
|
92
|
+
* Relative path to the agent-owned projects root used by the agent folder convention.
|
|
93
|
+
*
|
|
94
|
+
* Each direct child directory is one project — an isolated folder the agent fully controls
|
|
95
|
+
* (files, scripts, optionally its own git repository).
|
|
96
|
+
*
|
|
97
|
+
* @private internal constant of the agent folder convention, used by agent runners and the Agents Server
|
|
98
|
+
*/
|
|
99
|
+
const AGENT_PROJECTS_DIRECTORY_PATH = 'projects';
|
|
91
100
|
|
|
92
101
|
/**
|
|
93
102
|
* Parser for the agent source for Promptbook agents in book language
|
|
@@ -396,6 +405,34 @@
|
|
|
396
405
|
// TODO: [🤶] Maybe export through `@promptbook/utils` or `@promptbook/random` package
|
|
397
406
|
// TODO: Maybe use nanoid instead https://github.com/ai/nanoid
|
|
398
407
|
|
|
408
|
+
/**
|
|
409
|
+
* Increase the level of all headings in the markdown content
|
|
410
|
+
*
|
|
411
|
+
* @example h1 -> h2, h2 -> h3, ...
|
|
412
|
+
* @param content The markdown content
|
|
413
|
+
* @returns The markdown with increased headings
|
|
414
|
+
*/
|
|
415
|
+
function increaseHeadings(content) {
|
|
416
|
+
const lines = content.split(/\r?\n/);
|
|
417
|
+
let inCodeBlock = false;
|
|
418
|
+
for (let i = 0; i < lines.length; i++) {
|
|
419
|
+
const line = lines[i];
|
|
420
|
+
if (line.startsWith('```')) {
|
|
421
|
+
inCodeBlock = !inCodeBlock;
|
|
422
|
+
}
|
|
423
|
+
if (inCodeBlock) {
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
const headingMatch = line.match(/^(#+)(.*)/);
|
|
427
|
+
if (headingMatch) {
|
|
428
|
+
const headingLevel = headingMatch[1].length;
|
|
429
|
+
const headingText = headingMatch[2];
|
|
430
|
+
lines[i] = `${'#'.repeat(headingLevel + 1)}${headingText}`;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return lines.join('\n');
|
|
434
|
+
}
|
|
435
|
+
|
|
399
436
|
/**
|
|
400
437
|
* Appends optional coding context to a runner prompt.
|
|
401
438
|
*/
|
|
@@ -408,7 +445,13 @@
|
|
|
408
445
|
if (normalizedPrompt === '') {
|
|
409
446
|
return normalizedContext;
|
|
410
447
|
}
|
|
411
|
-
return
|
|
448
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
449
|
+
${block(normalizedPrompt)}
|
|
450
|
+
|
|
451
|
+
## Context
|
|
452
|
+
|
|
453
|
+
${block(increaseHeadings(normalizedContext))}
|
|
454
|
+
`);
|
|
412
455
|
}
|
|
413
456
|
|
|
414
457
|
/**
|
|
@@ -450,48 +493,6 @@
|
|
|
450
493
|
}
|
|
451
494
|
}
|
|
452
495
|
|
|
453
|
-
/**
|
|
454
|
-
* Orders JSON object by keys
|
|
455
|
-
*
|
|
456
|
-
* @returns The same type of object as the input re-ordered
|
|
457
|
-
*
|
|
458
|
-
* @public exported from `@promptbook/utils`
|
|
459
|
-
*/
|
|
460
|
-
function orderJson(options) {
|
|
461
|
-
const { value, order } = options;
|
|
462
|
-
const orderedValue = {
|
|
463
|
-
...(order === undefined ? {} : Object.fromEntries(order.map((key) => [key, undefined]))),
|
|
464
|
-
...value,
|
|
465
|
-
};
|
|
466
|
-
return orderedValue;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* Freezes the given object and all its nested objects recursively
|
|
471
|
-
*
|
|
472
|
-
* Note: `$` is used to indicate that this function is not a pure function - it mutates given object
|
|
473
|
-
* Note: This function mutates the object and returns the original (but mutated-deep-freezed) object
|
|
474
|
-
*
|
|
475
|
-
* @returns The same object as the input, but deeply frozen
|
|
476
|
-
*
|
|
477
|
-
* @public exported from `@promptbook/utils`
|
|
478
|
-
*/
|
|
479
|
-
function $deepFreeze(objectValue) {
|
|
480
|
-
if (Array.isArray(objectValue)) {
|
|
481
|
-
return Object.freeze(objectValue.map((item) => $deepFreeze(item)));
|
|
482
|
-
}
|
|
483
|
-
const propertyNames = Object.getOwnPropertyNames(objectValue);
|
|
484
|
-
for (const propertyName of propertyNames) {
|
|
485
|
-
const value = objectValue[propertyName];
|
|
486
|
-
if (value && typeof value === 'object') {
|
|
487
|
-
$deepFreeze(value);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
Object.freeze(objectValue);
|
|
491
|
-
return objectValue;
|
|
492
|
-
}
|
|
493
|
-
// TODO: [🧠] Is there a way how to meaningfully test this utility
|
|
494
|
-
|
|
495
496
|
/**
|
|
496
497
|
* Class implementing take chain.
|
|
497
498
|
*
|
|
@@ -537,6 +538,127 @@
|
|
|
537
538
|
});
|
|
538
539
|
}
|
|
539
540
|
|
|
541
|
+
/**
|
|
542
|
+
* Validates that a channel value is a valid number within the range of 0 to 255.
|
|
543
|
+
* Throws an error if the value is not valid.
|
|
544
|
+
*
|
|
545
|
+
* @param channelName - The name of the channel being validated.
|
|
546
|
+
* @param value - The value of the channel to validate.
|
|
547
|
+
* @throws Will throw an error if the value is not a valid channel number.
|
|
548
|
+
*
|
|
549
|
+
* @private util of `@promptbook/color`
|
|
550
|
+
*/
|
|
551
|
+
function checkChannelValue(channelName, value) {
|
|
552
|
+
if (typeof value !== 'number') {
|
|
553
|
+
throw new Error(`${channelName} channel value is not number but ${typeof value}`);
|
|
554
|
+
}
|
|
555
|
+
if (isNaN(value)) {
|
|
556
|
+
throw new Error(`${channelName} channel value is NaN`);
|
|
557
|
+
}
|
|
558
|
+
if (Math.round(value) !== value) {
|
|
559
|
+
throw new Error(`${channelName} channel is not whole number, it is ${value}`);
|
|
560
|
+
}
|
|
561
|
+
if (value < 0) {
|
|
562
|
+
throw new Error(`${channelName} channel is lower than 0, it is ${value}`);
|
|
563
|
+
}
|
|
564
|
+
if (value > 255) {
|
|
565
|
+
throw new Error(`${channelName} channel is greater than 255, it is ${value}`);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Shared immutable channel storage and serialization helpers for `Color`.
|
|
571
|
+
*
|
|
572
|
+
* @private base class of Color
|
|
573
|
+
*/
|
|
574
|
+
class ColorValue {
|
|
575
|
+
constructor(red, green, blue, alpha = 255) {
|
|
576
|
+
this.red = red;
|
|
577
|
+
this.green = green;
|
|
578
|
+
this.blue = blue;
|
|
579
|
+
this.alpha = alpha;
|
|
580
|
+
checkChannelValue('Red', red);
|
|
581
|
+
checkChannelValue('Green', green);
|
|
582
|
+
checkChannelValue('Blue', blue);
|
|
583
|
+
checkChannelValue('Alpha', alpha);
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Shortcut for `red` property
|
|
587
|
+
* Number from 0 to 255
|
|
588
|
+
* @alias red
|
|
589
|
+
*/
|
|
590
|
+
get r() {
|
|
591
|
+
return this.red;
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Shortcut for `green` property
|
|
595
|
+
* Number from 0 to 255
|
|
596
|
+
* @alias green
|
|
597
|
+
*/
|
|
598
|
+
get g() {
|
|
599
|
+
return this.green;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Shortcut for `blue` property
|
|
603
|
+
* Number from 0 to 255
|
|
604
|
+
* @alias blue
|
|
605
|
+
*/
|
|
606
|
+
get b() {
|
|
607
|
+
return this.blue;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Shortcut for `alpha` property
|
|
611
|
+
* Number from 0 (transparent) to 255 (opaque)
|
|
612
|
+
* @alias alpha
|
|
613
|
+
*/
|
|
614
|
+
get a() {
|
|
615
|
+
return this.alpha;
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Shortcut for `alpha` property
|
|
619
|
+
* Number from 0 (transparent) to 255 (opaque)
|
|
620
|
+
* @alias alpha
|
|
621
|
+
*/
|
|
622
|
+
get opacity() {
|
|
623
|
+
return this.alpha;
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Shortcut for 1-`alpha` property
|
|
627
|
+
*/
|
|
628
|
+
get transparency() {
|
|
629
|
+
return 255 - this.alpha;
|
|
630
|
+
}
|
|
631
|
+
clone() {
|
|
632
|
+
return take(this.createColor(this.red, this.green, this.blue, this.alpha));
|
|
633
|
+
}
|
|
634
|
+
toString() {
|
|
635
|
+
return this.toHex();
|
|
636
|
+
}
|
|
637
|
+
toHex() {
|
|
638
|
+
if (this.alpha === 255) {
|
|
639
|
+
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
640
|
+
.toString(16)
|
|
641
|
+
.padStart(2, '0')}`;
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
645
|
+
.toString(16)
|
|
646
|
+
.padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
toRgb() {
|
|
650
|
+
if (this.alpha === 255) {
|
|
651
|
+
return `rgb(${this.red}, ${this.green}, ${this.blue})`;
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
toHsl() {
|
|
658
|
+
throw new Error(`Getting HSL is not implemented`);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
540
662
|
/**
|
|
541
663
|
* 🎨 List of all 140 color names which are supported by CSS
|
|
542
664
|
*
|
|
@@ -696,127 +818,6 @@
|
|
|
696
818
|
};
|
|
697
819
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
698
820
|
|
|
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
821
|
/**
|
|
821
822
|
* Checks if the given value is a valid hex color string
|
|
822
823
|
*
|
|
@@ -1796,6 +1797,110 @@
|
|
|
1796
1797
|
}
|
|
1797
1798
|
}
|
|
1798
1799
|
|
|
1800
|
+
/**
|
|
1801
|
+
* Single source of truth about how each supported CLI coding harness is installed and detected.
|
|
1802
|
+
*
|
|
1803
|
+
* @private internal utility of `promptbookCli`
|
|
1804
|
+
*/
|
|
1805
|
+
const HARNESS_DEFINITIONS = {
|
|
1806
|
+
'openai-codex': {
|
|
1807
|
+
harnessName: 'openai-codex',
|
|
1808
|
+
label: 'OpenAI Codex',
|
|
1809
|
+
commandName: 'codex',
|
|
1810
|
+
npmPackageName: '@openai/codex',
|
|
1811
|
+
},
|
|
1812
|
+
'github-copilot': {
|
|
1813
|
+
harnessName: 'github-copilot',
|
|
1814
|
+
label: 'GitHub Copilot',
|
|
1815
|
+
commandName: 'copilot',
|
|
1816
|
+
npmPackageName: '@github/copilot',
|
|
1817
|
+
// Note: The GitHub Copilot CLI downloads its native binary in a postinstall script
|
|
1818
|
+
npmInstallEnvironment: { npm_config_ignore_scripts: 'false' },
|
|
1819
|
+
},
|
|
1820
|
+
cline: {
|
|
1821
|
+
harnessName: 'cline',
|
|
1822
|
+
label: 'Cline',
|
|
1823
|
+
commandName: 'cline',
|
|
1824
|
+
npmPackageName: 'cline',
|
|
1825
|
+
},
|
|
1826
|
+
'claude-code': {
|
|
1827
|
+
harnessName: 'claude-code',
|
|
1828
|
+
label: 'Claude Code',
|
|
1829
|
+
commandName: 'claude',
|
|
1830
|
+
npmPackageName: '@anthropic-ai/claude-code',
|
|
1831
|
+
},
|
|
1832
|
+
opencode: {
|
|
1833
|
+
harnessName: 'opencode',
|
|
1834
|
+
label: 'Opencode',
|
|
1835
|
+
commandName: 'opencode',
|
|
1836
|
+
npmPackageName: 'opencode-ai',
|
|
1837
|
+
},
|
|
1838
|
+
gemini: {
|
|
1839
|
+
harnessName: 'gemini',
|
|
1840
|
+
label: 'Gemini CLI',
|
|
1841
|
+
commandName: 'gemini',
|
|
1842
|
+
npmPackageName: '@google/gemini-cli',
|
|
1843
|
+
},
|
|
1844
|
+
};
|
|
1845
|
+
/**
|
|
1846
|
+
* Looks up the definition of one supported CLI coding harness.
|
|
1847
|
+
*
|
|
1848
|
+
* @private internal utility of `promptbookCli`
|
|
1849
|
+
*/
|
|
1850
|
+
function getHarnessDefinition(harnessName) {
|
|
1851
|
+
const definition = HARNESS_DEFINITIONS[harnessName];
|
|
1852
|
+
if (definition === undefined) {
|
|
1853
|
+
throw new UnexpectedError(_spaceTrim.spaceTrim(`
|
|
1854
|
+
Missing harness definition for \`${harnessName}\`.
|
|
1855
|
+
|
|
1856
|
+
Every harness must be described in \`HARNESS_DEFINITIONS\`.
|
|
1857
|
+
`));
|
|
1858
|
+
}
|
|
1859
|
+
return definition;
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
/**
|
|
1863
|
+
* Orders JSON object by keys
|
|
1864
|
+
*
|
|
1865
|
+
* @returns The same type of object as the input re-ordered
|
|
1866
|
+
*
|
|
1867
|
+
* @public exported from `@promptbook/utils`
|
|
1868
|
+
*/
|
|
1869
|
+
function orderJson(options) {
|
|
1870
|
+
const { value, order } = options;
|
|
1871
|
+
const orderedValue = {
|
|
1872
|
+
...(order === undefined ? {} : Object.fromEntries(order.map((key) => [key, undefined]))),
|
|
1873
|
+
...value,
|
|
1874
|
+
};
|
|
1875
|
+
return orderedValue;
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
/**
|
|
1879
|
+
* Freezes the given object and all its nested objects recursively
|
|
1880
|
+
*
|
|
1881
|
+
* Note: `$` is used to indicate that this function is not a pure function - it mutates given object
|
|
1882
|
+
* Note: This function mutates the object and returns the original (but mutated-deep-freezed) object
|
|
1883
|
+
*
|
|
1884
|
+
* @returns The same object as the input, but deeply frozen
|
|
1885
|
+
*
|
|
1886
|
+
* @public exported from `@promptbook/utils`
|
|
1887
|
+
*/
|
|
1888
|
+
function $deepFreeze(objectValue) {
|
|
1889
|
+
if (Array.isArray(objectValue)) {
|
|
1890
|
+
return Object.freeze(objectValue.map((item) => $deepFreeze(item)));
|
|
1891
|
+
}
|
|
1892
|
+
const propertyNames = Object.getOwnPropertyNames(objectValue);
|
|
1893
|
+
for (const propertyName of propertyNames) {
|
|
1894
|
+
const value = objectValue[propertyName];
|
|
1895
|
+
if (value && typeof value === 'object') {
|
|
1896
|
+
$deepFreeze(value);
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
Object.freeze(objectValue);
|
|
1900
|
+
return objectValue;
|
|
1901
|
+
}
|
|
1902
|
+
// TODO: [🧠] Is there a way how to meaningfully test this utility
|
|
1903
|
+
|
|
1799
1904
|
/**
|
|
1800
1905
|
* This error type indicates that somewhere in the code non-Error object was thrown and it was wrapped into the `WrappedError`
|
|
1801
1906
|
*
|
|
@@ -2790,6 +2895,31 @@
|
|
|
2790
2895
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
2791
2896
|
*/
|
|
2792
2897
|
|
|
2898
|
+
/**
|
|
2899
|
+
* Pattern that matches durations like "1h", "30m", "5s", "1h30m", "1h30m5s".
|
|
2900
|
+
*/
|
|
2901
|
+
/**
|
|
2902
|
+
* Formats a duration in milliseconds into a compact human-readable string.
|
|
2903
|
+
*
|
|
2904
|
+
* Examples: `3600000` → `"1h"`, `90000` → `"1m 30s"`, `5000` → `"5s"`.
|
|
2905
|
+
*
|
|
2906
|
+
* @private internal utility of `ptbk coder run`
|
|
2907
|
+
*/
|
|
2908
|
+
function formatDurationMs(ms) {
|
|
2909
|
+
const totalSeconds = Math.ceil(ms / 1000);
|
|
2910
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
2911
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
2912
|
+
const seconds = totalSeconds % 60;
|
|
2913
|
+
const parts = [];
|
|
2914
|
+
if (hours > 0)
|
|
2915
|
+
parts.push(`${hours}h`);
|
|
2916
|
+
if (minutes > 0)
|
|
2917
|
+
parts.push(`${minutes}m`);
|
|
2918
|
+
if (seconds > 0 || parts.length === 0)
|
|
2919
|
+
parts.push(`${seconds}s`);
|
|
2920
|
+
return parts.join(' ');
|
|
2921
|
+
}
|
|
2922
|
+
|
|
2793
2923
|
/**
|
|
2794
2924
|
* Formats one unknown error-like value into readable text for logs and feedback.
|
|
2795
2925
|
*/
|
|
@@ -3017,6 +3147,55 @@
|
|
|
3017
3147
|
});
|
|
3018
3148
|
}
|
|
3019
3149
|
|
|
3150
|
+
/**
|
|
3151
|
+
* Minimum timer duration used to avoid a zero-millisecond polling loop.
|
|
3152
|
+
*/
|
|
3153
|
+
const MINIMUM_WORLD_TIME_WAIT_POLL_INTERVAL_MS = 1;
|
|
3154
|
+
/**
|
|
3155
|
+
* Waits until one wall-clock deadline has passed.
|
|
3156
|
+
*
|
|
3157
|
+
* The remaining time is recalculated from `Date.now()` after every poll and after every tick callback.
|
|
3158
|
+
* This makes waits elapse while the process is paused at a checkpoint or the computer is asleep.
|
|
3159
|
+
*
|
|
3160
|
+
* @private internal utility of `ptbk coder` wait handling
|
|
3161
|
+
*/
|
|
3162
|
+
async function waitUntilWorldTimeDeadline(options) {
|
|
3163
|
+
var _a;
|
|
3164
|
+
const { deadlineTimeMs, pollIntervalMs, onTick, shouldStopWaiting } = options;
|
|
3165
|
+
const normalizedPollIntervalMs = Math.max(MINIMUM_WORLD_TIME_WAIT_POLL_INTERVAL_MS, pollIntervalMs);
|
|
3166
|
+
const waitForMilliseconds = (_a = options.waitForMilliseconds) !== null && _a !== void 0 ? _a : waitForRegularMilliseconds;
|
|
3167
|
+
while (true) {
|
|
3168
|
+
if (shouldStopWaiting === null || shouldStopWaiting === void 0 ? void 0 : shouldStopWaiting()) {
|
|
3169
|
+
return;
|
|
3170
|
+
}
|
|
3171
|
+
const remainingDurationMs = getRemainingDurationMs(deadlineTimeMs);
|
|
3172
|
+
if (remainingDurationMs <= 0) {
|
|
3173
|
+
return;
|
|
3174
|
+
}
|
|
3175
|
+
await (onTick === null || onTick === void 0 ? void 0 : onTick(remainingDurationMs));
|
|
3176
|
+
if (shouldStopWaiting === null || shouldStopWaiting === void 0 ? void 0 : shouldStopWaiting()) {
|
|
3177
|
+
return;
|
|
3178
|
+
}
|
|
3179
|
+
const remainingDurationAfterTickMs = getRemainingDurationMs(deadlineTimeMs);
|
|
3180
|
+
if (remainingDurationAfterTickMs <= 0) {
|
|
3181
|
+
return;
|
|
3182
|
+
}
|
|
3183
|
+
await waitForMilliseconds(Math.min(normalizedPollIntervalMs, remainingDurationAfterTickMs));
|
|
3184
|
+
}
|
|
3185
|
+
}
|
|
3186
|
+
/**
|
|
3187
|
+
* Returns the remaining wall-clock duration until a timestamp.
|
|
3188
|
+
*/
|
|
3189
|
+
function getRemainingDurationMs(deadlineTimeMs) {
|
|
3190
|
+
return Math.max(0, deadlineTimeMs - Date.now());
|
|
3191
|
+
}
|
|
3192
|
+
/**
|
|
3193
|
+
* Waits for one short polling interval.
|
|
3194
|
+
*/
|
|
3195
|
+
async function waitForRegularMilliseconds(durationMs) {
|
|
3196
|
+
await new Promise((resolve) => setTimeout(resolve, durationMs));
|
|
3197
|
+
}
|
|
3198
|
+
|
|
3020
3199
|
/**
|
|
3021
3200
|
* Base delimiter used for passing large prompts through stdin.
|
|
3022
3201
|
*/
|
|
@@ -3027,14 +3206,209 @@
|
|
|
3027
3206
|
function buildClaudeScript(options) {
|
|
3028
3207
|
const MODEL_ARGUMENT = options.model ? ` --model ${options.model}` : '';
|
|
3029
3208
|
const THINKING_LEVEL_ARGUMENT = options.thinkingLevel ? ` --effort ${options.thinkingLevel}` : '';
|
|
3209
|
+
const RESUME_SESSION_ARGUMENT = options.resumeSessionId
|
|
3210
|
+
? ` --resume ${quoteShellArgument(options.resumeSessionId)}`
|
|
3211
|
+
: '';
|
|
3030
3212
|
return spaceTrim((block) => `
|
|
3031
|
-
claude --allowedTools "Bash,Read,Edit,Write"${MODEL_ARGUMENT}${THINKING_LEVEL_ARGUMENT} --output-format stream-json --verbose --include-partial-messages --print <<'${CLAUDE_PROMPT_DELIMITER}'
|
|
3213
|
+
claude --allowedTools "Bash,Read,Edit,Write"${MODEL_ARGUMENT}${THINKING_LEVEL_ARGUMENT}${RESUME_SESSION_ARGUMENT} --output-format stream-json --verbose --include-partial-messages --print <<'${CLAUDE_PROMPT_DELIMITER}'
|
|
3032
3214
|
|
|
3033
3215
|
${block(options.prompt)}
|
|
3034
3216
|
|
|
3035
3217
|
${CLAUDE_PROMPT_DELIMITER}
|
|
3036
3218
|
`);
|
|
3037
3219
|
}
|
|
3220
|
+
/**
|
|
3221
|
+
* Quotes one shell argument for the generated Bash script.
|
|
3222
|
+
*/
|
|
3223
|
+
function quoteShellArgument(value) {
|
|
3224
|
+
return JSON.stringify(value);
|
|
3225
|
+
}
|
|
3226
|
+
|
|
3227
|
+
/**
|
|
3228
|
+
* Parses all JSON lines from Claude Code output while ignoring shell prefixes and stack traces.
|
|
3229
|
+
*/
|
|
3230
|
+
function parseClaudeCodeOutputEvents(output) {
|
|
3231
|
+
return output
|
|
3232
|
+
.split(/\r?\n/u)
|
|
3233
|
+
.map(parseClaudeCodeOutputLine)
|
|
3234
|
+
.filter((event) => event !== undefined);
|
|
3235
|
+
}
|
|
3236
|
+
/**
|
|
3237
|
+
* Finds the final Claude Code result event in a stream-json output blob.
|
|
3238
|
+
*/
|
|
3239
|
+
function findClaudeCodeResultEvent(output) {
|
|
3240
|
+
return parseClaudeCodeOutputEvents(output).find((event) => event.type === 'result');
|
|
3241
|
+
}
|
|
3242
|
+
/**
|
|
3243
|
+
* Parses one output line when it contains a JSON object.
|
|
3244
|
+
*/
|
|
3245
|
+
function parseClaudeCodeOutputLine(line) {
|
|
3246
|
+
const jsonStartIndex = line.indexOf('{');
|
|
3247
|
+
if (jsonStartIndex === -1) {
|
|
3248
|
+
return undefined;
|
|
3249
|
+
}
|
|
3250
|
+
const possibleJson = line.slice(jsonStartIndex).trim();
|
|
3251
|
+
try {
|
|
3252
|
+
const parsed = JSON.parse(possibleJson);
|
|
3253
|
+
if (isClaudeCodeOutputEvent(parsed)) {
|
|
3254
|
+
return parsed;
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3257
|
+
catch (_a) {
|
|
3258
|
+
return undefined;
|
|
3259
|
+
}
|
|
3260
|
+
return undefined;
|
|
3261
|
+
}
|
|
3262
|
+
/**
|
|
3263
|
+
* Checks whether an unknown parsed JSON value has the object shape expected from Claude Code events.
|
|
3264
|
+
*/
|
|
3265
|
+
function isClaudeCodeOutputEvent(value) {
|
|
3266
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3267
|
+
}
|
|
3268
|
+
|
|
3269
|
+
/**
|
|
3270
|
+
* Number of milliseconds added after Claude's reported reset timestamp before retrying.
|
|
3271
|
+
*/
|
|
3272
|
+
const CLAUDE_CODE_SESSION_LIMIT_RESET_BUFFER_MS = 30 * 1000;
|
|
3273
|
+
/**
|
|
3274
|
+
* Fallback delay used when Claude reports a session limit without a machine-readable reset timestamp.
|
|
3275
|
+
*/
|
|
3276
|
+
const DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS = 10 * 60 * 1000;
|
|
3277
|
+
/**
|
|
3278
|
+
* Extracts a Claude Code session-limit failure from a thrown runner error.
|
|
3279
|
+
*/
|
|
3280
|
+
function extractClaudeCodeSessionLimitFromError(error) {
|
|
3281
|
+
return extractClaudeCodeSessionLimitFromOutput(formatUnknownErrorDetails(error));
|
|
3282
|
+
}
|
|
3283
|
+
/**
|
|
3284
|
+
* Extracts a Claude Code session-limit failure from raw stream-json output.
|
|
3285
|
+
*/
|
|
3286
|
+
function extractClaudeCodeSessionLimitFromOutput(output) {
|
|
3287
|
+
var _a, _b, _c, _d, _e;
|
|
3288
|
+
const events = parseClaudeCodeOutputEvents(output);
|
|
3289
|
+
const rejectedRateLimitEvent = events.find(isRejectedRateLimitEvent);
|
|
3290
|
+
const sessionLimitResultEvent = events.find(isSessionLimitResultEvent);
|
|
3291
|
+
const sessionLimitTextEvent = events.find(isSessionLimitTextEvent);
|
|
3292
|
+
if (!sessionLimitResultEvent && !sessionLimitTextEvent) {
|
|
3293
|
+
return undefined;
|
|
3294
|
+
}
|
|
3295
|
+
const sessionId = findClaudeCodeSessionId(events);
|
|
3296
|
+
if (!sessionId) {
|
|
3297
|
+
return undefined;
|
|
3298
|
+
}
|
|
3299
|
+
const resetDate = extractResetDate(rejectedRateLimitEvent);
|
|
3300
|
+
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;
|
|
3301
|
+
const summary = (_e = (_d = extractSessionLimitSummary(sessionLimitResultEvent)) !== null && _d !== void 0 ? _d : extractSessionLimitSummary(sessionLimitTextEvent)) !== null && _e !== void 0 ? _e : 'Claude Code reported a session limit.';
|
|
3302
|
+
return {
|
|
3303
|
+
sessionId,
|
|
3304
|
+
resetDate,
|
|
3305
|
+
rateLimitType,
|
|
3306
|
+
summary,
|
|
3307
|
+
};
|
|
3308
|
+
}
|
|
3309
|
+
/**
|
|
3310
|
+
* Computes how long to wait before trying to resume the Claude Code session.
|
|
3311
|
+
*/
|
|
3312
|
+
function getClaudeCodeSessionLimitDelayMs(sessionLimit, nowMs = Date.now()) {
|
|
3313
|
+
if (!sessionLimit.resetDate) {
|
|
3314
|
+
return DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS;
|
|
3315
|
+
}
|
|
3316
|
+
return Math.max(0, sessionLimit.resetDate.getTime() - nowMs + CLAUDE_CODE_SESSION_LIMIT_RESET_BUFFER_MS);
|
|
3317
|
+
}
|
|
3318
|
+
/**
|
|
3319
|
+
* Builds the follow-up prompt sent into a resumed Claude Code session after its limit resets.
|
|
3320
|
+
*/
|
|
3321
|
+
function buildClaudeCodeSessionResurrectionPrompt(originalPrompt, sessionId) {
|
|
3322
|
+
return spaceTrim((block) => `
|
|
3323
|
+
## Claude Code session resurrection
|
|
3324
|
+
|
|
3325
|
+
You are resuming Claude Code session \`${sessionId}\` after Claude reported a session limit.
|
|
3326
|
+
Continue the same task from the existing repository and session state.
|
|
3327
|
+
Do not discard useful context, completed analysis, or file changes from the resumed session.
|
|
3328
|
+
|
|
3329
|
+
The original prompt is repeated below as reference in case the resumed session needs it.
|
|
3330
|
+
|
|
3331
|
+
## Original prompt
|
|
3332
|
+
|
|
3333
|
+
${block(originalPrompt)}
|
|
3334
|
+
`);
|
|
3335
|
+
}
|
|
3336
|
+
/**
|
|
3337
|
+
* Builds a compact one-line label for logs and terminal UI messages.
|
|
3338
|
+
*/
|
|
3339
|
+
function formatClaudeCodeSessionLimitForDisplay(sessionLimit) {
|
|
3340
|
+
const resetSuffix = sessionLimit.resetDate
|
|
3341
|
+
? `, resets at ${sessionLimit.resetDate.toISOString()}`
|
|
3342
|
+
: `, retrying every ${formatDurationMs(DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS)}`;
|
|
3343
|
+
const rateLimitSuffix = sessionLimit.rateLimitType ? ` (${sessionLimit.rateLimitType})` : '';
|
|
3344
|
+
return `${sessionLimit.summary}${rateLimitSuffix}${resetSuffix}`;
|
|
3345
|
+
}
|
|
3346
|
+
/**
|
|
3347
|
+
* Returns true when the event is an explicit rejected Claude Code rate-limit event.
|
|
3348
|
+
*/
|
|
3349
|
+
function isRejectedRateLimitEvent(event) {
|
|
3350
|
+
var _a;
|
|
3351
|
+
return event.type === 'rate_limit_event' && ((_a = event.rate_limit_info) === null || _a === void 0 ? void 0 : _a.status) === 'rejected';
|
|
3352
|
+
}
|
|
3353
|
+
/**
|
|
3354
|
+
* Returns true when the final result reports the Claude session limit.
|
|
3355
|
+
*/
|
|
3356
|
+
function isSessionLimitResultEvent(event) {
|
|
3357
|
+
return (event.type === 'result' &&
|
|
3358
|
+
event.is_error === true &&
|
|
3359
|
+
event.api_error_status === 429 &&
|
|
3360
|
+
isSessionLimitText(event.result));
|
|
3361
|
+
}
|
|
3362
|
+
/**
|
|
3363
|
+
* Returns true when any assistant event reports the Claude session limit in text.
|
|
3364
|
+
*/
|
|
3365
|
+
function isSessionLimitTextEvent(event) {
|
|
3366
|
+
if (event.error !== 'rate_limit') {
|
|
3367
|
+
return false;
|
|
3368
|
+
}
|
|
3369
|
+
return isSessionLimitText(extractSessionLimitSummary(event));
|
|
3370
|
+
}
|
|
3371
|
+
/**
|
|
3372
|
+
* Extracts the first session id reported by Claude Code.
|
|
3373
|
+
*/
|
|
3374
|
+
function findClaudeCodeSessionId(events) {
|
|
3375
|
+
return events.map((event) => event.session_id).find((sessionId) => Boolean(sessionId));
|
|
3376
|
+
}
|
|
3377
|
+
/**
|
|
3378
|
+
* Extracts Claude's reset timestamp from a rejected rate-limit event.
|
|
3379
|
+
*/
|
|
3380
|
+
function extractResetDate(event) {
|
|
3381
|
+
var _a;
|
|
3382
|
+
const resetsAt = (_a = event === null || event === void 0 ? void 0 : event.rate_limit_info) === null || _a === void 0 ? void 0 : _a.resetsAt;
|
|
3383
|
+
if (typeof resetsAt !== 'number' || !Number.isFinite(resetsAt)) {
|
|
3384
|
+
return undefined;
|
|
3385
|
+
}
|
|
3386
|
+
const resetDate = new Date(resetsAt * 1000);
|
|
3387
|
+
if (Number.isNaN(resetDate.getTime())) {
|
|
3388
|
+
return undefined;
|
|
3389
|
+
}
|
|
3390
|
+
return resetDate;
|
|
3391
|
+
}
|
|
3392
|
+
/**
|
|
3393
|
+
* Extracts a human-readable session-limit summary from an event.
|
|
3394
|
+
*/
|
|
3395
|
+
function extractSessionLimitSummary(event) {
|
|
3396
|
+
var _a, _b;
|
|
3397
|
+
if (!event) {
|
|
3398
|
+
return undefined;
|
|
3399
|
+
}
|
|
3400
|
+
if (typeof event.result === 'string' && event.result.trim()) {
|
|
3401
|
+
return event.result.trim();
|
|
3402
|
+
}
|
|
3403
|
+
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));
|
|
3404
|
+
return textContent;
|
|
3405
|
+
}
|
|
3406
|
+
/**
|
|
3407
|
+
* Checks whether a text value names the Claude Code session limit.
|
|
3408
|
+
*/
|
|
3409
|
+
function isSessionLimitText(text) {
|
|
3410
|
+
return /\bsession\s+limit\b/iu.test(text !== null && text !== void 0 ? text : '');
|
|
3411
|
+
}
|
|
3038
3412
|
|
|
3039
3413
|
/**
|
|
3040
3414
|
* Represents the uncertain value
|
|
@@ -3110,14 +3484,8 @@
|
|
|
3110
3484
|
function parseClaudeCodeJsonOutput(output) {
|
|
3111
3485
|
var _a, _b, _c, _d;
|
|
3112
3486
|
try {
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
const jsonLine = lines.find((line) => line.trim().startsWith('{"type":"result"'));
|
|
3116
|
-
if (!jsonLine) {
|
|
3117
|
-
return UNCERTAIN_USAGE;
|
|
3118
|
-
}
|
|
3119
|
-
const parsed = JSON.parse(jsonLine);
|
|
3120
|
-
if (parsed.type !== 'result') {
|
|
3487
|
+
const parsed = findClaudeCodeResultEvent(output);
|
|
3488
|
+
if (!parsed) {
|
|
3121
3489
|
return UNCERTAIN_USAGE;
|
|
3122
3490
|
}
|
|
3123
3491
|
const totalInputTokens = (((_a = parsed.usage) === null || _a === void 0 ? void 0 : _a.input_tokens) || 0) +
|
|
@@ -3161,6 +3529,10 @@
|
|
|
3161
3529
|
}
|
|
3162
3530
|
}
|
|
3163
3531
|
|
|
3532
|
+
/**
|
|
3533
|
+
* Polling interval used while waiting for Claude Code session limits to reset.
|
|
3534
|
+
*/
|
|
3535
|
+
const CLAUDE_CODE_SESSION_RESURRECTION_POLL_MS = 30 * 1000;
|
|
3164
3536
|
/**
|
|
3165
3537
|
* Runs prompts via the Claude Code CLI.
|
|
3166
3538
|
*/
|
|
@@ -3176,22 +3548,98 @@
|
|
|
3176
3548
|
* Runs the prompt using Claude Code and parses usage output.
|
|
3177
3549
|
*/
|
|
3178
3550
|
async runPrompt(options) {
|
|
3551
|
+
let resumeSessionId;
|
|
3552
|
+
let prompt = options.prompt;
|
|
3553
|
+
let resurrectionCount = 0;
|
|
3554
|
+
while (true) {
|
|
3555
|
+
const output = await this.runClaudeCodeOnce({
|
|
3556
|
+
...options,
|
|
3557
|
+
prompt,
|
|
3558
|
+
resumeSessionId,
|
|
3559
|
+
}).catch(async (error) => {
|
|
3560
|
+
const sessionLimit = extractClaudeCodeSessionLimitFromError(error);
|
|
3561
|
+
if (!sessionLimit) {
|
|
3562
|
+
throw error;
|
|
3563
|
+
}
|
|
3564
|
+
resurrectionCount++;
|
|
3565
|
+
await waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options);
|
|
3566
|
+
resumeSessionId = sessionLimit.sessionId;
|
|
3567
|
+
prompt = buildClaudeCodeSessionResurrectionPrompt(options.prompt, sessionLimit.sessionId);
|
|
3568
|
+
return undefined;
|
|
3569
|
+
});
|
|
3570
|
+
if (output === undefined) {
|
|
3571
|
+
continue;
|
|
3572
|
+
}
|
|
3573
|
+
const sessionLimit = extractClaudeCodeSessionLimitFromOutput(output);
|
|
3574
|
+
if (sessionLimit) {
|
|
3575
|
+
resurrectionCount++;
|
|
3576
|
+
await waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options);
|
|
3577
|
+
resumeSessionId = sessionLimit.sessionId;
|
|
3578
|
+
prompt = buildClaudeCodeSessionResurrectionPrompt(options.prompt, sessionLimit.sessionId);
|
|
3579
|
+
continue;
|
|
3580
|
+
}
|
|
3581
|
+
const usage = parseClaudeCodeJsonOutput(output);
|
|
3582
|
+
return { usage };
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
/**
|
|
3586
|
+
* Runs one Claude Code CLI process and returns its raw output.
|
|
3587
|
+
*/
|
|
3588
|
+
async runClaudeCodeOnce(options) {
|
|
3179
3589
|
const scriptContent = buildClaudeScript({
|
|
3180
3590
|
prompt: options.prompt,
|
|
3181
3591
|
model: this.options.model,
|
|
3182
3592
|
thinkingLevel: this.options.thinkingLevel,
|
|
3593
|
+
resumeSessionId: options.resumeSessionId,
|
|
3183
3594
|
});
|
|
3184
|
-
|
|
3595
|
+
return await $runGoScriptWithOutput({
|
|
3185
3596
|
scriptPath: options.scriptPath,
|
|
3186
3597
|
scriptContent,
|
|
3187
3598
|
logPath: options.logPath,
|
|
3188
3599
|
shouldPrintLiveOutput: options.shouldPrintLiveOutput,
|
|
3189
3600
|
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
3190
3601
|
});
|
|
3191
|
-
const usage = parseClaudeCodeJsonOutput(output);
|
|
3192
|
-
return { usage };
|
|
3193
3602
|
}
|
|
3194
3603
|
}
|
|
3604
|
+
/**
|
|
3605
|
+
* Waits until the Claude Code session can be resumed, keeping terminal status clear.
|
|
3606
|
+
*/
|
|
3607
|
+
async function waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options) {
|
|
3608
|
+
var _a, _b;
|
|
3609
|
+
const delayMs = getClaudeCodeSessionLimitDelayMs(sessionLimit);
|
|
3610
|
+
const resetDeadlineTimeMs = Date.now() + delayMs;
|
|
3611
|
+
const sessionLabel = formatClaudeCodeSessionIdForDisplay(sessionLimit.sessionId);
|
|
3612
|
+
const resetSummary = formatClaudeCodeSessionLimitForDisplay(sessionLimit);
|
|
3613
|
+
if ((_a = options.shouldPrintLiveOutput) !== null && _a !== void 0 ? _a : true) {
|
|
3614
|
+
console.warn(colors__default["default"].yellow(`[claude-code] Session limit detected for ${sessionLimit.sessionId}. Resurrection #${resurrectionCount} will resume with --resume after ${formatDurationMs(delayMs)}. ${resetSummary}`));
|
|
3615
|
+
}
|
|
3616
|
+
await waitUntilWorldTimeDeadline({
|
|
3617
|
+
deadlineTimeMs: resetDeadlineTimeMs,
|
|
3618
|
+
pollIntervalMs: CLAUDE_CODE_SESSION_RESURRECTION_POLL_MS,
|
|
3619
|
+
onTick: async (remainingDelayMs) => {
|
|
3620
|
+
var _a;
|
|
3621
|
+
await ((_a = options.waitForPauseCheckpoint) === null || _a === void 0 ? void 0 : _a.call(options, {
|
|
3622
|
+
checkpointLabel: 'the Claude Code session limit reset',
|
|
3623
|
+
phase: 'waiting',
|
|
3624
|
+
statusMessage: `Claude Code session ${sessionLabel} hit its limit; resurrection #${resurrectionCount} resumes in ${formatDurationMs(Math.min(remainingDelayMs, delayMs))}`,
|
|
3625
|
+
}));
|
|
3626
|
+
},
|
|
3627
|
+
});
|
|
3628
|
+
await ((_b = options.waitForPauseCheckpoint) === null || _b === void 0 ? void 0 : _b.call(options, {
|
|
3629
|
+
checkpointLabel: 'resurrecting the Claude Code session with --resume',
|
|
3630
|
+
phase: 'running',
|
|
3631
|
+
statusMessage: `Resurrecting Claude Code session ${sessionLabel} with --resume`,
|
|
3632
|
+
}));
|
|
3633
|
+
}
|
|
3634
|
+
/**
|
|
3635
|
+
* Formats a Claude Code session id for compact terminal status lines.
|
|
3636
|
+
*/
|
|
3637
|
+
function formatClaudeCodeSessionIdForDisplay(sessionId) {
|
|
3638
|
+
if (sessionId.length <= 8) {
|
|
3639
|
+
return sessionId;
|
|
3640
|
+
}
|
|
3641
|
+
return `${sessionId.slice(0, 8)}...`;
|
|
3642
|
+
}
|
|
3195
3643
|
|
|
3196
3644
|
/**
|
|
3197
3645
|
* Creates a temporary script file, runs it, and cleans it up unless preservation is requested or the run fails.
|
|
@@ -3790,6 +4238,27 @@
|
|
|
3790
4238
|
}
|
|
3791
4239
|
}
|
|
3792
4240
|
|
|
4241
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
4242
|
+
/**
|
|
4243
|
+
* Stable stdout marker printed by the generated Codex runner script to report which login method it used.
|
|
4244
|
+
*
|
|
4245
|
+
* The marker is followed by the resolved method keyword, for example `ptbk-codex-login-method: chatgpt`,
|
|
4246
|
+
* so `parseCodexLoginMethodFromOutput` can recover it from the captured runner output.
|
|
4247
|
+
*
|
|
4248
|
+
* @private internal constant of the OpenAI Codex runner
|
|
4249
|
+
*/
|
|
4250
|
+
const CODEX_LOGIN_METHOD_MARKER = 'ptbk-codex-login-method:';
|
|
4251
|
+
/**
|
|
4252
|
+
* Substring that the `codex login status` command prints when the Codex CLI is signed in with a
|
|
4253
|
+
* ChatGPT subscription account instead of an `OPENAI_API_KEY`.
|
|
4254
|
+
*
|
|
4255
|
+
* This is the single source of truth for detecting an active ChatGPT login, reused by the Codex runner
|
|
4256
|
+
* script and by the Agents Server harness authentication status resolver.
|
|
4257
|
+
*
|
|
4258
|
+
* @private internal constant of the OpenAI Codex runner and the Agents Server Harness Auth
|
|
4259
|
+
*/
|
|
4260
|
+
const CODEX_CHATGPT_LOGIN_STATUS_NEEDLE = 'Logged in using ChatGPT';
|
|
4261
|
+
|
|
3793
4262
|
/**
|
|
3794
4263
|
* Default Codex reasoning effort preserved for backwards compatibility when no CLI override is provided.
|
|
3795
4264
|
*/
|
|
@@ -3806,10 +4275,28 @@
|
|
|
3806
4275
|
const delimiter = resolveShellHereDocumentDelimiter(CODEX_PROMPT_DELIMITER, options.prompt);
|
|
3807
4276
|
const projectPath = toPosixPath(options.projectPath);
|
|
3808
4277
|
const loginMethodConfig = spaceTrim(`
|
|
4278
|
+
CODEX_LOGIN_STATUS="$(
|
|
4279
|
+
unset OPENAI_API_KEY OPENAI_BASE_URL CODEX_API_KEY
|
|
4280
|
+
# 'codex login status' prints the "Logged in using ChatGPT" line to stderr, so merge stderr into stdout (2>&1) to capture it
|
|
4281
|
+
${options.codexCommand} login status 2>&1 || true
|
|
4282
|
+
)"
|
|
4283
|
+
case "$CODEX_LOGIN_STATUS" in
|
|
4284
|
+
*"${CODEX_CHATGPT_LOGIN_STATUS_NEEDLE}"*)
|
|
4285
|
+
IS_CODEX_CHATGPT_LOGIN_ACTIVE=1
|
|
4286
|
+
;;
|
|
4287
|
+
*)
|
|
4288
|
+
IS_CODEX_CHATGPT_LOGIN_ACTIVE=0
|
|
4289
|
+
;;
|
|
4290
|
+
esac
|
|
4291
|
+
|
|
4292
|
+
CODEX_LOGIN_METHOD=chatgpt
|
|
3809
4293
|
${options.allowCredits ? 'CODEX_LOGIN_METHOD_ARGUMENTS=()' : 'CODEX_LOGIN_METHOD_ARGUMENTS=(-c forced_login_method=chatgpt)'}
|
|
3810
4294
|
unset CODEX_API_KEY
|
|
3811
|
-
if [ "
|
|
4295
|
+
if [ "$IS_CODEX_CHATGPT_LOGIN_ACTIVE" != "1" ] &&
|
|
4296
|
+
[ "\${PTBK_OPENAI_CODEX_USE_API_KEY:-0}" = "1" ] &&
|
|
4297
|
+
[ -n "\${OPENAI_API_KEY:-}" ]; then
|
|
3812
4298
|
CODEX_LOGIN_METHOD_ARGUMENTS=(-c forced_login_method=api)
|
|
4299
|
+
CODEX_LOGIN_METHOD=api
|
|
3813
4300
|
CODEX_API_KEY="\${OPENAI_API_KEY}"
|
|
3814
4301
|
export CODEX_API_KEY
|
|
3815
4302
|
fi
|
|
@@ -3828,11 +4315,15 @@
|
|
|
3828
4315
|
'',
|
|
3829
4316
|
loginMethodConfig,
|
|
3830
4317
|
'',
|
|
3831
|
-
'if [ "$
|
|
4318
|
+
'if [ "$IS_CODEX_CHATGPT_LOGIN_ACTIVE" = "1" ] ||',
|
|
4319
|
+
' [ "${PTBK_OPENAI_CODEX_USE_API_KEY:-0}" != "1" ] ||',
|
|
4320
|
+
' [ -z "${OPENAI_API_KEY:-}" ]; then',
|
|
3832
4321
|
'unset OPENAI_API_KEY',
|
|
3833
4322
|
'unset OPENAI_BASE_URL',
|
|
3834
4323
|
'fi',
|
|
3835
4324
|
'',
|
|
4325
|
+
`printf '%s %s\\n' '${CODEX_LOGIN_METHOD_MARKER}' "\${CODEX_LOGIN_METHOD}"`,
|
|
4326
|
+
'',
|
|
3836
4327
|
`${options.codexCommand} \\`,
|
|
3837
4328
|
' "${CODEX_LOGIN_METHOD_ARGUMENTS[@]}" \\',
|
|
3838
4329
|
` -c model_reasoning_effort="${thinkingLevel}" \\`,
|
|
@@ -4034,6 +4525,37 @@
|
|
|
4034
4525
|
return (_c = OPENAI_MODELS.find((model) => model.modelName === CODEX_FALLBACK_PRICING_MODEL)) === null || _c === void 0 ? void 0 : _c.pricing;
|
|
4035
4526
|
}
|
|
4036
4527
|
|
|
4528
|
+
/**
|
|
4529
|
+
* Detects which login method Codex used from the captured CLI output.
|
|
4530
|
+
*
|
|
4531
|
+
* The generated Codex runner script prints one `CODEX_LOGIN_METHOD_MARKER` line before invoking Codex.
|
|
4532
|
+
* The most recent marker wins so retries within one captured output resolve to the final decision.
|
|
4533
|
+
*
|
|
4534
|
+
* @returns The resolved login method, or `unknown` when no marker is present.
|
|
4535
|
+
*/
|
|
4536
|
+
function parseCodexLoginMethodFromOutput(output) {
|
|
4537
|
+
const lines = output.split(/\r?\n/);
|
|
4538
|
+
for (let index = lines.length - 1; index >= 0; index--) {
|
|
4539
|
+
const line = lines[index];
|
|
4540
|
+
if (line === undefined) {
|
|
4541
|
+
continue;
|
|
4542
|
+
}
|
|
4543
|
+
const markerIndex = line.indexOf(CODEX_LOGIN_METHOD_MARKER);
|
|
4544
|
+
if (markerIndex === -1) {
|
|
4545
|
+
continue;
|
|
4546
|
+
}
|
|
4547
|
+
const reportedMethod = line.slice(markerIndex + CODEX_LOGIN_METHOD_MARKER.length).trim().toLowerCase();
|
|
4548
|
+
if (reportedMethod === 'chatgpt') {
|
|
4549
|
+
return 'chatgpt';
|
|
4550
|
+
}
|
|
4551
|
+
if (reportedMethod === 'api') {
|
|
4552
|
+
return 'api';
|
|
4553
|
+
}
|
|
4554
|
+
return 'unknown';
|
|
4555
|
+
}
|
|
4556
|
+
return 'unknown';
|
|
4557
|
+
}
|
|
4558
|
+
|
|
4037
4559
|
/**
|
|
4038
4560
|
* Error signatures that mean Codex requires credit spending to continue.
|
|
4039
4561
|
*/
|
|
@@ -4143,12 +4665,6 @@
|
|
|
4143
4665
|
* Randomized delay proportion added/subtracted for retry jitter.
|
|
4144
4666
|
*/
|
|
4145
4667
|
const RATE_LIMIT_BACKOFF_JITTER_RATIO = 0.15;
|
|
4146
|
-
/**
|
|
4147
|
-
* Waits for one given amount of milliseconds.
|
|
4148
|
-
*/
|
|
4149
|
-
async function waitFor(delayMs) {
|
|
4150
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
4151
|
-
}
|
|
4152
4668
|
/**
|
|
4153
4669
|
* Formats a delay value into a concise `xh ym zs` style label.
|
|
4154
4670
|
*/
|
|
@@ -4226,7 +4742,10 @@
|
|
|
4226
4742
|
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
4227
4743
|
});
|
|
4228
4744
|
this.rateLimitBackoff.reset();
|
|
4229
|
-
return {
|
|
4745
|
+
return {
|
|
4746
|
+
usage: buildCodexUsageFromOutput(output, this.options.model),
|
|
4747
|
+
loginMethod: parseCodexLoginMethodFromOutput(output),
|
|
4748
|
+
};
|
|
4230
4749
|
}
|
|
4231
4750
|
catch (error) {
|
|
4232
4751
|
const details = extractCodexFailureDetails(error);
|
|
@@ -4238,13 +4757,18 @@
|
|
|
4238
4757
|
throw error;
|
|
4239
4758
|
}
|
|
4240
4759
|
const delayMs = this.rateLimitBackoff.nextDelayMs();
|
|
4241
|
-
const
|
|
4760
|
+
const retryDeadlineTimeMs = Date.now() + delayMs;
|
|
4761
|
+
const retryAt = new Date(retryDeadlineTimeMs).toISOString();
|
|
4242
4762
|
const retryIndex = this.rateLimitBackoff.retryCount;
|
|
4243
4763
|
const summary = extractFailureSummary(details);
|
|
4244
4764
|
if ((_b = options.shouldPrintLiveOutput) !== null && _b !== void 0 ? _b : true) {
|
|
4245
4765
|
console.warn(colors__default["default"].yellow(`[codex] Rate limit/quota detected (${summary}). Retry #${retryIndex} in ${formatDelay(delayMs)} at ${retryAt}.`));
|
|
4246
4766
|
}
|
|
4247
|
-
await waitForRetryDelay(
|
|
4767
|
+
await waitForRetryDelay({
|
|
4768
|
+
delayMs,
|
|
4769
|
+
retryDeadlineTimeMs,
|
|
4770
|
+
promptRunOptions: options,
|
|
4771
|
+
});
|
|
4248
4772
|
}
|
|
4249
4773
|
}
|
|
4250
4774
|
}
|
|
@@ -4252,20 +4776,21 @@
|
|
|
4252
4776
|
/**
|
|
4253
4777
|
* Waits for the next Codex retry while polling for requested pause checkpoints.
|
|
4254
4778
|
*/
|
|
4255
|
-
async function waitForRetryDelay(
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4779
|
+
async function waitForRetryDelay(options) {
|
|
4780
|
+
const { delayMs, retryDeadlineTimeMs, promptRunOptions } = options;
|
|
4781
|
+
await waitUntilWorldTimeDeadline({
|
|
4782
|
+
deadlineTimeMs: retryDeadlineTimeMs,
|
|
4783
|
+
pollIntervalMs: RATE_LIMIT_BACKOFF_POLL_MS,
|
|
4784
|
+
onTick: async (remainingDelayMs) => {
|
|
4785
|
+
var _a;
|
|
4786
|
+
const remainingDelayLabel = formatDelay(Math.min(remainingDelayMs, delayMs));
|
|
4787
|
+
await ((_a = promptRunOptions.waitForPauseCheckpoint) === null || _a === void 0 ? void 0 : _a.call(promptRunOptions, {
|
|
4788
|
+
checkpointLabel: 'the next OpenAI Codex retry after rate limit',
|
|
4789
|
+
phase: 'running',
|
|
4790
|
+
statusMessage: `Waiting ${remainingDelayLabel} before retrying OpenAI Codex`,
|
|
4791
|
+
}));
|
|
4792
|
+
},
|
|
4793
|
+
});
|
|
4269
4794
|
}
|
|
4270
4795
|
|
|
4271
4796
|
/**
|
|
@@ -4403,17 +4928,6 @@
|
|
|
4403
4928
|
* Constant for cline model.
|
|
4404
4929
|
*/
|
|
4405
4930
|
const CLINE_MODEL = 'gemini:gemini-3-flash-preview';
|
|
4406
|
-
/**
|
|
4407
|
-
* Map of runner labels.
|
|
4408
|
-
*/
|
|
4409
|
-
const RUNNER_LABELS = {
|
|
4410
|
-
'openai-codex': 'OpenAI Codex',
|
|
4411
|
-
'github-copilot': 'GitHub Copilot',
|
|
4412
|
-
cline: 'Cline',
|
|
4413
|
-
'claude-code': 'Claude Code',
|
|
4414
|
-
opencode: 'Opencode',
|
|
4415
|
-
gemini: 'Gemini CLI',
|
|
4416
|
-
};
|
|
4417
4931
|
/**
|
|
4418
4932
|
* Resolves the configured prompt runner together with status-line metadata.
|
|
4419
4933
|
*
|
|
@@ -4505,8 +5019,7 @@
|
|
|
4505
5019
|
* Resolves runner metadata for prompt status lines.
|
|
4506
5020
|
*/
|
|
4507
5021
|
function getRunnerMetadata(options, actualRunnerModel) {
|
|
4508
|
-
|
|
4509
|
-
const runnerName = options.agentName ? (_a = RUNNER_LABELS[options.agentName]) !== null && _a !== void 0 ? _a : 'unknown' : 'unknown';
|
|
5022
|
+
const runnerName = options.agentName ? getHarnessDefinition(options.agentName).label : 'unknown';
|
|
4510
5023
|
if (options.agentName === 'openai-codex' ||
|
|
4511
5024
|
options.agentName === 'github-copilot' ||
|
|
4512
5025
|
options.agentName === 'gemini') {
|
|
@@ -4552,16 +5065,87 @@
|
|
|
4552
5065
|
process.exit(1);
|
|
4553
5066
|
}
|
|
4554
5067
|
|
|
5068
|
+
/**
|
|
5069
|
+
* Builds the `## Projects` prompt section explaining the agent-owned projects convention.
|
|
5070
|
+
*
|
|
5071
|
+
* The section is part of the prompt of every harness, so each coding agent knows it has its
|
|
5072
|
+
* own isolated project folders it fully controls and how to reference them in the chat.
|
|
5073
|
+
*/
|
|
5074
|
+
function buildAgentProjectsPromptSection(options = {}) {
|
|
5075
|
+
const { projectsUrlPath } = options;
|
|
5076
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
5077
|
+
## Projects
|
|
5078
|
+
|
|
5079
|
+
You have your own projects folder \`${AGENT_PROJECTS_DIRECTORY_PATH}/\` in the current working directory. Each direct subfolder of it is one project — your own isolated environment for persistent work.
|
|
5080
|
+
|
|
5081
|
+
- You have 100% control over every project folder: create, read, modify, and delete files there, run scripts and commands inside it, and keep any persistent data you need between conversations.
|
|
5082
|
+
- When the user asks you to build something (for example a website) or to do longer-term work, create a new project folder \`${AGENT_PROJECTS_DIRECTORY_PATH}/<project-name>/\` (use a short kebab-case name) and do the work inside it. Modify an existing project when the user refers to work you already did.
|
|
5083
|
+
- A project can be a git repository — you can run \`git init\` inside a project folder and commit your work there.
|
|
5084
|
+
- Do not touch anything outside the \`${AGENT_PROJECTS_DIRECTORY_PATH}/\` directory except the queued message file you are answering.
|
|
5085
|
+
|
|
5086
|
+
${block(buildProjectReferenceInstructions(projectsUrlPath))}
|
|
5087
|
+
${block(buildProjectRuntimeInstructions(options.projectRuntimeApi))}
|
|
5088
|
+
`);
|
|
5089
|
+
}
|
|
5090
|
+
/**
|
|
5091
|
+
* Builds the part of the section explaining how to reference projects in chat answers.
|
|
5092
|
+
*/
|
|
5093
|
+
function buildProjectReferenceInstructions(projectsUrlPath) {
|
|
5094
|
+
if (!projectsUrlPath) {
|
|
5095
|
+
return _spaceTrim.spaceTrim(`
|
|
5096
|
+
When you mention a project or its files in your answer, reference them by the project name and the file path inside the project, for example \`${AGENT_PROJECTS_DIRECTORY_PATH}/my-website/index.html\`.
|
|
5097
|
+
`);
|
|
5098
|
+
}
|
|
5099
|
+
return _spaceTrim.spaceTrim(`
|
|
5100
|
+
You can link any project or any file of any project into the chat answer as a markdown link:
|
|
5101
|
+
|
|
5102
|
+
- Link one file: \`[index.html](${projectsUrlPath}/<project-name>/files/<file-path>)\` — for example \`[Homepage](${projectsUrlPath}/my-website/files/index.html)\`
|
|
5103
|
+
- Link the projects dashboard listing all your projects: \`[My projects](${projectsUrlPath})\`
|
|
5104
|
+
|
|
5105
|
+
Use these links whenever you want to show the user a file you created or changed in a project.
|
|
5106
|
+
`);
|
|
5107
|
+
}
|
|
5108
|
+
/**
|
|
5109
|
+
* Builds instructions for running projects through the Agents Server runtime API.
|
|
5110
|
+
*/
|
|
5111
|
+
function buildProjectRuntimeInstructions(projectRuntimeApi) {
|
|
5112
|
+
if (!projectRuntimeApi) {
|
|
5113
|
+
return '';
|
|
5114
|
+
}
|
|
5115
|
+
return _spaceTrim.spaceTrim(`
|
|
5116
|
+
You can make a project runnable in the user's browser by asking the Agents Server to start it:
|
|
5117
|
+
|
|
5118
|
+
- The server automatically runs \`npm run dev\` for a project whose \`package.json\` declares a non-empty \`dev\` script.
|
|
5119
|
+
- Otherwise, the server starts a static file server for the project.
|
|
5120
|
+
- If you need to run your own long-lived dev process, ask only for \`assign_port\`, then start your process on the returned \`runtime.port\`.
|
|
5121
|
+
- Always include the returned \`runtime.url\` in your answer when the user should open the running project.
|
|
5122
|
+
|
|
5123
|
+
Examples:
|
|
5124
|
+
|
|
5125
|
+
\`\`\`bash
|
|
5126
|
+
curl -sS -X POST "$${projectRuntimeApi.serverUrlEnvironmentVariableName}/api/internal/agent-project-runtimes" \\
|
|
5127
|
+
-H "Content-Type: application/json" \\
|
|
5128
|
+
-H "x-user-chat-worker-token: $${projectRuntimeApi.tokenEnvironmentVariableName}" \\
|
|
5129
|
+
-d '{"action":"start","agentPermanentId":"${projectRuntimeApi.agentPermanentId}","projectName":"<project-name>"}'
|
|
5130
|
+
|
|
5131
|
+
curl -sS -X POST "$${projectRuntimeApi.serverUrlEnvironmentVariableName}/api/internal/agent-project-runtimes" \\
|
|
5132
|
+
-H "Content-Type: application/json" \\
|
|
5133
|
+
-H "x-user-chat-worker-token: $${projectRuntimeApi.tokenEnvironmentVariableName}" \\
|
|
5134
|
+
-d '{"action":"assign_port","agentPermanentId":"${projectRuntimeApi.agentPermanentId}","projectName":"<project-name>"}'
|
|
5135
|
+
\`\`\`
|
|
5136
|
+
`);
|
|
5137
|
+
}
|
|
5138
|
+
|
|
4555
5139
|
/**
|
|
4556
5140
|
* Builds the prompt sent to the selected coding runner for one queued user-thread book.
|
|
4557
5141
|
*/
|
|
4558
|
-
function buildAgentMessagePrompt(messageRelativePath, agentSystemMessage) {
|
|
5142
|
+
function buildAgentMessagePrompt(messageRelativePath, agentSystemMessage, options = {}) {
|
|
4559
5143
|
return _spaceTrim.spaceTrim((block) => `
|
|
4560
5144
|
# Answer 1 user question
|
|
4561
5145
|
|
|
4562
5146
|
- Read \`${messageRelativePath}\` and answer the most recent \`MESSAGE @User\`
|
|
4563
5147
|
- Only change the queued message file by appending one new \`MESSAGE @Agent\` block
|
|
4564
|
-
- Do not modify any other file in the repository
|
|
5148
|
+
- Do not modify any other file in the repository, except files inside your own \`${AGENT_PROJECTS_DIRECTORY_PATH}/\` directory
|
|
4565
5149
|
|
|
4566
5150
|
## Rules for the answering
|
|
4567
5151
|
|
|
@@ -4597,34 +5181,46 @@
|
|
|
4597
5181
|
|
|
4598
5182
|
- 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.
|
|
4599
5183
|
|
|
5184
|
+
${block(buildAgentProjectsPromptSection(options))}
|
|
5185
|
+
|
|
4600
5186
|
## This is how you should behave
|
|
4601
5187
|
|
|
4602
5188
|
${block(agentSystemMessage)}
|
|
4603
5189
|
`);
|
|
4604
5190
|
}
|
|
4605
5191
|
|
|
4606
|
-
/**
|
|
4607
|
-
* Builds a normalized temporary shell script path for prompt runners.
|
|
4608
|
-
*/
|
|
4609
|
-
function buildTemporaryPromptScriptPath(options) {
|
|
4610
|
-
const sourceFileName = path.basename(options.sourceFileName);
|
|
4611
|
-
const scriptFileName = `${sourceFileName.replace(/\.[^.]+$/u, '')}${options.suffix || ''}.sh`;
|
|
4612
|
-
return resolvePromptbookTemporaryPath(options.projectPath, options.scriptDirectoryName, scriptFileName);
|
|
4613
|
-
}
|
|
4614
|
-
|
|
4615
5192
|
/**
|
|
4616
5193
|
* Temporary subdirectory used for agent-message runner shell scripts.
|
|
5194
|
+
*
|
|
5195
|
+
* @private internal constant of agent-message runtime paths
|
|
4617
5196
|
*/
|
|
4618
5197
|
const AGENT_MESSAGE_SCRIPT_DIRECTORY_NAME = 'agent-messages';
|
|
5198
|
+
/**
|
|
5199
|
+
* File extension used for temporary prompt-runner shell scripts.
|
|
5200
|
+
*
|
|
5201
|
+
* @private internal constant of agent-message runtime paths
|
|
5202
|
+
*/
|
|
5203
|
+
const AGENT_MESSAGE_SCRIPT_EXTENSION = '.sh';
|
|
5204
|
+
/**
|
|
5205
|
+
* Builds the temporary shell script path used by one queued agent-message harness run.
|
|
5206
|
+
*
|
|
5207
|
+
* @param projectPath - Local agent project path containing the message queue.
|
|
5208
|
+
* @param sourceFileName - Queued message filename used to name the temporary shell script.
|
|
5209
|
+
* @returns Temporary shell script path.
|
|
5210
|
+
* @private internal utility of agent-message runners
|
|
5211
|
+
*/
|
|
5212
|
+
function buildAgentMessageScriptPathFromFileName(projectPath, sourceFileName) {
|
|
5213
|
+
const sourceFileBasename = path.basename(sourceFileName);
|
|
5214
|
+
const scriptFileName = `${sourceFileBasename.replace(/\.[^.]+$/u, '')}${AGENT_MESSAGE_SCRIPT_EXTENSION}`;
|
|
5215
|
+
return resolvePromptbookTemporaryPath(projectPath, AGENT_MESSAGE_SCRIPT_DIRECTORY_NAME, scriptFileName);
|
|
5216
|
+
}
|
|
5217
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
5218
|
+
|
|
4619
5219
|
/**
|
|
4620
5220
|
* Builds a temporary script path for one agent message runner invocation.
|
|
4621
5221
|
*/
|
|
4622
5222
|
function buildAgentMessageScriptPath(projectPath, messageFile) {
|
|
4623
|
-
return
|
|
4624
|
-
projectPath,
|
|
4625
|
-
scriptDirectoryName: AGENT_MESSAGE_SCRIPT_DIRECTORY_NAME,
|
|
4626
|
-
sourceFileName: messageFile.fileName,
|
|
4627
|
-
});
|
|
5223
|
+
return buildAgentMessageScriptPathFromFileName(projectPath, messageFile.fileName);
|
|
4628
5224
|
}
|
|
4629
5225
|
|
|
4630
5226
|
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"}];
|
|
@@ -5087,6 +5683,95 @@
|
|
|
5087
5683
|
// TODO: [🏛] Escape all
|
|
5088
5684
|
// TODO: [🧠] Should be in generated .book.md file GENERATOR_WARNING
|
|
5089
5685
|
|
|
5686
|
+
/**
|
|
5687
|
+
* This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
|
|
5688
|
+
*
|
|
5689
|
+
* @public exported from `@promptbook/core`
|
|
5690
|
+
*/
|
|
5691
|
+
class PipelineLogicError extends Error {
|
|
5692
|
+
constructor(message) {
|
|
5693
|
+
super(message);
|
|
5694
|
+
this.name = 'PipelineLogicError';
|
|
5695
|
+
Object.setPrototypeOf(this, PipelineLogicError.prototype);
|
|
5696
|
+
}
|
|
5697
|
+
}
|
|
5698
|
+
|
|
5699
|
+
/**
|
|
5700
|
+
* Creates the shared validation context for one pipeline.
|
|
5701
|
+
*
|
|
5702
|
+
* @private function of `validatePipeline`
|
|
5703
|
+
*/
|
|
5704
|
+
function createPipelineValidationContext(pipeline) {
|
|
5705
|
+
return {
|
|
5706
|
+
pipeline,
|
|
5707
|
+
pipelineIdentification: getPipelineIdentification$1(pipeline),
|
|
5708
|
+
};
|
|
5709
|
+
}
|
|
5710
|
+
/**
|
|
5711
|
+
* Builds a short file/url identification block for validation errors.
|
|
5712
|
+
*
|
|
5713
|
+
* @private internal utility of `validatePipeline`
|
|
5714
|
+
*/
|
|
5715
|
+
function getPipelineIdentification$1(pipeline) {
|
|
5716
|
+
// Note: This is a 😐 implementation of [🚞]
|
|
5717
|
+
const pipelineIdentificationParts = [];
|
|
5718
|
+
if (pipeline.sourceFile !== undefined) {
|
|
5719
|
+
pipelineIdentificationParts.push(`File: ${pipeline.sourceFile}`);
|
|
5720
|
+
}
|
|
5721
|
+
if (pipeline.pipelineUrl !== undefined) {
|
|
5722
|
+
pipelineIdentificationParts.push(`Url: ${pipeline.pipelineUrl}`);
|
|
5723
|
+
}
|
|
5724
|
+
return pipelineIdentificationParts.join('\n');
|
|
5725
|
+
}
|
|
5726
|
+
|
|
5727
|
+
/**
|
|
5728
|
+
* Validates that the expected top-level collections have array structure.
|
|
5729
|
+
*
|
|
5730
|
+
* @private function of `validatePipeline`
|
|
5731
|
+
*/
|
|
5732
|
+
function validatePipelineCollectionsStructure({ pipeline, pipelineIdentification, }) {
|
|
5733
|
+
validatePipelineParametersCollection(pipeline, pipelineIdentification);
|
|
5734
|
+
validatePipelineTasksCollection(pipeline, pipelineIdentification);
|
|
5735
|
+
}
|
|
5736
|
+
/**
|
|
5737
|
+
* Validates that `pipeline.parameters` is an array.
|
|
5738
|
+
*
|
|
5739
|
+
* @private internal utility of `validatePipelineCollectionsStructure`
|
|
5740
|
+
*/
|
|
5741
|
+
function validatePipelineParametersCollection(pipeline, pipelineIdentification) {
|
|
5742
|
+
// TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
|
|
5743
|
+
if (Array.isArray(pipeline.parameters)) {
|
|
5744
|
+
return;
|
|
5745
|
+
}
|
|
5746
|
+
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5747
|
+
throw new ParseError(_spaceTrim.spaceTrim((block) => `
|
|
5748
|
+
Pipeline is valid JSON but with wrong structure
|
|
5749
|
+
|
|
5750
|
+
\`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
|
|
5751
|
+
|
|
5752
|
+
${block(pipelineIdentification)}
|
|
5753
|
+
`));
|
|
5754
|
+
}
|
|
5755
|
+
/**
|
|
5756
|
+
* Validates that `pipeline.tasks` is an array.
|
|
5757
|
+
*
|
|
5758
|
+
* @private internal utility of `validatePipelineCollectionsStructure`
|
|
5759
|
+
*/
|
|
5760
|
+
function validatePipelineTasksCollection(pipeline, pipelineIdentification) {
|
|
5761
|
+
// TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
|
|
5762
|
+
if (Array.isArray(pipeline.tasks)) {
|
|
5763
|
+
return;
|
|
5764
|
+
}
|
|
5765
|
+
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5766
|
+
throw new ParseError(_spaceTrim.spaceTrim((block) => `
|
|
5767
|
+
Pipeline is valid JSON but with wrong structure
|
|
5768
|
+
|
|
5769
|
+
\`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
|
|
5770
|
+
|
|
5771
|
+
${block(pipelineIdentification)}
|
|
5772
|
+
`));
|
|
5773
|
+
}
|
|
5774
|
+
|
|
5090
5775
|
/**
|
|
5091
5776
|
* Order of keys in the pipeline JSON
|
|
5092
5777
|
*
|
|
@@ -5199,17 +5884,138 @@
|
|
|
5199
5884
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
5200
5885
|
|
|
5201
5886
|
/**
|
|
5202
|
-
*
|
|
5887
|
+
* Validates that task dependencies can be resolved without cycles or missing definitions.
|
|
5203
5888
|
*
|
|
5204
|
-
* @
|
|
5889
|
+
* @private function of `validatePipeline`
|
|
5205
5890
|
*/
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5891
|
+
function validatePipelineDependencyResolution({ pipeline, pipelineIdentification, }) {
|
|
5892
|
+
let dependencyResolutionState = createInitialDependencyResolutionState(pipeline);
|
|
5893
|
+
let loopLimit = LOOP_LIMIT;
|
|
5894
|
+
while (hasUnresolvedTasks(dependencyResolutionState)) {
|
|
5895
|
+
if (loopLimit-- < 0) {
|
|
5896
|
+
throw createDependencyResolutionLoopLimitError(pipelineIdentification);
|
|
5897
|
+
}
|
|
5898
|
+
dependencyResolutionState = resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification);
|
|
5211
5899
|
}
|
|
5212
5900
|
}
|
|
5901
|
+
/**
|
|
5902
|
+
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
5903
|
+
*
|
|
5904
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5905
|
+
*/
|
|
5906
|
+
function createInitialDependencyResolutionState(pipeline) {
|
|
5907
|
+
return {
|
|
5908
|
+
resolvedParameterNames: createInitiallyResolvedParameterNames(pipeline),
|
|
5909
|
+
unresolvedTasks: [...pipeline.tasks],
|
|
5910
|
+
};
|
|
5911
|
+
}
|
|
5912
|
+
/**
|
|
5913
|
+
* Checks whether dependency resolution still has tasks left to process.
|
|
5914
|
+
*
|
|
5915
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5916
|
+
*/
|
|
5917
|
+
function hasUnresolvedTasks({ unresolvedTasks }) {
|
|
5918
|
+
return unresolvedTasks.length > 0;
|
|
5919
|
+
}
|
|
5920
|
+
/**
|
|
5921
|
+
* Resolves the next batch of currently satisfiable tasks.
|
|
5922
|
+
*
|
|
5923
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5924
|
+
*/
|
|
5925
|
+
function resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification) {
|
|
5926
|
+
const currentlyResolvedTasks = getCurrentlyResolvedTasks(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames);
|
|
5927
|
+
if (currentlyResolvedTasks.length === 0) {
|
|
5928
|
+
throw createUnresolvedTasksError(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames, pipelineIdentification);
|
|
5929
|
+
}
|
|
5930
|
+
return {
|
|
5931
|
+
resolvedParameterNames: appendResolvedTaskParameterNames(dependencyResolutionState.resolvedParameterNames, currentlyResolvedTasks),
|
|
5932
|
+
unresolvedTasks: dependencyResolutionState.unresolvedTasks.filter((task) => !currentlyResolvedTasks.includes(task)),
|
|
5933
|
+
};
|
|
5934
|
+
}
|
|
5935
|
+
/**
|
|
5936
|
+
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
5937
|
+
*
|
|
5938
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5939
|
+
*/
|
|
5940
|
+
function createInitiallyResolvedParameterNames(pipeline) {
|
|
5941
|
+
let resolvedParameterNames = pipeline.parameters
|
|
5942
|
+
.filter(({ isInput }) => isInput)
|
|
5943
|
+
.map(({ name }) => name);
|
|
5944
|
+
for (const reservedParameterName of RESERVED_PARAMETER_NAMES) {
|
|
5945
|
+
resolvedParameterNames = [...resolvedParameterNames, reservedParameterName];
|
|
5946
|
+
}
|
|
5947
|
+
return resolvedParameterNames;
|
|
5948
|
+
}
|
|
5949
|
+
/**
|
|
5950
|
+
* Adds newly resolved task outputs to the resolved parameter list.
|
|
5951
|
+
*
|
|
5952
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5953
|
+
*/
|
|
5954
|
+
function appendResolvedTaskParameterNames(resolvedParameterNames, currentlyResolvedTasks) {
|
|
5955
|
+
return [
|
|
5956
|
+
...resolvedParameterNames,
|
|
5957
|
+
...currentlyResolvedTasks.map(({ resultingParameterName }) => resultingParameterName),
|
|
5958
|
+
];
|
|
5959
|
+
}
|
|
5960
|
+
/**
|
|
5961
|
+
* Selects tasks whose dependencies are already resolved.
|
|
5962
|
+
*
|
|
5963
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5964
|
+
*/
|
|
5965
|
+
function getCurrentlyResolvedTasks(unresolvedTasks, resolvedParameterNames) {
|
|
5966
|
+
return unresolvedTasks.filter((task) => task.dependentParameterNames.every((name) => resolvedParameterNames.includes(name)));
|
|
5967
|
+
}
|
|
5968
|
+
/**
|
|
5969
|
+
* Creates the unexpected loop-limit error for dependency resolution.
|
|
5970
|
+
*
|
|
5971
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5972
|
+
*/
|
|
5973
|
+
function createDependencyResolutionLoopLimitError(pipelineIdentification) {
|
|
5974
|
+
// Note: Really UnexpectedError not LimitReachedError - this should not happen and be caught below
|
|
5975
|
+
return new UnexpectedError(_spaceTrim.spaceTrim((block) => `
|
|
5976
|
+
Loop limit reached during detection of circular dependencies in \`validatePipeline\`
|
|
5977
|
+
|
|
5978
|
+
${block(pipelineIdentification)}
|
|
5979
|
+
`));
|
|
5980
|
+
}
|
|
5981
|
+
/**
|
|
5982
|
+
* Creates the detailed error for unresolved or circular task dependencies.
|
|
5983
|
+
*
|
|
5984
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5985
|
+
*/
|
|
5986
|
+
function createUnresolvedTasksError(unresolvedTasks, resolvedParameterNames, pipelineIdentification) {
|
|
5987
|
+
return new PipelineLogicError(
|
|
5988
|
+
// TODO: [🐎] DRY
|
|
5989
|
+
_spaceTrim.spaceTrim((block) => `
|
|
5990
|
+
|
|
5991
|
+
Can not resolve some parameters:
|
|
5992
|
+
Either you are using a parameter that is not defined, or there are some circular dependencies.
|
|
5993
|
+
|
|
5994
|
+
${block(pipelineIdentification)}
|
|
5995
|
+
|
|
5996
|
+
**Can not resolve:**
|
|
5997
|
+
${block(unresolvedTasks
|
|
5998
|
+
.map(({ resultingParameterName, dependentParameterNames }) => `- Parameter \`{${resultingParameterName}}\` which depends on ${dependentParameterNames
|
|
5999
|
+
.map((dependentParameterName) => `\`{${dependentParameterName}}\``)
|
|
6000
|
+
.join(' and ')}`)
|
|
6001
|
+
.join('\n'))}
|
|
6002
|
+
|
|
6003
|
+
**Resolved:**
|
|
6004
|
+
${block(resolvedParameterNames
|
|
6005
|
+
.filter((name) => !RESERVED_PARAMETER_NAMES.includes(name))
|
|
6006
|
+
.map((name) => `- Parameter \`{${name}}\``)
|
|
6007
|
+
.join('\n'))}
|
|
6008
|
+
|
|
6009
|
+
|
|
6010
|
+
**Reserved (which are available):**
|
|
6011
|
+
${block(resolvedParameterNames
|
|
6012
|
+
.filter((name) => RESERVED_PARAMETER_NAMES.includes(name))
|
|
6013
|
+
.map((name) => `- Parameter \`{${name}}\``)
|
|
6014
|
+
.join('\n'))}
|
|
6015
|
+
|
|
6016
|
+
|
|
6017
|
+
`));
|
|
6018
|
+
}
|
|
5213
6019
|
|
|
5214
6020
|
/**
|
|
5215
6021
|
* Tests if given string is valid semantic version
|
|
@@ -5285,168 +6091,19 @@
|
|
|
5285
6091
|
}
|
|
5286
6092
|
// TODO: [🐠] Maybe more info why the URL is invalid
|
|
5287
6093
|
|
|
5288
|
-
/**
|
|
5289
|
-
* Validates PipelineJson if it is logically valid
|
|
5290
|
-
*
|
|
5291
|
-
* It checks:
|
|
5292
|
-
* - if it has correct parameters dependency
|
|
5293
|
-
*
|
|
5294
|
-
* It does NOT check:
|
|
5295
|
-
* - if it is valid json
|
|
5296
|
-
* - if it is meaningful
|
|
5297
|
-
*
|
|
5298
|
-
* Note: [🔂] This function is idempotent.
|
|
5299
|
-
*
|
|
5300
|
-
* @param pipeline valid or invalid PipelineJson
|
|
5301
|
-
* @returns the same pipeline if it is logically valid
|
|
5302
|
-
* @throws {PipelineLogicError} on logical error in the pipeline
|
|
5303
|
-
*
|
|
5304
|
-
* @public exported from `@promptbook/core`
|
|
5305
|
-
*/
|
|
5306
|
-
function validatePipeline(pipeline) {
|
|
5307
|
-
if (IS_PIPELINE_LOGIC_VALIDATED) {
|
|
5308
|
-
validatePipeline_InnerFunction(pipeline);
|
|
5309
|
-
}
|
|
5310
|
-
else {
|
|
5311
|
-
try {
|
|
5312
|
-
validatePipeline_InnerFunction(pipeline);
|
|
5313
|
-
}
|
|
5314
|
-
catch (error) {
|
|
5315
|
-
if (!(error instanceof PipelineLogicError)) {
|
|
5316
|
-
throw error;
|
|
5317
|
-
}
|
|
5318
|
-
console.error(_spaceTrim.spaceTrim((block) => `
|
|
5319
|
-
Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
|
|
5320
|
-
|
|
5321
|
-
${block(error.message)}
|
|
5322
|
-
`));
|
|
5323
|
-
}
|
|
5324
|
-
}
|
|
5325
|
-
return pipeline;
|
|
5326
|
-
}
|
|
5327
|
-
/**
|
|
5328
|
-
* Validates pipeline inner function.
|
|
5329
|
-
*
|
|
5330
|
-
* @private internal function for `validatePipeline`
|
|
5331
|
-
*/
|
|
5332
|
-
function validatePipeline_InnerFunction(pipeline) {
|
|
5333
|
-
// TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
|
|
5334
|
-
const context = createPipelineValidationContext(pipeline);
|
|
5335
|
-
validatePipelineMetadata(context);
|
|
5336
|
-
validatePipelineCollectionsStructure(context);
|
|
5337
|
-
validatePipelineParameters(context);
|
|
5338
|
-
validatePipelineTasks(context);
|
|
5339
|
-
validatePipelineDependencyResolution(context);
|
|
5340
|
-
// Note: Check that formfactor is corresponding to the pipeline interface
|
|
5341
|
-
// TODO: !!6 Implement this
|
|
5342
|
-
// pipeline.formfactorName
|
|
5343
|
-
}
|
|
5344
|
-
/**
|
|
5345
|
-
* Creates the shared validation context for one pipeline.
|
|
5346
|
-
*
|
|
5347
|
-
* @private internal utility of `validatePipeline`
|
|
5348
|
-
*/
|
|
5349
|
-
function createPipelineValidationContext(pipeline) {
|
|
5350
|
-
return {
|
|
5351
|
-
pipeline,
|
|
5352
|
-
pipelineIdentification: getPipelineIdentification$1(pipeline),
|
|
5353
|
-
};
|
|
5354
|
-
}
|
|
5355
|
-
/**
|
|
5356
|
-
* Builds a short file/url identification block for validation errors.
|
|
5357
|
-
*
|
|
5358
|
-
* @private internal utility of `validatePipeline`
|
|
5359
|
-
*/
|
|
5360
|
-
function getPipelineIdentification$1(pipeline) {
|
|
5361
|
-
// Note: This is a 😐 implementation of [🚞]
|
|
5362
|
-
const pipelineIdentificationParts = [];
|
|
5363
|
-
if (pipeline.sourceFile !== undefined) {
|
|
5364
|
-
pipelineIdentificationParts.push(`File: ${pipeline.sourceFile}`);
|
|
5365
|
-
}
|
|
5366
|
-
if (pipeline.pipelineUrl !== undefined) {
|
|
5367
|
-
pipelineIdentificationParts.push(`Url: ${pipeline.pipelineUrl}`);
|
|
5368
|
-
}
|
|
5369
|
-
return pipelineIdentificationParts.join('\n');
|
|
5370
|
-
}
|
|
5371
6094
|
/**
|
|
5372
6095
|
* Validates pipeline-level metadata fields.
|
|
5373
6096
|
*
|
|
5374
|
-
* @private
|
|
6097
|
+
* @private function of `validatePipeline`
|
|
5375
6098
|
*/
|
|
5376
6099
|
function validatePipelineMetadata({ pipeline, pipelineIdentification }) {
|
|
5377
6100
|
validatePipelineUrl(pipeline, pipelineIdentification);
|
|
5378
6101
|
validatePipelineBookVersion(pipeline, pipelineIdentification);
|
|
5379
6102
|
}
|
|
5380
|
-
/**
|
|
5381
|
-
* Validates that the expected top-level collections have array structure.
|
|
5382
|
-
*
|
|
5383
|
-
* @private internal step of `validatePipeline`
|
|
5384
|
-
*/
|
|
5385
|
-
function validatePipelineCollectionsStructure({ pipeline, pipelineIdentification }) {
|
|
5386
|
-
validatePipelineParametersCollection(pipeline, pipelineIdentification);
|
|
5387
|
-
validatePipelineTasksCollection(pipeline, pipelineIdentification);
|
|
5388
|
-
}
|
|
5389
|
-
/**
|
|
5390
|
-
* Validates all pipeline parameter declarations.
|
|
5391
|
-
*
|
|
5392
|
-
* @private internal step of `validatePipeline`
|
|
5393
|
-
*/
|
|
5394
|
-
function validatePipelineParameters({ pipeline, pipelineIdentification }) {
|
|
5395
|
-
for (const parameter of pipeline.parameters) {
|
|
5396
|
-
validatePipelineParameter(parameter, pipeline, pipelineIdentification);
|
|
5397
|
-
}
|
|
5398
|
-
}
|
|
5399
|
-
/**
|
|
5400
|
-
* Validates all pipeline tasks and their per-task invariants.
|
|
5401
|
-
*
|
|
5402
|
-
* @private internal step of `validatePipeline`
|
|
5403
|
-
*/
|
|
5404
|
-
function validatePipelineTasks({ pipeline, pipelineIdentification }) {
|
|
5405
|
-
// Note: All input parameters are defined - so that they can be used as result of some task
|
|
5406
|
-
const definedParameters = createInitiallyDefinedParameters(pipeline);
|
|
5407
|
-
for (const task of pipeline.tasks) {
|
|
5408
|
-
validatePipelineTask(task, definedParameters, pipelineIdentification);
|
|
5409
|
-
}
|
|
5410
|
-
}
|
|
5411
|
-
/**
|
|
5412
|
-
* Validates that task dependencies can be resolved without cycles or missing definitions.
|
|
5413
|
-
*
|
|
5414
|
-
* @private internal step of `validatePipeline`
|
|
5415
|
-
*/
|
|
5416
|
-
function validatePipelineDependencyResolution({ pipeline, pipelineIdentification }) {
|
|
5417
|
-
let dependencyResolutionState = createInitialDependencyResolutionState(pipeline);
|
|
5418
|
-
let loopLimit = LOOP_LIMIT;
|
|
5419
|
-
while (hasUnresolvedTasks(dependencyResolutionState)) {
|
|
5420
|
-
if (loopLimit-- < 0) {
|
|
5421
|
-
throw createDependencyResolutionLoopLimitError(pipelineIdentification);
|
|
5422
|
-
}
|
|
5423
|
-
dependencyResolutionState = resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification);
|
|
5424
|
-
}
|
|
5425
|
-
}
|
|
5426
|
-
/**
|
|
5427
|
-
* Validates one pipeline parameter declaration.
|
|
5428
|
-
*
|
|
5429
|
-
* @private internal step of `validatePipeline`
|
|
5430
|
-
*/
|
|
5431
|
-
function validatePipelineParameter(parameter, pipeline, pipelineIdentification) {
|
|
5432
|
-
validateParameterDirection(parameter, pipelineIdentification);
|
|
5433
|
-
validateParameterUsage(parameter, pipeline, pipelineIdentification);
|
|
5434
|
-
validateParameterDefinition(parameter, pipeline, pipelineIdentification);
|
|
5435
|
-
}
|
|
5436
|
-
/**
|
|
5437
|
-
* Validates one pipeline task and its invariants.
|
|
5438
|
-
*
|
|
5439
|
-
* @private internal step of `validatePipeline`
|
|
5440
|
-
*/
|
|
5441
|
-
function validatePipelineTask(task, definedParameters, pipelineIdentification) {
|
|
5442
|
-
validateTaskResultingParameter(task, definedParameters, pipelineIdentification);
|
|
5443
|
-
validateTaskJokers(task, pipelineIdentification);
|
|
5444
|
-
validateTaskExpectations(task, pipelineIdentification);
|
|
5445
|
-
}
|
|
5446
6103
|
/**
|
|
5447
6104
|
* Validates the pipeline URL, when present.
|
|
5448
6105
|
*
|
|
5449
|
-
* @private internal utility of `
|
|
6106
|
+
* @private internal utility of `validatePipelineMetadata`
|
|
5450
6107
|
*/
|
|
5451
6108
|
function validatePipelineUrl(pipeline, pipelineIdentification) {
|
|
5452
6109
|
if (pipeline.pipelineUrl === undefined || isValidPipelineUrl(pipeline.pipelineUrl)) {
|
|
@@ -5462,7 +6119,7 @@
|
|
|
5462
6119
|
/**
|
|
5463
6120
|
* Validates the Promptbook version, when present.
|
|
5464
6121
|
*
|
|
5465
|
-
* @private internal utility of `
|
|
6122
|
+
* @private internal utility of `validatePipelineMetadata`
|
|
5466
6123
|
*/
|
|
5467
6124
|
function validatePipelineBookVersion(pipeline, pipelineIdentification) {
|
|
5468
6125
|
if (pipeline.bookVersion === undefined || isValidPromptbookVersion(pipeline.bookVersion)) {
|
|
@@ -5475,48 +6132,31 @@
|
|
|
5475
6132
|
${block(pipelineIdentification)}
|
|
5476
6133
|
`));
|
|
5477
6134
|
}
|
|
6135
|
+
|
|
5478
6136
|
/**
|
|
5479
|
-
* Validates
|
|
6137
|
+
* Validates all pipeline parameter declarations.
|
|
5480
6138
|
*
|
|
5481
|
-
* @private
|
|
6139
|
+
* @private function of `validatePipeline`
|
|
5482
6140
|
*/
|
|
5483
|
-
function
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
return;
|
|
6141
|
+
function validatePipelineParameters({ pipeline, pipelineIdentification }) {
|
|
6142
|
+
for (const parameter of pipeline.parameters) {
|
|
6143
|
+
validatePipelineParameter(parameter, pipeline, pipelineIdentification);
|
|
5487
6144
|
}
|
|
5488
|
-
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5489
|
-
throw new ParseError(_spaceTrim.spaceTrim((block) => `
|
|
5490
|
-
Pipeline is valid JSON but with wrong structure
|
|
5491
|
-
|
|
5492
|
-
\`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
|
|
5493
|
-
|
|
5494
|
-
${block(pipelineIdentification)}
|
|
5495
|
-
`));
|
|
5496
6145
|
}
|
|
5497
6146
|
/**
|
|
5498
|
-
* Validates
|
|
6147
|
+
* Validates one pipeline parameter declaration.
|
|
5499
6148
|
*
|
|
5500
|
-
* @private internal utility of `
|
|
6149
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5501
6150
|
*/
|
|
5502
|
-
function
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
}
|
|
5507
|
-
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5508
|
-
throw new ParseError(_spaceTrim.spaceTrim((block) => `
|
|
5509
|
-
Pipeline is valid JSON but with wrong structure
|
|
5510
|
-
|
|
5511
|
-
\`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
|
|
5512
|
-
|
|
5513
|
-
${block(pipelineIdentification)}
|
|
5514
|
-
`));
|
|
6151
|
+
function validatePipelineParameter(parameter, pipeline, pipelineIdentification) {
|
|
6152
|
+
validateParameterDirection(parameter, pipelineIdentification);
|
|
6153
|
+
validateParameterUsage(parameter, pipeline, pipelineIdentification);
|
|
6154
|
+
validateParameterDefinition(parameter, pipeline, pipelineIdentification);
|
|
5515
6155
|
}
|
|
5516
6156
|
/**
|
|
5517
6157
|
* Validates that one parameter does not declare incompatible directions.
|
|
5518
6158
|
*
|
|
5519
|
-
* @private internal utility of `
|
|
6159
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5520
6160
|
*/
|
|
5521
6161
|
function validateParameterDirection(parameter, pipelineIdentification) {
|
|
5522
6162
|
if (!parameter.isInput || !parameter.isOutput) {
|
|
@@ -5533,7 +6173,7 @@
|
|
|
5533
6173
|
/**
|
|
5534
6174
|
* Validates that one intermediate parameter is actually consumed by at least one task.
|
|
5535
6175
|
*
|
|
5536
|
-
* @private internal utility of `
|
|
6176
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5537
6177
|
*/
|
|
5538
6178
|
function validateParameterUsage(parameter, pipeline, pipelineIdentification) {
|
|
5539
6179
|
if (parameter.isInput || parameter.isOutput || isParameterUsedByAnyTask(parameter, pipeline.tasks)) {
|
|
@@ -5552,7 +6192,7 @@
|
|
|
5552
6192
|
/**
|
|
5553
6193
|
* Validates that one non-input parameter is produced by at least one task.
|
|
5554
6194
|
*
|
|
5555
|
-
* @private internal utility of `
|
|
6195
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5556
6196
|
*/
|
|
5557
6197
|
function validateParameterDefinition(parameter, pipeline, pipelineIdentification) {
|
|
5558
6198
|
if (parameter.isInput || isParameterDefinedByAnyTask(parameter, pipeline.tasks)) {
|
|
@@ -5571,7 +6211,7 @@
|
|
|
5571
6211
|
/**
|
|
5572
6212
|
* Checks whether one parameter is consumed by at least one task dependency list.
|
|
5573
6213
|
*
|
|
5574
|
-
* @private internal utility of `
|
|
6214
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5575
6215
|
*/
|
|
5576
6216
|
function isParameterUsedByAnyTask(parameter, tasks) {
|
|
5577
6217
|
return tasks.some((task) => task.dependentParameterNames.includes(parameter.name));
|
|
@@ -5579,23 +6219,46 @@
|
|
|
5579
6219
|
/**
|
|
5580
6220
|
* Checks whether one parameter is produced by at least one task.
|
|
5581
6221
|
*
|
|
5582
|
-
* @private internal utility of `
|
|
6222
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5583
6223
|
*/
|
|
5584
6224
|
function isParameterDefinedByAnyTask(parameter, tasks) {
|
|
5585
6225
|
return tasks.some((task) => task.resultingParameterName === parameter.name);
|
|
5586
6226
|
}
|
|
6227
|
+
|
|
6228
|
+
/**
|
|
6229
|
+
* Validates all pipeline tasks and their per-task invariants.
|
|
6230
|
+
*
|
|
6231
|
+
* @private function of `validatePipeline`
|
|
6232
|
+
*/
|
|
6233
|
+
function validatePipelineTasks({ pipeline, pipelineIdentification }) {
|
|
6234
|
+
// Note: All input parameters are defined - so that they can be used as result of some task
|
|
6235
|
+
const definedParameters = createInitiallyDefinedParameters(pipeline);
|
|
6236
|
+
for (const task of pipeline.tasks) {
|
|
6237
|
+
validatePipelineTask(task, definedParameters, pipelineIdentification);
|
|
6238
|
+
}
|
|
6239
|
+
}
|
|
5587
6240
|
/**
|
|
5588
6241
|
* Collects the parameter names that are already defined before task validation starts.
|
|
5589
6242
|
*
|
|
5590
|
-
* @private internal utility of `
|
|
6243
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5591
6244
|
*/
|
|
5592
6245
|
function createInitiallyDefinedParameters(pipeline) {
|
|
5593
6246
|
return new Set(pipeline.parameters.filter(({ isInput }) => isInput).map(({ name }) => name));
|
|
5594
6247
|
}
|
|
6248
|
+
/**
|
|
6249
|
+
* Validates one pipeline task and its invariants.
|
|
6250
|
+
*
|
|
6251
|
+
* @private internal utility of `validatePipelineTasks`
|
|
6252
|
+
*/
|
|
6253
|
+
function validatePipelineTask(task, definedParameters, pipelineIdentification) {
|
|
6254
|
+
validateTaskResultingParameter(task, definedParameters, pipelineIdentification);
|
|
6255
|
+
validateTaskJokers(task, pipelineIdentification);
|
|
6256
|
+
validateTaskExpectations(task, pipelineIdentification);
|
|
6257
|
+
}
|
|
5595
6258
|
/**
|
|
5596
6259
|
* Validates one task result parameter declaration and marks it as defined.
|
|
5597
6260
|
*
|
|
5598
|
-
* @private internal utility of `
|
|
6261
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5599
6262
|
*/
|
|
5600
6263
|
function validateTaskResultingParameter(task, definedParameters, pipelineIdentification) {
|
|
5601
6264
|
if (definedParameters.has(task.resultingParameterName)) {
|
|
@@ -5617,7 +6280,7 @@
|
|
|
5617
6280
|
/**
|
|
5618
6281
|
* Validates joker parameters for one task.
|
|
5619
6282
|
*
|
|
5620
|
-
* @private internal utility of `
|
|
6283
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5621
6284
|
*/
|
|
5622
6285
|
function validateTaskJokers(task, pipelineIdentification) {
|
|
5623
6286
|
if (!hasTaskJokers(task)) {
|
|
@@ -5629,7 +6292,7 @@
|
|
|
5629
6292
|
/**
|
|
5630
6293
|
* Checks whether one task declares any joker parameters.
|
|
5631
6294
|
*
|
|
5632
|
-
* @private internal utility of `
|
|
6295
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5633
6296
|
*/
|
|
5634
6297
|
function hasTaskJokers(task) {
|
|
5635
6298
|
return !!task.jokerParameterNames && task.jokerParameterNames.length > 0;
|
|
@@ -5637,7 +6300,7 @@
|
|
|
5637
6300
|
/**
|
|
5638
6301
|
* Validates that a task has the required supporting features when using jokers.
|
|
5639
6302
|
*
|
|
5640
|
-
* @private internal utility of `
|
|
6303
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5641
6304
|
*/
|
|
5642
6305
|
function validateTaskSupportsJokers(task, pipelineIdentification) {
|
|
5643
6306
|
if (task.format || task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
|
|
@@ -5652,7 +6315,7 @@
|
|
|
5652
6315
|
/**
|
|
5653
6316
|
* Validates that every joker parameter is also listed among task dependencies.
|
|
5654
6317
|
*
|
|
5655
|
-
* @private internal utility of `
|
|
6318
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5656
6319
|
*/
|
|
5657
6320
|
function validateTaskJokerDependencies(task, pipelineIdentification) {
|
|
5658
6321
|
for (const joker of task.jokerParameterNames) {
|
|
@@ -5669,7 +6332,7 @@
|
|
|
5669
6332
|
/**
|
|
5670
6333
|
* Validates all expectation bounds configured on one task.
|
|
5671
6334
|
*
|
|
5672
|
-
* @private internal utility of `
|
|
6335
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5673
6336
|
*/
|
|
5674
6337
|
function validateTaskExpectations(task, pipelineIdentification) {
|
|
5675
6338
|
if (!task.expectations) {
|
|
@@ -5684,7 +6347,7 @@
|
|
|
5684
6347
|
/**
|
|
5685
6348
|
* Validates the minimum and maximum expectation ordering for one unit.
|
|
5686
6349
|
*
|
|
5687
|
-
* @private internal utility of `
|
|
6350
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5688
6351
|
*/
|
|
5689
6352
|
function validateTaskExpectationRange(unit, min, max, pipelineIdentification) {
|
|
5690
6353
|
if (min === undefined || max === undefined || min <= max) {
|
|
@@ -5699,7 +6362,7 @@
|
|
|
5699
6362
|
/**
|
|
5700
6363
|
* Validates the minimum expectation bound for one unit.
|
|
5701
6364
|
*
|
|
5702
|
-
* @private internal utility of `
|
|
6365
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5703
6366
|
*/
|
|
5704
6367
|
function validateTaskExpectationMin(unit, min, pipelineIdentification) {
|
|
5705
6368
|
if (min === undefined || min >= 0) {
|
|
@@ -5714,7 +6377,7 @@
|
|
|
5714
6377
|
/**
|
|
5715
6378
|
* Validates the maximum expectation bound for one unit.
|
|
5716
6379
|
*
|
|
5717
|
-
* @private internal utility of `
|
|
6380
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5718
6381
|
*/
|
|
5719
6382
|
function validateTaskExpectationMax(unit, max, pipelineIdentification) {
|
|
5720
6383
|
if (max === undefined || max > 0) {
|
|
@@ -5726,123 +6389,62 @@
|
|
|
5726
6389
|
${block(pipelineIdentification)}
|
|
5727
6390
|
`));
|
|
5728
6391
|
}
|
|
6392
|
+
|
|
5729
6393
|
/**
|
|
5730
|
-
*
|
|
5731
|
-
*
|
|
5732
|
-
* @private internal utility of `validatePipeline`
|
|
5733
|
-
*/
|
|
5734
|
-
function createInitialDependencyResolutionState(pipeline) {
|
|
5735
|
-
return {
|
|
5736
|
-
resolvedParameterNames: createInitiallyResolvedParameterNames(pipeline),
|
|
5737
|
-
unresolvedTasks: [...pipeline.tasks],
|
|
5738
|
-
};
|
|
5739
|
-
}
|
|
5740
|
-
/**
|
|
5741
|
-
* Checks whether dependency resolution still has tasks left to process.
|
|
5742
|
-
*
|
|
5743
|
-
* @private internal utility of `validatePipeline`
|
|
5744
|
-
*/
|
|
5745
|
-
function hasUnresolvedTasks({ unresolvedTasks }) {
|
|
5746
|
-
return unresolvedTasks.length > 0;
|
|
5747
|
-
}
|
|
5748
|
-
/**
|
|
5749
|
-
* Resolves the next batch of currently satisfiable tasks.
|
|
6394
|
+
* Validates PipelineJson if it is logically valid
|
|
5750
6395
|
*
|
|
5751
|
-
*
|
|
5752
|
-
|
|
5753
|
-
function resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification) {
|
|
5754
|
-
const currentlyResolvedTasks = getCurrentlyResolvedTasks(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames);
|
|
5755
|
-
if (currentlyResolvedTasks.length === 0) {
|
|
5756
|
-
throw createUnresolvedTasksError(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames, pipelineIdentification);
|
|
5757
|
-
}
|
|
5758
|
-
return {
|
|
5759
|
-
resolvedParameterNames: appendResolvedTaskParameterNames(dependencyResolutionState.resolvedParameterNames, currentlyResolvedTasks),
|
|
5760
|
-
unresolvedTasks: dependencyResolutionState.unresolvedTasks.filter((task) => !currentlyResolvedTasks.includes(task)),
|
|
5761
|
-
};
|
|
5762
|
-
}
|
|
5763
|
-
/**
|
|
5764
|
-
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
6396
|
+
* It checks:
|
|
6397
|
+
* - if it has correct parameters dependency
|
|
5765
6398
|
*
|
|
5766
|
-
*
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
let resolvedParameterNames = pipeline.parameters
|
|
5770
|
-
.filter(({ isInput }) => isInput)
|
|
5771
|
-
.map(({ name }) => name);
|
|
5772
|
-
for (const reservedParameterName of RESERVED_PARAMETER_NAMES) {
|
|
5773
|
-
resolvedParameterNames = [...resolvedParameterNames, reservedParameterName];
|
|
5774
|
-
}
|
|
5775
|
-
return resolvedParameterNames;
|
|
5776
|
-
}
|
|
5777
|
-
/**
|
|
5778
|
-
* Adds newly resolved task outputs to the resolved parameter list.
|
|
6399
|
+
* It does NOT check:
|
|
6400
|
+
* - if it is valid json
|
|
6401
|
+
* - if it is meaningful
|
|
5779
6402
|
*
|
|
5780
|
-
*
|
|
5781
|
-
*/
|
|
5782
|
-
function appendResolvedTaskParameterNames(resolvedParameterNames, currentlyResolvedTasks) {
|
|
5783
|
-
return [
|
|
5784
|
-
...resolvedParameterNames,
|
|
5785
|
-
...currentlyResolvedTasks.map(({ resultingParameterName }) => resultingParameterName),
|
|
5786
|
-
];
|
|
5787
|
-
}
|
|
5788
|
-
/**
|
|
5789
|
-
* Selects tasks whose dependencies are already resolved.
|
|
6403
|
+
* Note: [🔂] This function is idempotent.
|
|
5790
6404
|
*
|
|
5791
|
-
* @
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
return unresolvedTasks.filter((task) => task.dependentParameterNames.every((name) => resolvedParameterNames.includes(name)));
|
|
5795
|
-
}
|
|
5796
|
-
/**
|
|
5797
|
-
* Creates the unexpected loop-limit error for dependency resolution.
|
|
6405
|
+
* @param pipeline valid or invalid PipelineJson
|
|
6406
|
+
* @returns the same pipeline if it is logically valid
|
|
6407
|
+
* @throws {PipelineLogicError} on logical error in the pipeline
|
|
5798
6408
|
*
|
|
5799
|
-
* @
|
|
6409
|
+
* @public exported from `@promptbook/core`
|
|
5800
6410
|
*/
|
|
5801
|
-
function
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
6411
|
+
function validatePipeline(pipeline) {
|
|
6412
|
+
if (IS_PIPELINE_LOGIC_VALIDATED) {
|
|
6413
|
+
validatePipeline_InnerFunction(pipeline);
|
|
6414
|
+
}
|
|
6415
|
+
else {
|
|
6416
|
+
try {
|
|
6417
|
+
validatePipeline_InnerFunction(pipeline);
|
|
6418
|
+
}
|
|
6419
|
+
catch (error) {
|
|
6420
|
+
if (!(error instanceof PipelineLogicError)) {
|
|
6421
|
+
throw error;
|
|
6422
|
+
}
|
|
6423
|
+
console.error(_spaceTrim.spaceTrim((block) => `
|
|
6424
|
+
Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
|
|
5805
6425
|
|
|
5806
|
-
|
|
5807
|
-
|
|
6426
|
+
${block(error.message)}
|
|
6427
|
+
`));
|
|
6428
|
+
}
|
|
6429
|
+
}
|
|
6430
|
+
return pipeline;
|
|
5808
6431
|
}
|
|
5809
6432
|
/**
|
|
5810
|
-
*
|
|
6433
|
+
* Validates pipeline inner function.
|
|
5811
6434
|
*
|
|
5812
|
-
* @private internal
|
|
6435
|
+
* @private internal function for `validatePipeline`
|
|
5813
6436
|
*/
|
|
5814
|
-
function
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
${block(unresolvedTasks
|
|
5826
|
-
.map(({ resultingParameterName, dependentParameterNames }) => `- Parameter \`{${resultingParameterName}}\` which depends on ${dependentParameterNames
|
|
5827
|
-
.map((dependentParameterName) => `\`{${dependentParameterName}}\``)
|
|
5828
|
-
.join(' and ')}`)
|
|
5829
|
-
.join('\n'))}
|
|
5830
|
-
|
|
5831
|
-
**Resolved:**
|
|
5832
|
-
${block(resolvedParameterNames
|
|
5833
|
-
.filter((name) => !RESERVED_PARAMETER_NAMES.includes(name))
|
|
5834
|
-
.map((name) => `- Parameter \`{${name}}\``)
|
|
5835
|
-
.join('\n'))}
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
**Reserved (which are available):**
|
|
5839
|
-
${block(resolvedParameterNames
|
|
5840
|
-
.filter((name) => RESERVED_PARAMETER_NAMES.includes(name))
|
|
5841
|
-
.map((name) => `- Parameter \`{${name}}\``)
|
|
5842
|
-
.join('\n'))}
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
`));
|
|
6437
|
+
function validatePipeline_InnerFunction(pipeline) {
|
|
6438
|
+
// TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
|
|
6439
|
+
const context = createPipelineValidationContext(pipeline);
|
|
6440
|
+
validatePipelineMetadata(context);
|
|
6441
|
+
validatePipelineCollectionsStructure(context);
|
|
6442
|
+
validatePipelineParameters(context);
|
|
6443
|
+
validatePipelineTasks(context);
|
|
6444
|
+
validatePipelineDependencyResolution(context);
|
|
6445
|
+
// Note: Check that formfactor is corresponding to the pipeline interface
|
|
6446
|
+
// TODO: !!6 Implement this
|
|
6447
|
+
// pipeline.formfactorName
|
|
5846
6448
|
}
|
|
5847
6449
|
/**
|
|
5848
6450
|
* TODO: [🧞♀️] Do not allow joker + foreach
|
|
@@ -14162,13 +14764,14 @@
|
|
|
14162
14764
|
* META commitment definition
|
|
14163
14765
|
*
|
|
14164
14766
|
* The META commitment handles all meta-information about the agent such as:
|
|
14165
|
-
* - META AVATAR: Sets the agent's built-in default avatar visual
|
|
14767
|
+
* - META AVATAR / META VISUAL: Sets the agent's built-in default avatar visual
|
|
14166
14768
|
* - META IMAGE: Sets the agent's avatar/profile image URL
|
|
14167
14769
|
* - META LINK: Provides profile/source links for the person the agent models
|
|
14168
14770
|
* - META DOMAIN: Sets the canonical custom domain/host of the agent
|
|
14169
14771
|
* - META TITLE: Sets the agent's display title
|
|
14170
14772
|
* - META DESCRIPTION: Sets the agent's description
|
|
14171
14773
|
* - META INPUT PLACEHOLDER: Sets chat input placeholder text
|
|
14774
|
+
* - META THINKING MESSAGE: Adds custom thinking placeholder variants
|
|
14172
14775
|
* - META [ANYTHING]: Any other meta information in uppercase format
|
|
14173
14776
|
*
|
|
14174
14777
|
* These commitments are special because they don't affect the system message,
|
|
@@ -14177,13 +14780,14 @@
|
|
|
14177
14780
|
* Example usage in agent source:
|
|
14178
14781
|
*
|
|
14179
14782
|
* ```book
|
|
14180
|
-
* META
|
|
14783
|
+
* META VISUAL pixel-art
|
|
14181
14784
|
* META IMAGE https://example.com/avatar.jpg
|
|
14182
14785
|
* META LINK https://twitter.com/username
|
|
14183
14786
|
* META DOMAIN my-agent.com
|
|
14184
14787
|
* META TITLE Professional Assistant
|
|
14185
14788
|
* META DESCRIPTION An AI assistant specialized in business tasks
|
|
14186
14789
|
* META INPUT PLACEHOLDER Write a message...
|
|
14790
|
+
* META THINKING MESSAGE Thinking...
|
|
14187
14791
|
* META AUTHOR John Doe
|
|
14188
14792
|
* META VERSION 1.0
|
|
14189
14793
|
* ```
|
|
@@ -14217,13 +14821,14 @@
|
|
|
14217
14821
|
|
|
14218
14822
|
## Supported META types
|
|
14219
14823
|
|
|
14220
|
-
- **META AVATAR** - Sets the agent's built-in default avatar visual
|
|
14824
|
+
- **META AVATAR** / **META VISUAL** - Sets the agent's built-in default avatar visual
|
|
14221
14825
|
- **META IMAGE** - Sets the agent's avatar/profile image URL
|
|
14222
14826
|
- **META LINK** - Provides profile/source links for the person the agent models
|
|
14223
14827
|
- **META DOMAIN** - Sets the canonical custom domain/host of the agent
|
|
14224
14828
|
- **META TITLE** - Sets the agent's display title
|
|
14225
14829
|
- **META DESCRIPTION** - Sets the agent's description
|
|
14226
14830
|
- **META INPUT PLACEHOLDER** - Sets chat input placeholder text
|
|
14831
|
+
- **META THINKING MESSAGE** - Adds custom thinking placeholder variants
|
|
14227
14832
|
- **META [ANYTHING]** - Any other meta information in uppercase format
|
|
14228
14833
|
|
|
14229
14834
|
## Key aspects
|
|
@@ -14232,6 +14837,7 @@
|
|
|
14232
14837
|
- Used for visual representation and attribution in user interfaces
|
|
14233
14838
|
- Multiple META commitments of different types can be used
|
|
14234
14839
|
- Multiple META LINK commitments can be used for different social profiles
|
|
14840
|
+
- Multiple META THINKING MESSAGE commitments can be used for different thinking placeholder variants
|
|
14235
14841
|
- If multiple META commitments of the same type are specified, the last one takes precedence (except for LINK)
|
|
14236
14842
|
|
|
14237
14843
|
## Examples
|
|
@@ -14241,7 +14847,7 @@
|
|
|
14241
14847
|
\`\`\`book
|
|
14242
14848
|
Professional Assistant
|
|
14243
14849
|
|
|
14244
|
-
META
|
|
14850
|
+
META VISUAL octopus3
|
|
14245
14851
|
META IMAGE https://example.com/professional-avatar.jpg
|
|
14246
14852
|
META TITLE Senior Business Consultant
|
|
14247
14853
|
META DESCRIPTION Specialized in strategic planning and project management
|
|
@@ -17412,452 +18018,13 @@
|
|
|
17412
18018
|
.padStart(2, '0');
|
|
17413
18019
|
}
|
|
17414
18020
|
|
|
17415
|
-
/* eslint-disable no-magic-numbers */
|
|
17416
|
-
/**
|
|
17417
|
-
* Light direction used by the organic 3D octopus shading.
|
|
17418
|
-
*
|
|
17419
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17420
|
-
*/
|
|
17421
|
-
const LIGHT_DIRECTION$3 = normalizeVector3({
|
|
17422
|
-
x: 0.48,
|
|
17423
|
-
y: -0.62,
|
|
17424
|
-
z: 0.94,
|
|
17425
|
-
});
|
|
17426
|
-
/**
|
|
17427
|
-
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
17428
|
-
*
|
|
17429
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17430
|
-
*/
|
|
17431
|
-
const octopus3dStableStateCache = new WeakMap();
|
|
17432
|
-
/**
|
|
17433
|
-
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
17434
|
-
*
|
|
17435
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17436
|
-
*/
|
|
17437
|
-
function getOctopus3dStableState(createRandom) {
|
|
17438
|
-
const cached = octopus3dStableStateCache.get(createRandom);
|
|
17439
|
-
if (cached !== undefined) {
|
|
17440
|
-
return cached;
|
|
17441
|
-
}
|
|
17442
|
-
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
17443
|
-
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
17444
|
-
const leftEyePhaseOffset = eyeRandom() * 0.6;
|
|
17445
|
-
const rightEyePhaseOffset = eyeRandom() * 0.6;
|
|
17446
|
-
const state = {
|
|
17447
|
-
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
17448
|
-
animationPhase: animationRandom() * Math.PI * 2,
|
|
17449
|
-
leftEyePhaseOffset,
|
|
17450
|
-
rightEyePhaseOffset,
|
|
17451
|
-
};
|
|
17452
|
-
octopus3dStableStateCache.set(createRandom, state);
|
|
17453
|
-
return state;
|
|
17454
|
-
}
|
|
17455
|
-
/**
|
|
17456
|
-
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
17457
|
-
*
|
|
17458
|
-
* @private built-in avatar visual
|
|
17459
|
-
*/
|
|
17460
|
-
const octopus3dAvatarVisual = {
|
|
17461
|
-
id: 'octopus3d',
|
|
17462
|
-
title: 'Octopus 3D',
|
|
17463
|
-
description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
|
|
17464
|
-
isAnimated: true,
|
|
17465
|
-
supportsPointerTracking: true,
|
|
17466
|
-
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
17467
|
-
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
|
|
17468
|
-
const sceneCenterX = size * 0.5;
|
|
17469
|
-
const sceneCenterY = size * 0.56;
|
|
17470
|
-
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
17471
|
-
const mantleCenter = {
|
|
17472
|
-
x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
|
|
17473
|
-
y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
17474
|
-
z: interaction.intensity * size * 0.012,
|
|
17475
|
-
};
|
|
17476
|
-
const underbodyCenter = {
|
|
17477
|
-
x: mantleCenter.x * 0.86,
|
|
17478
|
-
y: mantleCenter.y + size * 0.168,
|
|
17479
|
-
z: mantleCenter.z - size * 0.018,
|
|
17480
|
-
};
|
|
17481
|
-
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
17482
|
-
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
17483
|
-
const mantleRadiusZ = size *
|
|
17484
|
-
morphologyProfile.body.bodyRadiusRatio *
|
|
17485
|
-
(0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
17486
|
-
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
17487
|
-
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
17488
|
-
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
17489
|
-
const bodyYaw = -0.18 +
|
|
17490
|
-
Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
|
|
17491
|
-
interaction.bodyOffsetX * 0.18 +
|
|
17492
|
-
interaction.gazeX * 0.22;
|
|
17493
|
-
const bodyPitch = -0.08 +
|
|
17494
|
-
Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
|
|
17495
|
-
interaction.bodyOffsetY * 0.08 -
|
|
17496
|
-
interaction.gazeY * 0.08;
|
|
17497
|
-
const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
|
|
17498
|
-
const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
|
|
17499
|
-
const mantlePatches = resolveVisibleEllipsoidPatches({
|
|
17500
|
-
center: mantleCenter,
|
|
17501
|
-
radiusX: mantleRadiusX,
|
|
17502
|
-
radiusY: mantleRadiusY,
|
|
17503
|
-
radiusZ: mantleRadiusZ,
|
|
17504
|
-
rotationX: headPitch,
|
|
17505
|
-
rotationY: headYaw,
|
|
17506
|
-
sceneCenterX,
|
|
17507
|
-
sceneCenterY,
|
|
17508
|
-
size,
|
|
17509
|
-
palette,
|
|
17510
|
-
verticalColorBias: 0,
|
|
17511
|
-
outlineColor: `${palette.highlight}7a`,
|
|
17512
|
-
});
|
|
17513
|
-
const underbodyPatches = resolveVisibleEllipsoidPatches({
|
|
17514
|
-
center: underbodyCenter,
|
|
17515
|
-
radiusX: underbodyRadiusX,
|
|
17516
|
-
radiusY: underbodyRadiusY,
|
|
17517
|
-
radiusZ: underbodyRadiusZ,
|
|
17518
|
-
rotationX: bodyPitch,
|
|
17519
|
-
rotationY: bodyYaw,
|
|
17520
|
-
sceneCenterX,
|
|
17521
|
-
sceneCenterY,
|
|
17522
|
-
size,
|
|
17523
|
-
palette,
|
|
17524
|
-
verticalColorBias: 0.18,
|
|
17525
|
-
outlineColor: `${palette.shadow}8f`,
|
|
17526
|
-
});
|
|
17527
|
-
const tentacleStrokes = createOctopusTentacleStrokes({
|
|
17528
|
-
createRandom,
|
|
17529
|
-
morphologyProfile,
|
|
17530
|
-
timeMs,
|
|
17531
|
-
size,
|
|
17532
|
-
center: underbodyCenter,
|
|
17533
|
-
radiusX: underbodyRadiusX,
|
|
17534
|
-
radiusY: underbodyRadiusY,
|
|
17535
|
-
radiusZ: underbodyRadiusZ,
|
|
17536
|
-
rotationX: bodyPitch,
|
|
17537
|
-
rotationY: bodyYaw,
|
|
17538
|
-
sceneCenterX,
|
|
17539
|
-
sceneCenterY,
|
|
17540
|
-
animationPhase,
|
|
17541
|
-
});
|
|
17542
|
-
const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
|
|
17543
|
-
const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
|
|
17544
|
-
const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
|
|
17545
|
-
const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
|
|
17546
|
-
const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
|
|
17547
|
-
const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
|
|
17548
|
-
drawAvatarFrame(context, size, palette);
|
|
17549
|
-
drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
17550
|
-
drawOctopus3dShadow(context, size, palette, interaction, timeMs);
|
|
17551
|
-
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
|
|
17552
|
-
drawTentacleStroke(context, tentacleStroke, palette);
|
|
17553
|
-
}
|
|
17554
|
-
for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
17555
|
-
drawSurfacePatch(context, surfacePatch);
|
|
17556
|
-
}
|
|
17557
|
-
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
17558
|
-
drawTentacleStroke(context, tentacleStroke, palette);
|
|
17559
|
-
}
|
|
17560
|
-
drawProjectedOrganicEye(context, {
|
|
17561
|
-
x: -faceEyeSpacing,
|
|
17562
|
-
y: faceEyeYOffset,
|
|
17563
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
17564
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
17565
|
-
drawProjectedOrganicEye(context, {
|
|
17566
|
-
x: faceEyeSpacing,
|
|
17567
|
-
y: faceEyeYOffset,
|
|
17568
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
17569
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
17570
|
-
drawProjectedOrganicMouth(context, [
|
|
17571
|
-
{
|
|
17572
|
-
x: -mouthHalfWidth,
|
|
17573
|
-
y: mouthY,
|
|
17574
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY),
|
|
17575
|
-
},
|
|
17576
|
-
{
|
|
17577
|
-
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
17578
|
-
y: mouthY +
|
|
17579
|
-
size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
|
|
17580
|
-
Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
|
|
17581
|
-
interaction.gazeY * size * 0.01,
|
|
17582
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
17583
|
-
},
|
|
17584
|
-
{
|
|
17585
|
-
x: mouthHalfWidth,
|
|
17586
|
-
y: mouthY,
|
|
17587
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY),
|
|
17588
|
-
},
|
|
17589
|
-
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
17590
|
-
},
|
|
17591
|
-
};
|
|
17592
|
-
/**
|
|
17593
|
-
* Draws the atmospheric underwater glow behind the octopus mesh.
|
|
17594
|
-
*
|
|
17595
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17596
|
-
*/
|
|
17597
|
-
function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
17598
|
-
const glowGradient = context.createRadialGradient(sceneCenterX + interaction.gazeX * size * 0.1, sceneCenterY - size * 0.2 + interaction.gazeY * size * 0.05, size * 0.04, sceneCenterX, sceneCenterY - size * 0.04, size * 0.62);
|
|
17599
|
-
glowGradient.addColorStop(0, `${palette.highlight}5c`);
|
|
17600
|
-
glowGradient.addColorStop(0.36, `${palette.accent}24`);
|
|
17601
|
-
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
17602
|
-
context.fillStyle = glowGradient;
|
|
17603
|
-
context.fillRect(0, 0, size, size);
|
|
17604
|
-
const lowerGradient = context.createRadialGradient(sceneCenterX + Math.sin(timeMs / 1700) * size * 0.05, sceneCenterY + size * 0.23, size * 0.08, sceneCenterX, sceneCenterY + size * 0.28, size * 0.5);
|
|
17605
|
-
lowerGradient.addColorStop(0, `${palette.secondary}1d`);
|
|
17606
|
-
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
17607
|
-
context.fillStyle = lowerGradient;
|
|
17608
|
-
context.fillRect(0, 0, size, size);
|
|
17609
|
-
}
|
|
17610
|
-
/**
|
|
17611
|
-
* Draws the soft ground shadow below the octopus.
|
|
17612
|
-
*
|
|
17613
|
-
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
17614
|
-
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
17615
|
-
*
|
|
17616
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17617
|
-
*/
|
|
17618
|
-
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
17619
|
-
const cx = size * 0.5 + interaction.gazeX * size * 0.04;
|
|
17620
|
-
const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
|
|
17621
|
-
const rx = size * (0.18 + interaction.intensity * 0.02);
|
|
17622
|
-
const ry = size * 0.06;
|
|
17623
|
-
context.save();
|
|
17624
|
-
context.translate(cx, cy);
|
|
17625
|
-
context.scale(1, ry / rx);
|
|
17626
|
-
const blurRadius = rx * 1.4;
|
|
17627
|
-
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
17628
|
-
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
17629
|
-
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
17630
|
-
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
17631
|
-
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
17632
|
-
context.fillStyle = shadowGradient;
|
|
17633
|
-
context.beginPath();
|
|
17634
|
-
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
17635
|
-
context.fill();
|
|
17636
|
-
context.restore();
|
|
17637
|
-
}
|
|
17638
|
-
/**
|
|
17639
|
-
* Resolves visible projected patches for one rotated ellipsoid mesh.
|
|
17640
|
-
*
|
|
17641
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17642
|
-
*/
|
|
17643
|
-
function resolveVisibleEllipsoidPatches(options) {
|
|
17644
|
-
const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
|
|
17645
|
-
const latitudePatchCount = 10;
|
|
17646
|
-
const longitudePatchCount = 18;
|
|
17647
|
-
const surfacePatches = [];
|
|
17648
|
-
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
17649
|
-
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
17650
|
-
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
17651
|
-
const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
|
|
17652
|
-
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
17653
|
-
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
17654
|
-
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
17655
|
-
const localCorners = [
|
|
17656
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
|
|
17657
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
|
|
17658
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
|
|
17659
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
|
|
17660
|
-
];
|
|
17661
|
-
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
17662
|
-
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
17663
|
-
if (surfaceNormal.z <= 0.01) {
|
|
17664
|
-
continue;
|
|
17665
|
-
}
|
|
17666
|
-
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
17667
|
-
surfacePatches.push({
|
|
17668
|
-
corners: projectedCorners,
|
|
17669
|
-
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
17670
|
-
transformedCorners.length,
|
|
17671
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$3), -1, 1),
|
|
17672
|
-
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
17673
|
-
outlineColor,
|
|
17674
|
-
});
|
|
17675
|
-
}
|
|
17676
|
-
}
|
|
17677
|
-
return surfacePatches;
|
|
17678
|
-
}
|
|
17679
|
-
/**
|
|
17680
|
-
* Samples one point on an ellipsoid aligned to the local axes.
|
|
17681
|
-
*
|
|
17682
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17683
|
-
*/
|
|
17684
|
-
function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
|
|
17685
|
-
const cosineLatitude = Math.cos(latitude);
|
|
17686
|
-
return {
|
|
17687
|
-
x: Math.sin(longitude) * cosineLatitude * radiusX,
|
|
17688
|
-
y: Math.sin(latitude) * radiusY,
|
|
17689
|
-
z: Math.cos(longitude) * cosineLatitude * radiusZ,
|
|
17690
|
-
};
|
|
17691
|
-
}
|
|
17692
|
-
/**
|
|
17693
|
-
* Resolves one base fill tone for a surface patch across the octopus body.
|
|
17694
|
-
*
|
|
17695
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17696
|
-
*/
|
|
17697
|
-
function resolveSurfacePatchFillStyle(palette, verticalProgress) {
|
|
17698
|
-
const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
|
|
17699
|
-
if (clampedVerticalProgress < 0.2) {
|
|
17700
|
-
return palette.highlight;
|
|
17701
|
-
}
|
|
17702
|
-
if (clampedVerticalProgress < 0.45) {
|
|
17703
|
-
return palette.secondary;
|
|
17704
|
-
}
|
|
17705
|
-
if (clampedVerticalProgress < 0.8) {
|
|
17706
|
-
return palette.primary;
|
|
17707
|
-
}
|
|
17708
|
-
return `${palette.shadow}f2`;
|
|
17709
|
-
}
|
|
17710
|
-
/**
|
|
17711
|
-
* Draws one projected mesh patch with organic shading.
|
|
17712
|
-
*
|
|
17713
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17714
|
-
*/
|
|
17715
|
-
function drawSurfacePatch(context, surfacePatch) {
|
|
17716
|
-
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
17717
|
-
if (surfacePatch.lightIntensity > 0) {
|
|
17718
|
-
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
|
|
17719
|
-
}
|
|
17720
|
-
else if (surfacePatch.lightIntensity < 0) {
|
|
17721
|
-
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
17722
|
-
}
|
|
17723
|
-
context.save();
|
|
17724
|
-
context.beginPath();
|
|
17725
|
-
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
17726
|
-
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
17727
|
-
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
17728
|
-
}
|
|
17729
|
-
context.closePath();
|
|
17730
|
-
context.strokeStyle = surfacePatch.outlineColor;
|
|
17731
|
-
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
|
|
17732
|
-
context.lineJoin = 'round';
|
|
17733
|
-
context.stroke();
|
|
17734
|
-
context.restore();
|
|
17735
|
-
}
|
|
17736
|
-
/**
|
|
17737
|
-
* Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
|
|
17738
|
-
*
|
|
17739
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17740
|
-
*/
|
|
17741
|
-
function createOctopusTentacleStrokes(options) {
|
|
17742
|
-
const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
|
|
17743
|
-
return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
|
|
17744
|
-
const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
|
|
17745
|
-
const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
|
|
17746
|
-
const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
|
|
17747
|
-
const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
|
|
17748
|
-
const lateralReach = size *
|
|
17749
|
-
(0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
|
|
17750
|
-
const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
|
|
17751
|
-
const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
|
|
17752
|
-
const anchorPoint = {
|
|
17753
|
-
x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
|
|
17754
|
-
y: radiusY * (0.22 + tentacleRandom() * 0.18),
|
|
17755
|
-
z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
|
|
17756
|
-
};
|
|
17757
|
-
const controlPointOne = {
|
|
17758
|
-
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
|
|
17759
|
-
y: anchorPoint.y + flowLength * 0.26,
|
|
17760
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
17761
|
-
};
|
|
17762
|
-
const controlPointTwo = {
|
|
17763
|
-
x: anchorPoint.x +
|
|
17764
|
-
Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
17765
|
-
y: anchorPoint.y + flowLength * 0.66,
|
|
17766
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
17767
|
-
};
|
|
17768
|
-
const endPoint = {
|
|
17769
|
-
x: anchorPoint.x +
|
|
17770
|
-
Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
|
|
17771
|
-
sway * size * 0.028,
|
|
17772
|
-
y: anchorPoint.y + flowLength,
|
|
17773
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
|
|
17774
|
-
};
|
|
17775
|
-
const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
|
|
17776
|
-
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
17777
|
-
const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
|
|
17778
|
-
return {
|
|
17779
|
-
projectedPoints,
|
|
17780
|
-
averageDepth,
|
|
17781
|
-
isFrontFacing: averageDepth >= center.z - size * 0.006,
|
|
17782
|
-
baseWidth: size *
|
|
17783
|
-
(0.019 +
|
|
17784
|
-
morphologyProfile.tentacles.baseWidthScale * 0.007 +
|
|
17785
|
-
tentacleRandom() * 0.003 +
|
|
17786
|
-
Math.abs(Math.sin(orbitAngle)) * 0.002),
|
|
17787
|
-
tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
|
|
17788
|
-
colorBias: tentacleRandom(),
|
|
17789
|
-
};
|
|
17790
|
-
});
|
|
17791
|
-
}
|
|
17792
|
-
/**
|
|
17793
|
-
* Samples one point on a cubic Bezier curve in 3D.
|
|
17794
|
-
*
|
|
17795
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17796
|
-
*/
|
|
17797
|
-
function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
|
|
17798
|
-
const inverseProgress = 1 - progress;
|
|
17799
|
-
return {
|
|
17800
|
-
x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
|
|
17801
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
|
|
17802
|
-
3 * inverseProgress * progress * progress * controlPointTwo.x +
|
|
17803
|
-
progress * progress * progress * endPoint.x,
|
|
17804
|
-
y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
|
|
17805
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
|
|
17806
|
-
3 * inverseProgress * progress * progress * controlPointTwo.y +
|
|
17807
|
-
progress * progress * progress * endPoint.y,
|
|
17808
|
-
z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
|
|
17809
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
|
|
17810
|
-
3 * inverseProgress * progress * progress * controlPointTwo.z +
|
|
17811
|
-
progress * progress * progress * endPoint.z,
|
|
17812
|
-
};
|
|
17813
|
-
}
|
|
17814
|
-
/**
|
|
17815
|
-
* Draws one projected tentacle stroke with a slim highlight ridge.
|
|
17816
|
-
*
|
|
17817
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17818
|
-
*/
|
|
17819
|
-
function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
17820
|
-
const projectedSegments = tentacleStroke.projectedPoints.length - 1;
|
|
17821
|
-
for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
|
|
17822
|
-
const startPoint = tentacleStroke.projectedPoints[segmentIndex];
|
|
17823
|
-
const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
|
|
17824
|
-
const progress = segmentIndex / projectedSegments;
|
|
17825
|
-
const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
|
|
17826
|
-
context.beginPath();
|
|
17827
|
-
context.moveTo(startPoint.x, startPoint.y);
|
|
17828
|
-
context.lineTo(endPoint.x, endPoint.y);
|
|
17829
|
-
context.strokeStyle = tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
17830
|
-
context.lineWidth = width;
|
|
17831
|
-
context.lineCap = 'round';
|
|
17832
|
-
context.stroke();
|
|
17833
|
-
context.beginPath();
|
|
17834
|
-
context.moveTo(startPoint.x, startPoint.y);
|
|
17835
|
-
context.lineTo(endPoint.x, endPoint.y);
|
|
17836
|
-
context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
|
|
17837
|
-
context.lineWidth = Math.max(1, width * 0.34);
|
|
17838
|
-
context.lineCap = 'round';
|
|
17839
|
-
context.stroke();
|
|
17840
|
-
}
|
|
17841
|
-
}
|
|
17842
|
-
/**
|
|
17843
|
-
* Resolves the front surface depth on an ellipsoid for one local face point.
|
|
17844
|
-
*
|
|
17845
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17846
|
-
*/
|
|
17847
|
-
function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
17848
|
-
const normalizedX = x / radiusX;
|
|
17849
|
-
const normalizedY = y / radiusY;
|
|
17850
|
-
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
17851
|
-
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
17852
|
-
}
|
|
17853
|
-
|
|
17854
18021
|
/* eslint-disable no-magic-numbers */
|
|
17855
18022
|
/**
|
|
17856
18023
|
* Light direction used by the single-mesh octopus shading.
|
|
17857
18024
|
*
|
|
17858
18025
|
* @private helper of `octopus3d2AvatarVisual`
|
|
17859
18026
|
*/
|
|
17860
|
-
const LIGHT_DIRECTION$
|
|
18027
|
+
const LIGHT_DIRECTION$3 = normalizeVector3({
|
|
17861
18028
|
x: 0.38,
|
|
17862
18029
|
y: -0.6,
|
|
17863
18030
|
z: 0.98,
|
|
@@ -18096,7 +18263,7 @@
|
|
|
18096
18263
|
transformedCorners[2].z +
|
|
18097
18264
|
transformedCorners[3].z) /
|
|
18098
18265
|
4,
|
|
18099
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$
|
|
18266
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$3), -1, 1),
|
|
18100
18267
|
fillStyle: resolveBlobbySurfacePatchFillStyle$1(palette, verticalProgress, Math.max(0, Math.cos(centerLongitude)), resolveLowerLobeWave(centerLongitude, morphologyProfile, animationPhase, timeMs)),
|
|
18101
18268
|
outlineColor: verticalProgress < 0.58 ? `${palette.highlight}73` : `${palette.shadow}8a`,
|
|
18102
18269
|
});
|
|
@@ -18211,7 +18378,7 @@
|
|
|
18211
18378
|
*
|
|
18212
18379
|
* @private helper of `octopus3d3AvatarVisual`
|
|
18213
18380
|
*/
|
|
18214
|
-
const LIGHT_DIRECTION$
|
|
18381
|
+
const LIGHT_DIRECTION$2 = normalizeVector3({
|
|
18215
18382
|
x: 0.34,
|
|
18216
18383
|
y: -0.62,
|
|
18217
18384
|
z: 1,
|
|
@@ -18518,7 +18685,7 @@
|
|
|
18518
18685
|
transformedCorners[2].z +
|
|
18519
18686
|
transformedCorners[3].z) /
|
|
18520
18687
|
4,
|
|
18521
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$
|
|
18688
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$2), -1, 1),
|
|
18522
18689
|
fillStyle: resolveContinuousSurfacePatchFillStyle(palette, verticalProgress, cachedCosByPatchCenterLongitude[longitudeIndex], cachedTentacleInfluencesByPatchCenterLongitude[longitudeIndex].core, cachedLobeWavesByPatchCenterLongitude[longitudeIndex]),
|
|
18523
18690
|
outlineColor: verticalProgress < 0.54 ? `${palette.highlight}69` : `${palette.shadow}78`,
|
|
18524
18691
|
});
|
|
@@ -18833,7 +19000,7 @@
|
|
|
18833
19000
|
*
|
|
18834
19001
|
* @private helper of `octopus3d4AvatarVisual`
|
|
18835
19002
|
*/
|
|
18836
|
-
const LIGHT_DIRECTION = normalizeVector3({
|
|
19003
|
+
const LIGHT_DIRECTION$1 = normalizeVector3({
|
|
18837
19004
|
x: 0.32,
|
|
18838
19005
|
y: -0.66,
|
|
18839
19006
|
z: 1,
|
|
@@ -19179,7 +19346,7 @@
|
|
|
19179
19346
|
projectScenePoint(transformedCorners[2], size, sceneCenterX, sceneCenterY),
|
|
19180
19347
|
projectScenePoint(transformedCorners[3], size, sceneCenterX, sceneCenterY),
|
|
19181
19348
|
];
|
|
19182
|
-
const lightIntensity = clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1);
|
|
19349
|
+
const lightIntensity = clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$1), -1, 1);
|
|
19183
19350
|
const rimLightIntensity = Math.pow(clampNumber$1(dotProduct3D(surfaceNormal, RIM_LIGHT_DIRECTION), 0, 1), 2.6);
|
|
19184
19351
|
surfacePatches.push({
|
|
19185
19352
|
corners: projectedCorners,
|
|
@@ -19578,6 +19745,445 @@
|
|
|
19578
19745
|
.padStart(2, '0');
|
|
19579
19746
|
}
|
|
19580
19747
|
|
|
19748
|
+
/* eslint-disable no-magic-numbers */
|
|
19749
|
+
/**
|
|
19750
|
+
* Light direction used by the organic 3D octopus shading.
|
|
19751
|
+
*
|
|
19752
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19753
|
+
*/
|
|
19754
|
+
const LIGHT_DIRECTION = normalizeVector3({
|
|
19755
|
+
x: 0.48,
|
|
19756
|
+
y: -0.62,
|
|
19757
|
+
z: 0.94,
|
|
19758
|
+
});
|
|
19759
|
+
/**
|
|
19760
|
+
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
19761
|
+
*
|
|
19762
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19763
|
+
*/
|
|
19764
|
+
const octopus3dStableStateCache = new WeakMap();
|
|
19765
|
+
/**
|
|
19766
|
+
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
19767
|
+
*
|
|
19768
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19769
|
+
*/
|
|
19770
|
+
function getOctopus3dStableState(createRandom) {
|
|
19771
|
+
const cached = octopus3dStableStateCache.get(createRandom);
|
|
19772
|
+
if (cached !== undefined) {
|
|
19773
|
+
return cached;
|
|
19774
|
+
}
|
|
19775
|
+
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
19776
|
+
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
19777
|
+
const leftEyePhaseOffset = eyeRandom() * 0.6;
|
|
19778
|
+
const rightEyePhaseOffset = eyeRandom() * 0.6;
|
|
19779
|
+
const state = {
|
|
19780
|
+
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
19781
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
19782
|
+
leftEyePhaseOffset,
|
|
19783
|
+
rightEyePhaseOffset,
|
|
19784
|
+
};
|
|
19785
|
+
octopus3dStableStateCache.set(createRandom, state);
|
|
19786
|
+
return state;
|
|
19787
|
+
}
|
|
19788
|
+
/**
|
|
19789
|
+
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
19790
|
+
*
|
|
19791
|
+
* @private built-in avatar visual
|
|
19792
|
+
*/
|
|
19793
|
+
const octopus3dAvatarVisual = {
|
|
19794
|
+
id: 'octopus3d',
|
|
19795
|
+
title: 'Octopus 3D',
|
|
19796
|
+
description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
|
|
19797
|
+
isAnimated: true,
|
|
19798
|
+
supportsPointerTracking: true,
|
|
19799
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
19800
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
|
|
19801
|
+
const sceneCenterX = size * 0.5;
|
|
19802
|
+
const sceneCenterY = size * 0.56;
|
|
19803
|
+
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
19804
|
+
const mantleCenter = {
|
|
19805
|
+
x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
|
|
19806
|
+
y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
19807
|
+
z: interaction.intensity * size * 0.012,
|
|
19808
|
+
};
|
|
19809
|
+
const underbodyCenter = {
|
|
19810
|
+
x: mantleCenter.x * 0.86,
|
|
19811
|
+
y: mantleCenter.y + size * 0.168,
|
|
19812
|
+
z: mantleCenter.z - size * 0.018,
|
|
19813
|
+
};
|
|
19814
|
+
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
19815
|
+
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
19816
|
+
const mantleRadiusZ = size *
|
|
19817
|
+
morphologyProfile.body.bodyRadiusRatio *
|
|
19818
|
+
(0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
19819
|
+
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
19820
|
+
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
19821
|
+
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
19822
|
+
const bodyYaw = -0.18 +
|
|
19823
|
+
Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
|
|
19824
|
+
interaction.bodyOffsetX * 0.18 +
|
|
19825
|
+
interaction.gazeX * 0.22;
|
|
19826
|
+
const bodyPitch = -0.08 +
|
|
19827
|
+
Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
|
|
19828
|
+
interaction.bodyOffsetY * 0.08 -
|
|
19829
|
+
interaction.gazeY * 0.08;
|
|
19830
|
+
const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
|
|
19831
|
+
const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
|
|
19832
|
+
const mantlePatches = resolveVisibleEllipsoidPatches({
|
|
19833
|
+
center: mantleCenter,
|
|
19834
|
+
radiusX: mantleRadiusX,
|
|
19835
|
+
radiusY: mantleRadiusY,
|
|
19836
|
+
radiusZ: mantleRadiusZ,
|
|
19837
|
+
rotationX: headPitch,
|
|
19838
|
+
rotationY: headYaw,
|
|
19839
|
+
sceneCenterX,
|
|
19840
|
+
sceneCenterY,
|
|
19841
|
+
size,
|
|
19842
|
+
palette,
|
|
19843
|
+
verticalColorBias: 0,
|
|
19844
|
+
outlineColor: `${palette.highlight}7a`,
|
|
19845
|
+
});
|
|
19846
|
+
const underbodyPatches = resolveVisibleEllipsoidPatches({
|
|
19847
|
+
center: underbodyCenter,
|
|
19848
|
+
radiusX: underbodyRadiusX,
|
|
19849
|
+
radiusY: underbodyRadiusY,
|
|
19850
|
+
radiusZ: underbodyRadiusZ,
|
|
19851
|
+
rotationX: bodyPitch,
|
|
19852
|
+
rotationY: bodyYaw,
|
|
19853
|
+
sceneCenterX,
|
|
19854
|
+
sceneCenterY,
|
|
19855
|
+
size,
|
|
19856
|
+
palette,
|
|
19857
|
+
verticalColorBias: 0.18,
|
|
19858
|
+
outlineColor: `${palette.shadow}8f`,
|
|
19859
|
+
});
|
|
19860
|
+
const tentacleStrokes = createOctopusTentacleStrokes({
|
|
19861
|
+
createRandom,
|
|
19862
|
+
morphologyProfile,
|
|
19863
|
+
timeMs,
|
|
19864
|
+
size,
|
|
19865
|
+
center: underbodyCenter,
|
|
19866
|
+
radiusX: underbodyRadiusX,
|
|
19867
|
+
radiusY: underbodyRadiusY,
|
|
19868
|
+
radiusZ: underbodyRadiusZ,
|
|
19869
|
+
rotationX: bodyPitch,
|
|
19870
|
+
rotationY: bodyYaw,
|
|
19871
|
+
sceneCenterX,
|
|
19872
|
+
sceneCenterY,
|
|
19873
|
+
animationPhase,
|
|
19874
|
+
});
|
|
19875
|
+
const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
|
|
19876
|
+
const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
|
|
19877
|
+
const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
|
|
19878
|
+
const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
|
|
19879
|
+
const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
|
|
19880
|
+
const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
|
|
19881
|
+
drawAvatarFrame(context, size, palette);
|
|
19882
|
+
drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
19883
|
+
drawOctopus3dShadow(context, size, palette, interaction, timeMs);
|
|
19884
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
|
|
19885
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
19886
|
+
}
|
|
19887
|
+
for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
19888
|
+
drawSurfacePatch(context, surfacePatch);
|
|
19889
|
+
}
|
|
19890
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
19891
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
19892
|
+
}
|
|
19893
|
+
drawProjectedOrganicEye(context, {
|
|
19894
|
+
x: -faceEyeSpacing,
|
|
19895
|
+
y: faceEyeYOffset,
|
|
19896
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
19897
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
19898
|
+
drawProjectedOrganicEye(context, {
|
|
19899
|
+
x: faceEyeSpacing,
|
|
19900
|
+
y: faceEyeYOffset,
|
|
19901
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
19902
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
19903
|
+
drawProjectedOrganicMouth(context, [
|
|
19904
|
+
{
|
|
19905
|
+
x: -mouthHalfWidth,
|
|
19906
|
+
y: mouthY,
|
|
19907
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY),
|
|
19908
|
+
},
|
|
19909
|
+
{
|
|
19910
|
+
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
19911
|
+
y: mouthY +
|
|
19912
|
+
size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
|
|
19913
|
+
Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
|
|
19914
|
+
interaction.gazeY * size * 0.01,
|
|
19915
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
19916
|
+
},
|
|
19917
|
+
{
|
|
19918
|
+
x: mouthHalfWidth,
|
|
19919
|
+
y: mouthY,
|
|
19920
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY),
|
|
19921
|
+
},
|
|
19922
|
+
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
19923
|
+
},
|
|
19924
|
+
};
|
|
19925
|
+
/**
|
|
19926
|
+
* Draws the atmospheric underwater glow behind the octopus mesh.
|
|
19927
|
+
*
|
|
19928
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19929
|
+
*/
|
|
19930
|
+
function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
19931
|
+
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);
|
|
19932
|
+
glowGradient.addColorStop(0, `${palette.highlight}5c`);
|
|
19933
|
+
glowGradient.addColorStop(0.36, `${palette.accent}24`);
|
|
19934
|
+
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
19935
|
+
context.fillStyle = glowGradient;
|
|
19936
|
+
context.fillRect(0, 0, size, size);
|
|
19937
|
+
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);
|
|
19938
|
+
lowerGradient.addColorStop(0, `${palette.secondary}1d`);
|
|
19939
|
+
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
19940
|
+
context.fillStyle = lowerGradient;
|
|
19941
|
+
context.fillRect(0, 0, size, size);
|
|
19942
|
+
}
|
|
19943
|
+
/**
|
|
19944
|
+
* Draws the soft ground shadow below the octopus.
|
|
19945
|
+
*
|
|
19946
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
19947
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
19948
|
+
*
|
|
19949
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19950
|
+
*/
|
|
19951
|
+
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
19952
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.04;
|
|
19953
|
+
const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
|
|
19954
|
+
const rx = size * (0.18 + interaction.intensity * 0.02);
|
|
19955
|
+
const ry = size * 0.06;
|
|
19956
|
+
context.save();
|
|
19957
|
+
context.translate(cx, cy);
|
|
19958
|
+
context.scale(1, ry / rx);
|
|
19959
|
+
const blurRadius = rx * 1.4;
|
|
19960
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
19961
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
19962
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
19963
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
19964
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
19965
|
+
context.fillStyle = shadowGradient;
|
|
19966
|
+
context.beginPath();
|
|
19967
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
19968
|
+
context.fill();
|
|
19969
|
+
context.restore();
|
|
19970
|
+
}
|
|
19971
|
+
/**
|
|
19972
|
+
* Resolves visible projected patches for one rotated ellipsoid mesh.
|
|
19973
|
+
*
|
|
19974
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19975
|
+
*/
|
|
19976
|
+
function resolveVisibleEllipsoidPatches(options) {
|
|
19977
|
+
const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
|
|
19978
|
+
const latitudePatchCount = 10;
|
|
19979
|
+
const longitudePatchCount = 18;
|
|
19980
|
+
const surfacePatches = [];
|
|
19981
|
+
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
19982
|
+
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
19983
|
+
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
19984
|
+
const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
|
|
19985
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
19986
|
+
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
19987
|
+
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
19988
|
+
const localCorners = [
|
|
19989
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
|
|
19990
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
|
|
19991
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
|
|
19992
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
|
|
19993
|
+
];
|
|
19994
|
+
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
19995
|
+
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
19996
|
+
if (surfaceNormal.z <= 0.01) {
|
|
19997
|
+
continue;
|
|
19998
|
+
}
|
|
19999
|
+
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
20000
|
+
surfacePatches.push({
|
|
20001
|
+
corners: projectedCorners,
|
|
20002
|
+
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
20003
|
+
transformedCorners.length,
|
|
20004
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
20005
|
+
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
20006
|
+
outlineColor,
|
|
20007
|
+
});
|
|
20008
|
+
}
|
|
20009
|
+
}
|
|
20010
|
+
return surfacePatches;
|
|
20011
|
+
}
|
|
20012
|
+
/**
|
|
20013
|
+
* Samples one point on an ellipsoid aligned to the local axes.
|
|
20014
|
+
*
|
|
20015
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20016
|
+
*/
|
|
20017
|
+
function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
|
|
20018
|
+
const cosineLatitude = Math.cos(latitude);
|
|
20019
|
+
return {
|
|
20020
|
+
x: Math.sin(longitude) * cosineLatitude * radiusX,
|
|
20021
|
+
y: Math.sin(latitude) * radiusY,
|
|
20022
|
+
z: Math.cos(longitude) * cosineLatitude * radiusZ,
|
|
20023
|
+
};
|
|
20024
|
+
}
|
|
20025
|
+
/**
|
|
20026
|
+
* Resolves one base fill tone for a surface patch across the octopus body.
|
|
20027
|
+
*
|
|
20028
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20029
|
+
*/
|
|
20030
|
+
function resolveSurfacePatchFillStyle(palette, verticalProgress) {
|
|
20031
|
+
const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
|
|
20032
|
+
if (clampedVerticalProgress < 0.2) {
|
|
20033
|
+
return palette.highlight;
|
|
20034
|
+
}
|
|
20035
|
+
if (clampedVerticalProgress < 0.45) {
|
|
20036
|
+
return palette.secondary;
|
|
20037
|
+
}
|
|
20038
|
+
if (clampedVerticalProgress < 0.8) {
|
|
20039
|
+
return palette.primary;
|
|
20040
|
+
}
|
|
20041
|
+
return `${palette.shadow}f2`;
|
|
20042
|
+
}
|
|
20043
|
+
/**
|
|
20044
|
+
* Draws one projected mesh patch with organic shading.
|
|
20045
|
+
*
|
|
20046
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20047
|
+
*/
|
|
20048
|
+
function drawSurfacePatch(context, surfacePatch) {
|
|
20049
|
+
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
20050
|
+
if (surfacePatch.lightIntensity > 0) {
|
|
20051
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
|
|
20052
|
+
}
|
|
20053
|
+
else if (surfacePatch.lightIntensity < 0) {
|
|
20054
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
20055
|
+
}
|
|
20056
|
+
context.save();
|
|
20057
|
+
context.beginPath();
|
|
20058
|
+
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
20059
|
+
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
20060
|
+
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
20061
|
+
}
|
|
20062
|
+
context.closePath();
|
|
20063
|
+
context.strokeStyle = surfacePatch.outlineColor;
|
|
20064
|
+
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
|
|
20065
|
+
context.lineJoin = 'round';
|
|
20066
|
+
context.stroke();
|
|
20067
|
+
context.restore();
|
|
20068
|
+
}
|
|
20069
|
+
/**
|
|
20070
|
+
* Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
|
|
20071
|
+
*
|
|
20072
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20073
|
+
*/
|
|
20074
|
+
function createOctopusTentacleStrokes(options) {
|
|
20075
|
+
const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
|
|
20076
|
+
return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
|
|
20077
|
+
const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
|
|
20078
|
+
const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
|
|
20079
|
+
const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
|
|
20080
|
+
const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
|
|
20081
|
+
const lateralReach = size *
|
|
20082
|
+
(0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
|
|
20083
|
+
const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
|
|
20084
|
+
const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
|
|
20085
|
+
const anchorPoint = {
|
|
20086
|
+
x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
|
|
20087
|
+
y: radiusY * (0.22 + tentacleRandom() * 0.18),
|
|
20088
|
+
z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
|
|
20089
|
+
};
|
|
20090
|
+
const controlPointOne = {
|
|
20091
|
+
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
|
|
20092
|
+
y: anchorPoint.y + flowLength * 0.26,
|
|
20093
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
20094
|
+
};
|
|
20095
|
+
const controlPointTwo = {
|
|
20096
|
+
x: anchorPoint.x +
|
|
20097
|
+
Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
20098
|
+
y: anchorPoint.y + flowLength * 0.66,
|
|
20099
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
20100
|
+
};
|
|
20101
|
+
const endPoint = {
|
|
20102
|
+
x: anchorPoint.x +
|
|
20103
|
+
Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
|
|
20104
|
+
sway * size * 0.028,
|
|
20105
|
+
y: anchorPoint.y + flowLength,
|
|
20106
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
|
|
20107
|
+
};
|
|
20108
|
+
const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
|
|
20109
|
+
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
20110
|
+
const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
|
|
20111
|
+
return {
|
|
20112
|
+
projectedPoints,
|
|
20113
|
+
averageDepth,
|
|
20114
|
+
isFrontFacing: averageDepth >= center.z - size * 0.006,
|
|
20115
|
+
baseWidth: size *
|
|
20116
|
+
(0.019 +
|
|
20117
|
+
morphologyProfile.tentacles.baseWidthScale * 0.007 +
|
|
20118
|
+
tentacleRandom() * 0.003 +
|
|
20119
|
+
Math.abs(Math.sin(orbitAngle)) * 0.002),
|
|
20120
|
+
tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
|
|
20121
|
+
colorBias: tentacleRandom(),
|
|
20122
|
+
};
|
|
20123
|
+
});
|
|
20124
|
+
}
|
|
20125
|
+
/**
|
|
20126
|
+
* Samples one point on a cubic Bezier curve in 3D.
|
|
20127
|
+
*
|
|
20128
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20129
|
+
*/
|
|
20130
|
+
function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
|
|
20131
|
+
const inverseProgress = 1 - progress;
|
|
20132
|
+
return {
|
|
20133
|
+
x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
|
|
20134
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
|
|
20135
|
+
3 * inverseProgress * progress * progress * controlPointTwo.x +
|
|
20136
|
+
progress * progress * progress * endPoint.x,
|
|
20137
|
+
y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
|
|
20138
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
|
|
20139
|
+
3 * inverseProgress * progress * progress * controlPointTwo.y +
|
|
20140
|
+
progress * progress * progress * endPoint.y,
|
|
20141
|
+
z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
|
|
20142
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
|
|
20143
|
+
3 * inverseProgress * progress * progress * controlPointTwo.z +
|
|
20144
|
+
progress * progress * progress * endPoint.z,
|
|
20145
|
+
};
|
|
20146
|
+
}
|
|
20147
|
+
/**
|
|
20148
|
+
* Draws one projected tentacle stroke with a slim highlight ridge.
|
|
20149
|
+
*
|
|
20150
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20151
|
+
*/
|
|
20152
|
+
function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
20153
|
+
const projectedSegments = tentacleStroke.projectedPoints.length - 1;
|
|
20154
|
+
for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
|
|
20155
|
+
const startPoint = tentacleStroke.projectedPoints[segmentIndex];
|
|
20156
|
+
const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
|
|
20157
|
+
const progress = segmentIndex / projectedSegments;
|
|
20158
|
+
const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
|
|
20159
|
+
context.beginPath();
|
|
20160
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
20161
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
20162
|
+
context.strokeStyle = tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
20163
|
+
context.lineWidth = width;
|
|
20164
|
+
context.lineCap = 'round';
|
|
20165
|
+
context.stroke();
|
|
20166
|
+
context.beginPath();
|
|
20167
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
20168
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
20169
|
+
context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
|
|
20170
|
+
context.lineWidth = Math.max(1, width * 0.34);
|
|
20171
|
+
context.lineCap = 'round';
|
|
20172
|
+
context.stroke();
|
|
20173
|
+
}
|
|
20174
|
+
}
|
|
20175
|
+
/**
|
|
20176
|
+
* Resolves the front surface depth on an ellipsoid for one local face point.
|
|
20177
|
+
*
|
|
20178
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20179
|
+
*/
|
|
20180
|
+
function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
20181
|
+
const normalizedX = x / radiusX;
|
|
20182
|
+
const normalizedY = y / radiusY;
|
|
20183
|
+
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
20184
|
+
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
20185
|
+
}
|
|
20186
|
+
|
|
19581
20187
|
/* eslint-disable no-magic-numbers */
|
|
19582
20188
|
/**
|
|
19583
20189
|
* Octopus avatar visual.
|
|
@@ -20398,14 +21004,14 @@
|
|
|
20398
21004
|
/**
|
|
20399
21005
|
* META AVATAR commitment definition
|
|
20400
21006
|
*
|
|
20401
|
-
* The `META AVATAR`
|
|
20402
|
-
* the agent does not provide an explicit `META IMAGE`.
|
|
21007
|
+
* The `META AVATAR` and `META VISUAL` commitments set the built-in default avatar visual
|
|
21008
|
+
* used when the agent does not provide an explicit `META IMAGE`.
|
|
20403
21009
|
*
|
|
20404
21010
|
* @private [🪔] Maybe export the commitments through some package
|
|
20405
21011
|
*/
|
|
20406
21012
|
class MetaAvatarCommitmentDefinition extends BaseCommitmentDefinition {
|
|
20407
|
-
constructor() {
|
|
20408
|
-
super(
|
|
21013
|
+
constructor(type = 'META AVATAR') {
|
|
21014
|
+
super(type);
|
|
20409
21015
|
}
|
|
20410
21016
|
/**
|
|
20411
21017
|
* Short one-line description of META AVATAR.
|
|
@@ -20425,14 +21031,15 @@
|
|
|
20425
21031
|
get documentation() {
|
|
20426
21032
|
const supportedVisuals = AVATAR_VISUALS.map((avatarVisual) => `\`${avatarVisual.id}\``).join(', ');
|
|
20427
21033
|
return _spaceTrim.spaceTrim(`
|
|
20428
|
-
#
|
|
21034
|
+
# ${this.type}
|
|
20429
21035
|
|
|
20430
21036
|
Sets the built-in avatar visual used for the agent when no explicit \`META IMAGE\` is provided.
|
|
21037
|
+
\`META AVATAR\` and \`META VISUAL\` are equivalent.
|
|
20431
21038
|
|
|
20432
21039
|
## Key aspects
|
|
20433
21040
|
|
|
20434
21041
|
- Does not modify the agent's behavior or responses.
|
|
20435
|
-
- Only one \`META AVATAR\` should be used per agent.
|
|
21042
|
+
- Only one \`META AVATAR\` or \`META VISUAL\` should be used per agent.
|
|
20436
21043
|
- If multiple are specified, the last one takes precedence.
|
|
20437
21044
|
- Values are matched case-insensitively and spaces, hyphens, and underscores are normalized.
|
|
20438
21045
|
- Supported visuals are derived from the shared avatar registry: ${supportedVisuals}.
|
|
@@ -20447,15 +21054,15 @@
|
|
|
20447
21054
|
\`\`\`
|
|
20448
21055
|
|
|
20449
21056
|
\`\`\`book
|
|
20450
|
-
|
|
21057
|
+
Minecraft Assistant
|
|
20451
21058
|
|
|
20452
|
-
META
|
|
21059
|
+
META VISUAL Minecraft2
|
|
20453
21060
|
GOAL Answer in a calm and focused way.
|
|
20454
21061
|
\`\`\`
|
|
20455
21062
|
`);
|
|
20456
21063
|
}
|
|
20457
21064
|
applyToAgentModelRequirements(requirements, content) {
|
|
20458
|
-
// META AVATAR
|
|
21065
|
+
// META AVATAR and META VISUAL don't modify the system message or model requirements.
|
|
20459
21066
|
// It's handled separately in the parsing logic for profile avatar resolution.
|
|
20460
21067
|
return requirements;
|
|
20461
21068
|
}
|
|
@@ -21029,6 +21636,68 @@
|
|
|
21029
21636
|
}
|
|
21030
21637
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
21031
21638
|
|
|
21639
|
+
/**
|
|
21640
|
+
* META THINKING MESSAGE commitment definition.
|
|
21641
|
+
*
|
|
21642
|
+
* The `META THINKING MESSAGE` commitment adds one custom thinking placeholder
|
|
21643
|
+
* variant used by chat UIs while an agent is composing a reply.
|
|
21644
|
+
*
|
|
21645
|
+
* @private Metadata-only commitment used by Agents Server chat UIs.
|
|
21646
|
+
*/
|
|
21647
|
+
class MetaThinkingMessageCommitmentDefinition extends BaseCommitmentDefinition {
|
|
21648
|
+
constructor() {
|
|
21649
|
+
super('META THINKING MESSAGE');
|
|
21650
|
+
}
|
|
21651
|
+
/**
|
|
21652
|
+
* Short one-line description of META THINKING MESSAGE.
|
|
21653
|
+
*/
|
|
21654
|
+
get description() {
|
|
21655
|
+
return 'Add a custom thinking placeholder shown while the agent replies.';
|
|
21656
|
+
}
|
|
21657
|
+
/**
|
|
21658
|
+
* Icon for this commitment.
|
|
21659
|
+
*/
|
|
21660
|
+
get icon() {
|
|
21661
|
+
return '💭';
|
|
21662
|
+
}
|
|
21663
|
+
/**
|
|
21664
|
+
* Markdown documentation for META THINKING MESSAGE commitment.
|
|
21665
|
+
*/
|
|
21666
|
+
get documentation() {
|
|
21667
|
+
return _spaceTrim.spaceTrim(`
|
|
21668
|
+
# META THINKING MESSAGE
|
|
21669
|
+
|
|
21670
|
+
Adds one custom placeholder variant shown while the agent is composing a reply.
|
|
21671
|
+
|
|
21672
|
+
## Key aspects
|
|
21673
|
+
|
|
21674
|
+
- Does not modify model behavior, system message, or tools.
|
|
21675
|
+
- Multiple \`META THINKING MESSAGE\` commitments define multiple variants.
|
|
21676
|
+
- Chat UIs randomly rotate between the configured variants while the reply is running.
|
|
21677
|
+
- When no non-empty variants are configured, the server-level \`THINKING_MESSAGES\` metadata is used.
|
|
21678
|
+
- Supports multiline markdown content.
|
|
21679
|
+
|
|
21680
|
+
## Example
|
|
21681
|
+
|
|
21682
|
+
\`\`\`book
|
|
21683
|
+
Helpful Assistant
|
|
21684
|
+
|
|
21685
|
+
META THINKING MESSAGE Thinking...
|
|
21686
|
+
META THINKING MESSAGE Processing...
|
|
21687
|
+
META THINKING MESSAGE
|
|
21688
|
+
|
|
21689
|
+
Doing
|
|
21690
|
+
extra **hard** work
|
|
21691
|
+
\`\`\`
|
|
21692
|
+
`);
|
|
21693
|
+
}
|
|
21694
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
21695
|
+
// META THINKING MESSAGE is metadata only and does not alter model requirements.
|
|
21696
|
+
return requirements;
|
|
21697
|
+
}
|
|
21698
|
+
}
|
|
21699
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
21700
|
+
|
|
21032
21701
|
/**
|
|
21033
21702
|
* META VISIBILITY commitment definition.
|
|
21034
21703
|
*
|
|
@@ -23107,6 +23776,7 @@
|
|
|
23107
23776
|
1. **One-shot URL fetching**: Simple function to fetch and scrape URL content (active)
|
|
23108
23777
|
2. **Running browser**: For complex tasks like scrolling, clicking, form filling, etc. (runtime-dependent)
|
|
23109
23778
|
- The actual browser tool usage is handled by the agent runtime
|
|
23779
|
+
- On the Agents Server, every agent browses in its own persistent isolated browser profile, so cookies and logged-in sessions survive across chats (the profile is linked from the agent wallet)
|
|
23110
23780
|
- Allows the agent to fetch current information from websites and documents
|
|
23111
23781
|
- Useful for research tasks, fact-checking, and accessing dynamic content
|
|
23112
23782
|
- Supports various content types including HTML pages and PDF documents
|
|
@@ -29643,6 +30313,7 @@
|
|
|
29643
30313
|
new ActionCommitmentDefinition('ACTIONS'),
|
|
29644
30314
|
new ComponentCommitmentDefinition(),
|
|
29645
30315
|
new MetaAvatarCommitmentDefinition(),
|
|
30316
|
+
new MetaAvatarCommitmentDefinition('META VISUAL'),
|
|
29646
30317
|
new MetaImageCommitmentDefinition(),
|
|
29647
30318
|
new MetaColorCommitmentDefinition(),
|
|
29648
30319
|
new MetaFontCommitmentDefinition(),
|
|
@@ -29650,6 +30321,7 @@
|
|
|
29650
30321
|
new MetaDomainCommitmentDefinition(),
|
|
29651
30322
|
new MetaDisclaimerCommitmentDefinition(),
|
|
29652
30323
|
new MetaInputPlaceholderCommitmentDefinition(),
|
|
30324
|
+
new MetaThinkingMessageCommitmentDefinition(),
|
|
29653
30325
|
new MetaVisibilityCommitmentDefinition(),
|
|
29654
30326
|
new MetaCommitmentDefinition(),
|
|
29655
30327
|
new MetaVoiceCommitmentDefinition(),
|
|
@@ -30994,12 +31666,14 @@
|
|
|
30994
31666
|
*/
|
|
30995
31667
|
const META_COMMITMENT_APPLIERS = {
|
|
30996
31668
|
'META AVATAR': applyMetaAvatarContent,
|
|
31669
|
+
'META VISUAL': applyMetaAvatarContent,
|
|
30997
31670
|
'META LINK': applyMetaLinkContent,
|
|
30998
31671
|
'META DOMAIN': applyMetaDomainContent,
|
|
30999
31672
|
'META IMAGE': applyMetaImageContent,
|
|
31000
31673
|
'META DESCRIPTION': applyMetaDescriptionContent,
|
|
31001
31674
|
'META DISCLAIMER': applyMetaDisclaimerContent,
|
|
31002
31675
|
'META INPUT PLACEHOLDER': applyMetaInputPlaceholderContent,
|
|
31676
|
+
'META THINKING MESSAGE': applyMetaThinkingMessageContent,
|
|
31003
31677
|
'MESSAGE SUFFIX': applyMessageSuffixContent,
|
|
31004
31678
|
'META COLOR': applyMetaColorContent,
|
|
31005
31679
|
'META FONT': applyMetaFontContent,
|
|
@@ -31042,7 +31716,7 @@
|
|
|
31042
31716
|
state.meta[metaType] = metaValue;
|
|
31043
31717
|
}
|
|
31044
31718
|
/**
|
|
31045
|
-
* Applies META AVATAR content into the canonical `meta.avatar` field.
|
|
31719
|
+
* Applies META AVATAR / META VISUAL content into the canonical `meta.avatar` field.
|
|
31046
31720
|
*/
|
|
31047
31721
|
function applyMetaAvatarContent(state, content) {
|
|
31048
31722
|
const avatarVisualId = resolveAvatarVisualId(content);
|
|
@@ -31090,6 +31764,16 @@
|
|
|
31090
31764
|
function applyMetaInputPlaceholderContent(state, content) {
|
|
31091
31765
|
state.meta.inputPlaceholder = _spaceTrim.spaceTrim(content);
|
|
31092
31766
|
}
|
|
31767
|
+
/**
|
|
31768
|
+
* Applies one META THINKING MESSAGE content block into the custom thinking-message variants.
|
|
31769
|
+
*/
|
|
31770
|
+
function applyMetaThinkingMessageContent(state, content) {
|
|
31771
|
+
const thinkingMessage = _spaceTrim.spaceTrim(content);
|
|
31772
|
+
if (!thinkingMessage) {
|
|
31773
|
+
return;
|
|
31774
|
+
}
|
|
31775
|
+
state.thinkingMessages = [...(state.thinkingMessages || []), thinkingMessage];
|
|
31776
|
+
}
|
|
31093
31777
|
/**
|
|
31094
31778
|
* Applies MESSAGE SUFFIX content into the canonical `meta.messageSuffix` field.
|
|
31095
31779
|
*/
|
|
@@ -31458,6 +32142,7 @@
|
|
|
31458
32142
|
capabilities: [],
|
|
31459
32143
|
samples: [],
|
|
31460
32144
|
knowledgeSources: [],
|
|
32145
|
+
thinkingMessages: [],
|
|
31461
32146
|
pendingUserMessage: null,
|
|
31462
32147
|
knownKnowledgeSourceUrls: new Set(),
|
|
31463
32148
|
};
|
|
@@ -31470,6 +32155,7 @@
|
|
|
31470
32155
|
capabilities: state.capabilities,
|
|
31471
32156
|
samples: state.samples,
|
|
31472
32157
|
knowledgeSources: state.knowledgeSources,
|
|
32158
|
+
thinkingMessages: state.thinkingMessages,
|
|
31473
32159
|
};
|
|
31474
32160
|
}
|
|
31475
32161
|
/**
|
|
@@ -31509,6 +32195,7 @@
|
|
|
31509
32195
|
permanentId: parsedProfile.meta.id,
|
|
31510
32196
|
personaDescription,
|
|
31511
32197
|
initialMessage,
|
|
32198
|
+
thinkingMessages: parsedProfile.thinkingMessages,
|
|
31512
32199
|
meta: parsedProfile.meta,
|
|
31513
32200
|
links: parsedProfile.links,
|
|
31514
32201
|
parameters: parseParameters(agentSource),
|
|
@@ -32106,6 +32793,78 @@
|
|
|
32106
32793
|
.replace(/^[._-]+|[._-]+$/gu, '');
|
|
32107
32794
|
}
|
|
32108
32795
|
|
|
32796
|
+
/**
|
|
32797
|
+
* Helper of usage compute
|
|
32798
|
+
*
|
|
32799
|
+
* @param content the content of prompt or response
|
|
32800
|
+
* @returns part of UsageCounts
|
|
32801
|
+
*
|
|
32802
|
+
* @private internal utility of LlmExecutionTools
|
|
32803
|
+
*/
|
|
32804
|
+
function computeUsageCounts(content) {
|
|
32805
|
+
return {
|
|
32806
|
+
charactersCount: { value: countCharacters(content) },
|
|
32807
|
+
wordsCount: { value: countWords(content) },
|
|
32808
|
+
sentencesCount: { value: countSentences(content) },
|
|
32809
|
+
linesCount: { value: countLines(content) },
|
|
32810
|
+
paragraphsCount: { value: countParagraphs(content) },
|
|
32811
|
+
pagesCount: { value: countPages(content) },
|
|
32812
|
+
};
|
|
32813
|
+
}
|
|
32814
|
+
|
|
32815
|
+
/**
|
|
32816
|
+
* Computes the usage of the OpenAI API based on the response from OpenAI
|
|
32817
|
+
*
|
|
32818
|
+
* @param promptContent The content of the prompt
|
|
32819
|
+
* @param resultContent The content of the result (for embedding prompts or failed prompts pass empty string)
|
|
32820
|
+
* @param rawResponse The raw response from OpenAI API
|
|
32821
|
+
* @param duration The duration of the execution
|
|
32822
|
+
* @throws {PipelineExecutionError} If the usage is not defined in the response from OpenAI
|
|
32823
|
+
*
|
|
32824
|
+
* @private internal utility of `OpenAiExecutionTools`
|
|
32825
|
+
*/
|
|
32826
|
+
function computeOpenAiUsage(promptContent, // <- Note: Intentionally using [] to access type properties to bring jsdoc from Prompt/PromptResult to consumer
|
|
32827
|
+
resultContent, rawResponse, duration = ZERO_VALUE) {
|
|
32828
|
+
var _a, _b;
|
|
32829
|
+
if (rawResponse.usage === undefined) {
|
|
32830
|
+
throw new PipelineExecutionError('The usage is not defined in the response from OpenAI');
|
|
32831
|
+
}
|
|
32832
|
+
if (((_a = rawResponse.usage) === null || _a === void 0 ? void 0 : _a.prompt_tokens) === undefined) {
|
|
32833
|
+
throw new PipelineExecutionError('In OpenAI response `usage.prompt_tokens` not defined');
|
|
32834
|
+
}
|
|
32835
|
+
const inputTokens = rawResponse.usage.prompt_tokens;
|
|
32836
|
+
const outputTokens = ((_b = rawResponse.usage) === null || _b === void 0 ? void 0 : _b.completion_tokens) || 0;
|
|
32837
|
+
let isUncertain = false;
|
|
32838
|
+
let modelInfo = OPENAI_MODELS.find((model) => model.modelName === rawResponse.model);
|
|
32839
|
+
if (modelInfo === undefined) {
|
|
32840
|
+
// Note: Model is not in the list of known models, fallback to the family of the models and mark price as uncertain
|
|
32841
|
+
modelInfo = OPENAI_MODELS.find((model) => (rawResponse.model || SALT_NONCE).startsWith(model.modelName));
|
|
32842
|
+
if (modelInfo !== undefined) {
|
|
32843
|
+
isUncertain = true;
|
|
32844
|
+
}
|
|
32845
|
+
}
|
|
32846
|
+
let price;
|
|
32847
|
+
if (modelInfo === undefined || modelInfo.pricing === undefined) {
|
|
32848
|
+
price = uncertainNumber();
|
|
32849
|
+
}
|
|
32850
|
+
else {
|
|
32851
|
+
price = uncertainNumber(inputTokens * modelInfo.pricing.prompt + outputTokens * modelInfo.pricing.output, isUncertain);
|
|
32852
|
+
}
|
|
32853
|
+
return {
|
|
32854
|
+
price,
|
|
32855
|
+
duration,
|
|
32856
|
+
input: {
|
|
32857
|
+
tokensCount: uncertainNumber(rawResponse.usage.prompt_tokens),
|
|
32858
|
+
...computeUsageCounts(promptContent),
|
|
32859
|
+
},
|
|
32860
|
+
output: {
|
|
32861
|
+
tokensCount: uncertainNumber(outputTokens),
|
|
32862
|
+
...computeUsageCounts(resultContent),
|
|
32863
|
+
},
|
|
32864
|
+
};
|
|
32865
|
+
}
|
|
32866
|
+
// TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
|
|
32867
|
+
|
|
32109
32868
|
/**
|
|
32110
32869
|
* Simple wrapper `new Date().toISOString()`
|
|
32111
32870
|
*
|
|
@@ -32514,78 +33273,6 @@
|
|
|
32514
33273
|
}
|
|
32515
33274
|
}
|
|
32516
33275
|
|
|
32517
|
-
/**
|
|
32518
|
-
* Helper of usage compute
|
|
32519
|
-
*
|
|
32520
|
-
* @param content the content of prompt or response
|
|
32521
|
-
* @returns part of UsageCounts
|
|
32522
|
-
*
|
|
32523
|
-
* @private internal utility of LlmExecutionTools
|
|
32524
|
-
*/
|
|
32525
|
-
function computeUsageCounts(content) {
|
|
32526
|
-
return {
|
|
32527
|
-
charactersCount: { value: countCharacters(content) },
|
|
32528
|
-
wordsCount: { value: countWords(content) },
|
|
32529
|
-
sentencesCount: { value: countSentences(content) },
|
|
32530
|
-
linesCount: { value: countLines(content) },
|
|
32531
|
-
paragraphsCount: { value: countParagraphs(content) },
|
|
32532
|
-
pagesCount: { value: countPages(content) },
|
|
32533
|
-
};
|
|
32534
|
-
}
|
|
32535
|
-
|
|
32536
|
-
/**
|
|
32537
|
-
* Computes the usage of the OpenAI API based on the response from OpenAI
|
|
32538
|
-
*
|
|
32539
|
-
* @param promptContent The content of the prompt
|
|
32540
|
-
* @param resultContent The content of the result (for embedding prompts or failed prompts pass empty string)
|
|
32541
|
-
* @param rawResponse The raw response from OpenAI API
|
|
32542
|
-
* @param duration The duration of the execution
|
|
32543
|
-
* @throws {PipelineExecutionError} If the usage is not defined in the response from OpenAI
|
|
32544
|
-
*
|
|
32545
|
-
* @private internal utility of `OpenAiExecutionTools`
|
|
32546
|
-
*/
|
|
32547
|
-
function computeOpenAiUsage(promptContent, // <- Note: Intentionally using [] to access type properties to bring jsdoc from Prompt/PromptResult to consumer
|
|
32548
|
-
resultContent, rawResponse, duration = ZERO_VALUE) {
|
|
32549
|
-
var _a, _b;
|
|
32550
|
-
if (rawResponse.usage === undefined) {
|
|
32551
|
-
throw new PipelineExecutionError('The usage is not defined in the response from OpenAI');
|
|
32552
|
-
}
|
|
32553
|
-
if (((_a = rawResponse.usage) === null || _a === void 0 ? void 0 : _a.prompt_tokens) === undefined) {
|
|
32554
|
-
throw new PipelineExecutionError('In OpenAI response `usage.prompt_tokens` not defined');
|
|
32555
|
-
}
|
|
32556
|
-
const inputTokens = rawResponse.usage.prompt_tokens;
|
|
32557
|
-
const outputTokens = ((_b = rawResponse.usage) === null || _b === void 0 ? void 0 : _b.completion_tokens) || 0;
|
|
32558
|
-
let isUncertain = false;
|
|
32559
|
-
let modelInfo = OPENAI_MODELS.find((model) => model.modelName === rawResponse.model);
|
|
32560
|
-
if (modelInfo === undefined) {
|
|
32561
|
-
// Note: Model is not in the list of known models, fallback to the family of the models and mark price as uncertain
|
|
32562
|
-
modelInfo = OPENAI_MODELS.find((model) => (rawResponse.model || SALT_NONCE).startsWith(model.modelName));
|
|
32563
|
-
if (modelInfo !== undefined) {
|
|
32564
|
-
isUncertain = true;
|
|
32565
|
-
}
|
|
32566
|
-
}
|
|
32567
|
-
let price;
|
|
32568
|
-
if (modelInfo === undefined || modelInfo.pricing === undefined) {
|
|
32569
|
-
price = uncertainNumber();
|
|
32570
|
-
}
|
|
32571
|
-
else {
|
|
32572
|
-
price = uncertainNumber(inputTokens * modelInfo.pricing.prompt + outputTokens * modelInfo.pricing.output, isUncertain);
|
|
32573
|
-
}
|
|
32574
|
-
return {
|
|
32575
|
-
price,
|
|
32576
|
-
duration,
|
|
32577
|
-
input: {
|
|
32578
|
-
tokensCount: uncertainNumber(rawResponse.usage.prompt_tokens),
|
|
32579
|
-
...computeUsageCounts(promptContent),
|
|
32580
|
-
},
|
|
32581
|
-
output: {
|
|
32582
|
-
tokensCount: uncertainNumber(outputTokens),
|
|
32583
|
-
...computeUsageCounts(resultContent),
|
|
32584
|
-
},
|
|
32585
|
-
};
|
|
32586
|
-
}
|
|
32587
|
-
// TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
|
|
32588
|
-
|
|
32589
33276
|
/**
|
|
32590
33277
|
* Finds the best hardcoded-model match for one API-listed model identifier.
|
|
32591
33278
|
*/
|
|
@@ -42945,7 +43632,7 @@
|
|
|
42945
43632
|
*
|
|
42946
43633
|
* @private within the repository
|
|
42947
43634
|
*/
|
|
42948
|
-
function locateApp(options) {
|
|
43635
|
+
async function locateApp(options) {
|
|
42949
43636
|
if (!$isRunningInNode()) {
|
|
42950
43637
|
throw new EnvironmentMismatchError('Locating apps works only in Node.js environment');
|
|
42951
43638
|
}
|
|
@@ -43043,18 +43730,6 @@
|
|
|
43043
43730
|
const $llmToolsMetadataRegister = new $Register('llm_tools_metadata');
|
|
43044
43731
|
// TODO: [®] DRY Register logic
|
|
43045
43732
|
|
|
43046
|
-
/**
|
|
43047
|
-
* Register for LLM tools.
|
|
43048
|
-
*
|
|
43049
|
-
* Note: `$` is used to indicate that this interacts with the global scope
|
|
43050
|
-
*
|
|
43051
|
-
* @singleton Only one instance of each register is created per build, but there can be more instances across different builds or environments.
|
|
43052
|
-
*
|
|
43053
|
-
* @public exported from `@promptbook/core`
|
|
43054
|
-
*/
|
|
43055
|
-
const $llmToolsRegister = new $Register('llm_execution_tools_constructors');
|
|
43056
|
-
// TODO: [®] DRY Register logic
|
|
43057
|
-
|
|
43058
43733
|
/**
|
|
43059
43734
|
* Path to the `.env` file which was used to configure LLM tools
|
|
43060
43735
|
*
|
|
@@ -43062,61 +43737,53 @@
|
|
|
43062
43737
|
*/
|
|
43063
43738
|
let $usedEnvFilename = null;
|
|
43064
43739
|
/**
|
|
43065
|
-
*
|
|
43066
|
-
*
|
|
43067
|
-
* Note: `$` is used to indicate that this variable is making side effect
|
|
43068
|
-
*
|
|
43069
|
-
* @private internal log of `$provideLlmToolsConfigurationFromEnv` and `$registeredLlmToolsMessage`
|
|
43070
|
-
*/
|
|
43071
|
-
function $setUsedEnvFilename(filepath) {
|
|
43072
|
-
$usedEnvFilename = filepath;
|
|
43073
|
-
}
|
|
43074
|
-
/**
|
|
43075
|
-
* Creates a message with all registered LLM tools
|
|
43076
|
-
*
|
|
43077
|
-
* Note: This function is used to create a (error) message when there is no constructor for some LLM provider
|
|
43078
|
-
*
|
|
43079
|
-
* @private internal function of `createLlmToolsFromConfiguration` and `$provideLlmToolsFromEnv`
|
|
43080
|
-
*/
|
|
43081
|
-
function $registeredLlmToolsMessage() {
|
|
43082
|
-
const registeredLlmToolsMessageContext = createRegisteredLlmToolsMessageContext();
|
|
43083
|
-
if (registeredLlmToolsMessageContext.llmToolStatuses.length === 0) {
|
|
43084
|
-
return renderNoRegisteredLlmToolsMessage(registeredLlmToolsMessageContext.usedEnvMessage);
|
|
43085
|
-
}
|
|
43086
|
-
return renderRegisteredLlmToolsMessage(registeredLlmToolsMessageContext);
|
|
43087
|
-
}
|
|
43088
|
-
/**
|
|
43089
|
-
* Collects all state needed to render the provider summary.
|
|
43740
|
+
* Shared state for the `.env` file used to configure LLM tools.
|
|
43090
43741
|
*
|
|
43091
|
-
* @private internal
|
|
43742
|
+
* @private internal state of `$registeredLlmToolsMessage`
|
|
43092
43743
|
*/
|
|
43093
|
-
|
|
43094
|
-
|
|
43095
|
-
|
|
43096
|
-
|
|
43097
|
-
|
|
43098
|
-
|
|
43099
|
-
|
|
43100
|
-
|
|
43101
|
-
|
|
43102
|
-
|
|
43103
|
-
|
|
43744
|
+
const USED_ENV_FILENAME = {
|
|
43745
|
+
set(filepath) {
|
|
43746
|
+
$usedEnvFilename = filepath;
|
|
43747
|
+
},
|
|
43748
|
+
createMessage() {
|
|
43749
|
+
return $usedEnvFilename === null
|
|
43750
|
+
? `Unknown \`.env\` file`
|
|
43751
|
+
: _spaceTrim.spaceTrim(`
|
|
43752
|
+
Used \`.env\` file:
|
|
43753
|
+
${$usedEnvFilename}
|
|
43754
|
+
`);
|
|
43755
|
+
},
|
|
43756
|
+
};
|
|
43757
|
+
|
|
43104
43758
|
/**
|
|
43105
43759
|
* Reads environment variables relevant for provider configuration.
|
|
43106
43760
|
*
|
|
43107
|
-
* @private
|
|
43761
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43108
43762
|
*/
|
|
43109
|
-
function
|
|
43763
|
+
function getAvailableRegisteredLlmToolsEnvironmentVariables(isRunningInNode) {
|
|
43110
43764
|
if (isRunningInNode) {
|
|
43111
43765
|
return process.env;
|
|
43112
43766
|
// <- TODO: [⚛] Some DRY way how to get to `process.env` and pass it into functions - ACRY search for `env`
|
|
43113
43767
|
}
|
|
43114
43768
|
return {};
|
|
43115
43769
|
}
|
|
43770
|
+
|
|
43771
|
+
/**
|
|
43772
|
+
* Register for LLM tools.
|
|
43773
|
+
*
|
|
43774
|
+
* Note: `$` is used to indicate that this interacts with the global scope
|
|
43775
|
+
*
|
|
43776
|
+
* @singleton Only one instance of each register is created per build, but there can be more instances across different builds or environments.
|
|
43777
|
+
*
|
|
43778
|
+
* @public exported from `@promptbook/core`
|
|
43779
|
+
*/
|
|
43780
|
+
const $llmToolsRegister = new $Register('llm_execution_tools_constructors');
|
|
43781
|
+
// TODO: [®] DRY Register logic
|
|
43782
|
+
|
|
43116
43783
|
/**
|
|
43117
43784
|
* Takes stable snapshots of both LLM provider registers.
|
|
43118
43785
|
*
|
|
43119
|
-
* @private
|
|
43786
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43120
43787
|
*/
|
|
43121
43788
|
function getRegisteredLlmToolRegisters() {
|
|
43122
43789
|
return {
|
|
@@ -43124,62 +43791,30 @@
|
|
|
43124
43791
|
registeredTools: $llmToolsRegister.list(),
|
|
43125
43792
|
};
|
|
43126
43793
|
}
|
|
43127
|
-
|
|
43128
|
-
* Lists provider entries enriched with installation and configuration state.
|
|
43129
|
-
*
|
|
43130
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43131
|
-
*/
|
|
43132
|
-
function listRegisteredLlmToolStatuses({ registeredMetadata, registeredTools }, env) {
|
|
43133
|
-
return listRegisteredLlmToolEntries(registeredMetadata, registeredTools).map((registeredLlmToolEntry) => createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env }));
|
|
43134
|
-
}
|
|
43135
|
-
/**
|
|
43136
|
-
* Merges provider entries from the metadata and constructor registers.
|
|
43137
|
-
*
|
|
43138
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43139
|
-
*/
|
|
43140
|
-
function listRegisteredLlmToolEntries(registeredMetadata, registeredTools) {
|
|
43141
|
-
const registeredLlmToolEntries = new Map();
|
|
43142
|
-
for (const { title, packageName, className, envVariables } of registeredMetadata) {
|
|
43143
|
-
addRegisteredLlmToolEntry(registeredLlmToolEntries, { title, packageName, className, envVariables });
|
|
43144
|
-
}
|
|
43145
|
-
for (const { packageName, className } of registeredTools) {
|
|
43146
|
-
addRegisteredLlmToolEntry(registeredLlmToolEntries, { packageName, className });
|
|
43147
|
-
}
|
|
43148
|
-
return [...registeredLlmToolEntries.values()];
|
|
43149
|
-
}
|
|
43150
|
-
/**
|
|
43151
|
-
* Adds a provider entry only when the provider is not already present.
|
|
43152
|
-
*
|
|
43153
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43154
|
-
*/
|
|
43155
|
-
function addRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43156
|
-
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43157
|
-
if (registeredLlmToolEntries.has(registeredLlmToolEntryKey)) {
|
|
43158
|
-
return;
|
|
43159
|
-
}
|
|
43160
|
-
registeredLlmToolEntries.set(registeredLlmToolEntryKey, registeredLlmToolEntry);
|
|
43161
|
-
}
|
|
43794
|
+
|
|
43162
43795
|
/**
|
|
43163
43796
|
* Creates a deduplication key for a provider entry.
|
|
43164
43797
|
*
|
|
43165
|
-
* @private
|
|
43798
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43166
43799
|
*/
|
|
43167
43800
|
function createRegisteredLlmToolEntryKey({ packageName, className }) {
|
|
43168
43801
|
return `${packageName}::${className}`;
|
|
43169
43802
|
}
|
|
43803
|
+
|
|
43170
43804
|
/**
|
|
43171
43805
|
* Checks whether the given provider entry already exists in the target register list.
|
|
43172
43806
|
*
|
|
43173
|
-
* @private
|
|
43807
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43174
43808
|
*/
|
|
43175
43809
|
function hasRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43176
43810
|
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43177
43811
|
return registeredLlmToolEntries.some((listedRegisteredLlmToolEntry) => createRegisteredLlmToolEntryKey(listedRegisteredLlmToolEntry) === registeredLlmToolEntryKey);
|
|
43178
43812
|
}
|
|
43813
|
+
|
|
43179
43814
|
/**
|
|
43180
43815
|
* Builds the runtime status for one provider entry.
|
|
43181
43816
|
*
|
|
43182
|
-
* @private
|
|
43817
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43183
43818
|
*/
|
|
43184
43819
|
function createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env, }) {
|
|
43185
43820
|
const availabilityStatus = createRegisteredLlmToolAvailabilityStatus(registeredLlmToolEntry, registeredMetadata, registeredTools);
|
|
@@ -43193,7 +43828,7 @@
|
|
|
43193
43828
|
/**
|
|
43194
43829
|
* Resolves whether the provider has metadata and a registered constructor.
|
|
43195
43830
|
*
|
|
43196
|
-
* @private
|
|
43831
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43197
43832
|
*/
|
|
43198
43833
|
function createRegisteredLlmToolAvailabilityStatus(registeredLlmToolEntry, registeredMetadata, registeredTools) {
|
|
43199
43834
|
return {
|
|
@@ -43204,7 +43839,7 @@
|
|
|
43204
43839
|
/**
|
|
43205
43840
|
* Resolves whether the provider has enough environment variables to be configured.
|
|
43206
43841
|
*
|
|
43207
|
-
* @private
|
|
43842
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43208
43843
|
*/
|
|
43209
43844
|
function createRegisteredLlmToolConfigurationStatus({ envVariables }, env) {
|
|
43210
43845
|
return {
|
|
@@ -43215,7 +43850,7 @@
|
|
|
43215
43850
|
/**
|
|
43216
43851
|
* Checks whether all required environment variables are present for a provider.
|
|
43217
43852
|
*
|
|
43218
|
-
* @private
|
|
43853
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43219
43854
|
*/
|
|
43220
43855
|
function isRegisteredLlmToolFullyConfigured(envVariables, env) {
|
|
43221
43856
|
if (envVariables === undefined || envVariables === null) {
|
|
@@ -43226,7 +43861,7 @@
|
|
|
43226
43861
|
/**
|
|
43227
43862
|
* Checks whether at least one required environment variable is present for a provider.
|
|
43228
43863
|
*
|
|
43229
|
-
* @private
|
|
43864
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43230
43865
|
*/
|
|
43231
43866
|
function isRegisteredLlmToolPartiallyConfigured(envVariables, env) {
|
|
43232
43867
|
if (envVariables === undefined || envVariables === null) {
|
|
@@ -43234,109 +43869,128 @@
|
|
|
43234
43869
|
}
|
|
43235
43870
|
return envVariables.some((envVariableName) => env[envVariableName] !== undefined);
|
|
43236
43871
|
}
|
|
43872
|
+
|
|
43237
43873
|
/**
|
|
43238
|
-
*
|
|
43874
|
+
* Merges provider entries from the metadata and constructor registers.
|
|
43239
43875
|
*
|
|
43240
|
-
* @private
|
|
43876
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43241
43877
|
*/
|
|
43242
|
-
function
|
|
43243
|
-
|
|
43244
|
-
|
|
43245
|
-
|
|
43246
|
-
|
|
43247
|
-
|
|
43878
|
+
function listRegisteredLlmToolEntries(registeredMetadata, registeredTools) {
|
|
43879
|
+
const registeredLlmToolEntries = new Map();
|
|
43880
|
+
for (const { title, packageName, className, envVariables } of registeredMetadata) {
|
|
43881
|
+
addRegisteredLlmToolEntry(registeredLlmToolEntries, { title, packageName, className, envVariables });
|
|
43882
|
+
}
|
|
43883
|
+
for (const { packageName, className } of registeredTools) {
|
|
43884
|
+
addRegisteredLlmToolEntry(registeredLlmToolEntries, { packageName, className });
|
|
43885
|
+
}
|
|
43886
|
+
return [...registeredLlmToolEntries.values()];
|
|
43248
43887
|
}
|
|
43249
43888
|
/**
|
|
43250
|
-
*
|
|
43889
|
+
* Adds a provider entry only when the provider is not already present.
|
|
43251
43890
|
*
|
|
43252
|
-
* @private
|
|
43891
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43253
43892
|
*/
|
|
43254
|
-
function
|
|
43255
|
-
|
|
43256
|
-
|
|
43257
|
-
|
|
43258
|
-
|
|
43259
|
-
|
|
43260
|
-
${block(renderRelevantEnvironmentVariables(env, llmToolStatuses))}
|
|
43261
|
-
|
|
43262
|
-
Available LLM providers are:
|
|
43263
|
-
${block(renderAvailableProviders(llmToolStatuses, env, isRunningInNode))}
|
|
43264
|
-
`);
|
|
43893
|
+
function addRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43894
|
+
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43895
|
+
if (registeredLlmToolEntries.has(registeredLlmToolEntryKey)) {
|
|
43896
|
+
return;
|
|
43897
|
+
}
|
|
43898
|
+
registeredLlmToolEntries.set(registeredLlmToolEntryKey, registeredLlmToolEntry);
|
|
43265
43899
|
}
|
|
43900
|
+
|
|
43266
43901
|
/**
|
|
43267
|
-
*
|
|
43902
|
+
* Lists provider entries enriched with installation and configuration state.
|
|
43268
43903
|
*
|
|
43269
|
-
* @private
|
|
43904
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43270
43905
|
*/
|
|
43271
|
-
function
|
|
43272
|
-
return
|
|
43273
|
-
.map((envVariableName) => `- \`${envVariableName}\``)
|
|
43274
|
-
.join('\n');
|
|
43906
|
+
function listRegisteredLlmToolStatuses({ registeredMetadata, registeredTools }, env) {
|
|
43907
|
+
return listRegisteredLlmToolEntries(registeredMetadata, registeredTools).map((registeredLlmToolEntry) => createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env }));
|
|
43275
43908
|
}
|
|
43909
|
+
|
|
43276
43910
|
/**
|
|
43277
|
-
*
|
|
43911
|
+
* Collects all state needed to render the provider summary.
|
|
43278
43912
|
*
|
|
43279
|
-
* @private
|
|
43913
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43280
43914
|
*/
|
|
43281
|
-
function
|
|
43282
|
-
|
|
43915
|
+
function createRegisteredLlmToolsMessageContext() {
|
|
43916
|
+
const isRunningInNode = $isRunningInNode();
|
|
43917
|
+
const env = getAvailableRegisteredLlmToolsEnvironmentVariables(isRunningInNode);
|
|
43918
|
+
const registeredLlmToolRegisters = getRegisteredLlmToolRegisters();
|
|
43919
|
+
return {
|
|
43920
|
+
env,
|
|
43921
|
+
llmToolStatuses: listRegisteredLlmToolStatuses(registeredLlmToolRegisters, env),
|
|
43922
|
+
usedEnvMessage: USED_ENV_FILENAME.createMessage(),
|
|
43923
|
+
isRunningInNode,
|
|
43924
|
+
};
|
|
43283
43925
|
}
|
|
43926
|
+
|
|
43284
43927
|
/**
|
|
43285
|
-
* Renders
|
|
43928
|
+
* Renders the fallback message for environments with no registered providers.
|
|
43286
43929
|
*
|
|
43287
|
-
* @private
|
|
43930
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43288
43931
|
*/
|
|
43289
|
-
function
|
|
43290
|
-
return
|
|
43291
|
-
|
|
43292
|
-
|
|
43932
|
+
function renderNoRegisteredLlmToolsMessage(usedEnvMessage) {
|
|
43933
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
43934
|
+
No LLM providers are available.
|
|
43935
|
+
|
|
43936
|
+
${block(usedEnvMessage)}
|
|
43937
|
+
`);
|
|
43293
43938
|
}
|
|
43939
|
+
|
|
43294
43940
|
/**
|
|
43295
|
-
*
|
|
43941
|
+
* Creates the configuration-status sentence for one provider.
|
|
43296
43942
|
*
|
|
43297
|
-
* @private
|
|
43943
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43298
43944
|
*/
|
|
43299
|
-
function
|
|
43300
|
-
|
|
43301
|
-
|
|
43302
|
-
|
|
43945
|
+
function createRegisteredLlmToolConfigurationStatusMessage({ envVariables, isFullyConfigured, isPartiallyConfigured }, env) {
|
|
43946
|
+
if (isFullyConfigured) {
|
|
43947
|
+
return `Configured`;
|
|
43948
|
+
}
|
|
43949
|
+
if (isPartiallyConfigured) {
|
|
43950
|
+
return createPartiallyConfiguredStatusMessage(envVariables, env);
|
|
43951
|
+
}
|
|
43952
|
+
if (envVariables !== null) {
|
|
43953
|
+
return createNotConfiguredStatusMessage(envVariables);
|
|
43303
43954
|
}
|
|
43304
|
-
return
|
|
43955
|
+
return `Not configured`;
|
|
43956
|
+
// <- Note: Can not be configured via environment variables
|
|
43305
43957
|
}
|
|
43306
43958
|
/**
|
|
43307
|
-
* Creates the
|
|
43959
|
+
* Creates the partial-configuration sentence including missing variables.
|
|
43308
43960
|
*
|
|
43309
|
-
* @private
|
|
43961
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43310
43962
|
*/
|
|
43311
|
-
function
|
|
43312
|
-
|
|
43313
|
-
const providerStatusMessages = createProviderStatusMessages(llmToolStatus, env);
|
|
43314
|
-
return _spaceTrim.spaceTrim(`
|
|
43315
|
-
${index + 1}) **${title}** \`${className}\` from \`${packageName}\`
|
|
43316
|
-
${providerStatusMessages.join('; ')}
|
|
43317
|
-
`);
|
|
43963
|
+
function createPartiallyConfiguredStatusMessage(envVariables, env) {
|
|
43964
|
+
return `Partially confugured, missing ${listMissingEnvironmentVariables(envVariables, env).join(' + ')}`;
|
|
43318
43965
|
}
|
|
43319
43966
|
/**
|
|
43320
|
-
* Creates the
|
|
43967
|
+
* Creates the not-configured sentence including the expected environment variables.
|
|
43321
43968
|
*
|
|
43322
|
-
* @private
|
|
43969
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43323
43970
|
*/
|
|
43324
|
-
function
|
|
43325
|
-
return
|
|
43971
|
+
function createNotConfiguredStatusMessage(envVariables) {
|
|
43972
|
+
return `Not configured, to configure set env ${envVariables === null || envVariables === void 0 ? void 0 : envVariables.join(' + ')}`;
|
|
43973
|
+
}
|
|
43974
|
+
/**
|
|
43975
|
+
* Lists environment variables that are required but currently missing.
|
|
43976
|
+
*
|
|
43977
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43978
|
+
*/
|
|
43979
|
+
function listMissingEnvironmentVariables(envVariables, env) {
|
|
43980
|
+
return (envVariables === null || envVariables === void 0 ? void 0 : envVariables.filter((envVariable) => env[envVariable] === undefined)) || [];
|
|
43326
43981
|
}
|
|
43982
|
+
|
|
43327
43983
|
/**
|
|
43328
43984
|
* Creates the installation-status sentence for one provider.
|
|
43329
43985
|
*
|
|
43330
|
-
* @private
|
|
43986
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43331
43987
|
*/
|
|
43332
|
-
function
|
|
43333
|
-
const installationStatusKey =
|
|
43988
|
+
function createRegisteredLlmToolInstallationStatusMessage({ isMetadataAvailable, isInstalled, }) {
|
|
43989
|
+
const installationStatusKey = createRegisteredLlmToolInstallationStatusKey(isMetadataAvailable, isInstalled);
|
|
43334
43990
|
switch (installationStatusKey) {
|
|
43335
43991
|
case 'missing-metadata-and-installation':
|
|
43336
|
-
// TODO: [�][�] Maybe do allow to do auto-install if package not registered and not found
|
|
43337
43992
|
return `Not installed and no metadata, looks like a unexpected behavior`;
|
|
43338
43993
|
case 'metadata-without-installation':
|
|
43339
|
-
// TODO: [�][�]
|
|
43340
43994
|
return `Not installed`;
|
|
43341
43995
|
case 'installation-without-metadata':
|
|
43342
43996
|
return `No metadata but installed, looks like a unexpected behavior`;
|
|
@@ -43349,9 +44003,9 @@
|
|
|
43349
44003
|
/**
|
|
43350
44004
|
* Creates a stable installation-state key from metadata and constructor availability.
|
|
43351
44005
|
*
|
|
43352
|
-
* @private
|
|
44006
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43353
44007
|
*/
|
|
43354
|
-
function
|
|
44008
|
+
function createRegisteredLlmToolInstallationStatusKey(isMetadataAvailable, isInstalled) {
|
|
43355
44009
|
if (!isMetadataAvailable && !isInstalled) {
|
|
43356
44010
|
return 'missing-metadata-and-installation';
|
|
43357
44011
|
}
|
|
@@ -43366,54 +44020,59 @@
|
|
|
43366
44020
|
}
|
|
43367
44021
|
return 'unknown';
|
|
43368
44022
|
}
|
|
44023
|
+
|
|
43369
44024
|
/**
|
|
43370
|
-
*
|
|
44025
|
+
* Renders all provider lines in the status summary.
|
|
43371
44026
|
*
|
|
43372
|
-
* @private
|
|
44027
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43373
44028
|
*/
|
|
43374
|
-
function
|
|
43375
|
-
|
|
43376
|
-
|
|
43377
|
-
|
|
43378
|
-
if (isPartiallyConfigured) {
|
|
43379
|
-
return createPartiallyConfiguredStatusMessage(envVariables, env);
|
|
43380
|
-
}
|
|
43381
|
-
if (envVariables !== null) {
|
|
43382
|
-
return createNotConfiguredStatusMessage(envVariables);
|
|
43383
|
-
}
|
|
43384
|
-
return `Not configured`;
|
|
43385
|
-
// <- Note: Can not be configured via environment variables
|
|
44029
|
+
function renderAvailableRegisteredLlmTools(llmToolStatuses, env, isRunningInNode) {
|
|
44030
|
+
return llmToolStatuses
|
|
44031
|
+
.map((llmToolStatus, index) => renderAvailableRegisteredLlmTool(llmToolStatus, index, env, isRunningInNode))
|
|
44032
|
+
.join('\n');
|
|
43386
44033
|
}
|
|
43387
44034
|
/**
|
|
43388
|
-
*
|
|
44035
|
+
* Renders one provider line in the status summary.
|
|
43389
44036
|
*
|
|
43390
|
-
* @private
|
|
44037
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43391
44038
|
*/
|
|
43392
|
-
function
|
|
43393
|
-
|
|
44039
|
+
function renderAvailableRegisteredLlmTool(llmToolStatus, index, env, isRunningInNode) {
|
|
44040
|
+
const providerMessage = createAvailableRegisteredLlmToolMessage(llmToolStatus, index, env);
|
|
44041
|
+
if (!isRunningInNode) {
|
|
44042
|
+
return providerMessage;
|
|
44043
|
+
}
|
|
44044
|
+
return colorizeAvailableRegisteredLlmToolMessage(providerMessage, llmToolStatus);
|
|
43394
44045
|
}
|
|
43395
44046
|
/**
|
|
43396
|
-
* Creates the
|
|
44047
|
+
* Creates the plain-text provider line before optional colorization.
|
|
43397
44048
|
*
|
|
43398
|
-
* @private
|
|
44049
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43399
44050
|
*/
|
|
43400
|
-
function
|
|
43401
|
-
|
|
44051
|
+
function createAvailableRegisteredLlmToolMessage(llmToolStatus, index, env) {
|
|
44052
|
+
const { title, packageName, className } = llmToolStatus;
|
|
44053
|
+
const providerStatusMessages = createRegisteredLlmToolStatusMessages(llmToolStatus, env);
|
|
44054
|
+
return _spaceTrim.spaceTrim(`
|
|
44055
|
+
${index + 1}) **${title}** \`${className}\` from \`${packageName}\`
|
|
44056
|
+
${providerStatusMessages.join('; ')}
|
|
44057
|
+
`);
|
|
43402
44058
|
}
|
|
43403
44059
|
/**
|
|
43404
|
-
*
|
|
44060
|
+
* Creates the install and configuration fragments for one provider line.
|
|
43405
44061
|
*
|
|
43406
|
-
* @private
|
|
44062
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43407
44063
|
*/
|
|
43408
|
-
function
|
|
43409
|
-
return
|
|
44064
|
+
function createRegisteredLlmToolStatusMessages(llmToolStatus, env) {
|
|
44065
|
+
return [
|
|
44066
|
+
createRegisteredLlmToolInstallationStatusMessage(llmToolStatus),
|
|
44067
|
+
createRegisteredLlmToolConfigurationStatusMessage(llmToolStatus, env),
|
|
44068
|
+
];
|
|
43410
44069
|
}
|
|
43411
44070
|
/**
|
|
43412
44071
|
* Applies the same terminal coloring rules as the original summary renderer.
|
|
43413
44072
|
*
|
|
43414
|
-
* @private
|
|
44073
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43415
44074
|
*/
|
|
43416
|
-
function
|
|
44075
|
+
function colorizeAvailableRegisteredLlmToolMessage(providerMessage, { isInstalled, isFullyConfigured, isPartiallyConfigured }) {
|
|
43417
44076
|
if (isInstalled && isFullyConfigured) {
|
|
43418
44077
|
return colors__default["default"].green(providerMessage);
|
|
43419
44078
|
}
|
|
@@ -43422,18 +44081,67 @@
|
|
|
43422
44081
|
}
|
|
43423
44082
|
return colors__default["default"].gray(providerMessage);
|
|
43424
44083
|
}
|
|
44084
|
+
|
|
43425
44085
|
/**
|
|
43426
|
-
*
|
|
44086
|
+
* Renders the list of environment variables used by at least one registered provider.
|
|
43427
44087
|
*
|
|
43428
|
-
* @private
|
|
44088
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43429
44089
|
*/
|
|
43430
|
-
function
|
|
43431
|
-
return
|
|
43432
|
-
|
|
43433
|
-
|
|
43434
|
-
|
|
43435
|
-
|
|
43436
|
-
|
|
44090
|
+
function renderRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses) {
|
|
44091
|
+
return listRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses)
|
|
44092
|
+
.map((envVariableName) => `- \`${envVariableName}\``)
|
|
44093
|
+
.join('\n');
|
|
44094
|
+
}
|
|
44095
|
+
/**
|
|
44096
|
+
* Lists environment variables that are both present and used by at least one provider.
|
|
44097
|
+
*
|
|
44098
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
44099
|
+
*/
|
|
44100
|
+
function listRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses) {
|
|
44101
|
+
return Object.keys(env).filter((envVariableName) => llmToolStatuses.some(({ envVariables }) => envVariables === null || envVariables === void 0 ? void 0 : envVariables.includes(envVariableName)));
|
|
44102
|
+
}
|
|
44103
|
+
|
|
44104
|
+
/**
|
|
44105
|
+
* Renders the full provider status summary.
|
|
44106
|
+
*
|
|
44107
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
44108
|
+
*/
|
|
44109
|
+
function renderRegisteredLlmToolsMessage({ env, llmToolStatuses, usedEnvMessage, isRunningInNode, }) {
|
|
44110
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
44111
|
+
|
|
44112
|
+
${block(usedEnvMessage)}
|
|
44113
|
+
|
|
44114
|
+
Relevant environment variables:
|
|
44115
|
+
${block(renderRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses))}
|
|
44116
|
+
|
|
44117
|
+
Available LLM providers are:
|
|
44118
|
+
${block(renderAvailableRegisteredLlmTools(llmToolStatuses, env, isRunningInNode))}
|
|
44119
|
+
`);
|
|
44120
|
+
}
|
|
44121
|
+
|
|
44122
|
+
/**
|
|
44123
|
+
* Pass the `.env` file which was used to configure LLM tools
|
|
44124
|
+
*
|
|
44125
|
+
* Note: `$` is used to indicate that this variable is making side effect
|
|
44126
|
+
*
|
|
44127
|
+
* @private internal log of `$provideLlmToolsConfigurationFromEnv` and `$registeredLlmToolsMessage`
|
|
44128
|
+
*/
|
|
44129
|
+
function $setUsedEnvFilename(filepath) {
|
|
44130
|
+
USED_ENV_FILENAME.set(filepath);
|
|
44131
|
+
}
|
|
44132
|
+
/**
|
|
44133
|
+
* Creates a message with all registered LLM tools
|
|
44134
|
+
*
|
|
44135
|
+
* Note: This function is used to create a (error) message when there is no constructor for some LLM provider
|
|
44136
|
+
*
|
|
44137
|
+
* @private internal function of `createLlmToolsFromConfiguration` and `$provideLlmToolsFromEnv`
|
|
44138
|
+
*/
|
|
44139
|
+
function $registeredLlmToolsMessage() {
|
|
44140
|
+
const registeredLlmToolsMessageContext = createRegisteredLlmToolsMessageContext();
|
|
44141
|
+
if (registeredLlmToolsMessageContext.llmToolStatuses.length === 0) {
|
|
44142
|
+
return renderNoRegisteredLlmToolsMessage(registeredLlmToolsMessageContext.usedEnvMessage);
|
|
44143
|
+
}
|
|
44144
|
+
return renderRegisteredLlmToolsMessage(registeredLlmToolsMessageContext);
|
|
43437
44145
|
}
|
|
43438
44146
|
// TODO: [®] DRY Register logic
|
|
43439
44147
|
// TODO: [🧠][⚛] Maybe pass env as argument
|