@sentry/junior 0.232.0 → 0.234.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/{agent-hooks-n9qfV697.js → agent-hooks-BcH6E48y.js} +89 -12
  2. package/dist/{agent-runner-D_FVvrwA.js → agent-runner-DUkGlK89.js} +224 -768
  3. package/dist/api/schema.d.ts +538 -2
  4. package/dist/api/schema.js +4 -4
  5. package/dist/api.js +230 -19
  6. package/dist/app.js +31 -21
  7. package/dist/{briefs-B7wDx-LM.js → briefs-lyAQbDxJ.js} +4 -4
  8. package/dist/{catalog-runtime-FU8TmK-W.js → catalog-runtime-BSgsPVnr.js} +1 -1
  9. package/dist/{checkpoint-DuA1tIcd.js → checkpoint-BNfXlq_1.js} +7 -7
  10. package/dist/cli/chat.js +13 -13
  11. package/dist/cli/check.js +3 -3
  12. package/dist/cli/main.js +1 -1
  13. package/dist/cli/plugins.js +3 -3
  14. package/dist/cli/snapshot-create.js +3 -3
  15. package/dist/cli/upgrade.js +3 -3
  16. package/dist/{client-BMqP14EE.js → client-BX5lJRqW.js} +2 -2
  17. package/dist/{config-Q7ayKDYh.js → config-DuCzUoCo.js} +2 -2
  18. package/dist/{conversation-DsuDtoYR.js → conversation-CPjHYOV5.js} +13 -2
  19. package/dist/{conversation-privacy-DNNsgprf.js → conversation-privacy-CSxvdSoV.js} +1 -1
  20. package/dist/{credential-sync-DbgAGIhd.js → credential-sync-BO4DfH9a.js} +13 -13
  21. package/dist/{executor-DDonSWxn.js → executor--jWf-Nnm.js} +1 -1
  22. package/dist/{images-Bj8PcvZ5.js → images-BaL19wFC.js} +3 -3
  23. package/dist/instrumentation.js +2 -2
  24. package/dist/{job-queue-Dqc7qQbR.js → job-queue-cwHVOwVZ.js} +1 -1
  25. package/dist/{logging-X4U7SInw.js → logging-Cox1Mgcv.js} +1 -1
  26. package/dist/nitro.js +3 -3
  27. package/dist/{oauth-authorization-CetcZcwQ.js → oauth-authorization-CC8a1JKP.js} +1 -1
  28. package/dist/{oauth-callback-server-o34WSoGm.js → oauth-callback-server-Z7QSt416.js} +2 -2
  29. package/dist/{pending-auth-XoxEa4O5.js → pending-auth-DQhC3eSR.js} +1 -1
  30. package/dist/{profile-DzqqgpDo.js → profile-BdApelHS.js} +4 -4
  31. package/dist/{prompt-D5RPLy92.js → prompt-3D0sSbTC.js} +1 -1
  32. package/dist/{registry-RrIfDnkS.js → registry-DiY6B8CN.js} +1 -1
  33. package/dist/{resolve-Ccu6uGtp.js → resolve-VpJoiDpc.js} +2 -2
  34. package/dist/{runner-DDQCEV1P.js → runner-BIMegnPE.js} +9 -9
  35. package/dist/{sandbox-egress-signals-CT3xOtNG.js → sandbox-egress-signals-Cbtxe492.js} +1 -1
  36. package/dist/{schema-B-Taar1W.js → schema-CxwnlTDN.js} +4 -117
  37. package/dist/{skills-NB_I9BuR.js → skills-WttpPJUy.js} +2 -2
  38. package/dist/{spawn-DmwIhiNu.js → spawn-DhfMKt4y.js} +2 -2
  39. package/dist/{task-queue-B5CERq_E.js → task-queue-CZqUNJD0.js} +3 -3
  40. package/dist/{task-runner-COivEGS3.js → task-runner-BZaqoUCT.js} +16 -13
  41. package/dist/{thread-state-C7yyfiVM.js → thread-state-8tXZhu0y.js} +5 -5
  42. package/dist/{turn-failure-response-D990svo-.js → turn-failure-response-DFJ9L9NQ.js} +8 -8
  43. package/dist/{turn-lifecycle-C-LUNJC6.js → turn-lifecycle-WbpTUQ_r.js} +1 -1
  44. package/dist/{turn-session-routing-CoF0GbaY.js → turn-session-routing--EhI76rH.js} +1 -1
  45. package/dist/types-Du-HbEun.js +621 -0
  46. package/dist/{validation-f0y71ety.js → validation-0F9IgG3b.js} +1 -1
  47. package/dist/{version-CkRTIRkV.js → version-A7-RRBOE.js} +1 -1
  48. package/dist/version.js +1 -1
  49. package/dist/{web-authorization-BBwQsNCZ.js → web-authorization-BJggXofy.js} +6 -6
  50. package/dist/{web-input-Bkn-JGWd.js → web-input-B-siN5Dr.js} +212 -164
  51. package/dist/web-message-id-CVVCTWUb.js +464 -0
  52. package/dist/{work-vWPq9P5x.js → work-CNc0ejGG.js} +7 -7
  53. package/dist/{worker-BgZog5Jp.js → worker-BHbqpUAu.js} +5 -5
  54. package/package.json +5 -5
  55. package/dist/web-message-id-xPI_EFSC.js +0 -239
@@ -1,26 +1,27 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.js";
2
- import { b as getGatewayApiKey, c as hasCompactedConversationContext, d as unwrapCurrentInstruction, f as escapeXml, g as getProviderErrorAttributes, h as findProviderError, i as completeText, l as isCompactionSummaryText, m as createProviderError, n as GEN_AI_SERVER_ADDRESS, o as resolveGatewayModel, p as ProviderError, r as completeObject, s as COMPACTION_SUMMARY_PREFIX, t as GEN_AI_PROVIDER_NAME, u as renderCurrentInstruction, v as isProviderRetryError, x as resolveGatewayCredential, y as MISSING_GATEWAY_CREDENTIALS_ERROR } from "./client-BMqP14EE.js";
3
- import { C as withLogContext, F as normalizeIdentityEmail, I as isRecord$3, L as toOptionalNumber, R as toOptionalString, a as extractGenAiUsageSummary, b as setTags, c as getLogContextAttributesForSpan, d as logException, f as logInfo, g as serializeGenAiAttribute, i as extractGenAiUsageAttributes, l as getTracePropagationHeaders, m as normalizeGenAiFinishReason, p as logWarn, s as getLogContextAttributes, u as logError, v as setSpanAttributes, w as withSpan, x as summarizeMessageText, y as setSpanStatus } from "./logging-X4U7SInw.js";
2
+ import { b as getGatewayApiKey, c as hasCompactedConversationContext, d as unwrapCurrentInstruction, f as escapeXml, g as getProviderErrorAttributes, h as findProviderError, i as completeText, l as isCompactionSummaryText, m as createProviderError, n as GEN_AI_SERVER_ADDRESS, o as resolveGatewayModel, p as ProviderError, r as completeObject, s as COMPACTION_SUMMARY_PREFIX, t as GEN_AI_PROVIDER_NAME, u as renderCurrentInstruction, v as isProviderRetryError, x as resolveGatewayCredential, y as MISSING_GATEWAY_CREDENTIALS_ERROR } from "./client-BX5lJRqW.js";
3
+ import { C as withLogContext, F as normalizeIdentityEmail, I as isRecord$3, L as toOptionalNumber, R as toOptionalString, a as extractGenAiUsageSummary, b as setTags, c as getLogContextAttributesForSpan, d as logException, f as logInfo, g as serializeGenAiAttribute, i as extractGenAiUsageAttributes, l as getTracePropagationHeaders, m as normalizeGenAiFinishReason, p as logWarn, s as getLogContextAttributes, u as logError, v as setSpanAttributes, w as withSpan, x as summarizeMessageText, y as setSpanStatus } from "./logging-Cox1Mgcv.js";
4
4
  import { m as startInactiveSpan, n as captureMessage, v as withActiveSpan } from "./sentry-CgWZM_kV.js";
5
- import { a as toCanonicalInputMessage, c as toGenAiPayloadMetadata, i as runWithConversationPrivacy, l as toGenAiPayloadTraceAttributes, o as toCanonicalOutputMessage, r as resolveConversationPrivacy, s as toGenAiMessagesTraceAttributes, t as canExposeConversationPayload } from "./conversation-privacy-DNNsgprf.js";
6
- import { a as getChatConfig, h as normalizeSlackEmojiName, n as botConfig } from "./config-Q7ayKDYh.js";
5
+ import { a as toCanonicalInputMessage, c as toGenAiPayloadMetadata, i as runWithConversationPrivacy, l as toGenAiPayloadTraceAttributes, o as toCanonicalOutputMessage, r as resolveConversationPrivacy, s as toGenAiMessagesTraceAttributes, t as canExposeConversationPayload } from "./conversation-privacy-CSxvdSoV.js";
6
+ import { a as getChatConfig, h as normalizeSlackEmojiName, n as botConfig } from "./config-DuCzUoCo.js";
7
7
  import { a as formatModelProfiles, c as profileConfig, i as formatModelProfile, l as TURN_REASONING_LEVELS, n as ModelProfileNotConfiguredError, o as modelIdForProfile, s as modelProfileSchema } from "./model-profile-BwU8mqwD.js";
8
8
  import { b as parseSlackMessageTs, d as parseStoredSlackActor, g as parseSlackUserId, h as parseSlackTeamId, i as credentialUserSubjectId, l as isUserActor, m as parseSlackChannelReferenceId, n as credentialContextSchema, p as parseSlackChannelId, t as credentialContextForActor } from "./context-0Et9iVSB.js";
9
- import { $t as getConversationStore, A as tryWorkspaceRepoCheckoutPath, B as downloadPrivateSlackFile, C as invalidateReadySnapshot, Ct as createPluginLogger, D as SANDBOX_RUNTIME, E as setWorkspaceSnapshotBuild, G as isDmChannel$1, Ht as saveObjectAnnotations, J as withSlackRetries, K as normalizeSlackConversationId, M as resolveChannelCapabilities, O as deleteWorkspaceSnapshotBuilders, Q as readActorIdentity, Qt as getConversationMessageSearchStore, Rt as matchSlackAttachments, S as WorkspaceValidationError, T as setWorkspaceSnapshot, U as getSlackClient, Ut as createPluginAnnotations, V as getFilePermalink, W as isConversationScopedChannel, Zt as getConversationEventStore, _ as deleteWorkspace, at as STOP_WATCHING_TOOL_NAME, b as listWorkspaces, bn as sameDestination$1, c as getPluginTools, cn as addAgentTurnUsage, dt as deliverWatch, en as getDb, fn as hasAgentTurnUsage, ft as findMatchingWatches, g as createWorkspace, gt as getDashboardConversationLink, ht as JUNIOR_THREAD_STATE_TTL_MS, it as RESOURCE_WATCH_TOOL_SOURCE, j as workspaceRepoCheckoutPath, k as getWorkspaceSnapshotBuilder, l as getPluginUserPromptContributions, lt as createTimerWatch, n as applyPluginFormatMarkdown, nt as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, ot as cancelSubscriptions, pt as listWatches, r as createPluginHookRunner, rt as RESOURCE_SUBSCRIPTION_MAX_TTL_MS, s as getPluginSystemPromptContributions, st as cancelWatch, tn as getSqlExecutor, tt as getSlackToolContext, u as getPlugins, ut as createWatch, v as getWorkspace, vn as parseDestination, vt as getDashboardTaskLink, w as loadSnapshotsForProfile, x as updateWorkspace, y as getWorkspaceByName, z as SlackActionError } from "./agent-hooks-n9qfV697.js";
9
+ import { $t as getConversationStore, A as tryWorkspaceRepoCheckoutPath, B as downloadPrivateSlackFile, C as invalidateReadySnapshot, Ct as createPluginLogger, D as SANDBOX_RUNTIME, E as setWorkspaceSnapshotBuild, G as isDmChannel$1, Ht as saveObjectAnnotations, J as withSlackRetries, K as normalizeSlackConversationId, M as resolveChannelCapabilities, O as deleteWorkspaceSnapshotBuilders, Q as readActorIdentity, Qt as getConversationMessageSearchStore, Rt as matchSlackAttachments, S as WorkspaceValidationError, T as setWorkspaceSnapshot, U as getSlackClient, Ut as createPluginAnnotations, V as getFilePermalink, W as isConversationScopedChannel, Zt as getConversationEventStore, _ as deleteWorkspace, at as STOP_WATCHING_TOOL_NAME, b as listWorkspaces, bn as sameDestination$1, c as getPluginTools, cn as addAgentTurnUsage, dt as deliverWatch, en as getDb, fn as hasAgentTurnUsage, ft as findMatchingWatches, g as createWorkspace, gt as getDashboardConversationLink, ht as JUNIOR_THREAD_STATE_TTL_MS, it as RESOURCE_WATCH_TOOL_SOURCE, j as workspaceRepoCheckoutPath, k as getWorkspaceSnapshotBuilder, l as getPluginUserPromptContributions, lt as createTimerWatch, n as applyPluginFormatMarkdown, nt as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, ot as cancelSubscriptions, pt as listWatches, r as createPluginHookRunner, rt as RESOURCE_SUBSCRIPTION_MAX_TTL_MS, s as getPluginSystemPromptContributions, st as cancelWatch, tn as getSqlExecutor, tt as getSlackToolContext, u as getPlugins, ut as createWatch, v as getWorkspace, vn as parseDestination, vt as getDashboardTaskLink, w as loadSnapshotsForProfile, x as updateWorkspace, y as getWorkspaceByName, z as SlackActionError } from "./agent-hooks-BcH6E48y.js";
10
10
  import { n as juniorDestinations } from "./destinations-BeBiJeEM.js";
