@sentry/junior 0.192.0 → 0.194.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 (97) hide show
  1. package/dist/{agent-hooks-3JY76L5X.js → agent-hooks-IDX764FD.js} +11 -11
  2. package/dist/api/conversations/aggregate.d.ts +2 -0
  3. package/dist/api/conversations/list.d.ts +1 -1
  4. package/dist/api/conversations/projection.d.ts +1 -1
  5. package/dist/api/locations/detail.d.ts +1 -1
  6. package/dist/api/schema/conversation.d.ts +3 -3
  7. package/dist/api/schema/location.d.ts +1 -1
  8. package/dist/api/schema/person.d.ts +1 -1
  9. package/dist/api/schema/task.d.ts +71 -8
  10. package/dist/api/schema.d.ts +2 -2
  11. package/dist/api/schema.js +3 -1
  12. package/dist/api.js +106 -187
  13. package/dist/app.js +55 -83
  14. package/dist/{catalog-runtime-5JVLWXRY.js → catalog-runtime-MICXEBLK.js} +4 -4
  15. package/dist/chat/agent/prompt.d.ts +1 -1
  16. package/dist/chat/agent/resume.d.ts +2 -0
  17. package/dist/chat/agent-dispatch/types.d.ts +2 -1
  18. package/dist/chat/agent-dispatch/validation.d.ts +1 -1
  19. package/dist/chat/agent-invocations/types.d.ts +24 -28
  20. package/dist/chat/config.d.ts +1 -0
  21. package/dist/chat/conversations/history.d.ts +4 -2
  22. package/dist/chat/event-tasks/tool-support.d.ts +10 -1
  23. package/dist/chat/plugins/agent-hooks.d.ts +2 -2
  24. package/dist/chat/prompt.d.ts +4 -5
  25. package/dist/chat/services/turn-limit.d.ts +11 -1
  26. package/dist/chat/services/turn-session-routing.d.ts +4 -3
  27. package/dist/chat/slack/{source-link.d.ts → location-url.d.ts} +1 -1
  28. package/dist/chat/slack/tool-support/context.d.ts +3 -6
  29. package/dist/chat/source.d.ts +4 -6
  30. package/dist/chat/task-execution/checkpoint.d.ts +2 -0
  31. package/dist/chat/task-execution/turn-cursor.d.ts +3 -0
  32. package/dist/chat/tasks/execution-stats.d.ts +13 -1
  33. package/dist/chat/tools/delete-event-task.d.ts +1 -1
  34. package/dist/chat/tools/types.d.ts +10 -9
  35. package/dist/chat/tools/update-event-task.d.ts +1 -1
  36. package/dist/chat/usage.d.ts +4 -0
  37. package/dist/{chunk-YRWGJ5OO.js → chunk-2NL3Y47F.js} +5 -5
  38. package/dist/{chunk-BGLMT6KP.js → chunk-53IEEFFP.js} +3 -3
  39. package/dist/{chunk-PXUBRZBU.js → chunk-6H2MKVV5.js} +1 -1
  40. package/dist/{chunk-47JFLZSF.js → chunk-73JEAQRT.js} +4 -4
  41. package/dist/{chunk-6LX6KV5C.js → chunk-7ANA7PBB.js} +3 -3
  42. package/dist/{chunk-AKR6W7VV.js → chunk-ADEACKAH.js} +82 -69
  43. package/dist/{chunk-YE6DVM43.js → chunk-AWZS5SVX.js} +8 -8
  44. package/dist/{chunk-BUTAWPUV.js → chunk-CCTYK5RH.js} +37 -31
  45. package/dist/{chunk-RWBZZMW6.js → chunk-CFGBKPWQ.js} +3 -3
  46. package/dist/{chunk-G4E5WIRL.js → chunk-E53C73ML.js} +4 -4
  47. package/dist/{chunk-3UJSII43.js → chunk-ELCYG6UU.js} +3 -3
  48. package/dist/{chunk-SSR6YBWW.js → chunk-ENWIHU54.js} +11 -7
  49. package/dist/{chunk-4CCQZHD3.js → chunk-F2KSURTJ.js} +11 -11
  50. package/dist/{chunk-7XO7PTZE.js → chunk-G35QGPO2.js} +1 -1
  51. package/dist/{chunk-4B4DQGOM.js → chunk-G4RARFNT.js} +101 -66
  52. package/dist/{chunk-Z4DNJI5F.js → chunk-GY5SEFVL.js} +5 -5
  53. package/dist/{chunk-KR5F3QSP.js → chunk-H4DCWLTR.js} +8 -8
  54. package/dist/{chunk-ARSUYYQG.js → chunk-IME5OW4Y.js} +1 -1
  55. package/dist/{chunk-3O2NXVGB.js → chunk-INTBMGNX.js} +23 -25
  56. package/dist/{chunk-4WIA45WD.js → chunk-IOGDKPVU.js} +1 -1
  57. package/dist/{chunk-EYNUOZCN.js → chunk-JOI3DHML.js} +1 -1
  58. package/dist/{chunk-5V4BAUCH.js → chunk-KNIAWMBU.js} +1 -1
  59. package/dist/{chunk-ITTEDZGY.js → chunk-NPO24LAN.js} +32 -25
  60. package/dist/{chunk-SZ2O3CGS.js → chunk-NWWDFHXP.js} +1 -1
  61. package/dist/{chunk-VF3EDS7P.js → chunk-OEQOAONV.js} +60 -29
  62. package/dist/{chunk-PYVGXGKC.js → chunk-P2P6MUQ4.js} +2 -2
  63. package/dist/{chunk-PXP2M32M.js → chunk-QMEF4Z7R.js} +6 -7
  64. package/dist/{chunk-OBN7UEQJ.js → chunk-RFE7DCZK.js} +24 -2
  65. package/dist/{chunk-6FCKJDKS.js → chunk-S7GX44BU.js} +1 -1
  66. package/dist/{chunk-4Z7B5WVV.js → chunk-U76RWMFR.js} +4 -2
  67. package/dist/{chunk-LRTEMMCZ.js → chunk-V4HXV5MY.js} +1 -1
  68. package/dist/{chunk-MB2CTEPD.js → chunk-VOB2DKO6.js} +174 -34
  69. package/dist/{chunk-EIYOABL4.js → chunk-WMJS5DDV.js} +12 -8
  70. package/dist/{chunk-FGYWKKTJ.js → chunk-WWXJUURQ.js} +1 -1
  71. package/dist/{chunk-3ADPXQBL.js → chunk-X76JVHQ4.js} +1 -1
  72. package/dist/{chunk-IBO4YFFZ.js → chunk-XLWZRHX5.js} +1 -1
  73. package/dist/{chunk-H5Q2T5VC.js → chunk-XND3J6AT.js} +1 -1
  74. package/dist/{chunk-4AFSQJD6.js → chunk-XRDSML3K.js} +3 -4
  75. package/dist/{chunk-EYIMZY5O.js → chunk-YSLIB7ER.js} +18 -3
  76. package/dist/cli/chat.js +33 -33
  77. package/dist/cli/check.js +5 -5
  78. package/dist/cli/plugins.js +12 -12
  79. package/dist/cli/snapshot-create.js +9 -9
  80. package/dist/cli/upgrade.js +6 -6
  81. package/dist/db/schema/agent-invocations.d.ts +16 -0
  82. package/dist/db/schema.d.ts +16 -0
  83. package/dist/{db-LRM6AP66.js → db-3IEVINAY.js} +6 -6
  84. package/dist/instrumentation.js +3 -3
  85. package/dist/nitro.js +6 -6
  86. package/dist/{oauth-callback-server-BKCDVYVH.js → oauth-callback-server-N7L2BB4L.js} +29 -29
  87. package/dist/{runner-RUXGS3E6.js → runner-PTTZV3WU.js} +21 -21
  88. package/dist/{skills-DXP2RCJF.js → skills-POMWS2RR.js} +5 -5
  89. package/dist/spawn-R75MXXKE.js +42 -0
  90. package/dist/task-runner-OQLRHADB.js +36 -0
  91. package/dist/{validation-F4KYLIF2.js → validation-U6LOMXR7.js} +5 -5
  92. package/dist/version.js +1 -1
  93. package/dist/{work-UUNMNSML.js → work-FHA3BS4L.js} +21 -21
  94. package/dist/{worker-PMIJ5NLD.js → worker-GR4UNVVP.js} +10 -10
  95. package/package.json +5 -5
  96. package/dist/spawn-HH7GH7XT.js +0 -42
  97. package/dist/task-runner-H5I7R3LJ.js +0 -36
