切换到使用pg数据库

This commit is contained in:
2026-05-28 18:22:39 +08:00
parent 4c47841483
commit 5ac50bfeaa
38 changed files with 2760 additions and 1331 deletions
+65 -28
View File
@@ -1,11 +1,6 @@
import { join } from "node:path";
import { type QueryResultRow } from "pg";
import { config } from "../config.js";
import {
atomicWriteJson,
ensureDirectory,
readJsonFile,
} from "../utils/fileStore.js";
import { AgentDatabase, getAgentDatabase } from "../db/index.js";
export type LearningSessionState = {
lastGatedTurn: number;
@@ -15,32 +10,65 @@ export type LearningSessionState = {
updatedAt: string;
};
type LearningStateRow = QueryResultRow & {
session_id: string;
last_gated_turn: number;
last_reviewed_turn: number;
pending_review: boolean;
updated_at: Date | string;
};
export class LearningStateStore {
constructor(private readonly baseDir = config.LEARNING_STATE_STORAGE_DIR) {}
constructor(private readonly db: AgentDatabase = getAgentDatabase()) {}
async initialize() {
await ensureDirectory(this.baseDir);
await this.db.initialize();
}
async read(sessionId: string): Promise<LearningSessionState> {
const existing = await readJsonFile<LearningSessionState>(this.filePath(sessionId));
if (existing) {
return existing;
}
return {
lastGatedTurn: 0,
lastReviewedTurn: 0,
pendingReview: false,
sessionId,
updatedAt: new Date(0).toISOString(),
};
const result = await this.db.query<LearningStateRow>(
`
SELECT session_id, last_gated_turn, last_reviewed_turn, pending_review, updated_at
FROM ${this.db.table("learning_states")}
WHERE session_id = $1
LIMIT 1
`,
[sessionId],
);
return (
mapLearningStateRow(result.rows[0]) ?? {
lastGatedTurn: 0,
lastReviewedTurn: 0,
pendingReview: false,
sessionId,
updatedAt: new Date(0).toISOString(),
}
);
}
async write(state: LearningSessionState) {
await atomicWriteJson(this.filePath(state.sessionId), {
...state,
updatedAt: new Date().toISOString(),
});
await this.db.query(
`
INSERT INTO ${this.db.table("learning_states")} (
session_id,
last_gated_turn,
last_reviewed_turn,
pending_review
)
VALUES ($1, $2, $3, $4)
ON CONFLICT (session_id)
DO UPDATE SET
last_gated_turn = EXCLUDED.last_gated_turn,
last_reviewed_turn = EXCLUDED.last_reviewed_turn,
pending_review = EXCLUDED.pending_review
`,
[
state.sessionId,
state.lastGatedTurn,
state.lastReviewedTurn,
state.pendingReview,
],
);
}
async markPending(sessionId: string, pendingReview: boolean) {
@@ -69,8 +97,17 @@ export class LearningStateStore {
pendingReview: false,
});
}
private filePath(sessionId: string) {
return join(this.baseDir, `${sessionId}.json`);
}
}
const mapLearningStateRow = (row?: LearningStateRow | null): LearningSessionState | null => {
if (!row) {
return null;
}
return {
sessionId: row.session_id,
lastGatedTurn: row.last_gated_turn,
lastReviewedTurn: row.last_reviewed_turn,
pendingReview: row.pending_review,
updatedAt: row.updated_at instanceof Date ? row.updated_at.toISOString() : row.updated_at,
};
};