@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.
Files changed (231) hide show
  1. package/apps/agents-server/next.config.ts +6 -0
  2. package/apps/agents-server/src/app/admin/_components/AdminFilterFields.tsx +84 -0
  3. package/apps/agents-server/src/app/admin/_components/AdminMetricCard.tsx +36 -0
  4. package/apps/agents-server/src/app/admin/_components/AdminTaskManagerTabs.tsx +97 -0
  5. package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerClient.tsx +103 -0
  6. package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerEditDialog.tsx +232 -0
  7. package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerFiltersCard.tsx +195 -0
  8. package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerRow.tsx +189 -0
  9. package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerSummaryMetrics.tsx +60 -0
  10. package/apps/agents-server/src/app/admin/planned-messages/PlannedMessageManagerTableCard.tsx +147 -0
  11. package/apps/agents-server/src/app/admin/planned-messages/page.tsx +17 -0
  12. package/apps/agents-server/src/app/admin/planned-messages/plannedMessageEditForm.ts +186 -0
  13. package/apps/agents-server/src/app/admin/planned-messages/plannedMessageManagerDialogs.ts +46 -0
  14. package/apps/agents-server/src/app/admin/planned-messages/plannedMessageManagerPresentation.tsx +188 -0
  15. package/apps/agents-server/src/app/admin/planned-messages/resolvePlannedMessageSortValue.ts +115 -0
  16. package/apps/agents-server/src/app/admin/planned-messages/usePlannedMessageManagerData.ts +116 -0
  17. package/apps/agents-server/src/app/admin/planned-messages/usePlannedMessageManagerState.ts +289 -0
  18. package/apps/agents-server/src/app/admin/task-manager/TaskManagerClient.tsx +7 -2
  19. package/apps/agents-server/src/app/admin/task-manager/TaskManagerFiltersCard.tsx +7 -73
  20. package/apps/agents-server/src/app/admin/task-manager/TaskManagerSummaryMetrics.tsx +5 -30
  21. package/apps/agents-server/src/app/admin/task-manager/[taskId]/TaskManagerTaskDetailClient.tsx +1 -1
  22. package/apps/agents-server/src/app/agents/[agentName]/api/book/reference-diagnostics/route.ts +30 -7
  23. package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +1 -0
  24. package/apps/agents-server/src/app/agents/[agentName]/api/book/test.http +3 -3
  25. package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorMissingReferences.tsx +106 -12
  26. package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorWrapper.tsx +3 -0
  27. package/apps/agents-server/src/app/agents/[agentName]/book/useBookEditorDiagnostics.ts +12 -0
  28. package/apps/agents-server/src/app/agents/[agentName]/book/useBookEditorWrapper.tsx +2 -0
  29. package/apps/agents-server/src/app/agents/[agentName]/chat/AgentGoalChatPlannedMessages.tsx +46 -3
  30. package/apps/agents-server/src/app/api/admin/default-agents/reinstate/route.ts +5 -1
  31. package/apps/agents-server/src/app/api/admin/planned-messages/[timeoutId]/route.ts +80 -0
  32. package/apps/agents-server/src/app/api/admin/planned-messages/route.ts +19 -0
  33. package/apps/agents-server/src/app/api/internal/agent-goal-chat-planned-messages/route.ts +30 -2
  34. package/apps/agents-server/src/components/DefaultAgents/ReinstateBundledAgentsButton.tsx +7 -0
  35. package/apps/agents-server/src/components/DefaultAgents/coreAgentsAdminRoute.ts +6 -0
  36. package/apps/agents-server/src/components/Header/buildHeaderSystemMenuItems.ts +7 -0
  37. package/apps/agents-server/src/components/Homepage/DefaultAgentsStatusNotice.tsx +1 -7
  38. package/apps/agents-server/src/database/migrations/2026-08-1800-user-chat-timeout-schedule.sql +11 -0
  39. package/apps/agents-server/src/instrumentation-node.ts +18 -0
  40. package/apps/agents-server/src/languages/ServerTranslationKeys.ts +4 -0
  41. package/apps/agents-server/src/languages/translations/czech.yaml +4 -0
  42. package/apps/agents-server/src/languages/translations/english.yaml +4 -0
  43. package/apps/agents-server/src/tools/agentGoalChatTimeoutToolFunctions.ts +62 -15
  44. package/apps/agents-server/src/tools/agentGoalChatTimeoutTools.ts +63 -9
  45. package/apps/agents-server/src/utils/adminEntityLookups/loadAgentNamesByPermanentId.ts +45 -0
  46. package/apps/agents-server/src/utils/adminEntityLookups/loadUsernamesByUserId.ts +36 -0
  47. package/apps/agents-server/src/utils/adminEntityLookups.ts +2 -0
  48. package/apps/agents-server/src/utils/agentGoalChat/agentGoalChatPlannedMessageActions.ts +299 -52
  49. package/apps/agents-server/src/utils/agentGoalChat/createAgentGoalChatNoteContent.ts +45 -17
  50. package/apps/agents-server/src/utils/agentGoalChat.ts +1 -0
  51. package/apps/agents-server/src/utils/agentProjects/agentProjectIdentity.ts +46 -0
  52. package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeAutostartScheduler.ts +162 -0
  53. package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeDesiredState.ts +252 -0
  54. package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeDisplay.ts +6 -3
  55. package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeDomains.ts +2 -44
  56. package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimePaths.ts +25 -0
  57. package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimePm2.ts +4 -3
  58. package/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeRegistry.ts +77 -24
  59. package/apps/agents-server/src/utils/agentProjects/agentProjectStateMutationQueue.ts +58 -0
  60. package/apps/agents-server/src/utils/agentProjects/listAllLocalAgentProjectIdentities.ts +48 -0
  61. package/apps/agents-server/src/utils/agentProjects/resolveAgentProjectRuntimeEnvironmentFlag.ts +23 -0
  62. package/apps/agents-server/src/utils/agentProjects/resolveAgentProjectRuntimeStatus.ts +73 -0
  63. package/apps/agents-server/src/utils/agentProjects/startDefaultAgentProjectRuntimes.ts +110 -0
  64. package/apps/agents-server/src/utils/agentReferenceResolver/MissingCoreAgentRecovery.ts +19 -0
  65. package/apps/agents-server/src/utils/agentReferenceResolver/bookScopedAgentReferences.ts +7 -0
  66. package/apps/agents-server/src/utils/agentReferenceResolver/createAgentInheritanceDiagnostics.ts +457 -0
  67. package/apps/agents-server/src/utils/agentReferenceResolver/createUnresolvedAgentReferenceDiagnostics.ts +27 -0
  68. package/apps/agents-server/src/utils/agentReferenceResolver/resolveCoreAgentAwareMissingReferences.ts +156 -0
  69. package/apps/agents-server/src/utils/chatMessageChips/createAnsweredMessageChipToolCalls.ts +15 -3
  70. package/apps/agents-server/src/utils/chatMessageChips/createPlannedMessageChipToolCalls.ts +8 -3
  71. package/apps/agents-server/src/utils/chatMessageChips/createTouchedExternalSourceChipToolCalls.ts +39 -0
  72. package/apps/agents-server/src/utils/chatMessageChips/createTouchedProjectChipResult.ts +45 -0
  73. package/apps/agents-server/src/utils/chatMessageChips/createTouchedProjectChipToolCalls.ts +58 -24
  74. package/apps/agents-server/src/utils/cronExpression/CronExpression.ts +63 -0
  75. package/apps/agents-server/src/utils/cronExpression/normalizeCronExpression.ts +34 -0
  76. package/apps/agents-server/src/utils/cronExpression/normalizeCronExpressionWhitespace.ts +11 -0
  77. package/apps/agents-server/src/utils/cronExpression/parseCronExpression.ts +41 -0
  78. package/apps/agents-server/src/utils/cronExpression/parseCronExpressionField.ts +140 -0
  79. package/apps/agents-server/src/utils/cronExpression/resolveNextCronRun.ts +100 -0
  80. package/apps/agents-server/src/utils/cronExpression/throwInvalidCronExpressionField.ts +20 -0
  81. package/apps/agents-server/src/utils/cronExpression.ts +10 -0
  82. package/apps/agents-server/src/utils/explicitFromCommitment.ts +130 -0
  83. package/apps/agents-server/src/utils/getAdminChatTasksResponse/getAdminChatTasks/loadAdminChatTaskFallbackData.ts +3 -77
  84. package/apps/agents-server/src/utils/localChatRunner/applyLocalAgentPlannedMessageCommands.ts +53 -4
  85. package/apps/agents-server/src/utils/localChatRunner/prepareLocalAgentPlannedMessagesSidecar.ts +15 -7
  86. package/apps/agents-server/src/utils/localChatRunner/processLocalUserChatJob.ts +8 -0
  87. package/apps/agents-server/src/utils/manGoOnboarding/manGoOnboardingAgentBooks.ts +5 -11
  88. package/apps/agents-server/src/utils/manGoOnboarding/manGoOnboardingAgentRuntime.ts +2 -2
  89. package/apps/agents-server/src/utils/managementApi/managementApiSchemas.ts +2 -2
  90. package/apps/agents-server/src/utils/plannedMessageManager/cancelManagedPlannedMessage.ts +35 -0
  91. package/apps/agents-server/src/utils/plannedMessageManager/collectPlannedMessageAgentOptions.ts +56 -0
  92. package/apps/agents-server/src/utils/plannedMessageManager/createPlannedMessageManagerCounters.ts +104 -0
  93. package/apps/agents-server/src/utils/plannedMessageManager/filterPlannedMessages.ts +191 -0
  94. package/apps/agents-server/src/utils/plannedMessageManager/getPlannedMessageManagerResponse.ts +55 -0
  95. package/apps/agents-server/src/utils/plannedMessageManager/isPlannedMessageStillPlanned.ts +18 -0
  96. package/apps/agents-server/src/utils/plannedMessageManager/loadPlannedMessageManagerRecord.ts +32 -0
  97. package/apps/agents-server/src/utils/plannedMessageManager/mapPlannedMessageManagerRecord.ts +73 -0
  98. package/apps/agents-server/src/utils/plannedMessageManager/parsePlannedMessageManagerUpdateRequest.ts +76 -0
  99. package/apps/agents-server/src/utils/plannedMessageManager/resolvePlannedMessageEndReason.ts +59 -0
  100. package/apps/agents-server/src/utils/plannedMessageManager/resolvePlannedMessageLifecycle.ts +99 -0
  101. package/apps/agents-server/src/utils/plannedMessageManager/resolvePlannedMessageRecurrenceKind.ts +40 -0
  102. package/apps/agents-server/src/utils/plannedMessageManager/updateManagedPlannedMessage.ts +121 -0
  103. package/apps/agents-server/src/utils/plannedMessagesAdmin.ts +200 -0
  104. package/apps/agents-server/src/utils/resolveInheritedAgentSource.ts +114 -95
  105. package/apps/agents-server/src/utils/userChatClient.ts +4 -0
  106. package/apps/agents-server/src/utils/userChatTimeout/UserChatTimeoutRecord.ts +37 -1
  107. package/apps/agents-server/src/utils/userChatTimeout/agentScopedTimeoutBulkActions.ts +11 -17
  108. package/apps/agents-server/src/utils/userChatTimeout/createTimeoutWakeUpMessage.ts +37 -13
  109. package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/PlannedMessageSchedule.ts +52 -0
  110. package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/hasPlannedMessageRecurrence.ts +13 -0
  111. package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/isPlannedMessageScheduleFinished.ts +30 -0
  112. package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/normalizePlannedMessageScheduleValues.ts +62 -0
  113. package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/parsePlannedMessageSchedule.ts +202 -0
  114. package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule/resolvePlannedMessageDueAt.ts +121 -0
  115. package/apps/agents-server/src/utils/userChatTimeout/plannedMessageSchedule.ts +12 -0
  116. package/apps/agents-server/src/utils/userChatTimeout/setAgentScopedUserChatTimeoutPausedState.ts +66 -0
  117. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/createUserChatTimeout.ts +76 -5
  118. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/listAllUserChatTimeouts.ts +37 -0
  119. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/mapUserChatTimeoutRow.ts +9 -0
  120. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/repeatFiredUserChatTimeout.ts +19 -9
  121. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/updateAgentScopedUserChatTimeout.ts +39 -6
  122. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore.ts +1 -0
  123. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutWorker.ts +110 -11
  124. package/apps/agents-server/src/utils/userChatTimeout.ts +16 -0
  125. package/apps/agents-server/src/utils/vpsSelfUpdate/vpsSelfUpdateCron.ts +23 -316
  126. package/apps/agents-server/tests/e2e/support/AgentManagementApi.ts +3 -3
  127. package/esm/index.es.js +951 -102
  128. package/esm/index.es.js.map +1 -1
  129. package/esm/scripts/run-agent-messages/git/commitAgentProjectChanges.d.ts +15 -0
  130. package/esm/scripts/run-agent-messages/git/commitAnsweredMessageProjectChanges.d.ts +24 -0
  131. package/esm/scripts/run-agent-messages/git/ensureAgentProjectGitRepository.d.ts +20 -0
  132. package/esm/scripts/run-agent-messages/git/readAgentProjectCommitChange.d.ts +11 -0
  133. package/esm/scripts/run-agent-messages/git/runAgentProjectGitCommand.d.ts +29 -0
  134. package/esm/scripts/run-agent-messages/messages/buildAgentGoalChatPromptSection.d.ts +3 -3
  135. package/esm/scripts/run-agent-messages/messages/listAgentProjectDirectoryNames.d.ts +7 -0
  136. package/esm/scripts/run-agent-messages/messages/resolveAnsweredMessageTouches.d.ts +29 -0
  137. package/esm/scripts/run-codex-prompts/ping/pingCoderHarnessPeriodically.d.ts +22 -0
  138. package/esm/src/book-3.0/AgentMessageRunReport.d.ts +18 -0
  139. package/esm/src/book-3.0/AgentPlannedMessagesSidecar.d.ts +38 -5
  140. package/esm/src/book-3.0/describeAgentPlannedMessageSchedule.d.ts +31 -0
  141. package/esm/src/book-components/BookEditor/createDeprecatedCommitmentDiagnostics.browser.d.ts +1 -9
  142. package/esm/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.d.ts +28 -0
  143. package/esm/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.test.d.ts +1 -0
  144. package/esm/src/book-components/Chat/Chat/renderAgentProjectDiff.d.ts +13 -0
  145. package/esm/src/book-components/Chat/Chat/renderAgentProjectToolCallDetails.d.ts +16 -0
  146. package/esm/src/book-components/Chat/utils/agentProjectToolCall.d.ts +39 -0
  147. package/esm/src/book-components/Chat/utils/agentProjectToolCall.test.d.ts +1 -0
  148. package/esm/src/book-components/Chat/utils/externalSourceToolCall.d.ts +38 -0
  149. package/esm/src/book-components/Chat/utils/timeoutToolCallPresentation.d.ts +6 -0
  150. package/esm/src/cli/cli-commands/coder/waitOptions.d.ts +12 -0
  151. package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +15 -0
  152. package/esm/src/utils/agent-message-runtime/AgentMessageProjectChange.d.ts +76 -0
  153. package/esm/src/utils/agent-message-runtime/AgentMessageTouchedExternalSource.d.ts +45 -0
  154. package/esm/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.d.ts +3 -0
  155. package/esm/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.d.ts +18 -0
  156. package/esm/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.test.d.ts +1 -0
  157. package/esm/src/utils/random/$generateBookBoilerplate.test.d.ts +1 -0
  158. package/esm/src/version.d.ts +1 -1
  159. package/package.json +1 -1
  160. package/src/book-2.0/agent-source/string_book.ts +1 -1
  161. package/src/book-2.0/book-language-documentation/czechBookLanguageManualDictionary.ts +6 -1
  162. package/src/book-2.0/book-language-documentation/englishBookLanguageManualDictionary.ts +6 -1
  163. package/src/book-3.0/AgentMessageRunReport.ts +59 -0
  164. package/src/book-3.0/AgentPlannedMessagesSidecar.ts +64 -9
  165. package/src/book-3.0/describeAgentPlannedMessageSchedule.ts +94 -0
  166. package/src/book-components/BookEditor/BookEditorMonaco.tsx +2 -0
  167. package/src/book-components/BookEditor/createDeprecatedCommitmentDiagnostics.browser.ts +3 -11
  168. package/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.ts +71 -0
  169. package/src/book-components/Chat/Chat/Chat.module.css +165 -18
  170. package/src/book-components/Chat/Chat/ChatMessageMap.tsx +0 -1
  171. package/src/book-components/Chat/Chat/renderAgentProjectDiff.tsx +85 -0
  172. package/src/book-components/Chat/Chat/renderAgentProjectToolCallDetails.tsx +206 -0
  173. package/src/book-components/Chat/Chat/renderToolCallDetails.tsx +8 -0
  174. package/src/book-components/Chat/MarkdownContent/MarkdownContent.tsx +2 -3
  175. package/src/book-components/Chat/utils/agentProjectToolCall.ts +82 -5
  176. package/src/book-components/Chat/utils/externalSourceToolCall.ts +65 -0
  177. package/src/book-components/Chat/utils/getToolCallChipletInfo.ts +36 -0
  178. package/src/book-components/Chat/utils/renderMarkdown.ts +3 -10
  179. package/src/book-components/Chat/utils/timeoutToolCallPresentation.ts +12 -1
  180. package/src/cli/cli-commands/coder/ping.ts +35 -9
  181. package/src/cli/cli-commands/coder/waitOptions.ts +33 -0
  182. package/src/cli/cli-commands/common/harness/$applyHarnessInstallationStatus.ts +3 -1
  183. package/src/cli/cli-commands/common/harness/$checkHarnessInstallation.ts +3 -1
  184. package/src/cli/cli-commands/common/harnessUpdateCliOptions.ts +1 -4
  185. package/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.ts +47 -3
  186. package/src/commands/FORMAT/formatCommandParser.ts +4 -2
  187. package/src/commitments/FROM/FROM.ts +13 -0
  188. package/src/other/templates/getTemplatesPipelineCollection.ts +819 -751
  189. package/src/utils/agent-message-runtime/AgentMessageProjectChange.ts +183 -0
  190. package/src/utils/agent-message-runtime/AgentMessageTouchedExternalSource.ts +80 -0
  191. package/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.ts +3 -0
  192. package/src/utils/agent-message-runtime/resolveAgentMessageRuntimeActivity.ts +2 -4
  193. package/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.ts +341 -0
  194. package/src/utils/random/$generateBookBoilerplate.ts +1 -1
  195. package/src/version.ts +2 -2
  196. package/src/versions.txt +5 -0
  197. package/umd/index.umd.js +950 -101
  198. package/umd/index.umd.js.map +1 -1
  199. package/umd/scripts/run-agent-messages/git/commitAgentProjectChanges.d.ts +15 -0
  200. package/umd/scripts/run-agent-messages/git/commitAnsweredMessageProjectChanges.d.ts +24 -0
  201. package/umd/scripts/run-agent-messages/git/ensureAgentProjectGitRepository.d.ts +20 -0
  202. package/umd/scripts/run-agent-messages/git/readAgentProjectCommitChange.d.ts +11 -0
  203. package/umd/scripts/run-agent-messages/git/runAgentProjectGitCommand.d.ts +29 -0
  204. package/umd/scripts/run-agent-messages/messages/buildAgentGoalChatPromptSection.d.ts +3 -3
  205. package/umd/scripts/run-agent-messages/messages/listAgentProjectDirectoryNames.d.ts +7 -0
  206. package/umd/scripts/run-agent-messages/messages/resolveAnsweredMessageTouches.d.ts +29 -0
  207. package/umd/scripts/run-codex-prompts/ping/pingCoderHarnessPeriodically.d.ts +22 -0
  208. package/umd/src/book-3.0/AgentMessageRunReport.d.ts +18 -0
  209. package/umd/src/book-3.0/AgentPlannedMessagesSidecar.d.ts +38 -5
  210. package/umd/src/book-3.0/describeAgentPlannedMessageSchedule.d.ts +31 -0
  211. package/umd/src/book-components/BookEditor/createDeprecatedCommitmentDiagnostics.browser.d.ts +1 -9
  212. package/umd/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.d.ts +28 -0
  213. package/umd/src/book-components/BookEditor/createDuplicateFromCommitmentDiagnostics.test.d.ts +1 -0
  214. package/umd/src/book-components/Chat/Chat/renderAgentProjectDiff.d.ts +13 -0
  215. package/umd/src/book-components/Chat/Chat/renderAgentProjectToolCallDetails.d.ts +16 -0
  216. package/umd/src/book-components/Chat/utils/agentProjectToolCall.d.ts +39 -0
  217. package/umd/src/book-components/Chat/utils/agentProjectToolCall.test.d.ts +1 -0
  218. package/umd/src/book-components/Chat/utils/externalSourceToolCall.d.ts +38 -0
  219. package/umd/src/book-components/Chat/utils/timeoutToolCallPresentation.d.ts +6 -0
  220. package/umd/src/cli/cli-commands/coder/waitOptions.d.ts +12 -0
  221. package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +15 -0
  222. package/umd/src/utils/agent-message-runtime/AgentMessageProjectChange.d.ts +76 -0
  223. package/umd/src/utils/agent-message-runtime/AgentMessageTouchedExternalSource.d.ts +45 -0
  224. package/umd/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.d.ts +3 -0
  225. package/umd/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.d.ts +18 -0
  226. package/umd/src/utils/agent-message-runtime/resolveAgentMessageTouchedExternalSources.test.d.ts +1 -0
  227. package/umd/src/utils/random/$generateBookBoilerplate.test.d.ts +1 -0
  228. package/umd/src/version.d.ts +1 -1
  229. package/apps/agents-server/src/app/admin/task-manager/TaskManagerScopeTabs.tsx +0 -74
  230. package/esm/scripts/run-agent-messages/messages/resolveTouchedAgentProjects.d.ts +0 -15
  231. package/umd/scripts/run-agent-messages/messages/resolveTouchedAgentProjects.d.ts +0 -15
