@sentry/junior 0.247.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 (61) hide show
  1. package/dist/{admin-BGwaqDMs.js → admin-BlHz8fGl.js} +1 -1
  2. package/dist/{agent-hooks-C72ByH0C.js → agent-hooks-DWCHBPYw.js} +24 -11
  3. package/dist/{agent-runner-DsAFAKKs.js → agent-runner-CnlFtbzb.js} +224 -89
  4. package/dist/api/schema.d.ts +171 -3
  5. package/dist/api/schema.js +3 -3
  6. package/dist/api.js +218 -155
  7. package/dist/{app-4t4mPTdS.d.ts → app-B0gT1Slp.d.ts} +3 -1
  8. package/dist/app.d.ts +1 -1
  9. package/dist/app.js +27 -27
  10. package/dist/{assistant-reply-ChOzcTBS.js → assistant-reply-BxCi7V4v.js} +1 -1
  11. package/dist/{briefs-Dc7qZrhc.js → briefs-CdkIl79U.js} +4 -4
  12. package/dist/{catalog-runtime-DS1k7fUG.js → catalog-runtime-CTBsdSam.js} +1 -1
  13. package/dist/cli/chat.js +15 -15
  14. package/dist/cli/check.js +3 -3
  15. package/dist/cli/main.js +2 -2
  16. package/dist/cli/plugins.js +4 -4
  17. package/dist/cli/snapshot-create.js +3 -3
  18. package/dist/cli/upgrade.js +3 -3
  19. package/dist/{client-BVnfNd3D.js → client-CWQtbizj.js} +2 -2
  20. package/dist/{config-CgWvImQL.js → config-aitDvTQm.js} +16 -9
  21. package/dist/{conversation-CYsbVFLx.js → conversation-Cjo9tHGm.js} +15 -1
  22. package/dist/{conversation-privacy-D3TdVM9H.js → conversation-privacy-BsqXHVBz.js} +1 -1
  23. package/dist/{credential-sync-DLw3jkv-.js → credential-sync-DqZF735a.js} +14 -14
  24. package/dist/{executor-DQazjeGA.js → executor-oIZAkQZb.js} +2 -2
  25. package/dist/{images-C3e5E-p_.js → images-Dzh3RBXY.js} +3 -3
  26. package/dist/instrumentation.js +2 -2
  27. package/dist/{job-queue-BEUqRhjC.js → job-queue-DyA2AEnY.js} +1 -1
  28. package/dist/{logging-CZEc8_v4.js → logging-OpC2jwiV.js} +1 -1
  29. package/dist/{message-BIJa7lKh.js → message-EyMrVXEf.js} +3 -3
  30. package/dist/nitro.d.ts +1 -1
  31. package/dist/nitro.js +3 -3
  32. package/dist/{oauth-callback-server-R9OSdLP1.js → oauth-callback-server-ClDv9Z5Y.js} +2 -2
  33. package/dist/{pending-auth-Oo5AQhaf.js → pending-auth-D_nf121N.js} +2 -2
  34. package/dist/{profile-aVLDAirh.js → profile-Dfg76pvk.js} +4 -4
  35. package/dist/{prompt-ZG1UCxjF.js → prompt-C7bRJ2vg.js} +1 -1
  36. package/dist/{registry-CtaDOOM5.js → registry-fpIZHoqE.js} +1 -1
  37. package/dist/{resolve-Bdw4hu7s.js → resolve-LMCZhQVg.js} +2 -2
  38. package/dist/{result-DNgmkASh.js → result-C1ZCRPLx.js} +7 -7
  39. package/dist/{runner-BUSScEu5.js → runner-DNZMviFH.js} +10 -10
  40. package/dist/{sandbox-egress-signals-E9r8bf9G.js → sandbox-egress-signals-Dcc-mwkl.js} +1 -1
  41. package/dist/{schema-tyd6hALh.js → schema-BRZsYL5-.js} +4 -3
  42. package/dist/{session-stop-CAhBfBUT.js → session-stop-dyvsZDB0.js} +11 -11
  43. package/dist/{skills-DQy-mmBC.js → skills-BgGiQt5Y.js} +2 -2
  44. package/dist/{spawn-DQ_MVWZ6.js → spawn-CpqxMPWE.js} +2 -2
  45. package/dist/{store-DjLA8GKs.js → store-OMQAFrJG.js} +6 -6
  46. package/dist/{task-queue-BT2h_t8I.js → task-queue-SWsXPSp-.js} +3 -3
  47. package/dist/{task-runner-CiPepjIB.js → task-runner-BOxv7shv.js} +10 -10
  48. package/dist/{tasks-DMmRrIVl.js → tasks-DREdnhVP.js} +49 -16
  49. package/dist/{thread-state-ehZYGpX9.js → thread-state-BoNCtSwk.js} +6 -6
  50. package/dist/{turn-failure-response-D7J10z7l.js → turn-failure-response-C6jrCPjc.js} +8 -8
  51. package/dist/{turn-lifecycle-Buswqs90.js → turn-lifecycle-cQFsZFOU.js} +1 -1
  52. package/dist/{turn-session-routing-Bw-yiSb4.js → turn-session-routing-Ba12fwXz.js} +1 -1
  53. package/dist/{validation-DTguegIe.js → validation-Dmfh2cTj.js} +1 -1
  54. package/dist/{version-BrZSE5du.js → version-ByV7nGOn.js} +1 -1
  55. package/dist/version.js +1 -1
  56. package/dist/{viewer-BlAozHer.js → viewer-CX41TWYr.js} +3 -3
  57. package/dist/{web-authorization-DwyTlkAg.js → web-authorization-rDLlKIS0.js} +6 -6
  58. package/dist/{web-input-DSYxI7Wi.js → web-input-Bn9HHZEo.js} +28 -28
  59. package/dist/{work-CRBXkJoU.js → work-CvFoEpRT.js} +10 -10
  60. package/dist/{worker-BVJKM9Ja.js → worker-CI5B63vk.js} +5 -5
  61. package/package.json +4 -4