@@ -7,7 +7,7 @@ import {
7
7
  toCanonicalInputMessage,
8
8
  toCanonicalOutputMessage,
9
9
  toGenAiMessagesTraceAttributes
10
- } from "./chunk-EYNUOZCN.js";
10
+ } from "./chunk-JOI3DHML.js";
11
11
  import {
12
12
  extractGenAiUsageAttributes,
13
13
  logException,
@@ -15,7 +15,7 @@ import {
15
15
  normalizeGenAiFinishReason,
16
16
  serializeGenAiAttribute,
17
17
  withSpan
18
- } from "./chunk-3ADPXQBL.js";
18
+ } from "./chunk-X76JVHQ4.js";
19
19
 
20
20
  // src/chat/services/provider-error.ts
21
21
  var ProviderError = class extends Error {
@@ -674,6 +674,7 @@ function normalizeSlackEmojiName(value) {
674
674
  var MIN_AGENT_TURN_TIMEOUT_MS = 10 * 1e3;
675
675
  var DEFAULT_AGENT_TURN_TIMEOUT_MS = 12 * 60 * 1e3;
676
676
  var MAX_SLICES_PER_TURN = 100;
677
+ var MAX_TOOL_CALLS_PER_TURN = 150;
677
678
  var DEFAULT_FUNCTION_MAX_DURATION_SECONDS = 300;
678
679
  var DEFAULT_SLACK_SLASH_COMMAND = "/jr";
679
680
  var DEFAULT_PROCESSING_REACTION_EMOJI = "eyes";
@@ -902,6 +903,7 @@ function readBotConfig(env, functionMaxDurationSeconds) {
902
903
  loadingMessages: parseLoadingMessages(env.JUNIOR_LOADING_MESSAGES),
903
904
  visionModelId: validateGatewayModelId(env.AI_VISION_MODEL),
904
905
  maxSlicesPerTurn: MAX_SLICES_PER_TURN,
906
+ maxToolCallsPerTurn: MAX_TOOL_CALLS_PER_TURN,
905
907
  turnTimeoutMs: parseAgentTurnTimeoutMs(
906
908
  env.AGENT_TURN_TIMEOUT_MS,
907
909
  maxTurnTimeoutMs
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getChatConfig
3
- } from "./chunk-4Z7B5WVV.js";
3
+ } from "./chunk-U76RWMFR.js";
4
4
 
5
5
  // src/chat/state/adapter.ts
6
6
  import { createMemoryState } from "@chat-adapter/state-memory";
@@ -1,13 +1,17 @@
1
+ import {
2
+ agentTurnCostUsd,
3
+ agentTurnTotalTokens
4
+ } from "./chunk-RFE7DCZK.js";
1
5
  import {
2
6
  getDb
3
- } from "./chunk-AKR6W7VV.js";
7
+ } from "./chunk-ADEACKAH.js";
4
8
  import {
5
9
  juniorConversations,
6
10
  juniorTaskExecutions
7
- } from "./chunk-IBO4YFFZ.js";
11
+ } from "./chunk-XLWZRHX5.js";
8
12
  import {
9
13
  logWarn
10
- } from "./chunk-3ADPXQBL.js";
14
+ } from "./chunk-X76JVHQ4.js";
11
15
 
