diff --git a/apps/server/src/services/threads/thread-data.ts b/apps/server/src/services/threads/thread-data.ts index 9cc53bc57..59394b3ea 100644 --- a/apps/server/src/services/threads/thread-data.ts +++ b/apps/server/src/services/threads/thread-data.ts @@ -1,7 +1,7 @@ import { findStoredEventRow as findStoredEventRowRecord, getLatestThreadOutputEventRow, - getLatestThreadSystemErrorEventRow, + getLatestThreadFailureEventRow, listStoredEventRows as listStoredEventRowRecords, } from "@bb/db"; import type { DbConnection, StoredEventRow } from "@bb/db"; @@ -169,8 +169,20 @@ export function getLastThreadErrorMessage( db: DbConnection, threadId: string, ): string | null { - const row = getLatestThreadSystemErrorEventRow(db, { threadId }); + const row = getLatestThreadFailureEventRow(db, { threadId }); if (!row) return null; const eventRow = parseStoredEventRow(row); - return eventRow.type === "system/error" ? eventRow.data.message : null; + if (eventRow.type === "system/error") return eventRow.data.message; + if (eventRow.type === "provider/error") { + const { message, detail, errorInfo } = eventRow.data; + const text = detail && detail.length > 0 ? detail : message; + if (!errorInfo) return text; + const parts: string[] = [errorInfo.category]; + if (errorInfo.httpStatusCode !== null) { + parts.push(`HTTP ${errorInfo.httpStatusCode}`); + } + if (errorInfo.providerCode !== null) parts.push(errorInfo.providerCode); + return `${text} (${parts.join(", ")})`; + } + return null; } diff --git a/packages/db/src/data/events.ts b/packages/db/src/data/events.ts index e7de63b63..1f5c55eea 100644 --- a/packages/db/src/data/events.ts +++ b/packages/db/src/data/events.ts @@ -3063,6 +3063,31 @@ export function getLatestThreadSystemErrorEventRow( ); } +/** + * Latest failure-describing event for a thread: either a bb-side + * `system/error` or a provider-originated `provider/error` (for example a + * 429 rate limit), whichever was stored last. + */ +export function getLatestThreadFailureEventRow( + db: DbConnection, + args: GetLatestThreadSystemErrorEventRowArgs, +): StoredEventRow | null { + return ( + db + .select(storedEventRowFields) + .from(events) + .where( + and( + eq(events.threadId, args.threadId), + inArray(events.type, ["system/error", "provider/error"]), + ), + ) + .orderBy(desc(events.sequence)) + .limit(1) + .get() ?? null + ); +} + export function getLatestThreadSequence( db: DbConnection, args: GetLatestThreadSequenceArgs, diff --git a/packages/db/src/data/index.ts b/packages/db/src/data/index.ts index 6e599d718..c14ca5415 100644 --- a/packages/db/src/data/index.ts +++ b/packages/db/src/data/index.ts @@ -339,6 +339,7 @@ export { getStoredTurnRequestEventForTurn, getLatestThreadOutputEventRow, getLatestThreadSystemErrorEventRow, + getLatestThreadFailureEventRow, getLatestThreadSequence, getLatestStoredEventRowByType, insertEvents,