@sentry/junior 0.106.0 → 0.107.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 (132) hide show
  1. package/dist/{agent-hooks-KR5BCWOK.js → agent-hooks-ICPIJAFY.js} +9 -7
  2. package/dist/api/conversations/detail.d.ts +1 -1
  3. package/dist/api/conversations/events.d.ts +14 -0
  4. package/dist/api/conversations/schema.d.ts +196 -463
  5. package/dist/api/schema.d.ts +2 -7
  6. package/dist/api/schema.js +10 -8
  7. package/dist/api.js +377 -810
  8. package/dist/app.js +3586 -3614
  9. package/dist/{catalog-runtime-5CVM2DOF.js → catalog-runtime-FOFNPR3P.js} +3 -2
  10. package/dist/chat/agent/prompt.d.ts +1 -1
  11. package/dist/chat/agent/request.d.ts +28 -29
  12. package/dist/chat/agent/resume.d.ts +7 -7
  13. package/dist/chat/agent/session.d.ts +5 -6
  14. package/dist/chat/agent/tools.d.ts +3 -3
  15. package/dist/chat/agent-dispatch/runner.d.ts +2 -0
  16. package/dist/chat/config.d.ts +2 -2
  17. package/dist/chat/conversations/history.d.ts +582 -167
  18. package/dist/chat/conversations/message-projection.d.ts +6 -0
  19. package/dist/chat/conversations/message-summaries.d.ts +9 -0
  20. package/dist/chat/conversations/messages.d.ts +13 -27
  21. package/dist/chat/conversations/projection.d.ts +30 -53
  22. package/dist/chat/conversations/provenance.d.ts +42 -0
  23. package/dist/chat/conversations/search.d.ts +2 -2
  24. package/dist/chat/conversations/sql/conversation-row.d.ts +1 -1
  25. package/dist/chat/conversations/sql/event-lock.d.ts +3 -0
  26. package/dist/chat/conversations/sql/history.d.ts +3 -3
  27. package/dist/chat/conversations/sql/privacy.d.ts +27 -0
  28. package/dist/chat/conversations/sql/purge.d.ts +2 -10
  29. package/dist/chat/conversations/sql/store.d.ts +0 -5
  30. package/dist/chat/conversations/store.d.ts +8 -13
  31. package/dist/chat/conversations/turn-lifecycle.d.ts +41 -0
  32. package/dist/chat/db.d.ts +4 -10
  33. package/dist/chat/model-profile.d.ts +10 -0
  34. package/dist/chat/oauth-flow.d.ts +0 -5
  35. package/dist/chat/pi/conversation-events.d.ts +33 -0
  36. package/dist/chat/pi/sql-model-usage.d.ts +10 -0
  37. package/dist/chat/plugins/agent-hooks.d.ts +4 -2
  38. package/dist/chat/resource-events/ingest.d.ts +0 -13
  39. package/dist/chat/runtime/delivered-turn-state.d.ts +1 -1
  40. package/dist/chat/runtime/generated-artifacts.d.ts +1 -1
  41. package/dist/chat/runtime/reply-executor.d.ts +2 -0
  42. package/dist/chat/runtime/slack-resume.d.ts +23 -28
  43. package/dist/chat/runtime/slack-runtime.d.ts +2 -0
  44. package/dist/chat/runtime/turn.d.ts +14 -1
  45. package/dist/chat/services/context-compaction-marker.d.ts +0 -1
  46. package/dist/chat/services/context-compaction.d.ts +1 -0
  47. package/dist/chat/services/conversation-memory.d.ts +9 -0
  48. package/dist/chat/services/plugin-auth-orchestration.d.ts +1 -4
  49. package/dist/chat/services/subscribed-decision.d.ts +1 -1
  50. package/dist/chat/services/turn-failure-response.d.ts +10 -3
  51. package/dist/chat/services/turn-result.d.ts +7 -12
  52. package/dist/chat/services/{turn-reasoning-level.d.ts → turn-router.d.ts} +12 -8
  53. package/dist/chat/services/turn-session-record.d.ts +15 -16
  54. package/dist/chat/slack/adapter.d.ts +2 -2
  55. package/dist/chat/slack/errors.d.ts +2 -0
  56. package/dist/chat/slack/outbound.d.ts +0 -1
  57. package/dist/chat/slack/reply.d.ts +2 -8
  58. package/dist/chat/slack/tools/channel-capabilities.d.ts +2 -2
  59. package/dist/chat/slack/tools/{send-message.d.ts → send-files.d.ts} +27 -19
  60. package/dist/chat/state/conversation.d.ts +4 -4
  61. package/dist/chat/state/turn-id.d.ts +2 -0
  62. package/dist/chat/state/turn-session-keys.d.ts +6 -0
  63. package/dist/chat/state/turn-session.d.ts +11 -9
  64. package/dist/chat/task-execution/state.d.ts +6 -1
  65. package/dist/chat/task-execution/store.d.ts +1 -1
  66. package/dist/chat/tool-support/pi-tool-adapter.d.ts +1 -1
  67. package/dist/chat/tool-support/tool-execution-report.d.ts +1 -0
  68. package/dist/chat/tools/handoff/tool.d.ts +2 -2
  69. package/dist/chat/tools/sandbox/file-uploads.d.ts +28 -6
  70. package/dist/chat/tools/types.d.ts +6 -9
  71. package/dist/chat/tools/web/image-generate.d.ts +4 -6
  72. package/dist/{chunk-DDRQ4U7I.js → chunk-4YF7Z6IA.js} +390 -270
  73. package/dist/{chunk-AZ5OMSN5.js → chunk-AUUOHQAT.js} +2 -2
  74. package/dist/chunk-B2Z2H66D.js +250 -0
  75. package/dist/{chunk-4W4O4DCV.js → chunk-CQ7KSO2B.js} +75 -45
  76. package/dist/{chunk-MJSJAHBW.js → chunk-DY7TRYB5.js} +1 -1
  77. package/dist/{chunk-GPPUTY5M.js → chunk-EDLNHZH3.js} +861 -891
  78. package/dist/{chunk-R5BFYK2O.js → chunk-IGHMVDWI.js} +134 -18
  79. package/dist/chunk-MU6HHZEN.js +99 -0
  80. package/dist/{chunk-XTKJPSMF.js → chunk-NVOTGWYX.js} +458 -684
  81. package/dist/{chunk-AEWZ7F65.js → chunk-O24R4DCK.js} +2 -179
  82. package/dist/{chunk-CCFROYAV.js → chunk-PUAMO4PI.js} +115 -125
  83. package/dist/{chunk-ZMRLBBD5.js → chunk-RMVOAJRL.js} +30 -13
  84. package/dist/{chunk-3NYUCBLE.js → chunk-SPUAJVVH.js} +6 -4
  85. package/dist/{chunk-4UYIRWDW.js → chunk-SS67LUOK.js} +41 -290
  86. package/dist/{chunk-FXFQNHRU.js → chunk-VFUK3X5B.js} +4 -2
  87. package/dist/{chunk-3MPPVPGZ.js → chunk-VH6KWKG2.js} +2 -2
  88. package/dist/chunk-VIXFG2VC.js +182 -0
  89. package/dist/{chunk-BKM4UXUD.js → chunk-YFQ7CQDE.js} +669 -18
  90. package/dist/{chunk-77LHNQK4.js → chunk-YIPD3L6L.js} +4 -2
  91. package/dist/{chunk-3OUSJPR7.js → chunk-YNP2ATQX.js} +6 -4
  92. package/dist/{chunk-WR7H7VLJ.js → chunk-YT72TOEK.js} +2 -2
  93. package/dist/cli/chat.js +21 -20
  94. package/dist/cli/check.js +4 -3
  95. package/dist/cli/plugins.js +11 -9
  96. package/dist/cli/snapshot-warmup.js +7 -5
  97. package/dist/cli/upgrade.js +2046 -105
  98. package/dist/db/schema/{agent-steps.d.ts → conversation-events.d.ts} +37 -21
  99. package/dist/db/schema.d.ts +28 -159
  100. package/dist/{db-S33LFWG2.js → db-DIGO4TGW.js} +6 -8
  101. package/dist/{runner-HA5XAL6K.js → runner-ACR2HAIC.js} +209 -101
  102. package/dist/{skills-722AXRV5.js → skills-ITNHBARB.js} +4 -3
  103. package/dist/{validation-EUI2UFRM.js → validation-AGQ46ZGV.js} +4 -3
  104. package/migrations/0005_conversation_events.sql +122 -0
  105. package/migrations/README.md +23 -10
  106. package/migrations/meta/0005_snapshot.json +948 -0
  107. package/migrations/meta/_journal.json +7 -0
  108. package/package.json +5 -5
  109. package/dist/api/conversations/activity.d.ts +0 -40
  110. package/dist/api/conversations/detail-projection.d.ts +0 -11
  111. package/dist/api/conversations/detail.query.d.ts +0 -3
  112. package/dist/api/conversations/subagent.d.ts +0 -10
  113. package/dist/api/conversations/transcript.d.ts +0 -28
  114. package/dist/chat/conversations/legacy-advisor-session.d.ts +0 -7
  115. package/dist/chat/conversations/legacy-import.d.ts +0 -38
  116. package/dist/chat/conversations/sql/legacy-history-import.d.ts +0 -55
  117. package/dist/chat/conversations/sql/messages.d.ts +0 -4
  118. package/dist/chat/conversations/visible-compactions.d.ts +0 -11
  119. package/dist/chat/conversations/visible-messages.d.ts +0 -47
  120. package/dist/chat/services/reply-delivery-plan.d.ts +0 -5
  121. package/dist/chat/state/session-log.d.ts +0 -384
  122. package/dist/chunk-P4P7O5WG.js +0 -1072
  123. package/dist/chunk-XIMUQ4IU.js +0 -147
  124. package/dist/db/schema/conversation-messages.d.ts +0 -153
  125. package/dist/handlers/github-webhook/check-suite.d.ts +0 -3
  126. package/dist/handlers/github-webhook/issue-comment.d.ts +0 -3
  127. package/dist/handlers/github-webhook/pull-request-review-comment.d.ts +0 -3
  128. package/dist/handlers/github-webhook/pull-request-review.d.ts +0 -3
  129. package/dist/handlers/github-webhook/pull-request.d.ts +0 -3
  130. package/dist/handlers/github-webhook/resource.d.ts +0 -10
  131. package/dist/handlers/github-webhook.d.ts +0 -15
  132. package/dist/legacy-import-TMJISRKO.js +0 -18