11
- import { D as juniorIdentities, E as juniorConversations, a as juniorSchedulerRuns, c as juniorStats, d as AGENT_INVOCATION_MAILBOX_STATUSES, g as juniorConversationBriefs, k as juniorArtifacts, l as juniorEventAutomations, o as juniorSchedulerTasks, w as juniorAttachments, x as juniorConversationAnnotations } from "./executor-DDonSWxn.js";
12
- import { F as briefLinkSchema, G as KNOWN_CONVERSATION_EVENT_TYPES, I as briefOutcomeStatusSchema, L as conversationBriefSchema, N as isVisionImageMediaType, U as removedCardSchema, et as contextProvenance, nt as instructionProvenanceFor, rt as sameActorIdentity, tt as instructionActors } from "./conversation-DsuDtoYR.js";
11
+ import { D as juniorIdentities, E as juniorConversations, a as juniorSchedulerRuns, c as juniorStats, d as AGENT_INVOCATION_MAILBOX_STATUSES, g as juniorConversationBriefs, k as juniorArtifacts, l as juniorEventAutomations, o as juniorSchedulerTasks, w as juniorAttachments, x as juniorConversationAnnotations } from "./executor--jWf-Nnm.js";
12
+ import { F as briefLinkSchema, G as KNOWN_CONVERSATION_EVENT_TYPES, I as briefOutcomeStatusSchema, L as conversationBriefSchema, N as isVisionImageMediaType, U as removedCardSchema, et as contextProvenance, nt as instructionProvenanceFor, rt as sameActorIdentity, tt as instructionActors } from "./conversation-CPjHYOV5.js";
13
13
  import { a as listReferenceFiles, c as soulPathCandidates, l as worldPathCandidates } from "./package-discovery-7a9YqLhE.js";
14
- import { a as resolveAuthTokenPlaceholder, c as fetchWithBoundedOAuthErrorBodies, d as CredentialUnavailableError, i as resolvePluginHeaderEnvRefs, l as getOAuthProviderErrorAttributes, o as resolvePluginCommandEnv, s as OAuthProviderError } from "./registry-RrIfDnkS.js";
15
- import { n as pluginCatalogRuntime } from "./catalog-runtime-FU8TmK-W.js";
16
- import { a as parseSkillInvocation, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-NB_I9BuR.js";
17
- import { $ as fallbackShortTitle, C as isToolResultError, D as stripRuntimeTurnContext, E as retainRuntimeTurnContext, F as loadTurnRoute, G as recordToolExecutionStarted, H as recordGuardianActionReviewed, I as openConversationProjection, K as recordTurnRoute, L as recordAgentsInstructionsUpdated, M as loadConnectedMcpProviders, N as loadConversationProjection, O as trimTrailingAssistantMessages, R as recordAttachmentsDelivered, S as isContinuablePiBoundary, T as normalizeToolNameFromResult, U as recordMcpProviderConnected, V as recordAuthorizationRequested, _ as getTerminalAssistantMessages, _t as piMessageFromHistoryItem, d as TurnSliceLimitExceededError, et as generateShortTitle, f as assertTurnToolCallLimit, g as getPiMessageRole, gt as historyItemFromPiMessage, h as extractAssistantText, ht as getAgentContextInputLimitTokens, k as TURN_CONTEXT_TAG, m as isTurnExecutionLimitExceededError, mt as getAgentContextCompactionTriggerTokens, n as loadTurnCheckpoint, pt as estimateTextTokens, r as saveTurnCheckpoint, t as continuableMessages, tt as resolveTaskTitle, v as getUserMessageInstructionText, w as isToolResultMessage, x as isAssistantMessage, y as hasRuntimeTurnContext } from "./checkpoint-DuA1tIcd.js";
18
- import { A as SANDBOX_DATA_ROOT, C as getDefaultRedisStateAdapterFor, D as fenceLock, E as acquireActiveLock, F as sandboxSkillFile, I as sandboxSkillPathResolution, M as SANDBOX_SKILLS_ROOT, N as SANDBOX_WORKSPACE_ROOT, O as withLock, P as sandboxSkillDir, _ as workspaceSnapshotNotReadyUserMessage, a as isAbortError, b as buildNonInteractiveShellScript, c as isSandboxCommandStreamInterruptedError, d as isSnapshottingError, f as throwSandboxOperationError, g as isWorkspaceSnapshotNotReadyError, h as getWorkspaceSnapshotNotReadyError, i as ensureDockerDaemon, j as SANDBOX_REPOS_ROOT, k as sleep$2, l as isSandboxMissingError, m as WorkspaceSnapshotNotReadyError, n as hash, o as isAlreadyExistsError, p as wrapSandboxSetupError, r as isStale, s as isSandboxApiTransientError, t as create, u as isSandboxUnavailableError, v as getVercelSandboxCredentials, w as getStateAdapter, x as runNonInteractiveCommand, y as buildCommandScript } from "./profile-DzqqgpDo.js";
19
- import { n as canReusePendingAuthLink, t as abandonReplacedPendingAuth } from "./pending-auth-XoxEa4O5.js";
20
- import { a as NO_REPLY_MARKER, c as CooperativeTurnYieldError, i as sanitizeAssistantText, l as TurnInputCommitLostError, n as decideReply, o as isNoReplyMarker, p as isTurnInputCommitLostError, r as getAssistantReplyText, t as authorizationId } from "./oauth-authorization-CetcZcwQ.js";
21
- import { r as EVENT_AUTHOR_ID } from "./prompt-D5RPLy92.js";
22
- import { a as createSandboxSession, c as postinstall, d as getSandboxResources, i as bindSandboxFileSystem, l as setSnapshotSpanAttributes, n as isMissingError, o as stopSession, r as resolve$1, s as dependencies } from "./resolve-Ccu6uGtp.js";
23
- import { a as getVercelConversationWorkQueue, f as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-Dqc7qQbR.js";
14
+ import { a as resolveAuthTokenPlaceholder, c as fetchWithBoundedOAuthErrorBodies, d as CredentialUnavailableError, i as resolvePluginHeaderEnvRefs, l as getOAuthProviderErrorAttributes, o as resolvePluginCommandEnv, s as OAuthProviderError } from "./registry-DiY6B8CN.js";
15
+ import { n as pluginCatalogRuntime } from "./catalog-runtime-BSgsPVnr.js";
16
+ import { a as parseSkillInvocation, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-WttpPJUy.js";
17
+ import { $ as fallbackShortTitle, C as isToolResultError, D as stripRuntimeTurnContext, E as retainRuntimeTurnContext, F as loadTurnRoute, G as recordToolExecutionStarted, H as recordGuardianActionReviewed, I as openConversationProjection, K as recordTurnRoute, L as recordAgentsInstructionsUpdated, M as loadConnectedMcpProviders, N as loadConversationProjection, O as trimTrailingAssistantMessages, R as recordAttachmentsDelivered, S as isContinuablePiBoundary, T as normalizeToolNameFromResult, U as recordMcpProviderConnected, V as recordAuthorizationRequested, _ as getTerminalAssistantMessages, d as TurnSliceLimitExceededError, et as resolveTaskTitle, f as assertTurnToolCallLimit, ft as estimateTextTokens, g as getPiMessageRole, gt as piMessageFromHistoryItem, h as extractAssistantText, ht as historyItemFromPiMessage, k as TURN_CONTEXT_TAG, m as isTurnExecutionLimitExceededError, mt as getAgentContextInputLimitTokens, n as loadTurnCheckpoint, pt as getAgentContextCompactionTriggerTokens, r as saveTurnCheckpoint, t as continuableMessages, v as getUserMessageInstructionText, w as isToolResultMessage, x as isAssistantMessage, y as hasRuntimeTurnContext } from "./checkpoint-BNfXlq_1.js";
18
+ import { A as SANDBOX_DATA_ROOT, C as getDefaultRedisStateAdapterFor, D as fenceLock, E as acquireActiveLock, F as sandboxSkillFile, I as sandboxSkillPathResolution, M as SANDBOX_SKILLS_ROOT, N as SANDBOX_WORKSPACE_ROOT, O as withLock, P as sandboxSkillDir, _ as workspaceSnapshotNotReadyUserMessage, a as isAbortError, b as buildNonInteractiveShellScript, c as isSandboxCommandStreamInterruptedError, d as isSnapshottingError, f as throwSandboxOperationError, g as isWorkspaceSnapshotNotReadyError, h as getWorkspaceSnapshotNotReadyError, i as ensureDockerDaemon, j as SANDBOX_REPOS_ROOT, k as sleep$2, l as isSandboxMissingError, m as WorkspaceSnapshotNotReadyError, n as hash, o as isAlreadyExistsError, p as wrapSandboxSetupError, r as isStale, s as isSandboxApiTransientError, t as create, u as isSandboxUnavailableError, v as getVercelSandboxCredentials, w as getStateAdapter, x as runNonInteractiveCommand, y as buildCommandScript } from "./profile-BdApelHS.js";
19
+ import { n as canReusePendingAuthLink, t as abandonReplacedPendingAuth } from "./pending-auth-DQhC3eSR.js";
20
+ import { a as NO_REPLY_MARKER, c as CooperativeTurnYieldError, i as sanitizeAssistantText, l as TurnInputCommitLostError, n as decideReply, o as isNoReplyMarker, p as isTurnInputCommitLostError, r as getAssistantReplyText, t as authorizationId } from "./oauth-authorization-CC8a1JKP.js";
21
+ import { r as EVENT_AUTHOR_ID } from "./prompt-3D0sSbTC.js";
22
+ import { a as createSandboxSession, c as postinstall, d as getSandboxResources, i as bindSandboxFileSystem, l as setSnapshotSpanAttributes, n as isMissingError, o as stopSession, r as resolve$1, s as dependencies } from "./resolve-VpJoiDpc.js";
23
+ import { a as getVercelConversationWorkQueue, f as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-cwHVOwVZ.js";
24
+ import { a as automationTitleSchema, c as ScheduleIntentError, g as taskOutcomeInputSchema, i as automationInstructionSchema, l as compileScheduleIntent, m as eventAutomationSchema, n as scheduledAutomationSchema, p as getZonedDateTimeParts, r as scheduledRunSchema, t as SCHEDULED_AUTOMATION_SYSTEM_ACTOR, u as scheduleIntentSchema } from "./types-Du-HbEun.js";
24
25
  import { n as privateTraceResultAttributes } from "./private-trace-result-BLvBjy_e.js";
25
26
  import { streamSimple } from "@earendil-works/pi-ai/compat";
26
27
  import { createGatewayProvider } from "@ai-sdk/gateway";
@@ -31,7 +32,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
31
32
  import { z } from "zod";
32
33
  import { createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
33
34
  import { and, asc, desc, eq, gt, gte, inArray, isNotNull, isNull, lt, lte, ne, notExists, notInArray, or, sql } from "drizzle-orm";
34
- import { EgressAuthRequired, EgressPolicyDenied, PluginToolInputError, actorSchema, actorUserIdSchema, destinationSchema, destinationVisibilitySchema, eventMatchSchema, eventMatches, eventSchema, eventTypeSchema, missingToolAnnotationKeys, normalizeEventIdentifier, objectTypeSchema, ownedObjectAnnotationSchema, pluginAuthorizationSchema, pluginCredentialHeaderTransformSchema, pluginCredentialResultSchema, pluginGrantSchema, pluginProviderAccountSchema, pluginStoredTokensSchema, slackDestinationSchema, sourceSchema, stableEventMatchKey, taskOutcomeSchema, watchResultSchema } from "@sentry/junior-plugin-api";
35
+ import { EgressAuthRequired, EgressPolicyDenied, PluginToolInputError, actorSchema, destinationSchema, eventMatchSchema, eventMatches, eventSchema, missingToolAnnotationKeys, normalizeEventIdentifier, objectTypeSchema, ownedObjectAnnotationSchema, pluginAuthorizationSchema, pluginCredentialHeaderTransformSchema, pluginCredentialResultSchema, pluginGrantSchema, pluginProviderAccountSchema, pluginStoredTokensSchema, slackDestinationSchema, sourceSchema, stableEventMatchKey, taskOutcomeSchema, watchResultSchema } from "@sentry/junior-plugin-api";
35
36
  import { alias } from "drizzle-orm/pg-core";
36
37
  import { Agent, estimateContextTokens } from "@earendil-works/pi-agent-core";
37
38
  import fs from "node:fs/promises";
@@ -9154,6 +9155,7 @@ var McpToolManager = class {
9154
9155
  };
9155
9156
  const cards = await this.options.onToolSuccess?.({
9156
9157
  arguments: resolvedArgs,
9158
+ content: toAgentToolContent(result),
9157
9159
  provider: plugin.manifest.name,
9158
9160
  ...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : void 0,
9159
9161
  toolName: tool.name
@@ -10251,37 +10253,28 @@ function createEventTools(context, catalog) {
10251
10253
  stopWatchingResources: createStopWatchingResourcesTool(context)
10252
10254
  };
10253
10255
  }
10254
- /** Validate the persisted Slack creator identity for an event automation. */
10255
- const eventAutomationPrincipalSchema = z.object({
10256
- slackUserId: actorUserIdSchema,
10257
- fullName: z.string().optional(),
10258
- userName: z.string().optional()
10259
- }).strict();
10260
- /** Validate one persisted event-automation selector and its presentation metadata. */
10261
- const eventAutomationTriggerSchema = z.object({
10262
- events: z.array(eventTypeSchema).min(1),
10263
- label: z.string().min(1),
10264
- match: eventMatchSchema.optional(),
10265
- namespace: z.string().min(1),
10266
- identifier: z.string().min(1).max(300),
10267
- resourceType: z.string().min(1)
10268
- }).strict();
10269
- /** Event automations target a Slack channel or DM, never a message thread. */
10270
- const eventAutomationDestinationSchema = slackDestinationSchema.omit({ threadTs: true });
10271
- const eventAutomationOutcomeSchema = taskOutcomeSchema.extend({ destination: eventAutomationDestinationSchema });
10272
- /** Validate one persisted event automation. */
10273
- const eventAutomationSchema = z.object({
10274
- id: z.string().min(1),
10275
- createdAtMs: z.number().finite(),
10276
- createdBy: eventAutomationPrincipalSchema,
10277
- credentialMode: z.enum(["system", "creator"]),
10278
- destination: eventAutomationDestinationSchema,
10279
- destinationVisibility: destinationVisibilitySchema,
10280
- /** Explicit visible effects after successful work. An empty list is silent. */
10281
- outcomes: z.array(eventAutomationOutcomeSchema).max(5),
10282
- task: z.object({ text: z.string().min(1) }).strict(),
10283
- trigger: eventAutomationTriggerSchema
10284
- }).strict();
10256
+ //#endregion
10257
+ //#region src/chat/automations/revision.ts
10258
+ /** Storage revisions prevent stale edits from replacing newer values. */
10259
+ var AutomationConflictError = class extends ToolInputError {
10260
+ constructor() {
10261
+ super("This Automation changed after it was loaded. Reload it before saving.");
10262
+ this.name = "AutomationConflictError";
10263
+ }
10264
+ };
10265
+ function canonicalJson$1(value) {
10266
+ if (Array.isArray(value)) return value.map(canonicalJson$1);
10267
+ if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, child]) => [key, canonicalJson$1(child)]));
10268
+ return value;
10269
+ }
10270
+ /** Identify the stored values being edited, including lifecycle and creator authority. */
10271
+ function automationRevision(task) {
10272
+ return createHash("sha256").update(JSON.stringify(canonicalJson$1(task))).digest("hex");
10273
+ }
10274
+ /** Reject a stale edit while the storage owner holds the write lock. */
10275
+ function requireAutomationRevision(task, revision) {
10276
+ if (!task || automationRevision(task) !== revision) throw new AutomationConflictError();
10277
+ }
10285
10278
  //#endregion
10286
10279
  //#region src/chat/event-automations/store.ts
10287
10280
  const retainedEventAutomationSchema = eventAutomationSchema.extend({
@@ -10293,7 +10286,8 @@ function eventAutomationJsonPayload(task) {
10293
10286
  const { status: _status, title: _title, ...payload } = task;
10294
10287
  return payload;
10295
10288
  }
10296
- function parseTask(row) {
10289
+ /** Decode a retained event Automation with its SQL-backed fields. */
10290
+ function parseEventAutomationRow(row) {
10297
10291
  const raw = row.task && typeof row.task === "object" ? { ...row.task } : row.task;
10298
10292
  if (raw && typeof raw === "object" && "title" in raw) delete raw.title;
10299
10293
  if (raw && typeof raw === "object" && !("outcomes" in raw) && "destination" in raw) raw.outcomes = [{
@@ -10313,7 +10307,7 @@ function parseTask(row) {
10313
10307
  destination
10314
10308
  };
10315
10309
  }),
10316
- status: row.status === "deleted" ? "deleted" : "active",
10310
+ status: row.status ?? "active",
10317
10311
  ...title ? { title } : void 0
10318
10312
  };
10319
10313
  }
@@ -10327,7 +10321,7 @@ async function getEventAutomation(db, id) {
10327
10321
  task: juniorEventAutomations.task,
10328
10322
  title: juniorEventAutomations.title
10329
10323
  }).from(juniorEventAutomations).where(eq(juniorEventAutomations.id, id)).limit(1);
10330
- return rows[0] ? parseTask(rows[0]) : void 0;
10324
+ return rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
10331
10325
  }
10332
10326
  /** Create one retry-stable event automation, or revive a deleted row with the new payload. */
10333
10327
  async function createEventAutomation(db, task) {
@@ -10362,14 +10356,19 @@ async function createEventAutomation(db, task) {
10362
10356
  task: juniorEventAutomations.task,
10363
10357
  title: juniorEventAutomations.title
10364
10358
  });
10365
- return rows[0] ? parseTask(rows[0]) : await getEventAutomation(db, parsed.id) ?? {
10359
+ return rows[0] ? parseEventAutomationRow(rows[0]) : await getEventAutomation(db, parsed.id) ?? {
10366
10360
  ...parsed,
10367
10361
  status: "active",
10368
10362
  ...title ? { title } : void 0
10369
10363
  };
10370
10364
  }
10371
10365
  /** Replace an existing non-deleted event automation. */
10372
- async function saveEventAutomation(db, task) {
10366
+ async function saveEventAutomation(db, task, expectedRevision) {
10367
+ if (expectedRevision !== void 0) return db.transaction(async (tx) => {
10368
+ const rows = await tx.select().from(juniorEventAutomations).where(eq(juniorEventAutomations.id, task.id)).for("update");
10369
+ requireAutomationRevision(rows[0] ? parseEventAutomationRow(rows[0]) : void 0, expectedRevision);
10370
+ return saveEventAutomation(tx, task);
10371
+ });
10373
10372
  const parsed = eventAutomationSchema.parse(eventAutomationJsonPayload(task));
10374
10373
  const title = task.title?.trim() || null;
10375
10374
  const rows = await db.update(juniorEventAutomations).set({
@@ -10382,7 +10381,7 @@ async function saveEventAutomation(db, task) {
10382
10381
  task: juniorEventAutomations.task,
10383
10382
  title: juniorEventAutomations.title
10384
10383
  });
10385
- return rows[0] ? parseTask(rows[0]) : void 0;
10384
+ return rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
10386
10385
  }
10387
10386
  /** Mark one existing event automation deleted while retaining the row for history. */
10388
10387
  async function deleteEventAutomation(db, id) {
@@ -10391,7 +10390,7 @@ async function deleteEventAutomation(db, id) {
10391
10390
  task: juniorEventAutomations.task,
10392
10391
  title: juniorEventAutomations.title
10393
10392
  });
10394
- return rows[0] ? parseTask(rows[0]) : void 0;
10393
+ return rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
10395
10394
  }
10396
10395
  /** List live event automations in one Slack workspace. */
10397
10396
  async function listEventAutomationsForTeam(db, teamId) {
@@ -10399,7 +10398,7 @@ async function listEventAutomationsForTeam(db, teamId) {
10399
10398
  status: juniorEventAutomations.status,
10400
10399
  task: juniorEventAutomations.task,
10401
10400
  title: juniorEventAutomations.title
10402
- }).from(juniorEventAutomations).where(and(eq(juniorEventAutomations.teamId, teamId), activeEventAutomationWhere())).orderBy(asc(juniorEventAutomations.createdAtMs), asc(juniorEventAutomations.id))).map(parseTask);
10401
+ }).from(juniorEventAutomations).where(and(eq(juniorEventAutomations.teamId, teamId), activeEventAutomationWhere())).orderBy(asc(juniorEventAutomations.createdAtMs), asc(juniorEventAutomations.id))).map(parseEventAutomationRow);
10403
10402
  }
