@sentry/junior 0.242.0 → 0.243.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 (65) hide show
  1. package/dist/{admin-C54kvHVC.js → admin-DHOGoI03.js} +1 -1
  2. package/dist/{agent-hooks-BVttjZvb.js → agent-hooks-Cqo6ULp6.js} +12 -12
  3. package/dist/agent-invocations-BzRAZ_nj.js +176 -0
  4. package/dist/{agent-runner-BTgnxJ7g.js → agent-runner-BZOjoMlZ.js} +621 -69
  5. package/dist/api/schema.d.ts +53 -1
  6. package/dist/api/schema.js +4 -4
  7. package/dist/api.js +52 -22
  8. package/dist/{app-MEd7wbF0.d.ts → app-DRLh-8zs.d.ts} +5 -0
  9. package/dist/app.d.ts +1 -1
  10. package/dist/app.js +41 -24
  11. package/dist/{briefs-CKUsv9F1.js → briefs-C4GogKaB.js} +4 -4
  12. package/dist/{catalog-runtime-C2YkfMZz.js → catalog-runtime-jazDa-oO.js} +1 -1
  13. package/dist/cli/chat.js +12 -12
  14. package/dist/cli/check.js +3 -3
  15. package/dist/cli/main.js +2 -2
  16. package/dist/cli/plugins.js +4 -4
  17. package/dist/cli/snapshot-create.js +3 -3
  18. package/dist/cli/upgrade.js +3 -3
  19. package/dist/{client-D51G-Jdg.js → client-Es79bknZ.js} +2 -2
  20. package/dist/{config-C6Uu3Re9.js → config-gype19qQ.js} +7 -2
  21. package/dist/{conversation-DwD-vquD.js → conversation-mt3yJ09u.js} +2 -1
  22. package/dist/{conversation-privacy-CzL47nXs.js → conversation-privacy-BIplVfmz.js} +1 -1
  23. package/dist/{credential-sync-DvDaE-Uj.js → credential-sync-BY97dkST.js} +14 -14
  24. package/dist/{executor-CGUukwus.js → executor-C7bsEF-c.js} +5 -124
  25. package/dist/{history-BLTUgFYO.js → history-DlsoHsoe.js} +1 -0
  26. package/dist/{images-DSxZt5vk.js → images-WmrEAtto.js} +3 -3
  27. package/dist/instrumentation.js +2 -2
  28. package/dist/{job-queue-hLylM9cy.js → job-queue-DQDesz8a.js} +1 -1
  29. package/dist/{logging-BdZ_mK3q.js → logging-CdZ1LQJ7.js} +1 -1
  30. package/dist/nitro.d.ts +1 -1
  31. package/dist/nitro.js +3 -3
  32. package/dist/{oauth-authorization-BokpeHv-.js → oauth-authorization-Di0KlyoJ.js} +1 -1
  33. package/dist/{oauth-callback-server-C3BOSmT_.js → oauth-callback-server-Cmog7Q3T.js} +2 -2
  34. package/dist/{pending-auth-DOzL4D24.js → pending-auth-CNAlGOyl.js} +2 -2
  35. package/dist/{profile-2gPzzMib.js → profile-qqt_2di0.js} +4 -4
  36. package/dist/{prompt-CMU-B4FA.js → prompt-D_cg2iqi.js} +1 -1
  37. package/dist/{registry-XJkXDNK2.js → registry-WOJKAIRI.js} +1 -1
  38. package/dist/{resolve-DhcdtDt6.js → resolve-C8VvY0lg.js} +2 -2
  39. package/dist/{runner-CGyrnIPm.js → runner-DojxjGmt.js} +10 -10
  40. package/dist/{sandbox-egress-signals-D6F3OZJP.js → sandbox-egress-signals-B7azPnsm.js} +1 -1
  41. package/dist/{schema-Cabm4jcj.js → schema-nQRsPWSr.js} +34 -3
  42. package/dist/{skills-C6PqcBPU.js → skills-Zj-9pbSU.js} +2 -2
  43. package/dist/{spawn-DL9x3T1o.js → spawn-DDJ5z9IC.js} +5 -4
  44. package/dist/{task-queue-vZnBGu9B.js → task-queue-CAi-XM8x.js} +3 -3
  45. package/dist/{task-runner-C-c0t5F5.js → task-runner-CIP2asjP.js} +12 -11
  46. package/dist/{tasks-EqCtmUJ2.js → tasks-Qx6Fos_R.js} +49 -17
  47. package/dist/{thread-state-B8IKs_J8.js → thread-state-BN_5S1bx.js} +7 -7
  48. package/dist/{turn-failure-response-BS7OO1BE.js → turn-failure-response-B1UW2T7a.js} +9 -9
  49. package/dist/{turn-lifecycle-Cxrt8qMD.js → turn-lifecycle-BzeE4sVD.js} +1 -1
  50. package/dist/{turn-session-routing-BlGt2AUb.js → turn-session-routing-DsvU39zW.js} +1 -1
  51. package/dist/{validation-C8hci6pj.js → validation-Dklx_nds.js} +1 -1
  52. package/dist/{version-CjnHQ8aY.js → version-BvG02ZTN.js} +1 -1
  53. package/dist/version.js +1 -1
  54. package/dist/{viewer-BOgEy5zC.js → viewer-B7qDM2DM.js} +6 -8
  55. package/dist/{web-authorization-DSMV5tMK.js → web-authorization-Cqv7bP19.js} +6 -6
  56. package/dist/{web-input-TD5P9jdo.js → web-input-CqnqSfzI.js} +227 -31
  57. package/dist/{work-D39OAwP1.js → work-D_BBvd4I.js} +111 -225
  58. package/dist/{worker-CWiLgCWH.js → worker-BWdV_5Ys.js} +5 -5
  59. package/migrations/0050_agent_invocation_parent_mailbox.sql +4 -0
  60. package/migrations/0051_agent_invocation_parent_tool_call.sql +1 -0
  61. package/migrations/meta/0050_snapshot.json +3753 -0
  62. package/migrations/meta/0051_snapshot.json +3759 -0
  63. package/migrations/meta/_journal.json +15 -1
  64. package/package.json +5 -5
  65. package/dist/destinations-BeBiJeEM.js +0 -29
@@ -1,28 +1,28 @@
1
- import { b as getGatewayApiKey, c as hasCompactedConversationContext, d as unwrapCurrentInstruction, f as escapeXml, g as getProviderErrorAttributes, h as findProviderError, i as completeText, l as isCompactionSummaryText, m as createProviderError, n as GEN_AI_SERVER_ADDRESS, o as resolveGatewayModel, p as ProviderError, r as completeObject, s as COMPACTION_SUMMARY_PREFIX, t as GEN_AI_PROVIDER_NAME, u as renderCurrentInstruction, v as isProviderRetryError, x as resolveGatewayCredential, y as MISSING_GATEWAY_CREDENTIALS_ERROR } from "./client-D51G-Jdg.js";
2
- import { C as withLogContext, F as normalizeIdentityEmail, I as isRecord$3, L as toOptionalNumber, R as toOptionalString, a as extractGenAiUsageSummary, b as setTags, c as getLogContextAttributesForSpan, d as logException, f as logInfo, g as serializeGenAiAttribute, i as extractGenAiUsageAttributes, l as getTracePropagationHeaders, m as normalizeGenAiFinishReason, p as logWarn, u as logError, v as setSpanAttributes, w as withSpan, x as summarizeMessageText, y as setSpanStatus } from "./logging-BdZ_mK3q.js";
1
+ import { b as getGatewayApiKey, c as hasCompactedConversationContext, d as unwrapCurrentInstruction, f as escapeXml, g as getProviderErrorAttributes, h as findProviderError, i as completeText, l as isCompactionSummaryText, m as createProviderError, n as GEN_AI_SERVER_ADDRESS, o as resolveGatewayModel, p as ProviderError, r as completeObject, s as COMPACTION_SUMMARY_PREFIX, t as GEN_AI_PROVIDER_NAME, u as renderCurrentInstruction, v as isProviderRetryError, x as resolveGatewayCredential, y as MISSING_GATEWAY_CREDENTIALS_ERROR } from "./client-Es79bknZ.js";
2
+ import { C as withLogContext, F as normalizeIdentityEmail, I as isRecord$3, L as toOptionalNumber, R as toOptionalString, a as extractGenAiUsageSummary, b as setTags, c as getLogContextAttributesForSpan, d as logException, f as logInfo, g as serializeGenAiAttribute, i as extractGenAiUsageAttributes, l as getTracePropagationHeaders, m as normalizeGenAiFinishReason, p as logWarn, u as logError, v as setSpanAttributes, w as withSpan, x as summarizeMessageText, y as setSpanStatus } from "./logging-CdZ1LQJ7.js";
3
3
  import { m as startInactiveSpan, v as withActiveSpan } from "./sentry-CgWZM_kV.js";
4
- import { a as toCanonicalInputMessage, c as toGenAiPayloadMetadata, i as runWithConversationPrivacy, l as toGenAiPayloadTraceAttributes, o as toCanonicalOutputMessage, r as resolveConversationPrivacy, s as toGenAiMessagesTraceAttributes, t as canExposeConversationPayload } from "./conversation-privacy-CzL47nXs.js";
5
- import { i as getChatConfig, n as botConfig, v as normalizeSlackEmojiName } from "./config-C6Uu3Re9.js";
4
+ import { a as toCanonicalInputMessage, c as toGenAiPayloadMetadata, i as runWithConversationPrivacy, l as toGenAiPayloadTraceAttributes, o as toCanonicalOutputMessage, r as resolveConversationPrivacy, s as toGenAiMessagesTraceAttributes, t as canExposeConversationPayload } from "./conversation-privacy-BIplVfmz.js";
5
+ import { i as getChatConfig, n as botConfig, v as normalizeSlackEmojiName } from "./config-gype19qQ.js";
6
6
  import { a as formatModelProfiles, c as profileConfig, i as formatModelProfile, l as TURN_REASONING_LEVELS, n as ModelProfileNotConfiguredError, o as modelIdForProfile, s as modelProfileSchema } from "./model-profile-BwU8mqwD.js";
7
7
  import { a as isUserActor, d as parseSlackTeamId, f as parseSlackUserId, g as parseSlackMessageTs, l as parseSlackChannelId, s as parseStoredSlackActor, u as parseSlackChannelReferenceId } from "./actor-BTtLaeWy.js";
8
- import { F as sameDestination$1, N as parseDestination, T as hasAgentTurnUsage, c as getConversationEventStore, d as getDb, f as getSqlExecutor, l as getConversationMessageSearchStore, r as readActorIdentity, u as getConversationStore, x as addAgentTurnUsage } from "./viewer-BOgEy5zC.js";
9
- import { n as juniorDestinations } from "./destinations-BeBiJeEM.js";
10
- import { A as juniorArtifacts, D as juniorConversations, O as juniorIdentities, S as juniorConversationAnnotations, T as juniorAttachments, _ as juniorConversationBriefs, a as juniorSchedulerRuns, f as AGENT_INVOCATION_MAILBOX_STATUSES, l as juniorStats } from "./executor-CGUukwus.js";
11
- import { d as instructionActors, f as instructionProvenanceFor, p as sameActorIdentity, t as KNOWN_CONVERSATION_EVENT_TYPES, u as contextProvenance } from "./history-BLTUgFYO.js";
8
+ import { F as sameDestination$1, N as parseDestination, T as hasAgentTurnUsage, c as getConversationEventStore, d as getDb, f as getSqlExecutor, l as getConversationMessageSearchStore, r as readActorIdentity, u as getConversationStore, x as addAgentTurnUsage } from "./viewer-B7qDM2DM.js";
9
+ import { a as juniorAgentInvocations, c as juniorIdentities, d as juniorDestinations, i as juniorAgentBindings, n as AGENT_INVOCATION_PARENT_MAILBOX_STATUSES, r as AGENT_INVOCATION_STATUSES, s as juniorConversations, t as AGENT_INVOCATION_MAILBOX_STATUSES } from "./agent-invocations-BzRAZ_nj.js";
10
+ import { C as juniorArtifacts, S as juniorAttachments, a as juniorSchedulerRuns, l as juniorStats, m as juniorConversationBriefs, y as juniorConversationAnnotations } from "./executor-C7bsEF-c.js";
11
+ import { d as instructionActors, f as instructionProvenanceFor, p as sameActorIdentity, t as KNOWN_CONVERSATION_EVENT_TYPES, u as contextProvenance } from "./history-DlsoHsoe.js";
12
12
  import { a as listReferenceFiles, c as soulPathCandidates, l as worldPathCandidates } from "./package-discovery-BVvSnQBB.js";
