@sentry/junior 0.246.0 → 0.248.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 (69) hide show
  1. package/dist/{admin-Bh-MYw-j.js → admin-BlHz8fGl.js} +1 -1
  2. package/dist/{agent-hooks-DpklSWZg.js → agent-hooks-DWCHBPYw.js} +25 -12
  3. package/dist/{agent-invocations-BO6ddZax.js → agent-invocations-D_YoNnAn.js} +8 -2
  4. package/dist/{agent-runner-DSKpHjHW.js → agent-runner-CnlFtbzb.js} +608 -2434
  5. package/dist/api/schema.d.ts +171 -3
  6. package/dist/api/schema.js +3 -3
  7. package/dist/api.js +219 -153
  8. package/dist/{app-BYB7szGb.d.ts → app-B0gT1Slp.d.ts} +11 -2
  9. package/dist/app.d.ts +1 -1
  10. package/dist/app.js +30 -27
  11. package/dist/assistant-reply-BxCi7V4v.js +45 -0
  12. package/dist/{briefs-cZ5vWqP_.js → briefs-CdkIl79U.js} +4 -4
  13. package/dist/{catalog-runtime-CTaQXYqS.js → catalog-runtime-CTBsdSam.js} +1 -1
  14. package/dist/cli/chat.js +22 -16
  15. package/dist/cli/check.js +3 -3
  16. package/dist/cli/main.js +2 -2
  17. package/dist/cli/plugins.js +4 -4
  18. package/dist/cli/snapshot-create.js +3 -3
  19. package/dist/cli/upgrade.js +3 -3
  20. package/dist/{client--xtsAxKP.js → client-CWQtbizj.js} +2 -2
  21. package/dist/{config-BK53Ip5C.js → config-aitDvTQm.js} +16 -9
  22. package/dist/{conversation-CvBG57Io.js → conversation-Cjo9tHGm.js} +85 -1
  23. package/dist/{conversation-privacy-BDBFw6Ws.js → conversation-privacy-BsqXHVBz.js} +1 -1
  24. package/dist/{credential-sync-BiuhC9Ds.js → credential-sync-DqZF735a.js} +14 -14
  25. package/dist/{executor-bmmuRY-w.js → executor-oIZAkQZb.js} +3 -3
  26. package/dist/{images-DZliDtSH.js → images-Dzh3RBXY.js} +4 -21
  27. package/dist/instrumentation.js +2 -2
  28. package/dist/{job-queue-Cz3M7gg4.js → job-queue-DyA2AEnY.js} +1 -1
  29. package/dist/{logging-DVtMYOdD.js → logging-OpC2jwiV.js} +1 -1
  30. package/dist/message-EyMrVXEf.js +59 -0
  31. package/dist/nitro.d.ts +1 -1
  32. package/dist/nitro.js +3 -3
  33. package/dist/{oauth-authorization-By_MVRDC.js → oauth-authorization-BA4Dt6a7.js} +1 -45
  34. package/dist/{oauth-callback-server-BrUo6w1e.js → oauth-callback-server-ClDv9Z5Y.js} +2 -2
  35. package/dist/{pending-auth-BuQLZ6dK.js → pending-auth-D_nf121N.js} +2 -2
  36. package/dist/{profile-BevMNSlr.js → profile-Dfg76pvk.js} +4 -4
  37. package/dist/{prompt-C9Q9cjD3.js → prompt-C7bRJ2vg.js} +1 -1
  38. package/dist/{registry-C2rSEio1.js → registry-fpIZHoqE.js} +1 -1
  39. package/dist/{resolve-qPhrznTf.js → resolve-LMCZhQVg.js} +2 -2
  40. package/dist/result-C1ZCRPLx.js +463 -0
  41. package/dist/{runner-CNh5eMWx.js → runner-DNZMviFH.js} +11 -10
  42. package/dist/{sandbox-egress-signals-BnDEKu8d.js → sandbox-egress-signals-Dcc-mwkl.js} +1 -1
  43. package/dist/{schema-BWMRg8JS.js → schema-BRZsYL5-.js} +5 -4
  44. package/dist/session-stop-dyvsZDB0.js +782 -0
  45. package/dist/{skills-C6zJbudq.js → skills-BgGiQt5Y.js} +2 -2
  46. package/dist/{spawn-C3efZSx3.js → spawn-CpqxMPWE.js} +3 -2
  47. package/dist/store-OMQAFrJG.js +1417 -0
  48. package/dist/{task-queue-BX4vG6uA.js → task-queue-SWsXPSp-.js} +3 -3
  49. package/dist/{task-runner-T51kll0U.js → task-runner-BOxv7shv.js} +11 -11
  50. package/dist/{tasks-B9OIjl2K.js → tasks-DREdnhVP.js} +49 -16
  51. package/dist/{thread-state-AGZtVyXp.js → thread-state-BoNCtSwk.js} +7 -7
  52. package/dist/{turn-failure-response-DJ8KU2bo.js → turn-failure-response-C6jrCPjc.js} +9 -9
  53. package/dist/{turn-lifecycle-DZJkJ95q.js → turn-lifecycle-cQFsZFOU.js} +1 -1
  54. package/dist/{turn-session-routing-mRqLbMZW.js → turn-session-routing-Ba12fwXz.js} +1 -1
  55. package/dist/{validation-Dg0Ihxzo.js → validation-Dmfh2cTj.js} +1 -1
  56. package/dist/{version-Deub4try.js → version-ByV7nGOn.js} +1 -1
  57. package/dist/version.js +1 -1
  58. package/dist/{viewer-D5hbx6TE.js → viewer-CX41TWYr.js} +4 -4
  59. package/dist/{web-authorization-DCxixz5S.js → web-authorization-rDLlKIS0.js} +6 -6
  60. package/dist/{web-input-0sorYVLh.js → web-input-Bn9HHZEo.js} +43 -208
  61. package/dist/{work-rm2X7jj4.js → work-CvFoEpRT.js} +90 -14
  62. package/dist/{worker-bnGsAOP3.js → worker-CI5B63vk.js} +7 -7
  63. package/migrations/0053_conversation_stopped_at.sql +1 -0
  64. package/migrations/0054_flowery_rage.sql +1 -0
  65. package/migrations/meta/0053_snapshot.json +3771 -0
  66. package/migrations/meta/0054_snapshot.json +3777 -0
  67. package/migrations/meta/_journal.json +14 -0
  68. package/package.json +6 -5
  69. package/dist/message-BSN-Ma5f.js +0 -317
package/dist/api.js CHANGED
@@ -1,24 +1,27 @@
1
- import { Et as automationEventCatalog, G as listChildAgents, Ht as getConversation, L as editEventAutomation, Mt as cancelHumanFacingPendingMessages, O as parseSlackThreadId, P as editScheduledAutomation, R as AutomationEditError, St as getEventCatalog, T as readLiveAttachment, V as resolveTaskOutcomes, g as readStats, it as getChildAgentLabel, z as eventAutomationTriggerAvailable } from "./agent-runner-DSKpHjHW.js";
2
- import { d as logException, p as logWarn } from "./logging-DVtMYOdD.js";
1
+ import { K as listChildAgents, L as editEventAutomation, O as parseSlackThreadId, P as editScheduledAutomation, R as AutomationEditError, T as readLiveAttachment, V as resolveTaskOutcomes, g as readStats, ot as getChildAgentLabel, z as eventAutomationTriggerAvailable } from "./agent-runner-CnlFtbzb.js";
2
+ import { d as logException, p as logWarn } from "./logging-OpC2jwiV.js";
3
3
  import { d as parseSlackTeamId, g as parseSlackMessageTs, l as parseSlackChannelId } from "./actor-BTtLaeWy.js";
