@sentry/junior 0.102.0 → 0.102.2
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/api/conversations/stats.query.d.ts +1 -1
- package/dist/api/locations/list.d.ts +7 -0
- package/dist/api/locations/schema.d.ts +13 -0
- package/dist/api/people/shared.d.ts +1 -1
- package/dist/api/schema.d.ts +2 -2
- package/dist/api/schema.js +3 -1
- package/dist/api.js +6 -6
- package/dist/app.js +1 -0
- package/dist/{chunk-MR6H67P2.js → chunk-4XNQSJAX.js} +60 -4
- package/dist/{chunk-E4EMFKGB.js → chunk-KFP3TZOS.js} +1 -1
- package/dist/{chunk-HNIT4HXU.js → chunk-WPHCUGN7.js} +10 -1
- package/dist/cli/upgrade.js +286 -0
- package/dist/{detail-U6IP2Z4N.js → detail-V37NTVBN.js} +2 -2
- package/dist/{list-Z3CC52CZ.js → list-FWLIZHSW.js} +2 -2
- package/dist/{list-UMZKA5AI.js → list-NTUT6A5M.js} +1 -1
- package/dist/{profile-CQMPFKED.js → profile-3FRQP4HP.js} +1 -1
- package/dist/{stats-ZYFQFCTL.js → stats-7UFY6FPE.js} +1 -1
- package/migrations/meta/_journal.json +1 -1
- package/package.json +5 -5
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ConversationStatsReport } from "./schema";
|
|
2
|
-
/** Build complete
|
|
2
|
+
/** Build complete 90-day dashboard stats from normalized durable SQL records. */
|
|
3
3
|
export declare function readConversationStatsFromSql(): Promise<ConversationStatsReport>;
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
/** Expose public conversation destinations as the dashboard's location index. */
|
|
2
2
|
export declare function readLocationDirectory(): Promise<{
|
|
3
|
+
activityDays: {
|
|
4
|
+
date: string;
|
|
5
|
+
privateConversations: number;
|
|
6
|
+
publicConversations: number;
|
|
7
|
+
}[];
|
|
3
8
|
generatedAt: string;
|
|
4
9
|
locations: {
|
|
5
10
|
active: number;
|
|
@@ -27,4 +32,6 @@ export declare function readLocationDirectory(): Promise<{
|
|
|
27
32
|
tokens?: number | undefined;
|
|
28
33
|
};
|
|
29
34
|
source: "conversation_index";
|
|
35
|
+
windowEnd: string;
|
|
36
|
+
windowStart: string;
|
|
30
37
|
}>;
|
|
@@ -37,7 +37,17 @@ export declare const locationActorSummaryReportSchema: z.ZodObject<{
|
|
|
37
37
|
slackUserName: z.ZodOptional<z.ZodString>;
|
|
38
38
|
}, z.core.$strict>;
|
|
39
39
|
}, z.core.$strict>;
|
|
40
|
+
export declare const locationActivityDayReportSchema: z.ZodObject<{
|
|
41
|
+
date: z.ZodString;
|
|
42
|
+
privateConversations: z.ZodNumber;
|
|
43
|
+
publicConversations: z.ZodNumber;
|
|
44
|
+
}, z.core.$strict>;
|
|
40
45
|
export declare const locationDirectoryReportSchema: z.ZodObject<{
|
|
46
|
+
activityDays: z.ZodArray<z.ZodObject<{
|
|
47
|
+
date: z.ZodString;
|
|
48
|
+
privateConversations: z.ZodNumber;
|
|
49
|
+
publicConversations: z.ZodNumber;
|
|
50
|
+
}, z.core.$strict>>;
|
|
41
51
|
generatedAt: z.ZodString;
|
|
42
52
|
locations: z.ZodArray<z.ZodObject<{
|
|
43
53
|
active: z.ZodNumber;
|
|
@@ -72,6 +82,8 @@ export declare const locationDirectoryReportSchema: z.ZodObject<{
|
|
|
72
82
|
tokens: z.ZodOptional<z.ZodNumber>;
|
|
73
83
|
}, z.core.$strict>;
|
|
74
84
|
source: z.ZodLiteral<"conversation_index">;
|
|
85
|
+
windowEnd: z.ZodString;
|
|
86
|
+
windowStart: z.ZodString;
|
|
75
87
|
}, z.core.$strict>;
|
|
76
88
|
export declare const locationDetailReportSchema: z.ZodObject<{
|
|
77
89
|
active: z.ZodNumber;
|
|
@@ -171,5 +183,6 @@ export declare const locationDetailReportSchema: z.ZodObject<{
|
|
|
171
183
|
}, z.core.$strict>;
|
|
172
184
|
export type LocationSummaryReport = z.infer<typeof locationSummaryReportSchema>;
|
|
173
185
|
export type LocationActorSummaryReport = z.infer<typeof locationActorSummaryReportSchema>;
|
|
186
|
+
export type LocationActivityDayReport = z.infer<typeof locationActivityDayReportSchema>;
|
|
174
187
|
export type LocationDirectoryReport = z.infer<typeof locationDirectoryReportSchema>;
|
|
175
188
|
export type LocationDetailReport = z.infer<typeof locationDetailReportSchema>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ActorActivityDayReport, ConversationStatsItem, ActorTotalsReport } from "./schema";
|
|
2
2
|
export declare const RECENT_LIMIT = 25;
|
|
3
|
-
export declare const ACTIVITY_DAYS =
|
|
3
|
+
export declare const ACTIVITY_DAYS = 90;
|
|
4
4
|
/** Normalize emails before matching people API rows. */
|
|
5
5
|
export declare function normalizeEmail(email: string | undefined): string | undefined;
|
|
6
6
|
/** Build a zeroed totals object for people API aggregations. */
|
package/dist/api/schema.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export type { DailyConversationActivity } from "./activity";
|
|
|
3
3
|
export { conversationDetailReportSchema, conversationFeedSchema, conversationStatsReportSchema, conversationSubagentTranscriptReportSchema, } from "./conversations/schema";
|
|
4
4
|
export type { ActorIdentity, ConversationActivityReport, ConversationActivityStatus, ConversationContextEvent, ConversationCost, ConversationDetailReport, ConversationFeed, ConversationReportStatus, ConversationStatsItem, ConversationStatsReport, ConversationSubagentActivityReport, ConversationSubagentTranscriptReport, ConversationSummaryReport, ConversationSurface, ConversationToolActivityReport, ConversationUsage, TranscriptMessage, TranscriptPart, TranscriptPartType, TranscriptRole, } from "./conversations/schema";
|
|
5
5
|
export { actorDirectoryReportSchema, actorProfileReportSchema, } from "./people/schema";
|
|
6
|
-
export { locationDetailReportSchema, locationDirectoryReportSchema, } from "./locations/schema";
|
|
7
|
-
export type { LocationActorSummaryReport, LocationDetailReport, LocationDirectoryReport, LocationSummaryReport, } from "./locations/schema";
|
|
6
|
+
export { locationActivityDayReportSchema, locationDetailReportSchema, locationDirectoryReportSchema, } from "./locations/schema";
|
|
7
|
+
export type { LocationActorSummaryReport, LocationActivityDayReport, LocationDetailReport, LocationDirectoryReport, LocationSummaryReport, } from "./locations/schema";
|
|
8
8
|
export type { ActorActivityDayReport, ActorDirectoryReport, ActorProfileReport, ActorSummaryReport, ActorTotalsReport, PeopleActivityDayReport, } from "./people/schema";
|
|
9
9
|
export { healthReportSchema, pluginOperationalReportFeedSchema, pluginOperationalReportSchema, pluginPackageContentItemReportSchema, pluginPackageContentReportSchema, pluginReportSchema, pluginReportsSchema, runtimeInfoReportSchema, skillReportSchema, skillReportsSchema, } from "../reporting-schema";
|
|
10
10
|
export type { HealthReport, PluginOperationalReport, PluginOperationalReportFeed, PluginPackageContentItemReport, PluginPackageContentReport, PluginReport, PluginReports, RuntimeInfoReport, SkillReport, SkillReports, } from "../reporting-schema";
|
package/dist/api/schema.js
CHANGED
|
@@ -7,9 +7,10 @@ import {
|
|
|
7
7
|
} from "../chunk-2RNOB32R.js";
|
|
8
8
|
import {
|
|
9
9
|
dailyConversationActivitySchema,
|
|
10
|
+
locationActivityDayReportSchema,
|
|
10
11
|
locationDetailReportSchema,
|
|
11
12
|
locationDirectoryReportSchema
|
|
12
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-WPHCUGN7.js";
|
|
13
14
|
import {
|
|
14
15
|
actorDirectoryReportSchema,
|
|
15
16
|
actorProfileReportSchema
|
|
@@ -46,6 +47,7 @@ export {
|
|
|
46
47
|
conversationSubagentTranscriptReportSchema,
|
|
47
48
|
dailyConversationActivitySchema,
|
|
48
49
|
healthReportSchema,
|
|
50
|
+
locationActivityDayReportSchema,
|
|
49
51
|
locationDetailReportSchema,
|
|
50
52
|
locationDirectoryReportSchema,
|
|
51
53
|
locationParamsSchema,
|
package/dist/api.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
personParamsSchema,
|
|
6
6
|
subagentParamsSchema
|
|
7
7
|
} from "./chunk-2RNOB32R.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-WPHCUGN7.js";
|
|
9
9
|
import "./chunk-4YN2ZXKB.js";
|
|
10
10
|
import "./chunk-HYDQULR2.js";
|
|
11
11
|
import {
|
|
@@ -134,7 +134,7 @@ function createJuniorApi() {
|
|
|
134
134
|
return Response.json(await readConversationFeed({ actorEmail }));
|
|
135
135
|
});
|
|
136
136
|
app.get("/api/conversations/stats", async () => {
|
|
137
|
-
const { readConversationStats } = await import("./stats-
|
|
137
|
+
const { readConversationStats } = await import("./stats-7UFY6FPE.js");
|
|
138
138
|
return Response.json(await readConversationStats());
|
|
139
139
|
});
|
|
140
140
|
app.get("/api/conversations/:conversationId", async (c) => {
|
|
@@ -159,21 +159,21 @@ function createJuniorApi() {
|
|
|
159
159
|
}
|
|
160
160
|
);
|
|
161
161
|
app.get("/api/people", async () => {
|
|
162
|
-
const { readPeopleList } = await import("./list-
|
|
162
|
+
const { readPeopleList } = await import("./list-NTUT6A5M.js");
|
|
163
163
|
return Response.json(await readPeopleList());
|
|
164
164
|
});
|
|
165
165
|
app.get("/api/people/:email", async (c) => {
|
|
166
166
|
const { email } = parseParams(personParamsSchema, c.req.param());
|
|
167
|
-
const { readPeopleProfile } = await import("./profile-
|
|
167
|
+
const { readPeopleProfile } = await import("./profile-3FRQP4HP.js");
|
|
168
168
|
return Response.json(await readPeopleProfile(email));
|
|
169
169
|
});
|
|
170
170
|
app.get("/api/locations", async () => {
|
|
171
|
-
const { readLocationDirectory } = await import("./list-
|
|
171
|
+
const { readLocationDirectory } = await import("./list-FWLIZHSW.js");
|
|
172
172
|
return Response.json(await readLocationDirectory());
|
|
173
173
|
});
|
|
174
174
|
app.get("/api/locations/:locationId", async (c) => {
|
|
175
175
|
const { locationId } = parseParams(locationParamsSchema, c.req.param());
|
|
176
|
-
const { readLocationDetail } = await import("./detail-
|
|
176
|
+
const { readLocationDetail } = await import("./detail-V37NTVBN.js");
|
|
177
177
|
const report = await readLocationDetail(locationId);
|
|
178
178
|
return report ? Response.json(report) : Response.json({ error: "Location not found." }, { status: 404 });
|
|
179
179
|
});
|
package/dist/app.js
CHANGED
|
@@ -11747,6 +11747,7 @@ function dashboardHostRoutePaths(dashboard) {
|
|
|
11747
11747
|
return [
|
|
11748
11748
|
...pagePaths,
|
|
11749
11749
|
"/favicon.ico",
|
|
11750
|
+
"/_junior/dashboard/avatar.png",
|
|
11750
11751
|
"/_junior/dashboard/client.js",
|
|
11751
11752
|
loginPath,
|
|
11752
11753
|
"/api/health",
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./chunk-F4CQEUTP.js";
|
|
8
8
|
import {
|
|
9
9
|
activityDays
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-WPHCUGN7.js";
|
|
11
11
|
import {
|
|
12
12
|
getDb,
|
|
13
13
|
juniorConversations,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
// src/api/locations/query.ts
|
|
22
22
|
import { and, asc, desc, eq, gte, isNull, sql } from "drizzle-orm";
|
|
23
23
|
var RECENT_LIMIT = 25;
|
|
24
|
-
var ACTIVITY_DAYS =
|
|
24
|
+
var ACTIVITY_DAYS = 90;
|
|
25
25
|
function emptyMetrics() {
|
|
26
26
|
return {
|
|
27
27
|
active: 0,
|
|
@@ -117,9 +117,62 @@ async function directoryRows(db) {
|
|
|
117
117
|
eq(juniorDestinations.id, juniorConversations.destinationId)
|
|
118
118
|
).where(topLevelWhere()).groupBy(...locationGroupBy());
|
|
119
119
|
}
|
|
120
|
+
async function directoryActivityRows(db, start) {
|
|
121
|
+
const date = sql`TO_CHAR(
|
|
122
|
+
${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
|
|
123
|
+
'YYYY-MM-DD'
|
|
124
|
+
)`;
|
|
125
|
+
return db.select({
|
|
126
|
+
conversations: sql`COUNT(*)::integer`,
|
|
127
|
+
date,
|
|
128
|
+
visibility: juniorDestinations.visibility
|
|
129
|
+
}).from(juniorConversations).leftJoin(
|
|
130
|
+
juniorDestinations,
|
|
131
|
+
eq(juniorDestinations.id, juniorConversations.destinationId)
|
|
132
|
+
).where(and(topLevelWhere(), gte(juniorConversations.lastActivityAt, start))).groupBy(date, juniorDestinations.visibility);
|
|
133
|
+
}
|
|
134
|
+
function directoryActivityDays(rows, nowMs) {
|
|
135
|
+
const days = /* @__PURE__ */ new Map();
|
|
136
|
+
for (const row of rows) {
|
|
137
|
+
const day = days.get(row.date) ?? {
|
|
138
|
+
date: row.date,
|
|
139
|
+
privateConversations: 0,
|
|
140
|
+
publicConversations: 0
|
|
141
|
+
};
|
|
142
|
+
if (row.visibility === "public") {
|
|
143
|
+
day.publicConversations += row.conversations;
|
|
144
|
+
} else {
|
|
145
|
+
day.privateConversations += row.conversations;
|
|
146
|
+
}
|
|
147
|
+
days.set(row.date, day);
|
|
148
|
+
}
|
|
149
|
+
const end = new Date(nowMs);
|
|
150
|
+
end.setUTCHours(0, 0, 0, 0);
|
|
151
|
+
const start = new Date(end);
|
|
152
|
+
start.setUTCDate(start.getUTCDate() - (ACTIVITY_DAYS - 1));
|
|
153
|
+
const activity = [];
|
|
154
|
+
for (const cursor = new Date(start); cursor.getTime() <= end.getTime(); cursor.setUTCDate(cursor.getUTCDate() + 1)) {
|
|
155
|
+
const date = cursor.toISOString().slice(0, 10);
|
|
156
|
+
activity.push(
|
|
157
|
+
days.get(date) ?? {
|
|
158
|
+
date,
|
|
159
|
+
privateConversations: 0,
|
|
160
|
+
publicConversations: 0
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return activity;
|
|
165
|
+
}
|
|
120
166
|
async function readLocationDirectoryFromSql() {
|
|
121
167
|
const nowMs = Date.now();
|
|
122
|
-
const
|
|
168
|
+
const end = new Date(nowMs);
|
|
169
|
+
end.setUTCHours(0, 0, 0, 0);
|
|
170
|
+
const start = new Date(end);
|
|
171
|
+
start.setUTCDate(start.getUTCDate() - (ACTIVITY_DAYS - 1));
|
|
172
|
+
const [rows, activityRows] = await Promise.all([
|
|
173
|
+
directoryRows(getDb()),
|
|
174
|
+
directoryActivityRows(getDb(), start)
|
|
175
|
+
]);
|
|
123
176
|
const locations = [];
|
|
124
177
|
const privateActivity = {
|
|
125
178
|
...emptyMetrics(),
|
|
@@ -131,12 +184,15 @@ async function readLocationDirectoryFromSql() {
|
|
|
131
184
|
else addMetrics(privateActivity, row);
|
|
132
185
|
}
|
|
133
186
|
return {
|
|
187
|
+
activityDays: directoryActivityDays(activityRows, nowMs),
|
|
134
188
|
generatedAt: new Date(nowMs).toISOString(),
|
|
135
189
|
locations: locations.sort(
|
|
136
190
|
(left, right) => Date.parse(right.lastSeenAt) - Date.parse(left.lastSeenAt) || right.conversations - left.conversations || left.label.localeCompare(right.label)
|
|
137
191
|
),
|
|
138
192
|
privateActivity,
|
|
139
|
-
source: "conversation_index"
|
|
193
|
+
source: "conversation_index",
|
|
194
|
+
windowEnd: end.toISOString(),
|
|
195
|
+
windowStart: start.toISOString()
|
|
140
196
|
};
|
|
141
197
|
}
|
|
142
198
|
async function recentLocationRows(db, locationId) {
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
// src/api/people/shared.ts
|
|
12
12
|
import { and, asc, desc, eq, sql } from "drizzle-orm";
|
|
13
13
|
var RECENT_LIMIT = 25;
|
|
14
|
-
var ACTIVITY_DAYS =
|
|
14
|
+
var ACTIVITY_DAYS = 90;
|
|
15
15
|
function normalizeEmail(email) {
|
|
16
16
|
const normalized = email?.trim().toLowerCase();
|
|
17
17
|
return normalized || void 0;
|
|
@@ -51,11 +51,19 @@ var locationSummaryReportSchema = conversationStatsItemSchema.extend({
|
|
|
51
51
|
visibility: z2.literal("public")
|
|
52
52
|
}).strict();
|
|
53
53
|
var locationActorSummaryReportSchema = conversationStatsItemSchema.extend({ actor: actorIdentitySchema }).strict();
|
|
54
|
+
var locationActivityDayReportSchema = z2.object({
|
|
55
|
+
date: z2.string(),
|
|
56
|
+
privateConversations: z2.number(),
|
|
57
|
+
publicConversations: z2.number()
|
|
58
|
+
}).strict();
|
|
54
59
|
var locationDirectoryReportSchema = z2.object({
|
|
60
|
+
activityDays: z2.array(locationActivityDayReportSchema),
|
|
55
61
|
generatedAt: z2.string(),
|
|
56
62
|
locations: z2.array(locationSummaryReportSchema),
|
|
57
63
|
privateActivity: conversationStatsItemSchema,
|
|
58
|
-
source: z2.literal("conversation_index")
|
|
64
|
+
source: z2.literal("conversation_index"),
|
|
65
|
+
windowEnd: z2.string(),
|
|
66
|
+
windowStart: z2.string()
|
|
59
67
|
}).strict();
|
|
60
68
|
var locationDetailReportSchema = locationSummaryReportSchema.extend({
|
|
61
69
|
activityDays: z2.array(dailyConversationActivitySchema),
|
|
@@ -70,6 +78,7 @@ var locationDetailReportSchema = locationSummaryReportSchema.extend({
|
|
|
70
78
|
export {
|
|
71
79
|
dailyConversationActivitySchema,
|
|
72
80
|
activityDays,
|
|
81
|
+
locationActivityDayReportSchema,
|
|
73
82
|
locationDirectoryReportSchema,
|
|
74
83
|
locationDetailReportSchema
|
|
75
84
|
};
|
package/dist/cli/upgrade.js
CHANGED
|
@@ -1310,6 +1310,291 @@ var agentTurnSessionActorMigration = {
|
|
|
1310
1310
|
run: migrateAgentTurnSessionActor
|
|
1311
1311
|
};
|
|
1312
1312
|
|
|
1313
|
+
// src/cli/upgrade/migrations/conversation-usage.ts
|
|
1314
|
+
var CONVERSATION_USAGE_REPAIR_BATCH_SIZE = 500;
|
|
1315
|
+
var MAX_SAFE_INTEGER = 9007199254740991;
|
|
1316
|
+
var MAX_FINITE_DOUBLE = "1.7976931348623157e308";
|
|
1317
|
+
var REPAIR_LOCK = "junior:upgrade:repair-conversation-usage";
|
|
1318
|
+
var USAGE_REPAIR_BATCH_SQL = `
|
|
1319
|
+
WITH candidates AS MATERIALIZED (
|
|
1320
|
+
SELECT
|
|
1321
|
+
conversation_id,
|
|
1322
|
+
updated_at,
|
|
1323
|
+
execution_updated_at
|
|
1324
|
+
FROM junior_conversations
|
|
1325
|
+
WHERE parent_conversation_id IS NULL
|
|
1326
|
+
AND execution_status = 'idle'
|
|
1327
|
+
AND conversation_id > $1
|
|
1328
|
+
ORDER BY conversation_id
|
|
1329
|
+
LIMIT $2
|
|
1330
|
+
),
|
|
1331
|
+
-- Occurrence numbers preserve intentional duplicates within one epoch while
|
|
1332
|
+
-- collapsing context copies of the same message across rebuilt epochs.
|
|
1333
|
+
message_occurrences AS (
|
|
1334
|
+
SELECT
|
|
1335
|
+
step.conversation_id,
|
|
1336
|
+
step.payload -> 'message' AS message,
|
|
1337
|
+
row_number() OVER (
|
|
1338
|
+
PARTITION BY
|
|
1339
|
+
step.conversation_id,
|
|
1340
|
+
step.context_epoch,
|
|
1341
|
+
step.payload -> 'message'
|
|
1342
|
+
ORDER BY step.seq
|
|
1343
|
+
) AS occurrence
|
|
1344
|
+
FROM junior_agent_steps AS step
|
|
1345
|
+
INNER JOIN candidates AS candidate
|
|
1346
|
+
ON candidate.conversation_id = step.conversation_id
|
|
1347
|
+
WHERE step.type = 'pi_message'
|
|
1348
|
+
AND step.role = 'assistant'
|
|
1349
|
+
AND jsonb_typeof(step.payload -> 'message' -> 'usage') = 'object'
|
|
1350
|
+
),
|
|
1351
|
+
canonical_messages AS (
|
|
1352
|
+
SELECT DISTINCT conversation_id, message, occurrence
|
|
1353
|
+
FROM message_occurrences
|
|
1354
|
+
),
|
|
1355
|
+
usage_values AS (
|
|
1356
|
+
SELECT
|
|
1357
|
+
conversation_id,
|
|
1358
|
+
CASE
|
|
1359
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'input') = 'number'
|
|
1360
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'input')::numeric))
|
|
1361
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'inputTokens') = 'number'
|
|
1362
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'inputTokens')::numeric))
|
|
1363
|
+
END AS input_tokens,
|
|
1364
|
+
CASE
|
|
1365
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'output') = 'number'
|
|
1366
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'output')::numeric))
|
|
1367
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'outputTokens') = 'number'
|
|
1368
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'outputTokens')::numeric))
|
|
1369
|
+
END AS output_tokens,
|
|
1370
|
+
CASE
|
|
1371
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'cacheRead') = 'number'
|
|
1372
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'cacheRead')::numeric))
|
|
1373
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'cachedInputTokens') = 'number'
|
|
1374
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'cachedInputTokens')::numeric))
|
|
1375
|
+
END AS cached_input_tokens,
|
|
1376
|
+
CASE
|
|
1377
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'cacheWrite') = 'number'
|
|
1378
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'cacheWrite')::numeric))
|
|
1379
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'cacheCreationTokens') = 'number'
|
|
1380
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'cacheCreationTokens')::numeric))
|
|
1381
|
+
END AS cache_creation_tokens,
|
|
1382
|
+
CASE
|
|
1383
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'reasoning') = 'number'
|
|
1384
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'reasoning')::numeric))
|
|
1385
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'reasoningTokens') = 'number'
|
|
1386
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'reasoningTokens')::numeric))
|
|
1387
|
+
END AS reasoning_tokens,
|
|
1388
|
+
CASE
|
|
1389
|
+
WHEN jsonb_typeof(message -> 'usage' -> 'totalTokens') = 'number'
|
|
1390
|
+
THEN greatest(0, floor((message -> 'usage' ->> 'totalTokens')::numeric))
|
|
1391
|
+
END AS total_tokens,
|
|
1392
|
+
CASE WHEN jsonb_typeof(message -> 'usage' -> 'cost' -> 'input') = 'number'
|
|
1393
|
+
THEN greatest(0, (message -> 'usage' -> 'cost' ->> 'input')::numeric)
|
|
1394
|
+
END AS cost_input,
|
|
1395
|
+
CASE WHEN jsonb_typeof(message -> 'usage' -> 'cost' -> 'output') = 'number'
|
|
1396
|
+
THEN greatest(0, (message -> 'usage' -> 'cost' ->> 'output')::numeric)
|
|
1397
|
+
END AS cost_output,
|
|
1398
|
+
CASE WHEN jsonb_typeof(message -> 'usage' -> 'cost' -> 'cacheRead') = 'number'
|
|
1399
|
+
THEN greatest(0, (message -> 'usage' -> 'cost' ->> 'cacheRead')::numeric)
|
|
1400
|
+
END AS cost_cache_read,
|
|
1401
|
+
CASE WHEN jsonb_typeof(message -> 'usage' -> 'cost' -> 'cacheWrite') = 'number'
|
|
1402
|
+
THEN greatest(0, (message -> 'usage' -> 'cost' ->> 'cacheWrite')::numeric)
|
|
1403
|
+
END AS cost_cache_write,
|
|
1404
|
+
CASE WHEN jsonb_typeof(message -> 'usage' -> 'cost' -> 'total') = 'number'
|
|
1405
|
+
THEN greatest(0, (message -> 'usage' -> 'cost' ->> 'total')::numeric)
|
|
1406
|
+
END AS cost_total
|
|
1407
|
+
FROM canonical_messages
|
|
1408
|
+
),
|
|
1409
|
+
rollups AS (
|
|
1410
|
+
SELECT
|
|
1411
|
+
conversation_id,
|
|
1412
|
+
sum(input_tokens) AS input_tokens,
|
|
1413
|
+
sum(output_tokens) AS output_tokens,
|
|
1414
|
+
sum(cached_input_tokens) AS cached_input_tokens,
|
|
1415
|
+
sum(cache_creation_tokens) AS cache_creation_tokens,
|
|
1416
|
+
sum(reasoning_tokens) AS reasoning_tokens,
|
|
1417
|
+
sum(
|
|
1418
|
+
CASE
|
|
1419
|
+
WHEN input_tokens IS NULL
|
|
1420
|
+
AND output_tokens IS NULL
|
|
1421
|
+
AND cached_input_tokens IS NULL
|
|
1422
|
+
AND cache_creation_tokens IS NULL
|
|
1423
|
+
THEN total_tokens
|
|
1424
|
+
END
|
|
1425
|
+
) AS total_only_tokens,
|
|
1426
|
+
round(sum(cost_input), 12) AS cost_input,
|
|
1427
|
+
round(sum(cost_output), 12) AS cost_output,
|
|
1428
|
+
round(sum(cost_cache_read), 12) AS cost_cache_read,
|
|
1429
|
+
round(sum(cost_cache_write), 12) AS cost_cache_write,
|
|
1430
|
+
round(sum(cost_total), 12) AS cost_total
|
|
1431
|
+
FROM usage_values
|
|
1432
|
+
GROUP BY conversation_id
|
|
1433
|
+
HAVING count(input_tokens)
|
|
1434
|
+
+ count(output_tokens)
|
|
1435
|
+
+ count(cached_input_tokens)
|
|
1436
|
+
+ count(cache_creation_tokens)
|
|
1437
|
+
+ count(reasoning_tokens)
|
|
1438
|
+
+ count(total_tokens)
|
|
1439
|
+
+ count(cost_input)
|
|
1440
|
+
+ count(cost_output)
|
|
1441
|
+
+ count(cost_cache_read)
|
|
1442
|
+
+ count(cost_cache_write)
|
|
1443
|
+
+ count(cost_total) > 0
|
|
1444
|
+
),
|
|
1445
|
+
valid_rollups AS (
|
|
1446
|
+
SELECT *
|
|
1447
|
+
FROM rollups
|
|
1448
|
+
WHERE (input_tokens IS NULL OR input_tokens <= ${MAX_SAFE_INTEGER})
|
|
1449
|
+
AND (output_tokens IS NULL OR output_tokens <= ${MAX_SAFE_INTEGER})
|
|
1450
|
+
AND (cached_input_tokens IS NULL OR cached_input_tokens <= ${MAX_SAFE_INTEGER})
|
|
1451
|
+
AND (cache_creation_tokens IS NULL OR cache_creation_tokens <= ${MAX_SAFE_INTEGER})
|
|
1452
|
+
AND (reasoning_tokens IS NULL OR reasoning_tokens <= ${MAX_SAFE_INTEGER})
|
|
1453
|
+
AND (total_only_tokens IS NULL OR total_only_tokens <= ${MAX_SAFE_INTEGER})
|
|
1454
|
+
AND (
|
|
1455
|
+
total_only_tokens IS NULL
|
|
1456
|
+
OR total_only_tokens
|
|
1457
|
+
+ coalesce(input_tokens, 0)
|
|
1458
|
+
+ coalesce(output_tokens, 0)
|
|
1459
|
+
+ coalesce(cached_input_tokens, 0)
|
|
1460
|
+
+ coalesce(cache_creation_tokens, 0) <= ${MAX_SAFE_INTEGER}
|
|
1461
|
+
)
|
|
1462
|
+
AND (cost_input IS NULL OR cost_input <= ${MAX_FINITE_DOUBLE}::numeric)
|
|
1463
|
+
AND (cost_output IS NULL OR cost_output <= ${MAX_FINITE_DOUBLE}::numeric)
|
|
1464
|
+
AND (cost_cache_read IS NULL OR cost_cache_read <= ${MAX_FINITE_DOUBLE}::numeric)
|
|
1465
|
+
AND (cost_cache_write IS NULL OR cost_cache_write <= ${MAX_FINITE_DOUBLE}::numeric)
|
|
1466
|
+
AND (cost_total IS NULL OR cost_total <= ${MAX_FINITE_DOUBLE}::numeric)
|
|
1467
|
+
),
|
|
1468
|
+
normalized AS (
|
|
1469
|
+
SELECT
|
|
1470
|
+
conversation_id,
|
|
1471
|
+
jsonb_strip_nulls(jsonb_build_object(
|
|
1472
|
+
'inputTokens', CASE WHEN total_only_tokens IS NULL THEN input_tokens END,
|
|
1473
|
+
'outputTokens', CASE WHEN total_only_tokens IS NULL THEN output_tokens END,
|
|
1474
|
+
'cachedInputTokens', CASE
|
|
1475
|
+
WHEN total_only_tokens IS NULL THEN cached_input_tokens
|
|
1476
|
+
END,
|
|
1477
|
+
'cacheCreationTokens', CASE
|
|
1478
|
+
WHEN total_only_tokens IS NULL THEN cache_creation_tokens
|
|
1479
|
+
END,
|
|
1480
|
+
'reasoningTokens', reasoning_tokens,
|
|
1481
|
+
'totalTokens', CASE
|
|
1482
|
+
WHEN total_only_tokens IS NOT NULL
|
|
1483
|
+
THEN total_only_tokens
|
|
1484
|
+
+ coalesce(input_tokens, 0)
|
|
1485
|
+
+ coalesce(output_tokens, 0)
|
|
1486
|
+
+ coalesce(cached_input_tokens, 0)
|
|
1487
|
+
+ coalesce(cache_creation_tokens, 0)
|
|
1488
|
+
END,
|
|
1489
|
+
'cost', CASE
|
|
1490
|
+
WHEN cost_input IS NULL
|
|
1491
|
+
AND cost_output IS NULL
|
|
1492
|
+
AND cost_cache_read IS NULL
|
|
1493
|
+
AND cost_cache_write IS NULL
|
|
1494
|
+
AND cost_total IS NULL
|
|
1495
|
+
THEN NULL
|
|
1496
|
+
ELSE jsonb_strip_nulls(jsonb_build_object(
|
|
1497
|
+
'input', cost_input,
|
|
1498
|
+
'output', cost_output,
|
|
1499
|
+
'cacheRead', cost_cache_read,
|
|
1500
|
+
'cacheWrite', cost_cache_write,
|
|
1501
|
+
'total', cost_total
|
|
1502
|
+
))
|
|
1503
|
+
END
|
|
1504
|
+
)) AS usage
|
|
1505
|
+
FROM valid_rollups
|
|
1506
|
+
),
|
|
1507
|
+
matched AS MATERIALIZED (
|
|
1508
|
+
SELECT conversation.conversation_id
|
|
1509
|
+
FROM junior_conversations AS conversation
|
|
1510
|
+
INNER JOIN candidates AS candidate USING (conversation_id)
|
|
1511
|
+
INNER JOIN normalized USING (conversation_id)
|
|
1512
|
+
WHERE conversation.execution_status = 'idle'
|
|
1513
|
+
AND conversation.updated_at = candidate.updated_at
|
|
1514
|
+
AND conversation.execution_updated_at IS NOT DISTINCT FROM candidate.execution_updated_at
|
|
1515
|
+
FOR UPDATE OF conversation
|
|
1516
|
+
),
|
|
1517
|
+
updated AS (
|
|
1518
|
+
UPDATE junior_conversations AS conversation
|
|
1519
|
+
SET usage_json = normalized.usage
|
|
1520
|
+
FROM normalized
|
|
1521
|
+
INNER JOIN matched USING (conversation_id)
|
|
1522
|
+
WHERE conversation.conversation_id = normalized.conversation_id
|
|
1523
|
+
AND conversation.usage_json IS DISTINCT FROM normalized.usage
|
|
1524
|
+
RETURNING conversation.conversation_id
|
|
1525
|
+
)
|
|
1526
|
+
SELECT
|
|
1527
|
+
candidate.conversation_id AS "conversationId",
|
|
1528
|
+
updated.conversation_id IS NOT NULL AS changed,
|
|
1529
|
+
matched.conversation_id IS NOT NULL AS matched,
|
|
1530
|
+
normalized.conversation_id IS NOT NULL AS repairable
|
|
1531
|
+
FROM candidates AS candidate
|
|
1532
|
+
LEFT JOIN normalized USING (conversation_id)
|
|
1533
|
+
LEFT JOIN matched USING (conversation_id)
|
|
1534
|
+
LEFT JOIN updated USING (conversation_id)
|
|
1535
|
+
ORDER BY candidate.conversation_id
|
|
1536
|
+
`;
|
|
1537
|
+
async function repairConversationUsage(_context, options = {}) {
|
|
1538
|
+
let executor = options.executor;
|
|
1539
|
+
let closeExecutor;
|
|
1540
|
+
if (!executor) {
|
|
1541
|
+
const { sql } = getChatConfig();
|
|
1542
|
+
executor = createJuniorSqlExecutor({
|
|
1543
|
+
connectionString: sql.databaseUrl,
|
|
1544
|
+
driver: sql.driver
|
|
1545
|
+
});
|
|
1546
|
+
closeExecutor = () => executor.close();
|
|
1547
|
+
}
|
|
1548
|
+
const batchSize = Math.max(
|
|
1549
|
+
1,
|
|
1550
|
+
Math.floor(options.batchSize ?? CONVERSATION_USAGE_REPAIR_BATCH_SIZE)
|
|
1551
|
+
);
|
|
1552
|
+
try {
|
|
1553
|
+
let cursor = "";
|
|
1554
|
+
let existing = 0;
|
|
1555
|
+
let migrated = 0;
|
|
1556
|
+
let missing = 0;
|
|
1557
|
+
let scanned = 0;
|
|
1558
|
+
let skipped = 0;
|
|
1559
|
+
while (true) {
|
|
1560
|
+
const sources = await executor.withLock(
|
|
1561
|
+
REPAIR_LOCK,
|
|
1562
|
+
() => executor.query(USAGE_REPAIR_BATCH_SQL, [
|
|
1563
|
+
cursor,
|
|
1564
|
+
batchSize
|
|
1565
|
+
])
|
|
1566
|
+
);
|
|
1567
|
+
if (sources.length === 0) break;
|
|
1568
|
+
scanned += sources.length;
|
|
1569
|
+
for (const source of sources) {
|
|
1570
|
+
if (!source.repairable) {
|
|
1571
|
+
missing += 1;
|
|
1572
|
+
} else if (source.changed) {
|
|
1573
|
+
migrated += 1;
|
|
1574
|
+
} else if (source.matched) {
|
|
1575
|
+
existing += 1;
|
|
1576
|
+
} else {
|
|
1577
|
+
skipped += 1;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
cursor = sources.at(-1).conversationId;
|
|
1581
|
+
}
|
|
1582
|
+
return {
|
|
1583
|
+
existing,
|
|
1584
|
+
migrated,
|
|
1585
|
+
missing,
|
|
1586
|
+
scanned,
|
|
1587
|
+
...skipped > 0 ? { skipped } : {}
|
|
1588
|
+
};
|
|
1589
|
+
} finally {
|
|
1590
|
+
await closeExecutor?.();
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
var conversationUsageRepairMigration = {
|
|
1594
|
+
name: "repair-conversation-usage",
|
|
1595
|
+
run: repairConversationUsage
|
|
1596
|
+
};
|
|
1597
|
+
|
|
1313
1598
|
// src/cli/upgrade.ts
|
|
1314
1599
|
var DEFAULT_IO = {
|
|
1315
1600
|
info: console.log
|
|
@@ -1321,6 +1606,7 @@ var MIGRATIONS = [
|
|
|
1321
1606
|
coreSqlSchemaMigration,
|
|
1322
1607
|
sqlConversationMigration,
|
|
1323
1608
|
sqlConversationHistoryMigration,
|
|
1609
|
+
conversationUsageRepairMigration,
|
|
1324
1610
|
sqlPluginMigration,
|
|
1325
1611
|
pluginStorageMigration
|
|
1326
1612
|
];
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
readLocationDetailFromSql
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-4XNQSJAX.js";
|
|
4
4
|
import "./chunk-QOZOJNSE.js";
|
|
5
5
|
import "./chunk-F4CQEUTP.js";
|
|
6
6
|
import {
|
|
7
7
|
locationDetailReportSchema
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-WPHCUGN7.js";
|
|
9
9
|
import "./chunk-HYDQULR2.js";
|
|
10
10
|
import "./chunk-PDO5BLNM.js";
|
|
11
11
|
import "./chunk-QZGVPPIJ.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
readLocationDirectoryFromSql
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-4XNQSJAX.js";
|
|
4
4
|
import "./chunk-QOZOJNSE.js";
|
|
5
5
|
import "./chunk-F4CQEUTP.js";
|
|
6
6
|
import {
|
|
7
7
|
locationDirectoryReportSchema
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-WPHCUGN7.js";
|
|
9
9
|
import "./chunk-HYDQULR2.js";
|
|
10
10
|
import "./chunk-PDO5BLNM.js";
|
|
11
11
|
import "./chunk-QZGVPPIJ.js";
|
|
@@ -25,7 +25,7 @@ import "./chunk-MLKGABMK.js";
|
|
|
25
25
|
|
|
26
26
|
// src/api/conversations/stats.query.ts
|
|
27
27
|
import { and, eq, gte, isNull, lte } from "drizzle-orm";
|
|
28
|
-
var WINDOW_MS =
|
|
28
|
+
var WINDOW_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
29
29
|
function emptyStatsItem(label) {
|
|
30
30
|
return {
|
|
31
31
|
active: 0,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/junior",
|
|
3
|
-
"version": "0.102.
|
|
3
|
+
"version": "0.102.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"pg": "^8.16.3",
|
|
76
76
|
"yaml": "^2.9.0",
|
|
77
77
|
"zod": "^4.4.3",
|
|
78
|
-
"@sentry/junior-plugin-api": "0.102.
|
|
78
|
+
"@sentry/junior-plugin-api": "0.102.2"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@emnapi/core": "^1.10.0",
|
|
@@ -92,9 +92,9 @@
|
|
|
92
92
|
"typescript": "^6.0.3",
|
|
93
93
|
"vercel": "^54.4.0",
|
|
94
94
|
"vitest": "^4.1.7",
|
|
95
|
-
"@sentry/junior-
|
|
96
|
-
"@sentry/junior-
|
|
97
|
-
"@sentry/junior-
|
|
95
|
+
"@sentry/junior-memory": "0.102.2",
|
|
96
|
+
"@sentry/junior-github": "0.102.2",
|
|
97
|
+
"@sentry/junior-scheduler": "0.102.2",
|
|
98
98
|
"@sentry/junior-testing": "0.0.0"
|
|
99
99
|
},
|
|
100
100
|
"scripts": {
|