12
16
  // src/chat/tasks/execution-stats.ts
13
17
  import {
@@ -21,19 +25,111 @@ import {
21
25
  lte,
22
26
  max,
23
27
  or,
24
- sql
28
+ sql as sql2
25
29
  } from "drizzle-orm";
30
+
31
+ // src/api/conversations/aggregate.ts
32
+ import { sql } from "drizzle-orm";
33
+ function usageTokenValue(source, field) {
34
+ return sql`CASE
35
+ WHEN ${source.usage}->>${field} IS NOT NULL
36
+ THEN (${source.usage}->>${field})::double precision
37
+ ELSE NULL
38
+ END`;
39
+ }
40
+ function tokenValue(source) {
41
+ return sql`
42
+ CASE
43
+ WHEN COALESCE(
44
+ ${source.usage}->>'inputTokens',
45
+ ${source.usage}->>'outputTokens',
46
+ ${source.usage}->>'cachedInputTokens',
47
+ ${source.usage}->>'cacheCreationTokens'
48
+ ) IS NOT NULL
49
+ THEN COALESCE((${source.usage}->>'inputTokens')::double precision, 0)
50
+ + COALESCE((${source.usage}->>'outputTokens')::double precision, 0)
51
+ + COALESCE((${source.usage}->>'cachedInputTokens')::double precision, 0)
52
+ + COALESCE((${source.usage}->>'cacheCreationTokens')::double precision, 0)
53
+ WHEN ${source.usage}->>'totalTokens' IS NOT NULL
54
+ THEN (${source.usage}->>'totalTokens')::double precision
55
+ ELSE NULL
56
+ END
57
+ `;
58
+ }
59
+ function costValue(source) {
60
+ return conversationUsageCostExpr(source.usage);
61
+ }
62
+ function conversationUsageCostExpr(usage) {
63
+ return sql`
64
+ CASE
65
+ WHEN ${usage}->'cost'->>'total' IS NOT NULL
66
+ THEN (${usage}->'cost'->>'total')::double precision
67
+ WHEN COALESCE(
68
+ ${usage}->'cost'->>'input',
69
+ ${usage}->'cost'->>'output',
70
+ ${usage}->'cost'->>'cacheRead',
71
+ ${usage}->'cost'->>'cacheWrite'
72
+ ) IS NOT NULL
73
+ THEN COALESCE((${usage}->'cost'->>'input')::double precision, 0)
74
+ + COALESCE((${usage}->'cost'->>'output')::double precision, 0)
75
+ + COALESCE((${usage}->'cost'->>'cacheRead')::double precision, 0)
76
+ + COALESCE((${usage}->'cost'->>'cacheWrite')::double precision, 0)
77
+ ELSE NULL
78
+ END
79
+ `;
80
+ }
81
+ function conversationAggregateColumns(sources) {
82
+ const metrics = sources?.metrics ?? juniorConversations;
83
+ const roots = sources?.roots ?? juniorConversations;
84
+ const conversationCount = sources ? sql`COUNT(DISTINCT ${roots.conversationId})` : sql`COUNT(*)`;
85
+ return {
86
+ active: sql`${conversationCount} FILTER (
87
+ WHERE ${roots.executionStatus} NOT IN ('idle', 'failed')
88
+ )::integer`,
89
+ conversations: sql`${conversationCount}::integer`,
90
+ cachedInputTokens: sql`SUM(${usageTokenValue(metrics, "cachedInputTokens")})::double precision`,
91
+ costUsd: sql`SUM(${costValue(metrics)})::double precision`,
92
+ durationMs: sql`COALESCE(SUM(${metrics.durationMs}), 0)::double precision`,
93
+ failed: sql`${conversationCount} FILTER (
94
+ WHERE ${roots.executionStatus} = 'failed'
95
+ )::integer`,
96
+ inputTokens: sql`SUM(${usageTokenValue(metrics, "inputTokens")})::double precision`,
97
+ tokens: sql`SUM(${tokenValue(metrics)})::double precision`
98
+ };
99
+ }
100
+ function conversationRangeColumns() {
101
+ return {
102
+ firstSeenAt: sql`MIN(${juniorConversations.createdAt})`.mapWith(
103
+ juniorConversations.createdAt
104
+ ),
105
+ lastSeenAt: sql`MAX(${juniorConversations.lastActivityAt})`.mapWith(
106
+ juniorConversations.lastActivityAt
107
+ )
108
+ };
109
+ }
110
+ function conversationActiveDaysColumn() {
111
+ return sql`COUNT(DISTINCT (${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC')::date)::integer`;
112
+ }
113
+
114
+ // src/chat/tasks/execution-stats.ts
26
115
  var TASK_EXECUTION_TYPES = ["scheduled", "event"];
27
116
  var TASK_EXECUTION_STATUSES = [
28
117
  "blocked",
29
118
  "completed",
30
119
  "failed"
31
120
  ];
121
+ function addUsd(current, next) {
122
+ return Math.round((current + next) * 1e12) / 1e12;
123
+ }
124
+ var EMPTY_RUN_WINDOWS = { 1: 0, 7: 0, 30: 0, 90: 0 };
125
+ function emptyTaskRunWindows() {
126
+ return { ...EMPTY_RUN_WINDOWS };
127
+ }
32
128
  function utcDate(nowMs) {
33
129
  return new Date(nowMs).toISOString().slice(0, 10);
34
130
  }
35
131
  function emptyDay(date) {
36
- return { date, event: 0, scheduled: 0 };
132
+ return { costUsd: 0, date, event: 0, scheduled: 0 };
37
133
  }
38
134
  function emptyStatusDay(date) {
39
135
  return { blocked: 0, completed: 0, date, failed: 0 };
@@ -70,7 +166,11 @@ async function recordTaskExecution(type, taskId, options) {
70
166
  }
71
167
  }
72
168
  async function readTaskExecutionSummaries(type, namespace, options = {}) {
73
- const sevenDaysAgoMs = (options.nowMs ?? Date.now()) - 7 * 24 * 60 * 60 * 1e3;
169
+ const nowMs = options.nowMs ?? Date.now();
170
+ const oneDayAgoMs = nowMs - 1 * 24 * 60 * 60 * 1e3;
171
+ const sevenDaysAgoMs = nowMs - 7 * 24 * 60 * 60 * 1e3;
172
+ const thirtyDaysAgoMs = nowMs - 30 * 24 * 60 * 60 * 1e3;
173
+ const ninetyDaysAgoMs = nowMs - 90 * 24 * 60 * 60 * 1e3;
74
174
  const db = getDb();
75
175
  const latest = db.selectDistinctOn([juniorTaskExecutions.taskId], {
76
176
  conversationId: juniorTaskExecutions.conversationId,
@@ -88,9 +188,12 @@ async function readTaskExecutionSummaries(type, namespace, options = {}) {
88
188
  const rows = await db.select({
89
189
  lastConversationId: latest.conversationId,
90
190
  lastExecutedAtMs: max(juniorTaskExecutions.executedAtMs),
91
- runsLast7Days: sql`count(*) filter (where ${juniorTaskExecutions.executedAtMs} >= ${sevenDaysAgoMs})::int`,
191
+ runsLast1Day: sql2`count(*) filter (where ${juniorTaskExecutions.executedAtMs} >= ${oneDayAgoMs})::int`,
192
+ runsLast7Days: sql2`count(*) filter (where ${juniorTaskExecutions.executedAtMs} >= ${sevenDaysAgoMs})::int`,
193
+ runsLast30Days: sql2`count(*) filter (where ${juniorTaskExecutions.executedAtMs} >= ${thirtyDaysAgoMs})::int`,
194
+ runsLast90Days: sql2`count(*) filter (where ${juniorTaskExecutions.executedAtMs} >= ${ninetyDaysAgoMs})::int`,
92
195
  taskId: juniorTaskExecutions.taskId,
93
- totalRuns: sql`count(*)::int`
196
+ totalRuns: sql2`count(*)::int`
94
197
  }).from(juniorTaskExecutions).innerJoin(latest, eq(latest.taskId, juniorTaskExecutions.taskId)).where(
95
198
  and(
96
199
  eq(juniorTaskExecutions.kind, type),
@@ -103,7 +206,12 @@ async function readTaskExecutionSummaries(type, namespace, options = {}) {
103
206
  {
104
207
  ...row.lastConversationId ? { lastConversationId: row.lastConversationId } : void 0,
105
208
  ...row.lastExecutedAtMs !== null ? { lastExecutedAtMs: row.lastExecutedAtMs } : void 0,
106
- runsLast7Days: row.runsLast7Days,
209
+ runs: {
210
+ 1: row.runsLast1Day,
211
+ 7: row.runsLast7Days,
212
+ 30: row.runsLast30Days,
213
+ 90: row.runsLast90Days
214
+ },
107
215
  totalRuns: row.totalRuns
108
216
  }
109
217
  ])
@@ -114,12 +222,20 @@ async function readTaskExecutionDays(dayCount = 90, options = {}) {
114
222
  const end = utcDate(nowMs);
115
223
  const endMs = Date.parse(`${end}T23:59:59.999Z`);
116
224
  const startMs = Date.parse(`${end}T00:00:00.000Z`) - (dayCount - 1) * 864e5;
117
- const executionDate = sql`to_char(to_timestamp(${juniorTaskExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD')`;
225
+ const executionDate = sql2`to_char(to_timestamp(${juniorTaskExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD')`;
226
+ const conversationCost = conversationUsageCostExpr(juniorConversations.usage);
118
227
  const rows = await getDb().select({
119
228
  count: count(),
229
+ costUsd: sql2`SUM(${conversationCost})::double precision`,
120
230
  date: executionDate,
121
231
  kind: juniorTaskExecutions.kind
122
- }).from(juniorTaskExecutions).where(
232
+ }).from(juniorTaskExecutions).leftJoin(
233
+ juniorConversations,
234
+ eq(
235
+ juniorConversations.conversationId,
236
+ juniorTaskExecutions.conversationId
237
+ )
238
+ ).where(
123
239
  and(
124
240
  gte(juniorTaskExecutions.executedAtMs, startMs),
125
241
  lte(juniorTaskExecutions.executedAtMs, endMs),
@@ -136,6 +252,9 @@ async function readTaskExecutionDays(dayCount = 90, options = {}) {
136
252
  if (!day) continue;
137
253
  if (row.kind === "scheduled") day.scheduled = row.count;
138
254
  else if (row.kind === "event") day.event = row.count;
255
+ if (row.costUsd !== null && row.costUsd > 0) {
256
+ day.costUsd = addUsd(day.costUsd, row.costUsd);
257
+ }
139
258
  }
140
259
  return [...byDate.values()];
141
260
  }
@@ -145,12 +264,20 @@ async function readTaskExecutionHours(hourCount = 24, options = {}) {
145
264
  end.setUTCMinutes(0, 0, 0);
146
265
  const endMs = end.getTime() + 3599999;
147
266
  const startMs = end.getTime() - (hourCount - 1) * 36e5;
148
- const executionHour = sql`to_char(to_timestamp(${juniorTaskExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD"T"HH24')`;
267
+ const executionHour = sql2`to_char(to_timestamp(${juniorTaskExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD"T"HH24')`;
268
+ const conversationCost = conversationUsageCostExpr(juniorConversations.usage);
149
269
  const rows = await getDb().select({
150
270
  count: count(),
271
+ costUsd: sql2`SUM(${conversationCost})::double precision`,
151
272
  date: executionHour,
152
273
  kind: juniorTaskExecutions.kind
153
- }).from(juniorTaskExecutions).where(
274
+ }).from(juniorTaskExecutions).leftJoin(
275
+ juniorConversations,
276
+ eq(
277
+ juniorConversations.conversationId,
278
+ juniorTaskExecutions.conversationId
279
+ )
280
+ ).where(
154
281
  and(
155
282
  gte(juniorTaskExecutions.executedAtMs, startMs),
156
283
  lte(juniorTaskExecutions.executedAtMs, endMs),
@@ -167,6 +294,9 @@ async function readTaskExecutionHours(hourCount = 24, options = {}) {
167
294
  if (!hour) continue;
168
295
  if (row.kind === "scheduled") hour.scheduled = row.count;
169
296
  else if (row.kind === "event") hour.event = row.count;
297
+ if (row.costUsd !== null && row.costUsd > 0) {
298
+ hour.costUsd = addUsd(hour.costUsd, row.costUsd);
299
+ }
170
300
  }
171
301
  return [...byHour.values()];
172
302
  }
@@ -194,10 +324,12 @@ async function readTaskExecutions(args) {
194
324
  const namespace = args.namespace ?? "junior";
195
325
  const rows = await getDb().select({
196
326
  conversationId: juniorTaskExecutions.conversationId,
327
+ durationMs: juniorConversations.durationMs,
197
328
  executedAtMs: juniorTaskExecutions.executedAtMs,
198
329
  executionId: juniorTaskExecutions.executionId,
199
330
  status: juniorTaskExecutions.status,
200
- title: juniorConversations.title
331
+ title: juniorConversations.title,
332
+ usage: juniorConversations.usage
201
333
  }).from(juniorTaskExecutions).leftJoin(
202
334
  juniorConversations,
203
335
  eq(
@@ -214,16 +346,7 @@ async function readTaskExecutions(args) {
214
346
  desc(juniorTaskExecutions.executedAtMs),
215
347
  desc(juniorTaskExecutions.executionId)
216
348
  ).limit(args.limit);
217
- return rows.map((row) => {
218
- const title = row.title?.trim();
219
- return {
220
- ...row.conversationId ? { conversationId: row.conversationId } : void 0,
221
- executedAt: new Date(row.executedAtMs).toISOString(),
222
- executionId: row.executionId,
223
- status: row.status,
224
- ...title ? { title } : void 0
225
- };
226
- });
349
+ return rows.map((row) => mapTaskExecutionRecord(row));
227
350
  }
228
351
  async function readTaskRuns(args) {
229
352
  if (args.tasks.length === 0) return [];
@@ -236,12 +359,14 @@ async function readTaskRuns(args) {
236
359
  );
237
360
  const rows = await getDb().select({
238
361
  conversationId: juniorTaskExecutions.conversationId,
362
+ durationMs: juniorConversations.durationMs,
239
363
  executedAtMs: juniorTaskExecutions.executedAtMs,
240
364
  executionId: juniorTaskExecutions.executionId,
241
365
  kind: juniorTaskExecutions.kind,
242
366
  status: juniorTaskExecutions.status,
243
367
  taskId: juniorTaskExecutions.taskId,
244
- title: juniorConversations.title
368
+ title: juniorConversations.title,
369
+ usage: juniorConversations.usage
245
370
  }).from(juniorTaskExecutions).leftJoin(
246
371
  juniorConversations,
247
372
  eq(
@@ -254,20 +379,31 @@ async function readTaskRuns(args) {
254
379
  ).limit(args.limit);
255
380
  return rows.flatMap((row) => {
256
381
  if (row.kind !== "scheduled" && row.kind !== "event") return [];
257
- const title = row.title?.trim();
258
382
  return [
259
383
  {
260
- ...row.conversationId ? { conversationId: row.conversationId } : void 0,
261
- executedAt: new Date(row.executedAtMs).toISOString(),
262
- executionId: row.executionId,
384
+ ...mapTaskExecutionRecord(row),
263
385
  kind: row.kind,
264
- status: row.status,
265
- taskId: row.taskId,
266
- ...title ? { title } : void 0
386
+ taskId: row.taskId
267
387
  }
268
388
  ];
269
389
  });
270
390
  }
391
+ function mapTaskExecutionRecord(row) {
392
+ const title = row.title?.trim();
393
+ const costUsd = agentTurnCostUsd(row.usage ?? void 0);
394
+ const totalTokens = agentTurnTotalTokens(row.usage ?? void 0);
395
+ const durationMs = typeof row.durationMs === "number" && Number.isFinite(row.durationMs) && row.durationMs > 0 ? row.durationMs : void 0;
396
+ return {
397
+ ...row.conversationId ? { conversationId: row.conversationId } : void 0,
398
+ ...costUsd !== void 0 ? { costUsd } : void 0,
399
+ ...durationMs !== void 0 ? { durationMs } : void 0,
400
+ executedAt: new Date(row.executedAtMs).toISOString(),
401
+ executionId: row.executionId,
402
+ status: row.status,
403
+ ...title ? { title } : void 0,
404
+ ...totalTokens !== void 0 ? { totalTokens } : void 0
405
+ };
406
+ }
271
407
  async function readTaskExecutionStatusDays(args) {
272
408
  const dayCount = args.dayCount ?? 90;
273
409
  const namespace = args.namespace ?? "junior";
@@ -275,7 +411,7 @@ async function readTaskExecutionStatusDays(args) {
275
411
  const end = utcDate(nowMs);
276
412
  const endMs = Date.parse(`${end}T23:59:59.999Z`);
277
413
  const startMs = Date.parse(`${end}T00:00:00.000Z`) - (dayCount - 1) * 864e5;
278
- const executionDate = sql`to_char(to_timestamp(${juniorTaskExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD')`;
414
+ const executionDate = sql2`to_char(to_timestamp(${juniorTaskExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD')`;
279
415
  const rows = await getDb().select({
280
416
  count: count(),
281
417
  date: executionDate,
@@ -312,7 +448,7 @@ async function readTaskExecutionStatusHours(args) {
312
448
  end.setUTCMinutes(0, 0, 0);
313
449
  const endMs = end.getTime() + 3599999;
314
450
  const startMs = end.getTime() - (hourCount - 1) * 36e5;
315
- const executionHour = sql`to_char(to_timestamp(${juniorTaskExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD"T"HH24')`;
451
+ const executionHour = sql2`to_char(to_timestamp(${juniorTaskExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD"T"HH24')`;
316
452
  const rows = await getDb().select({
317
453
  count: count(),
318
454
  date: executionHour,
@@ -343,6 +479,10 @@ async function readTaskExecutionStatusHours(args) {
343
479
  }
344
480
 
345
481
  export {
482
+ conversationAggregateColumns,
483
+ conversationRangeColumns,
484
+ conversationActiveDaysColumn,
485
+ emptyTaskRunWindows,
346
486
  recordTaskExecution,
347
487
  readTaskExecutionSummaries,
348
488
  readTaskExecutionDays,
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  ToolInputError
3
- } from "./chunk-OBN7UEQJ.js";
3
+ } from "./chunk-RFE7DCZK.js";
4
4
  import {
5
5
  getPlugins
6
- } from "./chunk-BUTAWPUV.js";
6
+ } from "./chunk-CCTYK5RH.js";
7
7
  import {
8
8
  getDb
9
- } from "./chunk-AKR6W7VV.js";
9
+ } from "./chunk-ADEACKAH.js";
10
10
  import {
11
11
  juniorAttachments,
12
12
  juniorConversations,
@@ -14,7 +14,7 @@ import {
14
14
  juniorSchedulerRuns,
15
15
  juniorSchedulerTasks,
16
16
  juniorStats
17
- } from "./chunk-IBO4YFFZ.js";
17
+ } from "./chunk-XLWZRHX5.js";
18
18
  import {
19
19
  juniorDestinations
20
20
  } from "./chunk-VFUK3X5B.js";
@@ -560,13 +560,17 @@ function requireEventTaskSlackContext(context) {
560
560
  function eventTaskMatchesDestination(task, destination) {
561
561
  return task.destination.teamId === destination.teamId && task.destination.channelId === destination.channelId;
562
562
  }
563
+ function eventTaskIsWritableFrom(task, destination) {
564
+ if (task.destination.teamId !== destination.teamId) {
565
+ return false;
566
+ }
567
+ return task.destination.channelId === destination.channelId || task.destinationVisibility === "public";
568
+ }
563
569
  async function writableEventTask(context, id) {
564
570
  const { destination } = requireEventTaskSlackContext(context);
565
571
  const task = await getEventTask(getDb(), id);
566
- if (!task || !eventTaskMatchesDestination(task, destination)) {
567
- throw new ToolInputError(
568
- "Event task was not found in this Slack channel or DM."
569
- );
572
+ if (!task || !eventTaskIsWritableFrom(task, destination)) {
573
+ throw new ToolInputError("Event task was not found.");
570
574
  }
571
575
  return task;
572
576
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createPluginCatalogRuntime
3
- } from "./chunk-6FCKJDKS.js";
3
+ } from "./chunk-S7GX44BU.js";
4
4
 
5
5
  // src/chat/plugins/catalog-runtime.ts
6
6
  var pluginCatalogRuntime = createPluginCatalogRuntime();
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-PEQXYSSE.js";
13
13
  import {
14
14
  JUNIOR_VERSION
15
- } from "./chunk-ARSUYYQG.js";
15
+ } from "./chunk-IME5OW4Y.js";
16
16
 
17
17
  // src/deployment.ts
18
18
  var JUNIOR_HEARTBEAT_ROUTE = "/api/internal/heartbeat";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-VFUK3X5B.js";
5
5
  import {
6
6
  DEFAULT_SQL_STATEMENT_TIMEOUT_MS
7
- } from "./chunk-4Z7B5WVV.js";
7
+ } from "./chunk-U76RWMFR.js";
8
8
 
9
9
  // src/db/neon.ts
10
10
  import { AsyncLocalStorage } from "async_hooks";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getStateAdapter
3
- } from "./chunk-LRTEMMCZ.js";
3
+ } from "./chunk-V4HXV5MY.js";
4
4
  import {
5
5
  getClient
6
6
  } from "./chunk-PEQXYSSE.js";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  createAndEnqueueAgentInvocation
3
- } from "./chunk-4CCQZHD3.js";
3
+ } from "./chunk-F2KSURTJ.js";
4
4
  import {
5
5
  actorFromRun,
6
6
  toolInvocationDestination
7
- } from "./chunk-SSR6YBWW.js";
7
+ } from "./chunk-ENWIHU54.js";
8
8
 
9
9
  // src/chat/agent-invocations/spawn.ts
10
10
  function bindSpawnAgent(run, options) {
@@ -24,8 +24,7 @@ function bindSpawnAgent(run, options) {
24
24
  idempotencyKey: `${run.turnId}:${call.toolCallId}`,
25
25
  input: input.task,
26
26
  parentConversationId: run.conversationId,
27
- ...input.reasoningLevel ? { reasoningLevel: input.reasoningLevel } : void 0,
28
- source: run.source
27
+ ...input.reasoningLevel ? { reasoningLevel: input.reasoningLevel } : void 0
29
28
  },
30
29
  { ...options, queue }
31
30
  );
@@ -320,7 +320,7 @@ var conversationSummaryReportSchema = z3.object({
320
320
  channelNameRedacted: z3.boolean().optional(),
321
321
  locationId: z3.string().optional(),
322
322
  sentryTraceUrl: z3.string().optional(),
323
- sourceUrl: z3.string().url().optional(),
323
+ locationUrl: z3.string().url().optional(),
324
324
  traceId: z3.string().optional(),
325
325
  /**
326
326
  * Plugin-owned resource links for this conversation.
@@ -918,6 +918,12 @@ var taskDestinationSchema = z9.object({
918
918
  teamId: z9.string().min(1),
919
919
  visibility: z9.enum(["private", "public"])
920
920
  }).strict();
921
+ var taskRunWindowsSchema = z9.object({
922
+ 1: z9.number().int().nonnegative(),
923
+ 7: z9.number().int().nonnegative(),
924
+ 30: z9.number().int().nonnegative(),
925
+ 90: z9.number().int().nonnegative()
926
+ }).strict();
921
927
  var taskSummaryBaseSchema = z9.object({
922
928
  createdAt: z9.string().datetime(),
923
929
  createdBy: z9.string().min(1),
@@ -928,7 +934,7 @@ var taskSummaryBaseSchema = z9.object({
928
934
  lastConversationId: z9.string().min(1).optional(),
929
935
  lastRunAt: z9.string().datetime().optional(),
930
936
  ownedByViewer: z9.boolean(),
931
- runsLast7Days: z9.number().int().nonnegative(),
937
+ runs: taskRunWindowsSchema,
932
938
  /** Short display title; falls back from instruction when unset. */
933
939
  title: z9.string().min(1),
934
940
  totalRuns: z9.number().int().nonnegative()
@@ -952,6 +958,8 @@ var taskSummarySchema = z9.discriminatedUnion("kind", [
952
958
  ]);
953
959
  var taskMetricBucketSchema = z9.string().regex(/^\d{4}-\d{2}-\d{2}(T\d{2})?$/);
954
960
  var taskExecutionDaySchema = z9.object({
961
+ /** Linked conversation spend for executions in this bucket. */
962
+ costUsd: z9.number().finite().nonnegative(),
955
963
  date: taskMetricBucketSchema,
956
964
  event: z9.number().int().nonnegative(),
957
965
  scheduled: z9.number().int().nonnegative()
@@ -973,10 +981,16 @@ var taskExecutionStatusSchema = z9.enum([
973
981
  ]);
974
982
  var taskExecutionSchema = z9.object({
975
983
  conversationId: z9.string().min(1).optional(),
984
+ /** Estimated model cost for the linked conversation, when known. */
985
+ costUsd: z9.number().finite().nonnegative().optional(),
986
+ /** Cumulative conversation runtime in milliseconds, when known. */
987
+ durationMs: z9.number().finite().nonnegative().optional(),
976
988
  executedAt: z9.string().datetime(),
977
989
  executionId: z9.string().min(1),
978
990
  status: taskExecutionStatusSchema,
979
- title: z9.string().min(1).optional()
991
+ title: z9.string().min(1).optional(),
992
+ /** Cumulative conversation token total, when known. */
993
+ totalTokens: z9.number().int().nonnegative().optional()
980
994
  }).strict();
981
995
  var taskExecutionStatusDaySchema = z9.object({
982
996
  blocked: z9.number().int().nonnegative(),
@@ -1075,6 +1089,7 @@ export {
1075
1089
  createdPersonalTokenSchema,
1076
1090
  personalTokenParamsSchema,
1077
1091
  revokePersonalTokenResponseSchema,
1092
+ taskRunWindowsSchema,
1078
1093
  scheduledTaskSummarySchema,
1079
1094
  eventTaskSummarySchema,
1080
1095
  taskSummarySchema,