10404
10403
  function viewerSlackIdentities(user) {
10405
10404
  return user.identities.filter((identity) => identity.provider === "slack" && Boolean(identity.providerTenantId) && Boolean(identity.providerSubjectId));
@@ -10408,17 +10407,6 @@ function viewerSlackIdentities(user) {
10408
10407
  function eventAutomationBelongsToUser(task, user) {
10409
10408
  return viewerSlackIdentities(user).some((identity) => identity.providerTenantId === task.destination.teamId && identity.providerSubjectId === task.createdBy.slackUserId);
10410
10409
  }
10411
- /** List a bounded newest-first page of live event automations created by one user. */
10412
- async function listEventAutomationsCreatedBy(db, user, limit, query) {
10413
- const identities = viewerSlackIdentities(user);
10414
- const ownership = or(...identities.map((identity) => and(eq(juniorEventAutomations.teamId, identity.providerTenantId), sql`${juniorEventAutomations.task}->'createdBy'->>'slackUserId' = ${identity.providerSubjectId}`)));
10415
- if (!ownership) return [];
10416
- return (await db.select({
10417
- status: juniorEventAutomations.status,
10418
- task: juniorEventAutomations.task,
10419
- title: juniorEventAutomations.title
10420
- }).from(juniorEventAutomations).where(and(ownership, activeEventAutomationWhere(), query ? sql`strpos(lower(coalesce(${juniorEventAutomations.title}, ${juniorEventAutomations.task}->'task'->>'text')), ${query}) > 0` : void 0)).orderBy(desc(juniorEventAutomations.createdAtMs), desc(juniorEventAutomations.id)).limit(limit)).map(parseTask);
10421
- }
10422
10410
  /**
10423
10411
  * List deleted event automations created by one user, newest first.
10424
10412
  * Used only to keep historical runs after the live automation list drops the row.
@@ -10431,16 +10419,7 @@ async function listDeletedEventAutomationsCreatedBy(db, user, limit) {
10431
10419
  status: juniorEventAutomations.status,
10432
10420
  task: juniorEventAutomations.task,
10433
10421
  title: juniorEventAutomations.title
10434
- }).from(juniorEventAutomations).where(and(ownership, eq(juniorEventAutomations.status, "deleted"))).orderBy(desc(juniorEventAutomations.createdAtMs), desc(juniorEventAutomations.id)).limit(limit)).map(parseTask);
10435
- }
10436
- /** List live event automations whose current Slack destination is public. */
10437
- async function listPublicEventAutomationsForTeams(db, teamIds, limit, query) {
10438
- if (teamIds.length === 0) return [];
10439
- return (await db.select({
10440
- status: juniorEventAutomations.status,
10441
- task: juniorEventAutomations.task,
10442
- title: juniorEventAutomations.title
10443
- }).from(juniorEventAutomations).innerJoin(juniorDestinations, and(eq(juniorDestinations.provider, "slack"), eq(juniorDestinations.providerTenantId, juniorEventAutomations.teamId), sql`${juniorDestinations.providerDestinationId} = ${juniorEventAutomations.task}->'destination'->>'channelId'`)).where(and(inArray(juniorEventAutomations.teamId, teamIds), activeEventAutomationWhere(), query ? sql`strpos(lower(coalesce(${juniorEventAutomations.title}, ${juniorEventAutomations.task}->'task'->>'text')), ${query}) > 0` : void 0, eq(juniorDestinations.visibility, "public"))).orderBy(desc(juniorEventAutomations.createdAtMs), desc(juniorEventAutomations.id)).limit(limit)).map(parseTask);
10422
+ }).from(juniorEventAutomations).where(and(ownership, eq(juniorEventAutomations.status, "deleted"))).orderBy(desc(juniorEventAutomations.createdAtMs), desc(juniorEventAutomations.id)).limit(limit)).map(parseEventAutomationRow);
10444
10423
  }
10445
10424
  /**
10446
10425
  * Collect match keys from live event automations for these identifiers and event types.
@@ -10454,10 +10433,10 @@ async function collectEventAutomationMatchKeys(db, input) {
10454
10433
  status: juniorEventAutomations.status,
10455
10434
  task: juniorEventAutomations.task,
10456
10435
  title: juniorEventAutomations.title
10457
- }).from(juniorEventAutomations).where(and(eq(juniorEventAutomations.teamId, input.teamId), eq(juniorEventAutomations.namespace, input.namespace), inArray(juniorEventAutomations.identifier, identifiers), activeEventAutomationWhere())).orderBy(asc(juniorEventAutomations.createdAtMs), asc(juniorEventAutomations.id));
10436
+ }).from(juniorEventAutomations).where(and(eq(juniorEventAutomations.teamId, input.teamId), eq(juniorEventAutomations.namespace, input.namespace), inArray(juniorEventAutomations.identifier, identifiers), eq(juniorEventAutomations.status, "active"))).orderBy(asc(juniorEventAutomations.createdAtMs), asc(juniorEventAutomations.id));
10458
10437
  const keys = /* @__PURE__ */ new Set();
10459
10438
  for (const row of rows) {
10460
- const task = parseTask(row);
10439
+ const task = parseEventAutomationRow(row);
10461
10440
  if (!task.trigger.events.some((eventType) => eventTypes.has(eventType))) continue;
10462
10441
  for (const key of Object.keys(task.trigger.match ?? {})) keys.add(key);
10463
10442
  }