4
- import { E as resolveRootConversationId, T as hasAgentTurnUsage, _ as locationFromRow, b as parseSessionSource, c as getConversationEventStore, d as getDb, f as getSqlExecutor, i as resolveViewerUser, m as withConversationEventLock, o as updateViewerDisplayName, t as findUserByEmail, u as getConversationStore, w as agentTurnUsageSchema } from "./viewer-D5hbx6TE.js";
5
- import { c as juniorIdentities, d as juniorDestinations, l as juniorUsers, o as conversationReadColumns, s as juniorConversations } from "./agent-invocations-BO6ddZax.js";
6
- import { _ as juniorConversationEvents, b as juniorCodeChanges, f as juniorConversationParticipants, g as juniorConversationMetrics, m as juniorConversationBriefs, v as juniorApiTokens, x as juniorCodeRepositories } from "./executor-bmmuRY-w.js";
4
+ import { E as resolveRootConversationId, T as hasAgentTurnUsage, _ as locationFromRow, b as parseSessionSource, c as getConversationEventStore, d as getDb, f as getSqlExecutor, i as resolveViewerUser, m as withConversationEventLock, o as updateViewerDisplayName, t as findUserByEmail, u as getConversationStore, w as agentTurnUsageSchema, x as addAgentTurnUsage } from "./viewer-CX41TWYr.js";
5
+ import { c as juniorIdentities, d as juniorDestinations, l as juniorUsers, o as conversationReadColumns, s as juniorConversations } from "./agent-invocations-D_YoNnAn.js";
6
+ import { _ as juniorConversationEvents, b as juniorCodeChanges, f as juniorConversationParticipants, g as juniorConversationMetrics, m as juniorConversationBriefs, v as juniorApiTokens, x as juniorCodeRepositories } from "./executor-oIZAkQZb.js";
7
7
  import { u as contextProvenance } from "./history-Nte1oVed.js";
8
- import { A as requireAutomationRevision, D as sameDefinitionValue, E as readAutomationVersion, O as AutomationConflictError, Ot as loadTurnProjection, a as readScheduledAutomation, b as saveEventAutomation, dn as piMessageFromHistoryItem, g as getEventAutomation, k as automationRevision, m as eventAutomationBelongsToUser, o as saveScheduledAutomation, w as automationDefinition, x as setEventAutomationStatus } from "./tasks-B9OIjl2K.js";
9
- import { At as listConversationAnnotations, C as WorkspaceValidationError, M as workspaceRepoCheckoutPath, O as SANDBOX_RUNTIME, Pt as lookupSlackUser, S as updateWorkspace, St as buildSentryConversationUrl, Wt as withSlackRetries, _ as deleteWorkspace, _t as conversationNotArchivedForUser, b as listWorkspaces, bt as readLatestConversationBrief, dt as conversationArchiveTimes, ft as conversationArchivedForEmail, g as createWorkspace, gt as conversationNotArchivedForEmail, ht as conversationHasParticipantUser, jt as listConversationAnnotationsById, lt as createPluginLogger, mt as conversationHasParticipantEmail, pt as conversationArchivedForUser, u as getPlugins, ut as readConversationAccessFromSql, v as getWorkspace, vt as viewerConversationMembership, x as listWorkspacesByRepository, xt as readConversationEventPage, zt as getSlackClient } from "./agent-hooks-DpklSWZg.js";
10
- import { A as forkConversationBodySchema, F as INPUT_IMAGE_TYPES, O as createConversationBodySchema, P as readMessageAttachments, T as conversationStatsReportSchema, _ as conversationParamsSchema, a as cancelConversationPendingMessagesBodySchema, c as conversationAttachmentParamsSchema, d as conversationDetailReportSchema, g as conversationFeedSchema, h as conversationFeedQuerySchema, i as archiveConversationResponseSchema, j as forkConversationResponseSchema, k as createConversationMessageBodySchema, m as conversationEventsQuerySchema, o as cancelConversationPendingMessagesResponseSchema, p as conversationEventPageSchema, r as archiveConversationBodySchema, t as acceptedConversationMessageSchema, u as conversationDetailQuerySchema, x as conversationPendingMessagesReportSchema } from "./conversation-CvBG57Io.js";
11
- import { n as hash, t as create } from "./profile-BevMNSlr.js";
8
+ import { A as requireAutomationRevision, D as sameDefinitionValue, E as readAutomationVersion, O as AutomationConflictError, a as readScheduledAutomation, b as saveEventAutomation, g as getEventAutomation, jt as loadTurnProjection, k as automationRevision, m as eventAutomationBelongsToUser, mn as piMessageFromHistoryItem, o as saveScheduledAutomation, w as automationDefinition, x as setEventAutomationStatus } from "./tasks-DREdnhVP.js";
9
+ import { C as WorkspaceValidationError, Ct as readConversationEventPage, It as lookupSlackUser, Kt as withSlackRetries, M as workspaceRepoCheckoutPath, Mt as listConversationAnnotations, Nt as listConversationAnnotationsById, O as SANDBOX_RUNTIME, S as updateWorkspace, St as readLatestConversationBrief, Vt as getSlackClient, _ as deleteWorkspace, _t as conversationHasParticipantUser, b as listWorkspaces, bt as viewerConversationMembership, dt as createPluginLogger, ft as readConversationAccessFromSql, g as createWorkspace, gt as conversationHasParticipantEmail, ht as conversationArchivedForUser, mt as conversationArchivedForEmail, pt as conversationArchiveTimes, u as getPlugins, v as getWorkspace, vt as conversationNotArchivedForEmail, wt as buildSentryConversationUrl, x as listWorkspacesByRepository, yt as conversationNotArchivedForUser } from "./agent-hooks-DWCHBPYw.js";
10
+ import { A as forkConversationBodySchema, F as readMessageAttachments, I as INPUT_IMAGE_TYPES, O as createConversationBodySchema, T as conversationStatsReportSchema, _ as conversationParamsSchema, a as cancelConversationPendingMessagesBodySchema, c as conversationAttachmentParamsSchema, d as conversationDetailReportSchema, g as conversationFeedSchema, h as conversationFeedQuerySchema, i as archiveConversationResponseSchema, j as forkConversationResponseSchema, k as createConversationMessageBodySchema, m as conversationEventsQuerySchema, o as cancelConversationPendingMessagesResponseSchema, p as conversationEventPageSchema, r as archiveConversationBodySchema, t as acceptedConversationMessageSchema, u as conversationDetailQuerySchema, x as conversationPendingMessagesReportSchema } from "./conversation-Cjo9tHGm.js";
11
+ import { n as hash, t as create } from "./profile-Dfg76pvk.js";
12
+ import { l as getEventCatalog, v as automationEventCatalog } from "./session-stop-dyvsZDB0.js";
12
13
  import { t as getFirstRunAtMs } from "./cadence-D00SCzT1.js";