13
- import { a as resolveAuthTokenPlaceholder, c as fetchWithBoundedOAuthErrorBodies, d as credentialContextForActor, f as credentialContextSchema, h as CredentialUnavailableError, i as resolvePluginHeaderEnvRefs, l as getOAuthProviderErrorAttributes, m as credentialUserSubjectId, o as resolvePluginCommandEnv, p as credentialSubjectSchema, s as OAuthProviderError } from "./registry-XJkXDNK2.js";
14
- import { n as pluginCatalogRuntime } from "./catalog-runtime-C2YkfMZz.js";
15
- import { a as parseSkillInvocation, i as parseSkillFile, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-C6PqcBPU.js";
16
- import { A as formatSlackLink, Ct as loadConversationProjection, D as automationRevision, Dt as openConversationProjection, Et as loadTurnRoute, F as addReactionToMessage, G as loadTurnCheckpoint, Gt as fallbackShortTitle, I as getSlackMessagePermalink, It as recordToolExecutionStarted, K as saveTurnCheckpoint, Kt as resolveTaskTitle, L as openSlackDirectMessage, Lt as recordTurnRoute, Mt as recordAuthorizationRequested, N as slackMention, Nt as recordGuardianActionReviewed, Ot as recordAgentsInstructionsUpdated, Pt as recordMcpProviderConnected, R as postSlackEphemeralMessage, St as loadConnectedMcpProviders, V as uploadFilesToConversation, W as continuableMessages, _t as trimTrailingAssistantMessages, a as readScheduledAutomation, an as getAgentContextCompactionTriggerTokens, at as getPiMessageRole, b as saveEventAutomation, cn as piMessageFromHistoryItem, ct as hasRuntimeTurnContext, dt as isContinuablePiBoundary, et as TurnSliceLimitExceededError, f as createEventAutomation, ft as isToolResultError, g as getEventAutomation, gt as stripRuntimeTurnContext, ht as retainRuntimeTurnContext, in as estimateTextTokens, it as extractAssistantText, k as escapeSlackMrkdwnText, kt as recordAttachmentsDelivered, mt as normalizeToolNameFromResult, o as saveScheduledAutomation, on as getAgentContextInputLimitTokens, ot as getTerminalAssistantMessages, p as deleteEventAutomation, pt as isToolResultMessage, r as listScheduledAutomationsForTeam, rt as isTurnExecutionLimitExceededError, sn as historyItemFromPiMessage, st as getUserMessageInstructionText, t as createScheduledAutomation, tt as assertTurnToolCallLimit, ut as isAssistantMessage, v as listEventAutomationsForTeam, vt as TURN_CONTEXT_TAG, x as setEventAutomationStatus, yt as ToolInputError, z as postSlackMessage } from "./tasks-EqCtmUJ2.js";
17
- import { A as getWorkspaceSnapshotBuilder, B as cancelWatch, Bt as isConversationScopedChannel, C as WorkspaceValidationError, D as setWorkspaceSnapshotBuild, E as setWorkspaceSnapshot, F as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, Ft as SlackActionError, G as findMatchingWatches, H as createTimerWatch, Ht as normalizeSlackConversationId, I as RESOURCE_SUBSCRIPTION_MAX_TTL_MS, It as downloadPrivateSlackFile, K as listWatches, L as RESOURCE_WATCH_TOOL_SOURCE, Lt as getFilePermalink, M as workspaceRepoCheckoutPath, Mt as defaultTimezone, N as resolveChannelCapabilities, Nt as resolveUserTimezone, O as SANDBOX_RUNTIME, Ot as saveObjectAnnotations, P as getSlackToolContext, R as STOP_WATCHING_TOOL_NAME, S as updateWorkspace, T as loadSnapshotsForProfile, U as createWatch, Vt as isDmChannel$1, W as deliverWatch, Wt as withSlackRetries, _ as deleteWorkspace, b as listWorkspaces, c as getPluginTools, et as verifyTimerWatchCredentialSubject, g as createWorkspace, it as getDashboardTaskLink, j as tryWorkspaceRepoCheckoutPath, k as deleteWorkspaceSnapshotBuilders, kt as createPluginAnnotations, l as getPluginUserPromptContributions, lt as createPluginLogger, nt as getDashboardConversationLink, r as createPluginHookRunner, s as getPluginSystemPromptContributions, tt as JUNIOR_THREAD_STATE_TTL_MS, u as getPlugins, v as getWorkspace, w as invalidateReadySnapshot, wt as matchSlackAttachments, y as getWorkspaceByName, z as cancelSubscriptions, zt as getSlackClient } from "./agent-hooks-BVttjZvb.js";
18
- import { F as isVisionImageMediaType, G as removedCardSchema, L as briefLinkSchema, R as briefOutcomeStatusSchema, z as conversationBriefSchema } from "./conversation-DwD-vquD.js";
19
- import { A as SANDBOX_DATA_ROOT, C as getDefaultRedisStateAdapterFor, D as fenceLock, E as acquireActiveLock, F as sandboxSkillFile, I as sandboxSkillPathResolution, M as SANDBOX_SKILLS_ROOT, N as SANDBOX_WORKSPACE_ROOT, O as withLock, P as sandboxSkillDir, _ as workspaceSnapshotNotReadyUserMessage, a as isAbortError, b as buildNonInteractiveShellScript, c as isSandboxCommandStreamInterruptedError, d as isSnapshottingError, f as throwSandboxOperationError, g as isWorkspaceSnapshotNotReadyError, h as getWorkspaceSnapshotNotReadyError, i as ensureDockerDaemon, j as SANDBOX_REPOS_ROOT, k as sleep$2, l as isSandboxMissingError, m as WorkspaceSnapshotNotReadyError, n as hash, o as isAlreadyExistsError, p as wrapSandboxSetupError, r as isStale, s as isSandboxApiTransientError, t as create, u as isSandboxUnavailableError, v as getVercelSandboxCredentials, w as getStateAdapter, x as runNonInteractiveCommand, y as buildCommandScript } from "./profile-2gPzzMib.js";
20
- import { n as canReusePendingAuthLink, t as abandonReplacedPendingAuth } from "./pending-auth-DOzL4D24.js";
21
- import { a as NO_REPLY_MARKER, c as CooperativeTurnYieldError, i as sanitizeAssistantText, l as TurnInputCommitLostError, n as decideReply, o as isNoReplyMarker, p as isTurnInputCommitLostError, r as getAssistantReplyText, t as authorizationId } from "./oauth-authorization-BokpeHv-.js";
13
+ import { a as resolveAuthTokenPlaceholder, c as fetchWithBoundedOAuthErrorBodies, d as credentialContextForActor, f as credentialContextSchema, h as CredentialUnavailableError, i as resolvePluginHeaderEnvRefs, l as getOAuthProviderErrorAttributes, m as credentialUserSubjectId, o as resolvePluginCommandEnv, p as credentialSubjectSchema, s as OAuthProviderError } from "./registry-WOJKAIRI.js";
14
+ import { n as pluginCatalogRuntime } from "./catalog-runtime-jazDa-oO.js";
15
+ import { a as parseSkillInvocation, i as parseSkillFile, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-Zj-9pbSU.js";
16
+ import { A as formatSlackLink, At as recordAttachmentsDelivered, Ct as loadConversationProjection, D as automationRevision, Dt as loadTurnRoute, F as addReactionToMessage, Ft as recordMcpProviderConnected, G as loadTurnCheckpoint, I as getSlackMessagePermalink, K as saveTurnCheckpoint, Kt as fallbackShortTitle, L as openSlackDirectMessage, Lt as recordToolExecutionStarted, N as slackMention, Nt as recordAuthorizationRequested, Ot as openConversationProjection, Pt as recordGuardianActionReviewed, R as postSlackEphemeralMessage, Rt as recordTurnRoute, St as loadConnectedMcpProviders, V as uploadFilesToConversation, W as continuableMessages, _t as trimTrailingAssistantMessages, a as readScheduledAutomation, an as estimateTextTokens, at as getPiMessageRole, b as saveEventAutomation, cn as historyItemFromPiMessage, ct as hasRuntimeTurnContext, dt as isContinuablePiBoundary, et as TurnSliceLimitExceededError, f as createEventAutomation, ft as isToolResultError, g as getEventAutomation, gt as stripRuntimeTurnContext, ht as retainRuntimeTurnContext, it as extractAssistantText, k as escapeSlackMrkdwnText, kt as recordAgentsInstructionsUpdated, ln as piMessageFromHistoryItem, mt as normalizeToolNameFromResult, o as saveScheduledAutomation, on as getAgentContextCompactionTriggerTokens, ot as getTerminalAssistantMessages, p as deleteEventAutomation, pt as isToolResultMessage, qt as resolveTaskTitle, r as listScheduledAutomationsForTeam, rt as isTurnExecutionLimitExceededError, sn as getAgentContextInputLimitTokens, st as getUserMessageInstructionText, t as createScheduledAutomation, tt as assertTurnToolCallLimit, ut as isAssistantMessage, v as listEventAutomationsForTeam, vt as TURN_CONTEXT_TAG, wt as loadLastModelProfile, x as setEventAutomationStatus, yt as ToolInputError, z as postSlackMessage } from "./tasks-Qx6Fos_R.js";
17
+ import { A as getWorkspaceSnapshotBuilder, B as cancelWatch, Bt as isConversationScopedChannel, C as WorkspaceValidationError, D as setWorkspaceSnapshotBuild, E as setWorkspaceSnapshot, F as RESOURCE_SUBSCRIPTION_DEFAULT_TTL_MS, Ft as SlackActionError, G as findMatchingWatches, H as createTimerWatch, Ht as normalizeSlackConversationId, I as RESOURCE_SUBSCRIPTION_MAX_TTL_MS, It as downloadPrivateSlackFile, K as listWatches, L as RESOURCE_WATCH_TOOL_SOURCE, Lt as getFilePermalink, M as workspaceRepoCheckoutPath, Mt as defaultTimezone, N as resolveChannelCapabilities, Nt as resolveUserTimezone, O as SANDBOX_RUNTIME, Ot as saveObjectAnnotations, P as getSlackToolContext, R as STOP_WATCHING_TOOL_NAME, S as updateWorkspace, T as loadSnapshotsForProfile, U as createWatch, Vt as isDmChannel$1, W as deliverWatch, Wt as withSlackRetries, _ as deleteWorkspace, b as listWorkspaces, c as getPluginTools, et as verifyTimerWatchCredentialSubject, g as createWorkspace, it as getDashboardTaskLink, j as tryWorkspaceRepoCheckoutPath, k as deleteWorkspaceSnapshotBuilders, kt as createPluginAnnotations, l as getPluginUserPromptContributions, lt as createPluginLogger, nt as getDashboardConversationLink, r as createPluginHookRunner, s as getPluginSystemPromptContributions, tt as JUNIOR_THREAD_STATE_TTL_MS, u as getPlugins, v as getWorkspace, w as invalidateReadySnapshot, wt as matchSlackAttachments, y as getWorkspaceByName, z as cancelSubscriptions, zt as getSlackClient } from "./agent-hooks-Cqo6ULp6.js";
18
+ import { F as isVisionImageMediaType, G as removedCardSchema, L as briefLinkSchema, R as briefOutcomeStatusSchema, z as conversationBriefSchema } from "./conversation-mt3yJ09u.js";
19
+ import { A as SANDBOX_DATA_ROOT, C as getDefaultRedisStateAdapterFor, D as fenceLock, E as acquireActiveLock, F as sandboxSkillFile, I as sandboxSkillPathResolution, M as SANDBOX_SKILLS_ROOT, N as SANDBOX_WORKSPACE_ROOT, O as withLock, P as sandboxSkillDir, _ as workspaceSnapshotNotReadyUserMessage, a as isAbortError, b as buildNonInteractiveShellScript, c as isSandboxCommandStreamInterruptedError, d as isSnapshottingError, f as throwSandboxOperationError, g as isWorkspaceSnapshotNotReadyError, h as getWorkspaceSnapshotNotReadyError, i as ensureDockerDaemon, j as SANDBOX_REPOS_ROOT, k as sleep$2, l as isSandboxMissingError, m as WorkspaceSnapshotNotReadyError, n as hash, o as isAlreadyExistsError, p as wrapSandboxSetupError, r as isStale, s as isSandboxApiTransientError, t as create, u as isSandboxUnavailableError, v as getVercelSandboxCredentials, w as getStateAdapter, x as runNonInteractiveCommand, y as buildCommandScript } from "./profile-qqt_2di0.js";
20
+ import { n as canReusePendingAuthLink, t as abandonReplacedPendingAuth } from "./pending-auth-CNAlGOyl.js";
21
+ import { a as NO_REPLY_MARKER, c as CooperativeTurnYieldError, i as sanitizeAssistantText, l as TurnInputCommitLostError, n as decideReply, o as isNoReplyMarker, p as isTurnInputCommitLostError, r as getAssistantReplyText, t as authorizationId } from "./oauth-authorization-Di0KlyoJ.js";
22
22
  import { i as isValidTimeZone, r as getZonedDateTimeParts } from "./cadence-D00SCzT1.js";
23
- import { r as EVENT_AUTHOR_ID } from "./prompt-CMU-B4FA.js";
24
- 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-DhcdtDt6.js";
25
- import { a as getVercelConversationWorkQueue, f as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-hLylM9cy.js";
23
+ import { r as EVENT_AUTHOR_ID } from "./prompt-D_cg2iqi.js";
24
+ 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-C8VvY0lg.js";
25
+ import { a as getVercelConversationWorkQueue, f as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-DQDesz8a.js";
26
26
  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-gznOMaQ2.js";
27
27
  import { r as isExperimentalFeatureEnabled } from "./experimental-Qn9rKLgx.js";
28
28
  import { n as privateTraceResultAttributes } from "./private-trace-result-BLvBjy_e.js";
@@ -34,7 +34,7 @@ import { isDeepStrictEqual } from "node:util";
34
34
  import { AsyncLocalStorage } from "node:async_hooks";
35
35
  import { z } from "zod";
36
36
  import { createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
37
- import { and, asc, desc, eq, gt, gte, inArray, isNotNull, isNull, lt, lte, ne, notExists, or, sql } from "drizzle-orm";
37
+ import { and, asc, count, desc, eq, gt, gte, inArray, isNotNull, isNull, lt, lte, ne, notExists, or, sql } from "drizzle-orm";
38
38
  import { EgressAuthRequired, EgressPolicyDenied, PluginToolInputError, actorSchema, destinationSchema, eventMatchSchema, eventSchema, missingToolAnnotationKeys, normalizeEventIdentifier, objectTypeSchema, ownedObjectAnnotationSchema, pluginAuthorizationSchema, pluginCredentialHeaderTransformSchema, pluginCredentialResultSchema, pluginGrantSchema, pluginProviderAccountSchema, pluginStoredTokensSchema, sourceSchema, stableEventMatchKey, watchResultSchema } from "@sentry/junior-plugin-api";
39
39
  import { alias } from "drizzle-orm/pg-core";
40
40
  import { Agent, estimateContextTokens } from "@earendil-works/pi-agent-core";
@@ -676,6 +676,7 @@ function createRepositoryInstructionsContext(options) {
676
676
  const context = currentUpdate?.context ?? currentContext;
677
677
  const messages = [...context.messages, message];
678
678
  options.setMessages(messages);
679
+ await options.commit(messages);
679
680
  visibleFingerprint = instructions?.fingerprint;
680
681
  instructionsVisible = Boolean(instructions);
681
682
  await options.onTransition?.(instructions);
@@ -1185,7 +1186,7 @@ function trimContextForRouter(text) {
1185
1186
  originalCharCount: trimmed.length
1186
1187
  };
1187
1188
  }
1188
- function buildClassifierSystemPrompt(profiles, profileNames, defaultProfile) {
1189
+ function buildClassifierSystemPrompt(profiles, profileNames, currentProfile) {
1189
1190
  const profileList = formatModelProfiles(profiles, profileNames);
1190
1191
  return [
1191
1192
  "Select the model profile and reasoning level for the current request. Do not execute the task.",
@@ -1200,10 +1201,10 @@ function buildClassifierSystemPrompt(profiles, profileNames, defaultProfile) {
1200
1201
  "Use xhigh for the most complex tasks: code changes, debugging/root-cause analysis, broad refactors, architecture decisions, multi-file implementation, or any task where deep reasoning across multiple systems or files is required.",
1201
1202
  "When unsure between two non-none buckets, choose the higher bucket. Do not use low as the default.",
1202
1203
  "",
1203
- `Default profile: "${defaultProfile}". Keep it unless another profile's description is a clearly better fit.`,
1204
+ `Current profile: "${currentProfile}". Keep it unless another profile's description is a clearly better fit.`,
1204
1205
  "Configured profiles (use each description's use and avoid cases; names are labels only; non-default does not mean stronger):",
1205
1206
  profileList,
1206
- "A previous profile choice is not binding. Keep follow-ups about unfinished work with that task; do not carry completed work into a new request.",
1207
+ "Keep follow-ups about unfinished work on the current profile. A new request after completed work can move to another profile.",
1207
1208
  "",
1208
1209
  "Classify based on the substance of the task, not the length of the current message. When the current instruction is a short affirmation (for example: 'go', 'do it', 'yes please', 'proceed') and prior thread context contains a pending task, classify the pending task — not the affirmation.",
1209
1210
  "",
@@ -1270,7 +1271,7 @@ async function selectTurnRoute(args) {
1270
1271
  actorId: args.context?.actorId ?? "",
1271
1272
  runId: args.context?.runId ?? ""
1272
1273
  },
1273
- defaultProfile: args.defaultProfile,
1274
+ currentProfile: args.currentProfile,
1274
1275
  profiles: args.profiles,
1275
1276
  prompt
1276
1277
  }), { minimum: trimmedContext || turnBlockCount > 0 ? "medium" : void 0 }), args.profiles);
@@ -1307,7 +1308,7 @@ function applyProfileReasoningOverride(route, profiles) {
1307
1308
  * The fast classifier model occasionally returns a malformed object
1308
1309
  * (`ProviderError` kind `invalid_response`, e.g. the AI SDK's
1309
1310
  * `NoObjectGeneratedError`) even though a retry usually succeeds. Give it
1310
- * one retry before falling back to `defaultProfile`; any other error kind
1311
+ * one retry before falling back to `currentProfile`; any other error kind
1311
1312
  * still falls back immediately.
1312
1313
  */
1313
1314
  const CLASSIFIER_MAX_ATTEMPTS = 2;
@@ -1325,7 +1326,7 @@ async function classifyTurn(args) {
1325
1326
  metadata: args.metadata,
1326
1327
  prompt: args.prompt,
1327
1328
  thinkingLevel: "low",
1328
- system: buildClassifierSystemPrompt(args.profiles, Object.keys(args.profiles), args.defaultProfile),
1329
+ system: buildClassifierSystemPrompt(args.profiles, Object.keys(args.profiles), args.currentProfile),
1329
1330
  temperature: 0,
1330
1331
  promptName: "junior.thinking_route"
1331
1332
  });
@@ -1334,7 +1335,7 @@ async function classifyTurn(args) {
1334
1335
  if (parsed.confidence < CLASSIFIER_CONFIDENCE_THRESHOLD) return {
1335
1336
  confidence: parsed.confidence,
1336
1337
  ...result.costUsd !== void 0 ? { costUsd: result.costUsd } : void 0,
1337
- profile: args.defaultProfile,
1338
+ profile: args.currentProfile,
1338
1339
  reasoningLevel: CLASSIFIER_FALLBACK_REASONING_LEVEL,
1339
1340
  reason: `low_confidence_medium_default:${reason}`,
1340
1341
  source: "router"
@@ -1354,7 +1355,7 @@ async function classifyTurn(args) {
1354
1355
  }
1355
1356
  logWarn("turn.router.classifier.failed", { "exception.message": lastError instanceof Error ? lastError.message : String(lastError) });
1356
1357
  return {
1357
- profile: args.defaultProfile,
1358
+ profile: args.currentProfile,
1358
1359
  reasoningLevel: CLASSIFIER_FALLBACK_REASONING_LEVEL,
1359
1360
  reason: "classifier_error_default",
1360
1361
  source: "router"
@@ -1934,7 +1935,12 @@ function buildOutputSection(platform, mode) {
1934
1935
  ].join("\n");
1935
1936
  }
1936
1937
  function buildIdentitySection(platform) {
1937
- return ["# Identity", platform === "slack" ? `Your Slack username is \`${botConfig.userName}\`.` : `Your assistant name is \`${botConfig.userName}\`.`].join("\n");
1938
+ if (platform !== "slack") return ["# Identity", `Your assistant name is \`${botConfig.userName}\`.`].join("\n");
1939
+ return [
1940
+ "# Identity",
1941
+ `Your Slack username is \`${botConfig.userName}\`. Your Slack user ID is \`slack.bot_user_id\` in the runtime context.`,
1942
+ "Slack text shows people as `<@U…>` and channels as `<#C…>`. A mention of your own user ID means you."
1943
+ ].join("\n");
1938
1944
  }
1939
1945
  function buildPersonalitySection() {
1940
1946
  return ["# Personality", JUNIOR_PERSONALITY.trim()].join("\n");
@@ -1948,7 +1954,8 @@ function buildRuntimeSection(params) {
1948
1954
  `- sandbox.workspace_root: ${escapeXml(SANDBOX_WORKSPACE_ROOT)}`,
1949
1955
  params.conversationId ? `- gen_ai.conversation.id: ${escapeXml(params.conversationId)}` : "",
1950
1956
  params.slackConversation?.type ? `- slack.conversation.type: ${escapeXml(params.slackConversation.type)}` : "",
1951
- params.slackConversation?.name ? `- slack.conversation.name: ${escapeXml(params.slackConversation.name)}` : ""
1957
+ params.slackConversation?.name ? `- slack.conversation.name: ${escapeXml(params.slackConversation.name)}` : "",
1958
+ params.slackConversation?.botUserId ? `- slack.bot_user_id: ${escapeXml(params.slackConversation.botUserId)}` : ""
1952
1959
  ].filter(Boolean);
1953
1960
  if (lines.length === 0) return null;
1954
1961
  return renderTagBlock("runtime", lines.join("\n"));
@@ -5343,7 +5350,7 @@ function isEventMailboxMetadata(value) {
5343
5350
  const event = record.event;
5344
5351
  if (!event || typeof event !== "object" || Array.isArray(event)) return false;
5345
5352
  const fields = event;
5346
- return typeof fields.eventKey === "string" && typeof fields.eventType === "string" && typeof fields.namespace === "string" && typeof fields.identifier === "string" && typeof fields.subscriptionId === "string" && (fields.objectType === void 0 || objectTypeSchema.safeParse(fields.objectType).success) && (fields.trustedSummary === void 0 || typeof fields.trustedSummary === "string");
5353
+ return typeof fields.eventKey === "string" && typeof fields.eventType === "string" && typeof fields.namespace === "string" && typeof fields.identifier === "string" && (fields.subscriptionId === void 0 || typeof fields.subscriptionId === "string") && (fields.objectType === void 0 || objectTypeSchema.safeParse(fields.objectType).success) && (fields.trustedSummary === void 0 || typeof fields.trustedSummary === "string");
5347
5354
  }
5348
5355
  /**
5349
5356
  * Return the timer creator subject when every event in the batch carries a
@@ -5355,7 +5362,7 @@ function timerWatchCredentialSubject(conversationId, messages) {
5355
5362
  const metadata = message.input.metadata;
5356
5363
  if (!isEventMailboxMetadata(metadata)) return void 0;
5357
5364
  const parsed = credentialSubjectSchema.safeParse(metadata.credentialSubject);
5358
- if (!parsed.success || !verifyTimerWatchCredentialSubject({
5365
+ if (!parsed.success || !metadata.event.subscriptionId || !verifyTimerWatchCredentialSubject({
5359
5366
  conversationId,
5360
5367
  subject: parsed.data,
5361
5368
  watchId: metadata.event.subscriptionId
@@ -9608,26 +9615,11 @@ function createUpdatePlanTool() {
9608
9615
  });
9609
9616
  }
9610
9617
  //#endregion
9611
- //#region src/chat/agent-invocations/errors.ts
9612
- /** Named child cannot accept another invocation until its active work ends. */
9613
- var AgentInvocationBusyError = class extends Error {
9614
- constructor(name) {
9615
- super(`Named agent "${name}" already has active work`);
9616
- this.name = "AgentInvocationBusyError";
9617
- }
9618
- };
9619
- /** Parent already has the maximum number of non-terminal child invocations. */
9620
- var AgentInvocationLimitError = class extends Error {
9621
- constructor(limit) {
9622
- super(`Parent already has ${limit} active child agent invocations (limit ${limit})`);
9623
- this.name = "AgentInvocationLimitError";
9624
- }
9625
- };
9626
- //#endregion
9627
9618
  //#region src/chat/agent-invocations/types.ts
9628
9619
  const exactStringSchema = z.string().min(1).refine((value) => value === value.trim());
9629
9620
  const agentNameSchema = exactStringSchema.max(64);
9630
9621
  const agentInvocationMailboxStatusSchema = z.enum(AGENT_INVOCATION_MAILBOX_STATUSES);
9622
+ const agentInvocationParentMailboxStatusSchema = z.enum(AGENT_INVOCATION_PARENT_MAILBOX_STATUSES);
9631
9623
  const agentBindingSchema = z.object({
9632
9624
  childConversationId: exactStringSchema,
9633
9625
  name: agentNameSchema,
@@ -9644,6 +9636,7 @@ const agentInvocationBaseSchema = z.object({
9644
9636
  invocationId: exactStringSchema,
9645
9637
  mailboxStatus: agentInvocationMailboxStatusSchema,
9646
9638
  parentConversationId: exactStringSchema,
9639
+ parentToolCallId: exactStringSchema.optional(),
9647
9640
  reasoningLevel: z.enum(TURN_REASONING_LEVELS).optional(),
9648
9641
  source: sourceSchema,
9649
9642
  updatedAtMs: z.number().finite()
@@ -9652,16 +9645,22 @@ const agentInvocationSchema = z.discriminatedUnion("status", [
9652
9645
  agentInvocationBaseSchema.extend({ status: z.enum([
9653
9646
  "pending",
9654
9647
  "running",
9655
- "awaiting_resume"
9648
+ "paused"
9656
9649
  ]) }),
9657
9650
  agentInvocationBaseSchema.extend({
9651
+ parentMailboxStatus: agentInvocationParentMailboxStatusSchema,
9658
9652
  result: z.string(),
9659
9653
  status: z.literal("completed"),
9660
9654
  terminalAtMs: z.number().finite()
9661
9655
  }),
9662
9656
  agentInvocationBaseSchema.extend({
9663
9657
  errorMessage: z.string(),
9664
- status: z.enum(["blocked", "failed"]),
9658
+ parentMailboxStatus: agentInvocationParentMailboxStatusSchema,
9659
+ status: z.enum([
9660
+ "blocked",
9661
+ "failed",
9662
+ "stopped"
9663
+ ]),
9665
9664
  terminalAtMs: z.number().finite()
9666
9665
  })
9667
9666
  ]);
@@ -9673,15 +9672,448 @@ const createAgentInvocationSchema = z.object({
9673
9672
  idempotencyKey: exactStringSchema,
9674
9673
  input: exactStringSchema,
9675
9674
  parentConversationId: exactStringSchema,
9675
+ parentToolCallId: exactStringSchema.optional(),
9676
9676
  reasoningLevel: z.enum(TURN_REASONING_LEVELS).optional()
9677
9677
  }).strict();
9678
9678
  //#endregion
9679
+ //#region src/chat/agent-invocations/errors.ts
9680
+ /** Named child cannot accept another invocation until its active work ends. */
9681
+ var AgentInvocationBusyError = class extends Error {
9682
+ constructor(name) {
9683
+ super(`Named agent "${name}" already has active work`);
9684
+ this.name = "AgentInvocationBusyError";
9685
+ }
9686
+ };
9687
+ /** Parent already has the maximum number of non-terminal child invocations. */
9688
+ var AgentInvocationLimitError = class extends Error {
9689
+ constructor(limit) {
9690
+ super(`Parent already has ${limit} active child agent invocations (limit ${limit})`);
9691
+ this.name = "AgentInvocationLimitError";
9692
+ }
9693
+ };
9694
+ //#endregion
9695
+ //#region src/chat/agent-invocations/store.ts
9696
+ const CREATE_LOCK_PREFIX = "junior:agent_invocation:create";
9697
+ function createLockName(parentConversationId) {
9698
+ return `${CREATE_LOCK_PREFIX}:${parentConversationId}`;
9699
+ }
9700
+ const TERMINAL_AGENT_INVOCATION_STATUSES = [
9701
+ "blocked",
9702
+ "completed",
9703
+ "failed",
9704
+ "stopped"
9705
+ ];
9706
+ const NON_TERMINAL_AGENT_INVOCATION_STATUSES = [
9707
+ "pending",
9708
+ "running",
9709
+ "paused"
9710
+ ];
9711
+ function stableId(prefix, ...parts) {
9712
+ return `${prefix}:${createHash("sha256").update(parts.join("\0")).digest("hex").slice(0, 32)}`;
9713
+ }
9714
+ /** Return the stable identity for one retry-safe delegated task. */
9715
+ function getAgentInvocationId(parentConversationId, idempotencyKey) {
9716
+ return stableId("agent-invocation", parentConversationId, idempotencyKey);
9717
+ }
9718
+ /** Return the stable child identity for one invocation without a named binding. */
9719
+ function getUnnamedAgentConversationId(invocationId) {
9720
+ return stableId("agent", invocationId);
9721
+ }
9722
+ /** Return the stable child identity for one named binding. */
9723
+ function getNamedAgentConversationId(parentConversationId, name) {
9724
+ return stableId("agent", parentConversationId, name);
9725
+ }
9726
+ /**
9727
+ * Return the stable identity of the agent invocation that gives one child
9728
+ * agent result to the child Conversation that started that child agent.
9729
+ */
9730
+ function getAgentInvocationIdForResult(resultInvocationId) {
9731
+ return stableId("agent-invocation", "result", resultInvocationId);
9732
+ }
9733
+ /** Return the stable turn identity advanced by one agent invocation. */
9734
+ function getAgentInvocationTurnId(invocationId) {
9735
+ return `agent-invocation:${invocationId}`;
9736
+ }
9737
+ /** Return the stable mailbox identity for one agent invocation. */
9738
+ function getAgentInvocationMessageId(invocationId) {
9739
+ return `agent-invocation:${invocationId}:input`;
9740
+ }
9741
+ /** Return the stable parent mailbox identity for one terminal result. */
9742
+ function getAgentInvocationResultMessageId(invocationId) {
9743
+ return `agent-invocation:${invocationId}:result`;
9744
+ }
9745
+ function bindingFromRow(row) {
9746
+ return agentBindingSchema.parse({
9747
+ childConversationId: row.childConversationId,
9748
+ name: row.name,
9749
+ parentConversationId: row.parentConversationId
9750
+ });
9751
+ }
9752
+ function invocationFromRow(row) {
9753
+ return agentInvocationSchema.parse({
9754
+ actor: row.actor,
9755
+ ...row.agentName ? { agentName: row.agentName } : void 0,
9756
+ childConversationId: row.childConversationId,
9757
+ createdAtMs: row.createdAt.getTime(),
9758
+ ...row.credentialContext ? { credentialContext: row.credentialContext } : void 0,
9759
+ destination: row.destination,
9760
+ ...row.errorMessage !== null ? { errorMessage: row.errorMessage } : void 0,
9761
+ input: row.input,
9762
+ invocationId: row.invocationId,
9763
+ mailboxStatus: row.mailboxStatus,
9764
+ parentConversationId: row.parentConversationId,
9765
+ ...row.parentMailboxStatus ? { parentMailboxStatus: row.parentMailboxStatus } : void 0,
9766
+ ...row.parentToolCallId ? { parentToolCallId: row.parentToolCallId } : void 0,
9767
+ ...row.reasoningLevel ? { reasoningLevel: row.reasoningLevel } : void 0,
9768
+ ...row.result !== null ? { result: row.result } : void 0,
9769
+ source: row.source,
9770
+ status: row.status,
9771
+ ...row.terminalAt ? { terminalAtMs: row.terminalAt.getTime() } : void 0,
9772
+ updatedAtMs: row.updatedAt.getTime()
9773
+ });
9774
+ }
9775
+ /** Require every durable creation input to match before replaying one key. */
9776
+ function sameCreateInput(invocation, input) {
9777
+ return invocation.parentConversationId === input.parentConversationId && invocation.agentName === input.agentName && invocation.input === input.input && invocation.reasoningLevel === input.reasoningLevel && JSON.stringify(invocation.actor) === JSON.stringify(input.actor) && JSON.stringify(invocation.credentialContext) === JSON.stringify(input.credentialContext) && JSON.stringify(invocation.destination) === JSON.stringify(input.destination);
9778
+ }
9779
+ /** Read one named child binding in its parent-agent scope. */
9780
+ async function getAgentBinding(args) {
9781
+ const rows = await getSqlExecutor().db().select().from(juniorAgentBindings).where(and(eq(juniorAgentBindings.parentConversationId, args.parentConversationId), eq(juniorAgentBindings.name, args.name)));
9782
+ return rows[0] ? bindingFromRow(rows[0]) : void 0;
9783
+ }
9784
+ /** Read one durable agent invocation. */
9785
+ async function getAgentInvocation(invocationId) {
9786
+ const rows = await getSqlExecutor().db().select().from(juniorAgentInvocations).where(eq(juniorAgentInvocations.invocationId, invocationId));
9787
+ return rows[0] ? invocationFromRow(rows[0]) : void 0;
9788
+ }
9789
+ /** Resolve the single invocation that may resume for one child conversation. */
9790
+ async function getActiveAgentInvocationForConversation(childConversationId) {
9791
+ const rows = await getSqlExecutor().db().select().from(juniorAgentInvocations).where(and(eq(juniorAgentInvocations.childConversationId, childConversationId), inArray(juniorAgentInvocations.status, ["running", "paused"]))).orderBy(asc(juniorAgentInvocations.createdAt)).limit(2);
9792
+ if (rows.length > 1) throw new Error(`Child conversation ${childConversationId} has multiple active agent invocations`);
9793
+ return rows[0] ? invocationFromRow(rows[0]) : void 0;
9794
+ }
9795
+ /** Read the newest agent invocation of one child Conversation. */
9796
+ async function getLatestAgentInvocationForConversation(childConversationId) {
9797
+ const rows = await getSqlExecutor().db().select().from(juniorAgentInvocations).where(eq(juniorAgentInvocations.childConversationId, childConversationId)).orderBy(desc(juniorAgentInvocations.createdAt)).limit(1);
9798
+ return rows[0] ? invocationFromRow(rows[0]) : void 0;
9799
+ }
9800
+ /** Bound the agent invocations that one child agent listing reads. */
9801
+ const CHILD_AGENT_LIST_INVOCATION_LIMIT = 200;
9802
+ /** Return the child state that one child's agent invocations show. */
9803
+ function childAgentFromInvocations(invocations, resultInvocationIds) {
9804
+ const latest = invocations[0];
9805
+ let current = latest;
9806
+ for (const invocation of invocations) if (!isTerminalAgentInvocation(invocation)) current = invocation;
9807
+ const task = invocations.find((invocation) => !resultInvocationIds.has(invocation.invocationId)) ?? invocations[invocations.length - 1];
9808
+ const terminal = isTerminalAgentInvocation(current) ? current : void 0;
9809
+ return {
9810
+ ...latest.agentName ? { agentName: latest.agentName } : void 0,
9811
+ childConversationId: latest.childConversationId,
9812
+ ...terminal && terminal.status !== "completed" ? { errorMessage: terminal.errorMessage } : void 0,
9813
+ status: terminal?.parentMailboxStatus === "replaced" ? "pending" : terminal?.parentMailboxStatus === "skipped" ? "stopped" : current.status,
9814
+ task: task.input,
9815
+ updatedAtMs: Math.max(...invocations.map((invocation) => invocation.updatedAtMs))
9816
+ };
9817
+ }
9818
+ /**
9819
+ * List the direct child agents of one parent Conversation, with the newest
9820
+ * activity first. The state comes from SQL agent invocation records, not from
9821
+ * model output.
9822
+ */
9823
+ async function listChildAgents(parentConversationId) {
9824
+ const db = getSqlExecutor().db();
9825
+ const rows = await db.select().from(juniorAgentInvocations).where(eq(juniorAgentInvocations.parentConversationId, parentConversationId)).orderBy(desc(juniorAgentInvocations.createdAt)).limit(CHILD_AGENT_LIST_INVOCATION_LIMIT);
9826
+ if (rows.length === 0) return [];
9827
+ const byChild = /* @__PURE__ */ new Map();
9828
+ for (const invocation of rows.map(invocationFromRow)) {
9829
+ const invocations = byChild.get(invocation.childConversationId) ?? [];
9830
+ invocations.push(invocation);
9831
+ byChild.set(invocation.childConversationId, invocations);
9832
+ }
9833
+ const grandchildren = await db.select({ invocationId: juniorAgentInvocations.invocationId }).from(juniorAgentInvocations).where(inArray(juniorAgentInvocations.parentConversationId, [...byChild.keys()]));
9834
+ const resultInvocationIds = new Set(grandchildren.map((row) => getAgentInvocationIdForResult(row.invocationId)));
9835
+ return [...byChild.values()].map((invocations) => childAgentFromInvocations(invocations, resultInvocationIds)).sort((left, right) => right.updatedAtMs - left.updatedAtMs);
9836
+ }
9837
+ async function getNonTerminalAgentInvocationForConversation(childConversationId) {
9838
+ const rows = await getSqlExecutor().db().select().from(juniorAgentInvocations).where(and(eq(juniorAgentInvocations.childConversationId, childConversationId), inArray(juniorAgentInvocations.status, NON_TERMINAL_AGENT_INVOCATION_STATUSES))).orderBy(asc(juniorAgentInvocations.createdAt)).limit(1);
9839
+ return rows[0] ? invocationFromRow(rows[0]) : void 0;
9840
+ }
9841
+ async function countNonTerminalAgentInvocationsForParent(parentConversationId) {
9842
+ return (await getSqlExecutor().db().select({ value: count() }).from(juniorAgentInvocations).where(and(eq(juniorAgentInvocations.parentConversationId, parentConversationId), inArray(juniorAgentInvocations.status, NON_TERMINAL_AGENT_INVOCATION_STATUSES))))[0]?.value ?? 0;
9843
+ }
9844
+ /**
9845
+ * Create or replay one invocation, reusing named child conversations and
9846
+ * keeping unnamed child identities scoped to the invocation.
9847
+ */
9848
+ async function createAgentInvocation(rawInput, nowMs = Date.now()) {
9849
+ const input = createAgentInvocationSchema.parse(rawInput);
9850
+ const invocationId = getAgentInvocationId(input.parentConversationId, input.idempotencyKey);
9851
+ const childConversationId = input.agentName ? getNamedAgentConversationId(input.parentConversationId, input.agentName) : getUnnamedAgentConversationId(invocationId);
9852
+ const lockName = createLockName(input.parentConversationId);
9853
+ return await getSqlExecutor().withLock(lockName, async () => {
9854
+ const existing = await getAgentInvocation(invocationId);
9855
+ if (existing) {
9856
+ if (!sameCreateInput(existing, input)) throw new Error(`Agent invocation idempotency key was reused with different input for ${invocationId}`);
9857
+ return existing;
9858
+ }
9859
+ if (await getLatestAgentInvocationForConversation(input.parentConversationId) && !await getNonTerminalAgentInvocationForConversation(input.parentConversationId)) throw new Error(`Agent conversation ${input.parentConversationId} has no open work and cannot start child agents`);
9860
+ if (await countNonTerminalAgentInvocationsForParent(input.parentConversationId) >= 8) throw new AgentInvocationLimitError(8);
9861
+ await getConversationStore().createChild({
9862
+ childConversationId,
9863
+ parentConversationId: input.parentConversationId,
9864
+ nowMs,
9865
+ source: "internal"
9866
+ });
9867
+ if (input.agentName) {
9868
+ await getSqlExecutor().db().insert(juniorAgentBindings).values({
9869
+ childConversationId,
9870
+ name: input.agentName,
9871
+ parentConversationId: input.parentConversationId
9872
+ }).onConflictDoNothing();
9873
+ const binding = await getAgentBinding({
9874
+ name: input.agentName,
9875
+ parentConversationId: input.parentConversationId
9876
+ });
9877
+ if (!binding || binding.childConversationId !== childConversationId) throw new Error(`Named agent binding did not resolve to ${childConversationId}`);
9878
+ if (await getNonTerminalAgentInvocationForConversation(childConversationId)) throw new AgentInvocationBusyError(input.agentName);
9879
+ }
9880
+ await getSqlExecutor().db().insert(juniorAgentInvocations).values({
9881
+ invocationId,
9882
+ parentConversationId: input.parentConversationId,
9883
+ childConversationId,
9884
+ agentName: input.agentName ?? null,
9885
+ input: input.input,
9886
+ actor: input.actor,
9887
+ credentialContext: input.credentialContext ?? null,
9888
+ source: { kind: "agent_invocation" },
9889
+ destination: input.destination,
9890
+ reasoningLevel: input.reasoningLevel ?? null,
9891
+ parentToolCallId: input.parentToolCallId ?? null,
9892
+ status: "pending",
9893
+ mailboxStatus: "pending",
9894
+ createdAt: new Date(nowMs),
9895
+ updatedAt: new Date(nowMs),
9896
+ terminalAt: null
9897
+ }).onConflictDoNothing();
9898
+ const invocation = await getAgentInvocation(invocationId);
9899
+ if (!invocation || !sameCreateInput(invocation, input)) throw new Error(`Agent invocation creation raced for ${invocationId}`);
9900
+ return invocation;
9901
+ });
9902
+ }
9903
+ /**
9904
+ * Create or replay the agent invocation that gives one child agent result to
9905
+ * the child Conversation that started it. It continues that Conversation for
9906
+ * the same parent, Actor, and credentials as `latest`. It skips the busy and
9907
+ * active-count checks because it continues work that already passed them.
9908
+ */
9909
+ async function createAgentInvocationForResult(args, nowMs = Date.now()) {
9910
+ const invocationId = getAgentInvocationIdForResult(args.resultInvocationId);
9911
+ await getSqlExecutor().db().insert(juniorAgentInvocations).values({
9912
+ invocationId,
9913
+ parentConversationId: args.latest.parentConversationId,
9914
+ childConversationId: args.latest.childConversationId,
9915
+ agentName: args.latest.agentName ?? null,
9916
+ input: args.input,
9917
+ actor: args.latest.actor,
9918
+ credentialContext: args.latest.credentialContext ?? null,
9919
+ source: { kind: "agent_invocation" },
9920
+ destination: args.latest.destination,
9921
+ reasoningLevel: args.latest.reasoningLevel ?? null,
9922
+ status: "pending",
9923
+ mailboxStatus: "pending",
9924
+ createdAt: new Date(nowMs),
9925
+ updatedAt: new Date(nowMs),
9926
+ terminalAt: null
9927
+ }).onConflictDoNothing();
9928
+ const invocation = await getAgentInvocation(invocationId);
9929
+ if (!invocation || invocation.childConversationId !== args.latest.childConversationId) throw new Error(`Agent invocation creation raced for ${invocationId}`);
9930
+ return invocation;
9931
+ }
9932
+ /**
9933
+ * Return whether a child Conversation has work that will start another agent
9934
+ * invocation on it: another open agent invocation, an open child agent, or a
9935
+ * sent child agent result that no agent invocation has received yet.
9936
+ */
9937
+ async function hasOpenChildWork(invocation) {
9938
+ const db = getSqlExecutor().db();
9939
+ const conversationId = invocation.childConversationId;
9940
+ if ((await db.select({ invocationId: juniorAgentInvocations.invocationId }).from(juniorAgentInvocations).where(and(or(eq(juniorAgentInvocations.childConversationId, conversationId), eq(juniorAgentInvocations.parentConversationId, conversationId)), ne(juniorAgentInvocations.invocationId, invocation.invocationId), inArray(juniorAgentInvocations.status, NON_TERMINAL_AGENT_INVOCATION_STATUSES))).limit(1)).length > 0) return true;
9941
+ const sent = await db.select({ invocationId: juniorAgentInvocations.invocationId }).from(juniorAgentInvocations).where(and(eq(juniorAgentInvocations.parentConversationId, conversationId), inArray(juniorAgentInvocations.parentMailboxStatus, ["pending", "appended"])));
9942
+ if (sent.length === 0) return false;
9943
+ return (await db.select({ invocationId: juniorAgentInvocations.invocationId }).from(juniorAgentInvocations).where(inArray(juniorAgentInvocations.invocationId, sent.map((row) => getAgentInvocationIdForResult(row.invocationId))))).length < sent.length;
9944
+ }
9945
+ /** List bounded invocation records whose mailbox append still needs repair. */
9946
+ async function listPendingAgentInvocationMailboxAppends(limit = 100) {
9947
+ return (await getSqlExecutor().db().select().from(juniorAgentInvocations).where(and(eq(juniorAgentInvocations.mailboxStatus, "pending"), inArray(juniorAgentInvocations.status, NON_TERMINAL_AGENT_INVOCATION_STATUSES))).orderBy(asc(juniorAgentInvocations.createdAt)).limit(limit)).map(invocationFromRow);
9948
+ }
9949
+ /** List terminal agent invocation results that still need a parent mailbox append. */
9950
+ async function listPendingAgentInvocationResults(limit = 100) {
9951
+ return (await getSqlExecutor().db().select().from(juniorAgentInvocations).where(eq(juniorAgentInvocations.parentMailboxStatus, "pending")).orderBy(asc(juniorAgentInvocations.terminalAt)).limit(limit)).map(invocationFromRow).filter(isTerminalAgentInvocation);
9952
+ }
9953
+ /**
9954
+ * Send a `replaced` result to the parent now. A stop ended the open work of
9955
+ * the child, so no later agent invocation sends the report.
9956
+ */
9957
+ async function reportReplacedAgentInvocation(invocationId, nowMs = Date.now()) {
9958
+ await getSqlExecutor().db().update(juniorAgentInvocations).set({
9959
+ parentMailboxStatus: "pending",
9960
+ updatedAt: new Date(nowMs)
9961
+ }).where(and(eq(juniorAgentInvocations.invocationId, invocationId), eq(juniorAgentInvocations.parentMailboxStatus, "replaced")));
9962
+ return await getAgentInvocation(invocationId);
9963
+ }
9964
+ /** Record that one terminal result is in its parent mailbox. */
9965
+ async function markAgentInvocationParentMailboxAppended(invocationId, nowMs = Date.now()) {
9966
+ await getSqlExecutor().db().update(juniorAgentInvocations).set({
9967
+ parentMailboxStatus: "appended",
9968
+ updatedAt: new Date(nowMs)
9969
+ }).where(and(eq(juniorAgentInvocations.invocationId, invocationId), eq(juniorAgentInvocations.parentMailboxStatus, "pending")));
9970
+ }
9971
+ /** Record that the invocation's idempotent mailbox append completed. */
9972
+ async function markAgentInvocationMailboxAppended(invocationId, nowMs = Date.now()) {
9973
+ await getSqlExecutor().db().update(juniorAgentInvocations).set({
9974
+ mailboxStatus: "appended",
9975
+ updatedAt: new Date(nowMs)
9976
+ }).where(eq(juniorAgentInvocations.invocationId, invocationId));
9977
+ }
9978
+ /** Mark one non-terminal invocation as actively executing. */
9979
+ async function markAgentInvocationRunning(invocationId, nowMs = Date.now()) {
9980
+ await getSqlExecutor().db().update(juniorAgentInvocations).set({
9981
+ status: "running",
9982
+ updatedAt: new Date(nowMs)
9983
+ }).where(and(eq(juniorAgentInvocations.invocationId, invocationId), inArray(juniorAgentInvocations.status, NON_TERMINAL_AGENT_INVOCATION_STATUSES)));
9984
+ return await getAgentInvocation(invocationId);
9985
+ }
9986
+ /** Mark one invocation as waiting for another shared execution slice. */
9987
+ async function markAgentInvocationPaused(invocationId, nowMs = Date.now()) {
9988
+ await getSqlExecutor().db().update(juniorAgentInvocations).set({
9989
+ status: "paused",
9990
+ updatedAt: new Date(nowMs)
9991
+ }).where(and(eq(juniorAgentInvocations.invocationId, invocationId), inArray(juniorAgentInvocations.status, NON_TERMINAL_AGENT_INVOCATION_STATUSES)));
9992
+ }
9993
+ /**
9994
+ * Persist one terminal invocation result without overwriting an earlier
9995
+ * result. The same write marks the result for the parent mailbox. If the
9996
+ * child still has open work, the result is `replaced`: the parent gets one
9997
+ * report, from the agent invocation that finishes the child's work.
9998
+ */
9999
+ async function completeAgentInvocation(args) {
10000
+ const nowMs = args.nowMs ?? Date.now();
10001
+ const current = await getAgentInvocation(args.invocationId);
10002
+ if (!current || isTerminalAgentInvocation(current)) return current;
10003
+ const parentMailboxStatus = args.status !== "stopped" && await hasOpenChildWork(current) ? "replaced" : "pending";
10004
+ await getSqlExecutor().db().update(juniorAgentInvocations).set({
10005
+ status: args.status,
10006
+ result: args.status === "completed" ? args.result : null,
10007
+ errorMessage: args.status === "completed" ? null : args.errorMessage,
10008
+ parentMailboxStatus,
10009
+ terminalAt: new Date(nowMs),
10010
+ updatedAt: new Date(nowMs)
10011
+ }).where(and(eq(juniorAgentInvocations.invocationId, args.invocationId), inArray(juniorAgentInvocations.status, NON_TERMINAL_AGENT_INVOCATION_STATUSES)));
10012
+ return await getAgentInvocation(args.invocationId);
10013
+ }
10014
+ /**
10015
+ * List one child Conversation and every Conversation below it, child first.
10016
+ * It takes the create lock of each Conversation before it reads that
10017
+ * Conversation's children, so no child agent can start in the tree until the
10018
+ * caller's transaction ends.
10019
+ */
10020
+ async function lockAgentConversationTree(childConversationId) {
10021
+ const executor = getSqlExecutor();
10022
+ const conversationIds = [childConversationId];
10023
+ let parents = conversationIds;
10024
+ while (parents.length > 0) {
10025
+ for (const parent of parents) await executor.withLock(createLockName(parent), async () => void 0);
10026
+ parents = (await executor.db().selectDistinct({ childConversationId: juniorAgentInvocations.childConversationId }).from(juniorAgentInvocations).where(inArray(juniorAgentInvocations.parentConversationId, parents))).map((row) => row.childConversationId).filter((id) => !conversationIds.includes(id));
10027
+ conversationIds.push(...parents);
10028
+ }
10029
+ return conversationIds;
10030
+ }
10031
+ /**
10032
+ * Stop the agent invocations of one direct child agent and of every child
10033
+ * agent below it. Returns undefined when the child does not belong to the
10034
+ * parent.
10035
+ */
10036
+ async function stopChildAgentInvocations(args) {
10037
+ if ((await getSqlExecutor().db().select({ invocationId: juniorAgentInvocations.invocationId }).from(juniorAgentInvocations).where(and(eq(juniorAgentInvocations.parentConversationId, args.parentConversationId), eq(juniorAgentInvocations.childConversationId, args.childConversationId))).limit(1)).length === 0) return;
10038
+ return await stopAgentInvocationTree(args.childConversationId, args.nowMs);
10039
+ }
10040
+ /**
10041
+ * Stop the agent invocations of one agent Conversation and of every child
10042
+ * agent below it. Open agent invocations become `stopped`. Results that would
10043
+ * still start or report work in the tree become `skipped`.
10044
+ */
10045
+ async function stopAgentInvocationTree(conversationId, nowMs = Date.now()) {
10046
+ return await getSqlExecutor().withLock(createLockName(conversationId), () => stopLockedAgentInvocationTree(conversationId, nowMs));
10047
+ }
10048
+ async function stopLockedAgentInvocationTree(conversationId, nowMs) {
10049
+ const db = getSqlExecutor().db();
10050
+ const now = new Date(nowMs);
10051
+ const conversationIds = await lockAgentConversationTree(conversationId);
10052
+ const stopped = await db.update(juniorAgentInvocations).set({
10053
+ errorMessage: "Stopped by the parent conversation",
10054
+ parentMailboxStatus: "skipped",
10055
+ result: null,
10056
+ status: "stopped",
10057
+ terminalAt: now,
10058
+ updatedAt: now
10059
+ }).where(and(inArray(juniorAgentInvocations.childConversationId, conversationIds), inArray(juniorAgentInvocations.status, NON_TERMINAL_AGENT_INVOCATION_STATUSES))).returning();
10060
+ await db.update(juniorAgentInvocations).set({
10061
+ parentMailboxStatus: "skipped",
10062
+ updatedAt: now
10063
+ }).where(or(and(inArray(juniorAgentInvocations.parentConversationId, conversationIds), inArray(juniorAgentInvocations.parentMailboxStatus, ["pending", "appended"])), and(inArray(juniorAgentInvocations.childConversationId, conversationIds), eq(juniorAgentInvocations.parentMailboxStatus, "replaced"))));
10064
+ return {
10065
+ conversationIds,
10066
+ stopped: stopped.map(invocationFromRow).filter(isTerminalAgentInvocation)
10067
+ };
10068
+ }
10069
+ /** Return whether an agent invocation has finished. */
10070
+ function isTerminalAgentInvocation(invocation) {
10071
+ return TERMINAL_AGENT_INVOCATION_STATUSES.includes(invocation.status);
10072
+ }
10073
+ //#endregion
10074
+ //#region src/chat/tools/runtime/list-agents.ts
10075
+ const TASK_MAX_LENGTH = 1e3;
10076
+ const ERROR_MAX_LENGTH = 500;
10077
+ function truncate(text, maxLength) {
10078
+ return text.length > maxLength ? `${text.slice(0, maxLength)}…` : text;
10079
+ }
10080
+ const listAgentsOutputSchema = juniorToolOutputSchema.extend({ agents: z.array(z.object({
10081
+ conversation_id: z.string().min(1).describe("Child conversation ID. Pass it to searchConversationEvents to read the child's history."),
10082
+ name: agentNameSchema.optional().describe("Child-agent name. Pass it to spawnAgent to reuse it."),
10083
+ status: z.enum(AGENT_INVOCATION_STATUSES).describe("pending: waiting to run. running or paused: working. completed, blocked, failed, or stopped: not working."),
10084
+ task: z.string().describe("Latest task given to the child agent"),
10085
+ error: z.string().optional().describe("Why the child agent is blocked, failed, or stopped"),
10086
+ updated_at: z.string().describe("Time of the latest change")
10087
+ }).strict()).describe("Child agents of this conversation, newest activity first") });
10088
+ /** Create the read-only tool that lists the child agents of one conversation. */
10089
+ function createListAgentsTool(conversationId) {
10090
+ return zodTool({
10091
+ description: "List the child agents that this conversation started, with the state recorded by the runtime. Use it to check which child agents are still working, or to find a named child agent before you give it more work with spawnAgent. Results still arrive as new tasks; do not poll with this tool.",
10092
+ annotations: {
10093
+ destructiveHint: false,
10094
+ idempotentHint: true,
10095
+ openWorldHint: false,
10096
+ readOnlyHint: true
10097
+ },
10098
+ inputSchema: z.object({}).strict(),
10099
+ outputSchema: listAgentsOutputSchema,
10100
+ execute: async () => ({ agents: (await listChildAgents(conversationId)).map((agent) => ({
10101
+ conversation_id: agent.childConversationId,
10102
+ ...agent.agentName ? { name: agent.agentName } : void 0,
10103
+ status: agent.status,
10104
+ task: truncate(agent.task, TASK_MAX_LENGTH),
10105
+ ...agent.errorMessage ? { error: truncate(agent.errorMessage, ERROR_MAX_LENGTH) } : void 0,
10106
+ updated_at: new Date(agent.updatedAtMs).toISOString()
10107
+ })) })
10108
+ });
10109
+ }
10110
+ //#endregion
9679
10111
  //#region src/chat/tools/runtime/spawn-agent.ts
9680
- const spawnAgentOutputSchema = juniorToolOutputSchema.extend({ invocation_id: z.string().min(1) });
10112
+ const spawnAgentOutputSchema = juniorToolOutputSchema.extend({ conversation_id: z.string().min(1).describe("Child conversation ID. Pass it to searchConversationEvents to read the child's history.") });
9681
10113
  /** Create the asynchronous child-agent tool for one parent run. */
9682
10114
  function createSpawnAgentTool(spawnAgent) {
9683
10115
  return zodTool({
9684
- description: "Start an asynchronous child agent on a delegated task. Give it a name to reuse the same child agent and its history on later calls; omit the name for a one-off agent. This call confirms durable scheduling, not task completion.",
10116
+ description: "Start an asynchronous child agent on a delegated task. Give it a name to reuse the same child agent and its history on later calls; omit the name for a one-off agent. This call confirms durable scheduling, not task completion. The result arrives later as a new task in this conversation; do not wait or poll for it.",
9685
10117
  annotations: {
9686
10118
  destructiveHint: false,
9687
10119
  idempotentHint: true,
@@ -9711,7 +10143,118 @@ function createSpawnAgentTool(spawnAgent) {
9711
10143
  if (error instanceof AgentInvocationLimitError) throw new ToolInputError(`${error.message}. Wait for active children to finish before spawning more.`, { cause: error });
9712
10144
  throw error;
9713
10145
  }
9714
- return { invocation_id: result.invocationId };
10146
+ return { conversation_id: result.childConversationId };
10147
+ }
10148
+ });
10149
+ }
10150
+ //#endregion
10151
+ //#region src/chat/agent-invocations/markers.ts
10152
+ /**
10153
+ * Dashboard markers for agent invocations. The parent Conversation gets one
10154
+ * `subagent_started` and one `subagent_ended` event for each agent invocation.
10155
+ */
10156
+ const SUBAGENT_KIND = "agent";
10157
+ /**
10158
+ * Record in the parent Conversation that one agent invocation started. The
10159
+ * dashboard pairs this event with `subagent_ended` to show the child and its
10160
+ * status. It must be written before the child mailbox append, so the child
10161
+ * cannot end first.
10162
+ */
10163
+ async function recordSubagentStarted(invocation) {
10164
+ await getConversationEventStore().append(invocation.parentConversationId, [{
10165
+ idempotencyKey: `subagent_started:${invocation.invocationId}`,
10166
+ data: {
10167
+ type: "subagent_started",
10168
+ subagentInvocationId: invocation.invocationId,
10169
+ subagentKind: SUBAGENT_KIND,
10170
+ childConversationId: invocation.childConversationId,
10171
+ ...invocation.parentToolCallId ? { parentToolCallId: invocation.parentToolCallId } : void 0,
10172
+ ...invocation.reasoningLevel ? { reasoningLevel: invocation.reasoningLevel } : void 0
10173
+ },
10174
+ createdAtMs: invocation.createdAtMs
10175
+ }]);
10176
+ }
10177
+ const SUBAGENT_OUTCOMES = {
10178
+ blocked: "blocked",
10179
+ completed: "success",
10180
+ failed: "error",
10181
+ stopped: "aborted"
10182
+ };
10183
+ /**
10184
+ * Record in the parent Conversation how one agent invocation ended. The
10185
+ * heartbeat result repair also calls this, because the child work can be
10186
+ * acknowledged before the worker reports the result.
10187
+ */
10188
+ async function recordSubagentEnded(invocation) {
10189
+ await getConversationEventStore().append(invocation.parentConversationId, [{
10190
+ idempotencyKey: `subagent_ended:${invocation.invocationId}`,
10191
+ data: {
10192
+ type: "subagent_ended",
10193
+ subagentInvocationId: invocation.invocationId,
10194
+ outcome: SUBAGENT_OUTCOMES[invocation.status]
10195
+ },
10196
+ createdAtMs: invocation.terminalAtMs
10197
+ }]);
10198
+ }
10199
+ //#endregion
10200
+ //#region src/chat/agent-invocations/stop.ts
10201
+ /**
10202
+ * Stop one child agent of a parent Conversation and every child agent below
10203
+ * it. The parent gets no result. SQL stops the work first. Then a
10204
+ * Conversation stop request aborts each run that is still working.
10205
+ *
10206
+ * Returns undefined when the child does not belong to the parent.
10207
+ */
10208
+ async function stopChildAgent(args) {
10209
+ const tree = await stopChildAgentInvocations(args);
10210
+ if (!tree) return;
10211
+ await finishStoppedTree(tree, tree.conversationIds, args.state);
10212
+ return { stoppedCount: tree.stopped.length };
10213
+ }
10214
+ /**
10215
+ * Stop the child agents of an agent Conversation that a stop interrupted.
10216
+ * The worker of that Conversation calls this after it records its own stop,
10217
+ * so this sends no stop request to that Conversation.
10218
+ */
10219
+ async function stopChildAgentsOf(conversationId, state) {
10220
+ const tree = await stopAgentInvocationTree(conversationId);
10221
+ await finishStoppedTree(tree, tree.conversationIds.filter((id) => id !== conversationId), state);
10222
+ }
10223
+ async function finishStoppedTree(tree, conversationIdsToStop, state) {
10224
+ for (const invocation of tree.stopped) await recordSubagentEnded(invocation);
10225
+ for (const conversationId of conversationIdsToStop) await stopConversationWork({
10226
+ conversationId,
10227
+ state
10228
+ });
10229
+ }
10230
+ //#endregion
10231
+ //#region src/chat/tools/runtime/stop-agent.ts
10232
+ const stopAgentOutputSchema = juniorToolOutputSchema.extend({
10233
+ conversation_id: z.string().min(1).describe("Stopped child conversation ID"),
10234
+ stopped: z.boolean().describe("True when work was stopped. False when the child agent had already stopped.")
10235
+ });
10236
+ /** Create the tool that stops one child agent of one conversation. */
10237
+ function createStopAgentTool(conversationId) {
10238
+ return zodTool({
10239
+ description: "Stop a child agent that this conversation started, and every child agent it started. Use it when the child agent's work is no longer needed or goes in the wrong direction. A stopped child agent sends no result. To give a named child agent new work later, call spawnAgent with its name.",
10240
+ annotations: {
10241
+ destructiveHint: true,
10242
+ idempotentHint: true,
10243
+ openWorldHint: false,
10244
+ readOnlyHint: false
10245
+ },
10246
+ inputSchema: z.object({ conversation_id: z.string().trim().min(1).describe("Child conversation ID from spawnAgent or listAgents to stop") }).strict(),
10247
+ outputSchema: stopAgentOutputSchema,
10248
+ execute: async (input) => {
10249
+ const stopped = await stopChildAgent({
10250
+ childConversationId: input.conversation_id,
10251
+ parentConversationId: conversationId
10252
+ });
10253
+ if (!stopped) throw new ToolInputError(`${input.conversation_id} is not a child agent of this conversation. Use listAgents to find its conversation_id.`);
10254
+ return {
10255
+ conversation_id: input.conversation_id,
10256
+ stopped: stopped.stoppedCount > 0
10257
+ };
9715
10258
  }
9716
10259
  });
9717
10260
  }
@@ -16128,7 +16671,11 @@ function createTools(availableSkills, hooks = {}, context, options = {}) {
16128
16671
  });
16129
16672
  }
16130
16673
  if (context.handoff) tools.handoff = createHandoffTool(context.handoff);
16131
- if (context.spawnAgent) tools.spawnAgent = createSpawnAgentTool(context.spawnAgent);
16674
+ if (context.spawnAgent) {
16675
+ tools.spawnAgent = createSpawnAgentTool(context.spawnAgent);
16676
+ tools.listAgents = createListAgentsTool(context.conversationId);
16677
+ tools.stopAgent = createStopAgentTool(context.conversationId);
16678
+ }
16132
16679
  if (context.automation) tools[FINISH_AUTOMATION_RUN_TOOL_NAME] = createFinishAutomationRunTool(context.automation);
16133
16680
  if (context.mcpToolManager) {
16134
16681
  tools.searchMcpTools = createSearchMcpToolsTool(context.mcpToolManager);
@@ -20049,11 +20596,12 @@ function applyHandoff(args) {
20049
20596
  * artifacts, and transcript state for destination-owned completion.
20050
20597
  */
20051
20598
  const AGENT_ABORT_SETTLE_GRACE_MS = 5e3;
20599
+ /** Read visibility from the Conversation, or from its nearest parent with one. */
20052
20600
  async function readRunConversationVisibility(conversationId) {
20053
20601
  const conversationStore = getConversationStore();
20054
- const conversation = await conversationStore.get({ conversationId });
20055
- if (conversation?.visibility || !conversation?.parentConversationId) return conversation?.visibility;
20056
- return (await conversationStore.get({ conversationId: conversation.parentConversationId }))?.visibility;
20602
+ let conversation = await conversationStore.get({ conversationId });
20603
+ while (!conversation?.visibility && conversation?.parentConversationId) conversation = await conversationStore.get({ conversationId: conversation.parentConversationId });
20604
+ return conversation?.visibility;
20057
20605
  }
20058
20606
  /** Preserve delivery-error ownership across the agent generation boundary. */
20059
20607
  var AssistantMessageDeliveryError = class extends Error {
@@ -20326,6 +20874,7 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
20326
20874
  });
20327
20875
  const preAgentPromptMessages = () => existingSessionRecord?.piMessages ?? [...input.piMessages ?? []];
20328
20876
  const handoffEnabled = !isAgentRunFeatureDisabled(policy.disabledFeatures, "handoff");
20877
+ const routeIsFixed = Object.keys(botConfig.profiles).length === 1 && (profileConfig(botConfig, activeModelProfile).reasoningLevel ?? configuredReasoningLevel) !== void 0;
20329
20878
  const storedTurnRoute = await loadTurnRoute({
20330
20879
  conversationId,
20331
20880
  turnId
@@ -20345,7 +20894,8 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
20345
20894
  reason: `persisted:${storedTurnRoute.source}`,
20346
20895
  source: storedTurnRoute.source
20347
20896
  };
20348
- } else if (handoffEnabled) {
20897
+ } else if (handoffEnabled && !routeIsFixed) {
20898
+ const lastProfile = await loadLastModelProfile({ conversationId });
20349
20899
  turnRoute = await selectTurnRoute({
20350
20900
  completeObject,
20351
20901
  conversationContext: input.conversationContext,
@@ -20355,8 +20905,8 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
20355
20905
  actorId: slackActor?.userId,
20356
20906
  runId
20357
20907
  },
20908
+ currentProfile: lastProfile && Object.hasOwn(botConfig.profiles, lastProfile) ? lastProfile : botConfig.defaultProfile,
20358
20909
  currentTurnBlocks: routerBlocks,
20359
- defaultProfile: botConfig.defaultProfile,
20360
20910
  fastModelId: botConfig.fastModelId,
20361
20911
  messageText: userInput,
20362
20912
  profiles: botConfig.profiles
@@ -20538,6 +21088,9 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
20538
21088
  baseInstructions = assembledBaseInstructions;
20539
21089
  const repositoryInstructionsContext = createRepositoryInstructionsContext({
20540
21090
  capture: wiring.captureRepositoryInstructions,
21091
+ async commit(messages) {
21092
+ await runResume.persistSafeBoundary(messages, [contextProvenance]);
21093
+ },
20541
21094
  hasSandbox: () => Boolean(wiring.getSandboxRef()),
20542
21095
  initialInstructions: initialRepositoryInstructions,
20543
21096
  onTransition: recordAgentsTransition,
@@ -20658,16 +21211,15 @@ async function executeAgentRunInPrivacyContext(run, conversationPrivacy, runLogC
20658
21211
  prepareNextTurnWithContext: async (nextTurn, hookSignal) => {
20659
21212
  try {
20660
21213
  const handoffUpdate = applyPendingHandoff();
21214
+ const contextUpdate = await repositoryInstructionsContext.applyUpdate(handoffUpdate, nextTurn.context);
20661
21215
  const pendingMessages = await drainSteeringMessages();
20662
- const capacityUpdate = await applyActiveContextCompaction(handoffUpdate ? currentAgentMessages() : nextTurn.context.messages, hookSignal, pendingMessages, true);
20663
- const combinedUpdate = capacityUpdate ? {
20664
- ...handoffUpdate,
20665
- ...capacityUpdate
20666
- } : handoffUpdate;
20667
- const repositoryInstructionsUpdate = await repositoryInstructionsContext.applyUpdate(combinedUpdate, nextTurn.context);
21216
+ const capacityUpdate = await applyActiveContextCompaction(contextUpdate ? currentAgentMessages() : nextTurn.context.messages, hookSignal, pendingMessages, true);
20668
21217
  const yieldError = runResume.prepareYieldIfDue(currentAgentMessages());
20669
21218
  if (yieldError) throw yieldError;
20670
- return repositoryInstructionsUpdate;
21219
+ return capacityUpdate ? {
21220
+ ...contextUpdate,
21221
+ ...capacityUpdate
21222
+ } : contextUpdate;
20671
21223
  } catch (error) {
20672
21224
  pendingPiHookError ??= error instanceof Error ? error : new Error(String(error));
20673
21225
  throw error;
@@ -21029,7 +21581,7 @@ function createAgentRunner(execute, options) {
21029
21581
  } } : void 0
21030
21582
  };
21031
21583
  if (run.instruction.storedAttachments?.length) {
21032
- const { loadInputImages } = await import("./images-DSxZt5vk.js").then((n) => n.n);
21584
+ const { loadInputImages } = await import("./images-WmrEAtto.js").then((n) => n.n);
21033
21585
  const storage = nextRun.environment?.attachmentStorage;
21034
21586
  if (!storage) throw new Error("Attachment storage is unavailable.");
21035
21587
  nextRun.instruction = {
@@ -21045,4 +21597,4 @@ function createAgentRunner(execute, options) {
21045
21597
  } };
21046
21598
  }
21047
21599
  //#endregion
21048
- export { getEventCatalog as $, actorFromRun as $t, resolveSlackChannelIdFromMessage as A, hasConversationStop as At, effectiveTaskOutcomes as B, SANDBOX_EGRESS_PROXY_PATH as Bt, renderBlockText as C, removeActiveConversation as Ct, storeAttachment as D, stopConversationWork as Dt, requestAttachmentDeletion as E, startConversationWork as Et, logScheduledAutomationRunSkipped as F, maybePostAutomatedTurnLimitNotice as Ft, AgentInvocationBusyError as G, sandboxEgressSignalsResponseSchema as Gt, agentBindingSchema as H, consumeSandboxEgressAuthRequiredSignal as Ht, scheduledAutomationRunAttributes as I, recordFinishedTurnForAutomatedLimit as It, processWorkspaceSnapshotJob as J, resolveBaseUrl as Jt, AgentInvocationLimitError as K, formatProviderLabel as Kt, editEventAutomation as L, resolveSandboxEgressProviderForHost as Lt, getConversationInfo as M, isFinalAttempt as Mt, listThreadReplies as N, isInvalidConversationRecordError as Nt, parseSlackThreadId as O, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS as Ot, editScheduledAutomation as P, renderTaskInput as Pt, timerWatchCredentialSubject as Q, RetryableDeliveryError as Qt, AutomationEditError as R, normalizeSandboxEgressTracePropagationDomains as Rt, renderAttachmentText as S, releaseConversationWork as St, readLiveAttachment as T, requestConversationWork as Tt, agentInvocationSchema as U, consumeSandboxEgressPermissionDeniedSignal as Ut, resolveTaskOutcomes as V, clearSandboxEgressSignals as Vt, createAgentInvocationSchema as W, parseSandboxEgressCredentialToken as Wt, EVENT_WAIT_MS as X, createUserTokenStore as Xt, ingestEvent as Y, startOAuthFlow as Yt, isEventMailboxMetadata as Z, buildSteeringPiMessage as Zt, resolvePluginOAuthAccount as _, getConversationWorkState as _t, buildAuthPauseResponse as a, shouldEmitDevAgentTrace as an, beginConversationResume as at, unpublishedArtifactHeaders as b, recordAttemptFailure as bt, deleteMcpAuthSessionsForUserProvider as c, clearConsumedConversationWake as ct, getMcpAuthSession as d, completeConversationWork as dt, toolInvocationDestination as en, eventGuidance as et, getMcpStoredOAuthCredentials as f, countPendingConversationMessages as ft, readStats as g, getConversation as gt, latestProgressStatus as h, ensureConversationWake as ht, executeCredentialedEgressRequest as i, runDispatchOutcome as in, appendAndEnqueueInboundMessage as it, resolveSlackChannelIdFromThreadId as j, hasRunnableConversationWork$1 as jt, readSlackRawMessageContext as k, CONVERSATION_WORK_STALE_ENQUEUE_MS as kt, deleteMcpServerSessionId as l, clearExpiredConversationLease as lt, PluginCredentialFailureError as m, drainConversationMailbox as mt, executeAgentRun as n, deliversFinalText as nn, ackMessages as nt, finalizeMcpAuthorization as o, getConfigDefaults as on, cancelHumanFacingPendingMessages as ot, putMcpStoredOAuthCredentials as p, deadLetterAttempt as pt, getMcpProviderErrorAttributes as q, parseOAuthStatePayload as qt, createContextCompactor as r, finishedRunReply as rn, appendAndEnqueueExclusiveInboundMessage as rt, deleteMcpAuthSession as s, setConfigDefaults as sn, checkInConversationWork as st, createAgentRunner as t, AuthorizationFlowDisabledError as tn, pluginEventCatalog as tt, deleteMcpStoredOAuthCredentials as u, completeConversationStop as ut, publicArtifactHeaders as v, hasRunnableConversationWork as vt, collectAttachmentGarbage as w, requestAnotherSlice as wt, lookupSlackUserProfile as x, recordConversationRetry as xt, readPublicArtifact as y, listActiveConversationIds as yt, eventAutomationTriggerAvailable as z, shouldPropagateSandboxEgressTrace as zt };
21600
+ export { getLatestAgentInvocationForConversation as $, resolveSandboxEgressProviderForHost as $t, resolveSlackChannelIdFromMessage as A, drainConversationMailbox as At, effectiveTaskOutcomes as B, requestAnotherSlice as Bt, renderBlockText as C, setConfigDefaults as Cn, checkInConversationWork as Ct, storeAttachment as D, completeConversationWork as Dt, requestAttachmentDeletion as E, completeConversationStop as Et, logScheduledAutomationRunSkipped as F, listActiveConversationIds as Ft, completeAgentInvocation as G, CONVERSATION_WORK_STALE_ENQUEUE_MS as Gt, stopChildAgentsOf as H, startConversationWork as Ht, scheduledAutomationRunAttributes as I, recordAttemptFailure as It, getActiveAgentInvocationForConversation as J, isFinalAttempt as Jt, createAgentInvocation as K, hasConversationStop as Kt, editEventAutomation as L, recordConversationRetry as Lt, getConversationInfo as M, getConversation as Mt, listThreadReplies as N, getConversationWorkState as Nt, parseSlackThreadId as O, countPendingConversationMessages as Ot, editScheduledAutomation as P, hasRunnableConversationWork as Pt, getAgentInvocationTurnId as Q, recordFinishedTurnForAutomatedLimit as Qt, AutomationEditError as R, releaseConversationWork as Rt, renderAttachmentText as S, getConfigDefaults as Sn, cancelHumanFacingPendingMessages as St, readLiveAttachment as T, clearExpiredConversationLease as Tt, recordSubagentEnded as U, stopConversationWork as Ut, resolveTaskOutcomes as V, requestConversationWork as Vt, recordSubagentStarted as W, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS as Wt, getAgentInvocationMessageId as X, renderTaskInput as Xt, getAgentInvocation as Y, isInvalidConversationRecordError as Yt, getAgentInvocationResultMessageId as Z, maybePostAutomatedTurnLimitNotice as Zt, resolvePluginOAuthAccount as _, AuthorizationFlowDisabledError as _n, pluginEventCatalog as _t, buildAuthPauseResponse as a, consumeSandboxEgressPermissionDeniedSignal as an, markAgentInvocationParentMailboxAppended as at, unpublishedArtifactHeaders as b, runDispatchOutcome as bn, appendAndEnqueueInboundMessage as bt, deleteMcpAuthSessionsForUserProvider as c, formatProviderLabel as cn, reportReplacedAgentInvocation as ct, getMcpAuthSession as d, startOAuthFlow as dn, ingestEvent as dt, normalizeSandboxEgressTracePropagationDomains as en, isTerminalAgentInvocation as et, getMcpStoredOAuthCredentials as f, createUserTokenStore as fn, EVENT_WAIT_MS as ft, readStats as g, toolInvocationDestination as gn, eventGuidance as gt, latestProgressStatus as h, actorFromRun as hn, getEventCatalog as ht, executeCredentialedEgressRequest as i, consumeSandboxEgressAuthRequiredSignal as in, markAgentInvocationMailboxAppended as it, resolveSlackChannelIdFromThreadId as j, ensureConversationWake as jt, readSlackRawMessageContext as k, deadLetterAttempt as kt, deleteMcpServerSessionId as l, parseOAuthStatePayload as ln, getMcpProviderErrorAttributes as lt, PluginCredentialFailureError as m, RetryableDeliveryError as mn, timerWatchCredentialSubject as mt, executeAgentRun as n, SANDBOX_EGRESS_PROXY_PATH as nn, listPendingAgentInvocationMailboxAppends as nt, finalizeMcpAuthorization as o, parseSandboxEgressCredentialToken as on, markAgentInvocationPaused as ot, putMcpStoredOAuthCredentials as p, buildSteeringPiMessage as pn, isEventMailboxMetadata as pt, createAgentInvocationForResult as q, hasRunnableConversationWork$1 as qt, createContextCompactor as r, clearSandboxEgressSignals as rn, listPendingAgentInvocationResults as rt, deleteMcpAuthSession as s, sandboxEgressSignalsResponseSchema as sn, markAgentInvocationRunning as st, createAgentRunner as t, shouldPropagateSandboxEgressTrace as tn, listChildAgents as tt, deleteMcpStoredOAuthCredentials as u, resolveBaseUrl as un, processWorkspaceSnapshotJob as ut, publicArtifactHeaders as v, deliversFinalText as vn, ackMessages as vt, collectAttachmentGarbage as w, clearConsumedConversationWake as wt, lookupSlackUserProfile as x, shouldEmitDevAgentTrace as xn, beginConversationResume as xt, readPublicArtifact as y, finishedRunReply as yn, appendAndEnqueueExclusiveInboundMessage as yt, eventAutomationTriggerAvailable as z, removeActiveConversation as zt };