@sentry/junior 0.234.0 → 0.236.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 (71) hide show
  1. package/dist/{agent-hooks-BcH6E48y.js → agent-hooks-Da_H0jHv.js} +17 -10
  2. package/dist/{agent-runner-DUkGlK89.js → agent-runner-uP7QRc4c.js} +484 -162
  3. package/dist/api/schema.d.ts +288 -2
  4. package/dist/api/schema.js +5 -4
  5. package/dist/api.d.ts +8 -2
  6. package/dist/api.js +524 -83
  7. package/dist/{app-xk2-Id1T.d.ts → app-MEd7wbF0.d.ts} +83 -49
  8. package/dist/app.d.ts +3 -3
  9. package/dist/app.js +164 -119
  10. package/dist/{types-Du-HbEun.js → automation-B9Kc1gcf.js} +304 -33
  11. package/dist/{briefs-lyAQbDxJ.js → briefs-DrjBPQFy.js} +4 -4
  12. package/dist/{catalog-runtime-BSgsPVnr.js → catalog-runtime-C7339Cfm.js} +1 -1
  13. package/dist/{checkpoint-BNfXlq_1.js → checkpoint-DaD7_Gsb.js} +16 -9
  14. package/dist/cli/chat.d.ts +1 -1
  15. package/dist/cli/chat.js +14 -14
  16. package/dist/cli/check.js +4 -4
  17. package/dist/cli/main.js +1 -1
  18. package/dist/cli/plugins.d.ts +1 -1
  19. package/dist/cli/plugins.js +4 -4
  20. package/dist/cli/snapshot-create.js +3 -3
  21. package/dist/cli/upgrade.d.ts +1 -1
  22. package/dist/cli/upgrade.js +5 -5
  23. package/dist/{client-BX5lJRqW.js → client-Ch9Hg9NU.js} +2 -2
  24. package/dist/{config-DuCzUoCo.js → config-JR9wke1W.js} +57 -17
  25. package/dist/{conversation-CPjHYOV5.js → conversation-9Fxa1Zbq.js} +14 -1
  26. package/dist/{conversation-privacy-CSxvdSoV.js → conversation-privacy-au02dyZK.js} +1 -1
  27. package/dist/{credential-sync-BO4DfH9a.js → credential-sync-BWTA3LnL.js} +14 -14
  28. package/dist/{executor--jWf-Nnm.js → executor-BW9XWgUQ.js} +70 -6
  29. package/dist/{images-BaL19wFC.js → images-BdG7zcNf.js} +3 -3
  30. package/dist/instrumentation.js +2 -2
  31. package/dist/{job-queue-cwHVOwVZ.js → job-queue-BqXd0ZPV.js} +1 -1
  32. package/dist/{logging-Cox1Mgcv.js → logging-B4sKwmCG.js} +1 -1
  33. package/dist/nitro.d.ts +2 -2
  34. package/dist/nitro.js +5 -5
  35. package/dist/{oauth-authorization-CC8a1JKP.js → oauth-authorization-BjRN99dc.js} +1 -1
  36. package/dist/{oauth-callback-server-Z7QSt416.js → oauth-callback-server-B_1p98Mb.js} +2 -2
  37. package/dist/{pending-auth-DQhC3eSR.js → pending-auth-WqF4Gh8Z.js} +1 -1
  38. package/dist/{plugins-BT2l4We3.d.ts → plugins-CjfUP5gJ.d.ts} +1 -0
  39. package/dist/{profile-BdApelHS.js → profile-BamYnmhO.js} +4 -4
  40. package/dist/{prompt-3D0sSbTC.js → prompt-Ctwy6hSI.js} +1 -1
  41. package/dist/queue-B5SnqRln.d.ts +25 -0
  42. package/dist/{registry-DiY6B8CN.js → registry-CXNv9fDX.js} +38 -2
  43. package/dist/{resolve-VpJoiDpc.js → resolve-C9ETkt4T.js} +2 -2
  44. package/dist/{runner-BIMegnPE.js → runner-DnBGVRnW.js} +9 -9
  45. package/dist/{sandbox-egress-signals-Cbtxe492.js → sandbox-egress-signals-DwJ7Boi_.js} +1 -1
  46. package/dist/{schema-CxwnlTDN.js → schema-CJiqDc5r.js} +26 -3
  47. package/dist/{skills-WttpPJUy.js → skills-Dd8O9Aav.js} +3 -3
  48. package/dist/{spawn-DhfMKt4y.js → spawn-DFdRspSD.js} +2 -2
  49. package/dist/{task-queue-CZqUNJD0.js → task-queue-DGQEOk1A.js} +16 -10
  50. package/dist/{task-runner-BZaqoUCT.js → task-runner-C5XCIDSF.js} +9 -9
  51. package/dist/{thread-state-8tXZhu0y.js → thread-state-D3E29wZk.js} +5 -5
  52. package/dist/{turn-failure-response-DFJ9L9NQ.js → turn-failure-response-TDoj0aZz.js} +8 -8
  53. package/dist/{turn-lifecycle-WbpTUQ_r.js → turn-lifecycle-DOnU45p7.js} +1 -1
  54. package/dist/{turn-session-routing--EhI76rH.js → turn-session-routing-DbpZZoin.js} +1 -1
  55. package/dist/{validation-0F9IgG3b.js → validation-B9lMbisx.js} +1 -1
  56. package/dist/{version-A7-RRBOE.js → version-CWkIGcLU.js} +1 -1
  57. package/dist/version.js +1 -1
  58. package/dist/{web-authorization-BJggXofy.js → web-authorization-PPaoj2ns.js} +6 -6
  59. package/dist/{web-input-B-siN5Dr.js → web-input-CfNxXtHm.js} +86 -34
  60. package/dist/web-message-id-xPI_EFSC.js +239 -0
  61. package/dist/{work-CNc0ejGG.js → work-DNaoFrEe.js} +7 -7
  62. package/dist/{worker-BHbqpUAu.js → worker-xeJLxYwm.js} +5 -5
  63. package/migrations/0045_conversation_forks.sql +3 -0
  64. package/migrations/0046_automation_versions.sql +71 -0
  65. package/migrations/meta/0045_snapshot.json +3503 -0
  66. package/migrations/meta/0046_snapshot.json +3707 -0
  67. package/migrations/meta/_journal.json +15 -1
  68. package/package.json +5 -5
  69. package/dist/web-message-id-CVVCTWUb.js +0 -464
  70. package/dist/{package-discovery-7a9YqLhE.js → package-discovery-BVvSnQBB.js} +1 -1
  71. package/dist/{plugin-module-BKGOXca2.js → plugin-module-CVvEUSMH.js} +1 -1
@@ -1,27 +1,27 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.js";
2
- import { b as getGatewayApiKey, c as hasCompactedConversationContext, d as unwrapCurrentInstruction, f as escapeXml, g as getProviderErrorAttributes, h as findProviderError, i as completeText, l as isCompactionSummaryText, m as createProviderError, n as GEN_AI_SERVER_ADDRESS, o as resolveGatewayModel, p as ProviderError, r as completeObject, s as COMPACTION_SUMMARY_PREFIX, t as GEN_AI_PROVIDER_NAME, u as renderCurrentInstruction, v as isProviderRetryError, x as resolveGatewayCredential, y as MISSING_GATEWAY_CREDENTIALS_ERROR } from "./client-BX5lJRqW.js";
3
- import { C as withLogContext, F as normalizeIdentityEmail, I as isRecord$3, L as toOptionalNumber, R as toOptionalString, a as extractGenAiUsageSummary, b as setTags, c as getLogContextAttributesForSpan, d as logException, f as logInfo, g as serializeGenAiAttribute, i as extractGenAiUsageAttributes, l as getTracePropagationHeaders, m as normalizeGenAiFinishReason, p as logWarn, s as getLogContextAttributes, u as logError, v as setSpanAttributes, w as withSpan, x as summarizeMessageText, y as setSpanStatus } from "./logging-Cox1Mgcv.js";
2
+ import { b as getGatewayApiKey, c as hasCompactedConversationContext, d as unwrapCurrentInstruction, f as escapeXml, g as getProviderErrorAttributes, h as findProviderError, i as completeText, l as isCompactionSummaryText, m as createProviderError, n as GEN_AI_SERVER_ADDRESS, o as resolveGatewayModel, p as ProviderError, r as completeObject, s as COMPACTION_SUMMARY_PREFIX, t as GEN_AI_PROVIDER_NAME, u as renderCurrentInstruction, v as isProviderRetryError, x as resolveGatewayCredential, y as MISSING_GATEWAY_CREDENTIALS_ERROR } from "./client-Ch9Hg9NU.js";
3
+ import { C as withLogContext, F as normalizeIdentityEmail, I as isRecord$3, L as toOptionalNumber, R as toOptionalString, a as extractGenAiUsageSummary, b as setTags, c as getLogContextAttributesForSpan, d as logException, f as logInfo, g as serializeGenAiAttribute, i as extractGenAiUsageAttributes, l as getTracePropagationHeaders, m as normalizeGenAiFinishReason, p as logWarn, s as getLogContextAttributes, u as logError, v as setSpanAttributes, w as withSpan, x as summarizeMessageText, y as setSpanStatus } from "./logging-B4sKwmCG.js";
4
4
  import { m as startInactiveSpan, n as captureMessage, v as withActiveSpan } from "./sentry-CgWZM_kV.js";
5
- import { a as toCanonicalInputMessage, c as toGenAiPayloadMetadata, i as runWithConversationPrivacy, l as toGenAiPayloadTraceAttributes, o as toCanonicalOutputMessage, r as resolveConversationPrivacy, s as toGenAiMessagesTraceAttributes, t as canExposeConversationPayload } from "./conversation-privacy-CSxvdSoV.js";
6
- import { a as getChatConfig, h as normalizeSlackEmojiName, n as botConfig } from "./config-DuCzUoCo.js";
5
+ import { a as toCanonicalInputMessage, c as toGenAiPayloadMetadata, i as runWithConversationPrivacy, l as toGenAiPayloadTraceAttributes, o as toCanonicalOutputMessage, r as resolveConversationPrivacy, s as toGenAiMessagesTraceAttributes, t as canExposeConversationPayload } from "./conversation-privacy-au02dyZK.js";
6
+ import { i as getChatConfig, n as botConfig, v as normalizeSlackEmojiName } from "./config-JR9wke1W.js";
7
7
  import { a as formatModelProfiles, c as profileConfig, i as formatModelProfile, l as TURN_REASONING_LEVELS, n as ModelProfileNotConfiguredError, o as modelIdForProfile, s as modelProfileSchema } from "./model-profile-BwU8mqwD.js";
8
8
  import { b as parseSlackMessageTs, d as parseStoredSlackActor, g as parseSlackUserId, h as parseSlackTeamId, i as credentialUserSubjectId, l as isUserActor, m as parseSlackChannelReferenceId, n as credentialContextSchema, p as parseSlackChannelId, t as credentialContextForActor } from "./context-0Et9iVSB.js";
