@sentry/junior 0.87.0 → 0.89.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +16 -5
  2. package/dist/{agent-hooks-NWOUB3UR.js → agent-hooks-RIJ5TSWP.js} +8 -8
  3. package/dist/api/people/list.d.ts +4 -0
  4. package/dist/api/people/list.js +83 -0
  5. package/dist/api/people/list.query.d.ts +4 -0
  6. package/dist/api/people/profile.d.ts +4 -0
  7. package/dist/api/people/profile.js +131 -0
  8. package/dist/api/people/profile.query.d.ts +4 -0
  9. package/dist/api/people/shared.d.ts +76 -0
  10. package/dist/api/people/types.d.ts +85 -0
  11. package/dist/app.js +43 -40
  12. package/dist/{catalog-runtime-XOD7YPRS.js → catalog-runtime-MW7XERSU.js} +3 -3
  13. package/dist/chat/conversations/sql/migrations.d.ts +1 -1
  14. package/dist/chat/conversations/sql/schema/identities.d.ts +54 -3
  15. package/dist/chat/conversations/sql/schema/users.d.ts +109 -0
  16. package/dist/chat/conversations/sql/schema.d.ts +164 -3
  17. package/dist/chat/conversations/sql/store.d.ts +0 -1
  18. package/dist/chat/identities/identity.d.ts +18 -0
  19. package/dist/chat/identities/sql.d.ts +4 -0
  20. package/dist/chat/runtime/processing-reaction.d.ts +2 -1
  21. package/dist/chat/runtime/slack-resume.d.ts +3 -2
  22. package/dist/chat/runtime/thread-context.d.ts +3 -1
  23. package/dist/chat/runtime/turn-user-message.d.ts +2 -1
  24. package/dist/chat/services/conversation-memory.d.ts +3 -1
  25. package/dist/chat/slack/message.d.ts +2 -1
  26. package/dist/chat/slack/outbound.d.ts +5 -4
  27. package/dist/chat/slack/timestamp.d.ts +6 -0
  28. package/dist/chat/sql/schema.d.ts +163 -3
  29. package/dist/chat/tools/slack/context.d.ts +2 -1
  30. package/dist/{chunk-ENPSU7L7.js → chunk-2DPZRS3B.js} +4 -4
  31. package/dist/{chunk-6I6HBOQM.js → chunk-4IXHIV37.js} +413 -157
  32. package/dist/{chunk-JRXCSSSU.js → chunk-6UPQ5GTJ.js} +3 -3
  33. package/dist/{chunk-64ACM6AP.js → chunk-7ES37H6U.js} +2 -2
  34. package/dist/{chunk-GGD6WK6V.js → chunk-AHLSXMOU.js} +2 -2
  35. package/dist/{chunk-2TAIGJPQ.js → chunk-C5NCV3OB.js} +1 -1
  36. package/dist/{chunk-6O5UI3RG.js → chunk-F22AM3OW.js} +1 -1
  37. package/dist/{chunk-BRSQQRG6.js → chunk-IATAYWFU.js} +2 -2
  38. package/dist/{chunk-BQ3ITJA6.js → chunk-KBFQXJL4.js} +2 -2
  39. package/dist/{chunk-ACJJJEGG.js → chunk-KBSLCOGE.js} +8 -8
  40. package/dist/{chunk-IXTBFABZ.js → chunk-KQKIA4CU.js} +1 -1
  41. package/dist/{chunk-B6FQPS7A.js → chunk-NYJLQI42.js} +22 -20
  42. package/dist/chunk-PBV4ZIVM.js +261 -0
  43. package/dist/{chunk-ZU2ALUVQ.js → chunk-S35CPNPT.js} +1 -1
  44. package/dist/{chunk-RIB3M6YA.js → chunk-V6XDCS3X.js} +4 -4
  45. package/dist/{chunk-KF7522P3.js → chunk-VMBZFPZM.js} +11 -1
  46. package/dist/{chunk-2NFV5FMB.js → chunk-XS6NLQPA.js} +21 -12
  47. package/dist/{chunk-GB5DFM4D.js → chunk-YPAE5RH3.js} +1 -1
  48. package/dist/cli/chat.js +6 -6
  49. package/dist/cli/check.js +4 -4
  50. package/dist/cli/init.js +30 -36
  51. package/dist/cli/plugins.js +11 -11
  52. package/dist/cli/snapshot-warmup.js +6 -6
  53. package/dist/cli/upgrade.js +12 -12
  54. package/dist/{db-SZVUU7RB.js → db-37HOGLI7.js} +5 -5
  55. package/dist/nitro.js +4 -4
  56. package/dist/reporting/conversations.d.ts +0 -56
  57. package/dist/reporting.d.ts +2 -8
  58. package/dist/reporting.js +14 -290
  59. package/dist/{runner-DMP3IQNM.js → runner-BCRF2FCI.js} +13 -13
  60. package/dist/{validation-MBNJKWPQ.js → validation-FMJO3L5P.js} +4 -4
  61. package/package.json +13 -5
