@sentry/junior 0.71.3 → 0.73.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.
- package/bin/junior.mjs +22 -10
- package/dist/api-reference.d.ts +2 -0
- package/dist/app.d.ts +12 -3
- package/dist/app.js +2522 -15560
- package/dist/chat/agent-dispatch/heartbeat.d.ts +0 -6
- package/dist/chat/agent-dispatch/runner.d.ts +2 -0
- package/dist/chat/agent-dispatch/store.d.ts +2 -2
- package/dist/chat/agent-dispatch/types.d.ts +6 -3
- package/dist/chat/agent-dispatch/validation.d.ts +2 -3
- package/dist/chat/app/production.d.ts +8 -1
- package/dist/chat/app/services.d.ts +7 -0
- package/dist/chat/destination.d.ts +3 -1
- package/dist/chat/logging.d.ts +3 -0
- package/dist/chat/mcp/errors.d.ts +3 -0
- package/dist/chat/mcp/tool-manager.d.ts +5 -1
- package/dist/chat/oauth-flow.d.ts +1 -1
- package/dist/chat/plugins/agent-hooks.d.ts +3 -2
- package/dist/chat/plugins/registry.d.ts +2 -0
- package/dist/chat/plugins/types.d.ts +2 -0
- package/dist/chat/prompt.d.ts +4 -1
- package/dist/chat/requester.d.ts +67 -0
- package/dist/chat/respond.d.ts +8 -8
- package/dist/chat/runtime/agent-continue-runner.d.ts +25 -0
- package/dist/chat/runtime/reply-executor.d.ts +7 -5
- package/dist/chat/runtime/slack-resume.d.ts +3 -3
- package/dist/chat/runtime/slack-runtime.d.ts +13 -3
- package/dist/chat/runtime/turn.d.ts +17 -3
- package/dist/chat/sandbox/egress-credentials.d.ts +5 -2
- package/dist/chat/sandbox/egress-policy.d.ts +5 -1
- package/dist/chat/sandbox/egress-proxy.d.ts +2 -0
- package/dist/chat/sandbox/egress-schemas.d.ts +4 -0
- package/dist/chat/sandbox/egress-session.d.ts +3 -1
- package/dist/chat/sandbox/egress-tracing.d.ts +7 -0
- package/dist/chat/sandbox/sandbox.d.ts +2 -0
- package/dist/chat/sandbox/session.d.ts +3 -2
- package/dist/chat/services/agent-continue.d.ts +27 -0
- package/dist/chat/services/auth-pause-response.d.ts +1 -1
- package/dist/chat/services/auth-pause.d.ts +2 -1
- package/dist/chat/services/mcp-auth-orchestration.d.ts +1 -1
- package/dist/chat/services/message-actor-identity.d.ts +12 -4
- package/dist/chat/services/plugin-auth-orchestration.d.ts +9 -8
- package/dist/chat/services/turn-result.d.ts +3 -0
- package/dist/chat/services/turn-session-record.d.ts +10 -7
- package/dist/chat/slack/user.d.ts +4 -4
- package/dist/chat/state/adapter.d.ts +2 -0
- package/dist/chat/state/conversation-details.d.ts +4 -3
- package/dist/chat/state/session-log.d.ts +43 -0
- package/dist/chat/state/turn-session.d.ts +7 -10
- package/dist/chat/task-execution/slack-work.d.ts +5 -5
- package/dist/chat/task-execution/store.d.ts +83 -48
- package/dist/chat/task-execution/worker.d.ts +3 -3
- package/dist/chat/tools/definition.d.ts +3 -0
- package/dist/chat/tools/execution/tool-error-handler.d.ts +2 -1
- package/dist/chat/tools/slack/canvas-tools.d.ts +3 -2
- package/dist/chat/tools/slack/channel-list-messages.d.ts +2 -2
- package/dist/chat/tools/slack/channel-post-message.d.ts +3 -2
- package/dist/chat/tools/slack/context.d.ts +15 -2
- package/dist/chat/tools/slack/message-add-reaction.d.ts +3 -2
- package/dist/chat/tools/slack/thread-read.d.ts +2 -2
- package/dist/chat/tools/types.d.ts +20 -23
- package/dist/{chunk-BBXYXOJW.js → chunk-3BYAPS6B.js} +48 -529
- package/dist/{chunk-UXG6TU2U.js → chunk-7Q5YOUUT.js} +16 -93
- package/dist/chunk-AL5T52ZD.js +1119 -0
- package/dist/chunk-CYUI7JU5.js +195 -0
- package/dist/{chunk-R62YWUNO.js → chunk-DIMX5F3T.js} +10 -28
- package/dist/chunk-G3E7SCME.js +28 -0
- package/dist/chunk-KVZL5NZS.js +519 -0
- package/dist/chunk-M4FLLXXD.js +212 -0
- package/dist/chunk-OQSYYOLM.js +12787 -0
- package/dist/{chunk-GT67ZWZQ.js → chunk-OR6NQJ5E.js} +5 -3
- package/dist/{chunk-B5HKWWQB.js → chunk-RY6AL5C7.js} +8 -6
- package/dist/chunk-SJHUF3DP.js +43 -0
- package/dist/{chunk-XE2VFQQN.js → chunk-UOTZ3EEQ.js} +1 -1
- package/dist/{chunk-HOGQL2H6.js → chunk-UZVHXZ7V.js} +1357 -1486
- package/dist/{chunk-76YMBKW7.js → chunk-V4VYUY4A.js} +27 -14
- package/dist/{chunk-JS4HURDT.js → chunk-WS2EG3GW.js} +224 -224
- package/dist/chunk-ZDA2HYX5.js +275 -0
- package/dist/cli/chat.js +205 -0
- package/dist/cli/check.js +6 -5
- package/dist/cli/run.js +18 -2
- package/dist/cli/snapshot-warmup.js +11 -8
- package/dist/cli/upgrade.js +599 -0
- package/dist/deployment.d.ts +4 -0
- package/dist/handlers/agent-dispatch.d.ts +6 -1
- package/dist/handlers/mcp-oauth-callback.d.ts +6 -1
- package/dist/handlers/oauth-callback.d.ts +6 -1
- package/dist/handlers/sandbox-egress-proxy.d.ts +2 -0
- package/dist/handlers/webhooks.d.ts +4 -2
- package/dist/instrumentation.js +17 -2
- package/dist/nitro.d.ts +1 -1
- package/dist/nitro.js +10 -10
- package/dist/plugins.d.ts +1 -1
- package/dist/reporting/conversations.d.ts +116 -0
- package/dist/reporting.d.ts +24 -129
- package/dist/reporting.js +320 -166
- package/dist/runner-LMAM4OGD.js +259 -0
- package/package.json +3 -3
- package/dist/chat/runtime/timeout-resume-runner.d.ts +0 -19
- package/dist/chat/services/requester-identity.d.ts +0 -19
- package/dist/chat/services/timeout-resume.d.ts +0 -23
- package/dist/chunk-6YY4Q3D4.js +0 -12
- package/dist/chunk-Z3YD6NHK.js +0 -12
- package/dist/handlers/turn-resume.d.ts +0 -4
package/dist/reporting.js
CHANGED
|
@@ -2,73 +2,57 @@ import {
|
|
|
2
2
|
GET,
|
|
3
3
|
buildSentryConversationUrl,
|
|
4
4
|
buildSentryTraceUrl,
|
|
5
|
-
buildSystemPrompt,
|
|
6
5
|
formatSlackConversationRedactedLabel,
|
|
7
|
-
getAgentPluginOperationalReports,
|
|
8
|
-
getAgentTurnSessionRecord,
|
|
9
6
|
getConversationDetails,
|
|
10
7
|
getConversationDetailsForIds,
|
|
11
|
-
listAgentTurnSessionSummaries,
|
|
12
|
-
listAgentTurnSessionSummariesForConversation,
|
|
13
8
|
resolveSlackConversationContextFromThreadId
|
|
14
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ZDA2HYX5.js";
|
|
10
|
+
import {
|
|
11
|
+
buildSystemPrompt,
|
|
12
|
+
getAgentPluginOperationalReports,
|
|
13
|
+
getAgentTurnSessionRecord,
|
|
14
|
+
listAgentTurnSessionSummariesForConversation
|
|
15
|
+
} from "./chunk-UZVHXZ7V.js";
|
|
15
16
|
import {
|
|
16
17
|
discoverSkills
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import
|
|
18
|
+
} from "./chunk-OR6NQJ5E.js";
|
|
19
|
+
import {
|
|
20
|
+
getConversation,
|
|
21
|
+
listConversationsByActivity
|
|
22
|
+
} from "./chunk-AL5T52ZD.js";
|
|
23
|
+
import "./chunk-V4VYUY4A.js";
|
|
24
|
+
import "./chunk-G3E7SCME.js";
|
|
19
25
|
import {
|
|
20
26
|
getPluginPackageContent,
|
|
21
27
|
getPluginProviders
|
|
22
|
-
} from "./chunk-
|
|
23
|
-
import
|
|
28
|
+
} from "./chunk-7Q5YOUUT.js";
|
|
29
|
+
import {
|
|
30
|
+
homeDir
|
|
31
|
+
} from "./chunk-KVZL5NZS.js";
|
|
32
|
+
import "./chunk-DIMX5F3T.js";
|
|
24
33
|
import {
|
|
25
34
|
canExposeConversationPayload,
|
|
26
35
|
parseSlackThreadId,
|
|
27
36
|
resolveConversationPrivacy
|
|
28
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-WS2EG3GW.js";
|
|
38
|
+
import "./chunk-CYUI7JU5.js";
|
|
29
39
|
import {
|
|
30
|
-
homeDir,
|
|
31
40
|
isRecord
|
|
32
|
-
} from "./chunk-
|
|
33
|
-
import "./chunk-
|
|
41
|
+
} from "./chunk-3BYAPS6B.js";
|
|
42
|
+
import "./chunk-SJHUF3DP.js";
|
|
34
43
|
import "./chunk-2KG3PWR4.js";
|
|
35
44
|
|
|
36
45
|
// src/reporting.ts
|
|
37
46
|
import { readFileSync } from "fs";
|
|
38
47
|
import path from "path";
|
|
48
|
+
|
|
49
|
+
// src/reporting/conversations.ts
|
|
39
50
|
var HUNG_TURN_PROGRESS_MS = 5 * 60 * 1e3;
|
|
40
51
|
var SAFE_METADATA_KEY_LIMIT = 20;
|
|
41
52
|
var PRIVATE_CONVERSATION_LABEL = "Private Conversation";
|
|
42
|
-
var
|
|
43
|
-
var
|
|
53
|
+
var CONVERSATION_FEED_LIMIT = 50;
|
|
54
|
+
var CONVERSATION_STATS_LIMIT = 5e3;
|
|
44
55
|
var RECENT_CONVERSATION_STATS_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
45
|
-
function readDescriptionText() {
|
|
46
|
-
try {
|
|
47
|
-
const raw = readFileSync(
|
|
48
|
-
path.join(homeDir(), "DESCRIPTION.md"),
|
|
49
|
-
"utf8"
|
|
50
|
-
).trim();
|
|
51
|
-
return raw || void 0;
|
|
52
|
-
} catch {
|
|
53
|
-
return void 0;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
async function readHealth() {
|
|
57
|
-
const res = GET();
|
|
58
|
-
return await res.json();
|
|
59
|
-
}
|
|
60
|
-
async function readSkills() {
|
|
61
|
-
const skills = await discoverSkills();
|
|
62
|
-
return skills.map((skill) => ({
|
|
63
|
-
name: skill.name,
|
|
64
|
-
pluginProvider: skill.pluginProvider
|
|
65
|
-
}));
|
|
66
|
-
}
|
|
67
|
-
async function readPlugins() {
|
|
68
|
-
return getPluginProviders().map((plugin) => ({
|
|
69
|
-
name: plugin.manifest.name
|
|
70
|
-
}));
|
|
71
|
-
}
|
|
72
56
|
function statusFromCheckpoint(summary, nowMs = Date.now()) {
|
|
73
57
|
const state = summary.state;
|
|
74
58
|
if (state === "running" && nowMs - summary.lastProgressAtMs > HUNG_TURN_PROGRESS_MS) {
|
|
@@ -91,6 +75,12 @@ function surfaceFromConversationId(conversationId) {
|
|
|
91
75
|
function surfaceFromSummary(summary) {
|
|
92
76
|
return summary.surface ?? surfaceFromConversationId(summary.conversationId);
|
|
93
77
|
}
|
|
78
|
+
function surfaceFromSource(source, conversationId) {
|
|
79
|
+
if (source === "slack" || source === "api" || source === "scheduler") {
|
|
80
|
+
return source;
|
|
81
|
+
}
|
|
82
|
+
return surfaceFromConversationId(conversationId);
|
|
83
|
+
}
|
|
94
84
|
function requesterIdentityReport(requester) {
|
|
95
85
|
if (!requester) return void 0;
|
|
96
86
|
const identity = {
|
|
@@ -101,7 +91,7 @@ function requesterIdentityReport(requester) {
|
|
|
101
91
|
};
|
|
102
92
|
return Object.keys(identity).length > 0 ? identity : void 0;
|
|
103
93
|
}
|
|
104
|
-
function
|
|
94
|
+
function usageReport(usage) {
|
|
105
95
|
if (!usage) return void 0;
|
|
106
96
|
const report = {
|
|
107
97
|
...usage.inputTokens !== void 0 ? { inputTokens: usage.inputTokens } : {},
|
|
@@ -135,7 +125,7 @@ function sessionReportFromSummary(summary, nowMs = Date.now(), details) {
|
|
|
135
125
|
);
|
|
136
126
|
const sentryTraceUrl = summary.traceId ? buildSentryTraceUrl(summary.traceId) : void 0;
|
|
137
127
|
const requesterIdentity = requesterIdentityReport(effectiveRequester);
|
|
138
|
-
const cumulativeUsage =
|
|
128
|
+
const cumulativeUsage = usageReport(summary.cumulativeUsage);
|
|
139
129
|
return {
|
|
140
130
|
conversationId: summary.conversationId,
|
|
141
131
|
displayTitle,
|
|
@@ -156,6 +146,98 @@ function sessionReportFromSummary(summary, nowMs = Date.now(), details) {
|
|
|
156
146
|
...sentryTraceUrl ? { sentryTraceUrl } : {}
|
|
157
147
|
};
|
|
158
148
|
}
|
|
149
|
+
function statusFromConversation(conversation, fallback, nowMs) {
|
|
150
|
+
if (conversation.execution.status === "idle") {
|
|
151
|
+
if (fallback === "failed" || fallback === "superseded") {
|
|
152
|
+
return fallback;
|
|
153
|
+
}
|
|
154
|
+
return "completed";
|
|
155
|
+
}
|
|
156
|
+
const updatedAtMs = conversation.execution.updatedAtMs ?? conversation.updatedAtMs;
|
|
157
|
+
if (conversation.execution.status === "running" && nowMs - updatedAtMs > HUNG_TURN_PROGRESS_MS) {
|
|
158
|
+
return "hung";
|
|
159
|
+
}
|
|
160
|
+
return "active";
|
|
161
|
+
}
|
|
162
|
+
function titleFromConversation(args) {
|
|
163
|
+
const slackThread = parseSlackThreadId(args.conversation.conversationId);
|
|
164
|
+
const effectiveChannelName = args.details?.channelName ?? args.conversation.channelName;
|
|
165
|
+
const slackConversation = resolveSlackConversationContextFromThreadId({
|
|
166
|
+
threadId: args.conversation.conversationId,
|
|
167
|
+
channelName: effectiveChannelName
|
|
168
|
+
});
|
|
169
|
+
const privateLabel = resolveConversationPrivacy({
|
|
170
|
+
conversationId: args.conversation.conversationId
|
|
171
|
+
}) !== "public" ? slackConversation ? formatSlackConversationRedactedLabel(slackConversation) : PRIVATE_CONVERSATION_LABEL : void 0;
|
|
172
|
+
return privateLabel ?? args.details?.displayTitle ?? args.conversation.title ?? slackStatsLocationLabel({
|
|
173
|
+
channel: slackThread?.channelId,
|
|
174
|
+
channelName: effectiveChannelName
|
|
175
|
+
}) ?? surfaceFallbackLabel(args.surface);
|
|
176
|
+
}
|
|
177
|
+
function applyConversationIndexMetadata(args) {
|
|
178
|
+
const surface = args.details?.originSurface ?? (args.conversation.source ? surfaceFromSource(
|
|
179
|
+
args.conversation.source,
|
|
180
|
+
args.conversation.conversationId
|
|
181
|
+
) : args.report.surface);
|
|
182
|
+
const slackThread = parseSlackThreadId(args.conversation.conversationId);
|
|
183
|
+
const effectiveChannelName = args.details?.channelName ?? args.conversation.channelName ?? args.report.channelName;
|
|
184
|
+
const requesterIdentity = requesterIdentityReport(args.details?.originRequester) ?? args.report.requesterIdentity ?? requesterIdentityReport(args.conversation.requester);
|
|
185
|
+
const status = statusFromConversation(
|
|
186
|
+
args.conversation,
|
|
187
|
+
args.report.status,
|
|
188
|
+
args.nowMs
|
|
189
|
+
);
|
|
190
|
+
const lastSeenAtMs = Math.max(
|
|
191
|
+
reportTime(args.report.lastSeenAt) ?? 0,
|
|
192
|
+
args.conversation.lastActivityAtMs
|
|
193
|
+
);
|
|
194
|
+
const lastProgressAtMs = Math.max(
|
|
195
|
+
reportTime(args.report.lastProgressAt) ?? 0,
|
|
196
|
+
args.conversation.execution.updatedAtMs ?? args.conversation.updatedAtMs
|
|
197
|
+
);
|
|
198
|
+
return {
|
|
199
|
+
...args.report,
|
|
200
|
+
displayTitle: titleFromConversation({
|
|
201
|
+
conversation: args.conversation,
|
|
202
|
+
details: args.details,
|
|
203
|
+
surface
|
|
204
|
+
}),
|
|
205
|
+
status,
|
|
206
|
+
lastSeenAt: new Date(lastSeenAtMs).toISOString(),
|
|
207
|
+
lastProgressAt: new Date(lastProgressAtMs).toISOString(),
|
|
208
|
+
surface,
|
|
209
|
+
...requesterIdentity ? { requesterIdentity } : {},
|
|
210
|
+
...slackThread ? { channel: slackThread.channelId } : {},
|
|
211
|
+
...effectiveChannelName ? { channelName: effectiveChannelName } : {}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function sessionReportFromConversation(conversation, nowMs, details) {
|
|
215
|
+
const surface = details?.originSurface ?? surfaceFromSource(conversation.source, conversation.conversationId);
|
|
216
|
+
const sentryConversationUrl = buildSentryConversationUrl(
|
|
217
|
+
conversation.conversationId
|
|
218
|
+
);
|
|
219
|
+
const requesterIdentity = requesterIdentityReport(
|
|
220
|
+
details?.originRequester ?? conversation.requester
|
|
221
|
+
);
|
|
222
|
+
const slackThread = parseSlackThreadId(conversation.conversationId);
|
|
223
|
+
return {
|
|
224
|
+
conversationId: conversation.conversationId,
|
|
225
|
+
cumulativeDurationMs: 0,
|
|
226
|
+
displayTitle: titleFromConversation({ conversation, details, surface }),
|
|
227
|
+
id: conversation.execution.runId ?? conversation.conversationId,
|
|
228
|
+
lastProgressAt: new Date(
|
|
229
|
+
conversation.execution.updatedAtMs ?? conversation.updatedAtMs
|
|
230
|
+
).toISOString(),
|
|
231
|
+
lastSeenAt: new Date(conversation.lastActivityAtMs).toISOString(),
|
|
232
|
+
startedAt: new Date(conversation.createdAtMs).toISOString(),
|
|
233
|
+
status: statusFromConversation(conversation, void 0, nowMs),
|
|
234
|
+
surface,
|
|
235
|
+
...requesterIdentity ? { requesterIdentity } : {},
|
|
236
|
+
...slackThread ? { channel: slackThread.channelId } : {},
|
|
237
|
+
...details?.channelName ?? conversation.channelName ? { channelName: details?.channelName ?? conversation.channelName } : {},
|
|
238
|
+
...sentryConversationUrl ? { sentryConversationUrl } : {}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
159
241
|
function reportTime(value) {
|
|
160
242
|
const time = Date.parse(value);
|
|
161
243
|
return Number.isFinite(time) ? time : void 0;
|
|
@@ -176,18 +258,18 @@ function usageTokenTotal(usage) {
|
|
|
176
258
|
}
|
|
177
259
|
return typeof usage.totalTokens === "number" && Number.isFinite(usage.totalTokens) ? Math.max(0, Math.floor(usage.totalTokens)) : void 0;
|
|
178
260
|
}
|
|
179
|
-
function
|
|
180
|
-
return typeof
|
|
261
|
+
function runDurationSnapshot(run) {
|
|
262
|
+
return typeof run.cumulativeDurationMs === "number" && Number.isFinite(run.cumulativeDurationMs) ? Math.max(0, Math.floor(run.cumulativeDurationMs)) : void 0;
|
|
181
263
|
}
|
|
182
|
-
function
|
|
264
|
+
function runContributions(runs) {
|
|
183
265
|
let previousDuration = 0;
|
|
184
266
|
let previousTokens = 0;
|
|
185
|
-
return
|
|
186
|
-
const duration =
|
|
187
|
-
const tokens = usageTokenTotal(
|
|
267
|
+
return runs.map((run) => {
|
|
268
|
+
const duration = runDurationSnapshot(run);
|
|
269
|
+
const tokens = usageTokenTotal(run.cumulativeUsage);
|
|
188
270
|
const contribution = {
|
|
189
271
|
durationMs: duration === void 0 ? 0 : Math.max(0, duration - previousDuration),
|
|
190
|
-
|
|
272
|
+
run
|
|
191
273
|
};
|
|
192
274
|
if (tokens !== void 0) {
|
|
193
275
|
contribution.tokens = Math.max(0, tokens - previousTokens);
|
|
@@ -257,8 +339,8 @@ function displayTitleFromDetails(conversationId, details) {
|
|
|
257
339
|
channelName: details.channelName
|
|
258
340
|
}) ?? (details.originSurface ? surfaceFallbackLabel(details.originSurface) : void 0);
|
|
259
341
|
}
|
|
260
|
-
function locationLabel(
|
|
261
|
-
return slackStatsLocationLabel(
|
|
342
|
+
function locationLabel(run) {
|
|
343
|
+
return slackStatsLocationLabel(run) ?? surfaceFallbackLabel(run.surface);
|
|
262
344
|
}
|
|
263
345
|
function emptyStatsItem(label) {
|
|
264
346
|
return {
|
|
@@ -268,7 +350,7 @@ function emptyStatsItem(label) {
|
|
|
268
350
|
failed: 0,
|
|
269
351
|
hung: 0,
|
|
270
352
|
label,
|
|
271
|
-
|
|
353
|
+
runs: 0
|
|
272
354
|
};
|
|
273
355
|
}
|
|
274
356
|
function addItemTokens(item, tokens) {
|
|
@@ -276,20 +358,20 @@ function addItemTokens(item, tokens) {
|
|
|
276
358
|
item.tokens = (item.tokens ?? 0) + tokens;
|
|
277
359
|
}
|
|
278
360
|
}
|
|
279
|
-
function statusSignals(
|
|
361
|
+
function statusSignals(runs) {
|
|
280
362
|
return {
|
|
281
|
-
active:
|
|
282
|
-
failed:
|
|
283
|
-
hung:
|
|
363
|
+
active: runs.some((run) => run.status === "active"),
|
|
364
|
+
failed: runs.some((run) => run.status === "failed"),
|
|
365
|
+
hung: runs.some((run) => run.status === "hung")
|
|
284
366
|
};
|
|
285
367
|
}
|
|
286
368
|
function statsItems(map) {
|
|
287
369
|
return [...map.values()].sort(
|
|
288
|
-
(left, right) => right.conversations - left.conversations || right.
|
|
370
|
+
(left, right) => right.conversations - left.conversations || right.runs - left.runs || right.durationMs - left.durationMs || left.label.localeCompare(right.label)
|
|
289
371
|
);
|
|
290
372
|
}
|
|
291
|
-
function
|
|
292
|
-
return [...
|
|
373
|
+
function newestRun(runs) {
|
|
374
|
+
return [...runs].sort(
|
|
293
375
|
(left, right) => (reportTime(right.lastSeenAt) ?? 0) - (reportTime(left.lastSeenAt) ?? 0) || right.id.localeCompare(left.id)
|
|
294
376
|
)[0];
|
|
295
377
|
}
|
|
@@ -303,19 +385,19 @@ function recentConversationGroups(args) {
|
|
|
303
385
|
]);
|
|
304
386
|
}
|
|
305
387
|
return [...groups.values()].map(
|
|
306
|
-
(
|
|
388
|
+
(runs) => [...runs].sort(
|
|
307
389
|
(left, right) => (reportTime(left.startedAt) ?? 0) - (reportTime(right.startedAt) ?? 0) || left.id.localeCompare(right.id)
|
|
308
390
|
)
|
|
309
|
-
).filter((
|
|
310
|
-
const activityAt = reportTime(
|
|
391
|
+
).filter((runs) => {
|
|
392
|
+
const activityAt = reportTime(newestRun(runs).lastSeenAt);
|
|
311
393
|
return activityAt !== void 0 && activityAt >= startMs && activityAt <= args.nowMs;
|
|
312
394
|
});
|
|
313
395
|
}
|
|
314
|
-
function conversationDurationMs(
|
|
315
|
-
if (!
|
|
396
|
+
function conversationDurationMs(runs) {
|
|
397
|
+
if (!runs.some((run) => runDurationSnapshot(run) !== void 0)) {
|
|
316
398
|
return 0;
|
|
317
399
|
}
|
|
318
|
-
return contributionDurationTotal(
|
|
400
|
+
return contributionDurationTotal(runContributions(runs));
|
|
319
401
|
}
|
|
320
402
|
function buildConversationStatsReport(args) {
|
|
321
403
|
const conversations = recentConversationGroups(args);
|
|
@@ -326,30 +408,30 @@ function buildConversationStatsReport(args) {
|
|
|
326
408
|
let active = 0;
|
|
327
409
|
let failed = 0;
|
|
328
410
|
let hung = 0;
|
|
329
|
-
for (const
|
|
330
|
-
const contributions =
|
|
331
|
-
const conversationSignals = statusSignals(
|
|
411
|
+
for (const runs of conversations) {
|
|
412
|
+
const contributions = runContributions(runs);
|
|
413
|
+
const conversationSignals = statusSignals(runs);
|
|
332
414
|
const conversationTokens = contributionTokenTotal(contributions);
|
|
333
415
|
durationMs += contributionDurationTotal(contributions);
|
|
334
416
|
tokens = addTokenTotal(tokens, conversationTokens);
|
|
335
417
|
active += conversationSignals.active ? 1 : 0;
|
|
336
418
|
failed += conversationSignals.failed ? 1 : 0;
|
|
337
419
|
hung += conversationSignals.hung ? 1 : 0;
|
|
338
|
-
const
|
|
420
|
+
const requesterRuns = /* @__PURE__ */ new Map();
|
|
339
421
|
for (const contribution of contributions) {
|
|
340
|
-
const requester = requesterLabel(contribution.
|
|
341
|
-
|
|
342
|
-
...
|
|
422
|
+
const requester = requesterLabel(contribution.run.requesterIdentity) ?? "Unknown";
|
|
423
|
+
requesterRuns.set(requester, [
|
|
424
|
+
...requesterRuns.get(requester) ?? [],
|
|
343
425
|
contribution
|
|
344
426
|
]);
|
|
345
427
|
}
|
|
346
|
-
for (const [requester, requesterContributions] of
|
|
428
|
+
for (const [requester, requesterContributions] of requesterRuns) {
|
|
347
429
|
const item = requesters.get(requester) ?? emptyStatsItem(requester);
|
|
348
430
|
const signals = statusSignals(
|
|
349
|
-
requesterContributions.map((contribution) => contribution.
|
|
431
|
+
requesterContributions.map((contribution) => contribution.run)
|
|
350
432
|
);
|
|
351
433
|
item.conversations += 1;
|
|
352
|
-
item.
|
|
434
|
+
item.runs += requesterContributions.length;
|
|
353
435
|
item.durationMs += contributionDurationTotal(requesterContributions);
|
|
354
436
|
item.active += signals.active ? 1 : 0;
|
|
355
437
|
item.failed += signals.failed ? 1 : 0;
|
|
@@ -357,11 +439,11 @@ function buildConversationStatsReport(args) {
|
|
|
357
439
|
addItemTokens(item, contributionTokenTotal(requesterContributions));
|
|
358
440
|
requesters.set(requester, item);
|
|
359
441
|
}
|
|
360
|
-
const location = locationLabel(
|
|
442
|
+
const location = locationLabel(newestRun(runs));
|
|
361
443
|
const locationItem = locations.get(location) ?? emptyStatsItem(location);
|
|
362
444
|
locationItem.conversations += 1;
|
|
363
|
-
locationItem.
|
|
364
|
-
locationItem.durationMs += conversationDurationMs(
|
|
445
|
+
locationItem.runs += runs.length;
|
|
446
|
+
locationItem.durationMs += conversationDurationMs(runs);
|
|
365
447
|
locationItem.active += conversationSignals.active ? 1 : 0;
|
|
366
448
|
locationItem.failed += conversationSignals.failed ? 1 : 0;
|
|
367
449
|
locationItem.hung += conversationSignals.hung ? 1 : 0;
|
|
@@ -379,41 +461,16 @@ function buildConversationStatsReport(args) {
|
|
|
379
461
|
requesters: statsItems(requesters),
|
|
380
462
|
sampleLimit: args.sampleLimit,
|
|
381
463
|
sampleSize: args.sampleSize,
|
|
382
|
-
source: "
|
|
464
|
+
source: "conversation_index",
|
|
383
465
|
...tokens !== void 0 ? { tokens } : {},
|
|
384
466
|
truncated: args.truncated,
|
|
385
|
-
|
|
467
|
+
runs: conversations.reduce((sum, runs) => sum + runs.length, 0),
|
|
386
468
|
windowEnd: new Date(args.nowMs).toISOString(),
|
|
387
469
|
windowStart: new Date(
|
|
388
470
|
args.nowMs - RECENT_CONVERSATION_STATS_WINDOW_MS
|
|
389
471
|
).toISOString()
|
|
390
472
|
};
|
|
391
473
|
}
|
|
392
|
-
async function completeSampledConversationSummaries(args) {
|
|
393
|
-
if (!args.truncated) {
|
|
394
|
-
return args.summaries;
|
|
395
|
-
}
|
|
396
|
-
const conversationIds = [
|
|
397
|
-
...new Set(args.summaries.map((summary) => summary.conversationId))
|
|
398
|
-
];
|
|
399
|
-
const groups = await Promise.all(
|
|
400
|
-
conversationIds.map(
|
|
401
|
-
(conversationId) => listAgentTurnSessionSummariesForConversation(conversationId)
|
|
402
|
-
)
|
|
403
|
-
);
|
|
404
|
-
const summariesByTurn = /* @__PURE__ */ new Map();
|
|
405
|
-
for (const group of groups) {
|
|
406
|
-
for (const summary of group) {
|
|
407
|
-
summariesByTurn.set(
|
|
408
|
-
`${summary.conversationId}:${summary.sessionId}`,
|
|
409
|
-
summary
|
|
410
|
-
);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
return [...summariesByTurn.values()].sort(
|
|
414
|
-
(left, right) => right.updatedAtMs - left.updatedAtMs
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
474
|
function canExposeConversationTranscript(summary) {
|
|
418
475
|
return canExposeConversationPayload({
|
|
419
476
|
conversationId: summary.conversationId
|
|
@@ -600,13 +657,19 @@ function isConversationMessage(message) {
|
|
|
600
657
|
function countConversationMessages(transcript) {
|
|
601
658
|
return transcript.filter(isConversationMessage).length;
|
|
602
659
|
}
|
|
603
|
-
function systemPromptMessage() {
|
|
660
|
+
function systemPromptMessage(destination) {
|
|
604
661
|
return {
|
|
605
662
|
role: "system",
|
|
606
|
-
parts: [{ type: "text", text: buildSystemPrompt() }]
|
|
663
|
+
parts: [{ type: "text", text: buildSystemPrompt({ source: destination }) }]
|
|
607
664
|
};
|
|
608
665
|
}
|
|
609
|
-
function turnScopedMessages(messages) {
|
|
666
|
+
function turnScopedMessages(messages, turnStartMessageIndex) {
|
|
667
|
+
if (turnStartMessageIndex !== void 0 && turnStartMessageIndex >= 0 && turnStartMessageIndex < messages.length) {
|
|
668
|
+
return {
|
|
669
|
+
messages: messages.slice(turnStartMessageIndex),
|
|
670
|
+
startsAtRunBoundary: turnStartMessageIndex === 0
|
|
671
|
+
};
|
|
672
|
+
}
|
|
610
673
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
611
674
|
const record = messages[index];
|
|
612
675
|
if (record.role === "user") {
|
|
@@ -635,96 +698,134 @@ function traceIdFromTranscript(transcript) {
|
|
|
635
698
|
}
|
|
636
699
|
return void 0;
|
|
637
700
|
}
|
|
638
|
-
async function
|
|
639
|
-
const
|
|
640
|
-
|
|
641
|
-
|
|
701
|
+
async function summariesByConversation(conversations) {
|
|
702
|
+
const entries = await Promise.all(
|
|
703
|
+
conversations.map(async (conversation) => {
|
|
704
|
+
const summaries = await listAgentTurnSessionSummariesForConversation(
|
|
705
|
+
conversation.conversationId
|
|
706
|
+
);
|
|
707
|
+
return [conversation.conversationId, summaries];
|
|
708
|
+
})
|
|
642
709
|
);
|
|
710
|
+
return new Map(entries);
|
|
711
|
+
}
|
|
712
|
+
async function reportsFromConversations(args) {
|
|
713
|
+
const summaries = await summariesByConversation(args.conversations);
|
|
714
|
+
const reports = /* @__PURE__ */ new Map();
|
|
715
|
+
for (const conversation of args.conversations) {
|
|
716
|
+
const details = args.detailsByConversationId.get(
|
|
717
|
+
conversation.conversationId
|
|
718
|
+
);
|
|
719
|
+
const conversationSummaries = summaries.get(conversation.conversationId) ?? [];
|
|
720
|
+
const conversationReports = conversationSummaries.length > 0 ? conversationSummaries.map(
|
|
721
|
+
(summary) => applyConversationIndexMetadata({
|
|
722
|
+
conversation,
|
|
723
|
+
details,
|
|
724
|
+
nowMs: args.nowMs,
|
|
725
|
+
report: sessionReportFromSummary(summary, args.nowMs, details)
|
|
726
|
+
})
|
|
727
|
+
) : [sessionReportFromConversation(conversation, args.nowMs, details)];
|
|
728
|
+
reports.set(conversation.conversationId, conversationReports);
|
|
729
|
+
}
|
|
730
|
+
return reports;
|
|
731
|
+
}
|
|
732
|
+
async function readConversationFeed() {
|
|
733
|
+
const nowMs = Date.now();
|
|
734
|
+
const conversations = await listConversationsByActivity({
|
|
735
|
+
limit: CONVERSATION_FEED_LIMIT
|
|
736
|
+
});
|
|
643
737
|
const detailsByConversationId = await getConversationDetailsForIds(
|
|
644
|
-
|
|
738
|
+
conversations.map((conversation) => conversation.conversationId)
|
|
645
739
|
);
|
|
740
|
+
const reportsByConversation = await reportsFromConversations({
|
|
741
|
+
conversations,
|
|
742
|
+
detailsByConversationId,
|
|
743
|
+
nowMs
|
|
744
|
+
});
|
|
646
745
|
return {
|
|
647
|
-
source: "
|
|
746
|
+
source: "conversation_index",
|
|
648
747
|
generatedAt: new Date(nowMs).toISOString(),
|
|
649
|
-
sessions:
|
|
650
|
-
(
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
748
|
+
sessions: conversations.map(
|
|
749
|
+
(conversation) => newestRun(
|
|
750
|
+
reportsByConversation.get(conversation.conversationId) ?? [
|
|
751
|
+
sessionReportFromConversation(
|
|
752
|
+
conversation,
|
|
753
|
+
nowMs,
|
|
754
|
+
detailsByConversationId.get(conversation.conversationId)
|
|
755
|
+
)
|
|
756
|
+
]
|
|
654
757
|
)
|
|
655
758
|
)
|
|
656
759
|
};
|
|
657
760
|
}
|
|
658
|
-
async function
|
|
761
|
+
async function readConversationStatsReport() {
|
|
659
762
|
const nowMs = Date.now();
|
|
660
763
|
const generatedAt = new Date(nowMs).toISOString();
|
|
661
|
-
const
|
|
662
|
-
|
|
663
|
-
);
|
|
664
|
-
const truncated = summaries.length >= DASHBOARD_CONVERSATION_STATS_LIMIT;
|
|
665
|
-
const sampledSummaries = summaries.slice(
|
|
666
|
-
0,
|
|
667
|
-
DASHBOARD_CONVERSATION_STATS_LIMIT
|
|
668
|
-
);
|
|
669
|
-
const reportSummaries = await completeSampledConversationSummaries({
|
|
670
|
-
summaries: sampledSummaries,
|
|
671
|
-
truncated
|
|
764
|
+
const conversations = await listConversationsByActivity({
|
|
765
|
+
limit: CONVERSATION_STATS_LIMIT + 1
|
|
672
766
|
});
|
|
767
|
+
const truncated = conversations.length > CONVERSATION_STATS_LIMIT;
|
|
768
|
+
const sampledConversations = conversations.slice(0, CONVERSATION_STATS_LIMIT);
|
|
673
769
|
const detailsByConversationId = await getConversationDetailsForIds(
|
|
674
|
-
|
|
770
|
+
sampledConversations.map((conversation) => conversation.conversationId)
|
|
771
|
+
);
|
|
772
|
+
const reportsByConversation = await reportsFromConversations({
|
|
773
|
+
conversations: sampledConversations,
|
|
774
|
+
detailsByConversationId,
|
|
775
|
+
nowMs
|
|
776
|
+
});
|
|
777
|
+
const sessions = sampledConversations.flatMap(
|
|
778
|
+
(conversation) => reportsByConversation.get(conversation.conversationId) ?? [
|
|
779
|
+
sessionReportFromConversation(
|
|
780
|
+
conversation,
|
|
781
|
+
nowMs,
|
|
782
|
+
detailsByConversationId.get(conversation.conversationId)
|
|
783
|
+
)
|
|
784
|
+
]
|
|
675
785
|
);
|
|
676
786
|
return buildConversationStatsReport({
|
|
677
787
|
generatedAt,
|
|
678
788
|
nowMs,
|
|
679
|
-
sampleLimit:
|
|
680
|
-
sampleSize:
|
|
681
|
-
sessions
|
|
682
|
-
(summary) => sessionReportFromSummary(
|
|
683
|
-
summary,
|
|
684
|
-
nowMs,
|
|
685
|
-
detailsByConversationId.get(summary.conversationId)
|
|
686
|
-
)
|
|
687
|
-
),
|
|
789
|
+
sampleLimit: CONVERSATION_STATS_LIMIT,
|
|
790
|
+
sampleSize: sampledConversations.length,
|
|
791
|
+
sessions,
|
|
688
792
|
truncated
|
|
689
793
|
});
|
|
690
794
|
}
|
|
691
|
-
async function
|
|
795
|
+
async function readConversationReport(conversationId) {
|
|
692
796
|
const nowMs = Date.now();
|
|
693
|
-
|
|
694
|
-
source: "plugins",
|
|
695
|
-
generatedAt: new Date(nowMs).toISOString(),
|
|
696
|
-
reports: await getAgentPluginOperationalReports(nowMs)
|
|
697
|
-
};
|
|
698
|
-
}
|
|
699
|
-
async function readConversation(conversationId) {
|
|
700
|
-
const [rawSummaries, details] = await Promise.all([
|
|
797
|
+
const [rawSummaries, details, conversation] = await Promise.all([
|
|
701
798
|
listAgentTurnSessionSummariesForConversation(conversationId),
|
|
702
|
-
getConversationDetails(conversationId)
|
|
799
|
+
getConversationDetails(conversationId),
|
|
800
|
+
getConversation({ conversationId })
|
|
703
801
|
]);
|
|
704
802
|
const summaries = rawSummaries.sort(
|
|
705
803
|
(left, right) => left.startedAtMs - right.startedAtMs || left.updatedAtMs - right.updatedAtMs || left.sessionId.localeCompare(right.sessionId)
|
|
706
804
|
);
|
|
707
|
-
const
|
|
805
|
+
const runs = await Promise.all(
|
|
708
806
|
summaries.map(async (summary) => {
|
|
709
807
|
const sessionRecord = await getAgentTurnSessionRecord(
|
|
710
808
|
summary.conversationId,
|
|
711
809
|
summary.sessionId
|
|
712
810
|
);
|
|
713
|
-
const scopedMessages = sessionRecord?.piMessages ? turnScopedMessages(
|
|
811
|
+
const scopedMessages = sessionRecord?.piMessages ? turnScopedMessages(
|
|
812
|
+
sessionRecord.piMessages,
|
|
813
|
+
sessionRecord.turnStartMessageIndex
|
|
814
|
+
) : { messages: [], startsAtRunBoundary: false };
|
|
714
815
|
const canExposeTranscript = canExposeConversationTranscript(summary);
|
|
715
816
|
const normalizedTranscript = scopedMessages.messages.map(
|
|
716
817
|
normalizeTranscriptMessage
|
|
717
818
|
);
|
|
718
819
|
const transcriptMessageCount = countConversationMessages(normalizedTranscript);
|
|
719
820
|
const transcript = canExposeTranscript ? [
|
|
720
|
-
...scopedMessages.startsAtRunBoundary && normalizedTranscript.length > 0 ? [systemPromptMessage()] : [],
|
|
821
|
+
...scopedMessages.startsAtRunBoundary && normalizedTranscript.length > 0 && sessionRecord?.destination ? [systemPromptMessage(sessionRecord.destination)] : [],
|
|
721
822
|
...normalizedTranscript
|
|
722
823
|
] : [];
|
|
723
824
|
const transcriptMetadata = canExposeTranscript ? void 0 : normalizedTranscript.map(redactTranscriptMessage);
|
|
724
825
|
const traceId = summary.traceId ?? sessionRecord?.traceId ?? (canExposeTranscript ? traceIdFromTranscript(transcript) : void 0);
|
|
725
826
|
const sentryTraceUrl = traceId ? buildSentryTraceUrl(traceId) : void 0;
|
|
726
|
-
|
|
727
|
-
...sessionReportFromSummary(summary,
|
|
827
|
+
const report = {
|
|
828
|
+
...sessionReportFromSummary(summary, nowMs, details),
|
|
728
829
|
...traceId ? { traceId } : {},
|
|
729
830
|
...sentryTraceUrl ? { sentryTraceUrl } : {},
|
|
730
831
|
transcriptAvailable: Boolean(sessionRecord) && canExposeTranscript,
|
|
@@ -736,15 +837,68 @@ async function readConversation(conversationId) {
|
|
|
736
837
|
} : {},
|
|
737
838
|
transcript
|
|
738
839
|
};
|
|
840
|
+
return conversation ? {
|
|
841
|
+
...report,
|
|
842
|
+
...applyConversationIndexMetadata({
|
|
843
|
+
conversation,
|
|
844
|
+
details,
|
|
845
|
+
nowMs,
|
|
846
|
+
report
|
|
847
|
+
})
|
|
848
|
+
} : report;
|
|
739
849
|
})
|
|
740
850
|
);
|
|
741
|
-
const
|
|
742
|
-
|
|
851
|
+
const effectiveRuns = runs.length > 0 || !conversation ? runs : [
|
|
852
|
+
{
|
|
853
|
+
...sessionReportFromConversation(conversation, nowMs, details),
|
|
854
|
+
transcriptAvailable: false,
|
|
855
|
+
transcript: []
|
|
856
|
+
}
|
|
857
|
+
];
|
|
858
|
+
const firstRun = effectiveRuns[0];
|
|
859
|
+
const displayTitle = firstRun?.displayTitle ?? displayTitleFromDetails(conversationId, details) ?? surfaceFallbackLabel(firstRun?.surface ?? "slack");
|
|
743
860
|
return {
|
|
744
861
|
conversationId,
|
|
745
862
|
displayTitle,
|
|
746
|
-
generatedAt:
|
|
747
|
-
|
|
863
|
+
generatedAt: new Date(nowMs).toISOString(),
|
|
864
|
+
runs: effectiveRuns
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// src/reporting.ts
|
|
869
|
+
function readDescriptionText() {
|
|
870
|
+
try {
|
|
871
|
+
const raw = readFileSync(
|
|
872
|
+
path.join(homeDir(), "DESCRIPTION.md"),
|
|
873
|
+
"utf8"
|
|
874
|
+
).trim();
|
|
875
|
+
return raw || void 0;
|
|
876
|
+
} catch {
|
|
877
|
+
return void 0;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
async function readHealth() {
|
|
881
|
+
const res = GET();
|
|
882
|
+
return await res.json();
|
|
883
|
+
}
|
|
884
|
+
async function readSkills() {
|
|
885
|
+
const skills = await discoverSkills();
|
|
886
|
+
return skills.map((skill) => ({
|
|
887
|
+
name: skill.name,
|
|
888
|
+
pluginProvider: skill.pluginProvider
|
|
889
|
+
}));
|
|
890
|
+
}
|
|
891
|
+
async function readPlugins() {
|
|
892
|
+
return getPluginProviders().map((plugin) => ({
|
|
893
|
+
name: plugin.manifest.name
|
|
894
|
+
}));
|
|
895
|
+
}
|
|
896
|
+
async function readPluginOperationalReports() {
|
|
897
|
+
const nowMs = Date.now();
|
|
898
|
+
return {
|
|
899
|
+
source: "plugins",
|
|
900
|
+
generatedAt: new Date(nowMs).toISOString(),
|
|
901
|
+
reports: await getAgentPluginOperationalReports(nowMs)
|
|
748
902
|
};
|
|
749
903
|
}
|
|
750
904
|
function createJuniorReporting() {
|
|
@@ -766,10 +920,10 @@ function createJuniorReporting() {
|
|
|
766
920
|
},
|
|
767
921
|
getPlugins: readPlugins,
|
|
768
922
|
getSkills: readSkills,
|
|
769
|
-
getSessions:
|
|
770
|
-
getConversationStats:
|
|
923
|
+
getSessions: readConversationFeed,
|
|
924
|
+
getConversationStats: readConversationStatsReport,
|
|
771
925
|
getPluginOperationalReports: readPluginOperationalReports,
|
|
772
|
-
getConversation:
|
|
926
|
+
getConversation: readConversationReport
|
|
773
927
|
};
|
|
774
928
|
}
|
|
775
929
|
export {
|