@vibes.diy/api-svc 14.3.105 → 14.3.107

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibes.diy/api-svc",
3
- "version": "14.3.105",
3
+ "version": "14.3.107",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -11,6 +11,7 @@
11
11
  "new-user-alert": "tsx ./usage-report/new-user-alert.ts",
12
12
  "egress-abuse-alert": "tsx ./usage-report/egress-abuse-alert.ts",
13
13
  "codegen-delivery-alert": "tsx ./usage-report/codegen-delivery-alert.ts",
14
+ "failed-turn-alert": "tsx ./usage-report/failed-turn-alert.ts",
14
15
  "boot-missing-export-alarm": "tsx ./usage-report/boot-missing-export-alarm.ts",
15
16
  "first-build-no-app-alarm": "tsx ./usage-report/first-build-no-app-alarm.ts",
16
17
  "gold-drip-sweep": "tsx ./usage-report/gold-drip-sweep.ts",
@@ -38,21 +39,21 @@
38
39
  "@neondatabase/serverless": "~1.2.0",
39
40
  "@noble/hashes": "~2.4.0",
40
41
  "@shadcn/lint": "~0.2.0",
41
- "@vibes.diy/api-pkg": "14.3.105",
42
- "@vibes.diy/api-sql": "14.3.105",
43
- "@vibes.diy/api-types": "14.3.105",
44
- "@vibes.diy/call-ai-v2": "14.3.105",
45
- "@vibes.diy/identity": "14.3.105",
46
- "@vibes.diy/look": "14.3.105",
47
- "@vibes.diy/pouf": "14.3.105",
48
- "@vibes.diy/prompts": "14.3.105",
49
- "@vibes.diy/vibe-db-explorer": "14.3.105",
50
- "@vibes.diy/vibe-runtime": "14.3.105",
51
- "@vibes.diy/vibe-types": "14.3.105",
42
+ "@vibes.diy/api-pkg": "14.3.107",
43
+ "@vibes.diy/api-sql": "14.3.107",
44
+ "@vibes.diy/api-types": "14.3.107",
45
+ "@vibes.diy/call-ai-v2": "14.3.107",
46
+ "@vibes.diy/identity": "14.3.107",
47
+ "@vibes.diy/look": "14.3.107",
48
+ "@vibes.diy/pouf": "14.3.107",
49
+ "@vibes.diy/prompts": "14.3.107",
50
+ "@vibes.diy/vibe-db-explorer": "14.3.107",
51
+ "@vibes.diy/vibe-runtime": "14.3.107",
52
+ "@vibes.diy/vibe-types": "14.3.107",
52
53
  "acorn": "~8.17.0",
53
54
  "acorn-jsx": "~5.3.2",
54
55
  "arktype": "~2.2.6",
55
- "call-ai": "14.3.105",
56
+ "call-ai": "14.3.107",
56
57
  "charwise": "~3.0.1",
57
58
  "cookie": "~2.0.1",
58
59
  "csv-parse": "~7.0.3",
