@promptbook/cli 0.114.0-13 → 0.114.0-18
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/apps/agents-server/next.config.ts +6 -0
- package/apps/agents-server/src/app/admin/_components/AdminFilterFields.tsx +84 -0
- package/apps/agents-server/src/app/admin/_components/AdminMetricCard.tsx +36 -0
- package/apps/agents-server/src/app/admin/_components/AdminTaskManagerTabs.tsx +97 -0
- package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerClient.tsx +103 -0
- package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerEditDialog.tsx +232 -0
- package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerFiltersCard.tsx +195 -0
- package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerRow.tsx +189 -0
- package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerSummaryMetrics.tsx +60 -0
- package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerTableCard.tsx +147 -0
- package/apps/agents-server/src/app/admin/planned-messages/page.tsx +17 -0
- package/apps/agents-server/src/app/admin/planned-messages/plannedMessageEditForm.ts +186 -0
- package/apps/agents-server/src/app/admin/planned-messages/plannedMessageManagerDialogs.ts +46 -0
- package/apps/agents-server/src/app/admin/planned-messages/plannedMessageManagerPresentation.tsx +188 -0
- package/apps/agents-server/src/app/admin/planned-messages/resolvePlannedMessageSortValue.ts +115 -0
- package/apps/agents-server/src/app/admin/planned-messages/usePlannedMessageManagerData.ts +116 -0
- package/apps/agents-server/src/app/admin/planned-messages/usePlannedMessageManagerState.ts +289 -0
- package/apps/agents-server/src/app/admin/task-manager/TaskManagerClient.tsx +7 -2
- package/apps/agents-server/src/app/admin/task-manager/TaskManagerFiltersCard.tsx +7 -73
- package/apps/agents-server/src/app/admin/task-manager/TaskManagerSummaryMetrics.tsx +5 -30
- package/apps/agents-server/src/app/admin/task-manager/[taskId]/TaskManagerTaskDetailClient.tsx +1 -1
- package/apps/agents-server/src/app/agents/[agentName]/api/book/reference-diagnostics/route.ts +30 -7
- package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +1 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/book/test.http +3 -3
- package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorMissingReferences.tsx +106 -12
- package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorWrapper.tsx +3 -0
- package/apps/agents-server/src/app/agents/[agentName]/book/useBookEditorDiagnostics.ts +12 -0
- package/apps/agents-server/src/app/agents/[agentName]/book/useBookEditorWrapper.tsx +2 -0
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentGoalChatPlannedMessages.tsx +46 -3
- package/apps/agents-server/src/app/api/admin/default-agents/reinstate/route.ts +5 -1
- package/apps/agents-server/src/app/api/admin/planned-messages/[timeoutId]/route.ts +80 -0
- package/apps/agents-server/src/app/api/admin/planned-messages/route.ts +19 -0
- package/apps/agents-server/src/app/api/internal/agent-goal-chat-planned-messages/route.ts +30 -2
- package/apps/agents-server/src/components/DefaultAgents/ReinstateBundledAgentsButton.tsx +7 -0
- package/apps/agents-server/src/components/DefaultAgents/coreAgentsAdminRoute.ts +6 -0
- package/apps/agents-server/src/components/Header/buildHeaderSystemMenuItems.ts +7 -0
- package/apps/agents-server/src/components/Homepage/DefaultAgentsStatusNotice.tsx +1 -7
- package/apps/agents-server/src/database/migrations/2026-08-1800-user-chat-timeout-schedule.sql +11 -0
- package/apps/agents-server/src/instrumentation-node.ts +18 -0
- package/apps/agents-server/src/languages/ServerTranslationKeys.ts +4 -0
- package/apps/agents-server/src/languages/translations/czech.yaml +4 -0
- package/apps/agents-server/src/languages/translations/english.yaml +4 -0
- package/apps/agents-server/src/tools/agentGoalChatTimeoutToolFunctions.ts +62 -15
- package/apps/agents-server/src/tools/agentGoalChatTimeoutTools.ts +63 -9
- package/apps/agents-server/src/utils/adminEntityLookups/loadAgentNamesByPermanentId.ts +45 -0
- package/apps/agents-server/src/utils/adminEntityLookups/loadUsernamesByUserId.ts +36 -0
- package/apps/agents-server/src/utils/adminEntityLookups.ts +2 -0
- package/apps/agents-server/src/utils/agentGoalChat/agentGoalChatPlannedMessageActions.ts +299 -52
- package/apps/agents-server/src/utils/agentGoalChat/createAgentGoalChatNoteContent.ts +45 -17
- package/apps/agents-server/src/utils/agentGoalChat.ts +1 -0
- package/apps/agents-server/src/utils/agentProjects/agentProjectIdentity.ts +46 -0
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeAutostartScheduler.ts +162 -0
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeDesiredState.ts +252 -0
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeDisplay.ts +6 -3
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeDomains.ts +2 -44
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimePaths.ts +25 -0
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimePm2.ts +4 -3
- package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeRegistry.ts +77 -24
- package/apps/agents-server/src/utils/agentProjects/agentProjectStateMutationQueue.ts +58 -0
- package/apps/agents-server/src/utils/agentProjects/listAllLocalAgentProjectIdentities.ts +48 -0
- package/apps/agents-server/src/utils/agentProjects/resolveAgentProjectRuntimeEnvironmentFlag.ts +23 -0
- package/apps/agents-server/src/utils/agentProjects/resolveAgentProjectRuntimeStatus.ts +73 -0
- package/apps/agents-server/src/utils/agentProjects/startDefaultAgentProjectRuntimes.ts +110 -0
- package/apps/agents-server/src/utils/agentReferenceResolver/MissingCoreAgentRecovery.ts +19 -0
- package/apps/agents-server/src/utils/agentReferenceResolver/bookScopedAgentReferences.ts +7 -0
- package/apps/agents-server/src/utils/agentReferenceResolver/createAgentInheritanceDiagnostics.ts +457 -0
- package/apps/agents-server/src/utils/agentReferenceResolver/createUnresolvedAgentReferenceDiagnostics.ts +27 -0
- package/apps/agents-server/src/utils/agentReferenceResolver/resolveCoreAgentAwareMissingReferences.ts +156 -0
- package/apps/agents-server/src/utils/chatMessageChips/createAnsweredMessageChipToolCalls.ts +15 -3
- package/apps/agents-server/src/utils/chatMessageChips/createPlannedMessageChipToolCalls.ts +8 -3
- package/apps/agents-server/src/utils/chatMessageChips/createTouchedExternalSourceChipToolCalls.ts +39 -0
- package/apps/agents-server/src/utils/chatMessageChips/createTouchedProjectChipResult.ts +45 -0
- package/apps/agents-server/src/utils/chatMessageChips/createTouchedProjectChipToolCalls.ts +58 -24
- package/apps/agents-server/src/utils/cronExpression/CronExpression.ts +63 -0
- package/apps/agents-server/src/utils/cronExpression/normalizeCronExpression.ts +34 -0
- package/apps/agents-server/src/utils/cronExpression/normalizeCronExpressionWhitespace.ts +11 -0
- package/apps/agents-server/src/utils/cronExpression/parseCronExpression.ts +41 -0
- package/apps/agents-server/src/utils/cronExpression/parseCronExpressionField.ts +140 -0
- package/apps/agents-server/src/utils/cronExpression/resolveNextCronRun.ts +100 -0
- package/apps/agents-server/src/utils/cronExpression/throwInvalidCronExpressionField.ts +20 -0
- package/apps/agents-server/src/utils/cronExpression.ts +10 -0
- package/apps/agents-server/src/utils/explicitFromCommitment.ts +130 -0
- package/apps/agents-server/src/utils/getAdminChatTasksResponse/getAdminChatTasks/loadAdminChatTaskFallbackData.ts +3 -77
- package/apps/agents-server/src/utils/localChatRunner/applyLocalAgentPlannedMessageCommands.ts +53 -4
- package/apps/agents-server/src/utils/localChatRunner/prepareLocalAgentPlannedMessagesSidecar.ts +15 -7
- package/apps/agents-server/src/utils/localChatRunner/processLocalUserChatJob.ts +8 -0
- package/apps/agents-server/src/utils/manGoOnboarding/manGoOnboardingAgentBooks.ts +5 -11
- package/apps/agents-server/src/utils/manGoOnboarding/manGoOnboardingAgentRuntime.ts +2 -2
- package/apps/agents-server/src/utils/managementApi/managementApiSchemas.ts +2 -2
- package/apps/agents-server/src/utils/plannedMessageManager/cancelManagedPlannedMessage.ts +35 -0
- package/apps/agents-server/src/utils/plannedMessageManager/collectPlannedMessageAgentOptions.ts +56 -0
- package/apps/agents-server/src/utils/plannedMessageManager/createPlannedMessageManagerCounters.ts +104 -0
- package/apps/agents-server/src/utils/plannedMessageManager/filterPlannedMessages.ts +191 -0
- package/apps/agents-server/src/utils/plannedMessageManager/getPlannedMessageManagerResponse.ts +55 -0
- package/apps/agents-server/src/utils/plannedMessageManager/isPlannedMessageStillPlanned.ts +18 -0
- package/apps/agents-server/src/utils/plannedMessageManager/loadPlannedMessageManagerRecord.ts +32 -0
- package/apps/agents-server/src/utils/plannedMessageManager/mapPlannedMessageManagerRecord.ts +73 -0
- package/apps/agents-server/src/utils/plannedMessageManager/parsePlannedMessageManagerUpdateRequest.ts +76 -0
- package/apps/agents-server/src/utils/plannedMessageManager/resolvePlannedMessageEndReason.ts +59 -0
- package/apps/agents-server/src/utils/plannedMessageManager/resolvePlannedMessageLifecycle.ts +99 -0
- package/apps/agents-server/src/utils/plannedMessageManager/resolvePlannedMessageRecurrenceKind.ts +40 -0
- package/apps/agents-server/src/utils/plannedMessageManager/updateManagedPlannedMessage.ts +121 -0
- package/apps/agents-server/src/utils/plannedMessagesAdmin.ts +200 -0
- package/apps/agents-server/src/utils/resolveInheritedAgentSource.ts +114 -95
- package/apps/agents-server/src/utils/userChatClient.ts +4 -0
- package/apps/agents-server/src/utils/userChatTimeout/UserChatTimeoutRecord.ts +37 -1
- package/apps/agents-server/src/utils/userChatTimeout/agentScopedTimeoutBulkActions.ts +11 -17
- package/apps/agents-server/src/utils/userChatTimeout/createTimeoutWakeUpMessage.ts +37 -13
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/PlannedMessageSchedule.ts +52 -0
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/hasPlannedMessageRecurrence.ts +13 -0
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/isPlannedMessageScheduleFinished.ts +30 -0
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/normalizePlannedMessageScheduleValues.ts +62 -0
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/parsePlannedMessageSchedule.ts +202 -0
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/resolvePlannedMessageDueAt.ts +121 -0
- package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule.ts +12 -0
- package/apps/agents-server/src/utils/userChatTimeout/setAgentScopedUserChatTimeoutPausedState.ts +66 -0
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/createUserChatTimeout.ts +76 -5
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/listAllUserChatTimeouts.ts +37 -0
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/mapUserChatTimeoutRow.ts +9 -0
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/repeatFiredUserChatTimeout.ts +19 -9
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/updateAgentScopedUserChatTimeout.ts +39 -6
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore.ts +1 -0
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutWorker.ts +110 -11
- package/apps/agents-server/src/utils/userChatTimeout.ts +16 -0
- package/apps/agents-server/src/utils/vpsSelfUpdate/vpsSelfUpdateCron.ts +23 -316
- package/apps/agents-server/tests/e2e/support/AgentManagementApi.ts +3 -3
- package/esm/index.es.js +951 -102
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-agent-messages/git/commitAgentProjectChanges.d.ts +15 -0
- package/esm/scripts/run-agent-messages/git/commitAnsweredMessageProjectChanges.d.ts +24 -0
- package/esm/scripts/run-agent-messages/git/ensureAgentProjectGitRepository.d.ts +20 -0
- package/esm/scripts/run-agent-messages/git/readAgentProjectCommitChange.d.ts +11 -0
- package/esm/scripts/run-agent-messages/git/runAgentProjectGitCommand.d.ts +29 -0
- package/esm/scripts/run-agent-messages/messages/buildAgentGoalChatPromptSection.d.ts +3 -3
- package/esm/scripts/run-agent-messages/messages/listAgentProjectDirectoryNames.d.ts +7 -0
- package/esm/scripts/run-agent-messages/messages/resolveAnsweredMessageTouches.d.ts +29 -0
- package/esm/scripts/run-codex-prompts/ping/pingCoderHarnessPeriodically.d.ts +22 -0
- package/esm/src/book-3.0/AgentMessageRunReport.d.ts +18 -0
- package/esm/src/book-3.0/AgentPlannedMessagesSidecar.d.ts +38 -5
- package/esm/src/book-3.0/describeAgentPlannedMessageSchedule.d.ts +31 -0
- package/esm/src/book-components/BookEditor/createDeprecatedCommitmentDiagnostics.browser.d.ts +1 -9
- package/esm/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.d.ts +28 -0
- package/esm/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.test.d.ts +1 -0
- package/esm/src/book-components/Chat/Chat/renderAgentProjectDiff.d.ts +13 -0
- package/esm/src/book-components/Chat/Chat/renderAgentProjectToolCallDetails.d.ts +16 -0
- package/esm/src/book-components/Chat/utils/agentProjectToolCall.d.ts +39 -0
- package/esm/src/book-components/Chat/utils/agentProjectToolCall.test.d.ts +1 -0
- package/esm/src/book-components/Chat/utils/externalSourceToolCall.d.ts +38 -0
- package/esm/src/book-components/Chat/utils/timeoutToolCallPresentation.d.ts +6 -0
- package/esm/src/cli/cli-commands/coder/waitOptions.d.ts +12 -0
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +15 -0
- package/esm/src/utils/agent-message-runtime/AgentMessageProjectChange.d.ts +76 -0
- package/esm/src/utils/agent-message-runtime/AgentMessageTouchedExternalSource.d.ts +45 -0
- package/esm/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.d.ts +3 -0
- package/esm/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.d.ts +18 -0
- package/esm/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.test.d.ts +1 -0
- package/esm/src/utils/random/$generateBookBoilerplate.test.d.ts +1 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/book-2.0/agent-source/string_book.ts +1 -1
- package/src/book-2.0/book-language-documentation/czechBookLanguageManualDictionary.ts +6 -1
- package/src/book-2.0/book-language-documentation/englishBookLanguageManualDictionary.ts +6 -1
- package/src/book-3.0/AgentMessageRunReport.ts +59 -0
- package/src/book-3.0/AgentPlannedMessagesSidecar.ts +64 -9
- package/src/book-3.0/describeAgentPlannedMessageSchedule.ts +94 -0
- package/src/book-components/BookEditor/BookEditorMonaco.tsx +2 -0
- package/src/book-components/BookEditor/createDeprecatedCommitmentDiagnostics.browser.ts +3 -11
- package/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.ts +71 -0
- package/src/book-components/Chat/Chat/Chat.module.css +165 -18
- package/src/book-components/Chat/Chat/ChatMessageMap.tsx +0 -1
- package/src/book-components/Chat/Chat/renderAgentProjectDiff.tsx +85 -0
- package/src/book-components/Chat/Chat/renderAgentProjectToolCallDetails.tsx +206 -0
- package/src/book-components/Chat/Chat/renderToolCallDetails.tsx +8 -0
- package/src/book-components/Chat/MarkdownContent/MarkdownContent.tsx +2 -3
- package/src/book-components/Chat/utils/agentProjectToolCall.ts +82 -5
- package/src/book-components/Chat/utils/externalSourceToolCall.ts +65 -0
- package/src/book-components/Chat/utils/getToolCallChipletInfo.ts +36 -0
- package/src/book-components/Chat/utils/renderMarkdown.ts +3 -10
- package/src/book-components/Chat/utils/timeoutToolCallPresentation.ts +12 -1
- package/src/cli/cli-commands/coder/ping.ts +35 -9
- package/src/cli/cli-commands/coder/waitOptions.ts +33 -0
- package/src/cli/cli-commands/common/harness/$applyHarnessInstallationStatus.ts +3 -1
- package/src/cli/cli-commands/common/harness/$checkHarnessInstallation.ts +3 -1
- package/src/cli/cli-commands/common/harnessUpdateCliOptions.ts +1 -4
- package/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.ts +47 -3
- package/src/commands/FORMAT/formatCommandParser.ts +4 -2
- package/src/commitments/FROM/FROM.ts +13 -0
- package/src/other/templates/getTemplatesPipelineCollection.ts +819 -751
- package/src/utils/agent-message-runtime/AgentMessageProjectChange.ts +183 -0
- package/src/utils/agent-message-runtime/AgentMessageTouchedExternalSource.ts +80 -0
- package/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.ts +3 -0
- package/src/utils/agent-message-runtime/resolveAgentMessageRuntimeActivity.ts +2 -4
- package/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.ts +341 -0
- package/src/utils/random/$generateBookBoilerplate.ts +1 -1
- package/src/version.ts +2 -2
- package/src/versions.txt +5 -0
- package/umd/index.umd.js +950 -101
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-agent-messages/git/commitAgentProjectChanges.d.ts +15 -0
- package/umd/scripts/run-agent-messages/git/commitAnsweredMessageProjectChanges.d.ts +24 -0
- package/umd/scripts/run-agent-messages/git/ensureAgentProjectGitRepository.d.ts +20 -0
- package/umd/scripts/run-agent-messages/git/readAgentProjectCommitChange.d.ts +11 -0
- package/umd/scripts/run-agent-messages/git/runAgentProjectGitCommand.d.ts +29 -0
- package/umd/scripts/run-agent-messages/messages/buildAgentGoalChatPromptSection.d.ts +3 -3
- package/umd/scripts/run-agent-messages/messages/listAgentProjectDirectoryNames.d.ts +7 -0
- package/umd/scripts/run-agent-messages/messages/resolveAnsweredMessageTouches.d.ts +29 -0
- package/umd/scripts/run-codex-prompts/ping/pingCoderHarnessPeriodically.d.ts +22 -0
- package/umd/src/book-3.0/AgentMessageRunReport.d.ts +18 -0
- package/umd/src/book-3.0/AgentPlannedMessagesSidecar.d.ts +38 -5
- package/umd/src/book-3.0/describeAgentPlannedMessageSchedule.d.ts +31 -0
- package/umd/src/book-components/BookEditor/createDeprecatedCommitmentDiagnostics.browser.d.ts +1 -9
- package/umd/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.d.ts +28 -0
- package/umd/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.test.d.ts +1 -0
- package/umd/src/book-components/Chat/Chat/renderAgentProjectDiff.d.ts +13 -0
- package/umd/src/book-components/Chat/Chat/renderAgentProjectToolCallDetails.d.ts +16 -0
- package/umd/src/book-components/Chat/utils/agentProjectToolCall.d.ts +39 -0
- package/umd/src/book-components/Chat/utils/agentProjectToolCall.test.d.ts +1 -0
- package/umd/src/book-components/Chat/utils/externalSourceToolCall.d.ts +38 -0
- package/umd/src/book-components/Chat/utils/timeoutToolCallPresentation.d.ts +6 -0
- package/umd/src/cli/cli-commands/coder/waitOptions.d.ts +12 -0
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +15 -0
- package/umd/src/utils/agent-message-runtime/AgentMessageProjectChange.d.ts +76 -0
- package/umd/src/utils/agent-message-runtime/AgentMessageTouchedExternalSource.d.ts +45 -0
- package/umd/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.d.ts +3 -0
- package/umd/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.d.ts +18 -0
- package/umd/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.test.d.ts +1 -0
- package/umd/src/utils/random/$generateBookBoilerplate.test.d.ts +1 -0
- package/umd/src/version.d.ts +1 -1
- package/apps/agents-server/src/app/admin/task-manager/TaskManagerScopeTabs.tsx +0 -74
- package/esm/scripts/run-agent-messages/messages/resolveTouchedAgentProjects.d.ts +0 -15
- package/umd/scripts/run-agent-messages/messages/resolveTouchedAgentProjects.d.ts +0 -15
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes one stored or untrusted total run count.
|
|
3
|
+
*
|
|
4
|
+
* @param value - Raw run-count limit.
|
|
5
|
+
* @returns Whole positive limit, or `null` when the planned message repeats without a count limit.
|
|
6
|
+
*
|
|
7
|
+
* @private function of `plannedMessageSchedule`
|
|
8
|
+
*/
|
|
9
|
+
export function normalizePlannedMessageMaxRunCount(value: unknown): number | null {
|
|
10
|
+
const maxRunCount = Number(value);
|
|
11
|
+
|
|
12
|
+
if (!Number.isFinite(maxRunCount) || maxRunCount < 1) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return Math.floor(maxRunCount);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Normalizes one stored or untrusted schedule boundary into an ISO timestamp.
|
|
21
|
+
*
|
|
22
|
+
* @param value - Raw date value.
|
|
23
|
+
* @returns ISO timestamp, or `null` when the value is not a usable date.
|
|
24
|
+
*
|
|
25
|
+
* @private function of `plannedMessageSchedule`
|
|
26
|
+
*/
|
|
27
|
+
export function normalizePlannedMessageDateIso(value: unknown): string | null {
|
|
28
|
+
if (value === null || value === undefined || value === '') {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (typeof value !== 'string' && typeof value !== 'number' && !(value instanceof Date)) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
37
|
+
|
|
38
|
+
if (Number.isNaN(date.getTime())) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return date.toISOString();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Normalizes one stored or untrusted cron expression without validating its fields.
|
|
47
|
+
*
|
|
48
|
+
* Stored expressions were already validated when they were planned, and mapping one database row must
|
|
49
|
+
* never throw, so the field syntax is checked only where a new schedule is accepted.
|
|
50
|
+
*
|
|
51
|
+
* @param value - Raw cron expression.
|
|
52
|
+
* @returns Trimmed expression, or `null` when there is none.
|
|
53
|
+
*
|
|
54
|
+
* @private function of `plannedMessageSchedule`
|
|
55
|
+
*/
|
|
56
|
+
export function normalizePlannedMessageCronExpression(value: unknown): string | null {
|
|
57
|
+
if (typeof value !== 'string') {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return value.trim() || null;
|
|
62
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { spaceTrim } from 'spacetrim';
|
|
2
|
+
import { ParseError } from '../../../../../../src/errors/ParseError';
|
|
3
|
+
import { normalizeCronExpression } from '../../cronExpression';
|
|
4
|
+
import { MINIMUM_PLANNED_MESSAGE_INTERVAL_MS, type PlannedMessageSchedule } from './PlannedMessageSchedule';
|
|
5
|
+
import { normalizePlannedMessageDateIso } from './normalizePlannedMessageScheduleValues';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Untrusted schedule fields of one planned message, as written by a model, a coding harness, or the
|
|
9
|
+
* internal runtime API.
|
|
10
|
+
*
|
|
11
|
+
* A missing field means "not requested", while an explicit `null` means "no such bound", which is what
|
|
12
|
+
* lets one update remove an ending date or a run-count limit.
|
|
13
|
+
*
|
|
14
|
+
* @private type of `plannedMessageSchedule`
|
|
15
|
+
*/
|
|
16
|
+
export type PlannedMessageScheduleInput = {
|
|
17
|
+
readonly milliseconds?: unknown;
|
|
18
|
+
readonly cronExpression?: unknown;
|
|
19
|
+
readonly startsAt?: unknown;
|
|
20
|
+
readonly endsAt?: unknown;
|
|
21
|
+
readonly maxRunCount?: unknown;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Parses one untrusted planned-message schedule.
|
|
26
|
+
*
|
|
27
|
+
* @param input - Schedule fields requested by an agent.
|
|
28
|
+
* @returns Validated recurrence rule.
|
|
29
|
+
*
|
|
30
|
+
* @private function of `plannedMessageSchedule`
|
|
31
|
+
*/
|
|
32
|
+
export function parsePlannedMessageSchedule(input: PlannedMessageScheduleInput): PlannedMessageSchedule {
|
|
33
|
+
const cronExpression = parsePlannedMessageCronExpression(input.cronExpression);
|
|
34
|
+
const recurrenceIntervalMs = parsePlannedMessageIntervalMs(input.milliseconds);
|
|
35
|
+
|
|
36
|
+
if (cronExpression !== null && recurrenceIntervalMs !== null) {
|
|
37
|
+
throw new ParseError(
|
|
38
|
+
spaceTrim(`
|
|
39
|
+
Invalid planned-message schedule.
|
|
40
|
+
|
|
41
|
+
- Use either \`cronExpression\` or \`milliseconds\`, **not both**.
|
|
42
|
+
`),
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const startsAt = parsePlannedMessageBoundaryDate(input.startsAt, 'startsAt');
|
|
47
|
+
const endsAt = parsePlannedMessageBoundaryDate(input.endsAt, 'endsAt');
|
|
48
|
+
|
|
49
|
+
if (startsAt !== null && endsAt !== null && Date.parse(endsAt) <= Date.parse(startsAt)) {
|
|
50
|
+
throw new ParseError(
|
|
51
|
+
spaceTrim(`
|
|
52
|
+
Invalid planned-message schedule.
|
|
53
|
+
|
|
54
|
+
- \`endsAt\` must be **after** \`startsAt\`.
|
|
55
|
+
`),
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (cronExpression === null && recurrenceIntervalMs === null && startsAt === null) {
|
|
60
|
+
throw new ParseError(
|
|
61
|
+
spaceTrim(`
|
|
62
|
+
Invalid planned-message schedule.
|
|
63
|
+
|
|
64
|
+
- Say when the planned message wakes you with \`cronExpression\`, \`milliseconds\`, or \`startsAt\`.
|
|
65
|
+
- Use \`maxRunCount\` and \`endsAt\` only to **bound** a schedule, never as the schedule itself.
|
|
66
|
+
`),
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
cronExpression,
|
|
72
|
+
recurrenceIntervalMs,
|
|
73
|
+
startsAt,
|
|
74
|
+
endsAt,
|
|
75
|
+
maxRunCount: parsePlannedMessageMaxRunCount(input.maxRunCount),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Parses one untrusted cron expression of a planned message.
|
|
81
|
+
*
|
|
82
|
+
* @param rawCronExpression - Untrusted cron expression.
|
|
83
|
+
* @returns Normalized expression, or `null` when none was requested.
|
|
84
|
+
*
|
|
85
|
+
* @private function of `parsePlannedMessageSchedule`
|
|
86
|
+
*/
|
|
87
|
+
function parsePlannedMessageCronExpression(rawCronExpression: unknown): string | null {
|
|
88
|
+
if (rawCronExpression === undefined || rawCronExpression === null || rawCronExpression === '') {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (typeof rawCronExpression !== 'string') {
|
|
93
|
+
throw new ParseError(
|
|
94
|
+
spaceTrim(`
|
|
95
|
+
Invalid planned-message \`cronExpression\`.
|
|
96
|
+
|
|
97
|
+
- Use a five-field cron string such as \`0 9 * * 1-5\`.
|
|
98
|
+
`),
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
return normalizeCronExpression(rawCronExpression);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
throw new ParseError(
|
|
106
|
+
spaceTrim(
|
|
107
|
+
(block) => `
|
|
108
|
+
Invalid planned-message \`cronExpression\`.
|
|
109
|
+
|
|
110
|
+
${block(error instanceof Error ? error.message : String(error))}
|
|
111
|
+
`,
|
|
112
|
+
),
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Parses one untrusted repeat interval of a planned message.
|
|
119
|
+
*
|
|
120
|
+
* @param rawMilliseconds - Untrusted interval in milliseconds.
|
|
121
|
+
* @returns Repeat interval in whole milliseconds, or `null` when none was requested.
|
|
122
|
+
*
|
|
123
|
+
* @private function of `parsePlannedMessageSchedule`
|
|
124
|
+
*/
|
|
125
|
+
function parsePlannedMessageIntervalMs(rawMilliseconds: unknown): number | null {
|
|
126
|
+
if (rawMilliseconds === undefined || rawMilliseconds === null) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const milliseconds = Number(rawMilliseconds);
|
|
131
|
+
|
|
132
|
+
if (!Number.isFinite(milliseconds) || milliseconds < MINIMUM_PLANNED_MESSAGE_INTERVAL_MS) {
|
|
133
|
+
throw new ParseError(
|
|
134
|
+
spaceTrim(`
|
|
135
|
+
Invalid planned-message interval.
|
|
136
|
+
|
|
137
|
+
- A planned message **repeats** at this interval until it is cancelled or bounded by \`maxRunCount\` or \`endsAt\`.
|
|
138
|
+
- \`milliseconds\` must be a number of at least \`${MINIMUM_PLANNED_MESSAGE_INTERVAL_MS}\`.
|
|
139
|
+
`),
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return Math.floor(milliseconds);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Parses one untrusted total run count of a planned message.
|
|
148
|
+
*
|
|
149
|
+
* @param rawMaxRunCount - Untrusted run-count limit.
|
|
150
|
+
* @returns Whole positive limit, or `null` when the planned message repeats without a count limit.
|
|
151
|
+
*
|
|
152
|
+
* @private function of `parsePlannedMessageSchedule`
|
|
153
|
+
*/
|
|
154
|
+
function parsePlannedMessageMaxRunCount(rawMaxRunCount: unknown): number | null {
|
|
155
|
+
if (rawMaxRunCount === undefined || rawMaxRunCount === null) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const maxRunCount = Number(rawMaxRunCount);
|
|
160
|
+
|
|
161
|
+
if (!Number.isInteger(maxRunCount) || maxRunCount < 1) {
|
|
162
|
+
throw new ParseError(
|
|
163
|
+
spaceTrim(`
|
|
164
|
+
Invalid planned-message \`maxRunCount\`.
|
|
165
|
+
|
|
166
|
+
- Use a whole number of at least \`1\`, which is **how many times in total** the planned message wakes you.
|
|
167
|
+
- Leave it out for a planned message that repeats until it is cancelled.
|
|
168
|
+
`),
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return maxRunCount;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Parses one untrusted starting or ending date of a planned message.
|
|
177
|
+
*
|
|
178
|
+
* @param rawDate - Untrusted date value.
|
|
179
|
+
* @param fieldName - Field name used in a detailed parse error.
|
|
180
|
+
* @returns ISO timestamp, or `null` when the boundary was not requested.
|
|
181
|
+
*
|
|
182
|
+
* @private function of `parsePlannedMessageSchedule`
|
|
183
|
+
*/
|
|
184
|
+
function parsePlannedMessageBoundaryDate(rawDate: unknown, fieldName: 'startsAt' | 'endsAt'): string | null {
|
|
185
|
+
if (rawDate === undefined || rawDate === null || rawDate === '') {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const dateIso = normalizePlannedMessageDateIso(rawDate);
|
|
190
|
+
|
|
191
|
+
if (dateIso === null) {
|
|
192
|
+
throw new ParseError(
|
|
193
|
+
spaceTrim(`
|
|
194
|
+
Invalid planned-message \`${fieldName}\`.
|
|
195
|
+
|
|
196
|
+
- Use an ISO date such as \`2026-08-20T09:00:00.000Z\`.
|
|
197
|
+
`),
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return dateIso;
|
|
202
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { resolveNextCronRun } from '../../cronExpression';
|
|
2
|
+
import type { PlannedMessageSchedule } from './PlannedMessageSchedule';
|
|
3
|
+
import { hasPlannedMessageRecurrence } from './hasPlannedMessageRecurrence';
|
|
4
|
+
import { isPlannedMessageScheduleFinished } from './isPlannedMessageScheduleFinished';
|
|
5
|
+
import { normalizePlannedMessageDateIso } from './normalizePlannedMessageScheduleValues';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Resolves when one planned message wakes the agent next.
|
|
9
|
+
*
|
|
10
|
+
* This is the single place deciding the whole life of a planned message: it answers both "when does it
|
|
11
|
+
* fire for the first time" and "when does it fire again after this firing", and it answers `null` when
|
|
12
|
+
* the plan is over — because it ran often enough, because its ending date passed, or because it never
|
|
13
|
+
* repeated in the first place.
|
|
14
|
+
*
|
|
15
|
+
* @param options - Recurrence rule, how many times the message already ran, the moment to schedule
|
|
16
|
+
* from, and the delay used by a planned message without any recurrence.
|
|
17
|
+
* @returns Next wake-up time, or `null` when the planned message is finished.
|
|
18
|
+
*
|
|
19
|
+
* @private function of `plannedMessageSchedule`
|
|
20
|
+
*/
|
|
21
|
+
export function resolvePlannedMessageDueAt(options: {
|
|
22
|
+
readonly schedule: PlannedMessageSchedule;
|
|
23
|
+
readonly completedRunCount: number;
|
|
24
|
+
readonly afterDate: Date;
|
|
25
|
+
readonly fallbackDelayMs?: number | null;
|
|
26
|
+
}): Date | null {
|
|
27
|
+
const { schedule, completedRunCount, afterDate } = options;
|
|
28
|
+
|
|
29
|
+
if (isPlannedMessageScheduleFinished({ schedule, completedRunCount, atDate: afterDate })) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const startsAtDate = resolvePlannedMessageStartDate(schedule);
|
|
34
|
+
const dueAtDate = resolvePlannedMessageCandidateDueAt({
|
|
35
|
+
schedule,
|
|
36
|
+
completedRunCount,
|
|
37
|
+
afterDate,
|
|
38
|
+
startsAtDate,
|
|
39
|
+
fallbackDelayMs: options.fallbackDelayMs ?? null,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (dueAtDate === null) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return isPlannedMessageDueAtAfterEnd(schedule, dueAtDate) ? null : dueAtDate;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Resolves the raw next wake-up time before the ending date is applied.
|
|
51
|
+
*
|
|
52
|
+
* @param options - Recurrence rule with the resolved starting date and the scheduling moment.
|
|
53
|
+
* @returns Candidate wake-up time, or `null` when the recurrence rule offers none.
|
|
54
|
+
*
|
|
55
|
+
* @private function of `resolvePlannedMessageDueAt`
|
|
56
|
+
*/
|
|
57
|
+
function resolvePlannedMessageCandidateDueAt(options: {
|
|
58
|
+
readonly schedule: PlannedMessageSchedule;
|
|
59
|
+
readonly completedRunCount: number;
|
|
60
|
+
readonly afterDate: Date;
|
|
61
|
+
readonly startsAtDate: Date | null;
|
|
62
|
+
readonly fallbackDelayMs: number | null;
|
|
63
|
+
}): Date | null {
|
|
64
|
+
const { schedule, completedRunCount, afterDate, startsAtDate, fallbackDelayMs } = options;
|
|
65
|
+
|
|
66
|
+
if (!hasPlannedMessageRecurrence(schedule) && completedRunCount > 0) {
|
|
67
|
+
// Note: A planned message without any recurrence wakes the agent exactly once
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const isWaitingForStart = startsAtDate !== null && startsAtDate.getTime() > afterDate.getTime();
|
|
72
|
+
|
|
73
|
+
if (schedule.cronExpression) {
|
|
74
|
+
// Note: One millisecond before the starting date keeps a cron run happening exactly at that date
|
|
75
|
+
return resolveNextCronRun(
|
|
76
|
+
schedule.cronExpression,
|
|
77
|
+
isWaitingForStart ? new Date(startsAtDate!.getTime() - 1) : afterDate,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (isWaitingForStart) {
|
|
82
|
+
// Note: A planned message never wakes the agent before its starting date, and an interval schedule
|
|
83
|
+
// wakes it for the first time exactly then
|
|
84
|
+
return startsAtDate;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (schedule.recurrenceIntervalMs) {
|
|
88
|
+
return new Date(afterDate.getTime() + schedule.recurrenceIntervalMs);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return fallbackDelayMs === null ? null : new Date(afterDate.getTime() + fallbackDelayMs);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Resolves the starting date of one planned message.
|
|
96
|
+
*
|
|
97
|
+
* @param schedule - Recurrence rule of the planned message.
|
|
98
|
+
* @returns Starting date, or `null` when the planned message may start immediately.
|
|
99
|
+
*
|
|
100
|
+
* @private function of `resolvePlannedMessageDueAt`
|
|
101
|
+
*/
|
|
102
|
+
function resolvePlannedMessageStartDate(schedule: PlannedMessageSchedule): Date | null {
|
|
103
|
+
const startsAtIso = normalizePlannedMessageDateIso(schedule.startsAt);
|
|
104
|
+
|
|
105
|
+
return startsAtIso === null ? null : new Date(startsAtIso);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Determines whether one candidate wake-up happens after the ending date.
|
|
110
|
+
*
|
|
111
|
+
* @param schedule - Recurrence rule of the planned message.
|
|
112
|
+
* @param dueAtDate - Candidate wake-up time.
|
|
113
|
+
* @returns `true` when the candidate is outside the planned window.
|
|
114
|
+
*
|
|
115
|
+
* @private function of `resolvePlannedMessageDueAt`
|
|
116
|
+
*/
|
|
117
|
+
function isPlannedMessageDueAtAfterEnd(schedule: PlannedMessageSchedule, dueAtDate: Date): boolean {
|
|
118
|
+
const endsAtIso = normalizePlannedMessageDateIso(schedule.endsAt);
|
|
119
|
+
|
|
120
|
+
return endsAtIso !== null && dueAtDate.getTime() > Date.parse(endsAtIso);
|
|
121
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { MINIMUM_PLANNED_MESSAGE_INTERVAL_MS } from './plannedMessageSchedule/PlannedMessageSchedule';
|
|
2
|
+
export { hasPlannedMessageRecurrence } from './plannedMessageSchedule/hasPlannedMessageRecurrence';
|
|
3
|
+
export { isPlannedMessageScheduleFinished } from './plannedMessageSchedule/isPlannedMessageScheduleFinished';
|
|
4
|
+
export {
|
|
5
|
+
normalizePlannedMessageCronExpression,
|
|
6
|
+
normalizePlannedMessageDateIso,
|
|
7
|
+
normalizePlannedMessageMaxRunCount,
|
|
8
|
+
} from './plannedMessageSchedule/normalizePlannedMessageScheduleValues';
|
|
9
|
+
export { parsePlannedMessageSchedule } from './plannedMessageSchedule/parsePlannedMessageSchedule';
|
|
10
|
+
export { resolvePlannedMessageDueAt } from './plannedMessageSchedule/resolvePlannedMessageDueAt';
|
|
11
|
+
export type { PlannedMessageSchedule } from './plannedMessageSchedule/PlannedMessageSchedule';
|
|
12
|
+
export type { PlannedMessageScheduleInput } from './plannedMessageSchedule/parsePlannedMessageSchedule';
|
package/apps/agents-server/src/utils/userChatTimeout/setAgentScopedUserChatTimeoutPausedState.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { UserChatTimeoutRecord } from './UserChatTimeoutRecord';
|
|
2
|
+
import { updateAgentScopedUserChatTimeout } from './userChatTimeoutStore';
|
|
3
|
+
import { notifyUserChatTimeoutScheduleChanged } from './userChatTimeoutWorker';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Outcome of holding one planned message back, or letting it go again.
|
|
7
|
+
*
|
|
8
|
+
* `isApplied` is `false` when the planned message could not take the requested state — because it is
|
|
9
|
+
* firing right now, because it is already over, or because there is no such planned message.
|
|
10
|
+
*
|
|
11
|
+
* @private internal utility of the Agents Server planned messages
|
|
12
|
+
*/
|
|
13
|
+
export type SetAgentScopedUserChatTimeoutPausedStateResult =
|
|
14
|
+
| { readonly isApplied: true; readonly plannedMessage: UserChatTimeoutRecord }
|
|
15
|
+
| { readonly isApplied: false; readonly plannedMessage: UserChatTimeoutRecord | null };
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Options for holding one planned message back, or letting it go again.
|
|
19
|
+
*
|
|
20
|
+
* @private internal utility of the Agents Server planned messages
|
|
21
|
+
*/
|
|
22
|
+
export type SetAgentScopedUserChatTimeoutPausedStateOptions = {
|
|
23
|
+
/**
|
|
24
|
+
* Owning user, or `undefined` to span every user of the agent.
|
|
25
|
+
*/
|
|
26
|
+
readonly userId?: number;
|
|
27
|
+
readonly agentPermanentId: string;
|
|
28
|
+
readonly timeoutId: string;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Whether the planned message should be held back from waking its agent.
|
|
32
|
+
*/
|
|
33
|
+
readonly isPaused: boolean;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Holds one planned message back from waking its agent, or lets it go again.
|
|
38
|
+
*
|
|
39
|
+
* This is the one place pausing is written and the worker is told about it, so a single planned
|
|
40
|
+
* message paused from the admin manager and a whole agent paused at once behave identically.
|
|
41
|
+
*
|
|
42
|
+
* @param options - Planned message and the state it should take.
|
|
43
|
+
* @returns Whether the planned message took the requested state, with the stored planned message.
|
|
44
|
+
*
|
|
45
|
+
* @private internal utility of the Agents Server planned messages
|
|
46
|
+
*/
|
|
47
|
+
export async function setAgentScopedUserChatTimeoutPausedState(
|
|
48
|
+
options: SetAgentScopedUserChatTimeoutPausedStateOptions,
|
|
49
|
+
): Promise<SetAgentScopedUserChatTimeoutPausedStateResult> {
|
|
50
|
+
const updatedPlannedMessage = await updateAgentScopedUserChatTimeout({
|
|
51
|
+
userId: options.userId,
|
|
52
|
+
agentPermanentId: options.agentPermanentId,
|
|
53
|
+
timeoutId: options.timeoutId,
|
|
54
|
+
patch: {
|
|
55
|
+
pausedAt: options.isPaused ? new Date().toISOString() : null,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (!updatedPlannedMessage || Boolean(updatedPlannedMessage.pausedAt) !== options.isPaused) {
|
|
60
|
+
return { isApplied: false, plannedMessage: updatedPlannedMessage };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
notifyUserChatTimeoutScheduleChanged(updatedPlannedMessage);
|
|
64
|
+
|
|
65
|
+
return { isApplied: true, plannedMessage: updatedPlannedMessage };
|
|
66
|
+
}
|
package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/createUserChatTimeout.ts
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import type { Json } from '@/src/database/schema';
|
|
2
|
+
import { spaceTrim } from 'spacetrim';
|
|
3
|
+
import { ParseError } from '../../../../../../src/errors/ParseError';
|
|
2
4
|
import { $randomBase58 } from '../../../../../../src/utils/random/$randomBase58';
|
|
3
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
CreateUserChatTimeoutOptions,
|
|
7
|
+
UserChatTimeoutInsert,
|
|
8
|
+
UserChatTimeoutRecord,
|
|
9
|
+
UserChatTimeoutRow,
|
|
10
|
+
} from '../UserChatTimeoutRecord';
|
|
11
|
+
import {
|
|
12
|
+
normalizePlannedMessageCronExpression,
|
|
13
|
+
normalizePlannedMessageDateIso,
|
|
14
|
+
normalizePlannedMessageMaxRunCount,
|
|
15
|
+
resolvePlannedMessageDueAt,
|
|
16
|
+
type PlannedMessageSchedule,
|
|
17
|
+
} from '../plannedMessageSchedule';
|
|
4
18
|
import { isMissingUserChatTimeoutRelationError } from './isMissingUserChatTimeoutRelationError';
|
|
5
19
|
import { mapUserChatTimeoutRow } from './mapUserChatTimeoutRow';
|
|
6
20
|
import { normalizeRecurrenceIntervalMs } from './normalizeRecurrenceIntervalMs';
|
|
@@ -38,8 +52,9 @@ export async function createUserChatTimeout(options: CreateUserChatTimeoutOption
|
|
|
38
52
|
const nowIso = new Date().toISOString();
|
|
39
53
|
const timeoutId =
|
|
40
54
|
options.id || `${USER_CHAT_TIMEOUT_ID_PREFIX}${$randomBase58(GENERATED_USER_CHAT_TIMEOUT_ID_LENGTH)}`;
|
|
41
|
-
const
|
|
42
|
-
const
|
|
55
|
+
const schedule = createUserChatTimeoutSchedule(options);
|
|
56
|
+
const dueAt = options.dueAt || resolveCreatedUserChatTimeoutDueAtIso(schedule, options.durationMs ?? null);
|
|
57
|
+
const durationMs = options.durationMs ?? Math.max(0, Date.parse(dueAt) - Date.parse(nowIso));
|
|
43
58
|
const userChatTimeoutTable = await provideUserChatTimeoutTable();
|
|
44
59
|
const insertPayload: UserChatTimeoutInsert = {
|
|
45
60
|
id: timeoutId,
|
|
@@ -51,9 +66,13 @@ export async function createUserChatTimeout(options: CreateUserChatTimeoutOption
|
|
|
51
66
|
status: 'QUEUED',
|
|
52
67
|
message: options.message || null,
|
|
53
68
|
parameters: (options.parameters || {}) satisfies Record<string, unknown> as Json,
|
|
54
|
-
durationMs
|
|
69
|
+
durationMs,
|
|
55
70
|
dueAt,
|
|
56
|
-
recurrenceIntervalMs,
|
|
71
|
+
recurrenceIntervalMs: schedule.recurrenceIntervalMs,
|
|
72
|
+
cronExpression: schedule.cronExpression,
|
|
73
|
+
startsAt: schedule.startsAt,
|
|
74
|
+
endsAt: schedule.endsAt,
|
|
75
|
+
maxRunCount: schedule.maxRunCount,
|
|
57
76
|
queuedAt: nowIso,
|
|
58
77
|
pausedAt: null,
|
|
59
78
|
attemptCount: 0,
|
|
@@ -77,3 +96,55 @@ export async function createUserChatTimeout(options: CreateUserChatTimeoutOption
|
|
|
77
96
|
|
|
78
97
|
return mapUserChatTimeoutRow(data as UserChatTimeoutRow);
|
|
79
98
|
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Collects the recurrence rule of one newly created timeout.
|
|
102
|
+
*
|
|
103
|
+
* @param options - Input of the created timeout.
|
|
104
|
+
* @returns Normalized recurrence rule.
|
|
105
|
+
*
|
|
106
|
+
* @private function of createUserChatTimeout
|
|
107
|
+
*/
|
|
108
|
+
function createUserChatTimeoutSchedule(options: CreateUserChatTimeoutOptions): PlannedMessageSchedule {
|
|
109
|
+
return {
|
|
110
|
+
recurrenceIntervalMs: normalizeRecurrenceIntervalMs(options.recurrenceIntervalMs),
|
|
111
|
+
cronExpression: normalizePlannedMessageCronExpression(options.cronExpression),
|
|
112
|
+
startsAt: normalizePlannedMessageDateIso(options.startsAt),
|
|
113
|
+
endsAt: normalizePlannedMessageDateIso(options.endsAt),
|
|
114
|
+
maxRunCount: normalizePlannedMessageMaxRunCount(options.maxRunCount),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Resolves when one newly created timeout fires for the first time.
|
|
120
|
+
*
|
|
121
|
+
* @param schedule - Recurrence rule of the created timeout.
|
|
122
|
+
* @param fallbackDelayMs - Delay used by a timeout that does not repeat.
|
|
123
|
+
* @returns ISO time of the first wake-up.
|
|
124
|
+
*
|
|
125
|
+
* @private function of createUserChatTimeout
|
|
126
|
+
*/
|
|
127
|
+
function resolveCreatedUserChatTimeoutDueAtIso(
|
|
128
|
+
schedule: PlannedMessageSchedule,
|
|
129
|
+
fallbackDelayMs: number | null,
|
|
130
|
+
): string {
|
|
131
|
+
const dueAtDate = resolvePlannedMessageDueAt({
|
|
132
|
+
schedule,
|
|
133
|
+
completedRunCount: 0,
|
|
134
|
+
afterDate: new Date(),
|
|
135
|
+
fallbackDelayMs,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (dueAtDate === null) {
|
|
139
|
+
throw new ParseError(
|
|
140
|
+
spaceTrim(`
|
|
141
|
+
This planned message would never wake the agent.
|
|
142
|
+
|
|
143
|
+
- Its schedule is already over, for example because \`endsAt\` is in the past or \`maxRunCount\` is exhausted.
|
|
144
|
+
- Plan a schedule with at least one wake-up still ahead.
|
|
145
|
+
`),
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return dueAtDate.toISOString();
|
|
150
|
+
}
|
package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/listAllUserChatTimeouts.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ListAllUserChatTimeoutsOptions,
|
|
3
|
+
UserChatTimeoutRecord,
|
|
4
|
+
UserChatTimeoutRow,
|
|
5
|
+
} from '../UserChatTimeoutRecord';
|
|
6
|
+
import { isMissingUserChatTimeoutRelationError } from './isMissingUserChatTimeoutRelationError';
|
|
7
|
+
import { mapUserChatTimeoutRow } from './mapUserChatTimeoutRow';
|
|
8
|
+
import { provideUserChatTimeoutTable } from './provideUserChatTimeoutTable';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Lists the timeouts of every agent and every user on this server, newest first.
|
|
12
|
+
*
|
|
13
|
+
* This is the server-wide counterpart of `listAgentUserChatTimeouts`, used by the admin
|
|
14
|
+
* planned-message manager which spans all agents instead of one.
|
|
15
|
+
*
|
|
16
|
+
* @private function of userChatTimeoutStore
|
|
17
|
+
*/
|
|
18
|
+
export async function listAllUserChatTimeouts(
|
|
19
|
+
options: ListAllUserChatTimeoutsOptions,
|
|
20
|
+
): Promise<Array<UserChatTimeoutRecord>> {
|
|
21
|
+
const userChatTimeoutTable = await provideUserChatTimeoutTable();
|
|
22
|
+
const { data, error } = await userChatTimeoutTable
|
|
23
|
+
.select('*')
|
|
24
|
+
.order('updatedAt', { ascending: false })
|
|
25
|
+
.order('createdAt', { ascending: false })
|
|
26
|
+
.range(0, Math.max(0, options.limit - 1));
|
|
27
|
+
|
|
28
|
+
if (error) {
|
|
29
|
+
if (isMissingUserChatTimeoutRelationError(error)) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
throw new Error(`Failed to list user chat timeouts of every agent: ${error.message}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return ((data || []) as Array<UserChatTimeoutRow>).map(mapUserChatTimeoutRow);
|
|
37
|
+
}
|
package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/mapUserChatTimeoutRow.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { UserChatTimeoutRecord, UserChatTimeoutRow } from '../UserChatTimeoutRecord';
|
|
2
|
+
import {
|
|
3
|
+
normalizePlannedMessageCronExpression,
|
|
4
|
+
normalizePlannedMessageDateIso,
|
|
5
|
+
normalizePlannedMessageMaxRunCount,
|
|
6
|
+
} from '../plannedMessageSchedule';
|
|
2
7
|
import { normalizeRecurrenceIntervalMs } from './normalizeRecurrenceIntervalMs';
|
|
3
8
|
import { normalizeUserChatTimeoutParameters } from './normalizeUserChatTimeoutParameters';
|
|
4
9
|
|
|
@@ -22,6 +27,10 @@ export function mapUserChatTimeoutRow(row: UserChatTimeoutRow): UserChatTimeoutR
|
|
|
22
27
|
durationMs: row.durationMs,
|
|
23
28
|
dueAt: row.dueAt,
|
|
24
29
|
recurrenceIntervalMs: normalizeRecurrenceIntervalMs(row.recurrenceIntervalMs),
|
|
30
|
+
cronExpression: normalizePlannedMessageCronExpression(row.cronExpression),
|
|
31
|
+
startsAt: normalizePlannedMessageDateIso(row.startsAt),
|
|
32
|
+
endsAt: normalizePlannedMessageDateIso(row.endsAt),
|
|
33
|
+
maxRunCount: normalizePlannedMessageMaxRunCount(row.maxRunCount),
|
|
25
34
|
queuedAt: row.queuedAt,
|
|
26
35
|
startedAt: row.startedAt,
|
|
27
36
|
completedAt: row.completedAt,
|