@sentry/junior 0.263.0 → 0.265.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 (67) hide show
  1. package/README.md +1 -1
  2. package/dist/{adapter-BIacI0Bt.js → adapter-cUkPH3Om.js} +1 -1
  3. package/dist/{admin-C7vUk7s9.js → admin-Cf0rDmWV.js} +1 -1
  4. package/dist/{agent-runner-BUBas7Yy.js → agent-runner-C6MwHJEs.js} +296 -238
  5. package/dist/api/schema.d.ts +213 -16
  6. package/dist/api/schema.js +3 -3
  7. package/dist/api.js +107 -40
  8. package/dist/{app-Bo0kB987.d.ts → app-Csbi9dW7.d.ts} +4 -3
  9. package/dist/app.d.ts +1 -1
  10. package/dist/app.js +101 -393
  11. package/dist/{assistant-reply-BFmjgJjD.js → assistant-reply-UPA8vKlC.js} +1 -1
  12. package/dist/{automation-CWX0qL8U.js → automation-2RbKzpMT.js} +30 -9
  13. package/dist/{briefs-h55v5lX9.js → briefs-DRjx8kQ9.js} +3 -3
  14. package/dist/{catalog-runtime-Suf-aLlh.js → catalog-runtime-D3qbJlYz.js} +1 -1
  15. package/dist/cli/chat.js +15 -15
  16. package/dist/cli/check.js +3 -3
  17. package/dist/cli/init.js +4 -18
  18. package/dist/cli/main.js +4 -4
  19. package/dist/cli/plugins.js +4 -4
  20. package/dist/cli/snapshot-create.js +4 -4
  21. package/dist/cli/upgrade.js +3 -3
  22. package/dist/{client-DZBCBj1M.js → client-DX34VNtH.js} +3 -8
  23. package/dist/{config-Dnv8KmNs.js → config-BayQ9hHH.js} +100 -3
  24. package/dist/{connections-Br0_xv27.js → connections-mpN5Lsnj.js} +11 -10
  25. package/dist/{conversation-privacy-FY8yc2q3.js → conversation-privacy-frjQCJa9.js} +1 -1
  26. package/dist/{credential-sync-BvkiyWF5.js → credential-sync-CZmyDNdR.js} +20 -20
  27. package/dist/{agent-hooks-CqnZfuCt.js → credentialed-C6pKlB1p.js} +3197 -66
  28. package/dist/{executor-J9k2sp9m.js → executor-CAr7xQr2.js} +10 -300
  29. package/dist/{images-DV2FlEGL.js → images-B2yA3HWE.js} +2 -2
  30. package/dist/instrumentation.js +41 -25
  31. package/dist/{job-queue-B4yTgklN.js → job-queue-Cjo6Yg_b.js} +53 -14
  32. package/dist/{logging-Dk_FpF36.js → logging-D2QBriUo.js} +19 -32
  33. package/dist/{message-BzseAFH1.js → message-C9ymnpBS.js} +4 -4
  34. package/dist/nitro.d.ts +17 -2
  35. package/dist/nitro.js +26 -27
  36. package/dist/{oauth-callback-server-bTspTMCC.js → oauth-callback-server-BtMf3TPZ.js} +2 -2
  37. package/dist/{prompt-CxatQVaj.js → prompt-CvaDdSX3.js} +1 -1
  38. package/dist/{registry-BFzQFV_y.js → registry-COTeZ2cV.js} +1 -1
  39. package/dist/{resolve-CnRHib0U.js → resolve-g9PKz9pH.js} +7 -106
  40. package/dist/{result-DczfmNBa.js → result-COnC42GR.js} +8 -8
  41. package/dist/{runner-CJd9Wec-.js → runner-BnTNS7x_.js} +10 -10
  42. package/dist/{sandbox-egress-signals-DUmVkOx4.js → sandbox-egress-signals-C_IIdLFk.js} +1 -1
  43. package/dist/{schema-QidbykYl.js → schema-D5Amlzkp.js} +44 -3
  44. package/dist/{sentry-BBUlHih9.js → sentry-MDkYAVPV.js} +3 -6
  45. package/dist/{service-account-BI2kQDrb.js → service-account-CwvToidT.js} +3 -3
  46. package/dist/{service-account-x2QZXm4X.js → service-account-YdYftwV2.js} +5 -5
  47. package/dist/{session-stop-CtyJsnEj.js → session-stop-CpCUy1ZJ.js} +121 -81
  48. package/dist/{skills-Dbzx9-rS.js → skills-Bb2KaJ3m.js} +2 -2
  49. package/dist/{spawn-D8WU99UV.js → spawn-mbTcrLb3.js} +2 -2
  50. package/dist/{store-TKg1HVKx.js → store-CqRnaZSq.js} +3 -3
  51. package/dist/{store-UlOrW6JC.js → store-DdT74Lvq.js} +18 -9
  52. package/dist/{task-queue-BRB49H-J.js → task-queue-8XjDIORF.js} +14 -19
  53. package/dist/{task-runner-C575f2Dd.js → task-runner-6mLmG6g_.js} +46 -28
  54. package/dist/{tasks-LOItiYgL.js → tasks-DGbrur6x.js} +14 -2075
  55. package/dist/{thread-state-IDHdZA7R.js → thread-state-D45lz-oC.js} +5 -5
  56. package/dist/{turn-failure-response-h_LSXJ-M.js → turn-failure-response-CaEPLSBn.js} +7 -7
  57. package/dist/{turn-lifecycle-Cvi6Sb8Y.js → turn-lifecycle-C35IyRGp.js} +1 -1
  58. package/dist/{turn-session-routing-5Nyv4fso.js → turn-session-routing-BKx6rfVd.js} +1 -1
  59. package/dist/{validation-BeTriWC2.js → validation-C0X3CX51.js} +1 -1
  60. package/dist/{version-BQX_hLDC.js → version-BPHgJwnm.js} +1 -1
  61. package/dist/version.js +1 -1
  62. package/dist/{viewer-DmNRM88V.js → viewer-B2wXNspU.js} +21 -5
  63. package/dist/{web-input-BHcGXSox.js → web-input-Y6aXvmfa.js} +145 -46
  64. package/dist/{work-DLJMV02b.js → work-DMbqK0kT.js} +10 -10
  65. package/dist/{worker-vfG2ESg1.js → worker-B-rDJ3XN.js} +8 -6
  66. package/package.json +10 -9
  67. package/dist/profile-Dq5I7TV1.js +0 -582
@@ -1,32 +1,31 @@
1
- import { $t as isToolResultMessage, An as createSandboxEgressCredentialToken, B as recordAttachmentsDelivered, Ct as canReusePendingAuthLink, Dn as clearSandboxEgressSignals, Dt as continuableMessages, G as recordMcpProviderConnected, Gn as getSlackMessagePermalink, Gt as getPiMessageRole, Hn as slackMention, Ht as isTurnExecutionLimitExceededError, In as resolveBaseUrl, It as TURN_LIMIT_DISABLED_REASON, J as recordTurnRoute, Jt as hasRuntimeTurnContext, Kn as openSlackDirectMessage, Kt as getTerminalAssistantMessages, L as loadTurnRoute, Lt as TurnBudgetExceededError, M as loadConnectedMcpProviders, N as loadConversationProjection, Nn as deliverOAuthAuthorization, O as automationRevision, On as consumeSandboxEgressAuthRequiredSignal, Ot as loadTurnCheckpoint, P as loadLastModelProfile, Pn as formatProviderLabel, Qn as getOAuthAccountProviders, Qt as isToolResultError, R as openConversationProjection, Rt as TurnSliceLimitExceededError, Sn as resolveSandboxCommandEnvironment, St as abandonReplacedPendingAuth, U as recordAuthorizationRequested, Vt as createTurnLimitGate, W as recordGuardianActionReviewed, Wn as addReactionToMessage, Wt as extractAssistantText, Xt as isAssistantMessage, Yn as uploadFilesToConversation, Zt as isContinuablePiBoundary, _n as isExperimentalFeatureEnabled, _t as createPluginAuthOrchestration, a as saveScheduledAutomation, an as SESSION_CONTEXT_SECTION_TAG, bn as createUserTokenStore, bt as AuthorizationFlowDisabledError, d as createEventAutomation, en as normalizeToolNameFromResult, f as deleteEventAutomation, g as listEventAutomationsForTeam, gt as PluginCredentialFailureError, hn as getAgentContextInputLimitTokens, ht as createPluginEgress, i as readScheduledAutomation, in as REQUEST_CONTEXT_SECTION_TAG, ir as getConfigDefaults, kn as consumeSandboxEgressPermissionDeniedSignal, kt as saveTurnCheckpoint, m as getEventAutomation, mn as getAgentContextCompactionTriggerTokens, n as listScheduledAutomationsForTeam, nn as stripRuntimeTurnContext, nr as historyItemFromPiMessage, nt as fallbackShortTitle, on as TURN_CONTEXT_TAG, pn as estimateTextTokens, q as recordToolExecutionStarted, qt as getUserMessageInstructionText, rn as trimTrailingAssistantMessages, rr as piMessageFromHistoryItem, rt as resolveTaskTitle, t as createScheduledAutomation, tn as retainRuntimeTurnContext, v as saveEventAutomation, vt as authorizationId, xn as buildSandboxEgressNetworkPolicy, xt as AuthorizationPauseError, y as setEventAutomationStatus, yt as AuthPausePersistenceError, z as recordAgentsInstructionsUpdated, zt as TurnToolCallLimitExceededError } from "./tasks-LOItiYgL.js";
2
- import { S as resolveGatewayCredential, _ as getProviderErrorAttributes, a as completeText, b as MISSING_GATEWAY_CREDENTIALS_ERROR, c as COMPACTION_SUMMARY_PREFIX, d as renderCurrentInstruction, f as unwrapCurrentInstruction, g as findProviderError, h as createProviderError, i as completeObject, l as hasCompactedConversationContext, m as ProviderError, n as GEN_AI_SERVER_ADDRESS, p as escapeXml, s as resolveGatewayModel, t as GEN_AI_PROVIDER_NAME, u as isCompactionSummaryText, x as getGatewayApiKey, y as isProviderRetryError } from "./client-DZBCBj1M.js";
3
- import { R as normalizeIdentityEmail, S as summarizeMessageText, T as withSpan, V as toOptionalString, _ as serializeGenAiAttribute, a as extractGenAiUsageSummary, b as setSpanStatus, c as getLogContextAttributesForSpan, d as logError, f as logException, h as normalizeGenAiFinishReason, i as extractGenAiUsageAttributes, l as getTracePropagationHeaders, m as logWarn, p as logInfo, w as withLogContext, x as setTags, y as setSpanAttributes, z as isRecord$4 } from "./logging-Dk_FpF36.js";
4
- import { m as startInactiveSpan, v as withActiveSpan } from "./sentry-BBUlHih9.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-FY8yc2q3.js";
6
- import { n as botConfig, v as normalizeSlackEmojiName } from "./config-Dnv8KmNs.js";
1
+ import { $t as isToolResultMessage, B as recordAttachmentsDelivered, Cn as getConfigDefaults, Ct as canReusePendingAuthLink, Dt as continuableMessages, G as recordMcpProviderConnected, Gt as getPiMessageRole, Ht as isTurnExecutionLimitExceededError, It as TURN_LIMIT_DISABLED_REASON, J as recordTurnRoute, Jt as hasRuntimeTurnContext, Kt as getTerminalAssistantMessages, L as loadTurnRoute, Lt as TurnBudgetExceededError, M as loadConnectedMcpProviders, N as loadConversationProjection, O as automationRevision, Ot as loadTurnCheckpoint, P as loadLastModelProfile, Qt as isToolResultError, R as openConversationProjection, Rt as TurnSliceLimitExceededError, Sn as piMessageFromHistoryItem, St as abandonReplacedPendingAuth, U as recordAuthorizationRequested, Vt as createTurnLimitGate, W as recordGuardianActionReviewed, Wt as extractAssistantText, Xt as isAssistantMessage, Zt as isContinuablePiBoundary, _n as isExperimentalFeatureEnabled, _t as createPluginAuthOrchestration, a as saveScheduledAutomation, an as SESSION_CONTEXT_SECTION_TAG, bt as AuthorizationFlowDisabledError, d as createEventAutomation, en as normalizeToolNameFromResult, f as deleteEventAutomation, g as listEventAutomationsForTeam, gt as PluginCredentialFailureError, hn as getAgentContextInputLimitTokens, ht as createPluginEgress, i as readScheduledAutomation, in as REQUEST_CONTEXT_SECTION_TAG, kt as saveTurnCheckpoint, m as getEventAutomation, mn as getAgentContextCompactionTriggerTokens, n as listScheduledAutomationsForTeam, nn as stripRuntimeTurnContext, nt as fallbackShortTitle, on as TURN_CONTEXT_TAG, pn as estimateTextTokens, q as recordToolExecutionStarted, qt as getUserMessageInstructionText, rn as trimTrailingAssistantMessages, rt as resolveTaskTitle, t as createScheduledAutomation, tn as retainRuntimeTurnContext, v as saveEventAutomation, vt as authorizationId, xn as historyItemFromPiMessage, xt as AuthorizationPauseError, y as setEventAutomationStatus, yt as AuthPausePersistenceError, z as recordAgentsInstructionsUpdated, zt as TurnToolCallLimitExceededError } from "./tasks-DGbrur6x.js";
2
+ import { S as resolveGatewayCredential, _ as getProviderErrorAttributes, a as completeText, b as MISSING_GATEWAY_CREDENTIALS_ERROR, c as COMPACTION_SUMMARY_PREFIX, d as renderCurrentInstruction, f as unwrapCurrentInstruction, g as findProviderError, h as createProviderError, i as completeObject, l as hasCompactedConversationContext, m as ProviderError, n as GEN_AI_SERVER_ADDRESS, p as escapeXml, s as resolveGatewayModel, t as GEN_AI_PROVIDER_NAME, u as isCompactionSummaryText, x as getGatewayApiKey, y as isProviderRetryError } from "./client-DX34VNtH.js";
3
+ import { n as botConfig, v as normalizeSlackEmojiName } from "./config-BayQ9hHH.js";
4
+ import { R as normalizeIdentityEmail, S as summarizeMessageText, T as withSpan, V as toOptionalString, _ as serializeGenAiAttribute, a as extractGenAiUsageSummary, b as setSpanStatus, c as getLogContextAttributesForSpan, d as logError, f as logException, h as normalizeGenAiFinishReason, i as extractGenAiUsageAttributes, l as getTracePropagationHeaders, m as logWarn, p as logInfo, w as withLogContext, x as setTags, y as setSpanAttributes, z as isRecord$4 } from "./logging-D2QBriUo.js";
5
+ import { g as withActiveSpan, m as startInactiveSpan } from "./sentry-MDkYAVPV.js";
6
+ 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-frjQCJa9.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-Bg8EoCKD.js";
8
8
  import { a as isUserActor, d as parseSlackTeamId, f as parseSlackUserId, g as parseSlackMessageTs, l as parseSlackChannelId, u as parseSlackChannelReferenceId } from "./actor-tlxzqaRe.js";