@@ -10469,16 +10448,24 @@ async function findMatchingEventAutomations(db, event, teamId) {
10469
10448
  status: juniorEventAutomations.status,
10470
10449
  task: juniorEventAutomations.task,
10471
10450
  title: juniorEventAutomations.title
10472
- }).from(juniorEventAutomations).where(and(eq(juniorEventAutomations.teamId, teamId), eq(juniorEventAutomations.namespace, event.namespace), eq(juniorEventAutomations.identifier, event.identifier), activeEventAutomationWhere())).orderBy(asc(juniorEventAutomations.createdAtMs), asc(juniorEventAutomations.id))).map(parseTask).filter((task) => task.trigger.events.includes(event.eventType) && eventMatches(task.trigger.match, event.data));
10451
+ }).from(juniorEventAutomations).where(and(eq(juniorEventAutomations.teamId, teamId), eq(juniorEventAutomations.namespace, event.namespace), eq(juniorEventAutomations.identifier, event.identifier), eq(juniorEventAutomations.status, "active"))).orderBy(asc(juniorEventAutomations.createdAtMs), asc(juniorEventAutomations.id))).map(parseEventAutomationRow).filter((task) => task.trigger.events.includes(event.eventType) && eventMatches(task.trigger.match, event.data));
10452
+ }
10453
+ /** Change lifecycle under the same row lock as edits, without changing credentials. */
10454
+ async function setEventAutomationStatus(db, id, status, revision) {
10455
+ return db.transaction(async (tx) => {
10456
+ const rows = await tx.select().from(juniorEventAutomations).where(eq(juniorEventAutomations.id, id)).for("update");
10457
+ const current = rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
10458
+ requireAutomationRevision(current, revision);
10459
+ if (!current || current.status === "deleted") throw new Error("Automation no longer exists.");
10460
+ await tx.update(juniorEventAutomations).set({ status }).where(eq(juniorEventAutomations.id, id));
10461
+ return {
10462
+ ...current,
10463
+ status
10464
+ };
10465
+ });
10473
10466
  }
10474
10467
  //#endregion
10475
10468
  //#region src/chat/task-outcomes.ts
10476
- const taskMessageDestinationInputSchema = z.enum(["current_conversation", "task_creator"]).describe("Where to send the message. Use current_conversation for posts, digests, summaries, and channel reminders. Use task_creator only when the user asks for a direct reminder or notification.");
10477
- /** Input accepted by task authoring tools before a user becomes a DM Destination. */
10478
- const taskOutcomeInputSchema = z.object({
10479
- action: z.literal("send_message"),
10480
- destination: taskMessageDestinationInputSchema
10481
- }).strict();
10482
10469
  /** Resolve explicit message outcomes to the Slack Destinations stored on an Automation. */