13
- import { t as getCachedSnapshot } from "./resolve-qPhrznTf.js";
14
- import { a as getVercelConversationWorkQueue } from "./job-queue-Cz3M7gg4.js";
14
+ import { t as getCachedSnapshot } from "./resolve-LMCZhQVg.js";
15
+ import { a as getVercelConversationWorkQueue } from "./job-queue-DyA2AEnY.js";
16
+ import { a as cancelHumanFacingPendingMessages, h as getConversation } from "./store-OMQAFrJG.js";
15
17
  import { M as compileScheduleIntent, P as weekdaySchema, _ as automationSummarySchema, b as automationVersionListSchema, c as automationLifecycleSchema, d as automationParamsSchema, f as automationRunListSchema, g as automationSchedulePreviewSchema, h as automationScheduleIntentSchema, i as automationExecutionListSchema, j as ScheduleIntentError, l as automationListQuerySchema, n as automationEditSchema, r as automationEventCatalogSchema, t as automationEditErrorSchema, u as automationListSchema, v as automationUpdateSchema, x as automationVersionParamsSchema, y as automationVersionActivateSchema } from "./automation-gznOMaQ2.js";
16
18
  import { C as skillReportsSchema, a as fillUtcHours, b as pluginsSchema, c as sumUtcHoursIntoSixHours, d as trailingUtcSixHourWindow, f as utcDayKey, h as pluginOperationalReportFeedSchema, i as fillUtcDays, l as trailingUtcDayWindow, m as healthReportSchema, n as DAY_MS$1, o as fillUtcSixHours, p as utcHourKey, r as HOUR_MS$1, s as startOfUtcHour, u as trailingUtcHourWindow, x as runtimeInfoReportSchema } from "./web-message-id-xPI_EFSC.js";
17
- import { H as readHealthReport, N as legacyWebMailboxMetadataSchema, R as createVercelAttachmentStorage, _ as readViewerAutomationRuns, a as recordWebConversationActivity, b as readViewerAutomations, d as resolveSlackConversationContextFromThreadId, g as readViewerAutomationExecutions, h as readConversationSourceTask, i as createConversationId, j as stopConversationTurn, l as getProductionSlackAdapter, m as deleteViewerTask, o as webActorFromEmail, p as ViewerTaskNotFoundError, r as createAndEnqueueConversation, t as appendAndEnqueueWebMessage, u as formatSlackConversationRedactedLabel, v as readViewerAutomationSummary, w as clearSlackPendingReactions, x as resolveViewerTaskCandidate, y as readViewerAutomationVersions } from "./web-input-0sorYVLh.js";
18
- import { A as conversationActiveDaysColumn, M as conversationRangeColumns, j as conversationAggregateColumns } from "./task-runner-T51kll0U.js";
19
- import { r as getWebAuthorization } from "./web-authorization-DCxixz5S.js";
20
- import { t as decodeInputImages } from "./images-DZliDtSH.js";
21
- import { C as locationParamsSchema, E as activitySixHours$1, L as conversationChildAgentsReportSchema, M as codePersonReportSchema, N as codeRepositoryParamsSchema, P as codeRepositoryReportSchema, R as stopConversationTurnResponseSchema, S as locationDirectoryReportSchema, T as activityHours$1, _ as actorProfileReportSchema, a as workspaceBodySchema, d as createdPersonalTokenSchema, f as personalTokenListSchema, g as actorDirectoryReportSchema, h as revokePersonalTokenResponseSchema, i as deleteWorkspaceResponseSchema, j as codeOverviewReportSchema, l as workspaceSchema, m as personalTokenParamsSchema, n as statsReportSchema, o as workspaceListSchema, s as workspaceParamsSchema, u as createPersonalTokenBodySchema, v as personParamsSchema, w as activityDays$1, x as locationDetailReportSchema, y as personalSpendReportSchema, z as apiErrorSchema } from "./schema-BWMRg8JS.js";
19
+ import { B as readHealthReport, I as createVercelAttachmentStorage, _ as readViewerAutomationRuns, a as recordWebConversationActivity, b as readViewerAutomations, d as resolveSlackConversationContextFromThreadId, g as readViewerAutomationExecutions, h as readConversationSourceTask, i as createConversationId, j as stopConversationTurn, l as getProductionSlackAdapter, m as deleteViewerTask, o as webActorFromEmail, p as ViewerTaskNotFoundError, r as createAndEnqueueConversation, t as appendAndEnqueueWebMessage, u as formatSlackConversationRedactedLabel, v as readViewerAutomationSummary, w as clearSlackPendingReactions, x as resolveViewerTaskCandidate, y as readViewerAutomationVersions } from "./web-input-Bn9HHZEo.js";
20
+ import { A as conversationActiveDaysColumn, M as conversationRangeColumns, j as conversationAggregateColumns } from "./task-runner-BOxv7shv.js";
21
+ import { d as legacyWebMailboxMetadataSchema } from "./result-C1ZCRPLx.js";
22
+ import { r as getWebAuthorization } from "./web-authorization-rDLlKIS0.js";
23
+ import { t as decodeInputImages } from "./images-Dzh3RBXY.js";
24
+ import { C as locationParamsSchema, E as activitySixHours$1, L as conversationChildAgentsReportSchema, M as codePersonReportSchema, N as codeRepositoryParamsSchema, P as codeRepositoryReportSchema, R as stopConversationTurnResponseSchema, S as locationDirectoryReportSchema, T as activityHours$1, _ as actorProfileReportSchema, a as workspaceBodySchema, d as createdPersonalTokenSchema, f as personalTokenListSchema, g as actorDirectoryReportSchema, h as revokePersonalTokenResponseSchema, i as deleteWorkspaceResponseSchema, j as codeOverviewReportSchema, l as workspaceSchema, m as personalTokenParamsSchema, n as statsReportSchema, o as workspaceListSchema, s as workspaceParamsSchema, u as createPersonalTokenBodySchema, v as personParamsSchema, w as activityDays$1, x as locationDetailReportSchema, y as personalSpendReportSchema, z as apiErrorSchema } from "./schema-BRZsYL5-.js";
22
25
  import { Hono } from "hono";
23
26
  import path from "node:path";
24
27
  import { z } from "zod";
@@ -131,6 +134,39 @@ async function archiveConversation(viewer, conversationId, body) {
131
134
  throwApiError(409, "Conversation received new activity.");
132
135
  }
133
136
  //#endregion
137
+ //#region src/chat/conversations/sql/subtree.ts
138
+ /** Columns of the `conversation_subtree` table that `conversationSubtree` returns. */
139
+ const conversationSubtreeColumns = {
140
+ conversationId: sql`conversation_subtree.conversation_id`,
141
+ scopeConversationId: sql`conversation_subtree.scope_conversation_id`
142
+ };
143
+ /**
144
+ * Return a joinable `conversation_subtree` table. It maps each selected
145
+ * Conversation to itself and to each descendant child Conversation at any
146
+ * depth. Reports use it so that a total for a Conversation always includes the
147
+ * work of all its child agents.
148
+ *
149
+ * A descendant must have the same root as the selected Conversation. Thus a
150
+ * Conversation that has no valid root gets only its own work.
151
+ */
152
+ function conversationSubtree(conversationIds) {
153
+ const selectedIds = sql.join(conversationIds.map((conversationId) => sql`${conversationId}`), sql`, `);
154
+ return sql`(
155
+ with recursive tree(scope_conversation_id, conversation_id, root_conversation_id) as (
156
+ select selected.conversation_id, selected.conversation_id, selected.root_conversation_id
157
+ from junior_conversations selected
158
+ where selected.conversation_id in (${selectedIds})
159
+ union
160
+ select tree.scope_conversation_id, child.conversation_id, child.root_conversation_id
161
+ from junior_conversations child
162
+ join tree
163
+ on child.parent_conversation_id = tree.conversation_id
164
+ and child.root_conversation_id = tree.root_conversation_id
165
+ )
166
+ select scope_conversation_id, conversation_id from tree
167
+ ) conversation_subtree`;
168
+ }
169
+ //#endregion
134
170
  //#region src/chat/conversations/fork.ts
