@sentry/junior 0.206.0 → 0.208.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-C9yuiZUF.js → agent-BfxfHsf1.js} +375 -346
- package/dist/{agent-hooks-DNjlz2A-.js → agent-hooks-CuGjLjmR.js} +224 -97
- package/dist/{agent-runner-E67lFrDG.js → agent-runner-Dz1PMKP0.js} +9 -9
- package/dist/api/schema.d.ts +39 -39
- package/dist/api/schema.js +2 -2
- package/dist/api.d.ts +1 -1
- package/dist/api.js +154 -154
- package/dist/{app-AxGmJHwK.d.ts → app-DfNrn_gS.d.ts} +2 -2
- package/dist/app.d.ts +1 -1
- package/dist/app.js +185 -183
- package/dist/{auth-pause-state-MVZ6xvEK.js → auth-pause-state-Bjoh8wCy.js} +7 -7
- package/dist/{briefs-CvJFQvhJ.js → briefs-q_onrGmf.js} +3 -3
- package/dist/{catalog-runtime-TBR8n4e1.js → catalog-runtime-D8YUMNhb.js} +1 -1
- package/dist/{checkpoint-BY47jJCB.js → checkpoint-FKMcINix.js} +8 -8
- package/dist/cli/chat.js +13 -13
- package/dist/cli/check.js +3 -3
- package/dist/cli/main.js +1 -1
- package/dist/cli/plugins.js +3 -3
- package/dist/cli/snapshot-create.js +3 -3
- package/dist/cli/upgrade.d.ts +1 -1
- package/dist/cli/upgrade.js +3 -3
- package/dist/{client-ceE7NtvC.js → client-bRyPqwAV.js} +4 -4
- package/dist/{config-CIE83sR2.js → config-EtF2uEaW.js} +6 -6
- package/dist/{context-B45_WqVX.js → context-Bplcgypl.js} +13 -13
- package/dist/{conversation-privacy-Auyq26XQ.js → conversation-privacy-whGaV2TG.js} +1 -1
- package/dist/{credential-sync-BO33aNQd.js → credential-sync-DM-EE1ey.js} +21 -21
- package/dist/{db-BeyXKJOI.d.ts → db-D74z7BZH.d.ts} +1 -1
- package/dist/{execution-stats-SiS2FLcv.js → execution-stats-C-f8zwMU.js} +77 -77
- package/dist/{executor-BfbYPW63.js → executor-BW5qp0jC.js} +43 -14
- package/dist/instrumentation.js +2 -2
- package/dist/{job-queue-CyTc24Es.js → job-queue-BIHNIEIX.js} +1 -1
- package/dist/{logging-D37bayDc.js → logging-sNS84Yuu.js} +1 -1
- package/dist/nitro.d.ts +1 -1
- package/dist/nitro.js +3 -3
- package/dist/{oauth-callback-server-BtfOeHTZ.js → oauth-callback-server-Co6D_yXP.js} +2 -2
- package/dist/{pending-auth-BPUzcs7n.js → pending-auth-CRJCt9Ux.js} +2 -2
- package/dist/{profile-CSixooTi.js → profile-BfLMVhWo.js} +4 -4
- package/dist/{prompt-3gqNY1Ka.js → prompt-x-0ZtTyb.js} +14 -14
- package/dist/{registry-DiR0-xRg.js → registry-Cyww_jnC.js} +2 -2
- package/dist/{resolve-Bn5q__9b.js → resolve-BApIFQXX.js} +2 -2
- package/dist/{runner-DFx3dIJH.js → runner-C9okx4GL.js} +10 -10
- package/dist/{sandbox-egress-signals-bwvjihxA.js → sandbox-egress-signals-BHfx0esj.js} +1 -1
- package/dist/{schema-8GXFfclK.js → schema-CwTeb-BF.js} +39 -39
- package/dist/{skills-BhM5qyCF.js → skills-DhL_wXEp.js} +2 -2
- package/dist/{spawn-Dk0PqdH6.js → spawn-msnzfE8_.js} +2 -2
- package/dist/{stats-DKRP4rsY.js → stats-Cq5w_Awk.js} +292 -268
- package/dist/{store-C5qxF2ac.d.ts → store-Det8MQ9g.d.ts} +1 -1
- package/dist/{task-queue-CdpTvu4R.js → task-queue-JfmWmpjS.js} +3 -3
- package/dist/{task-runner-alpjVSxQ.js → task-runner-Cm0gXoLH.js} +15 -15
- package/dist/{thread-state-CRK7aA41.js → thread-state-lw2QwQ-y.js} +5 -5
- package/dist/{turn-execution-XtyzIHog.js → turn-execution-C7K6lQp1.js} +3 -3
- package/dist/{turn-lifecycle-VbwZLfBv.js → turn-lifecycle-DVlJLwB0.js} +1 -1
- package/dist/{usage-D4A48Bdl.js → usage-BMuAlKIW.js} +2 -2
- package/dist/{validation-jn_46o4U.js → validation-BI-r3iQA.js} +1 -1
- package/dist/{version-DcfJxB4z.js → version-s6smK6lP.js} +1 -1
- package/dist/version.js +1 -1
- package/dist/{web-authorization-CsfLSfEs.js → web-authorization-C9MxPvXX.js} +1 -1
- package/dist/{web-input-BPp_sc7t.js → web-input-CwVlaLd0.js} +7 -109
- package/dist/{work-Di-ubSGg.js → work-BK0W1QAt.js} +9 -9
- package/dist/{worker-Cu_D5Mr8.js → worker-D-WWKHQD.js} +5 -5
- package/migrations/0041_automation_outcomes_backfill.sql +27 -0
- package/migrations/meta/0041_snapshot.json +3516 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +5 -5
package/dist/app.js
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
import { $ as shouldEmitDevAgentTrace, B as resolveSandboxEgressProviderForHost, C as renderBlockText, D as getNextRunAtMs, E as
|
|
2
|
-
import { b as isProviderRetryError, i as completeText, m as escapeXml, r as completeObject } from "./client-
|
|
3
|
-
import { A as JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE, C as withSpan, D as JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE, F as isRecord$1, I as toOptionalNumber, L as toOptionalString, S as withLogContext, _ as setSpanAttributes, d as logInfo, f as logWarn, g as setSentryUser, l as logError, n as createChatSdkLogger, o as getActiveTraceId, r as createRequestContext, t as buildTurnFailureResponse, u as logException, v as setSpanStatus, x as withContext, y as setTags } from "./logging-
|
|
1
|
+
import { $ as shouldEmitDevAgentTrace, B as resolveSandboxEgressProviderForHost, C as renderBlockText, D as getNextRunAtMs, E as scheduledAutomationRunAttributes, F as ingestEvent, G as consumeSandboxEgressAuthRequiredSignal, H as shouldPropagateSandboxEgressTrace, I as isEventMailboxMetadata, K as consumeSandboxEgressPermissionDeniedSignal, L as renderTaskInput, P as processWorkspaceSnapshotJob, Q as AuthorizationFlowDisabledError, R as maybePostAutomatedTurnLimitNotice, S as renderAttachmentText, T as logScheduledAutomationRunSkipped, U as SANDBOX_EGRESS_PROXY_PATH, V as normalizeSandboxEgressTracePropagationDomains, W as clearSandboxEgressSignals, X as buildSteeringPiMessage, Y as createUserTokenStore, Z as isVisionImageMediaType, _ as readPublicArtifact, b as readAttachmentVisionSummary, c as deleteMcpStoredOAuthCredentials, et as getConfigDefaults, f as PluginCredentialFailureError, g as publicArtifactHeaders, m as latestReportedProgress, n as createContextCompactor, o as deleteMcpAuthSessionsForUserProvider, q as parseSandboxEgressCredentialToken, r as executeCredentialedEgressRequest, s as deleteMcpServerSessionId, t as executeAgentRun, tt as setConfigDefaults, v as unpublishedArtifactHeaders, w as listThreadReplies, x as recordSlackAttachment, z as recordFinishedTurnForAutomatedLimit } from "./agent-BfxfHsf1.js";
|
|
2
|
+
import { b as isProviderRetryError, i as completeText, m as escapeXml, r as completeObject } from "./client-bRyPqwAV.js";
|
|
3
|
+
import { A as JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE, C as withSpan, D as JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE, F as isRecord$1, I as toOptionalNumber, L as toOptionalString, S as withLogContext, _ as setSpanAttributes, d as logInfo, f as logWarn, g as setSentryUser, l as logError, n as createChatSdkLogger, o as getActiveTraceId, r as createRequestContext, t as buildTurnFailureResponse, u as logException, v as setSpanStatus, x as withContext, y as setTags } from "./logging-sNS84Yuu.js";
|
|
4
4
|
import { r as continueTrace } from "./sentry-CD3SdJl-.js";
|
|
5
|
-
import { t as JUNIOR_VERSION } from "./version-
|
|
6
|
-
import { a as getChatConfig, c as getSlackClientId, d as getSlackSigningSecret, f as setBotModelConfig, i as configureFunctionMaxDurationSeconds, l as getSlackClientSecret, m as setSlackReactionConfig, n as botConfig, p as setProfiles, s as getSlackBotToken, u as getSlackReactionConfig } from "./config-
|
|
5
|
+
import { t as JUNIOR_VERSION } from "./version-s6smK6lP.js";
|
|
6
|
+
import { a as getChatConfig, c as getSlackClientId, d as getSlackSigningSecret, f as setBotModelConfig, i as configureFunctionMaxDurationSeconds, l as getSlackClientSecret, m as setSlackReactionConfig, n as botConfig, p as setProfiles, s as getSlackBotToken, u as getSlackReactionConfig } from "./config-EtF2uEaW.js";
|
|
7
7
|
import { a as modelIdForProfile, n as defaultModelId } from "./model-profile-CZmVoGdX.js";
|
|
8
|
-
import { _ as parseSlackMessageTs, a as createActor, c as isActorUserId, o as createSlackActor, p as parseSlackChannelId, s as createSlackResumeActor, t as credentialContextForActor, u as parseActorUserId } from "./context-
|
|
9
|
-
import { B as downloadPrivateSlackFile, F as bindSlackDirectCredentialSubject,
|
|
8
|
+
import { _ as parseSlackMessageTs, a as createActor, c as isActorUserId, o as createSlackActor, p as parseSlackChannelId, s as createSlackResumeActor, t as credentialContextForActor, u as parseActorUserId } from "./context-Bplcgypl.js";
|
|
9
|
+
import { B as downloadPrivateSlackFile, F as bindSlackDirectCredentialSubject, G as isDmChannel, Gt as getDb, Ht as getConversationEventStore, I as verifyEventAutomationCredentialSubject, Jt as withConversationEventLock, K as normalizeSlackConversationId, Kt as getSqlExecutor, L as verifyScheduledAutomationCredentialSubject, N as bindEventAutomationCredentialSubject, P as bindScheduledAutomationCredentialSubject, Pt as resolveRootVisibility, R as verifySlackDirectCredentialSubject, U as getSlackClient, Wt as getConversationStore, X as runWithWorkspaceTeamId, Xt as withConversationMutationLock, Y as getWorkspaceTeamId, _t as createPluginState, a as getPluginRoutes, bt as createPluginLogger, ct as collectEventMatchKeys, d as setPlugins, dt as findMatchingWatches, f as validatePlugins, gt as setDashboardConversationLinkOptions, h as setBriefsConfig, i as getPluginApiRoutes, in as createSlackDestination, on as requireSlackDestination, ot as cancelSubscriptions, pt as JUNIOR_THREAD_STATE_TTL_MS, q as runWithSlackInstallationToken, tn as deleteProviderIdentityForSlackUser, u as getPlugins, xt as readConversationAccessFromSql, z as SlackActionError } from "./agent-hooks-CuGjLjmR.js";
|
|
10
10
|
import { n as juniorDestinations } from "./destinations-BeBiJeEM.js";
|
|
11
|
-
import { _ as juniorConversationEvents, a as juniorSchedulerRuns, f as juniorAgentBindings, g as juniorConversationBriefs, o as juniorSchedulerTasks, p as juniorAgentInvocations, w as juniorConversations } from "./executor-
|
|
11
|
+
import { _ as juniorConversationEvents, a as juniorSchedulerRuns, f as juniorAgentBindings, g as juniorConversationBriefs, o as juniorSchedulerTasks, p as juniorAgentInvocations, w as juniorConversations } from "./executor-BW5qp0jC.js";
|
|
12
12
|
import { G as instructionProvenanceFor } from "./conversation-AA4R1VUn.js";
|
|
13
|
-
import { n as pluginCatalogRuntime } from "./catalog-runtime-
|
|
14
|
-
import { $ as persistConversationMessages, F as commitMessages, J as recordSubscribedReplyRoute, L as loadConversationProjection, Mt as trimTrailingAssistantMessages, P as commitAcceptedReply, Q as hydrateConversationMessages, R as loadProjection, Z as appendConversationMessages, a as completeTurnRecord, at as createConversationMemoryService, c as getTurnRecordForResume, ct as isHumanConversationMessage, d as persistWithRetry, dt as recordDeliveredAssistantMessage, et as projectConversationMessages, ft as turnHasReply, i as abandonTurnRecord, it as buildConversationContext, jt as stripRuntimeTurnContext, l as listTurnSummaries, lt as markConversationMessage, m as buildTurnErrorResponse, mt as estimateTextTokens, n as loadTurnCheckpoint, nt as resolveConversationTitle, o as failTurnRecord, ot as estimateConversationContextTokens, pt as upsertConversationMessage, r as saveTurnCheckpoint, rt as appendThreadContextMessages, s as getTurnRecord, st as getConversationMessageSlackTs, tt as persistConversationMessageSummaries, u as recordTurnSummary, ut as normalizeConversationText } from "./checkpoint-
|
|
15
|
-
import { E as acquireActiveLock, O as withActiveLock, T as MUTATION_LOCK_TTL_MS$1, k as withLock$1, w as getStateAdapter } from "./profile-
|
|
16
|
-
import { Dt as hasRunnableConversationWork, Et as getConversationWorkState, F as effectiveTaskOutcomes, Gt as buildDeterministicAssistantMessageId, It as stopConversationWork, Kt as buildDeterministicTurnId, Mt as removeActiveConversation, Ot as listActiveConversationIds, Pt as requestConversationWork, Rt as CONVERSATION_WORK_STALE_ENQUEUE_MS, S as
|
|
17
|
-
import { S as startActiveTurn, _ as isTurnInputCommitLostError, b as markTurnCompleted, d as ConversationTurnBoundaryError, f as CooperativeTurnYieldError, g as isCooperativeTurnYieldError, h as getConversationTurnBoundaryError, m as TurnInputDeferredError, p as TurnInputCommitLostError, r as clearPendingAuth, s as getAssistantReplyText, v as isTurnInputDeferredError, x as markTurnFailed, y as markTurnClosed } from "./pending-auth-
|
|
18
|
-
import { h as postSlackMessage, i as formatProviderLabel, s as startOAuthFlow, t as createAgentRunner, v as RetryableDeliveryError } from "./agent-runner-
|
|
19
|
-
import { a as
|
|
20
|
-
import { f as setSandboxResourceConfig, u as getSandboxResourceConfig } from "./resolve-
|
|
13
|
+
import { n as pluginCatalogRuntime } from "./catalog-runtime-D8YUMNhb.js";
|
|
14
|
+
import { $ as persistConversationMessages, F as commitMessages, J as recordSubscribedReplyRoute, L as loadConversationProjection, Mt as trimTrailingAssistantMessages, P as commitAcceptedReply, Q as hydrateConversationMessages, R as loadProjection, Z as appendConversationMessages, a as completeTurnRecord, at as createConversationMemoryService, c as getTurnRecordForResume, ct as isHumanConversationMessage, d as persistWithRetry, dt as recordDeliveredAssistantMessage, et as projectConversationMessages, ft as turnHasReply, i as abandonTurnRecord, it as buildConversationContext, jt as stripRuntimeTurnContext, l as listTurnSummaries, lt as markConversationMessage, m as buildTurnErrorResponse, mt as estimateTextTokens, n as loadTurnCheckpoint, nt as resolveConversationTitle, o as failTurnRecord, ot as estimateConversationContextTokens, pt as upsertConversationMessage, r as saveTurnCheckpoint, rt as appendThreadContextMessages, s as getTurnRecord, st as getConversationMessageSlackTs, tt as persistConversationMessageSummaries, u as recordTurnSummary, ut as normalizeConversationText } from "./checkpoint-FKMcINix.js";
|
|
15
|
+
import { E as acquireActiveLock, O as withActiveLock, T as MUTATION_LOCK_TTL_MS$1, k as withLock$1, w as getStateAdapter } from "./profile-BfLMVhWo.js";
|
|
16
|
+
import { Dt as hasRunnableConversationWork, Et as getConversationWorkState, F as effectiveTaskOutcomes, Gt as buildDeterministicAssistantMessageId, It as stopConversationWork, Kt as buildDeterministicTurnId, Mt as removeActiveConversation, Ot as listActiveConversationIds, Pt as requestConversationWork, Rt as CONVERSATION_WORK_STALE_ENQUEUE_MS, S as withScheduledAutomationLock, Tt as getConversation, U as findMatchingEventAutomations, Vt as isInvalidConversationRecordError, X as getEventCatalog, a as requestAttachmentDeletion, b as saveScheduledAutomationInLock, c as parseSlackThreadId, g as listScheduledAutomationsForTeam, h as listScheduledAutomations, o as storeAttachment, pt as appendAndEnqueueInboundMessage, r as collectAttachmentGarbage, tt as eventGuidance, v as readScheduledAutomation, vt as clearExpiredConversationLease, w as scheduledRunSchema, wt as ensureConversationWake, x as scheduledRunId, z as collectEventAutomationMatchKeys, zt as hasRunnableConversationWork$1 } from "./stats-Cq5w_Awk.js";
|
|
17
|
+
import { S as startActiveTurn, _ as isTurnInputCommitLostError, b as markTurnCompleted, d as ConversationTurnBoundaryError, f as CooperativeTurnYieldError, g as isCooperativeTurnYieldError, h as getConversationTurnBoundaryError, m as TurnInputDeferredError, p as TurnInputCommitLostError, r as clearPendingAuth, s as getAssistantReplyText, v as isTurnInputDeferredError, x as markTurnFailed, y as markTurnClosed } from "./pending-auth-CRJCt9Ux.js";
|
|
18
|
+
import { h as postSlackMessage, i as formatProviderLabel, s as startOAuthFlow, t as createAgentRunner, v as RetryableDeliveryError } from "./agent-runner-Dz1PMKP0.js";
|
|
19
|
+
import { a as EVENT_SYSTEM_ACTOR, i as EVENT_MESSAGE_AUTHOR, o as isEventConversationMessage } from "./prompt-x-0ZtTyb.js";
|
|
20
|
+
import { f as setSandboxResourceConfig, u as getSandboxResourceConfig } from "./resolve-BApIFQXX.js";
|
|
21
21
|
import { l as conversationQueueMessageSchema, n as resolveConversationWorkQueueTopic, r as verifyConversationQueueMessage, t as getVercelConversationWorkQueue, u as isConversationQueueMessageRejectedError } from "./vercel-queue-DIkVcfK4.js";
|
|
22
|
-
import { a as getTurnRequestDeadline, i as verifyWorkspaceSnapshotJobMessage, t as WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC } from "./job-queue-
|
|
22
|
+
import { a as getTurnRequestDeadline, i as verifyWorkspaceSnapshotJobMessage, t as WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC } from "./job-queue-BIHNIEIX.js";
|
|
23
23
|
import { i as setExperimentalFeatures, n as getExperimentalFeatures, r as isExperimentalFeatureEnabled } from "./experimental-CIXf7Uye.js";
|
|
24
|
-
import { n as validatePluginRegistrations, t as validatePluginEgressCredentialHooks } from "./validation-
|
|
24
|
+
import { n as validatePluginRegistrations, t as validatePluginEgressCredentialHooks } from "./validation-BI-r3iQA.js";
|
|
25
25
|
import { a as pluginRuntimeRegistrationsFromPluginSet, n as pluginCatalogConfigFromEnv, r as pluginCatalogConfigFromPluginSet, t as defineJuniorPlugins } from "./plugins-egKWjgue.js";
|
|
26
|
-
import {
|
|
27
|
-
import { u as
|
|
28
|
-
import { _ as markDispatchCompleted, a as claimDispatchMailboxAppend, c as getDispatchConversationId, d as getDispatchTurnId, f as getPluginDispatchProjection, g as markDispatchBlocked, h as markDispatchAwaitingResume, i as resolveTurnSessionRouting, l as getDispatchInputMessageId, m as listPendingDispatchMailboxAppends, n as scheduleSessionCompletedPluginTasks, o as confirmDispatchMailboxAppend, p as isTerminalDispatchStatus, s as createOrGetDispatch, t as processPluginTask, u as getDispatchRecord, v as markDispatchFailed, y as markDispatchRunning } from "./task-runner-
|
|
29
|
-
import { i as resolveAgentInvocationId, o as listPendingAgentInvocationMailboxAppends, r as enqueueAgentInvocation, t as createAgentInvocationWorker } from "./work-
|
|
30
|
-
import { n as getTurnLifecycle, t as ConversationTurnLifecycleService } from "./turn-lifecycle-
|
|
31
|
-
import { n as executeTurn, t as AgentRunError } from "./turn-execution-
|
|
32
|
-
import { a as persistThreadState, i as persistThreadRuntimeState, n as getPersistedSandboxState, o as persistThreadStateById, r as getPersistedThreadState, s as coerceThreadConversationState, t as getLocationConfigurationService } from "./thread-state-
|
|
33
|
-
import { a as requireTurnFailureEventId, d as buildDeliveredTurnStatePatch, i as getAgentTurnDiagnosticsAttributes, l as getTurnUserReplyAttachmentContext, n as persistAuthPauseTurnState, r as finalizeFailedTurnReplyWithEvent, s as getTurnUserMessage, t as completeAuthPauseTurn, u as getTurnUserSlackMessageTs } from "./auth-pause-state-
|
|
34
|
-
import { a as registerVercelPluginTaskDevConsumer, n as createVercelPluginTaskCallback, s as queueCallback } from "./task-queue-
|
|
35
|
-
import { C as isSlackTitlePermissionError, D as createSlackAdapterAssistantStatusSession, E as splitSlackReplyText, S as isRetryableSlackPostError, T as buildSlackOutputMessage, _ as getThreadId, a as GET$4, b as getSlackApiErrorCode, c as wakePausedTurn, d as shouldKeepProcessingReactionForToolInvocation, f as startProcessingReaction, g as getRunId, h as getMessageTs, i as publishAppHomeView, l as resumeSlackTurn, m as getChannelId, o as createPausedTurns, p as getAssistantThreadContext, r as GET$5, s as getPausedTurnRequest, t as receiveLocalOAuthCredential, u as buildAuthPauseResponse, v as getThreadTs, w as sendSlackReply, x as getSlackErrorObservabilityAttributes, y as stripLeadingBotMention } from "./credential-sync-
|
|
36
|
-
import { n as deleteWebAuthorization, t as createWebAuthorization } from "./web-authorization-
|
|
37
|
-
import { t as processConversationWork } from "./worker-
|
|
38
|
-
import { t as bindSpawnAgent } from "./spawn-
|
|
26
|
+
import { a as webActorFromEmail, f as lookupSlackUser, h as GET$3, i as recordWebConversationActivity, l as resolveSlackChannelTypeFromMessage, m as createVercelAttachmentStorage, n as conversationTurnIdForMessage, o as resolveConversationDestination, p as legacyWebMailboxMetadataSchema, s as conversationVisibilityFromSlackChannelType, t as appendAndEnqueueWebMessage, u as resolveSlackConversationContext } from "./web-input-CwVlaLd0.js";
|
|
27
|
+
import { u as recordAutomationExecution } from "./execution-stats-C-f8zwMU.js";
|
|
28
|
+
import { _ as markDispatchCompleted, a as claimDispatchMailboxAppend, c as getDispatchConversationId, d as getDispatchTurnId, f as getPluginDispatchProjection, g as markDispatchBlocked, h as markDispatchAwaitingResume, i as resolveTurnSessionRouting, l as getDispatchInputMessageId, m as listPendingDispatchMailboxAppends, n as scheduleSessionCompletedPluginTasks, o as confirmDispatchMailboxAppend, p as isTerminalDispatchStatus, s as createOrGetDispatch, t as processPluginTask, u as getDispatchRecord, v as markDispatchFailed, y as markDispatchRunning } from "./task-runner-Cm0gXoLH.js";
|
|
29
|
+
import { i as resolveAgentInvocationId, o as listPendingAgentInvocationMailboxAppends, r as enqueueAgentInvocation, t as createAgentInvocationWorker } from "./work-BK0W1QAt.js";
|
|
30
|
+
import { n as getTurnLifecycle, t as ConversationTurnLifecycleService } from "./turn-lifecycle-DVlJLwB0.js";
|
|
31
|
+
import { n as executeTurn, t as AgentRunError } from "./turn-execution-C7K6lQp1.js";
|
|
32
|
+
import { a as persistThreadState, i as persistThreadRuntimeState, n as getPersistedSandboxState, o as persistThreadStateById, r as getPersistedThreadState, s as coerceThreadConversationState, t as getLocationConfigurationService } from "./thread-state-lw2QwQ-y.js";
|
|
33
|
+
import { a as requireTurnFailureEventId, d as buildDeliveredTurnStatePatch, i as getAgentTurnDiagnosticsAttributes, l as getTurnUserReplyAttachmentContext, n as persistAuthPauseTurnState, r as finalizeFailedTurnReplyWithEvent, s as getTurnUserMessage, t as completeAuthPauseTurn, u as getTurnUserSlackMessageTs } from "./auth-pause-state-Bjoh8wCy.js";
|
|
34
|
+
import { a as registerVercelPluginTaskDevConsumer, n as createVercelPluginTaskCallback, s as queueCallback } from "./task-queue-JfmWmpjS.js";
|
|
35
|
+
import { C as isSlackTitlePermissionError, D as createSlackAdapterAssistantStatusSession, E as splitSlackReplyText, S as isRetryableSlackPostError, T as buildSlackOutputMessage, _ as getThreadId, a as GET$4, b as getSlackApiErrorCode, c as wakePausedTurn, d as shouldKeepProcessingReactionForToolInvocation, f as startProcessingReaction, g as getRunId, h as getMessageTs, i as publishAppHomeView, l as resumeSlackTurn, m as getChannelId, o as createPausedTurns, p as getAssistantThreadContext, r as GET$5, s as getPausedTurnRequest, t as receiveLocalOAuthCredential, u as buildAuthPauseResponse, v as getThreadTs, w as sendSlackReply, x as getSlackErrorObservabilityAttributes, y as stripLeadingBotMention } from "./credential-sync-DM-EE1ey.js";
|
|
36
|
+
import { n as deleteWebAuthorization, t as createWebAuthorization } from "./web-authorization-C9MxPvXX.js";
|
|
37
|
+
import { t as processConversationWork } from "./worker-D-WWKHQD.js";
|
|
38
|
+
import { t as bindSpawnAgent } from "./spawn-msnzfE8_.js";
|
|
39
39
|
import { createRequire } from "node:module";
|
|
40
40
|
import { pathToFileURL } from "node:url";
|
|
41
41
|
import { Hono } from "hono";
|
|
42
42
|
import { z } from "zod";
|
|
43
43
|
import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
44
44
|
import { and, asc, eq, inArray, isNotNull, isNull, lte, or, sql } from "drizzle-orm";
|
|
45
|
-
import {
|
|
45
|
+
import { EVENT_SUMMARY_MAX_LENGTH, EVENT_TEXT_MAX_LENGTH, createEventSource, createLocalSource, createSlackSource, createWebSource, dispatchOptionsSchema, eventSchema, isSlackDestination, userSchema } from "@sentry/junior-plugin-api";
|
|
46
46
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
47
47
|
import { createRemoteJWKSet, decodeJwt, jwtVerify } from "jose";
|
|
48
48
|
import { ChannelImpl, Message, ThreadImpl, stringifyMarkdown } from "chat";
|
|
@@ -431,10 +431,10 @@ function validateDispatchOptions(options) {
|
|
|
431
431
|
/** Verify runtime-owned access requirements for delegated dispatch credentials. */
|
|
432
432
|
async function verifyDispatchCredentialSubjectAccess(options, plugin) {
|
|
433
433
|
if (!options.credentialSubject) return;
|
|
434
|
-
if (!(options.credentialSubject.allowedWhen === "scheduled-
|
|
434
|
+
if (!(options.credentialSubject.allowedWhen === "scheduled-automation" ? verifyScheduledAutomationCredentialSubject({
|
|
435
435
|
plugin,
|
|
436
436
|
subject: options.credentialSubject
|
|
437
|
-
}) : options.credentialSubject.allowedWhen === "event-
|
|
437
|
+
}) : options.credentialSubject.allowedWhen === "event-automation" ? verifyEventAutomationCredentialSubject({
|
|
438
438
|
plugin,
|
|
439
439
|
subject: options.credentialSubject
|
|
440
440
|
}) : verifySlackDirectCredentialSubject({
|
|
@@ -453,7 +453,7 @@ function bindDispatchCredentialSubject(options, plugin) {
|
|
|
453
453
|
source: { kind: "plugin_dispatch" }
|
|
454
454
|
};
|
|
455
455
|
if ("binding" in credentialSubject) throw new Error("Dispatch credentialSubject binding is runtime-owned");
|
|
456
|
-
const boundSubject = credentialSubject.allowedWhen === "scheduled-
|
|
456
|
+
const boundSubject = credentialSubject.allowedWhen === "scheduled-automation" ? bindScheduledAutomationCredentialSubject({
|
|
457
457
|
plugin,
|
|
458
458
|
subject: credentialSubject
|
|
459
459
|
}) : bindSlackDirectCredentialSubject({
|
|
@@ -518,12 +518,12 @@ function createHeartbeatContext(args) {
|
|
|
518
518
|
}
|
|
519
519
|
};
|
|
520
520
|
}
|
|
521
|
-
/** Create and enqueue one core-owned event
|
|
522
|
-
async function
|
|
521
|
+
/** Create and enqueue one core-owned event automation dispatch. */
|
|
522
|
+
async function dispatchEventAutomation(args) {
|
|
523
523
|
const plugin = "junior";
|
|
524
524
|
const { credentialSubject, outcomes, ...unboundOptions } = args.options;
|
|
525
525
|
validateDispatchOptions({ ...unboundOptions });
|
|
526
|
-
const boundSubject = credentialSubject ?
|
|
526
|
+
const boundSubject = credentialSubject ? bindEventAutomationCredentialSubject({
|
|
527
527
|
plugin,
|
|
528
528
|
subject: credentialSubject
|
|
529
529
|
}) : void 0;
|
|
@@ -532,7 +532,7 @@ async function dispatchEventTask(args) {
|
|
|
532
532
|
...unboundOptions,
|
|
533
533
|
...outcomes !== void 0 ? { outcomes } : void 0,
|
|
534
534
|
...boundSubject ? { credentialSubject: boundSubject } : void 0,
|
|
535
|
-
source: { kind: "
|
|
535
|
+
source: { kind: "event_automation" }
|
|
536
536
|
};
|
|
537
537
|
return await dispatch({
|
|
538
538
|
conversationWorkQueue: args.conversationWorkQueue,
|
|
@@ -541,12 +541,12 @@ async function dispatchEventTask(args) {
|
|
|
541
541
|
plugin
|
|
542
542
|
});
|
|
543
543
|
}
|
|
544
|
-
/** Create and enqueue one core-owned scheduled
|
|
545
|
-
async function
|
|
544
|
+
/** Create and enqueue one core-owned scheduled automation dispatch. */
|
|
545
|
+
async function dispatchScheduledAutomation(args) {
|
|
546
546
|
const plugin = "scheduler";
|
|
547
547
|
const { credentialSubject, outcomes, ...unboundOptions } = args.options;
|
|
548
548
|
validateDispatchOptions({ ...unboundOptions });
|
|
549
|
-
const boundSubject = credentialSubject ?
|
|
549
|
+
const boundSubject = credentialSubject ? bindScheduledAutomationCredentialSubject({
|
|
550
550
|
plugin,
|
|
551
551
|
subject: credentialSubject
|
|
552
552
|
}) : void 0;
|
|
@@ -555,7 +555,7 @@ async function dispatchScheduledTask(args) {
|
|
|
555
555
|
...unboundOptions,
|
|
556
556
|
...outcomes !== void 0 ? { outcomes } : void 0,
|
|
557
557
|
...boundSubject ? { credentialSubject: boundSubject } : void 0,
|
|
558
|
-
source: { kind: "
|
|
558
|
+
source: { kind: "scheduled_automation" }
|
|
559
559
|
};
|
|
560
560
|
return await dispatch({
|
|
561
561
|
conversationWorkQueue: args.conversationWorkQueue,
|
|
@@ -564,15 +564,15 @@ async function dispatchScheduledTask(args) {
|
|
|
564
564
|
plugin
|
|
565
565
|
});
|
|
566
566
|
}
|
|
567
|
-
/** Read the bounded outcome for one core-owned scheduled
|
|
568
|
-
async function
|
|
567
|
+
/** Read the bounded outcome for one core-owned scheduled automation dispatch. */
|
|
568
|
+
async function getScheduledAutomationDispatch(id) {
|
|
569
569
|
return await getPluginDispatchProjection({
|
|
570
570
|
plugin: "scheduler",
|
|
571
571
|
id
|
|
572
572
|
});
|
|
573
573
|
}
|
|
574
574
|
//#endregion
|
|
575
|
-
//#region src/chat/scheduled-
|
|
575
|
+
//#region src/chat/scheduled-automations/runs.ts
|
|
576
576
|
const PENDING_CLAIM_STALE_MS = 6e4;
|
|
577
577
|
const MISSED_RUN_MAX_AGE_MS = 864e5;
|
|
578
578
|
const INCOMPLETE_RUN_STATUSES = ["pending", "running"];
|
|
@@ -616,9 +616,9 @@ async function listIncompleteRunsForTaskIds(db, taskIds) {
|
|
|
616
616
|
if (taskIds.length === 0) return [];
|
|
617
617
|
return (await db.select({ record: juniorSchedulerRuns.record }).from(juniorSchedulerRuns).where(and(inArray(juniorSchedulerRuns.taskId, taskIds), inArray(juniorSchedulerRuns.status, [...INCOMPLETE_RUN_STATUSES]))).orderBy(asc(juniorSchedulerRuns.scheduledForMs), asc(juniorSchedulerRuns.id))).map(parseScheduledRunRow).filter(present);
|
|
618
618
|
}
|
|
619
|
-
/** List incomplete runs for retained scheduled
|
|
619
|
+
/** List incomplete runs for retained scheduled automations. */
|
|
620
620
|
async function listIncompleteScheduledRuns(db) {
|
|
621
|
-
return await listIncompleteRunsForTaskIds(db, (await
|
|
621
|
+
return await listIncompleteRunsForTaskIds(db, (await listScheduledAutomations(db)).map((task) => task.id));
|
|
622
622
|
}
|
|
623
623
|
function getDueRunAtMs(task, nowMs) {
|
|
624
624
|
if (typeof task.runNowAtMs === "number" && Number.isFinite(task.runNowAtMs) && task.runNowAtMs <= nowMs) return task.runNowAtMs;
|
|
@@ -654,7 +654,7 @@ function taskDedupeFingerprint(task) {
|
|
|
654
654
|
}
|
|
655
655
|
async function findStaleRecoveryCanonicalTask(db, task) {
|
|
656
656
|
const fingerprint = taskDedupeFingerprint(task);
|
|
657
|
-
return (await
|
|
657
|
+
return (await listScheduledAutomationsForTeam(db, task.destination.teamId)).filter((candidate) => candidate.id !== task.id && candidate.status === "active" && (candidate.createdAtMs < task.createdAtMs || candidate.createdAtMs === task.createdAtMs && candidate.id < task.id) && taskDedupeFingerprint(candidate) === fingerprint).at(0);
|
|
658
658
|
}
|
|
659
659
|
function statusAfterTerminalOccurrence(args) {
|
|
660
660
|
if (args.outcome === "blocked") return "blocked";
|
|
@@ -666,7 +666,7 @@ async function skipMissedRun(db, args) {
|
|
|
666
666
|
const current = args.task;
|
|
667
667
|
if (current.status !== "active" || getDueRunAtMs(current, args.nowMs) !== args.scheduledForMs) return;
|
|
668
668
|
const duplicateOf = await findStaleRecoveryCanonicalTask(db, current);
|
|
669
|
-
const errorMessage = duplicateOf ? `Duplicate stale scheduled
|
|
669
|
+
const errorMessage = duplicateOf ? `Duplicate stale scheduled automation was skipped without dispatch. Canonical task: ${duplicateOf.id}.` : "Scheduled occurrence was more than 24 hours late and was skipped without dispatch.";
|
|
670
670
|
const skipped = {
|
|
671
671
|
id: scheduledRunId(current.id, args.scheduledForMs),
|
|
672
672
|
attempt: 1,
|
|
@@ -682,7 +682,7 @@ async function skipMissedRun(db, args) {
|
|
|
682
682
|
let nextRunAtMs;
|
|
683
683
|
if (!duplicateOf) nextRunAtMs = isRunNow && current.nextRunAtMs !== args.scheduledForMs ? current.nextRunAtMs : current.schedule.kind === "recurring" ? getNextRunAtMs(current, args.scheduledForMs, args.nowMs) : void 0;
|
|
684
684
|
const status = statusAfterTerminalOccurrence({ nextRunAtMs });
|
|
685
|
-
await
|
|
685
|
+
await saveScheduledAutomationInLock(db, {
|
|
686
686
|
...current,
|
|
687
687
|
nextRunAtMs,
|
|
688
688
|
runNowAtMs: isRunNow ? void 0 : current.runNowAtMs,
|
|
@@ -703,8 +703,8 @@ async function claimDueScheduledRun(db, args) {
|
|
|
703
703
|
await tx.execute(sql`SELECT pg_advisory_xact_lock(hashtext('junior:scheduler:claim'))`);
|
|
704
704
|
const rows = await tx.select({ id: juniorSchedulerTasks.id }).from(juniorSchedulerTasks).where(and(eq(juniorSchedulerTasks.status, "active"), or(and(isNotNull(juniorSchedulerTasks.runNowAtMs), lte(juniorSchedulerTasks.runNowAtMs, args.nowMs)), and(isNotNull(juniorSchedulerTasks.nextRunAtMs), lte(juniorSchedulerTasks.nextRunAtMs, args.nowMs))))).orderBy(asc(juniorSchedulerTasks.createdAtMs), asc(juniorSchedulerTasks.id));
|
|
705
705
|
for (const row of rows) {
|
|
706
|
-
const run = await
|
|
707
|
-
const task = await
|
|
706
|
+
const run = await withScheduledAutomationLock(tx, row.id, async (taskTx) => {
|
|
707
|
+
const task = await readScheduledAutomation(taskTx, row.id);
|
|
708
708
|
if (!task || task.status !== "active") return void 0;
|
|
709
709
|
const scheduledForMs = getDueRunAtMs(task, args.nowMs);
|
|
710
710
|
if (scheduledForMs === void 0) return void 0;
|
|
@@ -746,7 +746,7 @@ async function claimDueScheduledRun(db, args) {
|
|
|
746
746
|
if (run) return run;
|
|
747
747
|
}
|
|
748
748
|
});
|
|
749
|
-
for (const skipped of skippedRuns)
|
|
749
|
+
for (const skipped of skippedRuns) logScheduledAutomationRunSkipped(skipped.task, skipped.run, { "app.task.run.error": skipped.errorMessage });
|
|
750
750
|
return claimed;
|
|
751
751
|
}
|
|
752
752
|
async function updateRun(db, runId, update) {
|
|
@@ -809,15 +809,15 @@ async function markScheduledRunSkipped(db, args) {
|
|
|
809
809
|
status: "skipped"
|
|
810
810
|
} : void 0);
|
|
811
811
|
}
|
|
812
|
-
/** Advance a scheduled
|
|
813
|
-
async function
|
|
814
|
-
await
|
|
815
|
-
const current = await
|
|
812
|
+
/** Advance a scheduled automation after a terminal run under its task lock. */
|
|
813
|
+
async function advanceScheduledAutomationAfterRun(db, args) {
|
|
814
|
+
await withScheduledAutomationLock(db, args.run.taskId, async (tx) => {
|
|
815
|
+
const current = await readScheduledAutomation(tx, args.run.taskId);
|
|
816
816
|
if (!current || current.status === "deleted" || current.status === "completed") return;
|
|
817
817
|
if (current.runNowAtMs === args.run.scheduledForMs) {
|
|
818
818
|
let nextRunAtMs = current.nextRunAtMs;
|
|
819
819
|
if (args.status !== "blocked" && typeof current.nextRunAtMs === "number" && current.nextRunAtMs <= args.run.scheduledForMs) nextRunAtMs = getNextRunAtMs(current, current.nextRunAtMs, args.nowMs);
|
|
820
|
-
await
|
|
820
|
+
await saveScheduledAutomationInLock(tx, {
|
|
821
821
|
...current,
|
|
822
822
|
lastRunAtMs: args.run.scheduledForMs,
|
|
823
823
|
nextRunAtMs,
|
|
@@ -833,7 +833,7 @@ async function advanceScheduledTaskAfterRun(db, args) {
|
|
|
833
833
|
return;
|
|
834
834
|
}
|
|
835
835
|
if (current.status !== "active" || current.nextRunAtMs !== args.run.scheduledForMs) {
|
|
836
|
-
await
|
|
836
|
+
await saveScheduledAutomationInLock(tx, {
|
|
837
837
|
...current,
|
|
838
838
|
lastRunAtMs: args.run.scheduledForMs,
|
|
839
839
|
updatedAtMs: args.nowMs
|
|
@@ -841,7 +841,7 @@ async function advanceScheduledTaskAfterRun(db, args) {
|
|
|
841
841
|
return;
|
|
842
842
|
}
|
|
843
843
|
const nextRunAtMs = args.status === "blocked" ? void 0 : getNextRunAtMs(current, args.run.scheduledForMs, args.nowMs);
|
|
844
|
-
await
|
|
844
|
+
await saveScheduledAutomationInLock(tx, {
|
|
845
845
|
...current,
|
|
846
846
|
lastRunAtMs: args.run.scheduledForMs,
|
|
847
847
|
nextRunAtMs,
|
|
@@ -855,8 +855,8 @@ async function advanceScheduledTaskAfterRun(db, args) {
|
|
|
855
855
|
});
|
|
856
856
|
}
|
|
857
857
|
//#endregion
|
|
858
|
-
//#region src/chat/scheduled-
|
|
859
|
-
const
|
|
858
|
+
//#region src/chat/scheduled-automations/heartbeat.ts
|
|
859
|
+
const SCHEDULED_AUTOMATION_HEARTBEAT_LIMIT = 10;
|
|
860
860
|
const SCHEDULE_FREQUENCY_COPY = {
|
|
861
861
|
daily: {
|
|
862
862
|
label: "Daily",
|
|
@@ -878,7 +878,7 @@ const SCHEDULE_FREQUENCY_COPY = {
|
|
|
878
878
|
function singleLineMetadataValue(value) {
|
|
879
879
|
return value.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
|
|
880
880
|
}
|
|
881
|
-
/** Render the due scheduled
|
|
881
|
+
/** Render the due scheduled automation as plain agent input. */
|
|
882
882
|
function buildDispatchInput(task) {
|
|
883
883
|
return renderTaskInput({
|
|
884
884
|
instructions: task.task.text,
|
|
@@ -886,7 +886,7 @@ function buildDispatchInput(task) {
|
|
|
886
886
|
});
|
|
887
887
|
}
|
|
888
888
|
function buildDispatchMetadata(args) {
|
|
889
|
-
if (!args.task.task.text?.trim()) throw new Error("Scheduled
|
|
889
|
+
if (!args.task.task.text?.trim()) throw new Error("Scheduled automation text is required");
|
|
890
890
|
return {
|
|
891
891
|
runId: args.run.id,
|
|
892
892
|
schedule: singleLineMetadataValue(args.task.schedule.description),
|
|
@@ -904,31 +904,31 @@ function buildDispatchMetadata(args) {
|
|
|
904
904
|
}
|
|
905
905
|
function replyAttribution$1(task) {
|
|
906
906
|
if (task.schedule.kind === "one_off") return {
|
|
907
|
-
label: "Scheduled
|
|
907
|
+
label: "Scheduled automation",
|
|
908
908
|
detail: "One-time"
|
|
909
909
|
};
|
|
910
910
|
const recurrence = task.schedule.recurrence;
|
|
911
911
|
if (!recurrence) return {
|
|
912
|
-
label: "Scheduled
|
|
912
|
+
label: "Scheduled automation",
|
|
913
913
|
detail: "Recurring"
|
|
914
914
|
};
|
|
915
915
|
const frequency = SCHEDULE_FREQUENCY_COPY[recurrence.frequency];
|
|
916
916
|
return recurrence.interval === 1 ? {
|
|
917
|
-
label: "Scheduled
|
|
917
|
+
label: "Scheduled automation",
|
|
918
918
|
detail: frequency.label
|
|
919
919
|
} : {
|
|
920
|
-
label: "Scheduled
|
|
920
|
+
label: "Scheduled automation",
|
|
921
921
|
detail: `Every ${recurrence.interval} ${frequency.unit}s`
|
|
922
922
|
};
|
|
923
923
|
}
|
|
924
924
|
function shouldSkipRun(task, run) {
|
|
925
|
-
if (task.status === "deleted") return `Scheduled
|
|
926
|
-
if (task.status !== "active") return `Scheduled
|
|
927
|
-
if (task.nextRunAtMs !== run.scheduledForMs && task.runNowAtMs !== run.scheduledForMs) return `Scheduled
|
|
925
|
+
if (task.status === "deleted") return `Scheduled automation ${task.id} was deleted before the run started.`;
|
|
926
|
+
if (task.status !== "active") return `Scheduled automation ${task.id} was ${task.status} before the run started.`;
|
|
927
|
+
if (task.nextRunAtMs !== run.scheduledForMs && task.runNowAtMs !== run.scheduledForMs) return `Scheduled automation ${task.id} no longer targets ${new Date(run.scheduledForMs).toISOString()}.`;
|
|
928
928
|
}
|
|
929
929
|
async function recordScheduledExecution(args) {
|
|
930
930
|
const dispatchId = args.run.dispatchId;
|
|
931
|
-
await
|
|
931
|
+
await recordAutomationExecution("scheduled", args.run.taskId, {
|
|
932
932
|
...dispatchId ? { conversationId: getDispatchConversationId({ id: dispatchId }) } : void 0,
|
|
933
933
|
executionId: args.run.id,
|
|
934
934
|
nowMs: args.nowMs,
|
|
@@ -936,7 +936,7 @@ async function recordScheduledExecution(args) {
|
|
|
936
936
|
});
|
|
937
937
|
}
|
|
938
938
|
async function logRunOutcome(args) {
|
|
939
|
-
const task = args.task ?? await
|
|
939
|
+
const task = args.task ?? await readScheduledAutomation(args.db, args.run.taskId);
|
|
940
940
|
if (!task) {
|
|
941
941
|
logInfo(args.eventName, {
|
|
942
942
|
"app.task.id": args.run.taskId,
|
|
@@ -950,7 +950,7 @@ async function logRunOutcome(args) {
|
|
|
950
950
|
});
|
|
951
951
|
return;
|
|
952
952
|
}
|
|
953
|
-
logInfo(args.eventName,
|
|
953
|
+
logInfo(args.eventName, scheduledAutomationRunAttributes(task, args.run, args.extras));
|
|
954
954
|
}
|
|
955
955
|
async function applyDispatchResult(args) {
|
|
956
956
|
if (args.dispatch.status === "completed") {
|
|
@@ -961,7 +961,7 @@ async function applyDispatchResult(args) {
|
|
|
961
961
|
startedAtMs: args.run.startedAtMs
|
|
962
962
|
});
|
|
963
963
|
if (!completed) return false;
|
|
964
|
-
await
|
|
964
|
+
await advanceScheduledAutomationAfterRun(args.db, {
|
|
965
965
|
nowMs: args.nowMs,
|
|
966
966
|
run: args.run,
|
|
967
967
|
status: "completed"
|
|
@@ -972,7 +972,7 @@ async function applyDispatchResult(args) {
|
|
|
972
972
|
status: "completed"
|
|
973
973
|
});
|
|
974
974
|
await logRunOutcome({
|
|
975
|
-
eventName: "
|
|
975
|
+
eventName: "scheduled_automation.run.completed",
|
|
976
976
|
run: completed,
|
|
977
977
|
db: args.db
|
|
978
978
|
});
|
|
@@ -986,7 +986,7 @@ async function applyDispatchResult(args) {
|
|
|
986
986
|
startedAtMs: args.run.startedAtMs
|
|
987
987
|
});
|
|
988
988
|
if (!blocked) return false;
|
|
989
|
-
await
|
|
989
|
+
await advanceScheduledAutomationAfterRun(args.db, {
|
|
990
990
|
errorMessage: blocked.errorMessage,
|
|
991
991
|
nowMs: args.nowMs,
|
|
992
992
|
run: args.run,
|
|
@@ -998,7 +998,7 @@ async function applyDispatchResult(args) {
|
|
|
998
998
|
status: "blocked"
|
|
999
999
|
});
|
|
1000
1000
|
await logRunOutcome({
|
|
1001
|
-
eventName: "
|
|
1001
|
+
eventName: "scheduled_automation.run.blocked",
|
|
1002
1002
|
run: blocked,
|
|
1003
1003
|
db: args.db,
|
|
1004
1004
|
extras: blocked.errorMessage ? { "app.task.run.error": blocked.errorMessage } : void 0
|
|
@@ -1013,7 +1013,7 @@ async function applyDispatchResult(args) {
|
|
|
1013
1013
|
startedAtMs: args.run.startedAtMs
|
|
1014
1014
|
});
|
|
1015
1015
|
if (!failed) return false;
|
|
1016
|
-
await
|
|
1016
|
+
await advanceScheduledAutomationAfterRun(args.db, {
|
|
1017
1017
|
errorMessage: failed.errorMessage,
|
|
1018
1018
|
nowMs: args.nowMs,
|
|
1019
1019
|
run: args.run,
|
|
@@ -1025,7 +1025,7 @@ async function applyDispatchResult(args) {
|
|
|
1025
1025
|
status: "failed"
|
|
1026
1026
|
});
|
|
1027
1027
|
await logRunOutcome({
|
|
1028
|
-
eventName: "
|
|
1028
|
+
eventName: "scheduled_automation.run.failed",
|
|
1029
1029
|
run: failed,
|
|
1030
1030
|
db: args.db,
|
|
1031
1031
|
extras: failed.errorMessage ? { "app.task.run.error": failed.errorMessage } : void 0
|
|
@@ -1046,7 +1046,7 @@ async function finishClaimedRun(args) {
|
|
|
1046
1046
|
startedAtMs: args.run.startedAtMs
|
|
1047
1047
|
});
|
|
1048
1048
|
if (!finished) return;
|
|
1049
|
-
await
|
|
1049
|
+
await advanceScheduledAutomationAfterRun(args.db, {
|
|
1050
1050
|
errorMessage: args.errorMessage,
|
|
1051
1051
|
nowMs: args.nowMs,
|
|
1052
1052
|
run: args.run,
|
|
@@ -1058,24 +1058,24 @@ async function finishClaimedRun(args) {
|
|
|
1058
1058
|
status: args.status
|
|
1059
1059
|
});
|
|
1060
1060
|
await logRunOutcome({
|
|
1061
|
-
eventName: args.status === "blocked" ? "
|
|
1061
|
+
eventName: args.status === "blocked" ? "scheduled_automation.run.blocked" : "scheduled_automation.run.failed",
|
|
1062
1062
|
run: finished,
|
|
1063
1063
|
db: args.db,
|
|
1064
1064
|
extras: { "app.task.run.error": args.errorMessage }
|
|
1065
1065
|
});
|
|
1066
1066
|
}
|
|
1067
1067
|
/** Reconcile completed dispatches and enqueue a bounded batch of due tasks. */
|
|
1068
|
-
async function
|
|
1068
|
+
async function runScheduledAutomationHeartbeat(args) {
|
|
1069
1069
|
const db = getDb();
|
|
1070
1070
|
let processedCount = 0;
|
|
1071
1071
|
let dispatchCount = 0;
|
|
1072
1072
|
for (const run of await listIncompleteScheduledRuns(db)) {
|
|
1073
1073
|
if (!run.dispatchId) continue;
|
|
1074
|
-
const dispatch = await
|
|
1074
|
+
const dispatch = await getScheduledAutomationDispatch(run.dispatchId);
|
|
1075
1075
|
if (!dispatch) {
|
|
1076
1076
|
await finishClaimedRun({
|
|
1077
1077
|
db,
|
|
1078
|
-
errorMessage: "Scheduled
|
|
1078
|
+
errorMessage: "Scheduled automation dispatch record is missing.",
|
|
1079
1079
|
nowMs: args.nowMs,
|
|
1080
1080
|
run,
|
|
1081
1081
|
status: "failed"
|
|
@@ -1089,25 +1089,25 @@ async function runScheduledTaskHeartbeat(args) {
|
|
|
1089
1089
|
run
|
|
1090
1090
|
})) processedCount += 1;
|
|
1091
1091
|
}
|
|
1092
|
-
for (let index = processedCount; index <
|
|
1092
|
+
for (let index = processedCount; index < SCHEDULED_AUTOMATION_HEARTBEAT_LIMIT; index += 1) {
|
|
1093
1093
|
const run = await claimDueScheduledRun(db, { nowMs: args.nowMs });
|
|
1094
1094
|
if (!run) break;
|
|
1095
|
-
const task = await
|
|
1095
|
+
const task = await readScheduledAutomation(db, run.taskId);
|
|
1096
1096
|
if (!task) {
|
|
1097
1097
|
const failed = await markScheduledRunFailed(db, {
|
|
1098
1098
|
completedAtMs: args.nowMs,
|
|
1099
|
-
errorMessage: `Scheduled
|
|
1099
|
+
errorMessage: `Scheduled automation ${run.taskId} was not found`,
|
|
1100
1100
|
runId: run.id
|
|
1101
1101
|
});
|
|
1102
1102
|
if (failed) await logRunOutcome({
|
|
1103
|
-
eventName: "
|
|
1103
|
+
eventName: "scheduled_automation.run.failed",
|
|
1104
1104
|
run: failed,
|
|
1105
1105
|
db,
|
|
1106
|
-
extras: { "app.task.run.error": `Scheduled
|
|
1106
|
+
extras: { "app.task.run.error": `Scheduled automation ${run.taskId} was not found` }
|
|
1107
1107
|
});
|
|
1108
1108
|
continue;
|
|
1109
1109
|
}
|
|
1110
|
-
logInfo("
|
|
1110
|
+
logInfo("scheduled_automation.run.claimed", scheduledAutomationRunAttributes(task, run));
|
|
1111
1111
|
const skippedReason = shouldSkipRun(task, run);
|
|
1112
1112
|
if (skippedReason) {
|
|
1113
1113
|
const skipped = await markScheduledRunSkipped(db, {
|
|
@@ -1115,7 +1115,7 @@ async function runScheduledTaskHeartbeat(args) {
|
|
|
1115
1115
|
errorMessage: skippedReason,
|
|
1116
1116
|
runId: run.id
|
|
1117
1117
|
});
|
|
1118
|
-
if (skipped)
|
|
1118
|
+
if (skipped) logScheduledAutomationRunSkipped(task, skipped, { "app.task.run.error": skippedReason });
|
|
1119
1119
|
continue;
|
|
1120
1120
|
}
|
|
1121
1121
|
let metadata;
|
|
@@ -1128,7 +1128,7 @@ async function runScheduledTaskHeartbeat(args) {
|
|
|
1128
1128
|
} catch (error) {
|
|
1129
1129
|
await finishClaimedRun({
|
|
1130
1130
|
db,
|
|
1131
|
-
errorMessage: error instanceof Error ? `Scheduled
|
|
1131
|
+
errorMessage: error instanceof Error ? `Scheduled automation dispatch metadata could not be built: ${error.message}` : "Scheduled automation dispatch metadata could not be built.",
|
|
1132
1132
|
nowMs: args.nowMs,
|
|
1133
1133
|
run,
|
|
1134
1134
|
status: "blocked"
|
|
@@ -1137,7 +1137,7 @@ async function runScheduledTaskHeartbeat(args) {
|
|
|
1137
1137
|
}
|
|
1138
1138
|
let dispatch;
|
|
1139
1139
|
try {
|
|
1140
|
-
dispatch = await
|
|
1140
|
+
dispatch = await dispatchScheduledAutomation({
|
|
1141
1141
|
conversationWorkQueue: args.conversationWorkQueue,
|
|
1142
1142
|
nowMs: args.nowMs,
|
|
1143
1143
|
options: {
|
|
@@ -1145,7 +1145,7 @@ async function runScheduledTaskHeartbeat(args) {
|
|
|
1145
1145
|
...task.credentialMode === "creator" ? { credentialSubject: {
|
|
1146
1146
|
type: "user",
|
|
1147
1147
|
userId: task.createdBy.slackUserId,
|
|
1148
|
-
allowedWhen: "scheduled-
|
|
1148
|
+
allowedWhen: "scheduled-automation",
|
|
1149
1149
|
taskId: task.id
|
|
1150
1150
|
} } : void 0,
|
|
1151
1151
|
destination: task.destination,
|
|
@@ -1159,7 +1159,7 @@ async function runScheduledTaskHeartbeat(args) {
|
|
|
1159
1159
|
} catch (error) {
|
|
1160
1160
|
await finishClaimedRun({
|
|
1161
1161
|
db,
|
|
1162
|
-
errorMessage: error instanceof Error ? `Scheduled
|
|
1162
|
+
errorMessage: error instanceof Error ? `Scheduled automation dispatch could not be created: ${error.message}` : "Scheduled automation dispatch could not be created.",
|
|
1163
1163
|
nowMs: args.nowMs,
|
|
1164
1164
|
run,
|
|
1165
1165
|
status: "blocked"
|
|
@@ -1172,7 +1172,7 @@ async function runScheduledTaskHeartbeat(args) {
|
|
|
1172
1172
|
nowMs: args.nowMs,
|
|
1173
1173
|
runId: run.id
|
|
1174
1174
|
});
|
|
1175
|
-
logInfo("
|
|
1175
|
+
logInfo("scheduled_automation.run.dispatched", scheduledAutomationRunAttributes(task, dispatched ?? {
|
|
1176
1176
|
...run,
|
|
1177
1177
|
dispatchId: dispatch.id
|
|
1178
1178
|
}, { "app.dispatch.id": dispatch.id }));
|
|
@@ -1277,13 +1277,13 @@ async function runHeartbeat(args) {
|
|
|
1277
1277
|
nowMs: args.nowMs
|
|
1278
1278
|
});
|
|
1279
1279
|
try {
|
|
1280
|
-
const dispatchCount = await
|
|
1280
|
+
const dispatchCount = await runScheduledAutomationHeartbeat({
|
|
1281
1281
|
conversationWorkQueue: queue,
|
|
1282
1282
|
nowMs: args.nowMs
|
|
1283
1283
|
});
|
|
1284
|
-
if (dispatchCount > 0) logInfo("
|
|
1284
|
+
if (dispatchCount > 0) logInfo("scheduled_automations.heartbeat.dispatched", { "app.dispatch.count": dispatchCount });
|
|
1285
1285
|
} catch (error) {
|
|
1286
|
-
logException(error, "
|
|
1286
|
+
logException(error, "scheduled_automations.heartbeat.failed");
|
|
1287
1287
|
}
|
|
1288
1288
|
await runPluginHeartbeats({
|
|
1289
1289
|
conversationWorkQueue: queue,
|
|
@@ -2471,7 +2471,7 @@ function createSlackTurnRuntime(deps) {
|
|
|
2471
2471
|
/** Unsubscribe the thread and cancel resource watches for a stop decision. */
|
|
2472
2472
|
const maybeHandleThreadOptOutDecision = async (args) => {
|
|
2473
2473
|
if (!args.decision?.shouldUnsubscribe) return false;
|
|
2474
|
-
await deps.
|
|
2474
|
+
await deps.cancelWatches({ conversationId: args.thread.id });
|
|
2475
2475
|
await args.thread.unsubscribe();
|
|
2476
2476
|
await args.beforeFirstResponsePost?.();
|
|
2477
2477
|
await args.thread.post(THREAD_OPTOUT_ACK);
|
|
@@ -3135,9 +3135,9 @@ function createSlackTurnRuntime(deps) {
|
|
|
3135
3135
|
* after no deployed Turn cursor can omit either field.
|
|
3136
3136
|
*/
|
|
3137
3137
|
function turnInputFactsFromConversationMessage(message, args) {
|
|
3138
|
-
if (
|
|
3139
|
-
actor: args.savedActor ??
|
|
3140
|
-
author: message.author ??
|
|
3138
|
+
if (isEventConversationMessage(message)) return {
|
|
3139
|
+
actor: args.savedActor ?? EVENT_SYSTEM_ACTOR,
|
|
3140
|
+
author: message.author ?? EVENT_MESSAGE_AUTHOR,
|
|
3141
3141
|
source: args.savedSource ?? (args.location ? createWebSource(args.conversationId, args.visibility === "private" ? "private" : "public") : createLocalSource(args.conversationId))
|
|
3142
3142
|
};
|
|
3143
3143
|
const actor = args.savedActor ?? createActor(message.author, {
|
|
@@ -3156,8 +3156,8 @@ function sourceFromTurnInput(args) {
|
|
|
3156
3156
|
if (args.source.kind === "web") return createWebSource(args.conversationId, args.visibility === "private" ? "private" : "public");
|
|
3157
3157
|
return args.source;
|
|
3158
3158
|
}
|
|
3159
|
-
function
|
|
3160
|
-
return Boolean(actors?.some((actor) => actor.platform === "system" && actor.name ===
|
|
3159
|
+
function hasEventActor(actors) {
|
|
3160
|
+
return Boolean(actors?.some((actor) => actor.platform === "system" && actor.name === EVENT_SYSTEM_ACTOR.name));
|
|
3161
3161
|
}
|
|
3162
3162
|
/** Return the active web Turn for one Conversation, if it has one. */
|
|
3163
3163
|
async function getActiveConversationTurnId(conversationId) {
|
|
@@ -3168,10 +3168,10 @@ async function getActiveConversationTurnId(conversationId) {
|
|
|
3168
3168
|
const record = await getTurnRecord(conversationId, turnId);
|
|
3169
3169
|
return record && (record.source?.kind === "web" || !record.source && record.surface === "api") && !record.dispatchId && (record.state === "paused" || record.state === "running") ? turnId : void 0;
|
|
3170
3170
|
}
|
|
3171
|
-
/** Return the active web or
|
|
3171
|
+
/** Return the active web or event mailbox Turn. */
|
|
3172
3172
|
async function getActiveMailboxTurnId(conversationId) {
|
|
3173
3173
|
const summaries = await listTurnSummaries(conversationId);
|
|
3174
|
-
const active = (await Promise.all(summaries.filter((summary) => !summary.dispatchId && (summary.state === "paused" || summary.state === "running")).map((summary) => getTurnRecord(conversationId, summary.turnId)))).filter((record) => record && !record.dispatchId && (record.source?.kind === "web" || record.source?.kind === "
|
|
3174
|
+
const active = (await Promise.all(summaries.filter((summary) => !summary.dispatchId && (summary.state === "paused" || summary.state === "running")).map((summary) => getTurnRecord(conversationId, summary.turnId)))).filter((record) => record && !record.dispatchId && (record.source?.kind === "web" || record.source?.kind === "event" || !record.source && (record.surface === "api" || hasEventActor(record.actors))) && (record.state === "paused" || record.state === "running"));
|
|
3175
3175
|
if (active.length > 1) throw new Error(`Conversation ${conversationId} has multiple active mailbox Turns`);
|
|
3176
3176
|
return active[0]?.turnId;
|
|
3177
3177
|
}
|
|
@@ -3213,27 +3213,27 @@ function parseWebMessages(messages) {
|
|
|
3213
3213
|
};
|
|
3214
3214
|
});
|
|
3215
3215
|
}
|
|
3216
|
-
function
|
|
3216
|
+
function parseEventMessages(messages) {
|
|
3217
3217
|
if (messages.length === 0) return [];
|
|
3218
|
-
if (!messages.every((message) => message.source === "
|
|
3218
|
+
if (!messages.every((message) => message.source === "event" && isEventMailboxMetadata(message.input.metadata))) return [];
|
|
3219
3219
|
return messages.map((message) => {
|
|
3220
|
-
if (!
|
|
3220
|
+
if (!isEventMailboxMetadata(message.input.metadata)) throw new Error("Event has invalid metadata");
|
|
3221
3221
|
return {
|
|
3222
|
-
actor:
|
|
3223
|
-
author:
|
|
3222
|
+
actor: EVENT_SYSTEM_ACTOR,
|
|
3223
|
+
author: EVENT_MESSAGE_AUTHOR,
|
|
3224
3224
|
message,
|
|
3225
|
-
source:
|
|
3226
|
-
eventKey: message.input.metadata.
|
|
3227
|
-
eventType: message.input.metadata.
|
|
3228
|
-
identifier: message.input.metadata.
|
|
3229
|
-
namespace: message.input.metadata.
|
|
3225
|
+
source: createEventSource({
|
|
3226
|
+
eventKey: message.input.metadata.event.eventKey,
|
|
3227
|
+
eventType: message.input.metadata.event.eventType,
|
|
3228
|
+
identifier: message.input.metadata.event.identifier,
|
|
3229
|
+
namespace: message.input.metadata.event.namespace
|
|
3230
3230
|
})
|
|
3231
3231
|
};
|
|
3232
3232
|
});
|
|
3233
3233
|
}
|
|
3234
3234
|
/**
|
|
3235
|
-
* Select web or
|
|
3236
|
-
* Saved Actor data identifies a resumed
|
|
3235
|
+
* Select web or event work from new mailbox input or a saved Turn.
|
|
3236
|
+
* Saved Actor data identifies a resumed event Turn.
|
|
3237
3237
|
*/
|
|
3238
3238
|
async function resolveMailboxTurnWork(context) {
|
|
3239
3239
|
const batch = parseWebMessages(context.attempt.messages);
|
|
@@ -3241,7 +3241,7 @@ async function resolveMailboxTurnWork(context) {
|
|
|
3241
3241
|
kind: "mailbox",
|
|
3242
3242
|
batch
|
|
3243
3243
|
};
|
|
3244
|
-
const resourceBatch =
|
|
3244
|
+
const resourceBatch = parseEventMessages(context.attempt.messages);
|
|
3245
3245
|
if (resourceBatch.length > 0) return {
|
|
3246
3246
|
kind: "mailbox",
|
|
3247
3247
|
batch: resourceBatch
|
|
@@ -3656,8 +3656,8 @@ const slackConversationMessageMetadataBaseSchema = z.object({
|
|
|
3656
3656
|
thread: serializedThreadSchema
|
|
3657
3657
|
});
|
|
3658
3658
|
const slackConversationMessageMetadataSchema = z.union([slackConversationMessageMetadataBaseSchema.strict(), slackConversationMessageMetadataBaseSchema.extend({
|
|
3659
|
-
kind: z.literal("
|
|
3660
|
-
|
|
3659
|
+
kind: z.literal("event"),
|
|
3660
|
+
event: z.object({
|
|
3661
3661
|
eventKey: z.string(),
|
|
3662
3662
|
eventType: z.string(),
|
|
3663
3663
|
namespace: z.string(),
|
|
@@ -6770,7 +6770,7 @@ function createSlackRuntime(options) {
|
|
|
6770
6770
|
return {
|
|
6771
6771
|
...createSlackTurnRuntime({
|
|
6772
6772
|
assistantUserName: botConfig.userName,
|
|
6773
|
-
|
|
6773
|
+
cancelWatches: cancelSubscriptions,
|
|
6774
6774
|
getBotUserId: () => options.getSlackAdapter().botUserId,
|
|
6775
6775
|
modelId: defaultModelId(botConfig),
|
|
6776
6776
|
now: options.now ?? (() => Date.now()),
|
|
@@ -6972,7 +6972,7 @@ async function resolveSlackResumeUserActor(args) {
|
|
|
6972
6972
|
* Sources, in order:
|
|
6973
6973
|
* 1. Actor saved on the Turn.
|
|
6974
6974
|
* 2. Actor and credentials supplied by dispatch or OAuth.
|
|
6975
|
-
* 3. Legacy
|
|
6975
|
+
* 3. Legacy Event or Slack Message data.
|
|
6976
6976
|
*
|
|
6977
6977
|
* TODO(dcramer): Remove the routing and Message Actor fallbacks after no
|
|
6978
6978
|
* deployed Turn cursor can omit Actor.
|
|
@@ -6987,7 +6987,7 @@ async function resolveResumeExecutionIdentity(args) {
|
|
|
6987
6987
|
} : void 0;
|
|
6988
6988
|
}
|
|
6989
6989
|
let actor = args.actor ?? routing?.actor;
|
|
6990
|
-
if (!actor &&
|
|
6990
|
+
if (!actor && isEventConversationMessage(args.userMessage)) actor = EVENT_SYSTEM_ACTOR;
|
|
6991
6991
|
if (!actor && args.userMessage.author?.userId) actor = await resolveSlackResumeUserActor({
|
|
6992
6992
|
conversationId: args.conversationId,
|
|
6993
6993
|
teamId: args.teamId,
|
|
@@ -7408,7 +7408,7 @@ async function completeCancelledConversationTurn(args) {
|
|
|
7408
7408
|
await args.acknowledge();
|
|
7409
7409
|
}
|
|
7410
7410
|
/**
|
|
7411
|
-
* Create the shared mailbox worker for web and
|
|
7411
|
+
* Create the shared mailbox worker for web and event Turns.
|
|
7412
7412
|
*/
|
|
7413
7413
|
function createConversationTurnWorker(agentRunner, deliverMessage) {
|
|
7414
7414
|
return async (context, resolved) => {
|
|
@@ -7420,7 +7420,7 @@ function createConversationTurnWorker(agentRunner, deliverMessage) {
|
|
|
7420
7420
|
let userMessageId = "";
|
|
7421
7421
|
let startedAtMs = Date.now();
|
|
7422
7422
|
let inputMessageIds = [];
|
|
7423
|
-
let
|
|
7423
|
+
let event;
|
|
7424
7424
|
const storedConversation = await getConversationStore().get({ conversationId: context.conversationId });
|
|
7425
7425
|
const mailboxDestination = resolved.kind === "mailbox" ? resolved.batch[0]?.message.destination : void 0;
|
|
7426
7426
|
const destination = resolveConversationDestination({
|
|
@@ -7435,7 +7435,7 @@ function createConversationTurnWorker(agentRunner, deliverMessage) {
|
|
|
7435
7435
|
turnId = buildDeterministicTurnId(userMessageId);
|
|
7436
7436
|
inputMessageIds = resolved.batch.map((entry) => entry.message.inboundMessageId);
|
|
7437
7437
|
turnInputFacts = first;
|
|
7438
|
-
if (
|
|
7438
|
+
if (isEventMailboxMetadata(first.message.input.metadata)) event = first.message.input.metadata.event;
|
|
7439
7439
|
} else turnId = resolved.turnId;
|
|
7440
7440
|
const persisted = await getPersistedThreadState(context.conversationId);
|
|
7441
7441
|
const conversation = coerceThreadConversationState(persisted);
|
|
@@ -7444,11 +7444,11 @@ function createConversationTurnWorker(agentRunner, deliverMessage) {
|
|
|
7444
7444
|
conversationId: context.conversationId
|
|
7445
7445
|
});
|
|
7446
7446
|
const savedTurn = isResume ? await getTurnRecord(context.conversationId, turnId) : void 0;
|
|
7447
|
-
let
|
|
7447
|
+
let savedMessageIsEvent = false;
|
|
7448
7448
|
if (isResume) {
|
|
7449
7449
|
const userMessage = getTurnUserMessage(conversation, turnId);
|
|
7450
7450
|
if (!userMessage) throw new Error(`Unable to locate the persisted user message for Turn "${turnId}"`);
|
|
7451
|
-
|
|
7451
|
+
savedMessageIsEvent = isEventConversationMessage(userMessage);
|
|
7452
7452
|
turnInputFacts = turnInputFactsFromConversationMessage(userMessage, {
|
|
7453
7453
|
conversationId: context.conversationId,
|
|
7454
7454
|
location: storedConversation?.location,
|
|
@@ -7470,7 +7470,7 @@ function createConversationTurnWorker(agentRunner, deliverMessage) {
|
|
|
7470
7470
|
});
|
|
7471
7471
|
const webActor = actor.platform === "web" ? actor : void 0;
|
|
7472
7472
|
const conversationLocation = storedConversation?.location;
|
|
7473
|
-
const deliverToProvider = Boolean(conversationLocation) && (source.kind === "
|
|
7473
|
+
const deliverToProvider = Boolean(conversationLocation) && (source.kind === "event" || savedMessageIsEvent);
|
|
7474
7474
|
const surface = deliverToProvider ? "slack" : "api";
|
|
7475
7475
|
return await withLogContext({
|
|
7476
7476
|
conversationId: context.conversationId,
|
|
@@ -7522,9 +7522,9 @@ function createConversationTurnWorker(agentRunner, deliverMessage) {
|
|
|
7522
7522
|
explicitMention: true,
|
|
7523
7523
|
replied: false,
|
|
7524
7524
|
...source.kind === "web" ? { source: "web" } : void 0,
|
|
7525
|
-
...
|
|
7526
|
-
eventType:
|
|
7527
|
-
...
|
|
7525
|
+
...event ? {
|
|
7526
|
+
eventType: event.eventType,
|
|
7527
|
+
...event.trustedSummary ? { trustedSummary: event.trustedSummary } : void 0
|
|
7528
7528
|
} : void 0
|
|
7529
7529
|
}
|
|
7530
7530
|
});
|
|
@@ -7796,7 +7796,7 @@ function createConversationTurnWorker(agentRunner, deliverMessage) {
|
|
|
7796
7796
|
* Deliver system Turn output to Slack without a webhook Message.
|
|
7797
7797
|
*
|
|
7798
7798
|
* TODO(dcramer): Replace this Location-taking function with Delivery bound to one
|
|
7799
|
-
* Location after
|
|
7799
|
+
* Location after Event work supplies Delivery before the Run.
|
|
7800
7800
|
*/
|
|
7801
7801
|
function createSlackSystemTurnDelivery(args) {
|
|
7802
7802
|
return async ({ conversationId, location, text }) => {
|
|
@@ -7977,60 +7977,60 @@ async function publicArtifactGET(args) {
|
|
|
7977
7977
|
}
|
|
7978
7978
|
}
|
|
7979
7979
|
//#endregion
|
|
7980
|
-
//#region src/chat/event-
|
|
7980
|
+
//#region src/chat/event-automations/ingest.ts
|
|
7981
7981
|
/**
|
|
7982
|
-
* Owns
|
|
7982
|
+
* Owns event matching and durable event-automation dispatch.
|
|
7983
7983
|
*
|
|
7984
|
-
* Each matching
|
|
7984
|
+
* Each matching automation is independently idempotent. Aggregate failures propagate
|
|
7985
7985
|
* so the provider can retry the original delivery.
|
|
7986
7986
|
*/
|
|
7987
|
-
/** Bind provider delivery identity to one
|
|
7988
|
-
function
|
|
7989
|
-
return `event-
|
|
7987
|
+
/** Bind provider delivery identity to one automation's durable dispatch. */
|
|
7988
|
+
function eventAutomationDispatchKey(taskId, namespace, eventKey) {
|
|
7989
|
+
return `event-automation:${createHash("sha256").update(`${taskId}\0${namespace}\0${eventKey}`).digest("hex").slice(0, 32)}`;
|
|
7990
7990
|
}
|
|
7991
7991
|
function oneLine(value) {
|
|
7992
7992
|
return value.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim().slice(0, 512);
|
|
7993
7993
|
}
|
|
7994
|
-
/** Compact destination-visible context for event-
|
|
7994
|
+
/** Compact destination-visible context for event-automation replies. */
|
|
7995
7995
|
function replyAttribution(task) {
|
|
7996
7996
|
const detail = oneLine(task.trigger.label).slice(0, 128).trim();
|
|
7997
7997
|
return detail ? {
|
|
7998
|
-
label: "Event
|
|
7998
|
+
label: "Event automation",
|
|
7999
7999
|
detail
|
|
8000
|
-
} : { label: "Event
|
|
8000
|
+
} : { label: "Event automation" };
|
|
8001
8001
|
}
|
|
8002
|
-
/** Render plain agent input for one matching event
|
|
8002
|
+
/** Render plain agent input for one matching event automation. */
|
|
8003
8003
|
function eventInput(task, event) {
|
|
8004
|
-
const guidance =
|
|
8004
|
+
const guidance = eventGuidance(getEventCatalog(), event.namespace, task.trigger.resourceType, event.eventType);
|
|
8005
8005
|
return renderTaskInput({
|
|
8006
8006
|
about: task.trigger.label,
|
|
8007
8007
|
instructions: task.task.text,
|
|
8008
8008
|
outcomes: effectiveTaskOutcomes(task.outcomes, task.destination),
|
|
8009
8009
|
guidance,
|
|
8010
8010
|
trustedSummary: event.trustedSummary,
|
|
8011
|
-
trustedSummaryMaxLength:
|
|
8011
|
+
trustedSummaryMaxLength: EVENT_SUMMARY_MAX_LENGTH,
|
|
8012
8012
|
verifiedDetails: event.data,
|
|
8013
8013
|
externalText: event.untrustedText,
|
|
8014
|
-
externalTextMaxLength:
|
|
8014
|
+
externalTextMaxLength: EVENT_TEXT_MAX_LENGTH
|
|
8015
8015
|
});
|
|
8016
8016
|
}
|
|
8017
|
-
/** Match a normalized
|
|
8018
|
-
async function
|
|
8019
|
-
const event =
|
|
8017
|
+
/** Match a normalized event and dispatch every matching automation. */
|
|
8018
|
+
async function ingestEventAutomations(input, options) {
|
|
8019
|
+
const event = eventSchema.parse(input);
|
|
8020
8020
|
const db = getDb();
|
|
8021
8021
|
const nowMs = options.nowMs ?? Date.now();
|
|
8022
|
-
const tasks = await
|
|
8022
|
+
const tasks = await findMatchingEventAutomations(db, event, options.teamId);
|
|
8023
8023
|
let dispatched = 0;
|
|
8024
8024
|
const errors = [];
|
|
8025
8025
|
for (const task of tasks) try {
|
|
8026
|
-
const idempotencyKey =
|
|
8026
|
+
const idempotencyKey = eventAutomationDispatchKey(task.id, event.namespace, event.eventKey);
|
|
8027
8027
|
const credentialSubject = task.credentialMode === "creator" ? {
|
|
8028
8028
|
type: "user",
|
|
8029
8029
|
userId: task.createdBy.slackUserId,
|
|
8030
|
-
allowedWhen: "event-
|
|
8030
|
+
allowedWhen: "event-automation",
|
|
8031
8031
|
taskId: task.id
|
|
8032
8032
|
} : void 0;
|
|
8033
|
-
if ((await
|
|
8033
|
+
if ((await dispatchEventAutomation({
|
|
8034
8034
|
conversationWorkQueue: options.queue,
|
|
8035
8035
|
nowMs,
|
|
8036
8036
|
options: {
|
|
@@ -8039,7 +8039,7 @@ async function ingestEventTasks(input, options) {
|
|
|
8039
8039
|
destination: task.destination,
|
|
8040
8040
|
destinationVisibility: task.destinationVisibility,
|
|
8041
8041
|
input: eventInput(task, event),
|
|
8042
|
-
metadata: {
|
|
8042
|
+
metadata: { eventAutomationId: task.id },
|
|
8043
8043
|
replyAttribution: replyAttribution(task),
|
|
8044
8044
|
outcomes: effectiveTaskOutcomes(task.outcomes, task.destination)
|
|
8045
8045
|
}
|
|
@@ -8047,19 +8047,19 @@ async function ingestEventTasks(input, options) {
|
|
|
8047
8047
|
} catch (error) {
|
|
8048
8048
|
errors.push(error);
|
|
8049
8049
|
}
|
|
8050
|
-
if (errors.length > 0) throw new AggregateError(errors, "Failed to dispatch one or more event
|
|
8050
|
+
if (errors.length > 0) throw new AggregateError(errors, "Failed to dispatch one or more event automations");
|
|
8051
8051
|
return { dispatched };
|
|
8052
8052
|
}
|
|
8053
8053
|
//#endregion
|
|
8054
|
-
//#region src/chat/
|
|
8054
|
+
//#region src/chat/events/workspace.ts
|
|
8055
8055
|
/**
|
|
8056
|
-
* Resolve the single-bot Slack team id for event-
|
|
8056
|
+
* Resolve the single-bot Slack team id for event-automation indexing.
|
|
8057
8057
|
*
|
|
8058
|
-
*
|
|
8059
|
-
* until that store is conversation-owned.
|
|
8058
|
+
* Watches do not use this. Event automations still key by destination team
|
|
8059
|
+
* until that store is conversation-owned. Event delivery itself is
|
|
8060
8060
|
* not gated on Slack.
|
|
8061
8061
|
*/
|
|
8062
|
-
function
|
|
8062
|
+
function createEventTeamIdResolver() {
|
|
8063
8063
|
let pending;
|
|
8064
8064
|
return async () => {
|
|
8065
8065
|
if (!getSlackBotToken()) return void 0;
|
|
@@ -8075,49 +8075,49 @@ function createResourceEventTeamIdResolver() {
|
|
|
8075
8075
|
};
|
|
8076
8076
|
}
|
|
8077
8077
|
//#endregion
|
|
8078
|
-
//#region src/chat/
|
|
8079
|
-
/** Build the core
|
|
8080
|
-
function
|
|
8081
|
-
const
|
|
8078
|
+
//#region src/chat/events/app-publisher.ts
|
|
8079
|
+
/** Build the core event publisher used by plugin routes. */
|
|
8080
|
+
function createEventAppPublisher(args) {
|
|
8081
|
+
const resolveEventAutomationTeamId = createEventTeamIdResolver();
|
|
8082
8082
|
return {
|
|
8083
8083
|
async hasMatch(event) {
|
|
8084
8084
|
const work = args.conversationWork();
|
|
8085
|
-
const
|
|
8086
|
-
const [subscriptions, tasks] = await Promise.all([
|
|
8085
|
+
const eventAutomationTeamId = await resolveEventAutomationTeamId();
|
|
8086
|
+
const [subscriptions, tasks] = await Promise.all([findMatchingWatches({
|
|
8087
8087
|
data: event.data,
|
|
8088
8088
|
eventType: event.eventType,
|
|
8089
8089
|
namespace: event.namespace,
|
|
8090
8090
|
identifier: event.identifier,
|
|
8091
8091
|
state: work.state
|
|
8092
|
-
}),
|
|
8092
|
+
}), eventAutomationTeamId ? findMatchingEventAutomations(getDb(), event, eventAutomationTeamId) : Promise.resolve([])]);
|
|
8093
8093
|
return subscriptions.length > 0 || tasks.length > 0;
|
|
8094
8094
|
},
|
|
8095
8095
|
async neededMatchKeys(input) {
|
|
8096
8096
|
const work = args.conversationWork();
|
|
8097
|
-
const
|
|
8098
|
-
const [watchKeys, taskKeys] = await Promise.all([
|
|
8097
|
+
const eventAutomationTeamId = await resolveEventAutomationTeamId();
|
|
8098
|
+
const [watchKeys, taskKeys] = await Promise.all([collectEventMatchKeys({
|
|
8099
8099
|
eventTypes: input.eventTypes,
|
|
8100
8100
|
identifiers: input.identifiers,
|
|
8101
8101
|
namespace: input.namespace,
|
|
8102
8102
|
state: work.state
|
|
8103
|
-
}),
|
|
8103
|
+
}), eventAutomationTeamId ? collectEventAutomationMatchKeys(getDb(), {
|
|
8104
8104
|
eventTypes: input.eventTypes,
|
|
8105
8105
|
identifiers: input.identifiers,
|
|
8106
8106
|
namespace: input.namespace,
|
|
8107
|
-
teamId:
|
|
8107
|
+
teamId: eventAutomationTeamId
|
|
8108
8108
|
}) : Promise.resolve([])]);
|
|
8109
8109
|
return [.../* @__PURE__ */ new Set([...watchKeys, ...taskKeys])].sort();
|
|
8110
8110
|
},
|
|
8111
8111
|
async publish(event) {
|
|
8112
8112
|
const work = args.conversationWork();
|
|
8113
8113
|
const queue = work.queue ?? getVercelConversationWorkQueue();
|
|
8114
|
-
const
|
|
8115
|
-
await Promise.all([
|
|
8114
|
+
const eventAutomationTeamId = await resolveEventAutomationTeamId();
|
|
8115
|
+
await Promise.all([ingestEvent(event, {
|
|
8116
8116
|
queue,
|
|
8117
8117
|
state: work.state
|
|
8118
|
-
}),
|
|
8118
|
+
}), eventAutomationTeamId ? ingestEventAutomations(event, {
|
|
8119
8119
|
queue,
|
|
8120
|
-
teamId:
|
|
8120
|
+
teamId: eventAutomationTeamId
|
|
8121
8121
|
}) : Promise.resolve()]);
|
|
8122
8122
|
}
|
|
8123
8123
|
};
|
|
@@ -10002,6 +10002,8 @@ function dashboardHostRoutePaths(dashboard, authenticatedRoutes = []) {
|
|
|
10002
10002
|
`${pagePath("locations")}/*`,
|
|
10003
10003
|
peoplePath,
|
|
10004
10004
|
`${peoplePath}/*`,
|
|
10005
|
+
pagePath("automations"),
|
|
10006
|
+
`${pagePath("automations")}/*`,
|
|
10005
10007
|
pagePath("tasks"),
|
|
10006
10008
|
`${pagePath("tasks")}/*`,
|
|
10007
10009
|
pagePath("memories"),
|
|
@@ -10030,8 +10032,8 @@ function dashboardHostRoutePaths(dashboard, authenticatedRoutes = []) {
|
|
|
10030
10032
|
"/api/plugin-reports",
|
|
10031
10033
|
"/api/user-pages",
|
|
10032
10034
|
"/api/user-pages/*",
|
|
10033
|
-
"/api/
|
|
10034
|
-
"/api/
|
|
10035
|
+
"/api/automations",
|
|
10036
|
+
"/api/automations/*",
|
|
10035
10037
|
"/api/skills",
|
|
10036
10038
|
"/api/code",
|
|
10037
10039
|
"/api/stats",
|
|
@@ -10152,7 +10154,7 @@ async function createApp(options) {
|
|
|
10152
10154
|
};
|
|
10153
10155
|
let pluginRoutes = [];
|
|
10154
10156
|
let pluginApiRoutes = [];
|
|
10155
|
-
const
|
|
10157
|
+
const events = createEventAppPublisher({ conversationWork: () => getConversationWorkOptions() });
|
|
10156
10158
|
let sandboxEgressTracePropagationDomains = [];
|
|
10157
10159
|
try {
|
|
10158
10160
|
sandboxEgressTracePropagationDomains = normalizeSandboxEgressTracePropagationDomains(options?.sandbox?.egressTracePropagationDomains);
|
|
@@ -10168,7 +10170,7 @@ async function createApp(options) {
|
|
|
10168
10170
|
validatePluginRegistrations(configuredPlugins?.registrations ?? []);
|
|
10169
10171
|
validatePluginEgressCredentialHooks(configuredPlugins?.registrations ?? []);
|
|
10170
10172
|
}
|
|
10171
|
-
pluginRoutes = getPluginRoutes({
|
|
10173
|
+
pluginRoutes = getPluginRoutes({ events });
|
|
10172
10174
|
if (dashboard && !dashboard.disabled) pluginApiRoutes = getPluginApiRoutes();
|
|
10173
10175
|
} catch (error) {
|
|
10174
10176
|
restoreRuntimeConfig();
|