@@ -4,7 +4,6 @@ import { padBook } from '../../../../src/book-2.0/agent-source/padBook';
4
4
  import { isVoidPseudoAgentReference } from '../../../../src/book-2.0/agent-source/pseudoAgentReferences';
5
5
  import { validateBook } from '../../../../src/book-2.0/agent-source/string_book';
6
6
  import { ParseError } from '../../../../src/errors/ParseError';
7
- import { UnexpectedError } from '../../../../src/errors/UnexpectedError';
8
7
  import { spaceTrim } from '../../../../src/utils/organization/spaceTrim';
9
8
  import { isValidAgentUrl } from '../../../../src/utils/validators/url/isValidAgentUrl';
10
9
  import {
@@ -15,6 +14,7 @@ import {
15
14
  type AgentReferenceResolutionIssue,
16
15
  consumeAgentReferenceResolutionIssues,
17
16
  } from './agentReferenceResolver/AgentReferenceResolutionIssue';
17
+ import { collectExplicitFromCommitments, getExplicitFromCommitmentContent } from './explicitFromCommitment';
18
18
  import { type ImportAgentOptions } from './importAgent';
19
19
  import { importAgentWithFallback } from './importAgentWithFallback';
20
20
 
@@ -103,57 +103,6 @@ function insertNotesAfterTitle(agentSource: string_book, notes: ReadonlyArray<st
103
103
  return padBook(validateBook(nextLines.join('\n')));
104
104
  }
105
105
 
106
- /**
107
- * Returns the last explicit single-line commitment content for one commitment type.
108
- *
109
- * This lightweight parser is intentionally limited to the subset needed by
110
- * inheritance resolution so it stays safe to bundle into the Next.js proxy path.
111
- *
112
- * @param agentSource - Raw book source.
113
- * @param commitmentType - Commitment keyword to search for.
114
- * @returns Trimmed commitment content, empty string for a blank explicit commitment, or `undefined` when absent.
115
- */
116
- function getLastSingleLineCommitmentContent(agentSource: string_book, commitmentType: 'FROM'): string | undefined {
117
- const commitmentPrefix = `${commitmentType} `;
118
- const lines = agentSource.split(/\r?\n/);
119
- let hasSeenTitle = false;
120
- let isInsideCodeBlock = false;
121
- let matchedContent: string | undefined;
122
-
123
- for (const line of lines) {
124
- const trimmedLine = line.trim();
125
-
126
- if (!hasSeenTitle) {
127
- if (!trimmedLine) {
128
- continue;
129
- }
130
-
131
- hasSeenTitle = true;
132
- continue;
133
- }
134
-
135
- if (trimmedLine.startsWith('```')) {
136
- isInsideCodeBlock = !isInsideCodeBlock;
137
- continue;
138
- }
139
-
140
- if (isInsideCodeBlock) {
141
- continue;
142
- }
143
-
144
- if (trimmedLine === commitmentType) {
145
- matchedContent = '';
146
- continue;
147
- }
148
-
149
- if (trimmedLine.startsWith(commitmentPrefix)) {
150
- matchedContent = trimmedLine.slice(commitmentPrefix.length).trim();
151
- }
152
- }
153
-
154
- return matchedContent;
155
- }
156
-
157
106
  /**
158
107
  * Resolves the effective `FROM` parent URL using only lightweight commitment parsing.
159
108
  *
@@ -165,7 +114,7 @@ async function resolveParentAgentUrlFromCommitments(
165
114
  rawAgentSource: string_book,
166
115
  agentReferenceResolver?: AgentReferenceResolver,
167
116
  ): Promise<string_agent_url | null | undefined> {
168
- const explicitFromContent = getLastSingleLineCommitmentContent(rawAgentSource, 'FROM');
117
+ const explicitFromContent = getExplicitFromCommitmentContent(rawAgentSource);
169
118
 
170
119
  if (explicitFromContent === undefined) {
171
120
  return undefined;
@@ -285,6 +234,11 @@ type ResolvedParentAgentContext = {
285
234
  * Unresolved compact-reference issues captured while resolving `FROM`.
286
235
  */
287
236
  readonly fromResolutionIssues: Array<AgentReferenceResolutionIssue>;
237
+
238
+ /**
239
+ * Whether the effective parent closed the current lineage and must be materialized as `FROM @Null`.
240
+ */
241
+ readonly isCyclicFrom: boolean;
288
242
  };
