@sentry/junior 0.241.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.
- package/dist/{admin-CJkjl-aN.js → admin-DHOGoI03.js} +1 -1
- package/dist/{agent-hooks-C5zYOaJk.js → agent-hooks-Cqo6ULp6.js} +12 -12
- package/dist/agent-invocations-BzRAZ_nj.js +176 -0
- package/dist/{agent-runner-CMZ6lFQe.js → agent-runner-BZOjoMlZ.js} +621 -69
- package/dist/api/schema.d.ts +53 -1
- package/dist/api/schema.js +4 -4
- package/dist/api.js +52 -22
- package/dist/{app-MEd7wbF0.d.ts → app-DRLh-8zs.d.ts} +5 -0
- package/dist/app.d.ts +1 -1
- package/dist/app.js +41 -24
- package/dist/{briefs-CsQbFjRi.js → briefs-C4GogKaB.js} +4 -4
- package/dist/{catalog-runtime-Tz0O2MZe.js → catalog-runtime-jazDa-oO.js} +1 -1
- package/dist/cli/chat.js +12 -12
- package/dist/cli/check.js +3 -3
- package/dist/cli/main.js +2 -2
- package/dist/cli/plugins.js +4 -4
- package/dist/cli/snapshot-create.js +3 -3
- package/dist/cli/upgrade.js +3 -3
- package/dist/{client-CRZ-i1tH.js → client-Es79bknZ.js} +2 -2
- package/dist/{config-CCI82OTD.js → config-gype19qQ.js} +7 -2
- package/dist/{conversation-DwD-vquD.js → conversation-mt3yJ09u.js} +2 -1
- package/dist/{conversation-privacy-D5Byl5eC.js → conversation-privacy-BIplVfmz.js} +1 -1
- package/dist/{credential-sync-DUpSxUum.js → credential-sync-BY97dkST.js} +14 -14
- package/dist/{executor-CewKi7EG.js → executor-C7bsEF-c.js} +5 -124
- package/dist/{history-BLTUgFYO.js → history-DlsoHsoe.js} +1 -0
- package/dist/{images-DY6Pxq4w.js → images-WmrEAtto.js} +3 -3
- package/dist/instrumentation.js +2 -2
- package/dist/{job-queue-C6o2aJQ6.js → job-queue-DQDesz8a.js} +1 -1
- package/dist/{logging-LQnLlPf8.js → logging-CdZ1LQJ7.js} +1 -1
- package/dist/nitro.d.ts +1 -1
- package/dist/nitro.js +3 -3
- package/dist/{oauth-authorization-Clzkm-Ts.js → oauth-authorization-Di0KlyoJ.js} +1 -1
- package/dist/{oauth-callback-server-DcYAJSEz.js → oauth-callback-server-Cmog7Q3T.js} +2 -2
- package/dist/{pending-auth-CT3ojhKe.js → pending-auth-CNAlGOyl.js} +2 -2
- package/dist/{profile-mWuVZ8ht.js → profile-qqt_2di0.js} +4 -4
- package/dist/{prompt-CMU-B4FA.js → prompt-D_cg2iqi.js} +1 -1
- package/dist/{registry-DPDH6s5G.js → registry-WOJKAIRI.js} +1 -1
- package/dist/{resolve-BAN8BSGy.js → resolve-C8VvY0lg.js} +2 -2
- package/dist/{runner-CqXZJfzk.js → runner-DojxjGmt.js} +10 -10
- package/dist/{sandbox-egress-signals-DFUUokws.js → sandbox-egress-signals-B7azPnsm.js} +1 -1
- package/dist/{schema-Cabm4jcj.js → schema-nQRsPWSr.js} +34 -3
- package/dist/{skills-BtHhSATy.js → skills-Zj-9pbSU.js} +2 -2
- package/dist/{spawn-BszkFJKJ.js → spawn-DDJ5z9IC.js} +5 -4
- package/dist/{task-queue-1LP6benz.js → task-queue-CAi-XM8x.js} +3 -3
- package/dist/{task-runner-kLN3HC-_.js → task-runner-CIP2asjP.js} +12 -11
- package/dist/{tasks-CO52vLkI.js → tasks-Qx6Fos_R.js} +49 -17
- package/dist/{thread-state-CaFRG5Mh.js → thread-state-BN_5S1bx.js} +7 -7
- package/dist/{turn-failure-response-Dmovuiq1.js → turn-failure-response-B1UW2T7a.js} +9 -9
- package/dist/{turn-lifecycle-DGqZgU6J.js → turn-lifecycle-BzeE4sVD.js} +1 -1
- package/dist/{turn-session-routing-B_v8Wbn4.js → turn-session-routing-DsvU39zW.js} +1 -1
- package/dist/{validation-B4L2Rmiw.js → validation-Dklx_nds.js} +1 -1
- package/dist/{version-DiR36OaN.js → version-BvG02ZTN.js} +1 -1
- package/dist/version.js +1 -1
- package/dist/{viewer-D6stAU7h.js → viewer-B7qDM2DM.js} +6 -8
- package/dist/{web-authorization-DLMBx2nL.js → web-authorization-Cqv7bP19.js} +6 -6
- package/dist/{web-input---xuox1t.js → web-input-CqnqSfzI.js} +227 -31
- package/dist/{work-G-HdoOSF.js → work-D_BBvd4I.js} +111 -225
- package/dist/{worker-CDUDfL9P.js → worker-BWdV_5Ys.js} +5 -5
- package/migrations/0050_agent_invocation_parent_mailbox.sql +4 -0
- package/migrations/0051_agent_invocation_parent_tool_call.sql +1 -0
- package/migrations/meta/0050_snapshot.json +3753 -0
- package/migrations/meta/0051_snapshot.json +3759 -0
- package/migrations/meta/_journal.json +15 -1
- package/package.json +4 -4
- 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-
|
|
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-
|
|
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-
|
|
5
|
-
import { i as getChatConfig, n as botConfig, v as normalizeSlackEmojiName } from "./config-
|
|
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-
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { d as instructionActors, f as instructionProvenanceFor, p as sameActorIdentity, t as KNOWN_CONVERSATION_EVENT_TYPES, u as contextProvenance } from "./history-
|
|
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-
|
|
14
|
-
import { n as pluginCatalogRuntime } from "./catalog-runtime-
|
|
15
|
-
import { a as parseSkillInvocation, i as parseSkillFile, n as findSkillByName, r as loadSkillsByName, t as discoverSkills } from "./skills-
|
|
16
|
-
import { A as formatSlackLink, Ct as loadConversationProjection, D as automationRevision, Dt as
|
|
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-
|
|
18
|
-
import { F as isVisionImageMediaType, G as removedCardSchema, L as briefLinkSchema, R as briefOutcomeStatusSchema, z as conversationBriefSchema } from "./conversation-
|
|
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-
|
|
20
|
-
import { n as canReusePendingAuthLink, t as abandonReplacedPendingAuth } from "./pending-auth-
|
|
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-
|
|
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-
|
|
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-
|
|
25
|
-
import { a as getVercelConversationWorkQueue, f as getTurnRequestDeadline, n as sendNextWorkspaceSnapshotJob, r as sendWorkspaceSnapshotJob } from "./job-queue-
|
|
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,
|
|
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
|
-
`
|
|
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
|
-
"
|
|
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
|
-
|
|
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 `
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
"
|
|
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
|
-
|
|
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({
|
|
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 {
|
|
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)
|
|
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
|
-
|
|
20055
|
-
|
|
20056
|
-
return
|
|
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(
|
|
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
|
|
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-
|
|
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 {
|
|
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 };
|