fix: tolerate missing request detail logs table (#1848)

Integrated into release/v3.7.8
This commit is contained in:
bambuvnn
2026-05-01 18:35:52 +07:00
committed by GitHub
parent ea6f556ed2
commit ea9d9e09ba
2 changed files with 43 additions and 1 deletions

View File

@@ -33,6 +33,25 @@ export interface RequestDetailLog {
no_log?: boolean;
}
let requestDetailLogsTableExistsCache: boolean | undefined;
function requestDetailLogsTableExists(): boolean {
if (requestDetailLogsTableExistsCache !== undefined) {
return requestDetailLogsTableExistsCache;
}
const db = getDbInstance();
const row = db
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'request_detail_logs'")
.get() as { name?: string } | undefined;
requestDetailLogsTableExistsCache = Boolean(row?.name);
return requestDetailLogsTableExistsCache;
}
export function resetRequestDetailLogsTableExistsCache(): void {
requestDetailLogsTableExistsCache = undefined;
}
/** Returns true if detailed logging is enabled in settings */
export async function isDetailedLoggingEnabled(): Promise<boolean> {
try {
@@ -48,7 +67,7 @@ export async function isDetailedLoggingEnabled(): Promise<boolean> {
export function saveRequestDetailLog(entry: RequestDetailLog): void {
const noLogEnabled =
Boolean(entry.no_log) || (entry.api_key_id ? isNoLog(entry.api_key_id) : false);
if (noLogEnabled) return;
if (noLogEnabled || !requestDetailLogsTableExists()) return;
const db = getDbInstance();
const id = entry.id ?? uuidv4();
@@ -81,6 +100,7 @@ export function saveRequestDetailLog(entry: RequestDetailLog): void {
/** Fetch detailed logs (latest first) */
export function getRequestDetailLogs(limit = 50, offset = 0): RequestDetailLog[] {
if (!requestDetailLogsTableExists()) return [];
const db = getDbInstance();
const rows = db
.prepare(
@@ -97,6 +117,7 @@ export function getRequestDetailLogs(limit = 50, offset = 0): RequestDetailLog[]
/** Get a single detailed log by ID */
export function getRequestDetailLogById(id: string): RequestDetailLog | null {
if (!requestDetailLogsTableExists()) return null;
const db = getDbInstance();
const row = db.prepare("SELECT * FROM request_detail_logs WHERE id = ?").get(id) as
| Record<string, unknown>
@@ -106,6 +127,7 @@ export function getRequestDetailLogById(id: string): RequestDetailLog | null {
/** Get the most recent detailed log for a call log ID */
export function getRequestDetailLogByCallLogId(callLogId: string): RequestDetailLog | null {
if (!requestDetailLogsTableExists()) return null;
const db = getDbInstance();
const row = db
.prepare(
@@ -122,6 +144,7 @@ export function getRequestDetailLogByCallLogId(callLogId: string): RequestDetail
/** Get total count of detailed logs */
export function getRequestDetailLogCount(): number {
if (!requestDetailLogsTableExists()) return 0;
const db = getDbInstance();
const row = db.prepare("SELECT COUNT(*) as cnt FROM request_detail_logs").get() as {
cnt: number;

View File

@@ -23,6 +23,7 @@ const { createStructuredSSECollector } =
async function resetStorage() {
core.resetDbInstance();
apiKeysDb.resetApiKeyState();
detailedLogsDb.resetRequestDetailLogsTableExistsCache();
for (let attempt = 0; attempt < 10; attempt++) {
try {
@@ -72,6 +73,24 @@ test("isDetailedLoggingEnabled follows the stored setting", async () => {
assert.equal(await detailedLogsDb.isDetailedLoggingEnabled(), true);
});
test("legacy detailed log helpers tolerate databases without request_detail_logs", () => {
const db = core.getDbInstance();
db.exec("DROP TABLE request_detail_logs");
assert.doesNotThrow(() =>
detailedLogsDb.saveRequestDetailLog({
id: "missing-table-write",
call_log_id: "call-missing-table",
provider: "openai",
model: "gpt-4.1",
})
);
assert.deepEqual(detailedLogsDb.getRequestDetailLogs(), []);
assert.equal(detailedLogsDb.getRequestDetailLogCount(), 0);
assert.equal(detailedLogsDb.getRequestDetailLogById("missing-table-write"), null);
assert.equal(detailedLogsDb.getRequestDetailLogByCallLogId("call-missing-table"), null);
});
test("saveRequestDetailLog persists protected payloads and compacted stream summaries", () => {
const collector = createStructuredSSECollector({ stage: "provider-response" });
collector.push({