@sentry/junior 0.102.3 → 0.104.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 (86) hide show
  1. package/dist/{agent-hooks-I4I2DHSW.js → agent-hooks-EOFSY2PD.js} +5 -5
  2. package/dist/api/conversations/archive.d.ts +7 -0
  3. package/dist/api/conversations/detail.d.ts +7 -0
  4. package/dist/api/conversations/list.d.ts +109 -0
  5. package/dist/api/conversations/routes.d.ts +3 -0
  6. package/dist/api/conversations/schema.d.ts +88 -69
  7. package/dist/api/conversations/stats.d.ts +7 -0
  8. package/dist/api/conversations/subagent.d.ts +7 -0
  9. package/dist/api/http.d.ts +5 -0
  10. package/dist/api/locations/detail.d.ts +10 -2
  11. package/dist/api/locations/list.d.ts +7 -0
  12. package/dist/api/locations/routes.d.ts +3 -0
  13. package/dist/api/locations/schema.d.ts +4 -3
  14. package/dist/api/people/list.d.ts +7 -0
  15. package/dist/api/people/profile.d.ts +7 -0
  16. package/dist/api/people/routes.d.ts +3 -0
  17. package/dist/api/people/schema.d.ts +35 -33
  18. package/dist/api/people/shared.d.ts +4 -4
  19. package/dist/api/route.d.ts +7 -0
  20. package/dist/api/schema.js +11 -17
  21. package/dist/api.js +2184 -88
  22. package/dist/app.js +120 -162
  23. package/dist/chat/conversations/history.d.ts +6 -6
  24. package/dist/chat/conversations/store.d.ts +1 -0
  25. package/dist/chat/pi/messages.d.ts +2 -2
  26. package/dist/chat/plugins/agent-hooks.d.ts +2 -2
  27. package/dist/chat/resource-events/store.d.ts +2 -2
  28. package/dist/chat/sandbox/runtime-dependencies.d.ts +2 -0
  29. package/dist/chat/sandbox/sandbox.d.ts +1 -0
  30. package/dist/chat/services/provider-retry.d.ts +1 -2
  31. package/dist/chat/slack/tools/conversation-search.d.ts +2 -2
  32. package/dist/chat/state/session-log.d.ts +2 -2
  33. package/dist/chat/task-execution/store.d.ts +2 -2
  34. package/dist/chat/tools/search-tools.d.ts +2 -2
  35. package/dist/{chunk-ZSHL44IQ.js → chunk-4PDVOHXP.js} +1 -1
  36. package/dist/{chunk-3OABPOHR.js → chunk-7G4J3CR7.js} +11 -2
  37. package/dist/chunk-AIRE7Q2W.js +362 -0
  38. package/dist/{chunk-QZGVPPIJ.js → chunk-BCULHGZK.js} +24 -4
  39. package/dist/{chunk-IQ36I3DF.js → chunk-CCTCIISK.js} +1 -1
  40. package/dist/{chunk-SHBPSE7A.js → chunk-M3UAVLEN.js} +2 -3
  41. package/dist/{chunk-EMUZSROX.js → chunk-O7ILGCMJ.js} +78 -1
  42. package/dist/{chunk-EOB77KME.js → chunk-QDKRE3LS.js} +340 -9
  43. package/dist/{chunk-DTUSCR2Y.js → chunk-QVTVCJR4.js} +7 -7
  44. package/dist/{chunk-5K4N73TP.js → chunk-RMZ65YAA.js} +3 -3
  45. package/dist/{chunk-VSAFV2GI.js → chunk-RYDF4GOX.js} +3 -3
  46. package/dist/{chunk-ZIX4PNBI.js → chunk-TMWUGGSA.js} +37 -35
  47. package/dist/{chunk-3UK5DFKW.js → chunk-U26ZWZCN.js} +1 -1
  48. package/dist/{chunk-X2IPNCB5.js → chunk-VDHMFCDY.js} +65 -12
  49. package/dist/cli/chat.js +13 -14
  50. package/dist/cli/plugins.js +6 -6
  51. package/dist/cli/snapshot-warmup.js +7 -3
  52. package/dist/cli/upgrade.js +6 -7
  53. package/dist/db/schema/conversations.d.ts +17 -0
  54. package/dist/db/schema.d.ts +17 -0
  55. package/dist/{db-6QP6HY7U.js → db-PDMC67T3.js} +2 -2
  56. package/dist/{legacy-import-R3BMM2GH.js → legacy-import-G333RHJZ.js} +3 -3
  57. package/dist/reporting-schema.d.ts +4 -4
  58. package/dist/{runner-C2ZTIOUD.js → runner-6A7MQRUE.js} +9 -10
  59. package/migrations/0004_useful_magus.sql +1 -0
  60. package/migrations/meta/0004_snapshot.json +1041 -0
  61. package/migrations/meta/_journal.json +7 -0
  62. package/package.json +6 -6
  63. package/dist/api/conversations/list.query.d.ts +0 -103
  64. package/dist/chunk-2RNOB32R.js +0 -17
  65. package/dist/chunk-4XNQSJAX.js +0 -331
  66. package/dist/chunk-4YN2ZXKB.js +0 -66
  67. package/dist/chunk-B5QS4AVO.js +0 -319
  68. package/dist/chunk-F4CQEUTP.js +0 -77
  69. package/dist/chunk-HYDQULR2.js +0 -214
  70. package/dist/chunk-KFP3TZOS.js +0 -102
  71. package/dist/chunk-LJB2TLVT.js +0 -273
  72. package/dist/chunk-LVUKF5CE.js +0 -63
  73. package/dist/chunk-NSP6OGL2.js +0 -671
  74. package/dist/chunk-QNVHH5PU.js +0 -20
  75. package/dist/chunk-QOZOJNSE.js +0 -96
  76. package/dist/chunk-WPHCUGN7.js +0 -84
  77. package/dist/detail-OEIVZYXS.js +0 -68
  78. package/dist/detail-V37NTVBN.js +0 -29
  79. package/dist/list-AJ6RWBOG.js +0 -30
  80. package/dist/list-FWLIZHSW.js +0 -30
  81. package/dist/list-NTUT6A5M.js +0 -121
  82. package/dist/plugin-conversations-F3IBVNFX.js +0 -37
  83. package/dist/profile-3FRQP4HP.js +0 -212
  84. package/dist/reporting/plugin-conversations.d.ts +0 -3
  85. package/dist/stats-7UFY6FPE.js +0 -174
  86. package/dist/subagent-X3ZWJHR4.js +0 -49
