@sentry/junior 0.205.0 → 0.207.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 (73) hide show
  1. package/dist/{agent-D4nu8MQV.js → agent-CmQlX68D.js} +603 -394
  2. package/dist/{agent-hooks-DXHpTJ4m.js → agent-hooks-BBX9p6aG.js} +1171 -100
  3. package/dist/{agent-runner-C04colea.js → agent-runner-CQD4HKK2.js} +9 -9
  4. package/dist/api/schema.d.ts +116 -39
  5. package/dist/api/schema.js +3 -3
  6. package/dist/api.d.ts +1 -1
  7. package/dist/api.js +182 -649
  8. package/dist/{app-Cb776lL8.d.ts → app-DfNrn_gS.d.ts} +9 -2
  9. package/dist/app.d.ts +1 -1
  10. package/dist/app.js +205 -233
  11. package/dist/{auth-pause-state-C2P3guS1.js → auth-pause-state-uv8on6cT.js} +7 -7
  12. package/dist/briefs-BXEmjD9D.js +398 -0
  13. package/dist/{catalog-runtime-CXw3asJD.js → catalog-runtime-1BZEOR8J.js} +1 -1
  14. package/dist/{checkpoint-CrViJ8Ps.js → checkpoint-B-JO5F3c.js} +9 -8
  15. package/dist/cli/chat.js +14 -12
  16. package/dist/cli/check.js +3 -3
  17. package/dist/cli/init.js +1 -0
  18. package/dist/cli/main.js +5 -1
  19. package/dist/cli/plugins.js +3 -3
  20. package/dist/cli/run.d.ts +2 -1
  21. package/dist/cli/run.js +2 -1
  22. package/dist/cli/snapshot-create.js +3 -3
  23. package/dist/cli/upgrade.d.ts +1 -1
  24. package/dist/cli/upgrade.js +3 -3
  25. package/dist/{config-BOtJQ7Pc.js → client-Bp297GA0.js} +6 -369
  26. package/dist/config-G2gv97R1.js +386 -0
  27. package/dist/{context-B45_WqVX.js → context-Bplcgypl.js} +13 -13
  28. package/dist/{schema-Rn8-XEaN.js → conversation-AA4R1VUn.js} +580 -558
  29. package/dist/{conversation-privacy-BZRA6Pes.js → conversation-privacy-BUfel19D.js} +1 -1
  30. package/dist/{credential-sync-Bep34IB_.js → credential-sync-D04NWqMR.js} +21 -20
  31. package/dist/{db-BeyXKJOI.d.ts → db-D74z7BZH.d.ts} +1 -1
  32. package/dist/{execution-stats-B6lgWxCK.js → execution-stats-Ds4bSvam.js} +77 -77
  33. package/dist/{executor-BlUhFL7_.js → executor-BZu1Ta06.js} +41 -13
  34. package/dist/instrumentation.js +2 -2
  35. package/dist/{job-queue-DLMqIK74.js → job-queue-rnAPfUhP.js} +1 -1
  36. package/dist/{logging-BMJzdDlP.js → logging-Dx0S5k2z.js} +1 -1
  37. package/dist/nitro.d.ts +1 -1
  38. package/dist/nitro.js +3 -3
  39. package/dist/{oauth-callback-server-WwG5_Zgm.js → oauth-callback-server-xGpwURIj.js} +2 -2
  40. package/dist/{pending-auth-CUbXq06G.js → pending-auth-DIZ4iZjS.js} +2 -2
  41. package/dist/{profile-T0tXE4zu.js → profile-d-fKypxo.js} +4 -3
  42. package/dist/prompt-x-0ZtTyb.js +552 -0
  43. package/dist/{registry-BA0__8ai.js → registry-CWKdLCTG.js} +2 -2
  44. package/dist/{resolve-bvD1ORdv.js → resolve-BhRB1s2A.js} +2 -2
  45. package/dist/{runner-BXYxfIUL.js → runner-DNml3owD.js} +10 -10
  46. package/dist/{sandbox-egress-signals-ngEPjSEW.js → sandbox-egress-signals-DUIl3-gW.js} +1 -1
  47. package/dist/schema-CwTeb-BF.js +559 -0
  48. package/dist/{skills-DJOlYdBs.js → skills-D9WesdJJ.js} +2 -2
  49. package/dist/{spawn-h0R1bTEo.js → spawn-Eh_3-s0M.js} +2 -2
  50. package/dist/{stats-3YZn-Swi.js → stats-CFlUGqVA.js} +292 -268
  51. package/dist/{store-C5qxF2ac.d.ts → store-Det8MQ9g.d.ts} +1 -1
  52. package/dist/{task-queue-CoXwd2eq.js → task-queue-D8I1_5wP.js} +3 -3
  53. package/dist/{task-runner-B2_mJZj0.js → task-runner-DO79gdho.js} +18 -18
  54. package/dist/{thread-state-CqZ1m-es.js → thread-state-DD6BA4xz.js} +5 -5
  55. package/dist/{turn-execution-fI6PZ0iI.js → turn-execution-BSIHxmQJ.js} +3 -3
  56. package/dist/{turn-lifecycle-CcnwrOcp.js → turn-lifecycle-DSBK4Ars.js} +1 -1
  57. package/dist/{usage-B5SfMb3H.js → usage-WRXkNOHp.js} +4 -125
  58. package/dist/{validation-DfWcvhuS.js → validation-BbHZ4r4S.js} +1 -1
  59. package/dist/{version-oD-oPrbO.js → version-C71UcRWw.js} +1 -1
  60. package/dist/version.js +1 -1
  61. package/dist/web-authorization-C73gJV7l.js +38 -0
  62. package/dist/{web-input-BOuq3oKK.js → web-input-Ce1FcNIM.js} +8 -8
  63. package/dist/{work-B91LQKHr.js → work-BEzDU_2x.js} +9 -9
  64. package/dist/{worker-BcRRTe6k.js → worker-MK2ubOv-.js} +5 -4
  65. package/migrations/0040_conversation_briefs.sql +17 -0
  66. package/migrations/0041_automation_outcomes_backfill.sql +27 -0
  67. package/migrations/meta/0040_snapshot.json +3516 -0
  68. package/migrations/meta/0041_snapshot.json +3516 -0
  69. package/migrations/meta/_journal.json +14 -0
  70. package/package.json +4 -4
  71. package/dist/history-CqTuSAdI.js +0 -441
  72. package/dist/usage-schema-CKaDkH_j.js +0 -20
  73. package/dist/web-authorization-Crbzlmzo.js +0 -76
@@ -1,25 +1,28 @@
1
- import { A as createProviderError, C as MODEL_HANDOFF_SUMMARY_PREFIX, D as unwrapCurrentInstruction, E as renderCurrentInstruction, F as MISSING_GATEWAY_CREDENTIALS_ERROR, I as getGatewayApiKey, L as resolveGatewayCredential, M as getProviderErrorAttributes, O as escapeXml, P as isProviderRetryError, S as COMPACTION_SUMMARY_PREFIX, T as isCompactionSummaryText, _ as completeObject, b as resolveGatewayModel, g as GEN_AI_SERVER_ADDRESS, h as GEN_AI_PROVIDER_NAME, j as findProviderError, k as ProviderError, m as normalizeSlackEmojiName, n as botConfig, v as completeText, w as hasCompactedConversationContext, x as ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX } from "./config-BOtJQ7Pc.js";
2
- import { C as withSpan, F as isRecord$2, P as normalizeIdentityEmail, S as withLogContext, _ as setSpanAttributes, a as extractGenAiUsageSummary, b as summarizeMessageText, c as getTracePropagationHeaders, d as logInfo, f as logWarn, h as serializeGenAiAttribute, i as extractGenAiUsageAttributes, l as logError, p as normalizeGenAiFinishReason, s as getLogContextAttributesForSpan, u as logException, v as setSpanStatus, y as setTags } from "./logging-BMJzdDlP.js";
1
+ import { C as resolveGatewayCredential, S as getGatewayApiKey, _ as findProviderError, b as isProviderRetryError, c as COMPACTION_SUMMARY_PREFIX, d as isCompactionSummaryText, f as renderCurrentInstruction, g as createProviderError, h as ProviderError, i as completeText, l as MODEL_HANDOFF_SUMMARY_PREFIX, m as escapeXml, n as GEN_AI_SERVER_ADDRESS, o as resolveGatewayModel, p as unwrapCurrentInstruction, r as completeObject, s as ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX, t as GEN_AI_PROVIDER_NAME, u as hasCompactedConversationContext, v as getProviderErrorAttributes, x as MISSING_GATEWAY_CREDENTIALS_ERROR } from "./client-Bp297GA0.js";
2
+ import { C as withSpan, F as isRecord$2, P as normalizeIdentityEmail, S as withLogContext, _ as setSpanAttributes, a as extractGenAiUsageSummary, b as summarizeMessageText, c as getTracePropagationHeaders, d as logInfo, f as logWarn, h as serializeGenAiAttribute, i as extractGenAiUsageAttributes, l as logError, p as normalizeGenAiFinishReason, s as getLogContextAttributesForSpan, u as logException, v as setSpanStatus, y as setTags } from "./logging-Dx0S5k2z.js";
3
3
  import { _ as withActiveSpan, m as startInactiveSpan } from "./sentry-CD3SdJl-.js";
4
- 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-BZRA6Pes.js";
4
+ 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-BUfel19D.js";
5
+ import { h as normalizeSlackEmojiName, n as botConfig } from "./config-G2gv97R1.js";
5
6
  import { a as modelIdForProfile, c as TURN_REASONING_LEVELS, i as formatModelProfiles, o as modelProfileSchema, r as formatModelProfile, s as profileConfig, t as ModelProfileNotConfiguredError } from "./model-profile-CZmVoGdX.js";