135
171
  /** Event key of the agent note that follows the copied events in a fork. */
136
172
  const FORK_NOTE_KEY = "fork:note";
@@ -282,7 +318,6 @@ function hasUnfinishedToolCalls(messages) {
282
318
  }
283
319
  //#endregion
284
320
  //#region src/api/conversations/auxiliary-costs.ts
285
- const auxiliaryRootConversation = alias(juniorConversations, "auxiliary_root_conversation");
286
321
  function eventCost() {
287
322
  return sql`CASE
288
323
  WHEN ${juniorConversationEvents.type} = 'structured_event'
@@ -294,14 +329,17 @@ function eventCost() {
294
329
  ELSE NULL
295
330
  END`;
296
331
  }
297
- /** Aggregate additive event costs by namespaced operation for conversations. */
298
- async function readConversationAuxiliaryCostsFromSql(db, conversationIds, options) {
332
+ function addCostUsd(left, right) {
333
+ return Math.round((left + right) * 0xe8d4a51000) / 0xe8d4a51000;
334
+ }
335
+ /**
336
+ * Aggregate additive event costs by namespaced operation. The total for each
337
+ * selected Conversation includes itself and all its child agents at any depth.
338
+ */
339
+ async function readConversationAuxiliaryCostsFromSql(db, conversationIds) {
299
340
  if (conversationIds.length === 0) return /* @__PURE__ */ new Map();
300
- const selectedIds = [...conversationIds];
301
- const conversationId = options.includeDescendants ? sql`coalesce(
302
- ${auxiliaryRootConversation.conversationId},
303
- ${juniorConversations.conversationId}
304
- )` : sql`${juniorConversations.conversationId}`;
341
+ const scopeConversationId = conversationSubtreeColumns.scopeConversationId;
342
+ const isChildAgent = sql`(${conversationSubtreeColumns.conversationId} <> ${scopeConversationId})`;
305
343
  const namespace = sql`CASE
306
344
  WHEN ${juniorConversationEvents.type} = 'structured_event'
307
345
  THEN ${juniorConversationEvents.payload}->>'namespace'
@@ -313,22 +351,23 @@ async function readConversationAuxiliaryCostsFromSql(db, conversationIds, option
313
351
  ELSE ${juniorConversationEvents.type}
314
352
  END`;
315
353
  const cost = eventCost();
316
- const selectedConversation = options.includeDescendants ? or(and(inArray(juniorConversations.rootConversationId, selectedIds), isNotNull(auxiliaryRootConversation.conversationId)), inArray(juniorConversations.conversationId, selectedIds)) : inArray(juniorConversations.conversationId, selectedIds);
317
354
  const rows = await db.select({
318
- conversationId,
355
+ conversationId: scopeConversationId,
356
+ childAgentCostUsd: sql`coalesce(round(sum(case when ${isChildAgent} then ${cost} end), 12), 0)::double precision`.mapWith(Number),
319
357
  costUsd: sql`round(sum(${cost}), 12)::double precision`.mapWith(Number),
320
358
  events: sql`count(*)::integer`.mapWith(Number),
321
359
  name,
322
360
  namespace
323
- }).from(juniorConversationEvents).innerJoin(juniorConversations, eq(juniorConversations.conversationId, juniorConversationEvents.conversationId)).leftJoin(auxiliaryRootConversation, and(eq(auxiliaryRootConversation.conversationId, juniorConversations.rootConversationId), isNull(auxiliaryRootConversation.parentConversationId), eq(auxiliaryRootConversation.rootConversationId, auxiliaryRootConversation.conversationId))).where(and(selectedConversation, or(eq(juniorConversationEvents.type, "structured_event"), inArray(juniorConversationEvents.type, ["guardian_action_reviewed", "turn_routed"])), sql`${cost} >= 0`, notCopiedByFork())).groupBy(conversationId, namespace, name).orderBy(conversationId, namespace, name);
361
+ }).from(juniorConversationEvents).innerJoin(conversationSubtree(conversationIds), eq(conversationSubtreeColumns.conversationId, juniorConversationEvents.conversationId)).where(and(or(eq(juniorConversationEvents.type, "structured_event"), inArray(juniorConversationEvents.type, ["guardian_action_reviewed", "turn_routed"])), sql`${cost} >= 0`, notCopiedByFork())).groupBy(scopeConversationId, namespace, name).orderBy(scopeConversationId, namespace, name);
324
362
  const result = /* @__PURE__ */ new Map();