@@ -0,0 +1,98 @@
1
+ import { Result } from "@adviser/cement";
2
+ export declare function sanitizeForDiscord(value: string): string;
3
+ export declare const FAILED_TURN_ALERT_ENV_VARS: readonly string[];
4
+ export interface ThresholdEnv {
5
+ readonly FAILED_TURN_ALERT_THRESHOLD?: string;
6
+ readonly FAILED_TURN_ALERT_KNOWN_CATEGORIES?: string;
7
+ }
8
+ export declare const DEFAULT_THRESHOLD = 10;
9
+ export declare const TOP_N = 5;
10
+ export declare const ROW_CAP = 50000;
11
+ export declare const FAILED_TURN_CATEGORIES: readonly string[];
12
+ export declare const CATCH_ALL_CATEGORY = "other";
13
+ export declare const DEFAULT_KNOWN_CATEGORIES: readonly string[];
14
+ export type FailedTurnCategory = (typeof FAILED_TURN_CATEGORIES)[number];
15
+ export interface FailedTurnThresholds {
16
+ readonly threshold: number;
17
+ readonly knownCategories: readonly string[];
18
+ }
19
+ export declare function resolveThresholds(env: ThresholdEnv): FailedTurnThresholds;
20
+ export interface FailedTurnRow {
21
+ readonly chatId: string;
22
+ readonly promptId: string;
23
+ readonly error: string;
24
+ readonly code: string;
25
+ readonly created: string;
26
+ readonly ownerHandle: string;
27
+ readonly appSlug: string;
28
+ }
29
+ export declare function categorizeFailedTurn(error: string, code: string): FailedTurnCategory;
30
+ export interface FailedTurnSample {
31
+ readonly chatId: string;
32
+ readonly promptId: string;
33
+ readonly ownerHandle: string;
34
+ readonly appSlug: string;
35
+ }
36
+ export interface FailedTurnCategorySummary {
37
+ readonly category: string;
38
+ readonly turns: number;
39
+ readonly chats: number;
40
+ readonly sample: readonly FailedTurnSample[];
41
+ }
42
+ export interface FailedTurnSummary {
43
+ readonly failedTurns: number;
44
+ readonly failedChats: number;
45
+ readonly byCategory: readonly FailedTurnCategorySummary[];
46
+ readonly novelCategories: readonly string[];
47
+ readonly tripped: readonly string[];
48
+ readonly threshold: number;
49
+ readonly skipped: number;
50
+ }
51
+ export declare function summarizeFailedTurns(rows: readonly FailedTurnRow[], thresholds: FailedTurnThresholds, skipped?: number): FailedTurnSummary;
52
+ export interface DiscordEmbedBody {
53
+ readonly content?: string;
54
+ readonly allowed_mentions?: {
55
+ readonly parse: readonly string[];
56
+ };
57
+ readonly embeds?: readonly {
58
+ readonly title?: string;
59
+ readonly description?: string;
60
+ readonly color?: number;
61
+ }[];
62
+ }
63
+ export declare function vibeUrl(ownerHandle: string, appSlug: string): string;
64
+ export declare const DISCORD_CONTENT_CAP = 2000;
65
+ export declare const DISCORD_DESCRIPTION_CAP = 4096;
66
+ export declare function fitSampleSection(allSamples: readonly string[], fixedChars: number): string;
67
+ export declare function buildFailedTurnEmbed(input: {
68
+ summary: FailedTurnSummary;
69
+ sinceHours: number;
70
+ capped?: boolean;
71
+ }): DiscordEmbedBody;
72
+ export declare function postToDiscord(webhookUrl: string, body: DiscordEmbedBody, fetchFn?: typeof fetch): Promise<Result<void>>;
73
+ export declare function decodeFailedTurnRow(row: unknown): Result<FailedTurnRow>;
74
+ export declare function decodeFailedTurnRows(rows: readonly unknown[]): {
75
+ readonly rows: FailedTurnRow[];
76
+ readonly skipped: number;
77
+ };
78
+ export interface FailedTurnAlertQuery {
79
+ readonly rows: readonly unknown[];
80
+ readonly capped: boolean;
81
+ }
82
+ export interface ExecuteFailedTurnAlertDeps {
83
+ readonly sinceHours: number;
84
+ readonly thresholds: FailedTurnThresholds;
85
+ readonly explicitDryRun: boolean;
86
+ readonly webhookUrl: string | undefined;
87
+ readonly query: (sinceIso: string) => Promise<FailedTurnAlertQuery>;
88
+ readonly post: (body: DiscordEmbedBody) => Promise<Result<void>>;
89
+ readonly nowMs?: number;
90
+ }
91
+ export interface FailedTurnAlertOutcome {
92
+ readonly summary: FailedTurnSummary;
93
+ readonly body: DiscordEmbedBody;
94
+ readonly posted: boolean;
95
+ readonly skipped: number;
96
+ readonly capped: boolean;
97
+ }
98
+ export declare function executeFailedTurnAlert(deps: ExecuteFailedTurnAlertDeps): Promise<Result<FailedTurnAlertOutcome>>;
@@ -0,0 +1,288 @@
1
+ import { Result, exception2Result } from "@adviser/cement";
2
+ import { type } from "arktype";
3
+ const DISCORD_MARKUP_RE = /[\\`*_~|>#[\]()]/g;
4
+ export function sanitizeForDiscord(value) {
5
+ return value.replaceAll(DISCORD_MARKUP_RE, (c) => `\\${c}`);
6
+ }
7
+ export const FAILED_TURN_ALERT_ENV_VARS = [
8
+ "NEON_DATABASE_URL",
9
+ "DISCORD_WEBHOOK_URL",
10
+ "FAILED_TURN_ALERT_THRESHOLD",
11
+ "FAILED_TURN_ALERT_KNOWN_CATEGORIES",
12
+ ];
13
+ export const DEFAULT_THRESHOLD = 10;
14
+ export const TOP_N = 5;
15
+ export const ROW_CAP = 50_000;
16
+ export const FAILED_TURN_CATEGORIES = [
17
+ "stream-incomplete",
18
+ "turn-lost",
19
+ "first-build-start",
20
+ "llm-request-failed",
21
+ "stale-file",
22
+ "other",
23
+ ];
24
+ export const CATCH_ALL_CATEGORY = "other";
25
+ export const DEFAULT_KNOWN_CATEGORIES = [
26
+ "stream-incomplete",
27
+ "turn-lost",
28
+ "first-build-start",
29
+ "llm-request-failed",
30
+ "stale-file",
31
+ ];
32
+ function num(raw, fallback) {
33
+ if (raw === undefined || raw.trim() === "")
34
+ return fallback;
35
+ const parsed = Number(raw);
36
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
37
+ }
38
+ export function resolveThresholds(env) {
39
+ const rawKnown = env.FAILED_TURN_ALERT_KNOWN_CATEGORIES;
40
+ const knownCategories = rawKnown === undefined || rawKnown.trim() === ""
41
+ ? DEFAULT_KNOWN_CATEGORIES
42
+ : rawKnown
43
+ .split(",")
44
+ .map((s) => s.trim())
45
+ .filter((s) => s !== "" && s !== CATCH_ALL_CATEGORY);
46
+ return {
47
+ threshold: num(env.FAILED_TURN_ALERT_THRESHOLD, DEFAULT_THRESHOLD),
48
+ knownCategories,
49
+ };
50
+ }
51
+ export function categorizeFailedTurn(error, code) {
52
+ if (code === "turn-lost" || error.includes("turn-lost"))
53
+ return "turn-lost";
54
+ if (error.includes("stream ended before completing"))
55
+ return "stream-incomplete";
56
+ if (error.includes("could not be started"))
57
+ return "first-build-start";
58
+ if (error.includes("LLM request failed"))
59
+ return "llm-request-failed";
60
+ if (error.startsWith("stale-file"))
61
+ return "stale-file";
62
+ return "other";
63
+ }
64
+ export function summarizeFailedTurns(rows, thresholds, skipped = 0) {
65
+ const byTurn = new Map();
66
+ for (const row of rows) {
67
+ const key = `${row.chatId}|${row.promptId}`;
68
+ if (!byTurn.has(key))
69
+ byTurn.set(key, row);
70
+ }
71
+ const turns = [...byTurn.values()];
72
+ const chats = new Set(turns.map((t) => t.chatId));
73
+ const perCategory = new Map();
74
+ for (const turn of turns) {
75
+ const category = categorizeFailedTurn(turn.error, turn.code);
76
+ const list = perCategory.get(category) ?? [];
77
+ list.push(turn);
78
+ perCategory.set(category, list);
79
+ }
80
+ const byCategory = [...perCategory.entries()]
81
+ .map(([category, list]) => ({
82
+ category,
83
+ turns: list.length,
84
+ chats: new Set(list.map((t) => t.chatId)).size,
85
+ sample: list.slice(0, TOP_N).map((t) => ({
86
+ chatId: t.chatId,
87
+ promptId: t.promptId,
88
+ ownerHandle: t.ownerHandle,
89
+ appSlug: t.appSlug,
90
+ })),
91
+ }))
92
+ .sort((a, b) => b.turns - a.turns);
93
+ const present = new Set(byCategory.map((c) => c.category));
94
+ const novelCategories = [...present].filter((c) => !thresholds.knownCategories.includes(c));
95
+ const tripped = [];
96
+ if (turns.length >= thresholds.threshold) {
97
+ tripped.push(`${turns.length} failed turns across ${chats.size} chats (threshold ${thresholds.threshold}).`);
98
+ }
99
+ for (const novel of novelCategories) {
100
+ const count = perCategory.get(novel)?.length ?? 0;
101
+ const turnsLabel = `${count} turn${count === 1 ? "" : "s"}`;
102
+ tripped.push(novel === CATCH_ALL_CATEGORY
103
+ ? `unrecognized failures \`${novel}\` (${turnsLabel}) — triage, then give the understood shape its own category in failed-turn-alert-util.ts; \`other\` always alarms.`
104
+ : `new failure category \`${novel}\` (${turnsLabel}) — triage and add to FAILED_TURN_ALERT_KNOWN_CATEGORIES once understood.`);
105
+ }
106
+ return {
107
+ failedTurns: turns.length,
108
+ failedChats: chats.size,
109
+ byCategory,
110
+ novelCategories,
111
+ tripped,
112
+ threshold: thresholds.threshold,
113
+ skipped,
114
+ };
115
+ }
116
+ const COLOR_TRIPPED = 15548997;
117
+ const COLOR_QUIET = 3447003;
118
+ const COLOR_DARK = 16776960;
119
+ export function vibeUrl(ownerHandle, appSlug) {
120
+ return `https://vibes.diy/vibe/${encodeURIComponent(ownerHandle)}/${encodeURIComponent(appSlug)}`;
121
+ }
122
+ const AUTOPSY_NOTE = `Autopsy per turn: \`ChatSections\` by \`chatId\` + \`promptId\` (agents/db-inspect.md § failed-codegen-turn autopsy).`;
123
+ export const DISCORD_CONTENT_CAP = 2000;
124
+ export const DISCORD_DESCRIPTION_CAP = 4096;
125
+ function categoryLines(summary) {
126
+ return summary.byCategory
127
+ .map((c) => `- \`${c.category}\`: ${c.turns} turn${c.turns === 1 ? "" : "s"} across ${c.chats} chat${c.chats === 1 ? "" : "s"}`)
128
+ .join("\n");
129
+ }
130
+ function sampleLine(category, s) {
131
+ const where = s.ownerHandle !== "" && s.appSlug !== "" ? ` ${vibeUrl(s.ownerHandle, s.appSlug)}` : "";
132
+ return `- \`${sanitizeForDiscord(category)}\` chat \`${sanitizeForDiscord(s.chatId)}\` turn \`${sanitizeForDiscord(s.promptId)}\`${where}`;
133
+ }
134
+ function allSampleLines(summary) {
135
+ const lines = [];
136
+ for (const c of summary.byCategory) {
137
+ for (const s of c.sample)
138
+ lines.push(sampleLine(c.category, s));
139
+ }
140
+ return lines;
141
+ }
142
+ export function fitSampleSection(allSamples, fixedChars) {
143
+ const omissionPrefix = "- …(";
144
+ const omissionSuffix = " more samples omitted)";
145
+ const room = DISCORD_DESCRIPTION_CAP - fixedChars - 1;
146
+ const joined = allSamples.join("\n");
147
+ if (joined.length <= room)
148
+ return joined;
149
+ const kept = [];
150
+ let used = 0;
151
+ for (const line of allSamples) {
152
+ const omitted = allSamples.length - kept.length;
153
+ const omissionLen = `\n${omissionPrefix}${omitted}${omissionSuffix}`.length;
154
+ if (used + line.length + 1 + omissionLen > room)
155
+ break;
156
+ kept.push(line);
157
+ used += line.length + 1;
158
+ }
159
+ const omitted = allSamples.length - kept.length;
160
+ return [...kept, `${omissionPrefix}${omitted}${omissionSuffix}`].join("\n");
161
+ }
162
+ function embed(title, description, color, content) {
163
+ return {
164
+ content: truncateTo(content, DISCORD_CONTENT_CAP),
165
+ allowed_mentions: { parse: [] },
166
+ embeds: [{ title, description: truncateTo(description, DISCORD_DESCRIPTION_CAP), color }],
167
+ };
168
+ }
169
+ function truncateTo(text, cap) {
170
+ if (text.length <= cap)
171
+ return text;
172
+ const ellipsis = "\n…(truncated)";
173
+ return text.slice(0, Math.max(0, cap - ellipsis.length)) + ellipsis;
174
+ }
175
+ export function buildFailedTurnEmbed(input) {
176
+ const s = input.summary;
177
+ const { sinceHours } = input;
178
+ const title = `Failed codegen turns (last ${sinceHours}h)`;
179
+ const skippedNote = s.skipped > 0 ? `⚠️ ${s.skipped} malformed row${s.skipped === 1 ? "" : "s"} omitted — counts below are partial.` : "";
180
+ if (input.capped === true) {
181
+ const description = [
182
+ `The ChatSections read was truncated at the ${ROW_CAP}-row cap, so every count below is a floor, not a total.`,
183
+ ...(skippedNote !== "" ? [skippedNote] : []),
184
+ ``,
185
+ categoryLines(s),
186
+ ``,
187
+ AUTOPSY_NOTE,
188
+ ].join("\n");
189
+ return embed(title, description, COLOR_DARK, `Failed turns: the read hit its row cap — counts are a floor this run`);
190
+ }
191
+ if (s.failedTurns === 0) {
192
+ if (s.skipped > 0) {
193
+ const description = [
194
+ `${s.skipped} row${s.skipped === 1 ? " was" : "s were"} read but none decoded into a failed turn — the table shape may have changed since this query was written. Nothing below covers the window.`,
195
+ ``,
196
+ AUTOPSY_NOTE,
197
+ ].join("\n");
198
+ return embed(title, description, COLOR_DARK, `Failed turns: ${s.skipped} row${s.skipped === 1 ? " was" : "s were"} read but none usable in the last ${sinceHours}h (counts unknown)`);
199
+ }
200
+ const description = [
201
+ `No \`prompt.error\` rows in \`ChatSections\` this window. Capture status unknown from this query alone: a clean day and a stopped capture look identical here.`,
202
+ ``,
203
+ AUTOPSY_NOTE,
204
+ ].join("\n");
205
+ return embed(title, description, COLOR_DARK, `Failed turns: no prompt.error rows in the last ${sinceHours}h (capture status unknown)`);
206
+ }
207
+ const tripped = s.tripped.length > 0;
208
+ const headerLines = [...s.tripped.map((t) => sanitizeForDiscord(t)), ...(skippedNote !== "" ? [skippedNote] : [])];
209
+ const header = headerLines.length > 0 ? [...headerLines, ``] : [];
210
+ const fixed = [...header, categoryLines(s), ``, ``, AUTOPSY_NOTE].join("\n");
211
+ const samples = fitSampleSection(allSampleLines(s), fixed.length);
212
+ const description = [...header, categoryLines(s), ``, samples, ``, AUTOPSY_NOTE].join("\n");
213
+ const partialSuffix = s.skipped > 0 ? ` (partial data: ${s.skipped} row${s.skipped === 1 ? "" : "s"} omitted)` : "";
214
+ const content = tripped || s.skipped > 0
215
+ ? `Failed turns: ${s.failedTurns} across ${s.failedChats} chats in the last ${sinceHours}h${partialSuffix}`
216
+ : `Failed turns: ${s.failedTurns} across ${s.failedChats} chats in the last ${sinceHours}h — below threshold, nothing new`;
217
+ return embed(title, description, tripped ? COLOR_TRIPPED : COLOR_QUIET, content);
218
+ }
219
+ export async function postToDiscord(webhookUrl, body, fetchFn = fetch) {
220
+ const res = await exception2Result(() => fetchFn(webhookUrl, {
221
+ method: "POST",
222
+ headers: { "Content-Type": "application/json" },
223
+ body: JSON.stringify(body),
224
+ }));
225
+ if (res.isErr())
226
+ return Result.Err(new Error("discord delivery failed: transport error"));
227
+ if (res.Ok().status !== 204)
228
+ return Result.Err(new Error(`discord delivery failed: status ${res.Ok().status}`));
229
+ return Result.Ok(undefined);
230
+ }
231
+ const FailedTurnRowWire = type({
232
+ chatId: "string",
233
+ promptId: "string",
234
+ error: "string",
235
+ "code?": "string | null | undefined",
236
+ "created?": "string | null | undefined",
237
+ "ownerHandle?": "string | null | undefined",
238
+ "appSlug?": "string | null | undefined",
239
+ });
240
+ export function decodeFailedTurnRow(row) {
241
+ const parsed = FailedTurnRowWire(row);
242
+ if (parsed instanceof type.errors)
243
+ return Result.Err(new Error(parsed.summary));
244
+ if (parsed.chatId === "" || parsed.promptId === "") {
245
+ return Result.Err(new Error("failed-turn row has an empty chatId or promptId"));
246
+ }
247
+ return Result.Ok({
248
+ chatId: parsed.chatId,
249
+ promptId: parsed.promptId,
250
+ error: parsed.error,
251
+ code: parsed.code ?? "",
252
+ created: parsed.created ?? "",
253
+ ownerHandle: parsed.ownerHandle ?? "",
254
+ appSlug: parsed.appSlug ?? "",
255
+ });
256
+ }
257
+ export function decodeFailedTurnRows(rows) {
258
+ const kept = [];
259
+ let skipped = 0;
260
+ for (const row of rows) {
261
+ const decoded = decodeFailedTurnRow(row);
262
+ if (decoded.isErr())
263
+ skipped += 1;
264
+ else
265
+ kept.push(decoded.Ok());
266
+ }
267
+ return { rows: kept, skipped };
268
+ }
269
+ export async function executeFailedTurnAlert(deps) {
270
+ const nowMs = deps.nowMs ?? Date.now();
271
+ const sinceIso = new Date(nowMs - deps.sinceHours * 3600_000).toISOString();
272
+ const queried = await exception2Result(() => deps.query(sinceIso));
273
+ if (queried.isErr())
274
+ return Result.Err(queried);
275
+ const { rows, skipped } = decodeFailedTurnRows(queried.Ok().rows);
276
+ const summary = summarizeFailedTurns(rows, deps.thresholds, skipped);
277
+ const body = buildFailedTurnEmbed({ summary, sinceHours: deps.sinceHours, capped: queried.Ok().capped });
278
+ if (deps.explicitDryRun)
279
+ return Result.Ok({ summary, body, posted: false, skipped, capped: queried.Ok().capped });
280
+ if (deps.webhookUrl === undefined || deps.webhookUrl === "") {
281
+ return Result.Err(new Error("DISCORD_WEBHOOK_URL is required — nothing was posted (pass --dry-run to print instead)"));
282
+ }
283
+ const posted = await deps.post(body);
284
+ if (posted.isErr())
285
+ return Result.Err(posted);
286
+ return Result.Ok({ summary, body, posted: true, skipped, capped: queried.Ok().capped });
287
+ }
288
+ //# sourceMappingURL=failed-turn-alert-util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failed-turn-alert-util.js","sourceRoot":"","sources":["../../jsr/usage-report/failed-turn-alert-util.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,64 @@
1
+ import { Pool } from "@neondatabase/serverless";
2
+ import { Result } from "@adviser/cement";
3
+ import { arg, flag, formatError, loadDevVars } from "./usage-report-util.js";
4
+ import { ROW_CAP, executeFailedTurnAlert, postToDiscord, resolveThresholds } from "./failed-turn-alert-util.js";
5
+ const DEFAULT_SINCE_HOURS = 24;
6
+ async function run() {
7
+ loadDevVars();
8
+ const sinceHours = Number(arg("--since-hours") ?? DEFAULT_SINCE_HOURS);
9
+ if (!Number.isFinite(sinceHours) || sinceHours <= 0) {
10
+ return Result.Err("usage: pnpm --dir vibes.diy/api/svc run failed-turn-alert [--since-hours 24] [--dry-run]");
11
+ }
12
+ const connectionString = process.env["NEON_DATABASE_URL"];
13
+ if (connectionString === undefined)
14
+ return Result.Err("NEON_DATABASE_URL is required (prod Neon)");
15
+ const webhookUrl = process.env["DISCORD_WEBHOOK_URL"];
16
+ const thresholds = resolveThresholds({
17
+ FAILED_TURN_ALERT_THRESHOLD: process.env["FAILED_TURN_ALERT_THRESHOLD"],
18
+ FAILED_TURN_ALERT_KNOWN_CATEGORIES: process.env["FAILED_TURN_ALERT_KNOWN_CATEGORIES"],
19
+ });
20
+ const dryRun = flag("--dry-run");
21
+ const pool = new Pool({ connectionString });
22
+ const result = await executeFailedTurnAlert({
23
+ sinceHours,
24
+ thresholds,
25
+ explicitDryRun: dryRun,
26
+ webhookUrl,
27
+ query: async (sinceIso) => {
28
+ const res = await pool.query(`select s."chatId", s."promptId",
29
+ min(b->>'error') as error,
30
+ min(coalesce(b->>'code', '')) as code,
31
+ min(s.created) as created,
32
+ min(c."userSlug") as "ownerHandle",
33
+ min(c."appSlug") as "appSlug"
34
+ from "ChatSections" s
35
+ left join "ChatContexts" c on c."chatId" = s."chatId",
36
+ lateral jsonb_array_elements(s.blocks) as b
37
+ where s.created >= $1 and b->>'type' = 'prompt.error'
38
+ group by s."chatId", s."promptId"
39
+ order by min(s.created) desc limit ${ROW_CAP}`, [sinceIso]);
40
+ return { rows: res.rows, capped: res.rows.length === ROW_CAP };
41
+ },
42
+ post: (body) => {
43
+ if (webhookUrl === undefined || webhookUrl === "") {
44
+ return Promise.resolve(Result.Err(new Error("DISCORD_WEBHOOK_URL is required — nothing was posted")));
45
+ }
46
+ return postToDiscord(webhookUrl, body);
47
+ },
48
+ });
49
+ await pool.end();
50
+ if (result.isErr())
51
+ return result;
52
+ const outcome = result.Ok();
53
+ console.log(`[failed-turn-alert] window=${sinceHours}h failedTurns=${outcome.summary.failedTurns} chats=${outcome.summary.failedChats} signals=${outcome.summary.tripped.length} skipped=${outcome.skipped} capped=${outcome.capped} posted=${outcome.posted}`);
54
+ if (dryRun)
55
+ console.log(JSON.stringify(outcome.body, null, 2));
56
+ return result;
57
+ }
58
+ run().then((result) => {
59
+ if (result.isErr()) {
60
+ console.error(formatError(result.Err()));
61
+ process.exitCode = 1;
62
+ }
63
+ });
64
+ //# sourceMappingURL=failed-turn-alert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failed-turn-alert.js","sourceRoot":"","sources":["../../jsr/usage-report/failed-turn-alert.ts"],"names":[],"mappings":"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"}