package/dist/api.js CHANGED
@@ -6,21 +6,20 @@ import {
6
6
  conversationFeedQuerySchema,
7
7
  conversationFeedSchema,
8
8
  conversationParamsSchema,
9
+ conversationReportEventSchema,
9
10
  conversationStatsReportSchema,
10
- conversationSubagentTranscriptReportSchema,
11
11
  locationDetailReportSchema,
12
12
  locationDirectoryReportSchema,
13
13
  locationParamsSchema,
14
- personParamsSchema,
15
- subagentParamsSchema
16
- } from "./chunk-CCFROYAV.js";
14
+ personParamsSchema
15
+ } from "./chunk-PUAMO4PI.js";
17
16
  import {
18
17
  buildSentryConversationUrl,
19
- buildSentryTraceUrl,
20
18
  formatSlackConversationRedactedLabel,
19
+ readConversationEventPrivacySnapshot,
21
20
  readHealthReport,
22
21
  resolveSlackConversationContextFromThreadId
23
- } from "./chunk-R5BFYK2O.js";
22
+ } from "./chunk-IGHMVDWI.js";
24
23
  import {
25
24
  pluginOperationalReportFeedSchema,
26
25
  pluginReportsSchema,
@@ -28,42 +27,33 @@ import {
28
27
  skillReportsSchema
29
28
  } from "./chunk-CEA3A3UA.js";
30
29
  import {
31
- listBoundedAgentTurnSessionSummariesForConversation,
32
- loadProjection,
33
- projectSteps
34
- } from "./chunk-DDRQ4U7I.js";
35
- import "./chunk-P4P7O5WG.js";
30
+ agentTurnUsageSchema,
31
+ hasAgentTurnUsage
32
+ } from "./chunk-MU6HHZEN.js";
36
33
  import "./chunk-PDO5BLNM.js";
37
- import "./chunk-3MPPVPGZ.js";
34
+ import "./chunk-VH6KWKG2.js";
38
35
  import {
39
- getAgentStepStore,
40
- getConversationMessageStore,
36
+ decodeStoredConversationEvent,
41
37
  getDb,
38
+ getSqlExecutor,
39
+ juniorConversationEvents,
42
40
  juniorConversations,
43
41
  juniorIdentities,
44
42
  juniorUsers
45
- } from "./chunk-XTKJPSMF.js";
43
+ } from "./chunk-NVOTGWYX.js";
46
44
  import "./chunk-4ZNGQH7C.js";
47
- import {
48
- stripRuntimeTurnContext,
49
- unescapeXml,
50
- unwrapCurrentInstruction
51
- } from "./chunk-4UYIRWDW.js";
45
+ import "./chunk-SS67LUOK.js";
52
46
  import {
53
47
  juniorDestinations
54
- } from "./chunk-FXFQNHRU.js";
48
+ } from "./chunk-VFUK3X5B.js";
55
49
  import {
56
50
  canExposeConversationPayload,
57
51
  parseSlackThreadId,
58
52
  resolveConversationPrivacy
59
53
  } from "./chunk-RT5BUHR5.js";
60
54
  import "./chunk-B7PUBQQM.js";
61
- import {
62
- logException
63
- } from "./chunk-AEWZ7F65.js";
64
- import {
65
- isRecord
66
- } from "./chunk-OB42YVAE.js";
55
+ import "./chunk-O24R4DCK.js";
56
+ import "./chunk-OB42YVAE.js";
67
57
  import "./chunk-6GWA276C.js";
68
58
  import "./chunk-7FBGKXPE.js";
69
59
  import "./chunk-MLKGABMK.js";
@@ -159,387 +149,223 @@ var archive_default = {
159
149
  }
160
150
  };
161
151
 