package/dist/api.js CHANGED
@@ -1,27 +1,27 @@
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-DsAFAKKs.js";
2
- import { d as logException, p as logWarn } from "./logging-CZEc8_v4.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-BlAozHer.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
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-DQazjeGA.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-DMmRrIVl.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-C72ByH0C.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-CYsbVFLx.js";
11
- import { n as hash, t as create } from "./profile-aVLDAirh.js";
12
- import { l as getEventCatalog, v as automationEventCatalog } from "./session-stop-CAhBfBUT.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";
13
13
  import { t as getFirstRunAtMs } from "./cadence-D00SCzT1.js";
14
- import { t as getCachedSnapshot } from "./resolve-Bdw4hu7s.js";
15
- import { a as getVercelConversationWorkQueue } from "./job-queue-BEUqRhjC.js";
16
- import { a as cancelHumanFacingPendingMessages, h as getConversation } from "./store-DjLA8GKs.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";
17
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";
18
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";
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-DSYxI7Wi.js";
20
- import { A as conversationActiveDaysColumn, M as conversationRangeColumns, j as conversationAggregateColumns } from "./task-runner-CiPepjIB.js";
21
- import { d as legacyWebMailboxMetadataSchema } from "./result-DNgmkASh.js";
22
- import { r as getWebAuthorization } from "./web-authorization-DwyTlkAg.js";
23
- import { t as decodeInputImages } from "./images-C3e5E-p_.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-tyd6hALh.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";
25
25
  import { Hono } from "hono";
26
26
  import path from "node:path";
27
27
  import { z } from "zod";
@@ -134,6 +134,39 @@ async function archiveConversation(viewer, conversationId, body) {
134
134
  throwApiError(409, "Conversation received new activity.");
135
135
  }
136
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
137
170
  //#region src/chat/conversations/fork.ts
138
171
  /** Event key of the agent note that follows the copied events in a fork. */
139
172
  const FORK_NOTE_KEY = "fork:note";
@@ -285,7 +318,6 @@ function hasUnfinishedToolCalls(messages) {
285
318
  }
286
319
  //#endregion
287
320
  //#region src/api/conversations/auxiliary-costs.ts
288
- const auxiliaryRootConversation = alias(juniorConversations, "auxiliary_root_conversation");
289
321
  function eventCost() {
290
322
  return sql`CASE
291
323
  WHEN ${juniorConversationEvents.type} = 'structured_event'
@@ -297,14 +329,17 @@ function eventCost() {
297
329
  ELSE NULL
298
330
  END`;
299
331
  }