package/README.md CHANGED
@@ -10,6 +10,14 @@ pnpm add @sentry/junior hono @sentry/node
10
10
 
11
11
  ## Quick usage
12
12
 
13
+ `plugins.ts`:
14
+
15
+ ```ts
16
+ import { defineJuniorPlugins } from "@sentry/junior";
17
+
18
+ export const plugins = defineJuniorPlugins([]);
19
+ ```
20
+
13
21
  `server.ts`:
14
22
 
15
23
  ```ts
@@ -17,8 +25,11 @@ import { initSentry } from "@sentry/junior/instrumentation";
17
25
  initSentry();
18
26
 
19
27
  import { createApp } from "@sentry/junior";
28
+ import { plugins } from "./plugins.ts";
20
29
 
21
- const app = await createApp();
30
+ const app = await createApp({
31
+ plugins,
32
+ });
22
33
 
23
34
  export default app;
24
35
  ```
@@ -26,10 +37,10 @@ export default app;
26
37
  Run `junior init my-bot` to scaffold a complete project including `vercel.json` for Vercel deployment.
27
38
 
28
39
  Use `defineJuniorPlugins([...])` in a runtime-safe plugin module, then point
29
- `juniorNitro({ plugins: "./plugins" })` at that module. `createApp()` reads the
30
- same enabled set from Nitro's virtual module. Manifest-only packages use
31
- package-name strings; factories such as `githubPlugin()` register their
32
- manifest and in-process hooks together.
40
+ `juniorNitro({ plugins: "./plugins" })` at that module and pass the same set to
41
+ `createApp({ plugins })`. Manifest-only packages use package-name strings;
42
+ factories such as `githubPlugin()` register their manifest and in-process hooks
43
+ together.
33
44
 
34
45
  ## Full docs
35
46
 
@@ -11,16 +11,16 @@ import {
11
11
  getPlugins,
12
12
  setPlugins,
13
13
  validatePlugins
14
- } from "./chunk-2NFV5FMB.js";
15
- import "./chunk-BRSQQRG6.js";
16
- import "./chunk-6I6HBOQM.js";
14
+ } from "./chunk-XS6NLQPA.js";
15
+ import "./chunk-IATAYWFU.js";
17
16
  import "./chunk-G3E7SCME.js";
18
- import "./chunk-GB5DFM4D.js";
19
- import "./chunk-GGD6WK6V.js";
20
- import "./chunk-ZU2ALUVQ.js";
17
+ import "./chunk-YPAE5RH3.js";
18
+ import "./chunk-4IXHIV37.js";
19
+ import "./chunk-AHLSXMOU.js";
20
+ import "./chunk-S35CPNPT.js";
21
21
  import "./chunk-L7OHKDOX.js";
22
- import "./chunk-IXTBFABZ.js";
23
- import "./chunk-KF7522P3.js";
22
+ import "./chunk-KQKIA4CU.js";
23
+ import "./chunk-VMBZFPZM.js";
24
24
  import "./chunk-FTMXFBDC.js";
25
25
  import "./chunk-3DA7X2U3.js";
26
26
  import "./chunk-MLKGABMK.js";
