@sentry/junior 0.103.0 → 0.104.1
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.
- package/dist/{agent-hooks-NHIXBJW3.js → agent-hooks-EOFSY2PD.js} +3 -3
- package/dist/api/conversations/archive.d.ts +7 -0
- package/dist/api/conversations/detail.d.ts +7 -0
- package/dist/api/conversations/list.d.ts +109 -0
- package/dist/api/conversations/routes.d.ts +3 -0
- package/dist/api/conversations/schema.d.ts +72 -69
- package/dist/api/conversations/stats.d.ts +7 -0
- package/dist/api/conversations/subagent.d.ts +7 -0
- package/dist/api/http.d.ts +5 -0
- package/dist/api/locations/detail.d.ts +10 -2
- package/dist/api/locations/list.d.ts +7 -0
- package/dist/api/locations/routes.d.ts +3 -0
- package/dist/api/locations/schema.d.ts +4 -3
- package/dist/api/people/list.d.ts +7 -0
- package/dist/api/people/profile.d.ts +7 -0
- package/dist/api/people/routes.d.ts +3 -0
- package/dist/api/people/schema.d.ts +35 -33
- package/dist/api/people/shared.d.ts +3 -3
- package/dist/api/route.d.ts +7 -0
- package/dist/api/schema.js +11 -17
- package/dist/api.js +2184 -88
- package/dist/app.js +107 -101
- package/dist/chat/conversations/history.d.ts +6 -6
- package/dist/chat/conversations/store.d.ts +1 -0
- package/dist/chat/pi/messages.d.ts +2 -2
- package/dist/chat/plugins/agent-hooks.d.ts +2 -2
- package/dist/chat/resource-events/store.d.ts +2 -2
- package/dist/chat/slack/tools/conversation-search.d.ts +2 -2
- package/dist/chat/state/session-log.d.ts +2 -2
- package/dist/chat/task-execution/store.d.ts +2 -2
- package/dist/chat/tools/search-tools.d.ts +2 -2
- package/dist/chunk-AIRE7Q2W.js +362 -0
- package/dist/{chunk-HOBDQQJY.js → chunk-BCULHGZK.js} +23 -3
- package/dist/{chunk-DEQZ23O3.js → chunk-O7ILGCMJ.js} +77 -0
- package/dist/{chunk-C4BT2P2K.js → chunk-QDKRE3LS.js} +339 -8
- package/dist/{chunk-GY5ZRYPH.js → chunk-QVTVCJR4.js} +5 -5
- package/dist/{chunk-JXQWOCBE.js → chunk-RMZ65YAA.js} +2 -2
- package/dist/{chunk-E2VS47AZ.js → chunk-RYDF4GOX.js} +2 -2
- package/dist/{chunk-OE453VRG.js → chunk-TMWUGGSA.js} +26 -28
- package/dist/{chunk-JPXLAJUU.js → chunk-VDHMFCDY.js} +9 -10
- package/dist/cli/chat.js +10 -11
- package/dist/cli/plugins.js +4 -4
- package/dist/cli/upgrade.js +3 -4
- package/dist/db/schema/conversations.d.ts +17 -0
- package/dist/db/schema.d.ts +17 -0
- package/dist/{db-I343BSOM.js → db-PDMC67T3.js} +1 -1
- package/dist/{legacy-import-M7VBOQTK.js → legacy-import-G333RHJZ.js} +2 -2
- package/dist/reporting-schema.d.ts +4 -4
- package/dist/{runner-IEE5G4NV.js → runner-6A7MQRUE.js} +7 -8
- package/migrations/0004_useful_magus.sql +1 -0
- package/migrations/meta/0004_snapshot.json +1041 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +6 -6
- package/dist/api/conversations/list.query.d.ts +0 -103
- package/dist/chunk-2RNOB32R.js +0 -17
- package/dist/chunk-6FPTHPXF.js +0 -77
- package/dist/chunk-6LBNXC4F.js +0 -66
- package/dist/chunk-7LLRS2OK.js +0 -215
- package/dist/chunk-B43K4C5K.js +0 -102
- package/dist/chunk-BQCPAIAB.js +0 -319
- package/dist/chunk-FW7DVHTL.js +0 -673
- package/dist/chunk-GCGRQJR5.js +0 -84
- package/dist/chunk-HRDWLE7Q.js +0 -273
- package/dist/chunk-LVUKF5CE.js +0 -63
- package/dist/chunk-QNVHH5PU.js +0 -20
- package/dist/chunk-QOZOJNSE.js +0 -96
- package/dist/chunk-VKFOVMZL.js +0 -331
- package/dist/detail-ENVV4HIY.js +0 -68
- package/dist/detail-UIOKVIET.js +0 -29
- package/dist/list-WR5U6JVM.js +0 -30
- package/dist/list-XZ4HKQ4R.js +0 -121
- package/dist/list-ZOUSMSEH.js +0 -30
- package/dist/plugin-conversations-DTUP4RH6.js +0 -37
- package/dist/profile-UO2N3XXG.js +0 -212
- package/dist/reporting/plugin-conversations.d.ts +0 -3
- package/dist/stats-NZIET4LT.js +0 -174
- package/dist/subagent-DY6XKTJ5.js +0 -49
package/dist/chunk-FW7DVHTL.js
DELETED
|
@@ -1,673 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
conversationSummaryFromStoredConversation
|
|
3
|
-
} from "./chunk-HRDWLE7Q.js";
|
|
4
|
-
import {
|
|
5
|
-
buildSentryConversationUrl,
|
|
6
|
-
buildSentryTraceUrl
|
|
7
|
-
} from "./chunk-LVUKF5CE.js";
|
|
8
|
-
import {
|
|
9
|
-
loadProjection,
|
|
10
|
-
projectSteps
|
|
11
|
-
} from "./chunk-BQCPAIAB.js";
|
|
12
|
-
import {
|
|
13
|
-
getAgentStepStore,
|
|
14
|
-
getConversationMessageStore
|
|
15
|
-
} from "./chunk-HOBDQQJY.js";
|
|
16
|
-
import {
|
|
17
|
-
stripRuntimeTurnContext,
|
|
18
|
-
unescapeXml,
|
|
19
|
-
unwrapCurrentInstruction
|
|
20
|
-
} from "./chunk-M3UAVLEN.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
|
-
...role === "assistant" && (record.stopReason === "error" || record.stopReason === "aborted") ? { outcome: record.stopReason } : {},
|
|
165
|
-
...typeof record.timestamp === "number" ? { timestamp: record.timestamp } : {},
|
|
166
|
-
parts: role === "toolResult" ? [normalizeToolResultMessage(record)] : Array.isArray(content) ? content.map(
|
|
167
|
-
(part) => normalizeTranscriptPart(part, {
|
|
168
|
-
unwrapCurrentTask: role === "user",
|
|
169
|
-
unwrapLegacyAdvisorTask: options.unwrapLegacyAdvisorTask && role === "user"
|
|
170
|
-
})
|
|
171
|
-
).filter(isDisplayableTranscriptPart) : [
|
|
172
|
-
normalizeTranscriptPart(content, {
|
|
173
|
-
unwrapCurrentTask: role === "user",
|
|
174
|
-
unwrapLegacyAdvisorTask: options.unwrapLegacyAdvisorTask && role === "user"
|
|
175
|
-
})
|
|
176
|
-
]
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
function transcriptRole(role) {
|
|
180
|
-
return role === "assistant" || role === "system" || role === "tool" || role === "toolResult" || role === "user" ? role : "unknown";
|
|
181
|
-
}
|
|
182
|
-
function serializedChars(value) {
|
|
183
|
-
if (typeof value === "string") return value.length;
|
|
184
|
-
return JSON.stringify(value)?.length ?? 0;
|
|
185
|
-
}
|
|
186
|
-
function serializedBytes(value) {
|
|
187
|
-
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
188
|
-
return new TextEncoder().encode(serialized ?? "").byteLength;
|
|
189
|
-
}
|
|
190
|
-
function payloadType(value) {
|
|
191
|
-
return Array.isArray(value) ? "array" : typeof value;
|
|
192
|
-
}
|
|
193
|
-
function payloadKeys(value) {
|
|
194
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
195
|
-
return void 0;
|
|
196
|
-
}
|
|
197
|
-
const keys = Object.keys(value).slice(
|
|
198
|
-
0,
|
|
199
|
-
SAFE_METADATA_KEY_LIMIT
|
|
200
|
-
);
|
|
201
|
-
return keys.length > 0 ? keys : void 0;
|
|
202
|
-
}
|
|
203
|
-
function redactedPayloadFields(prefix, value) {
|
|
204
|
-
const keys = payloadKeys(value);
|
|
205
|
-
return {
|
|
206
|
-
[`${prefix}Type`]: payloadType(value),
|
|
207
|
-
[`${prefix}SizeBytes`]: serializedBytes(value),
|
|
208
|
-
[`${prefix}SizeChars`]: serializedChars(value),
|
|
209
|
-
...keys ? { [`${prefix}Keys`]: keys } : {}
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
function redactTranscriptPart(part) {
|
|
213
|
-
if (part.type === "text") {
|
|
214
|
-
return {
|
|
215
|
-
type: "text",
|
|
216
|
-
redacted: true,
|
|
217
|
-
bytes: serializedBytes(part.text ?? ""),
|
|
218
|
-
chars: serializedChars(part.text ?? "")
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
if (part.type === "thinking") {
|
|
222
|
-
return {
|
|
223
|
-
type: "thinking",
|
|
224
|
-
redacted: true,
|
|
225
|
-
...redactedPayloadFields("output", part.output)
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
if (part.type === "tool_call") {
|
|
229
|
-
return {
|
|
230
|
-
type: "tool_call",
|
|
231
|
-
redacted: true,
|
|
232
|
-
...part.id ? { id: part.id } : {},
|
|
233
|
-
...part.name ? { name: part.name } : {},
|
|
234
|
-
...redactedPayloadFields("input", part.input)
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
if (part.type === "tool_result") {
|
|
238
|
-
return {
|
|
239
|
-
type: "tool_result",
|
|
240
|
-
redacted: true,
|
|
241
|
-
...part.id ? { id: part.id } : {},
|
|
242
|
-
...part.name ? { name: part.name } : {},
|
|
243
|
-
...redactedPayloadFields("output", part.output)
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
return {
|
|
247
|
-
type: "unknown",
|
|
248
|
-
redacted: true,
|
|
249
|
-
...part.sourceType ? { sourceType: part.sourceType } : {},
|
|
250
|
-
...redactedPayloadFields("output", part.output ?? part.input ?? part.text)
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
function redactTranscriptMessage(message) {
|
|
254
|
-
return {
|
|
255
|
-
role: message.role,
|
|
256
|
-
...message.outcome ? { outcome: message.outcome } : {},
|
|
257
|
-
...typeof message.timestamp === "number" ? { timestamp: message.timestamp } : {},
|
|
258
|
-
parts: message.parts.map(redactTranscriptPart)
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
function isConversationMessageRole(role) {
|
|
262
|
-
return role === "user" || role === "assistant";
|
|
263
|
-
}
|
|
264
|
-
function hasTextPart(message) {
|
|
265
|
-
return message.parts.some((part) => {
|
|
266
|
-
if (part.type !== "text") return false;
|
|
267
|
-
if (part.redacted) return true;
|
|
268
|
-
return typeof part.text === "string" && part.text.trim().length > 0;
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
function isConversationMessage(message) {
|
|
272
|
-
if (!isConversationMessageRole(message.role)) return false;
|
|
273
|
-
if (message.role === "assistant") return hasTextPart(message);
|
|
274
|
-
return message.parts.length > 0;
|
|
275
|
-
}
|
|
276
|
-
function countConversationMessages(transcript) {
|
|
277
|
-
return transcript.filter(isConversationMessage).length;
|
|
278
|
-
}
|
|
279
|
-
function traceIdFromTranscript(transcript) {
|
|
280
|
-
for (const message of transcript) {
|
|
281
|
-
for (const part of message.parts) {
|
|
282
|
-
const text = part.text ?? (typeof part.output === "string" ? part.output : typeof part.input === "string" ? part.input : void 0);
|
|
283
|
-
const match = text?.match(
|
|
284
|
-
/\btrace[_-]?id["']?\s*[:=]\s*["']?([a-f0-9]{16,32})\b/i
|
|
285
|
-
);
|
|
286
|
-
if (match?.[1]) {
|
|
287
|
-
return match[1];
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
return void 0;
|
|
292
|
-
}
|
|
293
|
-
function subagentTranscriptReport(activity, options = {}) {
|
|
294
|
-
return {
|
|
295
|
-
type: "subagent",
|
|
296
|
-
...options.subagentConversationId ? { subagentConversationId: options.subagentConversationId } : {},
|
|
297
|
-
createdAt: activity.createdAt,
|
|
298
|
-
id: activity.id,
|
|
299
|
-
...activity.modelId ? { modelId: activity.modelId } : {},
|
|
300
|
-
status: activity.status,
|
|
301
|
-
...options.subagentSentryConversationUrl ? { subagentSentryConversationUrl: options.subagentSentryConversationUrl } : {},
|
|
302
|
-
subagentKind: activity.subagentKind,
|
|
303
|
-
transcript: options.transcript ?? [],
|
|
304
|
-
transcriptAvailable: Boolean(options.transcript?.length),
|
|
305
|
-
...activity.endedAt ? { endedAt: activity.endedAt } : {},
|
|
306
|
-
...activity.outcome ? { outcome: activity.outcome } : {},
|
|
307
|
-
...activity.parentToolCallId ? { parentToolCallId: activity.parentToolCallId } : {},
|
|
308
|
-
...activity.reasoningLevel ? { reasoningLevel: activity.reasoningLevel } : {},
|
|
309
|
-
...options.transcriptMessageCount !== void 0 ? { transcriptMessageCount: options.transcriptMessageCount } : {},
|
|
310
|
-
...options.transcriptRedacted ? { transcriptRedacted: options.transcriptRedacted } : {},
|
|
311
|
-
...options.transcriptRedactionReason ? { transcriptRedactionReason: options.transcriptRedactionReason } : {},
|
|
312
|
-
...options.transcriptExpired ? { transcriptExpired: options.transcriptExpired } : {},
|
|
313
|
-
...options.transcriptExpiredAt ? { transcriptExpiredAt: options.transcriptExpiredAt } : {},
|
|
314
|
-
...options.unavailableReason ? { unavailableReason: options.unavailableReason } : {}
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// src/api/conversations/activity.ts
|
|
319
|
-
function toolResultStatuses(messages) {
|
|
320
|
-
const statuses = /* @__PURE__ */ new Map();
|
|
321
|
-
for (const message of messages) {
|
|
322
|
-
const record = message;
|
|
323
|
-
if (record.role !== "toolResult" || typeof record.toolCallId !== "string") {
|
|
324
|
-
continue;
|
|
325
|
-
}
|
|
326
|
-
statuses.set(record.toolCallId, record.isError ? "error" : "completed");
|
|
327
|
-
}
|
|
328
|
-
return statuses;
|
|
329
|
-
}
|
|
330
|
-
function activityPayloadFields(args, canExposePayload) {
|
|
331
|
-
if (args === void 0) {
|
|
332
|
-
return {};
|
|
333
|
-
}
|
|
334
|
-
return canExposePayload ? { args } : { redacted: true, ...redactedPayloadFields("input", args) };
|
|
335
|
-
}
|
|
336
|
-
function buildConversationActivityFromSteps(args) {
|
|
337
|
-
const toolStatuses = toolResultStatuses(args.messages);
|
|
338
|
-
const subagentEnds = /* @__PURE__ */ new Map();
|
|
339
|
-
const subagentsByToolCallId = /* @__PURE__ */ new Map();
|
|
340
|
-
const orphanSubagents = [];
|
|
341
|
-
for (const step of args.steps) {
|
|
342
|
-
if (step.entry.type === "subagent_ended") {
|
|
343
|
-
subagentEnds.set(
|
|
344
|
-
step.entry.subagentInvocationId,
|
|
345
|
-
step
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
for (const step of args.steps) {
|
|
350
|
-
if (step.entry.type !== "subagent_started") {
|
|
351
|
-
continue;
|
|
352
|
-
}
|
|
353
|
-
const start = step;
|
|
354
|
-
const parentStatus = start.entry.parentToolCallId ? toolStatuses.get(start.entry.parentToolCallId) : void 0;
|
|
355
|
-
const activity = subagentActivityFromSteps(
|
|
356
|
-
start,
|
|
357
|
-
subagentEnds.get(start.entry.subagentInvocationId),
|
|
358
|
-
{ canExposeTranscript: args.canExposePayload, parentStatus }
|
|
359
|
-
);
|
|
360
|
-
if (start.entry.parentToolCallId) {
|
|
361
|
-
subagentsByToolCallId.set(start.entry.parentToolCallId, [
|
|
362
|
-
...subagentsByToolCallId.get(start.entry.parentToolCallId) ?? [],
|
|
363
|
-
activity
|
|
364
|
-
]);
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
orphanSubagents.push(activity);
|
|
368
|
-
}
|
|
369
|
-
const rows = [];
|
|
370
|
-
for (const step of args.steps) {
|
|
371
|
-
if (step.entry.type !== "tool_execution_started") {
|
|
372
|
-
continue;
|
|
373
|
-
}
|
|
374
|
-
rows.push({
|
|
375
|
-
type: "tool_execution",
|
|
376
|
-
id: step.entry.toolCallId,
|
|
377
|
-
toolCallId: step.entry.toolCallId,
|
|
378
|
-
toolName: step.entry.toolName,
|
|
379
|
-
createdAt: new Date(step.createdAtMs).toISOString(),
|
|
380
|
-
status: toolStatuses.get(step.entry.toolCallId) ?? "running",
|
|
381
|
-
subagents: subagentsByToolCallId.get(step.entry.toolCallId) ?? [],
|
|
382
|
-
...activityPayloadFields(step.entry.args, args.canExposePayload)
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
return [...rows, ...orphanSubagents].sort(
|
|
386
|
-
(left, right) => Date.parse(left.createdAt) - Date.parse(right.createdAt) || left.id.localeCompare(right.id)
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
function subagentActivityFromSteps(start, end, options = {}) {
|
|
390
|
-
return {
|
|
391
|
-
type: "subagent",
|
|
392
|
-
id: start.entry.subagentInvocationId,
|
|
393
|
-
subagentKind: start.entry.subagentKind,
|
|
394
|
-
...start.entry.modelId ? { modelId: start.entry.modelId } : {},
|
|
395
|
-
...start.entry.parentToolCallId ? { parentToolCallId: start.entry.parentToolCallId } : {},
|
|
396
|
-
...start.entry.reasoningLevel ? { reasoningLevel: start.entry.reasoningLevel } : {},
|
|
397
|
-
createdAt: new Date(start.createdAtMs).toISOString(),
|
|
398
|
-
...end ? {
|
|
399
|
-
endedAt: new Date(end.createdAtMs).toISOString(),
|
|
400
|
-
outcome: end.entry.outcome,
|
|
401
|
-
status: end.entry.outcome,
|
|
402
|
-
// Every subagent is a child conversation whose transcript loads on
|
|
403
|
-
// demand; expose the affordance only when the parent is public.
|
|
404
|
-
...options.canExposeTranscript ? { transcriptAvailable: true } : {}
|
|
405
|
-
} : { status: options.parentStatus ?? "running" }
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
// src/api/conversations/detail-projection.ts
|
|
410
|
-
var COMPACTION_SUMMARY_PREFIXES = [
|
|
411
|
-
"Context compaction summary for future Junior turns:",
|
|
412
|
-
"Context handoff summary for future Junior turns:"
|
|
413
|
-
];
|
|
414
|
-
var MODEL_HANDOFF_SUMMARY_PREFIX = "Model handoff checkpoint. Continue the outstanding request now using this summary as the complete prior context:";
|
|
415
|
-
function messageText(message) {
|
|
416
|
-
return normalizeTranscriptMessage(message).parts.filter((part) => part.type === "text").map((part) => part.text ?? "").join("\n").trim();
|
|
417
|
-
}
|
|
418
|
-
function summaryAfterPrefix(message, prefixes) {
|
|
419
|
-
const text = messageText(message);
|
|
420
|
-
const prefix = prefixes.find((candidate) => text.startsWith(candidate));
|
|
421
|
-
if (!prefix) return void 0;
|
|
422
|
-
return text.slice(prefix.length).trim();
|
|
423
|
-
}
|
|
424
|
-
function summaryIndex(messages, provenance, prefixes) {
|
|
425
|
-
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
426
|
-
if (provenance[index]?.authority === "context" && summaryAfterPrefix(messages[index], prefixes) !== void 0) {
|
|
427
|
-
return index;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
return -1;
|
|
431
|
-
}
|
|
432
|
-
function matchingPrefix(left, right) {
|
|
433
|
-
const limit = Math.min(left.length, right.length);
|
|
434
|
-
for (let index = 0; index < limit; index += 1) {
|
|
435
|
-
if (!isDeepStrictEqual(left[index], right[index])) return index;
|
|
436
|
-
}
|
|
437
|
-
return limit;
|
|
438
|
-
}
|
|
439
|
-
function historyContent(args) {
|
|
440
|
-
const contextEvents = [];
|
|
441
|
-
const messages = [];
|
|
442
|
-
const epochs = /* @__PURE__ */ new Map();
|
|
443
|
-
for (const step of args.steps) {
|
|
444
|
-
const epoch = epochs.get(step.contextEpoch);
|
|
445
|
-
if (epoch) epoch.push(step);
|
|
446
|
-
else epochs.set(step.contextEpoch, [step]);
|
|
447
|
-
}
|
|
448
|
-
let previousModelId;
|
|
449
|
-
let previousProjection = [];
|
|
450
|
-
for (const steps of epochs.values()) {
|
|
451
|
-
const marker = steps.find(
|
|
452
|
-
(step) => step.entry.type === "context_epoch_started"
|
|
453
|
-
);
|
|
454
|
-
const projection = projectSteps(steps);
|
|
455
|
-
const projected = [];
|
|
456
|
-
const projectedProvenance = [];
|
|
457
|
-
projection.messages.forEach((message, index) => {
|
|
458
|
-
for (const retained of stripRuntimeTurnContext([message])) {
|
|
459
|
-
projected.push(retained);
|
|
460
|
-
projectedProvenance.push(projection.provenance[index]);
|
|
461
|
-
}
|
|
462
|
-
});
|
|
463
|
-
const replacementSummaryIndex = marker?.entry.reason === "compaction" ? summaryIndex(
|
|
464
|
-
projected,
|
|
465
|
-
projectedProvenance,
|
|
466
|
-
COMPACTION_SUMMARY_PREFIXES
|
|
467
|
-
) : marker?.entry.reason === "handoff" ? summaryIndex(projected, projectedProvenance, [
|
|
468
|
-
MODEL_HANDOFF_SUMMARY_PREFIX
|
|
469
|
-
]) : -1;
|
|
470
|
-
const summary = marker?.entry.reason === "compaction" && replacementSummaryIndex >= 0 ? summaryAfterPrefix(
|
|
471
|
-
projected[replacementSummaryIndex],
|
|
472
|
-
COMPACTION_SUMMARY_PREFIXES
|
|
473
|
-
) : void 0;
|
|
474
|
-
const handoffMessage = marker?.entry.reason === "handoff" && replacementSummaryIndex >= 0 ? messageText(projected[replacementSummaryIndex]) || void 0 : void 0;
|
|
475
|
-
if (marker?.entry.reason === "compaction") {
|
|
476
|
-
contextEvents.push({
|
|
477
|
-
type: "context_compacted",
|
|
478
|
-
createdAt: new Date(marker.createdAtMs).toISOString(),
|
|
479
|
-
...marker.entry.modelId ? { modelId: marker.entry.modelId } : {},
|
|
480
|
-
...args.canExposePayload && summary ? { summary } : {},
|
|
481
|
-
transcriptIndex: messages.length
|
|
482
|
-
});
|
|
483
|
-
} else if (marker?.entry.reason === "handoff") {
|
|
484
|
-
contextEvents.push({
|
|
485
|
-
type: "model_handoff",
|
|
486
|
-
createdAt: new Date(marker.createdAtMs).toISOString(),
|
|
487
|
-
...previousModelId ? { fromModelId: previousModelId } : {},
|
|
488
|
-
toModelId: marker.entry.modelId,
|
|
489
|
-
...args.canExposePayload && handoffMessage ? { message: handoffMessage } : {},
|
|
490
|
-
transcriptIndex: messages.length
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
if (marker?.entry.reason === "rollback") {
|
|
494
|
-
messages.push(
|
|
495
|
-
...projected.slice(matchingPrefix(previousProjection, projected))
|
|
496
|
-
);
|
|
497
|
-
} else {
|
|
498
|
-
const copiedMessageIndexes = /* @__PURE__ */ new Set();
|
|
499
|
-
projected.forEach((message, index) => {
|
|
500
|
-
if (index === replacementSummaryIndex) return;
|
|
501
|
-
let copiedCompactionMessage = false;
|
|
502
|
-
if (marker?.entry.reason === "compaction" && replacementSummaryIndex >= 0 && index < replacementSummaryIndex) {
|
|
503
|
-
const copiedIndex = messages.findIndex(
|
|
504
|
-
(candidate, candidateIndex) => !copiedMessageIndexes.has(candidateIndex) && isDeepStrictEqual(candidate, message)
|
|
505
|
-
);
|
|
506
|
-
copiedCompactionMessage = copiedIndex >= 0;
|
|
507
|
-
if (copiedCompactionMessage) copiedMessageIndexes.add(copiedIndex);
|
|
508
|
-
}
|
|
509
|
-
if (!copiedCompactionMessage) messages.push(message);
|
|
510
|
-
});
|
|
511
|
-
}
|
|
512
|
-
previousModelId = marker?.entry.modelId ?? previousModelId;
|
|
513
|
-
previousProjection = projected;
|
|
514
|
-
}
|
|
515
|
-
return { contextEvents, messages };
|
|
516
|
-
}
|
|
517
|
-
async function conversationContent(args) {
|
|
518
|
-
const steps = await args.stepStore.loadHistory(args.conversationId);
|
|
519
|
-
const history = historyContent({
|
|
520
|
-
canExposePayload: args.canExposePayload,
|
|
521
|
-
steps
|
|
522
|
-
});
|
|
523
|
-
const messages = history.messages;
|
|
524
|
-
const transcript = messages.length > 0 ? messages.map((message) => normalizeTranscriptMessage(message)) : (await args.messageStore.list(args.conversationId)).map(
|
|
525
|
-
visibleMessageTranscript
|
|
526
|
-
);
|
|
527
|
-
return {
|
|
528
|
-
activity: buildConversationActivityFromSteps({
|
|
529
|
-
canExposePayload: args.canExposePayload,
|
|
530
|
-
steps,
|
|
531
|
-
messages
|
|
532
|
-
}),
|
|
533
|
-
contextEvents: history.contextEvents,
|
|
534
|
-
transcript
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
function visibleMessageTranscript(message) {
|
|
538
|
-
return {
|
|
539
|
-
role: message.role,
|
|
540
|
-
timestamp: message.createdAtMs,
|
|
541
|
-
parts: [{ type: "text", text: message.text }]
|
|
542
|
-
};
|
|
543
|
-
}
|
|
544
|
-
async function buildConversationDetail(args) {
|
|
545
|
-
const { conversation } = args;
|
|
546
|
-
const conversationId = conversation.conversationId;
|
|
547
|
-
const nowMs = Date.now();
|
|
548
|
-
const stepStore = getAgentStepStore();
|
|
549
|
-
const messageStore = getConversationMessageStore();
|
|
550
|
-
const transcriptPurgedAtMs = conversation.transcriptPurgedAtMs;
|
|
551
|
-
const transcriptExpiredAt = transcriptPurgedAtMs !== void 0 ? new Date(transcriptPurgedAtMs).toISOString() : void 0;
|
|
552
|
-
const canExposeSqlContent = canExposeConversationPayload({
|
|
553
|
-
conversationId,
|
|
554
|
-
visibility: conversation.visibility
|
|
555
|
-
});
|
|
556
|
-
const currentContent = transcriptPurgedAtMs === void 0 ? await conversationContent({
|
|
557
|
-
conversationId,
|
|
558
|
-
messageStore,
|
|
559
|
-
stepStore,
|
|
560
|
-
canExposePayload: canExposeSqlContent
|
|
561
|
-
}) : { activity: [], contextEvents: [], transcript: [] };
|
|
562
|
-
const currentTranscript = currentContent.transcript;
|
|
563
|
-
const traceId = canExposeSqlContent ? traceIdFromTranscript(currentTranscript) : void 0;
|
|
564
|
-
const sentryTraceUrl = traceId ? buildSentryTraceUrl(traceId) : void 0;
|
|
565
|
-
const sentryConversationUrl = buildSentryConversationUrl(conversationId);
|
|
566
|
-
return {
|
|
567
|
-
...conversationSummaryFromStoredConversation({
|
|
568
|
-
conversation,
|
|
569
|
-
durationMs: args.durationMs,
|
|
570
|
-
...args.locationId ? { locationId: args.locationId } : {},
|
|
571
|
-
usage: args.usage
|
|
572
|
-
}),
|
|
573
|
-
...traceId ? { traceId } : {},
|
|
574
|
-
...sentryTraceUrl ? { sentryTraceUrl } : {},
|
|
575
|
-
activity: currentContent.activity,
|
|
576
|
-
contextEvents: currentContent.contextEvents,
|
|
577
|
-
transcriptAvailable: transcriptExpiredAt === void 0 && canExposeSqlContent && currentTranscript.length > 0,
|
|
578
|
-
...currentTranscript.length > 0 ? {
|
|
579
|
-
transcriptMessageCount: countConversationMessages(currentTranscript)
|
|
580
|
-
} : {},
|
|
581
|
-
...!canExposeSqlContent && transcriptExpiredAt === void 0 ? {
|
|
582
|
-
transcriptMetadata: currentTranscript.map(redactTranscriptMessage),
|
|
583
|
-
transcriptRedacted: true,
|
|
584
|
-
transcriptRedactionReason: "non_public_conversation"
|
|
585
|
-
} : {},
|
|
586
|
-
...transcriptExpiredAt !== void 0 ? {
|
|
587
|
-
transcriptExpired: true,
|
|
588
|
-
transcriptExpiredAt,
|
|
589
|
-
transcriptMetadata: []
|
|
590
|
-
} : {},
|
|
591
|
-
transcript: transcriptExpiredAt === void 0 && canExposeSqlContent ? currentTranscript : [],
|
|
592
|
-
generatedAt: new Date(nowMs).toISOString(),
|
|
593
|
-
...sentryConversationUrl ? { sentryConversationUrl } : {}
|
|
594
|
-
};
|
|
595
|
-
}
|
|
596
|
-
async function buildConversationSubagent(conversation, subagentId) {
|
|
597
|
-
const conversationId = conversation.conversationId;
|
|
598
|
-
const stepStore = getAgentStepStore();
|
|
599
|
-
const parentSteps = await stepStore.loadHistory(conversationId);
|
|
600
|
-
if (conversation?.transcriptPurgedAtMs !== void 0) {
|
|
601
|
-
return {
|
|
602
|
-
type: "subagent",
|
|
603
|
-
createdAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
604
|
-
id: subagentId,
|
|
605
|
-
status: "completed",
|
|
606
|
-
subagentKind: "unknown",
|
|
607
|
-
transcript: [],
|
|
608
|
-
transcriptAvailable: false,
|
|
609
|
-
transcriptExpired: true,
|
|
610
|
-
transcriptExpiredAt: new Date(
|
|
611
|
-
conversation.transcriptPurgedAtMs
|
|
612
|
-
).toISOString()
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
const start = parentSteps.find(
|
|
616
|
-
(step) => step.entry.type === "subagent_started" && step.entry.subagentInvocationId === subagentId
|
|
617
|
-
);
|
|
618
|
-
if (!start) {
|
|
619
|
-
return {
|
|
620
|
-
type: "subagent",
|
|
621
|
-
createdAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
622
|
-
id: subagentId,
|
|
623
|
-
status: "error",
|
|
624
|
-
subagentKind: "unknown",
|
|
625
|
-
transcript: [],
|
|
626
|
-
transcriptAvailable: false,
|
|
627
|
-
unavailableReason: "not_found"
|
|
628
|
-
};
|
|
629
|
-
}
|
|
630
|
-
const end = parentSteps.find(
|
|
631
|
-
(step) => step.entry.type === "subagent_ended" && step.entry.subagentInvocationId === subagentId
|
|
632
|
-
);
|
|
633
|
-
const childConversationId = start.entry.childConversationId;
|
|
634
|
-
const activity = subagentActivityFromSteps(start, end);
|
|
635
|
-
const subagentSentryConversationUrl = buildSentryConversationUrl(childConversationId);
|
|
636
|
-
const conversationFields = {
|
|
637
|
-
subagentConversationId: childConversationId,
|
|
638
|
-
...subagentSentryConversationUrl ? { subagentSentryConversationUrl } : {}
|
|
639
|
-
};
|
|
640
|
-
const canExposeTranscript = canExposeConversationPayload({
|
|
641
|
-
conversationId,
|
|
642
|
-
visibility: conversation?.visibility
|
|
643
|
-
});
|
|
644
|
-
if (!canExposeTranscript) {
|
|
645
|
-
return subagentTranscriptReport(activity, {
|
|
646
|
-
...conversationFields,
|
|
647
|
-
transcriptRedacted: true,
|
|
648
|
-
transcriptRedactionReason: "non_public_conversation"
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
const childMessages = await loadProjection({
|
|
652
|
-
conversationId: childConversationId
|
|
653
|
-
});
|
|
654
|
-
if (childMessages.length === 0) {
|
|
655
|
-
return subagentTranscriptReport(activity, {
|
|
656
|
-
...conversationFields,
|
|
657
|
-
unavailableReason: "missing_transcript_ref"
|
|
658
|
-
});
|
|
659
|
-
}
|
|
660
|
-
const transcript = childMessages.map(
|
|
661
|
-
(message) => normalizeSubagentTranscriptMessage(message, activity.subagentKind)
|
|
662
|
-
);
|
|
663
|
-
return subagentTranscriptReport(activity, {
|
|
664
|
-
...conversationFields,
|
|
665
|
-
transcript,
|
|
666
|
-
transcriptMessageCount: countConversationMessages(transcript)
|
|
667
|
-
});
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
export {
|
|
671
|
-
buildConversationDetail,
|
|
672
|
-
buildConversationSubagent
|
|
673
|
-
};
|