9
- import { C as addAgentTurnUsage, D as hasAgentTurnUsage, R as parseDestination, c as getConversationEventStore, d as getDb, f as getSqlExecutor, l as getConversationMessageSearchStore, r as readActorIdentity, u as getConversationStore, w as agentTurnCostUsd } from "./viewer-DmNRM88V.js";
9
+ import { O as hasAgentTurnUsage, T as agentTurnCostUsd, d as getConversationStore, f as getDb, l as getConversationEventStore, p as getSqlExecutor, r as readActorIdentity, u as getConversationMessageSearchStore, w as addAgentTurnUsage, z as parseDestination } from "./viewer-B2wXNspU.js";
10
10
  import { a as juniorAgentInvocations, c as juniorIdentities, d as juniorDestinations, i as juniorAgentBindings, s as juniorConversations } from "./agent-invocations-CxKldAeB.js";
11
- import { _ as juniorConversationAnnotations, a as juniorAutomationRuns, b as juniorAttachments, c as juniorStats, f as juniorConversationBriefs, x as juniorArtifacts } from "./executor-J9k2sp9m.js";
11
+ import { _ as juniorConversationAnnotations, a as juniorAutomationRuns, b as juniorAttachments, c as juniorStats, f as juniorConversationBriefs, x as juniorArtifacts } from "./executor-CAr7xQr2.js";
12
12
  import { d as contextProvenance, f as instructionActors, m as sameActorIdentity, p as instructionProvenanceFor, t as KNOWN_CONVERSATION_EVENT_TYPES, u as agentInstructionProvenance } from "./history-AY8rs-FR.js";
13
13
  import { a as listReferenceFiles, c as soulPathCandidates, l as worldPathCandidates } from "./package-discovery-DJBompdd.js";