@@ -0,0 +1,4 @@
1
+ import type { RequesterDirectoryReport } from "./types";
2
+ /** Load the people list from verified user identities in SQL. */
3
+ export declare function readPeopleList(): Promise<RequesterDirectoryReport>;
4
+ export type { RequesterDirectoryReport, RequesterIdentity, RequesterSummaryReport, RequesterTotalsReport, } from "./types";
@@ -0,0 +1,83 @@
1
+ import {
2
+ SAMPLE_LIMIT,
3
+ addSignals,
4
+ emptyTotals,
5
+ identityWithEmail,
6
+ mergeIdentity,
7
+ reportDate,
8
+ reportTime,
9
+ requesterRows,
10
+ signals,
11
+ summaryFromRow
12
+ } from "../../chunk-PBV4ZIVM.js";
13
+ import "../../chunk-4IXHIV37.js";
14
+ import "../../chunk-AHLSXMOU.js";
15
+ import "../../chunk-S35CPNPT.js";
16
+ import "../../chunk-L7OHKDOX.js";
17
+ import "../../chunk-KQKIA4CU.js";
18
+ import "../../chunk-VMBZFPZM.js";
19
+ import "../../chunk-FTMXFBDC.js";
20
+ import "../../chunk-3DA7X2U3.js";
21
+ import "../../chunk-MLKGABMK.js";
22
+
23
+ // src/api/people/list.query.ts
24
+ function directoryItem(accumulator) {
25
+ return {
26
+ active: accumulator.active,
27
+ activeDays: accumulator.activeDates.size,
28
+ conversations: accumulator.conversations,
29
+ durationMs: accumulator.durationMs,
30
+ failed: accumulator.failed,
31
+ firstSeenAt: new Date(accumulator.firstSeenMs).toISOString(),
32
+ hung: accumulator.hung,
33
+ lastSeenAt: new Date(accumulator.lastSeenMs).toISOString(),
34
+ requester: accumulator.requester,
35
+ runs: accumulator.runs
36
+ };
37
+ }
38
+ async function readPeopleListFromSql(options = {}) {
39
+ const nowMs = Date.now();
40
+ const { rows, truncated } = await requesterRows(options);
41
+ const people = /* @__PURE__ */ new Map();
42
+ for (const row of rows) {
43
+ const summary = summaryFromRow(row, nowMs);
44
+ const requester = identityWithEmail(summary.requesterIdentity);
45
+ if (!requester) continue;
46
+ const firstSeenMs = reportTime(summary.startedAt) ?? row.createdAt.getTime();
47
+ const lastSeenMs = reportTime(summary.lastSeenAt) ?? row.lastActivityAt.getTime();
48
+ const date = reportDate(summary.lastSeenAt);
49
+ const accumulator = people.get(requester.email) ?? {
50
+ ...emptyTotals(),
51
+ activeDates: /* @__PURE__ */ new Set(),
52
+ firstSeenMs,
53
+ lastSeenMs,
54
+ requester
55
+ };
56
+ accumulator.requester = mergeIdentity(accumulator.requester, requester);
57
+ accumulator.conversations += 1;
58
+ accumulator.runs += 1;
59
+ addSignals(accumulator, signals(summary));
60
+ accumulator.firstSeenMs = Math.min(accumulator.firstSeenMs, firstSeenMs);
61
+ accumulator.lastSeenMs = Math.max(accumulator.lastSeenMs, lastSeenMs);
62
+ if (date) accumulator.activeDates.add(date);
63
+ people.set(requester.email, accumulator);
64
+ }
65
+ return {
66
+ generatedAt: new Date(nowMs).toISOString(),
67
+ people: [...people.values()].map(directoryItem).sort(
68
+ (left, right) => (reportTime(right.lastSeenAt) ?? 0) - (reportTime(left.lastSeenAt) ?? 0) || right.conversations - left.conversations || left.requester.email.localeCompare(right.requester.email)
69
+ ),
70
+ sampleLimit: SAMPLE_LIMIT,
71
+ sampleSize: rows.length,
72
+ source: "conversation_index",
73
+ truncated
74
+ };
75
+ }
76
+
77
+ // src/api/people/list.ts
78
+ async function readPeopleList() {
79
+ return readPeopleListFromSql();
80
+ }
81
+ export {
82
+ readPeopleList
83
+ };
@@ -0,0 +1,4 @@
1
+ import type { RequesterDirectoryReport } from "./types";
2
+ import { type PeopleApiQueryOptions } from "./shared";
3
+ /** Load the people list from the configured or injected SQL database. */
4
+ export declare function readPeopleListFromSql(options?: PeopleApiQueryOptions): Promise<RequesterDirectoryReport>;
@@ -0,0 +1,4 @@
1
+ import type { RequesterProfileReport } from "./types";
2
+ /** Load one person profile from verified user identities in SQL. */
3
+ export declare function readPeopleProfile(email: string): Promise<RequesterProfileReport>;
4
+ export type { ConversationStatsItem, ConversationSummaryReport, PeopleConversationStatus, PeopleConversationSurface, RequesterActivityDayReport, RequesterIdentity, RequesterProfileReport, RequesterTotalsReport, } from "./types";
@@ -0,0 +1,131 @@
1
+ import {
2
+ ACTIVITY_DAYS,
3
+ RECENT_LIMIT,
4
+ SAMPLE_LIMIT,
5
+ activityDays,
6
+ addSignals,
7
+ emptyActivityDay,
8
+ emptyStatsItem,
9
+ emptyTotals,
10
+ identityWithEmail,
11
+ mergeIdentity,
12
+ normalizeEmail,
13
+ reportDate,
14
+ reportTime,
15
+ requesterRows,
16
+ signals,
17
+ slackLocationLabel,
18
+ statsItems,
19
+ summaryFromRow,
20
+ surfaceLabel
21
+ } from "../../chunk-PBV4ZIVM.js";
22
+ import "../../chunk-4IXHIV37.js";
23
+ import "../../chunk-AHLSXMOU.js";
24
+ import "../../chunk-S35CPNPT.js";
25
+ import "../../chunk-L7OHKDOX.js";
26
+ import "../../chunk-KQKIA4CU.js";
27
+ import "../../chunk-VMBZFPZM.js";
28
+ import "../../chunk-FTMXFBDC.js";
29
+ import "../../chunk-3DA7X2U3.js";
30
+ import "../../chunk-MLKGABMK.js";
31
+
32
+ // src/api/people/profile.query.ts
33
+ function emptyProfile(email, nowMs) {
34
+ const end = new Date(nowMs);
35
+ end.setUTCHours(0, 0, 0, 0);
36
+ const start = new Date(end);
37
+ start.setUTCDate(start.getUTCDate() - (ACTIVITY_DAYS - 1));
38
+ return {
39
+ activityDays: activityDays(/* @__PURE__ */ new Map(), nowMs),
40
+ generatedAt: new Date(nowMs).toISOString(),
41
+ locations: [],
42
+ recentConversations: [],
43
+ requester: { email },
44
+ sampleLimit: SAMPLE_LIMIT,
45
+ sampleSize: 0,
46
+ source: "conversation_index",
47
+ surfaces: [],
48
+ totals: emptyTotals(),
49
+ truncated: false,
50
+ windowEnd: end.toISOString(),
51
+ windowStart: start.toISOString()
52
+ };
53
+ }
54
+ async function readPeopleProfileFromSql(email, options = {}) {
55
+ const nowMs = Date.now();
56
+ const normalizedEmail = normalizeEmail(email);
57
+ if (!normalizedEmail) {
58
+ return emptyProfile("", nowMs);
59
+ }
60
+ const { rows, truncated } = await requesterRows(options, normalizedEmail);
61
+ let requester;
62
+ const totals = emptyTotals();
63
+ const activeDates = /* @__PURE__ */ new Set();
64
+ const days = /* @__PURE__ */ new Map();
65
+ const locations = /* @__PURE__ */ new Map();
66
+ const surfaces = /* @__PURE__ */ new Map();
67
+ const recentConversations = [];
68
+ for (const row of rows) {
69
+ const summary = summaryFromRow(row, nowMs);
70
+ const identity = identityWithEmail(summary.requesterIdentity);
71
+ if (identity) {
72
+ requester = requester ? mergeIdentity(requester, identity) : identity;
73
+ }
74
+ recentConversations.push(summary);
75
+ const value = signals(summary);
76
+ const date = reportDate(summary.lastSeenAt);
77
+ totals.conversations += 1;
78
+ totals.runs += 1;
79
+ addSignals(totals, value);
80
+ if (date) {
81
+ activeDates.add(date);
82
+ const day = days.get(date) ?? emptyActivityDay(date);
83
+ day.conversations += 1;
84
+ day.runs += 1;
85
+ addSignals(day, value);
86
+ days.set(date, day);
87
+ }
88
+ const location = slackLocationLabel(summary) ?? surfaceLabel(summary.surface);
89
+ const locationItem = locations.get(location) ?? emptyStatsItem(location);
90
+ locationItem.conversations += 1;
91
+ locationItem.runs += 1;
92
+ addSignals(locationItem, value);
93
+ locations.set(location, locationItem);
94
+ const surface = surfaceLabel(summary.surface);
95
+ const surfaceItem = surfaces.get(surface) ?? emptyStatsItem(surface);
96
+ surfaceItem.conversations += 1;
97
+ surfaceItem.runs += 1;
98
+ addSignals(surfaceItem, value);
99
+ surfaces.set(surface, surfaceItem);
100
+ }
101
+ totals.activeDays = activeDates.size;
102
+ const end = new Date(nowMs);
103
+ end.setUTCHours(0, 0, 0, 0);
104
+ const start = new Date(end);
105
+ start.setUTCDate(start.getUTCDate() - (ACTIVITY_DAYS - 1));
106
+ return {
107
+ activityDays: activityDays(days, nowMs),
108
+ generatedAt: new Date(nowMs).toISOString(),
109
+ locations: statsItems(locations),
110
+ recentConversations: recentConversations.sort(
111
+ (left, right) => (reportTime(right.lastSeenAt) ?? 0) - (reportTime(left.lastSeenAt) ?? 0) || right.conversationId.localeCompare(left.conversationId)
112
+ ).slice(0, RECENT_LIMIT),
113
+ requester: requester ?? { email: normalizedEmail },
114
+ sampleLimit: SAMPLE_LIMIT,
115
+ sampleSize: rows.length,
116
+ source: "conversation_index",
117
+ surfaces: statsItems(surfaces),
118
+ totals,
119
+ truncated,
120
+ windowEnd: end.toISOString(),
121
+ windowStart: start.toISOString()
122
+ };
123
+ }
124
+
125
+ // src/api/people/profile.ts
126
+ async function readPeopleProfile(email) {
127
+ return readPeopleProfileFromSql(email);
128
+ }
129
+ export {
130
+ readPeopleProfile
131
+ };
@@ -0,0 +1,4 @@
1
+ import type { RequesterProfileReport } from "./types";
2
+ import { type PeopleApiQueryOptions } from "./shared";
3
+ /** Load one person profile from the configured or injected SQL database. */
4
+ export declare function readPeopleProfileFromSql(email: string, options?: PeopleApiQueryOptions): Promise<RequesterProfileReport>;
@@ -0,0 +1,76 @@
1
+ import type { JuniorDatabase } from "@/chat/sql/db";
2
+ import type { ConversationStatsItem, ConversationSummaryReport, PeopleConversationSurface, RequesterActivityDayReport, RequesterIdentity, RequesterTotalsReport } from "./types";
3
+ export declare const SAMPLE_LIMIT = 5000;
4
+ export declare const RECENT_LIMIT = 25;
5
+ export declare const ACTIVITY_DAYS = 366;
6
+ export interface PeopleApiQueryOptions {
7
+ db?: JuniorDatabase;
8
+ }
9
+ /** Normalize emails before matching people API rows. */
10
+ export declare function normalizeEmail(email: string | undefined): string | undefined;
11
+ /** Parse report timestamps without throwing on malformed legacy values. */
12
+ export declare function reportTime(value: string): number | undefined;
13
+ /** Convert a report timestamp into the UTC day used for people activity. */
14
+ export declare function reportDate(value: string): string | undefined;
15
+ /** Return the dashboard label for a conversation surface. */
16
+ export declare function surfaceLabel(surface: PeopleConversationSurface): string;
17
+ /** Return the dashboard-safe Slack location label for a conversation. */
18
+ export declare function slackLocationLabel(args: {
19
+ channel?: string;
20
+ channelName?: string;
21
+ channelNameRedacted?: boolean;
22
+ }): string | undefined;
23
+ /** Project one SQL conversation row into the people API conversation summary. */
24
+ export declare function summaryFromRow(row: PeopleConversationRow, nowMs: number): ConversationSummaryReport;
25
+ /** Build a zeroed totals object for people API aggregations. */
26
+ export declare function emptyTotals(): RequesterTotalsReport;
27
+ /** Build a zeroed labeled stats row for people API aggregations. */
28
+ export declare function emptyStatsItem(label: string): ConversationStatsItem;
29
+ /** Build a zeroed activity day for the people profile window. */
30
+ export declare function emptyActivityDay(date: string): RequesterActivityDayReport;
31
+ /** Collapse a conversation summary status into aggregate counters. */
32
+ export declare function signals(summary: ConversationSummaryReport): {
33
+ active: boolean;
34
+ failed: boolean;
35
+ hung: boolean;
36
+ };
37
+ /** Add status counters into a people API aggregate row. */
38
+ export declare function addSignals(target: Pick<RequesterTotalsReport, "active" | "failed" | "hung">, value: ReturnType<typeof signals>): void;
39
+ /** Return only requester identities that can be grouped by normalized email. */
40
+ export declare function identityWithEmail(requester: RequesterIdentity | undefined): (RequesterIdentity & {
41
+ email: string;
42
+ }) | undefined;
43
+ /** Preserve the first observed person fields while filling missing details. */
44
+ export declare function mergeIdentity(current: RequesterIdentity & {
45
+ email: string;
46
+ }, next: RequesterIdentity & {
47
+ email: string;
48
+ }): RequesterIdentity & {
49
+ email: string;
50
+ };
51
+ /** Fill the fixed people profile activity window from sparse day totals. */
52
+ export declare function activityDays(days: Map<string, RequesterActivityDayReport>, nowMs: number): RequesterActivityDayReport[];
53
+ /** Return deterministic stats rows for people API responses. */
54
+ export declare function statsItems(map: Map<string, ConversationStatsItem>): ConversationStatsItem[];
55
+ /** Read verified requester conversation rows directly from the SQL identity model. */
56
+ export declare function requesterRows(options?: PeopleApiQueryOptions, email?: string): Promise<{
57
+ rows: {
58
+ channelName: string | null;
59
+ conversationId: string;
60
+ createdAt: Date;
61
+ destinationVisibility: import("../../chat/conversations/sql/schema/destinations").JuniorDestinationVisibility | null;
62
+ email: string;
63
+ executionStatus: import("../../chat/conversations/store").ConversationStatus;
64
+ executionUpdatedAt: Date | null;
65
+ fullName: string | null;
66
+ handle: string | null;
67
+ lastActivityAt: Date;
68
+ providerSubjectId: string;
69
+ runId: string | null;
70
+ source: import("../../chat/conversations/store").ConversationSource | null;
71
+ title: string | null;
72
+ updatedAt: Date;
73
+ }[];
74
+ truncated: boolean;
75
+ }>;
76
+ export type PeopleConversationRow = Awaited<ReturnType<typeof requesterRows>>["rows"][number];
@@ -0,0 +1,85 @@
1
+ export type PeopleConversationStatus = "active" | "completed" | "failed" | "hung";
2
+ export type PeopleConversationSurface = "api" | "internal" | "scheduler" | "slack";
3
+ export interface RequesterIdentity {
4
+ email?: string;
5
+ fullName?: string;
6
+ slackUserId?: string;
7
+ slackUserName?: string;
8
+ }
9
+ export interface ConversationSummaryReport {
10
+ cumulativeDurationMs: number;
11
+ conversationId: string;
12
+ displayTitle: string;
13
+ id: string;
14
+ lastProgressAt: string;
15
+ lastSeenAt: string;
16
+ startedAt: string;
17
+ status: PeopleConversationStatus;
18
+ surface: PeopleConversationSurface;
19
+ channel?: string;
20
+ channelName?: string;
21
+ channelNameRedacted?: boolean;
22
+ requesterIdentity?: RequesterIdentity;
23
+ }
24
+ export interface ConversationStatsItem {
25
+ active: number;
26
+ conversations: number;
27
+ durationMs: number;
28
+ failed: number;
29
+ hung: number;
30
+ label: string;
31
+ runs: number;
32
+ tokens?: number;
33
+ }
34
+ export interface RequesterActivityDayReport {
35
+ active: number;
36
+ conversations: number;
37
+ date: string;
38
+ durationMs: number;
39
+ failed: number;
40
+ hung: number;
41
+ runs: number;
42
+ tokens?: number;
43
+ }
44
+ export interface RequesterTotalsReport {
45
+ active: number;
46
+ activeDays: number;
47
+ conversations: number;
48
+ durationMs: number;
49
+ failed: number;
50
+ hung: number;
51
+ runs: number;
52
+ tokens?: number;
53
+ }
54
+ export interface RequesterSummaryReport extends RequesterTotalsReport {
55
+ firstSeenAt: string;
56
+ lastSeenAt: string;
57
+ requester: RequesterIdentity & {
58
+ email: string;
59
+ };
60
+ }
61
+ export interface RequesterDirectoryReport {
62
+ generatedAt: string;
63
+ people: RequesterSummaryReport[];
64
+ sampleLimit: number;
65
+ sampleSize: number;
66
+ source: "conversation_index";
67
+ truncated: boolean;
68
+ }
69
+ export interface RequesterProfileReport {
70
+ activityDays: RequesterActivityDayReport[];
71
+ generatedAt: string;
72
+ locations: ConversationStatsItem[];
73
+ recentConversations: ConversationSummaryReport[];
74
+ requester: RequesterIdentity & {
75
+ email: string;
76
+ };
77
+ sampleLimit: number;
78
+ sampleSize: number;
79
+ source: "conversation_index";
80
+ surfaces: ConversationStatsItem[];
81
+ totals: RequesterTotalsReport;
82
+ truncated: boolean;
83
+ windowEnd: string;
84
+ windowStart: string;
85
+ }