@sentry/junior 0.176.2 → 0.178.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/dist/{agent-hooks-LQZFBXBK.js → agent-hooks-PBT4NNBV.js} +12 -12
- package/dist/api/conversations/archive.d.ts +5 -2
- package/dist/api/conversations/list.d.ts +0 -1
- package/dist/api/conversations/membership.d.ts +14 -0
- package/dist/api/conversations/projection.d.ts +2 -1
- package/dist/api/locations/detail.d.ts +1 -1
- package/dist/api/people/shared.d.ts +2 -2
- package/dist/api/schema/conversation.d.ts +4 -4
- package/dist/api/schema/location.d.ts +1 -1
- package/dist/api/schema/person.d.ts +1 -1
- package/dist/api/schema.js +1 -1
- package/dist/api.js +245 -166
- package/dist/app.js +52 -57
- package/dist/{catalog-runtime-P3DBC3XM.js → catalog-runtime-M7QGKPFZ.js} +5 -5
- package/dist/chat/agent/sandbox.d.ts +2 -0
- package/dist/chat/conversations/sql/participants.d.ts +1 -0
- package/dist/chat/conversations/store.d.ts +0 -1
- package/dist/chat/resource-events/notification.d.ts +6 -1
- package/dist/chat/sandbox/errors.d.ts +4 -0
- package/dist/chat/sandbox/noninteractive-command.d.ts +1 -0
- package/dist/chat/sandbox/prepare-workspace.d.ts +27 -3
- package/dist/chat/sandbox/sandbox.d.ts +2 -0
- package/dist/chat/sandbox/session.d.ts +2 -0
- package/dist/chat/sandbox/snapshot/builder-sandbox.d.ts +5 -0
- package/dist/chat/sandbox/snapshot/install.d.ts +2 -2
- package/dist/chat/sandbox/snapshot/span.d.ts +3 -0
- package/dist/chat/sandbox/snapshot/store.d.ts +20 -17
- package/dist/chat/sandbox/snapshot/waiting-error.d.ts +15 -0
- package/dist/chat/sandbox/snapshot/workspace.d.ts +17 -0
- package/dist/chat/services/workspace-snapshot-wait.d.ts +27 -0
- package/dist/chat/workspaces/types.d.ts +1 -0
- package/dist/{chunk-2PWBS4JK.js → chunk-22T3HB44.js} +1 -1
- package/dist/{chunk-LNV3NNDO.js → chunk-3ZZEPLLB.js} +2 -2
- package/dist/{chunk-DBXTXY2Z.js → chunk-4K6VNP3S.js} +9 -9
- package/dist/{chunk-SZWILPFG.js → chunk-534BO42N.js} +45 -276
- package/dist/{chunk-QWPKRFG6.js → chunk-6OYVH66J.js} +1 -1
- package/dist/{chunk-ESIS6NVJ.js → chunk-ABLODWPO.js} +1 -1
- package/dist/{chunk-LY6QWCJI.js → chunk-AGJ4OQ2V.js} +1 -1
- package/dist/{chunk-KKY2R2QF.js → chunk-AQHSXA3J.js} +331 -2
- package/dist/{chunk-JRDM64UU.js → chunk-AVRWMQ4U.js} +1 -1
- package/dist/{chunk-B2RBW7CX.js → chunk-BFLMRTPD.js} +6 -6
- package/dist/{chunk-HXX3CSGJ.js → chunk-BHHWCNXI.js} +5 -5
- package/dist/{chunk-H5SVUUPE.js → chunk-BUGO42R6.js} +4 -4
- package/dist/{chunk-2XQ45FB2.js → chunk-D3UJTX4U.js} +1 -1
- package/dist/{chunk-V4SBMRZ3.js → chunk-FQ6BMP5P.js} +767 -81
- package/dist/{chunk-AJ6M3LLM.js → chunk-G3CQEUHI.js} +5 -5
- package/dist/{chunk-RHNT2FYF.js → chunk-H6ZXBFGX.js} +1 -1
- package/dist/{chunk-FLBOMXLS.js → chunk-IQRPDKPJ.js} +1 -1
- package/dist/{chunk-OOH45KJS.js → chunk-JVXZ3WDH.js} +6 -6
- package/dist/{chunk-HLEE6JNT.js → chunk-KEQAA42D.js} +1 -1
- package/dist/{chunk-E7MUDWFH.js → chunk-LAOP4EPL.js} +6 -6
- package/dist/{chunk-FIWDSKL2.js → chunk-OGRD5PFM.js} +1 -1
- package/dist/{chunk-MNKXBIIA.js → chunk-PRDKO3QB.js} +124 -13
- package/dist/{chunk-YAB6CALP.js → chunk-QCCLDJHB.js} +8 -8
- package/dist/{chunk-FDA3E627.js → chunk-RE4XWXBV.js} +6 -6
- package/dist/{chunk-WVDCJ26T.js → chunk-RGV6KHDM.js} +4 -4
- package/dist/{chunk-73FXUNOB.js → chunk-RGXOLPWO.js} +1 -1
- package/dist/{chunk-ELEAIRTG.js → chunk-TKB25A3L.js} +2 -2
- package/dist/{chunk-UZM72ORS.js → chunk-U3UDPGZG.js} +2 -2
- package/dist/{chunk-PLJ3UO67.js → chunk-UGWBJAGN.js} +1 -1
- package/dist/{chunk-OJQTYDDD.js → chunk-UMG7M32G.js} +19 -19
- package/dist/{chunk-MOVIDCPX.js → chunk-XCNS3CXE.js} +11 -17
- package/dist/{chunk-TRG4RCTT.js → chunk-XWUJWHFD.js} +204 -100
- package/dist/{chunk-2KSPJ6EE.js → chunk-ZCHHVTMF.js} +14 -5
- package/dist/cli/chat.js +31 -30
- package/dist/cli/check.js +6 -6
- package/dist/cli/plugins.js +13 -13
- package/dist/cli/snapshot-create.js +10 -10
- package/dist/cli/upgrade.js +7 -7
- package/dist/db/schema/conversation-participants.d.ts +17 -0
- package/dist/db/schema/conversations.d.ts +629 -1
- package/dist/db/schema/snapshots.d.ts +1 -1
- package/dist/db/schema.d.ts +18 -1
- package/dist/{db-ATGRVFSI.js → db-QVYOWATH.js} +7 -7
- package/dist/instrumentation.js +4 -4
- package/dist/nitro.js +2 -2
- package/dist/{oauth-callback-server-55TYSRIZ.js → oauth-callback-server-PLPAFXO6.js} +23 -23
- package/dist/{runner-FD4BRECW.js → runner-AGNEIOZS.js} +15 -15
- package/dist/{skills-5YY7QYV6.js → skills-U5KQ66EM.js} +6 -6
- package/dist/spawn-ZRYYZP2B.js +37 -0
- package/dist/{validation-KH5UQUV4.js → validation-QE4U45KS.js} +6 -6
- package/dist/version.js +1 -1
- package/dist/{work-5LWDUEO4.js → work-ATAXAHJJ.js} +18 -18
- package/dist/worker-LIL5AOER.js +24 -0
- package/migrations/0033_workspace_snapshot_active_build.sql +1 -0
- package/migrations/0034_strong_randall.sql +31 -0
- package/migrations/meta/0033_snapshot.json +2914 -0
- package/migrations/meta/0034_snapshot.json +3038 -0
- package/migrations/meta/_journal.json +15 -1
- package/package.json +5 -5
- package/dist/spawn-6IS46YNW.js +0 -37
- package/dist/worker-XKVLTAI2.js +0 -24
package/dist/api.js
CHANGED
|
@@ -41,12 +41,17 @@ import {
|
|
|
41
41
|
workspaceListSchema,
|
|
42
42
|
workspaceParamsSchema,
|
|
43
43
|
workspaceSchema
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-TKB25A3L.js";
|
|
45
45
|
import {
|
|
46
46
|
appendAndEnqueueApiConversationMessage,
|
|
47
47
|
authenticatePersonalToken,
|
|
48
|
+
conversationArchiveTimes,
|
|
49
|
+
conversationArchivedForEmail,
|
|
50
|
+
conversationArchivedForUser,
|
|
48
51
|
conversationHasParticipantEmail,
|
|
49
52
|
conversationHasParticipantUser,
|
|
53
|
+
conversationNotArchivedForEmail,
|
|
54
|
+
conversationNotArchivedForUser,
|
|
50
55
|
createAndEnqueueApiConversation,
|
|
51
56
|
createPersonalToken,
|
|
52
57
|
createVercelAttachmentStorage,
|
|
@@ -59,15 +64,15 @@ import {
|
|
|
59
64
|
revokePersonalToken,
|
|
60
65
|
viewerConversationMembership,
|
|
61
66
|
webActorFromEmail
|
|
62
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-PRDKO3QB.js";
|
|
63
68
|
import {
|
|
64
69
|
buildSentryConversationUrl,
|
|
65
70
|
getWebAuthorization
|
|
66
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-AVRWMQ4U.js";
|
|
67
72
|
import {
|
|
68
73
|
cancelHumanFacingPendingMessages,
|
|
69
74
|
getConversation
|
|
70
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-BUGO42R6.js";
|
|
71
76
|
import {
|
|
72
77
|
readTaskExecutionByConversationId,
|
|
73
78
|
readTaskExecutionDays,
|
|
@@ -75,8 +80,8 @@ import {
|
|
|
75
80
|
readTaskExecutionSummaries,
|
|
76
81
|
readTaskExecutions,
|
|
77
82
|
readTaskRuns
|
|
78
|
-
} from "./chunk-
|
|
79
|
-
import "./chunk-
|
|
83
|
+
} from "./chunk-4K6VNP3S.js";
|
|
84
|
+
import "./chunk-G3CQEUHI.js";
|
|
80
85
|
import {
|
|
81
86
|
healthReportSchema,
|
|
82
87
|
pluginOperationalReportFeedSchema,
|
|
@@ -101,19 +106,19 @@ import {
|
|
|
101
106
|
listPublicScheduledTasksForTeams,
|
|
102
107
|
readLiveAttachment,
|
|
103
108
|
readStats
|
|
104
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-RGV6KHDM.js";
|
|
105
110
|
import {
|
|
106
111
|
parseSlackThreadId
|
|
107
|
-
} from "./chunk-
|
|
112
|
+
} from "./chunk-22T3HB44.js";
|
|
108
113
|
import {
|
|
109
114
|
agentTurnUsageSchema,
|
|
110
115
|
fallbackShortTitle,
|
|
111
116
|
hasAgentTurnUsage,
|
|
112
117
|
renderJuniorNativeConversationEvent
|
|
113
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-BFLMRTPD.js";
|
|
114
119
|
import {
|
|
115
120
|
getCachedSnapshot
|
|
116
|
-
} from "./chunk-
|
|
121
|
+
} from "./chunk-534BO42N.js";
|
|
117
122
|
import "./chunk-PDO5BLNM.js";
|
|
118
123
|
import {
|
|
119
124
|
SANDBOX_RUNTIME,
|
|
@@ -134,7 +139,7 @@ import {
|
|
|
134
139
|
updateWorkspace,
|
|
135
140
|
withSlackRetries,
|
|
136
141
|
workspaceRepoCheckoutPath
|
|
137
|
-
} from "./chunk-
|
|
142
|
+
} from "./chunk-XWUJWHFD.js";
|
|
138
143
|
import "./chunk-3Y47VMHV.js";
|
|
139
144
|
import {
|
|
140
145
|
decodeStoredConversationEvent,
|
|
@@ -142,26 +147,29 @@ import {
|
|
|
142
147
|
getDb,
|
|
143
148
|
getSqlExecutor,
|
|
144
149
|
locationFromRow,
|
|
145
|
-
parseSessionSource
|
|
146
|
-
|
|
150
|
+
parseSessionSource,
|
|
151
|
+
resolveRootConversationId
|
|
152
|
+
} from "./chunk-XCNS3CXE.js";
|
|
147
153
|
import {
|
|
154
|
+
conversationReadColumns,
|
|
148
155
|
juniorConversationEvents,
|
|
156
|
+
juniorConversationParticipants,
|
|
149
157
|
juniorConversations,
|
|
150
158
|
juniorIdentities,
|
|
151
159
|
juniorUsers
|
|
152
|
-
} from "./chunk-
|
|
160
|
+
} from "./chunk-ZCHHVTMF.js";
|
|
153
161
|
import {
|
|
154
162
|
create,
|
|
155
163
|
hash
|
|
156
|
-
} from "./chunk-
|
|
157
|
-
import "./chunk-
|
|
158
|
-
import "./chunk-
|
|
164
|
+
} from "./chunk-AQHSXA3J.js";
|
|
165
|
+
import "./chunk-H6ZXBFGX.js";
|
|
166
|
+
import "./chunk-3ZZEPLLB.js";
|
|
159
167
|
import {
|
|
160
168
|
juniorDestinations
|
|
161
169
|
} from "./chunk-VFUK3X5B.js";
|
|
162
|
-
import "./chunk-
|
|
163
|
-
import "./chunk-
|
|
164
|
-
import "./chunk-
|
|
170
|
+
import "./chunk-KEQAA42D.js";
|
|
171
|
+
import "./chunk-ABLODWPO.js";
|
|
172
|
+
import "./chunk-D3UJTX4U.js";
|
|
165
173
|
import "./chunk-CGA4ERJ5.js";
|
|
166
174
|
import {
|
|
167
175
|
parseSlackChannelId,
|
|
@@ -171,12 +179,12 @@ import {
|
|
|
171
179
|
import {
|
|
172
180
|
logException,
|
|
173
181
|
logWarn
|
|
174
|
-
} from "./chunk-
|
|
182
|
+
} from "./chunk-UGWBJAGN.js";
|
|
175
183
|
import "./chunk-6GWA276C.js";
|
|
176
184
|
import "./chunk-OOUNJNMR.js";
|
|
177
185
|
import "./chunk-H4HBKISO.js";
|
|
178
|
-
import "./chunk-
|
|
179
|
-
import "./chunk-
|
|
186
|
+
import "./chunk-AGJ4OQ2V.js";
|
|
187
|
+
import "./chunk-IQRPDKPJ.js";
|
|
180
188
|
import "./chunk-MLKGABMK.js";
|
|
181
189
|
|
|
182
190
|
// src/api.ts
|
|
@@ -231,33 +239,91 @@ var requireViewer = createMiddleware(
|
|
|
231
239
|
);
|
|
232
240
|
|
|
233
241
|
// src/api/conversations/archive.ts
|
|
234
|
-
import { and, eq, isNotNull } from "drizzle-orm";
|
|
235
|
-
async function
|
|
236
|
-
const
|
|
237
|
-
|
|
242
|
+
import { and, eq, isNotNull, sql } from "drizzle-orm";
|
|
243
|
+
async function setViewerArchive(args) {
|
|
244
|
+
const executor = getSqlExecutor();
|
|
245
|
+
return await executor.transaction(async () => {
|
|
246
|
+
const db = executor.db();
|
|
247
|
+
const [root] = await db.select({ lastActivityAt: juniorConversations.lastActivityAt }).from(juniorConversations).where(eq(juniorConversations.conversationId, args.rootConversationId)).limit(1).for("update");
|
|
248
|
+
if (!root) return { status: "missing" };
|
|
249
|
+
if (args.archived) {
|
|
250
|
+
if (root.lastActivityAt.getTime() !== Date.parse(args.lastSeenAt)) {
|
|
251
|
+
return { status: "conflict" };
|
|
252
|
+
}
|
|
253
|
+
const archivedAt = /* @__PURE__ */ new Date();
|
|
254
|
+
const lastMessageAt = new Date(args.lastSeenAt);
|
|
255
|
+
await db.insert(juniorConversationParticipants).values({
|
|
256
|
+
archivedAt,
|
|
257
|
+
lastMessageAt,
|
|
258
|
+
rootConversationId: args.rootConversationId,
|
|
259
|
+
userId: args.userId
|
|
260
|
+
}).onConflictDoUpdate({
|
|
261
|
+
target: [
|
|
262
|
+
juniorConversationParticipants.userId,
|
|
263
|
+
juniorConversationParticipants.rootConversationId
|
|
264
|
+
],
|
|
265
|
+
set: {
|
|
266
|
+
archivedAt,
|
|
267
|
+
lastMessageAt: sql`greatest(${juniorConversationParticipants.lastMessageAt}, excluded.last_message_at)`
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
return { archivedAt: archivedAt.toISOString(), status: "updated" };
|
|
271
|
+
}
|
|
272
|
+
await db.update(juniorConversationParticipants).set({ archivedAt: null }).where(
|
|
273
|
+
and(
|
|
274
|
+
eq(juniorConversationParticipants.userId, args.userId),
|
|
275
|
+
eq(
|
|
276
|
+
juniorConversationParticipants.rootConversationId,
|
|
277
|
+
args.rootConversationId
|
|
278
|
+
),
|
|
279
|
+
isNotNull(juniorConversationParticipants.archivedAt)
|
|
280
|
+
)
|
|
281
|
+
);
|
|
282
|
+
return { archivedAt: null, status: "updated" };
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
async function readConversationArchivedAt(viewer, conversationId) {
|
|
286
|
+
const rootConversationId = await resolveRootConversationId(
|
|
287
|
+
getSqlExecutor(),
|
|
288
|
+
conversationId
|
|
289
|
+
);
|
|
290
|
+
const [row] = await getDb().select({ archivedAt: juniorConversationParticipants.archivedAt }).from(juniorConversationParticipants).where(
|
|
238
291
|
and(
|
|
239
|
-
eq(
|
|
240
|
-
|
|
292
|
+
eq(juniorConversationParticipants.userId, viewer.id),
|
|
293
|
+
eq(
|
|
294
|
+
juniorConversationParticipants.rootConversationId,
|
|
295
|
+
rootConversationId
|
|
296
|
+
)
|
|
241
297
|
)
|
|
242
|
-
).
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
async function archiveConversation(conversationId, body) {
|
|
253
|
-
const result = await archiveIfUnchanged({ ...body, conversationId });
|
|
254
|
-
if (result === "not_found") {
|
|
298
|
+
).limit(1);
|
|
299
|
+
return row?.archivedAt?.getTime();
|
|
300
|
+
}
|
|
301
|
+
async function archiveConversation(viewer, conversationId, body) {
|
|
302
|
+
const access = await readConversationAccessFromSql(
|
|
303
|
+
getDb(),
|
|
304
|
+
[conversationId],
|
|
305
|
+
viewer
|
|
306
|
+
);
|
|
307
|
+
if (!access.get(conversationId)?.isParticipant) {
|
|
255
308
|
throwApiError(404, "Conversation not found.");
|
|
256
309
|
}
|
|
257
|
-
|
|
258
|
-
|
|
310
|
+
const rootConversationId = await resolveRootConversationId(
|
|
311
|
+
getSqlExecutor(),
|
|
312
|
+
conversationId
|
|
313
|
+
);
|
|
314
|
+
const result = await setViewerArchive({
|
|
315
|
+
archived: body.archived,
|
|
316
|
+
lastSeenAt: body.lastSeenAt,
|
|
317
|
+
rootConversationId,
|
|
318
|
+
userId: viewer.id
|
|
319
|
+
});
|
|
320
|
+
if (result.status === "updated") {
|
|
321
|
+
return { archivedAt: result.archivedAt };
|
|
322
|
+
}
|
|
323
|
+
if (result.status === "missing") {
|
|
324
|
+
throwApiError(404, "Conversation not found.");
|
|
259
325
|
}
|
|
260
|
-
|
|
326
|
+
throwApiError(409, "Conversation received new activity.");
|
|
261
327
|
}
|
|
262
328
|
|
|
263
329
|
// src/api/conversations/attachments.ts
|
|
@@ -480,31 +546,31 @@ async function resolveSlackTeamDomains(teamIds) {
|
|
|
480
546
|
}
|
|
481
547
|
|
|
482
548
|
// src/chat/pi/sql-model-usage.ts
|
|
483
|
-
import { and as and2, eq as eq2, sql } from "drizzle-orm";
|
|
484
|
-
var message =
|
|
485
|
-
var usage =
|
|
486
|
-
var cost =
|
|
549
|
+
import { and as and2, eq as eq2, sql as sql2 } from "drizzle-orm";
|
|
550
|
+
var message = sql2`${juniorConversationEvents.payload}`;
|
|
551
|
+
var usage = sql2`${message}->'usage'`;
|
|
552
|
+
var cost = sql2`${usage}->'cost'`;
|
|
487
553
|
function nonnegativeNumber(source, field, fallbackField, floor = false) {
|
|
488
|
-
const value = (name) =>
|
|
554
|
+
const value = (name) => sql2`case
|
|
489
555
|
when jsonb_typeof(${source}->${name}) = 'number'
|
|
490
556
|
and (${source}->>${name})::numeric >= 0
|
|
491
|
-
then ${floor ?
|
|
557
|
+
then ${floor ? sql2`floor((${source}->>${name})::numeric)` : sql2`(${source}->>${name})::numeric`}
|
|
492
558
|
end`;
|
|
493
559
|
const primary = value(field);
|
|
494
|
-
return fallbackField ?
|
|
560
|
+
return fallbackField ? sql2`coalesce(${primary}, ${value(fallbackField)})` : sql2`${primary}`;
|
|
495
561
|
}
|
|
496
562
|
function token(field, fallbackField) {
|
|
497
563
|
return nonnegativeNumber(usage, field, fallbackField, true);
|
|
498
564
|
}
|
|
499
565
|
function summed(value) {
|
|
500
|
-
return
|
|
566
|
+
return sql2`sum(${value})::double precision`;
|
|
501
567
|
}
|
|
502
568
|
function summedCost(value) {
|
|
503
|
-
return
|
|
569
|
+
return sql2`round(sum(${value}), 12)::double precision`;
|
|
504
570
|
}
|
|
505
571
|
function messageTotalTokens(args) {
|
|
506
572
|
const { input, output, cacheRead, cacheWrite } = args;
|
|
507
|
-
return
|
|
573
|
+
return sql2`case
|
|
508
574
|
when ${input} is not null
|
|
509
575
|
or ${output} is not null
|
|
510
576
|
or ${cacheRead} is not null
|
|
@@ -547,7 +613,7 @@ function usageFromRow(row) {
|
|
|
547
613
|
return hasAgentTurnUsage(result) ? agentTurnUsageSchema.parse(result) : void 0;
|
|
548
614
|
}
|
|
549
615
|
async function readConversationModelUsageFromSql(executor, options) {
|
|
550
|
-
const modelId =
|
|
616
|
+
const modelId = sql2`case
|
|
551
617
|
when position('/' in coalesce(${message}->>'model', '')) > 0
|
|
552
618
|
then ${message}->>'model'
|
|
553
619
|
else concat(${message}->>'provider', '/', ${message}->>'model')
|
|
@@ -586,10 +652,10 @@ async function readConversationModelUsageFromSql(executor, options) {
|
|
|
586
652
|
and2(
|
|
587
653
|
options.includeDescendants ? eq2(juniorConversations.rootConversationId, options.conversationId) : eq2(juniorConversationEvents.conversationId, options.conversationId),
|
|
588
654
|
eq2(juniorConversationEvents.type, "assistant_message"),
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
655
|
+
sql2`jsonb_typeof(${message}->'provider') = 'string'`,
|
|
656
|
+
sql2`jsonb_typeof(${message}->'model') = 'string'`,
|
|
657
|
+
sql2`coalesce(${message}->>'provider', '') <> ''`,
|
|
658
|
+
sql2`coalesce(${message}->>'model', '') <> ''`
|
|
593
659
|
)
|
|
594
660
|
).groupBy(modelId).orderBy(modelId);
|
|
595
661
|
return rows.flatMap((row) => {
|
|
@@ -654,7 +720,7 @@ import {
|
|
|
654
720
|
getTableColumns,
|
|
655
721
|
inArray,
|
|
656
722
|
lt,
|
|
657
|
-
sql as
|
|
723
|
+
sql as sql3
|
|
658
724
|
} from "drizzle-orm";
|
|
659
725
|
|
|
660
726
|
// src/api/conversations/events.ts
|
|
@@ -1065,7 +1131,7 @@ async function readConversationEventRows(executor, args) {
|
|
|
1065
1131
|
return executor.db().select({
|
|
1066
1132
|
...conversationEventColumns,
|
|
1067
1133
|
// Replacement history is model context, never dashboard report data.
|
|
1068
|
-
payload:
|
|
1134
|
+
payload: sql3`case
|
|
1069
1135
|
when ${juniorConversationEvents.type} in ('compaction', 'handoff')
|
|
1070
1136
|
then jsonb_set(
|
|
1071
1137
|
${juniorConversationEvents.payload},
|
|
@@ -1083,11 +1149,11 @@ async function readConversationEventRows(executor, args) {
|
|
|
1083
1149
|
args.types ?? [...conversationReportSourceEventTypes]
|
|
1084
1150
|
),
|
|
1085
1151
|
args.subagentInvocationIds === void 0 ? void 0 : inArray(
|
|
1086
|
-
|
|
1152
|
+
sql3`${juniorConversationEvents.payload}->>'subagentInvocationId'`,
|
|
1087
1153
|
args.subagentInvocationIds
|
|
1088
1154
|
),
|
|
1089
1155
|
args.toolCallIds === void 0 ? void 0 : inArray(
|
|
1090
|
-
|
|
1156
|
+
sql3`${juniorConversationEvents.payload}->>'toolCallId'`,
|
|
1091
1157
|
args.toolCallIds
|
|
1092
1158
|
)
|
|
1093
1159
|
)
|
|
@@ -1167,7 +1233,7 @@ async function readConversationEventPage(executor, args) {
|
|
|
1167
1233
|
}
|
|
1168
1234
|
|
|
1169
1235
|
// src/api/conversations/list.ts
|
|
1170
|
-
import { and as and7, asc as asc2, desc as desc2, eq as eq7,
|
|
1236
|
+
import { and as and7, asc as asc2, desc as desc2, eq as eq7, isNull as isNull3, sql as sql7 } from "drizzle-orm";
|
|
1171
1237
|
|
|
1172
1238
|
// src/api/conversations/shared.ts
|
|
1173
1239
|
function slackStatsLocationLabel(input) {
|
|
@@ -1341,7 +1407,7 @@ function conversationSummaryFromStoredConversation(args) {
|
|
|
1341
1407
|
...usage3 ? { cumulativeUsage: usage3 } : {},
|
|
1342
1408
|
...actorIdentity ? { actorIdentity } : {},
|
|
1343
1409
|
...sourceUrl ? { sourceUrl } : {},
|
|
1344
|
-
|
|
1410
|
+
archivedAt: args.archivedAtMs === void 0 ? null : new Date(args.archivedAtMs).toISOString(),
|
|
1345
1411
|
...slackThread ? { channel: slackThread.channelId } : {},
|
|
1346
1412
|
...channelName ? { channelName } : {},
|
|
1347
1413
|
...channelNameRedacted ? { channelNameRedacted: true } : {},
|
|
@@ -1350,7 +1416,7 @@ function conversationSummaryFromStoredConversation(args) {
|
|
|
1350
1416
|
}
|
|
1351
1417
|
|
|
1352
1418
|
// src/api/conversations/usage.ts
|
|
1353
|
-
import { and as and4, eq as eq4, inArray as inArray2, isNull, sql as
|
|
1419
|
+
import { and as and4, eq as eq4, inArray as inArray2, isNull, sql as sql4 } from "drizzle-orm";
|
|
1354
1420
|
import { alias } from "drizzle-orm/pg-core";
|
|
1355
1421
|
var usage2 = juniorConversations.usage;
|
|
1356
1422
|
var metricRootConversation = alias(
|
|
@@ -1364,10 +1430,10 @@ var componentFields = [
|
|
|
1364
1430
|
"cacheCreationTokens"
|
|
1365
1431
|
];
|
|
1366
1432
|
function summedUsageNumber(field) {
|
|
1367
|
-
return
|
|
1433
|
+
return sql4`sum((${usage2}->>${field})::double precision)::double precision`;
|
|
1368
1434
|
}
|
|
1369
1435
|
function summedCostNumber(field) {
|
|
1370
|
-
return
|
|
1436
|
+
return sql4`round(
|
|
1371
1437
|
sum((${usage2}->'cost'->>${field})::numeric),
|
|
1372
1438
|
12
|
|
1373
1439
|
)::double precision`;
|
|
@@ -1397,7 +1463,7 @@ function usageFromAggregate(row) {
|
|
|
1397
1463
|
}
|
|
1398
1464
|
async function readRootConversationMetricsFromSql(db, rootConversationIds) {
|
|
1399
1465
|
if (rootConversationIds.length === 0) return /* @__PURE__ */ new Map();
|
|
1400
|
-
const hasComponents =
|
|
1466
|
+
const hasComponents = sql4`coalesce(
|
|
1401
1467
|
${usage2}->>'inputTokens',
|
|
1402
1468
|
${usage2}->>'outputTokens',
|
|
1403
1469
|
${usage2}->>'cachedInputTokens',
|
|
@@ -1405,12 +1471,12 @@ async function readRootConversationMetricsFromSql(db, rootConversationIds) {
|
|
|
1405
1471
|
) is not null`;
|
|
1406
1472
|
const rows = await db.select({
|
|
1407
1473
|
rootConversationId: juniorConversations.rootConversationId,
|
|
1408
|
-
durationMs:
|
|
1474
|
+
durationMs: sql4`coalesce(sum(${juniorConversations.durationMs}), 0)::double precision`,
|
|
1409
1475
|
inputTokens: summedUsageNumber("inputTokens"),
|
|
1410
1476
|
outputTokens: summedUsageNumber("outputTokens"),
|
|
1411
1477
|
cachedInputTokens: summedUsageNumber("cachedInputTokens"),
|
|
1412
1478
|
cacheCreationTokens: summedUsageNumber("cacheCreationTokens"),
|
|
1413
|
-
totalOnlyTokens:
|
|
1479
|
+
totalOnlyTokens: sql4`sum(
|
|
1414
1480
|
case
|
|
1415
1481
|
when not (${hasComponents})
|
|
1416
1482
|
then (${usage2}->>'totalTokens')::double precision
|
|
@@ -1460,7 +1526,7 @@ import {
|
|
|
1460
1526
|
isNotNull as isNotNull2,
|
|
1461
1527
|
isNull as isNull2,
|
|
1462
1528
|
or,
|
|
1463
|
-
sql as
|
|
1529
|
+
sql as sql5
|
|
1464
1530
|
} from "drizzle-orm";
|
|
1465
1531
|
import { alias as alias2 } from "drizzle-orm/pg-core";
|
|
1466
1532
|
var auxiliaryRootConversation = alias2(
|
|
@@ -1468,7 +1534,7 @@ var auxiliaryRootConversation = alias2(
|
|
|
1468
1534
|
"auxiliary_root_conversation"
|
|
1469
1535
|
);
|
|
1470
1536
|
function eventCost() {
|
|
1471
|
-
return
|
|
1537
|
+
return sql5`CASE
|
|
1472
1538
|
WHEN ${juniorConversationEvents.type} = 'structured_event'
|
|
1473
1539
|
AND jsonb_typeof(${juniorConversationEvents.payload}->'content'->'costUsd') = 'number'
|
|
1474
1540
|
THEN (${juniorConversationEvents.payload}->'content'->>'costUsd')::numeric
|
|
@@ -1481,16 +1547,16 @@ function eventCost() {
|
|
|
1481
1547
|
async function readConversationAuxiliaryCostsFromSql(db, conversationIds, options) {
|
|
1482
1548
|
if (conversationIds.length === 0) return /* @__PURE__ */ new Map();
|
|
1483
1549
|
const selectedIds = [...conversationIds];
|
|
1484
|
-
const conversationId = options.includeDescendants ?
|
|
1550
|
+
const conversationId = options.includeDescendants ? sql5`coalesce(
|
|
1485
1551
|
${auxiliaryRootConversation.conversationId},
|
|
1486
1552
|
${juniorConversations.conversationId}
|
|
1487
|
-
)` :
|
|
1488
|
-
const namespace =
|
|
1553
|
+
)` : sql5`${juniorConversations.conversationId}`;
|
|
1554
|
+
const namespace = sql5`CASE
|
|
1489
1555
|
WHEN ${juniorConversationEvents.type} = 'structured_event'
|
|
1490
1556
|
THEN ${juniorConversationEvents.payload}->>'namespace'
|
|
1491
1557
|
ELSE 'junior'
|
|
1492
1558
|
END`;
|
|
1493
|
-
const name =
|
|
1559
|
+
const name = sql5`CASE
|
|
1494
1560
|
WHEN ${juniorConversationEvents.type} = 'structured_event'
|
|
1495
1561
|
THEN ${juniorConversationEvents.payload}->>'name'
|
|
1496
1562
|
ELSE ${juniorConversationEvents.type}
|
|
@@ -1505,10 +1571,10 @@ async function readConversationAuxiliaryCostsFromSql(db, conversationIds, option
|
|
|
1505
1571
|
) : inArray3(juniorConversations.conversationId, selectedIds);
|
|
1506
1572
|
const rows = await db.select({
|
|
1507
1573
|
conversationId,
|
|
1508
|
-
costUsd:
|
|
1574
|
+
costUsd: sql5`round(sum(${cost2}), 12)::double precision`.mapWith(
|
|
1509
1575
|
Number
|
|
1510
1576
|
),
|
|
1511
|
-
events:
|
|
1577
|
+
events: sql5`count(*)::integer`.mapWith(Number),
|
|
1512
1578
|
name,
|
|
1513
1579
|
namespace
|
|
1514
1580
|
}).from(juniorConversationEvents).innerJoin(
|
|
@@ -1540,7 +1606,7 @@ async function readConversationAuxiliaryCostsFromSql(db, conversationIds, option
|
|
|
1540
1606
|
"turn_routed"
|
|
1541
1607
|
])
|
|
1542
1608
|
),
|
|
1543
|
-
|
|
1609
|
+
sql5`${cost2} >= 0`
|
|
1544
1610
|
)
|
|
1545
1611
|
).groupBy(conversationId, namespace, name).orderBy(conversationId, namespace, name);
|
|
1546
1612
|
const result = /* @__PURE__ */ new Map();
|
|
@@ -1687,15 +1753,15 @@ function isConversationPriority(conversation, nowMs) {
|
|
|
1687
1753
|
}
|
|
1688
1754
|
|
|
1689
1755
|
// src/api/conversations/user-message-activity.ts
|
|
1690
|
-
import { and as and6, eq as eq6, inArray as inArray4, isNotNull as isNotNull3, or as or2, sql as
|
|
1756
|
+
import { and as and6, eq as eq6, inArray as inArray4, isNotNull as isNotNull3, or as or2, sql as sql6 } from "drizzle-orm";
|
|
1691
1757
|
async function readLastUserMessageAtByConversation(db, conversationIds) {
|
|
1692
1758
|
if (conversationIds.length === 0) return /* @__PURE__ */ new Map();
|
|
1693
|
-
const authority =
|
|
1694
|
-
const actorPlatform =
|
|
1695
|
-
const role =
|
|
1759
|
+
const authority = sql6`${juniorConversationEvents.payload}->'provenance'->>'authority'`;
|
|
1760
|
+
const actorPlatform = sql6`${juniorConversationEvents.payload}->'provenance'->'actor'->>'platform'`;
|
|
1761
|
+
const role = sql6`${juniorConversationEvents.payload}->>'role'`;
|
|
1696
1762
|
const rows = await db.select({
|
|
1697
1763
|
conversationId: juniorConversationEvents.conversationId,
|
|
1698
|
-
lastUserMessageAt:
|
|
1764
|
+
lastUserMessageAt: sql6`max(${juniorConversationEvents.createdAt})`
|
|
1699
1765
|
}).from(juniorConversationEvents).where(
|
|
1700
1766
|
and6(
|
|
1701
1767
|
inArray4(juniorConversationEvents.conversationId, conversationIds),
|
|
@@ -1703,7 +1769,7 @@ async function readLastUserMessageAtByConversation(db, conversationIds) {
|
|
|
1703
1769
|
and6(
|
|
1704
1770
|
eq6(juniorConversationEvents.type, "user_message"),
|
|
1705
1771
|
eq6(authority, "instruction"),
|
|
1706
|
-
|
|
1772
|
+
sql6`${actorPlatform} in ('slack', 'local', 'web')`
|
|
1707
1773
|
),
|
|
1708
1774
|
and6(
|
|
1709
1775
|
eq6(juniorConversationEvents.type, "message"),
|
|
@@ -1723,22 +1789,28 @@ async function readLastUserMessageAtByConversation(db, conversationIds) {
|
|
|
1723
1789
|
|
|
1724
1790
|
// src/api/conversations/list.ts
|
|
1725
1791
|
var CONVERSATION_FEED_LIMIT = 50;
|
|
1726
|
-
function conversationFeedMembershipFilter(filter) {
|
|
1727
|
-
if (!filter) return void 0;
|
|
1792
|
+
function conversationFeedMembershipFilter(status, filter) {
|
|
1793
|
+
if (!filter) return status === "archived" ? sql7`false` : void 0;
|
|
1728
1794
|
if (filter.kind === "viewer") {
|
|
1729
|
-
return
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1795
|
+
return and7(
|
|
1796
|
+
viewerConversationMembership({
|
|
1797
|
+
actorMatch: eq7(juniorIdentities.userId, filter.userId),
|
|
1798
|
+
participantMatch: conversationHasParticipantUser(filter.userId)
|
|
1799
|
+
}),
|
|
1800
|
+
status === "archived" ? conversationArchivedForUser(filter.userId) : conversationNotArchivedForUser(filter.userId)
|
|
1801
|
+
);
|
|
1733
1802
|
}
|
|
1734
|
-
return
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1803
|
+
return and7(
|
|
1804
|
+
viewerConversationMembership({
|
|
1805
|
+
actorMatch: eq7(juniorUsers.primaryEmailNormalized, filter.email),
|
|
1806
|
+
participantMatch: conversationHasParticipantEmail(filter.email)
|
|
1807
|
+
}),
|
|
1808
|
+
status === "archived" ? conversationArchivedForEmail(filter.email) : conversationNotArchivedForEmail(filter.email)
|
|
1809
|
+
);
|
|
1738
1810
|
}
|
|
1739
1811
|
async function conversationRows(db, limit, status, filter) {
|
|
1740
1812
|
return db.select({
|
|
1741
|
-
conversation:
|
|
1813
|
+
conversation: conversationReadColumns(),
|
|
1742
1814
|
destination: juniorDestinations,
|
|
1743
1815
|
identityDisplayName: juniorIdentities.displayName,
|
|
1744
1816
|
identityEmail: juniorIdentities.email,
|
|
@@ -1756,8 +1828,7 @@ async function conversationRows(db, limit, status, filter) {
|
|
|
1756
1828
|
).leftJoin(juniorUsers, eq7(juniorUsers.id, juniorIdentities.userId)).where(
|
|
1757
1829
|
and7(
|
|
1758
1830
|
isNull3(juniorConversations.parentConversationId),
|
|
1759
|
-
status
|
|
1760
|
-
conversationFeedMembershipFilter(filter)
|
|
1831
|
+
conversationFeedMembershipFilter(status, filter)
|
|
1761
1832
|
)
|
|
1762
1833
|
).orderBy(
|
|
1763
1834
|
desc2(juniorConversations.lastActivityAt),
|
|
@@ -1793,7 +1864,6 @@ function conversationFromRow(row) {
|
|
|
1793
1864
|
},
|
|
1794
1865
|
...actor ? { actor } : {},
|
|
1795
1866
|
...location ? { location } : {},
|
|
1796
|
-
...value.archivedAt ? { archivedAtMs: value.archivedAt.getTime() } : {},
|
|
1797
1867
|
...value.channelName ? { channelName: value.channelName } : {},
|
|
1798
1868
|
...value.source ? { source: value.source } : {},
|
|
1799
1869
|
...sessionSource ? { sessionSource } : {},
|
|
@@ -1804,7 +1874,7 @@ function conversationFromRow(row) {
|
|
|
1804
1874
|
async function readConversationRecordFromSql(conversationId) {
|
|
1805
1875
|
const db = getDb();
|
|
1806
1876
|
const rows = await db.select({
|
|
1807
|
-
conversation:
|
|
1877
|
+
conversation: conversationReadColumns(),
|
|
1808
1878
|
destination: juniorDestinations,
|
|
1809
1879
|
identityDisplayName: juniorIdentities.displayName,
|
|
1810
1880
|
identityEmail: juniorIdentities.email,
|
|
@@ -1847,11 +1917,12 @@ function conversationFeedFilter(options) {
|
|
|
1847
1917
|
async function readConversationFeedFromSql(options = {}) {
|
|
1848
1918
|
const nowMs = Date.now();
|
|
1849
1919
|
const db = getDb();
|
|
1920
|
+
const filter = conversationFeedFilter(options);
|
|
1850
1921
|
const rows = await conversationRows(
|
|
1851
1922
|
db,
|
|
1852
1923
|
options.limit ?? CONVERSATION_FEED_LIMIT,
|
|
1853
1924
|
options.status ?? "active",
|
|
1854
|
-
|
|
1925
|
+
filter
|
|
1855
1926
|
);
|
|
1856
1927
|
const conversations = rows.map((row) => conversationFromRow(row));
|
|
1857
1928
|
const conversationIds = conversations.map(
|
|
@@ -1859,6 +1930,7 @@ async function readConversationFeedFromSql(options = {}) {
|
|
|
1859
1930
|
);
|
|
1860
1931
|
const [
|
|
1861
1932
|
accessByConversation,
|
|
1933
|
+
archiveTimesByConversation,
|
|
1862
1934
|
annotationsByConversation,
|
|
1863
1935
|
auxiliaryCostsByRoot,
|
|
1864
1936
|
metricsByRoot,
|
|
@@ -1867,6 +1939,11 @@ async function readConversationFeedFromSql(options = {}) {
|
|
|
1867
1939
|
lastUserMessageAtByConversation
|
|
1868
1940
|
] = await Promise.all([
|
|
1869
1941
|
readConversationAccessFromSql(db, conversationIds, options.viewer),
|
|
1942
|
+
conversationArchiveTimes(
|
|
1943
|
+
db,
|
|
1944
|
+
conversationIds,
|
|
1945
|
+
filter?.kind === "viewer" ? { userId: filter.userId } : filter?.kind === "actorEmail" ? { email: filter.email } : void 0
|
|
1946
|
+
),
|
|
1870
1947
|
listConversationAnnotationsById(db, conversationIds),
|
|
1871
1948
|
readConversationAuxiliaryCostsFromSql(db, conversationIds, {
|
|
1872
1949
|
includeDescendants: true
|
|
@@ -1897,7 +1974,11 @@ async function readConversationFeedFromSql(options = {}) {
|
|
|
1897
1974
|
const row = rows[index];
|
|
1898
1975
|
const access = accessByConversation.get(conversation.conversationId);
|
|
1899
1976
|
const metrics = metricsByRoot.get(conversation.conversationId);
|
|
1977
|
+
const archivedAtMs = archiveTimesByConversation.get(
|
|
1978
|
+
conversation.conversationId
|
|
1979
|
+
);
|
|
1900
1980
|
const summary = conversationSummaryFromStoredConversation({
|
|
1981
|
+
...archivedAtMs === void 0 ? {} : { archivedAtMs },
|
|
1901
1982
|
conversation,
|
|
1902
1983
|
access,
|
|
1903
1984
|
auxiliaryCosts: auxiliaryCostsByRoot.get(conversation.conversationId),
|
|
@@ -2480,6 +2561,7 @@ function projectConversationDetail(args) {
|
|
|
2480
2561
|
return {
|
|
2481
2562
|
...conversationSummaryFromStoredConversation({
|
|
2482
2563
|
access: args.access,
|
|
2564
|
+
...args.archivedAtMs === void 0 ? {} : { archivedAtMs: args.archivedAtMs },
|
|
2483
2565
|
auxiliaryCosts: args.auxiliaryCosts,
|
|
2484
2566
|
conversation,
|
|
2485
2567
|
durationMs: args.durationMs,
|
|
@@ -2508,6 +2590,7 @@ function projectConversationDetail(args) {
|
|
|
2508
2590
|
async function readConversationDetailFromSql(conversationId, options) {
|
|
2509
2591
|
const record = await readConversationRecordFromSql(conversationId);
|
|
2510
2592
|
if (!record) return void 0;
|
|
2593
|
+
const archivedAtMs = options.viewer ? await readConversationArchivedAt(options.viewer, conversationId) : void 0;
|
|
2511
2594
|
const executor = getSqlExecutor();
|
|
2512
2595
|
const includeDescendantMetrics = record.rootConversationId === conversationId;
|
|
2513
2596
|
const [
|
|
@@ -2550,6 +2633,7 @@ async function readConversationDetailFromSql(conversationId, options) {
|
|
|
2550
2633
|
return projectConversationDetail({
|
|
2551
2634
|
...record,
|
|
2552
2635
|
access,
|
|
2636
|
+
...archivedAtMs === void 0 ? {} : { archivedAtMs },
|
|
2553
2637
|
annotations,
|
|
2554
2638
|
auxiliaryCosts: auxiliaryCostsByConversation.get(conversationId),
|
|
2555
2639
|
durationMs: metrics?.durationMs ?? record.durationMs,
|
|
@@ -2791,20 +2875,20 @@ async function requireConversationPendingMessages(conversationId, options = {})
|
|
|
2791
2875
|
}
|
|
2792
2876
|
|
|
2793
2877
|
// src/api/conversations/stats.query.ts
|
|
2794
|
-
import { and as and9, eq as eq9, gte, isNull as isNull4, lte, sql as
|
|
2878
|
+
import { and as and9, eq as eq9, gte, isNull as isNull4, lte, sql as sql9 } from "drizzle-orm";
|
|
2795
2879
|
import { alias as alias3 } from "drizzle-orm/pg-core";
|
|
2796
2880
|
|
|
2797
2881
|
// src/api/conversations/aggregate.ts
|
|
2798
|
-
import { sql as
|
|
2882
|
+
import { sql as sql8 } from "drizzle-orm";
|
|
2799
2883
|
function usageTokenValue(source, field) {
|
|
2800
|
-
return
|
|
2884
|
+
return sql8`CASE
|
|
2801
2885
|
WHEN ${source.usage}->>${field} IS NOT NULL
|
|
2802
2886
|
THEN (${source.usage}->>${field})::double precision
|
|
2803
2887
|
ELSE NULL
|
|
2804
2888
|
END`;
|
|
2805
2889
|
}
|
|
2806
2890
|
function tokenValue(source) {
|
|
2807
|
-
return
|
|
2891
|
+
return sql8`
|
|
2808
2892
|
CASE
|
|
2809
2893
|
WHEN COALESCE(
|
|
2810
2894
|
${source.usage}->>'inputTokens',
|
|
@@ -2823,7 +2907,7 @@ function tokenValue(source) {
|
|
|
2823
2907
|
`;
|
|
2824
2908
|
}
|
|
2825
2909
|
function costValue(source) {
|
|
2826
|
-
return
|
|
2910
|
+
return sql8`
|
|
2827
2911
|
CASE
|
|
2828
2912
|
WHEN ${source.usage}->'cost'->>'total' IS NOT NULL
|
|
2829
2913
|
THEN (${source.usage}->'cost'->>'total')::double precision
|
|
@@ -2844,34 +2928,34 @@ function costValue(source) {
|
|
|
2844
2928
|
function conversationAggregateColumns(sources) {
|
|
2845
2929
|
const metrics = sources?.metrics ?? juniorConversations;
|
|
2846
2930
|
const roots = sources?.roots ?? juniorConversations;
|
|
2847
|
-
const conversationCount = sources ?
|
|
2931
|
+
const conversationCount = sources ? sql8`COUNT(DISTINCT ${roots.conversationId})` : sql8`COUNT(*)`;
|
|
2848
2932
|
return {
|
|
2849
|
-
active:
|
|
2933
|
+
active: sql8`${conversationCount} FILTER (
|
|
2850
2934
|
WHERE ${roots.executionStatus} NOT IN ('idle', 'failed')
|
|
2851
2935
|
)::integer`,
|
|
2852
|
-
conversations:
|
|
2853
|
-
cachedInputTokens:
|
|
2854
|
-
costUsd:
|
|
2855
|
-
durationMs:
|
|
2856
|
-
failed:
|
|
2936
|
+
conversations: sql8`${conversationCount}::integer`,
|
|
2937
|
+
cachedInputTokens: sql8`SUM(${usageTokenValue(metrics, "cachedInputTokens")})::double precision`,
|
|
2938
|
+
costUsd: sql8`SUM(${costValue(metrics)})::double precision`,
|
|
2939
|
+
durationMs: sql8`COALESCE(SUM(${metrics.durationMs}), 0)::double precision`,
|
|
2940
|
+
failed: sql8`${conversationCount} FILTER (
|
|
2857
2941
|
WHERE ${roots.executionStatus} = 'failed'
|
|
2858
2942
|
)::integer`,
|
|
2859
|
-
inputTokens:
|
|
2860
|
-
tokens:
|
|
2943
|
+
inputTokens: sql8`SUM(${usageTokenValue(metrics, "inputTokens")})::double precision`,
|
|
2944
|
+
tokens: sql8`SUM(${tokenValue(metrics)})::double precision`
|
|
2861
2945
|
};
|
|
2862
2946
|
}
|
|
2863
2947
|
function conversationRangeColumns() {
|
|
2864
2948
|
return {
|
|
2865
|
-
firstSeenAt:
|
|
2949
|
+
firstSeenAt: sql8`MIN(${juniorConversations.createdAt})`.mapWith(
|
|
2866
2950
|
juniorConversations.createdAt
|
|
2867
2951
|
),
|
|
2868
|
-
lastSeenAt:
|
|
2952
|
+
lastSeenAt: sql8`MAX(${juniorConversations.lastActivityAt})`.mapWith(
|
|
2869
2953
|
juniorConversations.lastActivityAt
|
|
2870
2954
|
)
|
|
2871
2955
|
};
|
|
2872
2956
|
}
|
|
2873
2957
|
function conversationActiveDaysColumn() {
|
|
2874
|
-
return
|
|
2958
|
+
return sql8`COUNT(DISTINCT (${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC')::date)::integer`;
|
|
2875
2959
|
}
|
|
2876
2960
|
|
|
2877
2961
|
// src/api/conversations/stats.query.ts
|
|
@@ -3012,7 +3096,7 @@ function guardianStats(rows, endMs) {
|
|
|
3012
3096
|
}
|
|
3013
3097
|
async function aggregateStats(db, start, end) {
|
|
3014
3098
|
const where = statsWhere(start, end);
|
|
3015
|
-
const activityDate =
|
|
3099
|
+
const activityDate = sql9`TO_CHAR(
|
|
3016
3100
|
${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
|
|
3017
3101
|
'YYYY-MM-DD'
|
|
3018
3102
|
)`;
|
|
@@ -3093,23 +3177,23 @@ async function aggregateStats(db, start, end) {
|
|
|
3093
3177
|
return { actorRows, locationRows, metricRows, totals: totalsRows[0] };
|
|
3094
3178
|
}
|
|
3095
3179
|
async function aggregateGuardianStats(db, start, end) {
|
|
3096
|
-
const date =
|
|
3180
|
+
const date = sql9`TO_CHAR(
|
|
3097
3181
|
${juniorConversationEvents.createdAt} AT TIME ZONE 'UTC',
|
|
3098
3182
|
'YYYY-MM-DD'
|
|
3099
3183
|
)`;
|
|
3100
|
-
const decision =
|
|
3101
|
-
const cost2 =
|
|
3184
|
+
const decision = sql9`${juniorConversationEvents.payload}->>'decision'`;
|
|
3185
|
+
const cost2 = sql9`CASE
|
|
3102
3186
|
WHEN jsonb_typeof(${juniorConversationEvents.payload}->'costUsd') = 'number'
|
|
3103
3187
|
THEN (${juniorConversationEvents.payload}->>'costUsd')::double precision
|
|
3104
3188
|
ELSE NULL
|
|
3105
3189
|
END`;
|
|
3106
3190
|
return await db.select({
|
|
3107
|
-
allow:
|
|
3108
|
-
ask:
|
|
3109
|
-
costUsd:
|
|
3191
|
+
allow: sql9`COUNT(*) FILTER (WHERE ${decision} = 'allow')::integer`,
|
|
3192
|
+
ask: sql9`COUNT(*) FILTER (WHERE ${decision} = 'ask')::integer`,
|
|
3193
|
+
costUsd: sql9`SUM(${cost2})::double precision`,
|
|
3110
3194
|
date,
|
|
3111
|
-
deny:
|
|
3112
|
-
requests:
|
|
3195
|
+
deny: sql9`COUNT(*) FILTER (WHERE ${decision} = 'deny')::integer`,
|
|
3196
|
+
requests: sql9`COUNT(*)::integer`
|
|
3113
3197
|
}).from(juniorConversationEvents).where(
|
|
3114
3198
|
and9(
|
|
3115
3199
|
eq9(juniorConversationEvents.type, "guardian_action_reviewed"),
|
|
@@ -3230,6 +3314,7 @@ function createConversationRoutes(options) {
|
|
|
3230
3314
|
);
|
|
3231
3315
|
app.patch(
|
|
3232
3316
|
"/:conversationId/archive",
|
|
3317
|
+
requireViewer,
|
|
3233
3318
|
validateRequest(
|
|
3234
3319
|
"param",
|
|
3235
3320
|
conversationParamsSchema,
|
|
@@ -3241,11 +3326,12 @@ function createConversationRoutes(options) {
|
|
|
3241
3326
|
"Invalid request body."
|
|
3242
3327
|
),
|
|
3243
3328
|
async (context) => {
|
|
3329
|
+
const viewer = context.get("viewer");
|
|
3244
3330
|
const { conversationId } = context.req.valid("param");
|
|
3245
3331
|
const body = context.req.valid("json");
|
|
3246
3332
|
return jsonResponse(
|
|
3247
3333
|
archiveConversationResponseSchema,
|
|
3248
|
-
await archiveConversation(conversationId, body)
|
|
3334
|
+
await archiveConversation(viewer, conversationId, body)
|
|
3249
3335
|
);
|
|
3250
3336
|
}
|
|
3251
3337
|
);
|
|
@@ -3374,7 +3460,7 @@ function createConversationRoutes(options) {
|
|
|
3374
3460
|
import { Hono as Hono2 } from "hono";
|
|
3375
3461
|
|
|
3376
3462
|
// src/api/locations/query.ts
|
|
3377
|
-
import { and as and10, asc as asc3, desc as desc3, eq as eq10, gte as gte2, isNull as isNull5, sql as
|
|
3463
|
+
import { and as and10, asc as asc3, desc as desc3, eq as eq10, gte as gte2, isNull as isNull5, sql as sql10 } from "drizzle-orm";
|
|
3378
3464
|
import { alias as alias4 } from "drizzle-orm/pg-core";
|
|
3379
3465
|
|
|
3380
3466
|
// src/api/conversations/reporting.ts
|
|
@@ -3546,12 +3632,12 @@ async function directoryRows(db) {
|
|
|
3546
3632
|
).where(topLevelWhere()).groupBy(...locationGroupBy());
|
|
3547
3633
|
}
|
|
3548
3634
|
async function directoryActivityRows(db, start) {
|
|
3549
|
-
const date =
|
|
3635
|
+
const date = sql10`TO_CHAR(
|
|
3550
3636
|
${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
|
|
3551
3637
|
'YYYY-MM-DD'
|
|
3552
3638
|
)`;
|
|
3553
3639
|
return db.select({
|
|
3554
|
-
conversations:
|
|
3640
|
+
conversations: sql10`COUNT(*)::integer`,
|
|
3555
3641
|
date,
|
|
3556
3642
|
visibility: juniorDestinations.visibility
|
|
3557
3643
|
}).from(juniorConversations).leftJoin(
|
|
@@ -3630,7 +3716,7 @@ async function recentLocationRows(db, locationId) {
|
|
|
3630
3716
|
createdAt: juniorConversations.createdAt,
|
|
3631
3717
|
destinationId: juniorDestinations.id,
|
|
3632
3718
|
durationMs: juniorConversations.durationMs,
|
|
3633
|
-
email:
|
|
3719
|
+
email: sql10`COALESCE(
|
|
3634
3720
|
${juniorUsers.primaryEmailNormalized},
|
|
3635
3721
|
${juniorIdentities.email}
|
|
3636
3722
|
)`,
|
|
@@ -3639,7 +3725,7 @@ async function recentLocationRows(db, locationId) {
|
|
|
3639
3725
|
fullName: juniorUsers.displayName,
|
|
3640
3726
|
handle: juniorIdentities.handle,
|
|
3641
3727
|
lastActivityAt: juniorConversations.lastActivityAt,
|
|
3642
|
-
providerSubjectId:
|
|
3728
|
+
providerSubjectId: sql10`CASE
|
|
3643
3729
|
WHEN ${juniorIdentities.provider} = 'slack'
|
|
3644
3730
|
THEN ${juniorIdentities.providerSubjectId}
|
|
3645
3731
|
ELSE NULL
|
|
@@ -3654,12 +3740,7 @@ async function recentLocationRows(db, locationId) {
|
|
|
3654
3740
|
).leftJoin(
|
|
3655
3741
|
juniorIdentities,
|
|
3656
3742
|
eq10(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
3657
|
-
).leftJoin(juniorUsers, eq10(juniorUsers.id, juniorIdentities.userId)).where(
|
|
3658
|
-
and10(
|
|
3659
|
-
publicLocationWhere(locationId),
|
|
3660
|
-
isNull5(juniorConversations.archivedAt)
|
|
3661
|
-
)
|
|
3662
|
-
).orderBy(
|
|
3743
|
+
).leftJoin(juniorUsers, eq10(juniorUsers.id, juniorIdentities.userId)).where(publicLocationWhere(locationId)).orderBy(
|
|
3663
3744
|
desc3(juniorConversations.lastActivityAt),
|
|
3664
3745
|
asc3(juniorConversations.conversationId)
|
|
3665
3746
|
).limit(RECENT_LIMIT);
|
|
@@ -3671,7 +3752,7 @@ async function readLocationDetailFromSql(locationId, options = {}) {
|
|
|
3671
3752
|
const start = new Date(end);
|
|
3672
3753
|
start.setUTCDate(start.getUTCDate() - (ACTIVITY_DAYS - 1));
|
|
3673
3754
|
const where = publicLocationWhere(locationId);
|
|
3674
|
-
const activityDate =
|
|
3755
|
+
const activityDate = sql10`TO_CHAR(
|
|
3675
3756
|
${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
|
|
3676
3757
|
'YYYY-MM-DD'
|
|
3677
3758
|
)`;
|
|
@@ -3837,10 +3918,10 @@ function createLocationRoutes() {
|
|
|
3837
3918
|
import { Hono as Hono3 } from "hono";
|
|
3838
3919
|
|
|
3839
3920
|
// src/api/people/list.query.ts
|
|
3840
|
-
import { and as and12, eq as eq12, gte as gte3, sql as
|
|
3921
|
+
import { and as and12, eq as eq12, gte as gte3, sql as sql12 } from "drizzle-orm";
|
|
3841
3922
|
|
|
3842
3923
|
// src/api/people/shared.ts
|
|
3843
|
-
import { and as and11, asc as asc4, desc as desc4, eq as eq11, isNull as isNull6, notExists, or as or4, sql as
|
|
3924
|
+
import { and as and11, asc as asc4, desc as desc4, eq as eq11, isNull as isNull6, notExists, or as or4, sql as sql11 } from "drizzle-orm";
|
|
3844
3925
|
import { alias as alias5 } from "drizzle-orm/pg-core";
|
|
3845
3926
|
var RECENT_LIMIT2 = 25;
|
|
3846
3927
|
var ACTIVITY_DAYS2 = 365;
|
|
@@ -3943,7 +4024,7 @@ function verifiedActorWhere(email) {
|
|
|
3943
4024
|
return and11(
|
|
3944
4025
|
eq11(juniorIdentities.provider, "slack"),
|
|
3945
4026
|
eq11(juniorIdentities.emailVerified, true),
|
|
3946
|
-
|
|
4027
|
+
sql11`${juniorUsers.primaryEmailNormalized} IS NOT NULL`,
|
|
3947
4028
|
normalizedEmail ? eq11(juniorUsers.primaryEmailNormalized, normalizedEmail) : void 0
|
|
3948
4029
|
);
|
|
3949
4030
|
}
|
|
@@ -3971,9 +4052,7 @@ async function recentActorRows(email) {
|
|
|
3971
4052
|
).innerJoin(juniorUsers, eq11(juniorUsers.id, juniorIdentities.userId)).leftJoin(
|
|
3972
4053
|
juniorDestinations,
|
|
3973
4054
|
eq11(juniorDestinations.id, juniorConversations.destinationId)
|
|
3974
|
-
).where(
|
|
3975
|
-
and11(verifiedActorWhere(email), isNull6(juniorConversations.archivedAt))
|
|
3976
|
-
).orderBy(
|
|
4055
|
+
).where(verifiedActorWhere(email)).orderBy(
|
|
3977
4056
|
desc4(juniorConversations.lastActivityAt),
|
|
3978
4057
|
asc4(juniorConversations.conversationId)
|
|
3979
4058
|
).limit(RECENT_LIMIT2);
|
|
@@ -4001,7 +4080,7 @@ function directoryActivityDays2(rows, nowMs) {
|
|
|
4001
4080
|
async function readPeopleListFromSql() {
|
|
4002
4081
|
const nowMs = Date.now();
|
|
4003
4082
|
const { end, start } = activityWindow(nowMs);
|
|
4004
|
-
const activityDate =
|
|
4083
|
+
const activityDate = sql12`TO_CHAR(
|
|
4005
4084
|
${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
|
|
4006
4085
|
'YYYY-MM-DD'
|
|
4007
4086
|
)`;
|
|
@@ -4009,8 +4088,8 @@ async function readPeopleListFromSql() {
|
|
|
4009
4088
|
getDb().select({
|
|
4010
4089
|
email: juniorUsers.primaryEmailNormalized,
|
|
4011
4090
|
fullName: juniorUsers.displayName,
|
|
4012
|
-
slackUserId:
|
|
4013
|
-
slackUserName:
|
|
4091
|
+
slackUserId: sql12`MAX(${juniorIdentities.providerSubjectId})`,
|
|
4092
|
+
slackUserName: sql12`MAX(${juniorIdentities.handle})`,
|
|
4014
4093
|
activeDays: conversationActiveDaysColumn(),
|
|
4015
4094
|
...peopleTreeAggregateColumns,
|
|
4016
4095
|
...conversationRangeColumns()
|
|
@@ -4019,8 +4098,8 @@ async function readPeopleListFromSql() {
|
|
|
4019
4098
|
eq12(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
4020
4099
|
).innerJoin(juniorUsers, eq12(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, peopleTreeMetricsJoin()).where(verifiedActorWhere()).groupBy(juniorUsers.primaryEmailNormalized, juniorUsers.displayName),
|
|
4021
4100
|
getDb().select({
|
|
4022
|
-
activePeople:
|
|
4023
|
-
conversations:
|
|
4101
|
+
activePeople: sql12`COUNT(DISTINCT ${juniorUsers.id})::int`,
|
|
4102
|
+
conversations: sql12`COUNT(*)::int`,
|
|
4024
4103
|
date: activityDate
|
|
4025
4104
|
}).from(juniorConversations).innerJoin(
|
|
4026
4105
|
juniorIdentities,
|
|
@@ -4079,7 +4158,7 @@ async function readPeoplePluginReports(args) {
|
|
|
4079
4158
|
source: "plugins"
|
|
4080
4159
|
});
|
|
4081
4160
|
}
|
|
4082
|
-
const { getPluginProfileReports } = await import("./agent-hooks-
|
|
4161
|
+
const { getPluginProfileReports } = await import("./agent-hooks-PBT4NNBV.js");
|
|
4083
4162
|
return pluginOperationalReportFeedSchema.parse({
|
|
4084
4163
|
generatedAt: new Date(nowMs).toISOString(),
|
|
4085
4164
|
reports: await getPluginProfileReports({
|
|
@@ -4092,7 +4171,7 @@ async function readPeoplePluginReports(args) {
|
|
|
4092
4171
|
}
|
|
4093
4172
|
|
|
4094
4173
|
// src/api/people/profile.query.ts
|
|
4095
|
-
import { and as and13, eq as eq13, gte as gte4, sql as
|
|
4174
|
+
import { and as and13, eq as eq13, gte as gte4, sql as sql13 } from "drizzle-orm";
|
|
4096
4175
|
function emptyProfile(email, nowMs) {
|
|
4097
4176
|
const end = new Date(nowMs);
|
|
4098
4177
|
end.setUTCHours(0, 0, 0, 0);
|
|
@@ -4127,7 +4206,7 @@ function addAggregate2(map, label, row) {
|
|
|
4127
4206
|
map.set(label, item);
|
|
4128
4207
|
}
|
|
4129
4208
|
function surfaceExpression() {
|
|
4130
|
-
return
|
|
4209
|
+
return sql13`CASE
|
|
4131
4210
|
WHEN ${juniorConversations.source} IN ('api', 'scheduler', 'slack')
|
|
4132
4211
|
THEN ${juniorConversations.source}
|
|
4133
4212
|
WHEN ${juniorConversations.conversationId} LIKE 'slack:%' THEN 'slack'
|
|
@@ -4156,17 +4235,17 @@ async function readPeopleProfileFromSql(email, options = {}) {
|
|
|
4156
4235
|
const where = verifiedActorWhere(normalizedEmail);
|
|
4157
4236
|
const metricsJoin = peopleTreeMetricsJoin();
|
|
4158
4237
|
const surface = surfaceExpression();
|
|
4159
|
-
const activityDate =
|
|
4238
|
+
const activityDate = sql13`TO_CHAR(
|
|
4160
4239
|
${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
|
|
4161
4240
|
'YYYY-MM-DD'
|
|
4162
4241
|
)`;
|
|
4163
|
-
const channel =
|
|
4242
|
+
const channel = sql13`SPLIT_PART(${juniorConversations.conversationId}, ':', 2)`;
|
|
4164
4243
|
const [totalsRows, dayRows, locationRows, surfaceRows, recentRows] = await Promise.all([
|
|
4165
4244
|
getDb().select({
|
|
4166
4245
|
email: juniorUsers.primaryEmailNormalized,
|
|
4167
4246
|
fullName: juniorUsers.displayName,
|
|
4168
|
-
slackUserId:
|
|
4169
|
-
slackUserName:
|
|
4247
|
+
slackUserId: sql13`MAX(${juniorIdentities.providerSubjectId})`,
|
|
4248
|
+
slackUserName: sql13`MAX(${juniorIdentities.handle})`,
|
|
4170
4249
|
activeDays: conversationActiveDaysColumn(),
|
|
4171
4250
|
...peopleTreeAggregateColumns
|
|
4172
4251
|
}).from(juniorConversations).innerJoin(
|
|
@@ -4279,7 +4358,7 @@ async function readPeopleProfile(email, options = {}) {
|
|
|
4279
4358
|
}
|
|
4280
4359
|
|
|
4281
4360
|
// src/api/people/spend.query.ts
|
|
4282
|
-
import { and as and14, eq as eq14, gte as gte5, lte as lte2, sql as
|
|
4361
|
+
import { and as and14, eq as eq14, gte as gte5, lte as lte2, sql as sql14 } from "drizzle-orm";
|
|
4283
4362
|
var SEVEN_DAY_OFFSET = 6;
|
|
4284
4363
|
var THIRTY_DAY_OFFSET = 29;
|
|
4285
4364
|
function addUsd2(current, next) {
|
|
@@ -4298,7 +4377,7 @@ function spendWindow(nowMs) {
|
|
|
4298
4377
|
async function readPersonalSpendFromSql(email, nowMs = Date.now()) {
|
|
4299
4378
|
const normalizedEmail = normalizeEmail(email);
|
|
4300
4379
|
const { end, sevenDayStart, thirtyDayStart } = spendWindow(nowMs);
|
|
4301
|
-
const activityDate =
|
|
4380
|
+
const activityDate = sql14`TO_CHAR(
|
|
4302
4381
|
${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
|
|
4303
4382
|
'YYYY-MM-DD'
|
|
4304
4383
|
)`;
|
|
@@ -4798,7 +4877,7 @@ function readDescriptionText(home) {
|
|
|
4798
4877
|
}
|
|
4799
4878
|
}
|
|
4800
4879
|
async function readSkillReports() {
|
|
4801
|
-
const { discoverSkills } = await import("./skills-
|
|
4880
|
+
const { discoverSkills } = await import("./skills-U5KQ66EM.js");
|
|
4802
4881
|
const skills = await discoverSkills();
|
|
4803
4882
|
return skillReportsSchema.parse(
|
|
4804
4883
|
skills.map((skill) => ({
|
|
@@ -4808,7 +4887,7 @@ async function readSkillReports() {
|
|
|
4808
4887
|
);
|
|
4809
4888
|
}
|
|
4810
4889
|
async function readPlugins() {
|
|
4811
|
-
const { pluginCatalogRuntime } = await import("./catalog-runtime-
|
|
4890
|
+
const { pluginCatalogRuntime } = await import("./catalog-runtime-M7QGKPFZ.js");
|
|
4812
4891
|
return pluginsSchema.parse(
|
|
4813
4892
|
pluginCatalogRuntime.getProviders().map((plugin) => ({
|
|
4814
4893
|
configKeys: plugin.manifest.configKeys ?? [],
|
|
@@ -4821,7 +4900,7 @@ async function readPlugins() {
|
|
|
4821
4900
|
async function readRuntimeInfoReport() {
|
|
4822
4901
|
const [{ homeDir }, { pluginCatalogRuntime }, plugins, skills] = await Promise.all([
|
|
4823
4902
|
import("./discovery-GUFTFBTL.js"),
|
|
4824
|
-
import("./catalog-runtime-
|
|
4903
|
+
import("./catalog-runtime-M7QGKPFZ.js"),
|
|
4825
4904
|
readPlugins(),
|
|
4826
4905
|
readSkillReports()
|
|
4827
4906
|
]);
|
|
@@ -4837,7 +4916,7 @@ async function readRuntimeInfoReport() {
|
|
|
4837
4916
|
}
|
|
4838
4917
|
async function readPluginOperationalReportFeed() {
|
|
4839
4918
|
const nowMs = Date.now();
|
|
4840
|
-
const { getPluginOperationalReports } = await import("./agent-hooks-
|
|
4919
|
+
const { getPluginOperationalReports } = await import("./agent-hooks-PBT4NNBV.js");
|
|
4841
4920
|
return pluginOperationalReportFeedSchema.parse({
|
|
4842
4921
|
source: "plugins",
|
|
4843
4922
|
generatedAt: new Date(nowMs).toISOString(),
|