14
- import { c as fetchWithBoundedOAuthErrorBodies, d as actorLogContext, f as credentialContextForActor, g as credentialUserSubjectId, i as resolvePluginHeaderEnvRefs, l as getOAuthProviderErrorAttributes, s as OAuthProviderError } from "./registry-BFzQFV_y.js";
15
- import { n as pluginCatalogRuntime } from "./catalog-runtime-Suf-aLlh.js";
16
- import { a as parseSkillInvocation, i as parseSkillFile, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-Dbzx9-rS.js";
17
- import { A as getWorkspaceSnapshotBuilder, B as STOP_WATCHING_TOOL_NAME, C as WorkspaceValidationError, D as setWorkspaceSnapshotBuild, E as setWorkspaceSnapshot, F as isSlackMessageTurn, G as createWatch, Gt as saveObjectAnnotations, H as cancelWatch, I as slackMessageTurnDisabledReason, J as getWatch, K as deliverWatch, Kt as createPluginAnnotations, L as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, M as workspaceRepoCheckoutPath, N as resolveChannelCapabilities, O as SANDBOX_RUNTIME, P as getSlackToolContext, R as RESOURCE_SUBSCRIPTION_MAX_TTL_MS, S as updateWorkspace, St as PluginToolDeniedError, T as loadSnapshotsForProfile, V as cancelSubscriptions, Vt as matchSlackAttachments, W as createTimerWatch, Xt as resolveUserTimezone, Y as listWatches, Yt as defaultTimezone, _ as deleteWorkspace, _t as getDashboardConversationLink, at as downloadPrivateSlackFile, b as listWorkspaces, c as getPluginTools, ct as getSlackClient, dt as normalizeSlackConversationId, en as JUNIOR_NATIVE_EVENT_NAMESPACE, g as createWorkspace, in as conversationNoteEvent, it as SlackActionError, j as tryWorkspaceRepoCheckoutPath, k as deleteWorkspaceSnapshotBuilders, l as getPluginUserPromptContributions, lt as isConversationScopedChannel, ot as getFilePermalink, pt as withSlackRetries, q as findMatchingWatches, r as createPluginHookRunner, s as getPluginSystemPromptContributions, u as getPlugins, ut as isDmChannel$1, v as getWorkspace, w as invalidateReadySnapshot, xt as ToolInputError, y as getWorkspaceByName, yt as getDashboardTaskLink, z as RESOURCE_WATCH_TOOL_SOURCE } from "./agent-hooks-CqnZfuCt.js";
18
- import { o as fenceLock, r as getStateAdapter, s as withLock } from "./adapter-BIacI0Bt.js";
14
+ import { c as fetchWithBoundedOAuthErrorBodies, d as actorLogContext, f as credentialContextForActor, g as credentialUserSubjectId, i as resolvePluginHeaderEnvRefs, l as getOAuthProviderErrorAttributes, s as OAuthProviderError } from "./registry-COTeZ2cV.js";
15
+ import { n as pluginCatalogRuntime } from "./catalog-runtime-D3qbJlYz.js";
16
+ import { a as parseSkillInvocation, i as parseSkillFile, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-Bb2KaJ3m.js";
17
+ import { $n as defaultTimezone, A as setWorkspaceSnapshotBuild, At as RESOURCE_SUBSCRIPTION_MAX_TTL_MS, B as wrapSandboxSetupError, Bt as getWatch, C as listWorkspaces, Cn as SANDBOX_WORKSPACE_ROOT, Ct as tryWorkspaceRepoCheckoutPath, D as invalidateReadySnapshot, Dt as isSlackMessageTurn, E as WorkspaceValidationError, En as sandboxSkillPathResolution, Et as getSlackToolContext, F as ensureDockerDaemon, Gn as matchSlackAttachments, H as getWorkspaceSnapshotNotReadyError, I as getSandboxProvider, It as createTimerWatch, J as consumeSandboxEgressAuthRequiredSignal, L as isAbortError, Lt as createWatch, M as create, Mt as STOP_WATCHING_TOOL_NAME, N as hash, Nt as cancelSubscriptions, O as loadSnapshotsForProfile, Ot as slackMessageTurnDisabledReason, P as isStale, Pt as cancelWatch, Qt as getFilePermalink, R as isAlreadyExistsError, Rt as deliverWatch, S as getWorkspaceByName, Sn as SANDBOX_SKILLS_ROOT, T as updateWorkspace, Tn as sandboxSkillFile, Tt as resolveChannelCapabilities, U as isWorkspaceSnapshotNotReadyError, V as WorkspaceSnapshotNotReadyError, Vt as listWatches, W as workspaceSnapshotNotReadyUserMessage, X as createSandboxEgressCredentialToken, Xn as createPluginAnnotations, Xt as SlackActionError, Y as consumeSandboxEgressPermissionDeniedSignal, Yn as saveObjectAnnotations, Zt as downloadPrivateSlackFile, _n as buildNonInteractiveShellScript, _t as openSlackDirectMessage, an as withSlackRetries, at as formatProviderLabel, b as deleteWorkspace, bn as SANDBOX_DATA_ROOT, bt as uploadFilesToConversation, cr as conversationNoteEvent, d as getPluginTools, en as getSlackClient, er as resolveUserTimezone, et as buildSandboxEgressNetworkPolicy, f as getPluginUserPromptContributions, fn as getDashboardTaskLink, gn as buildCommandScript, gt as getSlackMessagePermalink, hn as PluginToolDeniedError, ht as addReactionToMessage, ir as JUNIOR_NATIVE_EVENT_NAMESPACE, it as deliverOAuthAuthorization, j as SANDBOX_RUNTIME, jt as RESOURCE_WATCH_TOOL_SOURCE, k as setWorkspaceSnapshot, kt as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, mn as ToolInputError, n as createUserTokenStore, o as createPluginHookRunner, on as sleep, p as getPlugins, pt as slackMention, q as clearSandboxEgressSignals, r as getOAuthAccountProviders, rn as normalizeSlackConversationId, st as resolveBaseUrl, tn as isConversationScopedChannel, tt as resolveSandboxCommandEnvironment, u as getPluginSystemPromptContributions, un as getDashboardConversationLink, vn as runNonInteractiveCommand, wn as sandboxSkillDir, wt as workspaceRepoCheckoutPath, x as getWorkspace, xn as SANDBOX_REPOS_ROOT, y as createWorkspace, yn as SANDBOX_COMMAND_PATH, z as throwSandboxOperationError, zt as findMatchingWatches } from "./credentialed-C6pKlB1p.js";
18
+ import { o as fenceLock, r as getStateAdapter, s as withLock } from "./adapter-cUkPH3Om.js";
19
19
  import { i as isValidTimeZone, r as getZonedDateTimeParts } from "./cadence-R7Em4RjE.js";
20
20
  import { G as briefLinkSchema, H as detectImageMediaType, I as removedCardSchema, K as briefOutcomeStatusSchema, U as isVisionImageMediaType, q as conversationBriefSchema } from "./conversation-B0baEwoA.js";
21
- import { A as sandboxSkillPathResolution, C as SANDBOX_COMMAND_PATH, D as SANDBOX_WORKSPACE_ROOT, E as SANDBOX_SKILLS_ROOT, O as sandboxSkillDir, S as runNonInteractiveCommand, T as SANDBOX_REPOS_ROOT, _ as workspaceSnapshotNotReadyUserMessage, a as isAbortError, b as buildCommandScript, c as isSandboxCommandStreamInterruptedError, d as isSnapshottingError, f as throwSandboxOperationError, g as isWorkspaceSnapshotNotReadyError, h as getWorkspaceSnapshotNotReadyError, i as ensureDockerDaemon, k as sandboxSkillFile, 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 SANDBOX_DATA_ROOT, x as buildNonInteractiveShellScript, y as sleep } from "./profile-Dq5I7TV1.js";
22
- import { A as AgentMessageQueueFullError, F as agentNameSchema, H as TurnInputCommitLostError, I as AGENT_TYPES, K as isTurnInputCommitLostError, M as AgentNameInUseError, N as CHILD_AGENT_RESULTS, P as PARENT_AGENT_TARGET, V as CooperativeTurnYieldError, _ as getLatestAgentInvocationForConversation, d as getAgentInvocationIdForResult, f as getAgentInvocationMessageId, g as getChildAgentLockName, j as AgentMessageTargetError, k as AgentInvocationLimitError, t as NON_TERMINAL_AGENT_INVOCATION_STATUSES, v as invocationFromRow, y as isTerminalAgentInvocation, z as formatAgentTypes } from "./store-TKg1HVKx.js";
23
- import { a as isNoReplyMarker, i as NO_REPLY_MARKER, n as getAssistantReplyText, r as sanitizeAssistantText, t as decideReply } from "./assistant-reply-BFmjgJjD.js";
24
- import { A as requireSupportedEventMatch, B as readAutomationResult, C as eventNamespaceSchema, D as registeredEventTypeSchema, E as registeredEventMatchSchema, I as FINISH_AUTOMATION_RUN_TOOL_NAME, L as automationResultSchema, O as registeredResourceTypeSchema, T as pluginSupportsEvent, V as remindMissingAutomationResult, _ as WORKSPACE_SNAPSHOT_FAILED_EVENT, b as workspaceSnapshotWatch, d as getEventCatalog, k as requireEventIdentifier, n as markConversationsStopped, o as enqueueEventNotification, p as requireSlackChannelMessageScope, t as getConversationStoppedAtMs, v as WORKSPACE_SNAPSHOT_READY_EVENT, w as hasEventCatalogEntries, x as automationEventCatalog, y as workspaceSnapshotFinishedEvent } from "./session-stop-CtyJsnEj.js";
25
- 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-CnRHib0U.js";
26
- import { a as getVercelConversationWorkQueue, f as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-B4yTgklN.js";
27
- import { E as stopConversationWork } from "./store-UlOrW6JC.js";
28
- import { _ as getMcpProviderErrorAttributes, a as serviceAccountOnly, c as createMcpServiceAccountClientProvider, d as PluginMcpClient, f as McpProviderError, g as getMcpAwareTelemetryMessage, h as getMcpAwareErrorType, i as serviceAccountAllows, l as getMcpServiceAccountCredentials, m as McpToolError, p as McpServiceAccountRequiredError, u as McpAuthorizationRequiredError, v as toMcpProviderError } from "./service-account-x2QZXm4X.js";
29
- import { F as taskOutcomeInputSchema, M as compileScheduleIntent, N as scheduleIntentSchema, O as automationInstructionToolSchema, T as SCHEDULED_AUTOMATION_SYSTEM_ACTOR, j as ScheduleIntentError, k as automationTitleSchema } from "./automation-CWX0qL8U.js";
21
+ import { A as AgentMessageQueueFullError, F as agentNameSchema, H as TurnInputCommitLostError, I as AGENT_TYPES, K as isTurnInputCommitLostError, M as AgentNameInUseError, N as CHILD_AGENT_RESULTS, P as PARENT_AGENT_TARGET, V as CooperativeTurnYieldError, _ as getLatestAgentInvocationForConversation, d as getAgentInvocationIdForResult, f as getAgentInvocationMessageId, g as getChildAgentLockName, j as AgentMessageTargetError, k as AgentInvocationLimitError, t as NON_TERMINAL_AGENT_INVOCATION_STATUSES, v as invocationFromRow, y as isTerminalAgentInvocation, z as formatAgentTypes } from "./store-CqRnaZSq.js";
22
+ import { a as isNoReplyMarker, i as NO_REPLY_MARKER, n as getAssistantReplyText, r as sanitizeAssistantText, t as decideReply } from "./assistant-reply-UPA8vKlC.js";
23
+ import { A as requireEventIdentifier, D as registeredEventMatchSchema, E as hasEventCatalogEntries, H as remindMissingAutomationResult, L as FINISH_AUTOMATION_RUN_TOOL_NAME, O as registeredEventTypeSchema, R as automationResultSchema, S as describeRegisteredEventTrigger, T as eventWatchUnavailable, V as readAutomationResult, _ as WORKSPACE_SNAPSHOT_FAILED_EVENT, b as workspaceSnapshotWatch, d as getEventCatalog, j as requireValidEventTrigger, k as registeredResourceTypeSchema, n as markConversationsStopped, o as enqueueEventNotification, p as requireSlackChannelMessageScope, t as getConversationStoppedAtMs, v as WORKSPACE_SNAPSHOT_READY_EVENT, w as eventNamespaceSchema, x as automationEventCatalog, y as workspaceSnapshotFinishedEvent } from "./session-stop-CpCUy1ZJ.js";
24
+ import { a as setSnapshotSpanAttributes, i as postinstall, n as resolve$1, r as dependencies, s as getSandboxResources } from "./resolve-g9PKz9pH.js";
25
+ import { a as getVercelConversationWorkQueue, f as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-Cjo6Yg_b.js";
26
+ import { E as stopConversationWork } from "./store-DdT74Lvq.js";
27
+ import { _ as getMcpProviderErrorAttributes, a as serviceAccountOnly, c as createMcpServiceAccountClientProvider, d as PluginMcpClient, f as McpProviderError, g as getMcpAwareTelemetryMessage, h as getMcpAwareErrorType, i as serviceAccountAllows, l as getMcpServiceAccountCredentials, m as McpToolError, p as McpServiceAccountRequiredError, u as McpAuthorizationRequiredError, v as toMcpProviderError } from "./service-account-YdYftwV2.js";
28
+ import { F as taskOutcomeInputSchema, M as compileScheduleIntent, N as scheduleIntentSchema, O as automationInstructionToolSchema, T as SCHEDULED_AUTOMATION_SYSTEM_ACTOR, j as ScheduleIntentError, k as automationTitleSchema } from "./automation-2RbKzpMT.js";
30
29
  import { n as privateTraceResultAttributes } from "./private-trace-result-CE7_lEdq.js";
31
30
  import { streamSimple } from "@earendil-works/pi-ai/compat";
32
31
  import { createGatewayProvider } from "@ai-sdk/gateway";
@@ -36,13 +35,13 @@ import { isDeepStrictEqual } from "node:util";
36
35
  import { z } from "zod";
37
36
  import { createHash, randomBytes, randomUUID } from "node:crypto";
38
37
  import { and, asc, desc, eq, gt, gte, inArray, isNotNull, isNull, lt, lte, ne, notExists, or, sql } from "drizzle-orm";
39
- import { PluginToolInputError, eventSchema, missingToolAnnotationKeys, ownedObjectAnnotationSchema, sourceSchema, stableEventMatchKey, watchResultSchema } from "@sentry/junior-plugin-api";
38
+ import { PluginToolInputError, eventMatchFieldSchema, eventSchema, eventTriggerText, missingToolAnnotationKeys, ownedObjectAnnotationSchema, sourceSchema, stableEventMatchKey, watchResultSchema } from "@sentry/junior-plugin-api";
40
39
  import { alias } from "drizzle-orm/pg-core";
41
40
  import { Agent, estimateContextTokens } from "@earendil-works/pi-agent-core";
42
41
  import fs from "node:fs/promises";
43
42
  import fs$1 from "node:fs";
44
- import { Sandbox } from "@vercel/sandbox";
45
- import { isRetryableAssistantError } from "@earendil-works/pi-ai";
43
+ import { SignJWT, importPKCS8 } from "jose";
44
+ import { createAssistantMessageEventStream, isRetryableAssistantError } from "@earendil-works/pi-ai";
46
45
  import { Kind } from "@sinclair/typebox";
47
46
  import { Bash, defineCommand } from "just-bash";
48
47
  import { structuredPatch } from "diff";
@@ -53,7 +52,6 @@ import https from "node:https";
53
52
  import net from "node:net";
54
53
  import { NodeHtmlMarkdown } from "node-html-markdown";
55
54
  import { Value } from "@sinclair/typebox/value";
56
- import { SignJWT, importPKCS8 } from "jose";
57
55
  // src/chat/sandbox/skill-sandbox.ts
58
56
  const MAX_SKILL_FILE_BYTES = 262144;
59
57
  const DEFAULT_MAX_SKILL_FILE_CHARS = 2e4;
@@ -716,6 +714,53 @@ function buildChatEndAttributes(message, mode) {
716
714
  }
717
715
  return attributes;
718
716
  }
717
+ const NON_CONTENT_EVENT_TYPES = /* @__PURE__ */ new Set([
718
+ "start",
719
+ "done",
720
+ "error"
721
+ ]);
722
+ function createResponseTiming(requestStartedAtMs) {
723
+ let firstByteAtMs;
724
+ let firstToken;
725
+ return {
726
+ observe: (event) => {
727
+ if (firstByteAtMs === void 0 && event.type !== "error") firstByteAtMs = Date.now();
728
+ if (!firstToken && !NON_CONTENT_EVENT_TYPES.has(event.type)) firstToken = {
729
+ type: event.type,
730
+ receivedAtMs: Date.now()
731
+ };
732
+ },
733
+ attributes: () => {
734
+ if (firstByteAtMs === void 0) return { "gen_ai.response.streaming": false };
735
+ return {
736
+ "gen_ai.response.streaming": true,
737
+ "app.ai.time_to_first_byte_ms": firstByteAtMs - requestStartedAtMs,
738
+ ...firstToken ? {
739
+ "gen_ai.response.time_to_first_chunk": (firstToken.receivedAtMs - requestStartedAtMs) / 1e3,
740
+ "app.ai.first_token_type": firstToken.type
741
+ } : void 0
742
+ };
743
+ }
744
+ };
745
+ }
746
+ function relayStream(source, onEvent) {
747
+ const relayed = createAssistantMessageEventStream();
748
+ const finished = (async () => {
749
+ try {
750
+ for await (const event of source) {
751
+ onEvent(event);
752
+ relayed.push(event);
753
+ }
754
+ } finally {
755
+ relayed.end();
756
+ }
757
+ })();
758
+ finished.then(() => source.result()).then((message) => relayed.end(message), () => {});
759
+ return {
760
+ stream: relayed,
761
+ finished
762
+ };
763
+ }
719
764
  /**
720
765
  * Wraps pi-ai's `streamSimple` so each LLM call inside a pi-agent-core agent
721
766
  * loop produces its own `gen_ai.chat` Sentry span. The returned function is
@@ -737,10 +782,16 @@ function createTracedStreamFn(baseOrOptions = streamSimple) {
737
782
  }
738
783
  });
739
784
  try {
785
+ const requestStartedAtMs = Date.now();
740
786
  const stream = await withActiveSpan(span, () => Promise.resolve(base(model, context, options)));
741
- stream.result().then((finalMessage) => {
787
+ const responseTiming = createResponseTiming(requestStartedAtMs);
788
+ const relay = relayStream(stream, responseTiming.observe);
789
+ relay.finished.then(() => stream.result()).then((finalMessage) => {
742
790
  try {
743
- const endAttributes = buildChatEndAttributes(finalMessage, mode);
791
+ const endAttributes = {
792
+ ...buildChatEndAttributes(finalMessage, mode),
793
+ ...responseTiming.attributes()
794
+ };
744
795
  for (const [key, value] of Object.entries(endAttributes)) span.setAttribute(key, value);
745
796
  if (finalMessage.stopReason === "error") {
746
797
  const summary = endAttributes["app.ai.provider_error.summary"];
@@ -753,6 +804,7 @@ function createTracedStreamFn(baseOrOptions = streamSimple) {
753
804
  span.end();
754
805
  }
755
806
  }, (error) => {
807
+ span.setAttributes(responseTiming.attributes());
756
808
  span.setAttribute("error.type", error instanceof Error ? error.name : typeof error);
757
809
  span.setStatus({
758
810
  code: 2,
@@ -760,7 +812,7 @@ function createTracedStreamFn(baseOrOptions = streamSimple) {
760
812
  });
761
813
  span.end();
762
814
  }).catch(() => {});
763
- return stream;
815
+ return relay.stream;
764
816
  } catch (error) {
765
817
  span.setAttribute("error.type", error instanceof Error ? error.name : typeof error);
766
818
  span.setStatus({
@@ -1664,7 +1716,7 @@ function formatAvailableSkillsForPrompt(skills) {
1664
1716
  }
1665
1717
  function formatActiveMcpCatalogsForPrompt(catalogs) {
1666
1718
  if (catalogs.length === 0) return null;
1667
- const lines = ["Active MCP provider catalogs are available through `searchMcpTools`. Call it with provider to list descriptors or with query to narrow results, then pass the exact returned `tool_name` to `callMcpTool`. Put provider fields inside `arguments`."];
1719
+ const lines = [];
1668
1720
  for (const catalog of catalogs) {
1669
1721
  lines.push(" <catalog>");
1670
1722
  lines.push(` <provider>${escapeXml(catalog.provider)}</provider>`);
@@ -1702,31 +1754,22 @@ const SLACK_HEADER = "You are a Slack-based helper assistant. Follow the persona
1702
1754
  const LOCAL_HEADER = "You are a helper assistant. Follow the personality section for voice and tone in every reply. Platform mechanics and output rules override personality and world context when they conflict.";
1703
1755
  const TURN_CONTEXT_HEADER = "Runtime context for this request. Treat these blocks as trusted runtime facts; the static system prompt remains authoritative.";
1704
1756
  const TOOL_POLICY_RULES = [
1705
- "- Tool schemas are the source of truth for parameters; tool names are case-sensitive, so call tools exactly by their exposed names and do not invent arguments.",
1706
1757
  "- Use tools for actionable work and for facts that are mutable, external, repository-backed, provider-backed, or requested as verified/current. Stable general knowledge and already-provided context may be answered directly.",
1707
1758
  "- Do not use tools to rediscover content already present in the current conversation. For drafting or rewriting with no referenced retrievable source, use clear placeholders or ask one focused question instead of searching unrelated memory, history, files, or providers.",
1708
1759
  "- Resolve provider action targets before calls: explicit target wins; ambient `<configuration>` fills omitted targets. Treat non-target links/references as context.",
1709
1760
  "- Verification source order: conversation/thread context; user-provided attachments, links, and reference files; local/sandbox files when present; loaded skill references; repository/provider tools; public web. Use the nearest authoritative available source before weaker sources.",
1710
1761
  "- For repository or implementation questions, inspect the target repository first: local checkout when present, otherwise the configured GitHub/source provider. Do not treat loaded skill files as repo source unless the user asks about the skill. Cite file paths, symbols, PRs/issues, commits, or URLs that support the answer.",
1711
- "- Workspaces are named prepared Sandbox recipes. Use `listWorkspaces` and `switchWorkspace` with them. Prefer a matching Workspace over an ad-hoc checkout when one fits.",
1712
1762
  "- After changing files, name the changed paths and summarize the completed result in the final answer.",
1713
- "- 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.",
1714
- "- For user-provided URLs, use `webFetch`; for discovery, use `webSearch` then fetch/read promising sources; for current time/date context, use `systemTime`.",
1715
- "- 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.",
1716
1763
  "- 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.",
1717
1764
  "- Cards returned by tools attach to your next visible reply automatically. Explain the outcome; do not repeat the card fields or draw a card in text.",
1718
- "- 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.",
1719
- "- Scheduled and event automations use their creator's connected credentials by default when the requested work needs them. Do not ask for separate confirmation merely to use those credentials. On creation, omit credentialMode for this default; set system only when the creator requires it. For updates, creator means the original createdBy actor, not the current requester. Only that creator may enable creator credential use; another requester's confirmation cannot authorize it.",
1720
- "- 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.",
1721
- "- Before loading a skill or starting substantial work, decide how to run it. When `handoff` is available and another profile fits better, switch first. When `spawnAgent` is available and its delegation rules fit, give independent tracks to child agents. Otherwise do the work inline.",
1722
- "- 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.",
1765
+ "- Scheduled and event automations use their creator's connected credentials by default when the requested work needs them. Do not ask for separate confirmation merely to use those credentials.",
1766
+ "- Before loading a skill or starting substantial work, decide whether `handoff` or `spawnAgent` fits better than inline work.",
1723
1767
  "- 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."
1724
1768
  ];
1725
1769
  const TOOL_CALL_STYLE_RULES = [
1726
1770
  "- For routine low-risk tool use, call the tool directly without narrating the obvious step first.",
1727
1771
  "- Briefly narrate only when it helps the user understand multi-step work, sensitive actions, destructive actions, or a notable change in approach.",
1728
- "- When a first-class tool exists for an action, use it directly instead of asking the user to run an equivalent command, slash command, or manual lookup.",
1729
- "- Keep tool-call explanations separate from final answers; final answers should report results, evidence, or blockers."
1772
+ "- When a first-class tool exists for an action, use it directly instead of asking the user to run an equivalent command, slash command, or manual lookup."
1730
1773
  ];
1731
1774
  const SKILL_POLICY_RULES = [
1732
1775
  "- A `<skill>` block in the current user turn is already loaded. Follow its instructions directly and do not call `loadSkill` for that skill.",
@@ -1739,9 +1782,8 @@ const PLANNING_RULES = [
1739
1782
  "- The tool displays the plan. Do not repeat it in chat, and do not finish with a plan when you can complete the work now."
1740
1783
  ];
1741
1784
  const TASK_EXECUTION_RULES = [
1742
- "- Actionable request: act in this turn.",
1743
1785
  "- Continue until done, genuinely blocked, or waiting on child agents you started. Do not finish with a plan, promise, or offer to check next when an available tool or source can move the request forward.",
1744
- "- Ask the user only for missing access, approval, or a decision that blocks safe progress. Ask one focused question; otherwise infer conservatively and continue.",
1786
+ "- Ask the user only for missing access or a decision that blocks safe progress. Ask one focused question; otherwise infer conservatively and continue. An open scope or follow-up question does not block delivery: deliver the requested work and state the question.",
1745
1787
  "- For conflicting evidence, compare sources and state which source is authoritative for the answer.",
1746
1788
  "- A tool result with `timed_out: true` means that attempt did not finish. Continue the active task. Before retrying work that may have side effects, inspect authoritative state and do not repeat a mutation that already applied."
1747
1789
  ];
@@ -1753,8 +1795,7 @@ const CONVERSATION_RULES = [
1753
1795
  "- Runtime owns continuation and authorization notices; on resumed turns, answer with the final requested content only."
1754
1796
  ];
1755
1797
  const SLACK_ACTION_RULES = [
1756
- "- Slack posts, reactions, new canvases, new lists, and file sends go only to the current conversation; if asked to send one somewhere else, explain the limitation instead of calling the tool. Slack read tools can target other public channels with `channel_id`.",
1757
- "- Assistant text is delivered only into the active conversation or thread. You cannot create a new top-level channel post; if asked to do so, explain that limitation and do not present the requested text as delivered.",
1798
+ "- Assistant text, Slack posts, reactions, new canvases, new lists, and file sends go only to the current conversation or thread. Your reply is not a channel post, and you cannot create a new top-level channel post. When asked to post to a channel or anywhere else right now, explain that limitation; do not call a Slack send tool, and do not reply with only the requested text or present it as delivered. Scheduled automations can still post to the active channel later. Slack read tools can target other public channels with `channel_id`.",
1758
1799
  "- Ambient reaction requests target the current inbound message; do not ask for a message reference.",
1759
1800
  `- When no visible thread reply is requested or useful, keep tool-calling messages text-free and make the final message exactly ${NO_REPLY_MARKER}.`
1760
1801
  ];
@@ -1898,22 +1939,12 @@ function formatDestinationLines(destination) {
1898
1939
  `- destination.channel_id: ${escapeXml(destination.channelId)}`
1899
1940
  ];
1900
1941
  }
1901
- function formatOutcomeLines(outcomes) {
1902
- if (!outcomes) return ["- dispatch.outcomes: send_message to the destination below (legacy default)"];
1903
- if (outcomes.length === 0) return ["- dispatch.outcomes: none; successful work posts nothing"];
1904
- return outcomes.map((outcome, index) => {
1905
- const { channelId, threadTs } = outcome.destination;
1906
- const recipient = isDmChannel$1(channelId) ? "the creator's direct message" : "a slack channel";
1907
- const target = [`channel_id=${escapeXml(channelId)}`, ...threadTs ? [`thread_ts=${escapeXml(threadTs)}`] : []].join(" ");
1908
- return `- dispatch.outcome.${index + 1}: ${outcome.action} to ${recipient} (${target})`;
1909
- });
1910
- }
1911
1942
  function buildDispatchSection(params) {
1912
1943
  if (!params) return null;
1913
1944
  const metadataLines = Object.entries(params.metadata ?? {}).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `- dispatch.metadata.${escapeXml(key)}: ${escapeXml(value)}`);
1914
1945
  return renderTag("dispatch", [
1915
1946
  "- dispatch.execution: execute the dispatched input now",
1916
- ...params.declaresResult ? formatOutcomeLines(params.outcomes) : ["- dispatch.delivery: the runtime delivers the final answer to the destination", "- dispatch.delivery_rule: do not request or require a separate posting tool just to deliver the final answer"],
1947
+ ...params.declaresResult ? [] : ["- dispatch.delivery: the runtime delivers the final answer to the destination", "- dispatch.delivery_rule: do not request or require a separate posting tool just to deliver the final answer"],
1917
1948
  ...params.actor ? [`- dispatch.actor.platform: ${escapeXml(params.actor.platform)}`, `- dispatch.actor.name: ${escapeXml(params.actor.name)}`] : [],
1918
1949
  ...params.plugin ? [`- dispatch.plugin: ${escapeXml(params.plugin)}`] : [],
1919
1950
  ...formatSourceLines(params.source),
@@ -2718,24 +2749,38 @@ function createJrRpcCommand(deps) {
2718
2749
  });
2719
2750
  });
2720
2751
  }
2752
+ function toolCommandResult(command, output) {
2753
+ return {
2754
+ ok: output.exitCode === 0,
2755
+ command,
2756
+ cwd: "/",
2757
+ exit_code: output.exitCode,
2758
+ signal: null,
2759
+ timed_out: false,
2760
+ stdout: output.stdout,
2761
+ stderr: output.stderr,
2762
+ stdout_truncated: false,
2763
+ stderr_truncated: false
2764
+ };
2765
+ }
2766
+ const CHAINED_JR_RPC_PATTERN = /(?:&&|\|\||[;|\n])\s*jr-rpc(?:\s|$)/;
2767
+ /** Run a standalone `jr-rpc` bash command, or reject one chained after other shell steps. */
2721
2768
  async function maybeExecuteJrRpcCustomCommand(command, deps) {
2722
2769
  const normalized = command.trim();
2723
- if (!/^jr-rpc(?:\s|$)/.test(normalized)) return { handled: false };
2724
- const execResult = await new Bash({ customCommands: [createJrRpcCommand(deps)] }).exec(normalized);
2770
+ if (!/^jr-rpc(?:\s|$)/.test(normalized)) {
2771
+ if (!CHAINED_JR_RPC_PATTERN.test(normalized)) return { handled: false };
2772
+ return {
2773
+ handled: true,
2774
+ result: toolCommandResult(normalized, {
2775
+ exitCode: 2,
2776
+ stdout: "",
2777
+ stderr: "jr-rpc runs only as a standalone bash command. Run the jr-rpc command by itself, without cd, &&, pipes, or other commands.\n"
2778
+ })
2779
+ };
2780
+ }
2725
2781
  return {
2726
2782
  handled: true,
2727
- result: {
2728
- ok: execResult.exitCode === 0,
2729
- command: normalized,
2730
- cwd: "/",
2731
- exit_code: execResult.exitCode,
2732
- signal: null,
2733
- timed_out: false,
2734
- stdout: execResult.stdout,
2735
- stderr: execResult.stderr,
2736
- stdout_truncated: false,
2737
- stderr_truncated: false
2738
- }
2783
+ result: toolCommandResult(normalized, await new Bash({ customCommands: [createJrRpcCommand(deps)] }).exec(normalized))
2739
2784
  };
2740
2785
  }
2741
2786
  // src/chat/sandbox/command-result.ts
@@ -2960,9 +3005,9 @@ const BUILD_COMMAND_TIMEOUT_ERROR = "Workspace snapshot build phase timed out af
2960
3005
  const COMMAND_STATUS_POLL_TIMEOUT_MS = 1e3;
2961
3006
  /** Leave time to save the build state before this request ends. */
2962
3007
  const STOP_BUFFER_MS = 4e4;
2963
- /** Keep the build open when a request stops or Vercel has a short failure. */
3008
+ /** Keep the build open when a request stops or the provider has a short failure. */
2964
3009
  function isCancelOrTransient(error) {
2965
- return isAbortError(error) || isSandboxApiTransientError(error);
3010
+ return isAbortError(error) || getSandboxProvider().errors.isTransient(error);
2966
3011
  }
2967
3012
  function buildLockKey(profileHash) {
2968
3013
  return `${BUILD_LOCK_PREFIX}:${profileHash}`;
@@ -3003,7 +3048,7 @@ function activeBuild(build) {
3003
3048
  }
3004
3049
  async function deleteBuilder(sandboxName) {
3005
3050
  if (!sandboxName) return;
3006
- await deleteWorkspaceSnapshotBuilders([sandboxName]);
3051
+ await getSandboxProvider().deleteWorkspaceSnapshotBuilders([sandboxName]);
3007
3052
  }
3008
3053
  function workspaceDeletedError(workspace) {
3009
3054
  return /* @__PURE__ */ new Error(`Workspace ${workspace.name} was deleted while its snapshot was building`);
@@ -3044,8 +3089,8 @@ async function finishBuild(workspace, value, signal, beforeWrite) {
3044
3089
  if (!build?.commandId || !build.sandboxName) return null;
3045
3090
  try {
3046
3091
  await requireRemainingBuildTime(workspace, build, beforeWrite);
3047
- const sandbox = await getWorkspaceSnapshotBuilder(build.sandboxName, signal);
3048
- const command = await sandbox.getCommand(build.commandId, { signal });
3092
+ const builder = await getSandboxProvider().getWorkspaceSnapshotBuilder(build.sandboxName, signal);
3093
+ const command = await builder.getCommand(build.commandId, { signal });
3049
3094
  const pollSignal = AbortSignal.timeout(COMMAND_STATUS_POLL_TIMEOUT_MS);
3050
3095
  const waitSignal = signal ? AbortSignal.any([signal, pollSignal]) : pollSignal;
3051
3096
  let finished;
@@ -3065,7 +3110,7 @@ async function finishBuild(workspace, value, signal, beforeWrite) {
3065
3110
  throw new Error(`Workspace ${workspace.name} snapshot setup failed: ${detail}`);
3066
3111
  }
3067
3112
  await requireRemainingBuildTime(workspace, build, beforeWrite);
3068
- const snapshot = await sandbox.snapshot({ signal });
3113
+ const snapshot = await builder.snapshot({ signal });
3069
3114
  await requireRemainingBuildTime(workspace, build, beforeWrite);
3070
3115
  const createdAtMs = Date.now();
3071
3116
  const buildDurationMs = Math.max(0, createdAtMs - build.startedAt.getTime());
@@ -3080,7 +3125,7 @@ async function finishBuild(workspace, value, signal, beforeWrite) {
3080
3125
  }, { buildId: build.id });
3081
3126
  requireBuildWrite(result.written, workspace);
3082
3127
  try {
3083
- await deleteWorkspaceSnapshotBuilders(result.replacedBuilderNames);
3128
+ await getSandboxProvider().deleteWorkspaceSnapshotBuilders(result.replacedBuilderNames);
3084
3129
  } catch (error) {
3085
3130
  logException(error, "sandbox.workspace_snapshot.builder.delete_failed", {
3086
3131
  "app.workspace.id": workspace.id,
@@ -3107,19 +3152,16 @@ async function finishBuild(workspace, value, signal, beforeWrite) {
3107
3152
  /** Create the Sandbox and save its name. */
3108
3153
  async function startBuild(params) {
3109
3154
  const { workspace, value, signal } = params;
3110
- const credentials = getVercelSandboxCredentials();
3111
3155
  const resources = getSandboxResources(workspace);
3112
3156
  const name = builderName();
3113
3157
  const buildId = randomUUID();
3114
3158
  const startedAt = /* @__PURE__ */ new Date();
3115
3159
  try {
3116
- await Sandbox.create({
3160
+ await getSandboxProvider().createWorkspaceSnapshotBuilder({
3117
3161
  name,
3118
- persistent: true,
3119
- timeout: BUILD_TIMEOUT_MS,
3120
3162
  runtime: params.runtime,
3163
+ timeoutMs: BUILD_TIMEOUT_MS,
3121
3164
  signal,
3122
- ...credentials ?? {},
3123
3165
  ...resources ? { resources } : void 0
3124
3166
  });
3125
3167
  await params.beforeWrite();
@@ -3181,8 +3223,8 @@ async function continueBuild(params) {
3181
3223
  const phaseTimeoutSignal = AbortSignal.timeout(commandTimeoutMs);
3182
3224
  const phaseSignal = params.signal ? AbortSignal.any([params.signal, phaseTimeoutSignal]) : phaseTimeoutSignal;
3183
3225
  try {
3184
- const sandbox = await getWorkspaceSnapshotBuilder(build.sandboxName, phaseSignal);
3185
- const session = createSandboxSession(sandbox);
3226
+ const builder = await getSandboxProvider().getWorkspaceSnapshotBuilder(build.sandboxName, phaseSignal);
3227
+ const session = builder.session();
3186
3228
  if (build.phase === "created") {
3187
3229
  await dependencies(session, params.value.dependencies, phaseSignal, commandTimeoutMs);
3188
3230
  await postinstall(session, params.value.postinstall, phaseSignal, commandTimeoutMs);
@@ -3212,16 +3254,15 @@ async function continueBuild(params) {
3212
3254
  return;
3213
3255
  }
3214
3256
  await params.beforeWrite();
3215
- const command = await sandbox.runCommand({
3257
+ const commandId = await builder.startDetachedCommand({
3216
3258
  ...workspaceSnapshotSetupCommand(params.workspace, build.id),
3217
- detached: true,
3218
3259
  timeoutMs: remainingMs,
3219
3260
  signal: phaseSignal
3220
3261
  });
3221
3262
  await params.beforeWrite();
3222
3263
  requireBuildWrite(await setWorkspaceSnapshotBuild(params.workspace.id, {
3223
3264
  ...build,
3224
- commandId: command.cmdId,
3265
+ commandId,
3225
3266
  error: null
3226
3267
  }), params.workspace);
3227
3268
  } catch (error) {
@@ -3318,7 +3359,7 @@ async function resolveWorkspaceSnapshot(params) {
3318
3359
  try {
3319
3360
  snapshot = await advanceWorkspaceSnapshot(current);
3320
3361
  } catch (error) {
3321
- if (!isSandboxApiTransientError(error)) throw error;
3362
+ if (!getSandboxProvider().errors.isTransient(error)) throw error;
3322
3363
  advanced = true;
3323
3364
  if (shouldStopForTimeLimit(current.shouldStop)) throw new WorkspaceSnapshotNotReadyError(workspace.name);
3324
3365
  await sleep(TRANSIENT_API_RETRY_MS, params.signal);
@@ -3583,6 +3624,42 @@ async function syncSkillsToSandbox(params) {
3583
3624
  });
3584
3625
  });
3585
3626
  }
3627
+ // src/chat/sandbox/workspace.ts
3628
+ /** Bind one tool call's cancellation to every sandbox filesystem operation. */
3629
+ function bindSandboxFileSystem(fs, signal) {
3630
+ if (!signal) return fs;
3631
+ return {
3632
+ readFile(filePath, options) {
3633
+ signal.throwIfAborted();
3634
+ return fs.readFile(filePath, {
3635
+ ...options,
3636
+ signal
3637
+ });
3638
+ },
3639
+ writeFile(filePath, content, options) {
3640
+ signal.throwIfAborted();
3641
+ return fs.writeFile(filePath, content, {
3642
+ ...options,
3643
+ signal
3644
+ });
3645
+ },
3646
+ readdir(filePath) {
3647
+ signal.throwIfAborted();
3648
+ return fs.readdir(filePath, { signal });
3649
+ },
3650
+ stat(filePath) {
3651
+ signal.throwIfAborted();
3652
+ return fs.stat(filePath, { signal });
3653
+ }
3654
+ };
3655
+ }
3656
+ /** Best-effort stop; ignore secondary stop failures during cleanup. */
3657
+ async function stopSession(session) {
3658
+ if (!session) return;
3659
+ try {
3660
+ await session.stop();
3661
+ } catch {}
3662
+ }
3586
3663
  // src/chat/sandbox/session.ts
3587
3664
  const DEFAULT_MAX_OUTPUT_LENGTH = 3e4;
3588
3665
  const DEFAULT_BASH_COMMAND_TIMEOUT_MS = 3e5;
@@ -3591,16 +3668,6 @@ const SNAPSHOT_BOOT_RETRY_DELAY_MS = 1e3;
3591
3668
  const SANDBOX_NAME_PREFIX = "junior-";
3592
3669
  const MAX_KEEPALIVE_INTERVAL_MS = 3e4;
3593
3670
  const MIN_KEEPALIVE_INTERVAL_MS = 1e3;
3594
- function sandboxFetchOptions(signal) {
3595
- if (!signal) return {};
3596
- return { fetch: (input, init) => {
3597
- const requestSignal = init?.signal ?? (input instanceof Request ? input.signal : void 0);
3598
- return globalThis.fetch(input, {
3599
- ...init,
3600
- signal: requestSignal ? AbortSignal.any([requestSignal, signal]) : signal
3601
- });
3602
- } };
3603
- }
3604
3671
  function truncateOutput(output, maxLength) {
3605
3672
  if (output.length <= maxLength) return {
3606
3673
  value: output,
@@ -3650,7 +3717,10 @@ function createSandboxRuntime(options) {
3650
3717
  keepAliveTimer = void 0;
3651
3718
  }
3652
3719
  };
3653
- const adaptSandbox = (vercelSandbox) => createSandboxSession(vercelSandbox, { onUnavailable: invalidateSession });
3720
+ const createSession = (input) => getSandboxProvider().createSession({
3721
+ ...input,
3722
+ onUnavailable: invalidateSession
3723
+ });
3654
3724
  const createSandboxName = () => `${SANDBOX_NAME_PREFIX}${randomUUID()}`;
3655
3725
  const preflightNetworkPolicy = (sandboxName) => options.createNetworkPolicy?.(sandboxName);
3656
3726
  const persistSandboxRef = async (nextRef) => {
@@ -3717,30 +3787,26 @@ function createSandboxRuntime(options) {
3717
3787
  }
3718
3788
  });
3719
3789
  };
3720
- const createSandboxFromSnapshot = async (snapshotId, sandboxCredentials, initialSandboxName, workspace, signal) => {
3790
+ const createSandboxFromSnapshot = async (snapshotId, initialSandboxName, workspace, signal) => {
3721
3791
  const resources = getSandboxResources(workspace);
3722
3792
  for (let attempt = 0; attempt < SNAPSHOT_BOOT_RETRY_COUNT; attempt += 1) {
3723
3793
  signal?.throwIfAborted();
3724
3794
  const sandboxName = attempt === 0 ? initialSandboxName : createSandboxName();
3725
3795
  const networkPolicy = preflightNetworkPolicy(sandboxName);
3726
3796
  try {
3727
- return adaptSandbox(await Sandbox.create({
3728
- timeout: timeoutMs,
3797
+ return await createSession({
3798
+ timeoutMs,
3729
3799
  ...networkPolicy ? {
3730
3800
  name: sandboxName,
3731
3801
  persistent: false,
3732
3802
  networkPolicy
3733
3803
  } : void 0,
3734
- source: {
3735
- type: "snapshot",
3736
- snapshotId
3737
- },
3804
+ snapshotId,
3738
3805
  ...resources ? { resources } : void 0,
3739
- ...sandboxCredentials ?? {},
3740
- ...sandboxFetchOptions(signal)
3741
- }));
3806
+ scopeSignal: signal
3807
+ });
3742
3808
  } catch (error) {
3743
- if (!isSnapshottingError(error) || attempt === 2) throw error;
3809
+ if (!getSandboxProvider().errors.isSnapshotting(error) || attempt === 2) throw error;
3744
3810
  await sleep(SNAPSHOT_BOOT_RETRY_DELAY_MS, signal);
3745
3811
  }
3746
3812
  }
@@ -3756,14 +3822,14 @@ function createSandboxRuntime(options) {
3756
3822
  }
3757
3823
  };
3758
3824
  const createSandboxFromResolvedSnapshot = async (params) => {
3759
- const { runtime, snapshot, sandboxCredentials, sandboxName, signal } = params;
3825
+ const { runtime, snapshot, sandboxName, signal } = params;
3760
3826
  signal?.throwIfAborted();
3761
3827
  if (!snapshot.snapshotId) {
3762
3828
  const networkPolicy = preflightNetworkPolicy(sandboxName);
3763
3829
  const resources = getSandboxResources(params.workspace);
3764
3830
  return {
3765
- session: adaptSandbox(await Sandbox.create({
3766
- timeout: timeoutMs,
3831
+ session: await createSession({
3832
+ timeoutMs,
3767
3833
  runtime,
3768
3834
  ...networkPolicy ? {
3769
3835
  name: sandboxName,
@@ -3771,19 +3837,18 @@ function createSandboxRuntime(options) {
3771
3837
  networkPolicy
3772
3838
  } : void 0,
3773
3839
  ...resources ? { resources } : void 0,
3774
- ...sandboxCredentials ?? {},
3775
- ...sandboxFetchOptions(signal)
3776
- })),
3840
+ scopeSignal: signal
3841
+ }),
3777
3842
  snapshot
3778
3843
  };
3779
3844
  }
3780
3845
  try {
3781
3846
  return {
3782
- session: await createSandboxFromSnapshot(snapshot.snapshotId, sandboxCredentials, sandboxName, params.workspace, signal),
3847
+ session: await createSandboxFromSnapshot(snapshot.snapshotId, sandboxName, params.workspace, signal),
3783
3848
  snapshot
3784
3849
  };
3785
3850
  } catch (error) {
3786
- if (!isMissingError(error)) throw error;
3851
+ if (!getSandboxProvider().errors.isSnapshotMissing(error)) throw error;
3787
3852
  setSpanAttributes({ "app.sandbox.snapshot.rebuild_after_missing": true });
3788
3853
  let rebuilt;
3789
3854
  if (params.workspace) rebuilt = await requireWorkspaceSnapshot({
@@ -3802,14 +3867,13 @@ function createSandboxRuntime(options) {
3802
3867
  if (!rebuilt.snapshotId) throw error;
3803
3868
  signal?.throwIfAborted();
3804
3869
  return {
3805
- session: await createSandboxFromSnapshot(rebuilt.snapshotId, sandboxCredentials, sandboxName, params.workspace, signal),
3870
+ session: await createSandboxFromSnapshot(rebuilt.snapshotId, sandboxName, params.workspace, signal),
3806
3871
  snapshot: rebuilt
3807
3872
  };
3808
3873
  }
3809
3874
  };
3810
3875
  const createSandboxCandidate = async (workspace, hash, signal) => {
3811
3876
  const runtime = SANDBOX_RUNTIME;
3812
- const sandboxCredentials = getVercelSandboxCredentials();
3813
3877
  const sandboxName = createSandboxName();
3814
3878
  const prepareWorkspace = workspace ? async (sandbox) => await prepareWorkspaceSnapshot({
3815
3879
  sandbox,
@@ -3840,7 +3904,6 @@ function createSandboxRuntime(options) {
3840
3904
  return (await createSandboxFromResolvedSnapshot({
3841
3905
  runtime,
3842
3906
  snapshot,
3843
- sandboxCredentials,
3844
3907
  sandboxName,
3845
3908
  signal,
3846
3909
  workspace,
@@ -3899,22 +3962,20 @@ function createSandboxRuntime(options) {
3899
3962
  if (!ref) return null;
3900
3963
  let hintedSandbox = null;
3901
3964
  try {
3902
- const sandboxCredentials = getVercelSandboxCredentials();
3903
3965
  hintedSandbox = await withSandboxSpan("sandbox.get", "sandbox.get", {
3904
3966
  "app.sandbox.reused": true,
3905
3967
  "app.sandbox.source": "id_hint"
3906
- }, async () => adaptSandbox(await Sandbox.get({
3968
+ }, async () => await getSandboxProvider().getSession({
3907
3969
  name: ref.id,
3908
- resume: true,
3909
- ...sandboxCredentials ?? {},
3910
- ...sandboxFetchOptions(signal)
3911
- })));
3970
+ onUnavailable: invalidateSession,
3971
+ scopeSignal: signal
3972
+ }));
3912
3973
  } catch (error) {
3913
- if (isSandboxMissingError(error)) {
3974
+ if (getSandboxProvider().errors.isMissing(error)) {
3914
3975
  sandboxRef = void 0;
3915
3976
  return null;
3916
3977
  }
3917
- if (isSandboxUnavailableError(error)) {
3978
+ if (getSandboxProvider().errors.isUnavailable(error)) {
3918
3979
  invalidateSession();
3919
3980
  throw error;
3920
3981
  }
@@ -3931,7 +3992,7 @@ function createSandboxRuntime(options) {
3931
3992
  });
3932
3993
  return rememberSandbox(hintedSandbox, networkPolicyKey);
3933
3994
  } catch (error) {
3934
- if (isSandboxUnavailableError(error)) throw error;
3995
+ if (getSandboxProvider().errors.isUnavailable(error)) throw error;
3935
3996
  return failSetup(error);
3936
3997
  }
3937
3998
  };
@@ -3941,13 +4002,21 @@ function createSandboxRuntime(options) {
3941
4002
  "app.sandbox.timeout_ms": timeoutMs,
3942
4003
  "app.sandbox.runtime": SANDBOX_RUNTIME,
3943
4004
  "app.sandbox.skills_count": availableSkills.length
3944
- }, async () => {
4005
+ }, async (setSpanAttributes) => {
3945
4006
  const cachedSandbox = await tryReuseCachedSandbox();
3946
- if (cachedSandbox) return cachedSandbox;
4007
+ if (cachedSandbox) {
4008
+ setSpanAttributes({ "app.sandbox.acquire.outcome": "memory" });
4009
+ return cachedSandbox;
4010
+ }
3947
4011
  signal?.throwIfAborted();
3948
4012
  const hintedSandbox = await tryRestoreHintedSandbox(signal);
3949
- if (hintedSandbox) return hintedSandbox;
3950
- return await createFreshSandbox(signal);
4013
+ if (hintedSandbox) {
4014
+ setSpanAttributes({ "app.sandbox.acquire.outcome": "resumed" });
4015
+ return hintedSandbox;
4016
+ }
4017
+ const createdSandbox = await createFreshSandbox(signal);
4018
+ setSpanAttributes({ "app.sandbox.acquire.outcome": "created" });
4019
+ return createdSandbox;
3951
4020
  });
3952
4021
  };
3953
4022
  const getOrAcquireSandbox = async (signal) => {
@@ -4017,7 +4086,7 @@ function createSandboxRuntime(options) {
4017
4086
  await session.extendTimeout(keepAliveMs);
4018
4087
  });
4019
4088
  } catch (error) {
4020
- if (isSandboxUnavailableError(error)) throw error;
4089
+ if (getSandboxProvider().errors.isUnavailable(error)) throw error;
4021
4090
  }
4022
4091
  };
4023
4092
  const startKeepAlive = (session) => {
@@ -5172,27 +5241,21 @@ function createSandbox(options) {
5172
5241
  const { bash: executeBash, sessionId: activeSessionId } = await runtime.tools(context.signal);
5173
5242
  await clearEgressSignals(activeSessionId);
5174
5243
  const result = await withSandboxToolSpan("bash", "process.exec", { "process.executable.name": "bash" }, async () => {
5175
- try {
5176
- const response = await executeBash({
5177
- command,
5178
- cwd,
5179
- ...env ? { env } : void 0,
5180
- ...timeoutMs ? { timeoutMs } : void 0,
5181
- ...context.signal ? { signal: context.signal } : void 0
5182
- });
5183
- setSpanAttributes({
5184
- "process.exit.code": response.exitCode,
5185
- "app.sandbox.stdout_bytes": Buffer.byteLength(response.stdout ?? "", "utf8"),
5186
- "app.sandbox.stderr_bytes": Buffer.byteLength(response.stderr ?? "", "utf8"),
5187
- ...response.aborted ? { "error.type": "outcome_unknown" } : response.exitCode !== 0 ? { "error.type": "nonzero_exit" } : {}
5188
- });
5189
- setSpanStatus(response.exitCode === 0 ? "ok" : "error");
5190
- return response;
5191
- } catch (error) {
5192
- setSpanAttributes({ "error.type": error instanceof Error ? error.name : "sandbox_execute_error" });
5193
- setSpanStatus("error");
5194
- throw error;
5195
- }
5244
+ const response = await executeBash({
5245
+ command,
5246
+ cwd,
5247
+ ...env ? { env } : void 0,
5248
+ ...timeoutMs ? { timeoutMs } : void 0,
5249
+ ...context.signal ? { signal: context.signal } : void 0
5250
+ });
5251
+ setSpanAttributes({
5252
+ "process.exit.code": response.exitCode,
5253
+ "app.sandbox.stdout_bytes": Buffer.byteLength(response.stdout ?? "", "utf8"),
5254
+ "app.sandbox.stderr_bytes": Buffer.byteLength(response.stderr ?? "", "utf8"),
5255
+ ...response.aborted ? { "error.type": "outcome_unknown" } : response.exitCode !== 0 ? { "error.type": "nonzero_exit" } : {}
5256
+ });
5257
+ setSpanStatus(response.exitCode === 0 ? "ok" : "error");
5258
+ return response;
5196
5259
  });
5197
5260
  const { authRequired, permissionDenied } = await consumeEgressSignals(activeSessionId);
5198
5261
  return formatSandboxCommandResult({
@@ -5386,8 +5449,8 @@ function createSandbox(options) {
5386
5449
  } catch (error) {
5387
5450
  params.signal?.throwIfAborted();
5388
5451
  if (getWorkspaceSnapshotNotReadyError(error)) return createWorkspaceSnapshotNotReadyToolResult(error);
5389
- if (isSandboxUnavailableError(error)) throw createSandboxUnavailableToolError(params.toolName, error);
5390
- if (isSandboxCommandStreamInterruptedError(error)) throw new ToolInputError(`The sandbox command stream was interrupted during ${params.toolName}, so the operation did not complete reliably. It may have produced side effects; inspect the workspace or retry only if it is safe.`, { cause: error });
5452
+ if (getSandboxProvider().errors.isUnavailable(error)) throw createSandboxUnavailableToolError(params.toolName, error);
5453
+ if (getSandboxProvider().errors.isCommandStreamInterrupted(error)) throw new ToolInputError(`The sandbox command stream was interrupted during ${params.toolName}, so the operation did not complete reliably. It may have produced side effects; inspect the workspace or retry only if it is safe.`, { cause: error });
5391
5454
  throw error;
5392
5455
  }
5393
5456
  throw new Error(`unsupported sandbox tool: ${params.toolName}`);
@@ -5398,7 +5461,7 @@ function createSandbox(options) {
5398
5461
  } catch (error) {
5399
5462
  const notReady = getWorkspaceSnapshotNotReadyError(error);
5400
5463
  if (notReady) throw new ToolInputError(workspaceSnapshotNotReadyUserMessage(notReady), { cause: notReady });
5401
- if (isSandboxUnavailableError(error)) throw createSandboxUnavailableToolError(operation, error);
5464
+ if (getSandboxProvider().errors.isUnavailable(error)) throw createSandboxUnavailableToolError(operation, error);
5402
5465
  throw error;
5403
5466
  }
5404
5467
  };
@@ -5664,7 +5727,7 @@ function upstreamPermissionDeniedText(value) {
5664
5727
  `Status: ${status}`,
5665
5728
  ...command ? [`Command: ${command}`] : [],
5666
5729
  "",
5667
- "Junior had a credential lease for this grant and forwarded the request. Do not diagnose this as a missing user token or a local Junior runtime block.",
5730
+ "The runtime had a credential lease for this grant and forwarded the request. Do not diagnose this as a missing user token or a local runtime block.",
5668
5731
  "Read the provider's error in the command output before you choose a cause. A provider can reject a request because of permissions, installation scope, SSO, or account access. It can also reject a valid credential because of the target's state, a rate limit, or another provider rule.",
5669
5732
  ...stderr ? ["", `stderr:\n${stderr}`] : [],
5670
5733
  ...stdout ? ["", `stdout:\n${stdout}`] : []
@@ -6068,7 +6131,7 @@ var McpToolManager = class {
6068
6131
  async clientForTool(plugin, client, toolName) {
6069
6132
  const provider = plugin.manifest.name;
6070
6133
  if (!this.serviceAccountProviders.has(provider) || serviceAccountAllows(plugin.manifest, { tool: toolName })) return client;
6071
- if (serviceAccountOnly(plugin.manifest)) throw new McpToolError(`${plugin.manifest.displayName} tool ${toolName} is not available: Junior's shared ${plugin.manifest.displayName} account cannot use it`);
6134
+ if (serviceAccountOnly(plugin.manifest)) throw new McpToolError(`${plugin.manifest.displayName} tool ${toolName} is not available: the shared ${plugin.manifest.displayName} account cannot use it`);
6072
6135
  const existing = this.actorClientsByProvider.get(provider);
6073
6136
  if (existing) return existing;
6074
6137
  const actorClient = await this.newClient(plugin);
@@ -6646,7 +6709,7 @@ function createLoadSkillTool(availableSkills, options) {
6646
6709
  readOnlyHint: false
6647
6710
  },
6648
6711
  description: "Load a skill by name for this turn. The result includes working_directory; resolve skill paths there and run skill-owned bash commands from there or with absolute paths. When the skill instructions name an MCP provider, use searchMcpTools before callMcpTool. Use when a request clearly matches a known skill.",
6649
- inputSchema: z.object({ skill_name: z.string().min(1).describe("Skill name to load, without the leading slash.") }),
6712
+ inputSchema: z.object({ skill_name: z.string().min(1).describe("Skill name to load, without the leading `$`.") }),
6650
6713
  outputSchema: juniorToolOutputSchema,
6651
6714
  execute: async ({ skill_name }) => {
6652
6715
  const result = await loadSkillFromHost(availableSkills, skill_name);
@@ -6795,10 +6858,10 @@ function createSearchMcpToolsTool(mcpToolManager) {
6795
6858
  openWorldHint: true,
6796
6859
  readOnlyHint: true
6797
6860
  },
6798
- description: "List or search MCP providers and active MCP tools. When provider is supplied and not yet active, Junior connects to it on demand and returns tool descriptors including schemas. Without provider, returns active tools plus matching configured providers without connecting. Use when choosing a provider tool or when callMcpTool arguments are unclear.",
6861
+ description: "List or search MCP providers and active MCP tools. When provider is supplied and not yet active, the runtime connects to it on demand and returns tool descriptors including schemas. Without provider, returns active tools plus matching configured providers without connecting. Use when choosing a provider tool or when callMcpTool arguments are unclear.",
6799
6862
  inputSchema: z.object({
6800
6863
  query: z.string().min(1).describe("Optional search terms describing the MCP tool or arguments needed.").optional(),
6801
- provider: z.string().min(1).describe("Optional provider name to list or search within. If configured but not yet connected, Junior activates it on demand.").optional(),
6864
+ provider: z.string().min(1).describe("Optional provider name to list or search within. If configured but not yet connected, the runtime activates it on demand.").optional(),
6802
6865
  intent: z.string().min(1).describe("Set this when you pass provider. A short purpose to show the user if this call needs them to connect their account, for example \"search Notion for the Q3 offsite doc\".").optional(),
6803
6866
  max_results: z.number().int().min(1).max(MAX_RESULTS$2).describe("Maximum matching tool descriptors to return.").optional()
6804
6867
  }).strict(),
@@ -7628,15 +7691,7 @@ const searchedResourceTypeSchema = z.object({
7628
7691
  identifierFormat: z.string().optional(),
7629
7692
  supportedEvents: z.array(z.string()),
7630
7693
  suggestedEvents: z.array(z.string()).optional(),
7631
- matchFields: z.record(z.string(), z.object({
7632
- kind: z.enum([
7633
- "boolean",
7634
- "string",
7635
- "number"
7636
- ]),
7637
- description: z.string(),
7638
- enum: z.array(z.string()).optional()
7639
- }).strict()).optional()
7694
+ matchFields: z.record(z.string(), eventMatchFieldSchema).optional()
7640
7695
  }).strict();
7641
7696
  const outputSchema$4 = juniorToolOutputSchema.extend({
7642
7697
  query: z.string().nullable(),
@@ -7666,7 +7721,7 @@ function createSearchEventTypesTool(catalog) {
7666
7721
  openWorldHint: false,
7667
7722
  readOnlyHint: true
7668
7723
  },
7669
- 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.",
7724
+ description: "Search the event types currently enabled without creating anything. Use only when the user asks what events are supported or the required resource type or event name is unclear. 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.",
7670
7725
  inputSchema: z.object({
7671
7726
  query: z.string().nullable().describe("Optional terms matching a namespace, resource type, or event name. Resource types that match more terms come first. Empty lists all enabled event types.").optional(),
7672
7727
  namespace: eventNamespaceSchema(catalog).nullable().describe("Optional enabled plugin namespace to search within.").optional(),
@@ -7801,15 +7856,7 @@ function inputSchema(catalog) {
7801
7856
  match: registeredEventMatchSchema(),
7802
7857
  intent: z.string().trim().min(1).max(4e3).describe("Concise reason this conversation wants these events, used when an event arrives."),
7803
7858
  ttlMs: z.coerce.number().describe("How long to keep the subscription active. Defaults to 14 days and must not exceed 30 days.").optional()
7804
- }).strict().superRefine((subscription, context) => {
7805
- subscription.events.forEach((eventType, index) => {
7806
- if (!pluginSupportsEvent(catalog, subscription.namespace, subscription.resourceType, eventType)) context.addIssue({
7807
- code: "custom",
7808
- message: `Resource type "${subscription.namespace}:${subscription.resourceType}" does not support event "${eventType}".`,
7809
- path: ["events", index]
7810
- });
7811
- });
7812
- });
7859
+ }).strict();
7813
7860
  }
7814
7861
  const stopWatchingActionSchema = z.object({
7815
7862
  execution_tool: z.literal("executeTool"),
@@ -7854,17 +7901,17 @@ function createWatchEventsTool(context, catalog) {
7854
7901
  inputSchema: inputSchema(catalog),
7855
7902
  outputSchema: outputSchema$2,
7856
7903
  async execute(input) {
7857
- if (input.namespace === "junior" && input.resourceType === "timer") throw new ToolInputError("Use watchTimer to create a timer Watch.");
7858
- if (input.namespace === "slack") throw new ToolInputError("Slack channel messages can trigger only an event automation in that channel. Use createEventAutomation.");
7904
+ const unavailable = eventWatchUnavailable(catalog, input.namespace, input.resourceType);
7905
+ if (unavailable) throw new ToolInputError(unavailable);
7859
7906
  const events = cleanStrings(input.events);
7860
- 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}".`);
7861
7907
  const intent = input.intent.trim();
7862
7908
  if (!intent) throw new ToolInputError("intent is required");
7863
- const match = requireSupportedEventMatch(catalog, {
7909
+ const match = requireValidEventTrigger(catalog, {
7910
+ events,
7864
7911
  match: input.match,
7865
7912
  namespace: input.namespace,
7866
7913
  resourceType: input.resourceType
7867
- });
7914
+ }, "watch");
7868
7915
  const nowMs = Date.now();
7869
7916
  const subscription = await createWatch({
7870
7917
  conversationId: context.conversationId,
@@ -7988,7 +8035,8 @@ const compactEventAutomationResultSchema = z.object({
7988
8035
  label: z.string().min(1),
7989
8036
  events: z.array(z.string().min(1)).min(1),
7990
8037
  match: z.record(z.string(), z.unknown()).optional(),
7991
- available: z.boolean()
8038
+ available: z.boolean(),
8039
+ problems: z.array(z.string().min(1)).min(1).optional()
7992
8040
  }).strict(),
7993
8041
  credentialMode: z.enum(["system", "creator"]),
7994
8042
  isCreator: z.boolean(),
@@ -8026,15 +8074,9 @@ function registeredEventAutomationTriggerSchema(catalog) {
8026
8074
  match: registeredEventMatchSchema()
8027
8075
  }).strict();
8028
8076
  }
8029
- /** Reject an event-automation trigger that is no longer supported by the catalog. */
8077
+ /** Reject an event-automation trigger that cannot work with the enabled plugins. */
8030
8078
  function requireSupportedEventAutomationTrigger(catalog, trigger) {
8031
- const plugins = automationEventCatalog(catalog);
8032
- for (const eventType of trigger.events) if (!pluginSupportsEvent(plugins, trigger.namespace, trigger.resourceType, eventType)) throw new ToolInputError(`Resource type "${trigger.namespace}:${trigger.resourceType}" does not support event "${eventType}".`);
8033
- return requireSupportedEventMatch(plugins, {
8034
- match: trigger.match,
8035
- namespace: trigger.namespace,
8036
- resourceType: trigger.resourceType
8037
- });
8079
+ return requireValidEventTrigger(automationEventCatalog(catalog), trigger, "event_automation");
8038
8080
  }
8039
8081
  /** Require the active Slack authority used for event-automation management. */
8040
8082
  function requireEventAutomationSlackContext(context) {
@@ -8069,12 +8111,18 @@ async function writableEventAutomation(context, id) {
8069
8111
  if (!task || task.status === "deleted" || !eventAutomationIsWritableFrom(task, destination)) throw new ToolInputError("Event automation was not found.");
8070
8112
  return task;
8071
8113
  }
8072
- function eventAutomationTriggerAvailable(task, catalog) {
8073
- const registration = automationEventCatalog(catalog)[task.trigger.namespace];
8074
- return Boolean(registration && task.trigger.events.every((eventType) => registration.resourceTypes.some((resourceType) => resourceType.supportedEvents.includes(eventType))));
8114
+ /**
8115
+ * Describe a saved trigger with the enabled plugins. Its problems say why it
8116
+ * cannot work: a plugin can remove or rename a resource type, event, or filter
8117
+ * after the trigger was saved. Resource types with `automation: false` never
8118
+ * dispatch event automations.
8119
+ */
8120
+ function describeEventAutomationTrigger(trigger, catalog) {
8121
+ return describeRegisteredEventTrigger(automationEventCatalog(catalog), trigger);
8075
8122
  }
8076
8123
  /** Project an event automation into the bounded tool-result shape. */
8077
8124
  function compactEventAutomation(task, catalog, requesterSlackUserId) {
8125
+ const { problems } = describeEventAutomationTrigger(task.trigger, catalog);
8078
8126
  return compactEventAutomationResultSchema.parse({
8079
8127
  id: task.id,
8080
8128
  status: task.status,
@@ -8089,7 +8137,8 @@ function compactEventAutomation(task, catalog, requesterSlackUserId) {
8089
8137
  label: task.trigger.label,
8090
8138
  events: task.trigger.events,
8091
8139
  ...task.trigger.match ? { match: task.trigger.match } : void 0,
8092
- available: eventAutomationTriggerAvailable(task, catalog)
8140
+ available: problems.length === 0,
8141
+ ...problems.length > 0 ? { problems } : void 0
8093
8142
  },
8094
8143
  credentialMode: task.credentialMode,
8095
8144
  isCreator: task.createdBy.slackUserId === requesterSlackUserId,
@@ -8109,7 +8158,7 @@ function compactEventAutomation(task, catalog, requesterSlackUserId) {
8109
8158
  /** Return the standard successful event-automation tool result. */
8110
8159
  async function eventAutomationToolResult(conversationId, task, catalog, requesterSlackUserId) {
8111
8160
  const automation = compactEventAutomation(task, catalog, requesterSlackUserId);
8112
- const filters = Object.entries(task.trigger.match ?? {}).map(([key, value]) => `${key} = ${JSON.stringify(value)}`);
8161
+ const description = describeEventAutomationTrigger(task.trigger, catalog);
8113
8162
  const title = automation.title ?? fallbackShortTitle(task.task.text, "Event automation");
8114
8163
  return {
8115
8164
  automation,
@@ -8121,13 +8170,9 @@ async function eventAutomationToolResult(conversationId, task, catalog, requeste
8121
8170
  title,
8122
8171
  url: automation.dashboardUrl,
8123
8172
  description: task.task.text,
8124
- status: automation.trigger.available ? "ready" : "unavailable",
8125
- trigger: [
8126
- task.trigger.label,
8127
- task.trigger.events.join(", "),
8128
- ...filters
8129
- ].join(" · "),
8130
- warning: !automation.trigger.available ? "Trigger unavailable. This automation cannot receive events." : void 0
8173
+ status: description.problems.length === 0 ? "ready" : "unavailable",
8174
+ trigger: eventTriggerText(task.trigger.label, description),
8175
+ warning: description.problems.length > 0 ? ["Trigger unavailable.", ...description.problems].join(" ") : void 0
8131
8176
  }])
8132
8177
  };
8133
8178
  }
@@ -8155,7 +8200,7 @@ function createEventAutomationTool(context, catalog) {
8155
8200
  readOnlyHint: false
8156
8201
  },
8157
8202
  executionMode: "sequential",
8158
- 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.",
8203
+ 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 only when the user explicitly asks for an event automation or durable whenever-this-happens-do-X automation; ordinary watch, notify, or tell-me-when requests use watchEvents instead. When the resource and events are known, create it without redundant confirmation. The automation may use the creator's connected credentials. Prefer a subscribable tool result when available.",
8159
8204
  inputSchema: z.object({
8160
8205
  instruction: automationInstructionToolSchema,
8161
8206
  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(),
@@ -8269,7 +8314,7 @@ function createListEventAutomationsTool(context, catalog) {
8269
8314
  openWorldHint: false,
8270
8315
  readOnlyHint: true
8271
8316
  },
8272
- description: "List event automations for the current destination. Each result says whether the requester is the creator and whether its trigger is available.",
8317
+ description: "List event automations for the current destination, not one thread. Each result says whether the requester is the creator (isCreator); only the creator can change its credential use. Warn when trigger.available is false and explain trigger.problems: the automation stays stored, but a plugin no longer supports its resource type, an event, or a filter. Update the trigger to fix it. Public automations can also be updated or deleted by id from another destination in the same workspace.",
8273
8318
  inputSchema: z.object({}).strict(),
8274
8319
  outputSchema: eventAutomationListToolResultSchema,
8275
8320
  async execute() {
@@ -8724,7 +8769,7 @@ function createSlackScheduleCreateAutomationTool(context) {
8724
8769
  openWorldHint: true,
8725
8770
  readOnlyHint: false
8726
8771
  },
8727
- 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.",
8772
+ description: "Create a one-time or recurring scheduled 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.",
8728
8773
  executionMode: "sequential",
8729
8774
  inputSchema: z.object({
8730
8775
  instruction: automationInstructionToolSchema,
@@ -8822,7 +8867,7 @@ function createSlackScheduleDeleteAutomationTool(context) {
8822
8867
  openWorldHint: false,
8823
8868
  readOnlyHint: false
8824
8869
  },
8825
- 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.",
8870
+ description: "Delete one scheduled 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.",
8826
8871
  executionMode: "sequential",
8827
8872
  inputSchema: z.object({ automationId: z.string().min(1).describe("ID of the task to delete. Must be from this active Slack conversation.") }),
8828
8873
  outputSchema: scheduleAutomationToolResultSchema.extend({ removedCards: z.array(removedCardSchema) }),
@@ -8953,7 +8998,7 @@ function createSlackScheduleRunAutomationNowTool(context) {
8953
8998
  openWorldHint: true,
8954
8999
  readOnlyHint: false
8955
9000
  },
8956
- 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.",
9001
+ description: "Queue an existing active scheduled 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.",
8957
9002
  executionMode: "sequential",
8958
9003
  inputSchema: z.object({ automationId: z.string().min(1).describe("ID of the active task to run now. Must be from this active Slack conversation.") }),
8959
9004
  outputSchema: scheduleAutomationToolResultSchema,
@@ -9279,7 +9324,7 @@ async function joinPublicChannelForRead(args) {
9279
9324
  }
9280
9325
  }
9281
9326
  /** Model-facing Slack channel id or known channel name parameter. */
9282
- const slackChannelRefParam = z.string().trim().min(1).max(160).describe("Slack channel id (`C123`), mention (`<#C123>` / `<#C123|name>`), Junior slack reference (`slack:C123`), or a channel name Junior already knows in this workspace.");
9327
+ const slackChannelRefParam = z.string().trim().min(1).max(160).describe("Slack channel id (`C123`), mention (`<#C123>` / `<#C123|name>`), Slack reference (`slack:C123`), or a channel name you already know in this workspace.");
9283
9328
  /**
9284
9329
  * Resolve a channel reference from a tool param value.
9285
9330
  *
@@ -9288,7 +9333,7 @@ const slackChannelRefParam = z.string().trim().min(1).max(160).describe("Slack c
9288
9333
  */
9289
9334
  async function resolveSlackChannelRef(input) {
9290
9335
  const trimmed = input.value.trim();
9291
- if (!trimmed) throw new ToolInputError(`Invalid \`${input.field}\`. Use a channel id (\`C123\`), a Slack mention (\`<#C123>\`), a Junior slack reference (\`slack:C123\`), or a channel name Junior already knows.`);
9336
+ if (!trimmed) throw new ToolInputError(`Invalid \`${input.field}\`. Use a channel id (\`C123\`), a Slack mention (\`<#C123>\`), a Slack reference (\`slack:C123\`), or a channel name you already know.`);
9292
9337
  const channelId = parseSlackChannelReferenceId(trimmed);
9293
9338
  if (channelId) return { channelId };
9294
9339
  const known = await getConversationStore().findSlackDestinationByName({
@@ -9300,7 +9345,7 @@ async function resolveSlackChannelRef(input) {
9300
9345
  channelId: knownChannelId,
9301
9346
  ...known.channelName ? { channelName: known.channelName } : void 0
9302
9347
  };
9303
- throw new ToolInputError(`Unknown \`${input.field}\` \`${trimmed}\`. Use a channel id (\`C123\`), a Slack mention (\`<#C123>\`), a link, or a channel name Junior has already seen in this workspace. Public search can discover channels; plain names are not scanned from Slack.`);
9348
+ throw new ToolInputError(`Unknown \`${input.field}\` \`${trimmed}\`. Use a channel id (\`C123\`), a Slack mention (\`<#C123>\`), a link, or a channel name you already saw in this workspace. Public search can discover channels; plain names are not scanned from Slack.`);
9304
9349
  }
9305
9350
  /**
9306
9351
  * Resolve an optional channel reference, falling back to the active channel.
@@ -9607,7 +9652,7 @@ function createSlackConversationBriefSearchPort(teamId) {
9607
9652
  /** Deferred tool catalog source for retained Junior conversations. */
9608
9653
  const CONVERSATIONS_TOOL_SOURCE = {
9609
9654
  id: "conversations",
9610
- description: "Search messages and events in retained Junior conversations."
9655
+ description: "Search messages and events in retained conversations."
9611
9656
  };
9612
9657
  // src/chat/slack/tools/conversation-message-search.ts
9613
9658
  const DEFAULT_LIMIT$3 = 20;
@@ -13351,19 +13396,33 @@ function createWebSearchTool(modelId, override) {
13351
13396
  const controller = new AbortController();
13352
13397
  const credential = await resolveGatewayCredential();
13353
13398
  const provider = createGatewayProvider(credential ? { apiKey: credential.token } : {});
13354
- const results = parseSearchResults((await withTimeout(generateText({
13355
- model: provider.chat(modelId),
13356
- prompt: query,
13357
- tools: { [SEARCH_TOOL_NAME]: provider.tools.parallelSearch({
13358
- mode: "agentic",
13359
- maxResults
13360
- }) },
13361
- toolChoice: {
13362
- type: "tool",
13363
- toolName: SEARCH_TOOL_NAME
13364
- },
13365
- abortSignal: controller.signal
13366
- }), SEARCH_TIMEOUT_MS, "webSearch", { onTimeout: () => controller.abort() })).toolResults, maxResults);
13399
+ const results = parseSearchResults((await withSpan(`chat ${modelId}`, "gen_ai.chat", {}, async (setSpanAttributes) => {
13400
+ const response = await withTimeout(generateText({
13401
+ model: provider.chat(modelId),
13402
+ prompt: query,
13403
+ tools: { [SEARCH_TOOL_NAME]: provider.tools.parallelSearch({
13404
+ mode: "agentic",
13405
+ maxResults
13406
+ }) },
13407
+ toolChoice: {
13408
+ type: "tool",
13409
+ toolName: SEARCH_TOOL_NAME
13410
+ },
13411
+ abortSignal: controller.signal
13412
+ }), SEARCH_TIMEOUT_MS, "webSearch", { onTimeout: () => controller.abort() });
13413
+ setSpanAttributes({
13414
+ "gen_ai.response.finish_reasons": [response.finishReason],
13415
+ ...extractGenAiUsageAttributes(response.usage)
13416
+ });
13417
+ return response;
13418
+ }, {
13419
+ "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
13420
+ "gen_ai.operation.name": "chat",
13421
+ "gen_ai.request.model": modelId,
13422
+ "server.address": GEN_AI_SERVER_ADDRESS,
13423
+ "server.port": 443,
13424
+ "gen_ai.provider.auth_mode": credential?.mode ?? "api_key"
13425
+ })).toolResults, maxResults);
13367
13426
  return {
13368
13427
  model: modelId,
13369
13428
  query,
@@ -15399,7 +15458,7 @@ function createMcpAuthOrchestration(input) {
15399
15458
  const authorizationRequest = {
15400
15459
  authorizationUrl: authSession.authorizationUrl,
15401
15460
  label: `Connect your ${providerLabel} account`,
15402
- completionText: "Once you've authorized, Junior will continue automatically."
15461
+ completionText: "Once you've authorized, I'll continue automatically."
15403
15462
  };
15404
15463
  if (!await deliverOAuthAuthorization(authorizationRequest, {
15405
15464
  authorization: input.authorization,
@@ -15511,7 +15570,7 @@ const GUARDIAN_RULE_IDS = ["none", ...Object.keys(GUARDIAN_BLOCK_RULES)];
15511
15570
  function renderRules(decision) {
15512
15571
  return Object.entries(GUARDIAN_BLOCK_RULES).filter(([, rule]) => rule.decision === decision).map(([id, rule]) => `- \`${id}\`: ${rule.description}`).join("\n");
15513
15572
  }
15514
- const GUARDIAN_ACTION_POLICY = `You are judging one planned Junior agent action.
15573
+ const GUARDIAN_ACTION_POLICY = `You are judging one planned action of the assistant agent.
15515
15574
  Assess the exact action's intrinsic risk and whether the user's intent authorizes its target and side effects. Then name the one block rule that the action matches, or \`none\`. Actions are allowed by default. Your primary objective is to prevent irreversible damage to the user or organization while allowing ordinary, proportionate work without interruption.
15516
15575
 
15517
15576
  # Evidence Handling
@@ -15560,7 +15619,7 @@ ${renderRules("deny")}
15560
15619
  - Whether the work is correct, complete, well proven, or well styled is not your concern, and neither is whether the agent checked enough before it acted. Posting results that the user or the automation instruction asked for matches no rule.
15561
15620
  - Content that the current actor's request is about, such as the conversation or examples they pointed to, is part of the requested work. Using it in the requested deliverable at an authorized destination is not data exposure, unless it includes secrets, credentials, or private data about other people.
15562
15621
  - Ordinary product context such as internal system names, repository names, or workflow descriptions is not private organization data, including on an authorized public destination.
15563
- - The active Junior conversation is not an untrusted destination merely because it is a public or multi-user channel.
15622
+ - The active conversation, where the assistant works with the user, is not an untrusted destination merely because it is a public or multi-user channel.
15564
15623
  - A user-requested read, query, or upload to a trusted destination is not data exposure. Using an existing credential to authenticate a user-requested action is not credential probing.
15565
15624
  - A tool that is external, multi-field, open-world, uses connected credentials, has plugin or catalog identity, or carries a destructive annotation does not match a rule by those facts alone. Judge actual side effects, not tool names or annotations.
15566
15625
  - 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.
@@ -15672,7 +15731,6 @@ function createGuardianActionReviewer(options) {
15672
15731
  system: GUARDIAN_ACTION_POLICY,
15673
15732
  prompt: guardianPrompt(proposal),
15674
15733
  maxTokens: GUARDIAN_REVIEW_MAX_TOKENS,
15675
- recordTelemetryPayloads: false,
15676
15734
  temperature: 0,
15677
15735
  promptName: "junior.guardian_action_review",
15678
15736
  signal,
@@ -18262,7 +18320,7 @@ function createAgentRunner(execute, options) {
18262
18320
  } } : void 0
18263
18321
  };
18264
18322
  if (run.instruction.storedAttachments?.length) {
18265
- const { loadInputImages } = await import("./images-DV2FlEGL.js").then((n) => n.n);
18323
+ const { loadInputImages } = await import("./images-B2yA3HWE.js").then((n) => n.n);
18266
18324
  const storage = nextRun.environment?.attachmentStorage;
18267
18325
  if (!storage) throw new Error("Attachment storage is unavailable.");
18268
18326
  nextRun.instruction = {
@@ -18277,4 +18335,4 @@ function createAgentRunner(execute, options) {
18277
18335
  return await execute(nextRun, streamFn);
18278
18336
  } };
18279
18337
  }
18280
- export { toolInvocationDestination as $, listThreadReplies as A, stopConversationSession as B, requestAttachmentDeletion as C, resolveSlackChannelIdFromMessage as D, readSlackRawMessageContext as E, AutomationEditError as F, conversationSubtree as G, recordSubagentStarted as H, eventAutomationTriggerAvailable as I, ingestEvent as J, conversationSubtreeColumns as K, effectiveTaskOutcomes as L, logScheduledAutomationRunSkipped as M, scheduledAutomationRunAttributes as N, resolveSlackChannelIdFromThreadId as O, editEventAutomation as P, actorFromRun as Q, resolveTaskOutcomes as R, readLiveAttachment as S, parseSlackThreadId as T, listChildAgents as U, recordSubagentEnded as V, listUnreportedSiblingAgents as W, withoutSavedSteeringMessages as X, buildSteeringPiMessage as Y, RetryableDeliveryError as Z, unpublishedArtifactHeaders as _, finalizeMcpAuthorization as a, renderBlockText as b, deleteMcpServerSessionId as c, getMcpStoredOAuthCredentials as d, readBlockedReport as et, putMcpStoredOAuthCredentials as f, readPublicArtifact as g, publicArtifactHeaders as h, buildAuthPauseResponse as i, editScheduledAutomation as j, getConversationInfo as k, deleteMcpStoredOAuthCredentials as l, readStats as m, executeAgentRun as n, deleteMcpAuthSession as o, latestProgressStatus as p, processWorkspaceSnapshotJob as q, createContextCompactor as r, deleteMcpAuthSessionsForUserProvider as s, createAgentRunner as t, shouldEmitDevAgentTrace as tt, getMcpAuthSession as u, lookupSlackUserProfile as v, storeAttachment as w, collectAttachmentGarbage as x, renderAttachmentText as y, stopChildAgentsOf as z };
18338
+ export { actorFromRun as $, listThreadReplies as A, stopChildAgentsOf as B, requestAttachmentDeletion as C, resolveSlackChannelIdFromMessage as D, readSlackRawMessageContext as E, AutomationEditError as F, listUnreportedSiblingAgents as G, recordSubagentEnded as H, describeEventAutomationTrigger as I, processWorkspaceSnapshotJob as J, conversationSubtree as K, effectiveTaskOutcomes as L, logScheduledAutomationRunSkipped as M, scheduledAutomationRunAttributes as N, resolveSlackChannelIdFromThreadId as O, editEventAutomation as P, RetryableDeliveryError as Q, resolveTaskOutcomes as R, readLiveAttachment as S, parseSlackThreadId as T, recordSubagentStarted as U, stopConversationSession as V, listChildAgents as W, buildSteeringPiMessage as X, ingestEvent as Y, withoutSavedSteeringMessages as Z, unpublishedArtifactHeaders as _, finalizeMcpAuthorization as a, renderBlockText as b, deleteMcpServerSessionId as c, getMcpStoredOAuthCredentials as d, toolInvocationDestination as et, putMcpStoredOAuthCredentials as f, readPublicArtifact as g, publicArtifactHeaders as h, buildAuthPauseResponse as i, editScheduledAutomation as j, getConversationInfo as k, deleteMcpStoredOAuthCredentials as l, readStats as m, executeAgentRun as n, shouldEmitDevAgentTrace as nt, deleteMcpAuthSession as o, latestProgressStatus as p, conversationSubtreeColumns as q, createContextCompactor as r, deleteMcpAuthSessionsForUserProvider as s, createAgentRunner as t, readBlockedReport as tt, getMcpAuthSession as u, lookupSlackUserProfile as v, storeAttachment as w, collectAttachmentGarbage as x, renderAttachmentText as y, listOwnedWatches as z };