162
- // src/api/conversations/detail-projection.ts
163
- import { isDeepStrictEqual } from "util";
164
-
165
- // src/api/conversations/transcript.ts
166
- var SAFE_METADATA_KEY_LIMIT = 20;
167
- var LEGACY_ADVISOR_TASK_OPEN = "<advisor-task>\n";
168
- var LEGACY_ADVISOR_TASK_CLOSE = "\n</advisor-task>";
169
- var LEGACY_EXECUTOR_CONTEXT_OPEN = "<executor-context>\n";
170
- var LEGACY_EXECUTOR_CONTEXT_CLOSE = "\n</executor-context>";
171
- function unwrapLegacyAdvisorTask(text) {
172
- if (!text.startsWith(LEGACY_ADVISOR_TASK_OPEN) || !text.endsWith(LEGACY_EXECUTOR_CONTEXT_CLOSE)) {
173
- return void 0;
174
- }
175
- const taskEnd = text.indexOf(
176
- LEGACY_ADVISOR_TASK_CLOSE,
177
- LEGACY_ADVISOR_TASK_OPEN.length
178
- );
179
- if (taskEnd < 0) return void 0;
180
- const contextStart = taskEnd + LEGACY_ADVISOR_TASK_CLOSE.length + 2;
181
- if (!text.startsWith(LEGACY_EXECUTOR_CONTEXT_OPEN, contextStart)) {
182
- return void 0;
183
- }
184
- const task = text.slice(LEGACY_ADVISOR_TASK_OPEN.length, taskEnd);
185
- const context = text.slice(
186
- contextStart + LEGACY_EXECUTOR_CONTEXT_OPEN.length,
187
- -LEGACY_EXECUTOR_CONTEXT_CLOSE.length
188
- );
189
- return `${unescapeXml(task)}
190
-
191
- Executor context:
192
- ${unescapeXml(context)}`;
193
- }
194
- function textPart(text) {
195
- return { type: "text", text };
196
- }
197
- function recordField(value, names) {
198
- for (const name of names) {
199
- if (value[name] !== void 0) {
200
- return value[name];
201
- }
202
- }
203
- return void 0;
204
- }
205
- function thinkingOutput(part) {
206
- const output = recordField(part, ["thinking", "text", "content", "output"]);
207
- return isRecord(output) ? recordField(output, ["thinking", "text", "content", "output"]) : output;
208
- }
209
- function isDisplayableTranscriptPart(part) {
210
- if (part.type !== "thinking") return true;
211
- return typeof part.output === "string" && part.output.trim().length > 0;
212
- }
213
- function normalizeTranscriptPart(part, options = {}) {
214
- const displayText = (text) => {
215
- if (options.unwrapCurrentTask) {
216
- const instruction = unwrapCurrentInstruction(text);
217
- if (instruction !== void 0) return instruction;
218
- }
219
- if (options.unwrapLegacyAdvisorTask) {
220
- return unwrapLegacyAdvisorTask(text) ?? text;
221
- }
222
- return text;
223
- };
224
- if (typeof part === "string") {
225
- return textPart(displayText(part));
226
- }
227
- if (!isRecord(part)) {
228
- return { type: "unknown", output: part };
229
- }
230
- const rawType = typeof part.type === "string" ? part.type : "unknown";
231
- if (rawType === "text") {
232
- const text = recordField(part, ["text", "content"]);
233
- return textPart(
234
- typeof text === "string" ? displayText(text) : JSON.stringify(text) ?? ""
235
- );
236
- }
237
- if (rawType === "toolCall") {
238
- return {
239
- type: "tool_call",
240
- ...typeof part.id === "string" ? { id: part.id } : {},
241
- ...typeof part.name === "string" ? { name: part.name } : {},
242
- input: recordField(part, ["arguments", "input", "args"])
243
- };
244
- }
245
- if (rawType === "toolResult") {
246
- return {
247
- type: "tool_result",
248
- ...typeof part.id === "string" ? { id: part.id } : {},
249
- ...typeof part.name === "string" ? { name: part.name } : {},
250
- output: recordField(part, ["result", "output", "content"])
251
- };
252
- }
253
- if (rawType === "thinking") {
254
- return {
255
- type: "thinking",
256
- output: thinkingOutput(part)
257
- };
258
- }
259
- return {
260
- type: "unknown",
261
- ...rawType !== "unknown" ? { sourceType: rawType } : {},
262
- output: part
263
- };
264
- }
265
- function normalizeToolResultMessage(record) {
266
- const content = record.content;
267
- let output = content;
268
- if (Array.isArray(content) && content.length === 1 && isRecord(content[0])) {
269
- const extracted = recordField(content[0], [
270
- "text",
271
- "content",
272
- "output",
273
- "result"
274
- ]);
275
- output = extracted !== void 0 ? extracted : content;
276
- }
277
- return {
278
- type: "tool_result",
279
- ...typeof record.toolCallId === "string" ? { id: record.toolCallId } : {},
280
- ...typeof record.name === "string" ? { name: record.name } : typeof record.toolName === "string" ? { name: record.toolName } : {},
281
- output
152
+ // src/chat/pi/sql-model-usage.ts
153
+ import { and as and2, eq as eq2, sql } from "drizzle-orm";
154
+ var message = sql`${juniorConversationEvents.payload}->'message'`;
155
+ var usage = sql`${message}->'usage'`;
156
+ var cost = sql`${usage}->'cost'`;
157
+ function nonnegativeNumber(source, field, fallbackField, floor = false) {
158
+ const value = (name) => sql`case
159
+ when jsonb_typeof(${source}->${name}) = 'number'
160
+ and (${source}->>${name})::numeric >= 0
161
+ then ${floor ? sql`floor((${source}->>${name})::numeric)` : sql`(${source}->>${name})::numeric`}
162
+ end`;
163
+ const primary = value(field);
164
+ return fallbackField ? sql`coalesce(${primary}, ${value(fallbackField)})` : sql`${primary}`;
165
+ }
166
+ function token(field, fallbackField) {
167
+ return nonnegativeNumber(usage, field, fallbackField, true);
168
+ }
169
+ function summed(value) {
170
+ return sql`sum(${value})::double precision`;
171
+ }
172
+ function summedCost(value) {
173
+ return sql`round(sum(${value}), 12)::double precision`;
174
+ }
175
+ function messageTotalTokens(args) {
176
+ const { input, output, cacheRead, cacheWrite } = args;
177
+ return sql`case
178
+ when ${input} is not null
179
+ or ${output} is not null
180
+ or ${cacheRead} is not null
181
+ or ${cacheWrite} is not null
182
+ then coalesce(${input}, 0)
183
+ + coalesce(${output}, 0)
184
+ + coalesce(${cacheRead}, 0)
185
+ + coalesce(${cacheWrite}, 0)
186
+ else ${token("totalTokens")}
187
+ end`;
188
+ }
189
+ function definedNumber(value) {
190
+ return value === null ? void 0 : value;
191
+ }
192
+ function usageFromRow(row) {
193
+ const components = {
194
+ inputTokens: definedNumber(row.inputTokens),
195
+ outputTokens: definedNumber(row.outputTokens),
196
+ cachedInputTokens: definedNumber(row.cachedInputTokens),
197
+ cacheCreationTokens: definedNumber(row.cacheCreationTokens)
282
198
  };
283
- }
284
- function normalizeTranscriptMessage(message) {
285
- return normalizeMessage(message);
286
- }
287
- function normalizeSubagentTranscriptMessage(message, subagentKind) {
288
- return normalizeMessage(message, {
289
- unwrapLegacyAdvisorTask: subagentKind === "advisor"
290
- });
291
- }
292
- function normalizeMessage(message, options = {}) {
293
- const record = message;
294
- const content = record.content;
295
- const role = transcriptRole(record.role);
296
- return {
297
- role,
298
- ...role === "assistant" && (record.stopReason === "error" || record.stopReason === "aborted") ? { outcome: record.stopReason } : {},
299
- ...typeof record.timestamp === "number" ? { timestamp: record.timestamp } : {},
300
- parts: role === "toolResult" ? [normalizeToolResultMessage(record)] : Array.isArray(content) ? content.map(
301
- (part) => normalizeTranscriptPart(part, {
302
- unwrapCurrentTask: role === "user",
303
- unwrapLegacyAdvisorTask: options.unwrapLegacyAdvisorTask && role === "user"
304
- })
305
- ).filter(isDisplayableTranscriptPart) : [
306
- normalizeTranscriptPart(content, {
307
- unwrapCurrentTask: role === "user",
308
- unwrapLegacyAdvisorTask: options.unwrapLegacyAdvisorTask && role === "user"
309
- })
310
- ]
199
+ const costFields = {
200
+ input: definedNumber(row.costInput),
201
+ output: definedNumber(row.costOutput),
202
+ cacheRead: definedNumber(row.costCacheRead),
203
+ cacheWrite: definedNumber(row.costCacheWrite),
204
+ total: definedNumber(row.costTotal)
311
205
  };
312
- }
313
- function transcriptRole(role) {
314
- return role === "assistant" || role === "system" || role === "tool" || role === "toolResult" || role === "user" ? role : "unknown";
315
- }
316
- function serializedChars(value) {
317
- if (typeof value === "string") return value.length;
318
- return JSON.stringify(value)?.length ?? 0;
319
- }
320
- function serializedBytes(value) {
321
- const serialized = typeof value === "string" ? value : JSON.stringify(value);
322
- return new TextEncoder().encode(serialized ?? "").byteLength;
323
- }
324
- function payloadType(value) {
325
- return Array.isArray(value) ? "array" : typeof value;
326
- }
327
- function payloadKeys(value) {
328
- if (!value || typeof value !== "object" || Array.isArray(value)) {
329
- return void 0;
330
- }
331
- const keys = Object.keys(value).slice(
332
- 0,
333
- SAFE_METADATA_KEY_LIMIT
206
+ const definedCost = Object.fromEntries(
207
+ Object.entries(costFields).filter(([, value]) => value !== void 0)
334
208
  );
335
- return keys.length > 0 ? keys : void 0;
336
- }
337
- function redactedPayloadFields(prefix, value) {
338
- const keys = payloadKeys(value);
339
- return {
340
- [`${prefix}Type`]: payloadType(value),
341
- [`${prefix}SizeBytes`]: serializedBytes(value),
342
- [`${prefix}SizeChars`]: serializedChars(value),
343
- ...keys ? { [`${prefix}Keys`]: keys } : {}
344
- };
345
- }
346
- function redactTranscriptPart(part) {
347
- if (part.type === "text") {
348
- return {
349
- type: "text",
350
- redacted: true,
351
- bytes: serializedBytes(part.text ?? ""),
352
- chars: serializedChars(part.text ?? "")
353
- };
354
- }
355
- if (part.type === "thinking") {
356
- return {
357
- type: "thinking",
358
- redacted: true,
359
- ...redactedPayloadFields("output", part.output)
360
- };
361
- }
362
- if (part.type === "tool_call") {
363
- return {
364
- type: "tool_call",
365
- redacted: true,
366
- ...part.id ? { id: part.id } : {},
367
- ...part.name ? { name: part.name } : {},
368
- ...redactedPayloadFields("input", part.input)
369
- };
370
- }
371
- if (part.type === "tool_result") {
372
- return {
373
- type: "tool_result",
374
- redacted: true,
375
- ...part.id ? { id: part.id } : {},
376
- ...part.name ? { name: part.name } : {},
377
- ...redactedPayloadFields("output", part.output)
378
- };
379
- }
380
- return {
381
- type: "unknown",
382
- redacted: true,
383
- ...part.sourceType ? { sourceType: part.sourceType } : {},
384
- ...redactedPayloadFields("output", part.output ?? part.input ?? part.text)
385
- };
386
- }
387
- function redactTranscriptMessage(message) {
388
- return {
389
- role: message.role,
390
- ...message.outcome ? { outcome: message.outcome } : {},
391
- ...typeof message.timestamp === "number" ? { timestamp: message.timestamp } : {},
392
- parts: message.parts.map(redactTranscriptPart)
209
+ const result = {
210
+ ...Object.fromEntries(
211
+ Object.entries(components).filter(([, value]) => value !== void 0)
212
+ ),
213
+ ...row.reasoningTokens === null ? {} : { reasoningTokens: row.reasoningTokens },
214
+ ...row.totalTokens === null ? {} : { totalTokens: row.totalTokens },
215
+ ...Object.keys(definedCost).length > 0 ? { cost: definedCost } : {}
393
216
  };
394
- }
395
- function isConversationMessageRole(role) {
396
- return role === "user" || role === "assistant";
397
- }
398
- function hasTextPart(message) {
399
- return message.parts.some((part) => {
400
- if (part.type !== "text") return false;
401
- if (part.redacted) return true;
402
- return typeof part.text === "string" && part.text.trim().length > 0;
217
+ return hasAgentTurnUsage(result) ? agentTurnUsageSchema.parse(result) : void 0;
218
+ }
219
+ async function readConversationModelUsageFromSql(executor, conversationId) {
220
+ const modelId = sql`concat(${message}->>'provider', '/', ${message}->>'model')`;
221
+ const inputTokens = token("input", "inputTokens");
222
+ const outputTokens = token("output", "outputTokens");
223
+ const cachedInputTokens = token("cacheRead", "cachedInputTokens");
224
+ const cacheCreationTokens = token("cacheWrite", "cacheCreationTokens");
225
+ const rows = await executor.db().select({
226
+ modelId,
227
+ inputTokens: summed(inputTokens),
228
+ outputTokens: summed(outputTokens),
229
+ cachedInputTokens: summed(cachedInputTokens),
230
+ cacheCreationTokens: summed(cacheCreationTokens),
231
+ reasoningTokens: summed(token("reasoning", "reasoningTokens")),
232
+ totalTokens: summed(
233
+ messageTotalTokens({
234
+ input: inputTokens,
235
+ output: outputTokens,
236
+ cacheRead: cachedInputTokens,
237
+ cacheWrite: cacheCreationTokens
238
+ })
239
+ ),
240
+ costInput: summedCost(nonnegativeNumber(cost, "input")),
241
+ costOutput: summedCost(nonnegativeNumber(cost, "output")),
242
+ costCacheRead: summedCost(nonnegativeNumber(cost, "cacheRead")),
243
+ costCacheWrite: summedCost(nonnegativeNumber(cost, "cacheWrite")),
244
+ costTotal: summedCost(nonnegativeNumber(cost, "total"))
245
+ }).from(juniorConversationEvents).where(
246
+ and2(
247
+ eq2(juniorConversationEvents.conversationId, conversationId),
248
+ eq2(juniorConversationEvents.type, "agent_step"),
249
+ sql`${message}->>'role' = 'assistant'`,
250
+ sql`jsonb_typeof(${message}->'provider') = 'string'`,
251
+ sql`jsonb_typeof(${message}->'model') = 'string'`,
252
+ sql`coalesce(${message}->>'provider', '') <> ''`,
253
+ sql`coalesce(${message}->>'model', '') <> ''`
254
+ )
255
+ ).groupBy(modelId).orderBy(modelId);
256
+ return rows.flatMap((row) => {
257
+ const modelUsage = usageFromRow(row);
258
+ return modelUsage ? [{ modelId: row.modelId, usage: modelUsage }] : [];
403
259
  });
404
260
  }
405
- function isConversationMessage(message) {
406
- if (!isConversationMessageRole(message.role)) return false;
407
- if (message.role === "assistant") return hasTextPart(message);
408
- return message.parts.length > 0;
409
- }
410
- function countConversationMessages(transcript) {
411
- return transcript.filter(isConversationMessage).length;
412
- }
413
- function traceIdFromTranscript(transcript) {
414
- for (const message of transcript) {
415
- for (const part of message.parts) {
416
- const text = part.text ?? (typeof part.output === "string" ? part.output : typeof part.input === "string" ? part.input : void 0);
417
- const match = text?.match(
418
- /\btrace[_-]?id["']?\s*[:=]\s*["']?([a-f0-9]{16,32})\b/i
419
- );
420
- if (match?.[1]) {
421
- return match[1];
422
- }
423
- }
424
- }
425
- return void 0;
426
- }
427
- function subagentTranscriptReport(activity, options = {}) {
428
- return {
429
- type: "subagent",
430
- ...options.subagentConversationId ? { subagentConversationId: options.subagentConversationId } : {},
431
- createdAt: activity.createdAt,
432
- id: activity.id,
433
- ...activity.modelId ? { modelId: activity.modelId } : {},
434
- status: activity.status,
435
- ...options.subagentSentryConversationUrl ? { subagentSentryConversationUrl: options.subagentSentryConversationUrl } : {},
436
- subagentKind: activity.subagentKind,
437
- transcript: options.transcript ?? [],
438
- transcriptAvailable: Boolean(options.transcript?.length),
439
- ...activity.endedAt ? { endedAt: activity.endedAt } : {},
440
- ...activity.outcome ? { outcome: activity.outcome } : {},
441
- ...activity.parentToolCallId ? { parentToolCallId: activity.parentToolCallId } : {},
442
- ...activity.reasoningLevel ? { reasoningLevel: activity.reasoningLevel } : {},
443
- ...options.transcriptMessageCount !== void 0 ? { transcriptMessageCount: options.transcriptMessageCount } : {},
444
- ...options.transcriptRedacted ? { transcriptRedacted: options.transcriptRedacted } : {},
445
- ...options.transcriptRedactionReason ? { transcriptRedactionReason: options.transcriptRedactionReason } : {},
446
- ...options.transcriptExpired ? { transcriptExpired: options.transcriptExpired } : {},
447
- ...options.transcriptExpiredAt ? { transcriptExpiredAt: options.transcriptExpiredAt } : {},
448
- ...options.unavailableReason ? { unavailableReason: options.unavailableReason } : {}
449
- };
450
- }
451
261
 
452
- // src/api/conversations/activity.ts
453
- function toolResultStatuses(messages) {
454
- const statuses = /* @__PURE__ */ new Map();
455
- for (const message of messages) {
456
- const record = message;
457
- if (record.role !== "toolResult" || typeof record.toolCallId !== "string") {
458
- continue;
459
- }
460
- statuses.set(record.toolCallId, record.isError ? "error" : "completed");
461
- }
462
- return statuses;
463
- }
464
- function activityPayloadFields(args, canExposePayload) {
465
- if (args === void 0) {
466
- return {};
467
- }
468
- return canExposePayload ? { args } : { redacted: true, ...redactedPayloadFields("input", args) };
469
- }
470
- function buildConversationActivityFromSteps(args) {
471
- const toolStatuses = toolResultStatuses(args.messages);
472
- const subagentEnds = /* @__PURE__ */ new Map();
473
- const subagentsByToolCallId = /* @__PURE__ */ new Map();
474
- const orphanSubagents = [];
475
- for (const step of args.steps) {
476
- if (step.entry.type === "subagent_ended") {
477
- subagentEnds.set(
478
- step.entry.subagentInvocationId,
479
- step
480
- );
481
- }
482
- }
483
- for (const step of args.steps) {
484
- if (step.entry.type !== "subagent_started") {
485
- continue;
262
+ // src/api/conversations/events.ts
263
+ var conversationReportSourceEventTypes = [
264
+ "message",
265
+ "message_handled",
266
+ "tool_execution_started",
267
+ "turn_started",
268
+ "turn_completed",
269
+ "turn_failed",
270
+ "compaction",
271
+ "handoff",
272
+ "subagent_started",
273
+ "subagent_ended"
274
+ ];
275
+ function reportEventData(args) {
276
+ const { data } = args;
277
+ switch (data.type) {
278
+ case "message":
279
+ return {
280
+ type: "message",
281
+ messageId: data.messageId,
282
+ role: data.role,
283
+ ...args.canExposePayload ? { text: data.text } : { redacted: true }
284
+ };
285
+ case "message_handled":
286
+ return {
287
+ type: "message_handled",
288
+ messageId: data.messageId
289
+ };
290
+ case "turn_started":
291
+ return {
292
+ type: "turn_lifecycle",
293
+ turnId: data.turnId,
294
+ state: "started"
295
+ };
296
+ case "turn_completed":
297
+ return {
298
+ type: "turn_lifecycle",
299
+ turnId: data.turnId,
300
+ state: data.outcome === "success" ? "succeeded" : "no_reply"
301
+ };
302
+ case "turn_failed":
303
+ return {
304
+ type: "turn_lifecycle",
305
+ turnId: data.turnId,
306
+ state: "failed",
307
+ failureKind: data.failureCode === "delivery_failed" ? "delivery" : "agent"
308
+ };
309
+ case "compaction":
310
+ return { type: "compaction" };
311
+ default:
312
+ return void 0;
313
+ }
314
+ }
315
+ function projectConversationReportEvents(args) {
316
+ const subagentStarts = /* @__PURE__ */ new Map();
317
+ const toolStarts = /* @__PURE__ */ new Map();
318
+ const projected = [];
319
+ for (const event of args.events) {
320
+ let data;
321
+ if (event.data.type === "tool_execution_started") {
322
+ toolStarts.set(event.data.toolCallId, event.seq);
323
+ data = { type: "tool_started", name: event.data.toolName };
324
+ } else if (event.data.type === "subagent_started") {
325
+ subagentStarts.set(event.data.subagentInvocationId, event.seq);
326
+ const toolStartedSeq = event.data.parentToolCallId ? toolStarts.get(event.data.parentToolCallId) : void 0;
327
+ data = {
328
+ type: "subagent_started",
329
+ childConversationId: event.data.childConversationId,
330
+ subagentKind: event.data.subagentKind,
331
+ ...toolStartedSeq === void 0 ? {} : { toolStartedSeq }
332
+ };
333
+ } else if (event.data.type === "subagent_ended") {
334
+ const startedSeq = subagentStarts.get(event.data.subagentInvocationId);
335
+ if (startedSeq !== void 0) {
336
+ data = {
337
+ type: "subagent_ended",
338
+ startedSeq,
339
+ outcome: event.data.outcome
340
+ };
341
+ }
342
+ } else if (event.data.type === "handoff") {
343
+ const toolStartedSeq = event.data.triggeringToolCallId ? toolStarts.get(event.data.triggeringToolCallId) : void 0;
344
+ data = {
345
+ type: "handoff",
346
+ ...toolStartedSeq === void 0 ? {} : { toolStartedSeq }
347
+ };
348
+ } else {
349
+ data = reportEventData({
350
+ canExposePayload: args.canExposePayload,
351
+ data: event.data
352
+ });
486
353
  }
487
- const start = step;
488
- const parentStatus = start.entry.parentToolCallId ? toolStatuses.get(start.entry.parentToolCallId) : void 0;
489
- const activity = subagentActivityFromSteps(
490
- start,
491
- subagentEnds.get(start.entry.subagentInvocationId),
492
- { canExposeTranscript: args.canExposePayload, parentStatus }
354
+ if (!data) continue;
355
+ projected.push(
356
+ conversationReportEventSchema.parse({
357
+ seq: event.seq,
358
+ createdAt: new Date(event.createdAtMs).toISOString(),
359
+ data
360
+ })
493
361
  );
494
- if (start.entry.parentToolCallId) {
495
- subagentsByToolCallId.set(start.entry.parentToolCallId, [
496
- ...subagentsByToolCallId.get(start.entry.parentToolCallId) ?? [],
497
- activity
498
- ]);
499
- continue;
500
- }
501
- orphanSubagents.push(activity);
502
- }
503
- const rows = [];
504
- for (const step of args.steps) {
505
- if (step.entry.type !== "tool_execution_started") {
506
- continue;
507
- }
508
- rows.push({
509
- type: "tool_execution",
510
- id: step.entry.toolCallId,
511
- toolCallId: step.entry.toolCallId,
512
- toolName: step.entry.toolName,
513
- createdAt: new Date(step.createdAtMs).toISOString(),
514
- status: toolStatuses.get(step.entry.toolCallId) ?? "running",
515
- subagents: subagentsByToolCallId.get(step.entry.toolCallId) ?? [],
516
- ...activityPayloadFields(step.entry.args, args.canExposePayload)
517
- });
518
362
  }
519
- return [...rows, ...orphanSubagents].sort(
520
- (left, right) => Date.parse(left.createdAt) - Date.parse(right.createdAt) || left.id.localeCompare(right.id)
521
- );
522
- }
523
- function subagentActivityFromSteps(start, end, options = {}) {
524
- return {
525
- type: "subagent",
526
- id: start.entry.subagentInvocationId,
527
- subagentKind: start.entry.subagentKind,
528
- ...start.entry.modelId ? { modelId: start.entry.modelId } : {},
529
- ...start.entry.parentToolCallId ? { parentToolCallId: start.entry.parentToolCallId } : {},
530
- ...start.entry.reasoningLevel ? { reasoningLevel: start.entry.reasoningLevel } : {},
531
- createdAt: new Date(start.createdAtMs).toISOString(),
532
- ...end ? {
533
- endedAt: new Date(end.createdAtMs).toISOString(),
534
- outcome: end.entry.outcome,
535
- status: end.entry.outcome,
536
- // Every subagent is a child conversation whose transcript loads on
537
- // demand; expose the affordance only when the parent is public.
538
- ...options.canExposeTranscript ? { transcriptAvailable: true } : {}
539
- } : { status: options.parentStatus ?? "running" }
540
- };
363
+ return projected;
541
364
  }
542
365
 
366
+ // src/api/conversations/list.ts
367
+ import { and as and3, asc, desc, eq as eq3, isNull } from "drizzle-orm";
368
+
543
369
  // src/api/conversations/shared.ts
544
370
  function slackStatsLocationLabel(input) {
545
371
  const channelId = input.channel;
@@ -648,7 +474,7 @@ function channelNameRedactedFromConversation(conversation) {
648
474
  }) !== "public";
649
475
  }
650
476
  function conversationSummaryFromStoredConversation(args) {
651
- const { conversation, durationMs, usage } = args;
477
+ const { conversation, durationMs, usage: usage2 } = args;
652
478
  const surface = surfaceFromSource(
653
479
  conversation.source,
654
480
  conversation.conversationId
@@ -668,7 +494,7 @@ function conversationSummaryFromStoredConversation(args) {
668
494
  startedAt: new Date(conversation.createdAtMs).toISOString(),
669
495
  status: statusFromConversation(conversation),
670
496
  surface,
671
- ...usage ? { cumulativeUsage: usage } : {},
497
+ ...usage2 ? { cumulativeUsage: usage2 } : {},
672
498
  ...actorIdentity ? { actorIdentity } : {},
673
499
  ...conversation.archivedAtMs ? { archivedAt: new Date(conversation.archivedAtMs).toISOString() } : {},
674
500
  ...slackThread ? { channel: slackThread.channelId } : {},
@@ -678,269 +504,7 @@ function conversationSummaryFromStoredConversation(args) {
678
504
  };
679
505
  }
680
506
 
681
- // src/api/conversations/detail-projection.ts
682
- var COMPACTION_SUMMARY_PREFIXES = [
683
- "Context compaction summary for future Junior turns:",
684
- "Context handoff summary for future Junior turns:"
685
- ];
686
- var MODEL_HANDOFF_SUMMARY_PREFIX = "Model handoff checkpoint. Continue the outstanding request now using this summary as the complete prior context:";
687
- function messageText(message) {
688
- return normalizeTranscriptMessage(message).parts.filter((part) => part.type === "text").map((part) => part.text ?? "").join("\n").trim();
689
- }
690
- function summaryAfterPrefix(message, prefixes) {
691
- const text = messageText(message);
692
- const prefix = prefixes.find((candidate) => text.startsWith(candidate));
693
- if (!prefix) return void 0;
694
- return text.slice(prefix.length).trim();
695
- }
696
- function summaryIndex(messages, provenance, prefixes) {
697
- for (let index = messages.length - 1; index >= 0; index -= 1) {
698
- if (provenance[index]?.authority === "context" && summaryAfterPrefix(messages[index], prefixes) !== void 0) {
699
- return index;
700
- }
701
- }
702
- return -1;
703
- }
704
- function matchingPrefix(left, right) {
705
- const limit = Math.min(left.length, right.length);
706
- for (let index = 0; index < limit; index += 1) {
707
- if (!isDeepStrictEqual(left[index], right[index])) return index;
708
- }
709
- return limit;
710
- }
711
- function historyContent(args) {
712
- const contextEvents = [];
713
- const messages = [];
714
- const epochs = /* @__PURE__ */ new Map();
715
- for (const step of args.steps) {
716
- const epoch = epochs.get(step.contextEpoch);
717
- if (epoch) epoch.push(step);
718
- else epochs.set(step.contextEpoch, [step]);
719
- }
720
- let previousModelId;
721
- let previousProjection = [];
722
- for (const steps of epochs.values()) {
723
- const marker = steps.find(
724
- (step) => step.entry.type === "context_epoch_started"
725
- );
726
- const projection = projectSteps(steps);
727
- const projected = [];
728
- const projectedProvenance = [];
729
- projection.messages.forEach((message, index) => {
730
- for (const retained of stripRuntimeTurnContext([message])) {
731
- projected.push(retained);
732
- projectedProvenance.push(projection.provenance[index]);
733
- }
734
- });
735
- const replacementSummaryIndex = marker?.entry.reason === "compaction" ? summaryIndex(
736
- projected,
737
- projectedProvenance,
738
- COMPACTION_SUMMARY_PREFIXES
739
- ) : marker?.entry.reason === "handoff" ? summaryIndex(projected, projectedProvenance, [
740
- MODEL_HANDOFF_SUMMARY_PREFIX
741
- ]) : -1;
742
- const summary = marker?.entry.reason === "compaction" && replacementSummaryIndex >= 0 ? summaryAfterPrefix(
743
- projected[replacementSummaryIndex],
744
- COMPACTION_SUMMARY_PREFIXES
745
- ) : void 0;
746
- const handoffMessage = marker?.entry.reason === "handoff" && replacementSummaryIndex >= 0 ? messageText(projected[replacementSummaryIndex]) || void 0 : void 0;
747
- if (marker?.entry.reason === "compaction") {
748
- contextEvents.push({
749
- type: "context_compacted",
750
- createdAt: new Date(marker.createdAtMs).toISOString(),
751
- ...marker.entry.modelId ? { modelId: marker.entry.modelId } : {},
752
- ...args.canExposePayload && summary ? { summary } : {},
753
- transcriptIndex: messages.length
754
- });
755
- } else if (marker?.entry.reason === "handoff") {
756
- contextEvents.push({
757
- type: "model_handoff",
758
- createdAt: new Date(marker.createdAtMs).toISOString(),
759
- ...previousModelId ? { fromModelId: previousModelId } : {},
760
- toModelId: marker.entry.modelId,
761
- ...args.canExposePayload && handoffMessage ? { message: handoffMessage } : {},
762
- transcriptIndex: messages.length
763
- });
764
- }
765
- if (marker?.entry.reason === "rollback") {
766
- messages.push(
767
- ...projected.slice(matchingPrefix(previousProjection, projected))
768
- );
769
- } else {
770
- const copiedMessageIndexes = /* @__PURE__ */ new Set();
771
- projected.forEach((message, index) => {
772
- if (index === replacementSummaryIndex) return;
773
- let copiedCompactionMessage = false;
774
- if (marker?.entry.reason === "compaction" && replacementSummaryIndex >= 0 && index < replacementSummaryIndex) {
775
- const copiedIndex = messages.findIndex(
776
- (candidate, candidateIndex) => !copiedMessageIndexes.has(candidateIndex) && isDeepStrictEqual(candidate, message)
777
- );
778
- copiedCompactionMessage = copiedIndex >= 0;
779
- if (copiedCompactionMessage) copiedMessageIndexes.add(copiedIndex);
780
- }
781
- if (!copiedCompactionMessage) messages.push(message);
782
- });
783
- }
784
- previousModelId = marker?.entry.modelId ?? previousModelId;
785
- previousProjection = projected;
786
- }
787
- return { contextEvents, messages };
788
- }
789
- async function conversationContent(args) {
790
- const steps = await args.stepStore.loadHistory(args.conversationId);
791
- const history = historyContent({
792
- canExposePayload: args.canExposePayload,
793
- steps
794
- });
795
- const messages = history.messages;
796
- const transcript = messages.length > 0 ? messages.map((message) => normalizeTranscriptMessage(message)) : (await args.messageStore.list(args.conversationId)).map(
797
- visibleMessageTranscript
798
- );
799
- return {
800
- activity: buildConversationActivityFromSteps({
801
- canExposePayload: args.canExposePayload,
802
- steps,
803
- messages
804
- }),
805
- contextEvents: history.contextEvents,
806
- transcript
807
- };
808
- }
809
- function visibleMessageTranscript(message) {
810
- return {
811
- role: message.role,
812
- timestamp: message.createdAtMs,
813
- parts: [{ type: "text", text: message.text }]
814
- };
815
- }
816
- async function buildConversationDetail(args) {
817
- const { conversation } = args;
818
- const conversationId = conversation.conversationId;
819
- const nowMs = Date.now();
820
- const stepStore = getAgentStepStore();
821
- const messageStore = getConversationMessageStore();
822
- const transcriptPurgedAtMs = conversation.transcriptPurgedAtMs;
823
- const transcriptExpiredAt = transcriptPurgedAtMs !== void 0 ? new Date(transcriptPurgedAtMs).toISOString() : void 0;
824
- const canExposeSqlContent = canExposeConversationPayload({
825
- conversationId,
826
- visibility: conversation.visibility
827
- });
828
- const currentContent = transcriptPurgedAtMs === void 0 ? await conversationContent({
829
- conversationId,
830
- messageStore,
831
- stepStore,
832
- canExposePayload: canExposeSqlContent
833
- }) : { activity: [], contextEvents: [], transcript: [] };
834
- const currentTranscript = currentContent.transcript;
835
- const traceId = canExposeSqlContent ? traceIdFromTranscript(currentTranscript) : void 0;
836
- const sentryTraceUrl = traceId ? buildSentryTraceUrl(traceId) : void 0;
837
- const sentryConversationUrl = buildSentryConversationUrl(conversationId);
838
- return {
839
- ...conversationSummaryFromStoredConversation({
840
- conversation,
841
- durationMs: args.durationMs,
842
- ...args.locationId ? { locationId: args.locationId } : {},
843
- usage: args.usage
844
- }),
845
- ...traceId ? { traceId } : {},
846
- ...sentryTraceUrl ? { sentryTraceUrl } : {},
847
- activity: currentContent.activity,
848
- contextEvents: currentContent.contextEvents,
849
- transcriptAvailable: transcriptExpiredAt === void 0 && canExposeSqlContent && currentTranscript.length > 0,
850
- ...currentTranscript.length > 0 ? {
851
- transcriptMessageCount: countConversationMessages(currentTranscript)
852
- } : {},
853
- ...!canExposeSqlContent && transcriptExpiredAt === void 0 ? {
854
- transcriptMetadata: currentTranscript.map(redactTranscriptMessage),
855
- transcriptRedacted: true,
856
- transcriptRedactionReason: "non_public_conversation"
857
- } : {},
858
- ...transcriptExpiredAt !== void 0 ? {
859
- transcriptExpired: true,
860
- transcriptExpiredAt,
861
- transcriptMetadata: []
862
- } : {},
863
- transcript: transcriptExpiredAt === void 0 && canExposeSqlContent ? currentTranscript : [],
864
- generatedAt: new Date(nowMs).toISOString(),
865
- ...sentryConversationUrl ? { sentryConversationUrl } : {}
866
- };
867
- }
868
- async function buildConversationSubagent(conversation, subagentId) {
869
- const conversationId = conversation.conversationId;
870
- const stepStore = getAgentStepStore();
871
- const parentSteps = await stepStore.loadHistory(conversationId);
872
- if (conversation?.transcriptPurgedAtMs !== void 0) {
873
- return {
874
- type: "subagent",
875
- createdAt: (/* @__PURE__ */ new Date(0)).toISOString(),
876
- id: subagentId,
877
- status: "completed",
878
- subagentKind: "unknown",
879
- transcript: [],
880
- transcriptAvailable: false,
881
- transcriptExpired: true,
882
- transcriptExpiredAt: new Date(
883
- conversation.transcriptPurgedAtMs
884
- ).toISOString()
885
- };
886
- }
887
- const start = parentSteps.find(
888
- (step) => step.entry.type === "subagent_started" && step.entry.subagentInvocationId === subagentId
889
- );
890
- if (!start) {
891
- return {
892
- type: "subagent",
893
- createdAt: (/* @__PURE__ */ new Date(0)).toISOString(),
894
- id: subagentId,
895
- status: "error",
896
- subagentKind: "unknown",
897
- transcript: [],
898
- transcriptAvailable: false,
899
- unavailableReason: "not_found"
900
- };
901
- }
902
- const end = parentSteps.find(
903
- (step) => step.entry.type === "subagent_ended" && step.entry.subagentInvocationId === subagentId
904
- );
905
- const childConversationId = start.entry.childConversationId;
906
- const activity = subagentActivityFromSteps(start, end);
907
- const subagentSentryConversationUrl = buildSentryConversationUrl(childConversationId);
908
- const conversationFields = {
909
- subagentConversationId: childConversationId,
910
- ...subagentSentryConversationUrl ? { subagentSentryConversationUrl } : {}
911
- };
912
- const canExposeTranscript = canExposeConversationPayload({
913
- conversationId,
914
- visibility: conversation?.visibility
915
- });
916
- if (!canExposeTranscript) {
917
- return subagentTranscriptReport(activity, {
918
- ...conversationFields,
919
- transcriptRedacted: true,
920
- transcriptRedactionReason: "non_public_conversation"
921
- });
922
- }
923
- const childMessages = await loadProjection({
924
- conversationId: childConversationId
925
- });
926
- if (childMessages.length === 0) {
927
- return subagentTranscriptReport(activity, {
928
- ...conversationFields,
929
- unavailableReason: "missing_transcript_ref"
930
- });
931
- }
932
- const transcript = childMessages.map(
933
- (message) => normalizeSubagentTranscriptMessage(message, activity.subagentKind)
934
- );
935
- return subagentTranscriptReport(activity, {
936
- ...conversationFields,
937
- transcript,
938
- transcriptMessageCount: countConversationMessages(transcript)
939
- });
940
- }
941
-
942
507
  // src/api/conversations/list.ts
943
- import { and as and2, asc, desc, eq as eq2, isNull } from "drizzle-orm";
944
508
  var CONVERSATION_FEED_LIMIT = 50;
945
509
  async function conversationRows(db, limit, actorEmail) {
946
510
  return db.select({
@@ -955,17 +519,17 @@ async function conversationRows(db, limit, actorEmail) {
955
519
  identityTenantId: juniorIdentities.providerTenantId
956
520
  }).from(juniorConversations).leftJoin(
957
521
  juniorDestinations,
958
- eq2(juniorDestinations.id, juniorConversations.destinationId)
522
+ eq3(juniorDestinations.id, juniorConversations.destinationId)
959
523
  ).leftJoin(
960
524
  juniorIdentities,
961
- eq2(juniorIdentities.id, juniorConversations.actorIdentityId)
525
+ eq3(juniorIdentities.id, juniorConversations.actorIdentityId)
962
526
  ).where(
963
- and2(
527
+ and3(
964
528
  isNull(juniorConversations.parentConversationId),
965
529
  isNull(juniorConversations.archivedAt),
966
- actorEmail ? and2(
967
- eq2(juniorIdentities.emailNormalized, actorEmail),
968
- eq2(juniorIdentities.emailVerified, true)
530
+ actorEmail ? and3(
531
+ eq3(juniorIdentities.emailNormalized, actorEmail),
532
+ eq3(juniorIdentities.emailVerified, true)
969
533
  ) : void 0
970
534
  )
971
535
  ).orderBy(
@@ -1019,11 +583,11 @@ async function readConversationRecordFromSql(conversationId) {
1019
583
  identityTenantId: juniorIdentities.providerTenantId
1020
584
  }).from(juniorConversations).leftJoin(
1021
585
  juniorDestinations,
1022
- eq2(juniorDestinations.id, juniorConversations.destinationId)
586
+ eq3(juniorDestinations.id, juniorConversations.destinationId)
1023
587
  ).leftJoin(
1024
588
  juniorIdentities,
1025
- eq2(juniorIdentities.id, juniorConversations.actorIdentityId)
1026
- ).where(eq2(juniorConversations.conversationId, conversationId)).limit(1);
589
+ eq3(juniorIdentities.id, juniorConversations.actorIdentityId)
590
+ ).where(eq3(juniorConversations.conversationId, conversationId)).limit(1);
1027
591
  const row = rows[0];
1028
592
  return row ? {
1029
593
  conversation: conversationFromRow(row),
@@ -1069,35 +633,76 @@ var list_default = {
1069
633
  }
1070
634
  };
1071
635
 
1072
- // src/api/conversations/detail.query.ts
1073
- async function readLatestRun(conversationId) {
1074
- try {
1075
- return (await listBoundedAgentTurnSessionSummariesForConversation(conversationId)).find((summary) => summary.modelId || summary.reasoningLevel);
1076
- } catch (error) {
1077
- logException(error, "conversation_execution_settings_read_failed", {
1078
- conversationId
1079
- });
1080
- return void 0;
1081
- }
636
+ // src/api/conversations/detail.ts
637
+ function projectConversationDetail(args) {
638
+ const { conversation } = args;
639
+ const conversationId = conversation.conversationId;
640
+ const transcriptPurgedAtMs = conversation.transcriptPurgedAtMs;
641
+ const { visibility: _storedVisibility, ...conversationWithoutVisibility } = conversation;
642
+ const authorizedConversation = {
643
+ ...conversationWithoutVisibility,
644
+ ...args.effectiveVisibility ? { visibility: args.effectiveVisibility } : {}
645
+ };
646
+ const canExposePayload = canExposeConversationPayload({
647
+ conversationId: args.privacyConversationId ?? conversationId,
648
+ visibility: args.effectiveVisibility
649
+ });
650
+ const events = transcriptPurgedAtMs === void 0 ? args.events : [];
651
+ const modelUsage = transcriptPurgedAtMs === void 0 ? args.modelUsage : [];
652
+ const sentryConversationUrl = buildSentryConversationUrl(conversationId);
653
+ return {
654
+ ...conversationSummaryFromStoredConversation({
655
+ conversation: authorizedConversation,
656
+ durationMs: args.durationMs,
657
+ ...args.locationId ? { locationId: args.locationId } : {},
658
+ usage: args.usage
659
+ }),
660
+ events: projectConversationReportEvents({ canExposePayload, events }),
661
+ ...modelUsage.length > 0 ? { modelUsage } : {},
662
+ eventHistory: transcriptPurgedAtMs !== void 0 ? {
663
+ status: "expired",
664
+ expiredAt: new Date(transcriptPurgedAtMs).toISOString()
665
+ } : canExposePayload ? { status: "available" } : {
666
+ status: "redacted",
667
+ reason: "non_public_conversation"
668
+ },
669
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
670
+ ...sentryConversationUrl ? { sentryConversationUrl } : {}
671
+ };
1082
672
  }
1083
673
  async function readConversationDetailFromSql(conversationId) {
1084
674
  const record = await readConversationRecordFromSql(conversationId);
1085
675
  if (!record) return void 0;
1086
- const [report, latestRun] = await Promise.all([
1087
- buildConversationDetail({
1088
- ...record,
1089
- usage: record.usage ?? void 0
676
+ const executor = getSqlExecutor();
677
+ const [snapshot, modelUsage] = await Promise.all([
678
+ readConversationEventPrivacySnapshot(executor, {
679
+ conversationId,
680
+ eventTypes: conversationReportSourceEventTypes
1090
681
  }),
1091
- readLatestRun(conversationId)
682
+ record.conversation.transcriptPurgedAtMs === void 0 ? readConversationModelUsageFromSql(executor, conversationId) : Promise.resolve([])
1092
683
  ]);
1093
- return {
1094
- ...report,
1095
- ...latestRun?.modelId ? { modelId: latestRun.modelId } : {},
1096
- ...latestRun?.reasoningLevel ? { reasoningLevel: latestRun.reasoningLevel } : {}
1097
- };
684
+ if (!snapshot) return void 0;
685
+ const events = snapshot.events.map(
686
+ (row) => decodeStoredConversationEvent({
687
+ schemaVersion: row.schemaVersion,
688
+ seq: row.seq,
689
+ historyVersion: row.historyVersion,
690
+ ...row.idempotencyKey ? { idempotencyKey: row.idempotencyKey } : {},
691
+ createdAtMs: row.createdAt.getTime(),
692
+ type: row.type,
693
+ payload: row.payload
694
+ })
695
+ );
696
+ const effectiveVisibility = snapshot.visibility === "public" || snapshot.visibility === "private" ? snapshot.visibility : void 0;
697
+ return projectConversationDetail({
698
+ ...record,
699
+ effectiveVisibility,
700
+ events,
701
+ modelUsage,
702
+ privacyConversationId: snapshot.rootConversationId,
703
+ usage: record.usage ?? void 0
704
+ });
1098
705
  }
1099
-
1100
- // src/api/conversations/detail.ts
1101
706
  async function readConversationDetail(conversationId) {
1102
707
  const report = await readConversationDetailFromSql(conversationId);
1103
708
  return report ? conversationDetailReportSchema.parse(report) : void 0;
@@ -1116,12 +721,12 @@ var detail_default = {
1116
721
  };
1117
722
 
1118
723
  // src/api/conversations/stats.query.ts
1119
- import { and as and3, eq as eq3, gte, isNull as isNull2, lte, sql as sql2 } from "drizzle-orm";
724
+ import { and as and4, eq as eq4, gte, isNull as isNull2, lte, sql as sql3 } from "drizzle-orm";
1120
725
 
1121
726
  // src/api/conversations/aggregate.ts
1122
- import { sql } from "drizzle-orm";
727
+ import { sql as sql2 } from "drizzle-orm";
1123
728
  function tokenValue() {
1124
- return sql`
729
+ return sql2`
1125
730
  CASE
1126
731
  WHEN ${juniorConversations.usage}->>'totalTokens' IS NOT NULL
1127
732
  THEN (${juniorConversations.usage}->>'totalTokens')::double precision
@@ -1140,7 +745,7 @@ function tokenValue() {
1140
745
  `;
1141
746
  }
1142
747
  function costValue() {
1143
- return sql`
748
+ return sql2`
1144
749
  CASE
1145
750
  WHEN ${juniorConversations.usage}->'cost'->>'total' IS NOT NULL
1146
751
  THEN (${juniorConversations.usage}->'cost'->>'total')::double precision
@@ -1160,30 +765,30 @@ function costValue() {
1160
765
  }
1161
766
  function conversationAggregateColumns() {
1162
767
  return {
1163
- active: sql`COUNT(*) FILTER (
768
+ active: sql2`COUNT(*) FILTER (
1164
769
  WHERE ${juniorConversations.executionStatus} NOT IN ('idle', 'failed')
1165
770
  )::integer`,
1166
- conversations: sql`COUNT(*)::integer`,
1167
- costUsd: sql`SUM(${costValue()})::double precision`,
1168
- durationMs: sql`COALESCE(SUM(${juniorConversations.durationMs}), 0)::double precision`,
1169
- failed: sql`COUNT(*) FILTER (
771
+ conversations: sql2`COUNT(*)::integer`,
772
+ costUsd: sql2`SUM(${costValue()})::double precision`,
773
+ durationMs: sql2`COALESCE(SUM(${juniorConversations.durationMs}), 0)::double precision`,
774
+ failed: sql2`COUNT(*) FILTER (
1170
775
  WHERE ${juniorConversations.executionStatus} = 'failed'
1171
776
  )::integer`,
1172
- tokens: sql`SUM(${tokenValue()})::double precision`
777
+ tokens: sql2`SUM(${tokenValue()})::double precision`
1173
778
  };
1174
779
  }
1175
780
  function conversationRangeColumns() {
1176
781
  return {
1177
- firstSeenAt: sql`MIN(${juniorConversations.createdAt})`.mapWith(
782
+ firstSeenAt: sql2`MIN(${juniorConversations.createdAt})`.mapWith(
1178
783
  juniorConversations.createdAt
1179
784
  ),
1180
- lastSeenAt: sql`MAX(${juniorConversations.lastActivityAt})`.mapWith(
785
+ lastSeenAt: sql2`MAX(${juniorConversations.lastActivityAt})`.mapWith(
1181
786
  juniorConversations.lastActivityAt
1182
787
  )
1183
788
  };
1184
789
  }
1185
790
  function conversationActiveDaysColumn() {
1186
- return sql`COUNT(DISTINCT (${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC')::date)::integer`;
791
+ return sql2`COUNT(DISTINCT (${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC')::date)::integer`;
1187
792
  }
1188
793
 
1189
794
  // src/api/conversations/stats.query.ts
@@ -1242,7 +847,7 @@ function statsItems(map) {
1242
847
  );
1243
848
  }
1244
849
  function statsWhere(start, end) {
1245
- return and3(
850
+ return and4(
1246
851
  isNull2(juniorConversations.parentConversationId),
1247
852
  gte(juniorConversations.lastActivityAt, start),
1248
853
  lte(juniorConversations.lastActivityAt, end)
@@ -1276,7 +881,7 @@ function metricDays(rows, endMs) {
1276
881
  }
1277
882
  async function aggregateStats(db, start, end) {
1278
883
  const where = statsWhere(start, end);
1279
- const activityDate = sql2`TO_CHAR(
884
+ const activityDate = sql3`TO_CHAR(
1280
885
  ${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
1281
886
  'YYYY-MM-DD'
1282
887
  )`;
@@ -1292,8 +897,8 @@ async function aggregateStats(db, start, end) {
1292
897
  ...conversationAggregateColumns()
1293
898
  }).from(juniorConversations).leftJoin(
1294
899
  juniorIdentities,
1295
- eq3(juniorIdentities.id, juniorConversations.actorIdentityId)
1296
- ).leftJoin(juniorUsers, eq3(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(
900
+ eq4(juniorIdentities.id, juniorConversations.actorIdentityId)
901
+ ).leftJoin(juniorUsers, eq4(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(
1297
902
  juniorIdentities.displayName,
1298
903
  juniorIdentities.emailNormalized,
1299
904
  juniorIdentities.handle,
@@ -1311,7 +916,7 @@ async function aggregateStats(db, start, end) {
1311
916
  ...conversationAggregateColumns()
1312
917
  }).from(juniorConversations).leftJoin(
1313
918
  juniorDestinations,
1314
- eq3(juniorDestinations.id, juniorConversations.destinationId)
919
+ eq4(juniorDestinations.id, juniorConversations.destinationId)
1315
920
  ).where(where).groupBy(
1316
921
  juniorConversations.channelName,
1317
922
  juniorConversations.source,
@@ -1374,46 +979,8 @@ var stats_default = {
1374
979
  handler: async () => Response.json(await readConversationStats())
1375
980
  };
1376
981
 
1377
- // src/api/conversations/subagent.ts
1378
- async function readConversationSubagent(conversationId, subagentId) {
1379
- const record = await readConversationRecordFromSql(conversationId);
1380
- if (!record) {
1381
- return conversationSubagentTranscriptReportSchema.parse({
1382
- type: "subagent",
1383
- createdAt: (/* @__PURE__ */ new Date(0)).toISOString(),
1384
- id: subagentId,
1385
- status: "error",
1386
- subagentKind: "unknown",
1387
- transcript: [],
1388
- transcriptAvailable: false,
1389
- unavailableReason: "not_found"
1390
- });
1391
- }
1392
- return conversationSubagentTranscriptReportSchema.parse(
1393
- await buildConversationSubagent(record.conversation, subagentId)
1394
- );
1395
- }
1396
- var subagent_default = {
1397
- method: "get",
1398
- path: "/:conversationId/subagents/:subagentId",
1399
- handler: async (c) => {
1400
- const { conversationId, subagentId } = parseParams(
1401
- subagentParamsSchema,
1402
- c.req.param()
1403
- );
1404
- const report = await readConversationSubagent(conversationId, subagentId);
1405
- return report.unavailableReason === "not_found" ? Response.json(report, { status: 404 }) : Response.json(report);
1406
- }
1407
- };
1408
-
1409
982
  // src/api/conversations/routes.ts
1410
- var routes = [
1411
- list_default,
1412
- stats_default,
1413
- archive_default,
1414
- detail_default,
1415
- subagent_default
1416
- ];
983
+ var routes = [list_default, stats_default, archive_default, detail_default];
1417
984
  function createConversationRoutes() {
1418
985
  const app = new Hono();
1419
986
  for (const route of routes) app.on(route.method, route.path, route.handler);
@@ -1424,7 +991,7 @@ function createConversationRoutes() {
1424
991
  import { Hono as Hono2 } from "hono";
1425
992
 
1426
993
  // src/api/locations/query.ts
1427
- import { and as and4, asc as asc2, desc as desc2, eq as eq4, gte as gte2, isNull as isNull3, sql as sql3 } from "drizzle-orm";
994
+ import { and as and5, asc as asc2, desc as desc2, eq as eq5, gte as gte2, isNull as isNull3, sql as sql4 } from "drizzle-orm";
1428
995
 
1429
996
  // src/api/conversations/reporting.ts
1430
997
  var PRIVATE_CONVERSATION_LABEL2 = "Private Conversation";
@@ -1558,10 +1125,10 @@ function topLevelWhere() {
1558
1125
  return isNull3(juniorConversations.parentConversationId);
1559
1126
  }
1560
1127
  function publicLocationWhere(destinationId) {
1561
- return and4(
1128
+ return and5(
1562
1129
  topLevelWhere(),
1563
- eq4(juniorDestinations.id, destinationId),
1564
- eq4(juniorDestinations.visibility, "public")
1130
+ eq5(juniorDestinations.id, destinationId),
1131
+ eq5(juniorDestinations.visibility, "public")
1565
1132
  );
1566
1133
  }
1567
1134
  function locationColumns() {
@@ -1612,22 +1179,22 @@ async function directoryRows(db) {
1612
1179
  ...conversationRangeColumns()
1613
1180
  }).from(juniorConversations).leftJoin(
1614
1181
  juniorDestinations,
1615
- eq4(juniorDestinations.id, juniorConversations.destinationId)
1182
+ eq5(juniorDestinations.id, juniorConversations.destinationId)
1616
1183
  ).where(topLevelWhere()).groupBy(...locationGroupBy());
1617
1184
  }
1618
1185
  async function directoryActivityRows(db, start) {
1619
- const date = sql3`TO_CHAR(
1186
+ const date = sql4`TO_CHAR(
1620
1187
  ${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
1621
1188
  'YYYY-MM-DD'
1622
1189
  )`;
1623
1190
  return db.select({
1624
- conversations: sql3`COUNT(*)::integer`,
1191
+ conversations: sql4`COUNT(*)::integer`,
1625
1192
  date,
1626
1193
  visibility: juniorDestinations.visibility
1627
1194
  }).from(juniorConversations).leftJoin(
1628
1195
  juniorDestinations,
1629
- eq4(juniorDestinations.id, juniorConversations.destinationId)
1630
- ).where(and4(topLevelWhere(), gte2(juniorConversations.lastActivityAt, start))).groupBy(date, juniorDestinations.visibility);
1196
+ eq5(juniorDestinations.id, juniorConversations.destinationId)
1197
+ ).where(and5(topLevelWhere(), gte2(juniorConversations.lastActivityAt, start))).groupBy(date, juniorDestinations.visibility);
1631
1198
  }
1632
1199
  function directoryActivityDays(rows, nowMs) {
1633
1200
  const days = /* @__PURE__ */ new Map();
@@ -1701,7 +1268,7 @@ async function recentLocationRows(db, locationId) {
1701
1268
  destinationId: juniorDestinations.id,
1702
1269
  destinationVisibility: juniorDestinations.visibility,
1703
1270
  durationMs: juniorConversations.durationMs,
1704
- email: sql3`COALESCE(
1271
+ email: sql4`COALESCE(
1705
1272
  ${juniorUsers.primaryEmailNormalized},
1706
1273
  ${juniorIdentities.email}
1707
1274
  )`,
@@ -1710,7 +1277,7 @@ async function recentLocationRows(db, locationId) {
1710
1277
  fullName: juniorUsers.displayName,
1711
1278
  handle: juniorIdentities.handle,
1712
1279
  lastActivityAt: juniorConversations.lastActivityAt,
1713
- providerSubjectId: sql3`CASE
1280
+ providerSubjectId: sql4`CASE
1714
1281
  WHEN ${juniorIdentities.provider} = 'slack'
1715
1282
  THEN ${juniorIdentities.providerSubjectId}
1716
1283
  ELSE NULL
@@ -1721,12 +1288,12 @@ async function recentLocationRows(db, locationId) {
1721
1288
  usage: juniorConversations.usage
1722
1289
  }).from(juniorConversations).innerJoin(
1723
1290
  juniorDestinations,
1724
- eq4(juniorDestinations.id, juniorConversations.destinationId)
1291
+ eq5(juniorDestinations.id, juniorConversations.destinationId)
1725
1292
  ).leftJoin(
1726
1293
  juniorIdentities,
1727
- eq4(juniorIdentities.id, juniorConversations.actorIdentityId)
1728
- ).leftJoin(juniorUsers, eq4(juniorUsers.id, juniorIdentities.userId)).where(
1729
- and4(
1294
+ eq5(juniorIdentities.id, juniorConversations.actorIdentityId)
1295
+ ).leftJoin(juniorUsers, eq5(juniorUsers.id, juniorIdentities.userId)).where(
1296
+ and5(
1730
1297
  publicLocationWhere(locationId),
1731
1298
  isNull3(juniorConversations.archivedAt)
1732
1299
  )
@@ -1742,7 +1309,7 @@ async function readLocationDetailFromSql(locationId) {
1742
1309
  const start = new Date(end);
1743
1310
  start.setUTCDate(start.getUTCDate() - (ACTIVITY_DAYS - 1));
1744
1311
  const where = publicLocationWhere(locationId);
1745
- const activityDate = sql3`TO_CHAR(
1312
+ const activityDate = sql4`TO_CHAR(
1746
1313
  ${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
1747
1314
  'YYYY-MM-DD'
1748
1315
  )`;
@@ -1753,12 +1320,12 @@ async function readLocationDetailFromSql(locationId) {
1753
1320
  ...conversationRangeColumns()
1754
1321
  }).from(juniorConversations).innerJoin(
1755
1322
  juniorDestinations,
1756
- eq4(juniorDestinations.id, juniorConversations.destinationId)
1323
+ eq5(juniorDestinations.id, juniorConversations.destinationId)
1757
1324
  ).where(where).groupBy(...locationGroupBy()),
1758
1325
  getDb().select({ date: activityDate, ...conversationAggregateColumns() }).from(juniorConversations).innerJoin(
1759
1326
  juniorDestinations,
1760
- eq4(juniorDestinations.id, juniorConversations.destinationId)
1761
- ).where(and4(where, gte2(juniorConversations.lastActivityAt, start))).groupBy(activityDate),
1327
+ eq5(juniorDestinations.id, juniorConversations.destinationId)
1328
+ ).where(and5(where, gte2(juniorConversations.lastActivityAt, start))).groupBy(activityDate),
1762
1329
  getDb().select({
1763
1330
  actorIdentityId: juniorConversations.actorIdentityId,
1764
1331
  email: juniorUsers.primaryEmailNormalized,
@@ -1770,11 +1337,11 @@ async function readLocationDetailFromSql(locationId) {
1770
1337
  ...conversationAggregateColumns()
1771
1338
  }).from(juniorConversations).innerJoin(
1772
1339
  juniorDestinations,
1773
- eq4(juniorDestinations.id, juniorConversations.destinationId)
1340
+ eq5(juniorDestinations.id, juniorConversations.destinationId)
1774
1341
  ).leftJoin(
1775
1342
  juniorIdentities,
1776
- eq4(juniorIdentities.id, juniorConversations.actorIdentityId)
1777
- ).leftJoin(juniorUsers, eq4(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(
1343
+ eq5(juniorIdentities.id, juniorConversations.actorIdentityId)
1344
+ ).leftJoin(juniorUsers, eq5(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(
1778
1345
  juniorConversations.actorIdentityId,
1779
1346
  juniorUsers.primaryEmailNormalized,
1780
1347
  juniorUsers.displayName,
@@ -1867,10 +1434,10 @@ function createLocationRoutes() {
1867
1434
  import { Hono as Hono3 } from "hono";
1868
1435
 
1869
1436
  // src/api/people/list.query.ts
1870
- import { and as and6, eq as eq6, gte as gte3, sql as sql5 } from "drizzle-orm";
1437
+ import { and as and7, eq as eq7, gte as gte3, sql as sql6 } from "drizzle-orm";
1871
1438
 
1872
1439
  // src/api/people/shared.ts
1873
- import { and as and5, asc as asc3, desc as desc3, eq as eq5, isNull as isNull4, sql as sql4 } from "drizzle-orm";
1440
+ import { and as and6, asc as asc3, desc as desc3, eq as eq6, isNull as isNull4, sql as sql5 } from "drizzle-orm";
1874
1441
  var RECENT_LIMIT2 = 25;
1875
1442
  var ACTIVITY_DAYS2 = 365;
1876
1443
  function normalizeEmail(email) {
@@ -1914,11 +1481,11 @@ function statsItems2(map) {
1914
1481
  }
1915
1482
  function verifiedActorWhere(email) {
1916
1483
  const normalizedEmail = normalizeEmail(email);
1917
- return and5(
1918
- eq5(juniorIdentities.provider, "slack"),
1919
- eq5(juniorIdentities.emailVerified, true),
1920
- sql4`${juniorUsers.primaryEmailNormalized} IS NOT NULL`,
1921
- normalizedEmail ? eq5(juniorUsers.primaryEmailNormalized, normalizedEmail) : void 0
1484
+ return and6(
1485
+ eq6(juniorIdentities.provider, "slack"),
1486
+ eq6(juniorIdentities.emailVerified, true),
1487
+ sql5`${juniorUsers.primaryEmailNormalized} IS NOT NULL`,
1488
+ normalizedEmail ? eq6(juniorUsers.primaryEmailNormalized, normalizedEmail) : void 0
1922
1489
  );
1923
1490
  }
1924
1491
  async function recentActorRows(email) {
@@ -1942,12 +1509,12 @@ async function recentActorRows(email) {
1942
1509
  usage: juniorConversations.usage
1943
1510
  }).from(juniorConversations).innerJoin(
1944
1511
  juniorIdentities,
1945
- eq5(juniorIdentities.id, juniorConversations.actorIdentityId)
1946
- ).innerJoin(juniorUsers, eq5(juniorUsers.id, juniorIdentities.userId)).leftJoin(
1512
+ eq6(juniorIdentities.id, juniorConversations.actorIdentityId)
1513
+ ).innerJoin(juniorUsers, eq6(juniorUsers.id, juniorIdentities.userId)).leftJoin(
1947
1514
  juniorDestinations,
1948
- eq5(juniorDestinations.id, juniorConversations.destinationId)
1515
+ eq6(juniorDestinations.id, juniorConversations.destinationId)
1949
1516
  ).where(
1950
- and5(verifiedActorWhere(email), isNull4(juniorConversations.archivedAt))
1517
+ and6(verifiedActorWhere(email), isNull4(juniorConversations.archivedAt))
1951
1518
  ).orderBy(
1952
1519
  desc3(juniorConversations.lastActivityAt),
1953
1520
  asc3(juniorConversations.conversationId)
@@ -1976,7 +1543,7 @@ function directoryActivityDays2(rows, nowMs) {
1976
1543
  async function readPeopleListFromSql() {
1977
1544
  const nowMs = Date.now();
1978
1545
  const { end, start } = activityWindow(nowMs);
1979
- const activityDate = sql5`TO_CHAR(
1546
+ const activityDate = sql6`TO_CHAR(
1980
1547
  ${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
1981
1548
  'YYYY-MM-DD'
1982
1549
  )`;
@@ -1984,24 +1551,24 @@ async function readPeopleListFromSql() {
1984
1551
  getDb().select({
1985
1552
  email: juniorUsers.primaryEmailNormalized,
1986
1553
  fullName: juniorUsers.displayName,
1987
- slackUserId: sql5`MAX(${juniorIdentities.providerSubjectId})`,
1988
- slackUserName: sql5`MAX(${juniorIdentities.handle})`,
1554
+ slackUserId: sql6`MAX(${juniorIdentities.providerSubjectId})`,
1555
+ slackUserName: sql6`MAX(${juniorIdentities.handle})`,
1989
1556
  activeDays: conversationActiveDaysColumn(),
1990
1557
  ...conversationAggregateColumns(),
1991
1558
  ...conversationRangeColumns()
1992
1559
  }).from(juniorConversations).innerJoin(
1993
1560
  juniorIdentities,
1994
- eq6(juniorIdentities.id, juniorConversations.actorIdentityId)
1995
- ).innerJoin(juniorUsers, eq6(juniorUsers.id, juniorIdentities.userId)).where(verifiedActorWhere()).groupBy(juniorUsers.primaryEmailNormalized, juniorUsers.displayName),
1561
+ eq7(juniorIdentities.id, juniorConversations.actorIdentityId)
1562
+ ).innerJoin(juniorUsers, eq7(juniorUsers.id, juniorIdentities.userId)).where(verifiedActorWhere()).groupBy(juniorUsers.primaryEmailNormalized, juniorUsers.displayName),
1996
1563
  getDb().select({
1997
- activePeople: sql5`COUNT(DISTINCT ${juniorUsers.id})::int`,
1998
- conversations: sql5`COUNT(*)::int`,
1564
+ activePeople: sql6`COUNT(DISTINCT ${juniorUsers.id})::int`,
1565
+ conversations: sql6`COUNT(*)::int`,
1999
1566
  date: activityDate
2000
1567
  }).from(juniorConversations).innerJoin(
2001
1568
  juniorIdentities,
2002
- eq6(juniorIdentities.id, juniorConversations.actorIdentityId)
2003
- ).innerJoin(juniorUsers, eq6(juniorUsers.id, juniorIdentities.userId)).where(
2004
- and6(
1569
+ eq7(juniorIdentities.id, juniorConversations.actorIdentityId)
1570
+ ).innerJoin(juniorUsers, eq7(juniorUsers.id, juniorIdentities.userId)).where(
1571
+ and7(
2005
1572
  verifiedActorWhere(),
2006
1573
  gte3(juniorConversations.lastActivityAt, start)
2007
1574
  )
@@ -2049,7 +1616,7 @@ var list_default3 = {
2049
1616
  };
2050
1617
 
2051
1618
  // src/api/people/profile.query.ts
2052
- import { and as and7, eq as eq7, gte as gte4, sql as sql6 } from "drizzle-orm";
1619
+ import { and as and8, eq as eq8, gte as gte4, sql as sql7 } from "drizzle-orm";
2053
1620
  function emptyProfile(email, nowMs) {
2054
1621
  const end = new Date(nowMs);
2055
1622
  end.setUTCHours(0, 0, 0, 0);
@@ -2084,7 +1651,7 @@ function addAggregate2(map, label, row) {
2084
1651
  map.set(label, item);
2085
1652
  }
2086
1653
  function surfaceExpression() {
2087
- return sql6`CASE
1654
+ return sql7`CASE
2088
1655
  WHEN ${juniorConversations.source} IN ('api', 'scheduler', 'slack')
2089
1656
  THEN ${juniorConversations.source}
2090
1657
  WHEN ${juniorConversations.conversationId} LIKE 'slack:%' THEN 'slack'
@@ -2112,30 +1679,30 @@ async function readPeopleProfileFromSql(email) {
2112
1679
  start.setUTCDate(start.getUTCDate() - (ACTIVITY_DAYS2 - 1));
2113
1680
  const where = verifiedActorWhere(normalizedEmail);
2114
1681
  const surface = surfaceExpression();
2115
- const activityDate = sql6`TO_CHAR(
1682
+ const activityDate = sql7`TO_CHAR(
2116
1683
  ${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
2117
1684
  'YYYY-MM-DD'
2118
1685
  )`;
2119
- const channel = sql6`SPLIT_PART(${juniorConversations.conversationId}, ':', 2)`;
1686
+ const channel = sql7`SPLIT_PART(${juniorConversations.conversationId}, ':', 2)`;
2120
1687
  const [totalsRows, dayRows, locationRows, surfaceRows, recentRows] = await Promise.all([
2121
1688
  getDb().select({
2122
1689
  email: juniorUsers.primaryEmailNormalized,
2123
1690
  fullName: juniorUsers.displayName,
2124
- slackUserId: sql6`MAX(${juniorIdentities.providerSubjectId})`,
2125
- slackUserName: sql6`MAX(${juniorIdentities.handle})`,
1691
+ slackUserId: sql7`MAX(${juniorIdentities.providerSubjectId})`,
1692
+ slackUserName: sql7`MAX(${juniorIdentities.handle})`,
2126
1693
  activeDays: conversationActiveDaysColumn(),
2127
1694
  ...conversationAggregateColumns()
2128
1695
  }).from(juniorConversations).innerJoin(
2129
1696
  juniorIdentities,
2130
- eq7(juniorIdentities.id, juniorConversations.actorIdentityId)
2131
- ).innerJoin(juniorUsers, eq7(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(juniorUsers.primaryEmailNormalized, juniorUsers.displayName),
1697
+ eq8(juniorIdentities.id, juniorConversations.actorIdentityId)
1698
+ ).innerJoin(juniorUsers, eq8(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(juniorUsers.primaryEmailNormalized, juniorUsers.displayName),
2132
1699
  getDb().select({
2133
1700
  date: activityDate,
2134
1701
  ...conversationAggregateColumns()
2135
1702
  }).from(juniorConversations).innerJoin(
2136
1703
  juniorIdentities,
2137
- eq7(juniorIdentities.id, juniorConversations.actorIdentityId)
2138
- ).innerJoin(juniorUsers, eq7(juniorUsers.id, juniorIdentities.userId)).where(and7(where, gte4(juniorConversations.lastActivityAt, start))).groupBy(activityDate),
1704
+ eq8(juniorIdentities.id, juniorConversations.actorIdentityId)
1705
+ ).innerJoin(juniorUsers, eq8(juniorUsers.id, juniorIdentities.userId)).where(and8(where, gte4(juniorConversations.lastActivityAt, start))).groupBy(activityDate),
2139
1706
  getDb().select({
2140
1707
  channel,
2141
1708
  channelName: juniorConversations.channelName,
@@ -2144,10 +1711,10 @@ async function readPeopleProfileFromSql(email) {
2144
1711
  ...conversationAggregateColumns()
2145
1712
  }).from(juniorConversations).innerJoin(
2146
1713
  juniorIdentities,
2147
- eq7(juniorIdentities.id, juniorConversations.actorIdentityId)
2148
- ).innerJoin(juniorUsers, eq7(juniorUsers.id, juniorIdentities.userId)).leftJoin(
1714
+ eq8(juniorIdentities.id, juniorConversations.actorIdentityId)
1715
+ ).innerJoin(juniorUsers, eq8(juniorUsers.id, juniorIdentities.userId)).leftJoin(
2149
1716
  juniorDestinations,
2150
- eq7(juniorDestinations.id, juniorConversations.destinationId)
1717
+ eq8(juniorDestinations.id, juniorConversations.destinationId)
2151
1718
  ).where(where).groupBy(
2152
1719
  channel,
2153
1720
  juniorConversations.channelName,
@@ -2156,8 +1723,8 @@ async function readPeopleProfileFromSql(email) {
2156
1723
  ),
2157
1724
  getDb().select({ surface, ...conversationAggregateColumns() }).from(juniorConversations).innerJoin(
2158
1725
  juniorIdentities,
2159
- eq7(juniorIdentities.id, juniorConversations.actorIdentityId)
2160
- ).innerJoin(juniorUsers, eq7(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(surface),
1726
+ eq8(juniorIdentities.id, juniorConversations.actorIdentityId)
1727
+ ).innerJoin(juniorUsers, eq8(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(surface),
2161
1728
  recentActorRows(normalizedEmail)
2162
1729
  ]);
2163
1730
  const totalsRow = totalsRows[0];
@@ -2245,7 +1812,7 @@ function readDescriptionText(home) {
2245
1812
  }
2246
1813
  }
2247
1814
  async function readSkillReports() {
2248
- const { discoverSkills } = await import("./skills-722AXRV5.js");
1815
+ const { discoverSkills } = await import("./skills-ITNHBARB.js");
2249
1816
  const skills = await discoverSkills();
2250
1817
  return skillReportsSchema.parse(
2251
1818
  skills.map((skill) => ({
@@ -2255,7 +1822,7 @@ async function readSkillReports() {
2255
1822
  );
2256
1823
  }
2257
1824
  async function readPluginReports() {
2258
- const { pluginCatalogRuntime } = await import("./catalog-runtime-5CVM2DOF.js");
1825
+ const { pluginCatalogRuntime } = await import("./catalog-runtime-FOFNPR3P.js");
2259
1826
  return pluginReportsSchema.parse(
2260
1827
  pluginCatalogRuntime.getProviders().map((plugin) => ({
2261
1828
  name: plugin.manifest.name
@@ -2265,7 +1832,7 @@ async function readPluginReports() {
2265
1832
  async function readRuntimeInfoReport() {
2266
1833
  const [{ homeDir }, { pluginCatalogRuntime }, plugins, skills] = await Promise.all([
2267
1834
  import("./discovery-RMHYSRL7.js"),
2268
- import("./catalog-runtime-5CVM2DOF.js"),
1835
+ import("./catalog-runtime-FOFNPR3P.js"),
2269
1836
  readPluginReports(),
2270
1837
  readSkillReports()
2271
1838
  ]);
@@ -2281,7 +1848,7 @@ async function readRuntimeInfoReport() {
2281
1848
  }
2282
1849
  async function readPluginOperationalReportFeed() {
2283
1850
  const nowMs = Date.now();
2284
- const { getPluginOperationalReports } = await import("./agent-hooks-KR5BCWOK.js");
1851
+ const { getPluginOperationalReports } = await import("./agent-hooks-ICPIJAFY.js");
2285
1852
  return pluginOperationalReportFeedSchema.parse({
2286
1853
  source: "plugins",
2287
1854
  generatedAt: new Date(nowMs).toISOString(),