289
243
 
290
244
  /**
@@ -357,6 +311,28 @@ type ResolvedFromCommitmentLine = {
357
311
  readonly fromResolutionIssues: Array<AgentReferenceResolutionIssue>;
358
312
  };
359
313
 
314
+ /**
315
+ * One cycle found while following a source-resolution lineage.
316
+ *
317
+ * @private internal helper for Agents Server inherited/imported agent resolution
318
+ */
319
+ type ResolutionCycle = {
320
+ /**
321
+ * Normalized URL that closes the cycle.
322
+ */
323
+ readonly normalizedReferenceUrl: string_agent_url;
324
+
325
+ /**
326
+ * URLs visited before the repeated reference was encountered.
327
+ */
328
+ readonly lineage: ReadonlyArray<string_agent_url>;
329
+
330
+ /**
331
+ * Position in `lineage` where the cycle begins.
332
+ */
333
+ readonly cycleStartIndex: number;
334
+ };
335
+
360
336
  /**
361
337
  * Normalizes agent URLs used for cycle detection and lineage reporting.
362
338
  *
@@ -387,6 +363,30 @@ function createResolutionLineage(options?: ResolveInheritedAgentSourceOptions):
387
363
  return [...new Set(lineage.map(normalizeAgentUrl))];
388
364
  }
389
365
 
366
+ /**
367
+ * Finds a cycle that would be closed by resolving one more agent reference.
368
+ *
369
+ * @param referenceUrl - Next agent reference to resolve.
370
+ * @param options - Current resolution options.
371
+ * @returns Cycle details, or `null` when the reference is not in the current lineage.
372
+ *
373
+ * @private internal helper for Agents Server inherited/imported agent resolution
374
+ */
375
+ function findResolutionCycle(
376
+ referenceUrl: string_agent_url,
377
+ options?: ResolveInheritedAgentSourceOptions,
378
+ ): ResolutionCycle | null {
379
+ const normalizedReferenceUrl = normalizeAgentUrl(referenceUrl);
380
+ const lineage = createResolutionLineage(options);
381
+ const cycleStartIndex = lineage.findIndex((visitedUrl) => visitedUrl === normalizedReferenceUrl);
382
+
383
+ if (cycleStartIndex === -1) {
384
+ return null;
385
+ }
386
+
387
+ return { normalizedReferenceUrl, lineage, cycleStartIndex };
388
+ }
389
+
390
390
  /**
391
391
  * Creates the shared import context used throughout one resolution pass.
392
392
  *
@@ -415,6 +415,7 @@ function createAgentImportContext(options?: ResolveInheritedAgentSourceOptions):
415
415
  * @param hasExplicitFromCommitment - Whether the source explicitly declared `FROM`.
416
416
  * @param adamAgentUrl - Default Adam ancestor URL.
417
417
  * @param currentAgentUrl - Canonical URL of the source being resolved.
418
+ * @param currentAgentAliases - Additional URLs that identify the source being resolved.
418
419
  * @param agentSource - Raw source used for unexpected diagnostics.
419
420
  * @returns Effective parent URL or `null` when inheritance is disabled.
420
421
  */