325
363
  for (const row of rows) {
326
- const current = result.get(row.conversationId) ?? {
364
+ const current = result.get(row.conversationId) ?? { total: {
327
365
  costUsd: 0,
328
366
  operations: []
329
- };
330
- current.costUsd = Math.round((current.costUsd + row.costUsd) * 0xe8d4a51000) / 0xe8d4a51000;
331
- current.operations.push({
367
+ } };
368
+ current.total.costUsd = addCostUsd(current.total.costUsd, row.costUsd);
369
+ if (row.childAgentCostUsd > 0) current.childAgentCostUsd = addCostUsd(current.childAgentCostUsd ?? 0, row.childAgentCostUsd);
370
+ current.total.operations.push({
332
371
  costUsd: row.costUsd,
333
372
  events: row.events,
334
373
  name: row.name,
@@ -339,20 +378,119 @@ async function readConversationAuxiliaryCostsFromSql(db, conversationIds, option
339
378
  return result;
340
379
  }
341
380
  //#endregion
342
- //#region src/api/conversations/child-agents.ts
343
- /** Read the runtime and usage saved on each child Conversation row. */
344
- async function readChildConversationMetrics(db, conversationIds) {
345
- const rows = conversationIds.length === 0 ? [] : await db.select({
346
- conversationId: juniorConversations.conversationId,
347
- durationMs: juniorConversations.durationMs,
348
- usage: juniorConversations.usage
349
- }).from(juniorConversations).where(inArray(juniorConversations.conversationId, [...conversationIds]));
350
- return new Map(rows.map((row) => [row.conversationId, {
351
- cumulativeDurationMs: row.durationMs,
352
- ...row.usage ? { cumulativeUsage: row.usage } : void 0
353
- }]));
381
+ //#region src/api/conversations/usage.ts
382
+ const usage$1 = juniorConversations.usage;
383
+ const componentFields = [
384
+ "inputTokens",
385
+ "outputTokens",
386
+ "cachedInputTokens",
387
+ "cacheCreationTokens"
388
+ ];
389
+ function summedUsageNumber(field) {
390
+ return sql`sum((${usage$1}->>${field})::double precision)::double precision`;
391
+ }
392
+ function summedCostNumber(field) {
393
+ return sql`round(
394
+ sum((${usage$1}->'cost'->>${field})::numeric),
395
+ 12
396
+ )::double precision`;
397
+ }
398
+ function usageFromAggregate(row) {
399
+ const components = {};
400
+ let componentTotal = 0;
401
+ for (const field of componentFields) {
402
+ const value = row[field];
403
+ if (value === null) continue;
404
+ components[field] = value;
405
+ componentTotal += value;
406
+ }
407
+ const cost = {
408
+ ...row.costInput === null ? void 0 : { input: row.costInput },
409
+ ...row.costOutput === null ? void 0 : { output: row.costOutput },
410
+ ...row.costCacheRead === null ? void 0 : { cacheRead: row.costCacheRead },
411
+ ...row.costCacheWrite === null ? void 0 : { cacheWrite: row.costCacheWrite },
412
+ ...row.costTotal === null ? void 0 : { total: row.costTotal }
413
+ };
414
+ const result = {
415
+ ...row.totalOnlyTokens === null ? components : { totalTokens: row.totalOnlyTokens + componentTotal },
416
+ ...row.reasoningTokens === null ? void 0 : { reasoningTokens: row.reasoningTokens },
417
+ ...Object.keys(cost).length === 0 ? void 0 : { cost }
418
+ };
419
+ return hasAgentTurnUsage(result) ? result : void 0;
420
+ }
421
+ /**
422
+ * Aggregate saved runtime and usage in PostgreSQL. The total for each selected
423
+ * Conversation includes itself and all its child agents at any depth.
424
+ */
425
+ async function readConversationTreeMetricsFromSql(db, conversationIds) {
426
+ if (conversationIds.length === 0) return /* @__PURE__ */ new Map();
427
+ const hasComponents = sql`coalesce(
428
+ ${usage$1}->>'inputTokens',
429
+ ${usage$1}->>'outputTokens',
430
+ ${usage$1}->>'cachedInputTokens',
431
+ ${usage$1}->>'cacheCreationTokens'
432
+ ) is not null`;
433
+ const isChildAgent = sql`(${conversationSubtreeColumns.conversationId} <> ${conversationSubtreeColumns.scopeConversationId})`;
434
+ const rows = await db.select({
435
+ scopeConversationId: conversationSubtreeColumns.scopeConversationId,
436
+ isChildAgent,
437
+ conversations: sql`count(*)::integer`.mapWith(Number),
438
+ durationMs: sql`coalesce(sum(${juniorConversations.durationMs}), 0)::double precision`,
439
+ inputTokens: summedUsageNumber("inputTokens"),
440
+ outputTokens: summedUsageNumber("outputTokens"),
441
+ cachedInputTokens: summedUsageNumber("cachedInputTokens"),
442
+ cacheCreationTokens: summedUsageNumber("cacheCreationTokens"),
443
+ totalOnlyTokens: sql`sum(
444
+ case
445
+ when not (${hasComponents})
446
+ then (${usage$1}->>'totalTokens')::double precision
447
+ end
448
+ )::double precision`,
449
+ reasoningTokens: summedUsageNumber("reasoningTokens"),
450
+ costInput: summedCostNumber("input"),
451
+ costOutput: summedCostNumber("output"),
452
+ costCacheRead: summedCostNumber("cacheRead"),
453
+ costCacheWrite: summedCostNumber("cacheWrite"),
454
+ costTotal: summedCostNumber("total")
455
+ }).from(juniorConversations).innerJoin(conversationSubtree(conversationIds), eq(conversationSubtreeColumns.conversationId, juniorConversations.conversationId)).groupBy(conversationSubtreeColumns.scopeConversationId, isChildAgent);
456
+ const ownRows = /* @__PURE__ */ new Map();
457
+ const childRows = /* @__PURE__ */ new Map();
458
+ for (const row of rows) (row.isChildAgent ? childRows : ownRows).set(row.scopeConversationId, row);
459
+ const result = /* @__PURE__ */ new Map();
460
+ for (const [conversationId, own] of ownRows) {
461
+ const ownUsage = usageFromAggregate(own);
462
+ const child = childRows.get(conversationId);
463
+ const childUsage = child ? usageFromAggregate(child) : void 0;
464
+ const usage = addAgentTurnUsage(ownUsage, childUsage);
465
+ result.set(conversationId, {
466
+ durationMs: own.durationMs + (child?.durationMs ?? 0),
467
+ ...usage ? { usage } : void 0,
468
+ ...child ? { childAgents: {
469
+ count: child.conversations,
470
+ durationMs: child.durationMs,
471
+ ...childUsage ? { usage: childUsage } : void 0
472
+ } } : void 0
473
+ });
474
+ }
475
+ return result;
354
476
  }
355
477
  /**
478
+ * Project the child agent part of tree metrics into the API shape. Return
479
+ * nothing when the Conversation has no child agents.
480
+ */
481
+ function childAgentTotalsReport(metrics, auxiliaryCosts) {
482
+ const childAgents = metrics?.childAgents;
483
+ if (!childAgents) return void 0;
484
+ return {
485
+ ...auxiliaryCosts?.childAgentCostUsd === void 0 ? void 0 : { auxiliaryCostUsd: auxiliaryCosts.childAgentCostUsd },
486
+ count: childAgents.count,
487
+ cumulativeDurationMs: childAgents.durationMs,
488
+ ...childAgents.usage ? { cumulativeUsage: childAgents.usage } : void 0
489
+ };
490
+ }
491
+ //#endregion
492
+ //#region src/api/conversations/child-agents.ts
493
+ /**
356
494
  * Load the direct child agents of one Conversation, or throw a standard API
357
495
  * not-found error. Viewers who cannot see private content get only the status,
358
496
  * time, and usage of each child agent.
@@ -363,14 +501,17 @@ async function requireConversationChildAgents(conversationId, options = {}) {
363
501
  const [accessByConversation, children] = await Promise.all([readConversationAccessFromSql(db, [conversationId], options.viewer), listChildAgents(conversationId)]);
364
502
  const canExposePayload = accessByConversation.get(conversationId)?.canViewPrivateContent ?? false;
365
503
  const childIds = children.map((agent) => agent.childConversationId);
366
- const [metricsByChild, auxiliaryCostsByChild] = await Promise.all([readChildConversationMetrics(db, childIds), readConversationAuxiliaryCostsFromSql(db, childIds, { includeDescendants: false })]);
504
+ const [metricsByChild, auxiliaryCostsByChild] = await Promise.all([readConversationTreeMetricsFromSql(db, childIds), readConversationAuxiliaryCostsFromSql(db, childIds)]);
367
505
  const agents = children.map((agent) => {
506
+ const metrics = metricsByChild.get(agent.childConversationId);
368
507
  const auxiliaryCosts = auxiliaryCostsByChild.get(agent.childConversationId);
508
+ const childAgentTotals = childAgentTotalsReport(metrics, auxiliaryCosts);
369
509
  return {
370
510
  conversationId: agent.childConversationId,
371
- cumulativeDurationMs: 0,
372
- ...metricsByChild.get(agent.childConversationId),
373
- ...auxiliaryCosts ? { auxiliaryCosts } : void 0,
511
+ cumulativeDurationMs: metrics?.durationMs ?? 0,
512
+ ...metrics?.usage ? { cumulativeUsage: metrics.usage } : void 0,
513
+ ...auxiliaryCosts ? { auxiliaryCosts: auxiliaryCosts.total } : void 0,
514
+ ...childAgentTotals ? { childAgentTotals } : void 0,
374
515
  status: agent.status,
375
516
  updatedAt: new Date(agent.updatedAtMs).toISOString(),
376
517
  ...canExposePayload ? {
@@ -642,8 +783,8 @@ async function resolveSlackTeamDomains(teamIds) {
642
783
  //#region src/chat/pi/sql-model-usage.ts
643
784
  /** SQL reporting adapter for usage stored on assistant history events. */
644
785
  const message = sql`${juniorConversationEvents.payload}`;
645
- const usage$1 = sql`${message}->'usage'`;
646
- const cost = sql`${usage$1}->'cost'`;
786
+ const usage = sql`${message}->'usage'`;
787
+ const cost = sql`${usage}->'cost'`;
647
788
  function nonnegativeNumber(source, field, fallbackField, floor = false) {
648
789
  const value = (name) => sql`case
649
790
  when jsonb_typeof(${source}->${name}) = 'number'
@@ -654,7 +795,7 @@ function nonnegativeNumber(source, field, fallbackField, floor = false) {
654
795
  return fallbackField ? sql`coalesce(${primary}, ${value(fallbackField)})` : sql`${primary}`;
655
796
  }
656
797
  function token(field, fallbackField) {
657
- return nonnegativeNumber(usage$1, field, fallbackField, true);
798
+ return nonnegativeNumber(usage, field, fallbackField, true);
658
799
  }
659
800
  function summed(value) {
660
801
  return sql`sum(${value})::double precision`;
@@ -703,8 +844,9 @@ function usageFromRow(row) {
703
844
  return hasAgentTurnUsage(result) ? agentTurnUsageSchema.parse(result) : void 0;
704
845
  }
705
846
  /**
706
- * Aggregate real assistant calls by provider/model in SQL. Replayed history is
707
- * not another call; its tokens appear in the next call's input usage.
847
+ * Aggregate real assistant calls by provider/model in SQL, for one
848
+ * Conversation and all its child agents at any depth. Replayed history is not
849
+ * another call; its tokens appear in the next call's input usage.
708
850
  */
709
851
  async function readConversationModelUsageFromSql(executor, options) {
710
852
  const modelId = sql`case
@@ -734,7 +876,7 @@ async function readConversationModelUsageFromSql(executor, options) {
734
876
  costCacheRead: summedCost(nonnegativeNumber(cost, "cacheRead")),
735
877
  costCacheWrite: summedCost(nonnegativeNumber(cost, "cacheWrite")),
736
878
  costTotal: summedCost(nonnegativeNumber(cost, "total"))
737
- }).from(juniorConversationEvents).innerJoin(juniorConversations, eq(juniorConversations.conversationId, juniorConversationEvents.conversationId)).where(and(options.includeDescendants ? eq(juniorConversations.rootConversationId, options.conversationId) : eq(juniorConversationEvents.conversationId, options.conversationId), eq(juniorConversationEvents.type, "assistant_message"), notCopiedByFork(), sql`jsonb_typeof(${message}->'provider') = 'string'`, sql`jsonb_typeof(${message}->'model') = 'string'`, sql`coalesce(${message}->>'provider', '') <> ''`, sql`coalesce(${message}->>'model', '') <> ''`)).groupBy(modelId).orderBy(modelId)).flatMap((row) => {
879
+ }).from(juniorConversationEvents).innerJoin(conversationSubtree([options.conversationId]), eq(conversationSubtreeColumns.conversationId, juniorConversationEvents.conversationId)).where(and(eq(juniorConversationEvents.type, "assistant_message"), notCopiedByFork(), sql`jsonb_typeof(${message}->'provider') = 'string'`, sql`jsonb_typeof(${message}->'model') = 'string'`, sql`coalesce(${message}->>'provider', '') <> ''`, sql`coalesce(${message}->>'model', '') <> ''`)).groupBy(modelId).orderBy(modelId)).flatMap((row) => {
738
880
  const modelUsage = usageFromRow(row);
739
881
  return modelUsage ? [{
740
882
  modelId: row.modelId,
@@ -925,6 +1067,7 @@ function conversationSummaryFromStoredConversation(args) {
925
1067
  surface,
926
1068
  ...args.auxiliaryCosts ? { auxiliaryCosts: args.auxiliaryCosts } : void 0,
927
1069
  ...usage ? { cumulativeUsage: usage } : void 0,
1070
+ ...args.childAgentTotals ? { childAgentTotals: args.childAgentTotals } : void 0,
928
1071
  ...actorIdentity ? { actorIdentity } : void 0,
929
1072
  ...locationUrl ? { locationUrl } : void 0,
930
1073
  archivedAt: args.archivedAtMs === void 0 ? null : new Date(args.archivedAtMs).toISOString(),
@@ -935,86 +1078,6 @@ function conversationSummaryFromStoredConversation(args) {
935
1078
  };
936
1079
  }
937
1080
  //#endregion
938
- //#region src/api/conversations/usage.ts
939
- const usage = juniorConversations.usage;
940
- const metricRootConversation = alias(juniorConversations, "metric_root_conversation");
941
- const componentFields = [
942
- "inputTokens",
943
- "outputTokens",
944
- "cachedInputTokens",
945
- "cacheCreationTokens"
946
- ];
947
- function summedUsageNumber(field) {
948
- return sql`sum((${usage}->>${field})::double precision)::double precision`;
949
- }
950
- function summedCostNumber(field) {
951
- return sql`round(
952
- sum((${usage}->'cost'->>${field})::numeric),
953
- 12
954
- )::double precision`;
955
- }
956
- function usageFromAggregate(row) {
957
- const components = {};
958
- let componentTotal = 0;
959
- for (const field of componentFields) {
960
- const value = row[field];
961
- if (value === null) continue;
962
- components[field] = value;
963
- componentTotal += value;
964
- }
965
- const cost = {
966
- ...row.costInput === null ? void 0 : { input: row.costInput },
967
- ...row.costOutput === null ? void 0 : { output: row.costOutput },
968
- ...row.costCacheRead === null ? void 0 : { cacheRead: row.costCacheRead },
969
- ...row.costCacheWrite === null ? void 0 : { cacheWrite: row.costCacheWrite },
970
- ...row.costTotal === null ? void 0 : { total: row.costTotal }
971
- };
972
- const result = {
973
- ...row.totalOnlyTokens === null ? components : { totalTokens: row.totalOnlyTokens + componentTotal },
974
- ...row.reasoningTokens === null ? void 0 : { reasoningTokens: row.reasoningTokens },
975
- ...Object.keys(cost).length === 0 ? void 0 : { cost }
976
- };
977
- return hasAgentTurnUsage(result) ? result : void 0;
978
- }
979
- /** Aggregate persisted metrics in PostgreSQL for selected conversation trees. */
980
- async function readRootConversationMetricsFromSql(db, rootConversationIds) {
981
- if (rootConversationIds.length === 0) return /* @__PURE__ */ new Map();
982
- const hasComponents = sql`coalesce(
983
- ${usage}->>'inputTokens',
984
- ${usage}->>'outputTokens',
985
- ${usage}->>'cachedInputTokens',
986
- ${usage}->>'cacheCreationTokens'
987
- ) is not null`;
988
- const rows = await db.select({
989
- rootConversationId: juniorConversations.rootConversationId,
990
- durationMs: sql`coalesce(sum(${juniorConversations.durationMs}), 0)::double precision`,
991
- inputTokens: summedUsageNumber("inputTokens"),
992
- outputTokens: summedUsageNumber("outputTokens"),
993
- cachedInputTokens: summedUsageNumber("cachedInputTokens"),
994
- cacheCreationTokens: summedUsageNumber("cacheCreationTokens"),
995
- totalOnlyTokens: sql`sum(
996
- case
997
- when not (${hasComponents})
998
- then (${usage}->>'totalTokens')::double precision
999
- end
1000
- )::double precision`,
1001
- reasoningTokens: summedUsageNumber("reasoningTokens"),
1002
- costInput: summedCostNumber("input"),
1003
- costOutput: summedCostNumber("output"),
1004
- costCacheRead: summedCostNumber("cacheRead"),
1005
- costCacheWrite: summedCostNumber("cacheWrite"),
1006
- costTotal: summedCostNumber("total")
1007
- }).from(juniorConversations).innerJoin(metricRootConversation, and(eq(metricRootConversation.conversationId, juniorConversations.rootConversationId), isNull(metricRootConversation.parentConversationId), eq(metricRootConversation.rootConversationId, metricRootConversation.conversationId))).where(inArray(juniorConversations.rootConversationId, [...rootConversationIds])).groupBy(juniorConversations.rootConversationId);
1008
- return new Map(rows.flatMap((row) => {
1009
- if (!row.rootConversationId) return [];
1010
- const usage = usageFromAggregate(row);
1011
- return [[row.rootConversationId, {
1012
- durationMs: row.durationMs,
1013
- ...usage ? { usage } : void 0
1014
- }]];
1015
- }));
1016
- }
1017
- //#endregion
1018
1081
  //#region src/chat/plugins/unfinished-work.ts
1019
1082
  /**
1020
1083
  * Return assigned and unfinished plugin work for the candidate conversations.
@@ -1333,8 +1396,8 @@ async function readConversationFeedFromSql(options = {}) {
1333
1396
  readConversationAccessFromSql(db, conversationIds, options.viewer),
1334
1397
  conversationArchiveTimes(db, conversationIds, filter?.kind === "viewer" ? { userId: filter.userId } : filter?.kind === "actorEmail" ? { email: filter.email } : void 0),
1335
1398
  listConversationAnnotationsById(db, conversationIds),
1336
- readConversationAuxiliaryCostsFromSql(db, conversationIds, { includeDescendants: true }),
1337
- readRootConversationMetricsFromSql(db, conversationIds),
1399
+ readConversationAuxiliaryCostsFromSql(db, conversationIds),
1400
+ readConversationTreeMetricsFromSql(db, conversationIds),
1338
1401
  readConversationParticipants(db, conversationIds),
1339
1402
  resolveSlackTeamDomains(conversations.flatMap((conversation) => conversation.location?.provider === "slack" ? [conversation.location.teamId] : [])),
1340
1403
  listConversationWork(conversationIds),
@@ -1349,12 +1412,15 @@ async function readConversationFeedFromSql(options = {}) {
1349
1412
  const row = rows[index];
1350
1413
  const access = accessByConversation.get(conversation.conversationId);
1351
1414
  const metrics = metricsByRoot.get(conversation.conversationId);
1415
+ const auxiliaryCosts = auxiliaryCostsByRoot.get(conversation.conversationId);
1416
+ const childAgentTotals = childAgentTotalsReport(metrics, auxiliaryCosts);
1352
1417
  const archivedAtMs = archiveTimesByConversation.get(conversation.conversationId);
1353
1418
  const summary = conversationSummaryFromStoredConversation({
1354
1419
  ...archivedAtMs === void 0 ? void 0 : { archivedAtMs },
1355
1420
  conversation,
1356
1421
  access,
1357
- auxiliaryCosts: auxiliaryCostsByRoot.get(conversation.conversationId),
1422
+ auxiliaryCosts: auxiliaryCosts?.total,
1423
+ ...childAgentTotals ? { childAgentTotals } : void 0,
1358
1424
  durationMs: metrics?.durationMs ?? row.conversation.durationMs,
1359
1425
  teamDomainByTeamId,
1360
1426
  ...row.location?.visibility === "public" ? { locationId: row.location.id } : void 0,
@@ -1507,6 +1573,7 @@ function projectConversationDetail(args) {
1507
1573
  access: args.access,
1508
1574
  ...args.archivedAtMs === void 0 ? void 0 : { archivedAtMs: args.archivedAtMs },
1509
1575
  auxiliaryCosts: args.auxiliaryCosts,
1576
+ ...args.childAgentTotals ? { childAgentTotals: args.childAgentTotals } : void 0,
1510
1577
  conversation,
1511
1578
  durationMs: args.durationMs,
1512
1579
  ...args.locationId ? { locationId: args.locationId } : void 0,
@@ -1537,17 +1604,13 @@ async function readConversationDetailFromSql(conversationId, options) {
1537
1604
  if (!record) return void 0;
1538
1605
  const archivedAtMs = options.viewer ? await readConversationArchivedAt(options.viewer, conversationId) : void 0;
1539
1606
  const executor = getSqlExecutor();
1540
- const includeDescendantMetrics = record.rootConversationId === conversationId;
1541
- const [accessByConversation, annotations, auxiliaryCostsByConversation, briefVersion, modelUsage, metricsByRoot, participantsByConversation, sourceTask, teamDomainByTeamId] = await Promise.all([
1607
+ const [accessByConversation, annotations, auxiliaryCostsByConversation, briefVersion, modelUsage, metricsByConversation, participantsByConversation, sourceTask, teamDomainByTeamId] = await Promise.all([
1542
1608
  readConversationAccessFromSql(getDb(), [conversationId], options.viewer),
1543
1609
  listConversationAnnotations(getDb(), conversationId),
1544
- readConversationAuxiliaryCostsFromSql(getDb(), [conversationId], { includeDescendants: includeDescendantMetrics }),
1610
+ readConversationAuxiliaryCostsFromSql(getDb(), [conversationId]),
1545
1611
  readLatestConversationBrief(getDb(), conversationId),
1546
- record.conversation.transcriptPurgedAtMs === void 0 ? readConversationModelUsageFromSql(executor, {
1547
- conversationId,
1548
- includeDescendants: includeDescendantMetrics
1549
- }) : Promise.resolve([]),
1550
- readRootConversationMetricsFromSql(getDb(), includeDescendantMetrics ? [conversationId] : []),
1612
+ record.conversation.transcriptPurgedAtMs === void 0 ? readConversationModelUsageFromSql(executor, { conversationId }) : Promise.resolve([]),
1613
+ readConversationTreeMetricsFromSql(getDb(), [conversationId]),
1551
1614
  readConversationParticipants(getDb(), [conversationId]),
1552
1615
  readConversationSourceTask({
1553
1616
  conversationId,
@@ -1562,14 +1625,17 @@ async function readConversationDetailFromSql(conversationId, options) {
1562
1625
  conversationId,
1563
1626
  limit: options.limit
1564
1627
  }) : { events: [] };
1565
- const metrics = metricsByRoot.get(conversationId);
1628
+ const metrics = metricsByConversation.get(conversationId);
1629
+ const auxiliaryCosts = auxiliaryCostsByConversation.get(conversationId);
1630
+ const childAgentTotals = childAgentTotalsReport(metrics, auxiliaryCosts);
1566
1631
  return projectConversationDetail({
1567
1632
  ...record,
1568
1633
  access,
1569
1634
  ...archivedAtMs === void 0 ? void 0 : { archivedAtMs },
1570
1635
  annotations,
1571
1636
  sidebarAnnotations,
1572
- auxiliaryCosts: auxiliaryCostsByConversation.get(conversationId),
1637
+ auxiliaryCosts: auxiliaryCosts?.total,
1638
+ ...childAgentTotals ? { childAgentTotals } : void 0,
1573
1639
  ...briefVersion ? { brief: {
1574
1640
  content: briefVersion.content,
1575
1641
  updatedAt: briefVersion.createdAt.toISOString(),
@@ -3118,7 +3184,7 @@ async function readLocationDetailFromSql(locationId, options = {}) {
3118
3184
  const activity = activityDays$1(days, nowMs, ACTIVITY_DAYS$1);
3119
3185
  const hourlyActivity = activityHours$1(hours, nowMs);
3120
3186
  const recentConversationIds = recentRows.map((row) => row.conversationId);
3121
- const [accessByConversation, metricsByRoot] = await Promise.all([readConversationAccessFromSql(getDb(), recentConversationIds, options.viewer), readRootConversationMetricsFromSql(getDb(), recentConversationIds)]);
3187
+ const [accessByConversation, metricsByRoot] = await Promise.all([readConversationAccessFromSql(getDb(), recentConversationIds, options.viewer), readConversationTreeMetricsFromSql(getDb(), recentConversationIds)]);
3122
3188
  return {
3123
3189
  ...location,
3124
3190
  activityDays: activity,
@@ -3515,7 +3581,7 @@ async function readPeoplePluginReports(args) {
3515
3581
  reports: [],
3516
3582
  source: "plugins"
3517
3583
  });
3518
- const { getPluginProfileReports } = await import("./agent-hooks-DpklSWZg.js").then((n) => n.t);
3584
+ const { getPluginProfileReports } = await import("./agent-hooks-DWCHBPYw.js").then((n) => n.t);
3519
3585
  return pluginOperationalReportFeedSchema.parse({
3520
3586
  generatedAt: new Date(nowMs).toISOString(),
3521
3587
  reports: await getPluginProfileReports({
@@ -3666,7 +3732,7 @@ async function readPeopleProfileFromSql(email, options = {}) {
3666
3732
  const surfaces = /* @__PURE__ */ new Map();
3667
3733
  for (const row of surfaceRows) addAggregate(surfaces, surfaceLabel(row.surface), row);
3668
3734
  const recentConversationIds = recentRows.map((row) => row.conversationId);
3669
- const [accessByConversation, metricsByRoot] = await Promise.all([readConversationAccessFromSql(getDb(), recentConversationIds, options.viewer), readRootConversationMetricsFromSql(getDb(), recentConversationIds)]);
3735
+ const [accessByConversation, metricsByRoot] = await Promise.all([readConversationAccessFromSql(getDb(), recentConversationIds, options.viewer), readConversationTreeMetricsFromSql(getDb(), recentConversationIds)]);
3670
3736
  return {
3671
3737
  activityDays: activityDays(days, nowMs),
3672
3738
  activityHours: activityHours(hours, nowMs),
@@ -4483,7 +4549,7 @@ function readDescriptionText(home) {
4483
4549
  }
4484
4550
  /** Read discovered skill names for authenticated runtime diagnostics. */
4485
4551
  async function readSkillReports() {
4486
- const { discoverSkills } = await import("./skills-C6zJbudq.js").then((n) => n.o);
4552
+ const { discoverSkills } = await import("./skills-BgGiQt5Y.js").then((n) => n.o);
4487
4553
  const skills = await discoverSkills();
4488
4554
  return skillReportsSchema.parse(skills.map((skill) => ({
4489
4555
  name: skill.name,
@@ -4492,7 +4558,7 @@ async function readSkillReports() {
4492
4558
  }
4493
4559
  /** Read safe configured plugin metadata for authenticated runtime diagnostics. */
4494
4560
  async function readPlugins() {
4495
- const { pluginCatalogRuntime } = await import("./catalog-runtime-CTaQXYqS.js").then((n) => n.t);
4561
+ const { pluginCatalogRuntime } = await import("./catalog-runtime-CTBsdSam.js").then((n) => n.t);
4496
4562
  return pluginsSchema.parse(pluginCatalogRuntime.getProviders().map((plugin) => ({
4497
4563
  configKeys: plugin.manifest.configKeys ?? [],
4498
4564
  description: plugin.manifest.description,
@@ -4504,7 +4570,7 @@ async function readPlugins() {
4504
4570
  async function readRuntimeInfoReport() {
4505
4571
  const [{ homeDir }, { pluginCatalogRuntime }, plugins, skills] = await Promise.all([
4506
4572
  import("./package-discovery-BVvSnQBB.js").then((n) => n.r),
4507
- import("./catalog-runtime-CTaQXYqS.js").then((n) => n.t),
4573
+ import("./catalog-runtime-CTBsdSam.js").then((n) => n.t),
4508
4574
  readPlugins(),
4509
4575
  readSkillReports()
4510
4576
  ]);
@@ -4521,7 +4587,7 @@ async function readRuntimeInfoReport() {
4521
4587
  /** Read sanitized operational summaries contributed by plugins. */
4522
4588
  async function readPluginOperationalReportFeed() {
4523
4589
  const nowMs = Date.now();
4524
- const { getPluginOperationalReports } = await import("./agent-hooks-DpklSWZg.js").then((n) => n.t);
4590
+ const { getPluginOperationalReports } = await import("./agent-hooks-DWCHBPYw.js").then((n) => n.t);
4525
4591
  return pluginOperationalReportFeedSchema.parse({
4526
4592
  source: "plugins",
4527
4593
  generatedAt: new Date(nowMs).toISOString(),
@@ -9,10 +9,10 @@ import { z } from "zod";
9
9
  import { Destination, OwnedObjectAnnotation, PluginRegistration, Source, User } from "@sentry/junior-plugin-api";
10
10
  import "@earendil-works/pi-agent-core";
11
11
  import "@earendil-works/pi-ai";
12
+ import "@sinclair/typebox";
12
13
  import { Sandbox } from "@vercel/sandbox";
13
14
  import { Client } from "@modelcontextprotocol/sdk/client";
14
15
  import "@modelcontextprotocol/sdk/client/auth.js";
15
- import "@sinclair/typebox";
16
16
  import { Message, StateAdapter } from "chat";
17
17
  import "@chat-adapter/slack";
18
18
  //#region src/chat/reasoning-level.d.ts
@@ -67,6 +67,8 @@ interface RuntimeLimits {
67
67
  maxSlicesPerTurn?: number;
68
68
  /** Tool calls one turn may make. */
69
69
  maxToolCallsPerTurn?: number;
70
+ /** Model spend in whole USD one turn may use. */
71
+ maxTurnCostUsd?: number;
70
72
  /** Agent turn deadline in ms. The function duration still caps it. */
71
73
  turnTimeoutMs?: number;
72
74
  }
@@ -155,7 +157,14 @@ interface InboxAttempt {
155
157
  ack(): Promise<void>;
156
158
  conversationId: string;
157
159
  destination?: Destination;
158
- drain(handle: (messages: InboundMessage[]) => Promise<readonly string[] | void>): Promise<InboundMessage[]>;
160
+ /**
161
+ * Give pending mailbox messages to the active Turn. By default only
162
+ * `interrupt` messages for this attempt are offered. With `deferred`, every
163
+ * pending message is offered, and the handler owns Actor and Source scoping.
164
+ */
165
+ drain(handle: (messages: InboundMessage[]) => Promise<readonly string[] | void>, options?: {
166
+ deferred?: boolean;
167
+ }): Promise<InboundMessage[]>;
159
168
  isFinalAttempt: boolean;
160
169
  messages: InboundMessage[];
161
170
  }
package/dist/app.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { i as ModelProfileInput, n as createApp, r as JuniorDashboardOptions, t as JuniorAppOptions } from "./app-BYB7szGb.js";
1
+ import { i as ModelProfileInput, n as createApp, r as JuniorDashboardOptions, t as JuniorAppOptions } from "./app-B0gT1Slp.js";
2
2
  import { i as defineJuniorPlugins, n as JuniorPluginSet, r as JuniorPluginSetOptions, t as JuniorPluginInput } from "./plugins-CjfUP5gJ.js";
3
3
  import { t as JUNIOR_VERSION } from "./version-CnXZ614E.js";
4
4
  export { JUNIOR_VERSION, JuniorAppOptions, type JuniorDashboardOptions, type JuniorPluginInput, type JuniorPluginSet, type JuniorPluginSetOptions, type ModelProfileInput, createApp, defineJuniorPlugins };