9
- import { $t as getConversationStore, A as tryWorkspaceRepoCheckoutPath, B as downloadPrivateSlackFile, C as invalidateReadySnapshot, Ct as createPluginLogger, D as SANDBOX_RUNTIME, E as setWorkspaceSnapshotBuild, G as isDmChannel$1, Ht as saveObjectAnnotations, J as withSlackRetries, K as normalizeSlackConversationId, M as resolveChannelCapabilities, O as deleteWorkspaceSnapshotBuilders, Q as readActorIdentity, Qt as getConversationMessageSearchStore, Rt as matchSlackAttachments, S as WorkspaceValidationError, T as setWorkspaceSnapshot, U as getSlackClient, Ut as createPluginAnnotations, V as getFilePermalink, W as isConversationScopedChannel, Zt as getConversationEventStore, _ as deleteWorkspace, at as STOP_WATCHING_TOOL_NAME, b as listWorkspaces, bn as sameDestination$1, c as getPluginTools, cn as addAgentTurnUsage, dt as deliverWatch, en as getDb, fn as hasAgentTurnUsage, ft as findMatchingWatches, g as createWorkspace, gt as getDashboardConversationLink, ht as JUNIOR_THREAD_STATE_TTL_MS, it as RESOURCE_WATCH_TOOL_SOURCE, j as workspaceRepoCheckoutPath, k as getWorkspaceSnapshotBuilder, l as getPluginUserPromptContributions, lt as createTimerWatch, n as applyPluginFormatMarkdown, nt as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, ot as cancelSubscriptions, pt as listWatches, r as createPluginHookRunner, rt as RESOURCE_SUBSCRIPTION_MAX_TTL_MS, s as getPluginSystemPromptContributions, st as cancelWatch, tn as getSqlExecutor, tt as getSlackToolContext, u as getPlugins, ut as createWatch, v as getWorkspace, vn as parseDestination, vt as getDashboardTaskLink, w as loadSnapshotsForProfile, x as updateWorkspace, y as getWorkspaceByName, z as SlackActionError } from "./agent-hooks-BcH6E48y.js";
9
+ import { $ as readActorIdentity, $t as getConversationMessageSearchStore, A as getWorkspaceSnapshotBuilder, B as SlackActionError, C as WorkspaceValidationError, D as setWorkspaceSnapshotBuild, E as setWorkspaceSnapshot, G as isConversationScopedChannel, H as getFilePermalink, K as isDmChannel$1, M as workspaceRepoCheckoutPath, N as resolveChannelCapabilities, O as SANDBOX_RUNTIME, Qt as getConversationEventStore, S as updateWorkspace, T as loadSnapshotsForProfile, Ut as saveObjectAnnotations, V as downloadPrivateSlackFile, W as getSlackClient, Wt as createPluginAnnotations, Y as withSlackRetries, _ as deleteWorkspace, _t as getDashboardConversationLink, at as RESOURCE_WATCH_TOOL_SOURCE, b as listWorkspaces, c as getPluginTools, ct as cancelWatch, dt as createWatch, en as getConversationStore, ft as deliverWatch, g as createWorkspace, gt as JUNIOR_THREAD_STATE_TTL_MS, it as RESOURCE_SUBSCRIPTION_MAX_TTL_MS, j as tryWorkspaceRepoCheckoutPath, k as deleteWorkspaceSnapshotBuilders, l as getPluginUserPromptContributions, ln as addAgentTurnUsage, mt as listWatches, n as applyPluginFormatMarkdown, nn as getSqlExecutor, nt as getSlackToolContext, ot as STOP_WATCHING_TOOL_NAME, pn as hasAgentTurnUsage, pt as findMatchingWatches, q as normalizeSlackConversationId, r as createPluginHookRunner, rt as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, s as getPluginSystemPromptContributions, st as cancelSubscriptions, tn as getDb, u as getPlugins, ut as createTimerWatch, v as getWorkspace, w as invalidateReadySnapshot, wt as createPluginLogger, xn as sameDestination$1, y as getWorkspaceByName, yn as parseDestination, yt as getDashboardTaskLink, zt as matchSlackAttachments } from "./agent-hooks-Da_H0jHv.js";
10
10
  import { n as juniorDestinations } from "./destinations-BeBiJeEM.js";