10483
10470
  async function resolveTaskOutcomes(outcomes, currentDestination, creatorSlackUserId) {
10484
10471
  if (outcomes === void 0) return [];
@@ -10526,6 +10513,11 @@ function moveTaskOutcomes(outcomes, currentDestination, nextDestination) {
10526
10513
  //#region src/chat/event-automations/tool-support.ts
10527
10514
  const compactEventAutomationResultSchema = z.object({
10528
10515
  id: z.string().min(1),
10516
+ status: z.enum([
10517
+ "active",
10518
+ "paused",
10519
+ "deleted"
10520
+ ]),
10529
10521
  title: z.string().min(1).nullable(),
10530
10522
  dashboardUrl: z.string().url().nullable(),
10531
10523
  instruction: z.string().min(1),
@@ -10625,6 +10617,7 @@ function eventAutomationTriggerAvailable(task, catalog) {
10625
10617
  function compactEventAutomation(task, catalog, requesterSlackUserId) {
10626
10618
  return compactEventAutomationResultSchema.parse({
10627
10619
  id: task.id,
10620
+ status: task.status,
10628
10621
  title: task.title?.trim() || null,
10629
10622
  dashboardUrl: getDashboardTaskLink(task.id) ?? null,
10630
10623
  instruction: task.task.text,
@@ -10828,13 +10821,78 @@ function createListEventAutomationsTool(context, catalog) {
10828
10821
  });
10829
10822
  }
10830
10823
  //#endregion
10831
- //#region src/chat/tools/update-event-automation.ts
10832
- /** Return whether an edit changes the task's executable event source. */
10824
+ //#region src/chat/automations/edit-rules.ts
10825
+ /** Shared edit rules. Transport access checks run before these rules. */
10826
+ var AutomationEditError = class extends ToolInputError {
10827
+ field;
10828
+ constructor(message, field) {
10829
+ super(message);
10830
+ this.field = field;
10831
+ this.name = "AutomationEditError";
10832
+ }
10833
+ };
10834
+ /** Apply shared title, instruction, outcome, and creator credential rules. */
10835
+ async function editAutomationFields(current, input, isCreator, changesExecution) {
10836
+ const kind = "schedule" in current ? "scheduled" : "event";
10837
+ if (input.credentialMode === "creator" && !isCreator) throw new AutomationEditError(`Only the ${kind} automation creator can enable creator credential use.`, "credentialMode");
10838
+ if (input.outcomes !== void 0 && !isCreator) throw new AutomationEditError(`Only the ${kind} automation creator can change message destinations.`, "outcomes");
10839
+ let outcomes = current.outcomes;
10840
+ if (input.outcomes !== void 0) {
10841
+ for (const outcome of input.outcomes) if (typeof outcome.destination !== "string" && !current.outcomes.some((stored) => isDeepStrictEqual(stored, outcome))) throw new AutomationEditError("Use the current Destination or the creator for a new message outcome.", "outcomes");
10842
+ outcomes = [];
10843
+ for (const outcome of input.outcomes) if (typeof outcome.destination === "string") outcomes.push(...await resolveTaskOutcomes([{
10844
+ action: outcome.action,
10845
+ destination: outcome.destination
10846
+ }], current.destination, current.createdBy.slackUserId));
10847
+ else outcomes.push({
10848
+ action: outcome.action,
10849
+ destination: outcome.destination
10850
+ });
10851
+ }
10852
+ return {
10853
+ title: input.title ?? current.title,
10854
+ task: { text: input.instruction ?? current.task.text },
10855
+ credentialMode: changesExecution && !isCreator ? "system" : input.credentialMode ?? current.credentialMode,
10856
+ outcomes
10857
+ };
10858
+ }
10859
+ //#endregion
10860
+ //#region src/chat/event-automations/edit.ts
10833
10861
  function changesEventAutomationTrigger(current, next) {
10834
10862
  const currentEvents = [...current.events].sort();
10835
10863
  const nextEvents = [...next.events].sort();
10836
10864
  return current.namespace !== next.namespace || current.identifier !== next.identifier || currentEvents.length !== nextEvents.length || currentEvents.some((event, index) => event !== nextEvents[index]) || stableEventMatchKey(current.match) !== stableEventMatchKey(next.match);
10837
10865
  }
10866
+ /** Build a validated edit while retaining an unchanged, possibly unavailable trigger. */
10867
+ async function editEventAutomation(current, input, isCreator, catalog) {
10868
+ let trigger = current.trigger;
10869
+ if (input.trigger !== void 0) {
10870
+ if (changesEventAutomationTrigger(current.trigger, input.trigger) || current.trigger.resourceType !== input.trigger.resourceType) try {
10871
+ const match = requireSupportedEventAutomationTrigger(catalog, input.trigger);
10872
+ trigger = {
10873
+ ...input.trigger,
10874
+ identifier: normalizeCatalogEventIdentifier(catalog, input.trigger.namespace, input.trigger.identifier),
10875
+ events: [...new Set(input.trigger.events)],
10876
+ match
10877
+ };
10878
+ } catch (error) {
10879
+ if (error instanceof ToolInputError) throw new AutomationEditError(error.message, "trigger");
10880
+ throw error;
10881
+ }
10882
+ else trigger = {
10883
+ ...current.trigger,
10884
+ label: input.trigger.label
10885
+ };
10886
+ }
10887
+ const changesExecution = input.instruction !== void 0 && input.instruction !== current.task.text || changesEventAutomationTrigger(current.trigger, trigger);
10888
+ return {
10889
+ ...current,
10890
+ ...await editAutomationFields(current, input, isCreator, changesExecution),
10891
+ trigger
10892
+ };
10893
+ }
10894
+ //#endregion
10895
+ //#region src/chat/tools/update-event-automation.ts
10838
10896
  /** Create the core tool that updates an event automation. */
10839
10897
  function createUpdateEventAutomationTool(context, catalog) {
10840
10898
  return zodTool({
@@ -10849,7 +10907,8 @@ function createUpdateEventAutomationTool(context, catalog) {
10849
10907
  description: "Update the instruction, registered trigger, or credential use for an event automation.",
10850
10908
  inputSchema: z.object({
10851
10909
  automationId: z.string().min(1),
10852
- instruction: z.string().trim().min(1).max(4e3).nullable().optional(),
10910
+ title: automationTitleSchema.optional(),
10911
+ instruction: automationInstructionSchema.nullable().optional(),
10853
10912
  trigger: registeredEventAutomationTriggerSchema(catalog).nullable().optional(),
10854
10913
  outcomes: z.array(taskOutcomeInputSchema).max(5).nullable().describe("Replacement messages to send after successful work. Use an empty list to send nothing. Omit or use null to leave unchanged.").optional(),
10855
10914
  credentialMode: z.enum(["system", "creator"]).nullable().describe("Set creator to make the task's original creator credentials available, or system to disable them. Creator always means the task's createdBy actor, never the current requester. Only that original creator may enable creator mode. Omit or use null to leave unchanged.").optional()
@@ -10865,43 +10924,19 @@ function createUpdateEventAutomationTool(context, catalog) {
10865
10924
  };
10866
10925
  },
10867
10926
  outputSchema: eventAutomationToolResultSchema,
10868
- async execute(input, options) {
10927
+ async execute(input) {
10869
10928
  const current = await writableEventAutomation(context, input.automationId);
10870
- const match = input.trigger ? requireSupportedEventAutomationTrigger(catalog, input.trigger) : void 0;
10871
10929
  const { actor } = requireEventAutomationSlackContext(context);
10872
10930
  const isCreator = actor.userId === current.createdBy.slackUserId;
10873
- if (input.credentialMode === "creator" && !isCreator) throw new ToolInputError("Only the event automation creator can enable creator credential use.");
10874
- if (input.outcomes != null && !isCreator) throw new ToolInputError("Only the event automation creator can change message destinations.");
10875
- if (input.instruction === void 0 && input.trigger === void 0 && input.outcomes == null && input.credentialMode == null) throw new ToolInputError("Event automation update requires a change.");
10876
- const nextTrigger = input.trigger ? {
10877
- namespace: input.trigger.namespace,
10878
- identifier: normalizeCatalogEventIdentifier(catalog, input.trigger.namespace, input.trigger.identifier),
10879
- resourceType: input.trigger.resourceType,
10880
- label: input.trigger.label,
10881
- events: [...new Set(input.trigger.events)],
10882
- ...match ? { match } : void 0
10883
- } : current.trigger;
10884
- const nextInstruction = input.instruction != null ? input.instruction : current.task.text;
10885
- const instructionChanged = nextInstruction !== current.task.text;
10886
- const changesExecution = instructionChanged || changesEventAutomationTrigger(current.trigger, nextTrigger);
10887
- const next = {
10888
- ...current,
10889
- credentialMode: changesExecution && !isCreator ? "system" : input.credentialMode ?? current.credentialMode,
10890
- outcomes: input.outcomes == null ? current.outcomes : await resolveTaskOutcomes(input.outcomes, current.destination, current.createdBy.slackUserId),
10891
- task: { text: nextInstruction },
10892
- trigger: nextTrigger
10893
- };
10894
- if (instructionChanged) {
10895
- const title = await generateShortTitle({
10896
- signal: options.signal,
10897
- completeText,
10898
- kind: "task",
10899
- sourceText: nextInstruction
10900
- });
10901
- if (title) next.title = title;
10902
- else delete next.title;
10903
- }
10904
- const saved = await saveEventAutomation(getDb(), next);
10931
+ if (input.title === void 0 && input.instruction === void 0 && input.trigger === void 0 && input.outcomes == null && input.credentialMode == null) throw new ToolInputError("Event automation update requires a change.");
10932
+ const next = await editEventAutomation(current, {
10933
+ title: input.title,
10934
+ instruction: input.instruction ?? void 0,
10935
+ trigger: input.trigger ?? void 0,
10936
+ outcomes: input.outcomes ?? void 0,
10937
+ credentialMode: input.credentialMode ?? void 0
10938
+ }, isCreator, catalog);
10939
+ const saved = await saveEventAutomation(getDb(), next, automationRevision(current));
10905
10940
  if (!saved) throw new ToolInputError("Event automation was not found.");
10906
10941
  return eventAutomationToolResult(context.conversationId, saved, catalog, actor.userId);
10907
10942
  }
@@ -10920,113 +10955,6 @@ function createEventAutomationTools(context, catalog) {
10920
10955
  };
10921
10956
  }
10922
10957
  //#endregion
10923
- //#region src/chat/scheduled-automations/types.ts
10924
- /** Durable scheduled-automation domain types owned by Junior core. */
10925
- const scheduledAutomationStatusSchema = z.enum([
10926
- "active",
10927
- "blocked",
10928
- "completed",
10929
- "deleted"
10930
- ]);
10931
- const scheduledAutomationCredentialModeSchema = z.enum(["system", "creator"]);
10932
- const scheduledRunStatusSchema = z.enum([
10933
- "pending",
10934
- "running",
10935
- "completed",
10936
- "failed",
10937
- "blocked",
10938
- "skipped"
10939
- ]);
10940
- const scheduledAutomationPrincipalSchema = z.object({
10941
- slackUserId: actorUserIdSchema,
10942
- fullName: z.string().optional(),
10943
- userName: z.string().optional()
10944
- }).strict();
10945
- const scheduledAutomationRecurrenceSchema = z.object({
10946
- dayOfMonth: z.number().optional(),
10947
- frequency: z.enum([
10948
- "daily",
10949
- "weekly",
10950
- "monthly",
10951
- "yearly"
10952
- ]),
10953
- interval: z.number(),
10954
- month: z.number().optional(),
10955
- startDate: z.string(),
10956
- time: z.object({
10957
- hour: z.number(),
10958
- minute: z.number()
10959
- }).strict(),
10960
- weekdays: z.array(z.number()).optional()
10961
- }).strict();
10962
- const scheduledAutomationScheduleSchema = z.object({
10963
- description: z.string(),
10964
- kind: z.enum(["one_off", "recurring"]),
10965
- recurrence: scheduledAutomationRecurrenceSchema.optional(),
10966
- timezone: z.string()
10967
- }).strict();
10968
- const scheduledAutomationExecutionActorSchema = z.object({
10969
- platform: z.literal("system"),
10970
- name: z.string()
10971
- }).strict();
10972
- /** Scheduled automations target a Slack conversation, never one message thread. */
10973
- const scheduledAutomationDestinationSchema = slackDestinationSchema.omit({ threadTs: true });
10974
- const scheduledAutomationOutcomeSchema = z.object({
10975
- action: z.literal("send_message"),
10976
- destination: scheduledAutomationDestinationSchema
10977
- }).strict();
10978
- /** Validate the current scheduled-automation domain shape. */
10979
- const scheduledAutomationSchema = z.object({
10980
- id: z.string(),
10981
- conversationAccess: z.object({
10982
- audience: z.enum([
10983
- "direct",
10984
- "group",
10985
- "channel"
10986
- ]),
10987
- visibility: z.enum(["private", "public"])
10988
- }).strict(),
10989
- createdAtMs: z.number(),
10990
- createdBy: scheduledAutomationPrincipalSchema,
10991
- /** Authoritative provider identity that created the task. */
10992
- creatorIdentityId: z.string(),
10993
- /** Selects system credentials or task-bound creator credential delegation. */
10994
- credentialMode: scheduledAutomationCredentialModeSchema,
10995
- destination: scheduledAutomationDestinationSchema,
10996
- executionActor: scheduledAutomationExecutionActorSchema.optional(),
10997
- lastRunAtMs: z.number().optional(),
10998
- nextRunAtMs: z.number().optional(),
10999
- originalRequest: z.string().optional(),
11000
- runNowAtMs: z.number().optional(),
11001
- schedule: scheduledAutomationScheduleSchema,
11002
- status: scheduledAutomationStatusSchema,
11003
- statusReason: z.string().optional(),
11004
- /** Explicit visible effects after successful work. An empty list is silent. */
11005
- outcomes: z.array(scheduledAutomationOutcomeSchema).max(5),
11006
- task: z.object({ text: z.string() }).strict(),
11007
- /** SQL-backed short display title generated from the task instruction. */
11008
- title: z.string().optional(),
11009
- updatedAtMs: z.number()
11010
- }).strict();
11011
- /** Validate the current scheduled-run domain shape. */
11012
- const scheduledRunSchema = z.object({
11013
- id: z.string(),
11014
- attempt: z.number(),
11015
- claimedAtMs: z.number(),
11016
- completedAtMs: z.number().optional(),
11017
- dispatchId: z.string().optional(),
11018
- errorMessage: z.string().optional(),
11019
- resultMessageTs: z.string().optional(),
11020
- scheduledForMs: z.number(),
11021
- startedAtMs: z.number().optional(),
11022
- status: scheduledRunStatusSchema,
11023
- taskId: z.string()
11024
- }).strict();
11025
- const SCHEDULED_AUTOMATION_SYSTEM_ACTOR = Object.freeze({
11026
- platform: "system",
11027
- name: "scheduled-automation"
11028
- });
11029
- //#endregion
11030
10958
  //#region src/chat/scheduled-automations/tasks.ts
11031
10959
  const SCHEDULER_KEY_PREFIX = "junior:scheduler";
11032
10960
  const retainedScheduledAutomationSchema = scheduledAutomationSchema.omit({
@@ -11035,13 +10963,6 @@ const retainedScheduledAutomationSchema = scheduledAutomationSchema.omit({
11035
10963
  }).extend({
11036
10964
  destination: slackDestinationSchema,
11037
10965
  outcomes: z.array(taskOutcomeSchema).max(5),
11038
- status: z.enum([
11039
- "active",
11040
- "blocked",
11041
- "completed",
11042
- "deleted",
11043
- "paused"
11044
- ]),
11045
10966
  version: z.number().optional()
11046
10967
  }).strict();
11047
10968
  /** Decode a retained scheduler task row and reject invalid routing context. */
@@ -11081,15 +11002,6 @@ function parseScheduledAutomationRow(row) {
11081
11002
  if (creatorIdentityId === void 0) return void 0;
11082
11003
  const fallbackTitle = row.title === null ? z.string().safeParse(legacyTitle) : void 0;
11083
11004
  const title = (row.title !== null ? row.title : fallbackTitle?.success ? fallbackTitle.data : void 0)?.trim() || void 0;
11084
- if (status === "paused") {
11085
- const { nextRunAtMs: _nextRunAtMs, runNowAtMs: _runNowAtMs, ...retained } = task;
11086
- return {
11087
- ...retained,
11088
- creatorIdentityId,
11089
- status: "deleted",
11090
- ...title ? { title } : void 0
11091
- };
11092
- }
11093
11005
  return {
11094
11006
  ...task,
11095
11007
  creatorIdentityId,
@@ -11168,7 +11080,7 @@ async function readListedScheduledAutomations(db, teamId) {
11168
11080
  creatorIdentityId: juniorSchedulerTasks.creatorIdentityId,
11169
11081
  record: juniorSchedulerTasks.record,
11170
11082
  title: juniorSchedulerTasks.title
11171
- }).from(juniorSchedulerTasks).where(and(notInArray(juniorSchedulerTasks.status, ["deleted", "paused"]), teamId === void 0 ? void 0 : eq(juniorSchedulerTasks.teamId, teamId))).orderBy(asc(juniorSchedulerTasks.createdAtMs), asc(juniorSchedulerTasks.id))).map(parseScheduledAutomationRow).filter(isListedScheduledAutomation);
11083
+ }).from(juniorSchedulerTasks).where(and(notInArray(juniorSchedulerTasks.status, ["deleted"]), teamId === void 0 ? void 0 : eq(juniorSchedulerTasks.teamId, teamId))).orderBy(asc(juniorSchedulerTasks.createdAtMs), asc(juniorSchedulerTasks.id))).map(parseScheduledAutomationRow).filter(isListedScheduledAutomation);
11172
11084
  }
11173
11085
  /** List decoded scheduled automations in stable creation order. */
11174
11086
  async function listScheduledAutomations(db) {
@@ -11212,10 +11124,11 @@ async function createScheduledAutomation(db, task) {
11212
11124
  });
11213
11125
  }
11214
11126
  /** Save a scheduled automation and clear its blocked occurrence on reactivation. */
11215
- async function saveScheduledAutomation(db, task) {
11127
+ async function saveScheduledAutomation(db, task, expectedRevision) {
11216
11128
  const next = requireStoredTask(task);
11217
11129
  await withScheduledAutomationLock(db, task.id, async (tx) => {
11218
11130
  const current = await readScheduledAutomation(tx, task.id);
11131
+ if (expectedRevision !== void 0) requireAutomationRevision(current, expectedRevision);
11219
11132
  await writeScheduledAutomation(tx, next, current);
11220
11133
  });
11221
11134
  return next;
@@ -11224,472 +11137,6 @@ async function saveScheduledAutomation(db, task) {
11224
11137
  async function saveScheduledAutomationInLock(db, task, current) {
11225
11138
  await writeScheduledAutomation(db, requireStoredTask(task), current);
11226
11139
  }
11227
- /** List scheduled automations whose current Slack destination is public. */
11228
- async function listPublicScheduledAutomationsForTeams(db, teamIds, input) {
11229
- if (teamIds.length === 0) return [];
11230
- return (await db.select({
11231
- creatorIdentityId: juniorSchedulerTasks.creatorIdentityId,
11232
- record: juniorSchedulerTasks.record,
11233
- title: juniorSchedulerTasks.title
11234
- }).from(juniorSchedulerTasks).innerJoin(juniorDestinations, and(eq(juniorDestinations.provider, "slack"), eq(juniorDestinations.providerTenantId, juniorSchedulerTasks.teamId), sql`${juniorDestinations.providerDestinationId} = ${juniorSchedulerTasks.record}->'destination'->>'channelId'`)).where(and(inArray(juniorSchedulerTasks.teamId, teamIds), notInArray(juniorSchedulerTasks.status, [
11235
- "completed",
11236
- "deleted",
11237
- "paused"
11238
- ]), input.query ? sql`strpos(lower(coalesce(${juniorSchedulerTasks.title}, ${juniorSchedulerTasks.record}->'task'->>'text')), ${input.query}) > 0` : void 0, eq(juniorDestinations.visibility, "public"))).orderBy(desc(juniorSchedulerTasks.createdAtMs), desc(juniorSchedulerTasks.id)).limit(input.limit)).map(parseScheduledAutomationRow).filter(isListedScheduledAutomation);
11239
- }
11240
- //#endregion
11241
- //#region src/chat/scheduled-automations/cadence.ts
11242
- const FORMATTERS = /* @__PURE__ */ new Map();
11243
- function getFormatter(timezone) {
11244
- const existing = FORMATTERS.get(timezone);
11245
- if (existing) return existing;
11246
- const formatter = new Intl.DateTimeFormat("en-US", {
11247
- timeZone: timezone,
11248
- hour12: false,
11249
- year: "numeric",
11250
- month: "2-digit",
11251
- day: "2-digit",
11252
- hour: "2-digit",
11253
- minute: "2-digit",
11254
- second: "2-digit"
11255
- });
11256
- FORMATTERS.set(timezone, formatter);
11257
- return formatter;
11258
- }
11259
- function normalizeHour(hour) {
11260
- return hour === 24 ? 0 : hour;
11261
- }
11262
- function getLocalDateWeekday(date) {
11263
- return new Date(Date.UTC(date.year, date.month - 1, date.day)).getUTCDay();
11264
- }
11265
- function getWeekStart(date) {
11266
- return addDays(date, -((getLocalDateWeekday(date) + 6) % 7));
11267
- }
11268
- /** Resolve a UTC timestamp into calendar parts for a named time zone. */
11269
- function getZonedDateTimeParts(timestampMs, timezone) {
11270
- const parts = getFormatter(timezone).formatToParts(new Date(timestampMs));
11271
- const values = new Map(parts.map((part) => [part.type, part.value]));
11272
- const year = Number(values.get("year"));
11273
- const month = Number(values.get("month"));
11274
- const day = Number(values.get("day"));
11275
- return {
11276
- year,
11277
- month,
11278
- day,
11279
- hour: normalizeHour(Number(values.get("hour"))),
11280
- minute: Number(values.get("minute")),
11281
- second: Number(values.get("second")),
11282
- weekday: getLocalDateWeekday({
11283
- year,
11284
- month,
11285
- day
11286
- })
11287
- };
11288
- }
11289
- function getTimeZoneOffsetMs(timestampMs, timezone) {
11290
- const parts = getZonedDateTimeParts(timestampMs, timezone);
11291
- return Date.UTC(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute, parts.second) - timestampMs;
11292
- }
11293
- function localDateTimeToTimestampMs(args) {
11294
- const localAsUtcMs = Date.UTC(args.date.year, args.date.month - 1, args.date.day, args.time.hour, args.time.minute, 0);
11295
- const offsets = /* @__PURE__ */ new Set();
11296
- for (const probeDeltaMs of [
11297
- -1296e5,
11298
- -432e5,
11299
- 0,
11300
- 432e5,
11301
- 1296e5
11302
- ]) offsets.add(getTimeZoneOffsetMs(localAsUtcMs + probeDeltaMs, args.timezone));
11303
- const matches = [...offsets].map((offsetMs) => localAsUtcMs - offsetMs).filter((timestampMs) => {
11304
- const parts = getZonedDateTimeParts(timestampMs, args.timezone);
11305
- return parts.year === args.date.year && parts.month === args.date.month && parts.day === args.date.day && parts.hour === args.time.hour && parts.minute === args.time.minute;
11306
- });
11307
- if (matches.length === 0) return;
11308
- return Math.min(...matches);
11309
- }
11310
- /** Resolve local time, rejecting DST gaps and choosing the earlier instant in a fold. */
11311
- function resolveLocalScheduleAtMs(args) {
11312
- const date = parseLocalDate(args.date);
11313
- if (!date) return;
11314
- return localDateTimeToTimestampMs({
11315
- date,
11316
- time: args.time,
11317
- timezone: args.timezone
11318
- });
11319
- }
11320
- function daysBetween(left, right) {
11321
- return Math.floor((Date.UTC(right.year, right.month - 1, right.day) - Date.UTC(left.year, left.month - 1, left.day)) / 864e5);
11322
- }
11323
- function weeklyRecurrenceMatchesDate(date, start, recurrence) {
11324
- if (compareDate(date, start) < 0) return false;
11325
- return normalizeWeekdays(recurrence.weekdays).includes(getLocalDateWeekday(date)) && Math.floor(daysBetween(getWeekStart(start), getWeekStart(date)) / 7) % recurrence.interval === 0;
11326
- }
11327
- function greatestCommonDivisor(left, right) {
11328
- let a = Math.abs(left);
11329
- let b = Math.abs(right);
11330
- while (b !== 0) [a, b] = [b, a % b];
11331
- return a;
11332
- }
11333
- function findNextRunAtMs(args) {
11334
- const start = parseLocalDate(args.recurrence.startDate);
11335
- const interval = args.recurrence.interval;
11336
- if (!start || !Number.isInteger(interval) || interval <= 0) return;
11337
- const searchFrom = compareDate(args.searchFrom, start) < 0 ? start : args.searchFrom;
11338
- if (args.recurrence.frequency === "daily") {
11339
- const offsetDays = daysBetween(start, searchFrom);
11340
- let candidateDate = addDays(start, Math.ceil(offsetDays / interval) * interval);
11341
- const gregorianCycleDays = 146097;
11342
- const candidateCount = gregorianCycleDays / greatestCommonDivisor(gregorianCycleDays, interval);
11343
- for (let attempts = 0; attempts < candidateCount; attempts += 1) {
11344
- const candidate = buildCandidate({
11345
- date: candidateDate,
11346
- recurrence: args.recurrence,
11347
- timezone: args.timezone
11348
- });
11349
- if (candidate !== void 0 && candidate > args.afterMs) return candidate;
11350
- candidateDate = addDays(candidateDate, interval);
11351
- }
11352
- return;
11353
- }
11354
- if (args.recurrence.frequency === "weekly") {
11355
- if (normalizeWeekdays(args.recurrence.weekdays).length === 0) return;
11356
- let candidateDate = searchFrom;
11357
- const gregorianCycleDays = 146097;
11358
- const cadenceDays = interval * 7;
11359
- const searchDays = gregorianCycleDays * cadenceDays / greatestCommonDivisor(gregorianCycleDays, cadenceDays);
11360
- for (let attempts = 0; attempts < searchDays; attempts += 1) {
11361
- if (weeklyRecurrenceMatchesDate(candidateDate, start, args.recurrence)) {
11362
- const candidate = buildCandidate({
11363
- date: candidateDate,
11364
- recurrence: args.recurrence,
11365
- timezone: args.timezone
11366
- });
11367
- if (candidate !== void 0 && candidate > args.afterMs) return candidate;
11368
- }
11369
- candidateDate = addDays(candidateDate, 1);
11370
- }
11371
- return;
11372
- }
11373
- if (args.recurrence.frequency === "monthly") {
11374
- const startMonth = start.year * 12 + start.month - 1;
11375
- const searchMonth = searchFrom.year * 12 + searchFrom.month - 1;
11376
- let candidateMonth = startMonth + Math.ceil((searchMonth - startMonth) / interval) * interval;
11377
- const gregorianCycleMonths = 4800;
11378
- const candidateCount = gregorianCycleMonths / greatestCommonDivisor(gregorianCycleMonths, interval);
11379
- for (let attempts = 0; attempts < candidateCount; attempts += 1) {
11380
- const candidateDate = {
11381
- year: Math.floor(candidateMonth / 12),
11382
- month: candidateMonth % 12 + 1,
11383
- day: args.recurrence.dayOfMonth ?? 0
11384
- };
11385
- if (compareDate(candidateDate, searchFrom) >= 0) {
11386
- const candidate = buildCandidate({
11387
- date: candidateDate,
11388
- recurrence: args.recurrence,
11389
- timezone: args.timezone
11390
- });
11391
- if (candidate !== void 0 && candidate > args.afterMs) return candidate;
11392
- }
11393
- candidateMonth += interval;
11394
- }
11395
- return;
11396
- }
11397
- let candidateYear = start.year + Math.ceil((searchFrom.year - start.year) / interval) * interval;
11398
- const candidateCount = 400 / greatestCommonDivisor(400, interval);
11399
- for (let attempts = 0; attempts < candidateCount; attempts += 1) {
11400
- const candidateDate = {
11401
- year: candidateYear,
11402
- month: args.recurrence.month ?? 0,
11403
- day: args.recurrence.dayOfMonth ?? 0
11404
- };
11405
- if (compareDate(candidateDate, searchFrom) >= 0) {
11406
- const candidate = buildCandidate({
11407
- date: candidateDate,
11408
- recurrence: args.recurrence,
11409
- timezone: args.timezone
11410
- });
11411
- if (candidate !== void 0 && candidate > args.afterMs) return candidate;
11412
- }
11413
- candidateYear += interval;
11414
- }
11415
- }
11416
- /** Compute the first recurring calendar occurrence strictly after a timestamp. */
11417
- function getFirstRunAtMs(args) {
11418
- return findNextRunAtMs({
11419
- ...args,
11420
- searchFrom: getLocalDate(args.afterMs, args.timezone)
11421
- });
11422
- }
11423
- function compareDate(left, right) {
11424
- return Date.UTC(left.year, left.month - 1, left.day) - Date.UTC(right.year, right.month - 1, right.day);
11425
- }
11426
- function addDays(date, days) {
11427
- const next = new Date(Date.UTC(date.year, date.month - 1, date.day + days));
11428
- return {
11429
- year: next.getUTCFullYear(),
11430
- month: next.getUTCMonth() + 1,
11431
- day: next.getUTCDate()
11432
- };
11433
- }
11434
- function daysInMonth(year, month) {
11435
- return new Date(Date.UTC(year, month, 0)).getUTCDate();
11436
- }
11437
- function parseLocalDate(value) {
11438
- const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
11439
- if (!match) return;
11440
- const year = Number(match[1]);
11441
- const month = Number(match[2]);
11442
- const day = Number(match[3]);
11443
- if (!Number.isInteger(year) || !Number.isInteger(month) || !Number.isInteger(day) || month < 1 || month > 12 || day < 1 || day > daysInMonth(year, month)) return;
11444
- return {
11445
- year,
11446
- month,
11447
- day
11448
- };
11449
- }
11450
- function getLocalDate(timestampMs, timezone) {
11451
- const parts = getZonedDateTimeParts(timestampMs, timezone);
11452
- return {
11453
- year: parts.year,
11454
- month: parts.month,
11455
- day: parts.day
11456
- };
11457
- }
11458
- function normalizeWeekdays(values) {
11459
- return [...new Set((values ?? []).filter((value) => value >= 0 && value <= 6))].sort((a, b) => a - b);
11460
- }
11461
- function buildCandidate(args) {
11462
- return localDateTimeToTimestampMs({
11463
- date: args.date,
11464
- time: args.recurrence.time,
11465
- timezone: args.timezone
11466
- });
11467
- }
11468
- /** Return the next fire time after a completed run, when the task recurs. */
11469
- function getNextRunAtMs(task, scheduledForMs, afterMs = scheduledForMs) {
11470
- if (task.schedule.kind !== "recurring") return;
11471
- const recurrence = task.schedule.recurrence;
11472
- if (!recurrence || !Number.isFinite(recurrence.interval) || recurrence.interval <= 0) return;
11473
- const timezone = task.schedule.timezone;
11474
- const afterDate = getLocalDate(afterMs, timezone);
11475
- const nextScheduledDate = addDays(getLocalDate(scheduledForMs, timezone), 1);
11476
- return findNextRunAtMs({
11477
- afterMs,
11478
- recurrence,
11479
- searchFrom: compareDate(afterDate, nextScheduledDate) < 0 ? nextScheduledDate : afterDate,
11480
- timezone
11481
- });
11482
- }
11483
- //#endregion
11484
- //#region src/chat/scheduled-automations/schedule-intent.ts
11485
- /**
11486
- * Owns model-facing schedule intent and materializes it against the trusted
11487
- * server clock into the canonical schedule persisted by core.
11488
- */
11489
- const localDateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Use a local date in YYYY-MM-DD format.");
11490
- const localTimeSchema = z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "Use local time in HH:MM format.");
11491
- const timezoneSchema = z.string().min(1).max(80).describe("IANA timezone, for example America/Los_Angeles. Omit or use null for the scheduler default.").nullable().optional();
11492
- const weekdaySchema = z.enum([
11493
- "sunday",
11494
- "monday",
11495
- "tuesday",
11496
- "wednesday",
11497
- "thursday",
11498
- "friday",
11499
- "saturday"
11500
- ]);
11501
- const oneOffScheduleIntentSchema = z.object({
11502
- kind: z.literal("one_off").describe("A schedule that runs once."),
11503
- timezone: timezoneSchema,
11504
- timing: z.discriminatedUnion("type", [z.object({
11505
- type: z.literal("after").describe("Run after a relative delay from the server clock."),
11506
- value: z.number().int().positive().max(1e5),
11507
- unit: z.enum([
11508
- "second",
11509
- "minute",
11510
- "hour",
11511
- "day",
11512
- "week"
11513
- ])
11514
- }).strict(), z.object({
11515
- type: z.literal("at").describe("Run at an explicit local calendar date and time."),
11516
- date: localDateSchema.describe("Requested local calendar date in YYYY-MM-DD format."),
11517
- time: localTimeSchema.describe("Requested local wall-clock time in HH:MM format.")
11518
- }).strict()]).describe("Relative delay or explicit local time for the one-off run.")
11519
- }).strict();
11520
- const recurringScheduleIntentSchema = z.object({
11521
- kind: z.literal("recurring").describe("A repeating calendar schedule."),
11522
- frequency: z.enum([
11523
- "daily",
11524
- "weekly",
11525
- "monthly",
11526
- "yearly"
11527
- ]).describe("Recurring tasks can run at most once per day."),
11528
- interval: z.number().int().positive().max(365).describe("Repeat every N frequency units. Defaults to 1.").nullable().optional(),
11529
- time: localTimeSchema.describe("Local wall-clock time for each occurrence in HH:MM format."),
11530
- weekdays: z.array(weekdaySchema).min(1).max(7).describe("Required for weekly schedules.").nullable().optional(),
11531
- dayOfMonth: z.number().int().min(1).max(31).describe("Required for monthly and yearly schedules.").nullable().optional(),
11532
- month: z.number().int().min(1).max(12).describe("Required for yearly schedules, where January is 1.").nullable().optional(),
11533
- startDate: localDateSchema.describe("Optional local calendar date that anchors the recurrence. Omit to start with the next matching occurrence.").nullable().optional(),
11534
- timezone: timezoneSchema
11535
- }).strict().superRefine((schedule, context) => {
11536
- if (schedule.frequency === "weekly" && schedule.weekdays == null) context.addIssue({
11537
- code: "custom",
11538
- message: "Weekly schedules require weekdays.",
11539
- path: ["weekdays"]
11540
- });
11541
- if ((schedule.frequency === "monthly" || schedule.frequency === "yearly") && schedule.dayOfMonth == null) context.addIssue({
11542
- code: "custom",
11543
- message: `${schedule.frequency} schedules require dayOfMonth.`,
11544
- path: ["dayOfMonth"]
11545
- });
11546
- if (schedule.frequency === "yearly" && schedule.month == null) context.addIssue({
11547
- code: "custom",
11548
- message: "Yearly schedules require month.",
11549
- path: ["month"]
11550
- });
11551
- if (schedule.frequency !== "weekly" && schedule.weekdays != null) context.addIssue({
11552
- code: "custom",
11553
- message: "weekdays applies only to weekly schedules.",
11554
- path: ["weekdays"]
11555
- });
11556
- if (schedule.frequency !== "monthly" && schedule.frequency !== "yearly" && schedule.dayOfMonth != null) context.addIssue({
11557
- code: "custom",
11558
- message: "dayOfMonth applies only to monthly or yearly schedules.",
11559
- path: ["dayOfMonth"]
11560
- });
11561
- if (schedule.frequency !== "yearly" && schedule.month != null) context.addIssue({
11562
- code: "custom",
11563
- message: "month applies only to yearly schedules.",
11564
- path: ["month"]
11565
- });
11566
- });
11567
- const scheduleIntentSchema = z.union([oneOffScheduleIntentSchema, recurringScheduleIntentSchema]);
11568
- const WEEKDAY_INDEX = {
11569
- sunday: 0,
11570
- monday: 1,
11571
- tuesday: 2,
11572
- wednesday: 3,
11573
- thursday: 4,
11574
- friday: 5,
11575
- saturday: 6
11576
- };
11577
- const DURATION_MS = {
11578
- second: 1e3,
11579
- minute: 6e4,
11580
- hour: 36e5,
11581
- day: 864e5,
11582
- week: 6048e5
11583
- };
11584
- function parseLocalTime(value) {
11585
- const [hour, minute] = value.split(":").map(Number);
11586
- return {
11587
- hour,
11588
- minute
11589
- };
11590
- }
11591
- function localDateAt(timestampMs, timezone) {
11592
- const parts = getZonedDateTimeParts(timestampMs, timezone);
11593
- return [
11594
- parts.year,
11595
- parts.month,
11596
- parts.day
11597
- ].map((value, index) => index === 0 ? String(value).padStart(4, "0") : String(value).padStart(2, "0")).join("-");
11598
- }
11599
- function isValidTimeZone$1(timezone) {
11600
- try {
11601
- new Intl.DateTimeFormat("en-US", { timeZone: timezone }).format();
11602
- return true;
11603
- } catch {
11604
- return false;
11605
- }
11606
- }
11607
- function plural(value, unit) {
11608
- return value === 1 ? unit : `${unit}s`;
11609
- }
11610
- function formatWeekdays(weekdays) {
11611
- const labels = weekdays.map((weekday) => `${weekday[0].toUpperCase()}${weekday.slice(1)}`);
11612
- if (labels.length < 2) return labels[0] ?? "";
11613
- return `${labels.slice(0, -1).join(", ")} and ${labels.at(-1)}`;
11614
- }
11615
- function recurringDescription(schedule, timezone) {
11616
- const interval = schedule.interval ?? 1;
11617
- const cadenceUnit = {
11618
- daily: "day",
11619
- weekly: "week",
11620
- monthly: "month",
11621
- yearly: "year"
11622
- }[schedule.frequency];
11623
- const cadence = interval === 1 ? cadenceUnit : `${interval} ${cadenceUnit}s`;
11624
- let detail = "";
11625
- if (schedule.frequency === "weekly") detail = ` on ${formatWeekdays(schedule.weekdays)}`;
11626
- else if (schedule.frequency === "monthly") detail = ` on day ${schedule.dayOfMonth}`;
11627
- else if (schedule.frequency === "yearly") detail = ` on ${String(schedule.month).padStart(2, "0")}-${String(schedule.dayOfMonth).padStart(2, "0")}`;
11628
- return `Every ${cadence}${detail} at ${schedule.time} (${timezone})`;
11629
- }
11630
- var ScheduleIntentError = class extends Error {};
11631
- /** Materialize model-interpreted schedule intent against the trusted server clock. */
11632
- function compileScheduleIntent(args) {
11633
- const timezone = args.intent.timezone ?? args.defaultTimezone;
11634
- if (!isValidTimeZone$1(timezone)) throw new ScheduleIntentError("timezone must be a valid IANA time zone.");
11635
- if (args.intent.kind === "one_off") {
11636
- if (args.intent.timing.type === "after") return {
11637
- nextRunAtMs: args.nowMs + args.intent.timing.value * DURATION_MS[args.intent.timing.unit],
11638
- schedule: {
11639
- description: `In ${args.intent.timing.value} ${plural(args.intent.timing.value, args.intent.timing.unit)}`,
11640
- kind: "one_off",
11641
- timezone
11642
- }
11643
- };
11644
- const nextRunAtMs = resolveLocalScheduleAtMs({
11645
- date: args.intent.timing.date,
11646
- time: parseLocalTime(args.intent.timing.time),
11647
- timezone
11648
- });
11649
- if (nextRunAtMs === void 0) throw new ScheduleIntentError("The requested local date or time does not exist in that timezone.");
11650
- if (nextRunAtMs <= args.nowMs) throw new ScheduleIntentError("The requested one-off schedule must be in the future.");
11651
- return {
11652
- nextRunAtMs,
11653
- schedule: {
11654
- description: `Once on ${args.intent.timing.date} at ${args.intent.timing.time} (${timezone})`,
11655
- kind: "one_off",
11656
- timezone
11657
- }
11658
- };
11659
- }
11660
- const recurrence = {
11661
- frequency: args.intent.frequency,
11662
- interval: args.intent.interval ?? 1,
11663
- startDate: args.intent.startDate ?? localDateAt(args.nowMs, timezone),
11664
- time: parseLocalTime(args.intent.time),
11665
- ...args.intent.frequency === "weekly" ? { weekdays: [...new Set(args.intent.weekdays.map((weekday) => WEEKDAY_INDEX[weekday]))].sort((left, right) => left - right) } : void 0,
11666
- ...args.intent.frequency === "monthly" || args.intent.frequency === "yearly" ? { dayOfMonth: args.intent.dayOfMonth ?? void 0 } : void 0,
11667
- ...args.intent.frequency === "yearly" ? { month: args.intent.month ?? void 0 } : void 0
11668
- };
11669
- const searchRecurrence = args.intent.startDate ? recurrence : {
11670
- ...recurrence,
11671
- interval: 1
11672
- };
11673
- const nextRunAtMs = getFirstRunAtMs({
11674
- afterMs: args.nowMs,
11675
- recurrence: searchRecurrence,
11676
- timezone
11677
- });
11678
- if (nextRunAtMs === void 0) throw new ScheduleIntentError("The recurring schedule has no valid future occurrence.");
11679
- const materializedRecurrence = args.intent.startDate ? recurrence : {
11680
- ...recurrence,
11681
- startDate: localDateAt(nextRunAtMs, timezone)
11682
- };
11683
- return {
11684
- nextRunAtMs,
11685
- schedule: {
11686
- description: recurringDescription(args.intent, timezone),
11687
- kind: "recurring",
11688
- recurrence: materializedRecurrence,
11689
- timezone
11690
- }
11691
- };
11692
- }
11693
11140
  //#endregion
11694
11141
  //#region src/chat/scheduled-automations/telemetry.ts
11695
11142
  /** Safe structured telemetry attributes for scheduled-automation lifecycle events. */
@@ -11764,6 +11211,7 @@ const compactTaskResultSchema = z.object({
11764
11211
  status: z.enum([
11765
11212
  "active",
11766
11213
  "blocked",
11214
+ "paused",
11767
11215
  "completed",
11768
11216
  "deleted"
11769
11217
  ]),
@@ -12081,17 +11529,18 @@ function createSlackScheduleDeleteAutomationTool(context) {
12081
11529
  inputSchema: z.object({ automationId: z.string().min(1).describe("ID of the task to delete. Must be from this active Slack conversation.") }),
12082
11530
  outputSchema: scheduleAutomationToolResultSchema.extend({ removedCards: z.array(removedCardSchema) }),
12083
11531
  execute: async ({ automationId }) => {
11532
+ const lookup = await getWritableTask({
11533
+ context,
11534
+ taskId: automationId
11535
+ });
12084
11536
  const next = {
12085
- ...await getWritableTask({
12086
- context,
12087
- taskId: automationId
12088
- }),
11537
+ ...lookup,
12089
11538
  updatedAtMs: Date.now(),
12090
11539
  status: "deleted",
12091
11540
  nextRunAtMs: void 0,
12092
11541
  runNowAtMs: void 0
12093
11542
  };
12094
- await saveScheduledAutomation(getDb(), next);
11543
+ await saveScheduledAutomation(getDb(), next, automationRevision(lookup));
12095
11544
  await createPluginAnnotations({
12096
11545
  conversationId: context.conversationId,
12097
11546
  db: getDb(),
@@ -12225,12 +11674,46 @@ function createSlackScheduleRunAutomationNowTool(context) {
12225
11674
  updatedAtMs: nowMs,
12226
11675
  runNowAtMs: nowMs
12227
11676
  };
12228
- await saveScheduledAutomation(getDb(), next);
11677
+ await saveScheduledAutomation(getDb(), next, automationRevision(lookup));
12229
11678
  return { automation: compactTask(next, context.actor?.userId) };
12230
11679
  }
12231
11680
  });
12232
11681
  }
12233
11682
  //#endregion
11683
+ //#region src/chat/scheduled-automations/edit.ts
11684
+ /** Build an edit without restarting completed work or changing creator identity. */
11685
+ async function editScheduledAutomation(current, input, isCreator, nowMs) {
11686
+ if (current.status === "completed" || current.status === "deleted") throw new AutomationEditError("Completed scheduled automations cannot be updated. Create a new automation instead.");
11687
+ let compiled;
11688
+ if (input.schedule !== void 0) try {
11689
+ compiled = compileScheduleIntent({
11690
+ defaultTimezone: current.schedule.timezone || getDefaultScheduleTimezone(),
11691
+ intent: input.schedule,
11692
+ nowMs
11693
+ });
11694
+ } catch (error) {
11695
+ if (error instanceof ScheduleIntentError) throw new AutomationEditError(error.message, "schedule");
11696
+ throw error;
11697
+ }
11698
+ const nextRunAtMs = compiled?.nextRunAtMs ?? current.nextRunAtMs;
11699
+ if (input.status === "active" && !nextRunAtMs) throw new AutomationEditError("Active scheduled automations require a schedule with a future occurrence.", "schedule");
11700
+ if (current.status === "paused" && input.status !== void 0) throw new AutomationEditError("Use Resume in the Automation settings to resume paused work.", "status");
11701
+ const status = input.status ?? current.status;
11702
+ const changesExecution = input.instruction !== void 0 && input.instruction !== current.task.text;
11703
+ return {
11704
+ ...current,
11705
+ ...await editAutomationFields(current, input, isCreator, changesExecution),
11706
+ updatedAtMs: nowMs,
11707
+ schedule: compiled?.schedule ?? current.schedule,
11708
+ nextRunAtMs,
11709
+ ...compiled !== void 0 || input.status !== void 0 ? {
11710
+ runNowAtMs: status === "active" && !compiled ? current.runNowAtMs : void 0,
11711
+ statusReason: status === "blocked" || status === "paused" ? current.statusReason : void 0
11712
+ } : void 0,
11713
+ status
11714
+ };
11715
+ }
11716
+ //#endregion
12234
11717
  //#region src/chat/scheduled-automations/tools/update.ts
12235
11718
  /** Create a tool that edits a scheduled automation, including moving it here. */
12236
11719
  function createSlackScheduleUpdateAutomationTool(context) {
@@ -12246,7 +11729,8 @@ function createSlackScheduleUpdateAutomationTool(context) {
12246
11729
  executionMode: "sequential",
12247
11730
  inputSchema: z.object({
12248
11731
  automationId: z.string().min(1).describe("Scheduled automation ID returned by slackScheduleListAutomations."),
12249
- instruction: z.string().min(1).max(4e3).optional(),
11732
+ title: automationTitleSchema.optional(),
11733
+ instruction: automationInstructionSchema.optional(),
12250
11734
  schedule: scheduleIntentSchema.describe("Complete replacement schedule. Omit to keep it unchanged.").nullable().optional(),
12251
11735
  outcomes: z.array(taskOutcomeInputSchema).max(5).describe("Replacement messages to send after successful work. Use an empty list to send nothing. Omit to keep unchanged.").optional(),
12252
11736
  status: z.enum(["active", "blocked"]).describe("Set active to resume a blocked task, or blocked to stop dispatch.").optional(),
@@ -12254,7 +11738,7 @@ function createSlackScheduleUpdateAutomationTool(context) {
12254
11738
  credentialMode: z.enum(["system", "creator"]).nullable().describe("Use creator credentials or system credentials. Only the task creator may enable creator mode. Omit to keep unchanged.").optional()
12255
11739
  }).strict(),
12256
11740
  outputSchema: scheduleAutomationToolResultSchema,
12257
- execute: async (input, options) => {
11741
+ execute: async (input) => {
12258
11742
  const activeDestination = requireActiveChannel(context);
12259
11743
  const actor = requireActor(context, activeDestination);
12260
11744
  const db = getDb();
@@ -12276,52 +11760,24 @@ function createSlackScheduleUpdateAutomationTool(context) {
12276
11760
  if ((await db.select({ id: juniorSchedulerRuns.id }).from(juniorSchedulerRuns).where(and(eq(juniorSchedulerRuns.taskId, lookup.id), inArray(juniorSchedulerRuns.status, ["pending", "running"]))).limit(1)).length > 0) throwToolInputError("Scheduled automation cannot be moved while an occurrence is already running. Try again after the current run finishes.");
12277
11761
  }
12278
11762
  const nowMs = context.now?.() ?? Date.now();
12279
- let compiled;
12280
- if (input.schedule) try {
12281
- compiled = compileScheduleIntent({
12282
- defaultTimezone: lookup.schedule.timezone || getDefaultScheduleTimezone(),
12283
- intent: input.schedule,
12284
- nowMs
12285
- });
12286
- } catch (error) {
12287
- if (error instanceof ScheduleIntentError) throwToolInputError(error.message);
12288
- throw error;
12289
- }
12290
- const nextRunAtMs = compiled?.nextRunAtMs ?? lookup.nextRunAtMs;
12291
11763
  const status = normalizeStatus(input.status);
12292
11764
  if (input.status && !status) throwToolInputError("status must be active or blocked.");
12293
- if (status === "active" && !nextRunAtMs) throwToolInputError("Active scheduled automations require a schedule with a future occurrence.");
12294
- const nextStatus = status ?? lookup.status;
12295
- const credentialMode = input.instruction !== void 0 && input.instruction !== lookup.task.text && !isCreator ? "system" : input.credentialMode ?? lookup.credentialMode;
12296
- const nextInstruction = input.instruction !== void 0 ? input.instruction : lookup.task.text;
12297
- const instructionChanged = nextInstruction !== lookup.task.text;
12298
- const nextDestination = changingDestination ? requestedDestination : lookup.destination;
12299
- const next = {
12300
- ...lookup,
12301
- conversationAccess: changingDestination ? getConversationAccess(activeDestination, context.source) : lookup.conversationAccess,
12302
- credentialMode,
12303
- destination: nextDestination,
12304
- updatedAtMs: nowMs,
12305
- nextRunAtMs,
12306
- runNowAtMs: nextStatus === "active" && !compiled ? lookup.runNowAtMs : void 0,
12307
- status: nextStatus,
12308
- statusReason: nextStatus === "blocked" ? lookup.statusReason : void 0,
12309
- schedule: compiled?.schedule ?? lookup.schedule,
12310
- outcomes: input.outcomes === void 0 ? changingDestination ? moveTaskOutcomes(lookup.outcomes, lookup.destination, nextDestination) : lookup.outcomes : await resolveTaskOutcomes(input.outcomes, nextDestination, lookup.createdBy.slackUserId),
12311
- task: { text: nextInstruction }
12312
- };
12313
- if (instructionChanged) {
12314
- const title = await generateShortTitle({
12315
- signal: options.signal,
12316
- completeText,
12317
- kind: "task",
12318
- sourceText: nextInstruction
12319
- });
12320
- if (title) next.title = title;
12321
- else delete next.title;
11765
+ const instructionChanged = input.instruction !== void 0 && input.instruction !== lookup.task.text;
11766
+ const next = await editScheduledAutomation(lookup, {
11767
+ title: input.title,
11768
+ instruction: input.instruction,
11769
+ schedule: input.schedule ?? void 0,
11770
+ status,
11771
+ credentialMode: input.credentialMode ?? void 0,
11772
+ outcomes: changingDestination ? void 0 : input.outcomes
11773
+ }, isCreator, nowMs);
11774
+ if (changingDestination) {
11775
+ next.destination = requestedDestination;
11776
+ next.conversationAccess = getConversationAccess(activeDestination, context.source);
11777
+ next.outcomes = input.outcomes === void 0 ? moveTaskOutcomes(lookup.outcomes, lookup.destination, requestedDestination) : await resolveTaskOutcomes(input.outcomes, requestedDestination, lookup.createdBy.slackUserId);
12322
11778
  }
12323
- if (!changingDestination && !instructionChanged && !compiled && status === void 0 && (input.credentialMode === void 0 || input.credentialMode === null || input.credentialMode === lookup.credentialMode) && input.outcomes === void 0 && moveDestination) return scheduleAutomationToolResult(context.conversationId, lookup, actor.slackUserId);
12324
- const committed = await saveScheduledAutomation(db, next);
11779
+ if (!changingDestination && !instructionChanged && !input.schedule && input.title === void 0 && status === void 0 && (input.credentialMode === void 0 || input.credentialMode === null || input.credentialMode === lookup.credentialMode) && input.outcomes === void 0 && moveDestination) return scheduleAutomationToolResult(context.conversationId, lookup, actor.slackUserId);
11780
+ const committed = await saveScheduledAutomation(db, next, automationRevision(lookup));
12325
11781
  if (changingDestination) logInfo("scheduled_automation.move.completed", scheduledAutomationAttributes(committed));
12326
11782
  return scheduleAutomationToolResult(context.conversationId, committed, actor.slackUserId);
12327
11783
  }
@@ -21934,7 +21390,7 @@ function createAgentRunner(execute, options) {
21934
21390
  } } : void 0
21935
21391
  };
21936
21392
  if (run.instruction.storedAttachments?.length) {
21937
- const { loadInputImages } = await import("./images-Bj8PcvZ5.js").then((n) => n.n);
21393
+ const { loadInputImages } = await import("./images-BaL19wFC.js").then((n) => n.n);
21938
21394
  const storage = nextRun.environment?.attachmentStorage;
21939
21395
  if (!storage) throw new Error("Attachment storage is unavailable.");
21940
21396
  nextRun.instruction = {
@@ -21985,4 +21441,4 @@ async function runAgentWithTimeout(agentRunner, run, timeoutMs) {
21985
21441
  }
21986
21442
  }
21987
21443
  //#endregion
21988
- export { collectEventAutomationMatchKeys as $, recordFinishedTurnForAutomatedLimit as $t, requestAttachmentDeletion as A, getConfigDefaults as An, deadLetterAttempt as At, isListedScheduledAutomation as B, removeActiveConversation as Bt, readPublicArtifact as C, createUserTokenStore as Cn, cancelHumanFacingPendingMessages as Ct, renderBlockText as D, toolInvocationDestination as Dn, completeConversationStop as Dt, renderAttachmentText as E, actorFromRun as En, clearExpiredConversationLease as Et, resolveSlackChannelIdFromThreadId as F, hasRunnableConversationWork as Ft, readScheduledAutomation as G, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS as Gt, listScheduledAutomations as H, requestConversationWork as Ht, listThreadReplies as I, listActiveConversationIds as It, scheduledRunId as J, hasRunnableConversationWork$1 as Jt, saveScheduledAutomation as K, CONVERSATION_WORK_STALE_ENQUEUE_MS as Kt, logScheduledAutomationRunSkipped as L, recordAttemptFailure as Lt, parseSlackThreadId as M, ensureConversationWake as Mt, readSlackRawMessageContext as N, getConversation as Nt, collectAttachmentGarbage as O, AuthorizationFlowDisabledError as On, completeConversationWork as Ot, resolveSlackChannelIdFromMessage as P, getConversationWorkState as Pt, effectiveTaskOutcomes as Q, maybePostAutomatedTurnLimitNotice as Qt, scheduledAutomationRunAttributes as R, recordConversationRetry as Rt, publicArtifactHeaders as S, slackExternalRefIdSchema as Sn, beginConversationResume as St, lookupSlackUserProfile as T, RetryableDeliveryError as Tn, clearConsumedConversationWake as Tt, listScheduledAutomationsForTeam as U, startConversationWork as Ut, listPublicScheduledAutomationsForTeams as V, requestAnotherSlice as Vt, parseScheduledAutomationRow as W, stopConversationWork as Wt, scheduledRunSchema as X, isInvalidConversationRecordError as Xt, withScheduledAutomationLock as Y, isFinalAttempt as Yt, eventAutomationTriggerAvailable as Z, renderTaskInput as Zt, putMcpStoredOAuthCredentials as _, truncateStatusText as _n, getEventCatalog as _t, isExperimentalFeatureEnabled as a, consumeSandboxEgressAuthRequiredSignal as an, listEventAutomationsCreatedBy as at, readStats as b, removeReactionFromMessage as bn, appendAndEnqueueExclusiveInboundMessage as bt, createContextCompactor as c, sandboxEgressSignalsResponseSchema as cn, agentInvocationSchema as ct, deleteMcpAuthSession as d, resolveBaseUrl as dn, AgentInvocationLimitError as dt, resolveSandboxEgressProviderForHost as en, deleteEventAutomation as et, deleteMcpAuthSessionsForUserProvider as f, startOAuthFlow as fn, getMcpProviderErrorAttributes as ft, getMcpStoredOAuthCredentials as g, normalizeSlackStatusText as gn, isEventMailboxMetadata as gt, getMcpAuthSession as h, normalizeSlackReplyMarkdown as hn, EVENT_WAIT_MS as ht, getExperimentalFeatures as i, clearSandboxEgressSignals as in, listDeletedEventAutomationsCreatedBy as it, storeAttachment as j, setConfigDefaults as jn, drainConversationMailbox as jt, readLiveAttachment as k, shouldEmitDevAgentTrace as kn, countPendingConversationMessages as kt, executeCredentialedEgressRequest as l, formatProviderLabel as ln, createAgentInvocationSchema as lt, deleteMcpStoredOAuthCredentials as m, formatSlackLink as mn, ingestEvent as mt, runAgentWithTimeout as n, shouldPropagateSandboxEgressTrace as nn, findMatchingEventAutomations as nt, setExperimentalFeatures as o, consumeSandboxEgressPermissionDeniedSignal as on, listPublicEventAutomationsForTeams as ot, deleteMcpServerSessionId as p, escapeSlackMrkdwnText as pn, processWorkspaceSnapshotJob as pt, saveScheduledAutomationInLock as q, hasConversationStop as qt, experimental_exports as r, SANDBOX_EGRESS_PROXY_PATH as rn, getEventAutomation as rt, executeAgentRun as s, parseSandboxEgressCredentialToken as sn, agentBindingSchema as st, createAgentRunner as t, normalizeSandboxEgressTracePropagationDomains as tn, eventAutomationBelongsToUser as tt, finalizeMcpAuthorization as u, parseOAuthStatePayload as un, AgentInvocationBusyError as ut, PluginCredentialFailureError as v, addReactionToMessage as vn, eventGuidance as vt, unpublishedArtifactHeaders as w, buildSteeringPiMessage as wn, checkInConversationWork as wt, resolvePluginOAuthAccount as x, slackEntitySchema as xn, appendAndEnqueueInboundMessage as xt, latestProgressStatus as y, postSlackMessage as yn, ackMessages as yt, getNextRunAtMs as z, releaseConversationWork as zt };
21444
+ export { deleteEventAutomation as $, isFinalAttempt as $t, requestAttachmentDeletion as A, actorFromRun as An, clearExpiredConversationLease as At, listScheduledAutomations as B, listActiveConversationIds as Bt, readPublicArtifact as C, postSlackMessage as Cn, ackMessages as Ct, renderBlockText as D, createUserTokenStore as Dn, cancelHumanFacingPendingMessages as Dt, renderAttachmentText as E, slackExternalRefIdSchema as En, beginConversationResume as Et, resolveSlackChannelIdFromThreadId as F, setConfigDefaults as Fn, drainConversationMailbox as Ft, saveScheduledAutomationInLock as G, requestAnotherSlice as Gt, parseScheduledAutomationRow as H, recordConversationRetry as Ht, listThreadReplies as I, ensureConversationWake as It, editEventAutomation as J, stopConversationWork as Jt, scheduledRunId as K, requestConversationWork as Kt, editScheduledAutomation as L, getConversation as Lt, parseSlackThreadId as M, AuthorizationFlowDisabledError as Mn, completeConversationWork as Mt, readSlackRawMessageContext as N, shouldEmitDevAgentTrace as Nn, countPendingConversationMessages as Nt, collectAttachmentGarbage as O, buildSteeringPiMessage as On, checkInConversationWork as Ot, resolveSlackChannelIdFromMessage as P, getConfigDefaults as Pn, deadLetterAttempt as Pt, collectEventAutomationMatchKeys as Q, hasRunnableConversationWork$1 as Qt, logScheduledAutomationRunSkipped as R, getConversationWorkState as Rt, publicArtifactHeaders as S, addReactionToMessage as Sn, pluginEventCatalog as St, lookupSlackUserProfile as T, slackEntitySchema as Tn, appendAndEnqueueInboundMessage as Tt, readScheduledAutomation as U, releaseConversationWork as Ut, listScheduledAutomationsForTeam as V, recordAttemptFailure as Vt, saveScheduledAutomation as W, removeActiveConversation as Wt, eventAutomationTriggerAvailable as X, CONVERSATION_WORK_STALE_ENQUEUE_MS as Xt, AutomationEditError as Y, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS as Yt, effectiveTaskOutcomes as Z, hasConversationStop as Zt, putMcpStoredOAuthCredentials as _, escapeSlackMrkdwnText as _n, ingestEvent as _t, isExperimentalFeatureEnabled as a, normalizeSandboxEgressTracePropagationDomains as an, saveEventAutomation as at, readStats as b, normalizeSlackStatusText as bn, getEventCatalog as bt, createContextCompactor as c, clearSandboxEgressSignals as cn, automationRevision as ct, deleteMcpAuthSession as d, parseSandboxEgressCredentialToken as dn, agentInvocationSchema as dt, isInvalidConversationRecordError as en, eventAutomationBelongsToUser as et, deleteMcpAuthSessionsForUserProvider as f, sandboxEgressSignalsResponseSchema as fn, createAgentInvocationSchema as ft, getMcpStoredOAuthCredentials as g, startOAuthFlow as gn, processWorkspaceSnapshotJob as gt, getMcpAuthSession as h, resolveBaseUrl as hn, getMcpProviderErrorAttributes as ht, getExperimentalFeatures as i, resolveSandboxEgressProviderForHost as in, parseEventAutomationRow as it, storeAttachment as j, toolInvocationDestination as jn, completeConversationStop as jt, readLiveAttachment as k, RetryableDeliveryError as kn, clearConsumedConversationWake as kt, executeCredentialedEgressRequest as l, consumeSandboxEgressAuthRequiredSignal as ln, requireAutomationRevision as lt, deleteMcpStoredOAuthCredentials as m, parseOAuthStatePayload as mn, AgentInvocationLimitError as mt, runAgentWithTimeout as n, maybePostAutomatedTurnLimitNotice as nn, getEventAutomation as nt, setExperimentalFeatures as o, shouldPropagateSandboxEgressTrace as on, setEventAutomationStatus as ot, deleteMcpServerSessionId as p, formatProviderLabel as pn, AgentInvocationBusyError as pt, withScheduledAutomationLock as q, startConversationWork as qt, experimental_exports as r, recordFinishedTurnForAutomatedLimit as rn, listDeletedEventAutomationsCreatedBy as rt, executeAgentRun as s, SANDBOX_EGRESS_PROXY_PATH as sn, AutomationConflictError as st, createAgentRunner as t, renderTaskInput as tn, findMatchingEventAutomations as tt, finalizeMcpAuthorization as u, consumeSandboxEgressPermissionDeniedSignal as un, agentBindingSchema as ut, PluginCredentialFailureError as v, formatSlackLink as vn, EVENT_WAIT_MS as vt, unpublishedArtifactHeaders as w, removeReactionFromMessage as wn, appendAndEnqueueExclusiveInboundMessage as wt, resolvePluginOAuthAccount as x, truncateStatusText as xn, eventGuidance as xt, latestProgressStatus as y, normalizeSlackReplyMarkdown as yn, isEventMailboxMetadata as yt, scheduledAutomationRunAttributes as z, hasRunnableConversationWork as zt };