切换到使用pg数据库
This commit is contained in:
+65
-28
@@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user