@@ -1,671 +0,0 @@
1
- import {
2
- conversationSummaryFromStoredConversation
3
- } from "./chunk-LJB2TLVT.js";
4
- import {
5
- buildSentryConversationUrl,
6
- buildSentryTraceUrl
7
- } from "./chunk-LVUKF5CE.js";
8
- import {
9
- loadProjection,
10
- projectSteps
11
- } from "./chunk-B5QS4AVO.js";
12
- import {
13
- getAgentStepStore,
14
- getConversationMessageStore
15
- } from "./chunk-QZGVPPIJ.js";
16
- import {
17
- stripRuntimeTurnContext,
18
- unescapeXml,
19
- unwrapCurrentInstruction
20
- } from "./chunk-SHBPSE7A.js";
21
- import {
22
- canExposeConversationPayload
23
- } from "./chunk-RT5BUHR5.js";
24
- import {
25
- isRecord
26
- } from "./chunk-OB42YVAE.js";
27
-
28
- // src/api/conversations/detail-projection.ts
29
- import { isDeepStrictEqual } from "util";
30
-
31
- // src/api/conversations/transcript.ts
32
- var SAFE_METADATA_KEY_LIMIT = 20;
33
- var LEGACY_ADVISOR_TASK_OPEN = "<advisor-task>\n";
34
- var LEGACY_ADVISOR_TASK_CLOSE = "\n</advisor-task>";
35
- var LEGACY_EXECUTOR_CONTEXT_OPEN = "<executor-context>\n";
36
- var LEGACY_EXECUTOR_CONTEXT_CLOSE = "\n</executor-context>";
37
- function unwrapLegacyAdvisorTask(text) {
38
- if (!text.startsWith(LEGACY_ADVISOR_TASK_OPEN) || !text.endsWith(LEGACY_EXECUTOR_CONTEXT_CLOSE)) {
39
- return void 0;
40
- }
41
- const taskEnd = text.indexOf(
42
- LEGACY_ADVISOR_TASK_CLOSE,
43
- LEGACY_ADVISOR_TASK_OPEN.length
44
- );
45
- if (taskEnd < 0) return void 0;
46
- const contextStart = taskEnd + LEGACY_ADVISOR_TASK_CLOSE.length + 2;
47
- if (!text.startsWith(LEGACY_EXECUTOR_CONTEXT_OPEN, contextStart)) {
48
- return void 0;
49
- }
50
- const task = text.slice(LEGACY_ADVISOR_TASK_OPEN.length, taskEnd);
51
- const context = text.slice(
52
- contextStart + LEGACY_EXECUTOR_CONTEXT_OPEN.length,
53
- -LEGACY_EXECUTOR_CONTEXT_CLOSE.length
54
- );
55
- return `${unescapeXml(task)}
56
-
57
- Executor context:
58
- ${unescapeXml(context)}`;
59
- }
60
- function textPart(text) {
61
- return { type: "text", text };
62
- }
63
- function recordField(value, names) {
64
- for (const name of names) {
65
- if (value[name] !== void 0) {
66
- return value[name];
67
- }
68
- }
69
- return void 0;
70
- }
71
- function thinkingOutput(part) {
72
- const output = recordField(part, ["thinking", "text", "content", "output"]);
73
- return isRecord(output) ? recordField(output, ["thinking", "text", "content", "output"]) : output;
74
- }
75
- function isDisplayableTranscriptPart(part) {
76
- if (part.type !== "thinking") return true;
77
- return typeof part.output === "string" && part.output.trim().length > 0;
78
- }
79
- function normalizeTranscriptPart(part, options = {}) {
80
- const displayText = (text) => {
81
- if (options.unwrapCurrentTask) {
82
- const instruction = unwrapCurrentInstruction(text);
83
- if (instruction !== void 0) return instruction;
84
- }
85
- if (options.unwrapLegacyAdvisorTask) {
86
- return unwrapLegacyAdvisorTask(text) ?? text;
87
- }
88
- return text;
89
- };
90
- if (typeof part === "string") {
91
- return textPart(displayText(part));
92
- }
93
- if (!isRecord(part)) {
94
- return { type: "unknown", output: part };
95
- }
96
- const rawType = typeof part.type === "string" ? part.type : "unknown";
97
- if (rawType === "text") {
98
- const text = recordField(part, ["text", "content"]);
99
- return textPart(
100
- typeof text === "string" ? displayText(text) : JSON.stringify(text) ?? ""
101
- );
102
- }
103
- if (rawType === "toolCall") {
104
- return {
105
- type: "tool_call",
106
- ...typeof part.id === "string" ? { id: part.id } : {},
107
- ...typeof part.name === "string" ? { name: part.name } : {},
108
- input: recordField(part, ["arguments", "input", "args"])
109
- };
110
- }
111
- if (rawType === "toolResult") {
112
- return {
113
- type: "tool_result",
114
- ...typeof part.id === "string" ? { id: part.id } : {},
115
- ...typeof part.name === "string" ? { name: part.name } : {},
116
- output: recordField(part, ["result", "output", "content"])
117
- };
118
- }
119
- if (rawType === "thinking") {
120
- return {
121
- type: "thinking",
122
- output: thinkingOutput(part)
123
- };
124
- }
125
- return {
126
- type: "unknown",
127
- ...rawType !== "unknown" ? { sourceType: rawType } : {},
128
- output: part
129
- };
130
- }
131
- function normalizeToolResultMessage(record) {
132
- const content = record.content;
133
- let output = content;
134
- if (Array.isArray(content) && content.length === 1 && isRecord(content[0])) {
135
- const extracted = recordField(content[0], [
136
- "text",
137
- "content",
138
- "output",
139
- "result"
140
- ]);
141
- output = extracted !== void 0 ? extracted : content;
142
- }
143
- return {
144
- type: "tool_result",
145
- ...typeof record.toolCallId === "string" ? { id: record.toolCallId } : {},
146
- ...typeof record.name === "string" ? { name: record.name } : typeof record.toolName === "string" ? { name: record.toolName } : {},
147
- output
148
- };
149
- }
150
- function normalizeTranscriptMessage(message) {
151
- return normalizeMessage(message);
152
- }
153
- function normalizeSubagentTranscriptMessage(message, subagentKind) {
154
- return normalizeMessage(message, {
155
- unwrapLegacyAdvisorTask: subagentKind === "advisor"
156
- });
157
- }
158
- function normalizeMessage(message, options = {}) {
159
- const record = message;
160
- const content = record.content;
161
- const role = transcriptRole(record.role);
162
- return {
163
- role,
164
- ...typeof record.timestamp === "number" ? { timestamp: record.timestamp } : {},
165
- parts: role === "toolResult" ? [normalizeToolResultMessage(record)] : Array.isArray(content) ? content.map(
166
- (part) => normalizeTranscriptPart(part, {
167
- unwrapCurrentTask: role === "user",
168
- unwrapLegacyAdvisorTask: options.unwrapLegacyAdvisorTask && role === "user"
169
- })
170
- ).filter(isDisplayableTranscriptPart) : [
171
- normalizeTranscriptPart(content, {
172
- unwrapCurrentTask: role === "user",
173
- unwrapLegacyAdvisorTask: options.unwrapLegacyAdvisorTask && role === "user"
174
- })
175
- ]
176
- };
177
- }
178
- function transcriptRole(role) {
179
- return role === "assistant" || role === "system" || role === "tool" || role === "toolResult" || role === "user" ? role : "unknown";
180
- }
181
- function serializedChars(value) {
182
- if (typeof value === "string") return value.length;
183
- return JSON.stringify(value)?.length ?? 0;
184
- }
185
- function serializedBytes(value) {
186
- const serialized = typeof value === "string" ? value : JSON.stringify(value);
187
- return new TextEncoder().encode(serialized ?? "").byteLength;
188
- }
189
- function payloadType(value) {
190
- return Array.isArray(value) ? "array" : typeof value;
191
- }
192
- function payloadKeys(value) {
193
- if (!value || typeof value !== "object" || Array.isArray(value)) {
194
- return void 0;
195
- }
196
- const keys = Object.keys(value).slice(
197
- 0,
198
- SAFE_METADATA_KEY_LIMIT
199
- );
200
- return keys.length > 0 ? keys : void 0;
201
- }
202
- function redactedPayloadFields(prefix, value) {
203
- const keys = payloadKeys(value);
204
- return {
205
- [`${prefix}Type`]: payloadType(value),
206
- [`${prefix}SizeBytes`]: serializedBytes(value),
207
- [`${prefix}SizeChars`]: serializedChars(value),
208
- ...keys ? { [`${prefix}Keys`]: keys } : {}
209
- };
210
- }
211
- function redactTranscriptPart(part) {
212
- if (part.type === "text") {
213
- return {
214
- type: "text",
215
- redacted: true,
216
- bytes: serializedBytes(part.text ?? ""),
217
- chars: serializedChars(part.text ?? "")
218
- };
219
- }
220
- if (part.type === "thinking") {
221
- return {
222
- type: "thinking",
223
- redacted: true,
224
- ...redactedPayloadFields("output", part.output)
225
- };
226
- }
227
- if (part.type === "tool_call") {
228
- return {
229
- type: "tool_call",
230
- redacted: true,
231
- ...part.id ? { id: part.id } : {},
232
- ...part.name ? { name: part.name } : {},
233
- ...redactedPayloadFields("input", part.input)
234
- };
235
- }
236
- if (part.type === "tool_result") {
237
- return {
238
- type: "tool_result",
239
- redacted: true,
240
- ...part.id ? { id: part.id } : {},
241
- ...part.name ? { name: part.name } : {},
242
- ...redactedPayloadFields("output", part.output)
243
- };
244
- }
245
- return {
246
- type: "unknown",
247
- redacted: true,
248
- ...part.sourceType ? { sourceType: part.sourceType } : {},
249
- ...redactedPayloadFields("output", part.output ?? part.input ?? part.text)
250
- };
251
- }
252
- function redactTranscriptMessage(message) {
253
- return {
254
- role: message.role,
255
- ...typeof message.timestamp === "number" ? { timestamp: message.timestamp } : {},
256
- parts: message.parts.map(redactTranscriptPart)
257
- };
258
- }
259
- function isConversationMessageRole(role) {
260
- return role === "user" || role === "assistant";
261
- }
262
- function hasTextPart(message) {
263
- return message.parts.some((part) => {
264
- if (part.type !== "text") return false;
265
- if (part.redacted) return true;
266
- return typeof part.text === "string" && part.text.trim().length > 0;
267
- });
268
- }
269
- function isConversationMessage(message) {
270
- if (!isConversationMessageRole(message.role)) return false;
271
- if (message.role === "assistant") return hasTextPart(message);
272
- return message.parts.length > 0;
273
- }
274
- function countConversationMessages(transcript) {
275
- return transcript.filter(isConversationMessage).length;
276
- }
277
- function traceIdFromTranscript(transcript) {
278
- for (const message of transcript) {
279
- for (const part of message.parts) {
280
- const text = part.text ?? (typeof part.output === "string" ? part.output : typeof part.input === "string" ? part.input : void 0);
281
- const match = text?.match(
282
- /\btrace[_-]?id["']?\s*[:=]\s*["']?([a-f0-9]{16,32})\b/i
283
- );
284
- if (match?.[1]) {
285
- return match[1];
286
- }
287
- }
288
- }
289
- return void 0;
290
- }
291
- function subagentTranscriptReport(activity, options = {}) {
292
- return {
293
- type: "subagent",
294
- ...options.subagentConversationId ? { subagentConversationId: options.subagentConversationId } : {},
295
- createdAt: activity.createdAt,
296
- id: activity.id,
297
- ...activity.modelId ? { modelId: activity.modelId } : {},
298
- status: activity.status,
299
- ...options.subagentSentryConversationUrl ? { subagentSentryConversationUrl: options.subagentSentryConversationUrl } : {},
300
- subagentKind: activity.subagentKind,
301
- transcript: options.transcript ?? [],
302
- transcriptAvailable: Boolean(options.transcript?.length),
303
- ...activity.endedAt ? { endedAt: activity.endedAt } : {},
304
- ...activity.outcome ? { outcome: activity.outcome } : {},
305
- ...activity.parentToolCallId ? { parentToolCallId: activity.parentToolCallId } : {},
306
- ...activity.reasoningLevel ? { reasoningLevel: activity.reasoningLevel } : {},
307
- ...options.transcriptMessageCount !== void 0 ? { transcriptMessageCount: options.transcriptMessageCount } : {},
308
- ...options.transcriptRedacted ? { transcriptRedacted: options.transcriptRedacted } : {},
309
- ...options.transcriptRedactionReason ? { transcriptRedactionReason: options.transcriptRedactionReason } : {},
310
- ...options.transcriptExpired ? { transcriptExpired: options.transcriptExpired } : {},
311
- ...options.transcriptExpiredAt ? { transcriptExpiredAt: options.transcriptExpiredAt } : {},
312
- ...options.unavailableReason ? { unavailableReason: options.unavailableReason } : {}
313
- };
314
- }
315
-
316
- // src/api/conversations/activity.ts
317
- function toolResultStatuses(messages) {
318
- const statuses = /* @__PURE__ */ new Map();
319
- for (const message of messages) {
320
- const record = message;
321
- if (record.role !== "toolResult" || typeof record.toolCallId !== "string") {
322
- continue;
323
- }
324
- statuses.set(record.toolCallId, record.isError ? "error" : "completed");
325
- }
326
- return statuses;
327
- }
328
- function activityPayloadFields(args, canExposePayload) {
329
- if (args === void 0) {
330
- return {};
331
- }
332
- return canExposePayload ? { args } : { redacted: true, ...redactedPayloadFields("input", args) };
333
- }
334
- function buildConversationActivityFromSteps(args) {
335
- const toolStatuses = toolResultStatuses(args.messages);
336
- const subagentEnds = /* @__PURE__ */ new Map();
337
- const subagentsByToolCallId = /* @__PURE__ */ new Map();
338
- const orphanSubagents = [];
339
- for (const step of args.steps) {
340
- if (step.entry.type === "subagent_ended") {
341
- subagentEnds.set(
342
- step.entry.subagentInvocationId,
343
- step
344
- );
345
- }
346
- }
347
- for (const step of args.steps) {
348
- if (step.entry.type !== "subagent_started") {
349
- continue;
350
- }
351
- const start = step;
352
- const parentStatus = start.entry.parentToolCallId ? toolStatuses.get(start.entry.parentToolCallId) : void 0;
353
- const activity = subagentActivityFromSteps(
354
- start,
355
- subagentEnds.get(start.entry.subagentInvocationId),
356
- { canExposeTranscript: args.canExposePayload, parentStatus }
357
- );
358
- if (start.entry.parentToolCallId) {
359
- subagentsByToolCallId.set(start.entry.parentToolCallId, [
360
- ...subagentsByToolCallId.get(start.entry.parentToolCallId) ?? [],
361
- activity
362
- ]);
363
- continue;
364
- }
365
- orphanSubagents.push(activity);
366
- }
367
- const rows = [];
368
- for (const step of args.steps) {
369
- if (step.entry.type !== "tool_execution_started") {
370
- continue;
371
- }
372
- rows.push({
373
- type: "tool_execution",
374
- id: step.entry.toolCallId,
375
- toolCallId: step.entry.toolCallId,
376
- toolName: step.entry.toolName,
377
- createdAt: new Date(step.createdAtMs).toISOString(),
378
- status: toolStatuses.get(step.entry.toolCallId) ?? "running",
379
- subagents: subagentsByToolCallId.get(step.entry.toolCallId) ?? [],
380
- ...activityPayloadFields(step.entry.args, args.canExposePayload)
381
- });
382
- }
383
- return [...rows, ...orphanSubagents].sort(
384
- (left, right) => Date.parse(left.createdAt) - Date.parse(right.createdAt) || left.id.localeCompare(right.id)
385
- );
386
- }
387
- function subagentActivityFromSteps(start, end, options = {}) {
388
- return {
389
- type: "subagent",
390
- id: start.entry.subagentInvocationId,
391
- subagentKind: start.entry.subagentKind,
392
- ...start.entry.modelId ? { modelId: start.entry.modelId } : {},
393
- ...start.entry.parentToolCallId ? { parentToolCallId: start.entry.parentToolCallId } : {},
394
- ...start.entry.reasoningLevel ? { reasoningLevel: start.entry.reasoningLevel } : {},
395
- createdAt: new Date(start.createdAtMs).toISOString(),
396
- ...end ? {
397
- endedAt: new Date(end.createdAtMs).toISOString(),
398
- outcome: end.entry.outcome,
399
- status: end.entry.outcome,
400
- // Every subagent is a child conversation whose transcript loads on
401
- // demand; expose the affordance only when the parent is public.
402
- ...options.canExposeTranscript ? { transcriptAvailable: true } : {}
403
- } : { status: options.parentStatus ?? "running" }
404
- };
405
- }
406
-
407
- // src/api/conversations/detail-projection.ts
408
- var COMPACTION_SUMMARY_PREFIXES = [
409
- "Context compaction summary for future Junior turns:",
410
- "Context handoff summary for future Junior turns:"
411
- ];
412
- var MODEL_HANDOFF_SUMMARY_PREFIX = "Model handoff checkpoint. Continue the outstanding request now using this summary as the complete prior context:";
413
- function messageText(message) {
414
- return normalizeTranscriptMessage(message).parts.filter((part) => part.type === "text").map((part) => part.text ?? "").join("\n").trim();
415
- }
416
- function summaryAfterPrefix(message, prefixes) {
417
- const text = messageText(message);
418
- const prefix = prefixes.find((candidate) => text.startsWith(candidate));
419
- if (!prefix) return void 0;
420
- return text.slice(prefix.length).trim();
421
- }
422
- function summaryIndex(messages, provenance, prefixes) {
423
- for (let index = messages.length - 1; index >= 0; index -= 1) {
424
- if (provenance[index]?.authority === "context" && summaryAfterPrefix(messages[index], prefixes) !== void 0) {
425
- return index;
426
- }
427
- }
428
- return -1;
429
- }
430
- function matchingPrefix(left, right) {
431
- const limit = Math.min(left.length, right.length);
432
- for (let index = 0; index < limit; index += 1) {
433
- if (!isDeepStrictEqual(left[index], right[index])) return index;
434
- }
435
- return limit;
436
- }
437
- function historyContent(args) {
438
- const contextEvents = [];
439
- const messages = [];
440
- const epochs = /* @__PURE__ */ new Map();
441
- for (const step of args.steps) {
442
- const epoch = epochs.get(step.contextEpoch);
443
- if (epoch) epoch.push(step);
444
- else epochs.set(step.contextEpoch, [step]);
445
- }
446
- let previousModelId;
447
- let previousProjection = [];
448
- for (const steps of epochs.values()) {
449
- const marker = steps.find(
450
- (step) => step.entry.type === "context_epoch_started"
451
- );
452
- const projection = projectSteps(steps);
453
- const projected = [];
454
- const projectedProvenance = [];
455
- projection.messages.forEach((message, index) => {
456
- for (const retained of stripRuntimeTurnContext([message])) {
457
- projected.push(retained);
458
- projectedProvenance.push(projection.provenance[index]);
459
- }
460
- });
461
- const replacementSummaryIndex = marker?.entry.reason === "compaction" ? summaryIndex(
462
- projected,
463
- projectedProvenance,
464
- COMPACTION_SUMMARY_PREFIXES
465
- ) : marker?.entry.reason === "handoff" ? summaryIndex(projected, projectedProvenance, [
466
- MODEL_HANDOFF_SUMMARY_PREFIX
467
- ]) : -1;
468
- const summary = marker?.entry.reason === "compaction" && replacementSummaryIndex >= 0 ? summaryAfterPrefix(
469
- projected[replacementSummaryIndex],
470
- COMPACTION_SUMMARY_PREFIXES
471
- ) : void 0;
472
- const handoffMessage = marker?.entry.reason === "handoff" && replacementSummaryIndex >= 0 ? messageText(projected[replacementSummaryIndex]) || void 0 : void 0;
473
- if (marker?.entry.reason === "compaction") {
474
- contextEvents.push({
475
- type: "context_compacted",
476
- createdAt: new Date(marker.createdAtMs).toISOString(),
477
- ...marker.entry.modelId ? { modelId: marker.entry.modelId } : {},
478
- ...args.canExposePayload && summary ? { summary } : {},
479
- transcriptIndex: messages.length
480
- });
481
- } else if (marker?.entry.reason === "handoff") {
482
- contextEvents.push({
483
- type: "model_handoff",
484
- createdAt: new Date(marker.createdAtMs).toISOString(),
485
- ...previousModelId ? { fromModelId: previousModelId } : {},
486
- toModelId: marker.entry.modelId,
487
- ...args.canExposePayload && handoffMessage ? { message: handoffMessage } : {},
488
- transcriptIndex: messages.length
489
- });
490
- }
491
- if (marker?.entry.reason === "rollback") {
492
- messages.push(
493
- ...projected.slice(matchingPrefix(previousProjection, projected))
494
- );
495
- } else {
496
- const copiedMessageIndexes = /* @__PURE__ */ new Set();
497
- projected.forEach((message, index) => {
498
- if (index === replacementSummaryIndex) return;
499
- let copiedCompactionMessage = false;
500
- if (marker?.entry.reason === "compaction" && replacementSummaryIndex >= 0 && index < replacementSummaryIndex) {
501
- const copiedIndex = messages.findIndex(
502
- (candidate, candidateIndex) => !copiedMessageIndexes.has(candidateIndex) && isDeepStrictEqual(candidate, message)
503
- );
504
- copiedCompactionMessage = copiedIndex >= 0;
505
- if (copiedCompactionMessage) copiedMessageIndexes.add(copiedIndex);
506
- }
507
- if (!copiedCompactionMessage) messages.push(message);
508
- });
509
- }
510
- previousModelId = marker?.entry.modelId ?? previousModelId;
511
- previousProjection = projected;
512
- }
513
- return { contextEvents, messages };
514
- }
515
- async function conversationContent(args) {
516
- const steps = await args.stepStore.loadHistory(args.conversationId);
517
- const history = historyContent({
518
- canExposePayload: args.canExposePayload,
519
- steps
520
- });
521
- const messages = history.messages;
522
- const transcript = messages.length > 0 ? messages.map((message) => normalizeTranscriptMessage(message)) : (await args.messageStore.list(args.conversationId)).map(
523
- visibleMessageTranscript
524
- );
525
- return {
526
- activity: buildConversationActivityFromSteps({
527
- canExposePayload: args.canExposePayload,
528
- steps,
529
- messages
530
- }),
531
- contextEvents: history.contextEvents,
532
- transcript
533
- };
534
- }
535
- function visibleMessageTranscript(message) {
536
- return {
537
- role: message.role,
538
- timestamp: message.createdAtMs,
539
- parts: [{ type: "text", text: message.text }]
540
- };
541
- }
542
- async function buildConversationDetail(args) {
543
- const { conversation } = args;
544
- const conversationId = conversation.conversationId;
545
- const nowMs = Date.now();
546
- const stepStore = getAgentStepStore();
547
- const messageStore = getConversationMessageStore();
548
- const transcriptPurgedAtMs = conversation.transcriptPurgedAtMs;
549
- const transcriptExpiredAt = transcriptPurgedAtMs !== void 0 ? new Date(transcriptPurgedAtMs).toISOString() : void 0;
550
- const canExposeSqlContent = canExposeConversationPayload({
551
- conversationId,
552
- visibility: conversation.visibility
553
- });
554
- const currentContent = transcriptPurgedAtMs === void 0 ? await conversationContent({
555
- conversationId,
556
- messageStore,
557
- stepStore,
558
- canExposePayload: canExposeSqlContent
559
- }) : { activity: [], contextEvents: [], transcript: [] };
560
- const currentTranscript = currentContent.transcript;
561
- const traceId = canExposeSqlContent ? traceIdFromTranscript(currentTranscript) : void 0;
562
- const sentryTraceUrl = traceId ? buildSentryTraceUrl(traceId) : void 0;
563
- const sentryConversationUrl = buildSentryConversationUrl(conversationId);
564
- return {
565
- ...conversationSummaryFromStoredConversation({
566
- conversation,
567
- durationMs: args.durationMs,
568
- ...args.locationId ? { locationId: args.locationId } : {},
569
- usage: args.usage
570
- }),
571
- ...traceId ? { traceId } : {},
572
- ...sentryTraceUrl ? { sentryTraceUrl } : {},
573
- activity: currentContent.activity,
574
- contextEvents: currentContent.contextEvents,
575
- transcriptAvailable: transcriptExpiredAt === void 0 && canExposeSqlContent && currentTranscript.length > 0,
576
- ...currentTranscript.length > 0 ? {
577
- transcriptMessageCount: countConversationMessages(currentTranscript)
578
- } : {},
579
- ...!canExposeSqlContent && transcriptExpiredAt === void 0 ? {
580
- transcriptMetadata: currentTranscript.map(redactTranscriptMessage),
581
- transcriptRedacted: true,
582
- transcriptRedactionReason: "non_public_conversation"
583
- } : {},
584
- ...transcriptExpiredAt !== void 0 ? {
585
- transcriptExpired: true,
586
- transcriptExpiredAt,
587
- transcriptMetadata: []
588
- } : {},
589
- transcript: transcriptExpiredAt === void 0 && canExposeSqlContent ? currentTranscript : [],
590
- generatedAt: new Date(nowMs).toISOString(),
591
- ...sentryConversationUrl ? { sentryConversationUrl } : {}
592
- };
593
- }
594
- async function buildConversationSubagent(conversation, subagentId) {
595
- const conversationId = conversation.conversationId;
596
- const stepStore = getAgentStepStore();
597
- const parentSteps = await stepStore.loadHistory(conversationId);
598
- if (conversation?.transcriptPurgedAtMs !== void 0) {
599
- return {
600
- type: "subagent",
601
- createdAt: (/* @__PURE__ */ new Date(0)).toISOString(),
602
- id: subagentId,
603
- status: "completed",
604
- subagentKind: "unknown",
605
- transcript: [],
606
- transcriptAvailable: false,
607
- transcriptExpired: true,
608
- transcriptExpiredAt: new Date(
609
- conversation.transcriptPurgedAtMs
610
- ).toISOString()
611
- };
612
- }
613
- const start = parentSteps.find(
614
- (step) => step.entry.type === "subagent_started" && step.entry.subagentInvocationId === subagentId
615
- );
616
- if (!start) {
617
- return {
618
- type: "subagent",
619
- createdAt: (/* @__PURE__ */ new Date(0)).toISOString(),
620
- id: subagentId,
621
- status: "error",
622
- subagentKind: "unknown",
623
- transcript: [],
624
- transcriptAvailable: false,
625
- unavailableReason: "not_found"
626
- };
627
- }
628
- const end = parentSteps.find(
629
- (step) => step.entry.type === "subagent_ended" && step.entry.subagentInvocationId === subagentId
630
- );
631
- const childConversationId = start.entry.childConversationId;
632
- const activity = subagentActivityFromSteps(start, end);
633
- const subagentSentryConversationUrl = buildSentryConversationUrl(childConversationId);
634
- const conversationFields = {
635
- subagentConversationId: childConversationId,
636
- ...subagentSentryConversationUrl ? { subagentSentryConversationUrl } : {}
637
- };
638
- const canExposeTranscript = canExposeConversationPayload({
639
- conversationId,
640
- visibility: conversation?.visibility
641
- });
642
- if (!canExposeTranscript) {
643
- return subagentTranscriptReport(activity, {
644
- ...conversationFields,
645
- transcriptRedacted: true,
646
- transcriptRedactionReason: "non_public_conversation"
647
- });
648
- }
649
- const childMessages = await loadProjection({
650
- conversationId: childConversationId
651
- });
652
- if (childMessages.length === 0) {
653
- return subagentTranscriptReport(activity, {
654
- ...conversationFields,
655
- unavailableReason: "missing_transcript_ref"
656
- });
657
- }
658
- const transcript = childMessages.map(
659
- (message) => normalizeSubagentTranscriptMessage(message, activity.subagentKind)
660
- );
661
- return subagentTranscriptReport(activity, {
662
- ...conversationFields,
663
- transcript,
664
- transcriptMessageCount: countConversationMessages(transcript)
665
- });
666
- }
667
-
668
- export {
669
- buildConversationDetail,
670
- buildConversationSubagent
671
- };
@@ -1,20 +0,0 @@
1
- import {
2
- healthReportSchema
3
- } from "./chunk-CEA3A3UA.js";
4
-
5
- // src/handlers/health.ts
6
- function readHealthReport() {
7
- return healthReportSchema.parse({
8
- status: "ok",
9
- service: "junior",
10
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
11
- });
12
- }
13
- function GET() {
14
- return Response.json(readHealthReport());
15
- }
16
-
17
- export {
18
- readHealthReport,
19
- GET
20
- };