78 lines
2.5 KiB
TypeScript
78 lines
2.5 KiB
TypeScript
|
|
/** 上下文检查点(A3.8):平台保存「发给模型的上下文」的摘要与来源,权威在平台(实施设计 1.5) */
|
|||
|
|
import type { Database } from './db.js';
|
|||
|
|
|
|||
|
|
export interface ContextCheckpoint {
|
|||
|
|
sessionId: string;
|
|||
|
|
summary: string;
|
|||
|
|
summarySourceIds: string[];
|
|||
|
|
includedMessageIds: string[];
|
|||
|
|
lastMessageId: string | null;
|
|||
|
|
pinned: string[];
|
|||
|
|
estimatedChars: number;
|
|||
|
|
updatedAt: number;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
interface CheckpointRow {
|
|||
|
|
session_id: string;
|
|||
|
|
summary: string;
|
|||
|
|
summary_source_ids: string;
|
|||
|
|
included_message_ids: string;
|
|||
|
|
last_message_id: string | null;
|
|||
|
|
pinned: string;
|
|||
|
|
estimated_chars: number;
|
|||
|
|
updated_at: number;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const parseIds = (raw: string): string[] => {
|
|||
|
|
try {
|
|||
|
|
const parsed = JSON.parse(raw) as unknown;
|
|||
|
|
return Array.isArray(parsed) ? parsed.filter((item): item is string => typeof item === 'string') : [];
|
|||
|
|
} catch {
|
|||
|
|
return [];
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export class ContextRepository {
|
|||
|
|
constructor(private readonly db: Database) {}
|
|||
|
|
|
|||
|
|
save(checkpoint: Omit<ContextCheckpoint, 'updatedAt'>): void {
|
|||
|
|
this.db
|
|||
|
|
.prepare(
|
|||
|
|
`insert into context_checkpoints (session_id, summary, summary_source_ids, included_message_ids, last_message_id, pinned, estimated_chars, updated_at)
|
|||
|
|
values (?, ?, ?, ?, ?, ?, ?, ?)
|
|||
|
|
on conflict(session_id) do update set
|
|||
|
|
summary = excluded.summary,
|
|||
|
|
summary_source_ids = excluded.summary_source_ids,
|
|||
|
|
included_message_ids = excluded.included_message_ids,
|
|||
|
|
last_message_id = excluded.last_message_id,
|
|||
|
|
pinned = excluded.pinned,
|
|||
|
|
estimated_chars = excluded.estimated_chars,
|
|||
|
|
updated_at = excluded.updated_at`,
|
|||
|
|
)
|
|||
|
|
.run(
|
|||
|
|
checkpoint.sessionId,
|
|||
|
|
checkpoint.summary,
|
|||
|
|
JSON.stringify(checkpoint.summarySourceIds),
|
|||
|
|
JSON.stringify(checkpoint.includedMessageIds),
|
|||
|
|
checkpoint.lastMessageId,
|
|||
|
|
JSON.stringify(checkpoint.pinned),
|
|||
|
|
checkpoint.estimatedChars,
|
|||
|
|
Date.now(),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
get(sessionId: string): ContextCheckpoint | undefined {
|
|||
|
|
const row = this.db.prepare('select * from context_checkpoints where session_id = ?').get(sessionId) as unknown as CheckpointRow | undefined;
|
|||
|
|
if (!row) return undefined;
|
|||
|
|
return {
|
|||
|
|
sessionId: row.session_id,
|
|||
|
|
summary: row.summary,
|
|||
|
|
summarySourceIds: parseIds(row.summary_source_ids),
|
|||
|
|
includedMessageIds: parseIds(row.included_message_ids),
|
|||
|
|
lastMessageId: row.last_message_id,
|
|||
|
|
pinned: parseIds(row.pinned),
|
|||
|
|
estimatedChars: row.estimated_chars,
|
|||
|
|
updatedAt: row.updated_at,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|