300
- /** Aggregate additive event costs by namespaced operation for conversations. */
301
- 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) {
302
340
  if (conversationIds.length === 0) return /* @__PURE__ */ new Map();
303
- const selectedIds = [...conversationIds];
304
- const conversationId = options.includeDescendants ? sql`coalesce(
305
- ${auxiliaryRootConversation.conversationId},
306
- ${juniorConversations.conversationId}
307
- )` : sql`${juniorConversations.conversationId}`;
341
+ const scopeConversationId = conversationSubtreeColumns.scopeConversationId;
342
+ const isChildAgent = sql`(${conversationSubtreeColumns.conversationId} <> ${scopeConversationId})`;
308
343
  const namespace = sql`CASE
309
344
  WHEN ${juniorConversationEvents.type} = 'structured_event'
310
345
  THEN ${juniorConversationEvents.payload}->>'namespace'
@@ -316,22 +351,23 @@ async function readConversationAuxiliaryCostsFromSql(db, conversationIds, option
316
351
  ELSE ${juniorConversationEvents.type}
317
352
  END`;
318
353
  const cost = eventCost();
319
- const selectedConversation = options.includeDescendants ? or(and(inArray(juniorConversations.rootConversationId, selectedIds), isNotNull(auxiliaryRootConversation.conversationId)), inArray(juniorConversations.conversationId, selectedIds)) : inArray(juniorConversations.conversationId, selectedIds);
320
354
  const rows = await db.select({
321
- conversationId,
355
+ conversationId: scopeConversationId,
356
+ childAgentCostUsd: sql`coalesce(round(sum(case when ${isChildAgent} then ${cost} end), 12), 0)::double precision`.mapWith(Number),
322
357
  costUsd: sql`round(sum(${cost}), 12)::double precision`.mapWith(Number),
323
358
  events: sql`count(*)::integer`.mapWith(Number),
324
359
  name,
325
360
  namespace
326
- }).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);
327
362
  const result = /* @__PURE__ */ new Map();
