@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/esm/index.es.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { join, dirname, basename, isAbsolute, resolve, relative } from 'path';
|
|
2
2
|
import { unlink, mkdir, appendFile, writeFile, readFile, stat, access, constants, readdir, watch, rm } from 'fs/promises';
|
|
3
|
+
import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
|
|
3
4
|
import colors from 'colors';
|
|
4
5
|
import { spawn } from 'child_process';
|
|
5
|
-
import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
|
|
6
6
|
import { fileSearchTool, tool, Agent as Agent$1, webSearchTool, run, setDefaultOpenAIClient, setDefaultOpenAIKey } from '@openai/agents';
|
|
7
7
|
import { fileURLToPath } from 'url';
|
|
8
8
|
import { Readability } from '@mozilla/readability';
|
|
@@ -36,7 +36,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
36
36
|
* @generated
|
|
37
37
|
* @see https://github.com/webgptorg/promptbook
|
|
38
38
|
*/
|
|
39
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.
|
|
39
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-0';
|
|
40
40
|
/**
|
|
41
41
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
42
42
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -73,6 +73,15 @@ const AGENT_FINISHED_MESSAGES_DIRECTORY_PATH = join(AGENT_MESSAGES_DIRECTORY_PAT
|
|
|
73
73
|
* @public exported from `@promptbook/node`
|
|
74
74
|
*/
|
|
75
75
|
const AGENT_FAILED_MESSAGES_DIRECTORY_PATH = join(AGENT_MESSAGES_DIRECTORY_PATH, 'failed');
|
|
76
|
+
/**
|
|
77
|
+
* Relative path to the agent-owned projects root used by the agent folder convention.
|
|
78
|
+
*
|
|
79
|
+
* Each direct child directory is one project — an isolated folder the agent fully controls
|
|
80
|
+
* (files, scripts, optionally its own git repository).
|
|
81
|
+
*
|
|
82
|
+
* @private internal constant of the agent folder convention, used by agent runners and the Agents Server
|
|
83
|
+
*/
|
|
84
|
+
const AGENT_PROJECTS_DIRECTORY_PATH = 'projects';
|
|
76
85
|
|
|
77
86
|
/**
|
|
78
87
|
* Parser for the agent source for Promptbook agents in book language
|
|
@@ -381,6 +390,34 @@ function $randomToken(randomness) {
|
|
|
381
390
|
// TODO: [🤶] Maybe export through `@promptbook/utils` or `@promptbook/random` package
|
|
382
391
|
// TODO: Maybe use nanoid instead https://github.com/ai/nanoid
|
|
383
392
|
|
|
393
|
+
/**
|
|
394
|
+
* Increase the level of all headings in the markdown content
|
|
395
|
+
*
|
|
396
|
+
* @example h1 -> h2, h2 -> h3, ...
|
|
397
|
+
* @param content The markdown content
|
|
398
|
+
* @returns The markdown with increased headings
|
|
399
|
+
*/
|
|
400
|
+
function increaseHeadings(content) {
|
|
401
|
+
const lines = content.split(/\r?\n/);
|
|
402
|
+
let inCodeBlock = false;
|
|
403
|
+
for (let i = 0; i < lines.length; i++) {
|
|
404
|
+
const line = lines[i];
|
|
405
|
+
if (line.startsWith('```')) {
|
|
406
|
+
inCodeBlock = !inCodeBlock;
|
|
407
|
+
}
|
|
408
|
+
if (inCodeBlock) {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
const headingMatch = line.match(/^(#+)(.*)/);
|
|
412
|
+
if (headingMatch) {
|
|
413
|
+
const headingLevel = headingMatch[1].length;
|
|
414
|
+
const headingText = headingMatch[2];
|
|
415
|
+
lines[i] = `${'#'.repeat(headingLevel + 1)}${headingText}`;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return lines.join('\n');
|
|
419
|
+
}
|
|
420
|
+
|
|
384
421
|
/**
|
|
385
422
|
* Appends optional coding context to a runner prompt.
|
|
386
423
|
*/
|
|
@@ -393,7 +430,13 @@ function appendCoderContext(prompt, context) {
|
|
|
393
430
|
if (normalizedPrompt === '') {
|
|
394
431
|
return normalizedContext;
|
|
395
432
|
}
|
|
396
|
-
return
|
|
433
|
+
return spaceTrim$1((block) => `
|
|
434
|
+
${block(normalizedPrompt)}
|
|
435
|
+
|
|
436
|
+
## Context
|
|
437
|
+
|
|
438
|
+
${block(increaseHeadings(normalizedContext))}
|
|
439
|
+
`);
|
|
397
440
|
}
|
|
398
441
|
|
|
399
442
|
/**
|
|
@@ -435,48 +478,6 @@ async function withPromptRuntimeLog(scriptPath, handler, options) {
|
|
|
435
478
|
}
|
|
436
479
|
}
|
|
437
480
|
|
|
438
|
-
/**
|
|
439
|
-
* Orders JSON object by keys
|
|
440
|
-
*
|
|
441
|
-
* @returns The same type of object as the input re-ordered
|
|
442
|
-
*
|
|
443
|
-
* @public exported from `@promptbook/utils`
|
|
444
|
-
*/
|
|
445
|
-
function orderJson(options) {
|
|
446
|
-
const { value, order } = options;
|
|
447
|
-
const orderedValue = {
|
|
448
|
-
...(order === undefined ? {} : Object.fromEntries(order.map((key) => [key, undefined]))),
|
|
449
|
-
...value,
|
|
450
|
-
};
|
|
451
|
-
return orderedValue;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Freezes the given object and all its nested objects recursively
|
|
456
|
-
*
|
|
457
|
-
* Note: `$` is used to indicate that this function is not a pure function - it mutates given object
|
|
458
|
-
* Note: This function mutates the object and returns the original (but mutated-deep-freezed) object
|
|
459
|
-
*
|
|
460
|
-
* @returns The same object as the input, but deeply frozen
|
|
461
|
-
*
|
|
462
|
-
* @public exported from `@promptbook/utils`
|
|
463
|
-
*/
|
|
464
|
-
function $deepFreeze(objectValue) {
|
|
465
|
-
if (Array.isArray(objectValue)) {
|
|
466
|
-
return Object.freeze(objectValue.map((item) => $deepFreeze(item)));
|
|
467
|
-
}
|
|
468
|
-
const propertyNames = Object.getOwnPropertyNames(objectValue);
|
|
469
|
-
for (const propertyName of propertyNames) {
|
|
470
|
-
const value = objectValue[propertyName];
|
|
471
|
-
if (value && typeof value === 'object') {
|
|
472
|
-
$deepFreeze(value);
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
Object.freeze(objectValue);
|
|
476
|
-
return objectValue;
|
|
477
|
-
}
|
|
478
|
-
// TODO: [🧠] Is there a way how to meaningfully test this utility
|
|
479
|
-
|
|
480
481
|
/**
|
|
481
482
|
* Class implementing take chain.
|
|
482
483
|
*
|
|
@@ -522,6 +523,127 @@ function take(initialValue) {
|
|
|
522
523
|
});
|
|
523
524
|
}
|
|
524
525
|
|
|
526
|
+
/**
|
|
527
|
+
* Validates that a channel value is a valid number within the range of 0 to 255.
|
|
528
|
+
* Throws an error if the value is not valid.
|
|
529
|
+
*
|
|
530
|
+
* @param channelName - The name of the channel being validated.
|
|
531
|
+
* @param value - The value of the channel to validate.
|
|
532
|
+
* @throws Will throw an error if the value is not a valid channel number.
|
|
533
|
+
*
|
|
534
|
+
* @private util of `@promptbook/color`
|
|
535
|
+
*/
|
|
536
|
+
function checkChannelValue(channelName, value) {
|
|
537
|
+
if (typeof value !== 'number') {
|
|
538
|
+
throw new Error(`${channelName} channel value is not number but ${typeof value}`);
|
|
539
|
+
}
|
|
540
|
+
if (isNaN(value)) {
|
|
541
|
+
throw new Error(`${channelName} channel value is NaN`);
|
|
542
|
+
}
|
|
543
|
+
if (Math.round(value) !== value) {
|
|
544
|
+
throw new Error(`${channelName} channel is not whole number, it is ${value}`);
|
|
545
|
+
}
|
|
546
|
+
if (value < 0) {
|
|
547
|
+
throw new Error(`${channelName} channel is lower than 0, it is ${value}`);
|
|
548
|
+
}
|
|
549
|
+
if (value > 255) {
|
|
550
|
+
throw new Error(`${channelName} channel is greater than 255, it is ${value}`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Shared immutable channel storage and serialization helpers for `Color`.
|
|
556
|
+
*
|
|
557
|
+
* @private base class of Color
|
|
558
|
+
*/
|
|
559
|
+
class ColorValue {
|
|
560
|
+
constructor(red, green, blue, alpha = 255) {
|
|
561
|
+
this.red = red;
|
|
562
|
+
this.green = green;
|
|
563
|
+
this.blue = blue;
|
|
564
|
+
this.alpha = alpha;
|
|
565
|
+
checkChannelValue('Red', red);
|
|
566
|
+
checkChannelValue('Green', green);
|
|
567
|
+
checkChannelValue('Blue', blue);
|
|
568
|
+
checkChannelValue('Alpha', alpha);
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Shortcut for `red` property
|
|
572
|
+
* Number from 0 to 255
|
|
573
|
+
* @alias red
|
|
574
|
+
*/
|
|
575
|
+
get r() {
|
|
576
|
+
return this.red;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Shortcut for `green` property
|
|
580
|
+
* Number from 0 to 255
|
|
581
|
+
* @alias green
|
|
582
|
+
*/
|
|
583
|
+
get g() {
|
|
584
|
+
return this.green;
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Shortcut for `blue` property
|
|
588
|
+
* Number from 0 to 255
|
|
589
|
+
* @alias blue
|
|
590
|
+
*/
|
|
591
|
+
get b() {
|
|
592
|
+
return this.blue;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Shortcut for `alpha` property
|
|
596
|
+
* Number from 0 (transparent) to 255 (opaque)
|
|
597
|
+
* @alias alpha
|
|
598
|
+
*/
|
|
599
|
+
get a() {
|
|
600
|
+
return this.alpha;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Shortcut for `alpha` property
|
|
604
|
+
* Number from 0 (transparent) to 255 (opaque)
|
|
605
|
+
* @alias alpha
|
|
606
|
+
*/
|
|
607
|
+
get opacity() {
|
|
608
|
+
return this.alpha;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Shortcut for 1-`alpha` property
|
|
612
|
+
*/
|
|
613
|
+
get transparency() {
|
|
614
|
+
return 255 - this.alpha;
|
|
615
|
+
}
|
|
616
|
+
clone() {
|
|
617
|
+
return take(this.createColor(this.red, this.green, this.blue, this.alpha));
|
|
618
|
+
}
|
|
619
|
+
toString() {
|
|
620
|
+
return this.toHex();
|
|
621
|
+
}
|
|
622
|
+
toHex() {
|
|
623
|
+
if (this.alpha === 255) {
|
|
624
|
+
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
625
|
+
.toString(16)
|
|
626
|
+
.padStart(2, '0')}`;
|
|
627
|
+
}
|
|
628
|
+
else {
|
|
629
|
+
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
630
|
+
.toString(16)
|
|
631
|
+
.padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
toRgb() {
|
|
635
|
+
if (this.alpha === 255) {
|
|
636
|
+
return `rgb(${this.red}, ${this.green}, ${this.blue})`;
|
|
637
|
+
}
|
|
638
|
+
else {
|
|
639
|
+
return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
toHsl() {
|
|
643
|
+
throw new Error(`Getting HSL is not implemented`);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
525
647
|
/**
|
|
526
648
|
* 🎨 List of all 140 color names which are supported by CSS
|
|
527
649
|
*
|
|
@@ -681,127 +803,6 @@ const CSS_COLORS = {
|
|
|
681
803
|
};
|
|
682
804
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
683
805
|
|
|
684
|
-
/**
|
|
685
|
-
* Validates that a channel value is a valid number within the range of 0 to 255.
|
|
686
|
-
* Throws an error if the value is not valid.
|
|
687
|
-
*
|
|
688
|
-
* @param channelName - The name of the channel being validated.
|
|
689
|
-
* @param value - The value of the channel to validate.
|
|
690
|
-
* @throws Will throw an error if the value is not a valid channel number.
|
|
691
|
-
*
|
|
692
|
-
* @private util of `@promptbook/color`
|
|
693
|
-
*/
|
|
694
|
-
function checkChannelValue(channelName, value) {
|
|
695
|
-
if (typeof value !== 'number') {
|
|
696
|
-
throw new Error(`${channelName} channel value is not number but ${typeof value}`);
|
|
697
|
-
}
|
|
698
|
-
if (isNaN(value)) {
|
|
699
|
-
throw new Error(`${channelName} channel value is NaN`);
|
|
700
|
-
}
|
|
701
|
-
if (Math.round(value) !== value) {
|
|
702
|
-
throw new Error(`${channelName} channel is not whole number, it is ${value}`);
|
|
703
|
-
}
|
|
704
|
-
if (value < 0) {
|
|
705
|
-
throw new Error(`${channelName} channel is lower than 0, it is ${value}`);
|
|
706
|
-
}
|
|
707
|
-
if (value > 255) {
|
|
708
|
-
throw new Error(`${channelName} channel is greater than 255, it is ${value}`);
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
/**
|
|
713
|
-
* Shared immutable channel storage and serialization helpers for `Color`.
|
|
714
|
-
*
|
|
715
|
-
* @private base class of Color
|
|
716
|
-
*/
|
|
717
|
-
class ColorValue {
|
|
718
|
-
constructor(red, green, blue, alpha = 255) {
|
|
719
|
-
this.red = red;
|
|
720
|
-
this.green = green;
|
|
721
|
-
this.blue = blue;
|
|
722
|
-
this.alpha = alpha;
|
|
723
|
-
checkChannelValue('Red', red);
|
|
724
|
-
checkChannelValue('Green', green);
|
|
725
|
-
checkChannelValue('Blue', blue);
|
|
726
|
-
checkChannelValue('Alpha', alpha);
|
|
727
|
-
}
|
|
728
|
-
/**
|
|
729
|
-
* Shortcut for `red` property
|
|
730
|
-
* Number from 0 to 255
|
|
731
|
-
* @alias red
|
|
732
|
-
*/
|
|
733
|
-
get r() {
|
|
734
|
-
return this.red;
|
|
735
|
-
}
|
|
736
|
-
/**
|
|
737
|
-
* Shortcut for `green` property
|
|
738
|
-
* Number from 0 to 255
|
|
739
|
-
* @alias green
|
|
740
|
-
*/
|
|
741
|
-
get g() {
|
|
742
|
-
return this.green;
|
|
743
|
-
}
|
|
744
|
-
/**
|
|
745
|
-
* Shortcut for `blue` property
|
|
746
|
-
* Number from 0 to 255
|
|
747
|
-
* @alias blue
|
|
748
|
-
*/
|
|
749
|
-
get b() {
|
|
750
|
-
return this.blue;
|
|
751
|
-
}
|
|
752
|
-
/**
|
|
753
|
-
* Shortcut for `alpha` property
|
|
754
|
-
* Number from 0 (transparent) to 255 (opaque)
|
|
755
|
-
* @alias alpha
|
|
756
|
-
*/
|
|
757
|
-
get a() {
|
|
758
|
-
return this.alpha;
|
|
759
|
-
}
|
|
760
|
-
/**
|
|
761
|
-
* Shortcut for `alpha` property
|
|
762
|
-
* Number from 0 (transparent) to 255 (opaque)
|
|
763
|
-
* @alias alpha
|
|
764
|
-
*/
|
|
765
|
-
get opacity() {
|
|
766
|
-
return this.alpha;
|
|
767
|
-
}
|
|
768
|
-
/**
|
|
769
|
-
* Shortcut for 1-`alpha` property
|
|
770
|
-
*/
|
|
771
|
-
get transparency() {
|
|
772
|
-
return 255 - this.alpha;
|
|
773
|
-
}
|
|
774
|
-
clone() {
|
|
775
|
-
return take(this.createColor(this.red, this.green, this.blue, this.alpha));
|
|
776
|
-
}
|
|
777
|
-
toString() {
|
|
778
|
-
return this.toHex();
|
|
779
|
-
}
|
|
780
|
-
toHex() {
|
|
781
|
-
if (this.alpha === 255) {
|
|
782
|
-
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
783
|
-
.toString(16)
|
|
784
|
-
.padStart(2, '0')}`;
|
|
785
|
-
}
|
|
786
|
-
else {
|
|
787
|
-
return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
|
|
788
|
-
.toString(16)
|
|
789
|
-
.padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
toRgb() {
|
|
793
|
-
if (this.alpha === 255) {
|
|
794
|
-
return `rgb(${this.red}, ${this.green}, ${this.blue})`;
|
|
795
|
-
}
|
|
796
|
-
else {
|
|
797
|
-
return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
toHsl() {
|
|
801
|
-
throw new Error(`Getting HSL is not implemented`);
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
|
|
805
806
|
/**
|
|
806
807
|
* Checks if the given value is a valid hex color string
|
|
807
808
|
*
|
|
@@ -1781,6 +1782,110 @@ class UnexpectedError extends Error {
|
|
|
1781
1782
|
}
|
|
1782
1783
|
}
|
|
1783
1784
|
|
|
1785
|
+
/**
|
|
1786
|
+
* Single source of truth about how each supported CLI coding harness is installed and detected.
|
|
1787
|
+
*
|
|
1788
|
+
* @private internal utility of `promptbookCli`
|
|
1789
|
+
*/
|
|
1790
|
+
const HARNESS_DEFINITIONS = {
|
|
1791
|
+
'openai-codex': {
|
|
1792
|
+
harnessName: 'openai-codex',
|
|
1793
|
+
label: 'OpenAI Codex',
|
|
1794
|
+
commandName: 'codex',
|
|
1795
|
+
npmPackageName: '@openai/codex',
|
|
1796
|
+
},
|
|
1797
|
+
'github-copilot': {
|
|
1798
|
+
harnessName: 'github-copilot',
|
|
1799
|
+
label: 'GitHub Copilot',
|
|
1800
|
+
commandName: 'copilot',
|
|
1801
|
+
npmPackageName: '@github/copilot',
|
|
1802
|
+
// Note: The GitHub Copilot CLI downloads its native binary in a postinstall script
|
|
1803
|
+
npmInstallEnvironment: { npm_config_ignore_scripts: 'false' },
|
|
1804
|
+
},
|
|
1805
|
+
cline: {
|
|
1806
|
+
harnessName: 'cline',
|
|
1807
|
+
label: 'Cline',
|
|
1808
|
+
commandName: 'cline',
|
|
1809
|
+
npmPackageName: 'cline',
|
|
1810
|
+
},
|
|
1811
|
+
'claude-code': {
|
|
1812
|
+
harnessName: 'claude-code',
|
|
1813
|
+
label: 'Claude Code',
|
|
1814
|
+
commandName: 'claude',
|
|
1815
|
+
npmPackageName: '@anthropic-ai/claude-code',
|
|
1816
|
+
},
|
|
1817
|
+
opencode: {
|
|
1818
|
+
harnessName: 'opencode',
|
|
1819
|
+
label: 'Opencode',
|
|
1820
|
+
commandName: 'opencode',
|
|
1821
|
+
npmPackageName: 'opencode-ai',
|
|
1822
|
+
},
|
|
1823
|
+
gemini: {
|
|
1824
|
+
harnessName: 'gemini',
|
|
1825
|
+
label: 'Gemini CLI',
|
|
1826
|
+
commandName: 'gemini',
|
|
1827
|
+
npmPackageName: '@google/gemini-cli',
|
|
1828
|
+
},
|
|
1829
|
+
};
|
|
1830
|
+
/**
|
|
1831
|
+
* Looks up the definition of one supported CLI coding harness.
|
|
1832
|
+
*
|
|
1833
|
+
* @private internal utility of `promptbookCli`
|
|
1834
|
+
*/
|
|
1835
|
+
function getHarnessDefinition(harnessName) {
|
|
1836
|
+
const definition = HARNESS_DEFINITIONS[harnessName];
|
|
1837
|
+
if (definition === undefined) {
|
|
1838
|
+
throw new UnexpectedError(spaceTrim$1(`
|
|
1839
|
+
Missing harness definition for \`${harnessName}\`.
|
|
1840
|
+
|
|
1841
|
+
Every harness must be described in \`HARNESS_DEFINITIONS\`.
|
|
1842
|
+
`));
|
|
1843
|
+
}
|
|
1844
|
+
return definition;
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
/**
|
|
1848
|
+
* Orders JSON object by keys
|
|
1849
|
+
*
|
|
1850
|
+
* @returns The same type of object as the input re-ordered
|
|
1851
|
+
*
|
|
1852
|
+
* @public exported from `@promptbook/utils`
|
|
1853
|
+
*/
|
|
1854
|
+
function orderJson(options) {
|
|
1855
|
+
const { value, order } = options;
|
|
1856
|
+
const orderedValue = {
|
|
1857
|
+
...(order === undefined ? {} : Object.fromEntries(order.map((key) => [key, undefined]))),
|
|
1858
|
+
...value,
|
|
1859
|
+
};
|
|
1860
|
+
return orderedValue;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
/**
|
|
1864
|
+
* Freezes the given object and all its nested objects recursively
|
|
1865
|
+
*
|
|
1866
|
+
* Note: `$` is used to indicate that this function is not a pure function - it mutates given object
|
|
1867
|
+
* Note: This function mutates the object and returns the original (but mutated-deep-freezed) object
|
|
1868
|
+
*
|
|
1869
|
+
* @returns The same object as the input, but deeply frozen
|
|
1870
|
+
*
|
|
1871
|
+
* @public exported from `@promptbook/utils`
|
|
1872
|
+
*/
|
|
1873
|
+
function $deepFreeze(objectValue) {
|
|
1874
|
+
if (Array.isArray(objectValue)) {
|
|
1875
|
+
return Object.freeze(objectValue.map((item) => $deepFreeze(item)));
|
|
1876
|
+
}
|
|
1877
|
+
const propertyNames = Object.getOwnPropertyNames(objectValue);
|
|
1878
|
+
for (const propertyName of propertyNames) {
|
|
1879
|
+
const value = objectValue[propertyName];
|
|
1880
|
+
if (value && typeof value === 'object') {
|
|
1881
|
+
$deepFreeze(value);
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
Object.freeze(objectValue);
|
|
1885
|
+
return objectValue;
|
|
1886
|
+
}
|
|
1887
|
+
// TODO: [🧠] Is there a way how to meaningfully test this utility
|
|
1888
|
+
|
|
1784
1889
|
/**
|
|
1785
1890
|
* This error type indicates that somewhere in the code non-Error object was thrown and it was wrapped into the `WrappedError`
|
|
1786
1891
|
*
|
|
@@ -2775,6 +2880,31 @@ const OPENAI_MODELS = exportJson({
|
|
|
2775
2880
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
2776
2881
|
*/
|
|
2777
2882
|
|
|
2883
|
+
/**
|
|
2884
|
+
* Pattern that matches durations like "1h", "30m", "5s", "1h30m", "1h30m5s".
|
|
2885
|
+
*/
|
|
2886
|
+
/**
|
|
2887
|
+
* Formats a duration in milliseconds into a compact human-readable string.
|
|
2888
|
+
*
|
|
2889
|
+
* Examples: `3600000` → `"1h"`, `90000` → `"1m 30s"`, `5000` → `"5s"`.
|
|
2890
|
+
*
|
|
2891
|
+
* @private internal utility of `ptbk coder run`
|
|
2892
|
+
*/
|
|
2893
|
+
function formatDurationMs(ms) {
|
|
2894
|
+
const totalSeconds = Math.ceil(ms / 1000);
|
|
2895
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
2896
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
2897
|
+
const seconds = totalSeconds % 60;
|
|
2898
|
+
const parts = [];
|
|
2899
|
+
if (hours > 0)
|
|
2900
|
+
parts.push(`${hours}h`);
|
|
2901
|
+
if (minutes > 0)
|
|
2902
|
+
parts.push(`${minutes}m`);
|
|
2903
|
+
if (seconds > 0 || parts.length === 0)
|
|
2904
|
+
parts.push(`${seconds}s`);
|
|
2905
|
+
return parts.join(' ');
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2778
2908
|
/**
|
|
2779
2909
|
* Formats one unknown error-like value into readable text for logs and feedback.
|
|
2780
2910
|
*/
|
|
@@ -3002,6 +3132,55 @@ async function $runGoScriptWithOutput(options) {
|
|
|
3002
3132
|
});
|
|
3003
3133
|
}
|
|
3004
3134
|
|
|
3135
|
+
/**
|
|
3136
|
+
* Minimum timer duration used to avoid a zero-millisecond polling loop.
|
|
3137
|
+
*/
|
|
3138
|
+
const MINIMUM_WORLD_TIME_WAIT_POLL_INTERVAL_MS = 1;
|
|
3139
|
+
/**
|
|
3140
|
+
* Waits until one wall-clock deadline has passed.
|
|
3141
|
+
*
|
|
3142
|
+
* The remaining time is recalculated from `Date.now()` after every poll and after every tick callback.
|
|
3143
|
+
* This makes waits elapse while the process is paused at a checkpoint or the computer is asleep.
|
|
3144
|
+
*
|
|
3145
|
+
* @private internal utility of `ptbk coder` wait handling
|
|
3146
|
+
*/
|
|
3147
|
+
async function waitUntilWorldTimeDeadline(options) {
|
|
3148
|
+
var _a;
|
|
3149
|
+
const { deadlineTimeMs, pollIntervalMs, onTick, shouldStopWaiting } = options;
|
|
3150
|
+
const normalizedPollIntervalMs = Math.max(MINIMUM_WORLD_TIME_WAIT_POLL_INTERVAL_MS, pollIntervalMs);
|
|
3151
|
+
const waitForMilliseconds = (_a = options.waitForMilliseconds) !== null && _a !== void 0 ? _a : waitForRegularMilliseconds;
|
|
3152
|
+
while (true) {
|
|
3153
|
+
if (shouldStopWaiting === null || shouldStopWaiting === void 0 ? void 0 : shouldStopWaiting()) {
|
|
3154
|
+
return;
|
|
3155
|
+
}
|
|
3156
|
+
const remainingDurationMs = getRemainingDurationMs(deadlineTimeMs);
|
|
3157
|
+
if (remainingDurationMs <= 0) {
|
|
3158
|
+
return;
|
|
3159
|
+
}
|
|
3160
|
+
await (onTick === null || onTick === void 0 ? void 0 : onTick(remainingDurationMs));
|
|
3161
|
+
if (shouldStopWaiting === null || shouldStopWaiting === void 0 ? void 0 : shouldStopWaiting()) {
|
|
3162
|
+
return;
|
|
3163
|
+
}
|
|
3164
|
+
const remainingDurationAfterTickMs = getRemainingDurationMs(deadlineTimeMs);
|
|
3165
|
+
if (remainingDurationAfterTickMs <= 0) {
|
|
3166
|
+
return;
|
|
3167
|
+
}
|
|
3168
|
+
await waitForMilliseconds(Math.min(normalizedPollIntervalMs, remainingDurationAfterTickMs));
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
/**
|
|
3172
|
+
* Returns the remaining wall-clock duration until a timestamp.
|
|
3173
|
+
*/
|
|
3174
|
+
function getRemainingDurationMs(deadlineTimeMs) {
|
|
3175
|
+
return Math.max(0, deadlineTimeMs - Date.now());
|
|
3176
|
+
}
|
|
3177
|
+
/**
|
|
3178
|
+
* Waits for one short polling interval.
|
|
3179
|
+
*/
|
|
3180
|
+
async function waitForRegularMilliseconds(durationMs) {
|
|
3181
|
+
await new Promise((resolve) => setTimeout(resolve, durationMs));
|
|
3182
|
+
}
|
|
3183
|
+
|
|
3005
3184
|
/**
|
|
3006
3185
|
* Base delimiter used for passing large prompts through stdin.
|
|
3007
3186
|
*/
|
|
@@ -3012,14 +3191,209 @@ const CLAUDE_PROMPT_DELIMITER = 'CLAUDE_PROMPT';
|
|
|
3012
3191
|
function buildClaudeScript(options) {
|
|
3013
3192
|
const MODEL_ARGUMENT = options.model ? ` --model ${options.model}` : '';
|
|
3014
3193
|
const THINKING_LEVEL_ARGUMENT = options.thinkingLevel ? ` --effort ${options.thinkingLevel}` : '';
|
|
3194
|
+
const RESUME_SESSION_ARGUMENT = options.resumeSessionId
|
|
3195
|
+
? ` --resume ${quoteShellArgument(options.resumeSessionId)}`
|
|
3196
|
+
: '';
|
|
3015
3197
|
return spaceTrim((block) => `
|
|
3016
|
-
claude --allowedTools "Bash,Read,Edit,Write"${MODEL_ARGUMENT}${THINKING_LEVEL_ARGUMENT} --output-format stream-json --verbose --include-partial-messages --print <<'${CLAUDE_PROMPT_DELIMITER}'
|
|
3198
|
+
claude --allowedTools "Bash,Read,Edit,Write"${MODEL_ARGUMENT}${THINKING_LEVEL_ARGUMENT}${RESUME_SESSION_ARGUMENT} --output-format stream-json --verbose --include-partial-messages --print <<'${CLAUDE_PROMPT_DELIMITER}'
|
|
3017
3199
|
|
|
3018
3200
|
${block(options.prompt)}
|
|
3019
3201
|
|
|
3020
3202
|
${CLAUDE_PROMPT_DELIMITER}
|
|
3021
3203
|
`);
|
|
3022
3204
|
}
|
|
3205
|
+
/**
|
|
3206
|
+
* Quotes one shell argument for the generated Bash script.
|
|
3207
|
+
*/
|
|
3208
|
+
function quoteShellArgument(value) {
|
|
3209
|
+
return JSON.stringify(value);
|
|
3210
|
+
}
|
|
3211
|
+
|
|
3212
|
+
/**
|
|
3213
|
+
* Parses all JSON lines from Claude Code output while ignoring shell prefixes and stack traces.
|
|
3214
|
+
*/
|
|
3215
|
+
function parseClaudeCodeOutputEvents(output) {
|
|
3216
|
+
return output
|
|
3217
|
+
.split(/\r?\n/u)
|
|
3218
|
+
.map(parseClaudeCodeOutputLine)
|
|
3219
|
+
.filter((event) => event !== undefined);
|
|
3220
|
+
}
|
|
3221
|
+
/**
|
|
3222
|
+
* Finds the final Claude Code result event in a stream-json output blob.
|
|
3223
|
+
*/
|
|
3224
|
+
function findClaudeCodeResultEvent(output) {
|
|
3225
|
+
return parseClaudeCodeOutputEvents(output).find((event) => event.type === 'result');
|
|
3226
|
+
}
|
|
3227
|
+
/**
|
|
3228
|
+
* Parses one output line when it contains a JSON object.
|
|
3229
|
+
*/
|
|
3230
|
+
function parseClaudeCodeOutputLine(line) {
|
|
3231
|
+
const jsonStartIndex = line.indexOf('{');
|
|
3232
|
+
if (jsonStartIndex === -1) {
|
|
3233
|
+
return undefined;
|
|
3234
|
+
}
|
|
3235
|
+
const possibleJson = line.slice(jsonStartIndex).trim();
|
|
3236
|
+
try {
|
|
3237
|
+
const parsed = JSON.parse(possibleJson);
|
|
3238
|
+
if (isClaudeCodeOutputEvent(parsed)) {
|
|
3239
|
+
return parsed;
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3242
|
+
catch (_a) {
|
|
3243
|
+
return undefined;
|
|
3244
|
+
}
|
|
3245
|
+
return undefined;
|
|
3246
|
+
}
|
|
3247
|
+
/**
|
|
3248
|
+
* Checks whether an unknown parsed JSON value has the object shape expected from Claude Code events.
|
|
3249
|
+
*/
|
|
3250
|
+
function isClaudeCodeOutputEvent(value) {
|
|
3251
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3252
|
+
}
|
|
3253
|
+
|
|
3254
|
+
/**
|
|
3255
|
+
* Number of milliseconds added after Claude's reported reset timestamp before retrying.
|
|
3256
|
+
*/
|
|
3257
|
+
const CLAUDE_CODE_SESSION_LIMIT_RESET_BUFFER_MS = 30 * 1000;
|
|
3258
|
+
/**
|
|
3259
|
+
* Fallback delay used when Claude reports a session limit without a machine-readable reset timestamp.
|
|
3260
|
+
*/
|
|
3261
|
+
const DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS = 10 * 60 * 1000;
|
|
3262
|
+
/**
|
|
3263
|
+
* Extracts a Claude Code session-limit failure from a thrown runner error.
|
|
3264
|
+
*/
|
|
3265
|
+
function extractClaudeCodeSessionLimitFromError(error) {
|
|
3266
|
+
return extractClaudeCodeSessionLimitFromOutput(formatUnknownErrorDetails(error));
|
|
3267
|
+
}
|
|
3268
|
+
/**
|
|
3269
|
+
* Extracts a Claude Code session-limit failure from raw stream-json output.
|
|
3270
|
+
*/
|
|
3271
|
+
function extractClaudeCodeSessionLimitFromOutput(output) {
|
|
3272
|
+
var _a, _b, _c, _d, _e;
|
|
3273
|
+
const events = parseClaudeCodeOutputEvents(output);
|
|
3274
|
+
const rejectedRateLimitEvent = events.find(isRejectedRateLimitEvent);
|
|
3275
|
+
const sessionLimitResultEvent = events.find(isSessionLimitResultEvent);
|
|
3276
|
+
const sessionLimitTextEvent = events.find(isSessionLimitTextEvent);
|
|
3277
|
+
if (!sessionLimitResultEvent && !sessionLimitTextEvent) {
|
|
3278
|
+
return undefined;
|
|
3279
|
+
}
|
|
3280
|
+
const sessionId = findClaudeCodeSessionId(events);
|
|
3281
|
+
if (!sessionId) {
|
|
3282
|
+
return undefined;
|
|
3283
|
+
}
|
|
3284
|
+
const resetDate = extractResetDate(rejectedRateLimitEvent);
|
|
3285
|
+
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;
|
|
3286
|
+
const summary = (_e = (_d = extractSessionLimitSummary(sessionLimitResultEvent)) !== null && _d !== void 0 ? _d : extractSessionLimitSummary(sessionLimitTextEvent)) !== null && _e !== void 0 ? _e : 'Claude Code reported a session limit.';
|
|
3287
|
+
return {
|
|
3288
|
+
sessionId,
|
|
3289
|
+
resetDate,
|
|
3290
|
+
rateLimitType,
|
|
3291
|
+
summary,
|
|
3292
|
+
};
|
|
3293
|
+
}
|
|
3294
|
+
/**
|
|
3295
|
+
* Computes how long to wait before trying to resume the Claude Code session.
|
|
3296
|
+
*/
|
|
3297
|
+
function getClaudeCodeSessionLimitDelayMs(sessionLimit, nowMs = Date.now()) {
|
|
3298
|
+
if (!sessionLimit.resetDate) {
|
|
3299
|
+
return DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS;
|
|
3300
|
+
}
|
|
3301
|
+
return Math.max(0, sessionLimit.resetDate.getTime() - nowMs + CLAUDE_CODE_SESSION_LIMIT_RESET_BUFFER_MS);
|
|
3302
|
+
}
|
|
3303
|
+
/**
|
|
3304
|
+
* Builds the follow-up prompt sent into a resumed Claude Code session after its limit resets.
|
|
3305
|
+
*/
|
|
3306
|
+
function buildClaudeCodeSessionResurrectionPrompt(originalPrompt, sessionId) {
|
|
3307
|
+
return spaceTrim((block) => `
|
|
3308
|
+
## Claude Code session resurrection
|
|
3309
|
+
|
|
3310
|
+
You are resuming Claude Code session \`${sessionId}\` after Claude reported a session limit.
|
|
3311
|
+
Continue the same task from the existing repository and session state.
|
|
3312
|
+
Do not discard useful context, completed analysis, or file changes from the resumed session.
|
|
3313
|
+
|
|
3314
|
+
The original prompt is repeated below as reference in case the resumed session needs it.
|
|
3315
|
+
|
|
3316
|
+
## Original prompt
|
|
3317
|
+
|
|
3318
|
+
${block(originalPrompt)}
|
|
3319
|
+
`);
|
|
3320
|
+
}
|
|
3321
|
+
/**
|
|
3322
|
+
* Builds a compact one-line label for logs and terminal UI messages.
|
|
3323
|
+
*/
|
|
3324
|
+
function formatClaudeCodeSessionLimitForDisplay(sessionLimit) {
|
|
3325
|
+
const resetSuffix = sessionLimit.resetDate
|
|
3326
|
+
? `, resets at ${sessionLimit.resetDate.toISOString()}`
|
|
3327
|
+
: `, retrying every ${formatDurationMs(DEFAULT_CLAUDE_CODE_SESSION_LIMIT_RETRY_DELAY_MS)}`;
|
|
3328
|
+
const rateLimitSuffix = sessionLimit.rateLimitType ? ` (${sessionLimit.rateLimitType})` : '';
|
|
3329
|
+
return `${sessionLimit.summary}${rateLimitSuffix}${resetSuffix}`;
|
|
3330
|
+
}
|
|
3331
|
+
/**
|
|
3332
|
+
* Returns true when the event is an explicit rejected Claude Code rate-limit event.
|
|
3333
|
+
*/
|
|
3334
|
+
function isRejectedRateLimitEvent(event) {
|
|
3335
|
+
var _a;
|
|
3336
|
+
return event.type === 'rate_limit_event' && ((_a = event.rate_limit_info) === null || _a === void 0 ? void 0 : _a.status) === 'rejected';
|
|
3337
|
+
}
|
|
3338
|
+
/**
|
|
3339
|
+
* Returns true when the final result reports the Claude session limit.
|
|
3340
|
+
*/
|
|
3341
|
+
function isSessionLimitResultEvent(event) {
|
|
3342
|
+
return (event.type === 'result' &&
|
|
3343
|
+
event.is_error === true &&
|
|
3344
|
+
event.api_error_status === 429 &&
|
|
3345
|
+
isSessionLimitText(event.result));
|
|
3346
|
+
}
|
|
3347
|
+
/**
|
|
3348
|
+
* Returns true when any assistant event reports the Claude session limit in text.
|
|
3349
|
+
*/
|
|
3350
|
+
function isSessionLimitTextEvent(event) {
|
|
3351
|
+
if (event.error !== 'rate_limit') {
|
|
3352
|
+
return false;
|
|
3353
|
+
}
|
|
3354
|
+
return isSessionLimitText(extractSessionLimitSummary(event));
|
|
3355
|
+
}
|
|
3356
|
+
/**
|
|
3357
|
+
* Extracts the first session id reported by Claude Code.
|
|
3358
|
+
*/
|
|
3359
|
+
function findClaudeCodeSessionId(events) {
|
|
3360
|
+
return events.map((event) => event.session_id).find((sessionId) => Boolean(sessionId));
|
|
3361
|
+
}
|
|
3362
|
+
/**
|
|
3363
|
+
* Extracts Claude's reset timestamp from a rejected rate-limit event.
|
|
3364
|
+
*/
|
|
3365
|
+
function extractResetDate(event) {
|
|
3366
|
+
var _a;
|
|
3367
|
+
const resetsAt = (_a = event === null || event === void 0 ? void 0 : event.rate_limit_info) === null || _a === void 0 ? void 0 : _a.resetsAt;
|
|
3368
|
+
if (typeof resetsAt !== 'number' || !Number.isFinite(resetsAt)) {
|
|
3369
|
+
return undefined;
|
|
3370
|
+
}
|
|
3371
|
+
const resetDate = new Date(resetsAt * 1000);
|
|
3372
|
+
if (Number.isNaN(resetDate.getTime())) {
|
|
3373
|
+
return undefined;
|
|
3374
|
+
}
|
|
3375
|
+
return resetDate;
|
|
3376
|
+
}
|
|
3377
|
+
/**
|
|
3378
|
+
* Extracts a human-readable session-limit summary from an event.
|
|
3379
|
+
*/
|
|
3380
|
+
function extractSessionLimitSummary(event) {
|
|
3381
|
+
var _a, _b;
|
|
3382
|
+
if (!event) {
|
|
3383
|
+
return undefined;
|
|
3384
|
+
}
|
|
3385
|
+
if (typeof event.result === 'string' && event.result.trim()) {
|
|
3386
|
+
return event.result.trim();
|
|
3387
|
+
}
|
|
3388
|
+
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));
|
|
3389
|
+
return textContent;
|
|
3390
|
+
}
|
|
3391
|
+
/**
|
|
3392
|
+
* Checks whether a text value names the Claude Code session limit.
|
|
3393
|
+
*/
|
|
3394
|
+
function isSessionLimitText(text) {
|
|
3395
|
+
return /\bsession\s+limit\b/iu.test(text !== null && text !== void 0 ? text : '');
|
|
3396
|
+
}
|
|
3023
3397
|
|
|
3024
3398
|
/**
|
|
3025
3399
|
* Represents the uncertain value
|
|
@@ -3095,14 +3469,8 @@ const UNCERTAIN_USAGE = $deepFreeze({
|
|
|
3095
3469
|
function parseClaudeCodeJsonOutput(output) {
|
|
3096
3470
|
var _a, _b, _c, _d;
|
|
3097
3471
|
try {
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
const jsonLine = lines.find((line) => line.trim().startsWith('{"type":"result"'));
|
|
3101
|
-
if (!jsonLine) {
|
|
3102
|
-
return UNCERTAIN_USAGE;
|
|
3103
|
-
}
|
|
3104
|
-
const parsed = JSON.parse(jsonLine);
|
|
3105
|
-
if (parsed.type !== 'result') {
|
|
3472
|
+
const parsed = findClaudeCodeResultEvent(output);
|
|
3473
|
+
if (!parsed) {
|
|
3106
3474
|
return UNCERTAIN_USAGE;
|
|
3107
3475
|
}
|
|
3108
3476
|
const totalInputTokens = (((_a = parsed.usage) === null || _a === void 0 ? void 0 : _a.input_tokens) || 0) +
|
|
@@ -3146,6 +3514,10 @@ function parseClaudeCodeJsonOutput(output) {
|
|
|
3146
3514
|
}
|
|
3147
3515
|
}
|
|
3148
3516
|
|
|
3517
|
+
/**
|
|
3518
|
+
* Polling interval used while waiting for Claude Code session limits to reset.
|
|
3519
|
+
*/
|
|
3520
|
+
const CLAUDE_CODE_SESSION_RESURRECTION_POLL_MS = 30 * 1000;
|
|
3149
3521
|
/**
|
|
3150
3522
|
* Runs prompts via the Claude Code CLI.
|
|
3151
3523
|
*/
|
|
@@ -3161,22 +3533,98 @@ class ClaudeCodeRunner {
|
|
|
3161
3533
|
* Runs the prompt using Claude Code and parses usage output.
|
|
3162
3534
|
*/
|
|
3163
3535
|
async runPrompt(options) {
|
|
3536
|
+
let resumeSessionId;
|
|
3537
|
+
let prompt = options.prompt;
|
|
3538
|
+
let resurrectionCount = 0;
|
|
3539
|
+
while (true) {
|
|
3540
|
+
const output = await this.runClaudeCodeOnce({
|
|
3541
|
+
...options,
|
|
3542
|
+
prompt,
|
|
3543
|
+
resumeSessionId,
|
|
3544
|
+
}).catch(async (error) => {
|
|
3545
|
+
const sessionLimit = extractClaudeCodeSessionLimitFromError(error);
|
|
3546
|
+
if (!sessionLimit) {
|
|
3547
|
+
throw error;
|
|
3548
|
+
}
|
|
3549
|
+
resurrectionCount++;
|
|
3550
|
+
await waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options);
|
|
3551
|
+
resumeSessionId = sessionLimit.sessionId;
|
|
3552
|
+
prompt = buildClaudeCodeSessionResurrectionPrompt(options.prompt, sessionLimit.sessionId);
|
|
3553
|
+
return undefined;
|
|
3554
|
+
});
|
|
3555
|
+
if (output === undefined) {
|
|
3556
|
+
continue;
|
|
3557
|
+
}
|
|
3558
|
+
const sessionLimit = extractClaudeCodeSessionLimitFromOutput(output);
|
|
3559
|
+
if (sessionLimit) {
|
|
3560
|
+
resurrectionCount++;
|
|
3561
|
+
await waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options);
|
|
3562
|
+
resumeSessionId = sessionLimit.sessionId;
|
|
3563
|
+
prompt = buildClaudeCodeSessionResurrectionPrompt(options.prompt, sessionLimit.sessionId);
|
|
3564
|
+
continue;
|
|
3565
|
+
}
|
|
3566
|
+
const usage = parseClaudeCodeJsonOutput(output);
|
|
3567
|
+
return { usage };
|
|
3568
|
+
}
|
|
3569
|
+
}
|
|
3570
|
+
/**
|
|
3571
|
+
* Runs one Claude Code CLI process and returns its raw output.
|
|
3572
|
+
*/
|
|
3573
|
+
async runClaudeCodeOnce(options) {
|
|
3164
3574
|
const scriptContent = buildClaudeScript({
|
|
3165
3575
|
prompt: options.prompt,
|
|
3166
3576
|
model: this.options.model,
|
|
3167
3577
|
thinkingLevel: this.options.thinkingLevel,
|
|
3578
|
+
resumeSessionId: options.resumeSessionId,
|
|
3168
3579
|
});
|
|
3169
|
-
|
|
3580
|
+
return await $runGoScriptWithOutput({
|
|
3170
3581
|
scriptPath: options.scriptPath,
|
|
3171
3582
|
scriptContent,
|
|
3172
3583
|
logPath: options.logPath,
|
|
3173
3584
|
shouldPrintLiveOutput: options.shouldPrintLiveOutput,
|
|
3174
3585
|
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
3175
3586
|
});
|
|
3176
|
-
const usage = parseClaudeCodeJsonOutput(output);
|
|
3177
|
-
return { usage };
|
|
3178
3587
|
}
|
|
3179
3588
|
}
|
|
3589
|
+
/**
|
|
3590
|
+
* Waits until the Claude Code session can be resumed, keeping terminal status clear.
|
|
3591
|
+
*/
|
|
3592
|
+
async function waitForClaudeCodeSessionLimitReset(sessionLimit, resurrectionCount, options) {
|
|
3593
|
+
var _a, _b;
|
|
3594
|
+
const delayMs = getClaudeCodeSessionLimitDelayMs(sessionLimit);
|
|
3595
|
+
const resetDeadlineTimeMs = Date.now() + delayMs;
|
|
3596
|
+
const sessionLabel = formatClaudeCodeSessionIdForDisplay(sessionLimit.sessionId);
|
|
3597
|
+
const resetSummary = formatClaudeCodeSessionLimitForDisplay(sessionLimit);
|
|
3598
|
+
if ((_a = options.shouldPrintLiveOutput) !== null && _a !== void 0 ? _a : true) {
|
|
3599
|
+
console.warn(colors.yellow(`[claude-code] Session limit detected for ${sessionLimit.sessionId}. Resurrection #${resurrectionCount} will resume with --resume after ${formatDurationMs(delayMs)}. ${resetSummary}`));
|
|
3600
|
+
}
|
|
3601
|
+
await waitUntilWorldTimeDeadline({
|
|
3602
|
+
deadlineTimeMs: resetDeadlineTimeMs,
|
|
3603
|
+
pollIntervalMs: CLAUDE_CODE_SESSION_RESURRECTION_POLL_MS,
|
|
3604
|
+
onTick: async (remainingDelayMs) => {
|
|
3605
|
+
var _a;
|
|
3606
|
+
await ((_a = options.waitForPauseCheckpoint) === null || _a === void 0 ? void 0 : _a.call(options, {
|
|
3607
|
+
checkpointLabel: 'the Claude Code session limit reset',
|
|
3608
|
+
phase: 'waiting',
|
|
3609
|
+
statusMessage: `Claude Code session ${sessionLabel} hit its limit; resurrection #${resurrectionCount} resumes in ${formatDurationMs(Math.min(remainingDelayMs, delayMs))}`,
|
|
3610
|
+
}));
|
|
3611
|
+
},
|
|
3612
|
+
});
|
|
3613
|
+
await ((_b = options.waitForPauseCheckpoint) === null || _b === void 0 ? void 0 : _b.call(options, {
|
|
3614
|
+
checkpointLabel: 'resurrecting the Claude Code session with --resume',
|
|
3615
|
+
phase: 'running',
|
|
3616
|
+
statusMessage: `Resurrecting Claude Code session ${sessionLabel} with --resume`,
|
|
3617
|
+
}));
|
|
3618
|
+
}
|
|
3619
|
+
/**
|
|
3620
|
+
* Formats a Claude Code session id for compact terminal status lines.
|
|
3621
|
+
*/
|
|
3622
|
+
function formatClaudeCodeSessionIdForDisplay(sessionId) {
|
|
3623
|
+
if (sessionId.length <= 8) {
|
|
3624
|
+
return sessionId;
|
|
3625
|
+
}
|
|
3626
|
+
return `${sessionId.slice(0, 8)}...`;
|
|
3627
|
+
}
|
|
3180
3628
|
|
|
3181
3629
|
/**
|
|
3182
3630
|
* Creates a temporary script file, runs it, and cleans it up unless preservation is requested or the run fails.
|
|
@@ -3775,6 +4223,27 @@ class ProgressiveBackoff {
|
|
|
3775
4223
|
}
|
|
3776
4224
|
}
|
|
3777
4225
|
|
|
4226
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
4227
|
+
/**
|
|
4228
|
+
* Stable stdout marker printed by the generated Codex runner script to report which login method it used.
|
|
4229
|
+
*
|
|
4230
|
+
* The marker is followed by the resolved method keyword, for example `ptbk-codex-login-method: chatgpt`,
|
|
4231
|
+
* so `parseCodexLoginMethodFromOutput` can recover it from the captured runner output.
|
|
4232
|
+
*
|
|
4233
|
+
* @private internal constant of the OpenAI Codex runner
|
|
4234
|
+
*/
|
|
4235
|
+
const CODEX_LOGIN_METHOD_MARKER = 'ptbk-codex-login-method:';
|
|
4236
|
+
/**
|
|
4237
|
+
* Substring that the `codex login status` command prints when the Codex CLI is signed in with a
|
|
4238
|
+
* ChatGPT subscription account instead of an `OPENAI_API_KEY`.
|
|
4239
|
+
*
|
|
4240
|
+
* This is the single source of truth for detecting an active ChatGPT login, reused by the Codex runner
|
|
4241
|
+
* script and by the Agents Server harness authentication status resolver.
|
|
4242
|
+
*
|
|
4243
|
+
* @private internal constant of the OpenAI Codex runner and the Agents Server Harness Auth
|
|
4244
|
+
*/
|
|
4245
|
+
const CODEX_CHATGPT_LOGIN_STATUS_NEEDLE = 'Logged in using ChatGPT';
|
|
4246
|
+
|
|
3778
4247
|
/**
|
|
3779
4248
|
* Default Codex reasoning effort preserved for backwards compatibility when no CLI override is provided.
|
|
3780
4249
|
*/
|
|
@@ -3791,10 +4260,28 @@ function buildCodexScript(options) {
|
|
|
3791
4260
|
const delimiter = resolveShellHereDocumentDelimiter(CODEX_PROMPT_DELIMITER, options.prompt);
|
|
3792
4261
|
const projectPath = toPosixPath(options.projectPath);
|
|
3793
4262
|
const loginMethodConfig = spaceTrim(`
|
|
4263
|
+
CODEX_LOGIN_STATUS="$(
|
|
4264
|
+
unset OPENAI_API_KEY OPENAI_BASE_URL CODEX_API_KEY
|
|
4265
|
+
# 'codex login status' prints the "Logged in using ChatGPT" line to stderr, so merge stderr into stdout (2>&1) to capture it
|
|
4266
|
+
${options.codexCommand} login status 2>&1 || true
|
|
4267
|
+
)"
|
|
4268
|
+
case "$CODEX_LOGIN_STATUS" in
|
|
4269
|
+
*"${CODEX_CHATGPT_LOGIN_STATUS_NEEDLE}"*)
|
|
4270
|
+
IS_CODEX_CHATGPT_LOGIN_ACTIVE=1
|
|
4271
|
+
;;
|
|
4272
|
+
*)
|
|
4273
|
+
IS_CODEX_CHATGPT_LOGIN_ACTIVE=0
|
|
4274
|
+
;;
|
|
4275
|
+
esac
|
|
4276
|
+
|
|
4277
|
+
CODEX_LOGIN_METHOD=chatgpt
|
|
3794
4278
|
${options.allowCredits ? 'CODEX_LOGIN_METHOD_ARGUMENTS=()' : 'CODEX_LOGIN_METHOD_ARGUMENTS=(-c forced_login_method=chatgpt)'}
|
|
3795
4279
|
unset CODEX_API_KEY
|
|
3796
|
-
if [ "
|
|
4280
|
+
if [ "$IS_CODEX_CHATGPT_LOGIN_ACTIVE" != "1" ] &&
|
|
4281
|
+
[ "\${PTBK_OPENAI_CODEX_USE_API_KEY:-0}" = "1" ] &&
|
|
4282
|
+
[ -n "\${OPENAI_API_KEY:-}" ]; then
|
|
3797
4283
|
CODEX_LOGIN_METHOD_ARGUMENTS=(-c forced_login_method=api)
|
|
4284
|
+
CODEX_LOGIN_METHOD=api
|
|
3798
4285
|
CODEX_API_KEY="\${OPENAI_API_KEY}"
|
|
3799
4286
|
export CODEX_API_KEY
|
|
3800
4287
|
fi
|
|
@@ -3813,11 +4300,15 @@ function buildCodexScript(options) {
|
|
|
3813
4300
|
'',
|
|
3814
4301
|
loginMethodConfig,
|
|
3815
4302
|
'',
|
|
3816
|
-
'if [ "$
|
|
4303
|
+
'if [ "$IS_CODEX_CHATGPT_LOGIN_ACTIVE" = "1" ] ||',
|
|
4304
|
+
' [ "${PTBK_OPENAI_CODEX_USE_API_KEY:-0}" != "1" ] ||',
|
|
4305
|
+
' [ -z "${OPENAI_API_KEY:-}" ]; then',
|
|
3817
4306
|
'unset OPENAI_API_KEY',
|
|
3818
4307
|
'unset OPENAI_BASE_URL',
|
|
3819
4308
|
'fi',
|
|
3820
4309
|
'',
|
|
4310
|
+
`printf '%s %s\\n' '${CODEX_LOGIN_METHOD_MARKER}' "\${CODEX_LOGIN_METHOD}"`,
|
|
4311
|
+
'',
|
|
3821
4312
|
`${options.codexCommand} \\`,
|
|
3822
4313
|
' "${CODEX_LOGIN_METHOD_ARGUMENTS[@]}" \\',
|
|
3823
4314
|
` -c model_reasoning_effort="${thinkingLevel}" \\`,
|
|
@@ -4019,6 +4510,37 @@ function resolveCodexPricing(modelName) {
|
|
|
4019
4510
|
return (_c = OPENAI_MODELS.find((model) => model.modelName === CODEX_FALLBACK_PRICING_MODEL)) === null || _c === void 0 ? void 0 : _c.pricing;
|
|
4020
4511
|
}
|
|
4021
4512
|
|
|
4513
|
+
/**
|
|
4514
|
+
* Detects which login method Codex used from the captured CLI output.
|
|
4515
|
+
*
|
|
4516
|
+
* The generated Codex runner script prints one `CODEX_LOGIN_METHOD_MARKER` line before invoking Codex.
|
|
4517
|
+
* The most recent marker wins so retries within one captured output resolve to the final decision.
|
|
4518
|
+
*
|
|
4519
|
+
* @returns The resolved login method, or `unknown` when no marker is present.
|
|
4520
|
+
*/
|
|
4521
|
+
function parseCodexLoginMethodFromOutput(output) {
|
|
4522
|
+
const lines = output.split(/\r?\n/);
|
|
4523
|
+
for (let index = lines.length - 1; index >= 0; index--) {
|
|
4524
|
+
const line = lines[index];
|
|
4525
|
+
if (line === undefined) {
|
|
4526
|
+
continue;
|
|
4527
|
+
}
|
|
4528
|
+
const markerIndex = line.indexOf(CODEX_LOGIN_METHOD_MARKER);
|
|
4529
|
+
if (markerIndex === -1) {
|
|
4530
|
+
continue;
|
|
4531
|
+
}
|
|
4532
|
+
const reportedMethod = line.slice(markerIndex + CODEX_LOGIN_METHOD_MARKER.length).trim().toLowerCase();
|
|
4533
|
+
if (reportedMethod === 'chatgpt') {
|
|
4534
|
+
return 'chatgpt';
|
|
4535
|
+
}
|
|
4536
|
+
if (reportedMethod === 'api') {
|
|
4537
|
+
return 'api';
|
|
4538
|
+
}
|
|
4539
|
+
return 'unknown';
|
|
4540
|
+
}
|
|
4541
|
+
return 'unknown';
|
|
4542
|
+
}
|
|
4543
|
+
|
|
4022
4544
|
/**
|
|
4023
4545
|
* Error signatures that mean Codex requires credit spending to continue.
|
|
4024
4546
|
*/
|
|
@@ -4128,12 +4650,6 @@ const RATE_LIMIT_BACKOFF_MAX_MS = 30 * 60 * 1000;
|
|
|
4128
4650
|
* Randomized delay proportion added/subtracted for retry jitter.
|
|
4129
4651
|
*/
|
|
4130
4652
|
const RATE_LIMIT_BACKOFF_JITTER_RATIO = 0.15;
|
|
4131
|
-
/**
|
|
4132
|
-
* Waits for one given amount of milliseconds.
|
|
4133
|
-
*/
|
|
4134
|
-
async function waitFor(delayMs) {
|
|
4135
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
4136
|
-
}
|
|
4137
4653
|
/**
|
|
4138
4654
|
* Formats a delay value into a concise `xh ym zs` style label.
|
|
4139
4655
|
*/
|
|
@@ -4211,7 +4727,10 @@ class OpenAiCodexRunner {
|
|
|
4211
4727
|
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
4212
4728
|
});
|
|
4213
4729
|
this.rateLimitBackoff.reset();
|
|
4214
|
-
return {
|
|
4730
|
+
return {
|
|
4731
|
+
usage: buildCodexUsageFromOutput(output, this.options.model),
|
|
4732
|
+
loginMethod: parseCodexLoginMethodFromOutput(output),
|
|
4733
|
+
};
|
|
4215
4734
|
}
|
|
4216
4735
|
catch (error) {
|
|
4217
4736
|
const details = extractCodexFailureDetails(error);
|
|
@@ -4223,13 +4742,18 @@ class OpenAiCodexRunner {
|
|
|
4223
4742
|
throw error;
|
|
4224
4743
|
}
|
|
4225
4744
|
const delayMs = this.rateLimitBackoff.nextDelayMs();
|
|
4226
|
-
const
|
|
4745
|
+
const retryDeadlineTimeMs = Date.now() + delayMs;
|
|
4746
|
+
const retryAt = new Date(retryDeadlineTimeMs).toISOString();
|
|
4227
4747
|
const retryIndex = this.rateLimitBackoff.retryCount;
|
|
4228
4748
|
const summary = extractFailureSummary(details);
|
|
4229
4749
|
if ((_b = options.shouldPrintLiveOutput) !== null && _b !== void 0 ? _b : true) {
|
|
4230
4750
|
console.warn(colors.yellow(`[codex] Rate limit/quota detected (${summary}). Retry #${retryIndex} in ${formatDelay(delayMs)} at ${retryAt}.`));
|
|
4231
4751
|
}
|
|
4232
|
-
await waitForRetryDelay(
|
|
4752
|
+
await waitForRetryDelay({
|
|
4753
|
+
delayMs,
|
|
4754
|
+
retryDeadlineTimeMs,
|
|
4755
|
+
promptRunOptions: options,
|
|
4756
|
+
});
|
|
4233
4757
|
}
|
|
4234
4758
|
}
|
|
4235
4759
|
}
|
|
@@ -4237,20 +4761,21 @@ class OpenAiCodexRunner {
|
|
|
4237
4761
|
/**
|
|
4238
4762
|
* Waits for the next Codex retry while polling for requested pause checkpoints.
|
|
4239
4763
|
*/
|
|
4240
|
-
async function waitForRetryDelay(
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4764
|
+
async function waitForRetryDelay(options) {
|
|
4765
|
+
const { delayMs, retryDeadlineTimeMs, promptRunOptions } = options;
|
|
4766
|
+
await waitUntilWorldTimeDeadline({
|
|
4767
|
+
deadlineTimeMs: retryDeadlineTimeMs,
|
|
4768
|
+
pollIntervalMs: RATE_LIMIT_BACKOFF_POLL_MS,
|
|
4769
|
+
onTick: async (remainingDelayMs) => {
|
|
4770
|
+
var _a;
|
|
4771
|
+
const remainingDelayLabel = formatDelay(Math.min(remainingDelayMs, delayMs));
|
|
4772
|
+
await ((_a = promptRunOptions.waitForPauseCheckpoint) === null || _a === void 0 ? void 0 : _a.call(promptRunOptions, {
|
|
4773
|
+
checkpointLabel: 'the next OpenAI Codex retry after rate limit',
|
|
4774
|
+
phase: 'running',
|
|
4775
|
+
statusMessage: `Waiting ${remainingDelayLabel} before retrying OpenAI Codex`,
|
|
4776
|
+
}));
|
|
4777
|
+
},
|
|
4778
|
+
});
|
|
4254
4779
|
}
|
|
4255
4780
|
|
|
4256
4781
|
/**
|
|
@@ -4388,17 +4913,6 @@ const DEFAULT_CODEX_MODEL = 'gpt-5.2-codex';
|
|
|
4388
4913
|
* Constant for cline model.
|
|
4389
4914
|
*/
|
|
4390
4915
|
const CLINE_MODEL = 'gemini:gemini-3-flash-preview';
|
|
4391
|
-
/**
|
|
4392
|
-
* Map of runner labels.
|
|
4393
|
-
*/
|
|
4394
|
-
const RUNNER_LABELS = {
|
|
4395
|
-
'openai-codex': 'OpenAI Codex',
|
|
4396
|
-
'github-copilot': 'GitHub Copilot',
|
|
4397
|
-
cline: 'Cline',
|
|
4398
|
-
'claude-code': 'Claude Code',
|
|
4399
|
-
opencode: 'Opencode',
|
|
4400
|
-
gemini: 'Gemini CLI',
|
|
4401
|
-
};
|
|
4402
4916
|
/**
|
|
4403
4917
|
* Resolves the configured prompt runner together with status-line metadata.
|
|
4404
4918
|
*
|
|
@@ -4490,8 +5004,7 @@ function createRunnerResolution(options, runner, actualRunnerModel) {
|
|
|
4490
5004
|
* Resolves runner metadata for prompt status lines.
|
|
4491
5005
|
*/
|
|
4492
5006
|
function getRunnerMetadata(options, actualRunnerModel) {
|
|
4493
|
-
|
|
4494
|
-
const runnerName = options.agentName ? (_a = RUNNER_LABELS[options.agentName]) !== null && _a !== void 0 ? _a : 'unknown' : 'unknown';
|
|
5007
|
+
const runnerName = options.agentName ? getHarnessDefinition(options.agentName).label : 'unknown';
|
|
4495
5008
|
if (options.agentName === 'openai-codex' ||
|
|
4496
5009
|
options.agentName === 'github-copilot' ||
|
|
4497
5010
|
options.agentName === 'gemini') {
|
|
@@ -4537,16 +5050,87 @@ function exitForMissingModel(agentName, availableModels, exampleUsages) {
|
|
|
4537
5050
|
process.exit(1);
|
|
4538
5051
|
}
|
|
4539
5052
|
|
|
5053
|
+
/**
|
|
5054
|
+
* Builds the `## Projects` prompt section explaining the agent-owned projects convention.
|
|
5055
|
+
*
|
|
5056
|
+
* The section is part of the prompt of every harness, so each coding agent knows it has its
|
|
5057
|
+
* own isolated project folders it fully controls and how to reference them in the chat.
|
|
5058
|
+
*/
|
|
5059
|
+
function buildAgentProjectsPromptSection(options = {}) {
|
|
5060
|
+
const { projectsUrlPath } = options;
|
|
5061
|
+
return spaceTrim$1((block) => `
|
|
5062
|
+
## Projects
|
|
5063
|
+
|
|
5064
|
+
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.
|
|
5065
|
+
|
|
5066
|
+
- 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.
|
|
5067
|
+
- 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.
|
|
5068
|
+
- A project can be a git repository — you can run \`git init\` inside a project folder and commit your work there.
|
|
5069
|
+
- Do not touch anything outside the \`${AGENT_PROJECTS_DIRECTORY_PATH}/\` directory except the queued message file you are answering.
|
|
5070
|
+
|
|
5071
|
+
${block(buildProjectReferenceInstructions(projectsUrlPath))}
|
|
5072
|
+
${block(buildProjectRuntimeInstructions(options.projectRuntimeApi))}
|
|
5073
|
+
`);
|
|
5074
|
+
}
|
|
5075
|
+
/**
|
|
5076
|
+
* Builds the part of the section explaining how to reference projects in chat answers.
|
|
5077
|
+
*/
|
|
5078
|
+
function buildProjectReferenceInstructions(projectsUrlPath) {
|
|
5079
|
+
if (!projectsUrlPath) {
|
|
5080
|
+
return spaceTrim$1(`
|
|
5081
|
+
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\`.
|
|
5082
|
+
`);
|
|
5083
|
+
}
|
|
5084
|
+
return spaceTrim$1(`
|
|
5085
|
+
You can link any project or any file of any project into the chat answer as a markdown link:
|
|
5086
|
+
|
|
5087
|
+
- Link one file: \`[index.html](${projectsUrlPath}/<project-name>/files/<file-path>)\` — for example \`[Homepage](${projectsUrlPath}/my-website/files/index.html)\`
|
|
5088
|
+
- Link the projects dashboard listing all your projects: \`[My projects](${projectsUrlPath})\`
|
|
5089
|
+
|
|
5090
|
+
Use these links whenever you want to show the user a file you created or changed in a project.
|
|
5091
|
+
`);
|
|
5092
|
+
}
|
|
5093
|
+
/**
|
|
5094
|
+
* Builds instructions for running projects through the Agents Server runtime API.
|
|
5095
|
+
*/
|
|
5096
|
+
function buildProjectRuntimeInstructions(projectRuntimeApi) {
|
|
5097
|
+
if (!projectRuntimeApi) {
|
|
5098
|
+
return '';
|
|
5099
|
+
}
|
|
5100
|
+
return spaceTrim$1(`
|
|
5101
|
+
You can make a project runnable in the user's browser by asking the Agents Server to start it:
|
|
5102
|
+
|
|
5103
|
+
- The server automatically runs \`npm run dev\` for a project whose \`package.json\` declares a non-empty \`dev\` script.
|
|
5104
|
+
- Otherwise, the server starts a static file server for the project.
|
|
5105
|
+
- 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\`.
|
|
5106
|
+
- Always include the returned \`runtime.url\` in your answer when the user should open the running project.
|
|
5107
|
+
|
|
5108
|
+
Examples:
|
|
5109
|
+
|
|
5110
|
+
\`\`\`bash
|
|
5111
|
+
curl -sS -X POST "$${projectRuntimeApi.serverUrlEnvironmentVariableName}/api/internal/agent-project-runtimes" \\
|
|
5112
|
+
-H "Content-Type: application/json" \\
|
|
5113
|
+
-H "x-user-chat-worker-token: $${projectRuntimeApi.tokenEnvironmentVariableName}" \\
|
|
5114
|
+
-d '{"action":"start","agentPermanentId":"${projectRuntimeApi.agentPermanentId}","projectName":"<project-name>"}'
|
|
5115
|
+
|
|
5116
|
+
curl -sS -X POST "$${projectRuntimeApi.serverUrlEnvironmentVariableName}/api/internal/agent-project-runtimes" \\
|
|
5117
|
+
-H "Content-Type: application/json" \\
|
|
5118
|
+
-H "x-user-chat-worker-token: $${projectRuntimeApi.tokenEnvironmentVariableName}" \\
|
|
5119
|
+
-d '{"action":"assign_port","agentPermanentId":"${projectRuntimeApi.agentPermanentId}","projectName":"<project-name>"}'
|
|
5120
|
+
\`\`\`
|
|
5121
|
+
`);
|
|
5122
|
+
}
|
|
5123
|
+
|
|
4540
5124
|
/**
|
|
4541
5125
|
* Builds the prompt sent to the selected coding runner for one queued user-thread book.
|
|
4542
5126
|
*/
|
|
4543
|
-
function buildAgentMessagePrompt(messageRelativePath, agentSystemMessage) {
|
|
5127
|
+
function buildAgentMessagePrompt(messageRelativePath, agentSystemMessage, options = {}) {
|
|
4544
5128
|
return spaceTrim$1((block) => `
|
|
4545
5129
|
# Answer 1 user question
|
|
4546
5130
|
|
|
4547
5131
|
- Read \`${messageRelativePath}\` and answer the most recent \`MESSAGE @User\`
|
|
4548
5132
|
- Only change the queued message file by appending one new \`MESSAGE @Agent\` block
|
|
4549
|
-
- Do not modify any other file in the repository
|
|
5133
|
+
- Do not modify any other file in the repository, except files inside your own \`${AGENT_PROJECTS_DIRECTORY_PATH}/\` directory
|
|
4550
5134
|
|
|
4551
5135
|
## Rules for the answering
|
|
4552
5136
|
|
|
@@ -4582,34 +5166,46 @@ function buildAgentMessagePrompt(messageRelativePath, agentSystemMessage) {
|
|
|
4582
5166
|
|
|
4583
5167
|
- 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.
|
|
4584
5168
|
|
|
5169
|
+
${block(buildAgentProjectsPromptSection(options))}
|
|
5170
|
+
|
|
4585
5171
|
## This is how you should behave
|
|
4586
5172
|
|
|
4587
5173
|
${block(agentSystemMessage)}
|
|
4588
5174
|
`);
|
|
4589
5175
|
}
|
|
4590
5176
|
|
|
4591
|
-
/**
|
|
4592
|
-
* Builds a normalized temporary shell script path for prompt runners.
|
|
4593
|
-
*/
|
|
4594
|
-
function buildTemporaryPromptScriptPath(options) {
|
|
4595
|
-
const sourceFileName = basename(options.sourceFileName);
|
|
4596
|
-
const scriptFileName = `${sourceFileName.replace(/\.[^.]+$/u, '')}${options.suffix || ''}.sh`;
|
|
4597
|
-
return resolvePromptbookTemporaryPath(options.projectPath, options.scriptDirectoryName, scriptFileName);
|
|
4598
|
-
}
|
|
4599
|
-
|
|
4600
5177
|
/**
|
|
4601
5178
|
* Temporary subdirectory used for agent-message runner shell scripts.
|
|
5179
|
+
*
|
|
5180
|
+
* @private internal constant of agent-message runtime paths
|
|
4602
5181
|
*/
|
|
4603
5182
|
const AGENT_MESSAGE_SCRIPT_DIRECTORY_NAME = 'agent-messages';
|
|
5183
|
+
/**
|
|
5184
|
+
* File extension used for temporary prompt-runner shell scripts.
|
|
5185
|
+
*
|
|
5186
|
+
* @private internal constant of agent-message runtime paths
|
|
5187
|
+
*/
|
|
5188
|
+
const AGENT_MESSAGE_SCRIPT_EXTENSION = '.sh';
|
|
5189
|
+
/**
|
|
5190
|
+
* Builds the temporary shell script path used by one queued agent-message harness run.
|
|
5191
|
+
*
|
|
5192
|
+
* @param projectPath - Local agent project path containing the message queue.
|
|
5193
|
+
* @param sourceFileName - Queued message filename used to name the temporary shell script.
|
|
5194
|
+
* @returns Temporary shell script path.
|
|
5195
|
+
* @private internal utility of agent-message runners
|
|
5196
|
+
*/
|
|
5197
|
+
function buildAgentMessageScriptPathFromFileName(projectPath, sourceFileName) {
|
|
5198
|
+
const sourceFileBasename = basename(sourceFileName);
|
|
5199
|
+
const scriptFileName = `${sourceFileBasename.replace(/\.[^.]+$/u, '')}${AGENT_MESSAGE_SCRIPT_EXTENSION}`;
|
|
5200
|
+
return resolvePromptbookTemporaryPath(projectPath, AGENT_MESSAGE_SCRIPT_DIRECTORY_NAME, scriptFileName);
|
|
5201
|
+
}
|
|
5202
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
5203
|
+
|
|
4604
5204
|
/**
|
|
4605
5205
|
* Builds a temporary script path for one agent message runner invocation.
|
|
4606
5206
|
*/
|
|
4607
5207
|
function buildAgentMessageScriptPath(projectPath, messageFile) {
|
|
4608
|
-
return
|
|
4609
|
-
projectPath,
|
|
4610
|
-
scriptDirectoryName: AGENT_MESSAGE_SCRIPT_DIRECTORY_NAME,
|
|
4611
|
-
sourceFileName: messageFile.fileName,
|
|
4612
|
-
});
|
|
5208
|
+
return buildAgentMessageScriptPathFromFileName(projectPath, messageFile.fileName);
|
|
4613
5209
|
}
|
|
4614
5210
|
|
|
4615
5211
|
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"}];
|
|
@@ -5072,6 +5668,95 @@ function pipelineJsonToString(pipelineJson) {
|
|
|
5072
5668
|
// TODO: [🏛] Escape all
|
|
5073
5669
|
// TODO: [🧠] Should be in generated .book.md file GENERATOR_WARNING
|
|
5074
5670
|
|
|
5671
|
+
/**
|
|
5672
|
+
* This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
|
|
5673
|
+
*
|
|
5674
|
+
* @public exported from `@promptbook/core`
|
|
5675
|
+
*/
|
|
5676
|
+
class PipelineLogicError extends Error {
|
|
5677
|
+
constructor(message) {
|
|
5678
|
+
super(message);
|
|
5679
|
+
this.name = 'PipelineLogicError';
|
|
5680
|
+
Object.setPrototypeOf(this, PipelineLogicError.prototype);
|
|
5681
|
+
}
|
|
5682
|
+
}
|
|
5683
|
+
|
|
5684
|
+
/**
|
|
5685
|
+
* Creates the shared validation context for one pipeline.
|
|
5686
|
+
*
|
|
5687
|
+
* @private function of `validatePipeline`
|
|
5688
|
+
*/
|
|
5689
|
+
function createPipelineValidationContext(pipeline) {
|
|
5690
|
+
return {
|
|
5691
|
+
pipeline,
|
|
5692
|
+
pipelineIdentification: getPipelineIdentification$1(pipeline),
|
|
5693
|
+
};
|
|
5694
|
+
}
|
|
5695
|
+
/**
|
|
5696
|
+
* Builds a short file/url identification block for validation errors.
|
|
5697
|
+
*
|
|
5698
|
+
* @private internal utility of `validatePipeline`
|
|
5699
|
+
*/
|
|
5700
|
+
function getPipelineIdentification$1(pipeline) {
|
|
5701
|
+
// Note: This is a 😐 implementation of [🚞]
|
|
5702
|
+
const pipelineIdentificationParts = [];
|
|
5703
|
+
if (pipeline.sourceFile !== undefined) {
|
|
5704
|
+
pipelineIdentificationParts.push(`File: ${pipeline.sourceFile}`);
|
|
5705
|
+
}
|
|
5706
|
+
if (pipeline.pipelineUrl !== undefined) {
|
|
5707
|
+
pipelineIdentificationParts.push(`Url: ${pipeline.pipelineUrl}`);
|
|
5708
|
+
}
|
|
5709
|
+
return pipelineIdentificationParts.join('\n');
|
|
5710
|
+
}
|
|
5711
|
+
|
|
5712
|
+
/**
|
|
5713
|
+
* Validates that the expected top-level collections have array structure.
|
|
5714
|
+
*
|
|
5715
|
+
* @private function of `validatePipeline`
|
|
5716
|
+
*/
|
|
5717
|
+
function validatePipelineCollectionsStructure({ pipeline, pipelineIdentification, }) {
|
|
5718
|
+
validatePipelineParametersCollection(pipeline, pipelineIdentification);
|
|
5719
|
+
validatePipelineTasksCollection(pipeline, pipelineIdentification);
|
|
5720
|
+
}
|
|
5721
|
+
/**
|
|
5722
|
+
* Validates that `pipeline.parameters` is an array.
|
|
5723
|
+
*
|
|
5724
|
+
* @private internal utility of `validatePipelineCollectionsStructure`
|
|
5725
|
+
*/
|
|
5726
|
+
function validatePipelineParametersCollection(pipeline, pipelineIdentification) {
|
|
5727
|
+
// TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
|
|
5728
|
+
if (Array.isArray(pipeline.parameters)) {
|
|
5729
|
+
return;
|
|
5730
|
+
}
|
|
5731
|
+
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5732
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
5733
|
+
Pipeline is valid JSON but with wrong structure
|
|
5734
|
+
|
|
5735
|
+
\`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
|
|
5736
|
+
|
|
5737
|
+
${block(pipelineIdentification)}
|
|
5738
|
+
`));
|
|
5739
|
+
}
|
|
5740
|
+
/**
|
|
5741
|
+
* Validates that `pipeline.tasks` is an array.
|
|
5742
|
+
*
|
|
5743
|
+
* @private internal utility of `validatePipelineCollectionsStructure`
|
|
5744
|
+
*/
|
|
5745
|
+
function validatePipelineTasksCollection(pipeline, pipelineIdentification) {
|
|
5746
|
+
// TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
|
|
5747
|
+
if (Array.isArray(pipeline.tasks)) {
|
|
5748
|
+
return;
|
|
5749
|
+
}
|
|
5750
|
+
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5751
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
5752
|
+
Pipeline is valid JSON but with wrong structure
|
|
5753
|
+
|
|
5754
|
+
\`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
|
|
5755
|
+
|
|
5756
|
+
${block(pipelineIdentification)}
|
|
5757
|
+
`));
|
|
5758
|
+
}
|
|
5759
|
+
|
|
5075
5760
|
/**
|
|
5076
5761
|
* Order of keys in the pipeline JSON
|
|
5077
5762
|
*
|
|
@@ -5184,17 +5869,138 @@ const LIMITS = {
|
|
|
5184
5869
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
5185
5870
|
|
|
5186
5871
|
/**
|
|
5187
|
-
*
|
|
5872
|
+
* Validates that task dependencies can be resolved without cycles or missing definitions.
|
|
5188
5873
|
*
|
|
5189
|
-
* @
|
|
5874
|
+
* @private function of `validatePipeline`
|
|
5190
5875
|
*/
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5876
|
+
function validatePipelineDependencyResolution({ pipeline, pipelineIdentification, }) {
|
|
5877
|
+
let dependencyResolutionState = createInitialDependencyResolutionState(pipeline);
|
|
5878
|
+
let loopLimit = LOOP_LIMIT;
|
|
5879
|
+
while (hasUnresolvedTasks(dependencyResolutionState)) {
|
|
5880
|
+
if (loopLimit-- < 0) {
|
|
5881
|
+
throw createDependencyResolutionLoopLimitError(pipelineIdentification);
|
|
5882
|
+
}
|
|
5883
|
+
dependencyResolutionState = resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification);
|
|
5196
5884
|
}
|
|
5197
5885
|
}
|
|
5886
|
+
/**
|
|
5887
|
+
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
5888
|
+
*
|
|
5889
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5890
|
+
*/
|
|
5891
|
+
function createInitialDependencyResolutionState(pipeline) {
|
|
5892
|
+
return {
|
|
5893
|
+
resolvedParameterNames: createInitiallyResolvedParameterNames(pipeline),
|
|
5894
|
+
unresolvedTasks: [...pipeline.tasks],
|
|
5895
|
+
};
|
|
5896
|
+
}
|
|
5897
|
+
/**
|
|
5898
|
+
* Checks whether dependency resolution still has tasks left to process.
|
|
5899
|
+
*
|
|
5900
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5901
|
+
*/
|
|
5902
|
+
function hasUnresolvedTasks({ unresolvedTasks }) {
|
|
5903
|
+
return unresolvedTasks.length > 0;
|
|
5904
|
+
}
|
|
5905
|
+
/**
|
|
5906
|
+
* Resolves the next batch of currently satisfiable tasks.
|
|
5907
|
+
*
|
|
5908
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5909
|
+
*/
|
|
5910
|
+
function resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification) {
|
|
5911
|
+
const currentlyResolvedTasks = getCurrentlyResolvedTasks(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames);
|
|
5912
|
+
if (currentlyResolvedTasks.length === 0) {
|
|
5913
|
+
throw createUnresolvedTasksError(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames, pipelineIdentification);
|
|
5914
|
+
}
|
|
5915
|
+
return {
|
|
5916
|
+
resolvedParameterNames: appendResolvedTaskParameterNames(dependencyResolutionState.resolvedParameterNames, currentlyResolvedTasks),
|
|
5917
|
+
unresolvedTasks: dependencyResolutionState.unresolvedTasks.filter((task) => !currentlyResolvedTasks.includes(task)),
|
|
5918
|
+
};
|
|
5919
|
+
}
|
|
5920
|
+
/**
|
|
5921
|
+
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
5922
|
+
*
|
|
5923
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5924
|
+
*/
|
|
5925
|
+
function createInitiallyResolvedParameterNames(pipeline) {
|
|
5926
|
+
let resolvedParameterNames = pipeline.parameters
|
|
5927
|
+
.filter(({ isInput }) => isInput)
|
|
5928
|
+
.map(({ name }) => name);
|
|
5929
|
+
for (const reservedParameterName of RESERVED_PARAMETER_NAMES) {
|
|
5930
|
+
resolvedParameterNames = [...resolvedParameterNames, reservedParameterName];
|
|
5931
|
+
}
|
|
5932
|
+
return resolvedParameterNames;
|
|
5933
|
+
}
|
|
5934
|
+
/**
|
|
5935
|
+
* Adds newly resolved task outputs to the resolved parameter list.
|
|
5936
|
+
*
|
|
5937
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5938
|
+
*/
|
|
5939
|
+
function appendResolvedTaskParameterNames(resolvedParameterNames, currentlyResolvedTasks) {
|
|
5940
|
+
return [
|
|
5941
|
+
...resolvedParameterNames,
|
|
5942
|
+
...currentlyResolvedTasks.map(({ resultingParameterName }) => resultingParameterName),
|
|
5943
|
+
];
|
|
5944
|
+
}
|
|
5945
|
+
/**
|
|
5946
|
+
* Selects tasks whose dependencies are already resolved.
|
|
5947
|
+
*
|
|
5948
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5949
|
+
*/
|
|
5950
|
+
function getCurrentlyResolvedTasks(unresolvedTasks, resolvedParameterNames) {
|
|
5951
|
+
return unresolvedTasks.filter((task) => task.dependentParameterNames.every((name) => resolvedParameterNames.includes(name)));
|
|
5952
|
+
}
|
|
5953
|
+
/**
|
|
5954
|
+
* Creates the unexpected loop-limit error for dependency resolution.
|
|
5955
|
+
*
|
|
5956
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5957
|
+
*/
|
|
5958
|
+
function createDependencyResolutionLoopLimitError(pipelineIdentification) {
|
|
5959
|
+
// Note: Really UnexpectedError not LimitReachedError - this should not happen and be caught below
|
|
5960
|
+
return new UnexpectedError(spaceTrim$1((block) => `
|
|
5961
|
+
Loop limit reached during detection of circular dependencies in \`validatePipeline\`
|
|
5962
|
+
|
|
5963
|
+
${block(pipelineIdentification)}
|
|
5964
|
+
`));
|
|
5965
|
+
}
|
|
5966
|
+
/**
|
|
5967
|
+
* Creates the detailed error for unresolved or circular task dependencies.
|
|
5968
|
+
*
|
|
5969
|
+
* @private internal utility of `validatePipelineDependencyResolution`
|
|
5970
|
+
*/
|
|
5971
|
+
function createUnresolvedTasksError(unresolvedTasks, resolvedParameterNames, pipelineIdentification) {
|
|
5972
|
+
return new PipelineLogicError(
|
|
5973
|
+
// TODO: [🐎] DRY
|
|
5974
|
+
spaceTrim$1((block) => `
|
|
5975
|
+
|
|
5976
|
+
Can not resolve some parameters:
|
|
5977
|
+
Either you are using a parameter that is not defined, or there are some circular dependencies.
|
|
5978
|
+
|
|
5979
|
+
${block(pipelineIdentification)}
|
|
5980
|
+
|
|
5981
|
+
**Can not resolve:**
|
|
5982
|
+
${block(unresolvedTasks
|
|
5983
|
+
.map(({ resultingParameterName, dependentParameterNames }) => `- Parameter \`{${resultingParameterName}}\` which depends on ${dependentParameterNames
|
|
5984
|
+
.map((dependentParameterName) => `\`{${dependentParameterName}}\``)
|
|
5985
|
+
.join(' and ')}`)
|
|
5986
|
+
.join('\n'))}
|
|
5987
|
+
|
|
5988
|
+
**Resolved:**
|
|
5989
|
+
${block(resolvedParameterNames
|
|
5990
|
+
.filter((name) => !RESERVED_PARAMETER_NAMES.includes(name))
|
|
5991
|
+
.map((name) => `- Parameter \`{${name}}\``)
|
|
5992
|
+
.join('\n'))}
|
|
5993
|
+
|
|
5994
|
+
|
|
5995
|
+
**Reserved (which are available):**
|
|
5996
|
+
${block(resolvedParameterNames
|
|
5997
|
+
.filter((name) => RESERVED_PARAMETER_NAMES.includes(name))
|
|
5998
|
+
.map((name) => `- Parameter \`{${name}}\``)
|
|
5999
|
+
.join('\n'))}
|
|
6000
|
+
|
|
6001
|
+
|
|
6002
|
+
`));
|
|
6003
|
+
}
|
|
5198
6004
|
|
|
5199
6005
|
/**
|
|
5200
6006
|
* Tests if given string is valid semantic version
|
|
@@ -5270,168 +6076,19 @@ function isValidPipelineUrl(url) {
|
|
|
5270
6076
|
}
|
|
5271
6077
|
// TODO: [🐠] Maybe more info why the URL is invalid
|
|
5272
6078
|
|
|
5273
|
-
/**
|
|
5274
|
-
* Validates PipelineJson if it is logically valid
|
|
5275
|
-
*
|
|
5276
|
-
* It checks:
|
|
5277
|
-
* - if it has correct parameters dependency
|
|
5278
|
-
*
|
|
5279
|
-
* It does NOT check:
|
|
5280
|
-
* - if it is valid json
|
|
5281
|
-
* - if it is meaningful
|
|
5282
|
-
*
|
|
5283
|
-
* Note: [🔂] This function is idempotent.
|
|
5284
|
-
*
|
|
5285
|
-
* @param pipeline valid or invalid PipelineJson
|
|
5286
|
-
* @returns the same pipeline if it is logically valid
|
|
5287
|
-
* @throws {PipelineLogicError} on logical error in the pipeline
|
|
5288
|
-
*
|
|
5289
|
-
* @public exported from `@promptbook/core`
|
|
5290
|
-
*/
|
|
5291
|
-
function validatePipeline(pipeline) {
|
|
5292
|
-
if (IS_PIPELINE_LOGIC_VALIDATED) {
|
|
5293
|
-
validatePipeline_InnerFunction(pipeline);
|
|
5294
|
-
}
|
|
5295
|
-
else {
|
|
5296
|
-
try {
|
|
5297
|
-
validatePipeline_InnerFunction(pipeline);
|
|
5298
|
-
}
|
|
5299
|
-
catch (error) {
|
|
5300
|
-
if (!(error instanceof PipelineLogicError)) {
|
|
5301
|
-
throw error;
|
|
5302
|
-
}
|
|
5303
|
-
console.error(spaceTrim$1((block) => `
|
|
5304
|
-
Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
|
|
5305
|
-
|
|
5306
|
-
${block(error.message)}
|
|
5307
|
-
`));
|
|
5308
|
-
}
|
|
5309
|
-
}
|
|
5310
|
-
return pipeline;
|
|
5311
|
-
}
|
|
5312
|
-
/**
|
|
5313
|
-
* Validates pipeline inner function.
|
|
5314
|
-
*
|
|
5315
|
-
* @private internal function for `validatePipeline`
|
|
5316
|
-
*/
|
|
5317
|
-
function validatePipeline_InnerFunction(pipeline) {
|
|
5318
|
-
// TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
|
|
5319
|
-
const context = createPipelineValidationContext(pipeline);
|
|
5320
|
-
validatePipelineMetadata(context);
|
|
5321
|
-
validatePipelineCollectionsStructure(context);
|
|
5322
|
-
validatePipelineParameters(context);
|
|
5323
|
-
validatePipelineTasks(context);
|
|
5324
|
-
validatePipelineDependencyResolution(context);
|
|
5325
|
-
// Note: Check that formfactor is corresponding to the pipeline interface
|
|
5326
|
-
// TODO: !!6 Implement this
|
|
5327
|
-
// pipeline.formfactorName
|
|
5328
|
-
}
|
|
5329
|
-
/**
|
|
5330
|
-
* Creates the shared validation context for one pipeline.
|
|
5331
|
-
*
|
|
5332
|
-
* @private internal utility of `validatePipeline`
|
|
5333
|
-
*/
|
|
5334
|
-
function createPipelineValidationContext(pipeline) {
|
|
5335
|
-
return {
|
|
5336
|
-
pipeline,
|
|
5337
|
-
pipelineIdentification: getPipelineIdentification$1(pipeline),
|
|
5338
|
-
};
|
|
5339
|
-
}
|
|
5340
|
-
/**
|
|
5341
|
-
* Builds a short file/url identification block for validation errors.
|
|
5342
|
-
*
|
|
5343
|
-
* @private internal utility of `validatePipeline`
|
|
5344
|
-
*/
|
|
5345
|
-
function getPipelineIdentification$1(pipeline) {
|
|
5346
|
-
// Note: This is a 😐 implementation of [🚞]
|
|
5347
|
-
const pipelineIdentificationParts = [];
|
|
5348
|
-
if (pipeline.sourceFile !== undefined) {
|
|
5349
|
-
pipelineIdentificationParts.push(`File: ${pipeline.sourceFile}`);
|
|
5350
|
-
}
|
|
5351
|
-
if (pipeline.pipelineUrl !== undefined) {
|
|
5352
|
-
pipelineIdentificationParts.push(`Url: ${pipeline.pipelineUrl}`);
|
|
5353
|
-
}
|
|
5354
|
-
return pipelineIdentificationParts.join('\n');
|
|
5355
|
-
}
|
|
5356
6079
|
/**
|
|
5357
6080
|
* Validates pipeline-level metadata fields.
|
|
5358
6081
|
*
|
|
5359
|
-
* @private
|
|
6082
|
+
* @private function of `validatePipeline`
|
|
5360
6083
|
*/
|
|
5361
6084
|
function validatePipelineMetadata({ pipeline, pipelineIdentification }) {
|
|
5362
6085
|
validatePipelineUrl(pipeline, pipelineIdentification);
|
|
5363
6086
|
validatePipelineBookVersion(pipeline, pipelineIdentification);
|
|
5364
6087
|
}
|
|
5365
|
-
/**
|
|
5366
|
-
* Validates that the expected top-level collections have array structure.
|
|
5367
|
-
*
|
|
5368
|
-
* @private internal step of `validatePipeline`
|
|
5369
|
-
*/
|
|
5370
|
-
function validatePipelineCollectionsStructure({ pipeline, pipelineIdentification }) {
|
|
5371
|
-
validatePipelineParametersCollection(pipeline, pipelineIdentification);
|
|
5372
|
-
validatePipelineTasksCollection(pipeline, pipelineIdentification);
|
|
5373
|
-
}
|
|
5374
|
-
/**
|
|
5375
|
-
* Validates all pipeline parameter declarations.
|
|
5376
|
-
*
|
|
5377
|
-
* @private internal step of `validatePipeline`
|
|
5378
|
-
*/
|
|
5379
|
-
function validatePipelineParameters({ pipeline, pipelineIdentification }) {
|
|
5380
|
-
for (const parameter of pipeline.parameters) {
|
|
5381
|
-
validatePipelineParameter(parameter, pipeline, pipelineIdentification);
|
|
5382
|
-
}
|
|
5383
|
-
}
|
|
5384
|
-
/**
|
|
5385
|
-
* Validates all pipeline tasks and their per-task invariants.
|
|
5386
|
-
*
|
|
5387
|
-
* @private internal step of `validatePipeline`
|
|
5388
|
-
*/
|
|
5389
|
-
function validatePipelineTasks({ pipeline, pipelineIdentification }) {
|
|
5390
|
-
// Note: All input parameters are defined - so that they can be used as result of some task
|
|
5391
|
-
const definedParameters = createInitiallyDefinedParameters(pipeline);
|
|
5392
|
-
for (const task of pipeline.tasks) {
|
|
5393
|
-
validatePipelineTask(task, definedParameters, pipelineIdentification);
|
|
5394
|
-
}
|
|
5395
|
-
}
|
|
5396
|
-
/**
|
|
5397
|
-
* Validates that task dependencies can be resolved without cycles or missing definitions.
|
|
5398
|
-
*
|
|
5399
|
-
* @private internal step of `validatePipeline`
|
|
5400
|
-
*/
|
|
5401
|
-
function validatePipelineDependencyResolution({ pipeline, pipelineIdentification }) {
|
|
5402
|
-
let dependencyResolutionState = createInitialDependencyResolutionState(pipeline);
|
|
5403
|
-
let loopLimit = LOOP_LIMIT;
|
|
5404
|
-
while (hasUnresolvedTasks(dependencyResolutionState)) {
|
|
5405
|
-
if (loopLimit-- < 0) {
|
|
5406
|
-
throw createDependencyResolutionLoopLimitError(pipelineIdentification);
|
|
5407
|
-
}
|
|
5408
|
-
dependencyResolutionState = resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification);
|
|
5409
|
-
}
|
|
5410
|
-
}
|
|
5411
|
-
/**
|
|
5412
|
-
* Validates one pipeline parameter declaration.
|
|
5413
|
-
*
|
|
5414
|
-
* @private internal step of `validatePipeline`
|
|
5415
|
-
*/
|
|
5416
|
-
function validatePipelineParameter(parameter, pipeline, pipelineIdentification) {
|
|
5417
|
-
validateParameterDirection(parameter, pipelineIdentification);
|
|
5418
|
-
validateParameterUsage(parameter, pipeline, pipelineIdentification);
|
|
5419
|
-
validateParameterDefinition(parameter, pipeline, pipelineIdentification);
|
|
5420
|
-
}
|
|
5421
|
-
/**
|
|
5422
|
-
* Validates one pipeline task and its invariants.
|
|
5423
|
-
*
|
|
5424
|
-
* @private internal step of `validatePipeline`
|
|
5425
|
-
*/
|
|
5426
|
-
function validatePipelineTask(task, definedParameters, pipelineIdentification) {
|
|
5427
|
-
validateTaskResultingParameter(task, definedParameters, pipelineIdentification);
|
|
5428
|
-
validateTaskJokers(task, pipelineIdentification);
|
|
5429
|
-
validateTaskExpectations(task, pipelineIdentification);
|
|
5430
|
-
}
|
|
5431
6088
|
/**
|
|
5432
6089
|
* Validates the pipeline URL, when present.
|
|
5433
6090
|
*
|
|
5434
|
-
* @private internal utility of `
|
|
6091
|
+
* @private internal utility of `validatePipelineMetadata`
|
|
5435
6092
|
*/
|
|
5436
6093
|
function validatePipelineUrl(pipeline, pipelineIdentification) {
|
|
5437
6094
|
if (pipeline.pipelineUrl === undefined || isValidPipelineUrl(pipeline.pipelineUrl)) {
|
|
@@ -5447,7 +6104,7 @@ function validatePipelineUrl(pipeline, pipelineIdentification) {
|
|
|
5447
6104
|
/**
|
|
5448
6105
|
* Validates the Promptbook version, when present.
|
|
5449
6106
|
*
|
|
5450
|
-
* @private internal utility of `
|
|
6107
|
+
* @private internal utility of `validatePipelineMetadata`
|
|
5451
6108
|
*/
|
|
5452
6109
|
function validatePipelineBookVersion(pipeline, pipelineIdentification) {
|
|
5453
6110
|
if (pipeline.bookVersion === undefined || isValidPromptbookVersion(pipeline.bookVersion)) {
|
|
@@ -5460,48 +6117,31 @@ function validatePipelineBookVersion(pipeline, pipelineIdentification) {
|
|
|
5460
6117
|
${block(pipelineIdentification)}
|
|
5461
6118
|
`));
|
|
5462
6119
|
}
|
|
6120
|
+
|
|
5463
6121
|
/**
|
|
5464
|
-
* Validates
|
|
6122
|
+
* Validates all pipeline parameter declarations.
|
|
5465
6123
|
*
|
|
5466
|
-
* @private
|
|
6124
|
+
* @private function of `validatePipeline`
|
|
5467
6125
|
*/
|
|
5468
|
-
function
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
return;
|
|
6126
|
+
function validatePipelineParameters({ pipeline, pipelineIdentification }) {
|
|
6127
|
+
for (const parameter of pipeline.parameters) {
|
|
6128
|
+
validatePipelineParameter(parameter, pipeline, pipelineIdentification);
|
|
5472
6129
|
}
|
|
5473
|
-
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5474
|
-
throw new ParseError(spaceTrim$1((block) => `
|
|
5475
|
-
Pipeline is valid JSON but with wrong structure
|
|
5476
|
-
|
|
5477
|
-
\`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
|
|
5478
|
-
|
|
5479
|
-
${block(pipelineIdentification)}
|
|
5480
|
-
`));
|
|
5481
6130
|
}
|
|
5482
6131
|
/**
|
|
5483
|
-
* Validates
|
|
6132
|
+
* Validates one pipeline parameter declaration.
|
|
5484
6133
|
*
|
|
5485
|
-
* @private internal utility of `
|
|
6134
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5486
6135
|
*/
|
|
5487
|
-
function
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
}
|
|
5492
|
-
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
5493
|
-
throw new ParseError(spaceTrim$1((block) => `
|
|
5494
|
-
Pipeline is valid JSON but with wrong structure
|
|
5495
|
-
|
|
5496
|
-
\`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
|
|
5497
|
-
|
|
5498
|
-
${block(pipelineIdentification)}
|
|
5499
|
-
`));
|
|
6136
|
+
function validatePipelineParameter(parameter, pipeline, pipelineIdentification) {
|
|
6137
|
+
validateParameterDirection(parameter, pipelineIdentification);
|
|
6138
|
+
validateParameterUsage(parameter, pipeline, pipelineIdentification);
|
|
6139
|
+
validateParameterDefinition(parameter, pipeline, pipelineIdentification);
|
|
5500
6140
|
}
|
|
5501
6141
|
/**
|
|
5502
6142
|
* Validates that one parameter does not declare incompatible directions.
|
|
5503
6143
|
*
|
|
5504
|
-
* @private internal utility of `
|
|
6144
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5505
6145
|
*/
|
|
5506
6146
|
function validateParameterDirection(parameter, pipelineIdentification) {
|
|
5507
6147
|
if (!parameter.isInput || !parameter.isOutput) {
|
|
@@ -5518,7 +6158,7 @@ function validateParameterDirection(parameter, pipelineIdentification) {
|
|
|
5518
6158
|
/**
|
|
5519
6159
|
* Validates that one intermediate parameter is actually consumed by at least one task.
|
|
5520
6160
|
*
|
|
5521
|
-
* @private internal utility of `
|
|
6161
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5522
6162
|
*/
|
|
5523
6163
|
function validateParameterUsage(parameter, pipeline, pipelineIdentification) {
|
|
5524
6164
|
if (parameter.isInput || parameter.isOutput || isParameterUsedByAnyTask(parameter, pipeline.tasks)) {
|
|
@@ -5537,7 +6177,7 @@ function validateParameterUsage(parameter, pipeline, pipelineIdentification) {
|
|
|
5537
6177
|
/**
|
|
5538
6178
|
* Validates that one non-input parameter is produced by at least one task.
|
|
5539
6179
|
*
|
|
5540
|
-
* @private internal utility of `
|
|
6180
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5541
6181
|
*/
|
|
5542
6182
|
function validateParameterDefinition(parameter, pipeline, pipelineIdentification) {
|
|
5543
6183
|
if (parameter.isInput || isParameterDefinedByAnyTask(parameter, pipeline.tasks)) {
|
|
@@ -5556,7 +6196,7 @@ function validateParameterDefinition(parameter, pipeline, pipelineIdentification
|
|
|
5556
6196
|
/**
|
|
5557
6197
|
* Checks whether one parameter is consumed by at least one task dependency list.
|
|
5558
6198
|
*
|
|
5559
|
-
* @private internal utility of `
|
|
6199
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5560
6200
|
*/
|
|
5561
6201
|
function isParameterUsedByAnyTask(parameter, tasks) {
|
|
5562
6202
|
return tasks.some((task) => task.dependentParameterNames.includes(parameter.name));
|
|
@@ -5564,23 +6204,46 @@ function isParameterUsedByAnyTask(parameter, tasks) {
|
|
|
5564
6204
|
/**
|
|
5565
6205
|
* Checks whether one parameter is produced by at least one task.
|
|
5566
6206
|
*
|
|
5567
|
-
* @private internal utility of `
|
|
6207
|
+
* @private internal utility of `validatePipelineParameters`
|
|
5568
6208
|
*/
|
|
5569
6209
|
function isParameterDefinedByAnyTask(parameter, tasks) {
|
|
5570
6210
|
return tasks.some((task) => task.resultingParameterName === parameter.name);
|
|
5571
6211
|
}
|
|
6212
|
+
|
|
6213
|
+
/**
|
|
6214
|
+
* Validates all pipeline tasks and their per-task invariants.
|
|
6215
|
+
*
|
|
6216
|
+
* @private function of `validatePipeline`
|
|
6217
|
+
*/
|
|
6218
|
+
function validatePipelineTasks({ pipeline, pipelineIdentification }) {
|
|
6219
|
+
// Note: All input parameters are defined - so that they can be used as result of some task
|
|
6220
|
+
const definedParameters = createInitiallyDefinedParameters(pipeline);
|
|
6221
|
+
for (const task of pipeline.tasks) {
|
|
6222
|
+
validatePipelineTask(task, definedParameters, pipelineIdentification);
|
|
6223
|
+
}
|
|
6224
|
+
}
|
|
5572
6225
|
/**
|
|
5573
6226
|
* Collects the parameter names that are already defined before task validation starts.
|
|
5574
6227
|
*
|
|
5575
|
-
* @private internal utility of `
|
|
6228
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5576
6229
|
*/
|
|
5577
6230
|
function createInitiallyDefinedParameters(pipeline) {
|
|
5578
6231
|
return new Set(pipeline.parameters.filter(({ isInput }) => isInput).map(({ name }) => name));
|
|
5579
6232
|
}
|
|
6233
|
+
/**
|
|
6234
|
+
* Validates one pipeline task and its invariants.
|
|
6235
|
+
*
|
|
6236
|
+
* @private internal utility of `validatePipelineTasks`
|
|
6237
|
+
*/
|
|
6238
|
+
function validatePipelineTask(task, definedParameters, pipelineIdentification) {
|
|
6239
|
+
validateTaskResultingParameter(task, definedParameters, pipelineIdentification);
|
|
6240
|
+
validateTaskJokers(task, pipelineIdentification);
|
|
6241
|
+
validateTaskExpectations(task, pipelineIdentification);
|
|
6242
|
+
}
|
|
5580
6243
|
/**
|
|
5581
6244
|
* Validates one task result parameter declaration and marks it as defined.
|
|
5582
6245
|
*
|
|
5583
|
-
* @private internal utility of `
|
|
6246
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5584
6247
|
*/
|
|
5585
6248
|
function validateTaskResultingParameter(task, definedParameters, pipelineIdentification) {
|
|
5586
6249
|
if (definedParameters.has(task.resultingParameterName)) {
|
|
@@ -5602,7 +6265,7 @@ function validateTaskResultingParameter(task, definedParameters, pipelineIdentif
|
|
|
5602
6265
|
/**
|
|
5603
6266
|
* Validates joker parameters for one task.
|
|
5604
6267
|
*
|
|
5605
|
-
* @private internal utility of `
|
|
6268
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5606
6269
|
*/
|
|
5607
6270
|
function validateTaskJokers(task, pipelineIdentification) {
|
|
5608
6271
|
if (!hasTaskJokers(task)) {
|
|
@@ -5614,7 +6277,7 @@ function validateTaskJokers(task, pipelineIdentification) {
|
|
|
5614
6277
|
/**
|
|
5615
6278
|
* Checks whether one task declares any joker parameters.
|
|
5616
6279
|
*
|
|
5617
|
-
* @private internal utility of `
|
|
6280
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5618
6281
|
*/
|
|
5619
6282
|
function hasTaskJokers(task) {
|
|
5620
6283
|
return !!task.jokerParameterNames && task.jokerParameterNames.length > 0;
|
|
@@ -5622,7 +6285,7 @@ function hasTaskJokers(task) {
|
|
|
5622
6285
|
/**
|
|
5623
6286
|
* Validates that a task has the required supporting features when using jokers.
|
|
5624
6287
|
*
|
|
5625
|
-
* @private internal utility of `
|
|
6288
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5626
6289
|
*/
|
|
5627
6290
|
function validateTaskSupportsJokers(task, pipelineIdentification) {
|
|
5628
6291
|
if (task.format || task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
|
|
@@ -5637,7 +6300,7 @@ function validateTaskSupportsJokers(task, pipelineIdentification) {
|
|
|
5637
6300
|
/**
|
|
5638
6301
|
* Validates that every joker parameter is also listed among task dependencies.
|
|
5639
6302
|
*
|
|
5640
|
-
* @private internal utility of `
|
|
6303
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5641
6304
|
*/
|
|
5642
6305
|
function validateTaskJokerDependencies(task, pipelineIdentification) {
|
|
5643
6306
|
for (const joker of task.jokerParameterNames) {
|
|
@@ -5654,7 +6317,7 @@ function validateTaskJokerDependencies(task, pipelineIdentification) {
|
|
|
5654
6317
|
/**
|
|
5655
6318
|
* Validates all expectation bounds configured on one task.
|
|
5656
6319
|
*
|
|
5657
|
-
* @private internal utility of `
|
|
6320
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5658
6321
|
*/
|
|
5659
6322
|
function validateTaskExpectations(task, pipelineIdentification) {
|
|
5660
6323
|
if (!task.expectations) {
|
|
@@ -5669,7 +6332,7 @@ function validateTaskExpectations(task, pipelineIdentification) {
|
|
|
5669
6332
|
/**
|
|
5670
6333
|
* Validates the minimum and maximum expectation ordering for one unit.
|
|
5671
6334
|
*
|
|
5672
|
-
* @private internal utility of `
|
|
6335
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5673
6336
|
*/
|
|
5674
6337
|
function validateTaskExpectationRange(unit, min, max, pipelineIdentification) {
|
|
5675
6338
|
if (min === undefined || max === undefined || min <= max) {
|
|
@@ -5684,7 +6347,7 @@ function validateTaskExpectationRange(unit, min, max, pipelineIdentification) {
|
|
|
5684
6347
|
/**
|
|
5685
6348
|
* Validates the minimum expectation bound for one unit.
|
|
5686
6349
|
*
|
|
5687
|
-
* @private internal utility of `
|
|
6350
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5688
6351
|
*/
|
|
5689
6352
|
function validateTaskExpectationMin(unit, min, pipelineIdentification) {
|
|
5690
6353
|
if (min === undefined || min >= 0) {
|
|
@@ -5699,7 +6362,7 @@ function validateTaskExpectationMin(unit, min, pipelineIdentification) {
|
|
|
5699
6362
|
/**
|
|
5700
6363
|
* Validates the maximum expectation bound for one unit.
|
|
5701
6364
|
*
|
|
5702
|
-
* @private internal utility of `
|
|
6365
|
+
* @private internal utility of `validatePipelineTasks`
|
|
5703
6366
|
*/
|
|
5704
6367
|
function validateTaskExpectationMax(unit, max, pipelineIdentification) {
|
|
5705
6368
|
if (max === undefined || max > 0) {
|
|
@@ -5711,123 +6374,62 @@ function validateTaskExpectationMax(unit, max, pipelineIdentification) {
|
|
|
5711
6374
|
${block(pipelineIdentification)}
|
|
5712
6375
|
`));
|
|
5713
6376
|
}
|
|
6377
|
+
|
|
5714
6378
|
/**
|
|
5715
|
-
*
|
|
5716
|
-
*
|
|
5717
|
-
* @private internal utility of `validatePipeline`
|
|
5718
|
-
*/
|
|
5719
|
-
function createInitialDependencyResolutionState(pipeline) {
|
|
5720
|
-
return {
|
|
5721
|
-
resolvedParameterNames: createInitiallyResolvedParameterNames(pipeline),
|
|
5722
|
-
unresolvedTasks: [...pipeline.tasks],
|
|
5723
|
-
};
|
|
5724
|
-
}
|
|
5725
|
-
/**
|
|
5726
|
-
* Checks whether dependency resolution still has tasks left to process.
|
|
5727
|
-
*
|
|
5728
|
-
* @private internal utility of `validatePipeline`
|
|
5729
|
-
*/
|
|
5730
|
-
function hasUnresolvedTasks({ unresolvedTasks }) {
|
|
5731
|
-
return unresolvedTasks.length > 0;
|
|
5732
|
-
}
|
|
5733
|
-
/**
|
|
5734
|
-
* Resolves the next batch of currently satisfiable tasks.
|
|
6379
|
+
* Validates PipelineJson if it is logically valid
|
|
5735
6380
|
*
|
|
5736
|
-
*
|
|
5737
|
-
|
|
5738
|
-
function resolveNextDependencyResolutionState(dependencyResolutionState, pipelineIdentification) {
|
|
5739
|
-
const currentlyResolvedTasks = getCurrentlyResolvedTasks(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames);
|
|
5740
|
-
if (currentlyResolvedTasks.length === 0) {
|
|
5741
|
-
throw createUnresolvedTasksError(dependencyResolutionState.unresolvedTasks, dependencyResolutionState.resolvedParameterNames, pipelineIdentification);
|
|
5742
|
-
}
|
|
5743
|
-
return {
|
|
5744
|
-
resolvedParameterNames: appendResolvedTaskParameterNames(dependencyResolutionState.resolvedParameterNames, currentlyResolvedTasks),
|
|
5745
|
-
unresolvedTasks: dependencyResolutionState.unresolvedTasks.filter((task) => !currentlyResolvedTasks.includes(task)),
|
|
5746
|
-
};
|
|
5747
|
-
}
|
|
5748
|
-
/**
|
|
5749
|
-
* Collects the parameter names that are already resolvable before dependency traversal starts.
|
|
6381
|
+
* It checks:
|
|
6382
|
+
* - if it has correct parameters dependency
|
|
5750
6383
|
*
|
|
5751
|
-
*
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
let resolvedParameterNames = pipeline.parameters
|
|
5755
|
-
.filter(({ isInput }) => isInput)
|
|
5756
|
-
.map(({ name }) => name);
|
|
5757
|
-
for (const reservedParameterName of RESERVED_PARAMETER_NAMES) {
|
|
5758
|
-
resolvedParameterNames = [...resolvedParameterNames, reservedParameterName];
|
|
5759
|
-
}
|
|
5760
|
-
return resolvedParameterNames;
|
|
5761
|
-
}
|
|
5762
|
-
/**
|
|
5763
|
-
* Adds newly resolved task outputs to the resolved parameter list.
|
|
6384
|
+
* It does NOT check:
|
|
6385
|
+
* - if it is valid json
|
|
6386
|
+
* - if it is meaningful
|
|
5764
6387
|
*
|
|
5765
|
-
*
|
|
5766
|
-
*/
|
|
5767
|
-
function appendResolvedTaskParameterNames(resolvedParameterNames, currentlyResolvedTasks) {
|
|
5768
|
-
return [
|
|
5769
|
-
...resolvedParameterNames,
|
|
5770
|
-
...currentlyResolvedTasks.map(({ resultingParameterName }) => resultingParameterName),
|
|
5771
|
-
];
|
|
5772
|
-
}
|
|
5773
|
-
/**
|
|
5774
|
-
* Selects tasks whose dependencies are already resolved.
|
|
6388
|
+
* Note: [🔂] This function is idempotent.
|
|
5775
6389
|
*
|
|
5776
|
-
* @
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
return unresolvedTasks.filter((task) => task.dependentParameterNames.every((name) => resolvedParameterNames.includes(name)));
|
|
5780
|
-
}
|
|
5781
|
-
/**
|
|
5782
|
-
* Creates the unexpected loop-limit error for dependency resolution.
|
|
6390
|
+
* @param pipeline valid or invalid PipelineJson
|
|
6391
|
+
* @returns the same pipeline if it is logically valid
|
|
6392
|
+
* @throws {PipelineLogicError} on logical error in the pipeline
|
|
5783
6393
|
*
|
|
5784
|
-
* @
|
|
6394
|
+
* @public exported from `@promptbook/core`
|
|
5785
6395
|
*/
|
|
5786
|
-
function
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
6396
|
+
function validatePipeline(pipeline) {
|
|
6397
|
+
if (IS_PIPELINE_LOGIC_VALIDATED) {
|
|
6398
|
+
validatePipeline_InnerFunction(pipeline);
|
|
6399
|
+
}
|
|
6400
|
+
else {
|
|
6401
|
+
try {
|
|
6402
|
+
validatePipeline_InnerFunction(pipeline);
|
|
6403
|
+
}
|
|
6404
|
+
catch (error) {
|
|
6405
|
+
if (!(error instanceof PipelineLogicError)) {
|
|
6406
|
+
throw error;
|
|
6407
|
+
}
|
|
6408
|
+
console.error(spaceTrim$1((block) => `
|
|
6409
|
+
Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
|
|
5790
6410
|
|
|
5791
|
-
|
|
5792
|
-
|
|
6411
|
+
${block(error.message)}
|
|
6412
|
+
`));
|
|
6413
|
+
}
|
|
6414
|
+
}
|
|
6415
|
+
return pipeline;
|
|
5793
6416
|
}
|
|
5794
6417
|
/**
|
|
5795
|
-
*
|
|
6418
|
+
* Validates pipeline inner function.
|
|
5796
6419
|
*
|
|
5797
|
-
* @private internal
|
|
6420
|
+
* @private internal function for `validatePipeline`
|
|
5798
6421
|
*/
|
|
5799
|
-
function
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
${block(unresolvedTasks
|
|
5811
|
-
.map(({ resultingParameterName, dependentParameterNames }) => `- Parameter \`{${resultingParameterName}}\` which depends on ${dependentParameterNames
|
|
5812
|
-
.map((dependentParameterName) => `\`{${dependentParameterName}}\``)
|
|
5813
|
-
.join(' and ')}`)
|
|
5814
|
-
.join('\n'))}
|
|
5815
|
-
|
|
5816
|
-
**Resolved:**
|
|
5817
|
-
${block(resolvedParameterNames
|
|
5818
|
-
.filter((name) => !RESERVED_PARAMETER_NAMES.includes(name))
|
|
5819
|
-
.map((name) => `- Parameter \`{${name}}\``)
|
|
5820
|
-
.join('\n'))}
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
**Reserved (which are available):**
|
|
5824
|
-
${block(resolvedParameterNames
|
|
5825
|
-
.filter((name) => RESERVED_PARAMETER_NAMES.includes(name))
|
|
5826
|
-
.map((name) => `- Parameter \`{${name}}\``)
|
|
5827
|
-
.join('\n'))}
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
`));
|
|
6422
|
+
function validatePipeline_InnerFunction(pipeline) {
|
|
6423
|
+
// TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
|
|
6424
|
+
const context = createPipelineValidationContext(pipeline);
|
|
6425
|
+
validatePipelineMetadata(context);
|
|
6426
|
+
validatePipelineCollectionsStructure(context);
|
|
6427
|
+
validatePipelineParameters(context);
|
|
6428
|
+
validatePipelineTasks(context);
|
|
6429
|
+
validatePipelineDependencyResolution(context);
|
|
6430
|
+
// Note: Check that formfactor is corresponding to the pipeline interface
|
|
6431
|
+
// TODO: !!6 Implement this
|
|
6432
|
+
// pipeline.formfactorName
|
|
5831
6433
|
}
|
|
5832
6434
|
/**
|
|
5833
6435
|
* TODO: [🧞♀️] Do not allow joker + foreach
|
|
@@ -14147,13 +14749,14 @@ class MessageSuffixCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
14147
14749
|
* META commitment definition
|
|
14148
14750
|
*
|
|
14149
14751
|
* The META commitment handles all meta-information about the agent such as:
|
|
14150
|
-
* - META AVATAR: Sets the agent's built-in default avatar visual
|
|
14752
|
+
* - META AVATAR / META VISUAL: Sets the agent's built-in default avatar visual
|
|
14151
14753
|
* - META IMAGE: Sets the agent's avatar/profile image URL
|
|
14152
14754
|
* - META LINK: Provides profile/source links for the person the agent models
|
|
14153
14755
|
* - META DOMAIN: Sets the canonical custom domain/host of the agent
|
|
14154
14756
|
* - META TITLE: Sets the agent's display title
|
|
14155
14757
|
* - META DESCRIPTION: Sets the agent's description
|
|
14156
14758
|
* - META INPUT PLACEHOLDER: Sets chat input placeholder text
|
|
14759
|
+
* - META THINKING MESSAGE: Adds custom thinking placeholder variants
|
|
14157
14760
|
* - META [ANYTHING]: Any other meta information in uppercase format
|
|
14158
14761
|
*
|
|
14159
14762
|
* These commitments are special because they don't affect the system message,
|
|
@@ -14162,13 +14765,14 @@ class MessageSuffixCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
14162
14765
|
* Example usage in agent source:
|
|
14163
14766
|
*
|
|
14164
14767
|
* ```book
|
|
14165
|
-
* META
|
|
14768
|
+
* META VISUAL pixel-art
|
|
14166
14769
|
* META IMAGE https://example.com/avatar.jpg
|
|
14167
14770
|
* META LINK https://twitter.com/username
|
|
14168
14771
|
* META DOMAIN my-agent.com
|
|
14169
14772
|
* META TITLE Professional Assistant
|
|
14170
14773
|
* META DESCRIPTION An AI assistant specialized in business tasks
|
|
14171
14774
|
* META INPUT PLACEHOLDER Write a message...
|
|
14775
|
+
* META THINKING MESSAGE Thinking...
|
|
14172
14776
|
* META AUTHOR John Doe
|
|
14173
14777
|
* META VERSION 1.0
|
|
14174
14778
|
* ```
|
|
@@ -14202,13 +14806,14 @@ class MetaCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
14202
14806
|
|
|
14203
14807
|
## Supported META types
|
|
14204
14808
|
|
|
14205
|
-
- **META AVATAR** - Sets the agent's built-in default avatar visual
|
|
14809
|
+
- **META AVATAR** / **META VISUAL** - Sets the agent's built-in default avatar visual
|
|
14206
14810
|
- **META IMAGE** - Sets the agent's avatar/profile image URL
|
|
14207
14811
|
- **META LINK** - Provides profile/source links for the person the agent models
|
|
14208
14812
|
- **META DOMAIN** - Sets the canonical custom domain/host of the agent
|
|
14209
14813
|
- **META TITLE** - Sets the agent's display title
|
|
14210
14814
|
- **META DESCRIPTION** - Sets the agent's description
|
|
14211
14815
|
- **META INPUT PLACEHOLDER** - Sets chat input placeholder text
|
|
14816
|
+
- **META THINKING MESSAGE** - Adds custom thinking placeholder variants
|
|
14212
14817
|
- **META [ANYTHING]** - Any other meta information in uppercase format
|
|
14213
14818
|
|
|
14214
14819
|
## Key aspects
|
|
@@ -14217,6 +14822,7 @@ class MetaCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
14217
14822
|
- Used for visual representation and attribution in user interfaces
|
|
14218
14823
|
- Multiple META commitments of different types can be used
|
|
14219
14824
|
- Multiple META LINK commitments can be used for different social profiles
|
|
14825
|
+
- Multiple META THINKING MESSAGE commitments can be used for different thinking placeholder variants
|
|
14220
14826
|
- If multiple META commitments of the same type are specified, the last one takes precedence (except for LINK)
|
|
14221
14827
|
|
|
14222
14828
|
## Examples
|
|
@@ -14226,7 +14832,7 @@ class MetaCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
14226
14832
|
\`\`\`book
|
|
14227
14833
|
Professional Assistant
|
|
14228
14834
|
|
|
14229
|
-
META
|
|
14835
|
+
META VISUAL octopus3
|
|
14230
14836
|
META IMAGE https://example.com/professional-avatar.jpg
|
|
14231
14837
|
META TITLE Senior Business Consultant
|
|
14232
14838
|
META DESCRIPTION Specialized in strategic planning and project management
|
|
@@ -17397,452 +18003,13 @@ function formatAlphaHex$1(opacity) {
|
|
|
17397
18003
|
.padStart(2, '0');
|
|
17398
18004
|
}
|
|
17399
18005
|
|
|
17400
|
-
/* eslint-disable no-magic-numbers */
|
|
17401
|
-
/**
|
|
17402
|
-
* Light direction used by the organic 3D octopus shading.
|
|
17403
|
-
*
|
|
17404
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17405
|
-
*/
|
|
17406
|
-
const LIGHT_DIRECTION$3 = normalizeVector3({
|
|
17407
|
-
x: 0.48,
|
|
17408
|
-
y: -0.62,
|
|
17409
|
-
z: 0.94,
|
|
17410
|
-
});
|
|
17411
|
-
/**
|
|
17412
|
-
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
17413
|
-
*
|
|
17414
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17415
|
-
*/
|
|
17416
|
-
const octopus3dStableStateCache = new WeakMap();
|
|
17417
|
-
/**
|
|
17418
|
-
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
17419
|
-
*
|
|
17420
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17421
|
-
*/
|
|
17422
|
-
function getOctopus3dStableState(createRandom) {
|
|
17423
|
-
const cached = octopus3dStableStateCache.get(createRandom);
|
|
17424
|
-
if (cached !== undefined) {
|
|
17425
|
-
return cached;
|
|
17426
|
-
}
|
|
17427
|
-
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
17428
|
-
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
17429
|
-
const leftEyePhaseOffset = eyeRandom() * 0.6;
|
|
17430
|
-
const rightEyePhaseOffset = eyeRandom() * 0.6;
|
|
17431
|
-
const state = {
|
|
17432
|
-
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
17433
|
-
animationPhase: animationRandom() * Math.PI * 2,
|
|
17434
|
-
leftEyePhaseOffset,
|
|
17435
|
-
rightEyePhaseOffset,
|
|
17436
|
-
};
|
|
17437
|
-
octopus3dStableStateCache.set(createRandom, state);
|
|
17438
|
-
return state;
|
|
17439
|
-
}
|
|
17440
|
-
/**
|
|
17441
|
-
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
17442
|
-
*
|
|
17443
|
-
* @private built-in avatar visual
|
|
17444
|
-
*/
|
|
17445
|
-
const octopus3dAvatarVisual = {
|
|
17446
|
-
id: 'octopus3d',
|
|
17447
|
-
title: 'Octopus 3D',
|
|
17448
|
-
description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
|
|
17449
|
-
isAnimated: true,
|
|
17450
|
-
supportsPointerTracking: true,
|
|
17451
|
-
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
17452
|
-
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
|
|
17453
|
-
const sceneCenterX = size * 0.5;
|
|
17454
|
-
const sceneCenterY = size * 0.56;
|
|
17455
|
-
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
17456
|
-
const mantleCenter = {
|
|
17457
|
-
x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
|
|
17458
|
-
y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
17459
|
-
z: interaction.intensity * size * 0.012,
|
|
17460
|
-
};
|
|
17461
|
-
const underbodyCenter = {
|
|
17462
|
-
x: mantleCenter.x * 0.86,
|
|
17463
|
-
y: mantleCenter.y + size * 0.168,
|
|
17464
|
-
z: mantleCenter.z - size * 0.018,
|
|
17465
|
-
};
|
|
17466
|
-
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
17467
|
-
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
17468
|
-
const mantleRadiusZ = size *
|
|
17469
|
-
morphologyProfile.body.bodyRadiusRatio *
|
|
17470
|
-
(0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
17471
|
-
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
17472
|
-
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
17473
|
-
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
17474
|
-
const bodyYaw = -0.18 +
|
|
17475
|
-
Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
|
|
17476
|
-
interaction.bodyOffsetX * 0.18 +
|
|
17477
|
-
interaction.gazeX * 0.22;
|
|
17478
|
-
const bodyPitch = -0.08 +
|
|
17479
|
-
Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
|
|
17480
|
-
interaction.bodyOffsetY * 0.08 -
|
|
17481
|
-
interaction.gazeY * 0.08;
|
|
17482
|
-
const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
|
|
17483
|
-
const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
|
|
17484
|
-
const mantlePatches = resolveVisibleEllipsoidPatches({
|
|
17485
|
-
center: mantleCenter,
|
|
17486
|
-
radiusX: mantleRadiusX,
|
|
17487
|
-
radiusY: mantleRadiusY,
|
|
17488
|
-
radiusZ: mantleRadiusZ,
|
|
17489
|
-
rotationX: headPitch,
|
|
17490
|
-
rotationY: headYaw,
|
|
17491
|
-
sceneCenterX,
|
|
17492
|
-
sceneCenterY,
|
|
17493
|
-
size,
|
|
17494
|
-
palette,
|
|
17495
|
-
verticalColorBias: 0,
|
|
17496
|
-
outlineColor: `${palette.highlight}7a`,
|
|
17497
|
-
});
|
|
17498
|
-
const underbodyPatches = resolveVisibleEllipsoidPatches({
|
|
17499
|
-
center: underbodyCenter,
|
|
17500
|
-
radiusX: underbodyRadiusX,
|
|
17501
|
-
radiusY: underbodyRadiusY,
|
|
17502
|
-
radiusZ: underbodyRadiusZ,
|
|
17503
|
-
rotationX: bodyPitch,
|
|
17504
|
-
rotationY: bodyYaw,
|
|
17505
|
-
sceneCenterX,
|
|
17506
|
-
sceneCenterY,
|
|
17507
|
-
size,
|
|
17508
|
-
palette,
|
|
17509
|
-
verticalColorBias: 0.18,
|
|
17510
|
-
outlineColor: `${palette.shadow}8f`,
|
|
17511
|
-
});
|
|
17512
|
-
const tentacleStrokes = createOctopusTentacleStrokes({
|
|
17513
|
-
createRandom,
|
|
17514
|
-
morphologyProfile,
|
|
17515
|
-
timeMs,
|
|
17516
|
-
size,
|
|
17517
|
-
center: underbodyCenter,
|
|
17518
|
-
radiusX: underbodyRadiusX,
|
|
17519
|
-
radiusY: underbodyRadiusY,
|
|
17520
|
-
radiusZ: underbodyRadiusZ,
|
|
17521
|
-
rotationX: bodyPitch,
|
|
17522
|
-
rotationY: bodyYaw,
|
|
17523
|
-
sceneCenterX,
|
|
17524
|
-
sceneCenterY,
|
|
17525
|
-
animationPhase,
|
|
17526
|
-
});
|
|
17527
|
-
const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
|
|
17528
|
-
const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
|
|
17529
|
-
const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
|
|
17530
|
-
const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
|
|
17531
|
-
const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
|
|
17532
|
-
const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
|
|
17533
|
-
drawAvatarFrame(context, size, palette);
|
|
17534
|
-
drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
17535
|
-
drawOctopus3dShadow(context, size, palette, interaction, timeMs);
|
|
17536
|
-
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
|
|
17537
|
-
drawTentacleStroke(context, tentacleStroke, palette);
|
|
17538
|
-
}
|
|
17539
|
-
for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
17540
|
-
drawSurfacePatch(context, surfacePatch);
|
|
17541
|
-
}
|
|
17542
|
-
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
17543
|
-
drawTentacleStroke(context, tentacleStroke, palette);
|
|
17544
|
-
}
|
|
17545
|
-
drawProjectedOrganicEye(context, {
|
|
17546
|
-
x: -faceEyeSpacing,
|
|
17547
|
-
y: faceEyeYOffset,
|
|
17548
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
17549
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
17550
|
-
drawProjectedOrganicEye(context, {
|
|
17551
|
-
x: faceEyeSpacing,
|
|
17552
|
-
y: faceEyeYOffset,
|
|
17553
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
17554
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
17555
|
-
drawProjectedOrganicMouth(context, [
|
|
17556
|
-
{
|
|
17557
|
-
x: -mouthHalfWidth,
|
|
17558
|
-
y: mouthY,
|
|
17559
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY),
|
|
17560
|
-
},
|
|
17561
|
-
{
|
|
17562
|
-
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
17563
|
-
y: mouthY +
|
|
17564
|
-
size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
|
|
17565
|
-
Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
|
|
17566
|
-
interaction.gazeY * size * 0.01,
|
|
17567
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
17568
|
-
},
|
|
17569
|
-
{
|
|
17570
|
-
x: mouthHalfWidth,
|
|
17571
|
-
y: mouthY,
|
|
17572
|
-
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY),
|
|
17573
|
-
},
|
|
17574
|
-
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
17575
|
-
},
|
|
17576
|
-
};
|
|
17577
|
-
/**
|
|
17578
|
-
* Draws the atmospheric underwater glow behind the octopus mesh.
|
|
17579
|
-
*
|
|
17580
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17581
|
-
*/
|
|
17582
|
-
function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
17583
|
-
const glowGradient = context.createRadialGradient(sceneCenterX + interaction.gazeX * size * 0.1, sceneCenterY - size * 0.2 + interaction.gazeY * size * 0.05, size * 0.04, sceneCenterX, sceneCenterY - size * 0.04, size * 0.62);
|
|
17584
|
-
glowGradient.addColorStop(0, `${palette.highlight}5c`);
|
|
17585
|
-
glowGradient.addColorStop(0.36, `${palette.accent}24`);
|
|
17586
|
-
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
17587
|
-
context.fillStyle = glowGradient;
|
|
17588
|
-
context.fillRect(0, 0, size, size);
|
|
17589
|
-
const lowerGradient = context.createRadialGradient(sceneCenterX + Math.sin(timeMs / 1700) * size * 0.05, sceneCenterY + size * 0.23, size * 0.08, sceneCenterX, sceneCenterY + size * 0.28, size * 0.5);
|
|
17590
|
-
lowerGradient.addColorStop(0, `${palette.secondary}1d`);
|
|
17591
|
-
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
17592
|
-
context.fillStyle = lowerGradient;
|
|
17593
|
-
context.fillRect(0, 0, size, size);
|
|
17594
|
-
}
|
|
17595
|
-
/**
|
|
17596
|
-
* Draws the soft ground shadow below the octopus.
|
|
17597
|
-
*
|
|
17598
|
-
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
17599
|
-
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
17600
|
-
*
|
|
17601
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17602
|
-
*/
|
|
17603
|
-
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
17604
|
-
const cx = size * 0.5 + interaction.gazeX * size * 0.04;
|
|
17605
|
-
const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
|
|
17606
|
-
const rx = size * (0.18 + interaction.intensity * 0.02);
|
|
17607
|
-
const ry = size * 0.06;
|
|
17608
|
-
context.save();
|
|
17609
|
-
context.translate(cx, cy);
|
|
17610
|
-
context.scale(1, ry / rx);
|
|
17611
|
-
const blurRadius = rx * 1.4;
|
|
17612
|
-
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
17613
|
-
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
17614
|
-
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
17615
|
-
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
17616
|
-
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
17617
|
-
context.fillStyle = shadowGradient;
|
|
17618
|
-
context.beginPath();
|
|
17619
|
-
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
17620
|
-
context.fill();
|
|
17621
|
-
context.restore();
|
|
17622
|
-
}
|
|
17623
|
-
/**
|
|
17624
|
-
* Resolves visible projected patches for one rotated ellipsoid mesh.
|
|
17625
|
-
*
|
|
17626
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17627
|
-
*/
|
|
17628
|
-
function resolveVisibleEllipsoidPatches(options) {
|
|
17629
|
-
const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
|
|
17630
|
-
const latitudePatchCount = 10;
|
|
17631
|
-
const longitudePatchCount = 18;
|
|
17632
|
-
const surfacePatches = [];
|
|
17633
|
-
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
17634
|
-
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
17635
|
-
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
17636
|
-
const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
|
|
17637
|
-
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
17638
|
-
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
17639
|
-
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
17640
|
-
const localCorners = [
|
|
17641
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
|
|
17642
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
|
|
17643
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
|
|
17644
|
-
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
|
|
17645
|
-
];
|
|
17646
|
-
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
17647
|
-
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
17648
|
-
if (surfaceNormal.z <= 0.01) {
|
|
17649
|
-
continue;
|
|
17650
|
-
}
|
|
17651
|
-
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
17652
|
-
surfacePatches.push({
|
|
17653
|
-
corners: projectedCorners,
|
|
17654
|
-
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
17655
|
-
transformedCorners.length,
|
|
17656
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$3), -1, 1),
|
|
17657
|
-
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
17658
|
-
outlineColor,
|
|
17659
|
-
});
|
|
17660
|
-
}
|
|
17661
|
-
}
|
|
17662
|
-
return surfacePatches;
|
|
17663
|
-
}
|
|
17664
|
-
/**
|
|
17665
|
-
* Samples one point on an ellipsoid aligned to the local axes.
|
|
17666
|
-
*
|
|
17667
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17668
|
-
*/
|
|
17669
|
-
function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
|
|
17670
|
-
const cosineLatitude = Math.cos(latitude);
|
|
17671
|
-
return {
|
|
17672
|
-
x: Math.sin(longitude) * cosineLatitude * radiusX,
|
|
17673
|
-
y: Math.sin(latitude) * radiusY,
|
|
17674
|
-
z: Math.cos(longitude) * cosineLatitude * radiusZ,
|
|
17675
|
-
};
|
|
17676
|
-
}
|
|
17677
|
-
/**
|
|
17678
|
-
* Resolves one base fill tone for a surface patch across the octopus body.
|
|
17679
|
-
*
|
|
17680
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17681
|
-
*/
|
|
17682
|
-
function resolveSurfacePatchFillStyle(palette, verticalProgress) {
|
|
17683
|
-
const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
|
|
17684
|
-
if (clampedVerticalProgress < 0.2) {
|
|
17685
|
-
return palette.highlight;
|
|
17686
|
-
}
|
|
17687
|
-
if (clampedVerticalProgress < 0.45) {
|
|
17688
|
-
return palette.secondary;
|
|
17689
|
-
}
|
|
17690
|
-
if (clampedVerticalProgress < 0.8) {
|
|
17691
|
-
return palette.primary;
|
|
17692
|
-
}
|
|
17693
|
-
return `${palette.shadow}f2`;
|
|
17694
|
-
}
|
|
17695
|
-
/**
|
|
17696
|
-
* Draws one projected mesh patch with organic shading.
|
|
17697
|
-
*
|
|
17698
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17699
|
-
*/
|
|
17700
|
-
function drawSurfacePatch(context, surfacePatch) {
|
|
17701
|
-
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
17702
|
-
if (surfacePatch.lightIntensity > 0) {
|
|
17703
|
-
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
|
|
17704
|
-
}
|
|
17705
|
-
else if (surfacePatch.lightIntensity < 0) {
|
|
17706
|
-
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
17707
|
-
}
|
|
17708
|
-
context.save();
|
|
17709
|
-
context.beginPath();
|
|
17710
|
-
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
17711
|
-
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
17712
|
-
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
17713
|
-
}
|
|
17714
|
-
context.closePath();
|
|
17715
|
-
context.strokeStyle = surfacePatch.outlineColor;
|
|
17716
|
-
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
|
|
17717
|
-
context.lineJoin = 'round';
|
|
17718
|
-
context.stroke();
|
|
17719
|
-
context.restore();
|
|
17720
|
-
}
|
|
17721
|
-
/**
|
|
17722
|
-
* Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
|
|
17723
|
-
*
|
|
17724
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17725
|
-
*/
|
|
17726
|
-
function createOctopusTentacleStrokes(options) {
|
|
17727
|
-
const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
|
|
17728
|
-
return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
|
|
17729
|
-
const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
|
|
17730
|
-
const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
|
|
17731
|
-
const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
|
|
17732
|
-
const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
|
|
17733
|
-
const lateralReach = size *
|
|
17734
|
-
(0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
|
|
17735
|
-
const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
|
|
17736
|
-
const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
|
|
17737
|
-
const anchorPoint = {
|
|
17738
|
-
x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
|
|
17739
|
-
y: radiusY * (0.22 + tentacleRandom() * 0.18),
|
|
17740
|
-
z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
|
|
17741
|
-
};
|
|
17742
|
-
const controlPointOne = {
|
|
17743
|
-
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
|
|
17744
|
-
y: anchorPoint.y + flowLength * 0.26,
|
|
17745
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
17746
|
-
};
|
|
17747
|
-
const controlPointTwo = {
|
|
17748
|
-
x: anchorPoint.x +
|
|
17749
|
-
Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
17750
|
-
y: anchorPoint.y + flowLength * 0.66,
|
|
17751
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
17752
|
-
};
|
|
17753
|
-
const endPoint = {
|
|
17754
|
-
x: anchorPoint.x +
|
|
17755
|
-
Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
|
|
17756
|
-
sway * size * 0.028,
|
|
17757
|
-
y: anchorPoint.y + flowLength,
|
|
17758
|
-
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
|
|
17759
|
-
};
|
|
17760
|
-
const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
|
|
17761
|
-
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
17762
|
-
const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
|
|
17763
|
-
return {
|
|
17764
|
-
projectedPoints,
|
|
17765
|
-
averageDepth,
|
|
17766
|
-
isFrontFacing: averageDepth >= center.z - size * 0.006,
|
|
17767
|
-
baseWidth: size *
|
|
17768
|
-
(0.019 +
|
|
17769
|
-
morphologyProfile.tentacles.baseWidthScale * 0.007 +
|
|
17770
|
-
tentacleRandom() * 0.003 +
|
|
17771
|
-
Math.abs(Math.sin(orbitAngle)) * 0.002),
|
|
17772
|
-
tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
|
|
17773
|
-
colorBias: tentacleRandom(),
|
|
17774
|
-
};
|
|
17775
|
-
});
|
|
17776
|
-
}
|
|
17777
|
-
/**
|
|
17778
|
-
* Samples one point on a cubic Bezier curve in 3D.
|
|
17779
|
-
*
|
|
17780
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17781
|
-
*/
|
|
17782
|
-
function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
|
|
17783
|
-
const inverseProgress = 1 - progress;
|
|
17784
|
-
return {
|
|
17785
|
-
x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
|
|
17786
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
|
|
17787
|
-
3 * inverseProgress * progress * progress * controlPointTwo.x +
|
|
17788
|
-
progress * progress * progress * endPoint.x,
|
|
17789
|
-
y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
|
|
17790
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
|
|
17791
|
-
3 * inverseProgress * progress * progress * controlPointTwo.y +
|
|
17792
|
-
progress * progress * progress * endPoint.y,
|
|
17793
|
-
z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
|
|
17794
|
-
3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
|
|
17795
|
-
3 * inverseProgress * progress * progress * controlPointTwo.z +
|
|
17796
|
-
progress * progress * progress * endPoint.z,
|
|
17797
|
-
};
|
|
17798
|
-
}
|
|
17799
|
-
/**
|
|
17800
|
-
* Draws one projected tentacle stroke with a slim highlight ridge.
|
|
17801
|
-
*
|
|
17802
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17803
|
-
*/
|
|
17804
|
-
function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
17805
|
-
const projectedSegments = tentacleStroke.projectedPoints.length - 1;
|
|
17806
|
-
for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
|
|
17807
|
-
const startPoint = tentacleStroke.projectedPoints[segmentIndex];
|
|
17808
|
-
const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
|
|
17809
|
-
const progress = segmentIndex / projectedSegments;
|
|
17810
|
-
const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
|
|
17811
|
-
context.beginPath();
|
|
17812
|
-
context.moveTo(startPoint.x, startPoint.y);
|
|
17813
|
-
context.lineTo(endPoint.x, endPoint.y);
|
|
17814
|
-
context.strokeStyle = tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
17815
|
-
context.lineWidth = width;
|
|
17816
|
-
context.lineCap = 'round';
|
|
17817
|
-
context.stroke();
|
|
17818
|
-
context.beginPath();
|
|
17819
|
-
context.moveTo(startPoint.x, startPoint.y);
|
|
17820
|
-
context.lineTo(endPoint.x, endPoint.y);
|
|
17821
|
-
context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
|
|
17822
|
-
context.lineWidth = Math.max(1, width * 0.34);
|
|
17823
|
-
context.lineCap = 'round';
|
|
17824
|
-
context.stroke();
|
|
17825
|
-
}
|
|
17826
|
-
}
|
|
17827
|
-
/**
|
|
17828
|
-
* Resolves the front surface depth on an ellipsoid for one local face point.
|
|
17829
|
-
*
|
|
17830
|
-
* @private helper of `octopus3dAvatarVisual`
|
|
17831
|
-
*/
|
|
17832
|
-
function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
17833
|
-
const normalizedX = x / radiusX;
|
|
17834
|
-
const normalizedY = y / radiusY;
|
|
17835
|
-
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
17836
|
-
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
17837
|
-
}
|
|
17838
|
-
|
|
17839
18006
|
/* eslint-disable no-magic-numbers */
|
|
17840
18007
|
/**
|
|
17841
18008
|
* Light direction used by the single-mesh octopus shading.
|
|
17842
18009
|
*
|
|
17843
18010
|
* @private helper of `octopus3d2AvatarVisual`
|
|
17844
18011
|
*/
|
|
17845
|
-
const LIGHT_DIRECTION$
|
|
18012
|
+
const LIGHT_DIRECTION$3 = normalizeVector3({
|
|
17846
18013
|
x: 0.38,
|
|
17847
18014
|
y: -0.6,
|
|
17848
18015
|
z: 0.98,
|
|
@@ -18081,7 +18248,7 @@ function resolveVisibleBlobbyOctopusPatches(options) {
|
|
|
18081
18248
|
transformedCorners[2].z +
|
|
18082
18249
|
transformedCorners[3].z) /
|
|
18083
18250
|
4,
|
|
18084
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$
|
|
18251
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$3), -1, 1),
|
|
18085
18252
|
fillStyle: resolveBlobbySurfacePatchFillStyle$1(palette, verticalProgress, Math.max(0, Math.cos(centerLongitude)), resolveLowerLobeWave(centerLongitude, morphologyProfile, animationPhase, timeMs)),
|
|
18086
18253
|
outlineColor: verticalProgress < 0.58 ? `${palette.highlight}73` : `${palette.shadow}8a`,
|
|
18087
18254
|
});
|
|
@@ -18196,7 +18363,7 @@ function drawBlobbySurfacePatch(context, surfacePatch) {
|
|
|
18196
18363
|
*
|
|
18197
18364
|
* @private helper of `octopus3d3AvatarVisual`
|
|
18198
18365
|
*/
|
|
18199
|
-
const LIGHT_DIRECTION$
|
|
18366
|
+
const LIGHT_DIRECTION$2 = normalizeVector3({
|
|
18200
18367
|
x: 0.34,
|
|
18201
18368
|
y: -0.62,
|
|
18202
18369
|
z: 1,
|
|
@@ -18503,7 +18670,7 @@ function resolveVisibleContinuousOctopusPatches(options) {
|
|
|
18503
18670
|
transformedCorners[2].z +
|
|
18504
18671
|
transformedCorners[3].z) /
|
|
18505
18672
|
4,
|
|
18506
|
-
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$
|
|
18673
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$2), -1, 1),
|
|
18507
18674
|
fillStyle: resolveContinuousSurfacePatchFillStyle(palette, verticalProgress, cachedCosByPatchCenterLongitude[longitudeIndex], cachedTentacleInfluencesByPatchCenterLongitude[longitudeIndex].core, cachedLobeWavesByPatchCenterLongitude[longitudeIndex]),
|
|
18508
18675
|
outlineColor: verticalProgress < 0.54 ? `${palette.highlight}69` : `${palette.shadow}78`,
|
|
18509
18676
|
});
|
|
@@ -18818,7 +18985,7 @@ function smoothStep$1(edgeStart, edgeEnd, value) {
|
|
|
18818
18985
|
*
|
|
18819
18986
|
* @private helper of `octopus3d4AvatarVisual`
|
|
18820
18987
|
*/
|
|
18821
|
-
const LIGHT_DIRECTION = normalizeVector3({
|
|
18988
|
+
const LIGHT_DIRECTION$1 = normalizeVector3({
|
|
18822
18989
|
x: 0.32,
|
|
18823
18990
|
y: -0.66,
|
|
18824
18991
|
z: 1,
|
|
@@ -19164,7 +19331,7 @@ function resolveVisibleBlobbyContinuousPatches(options) {
|
|
|
19164
19331
|
projectScenePoint(transformedCorners[2], size, sceneCenterX, sceneCenterY),
|
|
19165
19332
|
projectScenePoint(transformedCorners[3], size, sceneCenterX, sceneCenterY),
|
|
19166
19333
|
];
|
|
19167
|
-
const lightIntensity = clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1);
|
|
19334
|
+
const lightIntensity = clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$1), -1, 1);
|
|
19168
19335
|
const rimLightIntensity = Math.pow(clampNumber$1(dotProduct3D(surfaceNormal, RIM_LIGHT_DIRECTION), 0, 1), 2.6);
|
|
19169
19336
|
surfacePatches.push({
|
|
19170
19337
|
corners: projectedCorners,
|
|
@@ -19563,6 +19730,445 @@ function formatAlphaHex(opacity) {
|
|
|
19563
19730
|
.padStart(2, '0');
|
|
19564
19731
|
}
|
|
19565
19732
|
|
|
19733
|
+
/* eslint-disable no-magic-numbers */
|
|
19734
|
+
/**
|
|
19735
|
+
* Light direction used by the organic 3D octopus shading.
|
|
19736
|
+
*
|
|
19737
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19738
|
+
*/
|
|
19739
|
+
const LIGHT_DIRECTION = normalizeVector3({
|
|
19740
|
+
x: 0.48,
|
|
19741
|
+
y: -0.62,
|
|
19742
|
+
z: 0.94,
|
|
19743
|
+
});
|
|
19744
|
+
/**
|
|
19745
|
+
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
19746
|
+
*
|
|
19747
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19748
|
+
*/
|
|
19749
|
+
const octopus3dStableStateCache = new WeakMap();
|
|
19750
|
+
/**
|
|
19751
|
+
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
19752
|
+
*
|
|
19753
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19754
|
+
*/
|
|
19755
|
+
function getOctopus3dStableState(createRandom) {
|
|
19756
|
+
const cached = octopus3dStableStateCache.get(createRandom);
|
|
19757
|
+
if (cached !== undefined) {
|
|
19758
|
+
return cached;
|
|
19759
|
+
}
|
|
19760
|
+
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
19761
|
+
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
19762
|
+
const leftEyePhaseOffset = eyeRandom() * 0.6;
|
|
19763
|
+
const rightEyePhaseOffset = eyeRandom() * 0.6;
|
|
19764
|
+
const state = {
|
|
19765
|
+
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
19766
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
19767
|
+
leftEyePhaseOffset,
|
|
19768
|
+
rightEyePhaseOffset,
|
|
19769
|
+
};
|
|
19770
|
+
octopus3dStableStateCache.set(createRandom, state);
|
|
19771
|
+
return state;
|
|
19772
|
+
}
|
|
19773
|
+
/**
|
|
19774
|
+
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
19775
|
+
*
|
|
19776
|
+
* @private built-in avatar visual
|
|
19777
|
+
*/
|
|
19778
|
+
const octopus3dAvatarVisual = {
|
|
19779
|
+
id: 'octopus3d',
|
|
19780
|
+
title: 'Octopus 3D',
|
|
19781
|
+
description: 'Proper 3D octopus portrait with a turning silhouette, expressive eyes, and depth-sorted tentacles.',
|
|
19782
|
+
isAnimated: true,
|
|
19783
|
+
supportsPointerTracking: true,
|
|
19784
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
19785
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
|
|
19786
|
+
const sceneCenterX = size * 0.5;
|
|
19787
|
+
const sceneCenterY = size * 0.56;
|
|
19788
|
+
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
19789
|
+
const mantleCenter = {
|
|
19790
|
+
x: interaction.bodyOffsetX * size * 0.042 + size * morphologyProfile.body.centerXJitterRatio * 0.65,
|
|
19791
|
+
y: -size * 0.09 + interaction.bodyOffsetY * size * 0.028 + bob,
|
|
19792
|
+
z: interaction.intensity * size * 0.012,
|
|
19793
|
+
};
|
|
19794
|
+
const underbodyCenter = {
|
|
19795
|
+
x: mantleCenter.x * 0.86,
|
|
19796
|
+
y: mantleCenter.y + size * 0.168,
|
|
19797
|
+
z: mantleCenter.z - size * 0.018,
|
|
19798
|
+
};
|
|
19799
|
+
const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
|
|
19800
|
+
const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
|
|
19801
|
+
const mantleRadiusZ = size *
|
|
19802
|
+
morphologyProfile.body.bodyRadiusRatio *
|
|
19803
|
+
(0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
|
|
19804
|
+
const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
|
|
19805
|
+
const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
|
|
19806
|
+
const underbodyRadiusZ = mantleRadiusZ * 0.78;
|
|
19807
|
+
const bodyYaw = -0.18 +
|
|
19808
|
+
Math.sin(timeMs / 2400 + animationPhase) * 0.05 +
|
|
19809
|
+
interaction.bodyOffsetX * 0.18 +
|
|
19810
|
+
interaction.gazeX * 0.22;
|
|
19811
|
+
const bodyPitch = -0.08 +
|
|
19812
|
+
Math.cos(timeMs / 2700 + animationPhase * 0.6) * 0.025 -
|
|
19813
|
+
interaction.bodyOffsetY * 0.08 -
|
|
19814
|
+
interaction.gazeY * 0.08;
|
|
19815
|
+
const headYaw = bodyYaw - 0.04 + interaction.gazeX * 0.56;
|
|
19816
|
+
const headPitch = bodyPitch - 0.02 - interaction.gazeY * 0.32;
|
|
19817
|
+
const mantlePatches = resolveVisibleEllipsoidPatches({
|
|
19818
|
+
center: mantleCenter,
|
|
19819
|
+
radiusX: mantleRadiusX,
|
|
19820
|
+
radiusY: mantleRadiusY,
|
|
19821
|
+
radiusZ: mantleRadiusZ,
|
|
19822
|
+
rotationX: headPitch,
|
|
19823
|
+
rotationY: headYaw,
|
|
19824
|
+
sceneCenterX,
|
|
19825
|
+
sceneCenterY,
|
|
19826
|
+
size,
|
|
19827
|
+
palette,
|
|
19828
|
+
verticalColorBias: 0,
|
|
19829
|
+
outlineColor: `${palette.highlight}7a`,
|
|
19830
|
+
});
|
|
19831
|
+
const underbodyPatches = resolveVisibleEllipsoidPatches({
|
|
19832
|
+
center: underbodyCenter,
|
|
19833
|
+
radiusX: underbodyRadiusX,
|
|
19834
|
+
radiusY: underbodyRadiusY,
|
|
19835
|
+
radiusZ: underbodyRadiusZ,
|
|
19836
|
+
rotationX: bodyPitch,
|
|
19837
|
+
rotationY: bodyYaw,
|
|
19838
|
+
sceneCenterX,
|
|
19839
|
+
sceneCenterY,
|
|
19840
|
+
size,
|
|
19841
|
+
palette,
|
|
19842
|
+
verticalColorBias: 0.18,
|
|
19843
|
+
outlineColor: `${palette.shadow}8f`,
|
|
19844
|
+
});
|
|
19845
|
+
const tentacleStrokes = createOctopusTentacleStrokes({
|
|
19846
|
+
createRandom,
|
|
19847
|
+
morphologyProfile,
|
|
19848
|
+
timeMs,
|
|
19849
|
+
size,
|
|
19850
|
+
center: underbodyCenter,
|
|
19851
|
+
radiusX: underbodyRadiusX,
|
|
19852
|
+
radiusY: underbodyRadiusY,
|
|
19853
|
+
radiusZ: underbodyRadiusZ,
|
|
19854
|
+
rotationX: bodyPitch,
|
|
19855
|
+
rotationY: bodyYaw,
|
|
19856
|
+
sceneCenterX,
|
|
19857
|
+
sceneCenterY,
|
|
19858
|
+
animationPhase,
|
|
19859
|
+
});
|
|
19860
|
+
const faceEyeSpacing = size * morphologyProfile.face.eyeSpacingRatio * 0.92;
|
|
19861
|
+
const faceEyeYOffset = size * morphologyProfile.face.eyeCenterYOffsetRatio - mantleRadiusY * 0.02;
|
|
19862
|
+
const faceEyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.82;
|
|
19863
|
+
const faceEyeRadiusY = faceEyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.96;
|
|
19864
|
+
const mouthHalfWidth = size * morphologyProfile.face.mouthWidthRatio * 0.92;
|
|
19865
|
+
const mouthY = size * morphologyProfile.face.mouthYOffsetRatio + mantleRadiusY * 0.08;
|
|
19866
|
+
drawAvatarFrame(context, size, palette);
|
|
19867
|
+
drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs);
|
|
19868
|
+
drawOctopus3dShadow(context, size, palette, interaction, timeMs);
|
|
19869
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => !candidateTentacleStroke.isFrontFacing)) {
|
|
19870
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
19871
|
+
}
|
|
19872
|
+
for (const surfacePatch of [...mantlePatches, ...underbodyPatches].sort((firstSurfacePatch, secondSurfacePatch) => firstSurfacePatch.averageDepth - secondSurfacePatch.averageDepth)) {
|
|
19873
|
+
drawSurfacePatch(context, surfacePatch);
|
|
19874
|
+
}
|
|
19875
|
+
for (const tentacleStroke of tentacleStrokes.filter((candidateTentacleStroke) => candidateTentacleStroke.isFrontFacing)) {
|
|
19876
|
+
drawTentacleStroke(context, tentacleStroke, palette);
|
|
19877
|
+
}
|
|
19878
|
+
drawProjectedOrganicEye(context, {
|
|
19879
|
+
x: -faceEyeSpacing,
|
|
19880
|
+
y: faceEyeYOffset,
|
|
19881
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
19882
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
19883
|
+
drawProjectedOrganicEye(context, {
|
|
19884
|
+
x: faceEyeSpacing,
|
|
19885
|
+
y: faceEyeYOffset,
|
|
19886
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
19887
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
19888
|
+
drawProjectedOrganicMouth(context, [
|
|
19889
|
+
{
|
|
19890
|
+
x: -mouthHalfWidth,
|
|
19891
|
+
y: mouthY,
|
|
19892
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY),
|
|
19893
|
+
},
|
|
19894
|
+
{
|
|
19895
|
+
x: size * morphologyProfile.face.mouthCenterOffsetRatio,
|
|
19896
|
+
y: mouthY +
|
|
19897
|
+
size * morphologyProfile.face.mouthCurveDepthRatio * 0.38 +
|
|
19898
|
+
Math.sin(timeMs / 760 + animationPhase) * size * 0.01 +
|
|
19899
|
+
interaction.gazeY * size * 0.01,
|
|
19900
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
|
|
19901
|
+
},
|
|
19902
|
+
{
|
|
19903
|
+
x: mouthHalfWidth,
|
|
19904
|
+
y: mouthY,
|
|
19905
|
+
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY),
|
|
19906
|
+
},
|
|
19907
|
+
], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
|
|
19908
|
+
},
|
|
19909
|
+
};
|
|
19910
|
+
/**
|
|
19911
|
+
* Draws the atmospheric underwater glow behind the octopus mesh.
|
|
19912
|
+
*
|
|
19913
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19914
|
+
*/
|
|
19915
|
+
function drawOctopus3dAtmosphere(context, size, palette, sceneCenterX, sceneCenterY, interaction, timeMs) {
|
|
19916
|
+
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);
|
|
19917
|
+
glowGradient.addColorStop(0, `${palette.highlight}5c`);
|
|
19918
|
+
glowGradient.addColorStop(0.36, `${palette.accent}24`);
|
|
19919
|
+
glowGradient.addColorStop(1, `${palette.highlight}00`);
|
|
19920
|
+
context.fillStyle = glowGradient;
|
|
19921
|
+
context.fillRect(0, 0, size, size);
|
|
19922
|
+
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);
|
|
19923
|
+
lowerGradient.addColorStop(0, `${palette.secondary}1d`);
|
|
19924
|
+
lowerGradient.addColorStop(1, `${palette.secondary}00`);
|
|
19925
|
+
context.fillStyle = lowerGradient;
|
|
19926
|
+
context.fillRect(0, 0, size, size);
|
|
19927
|
+
}
|
|
19928
|
+
/**
|
|
19929
|
+
* Draws the soft ground shadow below the octopus.
|
|
19930
|
+
*
|
|
19931
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
19932
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
19933
|
+
*
|
|
19934
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19935
|
+
*/
|
|
19936
|
+
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
19937
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.04;
|
|
19938
|
+
const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
|
|
19939
|
+
const rx = size * (0.18 + interaction.intensity * 0.02);
|
|
19940
|
+
const ry = size * 0.06;
|
|
19941
|
+
context.save();
|
|
19942
|
+
context.translate(cx, cy);
|
|
19943
|
+
context.scale(1, ry / rx);
|
|
19944
|
+
const blurRadius = rx * 1.4;
|
|
19945
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
19946
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
19947
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
19948
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
19949
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
19950
|
+
context.fillStyle = shadowGradient;
|
|
19951
|
+
context.beginPath();
|
|
19952
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
19953
|
+
context.fill();
|
|
19954
|
+
context.restore();
|
|
19955
|
+
}
|
|
19956
|
+
/**
|
|
19957
|
+
* Resolves visible projected patches for one rotated ellipsoid mesh.
|
|
19958
|
+
*
|
|
19959
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
19960
|
+
*/
|
|
19961
|
+
function resolveVisibleEllipsoidPatches(options) {
|
|
19962
|
+
const { center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, verticalColorBias, outlineColor, } = options;
|
|
19963
|
+
const latitudePatchCount = 10;
|
|
19964
|
+
const longitudePatchCount = 18;
|
|
19965
|
+
const surfacePatches = [];
|
|
19966
|
+
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
19967
|
+
const startLatitude = -Math.PI / 2 + (latitudeIndex / latitudePatchCount) * Math.PI;
|
|
19968
|
+
const endLatitude = -Math.PI / 2 + ((latitudeIndex + 1) / latitudePatchCount) * Math.PI;
|
|
19969
|
+
const verticalProgress = (latitudeIndex + 0.5) / latitudePatchCount;
|
|
19970
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
19971
|
+
const startLongitude = -Math.PI + (longitudeIndex / longitudePatchCount) * Math.PI * 2;
|
|
19972
|
+
const endLongitude = -Math.PI + ((longitudeIndex + 1) / longitudePatchCount) * Math.PI * 2;
|
|
19973
|
+
const localCorners = [
|
|
19974
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, startLongitude),
|
|
19975
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, startLatitude, endLongitude),
|
|
19976
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, endLongitude),
|
|
19977
|
+
sampleEllipsoidPoint(radiusX, radiusY, radiusZ, endLatitude, startLongitude),
|
|
19978
|
+
];
|
|
19979
|
+
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
19980
|
+
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
19981
|
+
if (surfaceNormal.z <= 0.01) {
|
|
19982
|
+
continue;
|
|
19983
|
+
}
|
|
19984
|
+
const projectedCorners = transformedCorners.map((transformedCorner) => projectScenePoint(transformedCorner, size, sceneCenterX, sceneCenterY));
|
|
19985
|
+
surfacePatches.push({
|
|
19986
|
+
corners: projectedCorners,
|
|
19987
|
+
averageDepth: transformedCorners.reduce((depthSum, transformedCorner) => depthSum + transformedCorner.z, 0) /
|
|
19988
|
+
transformedCorners.length,
|
|
19989
|
+
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
19990
|
+
fillStyle: resolveSurfacePatchFillStyle(palette, verticalProgress + verticalColorBias),
|
|
19991
|
+
outlineColor,
|
|
19992
|
+
});
|
|
19993
|
+
}
|
|
19994
|
+
}
|
|
19995
|
+
return surfacePatches;
|
|
19996
|
+
}
|
|
19997
|
+
/**
|
|
19998
|
+
* Samples one point on an ellipsoid aligned to the local axes.
|
|
19999
|
+
*
|
|
20000
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20001
|
+
*/
|
|
20002
|
+
function sampleEllipsoidPoint(radiusX, radiusY, radiusZ, latitude, longitude) {
|
|
20003
|
+
const cosineLatitude = Math.cos(latitude);
|
|
20004
|
+
return {
|
|
20005
|
+
x: Math.sin(longitude) * cosineLatitude * radiusX,
|
|
20006
|
+
y: Math.sin(latitude) * radiusY,
|
|
20007
|
+
z: Math.cos(longitude) * cosineLatitude * radiusZ,
|
|
20008
|
+
};
|
|
20009
|
+
}
|
|
20010
|
+
/**
|
|
20011
|
+
* Resolves one base fill tone for a surface patch across the octopus body.
|
|
20012
|
+
*
|
|
20013
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20014
|
+
*/
|
|
20015
|
+
function resolveSurfacePatchFillStyle(palette, verticalProgress) {
|
|
20016
|
+
const clampedVerticalProgress = clampNumber$1(verticalProgress, 0, 1);
|
|
20017
|
+
if (clampedVerticalProgress < 0.2) {
|
|
20018
|
+
return palette.highlight;
|
|
20019
|
+
}
|
|
20020
|
+
if (clampedVerticalProgress < 0.45) {
|
|
20021
|
+
return palette.secondary;
|
|
20022
|
+
}
|
|
20023
|
+
if (clampedVerticalProgress < 0.8) {
|
|
20024
|
+
return palette.primary;
|
|
20025
|
+
}
|
|
20026
|
+
return `${palette.shadow}f2`;
|
|
20027
|
+
}
|
|
20028
|
+
/**
|
|
20029
|
+
* Draws one projected mesh patch with organic shading.
|
|
20030
|
+
*
|
|
20031
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20032
|
+
*/
|
|
20033
|
+
function drawSurfacePatch(context, surfacePatch) {
|
|
20034
|
+
drawProjectedQuad(context, surfacePatch.corners, surfacePatch.fillStyle);
|
|
20035
|
+
if (surfacePatch.lightIntensity > 0) {
|
|
20036
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(255, 255, 255, ${0.15 * surfacePatch.lightIntensity})`);
|
|
20037
|
+
}
|
|
20038
|
+
else if (surfacePatch.lightIntensity < 0) {
|
|
20039
|
+
drawProjectedQuad(context, surfacePatch.corners, `rgba(0, 0, 0, ${0.24 * Math.abs(surfacePatch.lightIntensity)})`);
|
|
20040
|
+
}
|
|
20041
|
+
context.save();
|
|
20042
|
+
context.beginPath();
|
|
20043
|
+
context.moveTo(surfacePatch.corners[0].x, surfacePatch.corners[0].y);
|
|
20044
|
+
for (let cornerIndex = 1; cornerIndex < surfacePatch.corners.length; cornerIndex++) {
|
|
20045
|
+
context.lineTo(surfacePatch.corners[cornerIndex].x, surfacePatch.corners[cornerIndex].y);
|
|
20046
|
+
}
|
|
20047
|
+
context.closePath();
|
|
20048
|
+
context.strokeStyle = surfacePatch.outlineColor;
|
|
20049
|
+
context.lineWidth = Math.max(1, getProjectedQuadPerimeter(surfacePatch.corners) * 0.0044);
|
|
20050
|
+
context.lineJoin = 'round';
|
|
20051
|
+
context.stroke();
|
|
20052
|
+
context.restore();
|
|
20053
|
+
}
|
|
20054
|
+
/**
|
|
20055
|
+
* Creates the projected 3D tentacle strokes orbiting around the lower octopus body.
|
|
20056
|
+
*
|
|
20057
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20058
|
+
*/
|
|
20059
|
+
function createOctopusTentacleStrokes(options) {
|
|
20060
|
+
const { createRandom, morphologyProfile, timeMs, size, center, radiusX, radiusY, radiusZ, rotationX, rotationY, sceneCenterX, sceneCenterY, animationPhase, } = options;
|
|
20061
|
+
return Array.from({ length: morphologyProfile.tentacles.count }, (_, tentacleIndex) => {
|
|
20062
|
+
const tentacleRandom = createRandom(`octopus3d-tentacle-${tentacleIndex}`);
|
|
20063
|
+
const spreadProgress = morphologyProfile.tentacles.count === 1 ? 0.5 : tentacleIndex / (morphologyProfile.tentacles.count - 1);
|
|
20064
|
+
const orbitAngle = -Math.PI * 0.92 + spreadProgress * Math.PI * 1.84 + (tentacleRandom() - 0.5) * 0.16;
|
|
20065
|
+
const flowLength = size * (0.19 + morphologyProfile.tentacles.flowLengthScale * 0.075 + tentacleRandom() * 0.018);
|
|
20066
|
+
const lateralReach = size *
|
|
20067
|
+
(0.08 + morphologyProfile.tentacles.lateralReachScale * 0.05 + Math.abs(Math.sin(orbitAngle)) * 0.018);
|
|
20068
|
+
const depthReach = size * (0.028 + morphologyProfile.tentacles.tipReachScale * 0.032);
|
|
20069
|
+
const sway = Math.sin(timeMs / (760 + tentacleIndex * 36) + animationPhase + tentacleRandom() * Math.PI * 2);
|
|
20070
|
+
const anchorPoint = {
|
|
20071
|
+
x: Math.sin(orbitAngle) * radiusX * (0.84 + tentacleRandom() * 0.08),
|
|
20072
|
+
y: radiusY * (0.22 + tentacleRandom() * 0.18),
|
|
20073
|
+
z: Math.cos(orbitAngle) * radiusZ * (0.72 + tentacleRandom() * 0.12),
|
|
20074
|
+
};
|
|
20075
|
+
const controlPointOne = {
|
|
20076
|
+
x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * 0.44,
|
|
20077
|
+
y: anchorPoint.y + flowLength * 0.26,
|
|
20078
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
|
|
20079
|
+
};
|
|
20080
|
+
const controlPointTwo = {
|
|
20081
|
+
x: anchorPoint.x +
|
|
20082
|
+
Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
|
|
20083
|
+
y: anchorPoint.y + flowLength * 0.66,
|
|
20084
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
|
|
20085
|
+
};
|
|
20086
|
+
const endPoint = {
|
|
20087
|
+
x: anchorPoint.x +
|
|
20088
|
+
Math.sin(orbitAngle) * lateralReach * (1.02 + morphologyProfile.tentacles.tipWidthScale * 0.12) +
|
|
20089
|
+
sway * size * 0.028,
|
|
20090
|
+
y: anchorPoint.y + flowLength,
|
|
20091
|
+
z: anchorPoint.z + Math.cos(orbitAngle) * depthReach + sway * size * 0.016,
|
|
20092
|
+
};
|
|
20093
|
+
const scenePoints = Array.from({ length: 12 }, (_, sampleIndex) => transformScenePoint(sampleCubicBezierPoint3D(anchorPoint, controlPointOne, controlPointTwo, endPoint, sampleIndex / 11), center, rotationX, rotationY));
|
|
20094
|
+
const projectedPoints = scenePoints.map((scenePoint) => projectScenePoint(scenePoint, size, sceneCenterX, sceneCenterY));
|
|
20095
|
+
const averageDepth = scenePoints.reduce((depthSum, scenePoint) => depthSum + scenePoint.z, 0) / scenePoints.length;
|
|
20096
|
+
return {
|
|
20097
|
+
projectedPoints,
|
|
20098
|
+
averageDepth,
|
|
20099
|
+
isFrontFacing: averageDepth >= center.z - size * 0.006,
|
|
20100
|
+
baseWidth: size *
|
|
20101
|
+
(0.019 +
|
|
20102
|
+
morphologyProfile.tentacles.baseWidthScale * 0.007 +
|
|
20103
|
+
tentacleRandom() * 0.003 +
|
|
20104
|
+
Math.abs(Math.sin(orbitAngle)) * 0.002),
|
|
20105
|
+
tipWidth: size * (0.0046 + morphologyProfile.tentacles.tipWidthScale * 0.0018),
|
|
20106
|
+
colorBias: tentacleRandom(),
|
|
20107
|
+
};
|
|
20108
|
+
});
|
|
20109
|
+
}
|
|
20110
|
+
/**
|
|
20111
|
+
* Samples one point on a cubic Bezier curve in 3D.
|
|
20112
|
+
*
|
|
20113
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20114
|
+
*/
|
|
20115
|
+
function sampleCubicBezierPoint3D(startPoint, controlPointOne, controlPointTwo, endPoint, progress) {
|
|
20116
|
+
const inverseProgress = 1 - progress;
|
|
20117
|
+
return {
|
|
20118
|
+
x: inverseProgress * inverseProgress * inverseProgress * startPoint.x +
|
|
20119
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.x +
|
|
20120
|
+
3 * inverseProgress * progress * progress * controlPointTwo.x +
|
|
20121
|
+
progress * progress * progress * endPoint.x,
|
|
20122
|
+
y: inverseProgress * inverseProgress * inverseProgress * startPoint.y +
|
|
20123
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.y +
|
|
20124
|
+
3 * inverseProgress * progress * progress * controlPointTwo.y +
|
|
20125
|
+
progress * progress * progress * endPoint.y,
|
|
20126
|
+
z: inverseProgress * inverseProgress * inverseProgress * startPoint.z +
|
|
20127
|
+
3 * inverseProgress * inverseProgress * progress * controlPointOne.z +
|
|
20128
|
+
3 * inverseProgress * progress * progress * controlPointTwo.z +
|
|
20129
|
+
progress * progress * progress * endPoint.z,
|
|
20130
|
+
};
|
|
20131
|
+
}
|
|
20132
|
+
/**
|
|
20133
|
+
* Draws one projected tentacle stroke with a slim highlight ridge.
|
|
20134
|
+
*
|
|
20135
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20136
|
+
*/
|
|
20137
|
+
function drawTentacleStroke(context, tentacleStroke, palette) {
|
|
20138
|
+
const projectedSegments = tentacleStroke.projectedPoints.length - 1;
|
|
20139
|
+
for (let segmentIndex = 0; segmentIndex < projectedSegments; segmentIndex++) {
|
|
20140
|
+
const startPoint = tentacleStroke.projectedPoints[segmentIndex];
|
|
20141
|
+
const endPoint = tentacleStroke.projectedPoints[segmentIndex + 1];
|
|
20142
|
+
const progress = segmentIndex / projectedSegments;
|
|
20143
|
+
const width = tentacleStroke.baseWidth + (tentacleStroke.tipWidth - tentacleStroke.baseWidth) * progress;
|
|
20144
|
+
context.beginPath();
|
|
20145
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
20146
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
20147
|
+
context.strokeStyle = tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
|
|
20148
|
+
context.lineWidth = width;
|
|
20149
|
+
context.lineCap = 'round';
|
|
20150
|
+
context.stroke();
|
|
20151
|
+
context.beginPath();
|
|
20152
|
+
context.moveTo(startPoint.x, startPoint.y);
|
|
20153
|
+
context.lineTo(endPoint.x, endPoint.y);
|
|
20154
|
+
context.strokeStyle = tentacleStroke.isFrontFacing ? `${palette.highlight}80` : `${palette.highlight}40`;
|
|
20155
|
+
context.lineWidth = Math.max(1, width * 0.34);
|
|
20156
|
+
context.lineCap = 'round';
|
|
20157
|
+
context.stroke();
|
|
20158
|
+
}
|
|
20159
|
+
}
|
|
20160
|
+
/**
|
|
20161
|
+
* Resolves the front surface depth on an ellipsoid for one local face point.
|
|
20162
|
+
*
|
|
20163
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
20164
|
+
*/
|
|
20165
|
+
function resolveEllipsoidSurfaceDepth(radiusX, radiusY, radiusZ, x, y) {
|
|
20166
|
+
const normalizedX = x / radiusX;
|
|
20167
|
+
const normalizedY = y / radiusY;
|
|
20168
|
+
const remainingDepthRatio = Math.max(0, 1 - normalizedX * normalizedX - normalizedY * normalizedY);
|
|
20169
|
+
return Math.sqrt(remainingDepthRatio) * radiusZ;
|
|
20170
|
+
}
|
|
20171
|
+
|
|
19566
20172
|
/* eslint-disable no-magic-numbers */
|
|
19567
20173
|
/**
|
|
19568
20174
|
* Octopus avatar visual.
|
|
@@ -20383,14 +20989,14 @@ function resolveAvatarVisualId(value) {
|
|
|
20383
20989
|
/**
|
|
20384
20990
|
* META AVATAR commitment definition
|
|
20385
20991
|
*
|
|
20386
|
-
* The `META AVATAR`
|
|
20387
|
-
* the agent does not provide an explicit `META IMAGE`.
|
|
20992
|
+
* The `META AVATAR` and `META VISUAL` commitments set the built-in default avatar visual
|
|
20993
|
+
* used when the agent does not provide an explicit `META IMAGE`.
|
|
20388
20994
|
*
|
|
20389
20995
|
* @private [🪔] Maybe export the commitments through some package
|
|
20390
20996
|
*/
|
|
20391
20997
|
class MetaAvatarCommitmentDefinition extends BaseCommitmentDefinition {
|
|
20392
|
-
constructor() {
|
|
20393
|
-
super(
|
|
20998
|
+
constructor(type = 'META AVATAR') {
|
|
20999
|
+
super(type);
|
|
20394
21000
|
}
|
|
20395
21001
|
/**
|
|
20396
21002
|
* Short one-line description of META AVATAR.
|
|
@@ -20410,14 +21016,15 @@ class MetaAvatarCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
20410
21016
|
get documentation() {
|
|
20411
21017
|
const supportedVisuals = AVATAR_VISUALS.map((avatarVisual) => `\`${avatarVisual.id}\``).join(', ');
|
|
20412
21018
|
return spaceTrim$1(`
|
|
20413
|
-
#
|
|
21019
|
+
# ${this.type}
|
|
20414
21020
|
|
|
20415
21021
|
Sets the built-in avatar visual used for the agent when no explicit \`META IMAGE\` is provided.
|
|
21022
|
+
\`META AVATAR\` and \`META VISUAL\` are equivalent.
|
|
20416
21023
|
|
|
20417
21024
|
## Key aspects
|
|
20418
21025
|
|
|
20419
21026
|
- Does not modify the agent's behavior or responses.
|
|
20420
|
-
- Only one \`META AVATAR\` should be used per agent.
|
|
21027
|
+
- Only one \`META AVATAR\` or \`META VISUAL\` should be used per agent.
|
|
20421
21028
|
- If multiple are specified, the last one takes precedence.
|
|
20422
21029
|
- Values are matched case-insensitively and spaces, hyphens, and underscores are normalized.
|
|
20423
21030
|
- Supported visuals are derived from the shared avatar registry: ${supportedVisuals}.
|
|
@@ -20432,15 +21039,15 @@ class MetaAvatarCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
20432
21039
|
\`\`\`
|
|
20433
21040
|
|
|
20434
21041
|
\`\`\`book
|
|
20435
|
-
|
|
21042
|
+
Minecraft Assistant
|
|
20436
21043
|
|
|
20437
|
-
META
|
|
21044
|
+
META VISUAL Minecraft2
|
|
20438
21045
|
GOAL Answer in a calm and focused way.
|
|
20439
21046
|
\`\`\`
|
|
20440
21047
|
`);
|
|
20441
21048
|
}
|
|
20442
21049
|
applyToAgentModelRequirements(requirements, content) {
|
|
20443
|
-
// META AVATAR
|
|
21050
|
+
// META AVATAR and META VISUAL don't modify the system message or model requirements.
|
|
20444
21051
|
// It's handled separately in the parsing logic for profile avatar resolution.
|
|
20445
21052
|
return requirements;
|
|
20446
21053
|
}
|
|
@@ -21014,6 +21621,68 @@ class MetaLinkCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21014
21621
|
}
|
|
21015
21622
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
21016
21623
|
|
|
21624
|
+
/**
|
|
21625
|
+
* META THINKING MESSAGE commitment definition.
|
|
21626
|
+
*
|
|
21627
|
+
* The `META THINKING MESSAGE` commitment adds one custom thinking placeholder
|
|
21628
|
+
* variant used by chat UIs while an agent is composing a reply.
|
|
21629
|
+
*
|
|
21630
|
+
* @private Metadata-only commitment used by Agents Server chat UIs.
|
|
21631
|
+
*/
|
|
21632
|
+
class MetaThinkingMessageCommitmentDefinition extends BaseCommitmentDefinition {
|
|
21633
|
+
constructor() {
|
|
21634
|
+
super('META THINKING MESSAGE');
|
|
21635
|
+
}
|
|
21636
|
+
/**
|
|
21637
|
+
* Short one-line description of META THINKING MESSAGE.
|
|
21638
|
+
*/
|
|
21639
|
+
get description() {
|
|
21640
|
+
return 'Add a custom thinking placeholder shown while the agent replies.';
|
|
21641
|
+
}
|
|
21642
|
+
/**
|
|
21643
|
+
* Icon for this commitment.
|
|
21644
|
+
*/
|
|
21645
|
+
get icon() {
|
|
21646
|
+
return '💭';
|
|
21647
|
+
}
|
|
21648
|
+
/**
|
|
21649
|
+
* Markdown documentation for META THINKING MESSAGE commitment.
|
|
21650
|
+
*/
|
|
21651
|
+
get documentation() {
|
|
21652
|
+
return spaceTrim$1(`
|
|
21653
|
+
# META THINKING MESSAGE
|
|
21654
|
+
|
|
21655
|
+
Adds one custom placeholder variant shown while the agent is composing a reply.
|
|
21656
|
+
|
|
21657
|
+
## Key aspects
|
|
21658
|
+
|
|
21659
|
+
- Does not modify model behavior, system message, or tools.
|
|
21660
|
+
- Multiple \`META THINKING MESSAGE\` commitments define multiple variants.
|
|
21661
|
+
- Chat UIs randomly rotate between the configured variants while the reply is running.
|
|
21662
|
+
- When no non-empty variants are configured, the server-level \`THINKING_MESSAGES\` metadata is used.
|
|
21663
|
+
- Supports multiline markdown content.
|
|
21664
|
+
|
|
21665
|
+
## Example
|
|
21666
|
+
|
|
21667
|
+
\`\`\`book
|
|
21668
|
+
Helpful Assistant
|
|
21669
|
+
|
|
21670
|
+
META THINKING MESSAGE Thinking...
|
|
21671
|
+
META THINKING MESSAGE Processing...
|
|
21672
|
+
META THINKING MESSAGE
|
|
21673
|
+
|
|
21674
|
+
Doing
|
|
21675
|
+
extra **hard** work
|
|
21676
|
+
\`\`\`
|
|
21677
|
+
`);
|
|
21678
|
+
}
|
|
21679
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
21680
|
+
// META THINKING MESSAGE is metadata only and does not alter model requirements.
|
|
21681
|
+
return requirements;
|
|
21682
|
+
}
|
|
21683
|
+
}
|
|
21684
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
21685
|
+
|
|
21017
21686
|
/**
|
|
21018
21687
|
* META VISIBILITY commitment definition.
|
|
21019
21688
|
*
|
|
@@ -23092,6 +23761,7 @@ class UseBrowserCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
23092
23761
|
1. **One-shot URL fetching**: Simple function to fetch and scrape URL content (active)
|
|
23093
23762
|
2. **Running browser**: For complex tasks like scrolling, clicking, form filling, etc. (runtime-dependent)
|
|
23094
23763
|
- The actual browser tool usage is handled by the agent runtime
|
|
23764
|
+
- 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)
|
|
23095
23765
|
- Allows the agent to fetch current information from websites and documents
|
|
23096
23766
|
- Useful for research tasks, fact-checking, and accessing dynamic content
|
|
23097
23767
|
- Supports various content types including HTML pages and PDF documents
|
|
@@ -29628,6 +30298,7 @@ const COMMITMENT_REGISTRY = [
|
|
|
29628
30298
|
new ActionCommitmentDefinition('ACTIONS'),
|
|
29629
30299
|
new ComponentCommitmentDefinition(),
|
|
29630
30300
|
new MetaAvatarCommitmentDefinition(),
|
|
30301
|
+
new MetaAvatarCommitmentDefinition('META VISUAL'),
|
|
29631
30302
|
new MetaImageCommitmentDefinition(),
|
|
29632
30303
|
new MetaColorCommitmentDefinition(),
|
|
29633
30304
|
new MetaFontCommitmentDefinition(),
|
|
@@ -29635,6 +30306,7 @@ const COMMITMENT_REGISTRY = [
|
|
|
29635
30306
|
new MetaDomainCommitmentDefinition(),
|
|
29636
30307
|
new MetaDisclaimerCommitmentDefinition(),
|
|
29637
30308
|
new MetaInputPlaceholderCommitmentDefinition(),
|
|
30309
|
+
new MetaThinkingMessageCommitmentDefinition(),
|
|
29638
30310
|
new MetaVisibilityCommitmentDefinition(),
|
|
29639
30311
|
new MetaCommitmentDefinition(),
|
|
29640
30312
|
new MetaVoiceCommitmentDefinition(),
|
|
@@ -30979,12 +31651,14 @@ function hasHttpProtocol(value) {
|
|
|
30979
31651
|
*/
|
|
30980
31652
|
const META_COMMITMENT_APPLIERS = {
|
|
30981
31653
|
'META AVATAR': applyMetaAvatarContent,
|
|
31654
|
+
'META VISUAL': applyMetaAvatarContent,
|
|
30982
31655
|
'META LINK': applyMetaLinkContent,
|
|
30983
31656
|
'META DOMAIN': applyMetaDomainContent,
|
|
30984
31657
|
'META IMAGE': applyMetaImageContent,
|
|
30985
31658
|
'META DESCRIPTION': applyMetaDescriptionContent,
|
|
30986
31659
|
'META DISCLAIMER': applyMetaDisclaimerContent,
|
|
30987
31660
|
'META INPUT PLACEHOLDER': applyMetaInputPlaceholderContent,
|
|
31661
|
+
'META THINKING MESSAGE': applyMetaThinkingMessageContent,
|
|
30988
31662
|
'MESSAGE SUFFIX': applyMessageSuffixContent,
|
|
30989
31663
|
'META COLOR': applyMetaColorContent,
|
|
30990
31664
|
'META FONT': applyMetaFontContent,
|
|
@@ -31027,7 +31701,7 @@ function applyGenericMetaCommitment(state, content) {
|
|
|
31027
31701
|
state.meta[metaType] = metaValue;
|
|
31028
31702
|
}
|
|
31029
31703
|
/**
|
|
31030
|
-
* Applies META AVATAR content into the canonical `meta.avatar` field.
|
|
31704
|
+
* Applies META AVATAR / META VISUAL content into the canonical `meta.avatar` field.
|
|
31031
31705
|
*/
|
|
31032
31706
|
function applyMetaAvatarContent(state, content) {
|
|
31033
31707
|
const avatarVisualId = resolveAvatarVisualId(content);
|
|
@@ -31075,6 +31749,16 @@ function applyMetaDisclaimerContent(state, content) {
|
|
|
31075
31749
|
function applyMetaInputPlaceholderContent(state, content) {
|
|
31076
31750
|
state.meta.inputPlaceholder = spaceTrim$1(content);
|
|
31077
31751
|
}
|
|
31752
|
+
/**
|
|
31753
|
+
* Applies one META THINKING MESSAGE content block into the custom thinking-message variants.
|
|
31754
|
+
*/
|
|
31755
|
+
function applyMetaThinkingMessageContent(state, content) {
|
|
31756
|
+
const thinkingMessage = spaceTrim$1(content);
|
|
31757
|
+
if (!thinkingMessage) {
|
|
31758
|
+
return;
|
|
31759
|
+
}
|
|
31760
|
+
state.thinkingMessages = [...(state.thinkingMessages || []), thinkingMessage];
|
|
31761
|
+
}
|
|
31078
31762
|
/**
|
|
31079
31763
|
* Applies MESSAGE SUFFIX content into the canonical `meta.messageSuffix` field.
|
|
31080
31764
|
*/
|
|
@@ -31443,6 +32127,7 @@ function extractParsedAgentProfile(commitments) {
|
|
|
31443
32127
|
capabilities: [],
|
|
31444
32128
|
samples: [],
|
|
31445
32129
|
knowledgeSources: [],
|
|
32130
|
+
thinkingMessages: [],
|
|
31446
32131
|
pendingUserMessage: null,
|
|
31447
32132
|
knownKnowledgeSourceUrls: new Set(),
|
|
31448
32133
|
};
|
|
@@ -31455,6 +32140,7 @@ function extractParsedAgentProfile(commitments) {
|
|
|
31455
32140
|
capabilities: state.capabilities,
|
|
31456
32141
|
samples: state.samples,
|
|
31457
32142
|
knowledgeSources: state.knowledgeSources,
|
|
32143
|
+
thinkingMessages: state.thinkingMessages,
|
|
31458
32144
|
};
|
|
31459
32145
|
}
|
|
31460
32146
|
/**
|
|
@@ -31494,6 +32180,7 @@ function parseAgentSource(agentSource) {
|
|
|
31494
32180
|
permanentId: parsedProfile.meta.id,
|
|
31495
32181
|
personaDescription,
|
|
31496
32182
|
initialMessage,
|
|
32183
|
+
thinkingMessages: parsedProfile.thinkingMessages,
|
|
31497
32184
|
meta: parsedProfile.meta,
|
|
31498
32185
|
links: parsedProfile.links,
|
|
31499
32186
|
parameters: parseParameters(agentSource),
|
|
@@ -32091,6 +32778,78 @@ function normalizeCliAgentFileSegment(value) {
|
|
|
32091
32778
|
.replace(/^[._-]+|[._-]+$/gu, '');
|
|
32092
32779
|
}
|
|
32093
32780
|
|
|
32781
|
+
/**
|
|
32782
|
+
* Helper of usage compute
|
|
32783
|
+
*
|
|
32784
|
+
* @param content the content of prompt or response
|
|
32785
|
+
* @returns part of UsageCounts
|
|
32786
|
+
*
|
|
32787
|
+
* @private internal utility of LlmExecutionTools
|
|
32788
|
+
*/
|
|
32789
|
+
function computeUsageCounts(content) {
|
|
32790
|
+
return {
|
|
32791
|
+
charactersCount: { value: countCharacters(content) },
|
|
32792
|
+
wordsCount: { value: countWords(content) },
|
|
32793
|
+
sentencesCount: { value: countSentences(content) },
|
|
32794
|
+
linesCount: { value: countLines(content) },
|
|
32795
|
+
paragraphsCount: { value: countParagraphs(content) },
|
|
32796
|
+
pagesCount: { value: countPages(content) },
|
|
32797
|
+
};
|
|
32798
|
+
}
|
|
32799
|
+
|
|
32800
|
+
/**
|
|
32801
|
+
* Computes the usage of the OpenAI API based on the response from OpenAI
|
|
32802
|
+
*
|
|
32803
|
+
* @param promptContent The content of the prompt
|
|
32804
|
+
* @param resultContent The content of the result (for embedding prompts or failed prompts pass empty string)
|
|
32805
|
+
* @param rawResponse The raw response from OpenAI API
|
|
32806
|
+
* @param duration The duration of the execution
|
|
32807
|
+
* @throws {PipelineExecutionError} If the usage is not defined in the response from OpenAI
|
|
32808
|
+
*
|
|
32809
|
+
* @private internal utility of `OpenAiExecutionTools`
|
|
32810
|
+
*/
|
|
32811
|
+
function computeOpenAiUsage(promptContent, // <- Note: Intentionally using [] to access type properties to bring jsdoc from Prompt/PromptResult to consumer
|
|
32812
|
+
resultContent, rawResponse, duration = ZERO_VALUE) {
|
|
32813
|
+
var _a, _b;
|
|
32814
|
+
if (rawResponse.usage === undefined) {
|
|
32815
|
+
throw new PipelineExecutionError('The usage is not defined in the response from OpenAI');
|
|
32816
|
+
}
|
|
32817
|
+
if (((_a = rawResponse.usage) === null || _a === void 0 ? void 0 : _a.prompt_tokens) === undefined) {
|
|
32818
|
+
throw new PipelineExecutionError('In OpenAI response `usage.prompt_tokens` not defined');
|
|
32819
|
+
}
|
|
32820
|
+
const inputTokens = rawResponse.usage.prompt_tokens;
|
|
32821
|
+
const outputTokens = ((_b = rawResponse.usage) === null || _b === void 0 ? void 0 : _b.completion_tokens) || 0;
|
|
32822
|
+
let isUncertain = false;
|
|
32823
|
+
let modelInfo = OPENAI_MODELS.find((model) => model.modelName === rawResponse.model);
|
|
32824
|
+
if (modelInfo === undefined) {
|
|
32825
|
+
// Note: Model is not in the list of known models, fallback to the family of the models and mark price as uncertain
|
|
32826
|
+
modelInfo = OPENAI_MODELS.find((model) => (rawResponse.model || SALT_NONCE).startsWith(model.modelName));
|
|
32827
|
+
if (modelInfo !== undefined) {
|
|
32828
|
+
isUncertain = true;
|
|
32829
|
+
}
|
|
32830
|
+
}
|
|
32831
|
+
let price;
|
|
32832
|
+
if (modelInfo === undefined || modelInfo.pricing === undefined) {
|
|
32833
|
+
price = uncertainNumber();
|
|
32834
|
+
}
|
|
32835
|
+
else {
|
|
32836
|
+
price = uncertainNumber(inputTokens * modelInfo.pricing.prompt + outputTokens * modelInfo.pricing.output, isUncertain);
|
|
32837
|
+
}
|
|
32838
|
+
return {
|
|
32839
|
+
price,
|
|
32840
|
+
duration,
|
|
32841
|
+
input: {
|
|
32842
|
+
tokensCount: uncertainNumber(rawResponse.usage.prompt_tokens),
|
|
32843
|
+
...computeUsageCounts(promptContent),
|
|
32844
|
+
},
|
|
32845
|
+
output: {
|
|
32846
|
+
tokensCount: uncertainNumber(outputTokens),
|
|
32847
|
+
...computeUsageCounts(resultContent),
|
|
32848
|
+
},
|
|
32849
|
+
};
|
|
32850
|
+
}
|
|
32851
|
+
// TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
|
|
32852
|
+
|
|
32094
32853
|
/**
|
|
32095
32854
|
* Simple wrapper `new Date().toISOString()`
|
|
32096
32855
|
*
|
|
@@ -32499,78 +33258,6 @@ class OpenAiAgentKitExecutionToolsToolBuilder {
|
|
|
32499
33258
|
}
|
|
32500
33259
|
}
|
|
32501
33260
|
|
|
32502
|
-
/**
|
|
32503
|
-
* Helper of usage compute
|
|
32504
|
-
*
|
|
32505
|
-
* @param content the content of prompt or response
|
|
32506
|
-
* @returns part of UsageCounts
|
|
32507
|
-
*
|
|
32508
|
-
* @private internal utility of LlmExecutionTools
|
|
32509
|
-
*/
|
|
32510
|
-
function computeUsageCounts(content) {
|
|
32511
|
-
return {
|
|
32512
|
-
charactersCount: { value: countCharacters(content) },
|
|
32513
|
-
wordsCount: { value: countWords(content) },
|
|
32514
|
-
sentencesCount: { value: countSentences(content) },
|
|
32515
|
-
linesCount: { value: countLines(content) },
|
|
32516
|
-
paragraphsCount: { value: countParagraphs(content) },
|
|
32517
|
-
pagesCount: { value: countPages(content) },
|
|
32518
|
-
};
|
|
32519
|
-
}
|
|
32520
|
-
|
|
32521
|
-
/**
|
|
32522
|
-
* Computes the usage of the OpenAI API based on the response from OpenAI
|
|
32523
|
-
*
|
|
32524
|
-
* @param promptContent The content of the prompt
|
|
32525
|
-
* @param resultContent The content of the result (for embedding prompts or failed prompts pass empty string)
|
|
32526
|
-
* @param rawResponse The raw response from OpenAI API
|
|
32527
|
-
* @param duration The duration of the execution
|
|
32528
|
-
* @throws {PipelineExecutionError} If the usage is not defined in the response from OpenAI
|
|
32529
|
-
*
|
|
32530
|
-
* @private internal utility of `OpenAiExecutionTools`
|
|
32531
|
-
*/
|
|
32532
|
-
function computeOpenAiUsage(promptContent, // <- Note: Intentionally using [] to access type properties to bring jsdoc from Prompt/PromptResult to consumer
|
|
32533
|
-
resultContent, rawResponse, duration = ZERO_VALUE) {
|
|
32534
|
-
var _a, _b;
|
|
32535
|
-
if (rawResponse.usage === undefined) {
|
|
32536
|
-
throw new PipelineExecutionError('The usage is not defined in the response from OpenAI');
|
|
32537
|
-
}
|
|
32538
|
-
if (((_a = rawResponse.usage) === null || _a === void 0 ? void 0 : _a.prompt_tokens) === undefined) {
|
|
32539
|
-
throw new PipelineExecutionError('In OpenAI response `usage.prompt_tokens` not defined');
|
|
32540
|
-
}
|
|
32541
|
-
const inputTokens = rawResponse.usage.prompt_tokens;
|
|
32542
|
-
const outputTokens = ((_b = rawResponse.usage) === null || _b === void 0 ? void 0 : _b.completion_tokens) || 0;
|
|
32543
|
-
let isUncertain = false;
|
|
32544
|
-
let modelInfo = OPENAI_MODELS.find((model) => model.modelName === rawResponse.model);
|
|
32545
|
-
if (modelInfo === undefined) {
|
|
32546
|
-
// Note: Model is not in the list of known models, fallback to the family of the models and mark price as uncertain
|
|
32547
|
-
modelInfo = OPENAI_MODELS.find((model) => (rawResponse.model || SALT_NONCE).startsWith(model.modelName));
|
|
32548
|
-
if (modelInfo !== undefined) {
|
|
32549
|
-
isUncertain = true;
|
|
32550
|
-
}
|
|
32551
|
-
}
|
|
32552
|
-
let price;
|
|
32553
|
-
if (modelInfo === undefined || modelInfo.pricing === undefined) {
|
|
32554
|
-
price = uncertainNumber();
|
|
32555
|
-
}
|
|
32556
|
-
else {
|
|
32557
|
-
price = uncertainNumber(inputTokens * modelInfo.pricing.prompt + outputTokens * modelInfo.pricing.output, isUncertain);
|
|
32558
|
-
}
|
|
32559
|
-
return {
|
|
32560
|
-
price,
|
|
32561
|
-
duration,
|
|
32562
|
-
input: {
|
|
32563
|
-
tokensCount: uncertainNumber(rawResponse.usage.prompt_tokens),
|
|
32564
|
-
...computeUsageCounts(promptContent),
|
|
32565
|
-
},
|
|
32566
|
-
output: {
|
|
32567
|
-
tokensCount: uncertainNumber(outputTokens),
|
|
32568
|
-
...computeUsageCounts(resultContent),
|
|
32569
|
-
},
|
|
32570
|
-
};
|
|
32571
|
-
}
|
|
32572
|
-
// TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
|
|
32573
|
-
|
|
32574
33261
|
/**
|
|
32575
33262
|
* Finds the best hardcoded-model match for one API-listed model identifier.
|
|
32576
33263
|
*/
|
|
@@ -42930,7 +43617,7 @@ async function locateAppOnWindows({ appName, windowsSuffix, }) {
|
|
|
42930
43617
|
*
|
|
42931
43618
|
* @private within the repository
|
|
42932
43619
|
*/
|
|
42933
|
-
function locateApp(options) {
|
|
43620
|
+
async function locateApp(options) {
|
|
42934
43621
|
if (!$isRunningInNode()) {
|
|
42935
43622
|
throw new EnvironmentMismatchError('Locating apps works only in Node.js environment');
|
|
42936
43623
|
}
|
|
@@ -43028,18 +43715,6 @@ async function $provideExecutablesForNode(options) {
|
|
|
43028
43715
|
const $llmToolsMetadataRegister = new $Register('llm_tools_metadata');
|
|
43029
43716
|
// TODO: [®] DRY Register logic
|
|
43030
43717
|
|
|
43031
|
-
/**
|
|
43032
|
-
* Register for LLM tools.
|
|
43033
|
-
*
|
|
43034
|
-
* Note: `$` is used to indicate that this interacts with the global scope
|
|
43035
|
-
*
|
|
43036
|
-
* @singleton Only one instance of each register is created per build, but there can be more instances across different builds or environments.
|
|
43037
|
-
*
|
|
43038
|
-
* @public exported from `@promptbook/core`
|
|
43039
|
-
*/
|
|
43040
|
-
const $llmToolsRegister = new $Register('llm_execution_tools_constructors');
|
|
43041
|
-
// TODO: [®] DRY Register logic
|
|
43042
|
-
|
|
43043
43718
|
/**
|
|
43044
43719
|
* Path to the `.env` file which was used to configure LLM tools
|
|
43045
43720
|
*
|
|
@@ -43047,61 +43722,53 @@ const $llmToolsRegister = new $Register('llm_execution_tools_constructors');
|
|
|
43047
43722
|
*/
|
|
43048
43723
|
let $usedEnvFilename = null;
|
|
43049
43724
|
/**
|
|
43050
|
-
*
|
|
43051
|
-
*
|
|
43052
|
-
* Note: `$` is used to indicate that this variable is making side effect
|
|
43053
|
-
*
|
|
43054
|
-
* @private internal log of `$provideLlmToolsConfigurationFromEnv` and `$registeredLlmToolsMessage`
|
|
43055
|
-
*/
|
|
43056
|
-
function $setUsedEnvFilename(filepath) {
|
|
43057
|
-
$usedEnvFilename = filepath;
|
|
43058
|
-
}
|
|
43059
|
-
/**
|
|
43060
|
-
* Creates a message with all registered LLM tools
|
|
43061
|
-
*
|
|
43062
|
-
* Note: This function is used to create a (error) message when there is no constructor for some LLM provider
|
|
43063
|
-
*
|
|
43064
|
-
* @private internal function of `createLlmToolsFromConfiguration` and `$provideLlmToolsFromEnv`
|
|
43065
|
-
*/
|
|
43066
|
-
function $registeredLlmToolsMessage() {
|
|
43067
|
-
const registeredLlmToolsMessageContext = createRegisteredLlmToolsMessageContext();
|
|
43068
|
-
if (registeredLlmToolsMessageContext.llmToolStatuses.length === 0) {
|
|
43069
|
-
return renderNoRegisteredLlmToolsMessage(registeredLlmToolsMessageContext.usedEnvMessage);
|
|
43070
|
-
}
|
|
43071
|
-
return renderRegisteredLlmToolsMessage(registeredLlmToolsMessageContext);
|
|
43072
|
-
}
|
|
43073
|
-
/**
|
|
43074
|
-
* Collects all state needed to render the provider summary.
|
|
43725
|
+
* Shared state for the `.env` file used to configure LLM tools.
|
|
43075
43726
|
*
|
|
43076
|
-
* @private internal
|
|
43727
|
+
* @private internal state of `$registeredLlmToolsMessage`
|
|
43077
43728
|
*/
|
|
43078
|
-
|
|
43079
|
-
|
|
43080
|
-
|
|
43081
|
-
|
|
43082
|
-
|
|
43083
|
-
|
|
43084
|
-
|
|
43085
|
-
|
|
43086
|
-
|
|
43087
|
-
|
|
43088
|
-
|
|
43729
|
+
const USED_ENV_FILENAME = {
|
|
43730
|
+
set(filepath) {
|
|
43731
|
+
$usedEnvFilename = filepath;
|
|
43732
|
+
},
|
|
43733
|
+
createMessage() {
|
|
43734
|
+
return $usedEnvFilename === null
|
|
43735
|
+
? `Unknown \`.env\` file`
|
|
43736
|
+
: spaceTrim$1(`
|
|
43737
|
+
Used \`.env\` file:
|
|
43738
|
+
${$usedEnvFilename}
|
|
43739
|
+
`);
|
|
43740
|
+
},
|
|
43741
|
+
};
|
|
43742
|
+
|
|
43089
43743
|
/**
|
|
43090
43744
|
* Reads environment variables relevant for provider configuration.
|
|
43091
43745
|
*
|
|
43092
|
-
* @private
|
|
43746
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43093
43747
|
*/
|
|
43094
|
-
function
|
|
43748
|
+
function getAvailableRegisteredLlmToolsEnvironmentVariables(isRunningInNode) {
|
|
43095
43749
|
if (isRunningInNode) {
|
|
43096
43750
|
return process.env;
|
|
43097
43751
|
// <- TODO: [⚛] Some DRY way how to get to `process.env` and pass it into functions - ACRY search for `env`
|
|
43098
43752
|
}
|
|
43099
43753
|
return {};
|
|
43100
43754
|
}
|
|
43755
|
+
|
|
43756
|
+
/**
|
|
43757
|
+
* Register for LLM tools.
|
|
43758
|
+
*
|
|
43759
|
+
* Note: `$` is used to indicate that this interacts with the global scope
|
|
43760
|
+
*
|
|
43761
|
+
* @singleton Only one instance of each register is created per build, but there can be more instances across different builds or environments.
|
|
43762
|
+
*
|
|
43763
|
+
* @public exported from `@promptbook/core`
|
|
43764
|
+
*/
|
|
43765
|
+
const $llmToolsRegister = new $Register('llm_execution_tools_constructors');
|
|
43766
|
+
// TODO: [®] DRY Register logic
|
|
43767
|
+
|
|
43101
43768
|
/**
|
|
43102
43769
|
* Takes stable snapshots of both LLM provider registers.
|
|
43103
43770
|
*
|
|
43104
|
-
* @private
|
|
43771
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43105
43772
|
*/
|
|
43106
43773
|
function getRegisteredLlmToolRegisters() {
|
|
43107
43774
|
return {
|
|
@@ -43109,62 +43776,30 @@ function getRegisteredLlmToolRegisters() {
|
|
|
43109
43776
|
registeredTools: $llmToolsRegister.list(),
|
|
43110
43777
|
};
|
|
43111
43778
|
}
|
|
43112
|
-
|
|
43113
|
-
* Lists provider entries enriched with installation and configuration state.
|
|
43114
|
-
*
|
|
43115
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43116
|
-
*/
|
|
43117
|
-
function listRegisteredLlmToolStatuses({ registeredMetadata, registeredTools }, env) {
|
|
43118
|
-
return listRegisteredLlmToolEntries(registeredMetadata, registeredTools).map((registeredLlmToolEntry) => createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env }));
|
|
43119
|
-
}
|
|
43120
|
-
/**
|
|
43121
|
-
* Merges provider entries from the metadata and constructor registers.
|
|
43122
|
-
*
|
|
43123
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43124
|
-
*/
|
|
43125
|
-
function listRegisteredLlmToolEntries(registeredMetadata, registeredTools) {
|
|
43126
|
-
const registeredLlmToolEntries = new Map();
|
|
43127
|
-
for (const { title, packageName, className, envVariables } of registeredMetadata) {
|
|
43128
|
-
addRegisteredLlmToolEntry(registeredLlmToolEntries, { title, packageName, className, envVariables });
|
|
43129
|
-
}
|
|
43130
|
-
for (const { packageName, className } of registeredTools) {
|
|
43131
|
-
addRegisteredLlmToolEntry(registeredLlmToolEntries, { packageName, className });
|
|
43132
|
-
}
|
|
43133
|
-
return [...registeredLlmToolEntries.values()];
|
|
43134
|
-
}
|
|
43135
|
-
/**
|
|
43136
|
-
* Adds a provider entry only when the provider is not already present.
|
|
43137
|
-
*
|
|
43138
|
-
* @private internal function of `$registeredLlmToolsMessage`
|
|
43139
|
-
*/
|
|
43140
|
-
function addRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43141
|
-
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43142
|
-
if (registeredLlmToolEntries.has(registeredLlmToolEntryKey)) {
|
|
43143
|
-
return;
|
|
43144
|
-
}
|
|
43145
|
-
registeredLlmToolEntries.set(registeredLlmToolEntryKey, registeredLlmToolEntry);
|
|
43146
|
-
}
|
|
43779
|
+
|
|
43147
43780
|
/**
|
|
43148
43781
|
* Creates a deduplication key for a provider entry.
|
|
43149
43782
|
*
|
|
43150
|
-
* @private
|
|
43783
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43151
43784
|
*/
|
|
43152
43785
|
function createRegisteredLlmToolEntryKey({ packageName, className }) {
|
|
43153
43786
|
return `${packageName}::${className}`;
|
|
43154
43787
|
}
|
|
43788
|
+
|
|
43155
43789
|
/**
|
|
43156
43790
|
* Checks whether the given provider entry already exists in the target register list.
|
|
43157
43791
|
*
|
|
43158
|
-
* @private
|
|
43792
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43159
43793
|
*/
|
|
43160
43794
|
function hasRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43161
43795
|
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43162
43796
|
return registeredLlmToolEntries.some((listedRegisteredLlmToolEntry) => createRegisteredLlmToolEntryKey(listedRegisteredLlmToolEntry) === registeredLlmToolEntryKey);
|
|
43163
43797
|
}
|
|
43798
|
+
|
|
43164
43799
|
/**
|
|
43165
43800
|
* Builds the runtime status for one provider entry.
|
|
43166
43801
|
*
|
|
43167
|
-
* @private
|
|
43802
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43168
43803
|
*/
|
|
43169
43804
|
function createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env, }) {
|
|
43170
43805
|
const availabilityStatus = createRegisteredLlmToolAvailabilityStatus(registeredLlmToolEntry, registeredMetadata, registeredTools);
|
|
@@ -43178,7 +43813,7 @@ function createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetad
|
|
|
43178
43813
|
/**
|
|
43179
43814
|
* Resolves whether the provider has metadata and a registered constructor.
|
|
43180
43815
|
*
|
|
43181
|
-
* @private
|
|
43816
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43182
43817
|
*/
|
|
43183
43818
|
function createRegisteredLlmToolAvailabilityStatus(registeredLlmToolEntry, registeredMetadata, registeredTools) {
|
|
43184
43819
|
return {
|
|
@@ -43189,7 +43824,7 @@ function createRegisteredLlmToolAvailabilityStatus(registeredLlmToolEntry, regis
|
|
|
43189
43824
|
/**
|
|
43190
43825
|
* Resolves whether the provider has enough environment variables to be configured.
|
|
43191
43826
|
*
|
|
43192
|
-
* @private
|
|
43827
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43193
43828
|
*/
|
|
43194
43829
|
function createRegisteredLlmToolConfigurationStatus({ envVariables }, env) {
|
|
43195
43830
|
return {
|
|
@@ -43200,7 +43835,7 @@ function createRegisteredLlmToolConfigurationStatus({ envVariables }, env) {
|
|
|
43200
43835
|
/**
|
|
43201
43836
|
* Checks whether all required environment variables are present for a provider.
|
|
43202
43837
|
*
|
|
43203
|
-
* @private
|
|
43838
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43204
43839
|
*/
|
|
43205
43840
|
function isRegisteredLlmToolFullyConfigured(envVariables, env) {
|
|
43206
43841
|
if (envVariables === undefined || envVariables === null) {
|
|
@@ -43211,7 +43846,7 @@ function isRegisteredLlmToolFullyConfigured(envVariables, env) {
|
|
|
43211
43846
|
/**
|
|
43212
43847
|
* Checks whether at least one required environment variable is present for a provider.
|
|
43213
43848
|
*
|
|
43214
|
-
* @private
|
|
43849
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43215
43850
|
*/
|
|
43216
43851
|
function isRegisteredLlmToolPartiallyConfigured(envVariables, env) {
|
|
43217
43852
|
if (envVariables === undefined || envVariables === null) {
|
|
@@ -43219,109 +43854,128 @@ function isRegisteredLlmToolPartiallyConfigured(envVariables, env) {
|
|
|
43219
43854
|
}
|
|
43220
43855
|
return envVariables.some((envVariableName) => env[envVariableName] !== undefined);
|
|
43221
43856
|
}
|
|
43857
|
+
|
|
43222
43858
|
/**
|
|
43223
|
-
*
|
|
43859
|
+
* Merges provider entries from the metadata and constructor registers.
|
|
43224
43860
|
*
|
|
43225
|
-
* @private
|
|
43861
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43226
43862
|
*/
|
|
43227
|
-
function
|
|
43228
|
-
|
|
43229
|
-
|
|
43230
|
-
|
|
43231
|
-
|
|
43232
|
-
|
|
43863
|
+
function listRegisteredLlmToolEntries(registeredMetadata, registeredTools) {
|
|
43864
|
+
const registeredLlmToolEntries = new Map();
|
|
43865
|
+
for (const { title, packageName, className, envVariables } of registeredMetadata) {
|
|
43866
|
+
addRegisteredLlmToolEntry(registeredLlmToolEntries, { title, packageName, className, envVariables });
|
|
43867
|
+
}
|
|
43868
|
+
for (const { packageName, className } of registeredTools) {
|
|
43869
|
+
addRegisteredLlmToolEntry(registeredLlmToolEntries, { packageName, className });
|
|
43870
|
+
}
|
|
43871
|
+
return [...registeredLlmToolEntries.values()];
|
|
43233
43872
|
}
|
|
43234
43873
|
/**
|
|
43235
|
-
*
|
|
43874
|
+
* Adds a provider entry only when the provider is not already present.
|
|
43236
43875
|
*
|
|
43237
|
-
* @private
|
|
43876
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43238
43877
|
*/
|
|
43239
|
-
function
|
|
43240
|
-
|
|
43241
|
-
|
|
43242
|
-
|
|
43243
|
-
|
|
43244
|
-
|
|
43245
|
-
${block(renderRelevantEnvironmentVariables(env, llmToolStatuses))}
|
|
43246
|
-
|
|
43247
|
-
Available LLM providers are:
|
|
43248
|
-
${block(renderAvailableProviders(llmToolStatuses, env, isRunningInNode))}
|
|
43249
|
-
`);
|
|
43878
|
+
function addRegisteredLlmToolEntry(registeredLlmToolEntries, registeredLlmToolEntry) {
|
|
43879
|
+
const registeredLlmToolEntryKey = createRegisteredLlmToolEntryKey(registeredLlmToolEntry);
|
|
43880
|
+
if (registeredLlmToolEntries.has(registeredLlmToolEntryKey)) {
|
|
43881
|
+
return;
|
|
43882
|
+
}
|
|
43883
|
+
registeredLlmToolEntries.set(registeredLlmToolEntryKey, registeredLlmToolEntry);
|
|
43250
43884
|
}
|
|
43885
|
+
|
|
43251
43886
|
/**
|
|
43252
|
-
*
|
|
43887
|
+
* Lists provider entries enriched with installation and configuration state.
|
|
43253
43888
|
*
|
|
43254
|
-
* @private
|
|
43889
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43255
43890
|
*/
|
|
43256
|
-
function
|
|
43257
|
-
return
|
|
43258
|
-
.map((envVariableName) => `- \`${envVariableName}\``)
|
|
43259
|
-
.join('\n');
|
|
43891
|
+
function listRegisteredLlmToolStatuses({ registeredMetadata, registeredTools }, env) {
|
|
43892
|
+
return listRegisteredLlmToolEntries(registeredMetadata, registeredTools).map((registeredLlmToolEntry) => createRegisteredLlmToolStatus({ registeredLlmToolEntry, registeredMetadata, registeredTools, env }));
|
|
43260
43893
|
}
|
|
43894
|
+
|
|
43261
43895
|
/**
|
|
43262
|
-
*
|
|
43896
|
+
* Collects all state needed to render the provider summary.
|
|
43263
43897
|
*
|
|
43264
|
-
* @private
|
|
43898
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43265
43899
|
*/
|
|
43266
|
-
function
|
|
43267
|
-
|
|
43900
|
+
function createRegisteredLlmToolsMessageContext() {
|
|
43901
|
+
const isRunningInNode = $isRunningInNode();
|
|
43902
|
+
const env = getAvailableRegisteredLlmToolsEnvironmentVariables(isRunningInNode);
|
|
43903
|
+
const registeredLlmToolRegisters = getRegisteredLlmToolRegisters();
|
|
43904
|
+
return {
|
|
43905
|
+
env,
|
|
43906
|
+
llmToolStatuses: listRegisteredLlmToolStatuses(registeredLlmToolRegisters, env),
|
|
43907
|
+
usedEnvMessage: USED_ENV_FILENAME.createMessage(),
|
|
43908
|
+
isRunningInNode,
|
|
43909
|
+
};
|
|
43268
43910
|
}
|
|
43911
|
+
|
|
43269
43912
|
/**
|
|
43270
|
-
* Renders
|
|
43913
|
+
* Renders the fallback message for environments with no registered providers.
|
|
43271
43914
|
*
|
|
43272
|
-
* @private
|
|
43915
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43273
43916
|
*/
|
|
43274
|
-
function
|
|
43275
|
-
return
|
|
43276
|
-
|
|
43277
|
-
|
|
43917
|
+
function renderNoRegisteredLlmToolsMessage(usedEnvMessage) {
|
|
43918
|
+
return spaceTrim$1((block) => `
|
|
43919
|
+
No LLM providers are available.
|
|
43920
|
+
|
|
43921
|
+
${block(usedEnvMessage)}
|
|
43922
|
+
`);
|
|
43278
43923
|
}
|
|
43924
|
+
|
|
43279
43925
|
/**
|
|
43280
|
-
*
|
|
43926
|
+
* Creates the configuration-status sentence for one provider.
|
|
43281
43927
|
*
|
|
43282
|
-
* @private
|
|
43928
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43283
43929
|
*/
|
|
43284
|
-
function
|
|
43285
|
-
|
|
43286
|
-
|
|
43287
|
-
|
|
43930
|
+
function createRegisteredLlmToolConfigurationStatusMessage({ envVariables, isFullyConfigured, isPartiallyConfigured }, env) {
|
|
43931
|
+
if (isFullyConfigured) {
|
|
43932
|
+
return `Configured`;
|
|
43933
|
+
}
|
|
43934
|
+
if (isPartiallyConfigured) {
|
|
43935
|
+
return createPartiallyConfiguredStatusMessage(envVariables, env);
|
|
43936
|
+
}
|
|
43937
|
+
if (envVariables !== null) {
|
|
43938
|
+
return createNotConfiguredStatusMessage(envVariables);
|
|
43288
43939
|
}
|
|
43289
|
-
return
|
|
43940
|
+
return `Not configured`;
|
|
43941
|
+
// <- Note: Can not be configured via environment variables
|
|
43290
43942
|
}
|
|
43291
43943
|
/**
|
|
43292
|
-
* Creates the
|
|
43944
|
+
* Creates the partial-configuration sentence including missing variables.
|
|
43293
43945
|
*
|
|
43294
|
-
* @private
|
|
43946
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43295
43947
|
*/
|
|
43296
|
-
function
|
|
43297
|
-
|
|
43298
|
-
const providerStatusMessages = createProviderStatusMessages(llmToolStatus, env);
|
|
43299
|
-
return spaceTrim$1(`
|
|
43300
|
-
${index + 1}) **${title}** \`${className}\` from \`${packageName}\`
|
|
43301
|
-
${providerStatusMessages.join('; ')}
|
|
43302
|
-
`);
|
|
43948
|
+
function createPartiallyConfiguredStatusMessage(envVariables, env) {
|
|
43949
|
+
return `Partially confugured, missing ${listMissingEnvironmentVariables(envVariables, env).join(' + ')}`;
|
|
43303
43950
|
}
|
|
43304
43951
|
/**
|
|
43305
|
-
* Creates the
|
|
43952
|
+
* Creates the not-configured sentence including the expected environment variables.
|
|
43306
43953
|
*
|
|
43307
|
-
* @private
|
|
43954
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43308
43955
|
*/
|
|
43309
|
-
function
|
|
43310
|
-
return
|
|
43956
|
+
function createNotConfiguredStatusMessage(envVariables) {
|
|
43957
|
+
return `Not configured, to configure set env ${envVariables === null || envVariables === void 0 ? void 0 : envVariables.join(' + ')}`;
|
|
43958
|
+
}
|
|
43959
|
+
/**
|
|
43960
|
+
* Lists environment variables that are required but currently missing.
|
|
43961
|
+
*
|
|
43962
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43963
|
+
*/
|
|
43964
|
+
function listMissingEnvironmentVariables(envVariables, env) {
|
|
43965
|
+
return (envVariables === null || envVariables === void 0 ? void 0 : envVariables.filter((envVariable) => env[envVariable] === undefined)) || [];
|
|
43311
43966
|
}
|
|
43967
|
+
|
|
43312
43968
|
/**
|
|
43313
43969
|
* Creates the installation-status sentence for one provider.
|
|
43314
43970
|
*
|
|
43315
|
-
* @private
|
|
43971
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43316
43972
|
*/
|
|
43317
|
-
function
|
|
43318
|
-
const installationStatusKey =
|
|
43973
|
+
function createRegisteredLlmToolInstallationStatusMessage({ isMetadataAvailable, isInstalled, }) {
|
|
43974
|
+
const installationStatusKey = createRegisteredLlmToolInstallationStatusKey(isMetadataAvailable, isInstalled);
|
|
43319
43975
|
switch (installationStatusKey) {
|
|
43320
43976
|
case 'missing-metadata-and-installation':
|
|
43321
|
-
// TODO: [�][�] Maybe do allow to do auto-install if package not registered and not found
|
|
43322
43977
|
return `Not installed and no metadata, looks like a unexpected behavior`;
|
|
43323
43978
|
case 'metadata-without-installation':
|
|
43324
|
-
// TODO: [�][�]
|
|
43325
43979
|
return `Not installed`;
|
|
43326
43980
|
case 'installation-without-metadata':
|
|
43327
43981
|
return `No metadata but installed, looks like a unexpected behavior`;
|
|
@@ -43334,9 +43988,9 @@ function createInstallationStatusMessage({ isMetadataAvailable, isInstalled, })
|
|
|
43334
43988
|
/**
|
|
43335
43989
|
* Creates a stable installation-state key from metadata and constructor availability.
|
|
43336
43990
|
*
|
|
43337
|
-
* @private
|
|
43991
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43338
43992
|
*/
|
|
43339
|
-
function
|
|
43993
|
+
function createRegisteredLlmToolInstallationStatusKey(isMetadataAvailable, isInstalled) {
|
|
43340
43994
|
if (!isMetadataAvailable && !isInstalled) {
|
|
43341
43995
|
return 'missing-metadata-and-installation';
|
|
43342
43996
|
}
|
|
@@ -43351,54 +44005,59 @@ function createInstallationStatusKey(isMetadataAvailable, isInstalled) {
|
|
|
43351
44005
|
}
|
|
43352
44006
|
return 'unknown';
|
|
43353
44007
|
}
|
|
44008
|
+
|
|
43354
44009
|
/**
|
|
43355
|
-
*
|
|
44010
|
+
* Renders all provider lines in the status summary.
|
|
43356
44011
|
*
|
|
43357
|
-
* @private
|
|
44012
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43358
44013
|
*/
|
|
43359
|
-
function
|
|
43360
|
-
|
|
43361
|
-
|
|
43362
|
-
|
|
43363
|
-
if (isPartiallyConfigured) {
|
|
43364
|
-
return createPartiallyConfiguredStatusMessage(envVariables, env);
|
|
43365
|
-
}
|
|
43366
|
-
if (envVariables !== null) {
|
|
43367
|
-
return createNotConfiguredStatusMessage(envVariables);
|
|
43368
|
-
}
|
|
43369
|
-
return `Not configured`;
|
|
43370
|
-
// <- Note: Can not be configured via environment variables
|
|
44014
|
+
function renderAvailableRegisteredLlmTools(llmToolStatuses, env, isRunningInNode) {
|
|
44015
|
+
return llmToolStatuses
|
|
44016
|
+
.map((llmToolStatus, index) => renderAvailableRegisteredLlmTool(llmToolStatus, index, env, isRunningInNode))
|
|
44017
|
+
.join('\n');
|
|
43371
44018
|
}
|
|
43372
44019
|
/**
|
|
43373
|
-
*
|
|
44020
|
+
* Renders one provider line in the status summary.
|
|
43374
44021
|
*
|
|
43375
|
-
* @private
|
|
44022
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43376
44023
|
*/
|
|
43377
|
-
function
|
|
43378
|
-
|
|
44024
|
+
function renderAvailableRegisteredLlmTool(llmToolStatus, index, env, isRunningInNode) {
|
|
44025
|
+
const providerMessage = createAvailableRegisteredLlmToolMessage(llmToolStatus, index, env);
|
|
44026
|
+
if (!isRunningInNode) {
|
|
44027
|
+
return providerMessage;
|
|
44028
|
+
}
|
|
44029
|
+
return colorizeAvailableRegisteredLlmToolMessage(providerMessage, llmToolStatus);
|
|
43379
44030
|
}
|
|
43380
44031
|
/**
|
|
43381
|
-
* Creates the
|
|
44032
|
+
* Creates the plain-text provider line before optional colorization.
|
|
43382
44033
|
*
|
|
43383
|
-
* @private
|
|
44034
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43384
44035
|
*/
|
|
43385
|
-
function
|
|
43386
|
-
|
|
44036
|
+
function createAvailableRegisteredLlmToolMessage(llmToolStatus, index, env) {
|
|
44037
|
+
const { title, packageName, className } = llmToolStatus;
|
|
44038
|
+
const providerStatusMessages = createRegisteredLlmToolStatusMessages(llmToolStatus, env);
|
|
44039
|
+
return spaceTrim$1(`
|
|
44040
|
+
${index + 1}) **${title}** \`${className}\` from \`${packageName}\`
|
|
44041
|
+
${providerStatusMessages.join('; ')}
|
|
44042
|
+
`);
|
|
43387
44043
|
}
|
|
43388
44044
|
/**
|
|
43389
|
-
*
|
|
44045
|
+
* Creates the install and configuration fragments for one provider line.
|
|
43390
44046
|
*
|
|
43391
|
-
* @private
|
|
44047
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43392
44048
|
*/
|
|
43393
|
-
function
|
|
43394
|
-
return
|
|
44049
|
+
function createRegisteredLlmToolStatusMessages(llmToolStatus, env) {
|
|
44050
|
+
return [
|
|
44051
|
+
createRegisteredLlmToolInstallationStatusMessage(llmToolStatus),
|
|
44052
|
+
createRegisteredLlmToolConfigurationStatusMessage(llmToolStatus, env),
|
|
44053
|
+
];
|
|
43395
44054
|
}
|
|
43396
44055
|
/**
|
|
43397
44056
|
* Applies the same terminal coloring rules as the original summary renderer.
|
|
43398
44057
|
*
|
|
43399
|
-
* @private
|
|
44058
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43400
44059
|
*/
|
|
43401
|
-
function
|
|
44060
|
+
function colorizeAvailableRegisteredLlmToolMessage(providerMessage, { isInstalled, isFullyConfigured, isPartiallyConfigured }) {
|
|
43402
44061
|
if (isInstalled && isFullyConfigured) {
|
|
43403
44062
|
return colors.green(providerMessage);
|
|
43404
44063
|
}
|
|
@@ -43407,18 +44066,67 @@ function colorizeAvailableProviderMessage(providerMessage, { isInstalled, isFull
|
|
|
43407
44066
|
}
|
|
43408
44067
|
return colors.gray(providerMessage);
|
|
43409
44068
|
}
|
|
44069
|
+
|
|
43410
44070
|
/**
|
|
43411
|
-
*
|
|
44071
|
+
* Renders the list of environment variables used by at least one registered provider.
|
|
43412
44072
|
*
|
|
43413
|
-
* @private
|
|
44073
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
43414
44074
|
*/
|
|
43415
|
-
function
|
|
43416
|
-
return
|
|
43417
|
-
|
|
43418
|
-
|
|
43419
|
-
|
|
43420
|
-
|
|
43421
|
-
|
|
44075
|
+
function renderRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses) {
|
|
44076
|
+
return listRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses)
|
|
44077
|
+
.map((envVariableName) => `- \`${envVariableName}\``)
|
|
44078
|
+
.join('\n');
|
|
44079
|
+
}
|
|
44080
|
+
/**
|
|
44081
|
+
* Lists environment variables that are both present and used by at least one provider.
|
|
44082
|
+
*
|
|
44083
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
44084
|
+
*/
|
|
44085
|
+
function listRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses) {
|
|
44086
|
+
return Object.keys(env).filter((envVariableName) => llmToolStatuses.some(({ envVariables }) => envVariables === null || envVariables === void 0 ? void 0 : envVariables.includes(envVariableName)));
|
|
44087
|
+
}
|
|
44088
|
+
|
|
44089
|
+
/**
|
|
44090
|
+
* Renders the full provider status summary.
|
|
44091
|
+
*
|
|
44092
|
+
* @private function of `$registeredLlmToolsMessage`
|
|
44093
|
+
*/
|
|
44094
|
+
function renderRegisteredLlmToolsMessage({ env, llmToolStatuses, usedEnvMessage, isRunningInNode, }) {
|
|
44095
|
+
return spaceTrim$1((block) => `
|
|
44096
|
+
|
|
44097
|
+
${block(usedEnvMessage)}
|
|
44098
|
+
|
|
44099
|
+
Relevant environment variables:
|
|
44100
|
+
${block(renderRelevantRegisteredLlmToolsEnvironmentVariables(env, llmToolStatuses))}
|
|
44101
|
+
|
|
44102
|
+
Available LLM providers are:
|
|
44103
|
+
${block(renderAvailableRegisteredLlmTools(llmToolStatuses, env, isRunningInNode))}
|
|
44104
|
+
`);
|
|
44105
|
+
}
|
|
44106
|
+
|
|
44107
|
+
/**
|
|
44108
|
+
* Pass the `.env` file which was used to configure LLM tools
|
|
44109
|
+
*
|
|
44110
|
+
* Note: `$` is used to indicate that this variable is making side effect
|
|
44111
|
+
*
|
|
44112
|
+
* @private internal log of `$provideLlmToolsConfigurationFromEnv` and `$registeredLlmToolsMessage`
|
|
44113
|
+
*/
|
|
44114
|
+
function $setUsedEnvFilename(filepath) {
|
|
44115
|
+
USED_ENV_FILENAME.set(filepath);
|
|
44116
|
+
}
|
|
44117
|
+
/**
|
|
44118
|
+
* Creates a message with all registered LLM tools
|
|
44119
|
+
*
|
|
44120
|
+
* Note: This function is used to create a (error) message when there is no constructor for some LLM provider
|
|
44121
|
+
*
|
|
44122
|
+
* @private internal function of `createLlmToolsFromConfiguration` and `$provideLlmToolsFromEnv`
|
|
44123
|
+
*/
|
|
44124
|
+
function $registeredLlmToolsMessage() {
|
|
44125
|
+
const registeredLlmToolsMessageContext = createRegisteredLlmToolsMessageContext();
|
|
44126
|
+
if (registeredLlmToolsMessageContext.llmToolStatuses.length === 0) {
|
|
44127
|
+
return renderNoRegisteredLlmToolsMessage(registeredLlmToolsMessageContext.usedEnvMessage);
|
|
44128
|
+
}
|
|
44129
|
+
return renderRegisteredLlmToolsMessage(registeredLlmToolsMessageContext);
|
|
43422
44130
|
}
|
|
43423
44131
|
// TODO: [®] DRY Register logic
|
|
43424
44132
|
// TODO: [🧠][⚛] Maybe pass env as argument
|