6
- import { _ as parseSlackMessageTs, 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-B45_WqVX.js";
7
- import { $ as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, B as getSlackClient, Bt as parseDestination, C as setWorkspaceSnapshotBuild, Ct as getConversationEventStore, D as tryWorkspaceRepoCheckoutPath, Dt as getSqlExecutor, E as getWorkspaceSnapshotBuilder, Et as getDb, G as withSlackRetries, I as SlackActionError, L as downloadPrivateSlackFile, O as workspaceRepoCheckoutPath, Q as getSlackToolContext, R as getFilePermalink, S as setWorkspaceSnapshot, T as deleteWorkspaceSnapshotBuilders, Tt as getConversationStore, U as normalizeSlackConversationId, V as isConversationScopedChannel, Y as readActorIdentity, _ as listWorkspaces, _t as createPluginLogger, b as invalidateReadySnapshot, c as getPluginTools, ct as findMatchingResourceEventSubscriptions, ft as getDashboardTaskLink, g as getWorkspaceByName, h as getWorkspace, it as cancelSubscriptions, k as resolveChannelCapabilities, l as getPluginUserPromptContributions, lt as listResourceEventSubscriptions, m as deleteWorkspace, nt as STOP_WATCHING_TOOL_NAME, ot as createResourceEventSubscription, p as createWorkspace, r as createPluginHookRunner, rt as cancelResourceEventSubscription, s as getPluginSystemPromptContributions, st as deliverResourceEventSubscription, tt as RESOURCE_WATCH_TOOL_SOURCE, u as getPlugins, ut as JUNIOR_THREAD_STATE_TTL_MS, v as updateWorkspace, w as SANDBOX_RUNTIME, wt as getConversationMessageSearchStore, x as loadSnapshotsForProfile, y as WorkspaceValidationError } from "./agent-hooks-DXHpTJ4m.js";
8
- import { E as juniorArtifacts, a as juniorSchedulerRuns, d as AGENT_INVOCATION_MAILBOX_STATUSES, w as juniorIdentities, x as juniorAttachments } from "./executor-BlUhFL7_.js";
9
- import { d as instructionProvenanceFor, f as sameActorIdentity, l as contextProvenance, t as KNOWN_CONVERSATION_EVENT_TYPES, u as instructionActors } from "./history-CqTuSAdI.js";
7
+ import { _ as parseSlackMessageTs, 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-Bplcgypl.js";
8
+ import { A as tryWorkspaceRepoCheckoutPath, B as downloadPrivateSlackFile, C as invalidateReadySnapshot, D as SANDBOX_RUNTIME, E as setWorkspaceSnapshotBuild, Ft as getConversationStore, It as getDb, J as withSlackRetries, K as normalizeSlackConversationId, Lt as getSqlExecutor, M as resolveChannelCapabilities, Nt as getConversationEventStore, O as deleteWorkspaceSnapshotBuilders, Pt as getConversationMessageSearchStore, Q as readActorIdentity, S as WorkspaceValidationError, T as setWorkspaceSnapshot, U as getSlackClient, V as getFilePermalink, W as isConversationScopedChannel, Xt as parseDestination, _ as deleteWorkspace, at as STOP_WATCHING_TOOL_NAME, b as listWorkspaces, bt as createPluginLogger, c as getPluginTools, dt as findMatchingWatches, ft as listWatches, g as createWorkspace, ht as getDashboardTaskLink, it as RESOURCE_WATCH_TOOL_SOURCE, j as workspaceRepoCheckoutPath, k as getWorkspaceSnapshotBuilder, l as getPluginUserPromptContributions, lt as createWatch, mt as getDashboardConversationLink, nt as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, ot as cancelSubscriptions, pt as JUNIOR_THREAD_STATE_TTL_MS, r as createPluginHookRunner, s as getPluginSystemPromptContributions, st as cancelWatch, tt as getSlackToolContext, u as getPlugins, ut as deliverWatch, v as getWorkspace, w as loadSnapshotsForProfile, x as updateWorkspace, y as getWorkspaceByName, z as SlackActionError } from "./agent-hooks-BBX9p6aG.js";
9
+ import { n as juniorDestinations } from "./destinations-BeBiJeEM.js";
10
+ import { D as juniorArtifacts, S as juniorAttachments, T as juniorIdentities, a as juniorSchedulerRuns, d as AGENT_INVOCATION_MAILBOX_STATUSES, g as juniorConversationBriefs, w as juniorConversations, y as juniorConversationAnnotations } from "./executor-BZu1Ta06.js";
11
+ import { A as briefLinkSchema, F as KNOWN_CONVERSATION_EVENT_TYPES, G as instructionProvenanceFor, K as sameActorIdentity, M as conversationBriefSchema, U as contextProvenance, W as instructionActors, j as briefOutcomeStatusSchema } from "./conversation-AA4R1VUn.js";
10
12
  import { a as listReferenceFiles, c as soulPathCandidates, l as worldPathCandidates } from "./package-discovery-7a9YqLhE.js";
11
- import { a as resolvePluginCommandEnv, c as getOAuthProviderErrorAttributes, i as resolveAuthTokenPlaceholder, o as OAuthProviderError, s as fetchWithBoundedOAuthErrorBodies, u as CredentialUnavailableError } from "./registry-BA0__8ai.js";
12
- import { n as pluginCatalogRuntime } from "./catalog-runtime-CXw3asJD.js";
13
- import { a as parseSkillInvocation, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-DJOlYdBs.js";
14
- import { A as normalizeToLf$1, At as retainRuntimeTurnContext, B as openConversationProjection, C as DEFAULT_SEARCH_COMMAND_TIMEOUT_MS, Ct as hasRuntimeTurnContext, D as getRipgrepSearchLocation, Dt as isToolResultError, E as collectFiles, Et as isContinuablePiBoundary, G as recordAuthorizationRequested, H as recordAttachmentsDelivered, I as loadConnectedMcpProviders, K as recordGuardianActionReviewed, L as loadConversationProjection, M as resolveWorkspacePath, Mt as trimTrailingAssistantMessages, N as truncateText$1, Nt as TURN_CONTEXT_TAG, O as isMissingPathError, Ot as isToolResultMessage, S as resolveRepositoryInstructionsForDirectories, St as getUserMessageInstructionText, T as RIPGREP_EXCLUDED_GLOBS, Tt as isAssistantMessage, V as recordAgentsInstructionsUpdated, X as recordTurnRoute, Y as recordToolExecutionStarted, _ as AGENTS_REPLACEMENT_NOTICE, _t as historyItemFromPiMessage, b as listRepositoryDirectories, bt as getPiMessageRole, f as TurnSliceLimitExceededError, g as AGENTS_REMOVAL_NOTICE, gt as getAgentContextInputLimitTokens, h as isTurnExecutionLimitExceededError, ht as getAgentContextCompactionTriggerTokens, j as positiveInteger$1, jt as stripRuntimeTurnContext, k as missingPathSearchResult, kt as normalizeToolNameFromResult, mt as estimateTextTokens, n as loadTurnCheckpoint, p as assertTurnToolCallLimit, q as recordMcpProviderConnected, r as saveTurnCheckpoint, t as continuableMessages, v as buildAgentsInstructionsMessage, vt as piMessageFromHistoryItem, w as MAX_TEXT_CHARS, x as renderAgentsInstructions, xt as getTerminalAssistantMessages, y as findVisibleAgentsInstructions, yt as extractAssistantText, z as loadTurnRoute } from "./checkpoint-CrViJ8Ps.js";
15
- import { a as hasAgentTurnUsage, c as generateShortTitle, l as resolveTaskTitle, o as ToolInputError, t as addAgentTurnUsage } from "./usage-B5SfMb3H.js";
16
- import { A as sleep$1, D as fenceLock, E as acquireActiveLock, F as sandboxSkillDir, I as sandboxSkillFile, L as sandboxSkillPathResolution, M as SANDBOX_REPOS_ROOT, N as SANDBOX_SKILLS_ROOT, P as SANDBOX_WORKSPACE_ROOT, _ 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_DATA_ROOT, k as withLock, 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-T0tXE4zu.js";
17
- import { $ as workspaceSnapshotFinishedEvent, B as createEventTask, C as SCHEDULED_TASK_SYSTEM_ACTOR, D as eventTaskMatchesDestination, E as eventTaskListToolResultSchema, F as effectiveTaskOutcomes, Ht as injectContinuationToolName, I as moveTaskOutcomes, L as resolveTaskOutcomes, M as requireEventTaskSlackContext, N as requireSupportedEventTaskTrigger, O as eventTaskSuccess, P as writableEventTask, Q as WORKSPACE_SNAPSHOT_READY_EVENT, R as taskOutcomeInputSchema, T as compactEventTask, Ut as juniorToolOutputSchema, V as deleteEventTask, W as getEventTask, Wt as makeStructuredToolOutput, X as getResourceEventCatalog, Y as saveEventTask, Z as WORKSPACE_SNAPSHOT_FAILED_EVENT, at as pluginSupportsEvent, c as parseSlackThreadId, ct as registeredResourceTypeSchema, et as workspaceSnapshotWatch, f as createScheduledTask, g as listScheduledTasksForTeam, i as readLiveAttachment, it as normalizeEventIdentifier, j as registeredEventTaskTriggerSchema, k as eventTaskToolResultSchema, lt as requireSupportedResourceEventMatch, nt as hasPluginResourceEventCatalogEntries, ot as registeredEventTypeSchema, pt as appendAndEnqueueInboundMessage, q as listEventTasksForTeam, rt as hasResourceEventCatalogEntries, s as storeAttachments, st as registeredResourceEventMatchSchema, t as incrementStat, tt as eventNamespaceSchema, ut as resourceEventGuidance, v as readScheduledTask, y as saveScheduledTask } from "./stats-3YZn-Swi.js";
18
- import { _ as isTurnInputCommitLostError, c as sanitizeAssistantText, f as CooperativeTurnYieldError, l as NO_REPLY_MARKER, n as canReusePendingAuthLink, o as decideReply, p as TurnInputCommitLostError, s as getAssistantReplyText, t as abandonReplacedPendingAuth, u as isNoReplyMarker } from "./pending-auth-CUbXq06G.js";
19
- import { C as toolInvocationDestination, S as surfaceFromRun, _ as uploadFilesToConversation, b as assertRunConsistency, h as postSlackMessage, i as formatProviderLabel, m as getSlackMessagePermalink, o as resolveBaseUrl, p as addReactionToMessage, r as deliverOAuthAuthorization, s as startOAuthFlow, v as RetryableDeliveryError, x as isAgentRunFeatureDisabled, y as actorFromRun } from "./agent-runner-C04colea.js";
20
- 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-bvD1ORdv.js";
13
+ import { a as resolvePluginCommandEnv, c as getOAuthProviderErrorAttributes, i as resolveAuthTokenPlaceholder, o as OAuthProviderError, s as fetchWithBoundedOAuthErrorBodies, u as CredentialUnavailableError } from "./registry-CWKdLCTG.js";
14
+ import { n as pluginCatalogRuntime } from "./catalog-runtime-1BZEOR8J.js";
15
+ import { a as parseSkillInvocation, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-D9WesdJJ.js";
16
+ import { A as normalizeToLf$1, At as retainRuntimeTurnContext, B as openConversationProjection, C as DEFAULT_SEARCH_COMMAND_TIMEOUT_MS, Ct as hasRuntimeTurnContext, D as getRipgrepSearchLocation, Dt as isToolResultError, E as collectFiles, Et as isContinuablePiBoundary, G as recordAuthorizationRequested, H as recordAttachmentsDelivered, I as loadConnectedMcpProviders, K as recordGuardianActionReviewed, L as loadConversationProjection, M as resolveWorkspacePath, Mt as trimTrailingAssistantMessages, N as truncateText$1, Nt as TURN_CONTEXT_TAG, O as isMissingPathError, Ot as isToolResultMessage, S as resolveRepositoryInstructionsForDirectories, St as getUserMessageInstructionText, T as RIPGREP_EXCLUDED_GLOBS, Tt as isAssistantMessage, V as recordAgentsInstructionsUpdated, X as recordTurnRoute, Y as recordToolExecutionStarted, _ as AGENTS_REPLACEMENT_NOTICE, _t as historyItemFromPiMessage, b as listRepositoryDirectories, bt as getPiMessageRole, f as TurnSliceLimitExceededError, g as AGENTS_REMOVAL_NOTICE, gt as getAgentContextInputLimitTokens, h as isTurnExecutionLimitExceededError, ht as getAgentContextCompactionTriggerTokens, j as positiveInteger$1, jt as stripRuntimeTurnContext, k as missingPathSearchResult, kt as normalizeToolNameFromResult, mt as estimateTextTokens, n as loadTurnCheckpoint, p as assertTurnToolCallLimit, q as recordMcpProviderConnected, r as saveTurnCheckpoint, t as continuableMessages, v as buildAgentsInstructionsMessage, vt as piMessageFromHistoryItem, w as MAX_TEXT_CHARS, x as renderAgentsInstructions, xt as getTerminalAssistantMessages, y as findVisibleAgentsInstructions, yt as extractAssistantText, z as loadTurnRoute } from "./checkpoint-B-JO5F3c.js";
17
+ import { a as hasAgentTurnUsage, c as generateShortTitle, l as resolveTaskTitle, o as ToolInputError, t as addAgentTurnUsage } from "./usage-WRXkNOHp.js";
18
+ import { A as sleep$1, D as fenceLock, E as acquireActiveLock, F as sandboxSkillDir, I as sandboxSkillFile, L as sandboxSkillPathResolution, M as SANDBOX_REPOS_ROOT, N as SANDBOX_SKILLS_ROOT, P as SANDBOX_WORKSPACE_ROOT, _ 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_DATA_ROOT, k as withLock, 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-d-fKypxo.js";
19
+ import { $ as workspaceSnapshotFinishedEvent, B as createEventAutomation, C as SCHEDULED_AUTOMATION_SYSTEM_ACTOR, D as eventAutomationMatchesDestination, E as eventAutomationListToolResultSchema, F as effectiveTaskOutcomes, Ht as injectContinuationToolName, I as moveTaskOutcomes, L as resolveTaskOutcomes, M as requireEventAutomationSlackContext, N as requireSupportedEventAutomationTrigger, O as eventAutomationToolResult, P as writableEventAutomation, Q as WORKSPACE_SNAPSHOT_READY_EVENT, R as taskOutcomeInputSchema, T as compactEventAutomation, Ut as juniorToolOutputSchema, V as deleteEventAutomation, W as getEventAutomation, Wt as makeStructuredToolOutput, X as getEventCatalog, Y as saveEventAutomation, Z as WORKSPACE_SNAPSHOT_FAILED_EVENT, at as normalizeCatalogEventIdentifier, c as parseSlackThreadId, ct as registeredEventTypeSchema, et as workspaceSnapshotWatch, f as createScheduledAutomation, g as listScheduledAutomationsForTeam, i as readLiveAttachment, it as hasPluginEventCatalogEntries, j as registeredEventAutomationTriggerSchema, k as eventAutomationToolResultSchema, lt as registeredResourceTypeSchema, nt as eventNamespaceSchema, ot as pluginSupportsEvent, pt as appendAndEnqueueInboundMessage, q as listEventAutomationsForTeam, rt as hasEventCatalogEntries, s as storeAttachments, st as registeredEventMatchSchema, t as incrementStat, tt as eventGuidance, ut as requireSupportedEventMatch, v as readScheduledAutomation, y as saveScheduledAutomation } from "./stats-CFlUGqVA.js";
20
+ import { _ as isTurnInputCommitLostError, c as sanitizeAssistantText, f as CooperativeTurnYieldError, l as NO_REPLY_MARKER, n as canReusePendingAuthLink, o as decideReply, p as TurnInputCommitLostError, s as getAssistantReplyText, t as abandonReplacedPendingAuth, u as isNoReplyMarker } from "./pending-auth-DIZ4iZjS.js";
21
+ import { C as toolInvocationDestination, S as surfaceFromRun, _ as uploadFilesToConversation, b as assertRunConsistency, h as postSlackMessage, i as formatProviderLabel, m as getSlackMessagePermalink, o as resolveBaseUrl, p as addReactionToMessage, r as deliverOAuthAuthorization, s as startOAuthFlow, v as RetryableDeliveryError, x as isAgentRunFeatureDisabled, y as actorFromRun } from "./agent-runner-CQD4HKK2.js";
22
+ import { r as EVENT_AUTHOR_ID } from "./prompt-x-0ZtTyb.js";
23
+ 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-BhRB1s2A.js";
21
24
  import { t as getVercelConversationWorkQueue } from "./vercel-queue-DIkVcfK4.js";
22
- import { a as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-DLMqIK74.js";
25
+ import { a as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-rnAPfUhP.js";
23
26
  import { n as privateTraceResultAttributes } from "./private-trace-result-BLvBjy_e.js";
24
27
  import { streamSimple } from "@earendil-works/pi-ai/compat";
25
28
  import { createGatewayProvider } from "@ai-sdk/gateway";
@@ -29,8 +32,8 @@ import { isDeepStrictEqual } from "node:util";
29
32
  import { AsyncLocalStorage } from "node:async_hooks";
30
33
  import { z } from "zod";
31
34
  import { createHash, createHmac, randomUUID, timingSafeEqual } from "node:crypto";
32
- import { and, eq, inArray, isNull, or, sql } from "drizzle-orm";
33
- import { EgressAuthRequired, EgressPolicyDenied, PluginToolInputError, actorSchema, destinationSchema, missingToolAnnotationKeys, pluginAuthorizationSchema, pluginCredentialHeaderTransformSchema, pluginCredentialResultSchema, pluginGrantSchema, pluginProviderAccountSchema, pluginStoredTokensSchema, resourceEventSchema, resourceEventSubscriptionResultSchema, sourceSchema, stableResourceEventMatchKey, taskOutcomeSchema } from "@sentry/junior-plugin-api";
35
+ import { and, desc, eq, gt, gte, inArray, isNull, lt, ne, notExists, or, sql } from "drizzle-orm";
36
+ import { EgressAuthRequired, EgressPolicyDenied, PluginToolInputError, actorSchema, destinationSchema, eventSchema, missingToolAnnotationKeys, pluginAuthorizationSchema, pluginCredentialHeaderTransformSchema, pluginCredentialResultSchema, pluginGrantSchema, pluginProviderAccountSchema, pluginStoredTokensSchema, sourceSchema, stableEventMatchKey, watchResultSchema } from "@sentry/junior-plugin-api";
34
37
  import { alias } from "drizzle-orm/pg-core";
35
38
  import { Agent, estimateContextTokens } from "@earendil-works/pi-agent-core";
36
39
  import fs from "node:fs/promises";
@@ -402,21 +405,22 @@ function buildTurnResult(input) {
402
405
  "app.ai.generated_files": input.generatedFileCount
403
406
  });
404
407
  const usedPrimaryText = Boolean(rawPrimaryText);
408
+ const suppressedPrimaryText = Boolean(rawPrimaryText && !noReplyRequested && !primaryText);
405
409
  let outcome;
406
410
  if (isProviderError) outcome = "provider_error";
411
+ else if (suppressedPrimaryText) outcome = "execution_failure";
407
412
  else if (primaryText || completedWithoutTerminalText) outcome = "success";
408
413
  else outcome = "execution_failure";
409
- const resolvedOutcome = Boolean(rawPrimaryText && !noReplyRequested && !primaryText) ? "execution_failure" : outcome;
410
414
  if (shouldTrace) logInfo("agent.message.generated", {
411
415
  "app.message.kind": "assistant_outbound",
412
416
  "app.message.length": primaryText.length,
413
417
  "app.message.output": summarizeMessageText(primaryText),
414
- "app.ai.outcome": resolvedOutcome,
418
+ "app.ai.outcome": outcome,
415
419
  "app.ai.assistant_messages": assistantMessages.length,
416
420
  ...stopReason ? { "gen_ai.response.finish_reasons": [stopReason] } : void 0
417
421
  });
418
422
  const resolvedDiagnostics = {
419
- outcome: resolvedOutcome,
423
+ outcome,
420
424
  modelId,
421
425
  assistantMessageCount: assistantMessages.length,
422
426
  reasoningLevel: executionProfile.reasoningLevel,
@@ -428,7 +432,7 @@ function buildTurnResult(input) {
428
432
  usage,
429
433
  stopReason,
430
434
  errorMessage,
431
- providerError: resolvedOutcome === "provider_error" && errorMessage ? createProviderError(errorMessage, {
435
+ providerError: outcome === "provider_error" && errorMessage ? createProviderError(errorMessage, {
432
436
  modelId,
433
437
  retryable: lastAssistant !== void 0 && isAssistantMessage(lastAssistant) && isRetryableAssistantError(lastAssistant)
434
438
  }) : void 0
@@ -1143,12 +1147,12 @@ const TOOL_POLICY_RULES = [
1143
1147
  "- After changing files, name the changed paths and summarize the completed result in the final answer.",
1144
1148
  "- If a sandbox-backed tool reports that sandbox execution is unavailable, treat that as a blocker for local file/shell inspection; do not pretend host files were inspected.",
1145
1149
  "- For user-provided URLs, use `webFetch`; for discovery, use `webSearch` then fetch/read promising sources; for current time/date context, use `systemTime`.",
1146
- "- When searchResourceEventTypes is exposed, use it only when the user asks what resource events are supported or the required resource type or event name is unclear. It discovers options but does not watch a resource or create a task. When explaining how results can be used, distinguish temporary current-thread watches from durable event tasks.",
1147
- "- When a tool result includes a subscription, those events are already watched; do not call watchResourceEvents for them. When a tool result includes a subscribable resource with suggestedEvents, use watchResourceEvents only for those remaining events that serve the current intent. If suggestedEvents is empty or omitted, do not invent a watch. Do not create scheduled polling tasks for events a watch can deliver. Write a concise intent summary, and tell the user when the temporary watch expires. Stop only the requested watch by id unless the user explicitly asks to stop every watch in the thread.",
1148
- "- Use createEventTask only when the user explicitly asks for an event task or durable whenever-this-happens-do-X automation. Ordinary watch, notify, and tell-me-when requests use watchResourceEvents. When an event task's resource and events are known, create it without redundant confirmation.",
1149
- "- Event tasks make the task creator's connected credentials available by default when the requested work needs user-bound authorization. Do not ask for separate confirmation merely to use credentials needed for the requested work. On creation, omit credentialMode for the creator default and set system only when the creator explicitly requires it. For later changes, creator always means the task's original createdBy actor, never the current requester. If the requester is not that creator, do not attempt to enable creator credential use or suggest that confirmation could authorize it.",
1150
- "- Event tasks list for the current destination, not one thread. Public tasks can also be updated or deleted by task id from another destination in the same workspace. When listing them, use createdBy to explain creator-only credential changes and warn when triggerAvailable is false; an unavailable task remains stored but cannot receive events until its plugin event is enabled again.",
1151
- "- Scheduled tasks make the task creator's connected credentials available by default when the requested work needs user-bound authorization. Do not ask for separate confirmation merely to use credentials needed for the requested work. On creation, omit credential_mode for the creator default and set system only when the creator explicitly requires it. For later changes, creator always means the task's original created_by actor, never the current requester. If the requester is not that creator, do not attempt to enable creator credential use or suggest that confirmation could authorize it.",
1150
+ "- When searchEventTypes is exposed, use it only when the user asks what events are supported or the required resource type or event name is unclear. It discovers options but does not watch a resource or create an automation. When explaining how results can be used, distinguish temporary current-thread watches from durable event automations.",
1151
+ "- When a tool result includes a subscription, those events are already watched; do not call watchEvents for them. When a tool result includes a subscribable resource with suggestedEvents, use watchEvents only for those remaining events that serve the current intent. If suggestedEvents is empty or omitted, do not invent a watch. Do not create scheduled polling tasks for events a watch can deliver. Write a concise intent summary, and tell the user when the temporary watch expires. Stop only the requested watch by id unless the user explicitly asks to stop every watch in the thread.",
1152
+ "- Use createEventAutomation only when the user explicitly asks for an event automation or durable whenever-this-happens-do-X automation. Ordinary watch, notify, and tell-me-when requests use watchEvents. When an event automation's resource and events are known, create it without redundant confirmation.",
1153
+ "- Event automations make the automation creator's connected credentials available by default when the requested work needs user-bound authorization. Do not ask for separate confirmation merely to use credentials needed for the requested work. On creation, omit credentialMode for the creator default and set system only when the creator explicitly requires it. For later changes, creator always means the automation's original createdBy actor, never the current requester. If the requester is not that creator, do not attempt to enable creator credential use or suggest that confirmation could authorize it.",
1154
+ "- Event automations list for the current destination, not one thread. Public automations can also be updated or deleted by automation id from another destination in the same workspace. When listing them, use createdBy to explain creator-only credential changes and warn when trigger.available is false; an unavailable automation remains stored but cannot receive events until its plugin event is enabled again.",
1155
+ "- Scheduled automations make the automation creator's connected credentials available by default when the requested work needs user-bound authorization. Do not ask for separate confirmation merely to use credentials needed for the requested work. On creation, omit credentialMode for the creator default and set system only when the creator explicitly requires it. For later changes, creator always means the automation's original createdBy actor, never the current requester. If the requester is not that creator, do not attempt to enable creator credential use or suggest that confirmation could authorize it.",
1152
1156
  "- When another model profile fits the task better, call `handoff` before substantial work. Follow the profile list and selection rules in the tool description.",
1153
1157
  "- Run `jr-rpc config get|set|unset|list` for provider defaults and `jr-rpc plugins list` for installed plugin introspection as standalone bash commands; do not chain them with `cd`, `&&`, pipes, or provider commands.",
1154
1158
  "- If the first result is empty, stale, ambiguous, or incomplete, try a focused alternate query, path, command, or source before concluding the answer cannot be verified."
@@ -1264,14 +1268,14 @@ function formatSourceLines(source) {
1264
1268
  ...source.messageTs ? [`- source.message_ts: ${escapeXml(source.messageTs)}`] : [],
1265
1269
  ...source.threadTs ? [`- source.thread_ts: ${escapeXml(source.threadTs)}`] : []
1266
1270
  ];
1267
- case "resource_event": return [
1268
- "- source.kind: resource_event",
1271
+ case "event": return [
1272
+ "- source.kind: event",
1269
1273
  `- source.namespace: ${escapeXml(source.namespace)}`,
1270
1274
  `- source.identifier: ${escapeXml(source.identifier)}`,
1271
1275
  `- source.event_type: ${escapeXml(source.eventType)}`
1272
1276
  ];
1273
- case "scheduled_task":
1274
- case "event_task":
1277
+ case "scheduled_automation":
1278
+ case "event_automation":
1275
1279
  case "plugin_dispatch":
1276
1280
  case "agent_invocation": return [`- source.kind: ${source.kind}`];
1277
1281
  }
@@ -2487,8 +2491,9 @@ async function prepareWorkspaceRepositories(params) {
2487
2491
  const { sandbox, workspace, signal } = params;
2488
2492
  signal?.throwIfAborted();
2489
2493
  await params.applyNetworkPolicy(sandbox);
2490
- await params.prepareRepositories?.(sandbox, workspace, signal);
2494
+ const finalize = await params.prepareRepositories?.(sandbox, workspace, signal);
2491
2495
  if (params.removeCredentialRoute) await sandbox.update({ networkPolicy: "allow-all" });
2496
+ await finalize?.();
2492
2497
  }
2493
2498
  /** Return bounded setup output for a Workspace failure. */
2494
2499
  function workspaceSetupFailureDetail(input) {
@@ -2611,7 +2616,7 @@ function emptyState(nowMs) {
2611
2616
  /** True when this Source starts an automated Turn rather than a user Turn. */
2612
2617
  function isAutomatedTurnSource(source) {
2613
2618
  if (!source) return false;
2614
- return source.kind === "resource_event" || source.kind === "event_task" || source.kind === "scheduled_task" || source.kind === "plugin_dispatch" || source.kind === "agent_invocation";
2619
+ return source.kind === "event" || source.kind === "event_automation" || source.kind === "scheduled_automation" || source.kind === "plugin_dispatch" || source.kind === "agent_invocation";
2615
2620
  }
2616
2621
  /** Plain notice when automatic updates stop until the user replies. */
2617
2622
  function buildAutomatedTurnLimitResponse(args) {
@@ -2823,48 +2828,15 @@ function renderTaskInput(args) {
2823
2828
  return lines.join("\n");
2824
2829
  }
2825
2830
  //#endregion
2826
- //#region src/chat/resource-events/actor.ts
2827
- /**
2828
- * System author ID stamped on resource-event mailbox messages.
2829
- *
2830
- * Keep this stable so conversation history can recognize the same system input
2831
- * for resource-event Turns.
2832
- *
2833
- * TODO(dcramer): Delete this ID after resumes read resource-event Source.kind
2834
- * from the Turn checkpoint instead of Message author data.
2835
- */
2836
- const RESOURCE_EVENT_AUTHOR_ID = "UJRNEVENT";
2837
- /** System Message author for resource-event input. */
2838
- const RESOURCE_EVENT_MESSAGE_AUTHOR = {
2839
- fullName: "Junior event",
2840
- isBot: true,
2841
- userId: RESOURCE_EVENT_AUTHOR_ID,
2842
- userName: "junior-event"
2843
- };
2844
- /** System execution actor for every resource-event turn. */
2845
- const RESOURCE_EVENT_SYSTEM_ACTOR = {
2846
- platform: "system",
2847
- name: "resource-event"
2848
- };
2849
- /**
2850
- * Whether a saved Message started a resource-event Turn.
2851
- *
2852
- * TODO(dcramer): Delete this marker check after deployed Turn cursors all store
2853
- * Source and Actor. `eventType` only supports saved synthetic Slack input.
2854
- */
2855
- function isResourceEventConversationMessage(message) {
2856
- return Boolean(message.meta?.eventType) || message.author?.userId === "UJRNEVENT";
2857
- }
2858
- //#endregion
2859
- //#region src/chat/resource-events/notification.ts
2831
+ //#region src/chat/events/notification.ts
2860
2832
  /**
2861
2833
  * Render the runtime-owned conversation message for a subscribed event.
2862
2834
  *
2863
2835
  * Keep this short: facts the model cannot reconstruct, plus a one-line handling
2864
2836
  * contract. Stable delivery rules live in runtime and docs, not this prompt.
2865
2837
  */
2866
- function renderResourceEventNotificationText(subscription, event) {
2867
- const guidance = resourceEventGuidance(getResourceEventCatalog(), event.namespace, subscription.resourceType, event.eventType);
2838
+ function renderEventNotificationText(subscription, event) {
2839
+ const guidance = eventGuidance(getEventCatalog(), event.namespace, subscription.resourceType, event.eventType);
2868
2840
  return renderTaskInput({
2869
2841
  about: subscription.label,
2870
2842
  instructions: subscription.intent,
@@ -2874,21 +2846,21 @@ function renderResourceEventNotificationText(subscription, event) {
2874
2846
  externalText: event.untrustedText
2875
2847
  });
2876
2848
  }
2877
- /** Whether mailbox metadata is a plain resource-event wake. */
2878
- function isResourceEventMailboxMetadata(value) {
2849
+ /** Whether mailbox metadata is a plain event wake. */
2850
+ function isEventMailboxMetadata(value) {
2879
2851
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
2880
2852
  const record = value;
2881
- if (record.kind !== "resource_event") return false;
2882
- const resourceEvent = record.resourceEvent;
2883
- if (!resourceEvent || typeof resourceEvent !== "object" || Array.isArray(resourceEvent)) return false;
2884
- const fields = resourceEvent;
2853
+ if (record.kind !== "event") return false;
2854
+ const event = record.event;
2855
+ if (!event || typeof event !== "object" || Array.isArray(event)) return false;
2856
+ const fields = event;
2885
2857
  return typeof fields.eventKey === "string" && typeof fields.eventType === "string" && typeof fields.namespace === "string" && typeof fields.identifier === "string" && typeof fields.subscriptionId === "string" && (fields.trustedSummary === void 0 || typeof fields.trustedSummary === "string");
2886
2858
  }
2887
2859
  /** Build plain conversation mailbox input for one matched watch. */
2888
- function createResourceEventInboundMessage(input) {
2860
+ function createEventInboundMessage(input) {
2889
2861
  const metadata = {
2890
- kind: "resource_event",
2891
- resourceEvent: {
2862
+ kind: "event",
2863
+ event: {
2892
2864
  eventKey: input.event.eventKey,
2893
2865
  eventType: input.event.eventType,
2894
2866
  namespace: input.event.namespace,
@@ -2900,25 +2872,25 @@ function createResourceEventInboundMessage(input) {
2900
2872
  return {
2901
2873
  conversationId: input.subscription.conversationId,
2902
2874
  createdAtMs: input.event.occurredAtMs,
2903
- inboundMessageId: `resource-event:${input.subscription.id}:${input.event.eventKey}`,
2875
+ inboundMessageId: `event:${input.subscription.id}:${input.event.eventKey}`,
2904
2876
  delivery: "defer",
2905
- source: "resource_event",
2877
+ source: "event",
2906
2878
  receivedAtMs: input.receivedAtMs ?? Date.now(),
2907
2879
  input: {
2908
2880
  text: input.text,
2909
- authorId: RESOURCE_EVENT_AUTHOR_ID,
2881
+ authorId: EVENT_AUTHOR_ID,
2910
2882
  metadata
2911
2883
  }
2912
2884
  };
2913
2885
  }
2914
2886
  /**
2915
- * Enqueue a resource event as normal conversation mailbox input.
2887
+ * Enqueue a event as normal conversation mailbox input.
2916
2888
  *
2917
2889
  * The watch only names the conversation. Destination stays on the conversation
2918
2890
  * and is applied when the worker runs. After too many automated Turns with no
2919
2891
  * user Turn, later wakes stay quiet until a user message clears the pause.
2920
2892
  */
2921
- async function enqueueResourceEventNotification(args) {
2893
+ async function enqueueEventNotification(args) {
2922
2894
  const maxTurns = botConfig.maxConsecutiveAutomatedTurns;
2923
2895
  const decision = await admitAutomatedTurn({
2924
2896
  conversationId: args.subscription.conversationId,
@@ -2927,12 +2899,12 @@ async function enqueueResourceEventNotification(args) {
2927
2899
  state: args.state
2928
2900
  });
2929
2901
  if (decision.status === "paused") {
2930
- logInfo("resource_events.automated_turn_limit.paused", {
2902
+ logInfo("events.automated_turn_limit.paused", {
2931
2903
  conversationId: args.subscription.conversationId,
2932
2904
  "app.automated_turn_limit.consecutive": decision.consecutiveAutomatedTurns,
2933
2905
  "app.automated_turn_limit.max": maxTurns,
2934
- "app.resource_event.event_type": args.event.eventType,
2935
- "app.resource_event.namespace": args.event.namespace
2906
+ "app.event.event_type": args.event.eventType,
2907
+ "app.event.namespace": args.event.namespace
2936
2908
  });
2937
2909
  if (decision.shouldPostNotice) await postAutomatedTurnLimitNoticeForConversation({
2938
2910
  conversationId: args.subscription.conversationId,
@@ -2941,9 +2913,9 @@ async function enqueueResourceEventNotification(args) {
2941
2913
  });
2942
2914
  return { status: "duplicate" };
2943
2915
  }
2944
- const text = renderResourceEventNotificationText(args.subscription, args.event);
2916
+ const text = renderEventNotificationText(args.subscription, args.event);
2945
2917
  return await appendAndEnqueueInboundMessage({
2946
- message: createResourceEventInboundMessage({
2918
+ message: createEventInboundMessage({
2947
2919
  event: args.event,
2948
2920
  subscription: {
2949
2921
  conversationId: args.subscription.conversationId,
@@ -2956,12 +2928,12 @@ async function enqueueResourceEventNotification(args) {
2956
2928
  });
2957
2929
  }
2958
2930
  //#endregion
2959
- //#region src/chat/resource-events/ingest.ts
2960
- /** Match a normalized resource event and enqueue notifications into conversations. */
2961
- async function ingestResourceEvent(input, options) {
2962
- const event = resourceEventSchema.parse(input);
2931
+ //#region src/chat/events/ingest.ts
2932
+ /** Match a normalized event and enqueue notifications into conversations. */
2933
+ async function ingestEvent(input, options) {
2934
+ const event = eventSchema.parse(input);
2963
2935
  const nowMs = options.nowMs ?? Date.now();
2964
- const subscriptions = await findMatchingResourceEventSubscriptions({
2936
+ const subscriptions = await findMatchingWatches({
2965
2937
  data: event.data,
2966
2938
  eventType: event.eventType,
2967
2939
  nowMs,
@@ -2973,7 +2945,7 @@ async function ingestResourceEvent(input, options) {
2973
2945
  const errors = [];
2974
2946
  const waitDeadlineMs = Date.now() + 1e4;
2975
2947
  for (const subscription of subscriptions) try {
2976
- if (await deliverResourceEventSubscription({
2948
+ if (await deliverWatch({
2977
2949
  data: event.data,
2978
2950
  eventType: event.eventType,
2979
2951
  namespace: event.namespace,
@@ -2984,7 +2956,7 @@ async function ingestResourceEvent(input, options) {
2984
2956
  subscription,
2985
2957
  waitDeadlineMs,
2986
2958
  deliver: async (current) => {
2987
- return (await enqueueResourceEventNotification({
2959
+ return (await enqueueEventNotification({
2988
2960
  event,
2989
2961
  queue: options.queue,
2990
2962
  state: options.state,
@@ -2995,7 +2967,7 @@ async function ingestResourceEvent(input, options) {
2995
2967
  } catch (error) {
2996
2968
  errors.push(error);
2997
2969
  }
2998
- if (errors.length > 0) throw new AggregateError(errors, "Failed to deliver one or more resource event subscriptions");
2970
+ if (errors.length > 0) throw new AggregateError(errors, "Failed to deliver one or more watches");
2999
2971
  return { enqueued };
3000
2972
  }
3001
2973
  //#endregion
@@ -3391,7 +3363,7 @@ const SNAPSHOT_BUILD_SYSTEM_ACTOR = {
3391
3363
  /** Leave time to send the next job before this request ends. */
3392
3364
  const JOB_STOP_BUFFER_MS = 4e4;
3393
3365
  async function publishFinishedEvent(input) {
3394
- await ingestResourceEvent(workspaceSnapshotFinishedEvent(input), { queue: getVercelConversationWorkQueue() });
3366
+ await ingestEvent(workspaceSnapshotFinishedEvent(input), { queue: getVercelConversationWorkQueue() });
3395
3367
  }
3396
3368
  function createSnapshotBuildHelpers() {
3397
3369
  const credentials = credentialContextForActor(SNAPSHOT_BUILD_SYSTEM_ACTOR);
@@ -3405,9 +3377,7 @@ function createSnapshotBuildHelpers() {
3405
3377
  await sandbox.update({ networkPolicy });
3406
3378
  return networkPolicy;
3407
3379
  };
3408
- const prepareRepositories = async (sandbox, target, signal) => {
3409
- await pluginHooks.prepareWorkspace(sandbox, target.repos, signal);
3410
- };
3380
+ const prepareRepositories = async (sandbox, target, signal) => await pluginHooks.prepareWorkspace(sandbox, target.repos, signal);
3411
3381
  return {
3412
3382
  applyNetworkPolicy,
3413
3383
  prepareRepositories
@@ -3917,7 +3887,14 @@ function createSandboxRuntime(options) {
3917
3887
  let networkPolicyKey;
3918
3888
  try {
3919
3889
  networkPolicyKey = await applyNetworkPolicy(createdSandbox);
3920
- if (workspace) await options.onWorkspacePrepare?.(createdSandbox, workspace, signal);
3890
+ if (workspace) {
3891
+ const finalize = await options.onWorkspacePrepare?.(createdSandbox, workspace, signal);
3892
+ if (options.createNetworkPolicy) {
3893
+ await createdSandbox.update({ networkPolicy: "allow-all" });
3894
+ networkPolicyKey = void 0;
3895
+ }
3896
+ await finalize?.();
3897
+ }
3921
3898
  await prepareSandbox(createdSandbox);
3922
3899
  } catch (error) {
3923
3900
  if (workspace) await stopSession(createdSandbox);
@@ -7174,7 +7151,7 @@ function createSpawnAgentTool(spawnAgent) {
7174
7151
  });
7175
7152
  }
7176
7153
  //#endregion
7177
- //#region src/chat/tools/list-resource-event-subscriptions.ts
7154
+ //#region src/chat/tools/list-watches.ts
7178
7155
  const listedResourceWatchSchema = z.object({
7179
7156
  id: z.string().min(1),
7180
7157
  label: z.string().min(1),
@@ -7188,8 +7165,8 @@ const listedResourceWatchSchema = z.object({
7188
7165
  }).strict();
7189
7166
  const resultDataSchema$2 = z.object({ subscriptions: z.array(listedResourceWatchSchema) }).strict();
7190
7167
  const outputSchema$5 = juniorToolOutputSchema.merge(resultDataSchema$2);
7191
- /** Create the tool that lists active resource watches for this conversation. */
7192
- function createListResourceEventSubscriptionsTool(context) {
7168
+ /** Create the tool that lists active watches for this conversation. */
7169
+ function createListWatchesTool(context) {
7193
7170
  return zodTool({
7194
7171
  annotations: {
7195
7172
  destructiveHint: false,
@@ -7197,13 +7174,13 @@ function createListResourceEventSubscriptionsTool(context) {
7197
7174
  openWorldHint: false,
7198
7175
  readOnlyHint: true
7199
7176
  },
7200
- description: "List active resource event subscriptions for the current conversation.",
7177
+ description: "List active watches for the current conversation.",
7201
7178
  exposure: "deferred",
7202
7179
  source: RESOURCE_WATCH_TOOL_SOURCE,
7203
7180
  inputSchema: z.object({}).strict(),
7204
7181
  outputSchema: outputSchema$5,
7205
7182
  async execute() {
7206
- return { subscriptions: (await listResourceEventSubscriptions({ conversationId: context.conversationId })).map((subscription) => ({
7183
+ return { subscriptions: (await listWatches({ conversationId: context.conversationId })).map((subscription) => ({
7207
7184
  id: subscription.id,
7208
7185
  label: subscription.label,
7209
7186
  identifier: subscription.identifier,
@@ -7218,7 +7195,7 @@ function createListResourceEventSubscriptionsTool(context) {
7218
7195
  });
7219
7196
  }
7220
7197
  //#endregion
7221
- //#region src/chat/tools/search-resource-event-types.ts
7198
+ //#region src/chat/tools/search-event-types.ts
7222
7199
  const DEFAULT_SEARCH_RESULTS = 10;
7223
7200
  const MAX_SEARCH_RESULTS = 20;
7224
7201
  const searchedResourceTypeSchema = z.object({
@@ -7254,8 +7231,8 @@ function searchableResourceTypes(catalog) {
7254
7231
  ...resourceType.matchFields ? { matchFields: resourceType.matchFields } : void 0
7255
7232
  }))).sort((left, right) => left.namespace.localeCompare(right.namespace) || left.type.localeCompare(right.type));
7256
7233
  }
7257
- /** Create the read-only tool that searches enabled resource event types. */
7258
- function createSearchResourceEventTypesTool(catalog) {
7234
+ /** Create the read-only tool that searches enabled event types. */
7235
+ function createSearchEventTypesTool(catalog) {
7259
7236
  return zodTool({
7260
7237
  annotations: {
7261
7238
  destructiveHint: false,
@@ -7263,9 +7240,9 @@ function createSearchResourceEventTypesTool(catalog) {
7263
7240
  openWorldHint: false,
7264
7241
  readOnlyHint: true
7265
7242
  },
7266
- description: "Search the resource event types currently enabled without creating anything. Includes plugin resources and core Workspace snapshot events. Use watchResourceEvents for temporary updates in the current conversation; use createEventTask for durable automation. This tool does not watch a resource, create a task, or list concrete resources.",
7243
+ description: "Search the event types currently enabled without creating anything. Includes plugin resources and core Workspace snapshot events. Use watchEvents for temporary updates in the current conversation; use createEventAutomation for durable automation. This tool does not watch a resource, create an automation, or list concrete resources.",
7267
7244
  inputSchema: z.object({
7268
- query: z.string().nullable().describe("Optional terms matching a namespace, resource type, or event name. Empty lists all enabled resource event types.").optional(),
7245
+ query: z.string().nullable().describe("Optional terms matching a namespace, resource type, or event name. Empty lists all enabled event types.").optional(),
7269
7246
  namespace: eventNamespaceSchema(catalog).nullable().describe("Optional enabled plugin namespace to search within.").optional(),
7270
7247
  maxResults: z.number().int().min(1).max(MAX_SEARCH_RESULTS).nullable().describe("Maximum matching resource types to return.").optional()
7271
7248
  }).strict(),
@@ -7294,13 +7271,13 @@ function createSearchResourceEventTypesTool(catalog) {
7294
7271
  });
7295
7272
  }
7296
7273
  //#endregion
7297
- //#region src/chat/tools/stop-watching-resources.ts
7274
+ //#region src/chat/tools/stop-watches.ts
7298
7275
  const resultDataSchema$1 = z.object({
7299
7276
  watching_status: z.literal("stopped"),
7300
7277
  stoppedIds: z.array(z.string().min(1))
7301
7278
  }).strict();
7302
7279
  const outputSchema$3 = juniorToolOutputSchema.merge(resultDataSchema$1);
7303
- /** Create the tool that stops resource watches for this conversation. */
7280
+ /** Create the tool that stops watches for this conversation. */
7304
7281
  function createStopWatchingResourcesTool(context) {
7305
7282
  return zodTool({
7306
7283
  annotations: {
@@ -7309,7 +7286,7 @@ function createStopWatchingResourcesTool(context) {
7309
7286
  openWorldHint: false,
7310
7287
  readOnlyHint: false
7311
7288
  },
7312
- description: "Stop one resource watch in the current conversation by id. Omit id only when the user explicitly asks to stop every watch in this conversation. Infer terse stop requests from context, inspect active watches when the target is unclear, and call this tool before confirming that watching stopped.",
7289
+ description: "Stop one watch in the current conversation by id. Omit id only when the user explicitly asks to stop every watch in this conversation. Infer terse stop requests from context, inspect active watches when the target is unclear, and call this tool before confirming that watching stopped.",
7313
7290
  exposure: "deferred",
7314
7291
  source: RESOURCE_WATCH_TOOL_SOURCE,
7315
7292
  inputSchema: z.object({ id: z.string().min(1).nullable().optional() }).strict(),
@@ -7317,14 +7294,14 @@ function createStopWatchingResourcesTool(context) {
7317
7294
  async execute({ id }) {
7318
7295
  let stoppedIds;
7319
7296
  if (id) {
7320
- const stopped = await cancelResourceEventSubscription({
7297
+ const stopped = await cancelWatch({
7321
7298
  conversationId: context.conversationId,
7322
7299
  id
7323
7300
  });
7324
- if (!stopped) throw new ToolInputError("Resource watch was not found in the current conversation.");
7301
+ if (!stopped) throw new ToolInputError("Watch was not found in the current conversation.");
7325
7302
  stoppedIds = [stopped.id];
7326
7303
  } else {
7327
- const subscriptions = await listResourceEventSubscriptions({ conversationId: context.conversationId });
7304
+ const subscriptions = await listWatches({ conversationId: context.conversationId });
7328
7305
  await cancelSubscriptions({ conversationId: context.conversationId });
7329
7306
  stoppedIds = subscriptions.map((subscription) => subscription.id);
7330
7307
  }
@@ -7336,7 +7313,7 @@ function createStopWatchingResourcesTool(context) {
7336
7313
  });
7337
7314
  }
7338
7315
  //#endregion
7339
- //#region src/chat/tools/watch-resource-events.ts
7316
+ //#region src/chat/tools/watch-events.ts
7340
7317
  function inputSchema(catalog) {
7341
7318
  return z.object({
7342
7319
  identifier: z.string().trim().min(1).describe("Plugin-defined resource identifier."),
@@ -7344,7 +7321,7 @@ function inputSchema(catalog) {
7344
7321
  resourceType: registeredResourceTypeSchema(catalog).describe("Plugin-defined resource type."),
7345
7322
  label: z.string().trim().min(1).max(500).describe("Human-readable resource label."),
7346
7323
  events: z.array(registeredEventTypeSchema(catalog)).min(1).describe("High-signal event names to deliver to this conversation when they occur."),
7347
- match: registeredResourceEventMatchSchema(),
7324
+ match: registeredEventMatchSchema(),
7348
7325
  intent: z.string().trim().min(1).max(4e3).describe("Concise reason this conversation wants these events, used when an event arrives."),
7349
7326
  ttlMs: z.coerce.number().describe("How long to keep the subscription active. Defaults to 14 days and must not exceed 30 days.").optional()
7350
7327
  }).strict().superRefine((subscription, context) => {
@@ -7384,11 +7361,11 @@ function cleanStrings(values) {
7384
7361
  function ttlMs(input) {
7385
7362
  if (input.ttlMs === void 0) return RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS;
7386
7363
  if (!Number.isFinite(input.ttlMs) || input.ttlMs <= 0) throw new ToolInputError("ttlMs must be a positive finite number");
7387
- if (input.ttlMs > 2592e6) throw new ToolInputError("Resource watches cannot exceed 30 days");
7364
+ if (input.ttlMs > 2592e6) throw new ToolInputError("Watches cannot exceed 30 days");
7388
7365
  return input.ttlMs;
7389
7366
  }
7390
- /** Create the tool that temporarily watches resource events in one conversation. */
7391
- function createWatchResourceEventsTool(context, catalog) {
7367
+ /** Create the tool that temporarily watches events in one conversation. */
7368
+ function createWatchEventsTool(context, catalog) {
7392
7369
  return zodTool({
7393
7370
  annotations: {
7394
7371
  destructiveHint: false,
@@ -7396,7 +7373,7 @@ function createWatchResourceEventsTool(context, catalog) {
7396
7373
  openWorldHint: true,
7397
7374
  readOnlyHint: false
7398
7375
  },
7399
- description: "Watch one plugin resource in the current conversation for a limited time; matching events return to this conversation as updates. Use for watch, notify, or tell-me-when requests. This does not create an event task or execute a durable task instruction. Prefer a subscribable tool result when available.",
7376
+ description: "Watch one plugin resource in the current conversation for a limited time; matching events return to this conversation as updates. Use for watch, notify, or tell-me-when requests. This does not create an event automation or execute a durable automation instruction. Prefer a subscribable tool result when available.",
7400
7377
  inputSchema: inputSchema(catalog),
7401
7378
  outputSchema: outputSchema$2,
7402
7379
  async execute(input) {
@@ -7404,13 +7381,13 @@ function createWatchResourceEventsTool(context, catalog) {
7404
7381
  for (const eventType of events) if (!pluginSupportsEvent(catalog, input.namespace, input.resourceType, eventType)) throw new ToolInputError(`Resource type "${input.namespace}:${input.resourceType}" does not support event "${eventType}".`);
7405
7382
  const intent = input.intent.trim();
7406
7383
  if (!intent) throw new ToolInputError("intent is required");
7407
- const match = requireSupportedResourceEventMatch(catalog, {
7384
+ const match = requireSupportedEventMatch(catalog, {
7408
7385
  match: input.match,
7409
7386
  namespace: input.namespace,
7410
7387
  resourceType: input.resourceType
7411
7388
  });
7412
7389
  const nowMs = Date.now();
7413
- const subscription = await createResourceEventSubscription({
7390
+ const subscription = await createWatch({
7414
7391
  conversationId: context.conversationId,
7415
7392
  events,
7416
7393
  expiresAtMs: nowMs + ttlMs(input),
@@ -7418,7 +7395,7 @@ function createWatchResourceEventsTool(context, catalog) {
7418
7395
  label: input.label.trim(),
7419
7396
  ...match ? { match } : void 0,
7420
7397
  namespace: input.namespace.trim(),
7421
- identifier: normalizeEventIdentifier(catalog, input.namespace, input.identifier),
7398
+ identifier: normalizeCatalogEventIdentifier(catalog, input.namespace, input.identifier),
7422
7399
  resourceType: input.resourceType.trim()
7423
7400
  });
7424
7401
  return {
@@ -7440,24 +7417,24 @@ function createWatchResourceEventsTool(context, catalog) {
7440
7417
  });
7441
7418
  }
7442
7419
  //#endregion
7443
- //#region src/chat/tools/resource-events.ts
7420
+ //#region src/chat/tools/events.ts
7444
7421
  /** Build the complete resource-watch tool set for this runtime context. */
7445
- function createResourceEventTools(context, catalog) {
7422
+ function createEventTools(context, catalog) {
7446
7423
  return {
7447
- ...hasResourceEventCatalogEntries(catalog) ? {
7448
- searchResourceEventTypes: createSearchResourceEventTypesTool(catalog),
7449
- watchResourceEvents: createWatchResourceEventsTool(context, catalog)
7424
+ ...hasEventCatalogEntries(catalog) ? {
7425
+ searchEventTypes: createSearchEventTypesTool(catalog),
7426
+ watchEvents: createWatchEventsTool(context, catalog)
7450
7427
  } : void 0,
7451
- listResourceEventSubscriptions: createListResourceEventSubscriptionsTool(context),
7428
+ listWatches: createListWatchesTool(context),
7452
7429
  stopWatchingResources: createStopWatchingResourcesTool(context)
7453
7430
  };
7454
7431
  }
7455
7432
  //#endregion
7456
- //#region src/chat/tools/create-event-task.ts
7457
- /** Build a retry-stable task id scoped to actor, destination, and tool call. */
7458
- function buildEventTaskId(args) {
7433
+ //#region src/chat/tools/create-event-automation.ts
7434
+ /** Build a retry-stable automation id scoped to actor, destination, and tool call. */
7435
+ function buildEventAutomationId(args) {
7459
7436
  const toolCallId = args.toolCallId?.trim();
7460
- if (!toolCallId) throw new Error("Event task creation requires a tool-call identity.");
7437
+ if (!toolCallId) throw new Error("Event automation creation requires a tool-call identity.");
7461
7438
  return `evt_${createHash("sha256").update(JSON.stringify({
7462
7439
  actor: args.userId,
7463
7440
  channel: args.channelId,
@@ -7465,9 +7442,9 @@ function buildEventTaskId(args) {
7465
7442
  team: args.teamId
7466
7443
  })).digest("hex").slice(0, 32)}`;
7467
7444
  }
7468
- /** Create the core tool that stores an event task. */
7469
- function createEventTaskTool(context, catalog) {
7470
- const trigger = registeredEventTaskTriggerSchema(catalog);
7445
+ /** Create the core tool that stores an event automation. */
7446
+ function createEventAutomationTool(context, catalog) {
7447
+ const trigger = registeredEventAutomationTriggerSchema(catalog);
7471
7448
  return zodTool({
7472
7449
  approvalMode: "review",
7473
7450
  annotations: {
@@ -7477,12 +7454,12 @@ function createEventTaskTool(context, catalog) {
7477
7454
  readOnlyHint: false
7478
7455
  },
7479
7456
  executionMode: "sequential",
7480
- description: "Create a durable event task that executes the supplied instruction for every matching resource event. Use for whenever-this-happens-do-X automation; ordinary watch, notify, or tell-me-when requests use watchResourceEvents instead. The task may use the creator's connected credentials. Prefer a subscribable tool result when available.",
7457
+ description: "Create a durable event automation that executes the supplied instruction for every matching event. Use for whenever-this-happens-do-X automation; ordinary watch, notify, or tell-me-when requests use watchEvents instead. The automation may use the creator's connected credentials. Prefer a subscribable tool result when available.",
7481
7458
  inputSchema: z.object({
7482
- task: z.string().trim().min(1).max(4e3),
7459
+ instruction: z.string().trim().min(1).max(4e3),
7483
7460
  title: z.string().trim().min(1).max(60).nullable().describe("Optional short display title. Omit or use null to generate one from the task instruction.").optional(),
7484
7461
  trigger,
7485
- outcomes: z.array(taskOutcomeInputSchema).max(5).describe("Messages to send after successful work. Use an empty list to send nothing. Omit to send one message to the current Slack conversation.").optional(),
7462
+ outcomes: z.array(taskOutcomeInputSchema).max(5).describe("Successful work is silent by default. Omit this field or use an empty list when the Automation should act through tools without a status message. Add send_message only when the user asks for a notification, post, digest, summary, or other visible result.").optional(),
7486
7463
  credentialMode: z.enum(["creator", "system"]).nullable().describe("Use creator to make the task creator's connected credentials available, or system when the creator says not to use them. Omit or use null for the creator default.").optional()
7487
7464
  }).strict(),
7488
7465
  prepareArguments(args) {
@@ -7491,25 +7468,25 @@ function createEventTaskTool(context, catalog) {
7491
7468
  if (prepared.credentialMode === "creator" || prepared.credentialMode === null) delete prepared.credentialMode;
7492
7469
  return prepared;
7493
7470
  },
7494
- outputSchema: eventTaskToolResultSchema,
7471
+ outputSchema: eventAutomationToolResultSchema,
7495
7472
  async execute(input, options) {
7496
- const { actor, destination, source } = requireEventTaskSlackContext(context);
7497
- const match = requireSupportedEventTaskTrigger(catalog, input.trigger);
7498
- const id = buildEventTaskId({
7473
+ const { actor, destination, source } = requireEventAutomationSlackContext(context);
7474
+ const match = requireSupportedEventAutomationTrigger(catalog, input.trigger);
7475
+ const id = buildEventAutomationId({
7499
7476
  channelId: destination.channelId,
7500
7477
  teamId: destination.teamId,
7501
7478
  toolCallId: options.toolCallId,
7502
7479
  userId: actor.userId
7503
7480
  });
7504
7481
  const db = getDb();
7505
- const existing = await getEventTask(db, id);
7482
+ const existing = await getEventAutomation(db, id);
7506
7483
  if (existing) {
7507
- if (!eventTaskMatchesDestination(existing, destination) || existing.createdBy.slackUserId !== actor.userId) throw new ToolInputError("Event task operation identity is invalid.");
7508
- if (existing.status !== "deleted") return eventTaskSuccess(existing, catalog);
7484
+ if (!eventAutomationMatchesDestination(existing, destination) || existing.createdBy.slackUserId !== actor.userId) throw new ToolInputError("Event automation operation identity is invalid.");
7485
+ if (existing.status !== "deleted") return eventAutomationToolResult(existing, catalog, actor.userId);
7509
7486
  }
7510
7487
  const title = await resolveTaskTitle({
7511
7488
  completeText,
7512
- instruction: input.task,
7489
+ instruction: input.instruction,
7513
7490
  title: input.title
7514
7491
  });
7515
7492
  const task = {
@@ -7524,25 +7501,25 @@ function createEventTaskTool(context, catalog) {
7524
7501
  credentialMode: input.credentialMode ?? "creator",
7525
7502
  destination,
7526
7503
  outcomes: await resolveTaskOutcomes(input.outcomes, destination, actor.userId),
7527
- task: { text: input.task },
7504
+ task: { text: input.instruction },
7528
7505
  ...title ? { title } : void 0,
7529
7506
  trigger: {
7530
7507
  namespace: input.trigger.namespace,
7531
- identifier: normalizeEventIdentifier(catalog, input.trigger.namespace, input.trigger.identifier),
7508
+ identifier: normalizeCatalogEventIdentifier(catalog, input.trigger.namespace, input.trigger.identifier),
7532
7509
  resourceType: input.trigger.resourceType,
7533
7510
  label: input.trigger.label,
7534
7511
  events: [...new Set(input.trigger.events)],
7535
7512
  ...match ? { match } : void 0
7536
7513
  }
7537
7514
  };
7538
- return eventTaskSuccess(await createEventTask(db, task), catalog);
7515
+ return eventAutomationToolResult(await createEventAutomation(db, task), catalog, actor.userId);
7539
7516
  }
7540
7517
  });
7541
7518
  }
7542
7519
  //#endregion
7543
- //#region src/chat/tools/delete-event-task.ts
7544
- /** Create the core tool that deletes an event task. */
7545
- function createDeleteEventTaskTool(context, catalog) {
7520
+ //#region src/chat/tools/delete-event-automation.ts
7521
+ /** Create the core tool that deletes an event automation. */
7522
+ function createDeleteEventAutomationTool(context, catalog) {
7546
7523
  return zodTool({
7547
7524
  approvalMode: "review",
7548
7525
  annotations: {
@@ -7552,22 +7529,23 @@ function createDeleteEventTaskTool(context, catalog) {
7552
7529
  readOnlyHint: false
7553
7530
  },
7554
7531
  executionMode: "sequential",
7555
- description: "Delete an event task.",
7556
- inputSchema: z.object({ taskId: z.string().min(1) }).strict(),
7557
- outputSchema: eventTaskToolResultSchema,
7558
- async execute({ taskId }) {
7559
- const current = await writableEventTask(context, taskId);
7560
- const deleted = await deleteEventTask(getDb(), current.id);
7561
- if (!deleted) throw new ToolInputError("Event task was not found.");
7562
- return eventTaskSuccess(deleted, catalog);
7532
+ description: "Delete an event automation.",
7533
+ inputSchema: z.object({ automationId: z.string().min(1) }).strict(),
7534
+ outputSchema: eventAutomationToolResultSchema,
7535
+ async execute({ automationId }) {
7536
+ const { actor } = requireEventAutomationSlackContext(context);
7537
+ const current = await writableEventAutomation(context, automationId);
7538
+ const deleted = await deleteEventAutomation(getDb(), current.id);
7539
+ if (!deleted) throw new ToolInputError("Event automation was not found.");
7540
+ return eventAutomationToolResult(deleted, catalog, actor.userId);
7563
7541
  }
7564
7542
  });
7565
7543
  }
7566
7544
  //#endregion
7567
- //#region src/chat/tools/list-event-tasks.ts
7568
- const MAX_LISTED_EVENT_TASKS = 50;
7569
- /** Create the core tool that lists event tasks for this destination. */
7570
- function createListEventTasksTool(context, catalog) {
7545
+ //#region src/chat/tools/list-event-automations.ts
7546
+ const MAX_LISTED_EVENT_AUTOMATIONS = 50;
7547
+ /** Create the core tool that lists event automations for this destination. */
7548
+ function createListEventAutomationsTool(context, catalog) {
7571
7549
  return zodTool({
7572
7550
  annotations: {
7573
7551
  destructiveHint: false,
@@ -7575,30 +7553,30 @@ function createListEventTasksTool(context, catalog) {
7575
7553
  openWorldHint: false,
7576
7554
  readOnlyHint: true
7577
7555
  },
7578
- description: "List event tasks for the current destination. A false triggerAvailable value means the task remains stored but its plugin event is not currently enabled.",
7556
+ description: "List event automations for the current destination. Each result says whether the requester is the creator and whether its trigger is available.",
7579
7557
  inputSchema: z.object({}).strict(),
7580
- outputSchema: eventTaskListToolResultSchema,
7558
+ outputSchema: eventAutomationListToolResultSchema,
7581
7559
  async execute() {
7582
- const { destination } = requireEventTaskSlackContext(context);
7583
- const matching = (await listEventTasksForTeam(getDb(), destination.teamId)).filter((task) => eventTaskMatchesDestination(task, destination));
7584
- const tasks = matching.slice(0, MAX_LISTED_EVENT_TASKS).map((task) => compactEventTask(task, catalog));
7560
+ const { actor, destination } = requireEventAutomationSlackContext(context);
7561
+ const matching = (await listEventAutomationsForTeam(getDb(), destination.teamId)).filter((task) => eventAutomationMatchesDestination(task, destination));
7562
+ const automations = matching.slice(0, MAX_LISTED_EVENT_AUTOMATIONS).map((task) => compactEventAutomation(task, catalog, actor.userId));
7585
7563
  return {
7586
- tasks,
7587
- truncated: matching.length > tasks.length
7564
+ automations,
7565
+ truncated: matching.length > automations.length
7588
7566
  };
7589
7567
  }
7590
7568
  });
7591
7569
  }
7592
7570
  //#endregion
7593
- //#region src/chat/tools/update-event-task.ts
7571
+ //#region src/chat/tools/update-event-automation.ts
7594
7572
  /** Return whether an edit changes the task's executable event source. */
7595
- function changesEventTaskTrigger(current, next) {
7573
+ function changesEventAutomationTrigger(current, next) {
7596
7574
  const currentEvents = [...current.events].sort();
7597
7575
  const nextEvents = [...next.events].sort();
7598
- return current.namespace !== next.namespace || current.identifier !== next.identifier || currentEvents.length !== nextEvents.length || currentEvents.some((event, index) => event !== nextEvents[index]) || stableResourceEventMatchKey(current.match) !== stableResourceEventMatchKey(next.match);
7576
+ 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);
7599
7577
  }
7600
- /** Create the core tool that updates an event task. */
7601
- function createUpdateEventTaskTool(context, catalog) {
7578
+ /** Create the core tool that updates an event automation. */
7579
+ function createUpdateEventAutomationTool(context, catalog) {
7602
7580
  return zodTool({
7603
7581
  approvalMode: "review",
7604
7582
  annotations: {
@@ -7608,44 +7586,44 @@ function createUpdateEventTaskTool(context, catalog) {
7608
7586
  readOnlyHint: false
7609
7587
  },
7610
7588
  executionMode: "sequential",
7611
- description: "Update the instruction, registered trigger, or credential use for an event task.",
7589
+ description: "Update the instruction, registered trigger, or credential use for an event automation.",
7612
7590
  inputSchema: z.object({
7613
- taskId: z.string().min(1),
7614
- task: z.string().trim().min(1).max(4e3).nullable().optional(),
7615
- trigger: registeredEventTaskTriggerSchema(catalog).nullable().optional(),
7591
+ automationId: z.string().min(1),
7592
+ instruction: z.string().trim().min(1).max(4e3).nullable().optional(),
7593
+ trigger: registeredEventAutomationTriggerSchema(catalog).nullable().optional(),
7616
7594
  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(),
7617
7595
  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()
7618
7596
  }).strict(),
7619
7597
  prepareArguments(args) {
7620
- const { credentialMode, outcomes, task, trigger, ...prepared } = args;
7598
+ const { credentialMode, outcomes, instruction, trigger, ...prepared } = args;
7621
7599
  return {
7622
7600
  ...prepared,
7623
- ...task != null ? { task } : void 0,
7601
+ ...instruction != null ? { instruction } : void 0,
7624
7602
  ...trigger != null ? { trigger } : void 0,
7625
7603
  ...outcomes != null ? { outcomes } : void 0,
7626
7604
  ...credentialMode != null ? { credentialMode } : void 0
7627
7605
  };
7628
7606
  },
7629
- outputSchema: eventTaskToolResultSchema,
7607
+ outputSchema: eventAutomationToolResultSchema,
7630
7608
  async execute(input) {
7631
- const current = await writableEventTask(context, input.taskId);
7632
- const match = input.trigger ? requireSupportedEventTaskTrigger(catalog, input.trigger) : void 0;
7633
- const { actor } = requireEventTaskSlackContext(context);
7609
+ const current = await writableEventAutomation(context, input.automationId);
7610
+ const match = input.trigger ? requireSupportedEventAutomationTrigger(catalog, input.trigger) : void 0;
7611
+ const { actor } = requireEventAutomationSlackContext(context);
7634
7612
  const isCreator = actor.userId === current.createdBy.slackUserId;
7635
- if (input.credentialMode === "creator" && !isCreator) throw new ToolInputError("Only the event task creator can enable creator credential use.");
7636
- if (input.outcomes != null && !isCreator) throw new ToolInputError("Only the event task creator can change message destinations.");
7637
- if (input.task === void 0 && input.trigger === void 0 && input.outcomes == null && input.credentialMode == null) throw new ToolInputError("Event task update requires a change.");
7613
+ if (input.credentialMode === "creator" && !isCreator) throw new ToolInputError("Only the event automation creator can enable creator credential use.");
7614
+ if (input.outcomes != null && !isCreator) throw new ToolInputError("Only the event automation creator can change message destinations.");
7615
+ if (input.instruction === void 0 && input.trigger === void 0 && input.outcomes == null && input.credentialMode == null) throw new ToolInputError("Event automation update requires a change.");
7638
7616
  const nextTrigger = input.trigger ? {
7639
7617
  namespace: input.trigger.namespace,
7640
- identifier: normalizeEventIdentifier(catalog, input.trigger.namespace, input.trigger.identifier),
7618
+ identifier: normalizeCatalogEventIdentifier(catalog, input.trigger.namespace, input.trigger.identifier),
7641
7619
  resourceType: input.trigger.resourceType,
7642
7620
  label: input.trigger.label,
7643
7621
  events: [...new Set(input.trigger.events)],
7644
7622
  ...match ? { match } : void 0
7645
7623
  } : current.trigger;
7646
- const nextInstruction = input.task != null ? input.task : current.task.text;
7624
+ const nextInstruction = input.instruction != null ? input.instruction : current.task.text;
7647
7625
  const instructionChanged = nextInstruction !== current.task.text;
7648
- const changesExecution = instructionChanged || changesEventTaskTrigger(current.trigger, nextTrigger);
7626
+ const changesExecution = instructionChanged || changesEventAutomationTrigger(current.trigger, nextTrigger);
7649
7627
  const next = {
7650
7628
  ...current,
7651
7629
  credentialMode: changesExecution && !isCreator ? "system" : input.credentialMode ?? current.credentialMode,
@@ -7662,26 +7640,26 @@ function createUpdateEventTaskTool(context, catalog) {
7662
7640
  if (title) next.title = title;
7663
7641
  else delete next.title;
7664
7642
  }
7665
- const saved = await saveEventTask(getDb(), next);
7666
- if (!saved) throw new ToolInputError("Event task was not found.");
7667
- return eventTaskSuccess(saved, catalog);
7643
+ const saved = await saveEventAutomation(getDb(), next);
7644
+ if (!saved) throw new ToolInputError("Event automation was not found.");
7645
+ return eventAutomationToolResult(saved, catalog, actor.userId);
7668
7646
  }
7669
7647
  });
7670
7648
  }
7671
7649
  //#endregion
7672
- //#region src/chat/tools/event-tasks.ts
7673
- /** Build event task tools for an interactive Slack actor. */
7674
- function createEventTaskTools(context, catalog) {
7650
+ //#region src/chat/tools/event-automations.ts
7651
+ /** Build event automation tools for an interactive Slack actor. */
7652
+ function createEventAutomationTools(context, catalog) {
7675
7653
  if (context.source.kind !== "slack" || context.destination.platform !== "slack" || context.actor?.platform !== "slack") return {};
7676
7654
  return {
7677
- ...hasPluginResourceEventCatalogEntries(catalog) ? { createEventTask: createEventTaskTool(context, catalog) } : void 0,
7678
- listEventTasks: createListEventTasksTool(context, catalog),
7679
- updateEventTask: createUpdateEventTaskTool(context, catalog),
7680
- deleteEventTask: createDeleteEventTaskTool(context, catalog)
7655
+ ...hasPluginEventCatalogEntries(catalog) ? { createEventAutomation: createEventAutomationTool(context, catalog) } : void 0,
7656
+ listEventAutomations: createListEventAutomationsTool(context, catalog),
7657
+ updateEventAutomation: createUpdateEventAutomationTool(context, catalog),
7658
+ deleteEventAutomation: createDeleteEventAutomationTool(context, catalog)
7681
7659
  };
7682
7660
  }
7683
7661
  //#endregion
7684
- //#region src/chat/scheduled-tasks/cadence.ts
7662
+ //#region src/chat/scheduled-automations/cadence.ts
7685
7663
  const FORMATTERS = /* @__PURE__ */ new Map();
7686
7664
  function getFormatter(timezone) {
7687
7665
  const existing = FORMATTERS.get(timezone);
@@ -7924,7 +7902,7 @@ function getNextRunAtMs(task, scheduledForMs, afterMs = scheduledForMs) {
7924
7902
  });
7925
7903
  }
7926
7904
  //#endregion
7927
- //#region src/chat/scheduled-tasks/schedule-intent.ts
7905
+ //#region src/chat/scheduled-automations/schedule-intent.ts
7928
7906
  /**
7929
7907
  * Owns model-facing schedule intent and materializes it against the trusted
7930
7908
  * server clock into the canonical schedule persisted by core.
@@ -7971,9 +7949,9 @@ const recurringScheduleIntentSchema = z.object({
7971
7949
  interval: z.number().int().positive().max(365).describe("Repeat every N frequency units. Defaults to 1.").nullable().optional(),
7972
7950
  time: localTimeSchema.describe("Local wall-clock time for each occurrence in HH:MM format."),
7973
7951
  weekdays: z.array(weekdaySchema).min(1).max(7).describe("Required for weekly schedules.").nullable().optional(),
7974
- day_of_month: z.number().int().min(1).max(31).describe("Required for monthly and yearly schedules.").nullable().optional(),
7952
+ dayOfMonth: z.number().int().min(1).max(31).describe("Required for monthly and yearly schedules.").nullable().optional(),
7975
7953
  month: z.number().int().min(1).max(12).describe("Required for yearly schedules, where January is 1.").nullable().optional(),
7976
- start_date: localDateSchema.describe("Optional local calendar date that anchors the recurrence. Omit to start with the next matching occurrence.").nullable().optional(),
7954
+ startDate: localDateSchema.describe("Optional local calendar date that anchors the recurrence. Omit to start with the next matching occurrence.").nullable().optional(),
7977
7955
  timezone: timezoneSchema
7978
7956
  }).strict().superRefine((schedule, context) => {
7979
7957
  if (schedule.frequency === "weekly" && schedule.weekdays == null) context.addIssue({
@@ -7981,10 +7959,10 @@ const recurringScheduleIntentSchema = z.object({
7981
7959
  message: "Weekly schedules require weekdays.",
7982
7960
  path: ["weekdays"]
7983
7961
  });
7984
- if ((schedule.frequency === "monthly" || schedule.frequency === "yearly") && schedule.day_of_month == null) context.addIssue({
7962
+ if ((schedule.frequency === "monthly" || schedule.frequency === "yearly") && schedule.dayOfMonth == null) context.addIssue({
7985
7963
  code: "custom",
7986
- message: `${schedule.frequency} schedules require day_of_month.`,
7987
- path: ["day_of_month"]
7964
+ message: `${schedule.frequency} schedules require dayOfMonth.`,
7965
+ path: ["dayOfMonth"]
7988
7966
  });
7989
7967
  if (schedule.frequency === "yearly" && schedule.month == null) context.addIssue({
7990
7968
  code: "custom",
@@ -7996,10 +7974,10 @@ const recurringScheduleIntentSchema = z.object({
7996
7974
  message: "weekdays applies only to weekly schedules.",
7997
7975
  path: ["weekdays"]
7998
7976
  });
7999
- if (schedule.frequency !== "monthly" && schedule.frequency !== "yearly" && schedule.day_of_month != null) context.addIssue({
7977
+ if (schedule.frequency !== "monthly" && schedule.frequency !== "yearly" && schedule.dayOfMonth != null) context.addIssue({
8000
7978
  code: "custom",
8001
- message: "day_of_month applies only to monthly or yearly schedules.",
8002
- path: ["day_of_month"]
7979
+ message: "dayOfMonth applies only to monthly or yearly schedules.",
7980
+ path: ["dayOfMonth"]
8003
7981
  });
8004
7982
  if (schedule.frequency !== "yearly" && schedule.month != null) context.addIssue({
8005
7983
  code: "custom",
@@ -8066,8 +8044,8 @@ function recurringDescription(schedule, timezone) {
8066
8044
  const cadence = interval === 1 ? cadenceUnit : `${interval} ${cadenceUnit}s`;
8067
8045
  let detail = "";
8068
8046
  if (schedule.frequency === "weekly") detail = ` on ${formatWeekdays(schedule.weekdays)}`;
8069
- else if (schedule.frequency === "monthly") detail = ` on day ${schedule.day_of_month}`;
8070
- else if (schedule.frequency === "yearly") detail = ` on ${String(schedule.month).padStart(2, "0")}-${String(schedule.day_of_month).padStart(2, "0")}`;
8047
+ else if (schedule.frequency === "monthly") detail = ` on day ${schedule.dayOfMonth}`;
8048
+ else if (schedule.frequency === "yearly") detail = ` on ${String(schedule.month).padStart(2, "0")}-${String(schedule.dayOfMonth).padStart(2, "0")}`;
8071
8049
  return `Every ${cadence}${detail} at ${schedule.time} (${timezone})`;
8072
8050
  }
8073
8051
  var ScheduleIntentError = class extends Error {};
@@ -8103,13 +8081,13 @@ function compileScheduleIntent(args) {
8103
8081
  const recurrence = {
8104
8082
  frequency: args.intent.frequency,
8105
8083
  interval: args.intent.interval ?? 1,
8106
- startDate: args.intent.start_date ?? localDateAt(args.nowMs, timezone),
8084
+ startDate: args.intent.startDate ?? localDateAt(args.nowMs, timezone),
8107
8085
  time: parseLocalTime(args.intent.time),
8108
8086
  ...args.intent.frequency === "weekly" ? { weekdays: [...new Set(args.intent.weekdays.map((weekday) => WEEKDAY_INDEX[weekday]))].sort((left, right) => left - right) } : void 0,
8109
- ...args.intent.frequency === "monthly" || args.intent.frequency === "yearly" ? { dayOfMonth: args.intent.day_of_month ?? void 0 } : void 0,
8087
+ ...args.intent.frequency === "monthly" || args.intent.frequency === "yearly" ? { dayOfMonth: args.intent.dayOfMonth ?? void 0 } : void 0,
8110
8088
  ...args.intent.frequency === "yearly" ? { month: args.intent.month ?? void 0 } : void 0
8111
8089
  };
8112
- const searchRecurrence = args.intent.start_date ? recurrence : {
8090
+ const searchRecurrence = args.intent.startDate ? recurrence : {
8113
8091
  ...recurrence,
8114
8092
  interval: 1
8115
8093
  };
@@ -8119,7 +8097,7 @@ function compileScheduleIntent(args) {
8119
8097
  timezone
8120
8098
  });
8121
8099
  if (nextRunAtMs === void 0) throw new ScheduleIntentError("The recurring schedule has no valid future occurrence.");
8122
- const materializedRecurrence = args.intent.start_date ? recurrence : {
8100
+ const materializedRecurrence = args.intent.startDate ? recurrence : {
8123
8101
  ...recurrence,
8124
8102
  startDate: localDateAt(nextRunAtMs, timezone)
8125
8103
  };
@@ -8134,10 +8112,10 @@ function compileScheduleIntent(args) {
8134
8112
  };
8135
8113
  }
8136
8114
  //#endregion
8137
- //#region src/chat/scheduled-tasks/telemetry.ts
8138
- /** Safe structured telemetry attributes for scheduled-task lifecycle events. */
8139
- /** Correlation attributes shared by scheduled-task create and run events. */
8140
- function scheduledTaskAttributes(task, extras = {}) {
8115
+ //#region src/chat/scheduled-automations/telemetry.ts
8116
+ /** Safe structured telemetry attributes for scheduled-automation lifecycle events. */
8117
+ /** Correlation attributes shared by scheduled-automation create and run events. */
8118
+ function scheduledAutomationAttributes(task, extras = {}) {
8141
8119
  return {
8142
8120
  "app.task.id": task.id,
8143
8121
  "app.task.type": "scheduled",
@@ -8154,9 +8132,9 @@ function scheduledTaskAttributes(task, extras = {}) {
8154
8132
  ...extras
8155
8133
  };
8156
8134
  }
8157
- /** Correlation attributes for one scheduled-task run transition. */
8158
- function scheduledTaskRunAttributes(task, run, extras = {}) {
8159
- return scheduledTaskAttributes(task, {
8135
+ /** Correlation attributes for one scheduled-automation run transition. */
8136
+ function scheduledAutomationRunAttributes(task, run, extras = {}) {
8137
+ return scheduledAutomationAttributes(task, {
8160
8138
  "app.task.run.id": run.id,
8161
8139
  "app.task.run.status": run.status,
8162
8140
  "app.task.run.scheduled_for": new Date(run.scheduledForMs).toISOString(),
@@ -8165,12 +8143,12 @@ function scheduledTaskRunAttributes(task, run, extras = {}) {
8165
8143
  ...extras
8166
8144
  });
8167
8145
  }
8168
- /** Emit the lifecycle event for one skipped scheduled-task run. */
8169
- function logScheduledTaskRunSkipped(task, run, extras = {}) {
8170
- logInfo("scheduled_task.run.skipped", scheduledTaskRunAttributes(task, run, extras));
8146
+ /** Emit the lifecycle event for one skipped scheduled-automation run. */
8147
+ function logScheduledAutomationRunSkipped(task, run, extras = {}) {
8148
+ logInfo("scheduled_automation.run.skipped", scheduledAutomationRunAttributes(task, run, extras));
8171
8149
  }
8172
8150
  //#endregion
8173
- //#region src/chat/scheduled-tasks/identity.ts
8151
+ //#region src/chat/scheduled-automations/identity.ts
8174
8152
  const SLACK_USER_ID_PATTERN = /^[UW][A-Z0-9]{5,}$/;
8175
8153
  function clean(value) {
8176
8154
  const normalized = value?.trim();
@@ -8186,9 +8164,9 @@ function cleanDisplay(value, slackUserId) {
8186
8164
  return SLACK_USER_ID_PATTERN.test(normalized) ? void 0 : normalized;
8187
8165
  }
8188
8166
  /** Keep scheduler creator metadata from promoting Slack IDs into display names. */
8189
- function sanitizeScheduledTaskPrincipal(principal) {
8167
+ function sanitizeScheduledAutomationPrincipal(principal) {
8190
8168
  const slackUserId = cleanSlackUserId(principal.slackUserId);
8191
- if (!slackUserId) throw new Error("Scheduled task principal requires a Slack user id");
8169
+ if (!slackUserId) throw new Error("Scheduled automation principal requires a Slack user id");
8192
8170
  const fullName = cleanDisplay(principal.fullName, slackUserId);
8193
8171
  const userName = cleanDisplay(principal.userName, slackUserId);
8194
8172
  return {
@@ -8198,28 +8176,32 @@ function sanitizeScheduledTaskPrincipal(principal) {
8198
8176
  };
8199
8177
  }
8200
8178
  //#endregion
8201
- //#region src/chat/scheduled-tasks/tool-support.ts
8179
+ //#region src/chat/scheduled-automations/tool-support.ts
8202
8180
  const TASK_ID_PREFIX = "sched";
8203
8181
  const DEFAULT_SCHEDULE_TIMEZONE = "America/Los_Angeles";
8204
8182
  const compactTaskResultSchema = z.object({
8205
8183
  id: z.string(),
8184
+ title: z.string().nullable(),
8206
8185
  status: z.enum([
8207
8186
  "active",
8208
8187
  "blocked",
8209
8188
  "completed",
8210
8189
  "deleted"
8211
8190
  ]),
8212
- task: z.string(),
8191
+ statusReason: z.string().nullable(),
8192
+ createdAt: z.string().datetime(),
8193
+ updatedAt: z.string().datetime(),
8194
+ originalRequest: z.string().nullable(),
8195
+ instruction: z.string(),
8213
8196
  schedule: z.string(),
8214
8197
  timezone: z.string(),
8215
8198
  recurrence: z.unknown().nullable(),
8216
- next_run_at: z.string().nullable(),
8199
+ nextRunAt: z.string().nullable(),
8217
8200
  destination: z.object({
8218
- platform: z.literal("slack"),
8219
- team_id: z.string().min(1),
8220
- channel_id: z.string().min(1)
8201
+ channel: z.string().min(1),
8202
+ thread: z.string().min(1).nullable()
8221
8203
  }).strict(),
8222
- conversation_access: z.object({
8204
+ conversationAccess: z.object({
8223
8205
  audience: z.enum([
8224
8206
  "direct",
8225
8207
  "group",
@@ -8227,22 +8209,29 @@ const compactTaskResultSchema = z.object({
8227
8209
  ]),
8228
8210
  visibility: z.enum(["private", "public"])
8229
8211
  }).strict(),
8230
- credential_mode: z.enum(["system", "creator"]),
8231
- outcomes: z.array(taskOutcomeSchema).max(5),
8232
- dashboard_url: z.string().url().nullable(),
8233
- last_run_at: z.string().nullable(),
8234
- run_now_at: z.string().nullable()
8235
- }).strict();
8236
- const scheduleTaskToolResultSchema = juniorToolOutputSchema.extend({
8237
- target: z.string(),
8238
- task: compactTaskResultSchema
8212
+ credentialMode: z.enum(["system", "creator"]),
8213
+ isCreator: z.boolean(),
8214
+ createdBy: z.object({
8215
+ name: z.string().min(1).nullable(),
8216
+ username: z.string().min(1).nullable()
8217
+ }).strict(),
8218
+ outcomes: z.array(z.object({
8219
+ action: z.literal("send_message"),
8220
+ destination: z.object({
8221
+ channel: z.string().min(1),
8222
+ thread: z.string().min(1).nullable()
8223
+ }).strict()
8224
+ }).strict()).max(5),
8225
+ dashboardUrl: z.string().url().nullable(),
8226
+ lastRunAt: z.string().nullable(),
8227
+ runNowAt: z.string().nullable()
8239
8228
  }).strict();
8229
+ const scheduleAutomationToolResultSchema = juniorToolOutputSchema.extend({ automation: compactTaskResultSchema }).strict();
8240
8230
  const scheduleListToolResultSchema = juniorToolOutputSchema.extend({
8241
- target: z.string(),
8242
- tasks: z.array(compactTaskResultSchema),
8231
+ automations: z.array(compactTaskResultSchema),
8243
8232
  truncated: z.boolean()
8244
8233
  }).strict();
8245
- /** Normalize scheduled-task validation failures into the core tool contract. */
8234
+ /** Normalize scheduled-automation validation failures into the core tool contract. */
8246
8235
  function throwToolInputError(error) {
8247
8236
  throw new ToolInputError(error);
8248
8237
  }
@@ -8271,7 +8260,7 @@ function requireActor(context, destination) {
8271
8260
  if (context.actor?.platform !== "slack" || context.actor.teamId !== destination.teamId) throwToolInputError("No active Slack actor context is available.");
8272
8261
  const userId = context.actor?.userId?.trim();
8273
8262
  if (!userId || userId.toLowerCase() === "unknown") throwToolInputError("No active Slack actor context is available.");
8274
- return sanitizeScheduledTaskPrincipal({
8263
+ return sanitizeScheduledAutomationPrincipal({
8275
8264
  slackUserId: userId,
8276
8265
  ...context.actor?.userName ? { userName: context.actor.userName } : void 0,
8277
8266
  ...context.actor?.fullName ? { fullName: context.actor.fullName } : void 0
@@ -8303,54 +8292,65 @@ function sameDestination(task, destination) {
8303
8292
  /** Look up a mutable task only after enforcing active-conversation ownership. */
8304
8293
  async function getWritableTask(args) {
8305
8294
  const destination = requireActiveConversation(args.context);
8306
- const task = await readScheduledTask(getDb(), args.taskId);
8307
- if (!task || task.status === "deleted") throwToolInputError("Scheduled task was not found in the active Slack conversation.");
8308
- if (!sameDestination(task, destination)) throwToolInputError("Scheduled task can only be managed from the Slack destination where it currently delivers.");
8295
+ const task = await readScheduledAutomation(getDb(), args.taskId);
8296
+ if (!task || task.status === "deleted") throwToolInputError("Scheduled automation was not found in the active Slack conversation.");
8297
+ if (!sameDestination(task, destination)) throwToolInputError("Scheduled automation can only be managed from the Slack destination where it currently delivers.");
8309
8298
  return task;
8310
8299
  }
8311
- /** Project scheduled task state into the stable model-facing result shape. */
8312
- function compactTask(task) {
8300
+ /** Project scheduled automation state into the stable model-facing result shape. */
8301
+ function compactTask(task, requesterSlackUserId) {
8313
8302
  return compactTaskResultSchema.parse({
8314
8303
  id: task.id,
8304
+ title: task.title?.trim() || null,
8315
8305
  status: task.status,
8316
- task: task.task.text,
8306
+ statusReason: task.statusReason ?? null,
8307
+ createdAt: new Date(task.createdAtMs).toISOString(),
8308
+ updatedAt: new Date(task.updatedAtMs).toISOString(),
8309
+ originalRequest: task.originalRequest ?? null,
8310
+ instruction: task.task.text,
8317
8311
  schedule: task.schedule.description,
8318
8312
  timezone: task.schedule.timezone,
8319
8313
  recurrence: task.schedule.recurrence ? {
8320
8314
  frequency: task.schedule.recurrence.frequency,
8321
8315
  interval: task.schedule.recurrence.interval,
8322
- start_date: task.schedule.recurrence.startDate,
8316
+ startDate: task.schedule.recurrence.startDate,
8323
8317
  time: task.schedule.recurrence.time,
8324
8318
  weekdays: task.schedule.recurrence.weekdays,
8325
8319
  month: task.schedule.recurrence.month,
8326
- day_of_month: task.schedule.recurrence.dayOfMonth
8320
+ dayOfMonth: task.schedule.recurrence.dayOfMonth
8327
8321
  } : null,
8328
- next_run_at: task.nextRunAtMs ? new Date(task.nextRunAtMs).toISOString() : null,
8322
+ nextRunAt: task.nextRunAtMs ? new Date(task.nextRunAtMs).toISOString() : null,
8329
8323
  destination: {
8330
- platform: "slack",
8331
- team_id: task.destination.teamId,
8332
- channel_id: task.destination.channelId
8324
+ channel: task.destination.channelId,
8325
+ thread: task.destination.threadTs ?? null
8333
8326
  },
8334
- conversation_access: task.conversationAccess,
8335
- credential_mode: task.credentialMode,
8336
- outcomes: effectiveTaskOutcomes(task.outcomes, task.destination),
8337
- dashboard_url: getDashboardTaskLink(task.id) ?? null,
8338
- last_run_at: task.lastRunAtMs ? new Date(task.lastRunAtMs).toISOString() : null,
8339
- run_now_at: task.runNowAtMs ? new Date(task.runNowAtMs).toISOString() : null
8327
+ conversationAccess: task.conversationAccess,
8328
+ credentialMode: task.credentialMode,
8329
+ isCreator: task.createdBy.slackUserId === requesterSlackUserId,
8330
+ createdBy: {
8331
+ name: task.createdBy.fullName ?? null,
8332
+ username: task.createdBy.userName ?? null
8333
+ },
8334
+ outcomes: effectiveTaskOutcomes(task.outcomes, task.destination).map((outcome) => ({
8335
+ action: outcome.action,
8336
+ destination: {
8337
+ channel: outcome.destination.channelId,
8338
+ thread: outcome.destination.threadTs ?? null
8339
+ }
8340
+ })),
8341
+ dashboardUrl: getDashboardTaskLink(task.id) ?? null,
8342
+ lastRunAt: task.lastRunAtMs ? new Date(task.lastRunAtMs).toISOString() : null,
8343
+ runNowAt: task.runNowAtMs ? new Date(task.runNowAtMs).toISOString() : null
8340
8344
  });
8341
8345
  }
8342
8346
  /** Build the structured result shared by single-task scheduler tools. */
8343
- function scheduleTaskToolResult(target, task) {
8344
- return {
8345
- target,
8346
- task
8347
- };
8347
+ function scheduleAutomationToolResult(task, requesterSlackUserId) {
8348
+ return { automation: compactTask(task, requesterSlackUserId) };
8348
8349
  }
8349
8350
  /** Build the structured result for listing scheduler tools. */
8350
8351
  function scheduleListToolResult(args) {
8351
8352
  return {
8352
- target: args.target,
8353
- tasks: args.tasks,
8353
+ automations: args.automations,
8354
8354
  truncated: args.truncated
8355
8355
  };
8356
8356
  }
@@ -8376,9 +8376,9 @@ function getDefaultScheduleTimezone() {
8376
8376
  return process.env.JUNIOR_TIMEZONE?.trim() || DEFAULT_SCHEDULE_TIMEZONE;
8377
8377
  }
8378
8378
  //#endregion
8379
- //#region src/chat/scheduled-tasks/tools/create.ts
8380
- /** Create a tool that stores a scheduled task for the active Slack context. */
8381
- function createSlackScheduleCreateTaskTool(context) {
8379
+ //#region src/chat/scheduled-automations/tools/create.ts
8380
+ /** Create a tool that stores a scheduled automation for the active Slack context. */
8381
+ function createSlackScheduleCreateAutomationTool(context) {
8382
8382
  return zodTool({
8383
8383
  approvalMode: "review",
8384
8384
  annotations: {
@@ -8390,19 +8390,19 @@ function createSlackScheduleCreateTaskTool(context) {
8390
8390
  description: "Create a one-time or recurring Junior task in the active Slack conversation when the user asks Junior to do work later or repeatedly.",
8391
8391
  executionMode: "sequential",
8392
8392
  inputSchema: z.object({
8393
- task: z.string().min(1).max(4e3),
8393
+ instruction: z.string().min(1).max(4e3),
8394
8394
  title: z.string().trim().min(1).max(60).nullable().describe("Optional short display title. Omit or use null to generate one from the task instruction.").optional(),
8395
8395
  schedule: scheduleIntentSchema.describe("When the task runs. The scheduler computes the exact next run from this intent and the server clock."),
8396
- outcomes: z.array(taskOutcomeInputSchema).max(5).describe("Messages to send after successful work. Use an empty list to send nothing. Omit to send one message to the current Slack conversation.").optional(),
8397
- credential_mode: z.enum(["creator", "system"]).nullable().describe("Use creator to make the task creator's connected credentials available, or system when the creator says not to use them. Omit or use null for the creator default.").optional()
8396
+ outcomes: z.array(taskOutcomeInputSchema).max(5).describe("Successful work is silent by default. Omit this field or use an empty list when the Automation should act through tools without a status message. Add send_message only when the user asks for a reminder, post, digest, summary, or other visible result.").optional(),
8397
+ credentialMode: z.enum(["creator", "system"]).nullable().describe("Use creator to make the task creator's connected credentials available, or system when the creator says not to use them. Omit or use null for the creator default.").optional()
8398
8398
  }).strict(),
8399
8399
  prepareArguments(args) {
8400
8400
  const prepared = { ...args };
8401
8401
  if (prepared.title == null) delete prepared.title;
8402
- if (prepared.credential_mode === "creator" || prepared.credential_mode === null) delete prepared.credential_mode;
8402
+ if (prepared.credentialMode === "creator" || prepared.credentialMode === null) delete prepared.credentialMode;
8403
8403
  return prepared;
8404
8404
  },
8405
- outputSchema: scheduleTaskToolResultSchema,
8405
+ outputSchema: scheduleAutomationToolResultSchema,
8406
8406
  execute: async (input, options) => {
8407
8407
  const destination = requireActiveConversation(context);
8408
8408
  const actor = requireActor(context, destination);
@@ -8412,13 +8412,13 @@ function createSlackScheduleCreateTaskTool(context) {
8412
8412
  toolCallId: options.toolCallId
8413
8413
  });
8414
8414
  const db = getDb();
8415
- const existing = await readScheduledTask(db, id);
8415
+ const existing = await readScheduledAutomation(db, id);
8416
8416
  if (existing) {
8417
- if (!sameDestination(existing, destination) || existing.createdBy.slackUserId !== actor.slackUserId) throwToolInputError("Scheduled task operation identity is invalid.");
8418
- return scheduleTaskToolResult("slackScheduleCreateTask", compactTask(existing));
8417
+ if (!sameDestination(existing, destination) || existing.createdBy.slackUserId !== actor.slackUserId) throwToolInputError("Scheduled automation operation identity is invalid.");
8418
+ return scheduleAutomationToolResult(existing, actor.slackUserId);
8419
8419
  }
8420
8420
  const identity = (await context.users.resolveActor())?.identity;
8421
- if (!identity || identity.provider !== "slack" || identity.providerTenantId !== destination.teamId || identity.providerSubjectId !== actor.slackUserId) throwToolInputError("Scheduled task creator identity is unavailable.");
8421
+ if (!identity || identity.provider !== "slack" || identity.providerTenantId !== destination.teamId || identity.providerSubjectId !== actor.slackUserId) throwToolInputError("Scheduled automation creator identity is unavailable.");
8422
8422
  const nowMs = context.now?.() ?? Date.now();
8423
8423
  let compiled;
8424
8424
  try {
@@ -8434,7 +8434,7 @@ function createSlackScheduleCreateTaskTool(context) {
8434
8434
  const conversationAccess = getConversationAccess(destination, context.source);
8435
8435
  const title = await resolveTaskTitle({
8436
8436
  completeText,
8437
- instruction: input.task,
8437
+ instruction: input.instruction,
8438
8438
  title: input.title
8439
8439
  });
8440
8440
  const task = {
@@ -8444,28 +8444,28 @@ function createSlackScheduleCreateTaskTool(context) {
8444
8444
  createdBy: actor,
8445
8445
  creatorIdentityId: identity.id,
8446
8446
  conversationAccess,
8447
- credentialMode: input.credential_mode ?? "creator",
8447
+ credentialMode: input.credentialMode ?? "creator",
8448
8448
  destination,
8449
- executionActor: SCHEDULED_TASK_SYSTEM_ACTOR,
8449
+ executionActor: SCHEDULED_AUTOMATION_SYSTEM_ACTOR,
8450
8450
  nextRunAtMs: compiled.nextRunAtMs,
8451
8451
  originalRequest: context.userText,
8452
8452
  schedule: compiled.schedule,
8453
8453
  status: "active",
8454
8454
  outcomes: await resolveTaskOutcomes(input.outcomes, destination, actor.slackUserId),
8455
- task: { text: input.task },
8455
+ task: { text: input.instruction },
8456
8456
  ...title ? { title } : void 0
8457
8457
  };
8458
- const committed = await createScheduledTask(db, task);
8459
- if (!sameDestination(committed, destination) || committed.createdBy.slackUserId !== actor.slackUserId) throwToolInputError("Scheduled task operation identity is invalid.");
8460
- logInfo("scheduled_task.create.completed", scheduledTaskAttributes(committed));
8461
- return scheduleTaskToolResult("slackScheduleCreateTask", compactTask(committed));
8458
+ const committed = await createScheduledAutomation(db, task);
8459
+ if (!sameDestination(committed, destination) || committed.createdBy.slackUserId !== actor.slackUserId) throwToolInputError("Scheduled automation operation identity is invalid.");
8460
+ logInfo("scheduled_automation.create.completed", scheduledAutomationAttributes(committed));
8461
+ return scheduleAutomationToolResult(committed, actor.slackUserId);
8462
8462
  }
8463
8463
  });
8464
8464
  }
8465
8465
  //#endregion
8466
- //#region src/chat/scheduled-tasks/tools/delete.ts
8467
- /** Create a tool that removes a scheduled task from the active Slack conversation. */
8468
- function createSlackScheduleDeleteTaskTool(context) {
8466
+ //#region src/chat/scheduled-automations/tools/delete.ts
8467
+ /** Create a tool that removes a scheduled automation from the active Slack conversation. */
8468
+ function createSlackScheduleDeleteAutomationTool(context) {
8469
8469
  return zodTool({
8470
8470
  approvalMode: "review",
8471
8471
  annotations: {
@@ -8476,21 +8476,21 @@ function createSlackScheduleDeleteTaskTool(context) {
8476
8476
  },
8477
8477
  description: "Delete one scheduled Junior task from the active Slack conversation. Use only task IDs returned for this conversation. Do not delete schedules from threads, other channels, or another user's DM.",
8478
8478
  executionMode: "sequential",
8479
- inputSchema: z.object({ task_id: z.string().min(1).describe("ID of the task to delete. Must be from this active Slack conversation.") }),
8480
- outputSchema: scheduleTaskToolResultSchema,
8481
- execute: async ({ task_id }) => {
8479
+ inputSchema: z.object({ automationId: z.string().min(1).describe("ID of the task to delete. Must be from this active Slack conversation.") }),
8480
+ outputSchema: scheduleAutomationToolResultSchema,
8481
+ execute: async ({ automationId }) => {
8482
8482
  const next = {
8483
8483
  ...await getWritableTask({
8484
8484
  context,
8485
- taskId: task_id
8485
+ taskId: automationId
8486
8486
  }),
8487
8487
  updatedAtMs: Date.now(),
8488
8488
  status: "deleted",
8489
8489
  nextRunAtMs: void 0,
8490
8490
  runNowAtMs: void 0
8491
8491
  };
8492
- await saveScheduledTask(getDb(), next);
8493
- return scheduleTaskToolResult("slackScheduleDeleteTask", compactTask(next));
8492
+ await saveScheduledAutomation(getDb(), next);
8493
+ return scheduleAutomationToolResult(next, context.actor?.userId);
8494
8494
  }
8495
8495
  });
8496
8496
  }
@@ -8529,7 +8529,7 @@ function parseRequiredSlackUserIdParam(field, value) {
8529
8529
  };
8530
8530
  }
8531
8531
  //#endregion
8532
- //#region src/chat/scheduled-tasks/tools/list.ts
8532
+ //#region src/chat/scheduled-automations/tools/list.ts
8533
8533
  function taskMatchesQuery(task, query) {
8534
8534
  const normalized = query.toLowerCase();
8535
8535
  return [
@@ -8540,10 +8540,10 @@ function taskMatchesQuery(task, query) {
8540
8540
  task.status
8541
8541
  ].some((value) => value?.toLowerCase().includes(normalized));
8542
8542
  }
8543
- /** Create a tool that lists scheduled tasks for the active conversation or the requester. */
8544
- function createSlackScheduleListTasksTool(context) {
8543
+ /** Create a tool that lists scheduled automations for the active conversation or the requester. */
8544
+ function createSlackScheduleListAutomationsTool(context) {
8545
8545
  return zodTool({
8546
- description: "List scheduled tasks in this Slack conversation. To find one of the requester's tasks elsewhere in the workspace, pass channel_id and/or query.",
8546
+ description: "List scheduled automations in this Slack conversation. Each result says whether the requester is the creator. To find one of the requester's automations elsewhere in the workspace, pass channel_id and/or query.",
8547
8547
  annotations: {
8548
8548
  destructiveHint: false,
8549
8549
  idempotentHint: true,
@@ -8552,7 +8552,7 @@ function createSlackScheduleListTasksTool(context) {
8552
8552
  },
8553
8553
  inputSchema: z.object({
8554
8554
  channel_id: slackChannelIdParam("Current destination channel ID to filter by. Use the ID from a channel mention; do not guess.").nullable().optional(),
8555
- query: z.string().trim().min(1).max(200).nullable().describe("Text to match in the requester's scheduled tasks.").optional()
8555
+ query: z.string().trim().min(1).max(200).nullable().describe("Text to match in the requester's scheduled automations.").optional()
8556
8556
  }).strict(),
8557
8557
  outputSchema: scheduleListToolResultSchema,
8558
8558
  execute: async (input) => {
@@ -8566,7 +8566,7 @@ function createSlackScheduleListTasksTool(context) {
8566
8566
  }
8567
8567
  const query = input.query?.trim() || void 0;
8568
8568
  const crossConversation = Boolean(query) || channelId !== void 0 && channelId !== destination.channelId;
8569
- const matching = (await listScheduledTasksForTeam(getDb(), destination.teamId)).filter((task) => {
8569
+ const matching = (await listScheduledAutomationsForTeam(getDb(), destination.teamId)).filter((task) => {
8570
8570
  if (task.destination.platform !== "slack") return false;
8571
8571
  if (task.destination.teamId !== destination.teamId) return false;
8572
8572
  if (task.status === "completed") return false;
@@ -8576,19 +8576,18 @@ function createSlackScheduleListTasksTool(context) {
8576
8576
  if (query && !taskMatchesQuery(task, query)) return false;
8577
8577
  return true;
8578
8578
  }).sort((left, right) => right.createdAtMs - left.createdAtMs || right.id.localeCompare(left.id));
8579
- const visible = matching.slice(0, 50).map(compactTask);
8579
+ const visible = matching.slice(0, 50).map((task) => compactTask(task, actor.slackUserId));
8580
8580
  return scheduleListToolResult({
8581
- target: "slackScheduleListTasks",
8582
- tasks: visible,
8581
+ automations: visible,
8583
8582
  truncated: matching.length > visible.length
8584
8583
  });
8585
8584
  }
8586
8585
  });
8587
8586
  }
8588
8587
  //#endregion
8589
- //#region src/chat/scheduled-tasks/tools/run-now.ts
8590
- /** Create a tool that marks an existing scheduled task due immediately. */
8591
- function createSlackScheduleRunTaskNowTool(context) {
8588
+ //#region src/chat/scheduled-automations/tools/run-now.ts
8589
+ /** Create a tool that marks an existing scheduled automation due immediately. */
8590
+ function createSlackScheduleRunAutomationNowTool(context) {
8592
8591
  return zodTool({
8593
8592
  approvalMode: "review",
8594
8593
  annotations: {
@@ -8597,31 +8596,31 @@ function createSlackScheduleRunTaskNowTool(context) {
8597
8596
  openWorldHint: true,
8598
8597
  readOnlyHint: false
8599
8598
  },
8600
- description: "Queue an existing active scheduled Junior task to run as soon as possible, without changing its cadence. Use when the user asks to run an existing scheduled task now. Use only task IDs returned for this conversation.",
8599
+ description: "Queue an existing active scheduled Junior task to run as soon as possible, without changing its cadence. Use when the user asks to run an existing scheduled automation now. Use only task IDs returned for this conversation.",
8601
8600
  executionMode: "sequential",
8602
- inputSchema: z.object({ task_id: z.string().min(1).describe("ID of the active task to run now. Must be from this active Slack conversation.") }),
8603
- outputSchema: scheduleTaskToolResultSchema,
8604
- execute: async ({ task_id }) => {
8601
+ inputSchema: z.object({ automationId: z.string().min(1).describe("ID of the active task to run now. Must be from this active Slack conversation.") }),
8602
+ outputSchema: scheduleAutomationToolResultSchema,
8603
+ execute: async ({ automationId }) => {
8605
8604
  const lookup = await getWritableTask({
8606
8605
  context,
8607
- taskId: task_id
8606
+ taskId: automationId
8608
8607
  });
8609
- if (lookup.status !== "active") throwToolInputError("Scheduled task must be active before it can be run now.");
8608
+ if (lookup.status !== "active") throwToolInputError("Scheduled automation must be active before it can be run now.");
8610
8609
  const nowMs = Date.now();
8611
8610
  const next = {
8612
8611
  ...lookup,
8613
8612
  updatedAtMs: nowMs,
8614
8613
  runNowAtMs: nowMs
8615
8614
  };
8616
- await saveScheduledTask(getDb(), next);
8617
- return scheduleTaskToolResult("slackScheduleRunTaskNow", compactTask(next));
8615
+ await saveScheduledAutomation(getDb(), next);
8616
+ return scheduleAutomationToolResult(next, context.actor?.userId);
8618
8617
  }
8619
8618
  });
8620
8619
  }
8621
8620
  //#endregion
8622
- //#region src/chat/scheduled-tasks/tools/update.ts
8623
- /** Create a tool that edits a scheduled task, including moving it here. */
8624
- function createSlackScheduleUpdateTaskTool(context) {
8621
+ //#region src/chat/scheduled-automations/tools/update.ts
8622
+ /** Create a tool that edits a scheduled automation, including moving it here. */
8623
+ function createSlackScheduleUpdateAutomationTool(context) {
8625
8624
  return zodTool({
8626
8625
  approvalMode: "review",
8627
8626
  annotations: {
@@ -8630,37 +8629,37 @@ function createSlackScheduleUpdateTaskTool(context) {
8630
8629
  openWorldHint: true,
8631
8630
  readOnlyHint: false
8632
8631
  },
8633
- description: "Update a scheduled task. To move the requester's task into this Slack conversation, set destination to \"here\".",
8632
+ description: "Update a scheduled automation. To move the requester's task into this Slack conversation, set destination to \"here\".",
8634
8633
  executionMode: "sequential",
8635
8634
  inputSchema: z.object({
8636
- task_id: z.string().min(1).describe("Scheduled task ID returned by slackScheduleListTasks."),
8637
- task: z.string().min(1).max(4e3).optional(),
8635
+ automationId: z.string().min(1).describe("Scheduled automation ID returned by slackScheduleListAutomations."),
8636
+ instruction: z.string().min(1).max(4e3).optional(),
8638
8637
  schedule: scheduleIntentSchema.describe("Complete replacement schedule. Omit to keep it unchanged.").nullable().optional(),
8639
8638
  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(),
8640
8639
  status: z.enum(["active", "blocked"]).describe("Set active to resume a blocked task, or blocked to stop dispatch.").optional(),
8641
8640
  destination: z.literal("here").nullable().describe("Set to \"here\" to move the creator's task into this Slack conversation. Omit to keep its destination.").optional(),
8642
- credential_mode: 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()
8641
+ 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()
8643
8642
  }).strict(),
8644
- outputSchema: scheduleTaskToolResultSchema,
8643
+ outputSchema: scheduleAutomationToolResultSchema,
8645
8644
  execute: async (input) => {
8646
8645
  const activeDestination = requireActiveConversation(context);
8647
8646
  const actor = requireActor(context, activeDestination);
8648
8647
  const db = getDb();
8649
- const lookup = await readScheduledTask(db, input.task_id);
8650
- if (!lookup || lookup.status === "deleted") throwToolInputError("Scheduled task was not found.");
8651
- if (lookup.status === "completed") throwToolInputError("Completed scheduled tasks cannot be updated. Create a new task instead.");
8652
- if (lookup.destination.platform !== "slack") throwToolInputError("Scheduled task destination is invalid.");
8653
- if (lookup.destination.teamId !== activeDestination.teamId) throwToolInputError("Scheduled tasks can only be managed within the same Slack workspace.");
8648
+ const lookup = await readScheduledAutomation(db, input.automationId);
8649
+ if (!lookup || lookup.status === "deleted") throwToolInputError("Scheduled automation was not found.");
8650
+ if (lookup.status === "completed") throwToolInputError("Completed scheduled automations cannot be updated. Create a new automation instead.");
8651
+ if (lookup.destination.platform !== "slack") throwToolInputError("Scheduled automation destination is invalid.");
8652
+ if (lookup.destination.teamId !== activeDestination.teamId) throwToolInputError("Scheduled automations can only be managed within the same Slack workspace.");
8654
8653
  const moveHere = input.destination === "here";
8655
8654
  const alreadyHere = sameDestination(lookup, activeDestination);
8656
8655
  const isCreator = actor.slackUserId === lookup.createdBy.slackUserId;
8657
- if (!alreadyHere && !moveHere) throwToolInputError("Scheduled task can only be managed from the Slack destination where it currently delivers. Set destination to \"here\" to move it into this conversation.");
8658
- if (moveHere && !isCreator) throwToolInputError("Only the scheduled task creator can move this task.");
8659
- if (input.credential_mode === "creator" && !isCreator) throwToolInputError("Only the scheduled task creator can enable creator credential use.");
8660
- if (input.outcomes !== void 0 && !isCreator) throwToolInputError("Only the scheduled task creator can change message destinations.");
8656
+ if (!alreadyHere && !moveHere) throwToolInputError("Scheduled automation can only be managed from the Slack destination where it currently delivers. Set destination to \"here\" to move it into this conversation.");
8657
+ if (moveHere && !isCreator) throwToolInputError("Only the scheduled automation creator can move this task.");
8658
+ if (input.credentialMode === "creator" && !isCreator) throwToolInputError("Only the scheduled automation creator can enable creator credential use.");
8659
+ if (input.outcomes !== void 0 && !isCreator) throwToolInputError("Only the scheduled automation creator can change message destinations.");
8661
8660
  const changingDestination = moveHere && !alreadyHere;
8662
8661
  if (changingDestination) {
8663
- 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 task cannot be moved while an occurrence is already running. Try again after the current run finishes.");
8662
+ 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.");
8664
8663
  }
8665
8664
  const nowMs = context.now?.() ?? Date.now();
8666
8665
  let compiled;
@@ -8677,10 +8676,10 @@ function createSlackScheduleUpdateTaskTool(context) {
8677
8676
  const nextRunAtMs = compiled?.nextRunAtMs ?? lookup.nextRunAtMs;
8678
8677
  const status = normalizeStatus(input.status);
8679
8678
  if (input.status && !status) throwToolInputError("status must be active or blocked.");
8680
- if (status === "active" && !nextRunAtMs) throwToolInputError("Active scheduled tasks require a schedule with a future occurrence.");
8679
+ if (status === "active" && !nextRunAtMs) throwToolInputError("Active scheduled automations require a schedule with a future occurrence.");
8681
8680
  const nextStatus = status ?? lookup.status;
8682
- const credentialMode = input.task !== void 0 && input.task !== lookup.task.text && !isCreator ? "system" : input.credential_mode ?? lookup.credentialMode;
8683
- const nextInstruction = input.task !== void 0 ? input.task : lookup.task.text;
8681
+ const credentialMode = input.instruction !== void 0 && input.instruction !== lookup.task.text && !isCreator ? "system" : input.credentialMode ?? lookup.credentialMode;
8682
+ const nextInstruction = input.instruction !== void 0 ? input.instruction : lookup.task.text;
8684
8683
  const instructionChanged = nextInstruction !== lookup.task.text;
8685
8684
  const nextDestination = changingDestination ? activeDestination : lookup.destination;
8686
8685
  const next = {
@@ -8706,16 +8705,16 @@ function createSlackScheduleUpdateTaskTool(context) {
8706
8705
  if (title) next.title = title;
8707
8706
  else delete next.title;
8708
8707
  }
8709
- if (!changingDestination && !instructionChanged && !compiled && status === void 0 && (input.credential_mode === void 0 || input.credential_mode === null || input.credential_mode === lookup.credentialMode) && input.outcomes === void 0 && moveHere) return scheduleTaskToolResult("slackScheduleUpdateTask", compactTask(lookup));
8710
- const committed = await saveScheduledTask(db, next);
8711
- if (changingDestination) logInfo("scheduled_task.move.completed", scheduledTaskAttributes(committed));
8712
- return scheduleTaskToolResult("slackScheduleUpdateTask", compactTask(committed));
8708
+ if (!changingDestination && !instructionChanged && !compiled && status === void 0 && (input.credentialMode === void 0 || input.credentialMode === null || input.credentialMode === lookup.credentialMode) && input.outcomes === void 0 && moveHere) return scheduleAutomationToolResult(lookup, actor.slackUserId);
8709
+ const committed = await saveScheduledAutomation(db, next);
8710
+ if (changingDestination) logInfo("scheduled_automation.move.completed", scheduledAutomationAttributes(committed));
8711
+ return scheduleAutomationToolResult(committed, actor.slackUserId);
8713
8712
  }
8714
8713
  });
8715
8714
  }
8716
8715
  //#endregion
8717
- //#region src/chat/tools/scheduled-tasks.ts
8718
- function scheduledTaskToolContext(context) {
8716
+ //#region src/chat/tools/scheduled-automations.ts
8717
+ function scheduledAutomationToolContext(context) {
8719
8718
  if (context.source.kind !== "slack" || context.destination.platform !== "slack" || context.actor?.platform !== "slack" || !context.resolveActorIdentity) return;
8720
8719
  return {
8721
8720
  actor: context.actor,
@@ -8724,16 +8723,16 @@ function scheduledTaskToolContext(context) {
8724
8723
  ...context.userText ? { userText: context.userText } : void 0
8725
8724
  };
8726
8725
  }
8727
- /** Build scheduled-task tools for an interactive Slack actor. */
8728
- function createScheduledTaskTools(context) {
8729
- const taskContext = scheduledTaskToolContext(context);
8726
+ /** Build scheduled-automation tools for an interactive Slack actor. */
8727
+ function createScheduledAutomationTools(context) {
8728
+ const taskContext = scheduledAutomationToolContext(context);
8730
8729
  if (!taskContext) return {};
8731
8730
  return {
8732
- slackScheduleCreateTask: createSlackScheduleCreateTaskTool(taskContext),
8733
- slackScheduleListTasks: createSlackScheduleListTasksTool(taskContext),
8734
- slackScheduleUpdateTask: createSlackScheduleUpdateTaskTool(taskContext),
8735
- slackScheduleDeleteTask: createSlackScheduleDeleteTaskTool(taskContext),
8736
- slackScheduleRunTaskNow: createSlackScheduleRunTaskNowTool(taskContext)
8731
+ slackScheduleCreateAutomation: createSlackScheduleCreateAutomationTool(taskContext),
8732
+ slackScheduleListAutomations: createSlackScheduleListAutomationsTool(taskContext),
8733
+ slackScheduleUpdateAutomation: createSlackScheduleUpdateAutomationTool(taskContext),
8734
+ slackScheduleDeleteAutomation: createSlackScheduleDeleteAutomationTool(taskContext),
8735
+ slackScheduleRunAutomationNow: createSlackScheduleRunAutomationNowTool(taskContext)
8737
8736
  };
8738
8737
  }
8739
8738
  //#endregion
@@ -9147,6 +9146,34 @@ function createSlackChannelListMessagesTool(context) {
9147
9146
  });
9148
9147
  }
9149
9148
  //#endregion
9149
+ //#region src/chat/slack/tools/conversation-brief-search.ts
9150
+ /** Create Slack-owned filtering and match details for Brief search. */
9151
+ function createSlackConversationBriefSearchPort(teamId) {
9152
+ return {
9153
+ channelFilterSchema: slackChannelRefParam,
9154
+ async resolveChannel(input) {
9155
+ return (await resolveSlackChannelRef({
9156
+ field: "channel_id",
9157
+ value: input,
9158
+ teamId
9159
+ })).channelId;
9160
+ },
9161
+ async describeMatch(match) {
9162
+ const reference = parseSlackThreadId(match.conversationId);
9163
+ if (!reference || reference.channelId !== match.providerDestinationId) return {};
9164
+ const permalink = await getSlackMessagePermalink({
9165
+ channelId: reference.channelId,
9166
+ messageTs: reference.threadTs
9167
+ });
9168
+ return {
9169
+ channel_id: reference.channelId,
9170
+ ...match.channelName ? { channel_name: match.channelName } : void 0,
9171
+ ...permalink ? { permalink } : void 0
9172
+ };
9173
+ }
9174
+ };
9175
+ }
9176
+ //#endregion
9150
9177
  //#region src/chat/conversations/tool-source.ts
9151
9178
  /** Deferred tool catalog source for retained Junior conversations. */
9152
9179
  const CONVERSATIONS_TOOL_SOURCE = {
@@ -9155,8 +9182,8 @@ const CONVERSATIONS_TOOL_SOURCE = {
9155
9182
  };
9156
9183
  //#endregion
9157
9184
  //#region src/chat/slack/tools/conversation-message-search.ts
9158
- const DEFAULT_LIMIT$2 = 20;
9159
- const MAX_LIMIT$1 = 50;
9185
+ const DEFAULT_LIMIT$3 = 20;
9186
+ const MAX_LIMIT$2 = 50;
9160
9187
  const conversationMessageSearchOutputSchema = juniorToolOutputSchema.extend({
9161
9188
  after: z.string().datetime().optional(),
9162
9189
  annotation: z.string().min(1).optional(),
@@ -9176,17 +9203,17 @@ const conversationMessageSearchOutputSchema = juniorToolOutputSchema.extend({
9176
9203
  thread_ts: z.string().min(1)
9177
9204
  }).strict())
9178
9205
  });
9179
- function parseTimestamp(field, value) {
9206
+ function parseTimestamp$1(field, value) {
9180
9207
  if (value == null || value.trim() === "") return;
9181
9208
  const parsed = Date.parse(value);
9182
9209
  if (!Number.isFinite(parsed)) throw new ToolInputError(`${field} must be a valid ISO-8601 timestamp`);
9183
9210
  return parsed;
9184
9211
  }
9185
- async function resolveSearchFilters(input) {
9212
+ async function resolveSearchFilters$1(input) {
9186
9213
  const query = input.query?.trim() || void 0;
9187
9214
  const annotation = input.annotation?.trim() || void 0;
9188
- const afterMs = parseTimestamp("after", input.after);
9189
- const beforeMs = parseTimestamp("before", input.before);
9215
+ const afterMs = parseTimestamp$1("after", input.after);
9216
+ const beforeMs = parseTimestamp$1("before", input.before);
9190
9217
  let channelId;
9191
9218
  if (input.channel_id != null && input.channel_id.trim() !== "") channelId = (await resolveSlackChannelRef({
9192
9219
  field: "channel_id",
@@ -9221,20 +9248,20 @@ function createSlackConversationMessageSearchTool(scope, currentConversationId)
9221
9248
  before: z.string().datetime().nullable().describe("Include conversations active before this timestamp.").optional(),
9222
9249
  channel_id: slackChannelRefParam.nullable().optional(),
9223
9250
  query: z.string().trim().min(1).max(200).nullable().describe("Words or phrase to match in message text.").optional(),
9224
- limit: z.number().int().min(1).max(MAX_LIMIT$1).describe(`Maximum conversations. Default ${DEFAULT_LIMIT$2}; max ${MAX_LIMIT$1}.`).nullable().optional()
9251
+ limit: z.number().int().min(1).max(MAX_LIMIT$2).describe(`Maximum conversations. Default ${DEFAULT_LIMIT$3}; max ${MAX_LIMIT$2}.`).nullable().optional()
9225
9252
  }).strict(),
9226
9253
  outputSchema: conversationMessageSearchOutputSchema,
9227
9254
  execute: async (input) => {
9228
9255
  const teamId = parseSlackTeamId(scope.providerTenantId);
9229
9256
  if (!teamId) throw new ToolInputError("Cannot search retained messages without a valid Slack workspace id.");
9230
- const filters = await resolveSearchFilters({
9257
+ const filters = await resolveSearchFilters$1({
9231
9258
  ...input,
9232
9259
  teamId
9233
9260
  });
9234
9261
  const matches = await getConversationMessageSearchStore().search({
9235
9262
  currentConversationId,
9236
9263
  filters,
9237
- limit: input.limit ?? DEFAULT_LIMIT$2,
9264
+ limit: input.limit ?? DEFAULT_LIMIT$3,
9238
9265
  scope
9239
9266
  });
9240
9267
  const matchesOutput = await Promise.all(matches.map(async (match) => {
@@ -9270,7 +9297,7 @@ function createSlackConversationMessageSearchTool(scope, currentConversationId)
9270
9297
  }
9271
9298
  //#endregion
9272
9299
  //#region src/chat/slack/tools/public-search.ts
9273
- const DEFAULT_LIMIT$1 = 10;
9300
+ const DEFAULT_LIMIT$2 = 10;
9274
9301
  const DEFAULT_CONTENT_TYPES = ["messages"];
9275
9302
  const CONTENT_TYPES = [
9276
9303
  "messages",
@@ -9533,7 +9560,7 @@ function createSlackPublicSearchTool(actionToken) {
9533
9560
  channel_types: ["public_channel"],
9534
9561
  content_types: normalizedContentTypes,
9535
9562
  include_bots: true,
9536
- limit: limit ?? DEFAULT_LIMIT$1,
9563
+ limit: limit ?? DEFAULT_LIMIT$2,
9537
9564
  ...normalizedAfter !== void 0 ? { after: normalizedAfter } : void 0,
9538
9565
  ...normalizedBefore !== void 0 ? { before: normalizedBefore } : void 0,
9539
9566
  ...cursor ? { cursor } : void 0,
@@ -11709,8 +11736,8 @@ function createLoadAttachmentTool(args) {
11709
11736
  }
11710
11737
  //#endregion
11711
11738
  //#region src/chat/tools/search-conversation-events.ts
11712
- const DEFAULT_LIMIT = 25;
11713
- const MAX_LIMIT = 100;
11739
+ const DEFAULT_LIMIT$1 = 25;
11740
+ const MAX_LIMIT$1 = 100;
11714
11741
  const MAX_EVENT_DATA_BYTES = 4e3;
11715
11742
  const MAX_EVENTS_JSON_BYTES = 2e4;
11716
11743
  const MAX_IDENTITY_CHARS = 256;
@@ -11746,7 +11773,7 @@ function createSearchConversationEventsTool(context) {
11746
11773
  conversation_id: z.string().trim().min(1).nullable().describe("Conversation ID to search. Omit or null for the current conversation.").optional(),
11747
11774
  after_seq: z.number().int().nonnegative().nullable().describe("Exclusive event sequence lower bound; returns ascending.").optional(),
11748
11775
  before_seq: z.number().int().nonnegative().nullable().describe("Exclusive event sequence upper bound.").optional(),
11749
- limit: z.number().int().min(1).max(MAX_LIMIT).nullable().describe(`Maximum events. Default ${DEFAULT_LIMIT}; max ${MAX_LIMIT}.`).optional(),
11776
+ limit: z.number().int().min(1).max(MAX_LIMIT$1).nullable().describe(`Maximum events. Default ${DEFAULT_LIMIT$1}; max ${MAX_LIMIT$1}.`).optional(),
11750
11777
  types: z.array(knownEventTypeSchema).min(1).nullable().describe("Event types to include; omit for all types.").optional()
11751
11778
  }).strict(),
11752
11779
  outputSchema: searchConversationEventsOutputSchema,
@@ -11755,7 +11782,7 @@ function createSearchConversationEventsTool(context) {
11755
11782
  const conversationId = input.conversation_id?.trim() || currentConversationId;
11756
11783
  const afterSeq = input.after_seq ?? void 0;
11757
11784
  const beforeSeq = input.before_seq ?? void 0;
11758
- const limit = input.limit ?? DEFAULT_LIMIT;
11785
+ const limit = input.limit ?? DEFAULT_LIMIT$1;
11759
11786
  const types = input.types ?? void 0;
11760
11787
  if (afterSeq !== void 0 && beforeSeq !== void 0 && afterSeq >= beforeSeq) throw new ToolInputError("after_seq must be less than before_seq when both are provided");
11761
11788
  const conversationStore = getConversationStore();
@@ -11919,6 +11946,183 @@ function stripReplacementHistoryField(value) {
11919
11946
  };
11920
11947
  }
11921
11948
  //#endregion
11949
+ //#region src/chat/briefs/search.ts
11950
+ /** Search the latest Brief of each public root Conversation in one scope. */
11951
+ async function searchConversationBriefs(db, args) {
11952
+ const query = args.filters.query?.trim() || void 0;
11953
+ const tsquery = query ? sql`websearch_to_tsquery('english', ${query})` : void 0;
11954
+ const briefs = juniorConversationBriefs;
11955
+ const newer = alias(juniorConversationBriefs, "newer_briefs");
11956
+ const searchVector = sql`to_tsvector('english', ${briefs.searchText})`;
11957
+ const rank = tsquery ? sql`ts_rank_cd(${searchVector}, ${tsquery})` : sql`1`;
11958
+ const excerpt = tsquery ? sql`ts_headline('english', ${briefs.searchText}, ${tsquery}, 'MaxFragments=2, MinWords=8, MaxWords=40, FragmentDelimiter=" … ", StartSel=**, StopSel=**')` : sql`${briefs.content}->>'summary'`;
11959
+ const outcomeStatus = sql`${briefs.content}->'outcome'->>'status'`;
11960
+ const conditions = [
11961
+ notExists(db.select({ one: sql`1` }).from(newer).where(and(eq(newer.conversationId, briefs.conversationId), gt(newer.version, briefs.version)))),
11962
+ isNull(juniorConversations.parentConversationId),
11963
+ ne(juniorConversations.conversationId, args.currentConversationId),
11964
+ eq(juniorDestinations.visibility, "public")
11965
+ ];
11966
+ if (args.scope.kind === "public_provider_tenant") conditions.push(eq(juniorConversations.source, args.scope.provider), eq(juniorDestinations.provider, args.scope.provider), eq(juniorDestinations.providerTenantId, args.scope.providerTenantId));
11967
+ if (tsquery) conditions.push(sql`${searchVector} @@ ${tsquery}`);
11968
+ if (args.filters.channelId) conditions.push(eq(juniorDestinations.providerDestinationId, args.filters.channelId));
11969
+ if (args.filters.status) conditions.push(sql`${outcomeStatus} = ${args.filters.status}`);
11970
+ if (args.filters.afterMs !== void 0) conditions.push(gte(briefs.createdAt, new Date(args.filters.afterMs)));
11971
+ if (args.filters.beforeMs !== void 0) conditions.push(lt(briefs.createdAt, new Date(args.filters.beforeMs)));
11972
+ if (args.filters.annotation) {
11973
+ const annotation = args.filters.annotation.toLowerCase();
11974
+ const nestedAnnotationPrefix = `${annotation}#`;
11975
+ conditions.push(sql`exists (
11976
+ select 1
11977
+ from ${juniorConversationAnnotations}
11978
+ where ${and(eq(juniorConversationAnnotations.conversationId, juniorConversations.conversationId), sql`(
11979
+ lower(${juniorConversationAnnotations.key}) = ${annotation}
11980
+ or starts_with(
11981
+ lower(${juniorConversationAnnotations.key}),
11982
+ ${nestedAnnotationPrefix}
11983
+ )
11984
+ )`)}
11985
+ )`);
11986
+ }
11987
+ return (await db.select({
11988
+ channelName: juniorDestinations.displayName,
11989
+ content: briefs.content,
11990
+ conversationId: juniorConversations.conversationId,
11991
+ excerpt: excerpt.as("excerpt"),
11992
+ providerDestinationId: juniorDestinations.providerDestinationId,
11993
+ rank: rank.as("rank"),
11994
+ title: juniorConversations.title,
11995
+ updatedAt: briefs.createdAt,
11996
+ version: briefs.version
11997
+ }).from(briefs).innerJoin(juniorConversations, eq(juniorConversations.conversationId, briefs.conversationId)).innerJoin(juniorDestinations, eq(juniorDestinations.id, juniorConversations.destinationId)).where(and(...conditions)).orderBy(desc(rank), desc(briefs.createdAt)).limit(args.limit)).map((row) => {
11998
+ const content = conversationBriefSchema.parse(row.content);
11999
+ return {
12000
+ conversationId: row.conversationId,
12001
+ excerpt: row.excerpt,
12002
+ links: content.links.slice(0, 5),
12003
+ outcomeStatus: content.outcome.status,
12004
+ providerDestinationId: row.providerDestinationId,
12005
+ summary: content.summary,
12006
+ updatedAtMs: row.updatedAt.getTime(),
12007
+ version: row.version,
12008
+ ...row.channelName ? { channelName: row.channelName } : void 0,
12009
+ ...row.title ? { title: row.title } : void 0
12010
+ };
12011
+ });
12012
+ }
12013
+ //#endregion
12014
+ //#region src/chat/tools/search-conversation-briefs.ts
12015
+ const DEFAULT_LIMIT = 10;
12016
+ const MAX_LIMIT = 25;
12017
+ const conversationBriefSearchOutputSchema = juniorToolOutputSchema.extend({
12018
+ after: z.string().datetime().optional(),
12019
+ annotation: z.string().min(1).optional(),
12020
+ before: z.string().datetime().optional(),
12021
+ channel_id: z.string().min(1).optional(),
12022
+ count: z.number().int().nonnegative(),
12023
+ matches: z.array(z.object({
12024
+ channel_id: z.string().min(1).optional(),
12025
+ channel_name: z.string().min(1).optional(),
12026
+ conversation_id: z.string().min(1),
12027
+ dashboard_url: z.string().url().optional(),
12028
+ excerpt: z.string(),
12029
+ links: z.array(briefLinkSchema).max(5),
12030
+ permalink: z.string().url().optional(),
12031
+ status: briefOutcomeStatusSchema,
12032
+ summary: z.string().min(1),
12033
+ title: z.string().min(1).optional(),
12034
+ updated_at: z.string().datetime(),
12035
+ version: z.number().int().positive()
12036
+ }).strict()),
12037
+ query: z.string().optional(),
12038
+ status: briefOutcomeStatusSchema.optional()
12039
+ });
12040
+ function parseTimestamp(field, value) {
12041
+ if (value == null || value.trim() === "") return void 0;
12042
+ const parsed = Date.parse(value);
12043
+ if (!Number.isFinite(parsed)) throw new ToolInputError(`${field} must be a valid ISO-8601 timestamp`);
12044
+ return parsed;
12045
+ }
12046
+ async function resolveSearchFilters(input, provider) {
12047
+ const query = input.query?.trim() || void 0;
12048
+ const annotation = input.annotation?.trim() || void 0;
12049
+ const afterMs = parseTimestamp("after", input.after);
12050
+ const beforeMs = parseTimestamp("before", input.before);
12051
+ let channelId;
12052
+ if (typeof input.channel_id === "string" && input.channel_id.trim() !== "") {
12053
+ if (!provider) throw new ToolInputError("channel_id is not available in this conversation.");
12054
+ channelId = await provider.resolveChannel(input.channel_id);
12055
+ }
12056
+ if (afterMs !== void 0 && beforeMs !== void 0 && afterMs >= beforeMs) throw new ToolInputError("`after` must be earlier than `before`");
12057
+ return {
12058
+ ...afterMs !== void 0 ? { afterMs } : void 0,
12059
+ ...annotation ? { annotation } : void 0,
12060
+ ...beforeMs !== void 0 ? { beforeMs } : void 0,
12061
+ ...channelId ? { channelId } : void 0,
12062
+ ...query ? { query } : void 0,
12063
+ ...input.status ? { status: input.status } : void 0
12064
+ };
12065
+ }
12066
+ /** Create a deferred tool that searches the latest public Conversation Briefs. */
12067
+ function createSearchConversationBriefsTool(scope, currentConversationId, provider) {
12068
+ return zodTool({
12069
+ description: "Search Briefs from past public conversations. Briefs preserve intent, outcomes, decisions, facts, and links after transcripts expire. Use this before searchConversationMessages for questions such as what was decided or which pull request handled the work.",
12070
+ exposure: "deferred",
12071
+ source: CONVERSATIONS_TOOL_SOURCE,
12072
+ annotations: {
12073
+ destructiveHint: false,
12074
+ idempotentHint: true,
12075
+ openWorldHint: false,
12076
+ readOnlyHint: true
12077
+ },
12078
+ inputSchema: z.object({
12079
+ after: z.string().datetime().nullable().describe("Include Briefs updated at or after this timestamp.").optional(),
12080
+ annotation: z.string().trim().min(1).max(256).nullable().describe("Linked resource key. Matches that key, or nested children that continue with #.").optional(),
12081
+ before: z.string().datetime().nullable().describe("Include Briefs updated before this timestamp.").optional(),
12082
+ ...provider ? { channel_id: provider.channelFilterSchema.nullable().optional() } : void 0,
12083
+ limit: z.number().int().min(1).max(MAX_LIMIT).nullable().describe(`Maximum conversations. Default ${DEFAULT_LIMIT}; max ${MAX_LIMIT}.`).optional(),
12084
+ query: z.string().trim().min(1).max(200).nullable().describe("Words or phrase to match in current Briefs.").optional(),
12085
+ status: briefOutcomeStatusSchema.nullable().describe("Current Brief outcome status.").optional()
12086
+ }).strict(),
12087
+ outputSchema: conversationBriefSearchOutputSchema,
12088
+ execute: async (input) => {
12089
+ const filters = await resolveSearchFilters(input, provider);
12090
+ const matches = await searchConversationBriefs(getDb(), {
12091
+ currentConversationId,
12092
+ filters,
12093
+ limit: input.limit ?? DEFAULT_LIMIT,
12094
+ scope
12095
+ });
12096
+ const outputMatches = await Promise.all(matches.map(async (match) => {
12097
+ const providerFields = provider ? await provider.describeMatch(match) : void 0;
12098
+ const dashboardUrl = getDashboardConversationLink(match.conversationId);
12099
+ return {
12100
+ conversation_id: match.conversationId,
12101
+ status: match.outcomeStatus,
12102
+ updated_at: new Date(match.updatedAtMs).toISOString(),
12103
+ version: match.version,
12104
+ summary: match.summary,
12105
+ excerpt: match.excerpt,
12106
+ links: match.links,
12107
+ ...match.title ? { title: match.title } : void 0,
12108
+ ...dashboardUrl ? { dashboard_url: dashboardUrl } : void 0,
12109
+ ...providerFields
12110
+ };
12111
+ }));
12112
+ return {
12113
+ ...filters.afterMs !== void 0 ? { after: new Date(filters.afterMs).toISOString() } : void 0,
12114
+ ...filters.annotation ? { annotation: filters.annotation } : void 0,
12115
+ ...filters.beforeMs !== void 0 ? { before: new Date(filters.beforeMs).toISOString() } : void 0,
12116
+ ...filters.channelId ? { channel_id: filters.channelId } : void 0,
12117
+ ...filters.query ? { query: filters.query } : void 0,
12118
+ ...filters.status ? { status: filters.status } : void 0,
12119
+ count: outputMatches.length,
12120
+ matches: outputMatches
12121
+ };
12122
+ }
12123
+ });
12124
+ }
12125
+ //#endregion
11922
12126
  //#region src/chat/tools/handoff/tool.ts
11923
12127
  const HANDOFF_TOOL_NAME = "handoff";
11924
12128
  function formatHandoffProfiles(handoff) {
@@ -12595,7 +12799,7 @@ async function tryRecordWorkspaceSwitchStat(workspace) {
12595
12799
  }
12596
12800
  async function stopWorkspaceSnapshotWatch(input) {
12597
12801
  try {
12598
- await cancelResourceEventSubscription({
12802
+ await cancelWatch({
12599
12803
  conversationId: input.conversationId,
12600
12804
  id: input.subscriptionId
12601
12805
  });
@@ -12792,7 +12996,7 @@ function createWorkspaceTools(context) {
12792
12996
  outputSchema: juniorToolOutputSchema.extend({
12793
12997
  workspace: workspaceSchema,
12794
12998
  status: z.enum(["ready", "building"]),
12795
- subscription: resourceEventSubscriptionResultSchema.optional().describe("Present when the snapshot ready and failed events are already watched for this conversation.")
12999
+ subscription: watchResultSchema.optional().describe("Present when the snapshot ready and failed events are already watched for this conversation.")
12796
13000
  }),
12797
13001
  async execute({ name }, options) {
12798
13002
  const workspace = await getWorkspaceByName(getDb(), name);
@@ -12802,7 +13006,7 @@ function createWorkspaceTools(context) {
12802
13006
  workspaceName: workspace.name
12803
13007
  });
12804
13008
  const conversationId = context.conversationId.trim();
12805
- const subscription = conversationId ? await createResourceEventSubscription({
13009
+ const subscription = conversationId ? await createWatch({
12806
13010
  conversationId,
12807
13011
  events: [WORKSPACE_SNAPSHOT_READY_EVENT, WORKSPACE_SNAPSHOT_FAILED_EVENT],
12808
13012
  expiresAtMs: Date.now() + RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS,
@@ -12867,7 +13071,7 @@ function createTools(availableSkills, hooks = {}, context, options = {}) {
12867
13071
  const slackContext = getSlackToolContext(context);
12868
13072
  const slackLocationCapabilities = slackContext ? resolveChannelCapabilities(slackContext.locationChannelId) : void 0;
12869
13073
  const canSendFilesToActiveConversation = Boolean(slackContext && slackLocationCapabilities?.canSendFiles);
12870
- const resourceEventCatalog = getResourceEventCatalog();
13074
+ const eventCatalog = getEventCatalog();
12871
13075
  const tools = {
12872
13076
  ...options.includeLoadSkill === false ? void 0 : { loadSkill: createLoadSkillTool(availableSkills, { onSkillLoaded: hooks.onSkillLoaded }) },
12873
13077
  reportProgress: createReportProgressTool(),
@@ -12881,12 +13085,17 @@ function createTools(availableSkills, hooks = {}, context, options = {}) {
12881
13085
  writeFile: createWriteFileTool(),
12882
13086
  webSearch: createWebSearchTool(botConfig.webSearchModelId, hooks.toolOverrides?.webSearch),
12883
13087
  webFetch: createWebFetchTool(hooks, { canSendFilesToActiveConversation }),
12884
- ...createResourceEventTools(context, resourceEventCatalog),
12885
- ...createEventTaskTools(context, resourceEventCatalog),
12886
- ...createScheduledTaskTools(context),
13088
+ ...createEventTools(context, eventCatalog),
13089
+ ...createEventAutomationTools(context, eventCatalog),
13090
+ ...createScheduledAutomationTools(context),
12887
13091
  ...createWorkspaceTools(context)
12888
13092
  };
12889
13093
  tools.searchConversationEvents = createSearchConversationEventsTool(context);
13094
+ if (context.conversationPrivacy === "public") tools.searchConversationBriefs = createSearchConversationBriefsTool(slackContext ? {
13095
+ kind: "public_provider_tenant",
13096
+ provider: "slack",
13097
+ providerTenantId: slackContext.teamId
13098
+ } : { kind: "public" }, context.conversationId, slackContext ? createSlackConversationBriefSearchPort(slackContext.teamId) : void 0);
12890
13099
  if (context.supportsImageInput) tools.viewImage = createViewImageTool(context.workspace, context.supportsImageInput, hooks.toolOverrides?.viewImage);
12891
13100
  if (hooks.writeGeneratedArtifacts) tools.imageGenerate = createImageGenerateTool({ writeGeneratedArtifacts: hooks.writeGeneratedArtifacts }, {
12892
13101
  modelId: botConfig.imageGenerationModelId,
@@ -15254,7 +15463,7 @@ Assess the exact action's intrinsic risk and whether the user's intent authorize
15254
15463
  ## Data Exfiltration
15255
15464
  - Sending private data, organization data, secrets, or credentials to an untrusted destination is high or critical risk.
15256
15465
  - A user-requested read, query, or upload to a trusted destination is not exfiltration by default.
15257
- - The active Junior conversation is not an untrusted destination merely because it is a public or multi-user channel. For a scheduled task or event task, a request by the current actor for scoped work that needs their connected service access authorizes routine service-native reads and posting the requested result to the task's stored Slack destination. It does not authorize exposing credential values, broad data dumps, or delivery to another destination.
15466
+ - The active Junior conversation is not an untrusted destination merely because it is a public or multi-user channel. For a scheduled automation or event automation, a request by the current actor for scoped work that needs their connected service access authorizes routine service-native reads and posting the requested result to the task's stored Slack destination. It does not authorize exposing credential values, broad data dumps, or delivery to another destination.
15258
15467
  - Using an existing credential to authenticate a user-requested action is not credential exfiltration by itself.
15259
15468
  - Ordinary product context such as internal system names, repository names, or workflow descriptions is not private organization data by itself, including on an authorized public write destination.
15260
15469
  - Deny disclosure of secrets, credentials, or private organization data to an untrusted destination even when the user requested it.
@@ -15548,9 +15757,9 @@ function resolveToolRuntimeRoute(args) {
15548
15757
  actor: args.actor?.platform === "web" ? args.actor : void 0,
15549
15758
  source: args.run.source
15550
15759
  };
15551
- case "resource_event":
15552
- case "scheduled_task":
15553
- case "event_task":
15760
+ case "event":
15761
+ case "scheduled_automation":
15762
+ case "event_automation":
15554
15763
  case "plugin_dispatch":
15555
15764
  case "agent_invocation": return {
15556
15765
  destination,
@@ -17518,4 +17727,4 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
17518
17727
  }
17519
17728
  }
17520
17729
  //#endregion
17521
- export { buildSteeringPiMessage as $, createAgentInvocationSchema as A, renderTaskInput as B, renderBlockText as C, getNextRunAtMs as D, scheduledTaskRunAttributes as E, ingestResourceEvent as F, shouldPropagateSandboxEgressTrace as G, recordFinishedTurnForAutomatedLimit as H, isResourceEventMailboxMetadata as I, consumeSandboxEgressAuthRequiredSignal as J, SANDBOX_EGRESS_PROXY_PATH as K, RESOURCE_EVENT_MESSAGE_AUTHOR as L, AgentInvocationLimitError as M, getMcpProviderErrorAttributes as N, agentBindingSchema as O, processWorkspaceSnapshotJob as P, createUserTokenStore as Q, RESOURCE_EVENT_SYSTEM_ACTOR as R, renderAttachmentText as S, logScheduledTaskRunSkipped as T, resolveSandboxEgressProviderForHost as U, maybePostAutomatedTurnLimitNotice as V, normalizeSandboxEgressTracePropagationDomains as W, parseSandboxEgressCredentialToken as X, consumeSandboxEgressPermissionDeniedSignal as Y, sandboxEgressSignalsResponseSchema as Z, readPublicArtifact as _, deleteMcpAuthSession as a, readAttachmentVisionSummary as b, deleteMcpStoredOAuthCredentials as c, putMcpStoredOAuthCredentials as d, isVisionImageMediaType as et, PluginCredentialFailureError as f, publicArtifactHeaders as g, resolvePluginOAuthAccount as h, finalizeMcpAuthorization as i, setConfigDefaults as it, AgentInvocationBusyError as j, agentInvocationSchema as k, getMcpAuthSession as l, latestReportedProgress as m, createContextCompactor as n, shouldEmitDevAgentTrace as nt, deleteMcpAuthSessionsForUserProvider as o, authorizationId as p, clearSandboxEgressSignals as q, executeCredentialedEgressRequest as r, getConfigDefaults as rt, deleteMcpServerSessionId as s, executeAgentRun as t, AuthorizationFlowDisabledError as tt, getMcpStoredOAuthCredentials as u, unpublishedArtifactHeaders as v, listThreadReplies as w, recordSlackAttachment as x, lookupSlackUserProfile as y, isResourceEventConversationMessage as z };
17730
+ export { shouldEmitDevAgentTrace as $, createAgentInvocationSchema as A, resolveSandboxEgressProviderForHost as B, renderBlockText as C, getNextRunAtMs as D, scheduledAutomationRunAttributes as E, ingestEvent as F, consumeSandboxEgressAuthRequiredSignal as G, shouldPropagateSandboxEgressTrace as H, isEventMailboxMetadata as I, sandboxEgressSignalsResponseSchema as J, consumeSandboxEgressPermissionDeniedSignal as K, renderTaskInput as L, AgentInvocationLimitError as M, getMcpProviderErrorAttributes as N, agentBindingSchema as O, processWorkspaceSnapshotJob as P, AuthorizationFlowDisabledError as Q, maybePostAutomatedTurnLimitNotice as R, renderAttachmentText as S, logScheduledAutomationRunSkipped as T, SANDBOX_EGRESS_PROXY_PATH as U, normalizeSandboxEgressTracePropagationDomains as V, clearSandboxEgressSignals as W, buildSteeringPiMessage as X, createUserTokenStore as Y, isVisionImageMediaType as Z, readPublicArtifact as _, deleteMcpAuthSession as a, readAttachmentVisionSummary as b, deleteMcpStoredOAuthCredentials as c, putMcpStoredOAuthCredentials as d, getConfigDefaults as et, PluginCredentialFailureError as f, publicArtifactHeaders as g, resolvePluginOAuthAccount as h, finalizeMcpAuthorization as i, AgentInvocationBusyError as j, agentInvocationSchema as k, getMcpAuthSession as l, latestReportedProgress as m, createContextCompactor as n, deleteMcpAuthSessionsForUserProvider as o, authorizationId as p, parseSandboxEgressCredentialToken as q, executeCredentialedEgressRequest as r, deleteMcpServerSessionId as s, executeAgentRun as t, setConfigDefaults as tt, getMcpStoredOAuthCredentials as u, unpublishedArtifactHeaders as v, listThreadReplies as w, recordSlackAttachment as x, lookupSlackUserProfile as y, recordFinishedTurnForAutomatedLimit as z };