11
- import { D as juniorIdentities, E as juniorConversations, a as juniorSchedulerRuns, c as juniorStats, d as AGENT_INVOCATION_MAILBOX_STATUSES, g as juniorConversationBriefs, k as juniorArtifacts, l as juniorEventAutomations, o as juniorSchedulerTasks, w as juniorAttachments, x as juniorConversationAnnotations } from "./executor--jWf-Nnm.js";
12
- import { F as briefLinkSchema, G as KNOWN_CONVERSATION_EVENT_TYPES, I as briefOutcomeStatusSchema, L as conversationBriefSchema, N as isVisionImageMediaType, U as removedCardSchema, et as contextProvenance, nt as instructionProvenanceFor, rt as sameActorIdentity, tt as instructionActors } from "./conversation-CPjHYOV5.js";
13
- import { a as listReferenceFiles, c as soulPathCandidates, l as worldPathCandidates } from "./package-discovery-7a9YqLhE.js";
14
- import { a as resolveAuthTokenPlaceholder, c as fetchWithBoundedOAuthErrorBodies, d as CredentialUnavailableError, i as resolvePluginHeaderEnvRefs, l as getOAuthProviderErrorAttributes, o as resolvePluginCommandEnv, s as OAuthProviderError } from "./registry-DiY6B8CN.js";
15
- import { n as pluginCatalogRuntime } from "./catalog-runtime-BSgsPVnr.js";
16
- import { a as parseSkillInvocation, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-WttpPJUy.js";
17
- import { $ as fallbackShortTitle, C as isToolResultError, D as stripRuntimeTurnContext, E as retainRuntimeTurnContext, F as loadTurnRoute, G as recordToolExecutionStarted, H as recordGuardianActionReviewed, I as openConversationProjection, K as recordTurnRoute, L as recordAgentsInstructionsUpdated, M as loadConnectedMcpProviders, N as loadConversationProjection, O as trimTrailingAssistantMessages, R as recordAttachmentsDelivered, S as isContinuablePiBoundary, T as normalizeToolNameFromResult, U as recordMcpProviderConnected, V as recordAuthorizationRequested, _ as getTerminalAssistantMessages, d as TurnSliceLimitExceededError, et as resolveTaskTitle, f as assertTurnToolCallLimit, ft as estimateTextTokens, g as getPiMessageRole, gt as piMessageFromHistoryItem, h as extractAssistantText, ht as historyItemFromPiMessage, k as TURN_CONTEXT_TAG, m as isTurnExecutionLimitExceededError, mt as getAgentContextInputLimitTokens, n as loadTurnCheckpoint, pt as getAgentContextCompactionTriggerTokens, r as saveTurnCheckpoint, t as continuableMessages, v as getUserMessageInstructionText, w as isToolResultMessage, x as isAssistantMessage, y as hasRuntimeTurnContext } from "./checkpoint-BNfXlq_1.js";
18
- import { A as SANDBOX_DATA_ROOT, C as getDefaultRedisStateAdapterFor, D as fenceLock, E as acquireActiveLock, F as sandboxSkillFile, I as sandboxSkillPathResolution, M as SANDBOX_SKILLS_ROOT, N as SANDBOX_WORKSPACE_ROOT, O as withLock, P as sandboxSkillDir, _ as workspaceSnapshotNotReadyUserMessage, a as isAbortError, b as buildNonInteractiveShellScript, c as isSandboxCommandStreamInterruptedError, d as isSnapshottingError, f as throwSandboxOperationError, g as isWorkspaceSnapshotNotReadyError, h as getWorkspaceSnapshotNotReadyError, i as ensureDockerDaemon, j as SANDBOX_REPOS_ROOT, k as sleep$2, l as isSandboxMissingError, m as WorkspaceSnapshotNotReadyError, n as hash, o as isAlreadyExistsError, p as wrapSandboxSetupError, r as isStale, s as isSandboxApiTransientError, t as create, u as isSandboxUnavailableError, v as getVercelSandboxCredentials, w as getStateAdapter, x as runNonInteractiveCommand, y as buildCommandScript } from "./profile-BdApelHS.js";
19
- import { n as canReusePendingAuthLink, t as abandonReplacedPendingAuth } from "./pending-auth-DQhC3eSR.js";
20
- import { a as NO_REPLY_MARKER, c as CooperativeTurnYieldError, i as sanitizeAssistantText, l as TurnInputCommitLostError, n as decideReply, o as isNoReplyMarker, p as isTurnInputCommitLostError, r as getAssistantReplyText, t as authorizationId } from "./oauth-authorization-CC8a1JKP.js";
21
- import { r as EVENT_AUTHOR_ID } from "./prompt-3D0sSbTC.js";
22
- import { a as createSandboxSession, c as postinstall, d as getSandboxResources, i as bindSandboxFileSystem, l as setSnapshotSpanAttributes, n as isMissingError, o as stopSession, r as resolve$1, s as dependencies } from "./resolve-VpJoiDpc.js";
23
- import { a as getVercelConversationWorkQueue, f as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-cwHVOwVZ.js";
24
- import { a as automationTitleSchema, c as ScheduleIntentError, g as taskOutcomeInputSchema, i as automationInstructionSchema, l as compileScheduleIntent, m as eventAutomationSchema, n as scheduledAutomationSchema, p as getZonedDateTimeParts, r as scheduledRunSchema, t as SCHEDULED_AUTOMATION_SYSTEM_ACTOR, u as scheduleIntentSchema } from "./types-Du-HbEun.js";
11
+ import { A as juniorArtifacts, D as juniorConversations, O as juniorIdentities, S as juniorConversationAnnotations, T as juniorAttachments, _ as juniorConversationBriefs, a as juniorSchedulerRuns, f as AGENT_INVOCATION_MAILBOX_STATUSES, l as juniorStats, o as juniorSchedulerTasks, s as juniorAutomationVersions, u as juniorEventAutomations } from "./executor-BW9XWgUQ.js";
12
+ import { F as isVisionImageMediaType, G as removedCardSchema, L as briefLinkSchema, R as briefOutcomeStatusSchema, at as sameActorIdentity, it as instructionProvenanceFor, nt as contextProvenance, q as KNOWN_CONVERSATION_EVENT_TYPES, rt as instructionActors, z as conversationBriefSchema } from "./conversation-9Fxa1Zbq.js";
13
+ import { a as listReferenceFiles, c as soulPathCandidates, l as worldPathCandidates } from "./package-discovery-BVvSnQBB.js";
14
+ import { a as resolveAuthTokenPlaceholder, c as fetchWithBoundedOAuthErrorBodies, d as CredentialUnavailableError, i as resolvePluginHeaderEnvRefs, l as getOAuthProviderErrorAttributes, o as resolvePluginCommandEnv, s as OAuthProviderError } from "./registry-CXNv9fDX.js";
15
+ import { n as pluginCatalogRuntime } from "./catalog-runtime-C7339Cfm.js";
16
+ import { a as parseSkillInvocation, i as parseSkillFile, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-Dd8O9Aav.js";
17
+ import { C as isToolResultError, D as stripRuntimeTurnContext, E as retainRuntimeTurnContext, H as recordAuthorizationRequested, I as loadTurnRoute, K as recordToolExecutionStarted, L as openConversationProjection, M as loadConnectedMcpProviders, N as loadConversationProjection, O as trimTrailingAssistantMessages, R as recordAgentsInstructionsUpdated, S as isContinuablePiBoundary, T as normalizeToolNameFromResult, U as recordGuardianActionReviewed, W as recordMcpProviderConnected, _ as getTerminalAssistantMessages, _t as historyItemFromPiMessage, d as TurnSliceLimitExceededError, f as assertTurnToolCallLimit, g as getPiMessageRole, gt as getAgentContextInputLimitTokens, h as extractAssistantText, ht as getAgentContextCompactionTriggerTokens, k as TURN_CONTEXT_TAG, m as isTurnExecutionLimitExceededError, mt as estimateTextTokens, n as loadTurnCheckpoint, nt as resolveTaskTitle, q as recordTurnRoute, r as saveTurnCheckpoint, t as continuableMessages, tt as fallbackShortTitle, v as getUserMessageInstructionText, vt as piMessageFromHistoryItem, w as isToolResultMessage, x as isAssistantMessage, y as hasRuntimeTurnContext, z as recordAttachmentsDelivered } from "./checkpoint-DaD7_Gsb.js";
18
+ import { A as SANDBOX_DATA_ROOT, C as getDefaultRedisStateAdapterFor, D as fenceLock, E as acquireActiveLock, F as sandboxSkillFile, I as sandboxSkillPathResolution, M as SANDBOX_SKILLS_ROOT, N as SANDBOX_WORKSPACE_ROOT, O as withLock, P as sandboxSkillDir, _ as workspaceSnapshotNotReadyUserMessage, a as isAbortError, b as buildNonInteractiveShellScript, c as isSandboxCommandStreamInterruptedError, d as isSnapshottingError, f as throwSandboxOperationError, g as isWorkspaceSnapshotNotReadyError, h as getWorkspaceSnapshotNotReadyError, i as ensureDockerDaemon, j as SANDBOX_REPOS_ROOT, k as sleep$2, l as isSandboxMissingError, m as WorkspaceSnapshotNotReadyError, n as hash, o as isAlreadyExistsError, p as wrapSandboxSetupError, r as isStale, s as isSandboxApiTransientError, t as create, u as isSandboxUnavailableError, v as getVercelSandboxCredentials, w as getStateAdapter, x as runNonInteractiveCommand, y as buildCommandScript } from "./profile-BamYnmhO.js";
19
+ import { n as canReusePendingAuthLink, t as abandonReplacedPendingAuth } from "./pending-auth-WqF4Gh8Z.js";
20
+ import { a as NO_REPLY_MARKER, c as CooperativeTurnYieldError, i as sanitizeAssistantText, l as TurnInputCommitLostError, n as decideReply, o as isNoReplyMarker, p as isTurnInputCommitLostError, r as getAssistantReplyText, t as authorizationId } from "./oauth-authorization-BjRN99dc.js";
21
+ import { r as EVENT_AUTHOR_ID } from "./prompt-Ctwy6hSI.js";
22
+ import { a as createSandboxSession, c as postinstall, d as getSandboxResources, i as bindSandboxFileSystem, l as setSnapshotSpanAttributes, n as isMissingError, o as stopSession, r as resolve$1, s as dependencies } from "./resolve-C9ETkt4T.js";
23
+ import { a as getVercelConversationWorkQueue, f as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-BqXd0ZPV.js";
24
+ import { A as eventAutomationSchema, D as scheduledRunSchema, E as scheduledAutomationSchema, L as getZonedDateTimeParts, M as compileScheduleIntent, N as scheduleIntentSchema, O as automationInstructionToolSchema, R as taskOutcomeInputSchema, S as automationVersionSchema, T as SCHEDULED_AUTOMATION_SYSTEM_ACTOR, j as ScheduleIntentError, k as automationTitleSchema } from "./automation-B9Kc1gcf.js";
25
25
  import { n as privateTraceResultAttributes } from "./private-trace-result-BLvBjy_e.js";
26
26
  import { streamSimple } from "@earendil-works/pi-ai/compat";
27
27
  import { createGatewayProvider } from "@ai-sdk/gateway";
@@ -397,6 +397,15 @@ async function collectFiles(params) {
397
397
  //#region src/chat/repository-instructions.ts
398
398
  const AGENTS_FILENAME = "AGENTS.md";
399
399
  const MAX_REPOSITORY_INSTRUCTIONS_BYTES = 32768;
400
+ /** Repository skill directories, in priority order, relative to the Git root. */
401
+ const REPOSITORY_SKILL_ROOTS = [".agents/skills", ".claude/skills"];
402
+ const REPOSITORY_SKILLS_HEADER = [
403
+ "## Repository skills",
404
+ "",
405
+ "These skills come from the repository, not from `<available-skills>`. `loadSkill` cannot load them.",
406
+ "Before work that matches a skill description, read its `SKILL.md` with `readFile` and follow it.",
407
+ "Resolve relative paths in a skill against the skill directory."
408
+ ].join("\n");
400
409
  const AGENTS_REPLACEMENT_NOTICE = "These AGENTS.md instructions replace all previously provided AGENTS.md instructions.";
401
410
  const AGENTS_REMOVAL_NOTICE = "The previously provided AGENTS.md instructions no longer apply.";
402
411
  async function pathExists(fs, target) {
@@ -446,20 +455,53 @@ async function readInstructionFile(fs, filePath) {
446
455
  throw error;
447
456
  }
448
457
  }
449
- /** Resolve the effective root-to-cwd AGENTS.md bundle for one selected directory. */
450
- async function resolveRepositoryInstructions(args) {
451
- const gitRoot = await findGitRoot(args.fs, args.cwd);
452
- if (!gitRoot) return;
458
+ async function readOptionalDirectory(fs, directory) {
459
+ try {
460
+ return await fs.readdir(directory);
461
+ } catch (error) {
462
+ if (isMissingPathError(error)) return [];
463
+ throw error;
464
+ }
465
+ }
466
+ /** Read model-invocable skills from the repository skill directories. */
467
+ async function readRepositorySkills(fs, gitRoot) {
468
+ const roots = REPOSITORY_SKILL_ROOTS.map((root) => path.posix.join(gitRoot, root));
469
+ const listings = await Promise.all(roots.map(async (root) => await readOptionalDirectory(fs, root)));
470
+ const candidates = /* @__PURE__ */ new Map();
471
+ listings.forEach((entries, index) => {
472
+ for (const entry of [...entries].sort()) if (!candidates.has(entry)) candidates.set(entry, path.posix.join(roots[index], entry));
473
+ });
474
+ return (await Promise.all([...candidates].map(async ([name, skillDirectory]) => {
475
+ if (!await directoryExists(fs, skillDirectory)) return;
476
+ const filePath = path.posix.join(skillDirectory, "SKILL.md");
477
+ const raw = await readInstructionFile(fs, filePath);
478
+ const parsed = raw ? parseSkillFile(raw, name) : void 0;
479
+ if (!parsed?.ok || parsed.skill.disableModelInvocation) return;
480
+ return {
481
+ description: parsed.skill.description.replace(/\s+/g, " ").trim(),
482
+ name,
483
+ path: filePath
484
+ };
485
+ }))).filter((skill) => Boolean(skill)).sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
486
+ }
487
+ function sourceBytes(sources) {
488
+ return sources.reduce((total, source) => total + Buffer.byteLength(source.content, "utf8"), 0);
489
+ }
490
+ function skillListBytes(skills) {
491
+ return skills.reduce((total, skill) => total + repositorySkillBytes(skill), 0);
492
+ }
493
+ /** Read root-to-cwd AGENTS.md files within the byte budget. */
494
+ async function readAgentsSources(args) {
453
495
  const directories = [];
454
496
  let current = args.cwd;
455
497
  for (;;) {
456
498
  directories.push(current);
457
- if (current === gitRoot) break;
499
+ if (current === args.gitRoot) break;
458
500
  current = path.posix.dirname(current);
459
501
  }
460
502
  directories.reverse();
461
503
  const sources = [];
462
- let remaining = Math.max(0, args.maxBytes ?? MAX_REPOSITORY_INSTRUCTIONS_BYTES);
504
+ let remaining = Math.max(0, args.maxBytes);
463
505
  for (const directory of directories) {
464
506
  if (remaining <= 0) break;
465
507
  const filePath = path.posix.join(directory, AGENTS_FILENAME);
@@ -473,34 +515,69 @@ async function resolveRepositoryInstructions(args) {
473
515
  });
474
516
  remaining -= Buffer.byteLength(bounded, "utf8");
475
517
  }
476
- if (sources.length === 0) return;
477
- const text = formatInstructionSources(sources);
478
- const fingerprint = createHash("sha256").update(JSON.stringify({
479
- directory: args.cwd,
480
- sources
481
- })).digest("hex");
518
+ return sources;
519
+ }
520
+ /** Read repository skills that fit the byte budget, keeping each entry whole. */
521
+ async function readRepositorySkillsWithinBudget(args) {
522
+ const skills = [];
523
+ let remaining = args.maxBytes;
524
+ if (remaining <= 0) return skills;
525
+ for (const skill of await readRepositorySkills(args.fs, args.gitRoot)) {
526
+ const bytes = repositorySkillBytes(skill);
527
+ if (bytes > remaining) break;
528
+ skills.push(skill);
529
+ remaining -= bytes;
530
+ }
531
+ return skills;
532
+ }
533
+ function buildRepositoryInstructions(directory, sources, skills) {
534
+ if (sources.length === 0 && skills.length === 0) return;
482
535
  return {
483
- directory: args.cwd,
484
- fingerprint,
536
+ directory,
537
+ fingerprint: createHash("sha256").update(JSON.stringify({
538
+ directory,
539
+ sources,
540
+ ...skills.length > 0 ? { skills } : void 0
541
+ })).digest("hex"),
542
+ ...skills.length > 0 ? { skills } : void 0,
485
543
  sources,
486
- text
544
+ text: formatRepositoryInstructions(sources, skills)
487
545
  };
488
546
  }
489
547
  function formatInstructionSources(sources) {
490
548
  if (sources.length === 1) return sources[0].content;
491
549
  return sources.map((source) => `## ${path.posix.dirname(source.path)}\n\n${source.content}`).join("\n\n");
492
550
  }
551
+ function formatRepositorySkill(skill) {
552
+ return `- \`${skill.name}\` (\`${skill.path}\`): ${skill.description}`;
553
+ }
554
+ function repositorySkillBytes(skill) {
555
+ return Buffer.byteLength(formatRepositorySkill(skill), "utf8") + 1;
556
+ }
557
+ function formatRepositoryInstructions(sources, skills) {
558
+ const sections = [];
559
+ if (sources.length > 0) sections.push(formatInstructionSources(sources));
560
+ if (skills.length > 0) sections.push([
561
+ REPOSITORY_SKILLS_HEADER,
562
+ "",
563
+ ...skills.map(formatRepositorySkill)
564
+ ].join("\n"));
565
+ return sections.join("\n\n");
566
+ }
493
567
  /** Combine AGENTS.md bundles from one or more repository directories. */
494
568
  function mergeRepositoryInstructions(bundles) {
495
569
  if (bundles.length === 0) return;
496
570
  if (bundles.length === 1) return bundles[0];
497
571
  const sources = bundles.flatMap((bundle) => bundle.sources);
498
- const text = formatInstructionSources(sources);
572
+ const skills = bundles.flatMap((bundle) => bundle.skills ?? []);
573
+ const text = formatRepositoryInstructions(sources, skills);
499
574
  return {
500
575
  fingerprint: createHash("sha256").update(JSON.stringify({
501
576
  directories: bundles.map((bundle) => bundle.directory ?? null),
502
- sources
577
+ sources,
578
+ ...skills.length > 0 ? { skills } : void 0
503
579
  })).digest("hex"),
580
+ ...skills.length > 0 ? { skills } : void 0,
504
581
  sources,
505
582
  text
506
583
  };
@@ -509,17 +586,33 @@ function mergeRepositoryInstructions(bundles) {
509
586
  async function resolveRepositoryInstructionsForDirectories(args) {
510
587
  const uniqueDirectories = [...new Set(args.directories.filter((directory) => directory === SANDBOX_WORKSPACE_ROOT || directory.startsWith(`${SANDBOX_WORKSPACE_ROOT}/`)))].sort((left, right) => left < right ? -1 : left > right ? 1 : 0);
511
588
  let remaining = MAX_REPOSITORY_INSTRUCTIONS_BYTES;
512
- const bundles = [];
589
+ const repositories = [];
513
590
  for (const directory of uniqueDirectories) {
514
- if (remaining <= 0) break;
515
- const instructions = await resolveRepositoryInstructions({
591
+ const gitRoot = await findGitRoot(args.fs, directory);
592
+ if (!gitRoot) continue;
593
+ const sources = await readAgentsSources({
516
594
  cwd: directory,
517
595
  fs: args.fs,
596
+ gitRoot,
597
+ maxBytes: remaining
598
+ });
599
+ remaining -= sourceBytes(sources);
600
+ repositories.push({
601
+ directory,
602
+ gitRoot,
603
+ sources
604
+ });
605
+ }
606
+ const bundles = [];
607
+ for (const repository of repositories) {
608
+ const skills = await readRepositorySkillsWithinBudget({
609
+ fs: args.fs,
610
+ gitRoot: repository.gitRoot,
518
611
  maxBytes: remaining
519
612
  });
520
- if (!instructions) continue;
521
- bundles.push(instructions);
522
- remaining -= instructions.sources.reduce((total, source) => total + Buffer.byteLength(source.content, "utf8"), 0);
613
+ remaining -= skillListBytes(skills);
614
+ const bundle = buildRepositoryInstructions(repository.directory, repository.sources, skills);
615
+ if (bundle) bundles.push(bundle);
523
616
  }
524
617
  return mergeRepositoryInstructions(bundles);
525
618
  }
@@ -3095,6 +3188,10 @@ function normalizeSlackStatusText(text) {
3095
3188
  if (!trimmed) return "";
3096
3189
  return truncateStatusText(trimmed.replace(/(?:\.\s*)+$/, "").trim());
3097
3190
  }
3191
+ /** Render a Slack user mention, which Slack shows as the person's name. */
3192
+ function slackMention(userId) {
3193
+ return `<@${userId}>`;
3194
+ }
3098
3195
  //#endregion
3099
3196
  //#region src/chat/slack/oauth-authorization-message.ts
3100
3197
  /** Present private OAuth authorization with a clear action and text fallback. */
@@ -3984,12 +4081,14 @@ function renderTaskInput(args) {
3984
4081
  const instructions = args.instructions.trim();
3985
4082
  if (!instructions) throw new Error("Task instructions are required");
3986
4083
  const about = args.about?.trim();
4084
+ const creator = args.creator?.trim();
3987
4085
  const lines = [
3988
4086
  "[task]",
3989
4087
  "",
3990
4088
  "This is a task, not a message from a person.",
3991
4089
  "",
3992
4090
  ...about ? [`About: ${oneLine(about)}`] : [],
4091
+ ...creator ? [`Created by: ${oneLine(creator)}. Where the instructions say "me" or "my", write this mention.`] : [],
3993
4092
  `Instructions: ${instructions}`
3994
4093
  ];
3995
4094
  const guidance = args.guidance?.trim();
@@ -8742,7 +8841,7 @@ var PluginMcpClient = class {
8742
8841
  return [...this.listedTools];
8743
8842
  });
8744
8843
  }
8745
- async callTool(name, args) {
8844
+ async callTool(name, args, signal) {
8746
8845
  return await this.withSessionRecovery(async () => {
8747
8846
  const client = await this.getClient();
8748
8847
  const mcp = this.plugin.manifest.mcp;
@@ -8759,7 +8858,7 @@ var PluginMcpClient = class {
8759
8858
  const result = await this.wrapAuth(() => client.callTool({
8760
8859
  name,
8761
8860
  arguments: args ?? {}
8762
- }), "call_tool");
8861
+ }, void 0, signal ? { signal } : void 0), "call_tool");
8763
8862
  await this.syncTransportSessionId();
8764
8863
  return result;
8765
8864
  });
@@ -9143,7 +9242,7 @@ var McpToolManager = class {
9143
9242
  const argumentAttribute = serializeMcpPayload(resolvedArgs, conversationPrivacy, { privateMetadata: true });
9144
9243
  return await withSpan(`execute_tool ${managedToolName}`, "gen_ai.execute_tool", {}, async () => {
9145
9244
  try {
9146
- const result = await client.callTool(tool.name, resolvedArgs);
9245
+ const result = await client.callTool(tool.name, resolvedArgs, options?.signal);
9147
9246
  if ("isError" in result && result.isError) throw new McpToolError(extractMcpErrorMessage(result));
9148
9247
  const resultAttribute = serializeMcpPayload(result, conversationPrivacy, { privateMetadata: true });
9149
9248
  if (resultAttribute) setSpanAttributes({ "gen_ai.tool.call.result": resultAttribute });
@@ -9503,6 +9602,7 @@ function createCallMcpToolTool(mcpToolManager) {
9503
9602
  }
9504
9603
  const result = await mcpTool.execute(resolveMcpArguments(input), {
9505
9604
  conversationPrivacy: options?.conversationPrivacy ?? "private",
9605
+ ...options?.signal ? { signal: options.signal } : void 0,
9506
9606
  ...options?.toolCallId ? { toolCallId: options.toolCallId } : void 0
9507
9607
  });
9508
9608
  return {
@@ -10262,6 +10362,7 @@ var AutomationConflictError = class extends ToolInputError {
10262
10362
  this.name = "AutomationConflictError";
10263
10363
  }
10264
10364
  };
10365
+ /** Sort object keys so equal values produce equal JSON. */
10265
10366
  function canonicalJson$1(value) {
10266
10367
  if (Array.isArray(value)) return value.map(canonicalJson$1);
10267
10368
  if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, child]) => [key, canonicalJson$1(child)]));
@@ -10276,6 +10377,70 @@ function requireAutomationRevision(task, revision) {
10276
10377
  if (!task || automationRevision(task) !== revision) throw new AutomationConflictError();
10277
10378
  }
10278
10379
  //#endregion
10380
+ //#region src/chat/automations/versions.ts
10381
+ /** Automation versions keep each saved definition so people can see how it changed. */
10382
+ /** Return the versioned part of an Automation. Lifecycle and run state are excluded. */
10383
+ function automationDefinition(task) {
10384
+ const common = {
10385
+ title: task.title?.trim() || null,
10386
+ instruction: task.task.text,
10387
+ credentialMode: task.credentialMode,
10388
+ destination: task.destination,
10389
+ outcomes: task.outcomes
10390
+ };
10391
+ return "schedule" in task ? {
10392
+ ...common,
10393
+ schedule: task.schedule
10394
+ } : {
10395
+ ...common,
10396
+ trigger: task.trigger
10397
+ };
10398
+ }
10399
+ /** Compare definition values after key sorting. */
10400
+ function sameDefinitionValue(left, right) {
10401
+ return JSON.stringify(canonicalJson$1(left)) === JSON.stringify(canonicalJson$1(right));
10402
+ }
10403
+ /**
10404
+ * Save a version when the definition changed. Call this in the same
10405
+ * transaction and lock as the Automation write. Without `current`, the
10406
+ * Automation is new, so the creator saves version 1.
10407
+ */
10408
+ async function recordAutomationVersion(db, kind, task, current, editedBy) {
10409
+ const definition = automationDefinition(task);
10410
+ if (current && sameDefinitionValue(automationDefinition(current), definition)) return;
10411
+ await db.insert(juniorAutomationVersions).values({
10412
+ kind,
10413
+ automationId: task.id,
10414
+ version: sql`(
10415
+ SELECT coalesce(max(${juniorAutomationVersions.version}), 0) + 1
10416
+ FROM ${juniorAutomationVersions}
10417
+ WHERE ${juniorAutomationVersions.kind} = ${kind}
10418
+ AND ${juniorAutomationVersions.automationId} = ${task.id}
10419
+ )`,
10420
+ createdAtMs: Date.now(),
10421
+ editedBy: editedBy ?? (current ? null : task.createdBy),
10422
+ definition
10423
+ });
10424
+ }
10425
+ function parseVersionRow(kind, row) {
10426
+ return automationVersionSchema.parse({
10427
+ kind,
10428
+ version: row.version,
10429
+ createdAt: new Date(row.createdAtMs).toISOString(),
10430
+ editedBy: row.editedBy,
10431
+ definition: row.definition
10432
+ });
10433
+ }
10434
+ /** Read one saved definition. */
10435
+ async function readAutomationVersion(db, kind, automationId, version) {
10436
+ const [row] = await db.select().from(juniorAutomationVersions).where(and(eq(juniorAutomationVersions.kind, kind), eq(juniorAutomationVersions.automationId, automationId), eq(juniorAutomationVersions.version, version))).limit(1);
10437
+ return row ? parseVersionRow(kind, row) : void 0;
10438
+ }
10439
+ /** Read saved definitions, newest first. */
10440
+ async function listAutomationVersions(db, kind, automationId, limit) {
10441
+ return (await db.select().from(juniorAutomationVersions).where(and(eq(juniorAutomationVersions.kind, kind), eq(juniorAutomationVersions.automationId, automationId))).orderBy(desc(juniorAutomationVersions.version)).limit(limit)).map((row) => parseVersionRow(kind, row));
10442
+ }
10443
+ //#endregion
10279
10444
  //#region src/chat/event-automations/store.ts
10280
10445
  const retainedEventAutomationSchema = eventAutomationSchema.extend({
10281
10446
  destination: slackDestinationSchema,
@@ -10327,61 +10492,84 @@ async function getEventAutomation(db, id) {
10327
10492
  async function createEventAutomation(db, task) {
10328
10493
  const parsed = eventAutomationSchema.parse(eventAutomationJsonPayload(task));
10329
10494
  const title = task.title?.trim() || null;
10330
- await db.insert(juniorEventAutomations).values({
10331
- id: parsed.id,
10332
- teamId: parsed.destination.teamId,
10333
- namespace: parsed.trigger.namespace,
10334
- identifier: parsed.trigger.identifier,
10335
- createdAtMs: parsed.createdAtMs,
10336
- status: "active",
10337
- title,
10338
- task: parsed
10339
- }).onConflictDoNothing();
10340
- const existing = await getEventAutomation(db, parsed.id);
10341
- if (!existing) return {
10342
- ...parsed,
10343
- status: "active",
10344
- ...title ? { title } : void 0
10345
- };
10346
- if (existing.status !== "deleted") return existing;
10347
- const rows = await db.update(juniorEventAutomations).set({
10348
- teamId: parsed.destination.teamId,
10349
- namespace: parsed.trigger.namespace,
10350
- identifier: parsed.trigger.identifier,
10351
- status: "active",
10352
- title,
10353
- task: parsed
10354
- }).where(and(eq(juniorEventAutomations.id, parsed.id), eq(juniorEventAutomations.status, "deleted"))).returning({
10355
- status: juniorEventAutomations.status,
10356
- task: juniorEventAutomations.task,
10357
- title: juniorEventAutomations.title
10495
+ return db.transaction(async (tx) => {
10496
+ const inserted = await tx.insert(juniorEventAutomations).values({
10497
+ id: parsed.id,
10498
+ teamId: parsed.destination.teamId,
10499
+ namespace: parsed.trigger.namespace,
10500
+ identifier: parsed.trigger.identifier,
10501
+ createdAtMs: parsed.createdAtMs,
10502
+ status: "active",
10503
+ title,
10504
+ task: parsed
10505
+ }).onConflictDoNothing().returning({
10506
+ status: juniorEventAutomations.status,
10507
+ task: juniorEventAutomations.task,
10508
+ title: juniorEventAutomations.title
10509
+ });
10510
+ if (inserted[0]) {
10511
+ const created = parseEventAutomationRow(inserted[0]);
10512
+ await recordAutomationVersion(tx, "event", created, void 0);
10513
+ return created;
10514
+ }
10515
+ const existing = await getEventAutomation(tx, parsed.id);
10516
+ if (!existing) return {
10517
+ ...parsed,
10518
+ status: "active",
10519
+ ...title ? { title } : void 0
10520
+ };
10521
+ if (existing.status !== "deleted") return existing;
10522
+ const rows = await tx.update(juniorEventAutomations).set({
10523
+ teamId: parsed.destination.teamId,
10524
+ namespace: parsed.trigger.namespace,
10525
+ identifier: parsed.trigger.identifier,
10526
+ status: "active",
10527
+ title,
10528
+ task: parsed
10529
+ }).where(and(eq(juniorEventAutomations.id, parsed.id), eq(juniorEventAutomations.status, "deleted"))).returning({
10530
+ status: juniorEventAutomations.status,
10531
+ task: juniorEventAutomations.task,
10532
+ title: juniorEventAutomations.title
10533
+ });
10534
+ if (!rows[0]) return await getEventAutomation(tx, parsed.id) ?? {
10535
+ ...parsed,
10536
+ status: "active",
10537
+ ...title ? { title } : void 0
10538
+ };
10539
+ const revived = parseEventAutomationRow(rows[0]);
10540
+ await recordAutomationVersion(tx, "event", revived, void 0);
10541
+ return revived;
10358
10542
  });
10359
- return rows[0] ? parseEventAutomationRow(rows[0]) : await getEventAutomation(db, parsed.id) ?? {
10360
- ...parsed,
10361
- status: "active",
10362
- ...title ? { title } : void 0
10363
- };
10364
10543
  }
10365
- /** Replace an existing non-deleted event automation. */
10366
- async function saveEventAutomation(db, task, expectedRevision) {
10367
- if (expectedRevision !== void 0) return db.transaction(async (tx) => {
10368
- const rows = await tx.select().from(juniorEventAutomations).where(eq(juniorEventAutomations.id, task.id)).for("update");
10369
- requireAutomationRevision(rows[0] ? parseEventAutomationRow(rows[0]) : void 0, expectedRevision);
10370
- return saveEventAutomation(tx, task);
10371
- });
10544
+ /**
10545
+ * Replace an existing non-deleted event automation under a row lock.
10546
+ * Pass `editedBy` when a person changes the definition so its version names them.
10547
+ */
10548
+ async function saveEventAutomation(db, task, expectedRevision, editedBy) {
10372
10549
  const parsed = eventAutomationSchema.parse(eventAutomationJsonPayload(task));
10373
10550
  const title = task.title?.trim() || null;
10374
- const rows = await db.update(juniorEventAutomations).set({
10375
- namespace: parsed.trigger.namespace,
10376
- identifier: parsed.trigger.identifier,
10377
- title,
10378
- task: parsed
10379
- }).where(and(eq(juniorEventAutomations.id, parsed.id), activeEventAutomationWhere())).returning({
10380
- status: juniorEventAutomations.status,
10381
- task: juniorEventAutomations.task,
10382
- title: juniorEventAutomations.title
10551
+ return db.transaction(async (tx) => {
10552
+ const rows = await tx.select({
10553
+ status: juniorEventAutomations.status,
10554
+ task: juniorEventAutomations.task,
10555
+ title: juniorEventAutomations.title
10556
+ }).from(juniorEventAutomations).where(eq(juniorEventAutomations.id, parsed.id)).for("update");
10557
+ const current = rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
10558
+ if (expectedRevision !== void 0) requireAutomationRevision(current, expectedRevision);
10559
+ if (!current || current.status === "deleted") return void 0;
10560
+ const saved = parseEventAutomationRow((await tx.update(juniorEventAutomations).set({
10561
+ namespace: parsed.trigger.namespace,
10562
+ identifier: parsed.trigger.identifier,
10563
+ title,
10564
+ task: parsed
10565
+ }).where(eq(juniorEventAutomations.id, parsed.id)).returning({
10566
+ status: juniorEventAutomations.status,
10567
+ task: juniorEventAutomations.task,
10568
+ title: juniorEventAutomations.title
10569
+ }))[0]);
10570
+ await recordAutomationVersion(tx, "event", saved, current, editedBy);
10571
+ return saved;
10383
10572
  });
10384
- return rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
10385
10573
  }
10386
10574
  /** Mark one existing event automation deleted while retaining the row for history. */
10387
10575
  async function deleteEventAutomation(db, id) {
@@ -10697,7 +10885,7 @@ function createEventAutomationTool(context, catalog) {
10697
10885
  executionMode: "sequential",
10698
10886
  description: "Create a durable event automation in the active Slack channel or DM, never a thread. It 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.",
10699
10887
  inputSchema: z.object({
10700
- instruction: z.string().trim().min(1).max(4e3),
10888
+ instruction: automationInstructionToolSchema,
10701
10889
  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(),
10702
10890
  trigger,
10703
10891
  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(),
@@ -10908,7 +11096,7 @@ function createUpdateEventAutomationTool(context, catalog) {
10908
11096
  inputSchema: z.object({
10909
11097
  automationId: z.string().min(1),
10910
11098
  title: automationTitleSchema.optional(),
10911
- instruction: automationInstructionSchema.nullable().optional(),
11099
+ instruction: automationInstructionToolSchema.nullable().optional(),
10912
11100
  trigger: registeredEventAutomationTriggerSchema(catalog).nullable().optional(),
10913
11101
  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(),
10914
11102
  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()
@@ -10936,7 +11124,11 @@ function createUpdateEventAutomationTool(context, catalog) {
10936
11124
  outcomes: input.outcomes ?? void 0,
10937
11125
  credentialMode: input.credentialMode ?? void 0
10938
11126
  }, isCreator, catalog);
10939
- const saved = await saveEventAutomation(getDb(), next, automationRevision(current));
11127
+ const saved = await saveEventAutomation(getDb(), next, automationRevision(current), {
11128
+ slackUserId: actor.userId,
11129
+ ...actor.fullName ? { fullName: actor.fullName } : void 0,
11130
+ ...actor.userName ? { userName: actor.userName } : void 0
11131
+ });
10940
11132
  if (!saved) throw new ToolInputError("Event automation was not found.");
10941
11133
  return eventAutomationToolResult(context.conversationId, saved, catalog, actor.userId);
10942
11134
  }
@@ -11090,10 +11282,11 @@ async function listScheduledAutomations(db) {
11090
11282
  async function listScheduledAutomationsForTeam(db, teamId) {
11091
11283
  return await readListedScheduledAutomations(db, teamId);
11092
11284
  }
11093
- async function writeScheduledAutomation(db, task, current) {
11285
+ async function writeScheduledAutomation(db, task, current, editedBy) {
11094
11286
  if (current?.status === "blocked" && task.status === "active" && typeof task.nextRunAtMs === "number" && Number.isFinite(task.nextRunAtMs)) await db.delete(juniorSchedulerRuns).where(and(eq(juniorSchedulerRuns.id, scheduledRunId(task.id, task.nextRunAtMs)), eq(juniorSchedulerRuns.status, "blocked")));
11095
11287
  if (task.status === "deleted" && current?.status !== "deleted") await skipPendingRunsForDeletedTask(db, task);
11096
11288
  await upsertScheduledAutomation(db, task);
11289
+ await recordAutomationVersion(db, "scheduled", task, current, editedBy);
11097
11290
  }
11098
11291
  async function skipPendingRunsForDeletedTask(db, task) {
11099
11292
  const errorMessage = `Scheduled automation ${task.id} was deleted before the run started.`;
@@ -11123,13 +11316,16 @@ async function createScheduledAutomation(db, task) {
11123
11316
  return next;
11124
11317
  });
11125
11318
  }
11126
- /** Save a scheduled automation and clear its blocked occurrence on reactivation. */
11127
- async function saveScheduledAutomation(db, task, expectedRevision) {
11319
+ /**
11320
+ * Save a scheduled automation and clear its blocked occurrence on reactivation.
11321
+ * Pass `editedBy` when a person changes the definition so its version names them.
11322
+ */
11323
+ async function saveScheduledAutomation(db, task, expectedRevision, editedBy) {
11128
11324
  const next = requireStoredTask(task);
11129
11325
  await withScheduledAutomationLock(db, task.id, async (tx) => {
11130
11326
  const current = await readScheduledAutomation(tx, task.id);
11131
11327
  if (expectedRevision !== void 0) requireAutomationRevision(current, expectedRevision);
11132
- await writeScheduledAutomation(tx, next, current);
11328
+ await writeScheduledAutomation(tx, next, current, editedBy);
11133
11329
  });
11134
11330
  return next;
11135
11331
  }
@@ -11440,7 +11636,7 @@ function createSlackScheduleCreateAutomationTool(context) {
11440
11636
  description: "Create a one-time or recurring Junior task in the active Slack channel. Store the requested future work; do not perform it or check its service access now unless the user also asks for that.",
11441
11637
  executionMode: "sequential",
11442
11638
  inputSchema: z.object({
11443
- instruction: z.string().min(1).max(4e3).describe("Work to perform when the task runs. Preserve the user's scope, targets, and constraints. Do not add permissions or side effects the user did not request."),
11639
+ instruction: automationInstructionToolSchema,
11444
11640
  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(),
11445
11641
  schedule: scheduleIntentSchema.describe("When the task runs. The scheduler computes the exact next run from this intent and the server clock."),
11446
11642
  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(),
@@ -11730,7 +11926,7 @@ function createSlackScheduleUpdateAutomationTool(context) {
11730
11926
  inputSchema: z.object({
11731
11927
  automationId: z.string().min(1).describe("Scheduled automation ID returned by slackScheduleListAutomations."),
11732
11928
  title: automationTitleSchema.optional(),
11733
- instruction: automationInstructionSchema.optional(),
11929
+ instruction: automationInstructionToolSchema.optional(),
11734
11930
  schedule: scheduleIntentSchema.describe("Complete replacement schedule. Omit to keep it unchanged.").nullable().optional(),
11735
11931
  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(),
11736
11932
  status: z.enum(["active", "blocked"]).describe("Set active to resume a blocked task, or blocked to stop dispatch.").optional(),
@@ -11777,7 +11973,7 @@ function createSlackScheduleUpdateAutomationTool(context) {
11777
11973
  next.outcomes = input.outcomes === void 0 ? moveTaskOutcomes(lookup.outcomes, lookup.destination, requestedDestination) : await resolveTaskOutcomes(input.outcomes, requestedDestination, lookup.createdBy.slackUserId);
11778
11974
  }
11779
11975
  if (!changingDestination && !instructionChanged && !input.schedule && input.title === void 0 && status === void 0 && (input.credentialMode === void 0 || input.credentialMode === null || input.credentialMode === lookup.credentialMode) && input.outcomes === void 0 && moveDestination) return scheduleAutomationToolResult(context.conversationId, lookup, actor.slackUserId);
11780
- const committed = await saveScheduledAutomation(db, next, automationRevision(lookup));
11976
+ const committed = await saveScheduledAutomation(db, next, automationRevision(lookup), actor);
11781
11977
  if (changingDestination) logInfo("scheduled_automation.move.completed", scheduledAutomationAttributes(committed));
11782
11978
  return scheduleAutomationToolResult(context.conversationId, committed, actor.slackUserId);
11783
11979
  }
@@ -14651,9 +14847,6 @@ function explicitUserLookupError(error) {
14651
14847
  if (error.code === "invalid_arguments") return `Slack rejected the user lookup arguments (${error.apiError ?? error.code}).`;
14652
14848
  if (error.code === "feature_unavailable") return "User lookup is not available for this workspace or app installation.";
14653
14849
  }
14654
- function slackMention(userId) {
14655
- return `<@${userId}>`;
14656
- }
14657
14850
  function asMatch(user) {
14658
14851
  return {
14659
14852
  ...user,
@@ -14860,6 +15053,135 @@ function getTimeZoneOffsetMinutes(timestampMs, timezone) {
14860
15053
  return Math.round((timestampMs - asUtcMs) / 6e4);
14861
15054
  }
14862
15055
  //#endregion
15056
+ //#region src/chat/experimental.ts
15057
+ var experimental_exports = /* @__PURE__ */ __exportAll({
15058
+ EXPERIMENTAL_FEATURES: () => EXPERIMENTAL_FEATURES,
15059
+ getExperimentalFeatures: () => getExperimentalFeatures,
15060
+ isExperimentalFeatureEnabled: () => isExperimentalFeatureEnabled,
15061
+ setExperimentalFeatures: () => setExperimentalFeatures
15062
+ });
15063
+ /**
15064
+ * Known unstable product features that must be opted into explicitly.
15065
+ * Add new keys here as features graduate from private experiments; remove them
15066
+ * once they become stable defaults.
15067
+ */
15068
+ const EXPERIMENTAL_FEATURES = [
15069
+ "operator-tools",
15070
+ "passive-routing",
15071
+ "subagents"
15072
+ ];
15073
+ const EXPERIMENTAL_FEATURE_SET = new Set(EXPERIMENTAL_FEATURES);
15074
+ let configuredExperimental = {};
15075
+ function isExperimentalFeature(value) {
15076
+ return EXPERIMENTAL_FEATURE_SET.has(value);
15077
+ }
15078
+ /** Replace app-level experimental opt-ins and return the previous setting. */
15079
+ function setExperimentalFeatures(config) {
15080
+ const previous = { ...configuredExperimental };
15081
+ if (config === void 0) {
15082
+ configuredExperimental = {};
15083
+ return previous;
15084
+ }
15085
+ const next = {};
15086
+ for (const [rawName, enabled] of Object.entries(config)) {
15087
+ if (enabled === void 0) continue;
15088
+ if (typeof enabled !== "boolean") throw new Error(`experimental.${rawName} must be a boolean when provided`);
15089
+ if (!isExperimentalFeature(rawName)) throw new Error(`experimental.${rawName} is not a known experimental feature. Known features: ${EXPERIMENTAL_FEATURES.join(", ")}`);
15090
+ next[rawName] = enabled;
15091
+ }
15092
+ configuredExperimental = next;
15093
+ return previous;
15094
+ }
15095
+ /** Return a copy of the app-level experimental opt-ins configured by createApp(). */
15096
+ function getExperimentalFeatures() {
15097
+ return { ...configuredExperimental };
15098
+ }
15099
+ /** Return whether one experimental feature is enabled via createApp({ experimental }). */
15100
+ function isExperimentalFeatureEnabled(feature) {
15101
+ return configuredExperimental[feature] === true;
15102
+ }
15103
+ //#endregion
15104
+ //#region src/chat/tools/operator-sql.ts
15105
+ /** Deferred tool catalog source for operator tools. */
15106
+ const OPERATOR_TOOL_SOURCE = {
15107
+ id: "operator",
15108
+ description: "Run SQL directly against this deployment's database. Enabled only on deployments that opt in, such as Previews."
15109
+ };
15110
+ const DEFAULT_ROW_LIMIT = 50;
15111
+ const MAX_ROW_LIMIT = 200;
15112
+ const MAX_OUTPUT_CHARS = 4e4;
15113
+ const paramSchema = z.union([
15114
+ z.string(),
15115
+ z.number(),
15116
+ z.boolean(),
15117
+ z.null()
15118
+ ]);
15119
+ /** Find the Postgres SQLSTATE code that marks a statement the caller can fix. */
15120
+ function findSqlState(error) {
15121
+ for (let current = error; current instanceof Error; current = current.cause) {
15122
+ const code = current.code;
15123
+ if (typeof code === "string" && /^[0-9A-Z]{5}$/.test(code)) return {
15124
+ code,
15125
+ message: current.message
15126
+ };
15127
+ }
15128
+ }
15129
+ /** Keep the tool result small enough for the model context. */
15130
+ function limitRows(rows, rowLimit) {
15131
+ const limited = rows.slice(0, rowLimit);
15132
+ while (limited.length > 0 && JSON.stringify(limited).length > MAX_OUTPUT_CHARS) limited.pop();
15133
+ return limited;
15134
+ }
15135
+ /**
15136
+ * Build the operator tools when the app enables `operator-tools`.
15137
+ *
15138
+ * These tools bypass every Conversation privacy gate, so they only exist in
15139
+ * non-public Conversations. Their results never reach a public transcript or a
15140
+ * public Brief.
15141
+ */
15142
+ function createOperatorTools(context) {
15143
+ if (!isExperimentalFeatureEnabled("operator-tools")) return {};
15144
+ if (context.conversationPrivacy === "public") return {};
15145
+ return { runOperatorSql: zodTool({
15146
+ exposure: "deferred",
15147
+ source: OPERATOR_TOOL_SOURCE,
15148
+ executionMode: "sequential",
15149
+ annotations: {
15150
+ destructiveHint: true,
15151
+ idempotentHint: false,
15152
+ openWorldHint: false,
15153
+ readOnlyHint: false
15154
+ },
15155
+ description: "Run one SQL statement against this deployment's Postgres database and return its rows. Reads and writes are allowed. Add RETURNING to see rows changed by INSERT, UPDATE, or DELETE. Use $1, $2 placeholders with params for values.",
15156
+ inputSchema: z.object({
15157
+ statement: z.string().trim().min(1).max(2e4),
15158
+ params: z.array(paramSchema).max(100).nullable().optional().describe("Values for $1, $2, ... placeholders."),
15159
+ row_limit: z.number().int().min(1).max(MAX_ROW_LIMIT).nullable().optional().describe(`Maximum rows to return. Default ${DEFAULT_ROW_LIMIT}.`)
15160
+ }).strict(),
15161
+ outputSchema: juniorToolOutputSchema.extend({
15162
+ row_count: z.number().int(),
15163
+ rows: z.array(z.unknown()),
15164
+ truncated: z.boolean()
15165
+ }),
15166
+ async execute(input) {
15167
+ let rows;
15168
+ try {
15169
+ rows = await getSqlExecutor().queryIsolated(input.statement, input.params ?? []);
15170
+ } catch (error) {
15171
+ const sqlState = findSqlState(error);
15172
+ if (!sqlState) throw error;
15173
+ throw new ToolInputError(`SQL error ${sqlState.code}: ${sqlState.message}`, { cause: error });
15174
+ }
15175
+ const returned = limitRows(rows, input.row_limit ?? DEFAULT_ROW_LIMIT);
15176
+ return {
15177
+ row_count: rows.length,
15178
+ rows: returned,
15179
+ truncated: returned.length < rows.length
15180
+ };
15181
+ }
15182
+ }) };
15183
+ }
15184
+ //#endregion
14863
15185
  //#region src/chat/artifacts/store.ts
14864
15186
  const MAX_IMAGE_BYTES = 10485760;
14865
15187
  const IMAGE_TYPES = {
@@ -16545,7 +16867,8 @@ function createTools(availableSkills, hooks = {}, context, options = {}) {
16545
16867
  ...createEventTools(context, eventCatalog),
16546
16868
  ...createEventAutomationTools(context, eventCatalog),
16547
16869
  ...createScheduledAutomationTools(context),
16548
- ...createWorkspaceTools(context)
16870
+ ...createWorkspaceTools(context),
16871
+ ...createOperatorTools(context)
16549
16872
  };
16550
16873
  tools.searchConversationEvents = createSearchConversationEventsTool(context);
16551
16874
  if (context.conversationPrivacy === "public") tools.searchConversationBriefs = createSearchConversationBriefsTool(slackContext ? {
@@ -17487,6 +17810,36 @@ function createSearchToolsTool(catalogTools) {
17487
17810
  }
17488
17811
  //#endregion
17489
17812
  //#region src/chat/tool-support/pi-tool-adapter.ts
17813
+ /**
17814
+ * How long a preempted tool may take to return its own aborted result. Keep it
17815
+ * below the agent's abort settle grace, so the parked turn sees the result.
17816
+ */
17817
+ const TOOL_ABORT_SETTLE_GRACE_MS = 2e3;
17818
+ /**
17819
+ * Stop waiting for a tool shortly after the host preempts it. A tool that
17820
+ * ignores the signal must not hold the turn past its deadline, or the parked
17821
+ * turn loses the attempt. Work that keeps running is detached; its outcome is
17822
+ * unknown.
17823
+ */
17824
+ async function untilPreempted(work, signal) {
17825
+ if (!signal) return await work;
17826
+ let timer;
17827
+ let onAbort = () => {};
17828
+ const preempted = new Promise((_, reject) => {
17829
+ onAbort = () => {
17830
+ timer = setTimeout(() => reject(signal.reason), TOOL_ABORT_SETTLE_GRACE_MS);
17831
+ };
17832
+ if (signal.aborted) onAbort();
17833
+ else signal.addEventListener("abort", onAbort, { once: true });
17834
+ });
17835
+ try {
17836
+ return await Promise.race([work, preempted]);
17837
+ } finally {
17838
+ clearTimeout(timer);
17839
+ signal.removeEventListener("abort", onAbort);
17840
+ work.catch(() => void 0);
17841
+ }
17842
+ }
17490
17843
  /** Wrap tool definitions into Pi Agent tool objects with logging, validation, and sandbox execution. */
17491
17844
  function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxTools, pluginAuthOrchestration, onToolCall, agentHooks, conversationPrivacy, onToolResult, actionReview) {
17492
17845
  const plannedTools = planToolExposure(tools);
@@ -17548,17 +17901,17 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxTools,
17548
17901
  }
17549
17902
  const sandboxInput = buildSandboxInput(toolName, executionInput);
17550
17903
  const isSandbox = Boolean(sandboxTools?.supports(toolName));
17551
- const result = isSandbox ? await sandboxTools.execute({
17904
+ const result = await untilPreempted(isSandbox ? sandboxTools.execute({
17552
17905
  toolName,
17553
17906
  input: sandboxInput,
17554
17907
  ...signal ? { signal } : void 0,
17555
17908
  ...toolName === "grep" || toolName === "findFiles" ? { setToolCallSpanAttributes: setSpanAttributes } : void 0
17556
- }) : await toolDef.execute(executionInput, {
17909
+ }) : Promise.resolve(toolDef.execute(executionInput, {
17557
17910
  experimental_context: sandbox,
17558
17911
  ...signal ? { signal } : void 0,
17559
17912
  conversationPrivacy: effectiveConversationPrivacy,
17560
17913
  toolCallId
17561
- });
17914
+ })), signal);
17562
17915
  const normalized = normalizeToolResult(result, {
17563
17916
  requireStructuredResult: Boolean(toolDef.outputSchema),
17564
17917
  toolName
@@ -17938,17 +18291,24 @@ function clientAllowsRedirectUri(clientInformation, callbackUrl) {
17938
18291
  if (!Array.isArray(redirectUris)) return true;
17939
18292
  return redirectUris.includes(callbackUrl);
17940
18293
  }
18294
+ function requireEnv(name) {
18295
+ const value = process.env[name]?.trim();
18296
+ if (!value) throw new Error(`MCP OAuth client env var ${name} is unset`);
18297
+ return value;
18298
+ }
17941
18299
  var StateBackedMcpOAuthClientProvider = class {
17942
18300
  authSessionId;
17943
18301
  callbackUrl;
17944
18302
  sessionContext;
17945
18303
  runCredentialMutation;
18304
+ oauthClient;
17946
18305
  clientMetadata;
17947
- constructor(authSessionId, callbackUrl, sessionContext, runCredentialMutation) {
18306
+ constructor(authSessionId, callbackUrl, sessionContext, runCredentialMutation, oauthClient) {
17948
18307
  this.authSessionId = authSessionId;
17949
18308
  this.callbackUrl = callbackUrl;
17950
18309
  this.sessionContext = sessionContext;
17951
18310
  this.runCredentialMutation = runCredentialMutation;
18311
+ this.oauthClient = oauthClient;
17952
18312
  this.clientMetadata = createClientMetadata(callbackUrl);
17953
18313
  }
17954
18314
  get redirectUrl() {
@@ -17958,6 +18318,10 @@ var StateBackedMcpOAuthClientProvider = class {
17958
18318
  return this.authSessionId;
17959
18319
  }
17960
18320
  async clientInformation() {
18321
+ if (this.oauthClient) return {
18322
+ client_id: requireEnv(this.oauthClient.clientIdEnv),
18323
+ client_secret: requireEnv(this.oauthClient.clientSecretEnv)
18324
+ };
17961
18325
  const session = await this.getCredentialContext();
17962
18326
  const clientInformation = (await getMcpStoredOAuthCredentials(session.userId, session.provider))?.clientInformation;
17963
18327
  if (!clientInformation) return;
@@ -17988,6 +18352,8 @@ var StateBackedMcpOAuthClientProvider = class {
17988
18352
  });
17989
18353
  }
17990
18354
  async redirectToAuthorization(authorizationUrl) {
18355
+ if (this.oauthClient?.scope) authorizationUrl.searchParams.set("scope", this.oauthClient.scope);
18356
+ for (const [key, value] of Object.entries(this.oauthClient?.authorizeParams ?? {})) authorizationUrl.searchParams.set(key, value);
17991
18357
  const existing = await getMcpAuthSession(this.authSessionId);
17992
18358
  if (existing?.authorizationUrl && existing.authorizationUrl !== authorizationUrl.toString()) throw new Error("MCP OAuth authorization attempt is already initialized");
17993
18359
  await this.ensureSession({ authorizationUrl: authorizationUrl.toString() });
@@ -18081,7 +18447,7 @@ function requirePluginWithMcp(provider) {
18081
18447
  }
18082
18448
  /** Create one immutable provider authorization attempt for the active turn. */
18083
18449
  async function createMcpOAuthClientProvider(input) {
18084
- requirePluginWithMcp(input.provider);
18450
+ const plugin = requirePluginWithMcp(input.provider);
18085
18451
  const baseUrl = resolveBaseUrl();
18086
18452
  if (!baseUrl) throw new Error("Cannot determine base URL (set JUNIOR_BASE_URL or deploy to Vercel)");
18087
18453
  return new StateBackedMcpOAuthClientProvider(input.createAuthorizationState ? await input.createAuthorizationState() : randomUUID(), `${baseUrl}${getMcpOAuthCallbackPath(input.provider)}`, {
@@ -18096,7 +18462,7 @@ async function createMcpOAuthClientProvider(input) {
18096
18462
  ...input.threadTs ? { threadTs: input.threadTs } : void 0,
18097
18463
  ...input.toolChannelId ? { toolChannelId: input.toolChannelId } : void 0,
18098
18464
  ...input.configuration ? { configuration: input.configuration } : void 0
18099
- });
18465
+ }, void 0, plugin.manifest.mcp?.oauthClient);
18100
18466
  }
18101
18467
  /** Exchange a callback code while guarding every shared credential mutation. */
18102
18468
  async function finalizeMcpAuthorization(provider, authSessionId, authorizationCode, runCredentialMutation) {
@@ -18107,7 +18473,7 @@ async function finalizeMcpAuthorization(provider, authSessionId, authorizationCo
18107
18473
  if (session.provider !== provider) throw new Error(`MCP auth session provider mismatch: expected "${provider}", got "${session.provider}"`);
18108
18474
  const baseUrl = resolveBaseUrl();
18109
18475
  if (!baseUrl) throw new Error("Cannot determine base URL (set JUNIOR_BASE_URL or deploy to Vercel)");
18110
- const authProvider = new StateBackedMcpOAuthClientProvider(authSessionId, `${baseUrl}${getMcpOAuthCallbackPath(provider)}`, void 0, runCredentialMutation);
18476
+ const authProvider = new StateBackedMcpOAuthClientProvider(authSessionId, `${baseUrl}${getMcpOAuthCallbackPath(provider)}`, void 0, runCredentialMutation, mcp.oauthClient);
18111
18477
  const headers = mcp.headers ? resolvePluginHeaderEnvRefs(provider, mcp.headers, "MCP header") : void 0;
18112
18478
  let providerStatus;
18113
18479
  const transport = new StreamableHTTPClientTransport(new URL(mcp.url), {
@@ -21322,50 +21688,6 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
21322
21688
  }
21323
21689
  }
21324
21690
  //#endregion
21325
- //#region src/chat/experimental.ts
21326
- var experimental_exports = /* @__PURE__ */ __exportAll({
21327
- EXPERIMENTAL_FEATURES: () => EXPERIMENTAL_FEATURES,
21328
- getExperimentalFeatures: () => getExperimentalFeatures,
21329
- isExperimentalFeatureEnabled: () => isExperimentalFeatureEnabled,
21330
- setExperimentalFeatures: () => setExperimentalFeatures
21331
- });
21332
- /**
21333
- * Known unstable product features that must be opted into explicitly.
21334
- * Add new keys here as features graduate from private experiments; remove them
21335
- * once they become stable defaults.
21336
- */
21337
- const EXPERIMENTAL_FEATURES = ["passive-routing", "subagents"];
21338
- const EXPERIMENTAL_FEATURE_SET = new Set(EXPERIMENTAL_FEATURES);
21339
- let configuredExperimental = {};
21340
- function isExperimentalFeature(value) {
21341
- return EXPERIMENTAL_FEATURE_SET.has(value);
21342
- }
21343
- /** Replace app-level experimental opt-ins and return the previous setting. */
21344
- function setExperimentalFeatures(config) {
21345
- const previous = { ...configuredExperimental };
21346
- if (config === void 0) {
21347
- configuredExperimental = {};
21348
- return previous;
21349
- }
21350
- const next = {};
21351
- for (const [rawName, enabled] of Object.entries(config)) {
21352
- if (enabled === void 0) continue;
21353
- if (typeof enabled !== "boolean") throw new Error(`experimental.${rawName} must be a boolean when provided`);
21354
- if (!isExperimentalFeature(rawName)) throw new Error(`experimental.${rawName} is not a known experimental feature. Known features: ${EXPERIMENTAL_FEATURES.join(", ")}`);
21355
- next[rawName] = enabled;
21356
- }
21357
- configuredExperimental = next;
21358
- return previous;
21359
- }
21360
- /** Return a copy of the app-level experimental opt-ins configured by createApp(). */
21361
- function getExperimentalFeatures() {
21362
- return { ...configuredExperimental };
21363
- }
21364
- /** Return whether one experimental feature is enabled via createApp({ experimental }). */
21365
- function isExperimentalFeatureEnabled(feature) {
21366
- return configuredExperimental[feature] === true;
21367
- }
21368
- //#endregion
21369
21691
  //#region src/chat/runtime/agent-runner.ts
21370
21692
  const AGENT_ABORT_SETTLE_GRACE_MS = 5e3;
21371
21693
  /** Compose the agent executor with stable host dependencies. */
@@ -21390,7 +21712,7 @@ function createAgentRunner(execute, options) {
21390
21712
  } } : void 0
21391
21713
  };
21392
21714
  if (run.instruction.storedAttachments?.length) {
21393
- const { loadInputImages } = await import("./images-BaL19wFC.js").then((n) => n.n);
21715
+ const { loadInputImages } = await import("./images-BdG7zcNf.js").then((n) => n.n);
21394
21716
  const storage = nextRun.environment?.attachmentStorage;
21395
21717
  if (!storage) throw new Error("Attachment storage is unavailable.");
21396
21718
  nextRun.instruction = {
@@ -21441,4 +21763,4 @@ async function runAgentWithTimeout(agentRunner, run, timeoutMs) {
21441
21763
  }
21442
21764
  }
21443
21765
  //#endregion
21444
- export { deleteEventAutomation as $, isFinalAttempt as $t, requestAttachmentDeletion as A, actorFromRun as An, clearExpiredConversationLease as At, listScheduledAutomations as B, listActiveConversationIds as Bt, readPublicArtifact as C, postSlackMessage as Cn, ackMessages as Ct, renderBlockText as D, createUserTokenStore as Dn, cancelHumanFacingPendingMessages as Dt, renderAttachmentText as E, slackExternalRefIdSchema as En, beginConversationResume as Et, resolveSlackChannelIdFromThreadId as F, setConfigDefaults as Fn, drainConversationMailbox as Ft, saveScheduledAutomationInLock as G, requestAnotherSlice as Gt, parseScheduledAutomationRow as H, recordConversationRetry as Ht, listThreadReplies as I, ensureConversationWake as It, editEventAutomation as J, stopConversationWork as Jt, scheduledRunId as K, requestConversationWork as Kt, editScheduledAutomation as L, getConversation as Lt, parseSlackThreadId as M, AuthorizationFlowDisabledError as Mn, completeConversationWork as Mt, readSlackRawMessageContext as N, shouldEmitDevAgentTrace as Nn, countPendingConversationMessages as Nt, collectAttachmentGarbage as O, buildSteeringPiMessage as On, checkInConversationWork as Ot, resolveSlackChannelIdFromMessage as P, getConfigDefaults as Pn, deadLetterAttempt as Pt, collectEventAutomationMatchKeys as Q, hasRunnableConversationWork$1 as Qt, logScheduledAutomationRunSkipped as R, getConversationWorkState as Rt, publicArtifactHeaders as S, addReactionToMessage as Sn, pluginEventCatalog as St, lookupSlackUserProfile as T, slackEntitySchema as Tn, appendAndEnqueueInboundMessage as Tt, readScheduledAutomation as U, releaseConversationWork as Ut, listScheduledAutomationsForTeam as V, recordAttemptFailure as Vt, saveScheduledAutomation as W, removeActiveConversation as Wt, eventAutomationTriggerAvailable as X, CONVERSATION_WORK_STALE_ENQUEUE_MS as Xt, AutomationEditError as Y, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS as Yt, effectiveTaskOutcomes as Z, hasConversationStop as Zt, putMcpStoredOAuthCredentials as _, escapeSlackMrkdwnText as _n, ingestEvent as _t, isExperimentalFeatureEnabled as a, normalizeSandboxEgressTracePropagationDomains as an, saveEventAutomation as at, readStats as b, normalizeSlackStatusText as bn, getEventCatalog as bt, createContextCompactor as c, clearSandboxEgressSignals as cn, automationRevision as ct, deleteMcpAuthSession as d, parseSandboxEgressCredentialToken as dn, agentInvocationSchema as dt, isInvalidConversationRecordError as en, eventAutomationBelongsToUser as et, deleteMcpAuthSessionsForUserProvider as f, sandboxEgressSignalsResponseSchema as fn, createAgentInvocationSchema as ft, getMcpStoredOAuthCredentials as g, startOAuthFlow as gn, processWorkspaceSnapshotJob as gt, getMcpAuthSession as h, resolveBaseUrl as hn, getMcpProviderErrorAttributes as ht, getExperimentalFeatures as i, resolveSandboxEgressProviderForHost as in, parseEventAutomationRow as it, storeAttachment as j, toolInvocationDestination as jn, completeConversationStop as jt, readLiveAttachment as k, RetryableDeliveryError as kn, clearConsumedConversationWake as kt, executeCredentialedEgressRequest as l, consumeSandboxEgressAuthRequiredSignal as ln, requireAutomationRevision as lt, deleteMcpStoredOAuthCredentials as m, parseOAuthStatePayload as mn, AgentInvocationLimitError as mt, runAgentWithTimeout as n, maybePostAutomatedTurnLimitNotice as nn, getEventAutomation as nt, setExperimentalFeatures as o, shouldPropagateSandboxEgressTrace as on, setEventAutomationStatus as ot, deleteMcpServerSessionId as p, formatProviderLabel as pn, AgentInvocationBusyError as pt, withScheduledAutomationLock as q, startConversationWork as qt, experimental_exports as r, recordFinishedTurnForAutomatedLimit as rn, listDeletedEventAutomationsCreatedBy as rt, executeAgentRun as s, SANDBOX_EGRESS_PROXY_PATH as sn, AutomationConflictError as st, createAgentRunner as t, renderTaskInput as tn, findMatchingEventAutomations as tt, finalizeMcpAuthorization as u, consumeSandboxEgressPermissionDeniedSignal as un, agentBindingSchema as ut, PluginCredentialFailureError as v, formatSlackLink as vn, EVENT_WAIT_MS as vt, unpublishedArtifactHeaders as w, removeReactionFromMessage as wn, appendAndEnqueueExclusiveInboundMessage as wt, resolvePluginOAuthAccount as x, truncateStatusText as xn, eventGuidance as xt, latestProgressStatus as y, normalizeSlackReplyMarkdown as yn, isEventMailboxMetadata as yt, scheduledAutomationRunAttributes as z, hasRunnableConversationWork as zt };
21766
+ export { resolveTaskOutcomes as $, startConversationWork as $t, requestAttachmentDeletion as A, postSlackMessage as An, appendAndEnqueueExclusiveInboundMessage as At, scheduledAutomationRunAttributes as B, shouldEmitDevAgentTrace as Bn, deadLetterAttempt as Bt, isExperimentalFeatureEnabled as C, escapeSlackMrkdwnText as Cn, ingestEvent as Ct, renderBlockText as D, slackMention as Dn, eventGuidance as Dt, renderAttachmentText as E, normalizeSlackStatusText as En, getEventCatalog as Et, resolveSlackChannelIdFromThreadId as F, buildSteeringPiMessage as Fn, clearConsumedConversationWake as Ft, saveScheduledAutomation as G, hasRunnableConversationWork as Gt, listScheduledAutomationsForTeam as H, setConfigDefaults as Hn, ensureConversationWake as Ht, getConversationInfo as I, RetryableDeliveryError as In, clearExpiredConversationLease as It, withScheduledAutomationLock as J, recordConversationRetry as Jt, saveScheduledAutomationInLock as K, listActiveConversationIds as Kt, listThreadReplies as L, actorFromRun as Ln, completeConversationStop as Lt, parseSlackThreadId as M, slackEntitySchema as Mn, beginConversationResume as Mt, readSlackRawMessageContext as N, slackExternalRefIdSchema as Nn, cancelHumanFacingPendingMessages as Nt, collectAttachmentGarbage as O, truncateStatusText as On, pluginEventCatalog as Ot, resolveSlackChannelIdFromMessage as P, createUserTokenStore as Pn, checkInConversationWork as Pt, effectiveTaskOutcomes as Q, requestConversationWork as Qt, editScheduledAutomation as R, toolInvocationDestination as Rn, completeConversationWork as Rt, getExperimentalFeatures as S, startOAuthFlow as Sn, processWorkspaceSnapshotJob as St, lookupSlackUserProfile as T, normalizeSlackReplyMarkdown as Tn, isEventMailboxMetadata as Tt, parseScheduledAutomationRow as U, getConversation as Ut, listScheduledAutomations as V, getConfigDefaults as Vn, drainConversationMailbox as Vt, readScheduledAutomation as W, getConversationWorkState as Wt, AutomationEditError as X, removeActiveConversation as Xt, editEventAutomation as Y, releaseConversationWork as Yt, eventAutomationTriggerAvailable as Z, requestAnotherSlice as Zt, resolvePluginOAuthAccount as _, parseSandboxEgressCredentialToken as _n, agentInvocationSchema as _t, executeCredentialedEgressRequest as a, isFinalAttempt as an, listDeletedEventAutomationsCreatedBy as at, unpublishedArtifactHeaders as b, parseOAuthStatePayload as bn, AgentInvocationLimitError as bt, deleteMcpAuthSessionsForUserProvider as c, maybePostAutomatedTurnLimitNotice as cn, setEventAutomationStatus as ct, getMcpAuthSession as d, normalizeSandboxEgressTracePropagationDomains as dn, readAutomationVersion as dt, stopConversationWork as en, collectEventAutomationMatchKeys as et, getMcpStoredOAuthCredentials as f, shouldPropagateSandboxEgressTrace as fn, sameDefinitionValue as ft, readStats as g, consumeSandboxEgressPermissionDeniedSignal as gn, agentBindingSchema as gt, latestProgressStatus as h, consumeSandboxEgressAuthRequiredSignal as hn, requireAutomationRevision as ht, createContextCompactor as i, hasRunnableConversationWork$1 as in, getEventAutomation as it, storeAttachment as j, removeReactionFromMessage as jn, appendAndEnqueueInboundMessage as jt, readLiveAttachment as k, addReactionToMessage as kn, ackMessages as kt, deleteMcpServerSessionId as l, recordFinishedTurnForAutomatedLimit as ln, automationDefinition as lt, PluginCredentialFailureError as m, clearSandboxEgressSignals as mn, automationRevision as mt, runAgentWithTimeout as n, CONVERSATION_WORK_STALE_ENQUEUE_MS as nn, eventAutomationBelongsToUser as nt, finalizeMcpAuthorization as o, isInvalidConversationRecordError as on, parseEventAutomationRow as ot, putMcpStoredOAuthCredentials as p, SANDBOX_EGRESS_PROXY_PATH as pn, AutomationConflictError as pt, scheduledRunId as q, recordAttemptFailure as qt, executeAgentRun as r, hasConversationStop as rn, findMatchingEventAutomations as rt, deleteMcpAuthSession as s, renderTaskInput as sn, saveEventAutomation as st, createAgentRunner as t, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS as tn, deleteEventAutomation as tt, deleteMcpStoredOAuthCredentials as u, resolveSandboxEgressProviderForHost as un, listAutomationVersions as ut, publicArtifactHeaders as v, sandboxEgressSignalsResponseSchema as vn, createAgentInvocationSchema as vt, setExperimentalFeatures as w, formatSlackLink as wn, EVENT_WAIT_MS as wt, experimental_exports as x, resolveBaseUrl as xn, getMcpProviderErrorAttributes as xt, readPublicArtifact as y, formatProviderLabel as yn, AgentInvocationBusyError as yt, logScheduledAutomationRunSkipped as z, AuthorizationFlowDisabledError as zn, countPendingConversationMessages as zt };