328
363
  for (const row of rows) {
329
- const current = result.get(row.conversationId) ?? {
364
+ const current = result.get(row.conversationId) ?? { total: {
330
365
  costUsd: 0,
331
366
  operations: []
332
- };
333
- current.costUsd = Math.round((current.costUsd + row.costUsd) * 0xe8d4a51000) / 0xe8d4a51000;
334
- 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({
335
371
  costUsd: row.costUsd,
336
372
  events: row.events,
337
373
  name: row.name,
@@ -342,20 +378,119 @@ async function readConversationAuxiliaryCostsFromSql(db, conversationIds, option
342
378
  return result;
343
379
  }
344
380
  //#endregion
345
- //#region src/api/conversations/child-agents.ts
346
- /** Read the runtime and usage saved on each child Conversation row. */
347
- async function readChildConversationMetrics(db, conversationIds) {
348
- const rows = conversationIds.length === 0 ? [] : await db.select({
349
- conversationId: juniorConversations.conversationId,
350
- durationMs: juniorConversations.durationMs,
351
- usage: juniorConversations.usage
352
- }).from(juniorConversations).where(inArray(juniorConversations.conversationId, [...conversationIds]));
353
- return new Map(rows.map((row) => [row.conversationId, {
354
- cumulativeDurationMs: row.durationMs,
355
- ...row.usage ? { cumulativeUsage: row.usage } : void 0
356
- }]));
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;
357
476
  }
358
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
+ /**
359
494
  * Load the direct child agents of one Conversation, or throw a standard API
360
495
  * not-found error. Viewers who cannot see private content get only the status,
361
496
  * time, and usage of each child agent.
@@ -366,14 +501,17 @@ async function requireConversationChildAgents(conversationId, options = {}) {
366
501
  const [accessByConversation, children] = await Promise.all([readConversationAccessFromSql(db, [conversationId], options.viewer), listChildAgents(conversationId)]);
367
502
  const canExposePayload = accessByConversation.get(conversationId)?.canViewPrivateContent ?? false;
368
503
  const childIds = children.map((agent) => agent.childConversationId);
369
- 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)]);
370
505
  const agents = children.map((agent) => {
506
+ const metrics = metricsByChild.get(agent.childConversationId);
371
507
  const auxiliaryCosts = auxiliaryCostsByChild.get(agent.childConversationId);
508
+ const childAgentTotals = childAgentTotalsReport(metrics, auxiliaryCosts);
372
509
  return {
373
510
  conversationId: agent.childConversationId,
374
- cumulativeDurationMs: 0,
375
- ...metricsByChild.get(agent.childConversationId),
376
- ...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,
377
515
  status: agent.status,
378
516
  updatedAt: new Date(agent.updatedAtMs).toISOString(),
379
517
  ...canExposePayload ? {
@@ -645,8 +783,8 @@ async function resolveSlackTeamDomains(teamIds) {
645
783
  //#region src/chat/pi/sql-model-usage.ts
646
784
  /** SQL reporting adapter for usage stored on assistant history events. */
647
785
  const message = sql`${juniorConversationEvents.payload}`;
648
- const usage$1 = sql`${message}->'usage'`;
649
- const cost = sql`${usage$1}->'cost'`;
786
+ const usage = sql`${message}->'usage'`;
787
+ const cost = sql`${usage}->'cost'`;
650
788
  function nonnegativeNumber(source, field, fallbackField, floor = false) {
651
789
  const value = (name) => sql`case
652
790
  when jsonb_typeof(${source}->${name}) = 'number'
@@ -657,7 +795,7 @@ function nonnegativeNumber(source, field, fallbackField, floor = false) {
657
795
  return fallbackField ? sql`coalesce(${primary}, ${value(fallbackField)})` : sql`${primary}`;
658
796
  }
659
797
  function token(field, fallbackField) {
660
- return nonnegativeNumber(usage$1, field, fallbackField, true);
798
+ return nonnegativeNumber(usage, field, fallbackField, true);
661
799
  }
662
800
  function summed(value) {
663
801
  return sql`sum(${value})::double precision`;
@@ -706,8 +844,9 @@ function usageFromRow(row) {
706
844
  return hasAgentTurnUsage(result) ? agentTurnUsageSchema.parse(result) : void 0;
707
845
  }
708
846
  /**
709
- * Aggregate real assistant calls by provider/model in SQL. Replayed history is
710
- * 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.
711
850
  */
712
851
  async function readConversationModelUsageFromSql(executor, options) {
713
852
  const modelId = sql`case
@@ -737,7 +876,7 @@ async function readConversationModelUsageFromSql(executor, options) {
737
876
  costCacheRead: summedCost(nonnegativeNumber(cost, "cacheRead")),
738
877
  costCacheWrite: summedCost(nonnegativeNumber(cost, "cacheWrite")),
739
878
  costTotal: summedCost(nonnegativeNumber(cost, "total"))
740
- }).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) => {
741
880
  const modelUsage = usageFromRow(row);
742
881
  return modelUsage ? [{
743
882
  modelId: row.modelId,
@@ -928,6 +1067,7 @@ function conversationSummaryFromStoredConversation(args) {
928
1067
  surface,
929
1068
  ...args.auxiliaryCosts ? { auxiliaryCosts: args.auxiliaryCosts } : void 0,
930
1069
  ...usage ? { cumulativeUsage: usage } : void 0,
1070
+ ...args.childAgentTotals ? { childAgentTotals: args.childAgentTotals } : void 0,
931
1071
  ...actorIdentity ? { actorIdentity } : void 0,
932
1072
  ...locationUrl ? { locationUrl } : void 0,
933
1073
  archivedAt: args.archivedAtMs === void 0 ? null : new Date(args.archivedAtMs).toISOString(),
@@ -938,86 +1078,6 @@ function conversationSummaryFromStoredConversation(args) {
938
1078
  };
939
1079
  }
940
1080
  //#endregion
941
- //#region src/api/conversations/usage.ts
942
- const usage = juniorConversations.usage;
943
- const metricRootConversation = alias(juniorConversations, "metric_root_conversation");
944
- const componentFields = [
945
- "inputTokens",
946
- "outputTokens",
947
- "cachedInputTokens",
948
- "cacheCreationTokens"
949
- ];
950
- function summedUsageNumber(field) {
951
- return sql`sum((${usage}->>${field})::double precision)::double precision`;
952
- }
953
- function summedCostNumber(field) {
954
- return sql`round(
955
- sum((${usage}->'cost'->>${field})::numeric),
956
- 12
957
- )::double precision`;
958
- }
959
- function usageFromAggregate(row) {
960
- const components = {};
961
- let componentTotal = 0;
962
- for (const field of componentFields) {
963
- const value = row[field];
964
- if (value === null) continue;
965
- components[field] = value;
966
- componentTotal += value;
967
- }
968
- const cost = {
969
- ...row.costInput === null ? void 0 : { input: row.costInput },
970
- ...row.costOutput === null ? void 0 : { output: row.costOutput },
971
- ...row.costCacheRead === null ? void 0 : { cacheRead: row.costCacheRead },
972
- ...row.costCacheWrite === null ? void 0 : { cacheWrite: row.costCacheWrite },
973
- ...row.costTotal === null ? void 0 : { total: row.costTotal }
974
- };
975
- const result = {
976
- ...row.totalOnlyTokens === null ? components : { totalTokens: row.totalOnlyTokens + componentTotal },
977
- ...row.reasoningTokens === null ? void 0 : { reasoningTokens: row.reasoningTokens },
978
- ...Object.keys(cost).length === 0 ? void 0 : { cost }
979
- };
980
- return hasAgentTurnUsage(result) ? result : void 0;
981
- }
982
- /** Aggregate persisted metrics in PostgreSQL for selected conversation trees. */
983
- async function readRootConversationMetricsFromSql(db, rootConversationIds) {
984
- if (rootConversationIds.length === 0) return /* @__PURE__ */ new Map();
985
- const hasComponents = sql`coalesce(
986
- ${usage}->>'inputTokens',
987
- ${usage}->>'outputTokens',
988
- ${usage}->>'cachedInputTokens',
989
- ${usage}->>'cacheCreationTokens'
990
- ) is not null`;
991
- const rows = await db.select({
992
- rootConversationId: juniorConversations.rootConversationId,
993
- durationMs: sql`coalesce(sum(${juniorConversations.durationMs}), 0)::double precision`,
994
- inputTokens: summedUsageNumber("inputTokens"),
995
- outputTokens: summedUsageNumber("outputTokens"),
996
- cachedInputTokens: summedUsageNumber("cachedInputTokens"),
997
- cacheCreationTokens: summedUsageNumber("cacheCreationTokens"),
998
- totalOnlyTokens: sql`sum(
999
- case
1000
- when not (${hasComponents})
1001
- then (${usage}->>'totalTokens')::double precision
1002
- end
1003
- )::double precision`,
1004
- reasoningTokens: summedUsageNumber("reasoningTokens"),
1005
- costInput: summedCostNumber("input"),
1006
- costOutput: summedCostNumber("output"),
1007
- costCacheRead: summedCostNumber("cacheRead"),
1008
- costCacheWrite: summedCostNumber("cacheWrite"),
1009
- costTotal: summedCostNumber("total")
1010
- }).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);
1011
- return new Map(rows.flatMap((row) => {
1012
- if (!row.rootConversationId) return [];
1013
- const usage = usageFromAggregate(row);
1014
- return [[row.rootConversationId, {
1015
- durationMs: row.durationMs,
1016
- ...usage ? { usage } : void 0
1017
- }]];
1018
- }));
1019
- }
1020
- //#endregion
1021
1081
  //#region src/chat/plugins/unfinished-work.ts
1022
1082
  /**
1023
1083
  * Return assigned and unfinished plugin work for the candidate conversations.
@@ -1336,8 +1396,8 @@ async function readConversationFeedFromSql(options = {}) {
1336
1396
  readConversationAccessFromSql(db, conversationIds, options.viewer),
1337
1397
  conversationArchiveTimes(db, conversationIds, filter?.kind === "viewer" ? { userId: filter.userId } : filter?.kind === "actorEmail" ? { email: filter.email } : void 0),
1338
1398
  listConversationAnnotationsById(db, conversationIds),
1339
- readConversationAuxiliaryCostsFromSql(db, conversationIds, { includeDescendants: true }),
1340
- readRootConversationMetricsFromSql(db, conversationIds),
1399
+ readConversationAuxiliaryCostsFromSql(db, conversationIds),
1400
+ readConversationTreeMetricsFromSql(db, conversationIds),
1341
1401
  readConversationParticipants(db, conversationIds),
1342
1402
  resolveSlackTeamDomains(conversations.flatMap((conversation) => conversation.location?.provider === "slack" ? [conversation.location.teamId] : [])),
1343
1403
  listConversationWork(conversationIds),
@@ -1352,12 +1412,15 @@ async function readConversationFeedFromSql(options = {}) {
1352
1412
  const row = rows[index];
1353
1413
  const access = accessByConversation.get(conversation.conversationId);
1354
1414
  const metrics = metricsByRoot.get(conversation.conversationId);
1415
+ const auxiliaryCosts = auxiliaryCostsByRoot.get(conversation.conversationId);
1416
+ const childAgentTotals = childAgentTotalsReport(metrics, auxiliaryCosts);
1355
1417
  const archivedAtMs = archiveTimesByConversation.get(conversation.conversationId);
1356
1418
  const summary = conversationSummaryFromStoredConversation({
1357
1419
  ...archivedAtMs === void 0 ? void 0 : { archivedAtMs },
1358
1420
  conversation,
1359
1421
  access,
1360
- auxiliaryCosts: auxiliaryCostsByRoot.get(conversation.conversationId),
1422
+ auxiliaryCosts: auxiliaryCosts?.total,
1423
+ ...childAgentTotals ? { childAgentTotals } : void 0,
1361
1424
  durationMs: metrics?.durationMs ?? row.conversation.durationMs,
1362
1425
  teamDomainByTeamId,
1363
1426
  ...row.location?.visibility === "public" ? { locationId: row.location.id } : void 0,
@@ -1510,6 +1573,7 @@ function projectConversationDetail(args) {
1510
1573
  access: args.access,
1511
1574
  ...args.archivedAtMs === void 0 ? void 0 : { archivedAtMs: args.archivedAtMs },
1512
1575
  auxiliaryCosts: args.auxiliaryCosts,
1576
+ ...args.childAgentTotals ? { childAgentTotals: args.childAgentTotals } : void 0,
1513
1577
  conversation,
1514
1578
  durationMs: args.durationMs,
1515
1579
  ...args.locationId ? { locationId: args.locationId } : void 0,
@@ -1540,17 +1604,13 @@ async function readConversationDetailFromSql(conversationId, options) {
1540
1604
  if (!record) return void 0;
1541
1605
  const archivedAtMs = options.viewer ? await readConversationArchivedAt(options.viewer, conversationId) : void 0;
1542
1606
  const executor = getSqlExecutor();
1543
- const includeDescendantMetrics = record.rootConversationId === conversationId;
1544
- 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([
1545
1608
  readConversationAccessFromSql(getDb(), [conversationId], options.viewer),
1546
1609
  listConversationAnnotations(getDb(), conversationId),
1547
- readConversationAuxiliaryCostsFromSql(getDb(), [conversationId], { includeDescendants: includeDescendantMetrics }),
1610
+ readConversationAuxiliaryCostsFromSql(getDb(), [conversationId]),
1548
1611
  readLatestConversationBrief(getDb(), conversationId),
1549
- record.conversation.transcriptPurgedAtMs === void 0 ? readConversationModelUsageFromSql(executor, {
1550
- conversationId,
1551
- includeDescendants: includeDescendantMetrics
1552
- }) : Promise.resolve([]),
1553
- readRootConversationMetricsFromSql(getDb(), includeDescendantMetrics ? [conversationId] : []),
1612
+ record.conversation.transcriptPurgedAtMs === void 0 ? readConversationModelUsageFromSql(executor, { conversationId }) : Promise.resolve([]),
1613
+ readConversationTreeMetricsFromSql(getDb(), [conversationId]),
1554
1614
  readConversationParticipants(getDb(), [conversationId]),
1555
1615
  readConversationSourceTask({
1556
1616
  conversationId,
@@ -1565,14 +1625,17 @@ async function readConversationDetailFromSql(conversationId, options) {
1565
1625
  conversationId,
1566
1626
  limit: options.limit
1567
1627
  }) : { events: [] };
1568
- const metrics = metricsByRoot.get(conversationId);
1628
+ const metrics = metricsByConversation.get(conversationId);
1629
+ const auxiliaryCosts = auxiliaryCostsByConversation.get(conversationId);
1630
+ const childAgentTotals = childAgentTotalsReport(metrics, auxiliaryCosts);
1569
1631
  return projectConversationDetail({
1570
1632
  ...record,
1571
1633
  access,
1572
1634
  ...archivedAtMs === void 0 ? void 0 : { archivedAtMs },
1573
1635
  annotations,
1574
1636
  sidebarAnnotations,
1575
- auxiliaryCosts: auxiliaryCostsByConversation.get(conversationId),
1637
+ auxiliaryCosts: auxiliaryCosts?.total,
1638
+ ...childAgentTotals ? { childAgentTotals } : void 0,
1576
1639
  ...briefVersion ? { brief: {
1577
1640
  content: briefVersion.content,
1578
1641
  updatedAt: briefVersion.createdAt.toISOString(),
@@ -3121,7 +3184,7 @@ async function readLocationDetailFromSql(locationId, options = {}) {
3121
3184
  const activity = activityDays$1(days, nowMs, ACTIVITY_DAYS$1);
3122
3185
  const hourlyActivity = activityHours$1(hours, nowMs);
3123
3186
  const recentConversationIds = recentRows.map((row) => row.conversationId);
3124
- 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)]);
3125
3188
  return {
3126
3189
  ...location,
3127
3190
  activityDays: activity,
@@ -3518,7 +3581,7 @@ async function readPeoplePluginReports(args) {
3518
3581
  reports: [],
3519
3582
  source: "plugins"
3520
3583
  });
3521
- const { getPluginProfileReports } = await import("./agent-hooks-C72ByH0C.js").then((n) => n.t);
3584
+ const { getPluginProfileReports } = await import("./agent-hooks-DWCHBPYw.js").then((n) => n.t);
3522
3585
  return pluginOperationalReportFeedSchema.parse({
3523
3586
  generatedAt: new Date(nowMs).toISOString(),
3524
3587
  reports: await getPluginProfileReports({
@@ -3669,7 +3732,7 @@ async function readPeopleProfileFromSql(email, options = {}) {
3669
3732
  const surfaces = /* @__PURE__ */ new Map();
3670
3733
  for (const row of surfaceRows) addAggregate(surfaces, surfaceLabel(row.surface), row);
3671
3734
  const recentConversationIds = recentRows.map((row) => row.conversationId);
3672
- 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)]);
3673
3736
  return {
3674
3737
  activityDays: activityDays(days, nowMs),
3675
3738
  activityHours: activityHours(hours, nowMs),
@@ -4486,7 +4549,7 @@ function readDescriptionText(home) {
4486
4549
  }
4487
4550
  /** Read discovered skill names for authenticated runtime diagnostics. */
4488
4551
  async function readSkillReports() {
4489
- const { discoverSkills } = await import("./skills-DQy-mmBC.js").then((n) => n.o);
4552
+ const { discoverSkills } = await import("./skills-BgGiQt5Y.js").then((n) => n.o);
4490
4553
  const skills = await discoverSkills();
4491
4554
  return skillReportsSchema.parse(skills.map((skill) => ({
4492
4555
  name: skill.name,
@@ -4495,7 +4558,7 @@ async function readSkillReports() {
4495
4558
  }
4496
4559
  /** Read safe configured plugin metadata for authenticated runtime diagnostics. */
4497
4560
  async function readPlugins() {
4498
- const { pluginCatalogRuntime } = await import("./catalog-runtime-DS1k7fUG.js").then((n) => n.t);
4561
+ const { pluginCatalogRuntime } = await import("./catalog-runtime-CTBsdSam.js").then((n) => n.t);
4499
4562
  return pluginsSchema.parse(pluginCatalogRuntime.getProviders().map((plugin) => ({
4500
4563
  configKeys: plugin.manifest.configKeys ?? [],
4501
4564
  description: plugin.manifest.description,
@@ -4507,7 +4570,7 @@ async function readPlugins() {
4507
4570
  async function readRuntimeInfoReport() {
4508
4571
  const [{ homeDir }, { pluginCatalogRuntime }, plugins, skills] = await Promise.all([
4509
4572
  import("./package-discovery-BVvSnQBB.js").then((n) => n.r),
4510
- import("./catalog-runtime-DS1k7fUG.js").then((n) => n.t),
4573
+ import("./catalog-runtime-CTBsdSam.js").then((n) => n.t),
4511
4574
  readPlugins(),
4512
4575
  readSkillReports()
4513
4576
  ]);
@@ -4524,7 +4587,7 @@ async function readRuntimeInfoReport() {
4524
4587
  /** Read sanitized operational summaries contributed by plugins. */
4525
4588
  async function readPluginOperationalReportFeed() {
4526
4589
  const nowMs = Date.now();
4527
- const { getPluginOperationalReports } = await import("./agent-hooks-C72ByH0C.js").then((n) => n.t);
4590
+ const { getPluginOperationalReports } = await import("./agent-hooks-DWCHBPYw.js").then((n) => n.t);
4528
4591
  return pluginOperationalReportFeedSchema.parse({
4529
4592
  source: "plugins",
4530
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
  }
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-4t4mPTdS.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 };