@@ -423,6 +424,7 @@ function determineParentAgentUrl(
423
424
  hasExplicitFromCommitment: boolean,
424
425
  adamAgentUrl: string_agent_url,
425
426
  currentAgentUrl?: string_agent_url,
427
+ currentAgentAliases?: ReadonlyArray<string_agent_url>,
426
428
  agentSource?: string_book,
427
429
  ): string_agent_url | null {
428
430
  if (isValidAgentUrl(resolvedParentAgentUrl)) {
@@ -434,9 +436,14 @@ function determineParentAgentUrl(
434
436
  }
435
437
 
436
438
  if (resolvedParentAgentUrl === undefined || resolvedParentAgentUrl === null) {
437
- return currentAgentUrl && normalizeAgentUrl(currentAgentUrl) === normalizeAgentUrl(adamAgentUrl)
438
- ? null
439
- : adamAgentUrl;
439
+ const currentAgentUrls = [currentAgentUrl, ...(currentAgentAliases || [])].filter(
440
+ (agentUrl): agentUrl is string_agent_url => Boolean(agentUrl),
441
+ );
442
+ const isCurrentAgentAdam = currentAgentUrls.some(
443
+ (agentUrl) => normalizeAgentUrl(agentUrl) === normalizeAgentUrl(adamAgentUrl),
444
+ );
445
+
446
+ return isCurrentAgentAdam ? null : adamAgentUrl;
440
447
  }
441
448
 
442
449
  throw new ParseError(
@@ -496,7 +503,7 @@ async function resolveParentAgentContext(
496
503
  agentSource: string_book,
497
504
  context: AgentImportContext,
498
505
  ): Promise<ResolvedParentAgentContext> {
499
- const explicitFromContent = getLastSingleLineCommitmentContent(agentSource, 'FROM');
506
+ const explicitFromContent = getExplicitFromCommitmentContent(agentSource);
500
507
  const hasExplicitFromCommitment = explicitFromContent !== undefined;
501
508
  const resolvedParentAgentUrl = await resolveParentAgentUrlFromCommitments(
502
509
  agentSource,
@@ -510,14 +517,21 @@ async function resolveParentAgentContext(
510
517
  hasExplicitFromCommitment,
511
518
  context.adamAgentUrl,
512
519
  context.resolutionOptions?.currentAgentUrl,
520
+ context.resolutionOptions?.currentAgentAliases,
513
521
  agentSource,
514
522
  );
515
- const parentAgentSourceCorpus = parentAgentUrl ? await importAgentCorpus(parentAgentUrl, 'FROM', context) : null;
523
+ const isCyclicFrom = Boolean(parentAgentUrl && findResolutionCycle(parentAgentUrl, context.resolutionOptions));
524
+ const effectiveParentAgentUrl = isCyclicFrom ? null : parentAgentUrl;
525
+ const parentAgentSourceCorpus = effectiveParentAgentUrl
526
+ ? await importAgentCorpus(effectiveParentAgentUrl, 'FROM', context)
527
+ : null;
516
528
 
517
529
  return {
518
- parentAgentUrl,
530
+ // A parent that closes the current lineage has the same runtime effect as `FROM @Null`.
531
+ parentAgentUrl: effectiveParentAgentUrl,
519
532
  parentAgentSourceCorpus,
520
533
  fromResolutionIssues,
534
+ isCyclicFrom,
521
535
  };
522
536
  }
523
537
 
@@ -591,36 +605,18 @@ async function resolveImportCommitmentLine(line: string, context: AgentImportCon
591
605
  }
592
606
 
593
607
  /**
594
- * Resolves one explicit `FROM ...` line into inherited content or fallback NOTE lines.
608
+ * Resolves the effective `FROM ...` line into inherited content or fallback NOTE lines.
595
609
  *
596
610
  * @param line - Current source line.
597
- * @param agentSource - Full source used for duplicate-`FROM` diagnostics.
598
- * @param isFromResolved - Whether a previous `FROM ...` line was already handled.
599
611
  * @param parentContext - Effective parent state computed earlier in the resolution.
600
612
  * @returns Output lines and remaining `FROM` issues.
601
613
  */
602
614
  function resolveFromCommitmentLine(
603
615
  line: string,
604
- agentSource: string_book,
605
- isFromResolved: boolean,
606
616
  parentContext: ResolvedParentAgentContext,
607
617
  ): ResolvedFromCommitmentLine {
608
- if (isFromResolved) {
609
- throw new UnexpectedError(
610
- spaceTrim(
611
- (block) => `
612
- Multiple \`FROM\` commitments found in agent source:
613
-
614
- \`\`\`book
615
- ${block(agentSource)}
616
- \`\`\`
617
- `,
618
- ),
619
- );
620
- }
621
-
622
618
  if (parentContext.parentAgentUrl === null) {
623
- const agentSourceChunks = [line];
619
+ const agentSourceChunks = [parentContext.isCyclicFrom ? 'FROM @Null' : line];
624
620
 
625
621
  if (parentContext.fromResolutionIssues.length > 0) {
626
622
  appendResolutionIssueNotes(agentSourceChunks, parentContext.fromResolutionIssues);
@@ -654,6 +650,23 @@ function resolveFromCommitmentLine(
654
650
  };
655
651
  }
656
652
 
653
+ /**
654
+ * Finds the `FROM` lines that a later `FROM` takes precedence over.
655
+ *
656
+ * A book is allowed to repeat `FROM`; the last one wins, so every earlier one is dropped instead of being resolved.
657
+ * The Book editor warns about this while the author is still writing the book.
658
+ *
659
+ * @param explicitFromCommitments - Explicit parent declarations found in source order.
660
+ * @returns Zero-based indexes of every overridden `FROM` line, empty when at most one `FROM` is present.
661
+ */
662
+ function collectOverriddenFromLineIndexes(
663
+ explicitFromCommitments: ReadonlyArray<{ readonly lineIndex: number }>,
664
+ ): ReadonlySet<number> {
665
+ return new Set(
666
+ explicitFromCommitments.slice(0, -1).map((explicitFromCommitment) => explicitFromCommitment.lineIndex),
667
+ );
668
+ }
669
+
657
670
  /**
658
671
  * Rewrites the source body line by line while delegating each branching step to a focused helper.
659
672
  *
@@ -669,26 +682,31 @@ async function resolveAgentSourceBuild(
669
682
  ): Promise<ResolvedAgentSourceBuild> {
670
683
  const agentSourceChunks = spaceTrim(agentSource).split(/\r?\n/);
671
684
  const resolvedAgentSourceChunks: Array<string> = [];
685
+ const explicitFromCommitments = collectExplicitFromCommitments(agentSourceChunks);
686
+ const effectiveFromCommitment = explicitFromCommitments[explicitFromCommitments.length - 1];
687
+ const overriddenFromLineIndexes = collectOverriddenFromLineIndexes(explicitFromCommitments);
672
688
  let isFromResolved = false;
673
689
  let fromResolutionIssues = parentContext.fromResolutionIssues;
674
690
  // <- TODO: [🈲] Simple and encapsulated way to split book into commitments
675
691
 
676
- for (const line of agentSourceChunks) {
692
+ for (let lineIndex = 0; lineIndex < agentSourceChunks.length; lineIndex++) {
693
+ const line = agentSourceChunks[lineIndex] || '';
694
+
695
+ // Note: A repeated `FROM` is overridden by the last one, so the outdated line is dropped from the resolved source.
696
+ if (overriddenFromLineIndexes.has(lineIndex)) {
697
+ continue;
698
+ }
699
+
677
700
  if (line.trim().startsWith('IMPORT ')) {
678
701
  resolvedAgentSourceChunks.push(...(await resolveImportCommitmentLine(line, context)));
679
702
  continue;
680
703
  }
681
704
 
682
- if (line.trim().startsWith('FROM ')) {
683
- const resolvedFromCommitment = resolveFromCommitmentLine(
684
- line,
685
- agentSource,
686
- isFromResolved,
687
- {
688
- ...parentContext,
689
- fromResolutionIssues,
690
- },
691
- );
705
+ if (effectiveFromCommitment?.lineIndex === lineIndex) {
706
+ const resolvedFromCommitment = resolveFromCommitmentLine(line, {
707
+ ...parentContext,
708
+ fromResolutionIssues,
709
+ });
692
710
 
693
711
  resolvedAgentSourceChunks.push(...resolvedFromCommitment.agentSourceChunks);
694
712
  fromResolutionIssues = resolvedFromCommitment.fromResolutionIssues;
@@ -779,15 +797,16 @@ function assertNoResolutionCycle(
779
797
  commitmentType: 'FROM' | 'IMPORT',
780
798
  options?: ResolveInheritedAgentSourceOptions,
781
799
  ): void {
782
- const normalizedReferenceUrl = normalizeAgentUrl(referenceUrl);
783
- const lineage = createResolutionLineage(options);
784
- const cycleStartIndex = lineage.findIndex((visitedUrl) => visitedUrl === normalizedReferenceUrl);
800
+ const resolutionCycle = findResolutionCycle(referenceUrl, options);
785
801
 
786
- if (cycleStartIndex === -1) {
802
+ if (!resolutionCycle) {
787
803
  return;
788
804
  }
789
805
 
790
- const cycleChain = [...lineage.slice(cycleStartIndex), normalizedReferenceUrl]
806
+ const cycleChain = [
807
+ ...resolutionCycle.lineage.slice(resolutionCycle.cycleStartIndex),
808
+ resolutionCycle.normalizedReferenceUrl,
809
+ ]
791
810
  .map((visitedUrl) => `- \`${visitedUrl}\``)
792
811
  .join('\n');
793
812
 
@@ -107,6 +107,10 @@ export type UserChatTimeout = {
107
107
  durationMs: number;
108
108
  dueAt: string;
109
109
  recurrenceIntervalMs: number | null;
110
+ cronExpression: string | null;
111
+ startsAt: string | null;
112
+ endsAt: string | null;
113
+ maxRunCount: number | null;
110
114
  queuedAt: string;
111
115
  startedAt: string | null;
112
116
  completedAt: string | null;
@@ -27,6 +27,10 @@ export type UserChatTimeoutRecord = {
27
27
  durationMs: number;
28
28
  dueAt: string;
29
29
  recurrenceIntervalMs: number | null;
30
+ cronExpression: string | null;
31
+ startsAt: string | null;
32
+ endsAt: string | null;
33
+ maxRunCount: number | null;
30
34
  queuedAt: string;
31
35
  startedAt: string | null;
32
36
  completedAt: string | null;
@@ -55,6 +59,10 @@ export type UserChatTimeoutRow = {
55
59
  durationMs: number;
56
60
  dueAt: string;
57
61
  recurrenceIntervalMs: number | null;
62
+ cronExpression: string | null;
63
+ startsAt: string | null;
64
+ endsAt: string | null;
65
+ maxRunCount: number | null;
58
66
  queuedAt: string;
59
67
  startedAt: string | null;
60
68
  completedAt: string | null;
@@ -83,6 +91,10 @@ export type UserChatTimeoutInsert = {
83
91
  durationMs: number;
84
92
  dueAt: string;
85
93
  recurrenceIntervalMs?: number | null;
94
+ cronExpression?: string | null;
95
+ startsAt?: string | null;
96
+ endsAt?: string | null;
97
+ maxRunCount?: number | null;
86
98
  queuedAt: string;
87
99
  startedAt?: string | null;
88
100
  completedAt?: string | null;
@@ -97,15 +109,22 @@ export type UserChatTimeoutInsert = {
97
109
 
98
110
  /**
99
111
  * Input used when persisting one new chat timeout.
112
+ *
113
+ * The schedule fields describe the whole life of a planned message, so `durationMs` and `dueAt` are
114
+ * only needed by a caller that schedules one plain wake-up at a fixed delay.
100
115
  */
101
116
  export type CreateUserChatTimeoutOptions = {
102
117
  id?: string;
103
118
  userId: number;
104
119
  agentPermanentId: string;
105
120
  chatId: string;
106
- durationMs: number;
121
+ durationMs?: number;
107
122
  dueAt?: string;
108
123
  recurrenceIntervalMs?: number | null;
124
+ cronExpression?: string | null;
125
+ startsAt?: string | null;
126
+ endsAt?: string | null;
127
+ maxRunCount?: number | null;
109
128
  message?: string;
110
129
  parameters?: UserChatTimeoutParameters;
111
130
  };
@@ -130,6 +149,16 @@ export type ListUserChatTimeoutsOptions = {
130
149
  onlyActive?: boolean;
131
150
  };
132
151
 
152
+ /**
153
+ * Query options for listing the timeouts of every agent on the server.
154
+ */
155
+ export type ListAllUserChatTimeoutsOptions = {
156
+ /**
157
+ * Largest number of rows to return, newest first.
158
+ */
159
+ limit: number;
160
+ };
161
+
133
162
  /**
134
163
  * Query options for loading one timeout scoped only to user + agent.
135
164
  */
@@ -162,10 +191,17 @@ export type ListAgentUserChatTimeoutsOptions = {
162
191
 
163
192
  /**
164
193
  * Mutable fields accepted when editing one agent-scoped timeout.
194
+ *
195
+ * Every schedule field that is present is written, so leaving one out keeps it as it is and passing
196
+ * `null` removes it.
165
197
  */
166
198
  export type UpdateAgentScopedUserChatTimeoutPatch = {
167
199
  dueAt?: string;
168
200
  recurrenceIntervalMs?: number | null;
201
+ cronExpression?: string | null;
202
+ startsAt?: string | null;
203
+ endsAt?: string | null;
204
+ maxRunCount?: number | null;
169
205
  message?: string | null;
170
206
  parameters?: UserChatTimeoutParameters;
171
207
  pausedAt?: string | null;
@@ -1,6 +1,7 @@
1
+ import { setAgentScopedUserChatTimeoutPausedState } from './setAgentScopedUserChatTimeoutPausedState';
1
2
  import type { UserChatTimeoutStatus, UserChatTimeoutRecord } from './UserChatTimeoutRecord';
2
- import { listAgentUserChatTimeouts, updateAgentScopedUserChatTimeout } from './userChatTimeoutStore';
3
- import { cancelScheduledUserChatTimeout, notifyUserChatTimeoutScheduleChanged } from './userChatTimeoutWorker';
3
+ import { listAgentUserChatTimeouts } from './userChatTimeoutStore';
4
+ import { cancelScheduledUserChatTimeout } from './userChatTimeoutWorker';
4
5
 
5
6
  /**
6
7
  * Number of timeout rows loaded per page while collecting bulk-mutation targets.
@@ -68,22 +69,18 @@ export async function pauseAllActiveAgentScopedUserChatTimeouts(options: {
68
69
  statuses: ['QUEUED'],
69
70
  paused: false,
70
71
  });
71
- const pausedAtIso = new Date().toISOString();
72
72
  const pausedTimeoutIds: Array<string> = [];
73
73
 
74
74
  for (const timeout of collectedTimeouts.timeouts) {
75
- const updatedTimeout = await updateAgentScopedUserChatTimeout({
75
+ const pauseResult = await setAgentScopedUserChatTimeoutPausedState({
76
76
  userId: options.userId,
77
77
  agentPermanentId: options.agentPermanentId,
78
78
  timeoutId: timeout.timeoutId,
79
- patch: {
80
- pausedAt: pausedAtIso,
81
- },
79
+ isPaused: true,
82
80
  });
83
81
 
84
- if (updatedTimeout && updatedTimeout.pausedAt) {
85
- notifyUserChatTimeoutScheduleChanged(updatedTimeout);
86
- pausedTimeoutIds.push(updatedTimeout.timeoutId);
82
+ if (pauseResult.isApplied) {
83
+ pausedTimeoutIds.push(pauseResult.plannedMessage.timeoutId);
87
84
  }
88
85
  }
89
86
 
@@ -111,18 +108,15 @@ export async function resumeAllPausedAgentScopedUserChatTimeouts(options: {
111
108
  const resumedTimeoutIds: Array<string> = [];
112
109
 
113
110
  for (const timeout of collectedTimeouts.timeouts) {
114
- const updatedTimeout = await updateAgentScopedUserChatTimeout({
111
+ const resumeResult = await setAgentScopedUserChatTimeoutPausedState({
115
112
  userId: options.userId,
116
113
  agentPermanentId: options.agentPermanentId,
117
114
  timeoutId: timeout.timeoutId,
118
- patch: {
119
- pausedAt: null,
120
- },
115
+ isPaused: false,
121
116
  });
122
117
 
123
- if (updatedTimeout && !updatedTimeout.pausedAt) {
124
- notifyUserChatTimeoutScheduleChanged(updatedTimeout);
125
- resumedTimeoutIds.push(updatedTimeout.timeoutId);
118
+ if (resumeResult.isApplied) {
119
+ resumedTimeoutIds.push(resumeResult.plannedMessage.timeoutId);
126
120
  }
127
121
  }
128
122
 
@@ -1,30 +1,54 @@
1
1
  import { spaceTrim } from 'spacetrim';
2
- import { formatTimeoutDurationHuman } from '../../../../../src/book-components/Chat/utils/timeoutToolCallPresentation';
2
+ import {
3
+ describeAgentPlannedMessageSchedule,
4
+ type AgentPlannedMessageScheduleDescription,
5
+ } from '../../../../../src/book-3.0/describeAgentPlannedMessageSchedule';
3
6
 
4
7
  /**
5
8
  * Builds the synthetic user-like message injected when a timeout elapses.
6
9
  *
7
- * A repeating planned message stays armed after every firing, so its wake-up says so: the agent
8
- * only has to act on the message itself, not to plan the same wake-up again.
10
+ * A planned message carries its whole schedule into its own wake-up, so the agent immediately knows
11
+ * whether this was its last run and does not have to plan anything again just to keep the plan alive.
9
12
  *
10
13
  * @private internal utility of userChatTimeout
11
14
  */
12
- export function createTimeoutWakeUpMessage(options: {
13
- readonly timeoutId: string;
14
- readonly durationMs: number;
15
- readonly intervalMs?: number | null;
16
- readonly message?: string | null;
17
- }): string {
15
+ export function createTimeoutWakeUpMessage(
16
+ options: AgentPlannedMessageScheduleDescription & {
17
+ readonly timeoutId: string;
18
+ readonly durationMs: number;
19
+ readonly message?: string | null;
20
+ },
21
+ ): string {
18
22
  const message = options.message?.trim() || '';
19
- const headline = options.intervalMs
20
- ? `⏱️ Planned message elapsed, repeating every ${formatTimeoutDurationHuman(options.intervalMs)}.`
21
- : `⏱️ Timeout elapsed after ${options.durationMs}ms.`;
22
23
 
23
24
  return spaceTrim(
24
25
  (block) => `
25
- ${headline}
26
+ ${createTimeoutWakeUpHeadline(options)}
26
27
  timeoutId: ${options.timeoutId}
27
28
  ${message ? block(message) : ''}
28
29
  `,
29
30
  );
30
31
  }
32
+
33
+ /**
34
+ * Builds the first line of one wake-up, telling the agent what woke it and where in its plan it is.
35
+ *
36
+ * @param options - Schedule of the planned message together with the plain timeout duration.
37
+ * @returns Headline of the wake-up message.
38
+ *
39
+ * @private internal utility of `createTimeoutWakeUpMessage`
40
+ */
41
+ function createTimeoutWakeUpHeadline(
42
+ options: AgentPlannedMessageScheduleDescription & { readonly durationMs: number },
43
+ ): string {
44
+ if (options.intervalMs || options.cronExpression) {
45
+ // Note: The next wake-up is resolved only after this one is queued, so the schedule is described without it
46
+ return `⏱️ Planned message elapsed, ${describeAgentPlannedMessageSchedule({ ...options, dueAt: null })}.`;
47
+ }
48
+
49
+ if (options.maxRunCount || options.startsAt) {
50
+ return '⏱️ Planned message elapsed, this was its only wake-up.';
51
+ }
52
+
53
+ return `⏱️ Timeout elapsed after ${options.durationMs}ms.`;
54
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Shortest repeat interval one planned message may use.
3
+ *
4
+ * A planned message wakes a whole agent invocation, so an interval below one minute would turn a plan
5
+ * into an unattended self-invocation loop. Cron expressions have the very same one-minute resolution.
6
+ *
7
+ * @private constant of `plannedMessageSchedule`
8
+ */
9
+ export const MINIMUM_PLANNED_MESSAGE_INTERVAL_MS = 60_000;
10
+
11
+ /**
12
+ * Complete recurrence rule of one planned message.
13
+ *
14
+ * A planned message can be a one-shot wake-up, an endless repetition, or anything between the two:
15
+ * `cronExpression` or `recurrenceIntervalMs` says how it repeats, while `startsAt`, `endsAt`, and
16
+ * `maxRunCount` bound how long it keeps repeating.
17
+ *
18
+ * Field names match `UserChatTimeoutRecord`, so one stored timeout row is already a valid schedule.
19
+ *
20
+ * @private type of `plannedMessageSchedule`
21
+ */
22
+ export type PlannedMessageSchedule = {
23
+ /**
24
+ * Five-field cron expression evaluated in the local server time, or `null` when the planned
25
+ * message does not follow a cron.
26
+ */
27
+ readonly cronExpression: string | null;
28
+
29
+ /**
30
+ * Fixed repeat interval in milliseconds, or `null` when the planned message does not repeat at a
31
+ * fixed interval.
32
+ */
33
+ readonly recurrenceIntervalMs: number | null;
34
+
35
+ /**
36
+ * Moment before which the planned message never wakes the agent, or `null` when it may start
37
+ * immediately.
38
+ */
39
+ readonly startsAt: string | null;
40
+
41
+ /**
42
+ * Moment after which the planned message never wakes the agent again, or `null` when it has no
43
+ * ending date.
44
+ */
45
+ readonly endsAt: string | null;
46
+
47
+ /**
48
+ * Total number of times the planned message wakes the agent, or `null` when it repeats until it
49
+ * is cancelled.
50
+ */
51
+ readonly maxRunCount: number | null;
52
+ };
@@ -0,0 +1,13 @@
1
+ import type { PlannedMessageSchedule } from './PlannedMessageSchedule';
2
+
3
+ /**
4
+ * Determines whether one planned message can wake the agent more than once.
5
+ *
6
+ * @param schedule - Recurrence rule of the planned message.
7
+ * @returns `true` when the schedule has a cron expression or a fixed repeat interval.
8
+ *
9
+ * @private function of `plannedMessageSchedule`
10
+ */
11
+ export function hasPlannedMessageRecurrence(schedule: PlannedMessageSchedule): boolean {
12
+ return Boolean(schedule.cronExpression || schedule.recurrenceIntervalMs);
13
+ }
@@ -0,0 +1,30 @@
1
+ import type { PlannedMessageSchedule } from './PlannedMessageSchedule';
2
+ import { normalizePlannedMessageDateIso } from './normalizePlannedMessageScheduleValues';
3
+
4
+ /**
5
+ * Determines whether one planned message must never wake the agent again.
6
+ *
7
+ * A planned message is finished once it ran as many times as it was planned to run, or once its
8
+ * ending date has passed. Such a message is closed instead of being fired, so an agent is never woken
9
+ * by a plan it already completed.
10
+ *
11
+ * @param options - Recurrence rule, how many times it already ran, and the moment being judged.
12
+ * @returns `true` when no further wake-up is allowed.
13
+ *
14
+ * @private function of `plannedMessageSchedule`
15
+ */
16
+ export function isPlannedMessageScheduleFinished(options: {
17
+ readonly schedule: PlannedMessageSchedule;
18
+ readonly completedRunCount: number;
19
+ readonly atDate: Date;
20
+ }): boolean {
21
+ const { schedule, completedRunCount, atDate } = options;
22
+
23
+ if (schedule.maxRunCount !== null && completedRunCount >= schedule.maxRunCount) {
24
+ return true;
25
+ }
26
+
27
+ const endsAtIso = normalizePlannedMessageDateIso(schedule.endsAt);
28
+
29
+ return endsAtIso !== null && atDate.getTime() > Date.parse(endsAtIso);
30
+ }