@ykurilov/agent-chat-storage-sqlite 0.63.1 → 0.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/index.js.map +1 -1
- package/dist/types/schema.d.ts +3 -7
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @ykurilov/agent-chat-storage-sqlite
|
|
2
2
|
|
|
3
|
+
## 0.64.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 99cded9: Подробности сбоя провайдера для админа. Ответ, упавший на провайдере, хранит `error.details`: провайдер, модель, код, причина одной строкой (до 300 знаков; ключи окружения, `Bearer`, значения `key=`/`token`/`api-key`/`password`, маски ключей со `*`, параметры адресов, `org-…`/`proj_…` и e-mail вычищены; модерация может повторять текст человека) и `resetsAt` — когда провайдер снимет предел (OpenRouter «resets 2026-11-01»; только будущее до двух лет, без пояса — UTC). В браузер подробности уходят только по новому праву `chatCapabilities` → `errorDetails: true` (по умолчанию `false`, при `modelDetails: false` тоже `false`) — в истории, потоке и при переподключении; остальным — только `error.kind`. `afterTurn` получает их всегда. Экран: подпись-функция `labels.errorText(error, plain)`, без неё или если она бросила исключение — прежний текст `labels.errors[kind]`; типы `ChatError`, `ChatErrorDetails`, помощник `customErrorText`. Хранилища: тип колонки `error` — `ChatError`, миграций нет.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [99cded9]
|
|
12
|
+
- @ykurilov/agent-chat-core@0.64.0
|
|
13
|
+
|
|
14
|
+
## 0.63.2
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies [c772243]
|
|
19
|
+
- @ykurilov/agent-chat-core@0.63.2
|
|
20
|
+
|
|
3
21
|
## 0.63.1
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sqlite-storage.ts","../src/schema.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport {\n aliveAtByLocalClock,\n assertChatDataFilter,\n assertKnownFormatVersion,\n ChatAlreadyExistsError,\n chatDataFields,\n chatDataOfInput,\n DuplicateChatSubjectError,\n DuplicateMessageError,\n isOptimizationBlocked,\n mergeChatData,\n MessageAlreadyFinishedError,\n MessageNotAwaitingError,\n revertRefusal,\n sameMessageParts,\n silenceBoundaryByLocalClock,\n} from \"@ykurilov/agent-chat-core\";\nimport type { AnswerAliveMark, Chat, ChatDataFilter, ChatListOptions, ChatStorage, ChatSubjectFilter, MemoryMergeGroup, MemoryNote, MemoryNoteInput, MemoryOptimizationRun, MergedMemoryNote, StoredMessage } from \"@ykurilov/agent-chat-core\";\nimport Database from \"better-sqlite3\";\nimport { and, asc, desc, eq, gte, inArray, isNotNull, isNull, lte, ne, sql } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/better-sqlite3\";\nimport { readMigrationFiles } from \"drizzle-orm/migrator\";\nimport { branchSelections, chats, chatTurnLeases, compactions, memoryNotes, memoryOptimizationRuns, messages, pendingBursts, spendingLimitStates, usageRecords, userModelChoices, voiceChoices } from \"./schema\";\n\nexport interface SqliteChatStorage extends ChatStorage {\n /** Закрывает файл базы. */\n close(): void;\n}\n\nconst migrationsFolder = fileURLToPath(new URL(\"../drizzle\", import.meta.url));\n/** Свой журнал миграций SDK: общий журнал drizzle в файле может вести и приложение. */\nconst MIGRATIONS_TABLE = \"__agent_chat_migrations\";\n/** Общий журнал drizzle: в нём SDK вёл свои миграции до 0.32. */\nconst SHARED_MIGRATIONS_TABLE = \"__drizzle_migrations\";\n\n/** В файле таблицы `chats` или `messages` создал не SDK: открывать такой файл нельзя, миграции испортили бы чужие данные. */\nexport class ForeignChatTablesError extends Error {\n constructor(\n readonly filePath: string,\n readonly tables: readonly string[],\n ) {\n super(\n `В файле ${filePath} чужие таблицы ${tables.join(\" и \")}: их создало не SDK чата. ` +\n `Дайте SDK отдельный файл (например, data/chat.sqlite): общий файл с таблицами приложения не поддерживается. Файл не тронут.`,\n );\n this.name = \"ForeignChatTablesError\";\n }\n}\n\n/**\n * Таблицы SDK узнаются по журналу миграций: в нём есть запись первой миграции SDK. Нет `chats`/`messages` — файл\n * пустой или со своими другими таблицами приложения, SDK создаст свои рядом. Есть, а записи нет — таблицы чужие.\n */\nfunction assertNoForeignChatTables(sqlite: Database.Database, filePath: string): void {\n const names = tableNames(sqlite);\n const found = [\"chats\", \"messages\"].filter((name) => names.has(name));\n if (found.length === 0) return;\n const firstMigrationHash = readMigrationFiles({ migrationsFolder })[0]?.hash;\n const ours = [MIGRATIONS_TABLE, SHARED_MIGRATIONS_TABLE].some((table) => {\n try {\n return names.has(table) && sqlite.prepare(`select 1 from \"${table}\" where hash = ?`).get(firstMigrationHash) !== undefined;\n } catch {\n // У журнала приложения другие колонки: он не наш.\n return false;\n }\n });\n if (!ours) throw new ForeignChatTablesError(filePath, found);\n}\n\nfunction tableNames(sqlite: Database.Database): Set<string> {\n return new Set(sqlite.prepare(\"select name from sqlite_master where type = 'table'\").pluck().all() as string[]);\n}\n\n/**\n * До 0.32 SDK вёл миграции в общем журнале drizzle. drizzle смотрит только на время последней записи: запись приложения\n * новее миграций SDK заставляла их пропускать. Записи SDK (узнаются по хешу или времени своих миграций) один раз\n * копируются в свой журнал; общий журнал не меняется. Под замком записи: две копии сервера не перенесут дважды.\n */\nfunction moveSharedMigrationJournal(sqlite: Database.Database): void {\n sqlite\n .transaction(() => {\n const names = tableNames(sqlite);\n if (names.has(MIGRATIONS_TABLE) || !names.has(SHARED_MIGRATIONS_TABLE)) return;\n let rows: Array<{ hash: string; created_at: number }>;\n try {\n rows = sqlite.prepare(`select hash, created_at from \"${SHARED_MIGRATIONS_TABLE}\"`).all() as typeof rows;\n } catch {\n // У журнала приложения другие колонки: записей SDK в нём нет.\n return;\n }\n const sdk = readMigrationFiles({ migrationsFolder });\n const ours = rows.filter((row) => sdk.some((migration) => migration.hash === row.hash || migration.folderMillis === Number(row.created_at)));\n if (ours.length === 0) return;\n // Та же таблица, что создаёт drizzle для журнала.\n sqlite.exec(`create table \"${MIGRATIONS_TABLE}\" (id SERIAL PRIMARY KEY, hash text NOT NULL, created_at numeric)`);\n const insert = sqlite.prepare(`insert into \"${MIGRATIONS_TABLE}\" (hash, created_at) values (?, ?)`);\n for (const row of ours) insert.run(row.hash, row.created_at);\n })\n .immediate();\n}\n\n/**\n * Применяет миграции SDK, которых нет в своём журнале. Применённой считается миграция, чей хеш или время есть в журнале\n * (drizzle пишет время миграции из `_journal.json`). drizzle сверяет только последнюю запись, поэтому дыру в середине,\n * оставленную общим журналом до 0.32, не видит; здесь она закрывается. Такие миграции идут не по порядку, и это безопасно:\n * пропасть могли только миграции до 0.32, а они лишь добавляют таблицы, столбцы и индексы (это проверяет тест).\n * Журнал тот же, что у drizzle. Всё — одной транзакцией под замком записи: две копии сервера не применят миграцию дважды.\n */\nfunction applyMigrations(sqlite: Database.Database): void {\n const migrations = readMigrationFiles({ migrationsFolder });\n sqlite\n .transaction(() => {\n sqlite.exec(`create table if not exists \"${MIGRATIONS_TABLE}\" (id SERIAL PRIMARY KEY, hash text NOT NULL, created_at numeric)`);\n const rows = sqlite.prepare(`select hash, created_at from \"${MIGRATIONS_TABLE}\"`).all() as Array<{ hash: string; created_at: number }>;\n const hashes = new Set(rows.map((row) => row.hash));\n const times = new Set(rows.map((row) => Number(row.created_at)));\n const record = sqlite.prepare(`insert into \"${MIGRATIONS_TABLE}\" (hash, created_at) values (?, ?)`);\n for (const migration of migrations) {\n if (hashes.has(migration.hash) || times.has(migration.folderMillis)) continue;\n for (const statement of migration.sql) if (statement.trim()) sqlite.exec(statement);\n record.run(migration.hash, migration.folderMillis);\n }\n })\n .immediate();\n}\n\n/** Хранилище в файле SQLite. Схема приводится к последней миграции при открытии. */\nexport function createSqliteChatStorage(options: { filePath: string }): SqliteChatStorage {\n const sqlite = new Database(options.filePath);\n try {\n assertNoForeignChatTables(sqlite, options.filePath);\n moveSharedMigrationJournal(sqlite);\n } catch (error) {\n sqlite.close();\n throw error;\n }\n sqlite.pragma(\"journal_mode = WAL\");\n sqlite.pragma(\"foreign_keys = ON\");\n const db = drizzle(sqlite, { schema: { chats, messages, compactions, branchSelections, usageRecords, userModelChoices, voiceChoices, spendingLimitStates, memoryNotes, memoryOptimizationRuns } });\n applyMigrations(sqlite);\n\n // Транзакции, которые пишут, — «immediate»: запись базы берётся сразу. Иначе чтение и запись разрывались бы, и вторая\n // копия сервера на том же файле роняла бы запись ошибкой «database is locked» вместо ожидания очереди.\n type Transaction = Parameters<Parameters<typeof db.transaction>[0]>[0];\n\n function visibleNotes(tx: Transaction, ownerId: string): MemoryNote[] {\n return tx\n .select()\n .from(memoryNotes)\n .where(and(eq(memoryNotes.ownerId, ownerId), isNull(memoryNotes.mergedInto)))\n .orderBy(desc(memoryNotes.updatedAt), desc(memoryNotes.createdAt), desc(memoryNotes.id))\n .all()\n .map(toMemoryNote);\n }\n\n function insertNotes(tx: Transaction, ownerId: string, inputs: MemoryNoteInput[]): MemoryNote[] {\n const now = Date.now();\n const rows = inputs.map(({ categories, content }): typeof memoryNotes.$inferInsert => ({\n id: crypto.randomUUID(),\n ownerId,\n categories,\n content,\n version: 1,\n createdAt: now,\n updatedAt: now,\n }));\n for (const row of rows) tx.insert(memoryNotes).values(row).run();\n return rows.map((row) => toMemoryNote(row as typeof memoryNotes.$inferSelect));\n }\n\n function updateNote(tx: Transaction, ownerId: string, id: string, expectedVersion: number, input: MemoryNoteInput): MemoryNote | \"not_found\" | \"stale_version\" {\n const row = tx.select().from(memoryNotes).where(ownerNote(ownerId, id)).get();\n if (!row) return \"not_found\";\n if (row.version !== expectedVersion) return \"stale_version\";\n const updated = tx\n .update(memoryNotes)\n .set({\n categories: input.categories,\n content: input.content,\n version: row.version + 1,\n // Часы не отстают от записи: время правки не убывает.\n updatedAt: Math.max(Date.now(), row.updatedAt),\n })\n .where(and(ownerNote(ownerId, id), eq(memoryNotes.version, expectedVersion)))\n .returning()\n .get();\n return updated ? toMemoryNote(updated) : \"stale_version\";\n }\n\n /** Знак жизни в колонку `alive_at`: SQLite живёт на одной машине с сервером, время — по её часам. */\n const aliveAtColumn = (alive: AnswerAliveMark | undefined) => (alive ? { aliveAt: aliveAtByLocalClock(alive) } : {});\n\n /** Пишет в идущий ответ; отличает «нет такого» от «уже в конечном состоянии». */\n function updateStreaming(messageId: string, { alive, ...values }: Partial<typeof messages.$inferInsert> & { alive?: AnswerAliveMark }): void {\n const result = db\n .update(messages)\n .set({ ...values, ...aliveAtColumn(alive) })\n .where(and(eq(messages.id, messageId), eq(messages.status, \"streaming\")))\n .run();\n if (result.changes > 0) return;\n const existing = db.select({ id: messages.id }).from(messages).where(eq(messages.id, messageId)).get();\n if (!existing) throw new Error(`Сообщения ${messageId} нет`);\n throw new MessageAlreadyFinishedError(messageId);\n }\n\n return {\n async createChat({ createdAt, ...input }) {\n const at = createdAt ?? new Date().toISOString();\n const row = chatRow({ ...input, createdAt: at, updatedAt: at });\n try {\n db.insert(chats).values(row).run();\n } catch (error) {\n if (isSubjectConflict(error)) throw new DuplicateChatSubjectError(input.ownerId, input.subjectKey!);\n throw error;\n }\n return toChat(row);\n },\n\n async findChatBySubject(ownerId, subjectKey) {\n const row = db.select().from(chats).where(and(eq(chats.ownerId, ownerId), eq(chats.subjectKey, subjectKey))).get();\n return row ? toChat(row) : null;\n },\n\n async importChat(chat, imported) {\n db.transaction((tx) => {\n try {\n tx.insert(chats).values(chatRow(chat)).run();\n } catch (error) {\n if (isSubjectConflict(error)) throw new DuplicateChatSubjectError(chat.ownerId, chat.subjectKey!);\n if (isPrimaryKeyConflict(error)) throw new ChatAlreadyExistsError(chat.id);\n throw error;\n }\n for (const message of imported) {\n const nextSeq = sql<number>`(select coalesce(max(${messages.seq}), 0) + 1 from ${messages})`;\n const { alive: _alive, ...stored } = message;\n try {\n tx.insert(messages).values({ ...stored, seq: nextSeq }).run();\n } catch (error) {\n if (isPrimaryKeyConflict(error)) throw new DuplicateMessageError(message.id);\n throw error;\n }\n }\n }, { behavior: \"immediate\" });\n },\n\n async setAfterTurnState(messageId, state, options) {\n // Чтение, проверка состояния и запись — одна транзакция с блокировкой записи: другая копия не вклинится.\n return db.transaction(\n (tx) => {\n const existing = tx.select({ parts: messages.parts, afterTurn: messages.afterTurn }).from(messages).where(eq(messages.id, messageId)).get();\n if (!existing || (state !== \"pending\" && existing.afterTurn !== \"pending\")) return false;\n tx.update(messages)\n .set({\n afterTurn: state,\n ...(options?.appendParts && { parts: [...existing.parts, ...options.appendParts] }),\n // Отметка ожидания хука — в колонке знака жизни: у законченного ответа она больше ни для чего.\n ...(state === \"pending\" && aliveAtColumn(\"now\")),\n })\n .where(eq(messages.id, messageId))\n .run();\n return true;\n },\n { behavior: \"immediate\" },\n );\n },\n\n async listPendingAfterTurn(filter) {\n return db\n .select({ id: messages.id })\n .from(messages)\n .where(\n filter?.pendingForMs === undefined\n ? eq(messages.afterTurn, \"pending\")\n : and(\n eq(messages.afterTurn, \"pending\"),\n sql`coalesce(${messages.aliveAt}, ${messages.createdAt}) < ${silenceBoundaryByLocalClock(filter.pendingForMs)}`,\n ),\n )\n .all()\n .map((row) => row.id);\n },\n\n async getChat(chatId) {\n const row = db.select().from(chats).where(eq(chats.id, chatId)).get();\n return row ? toChat(row) : null;\n },\n\n async updateChatModel(chatId, model) {\n db.update(chats)\n .set({ modelId: model.modelId, providerId: model.providerId, reasoning: model.reasoning ?? null })\n .where(eq(chats.id, chatId))\n .run();\n },\n\n async updateChatData(chatId, patch, { maxBytes }) {\n // Чтение, слияние и запись — одна транзакция с блокировкой на запись: параллельные правки не затирают друг друга.\n return db.transaction(\n (tx) => {\n const row = tx.select().from(chats).where(eq(chats.id, chatId)).get();\n if (!row) return null;\n const merged = mergeChatData(row.subjectData ?? undefined, patch, maxBytes);\n tx.update(chats).set({ subjectData: merged ?? null }).where(eq(chats.id, chatId)).run();\n return toChat({ ...row, subjectData: merged ?? null });\n },\n { behavior: \"immediate\" },\n );\n },\n\n async listChats(ownerId, options?: ChatListOptions) {\n if (options?.data) assertChatDataFilter(options.data);\n const rows = db\n .select()\n .from(chats)\n .where(and(eq(chats.ownerId, ownerId), subjectCondition(options?.subjects), ...dataConditions(options?.data)))\n .orderBy(desc(chats.updatedAt), desc(chats.createdAt), desc(chats.id))\n .all();\n return rows.map(toChat);\n },\n\n async renameChat(chatId, title) {\n db.update(chats).set({ title }).where(eq(chats.id, chatId)).run();\n },\n\n async setChatClosed(chatId, closed) {\n db.update(chats).set({ closed: closed && { code: closed.code, message: closed.message } }).where(eq(chats.id, chatId)).run();\n },\n\n async deleteChat(chatId) {\n db.transaction((tx) => {\n tx.delete(compactions).where(eq(compactions.chatId, chatId)).run();\n tx.delete(branchSelections).where(eq(branchSelections.chatId, chatId)).run();\n tx.delete(messages).where(eq(messages.chatId, chatId)).run();\n tx.delete(chats).where(eq(chats.id, chatId)).run();\n tx.delete(chatTurnLeases).where(eq(chatTurnLeases.chatId, chatId)).run();\n tx.delete(pendingBursts).where(eq(pendingBursts.chatId, chatId)).run();\n }, { behavior: \"immediate\" });\n },\n\n async claimChatTurn(chatId, holder, leaseMs) {\n const now = Date.now();\n // Одной записью: свободный чат — вставка; своя или просроченная чужая — замена; живая чужая — ничего.\n const claimed = db\n .insert(chatTurnLeases)\n .values({ chatId, holder, until: now + leaseMs })\n .onConflictDoUpdate({\n target: chatTurnLeases.chatId,\n set: { holder, until: now + leaseMs },\n setWhere: sql`${chatTurnLeases.holder} = ${holder} or ${chatTurnLeases.until} <= ${now}`,\n })\n .returning({ chatId: chatTurnLeases.chatId })\n .all();\n return claimed.length > 0;\n },\n\n async releaseChatTurn(chatId, holder) {\n db.delete(chatTurnLeases).where(and(eq(chatTurnLeases.chatId, chatId), eq(chatTurnLeases.holder, holder))).run();\n },\n\n async clearChatTurnLeases() {\n db.delete(chatTurnLeases).run();\n },\n\n async savePendingBurst(burst) {\n const row = {\n chatId: burst.chatId,\n ownerId: burst.ownerId,\n messageId: burst.messageId,\n dueAt: Date.parse(burst.dueAt),\n holder: burst.holder,\n heldUntil: Date.parse(burst.heldUntil),\n page: burst.page ?? null,\n };\n db.insert(pendingBursts).values(row).onConflictDoUpdate({ target: pendingBursts.chatId, set: row }).run();\n },\n\n async takeAbandonedBursts({ abandonedBefore, holder, heldUntil, limit, exceptHolder }) {\n // Выбор и захват — одной записью: другая копия на той же базе ждёт замка и видит пачку уже взятой.\n return db.transaction((tx) => {\n const abandoned = tx\n .select()\n .from(pendingBursts)\n .where(and(lte(pendingBursts.heldUntil, Date.parse(abandonedBefore)), exceptHolder === undefined ? undefined : ne(pendingBursts.holder, exceptHolder)))\n .orderBy(asc(pendingBursts.dueAt))\n .limit(limit)\n .all();\n const until = Date.parse(heldUntil);\n for (const row of abandoned) tx.update(pendingBursts).set({ holder, heldUntil: until }).where(eq(pendingBursts.chatId, row.chatId)).run();\n return abandoned.map((row) => ({\n chatId: row.chatId,\n ownerId: row.ownerId,\n messageId: row.messageId,\n dueAt: new Date(row.dueAt).toISOString(),\n holder,\n heldUntil,\n ...(row.page && { page: row.page }),\n }));\n }, { behavior: \"immediate\" });\n },\n\n async renewPendingBurst({ chatId, messageId, holder, heldUntil }) {\n const renewed = db\n .update(pendingBursts)\n .set({ heldUntil: Date.parse(heldUntil) })\n .where(and(eq(pendingBursts.chatId, chatId), eq(pendingBursts.messageId, messageId), eq(pendingBursts.holder, holder)))\n .run();\n return renewed.changes > 0;\n },\n\n async removePendingBurst(chatId, messageId) {\n db.delete(pendingBursts).where(and(eq(pendingBursts.chatId, chatId), eq(pendingBursts.messageId, messageId))).run();\n },\n\n async getMessage(messageId) {\n const row = db.select().from(messages).where(eq(messages.id, messageId)).get();\n if (!row) return null;\n const message = toMessage(row);\n assertKnownFormatVersion(message);\n return message;\n },\n\n // При равном времени порядок записи задаёт `seq`: `rowid` VACUUM вправе перенумеровать.\n async listMessages(chatId) {\n const rows = db\n .select()\n .from(messages)\n .where(eq(messages.chatId, chatId))\n .orderBy(asc(messages.createdAt), messages.seq)\n .all();\n const found: StoredMessage[] = rows.map(toMessage);\n found.forEach(assertKnownFormatVersion);\n return found;\n },\n\n async listMessageLinks(chatId) {\n return db\n .select({ id: messages.id, parentId: messages.parentId, createdAt: messages.createdAt })\n .from(messages)\n .where(eq(messages.chatId, chatId))\n .orderBy(asc(messages.createdAt), messages.seq)\n .all();\n },\n\n // Части нужных типов выбираются внутри базы: тексты и выводы инструментов в процесс не идут.\n async listMessagePartsOfTypes(chatId, types) {\n const wanted = JSON.stringify([...types]);\n const rows = db\n .select({\n id: messages.id,\n parentId: messages.parentId,\n createdAt: messages.createdAt,\n parts: sql<string>`(select coalesce(json_group_array(json(picked.value)), '[]') from (select part.value from json_each(${messages.parts}) as part where json_extract(part.value, '$.type') in (select value from json_each(${wanted})) order by part.key) as picked)`,\n })\n .from(messages)\n .where(eq(messages.chatId, chatId))\n .orderBy(asc(messages.createdAt), messages.seq)\n .all();\n return rows.map((row) => ({ ...row, parts: JSON.parse(row.parts) as StoredMessage[\"parts\"] }));\n },\n\n async insertMessage(message) {\n try {\n db.transaction((tx) => {\n const nextSeq = sql<number>`(select coalesce(max(${messages.seq}), 0) + 1 from ${messages})`;\n const { alive, ...stored } = message;\n tx.insert(messages).values({ ...stored, ...aliveAtColumn(alive), seq: nextSeq }).run();\n tx.update(chats).set({ updatedAt: message.createdAt }).where(eq(chats.id, message.chatId)).run();\n }, { behavior: \"immediate\" });\n } catch (error) {\n if (isPrimaryKeyConflict(error)) throw new DuplicateMessageError(message.id);\n throw error;\n }\n },\n\n updateStreamingMessage: async (messageId, patch) => updateStreaming(messageId, patch),\n\n markAnswerAlive: async (messageId) => updateStreaming(messageId, { alive: \"now\" }),\n\n finishMessage: async (messageId, final) => updateStreaming(messageId, { ...final, ...(final.afterTurn === \"pending\" && { alive: \"now\" as const }) }),\n\n async updateAwaitingMessage(messageId, patch) {\n // Чтение, сравнение частей и запись — одна транзакция с блокировкой записи: другая копия не вклинится между ними.\n db.transaction(\n (tx) => {\n const existing = tx.select({ status: messages.status, parts: messages.parts }).from(messages).where(eq(messages.id, messageId)).get();\n if (!existing) throw new Error(`Сообщения ${messageId} нет`);\n if (existing.status !== \"awaiting_approval\") throw new MessageNotAwaitingError(messageId);\n if (patch.expectedParts && !sameMessageParts(existing.parts, patch.expectedParts)) throw new MessageNotAwaitingError(messageId);\n tx.update(messages)\n .set({ parts: patch.parts, ...(patch.status && { status: patch.status }), ...aliveAtColumn(patch.alive) })\n .where(eq(messages.id, messageId))\n .run();\n },\n { behavior: \"immediate\" },\n );\n },\n\n async listStreamingMessageIds() {\n return db\n .select({ id: messages.id })\n .from(messages)\n .where(eq(messages.status, \"streaming\"))\n .all()\n .map((row) => row.id);\n },\n\n async listSilentAnswerIds({ silentForMs, chatId }) {\n const silent = sql`coalesce(${messages.aliveAt}, ${messages.createdAt}) < ${silenceBoundaryByLocalClock(silentForMs)}`;\n return db\n .select({ id: messages.id })\n .from(messages)\n .where(and(eq(messages.status, \"streaming\"), silent, chatId === undefined ? undefined : eq(messages.chatId, chatId)))\n .all()\n .map((row) => row.id);\n },\n\n async insertCompaction(record) {\n const nextSeq = sql<number>`(select coalesce(max(${compactions.seq}), 0) + 1 from ${compactions})`;\n db.insert(compactions).values({ ...record, seq: nextSeq }).run();\n },\n\n async listCompactions(chatId) {\n const rows = db.select().from(compactions).where(eq(compactions.chatId, chatId)).orderBy(asc(compactions.seq)).all();\n return rows.map(({ seq: _seq, ...record }) => record);\n },\n\n async insertBranchSelection(record) {\n const nextSeq = sql<number>`(select coalesce(max(${branchSelections.seq}), 0) + 1 from ${branchSelections})`;\n db.insert(branchSelections).values({ ...record, seq: nextSeq }).run();\n },\n\n async listBranchSelections(chatId) {\n const rows = db.select().from(branchSelections).where(eq(branchSelections.chatId, chatId)).orderBy(asc(branchSelections.seq)).all();\n return rows.map(({ seq: _seq, ...record }) => record);\n },\n\n async insertUsageRecord(record) {\n db.insert(usageRecords).values(record).run();\n },\n\n async hasUsageRecord(id) {\n return db.select({ id: usageRecords.id }).from(usageRecords).where(eq(usageRecords.id, id)).get() !== undefined;\n },\n\n async sumUsage({ ownerId, chatId, messageId, source, since }) {\n const filters = [\n ...(ownerId !== undefined ? [eq(usageRecords.ownerId, ownerId)] : []),\n ...(chatId !== undefined ? [eq(usageRecords.chatId, chatId)] : []),\n ...(messageId !== undefined ? [eq(usageRecords.messageId, messageId)] : []),\n ...(source !== undefined ? [eq(usageRecords.source, source)] : []),\n ...(since !== undefined ? [gte(usageRecords.createdAt, since)] : []),\n ];\n return db\n .select({\n modelId: usageRecords.modelId,\n providerId: usageRecords.providerId,\n inputTokens: sql<number>`sum(${usageRecords.inputTokens})`.mapWith(Number),\n cachedInputTokens: sql<number>`sum(${usageRecords.cachedInputTokens})`.mapWith(Number),\n cacheWriteTokens: sql<number>`sum(${usageRecords.cacheWriteTokens})`.mapWith(Number),\n outputTokens: sql<number>`sum(${usageRecords.outputTokens})`.mapWith(Number),\n reasoningTokens: sql<number>`sum(${usageRecords.reasoningTokens})`.mapWith(Number),\n costUsd: sql<number>`sum(${usageRecords.costUsd})`.mapWith(Number),\n })\n .from(usageRecords)\n .where(and(...filters))\n .groupBy(usageRecords.modelId, usageRecords.providerId)\n .all();\n },\n\n async sumUsageByChat({ chatIds, ownerId, source, since }) {\n if (chatIds.length === 0) return [];\n const filters = [\n inArray(usageRecords.chatId, [...chatIds]),\n ...(ownerId !== undefined ? [eq(usageRecords.ownerId, ownerId)] : []),\n ...(source !== undefined ? [eq(usageRecords.source, source)] : []),\n ...(since !== undefined ? [gte(usageRecords.createdAt, since)] : []),\n ];\n return db\n .select({\n chatId: usageRecords.chatId,\n modelId: usageRecords.modelId,\n providerId: usageRecords.providerId,\n inputTokens: sql<number>`sum(${usageRecords.inputTokens})`.mapWith(Number),\n cachedInputTokens: sql<number>`sum(${usageRecords.cachedInputTokens})`.mapWith(Number),\n cacheWriteTokens: sql<number>`sum(${usageRecords.cacheWriteTokens})`.mapWith(Number),\n outputTokens: sql<number>`sum(${usageRecords.outputTokens})`.mapWith(Number),\n reasoningTokens: sql<number>`sum(${usageRecords.reasoningTokens})`.mapWith(Number),\n costUsd: sql<number>`sum(${usageRecords.costUsd})`.mapWith(Number),\n })\n .from(usageRecords)\n .where(and(...filters))\n .groupBy(usageRecords.chatId, usageRecords.modelId, usageRecords.providerId)\n .all();\n },\n\n async getUserModelChoice(ownerId) {\n const row = db.select().from(userModelChoices).where(eq(userModelChoices.ownerId, ownerId)).get();\n if (!row) return null;\n return { modelId: row.modelId, providerId: row.providerId, ...(row.reasoning !== null && { reasoning: row.reasoning }) };\n },\n\n async saveUserModelChoice(ownerId, choice) {\n const values = { modelId: choice.modelId, providerId: choice.providerId, reasoning: choice.reasoning ?? null, updatedAt: new Date().toISOString() };\n db.insert(userModelChoices).values({ ownerId, ...values }).onConflictDoUpdate({ target: userModelChoices.ownerId, set: values }).run();\n },\n\n async setVoiceCut({ ownerId, chatId, messageId, voiceCut }) {\n db.update(messages)\n .set({ voiceCut })\n .where(\n and(\n eq(messages.id, messageId),\n eq(messages.chatId, chatId),\n sql`exists (select 1 from ${chats} where ${chats.id} = ${chatId} and ${chats.ownerId} = ${ownerId})`,\n ),\n )\n .run();\n },\n\n async getSpendingLimitState(key) {\n const row = db.select().from(spendingLimitStates).where(eq(spendingLimitStates.key, key)).get();\n return row ? { value: row.value, version: row.version } : null;\n },\n\n // Одна команда без чтения: вставка или правка срабатывает только при совпавшей версии, лишнего «вклинивания» нет.\n async saveSpendingLimitState(key, value, expectedVersion) {\n const updatedAt = new Date().toISOString();\n if (expectedVersion === null) {\n return db.insert(spendingLimitStates).values({ key, value, version: 1, updatedAt }).onConflictDoNothing().run().changes === 1;\n }\n const changed = db\n .update(spendingLimitStates)\n .set({ value, version: expectedVersion + 1, updatedAt })\n .where(and(eq(spendingLimitStates.key, key), eq(spendingLimitStates.version, expectedVersion)))\n .run().changes;\n return changed === 1;\n },\n\n async deleteSpendingLimitStates(keys) {\n if (keys.length > 0) db.delete(spendingLimitStates).where(inArray(spendingLimitStates.key, keys)).run();\n },\n\n async getVoiceChoice(ownerId) {\n return db.select().from(voiceChoices).where(eq(voiceChoices.ownerId, ownerId)).get()?.voiceId ?? null;\n },\n\n async setVoiceChoice(ownerId, voiceId) {\n const values = { voiceId, updatedAt: new Date().toISOString() };\n db.insert(voiceChoices).values({ ownerId, ...values }).onConflictDoUpdate({ target: voiceChoices.ownerId, set: values }).run();\n },\n\n async listMemoryNotes(ownerId) {\n return db.transaction((tx) => visibleNotes(tx, ownerId));\n },\n\n // Пакет вставляется одной транзакцией: негодная запись (NOT NULL) откатывает и остальные.\n async insertMemoryNotes(ownerId, inputs) {\n return db.transaction((tx) => insertNotes(tx, ownerId, inputs), { behavior: \"immediate\" });\n },\n\n async insertMemoryNotesChecked(ownerId, inputs, guard) {\n return db.transaction(\n (tx) => {\n const error = guard(visibleNotes(tx, ownerId));\n return error ?? insertNotes(tx, ownerId, inputs);\n },\n { behavior: \"immediate\" },\n );\n },\n\n async updateMemoryNote(ownerId, id, expectedVersion, input) {\n return db.transaction((tx) => updateNote(tx, ownerId, id, expectedVersion, input), { behavior: \"immediate\" });\n },\n\n async updateMemoryNoteChecked(ownerId, id, expectedVersion, input, guard) {\n return db.transaction((tx) => guard(visibleNotes(tx, ownerId)) ?? updateNote(tx, ownerId, id, expectedVersion, input), { behavior: \"immediate\" });\n },\n\n async deleteMemoryNote(ownerId, id, expectedVersion) {\n return db.transaction((tx) => {\n const row = tx.select({ version: memoryNotes.version }).from(memoryNotes).where(ownerNote(ownerId, id)).get();\n if (!row) return \"not_found\";\n if (row.version !== expectedVersion) return \"stale_version\";\n const result = tx.delete(memoryNotes).where(and(ownerNote(ownerId, id), eq(memoryNotes.version, expectedVersion))).run();\n if (result.changes === 0) return \"stale_version\";\n // Скрытые оригиналы слияния уходят вместе с результатом.\n tx.delete(memoryNotes).where(and(eq(memoryNotes.ownerId, ownerId), eq(memoryNotes.mergedInto, id))).run();\n return \"ok\";\n }, { behavior: \"immediate\" });\n },\n\n async clearMemoryNotes(ownerId) {\n return db.transaction((tx) => {\n const deleted = tx.delete(memoryNotes).where(eq(memoryNotes.ownerId, ownerId)).returning({ mergedInto: memoryNotes.mergedInto }).all();\n tx.delete(memoryOptimizationRuns).where(eq(memoryOptimizationRuns.ownerId, ownerId)).run();\n // Считаются записи, которые человек видел; скрытые оригиналы — служебные.\n return deleted.filter((row) => row.mergedInto === null).length;\n }, { behavior: \"immediate\" });\n },\n\n // Взятие запуска — одна транзакция: проверка правил и вставка не разрываются (SQLite пишет по одному).\n async claimMemoryOptimizationRun(ownerId, rules, now) {\n const nowMs = Date.parse(now);\n return db.transaction((tx) => {\n const runs = tx.select().from(memoryOptimizationRuns).where(eq(memoryOptimizationRuns.ownerId, ownerId)).all();\n for (const run of runs) {\n const leaseEnd = run.startedAt + rules.leaseMs;\n if (run.status !== \"running\" || nowMs < leaseEnd) continue;\n tx.update(memoryOptimizationRuns).set({ status: \"failed\", error: \"lease_expired\", finishedAt: leaseEnd }).where(eq(memoryOptimizationRuns.id, run.id)).run();\n Object.assign(run, { status: \"failed\", finishedAt: leaseEnd });\n }\n const blocked = isOptimizationBlocked(\n runs.map((run) => ({ status: run.status, startedAtMs: run.startedAt, endedAtMs: run.finishedAt })),\n rules,\n nowMs,\n );\n if (blocked) return null;\n const row = { id: crypto.randomUUID(), ownerId, startedAt: nowMs, finishedAt: null, status: \"running\" as const, groups: [], error: null, usageRecordId: null };\n tx.insert(memoryOptimizationRuns).values(row).run();\n return toOptimizationRun(row);\n }, { behavior: \"immediate\" });\n },\n\n async finishMemoryOptimizationRun(ownerId, runId, outcome) {\n const result = db\n .update(memoryOptimizationRuns)\n .set({ status: outcome.status, finishedAt: Date.parse(outcome.finishedAt), error: outcome.error ?? null, usageRecordId: outcome.usageRecordId ?? null })\n .where(and(eq(memoryOptimizationRuns.id, runId), eq(memoryOptimizationRuns.ownerId, ownerId), eq(memoryOptimizationRuns.status, \"running\")))\n .run();\n return result.changes > 0 ? \"ok\" : \"not_found\";\n },\n\n // Слияние — одна транзакция: любая неудача (в том числе негодный результат) откатывает всё.\n async applyMemoryMerge(ownerId, merge) {\n const { merges } = merge;\n if (merges.length === 0) throw new TypeError(\"Слияние без склеек\");\n const seen = new Set<string>();\n for (const { originals } of merges) {\n if (originals.length === 0) throw new TypeError(\"Склейка без оригиналов\");\n for (const { id } of originals) {\n if (seen.has(id)) throw new TypeError(`Запись ${id} названа в двух склейках`);\n seen.add(id);\n }\n }\n return db.transaction((tx) => {\n const run = tx.select().from(memoryOptimizationRuns).where(and(eq(memoryOptimizationRuns.id, merge.runId), eq(memoryOptimizationRuns.ownerId, ownerId))).get();\n if (run?.status !== \"running\") return \"run_not_active\";\n // Сначала проверка всех оригиналов, потом запись: откат в транзакции только по исключению.\n for (const { originals } of merges) {\n for (const { id, version } of originals) {\n const original = tx.select({ version: memoryNotes.version }).from(memoryNotes).where(ownerNote(ownerId, id)).get();\n if (original?.version !== version) return \"stale_version\";\n }\n }\n const now = Date.now();\n const groups: MemoryMergeGroup[] = merges.map(({ result, originals }) => {\n const created = { id: crypto.randomUUID(), ownerId, categories: result.categories, content: result.content, version: 1, createdAt: now, updatedAt: now };\n tx.insert(memoryNotes).values(created).run();\n for (const { id } of originals) tx.update(memoryNotes).set({ mergedInto: created.id }).where(ownerNote(ownerId, id)).run();\n return { resultId: created.id, originalIds: originals.map(({ id }) => id), resultVersion: 1 };\n });\n const finished = { status: \"applied\" as const, finishedAt: Date.parse(merge.finishedAt), groups, usageRecordId: merge.usageRecordId ?? null };\n tx.update(memoryOptimizationRuns).set(finished).where(eq(memoryOptimizationRuns.id, run.id)).run();\n return toOptimizationRun({ ...run, ...finished });\n }, { behavior: \"immediate\" });\n },\n\n async revertMemoryMerge(ownerId, runId, guard) {\n return db.transaction((tx) => {\n const run = tx.select().from(memoryOptimizationRuns).where(and(eq(memoryOptimizationRuns.id, runId), eq(memoryOptimizationRuns.ownerId, ownerId))).get();\n if (run?.status !== \"applied\") return \"not_found\";\n for (const { resultId, originalIds, resultVersion } of run.groups) {\n const result = tx.select({ version: memoryNotes.version }).from(memoryNotes).where(ownerNote(ownerId, resultId)).get();\n if (result?.version !== resultVersion) return \"conflict\";\n const hidden = tx\n .select({ id: memoryNotes.id })\n .from(memoryNotes)\n .where(and(eq(memoryNotes.ownerId, ownerId), eq(memoryNotes.mergedInto, resultId), inArray(memoryNotes.id, originalIds)))\n .all();\n if (hidden.length !== originalIds.length) return \"conflict\";\n }\n if (guard) {\n const resultIds = run.groups.map(({ resultId }) => resultId);\n const remaining = visibleNotes(tx, ownerId).filter((note) => !resultIds.includes(note.id));\n const restored = tx\n .select()\n .from(memoryNotes)\n .where(and(eq(memoryNotes.ownerId, ownerId), inArray(memoryNotes.mergedInto, resultIds)))\n .orderBy(desc(memoryNotes.updatedAt), desc(memoryNotes.createdAt), desc(memoryNotes.id))\n .all()\n .map(toMemoryNote);\n const error = guard(remaining, restored);\n if (error) return revertRefusal(error);\n }\n for (const { resultId } of run.groups) {\n tx.update(memoryNotes).set({ mergedInto: null }).where(and(eq(memoryNotes.ownerId, ownerId), eq(memoryNotes.mergedInto, resultId))).run();\n tx.delete(memoryNotes).where(ownerNote(ownerId, resultId)).run();\n }\n tx.update(memoryOptimizationRuns).set({ status: \"reverted\" }).where(eq(memoryOptimizationRuns.id, run.id)).run();\n return \"ok\";\n }, { behavior: \"immediate\" });\n },\n\n async listMemoryOptimizationRuns(ownerId, filter) {\n const rows = db\n .select()\n .from(memoryOptimizationRuns)\n .where(and(eq(memoryOptimizationRuns.ownerId, ownerId), ...(filter?.status ? [inArray(memoryOptimizationRuns.status, filter.status)] : [])))\n .orderBy(desc(memoryOptimizationRuns.startedAt), sql`rowid desc`)\n .limit(filter?.limit ?? -1)\n .all();\n return rows.map(toOptimizationRun);\n },\n\n async listMergedMemoryNotes(ownerId) {\n const rows = db\n .select()\n .from(memoryNotes)\n .where(and(eq(memoryNotes.ownerId, ownerId), isNotNull(memoryNotes.mergedInto)))\n .orderBy(desc(memoryNotes.updatedAt), desc(memoryNotes.createdAt), desc(memoryNotes.id))\n .all();\n return rows.map((row): MergedMemoryNote => ({ ...toMemoryNote(row), mergedInto: row.mergedInto! }));\n },\n\n close() {\n sqlite.close();\n },\n };\n}\n\n/** Запись чата в строку: поле без значения — пусто. */\nfunction chatRow(chat: Chat): typeof chats.$inferSelect {\n return {\n id: chat.id,\n ownerId: chat.ownerId,\n modelId: chat.modelId,\n providerId: chat.providerId,\n reasoning: chat.reasoning ?? null,\n title: chat.title ?? null,\n origin: chat.origin ?? null,\n subjectKey: chat.subjectKey ?? null,\n subjectData: chatDataOfInput(chat) ?? null,\n closed: chat.closed ?? null,\n createdAt: chat.createdAt,\n updatedAt: chat.updatedAt,\n };\n}\n\n/** Строка чата в запись ядра: пустые необязательные поля — отсутствие поля. */\nfunction toChat(row: typeof chats.$inferSelect): Chat {\n const { reasoning, title, origin, subjectKey, subjectData, closed, ...chat } = row;\n return {\n ...chat,\n ...(reasoning !== null && { reasoning }),\n ...(title !== null && { title }),\n ...(origin !== null && { origin }),\n ...(subjectKey !== null && { subjectKey }),\n ...chatDataFields(subjectData),\n ...(closed !== null && { closed }),\n };\n}\n\n/** Фильтр `listChats` по ключу объекта; по умолчанию — только чаты без ключа. */\nfunction subjectCondition(subjects: ChatSubjectFilter = \"exclude\") {\n if (subjects === \"include\") return undefined;\n return subjects === \"only\" ? isNotNull(chats.subjectKey) : isNull(chats.subjectKey);\n}\n\n/**\n * Фильтр `listChats` по данным чата: на каждый ключ — проверка через `json_each`: ключ как есть (точки и кавычки не\n * путаются с путём), тип значения важен (`true` не равно `1`, `\"1\"` не равно `1`).\n */\nfunction dataConditions(filter: ChatDataFilter | undefined) {\n return Object.entries(filter ?? {}).map(([key, value]) => {\n const typed =\n value === null\n ? sql`type = 'null'`\n : typeof value === \"string\"\n ? sql`type = 'text' and value = ${value}`\n : typeof value === \"boolean\"\n ? sql`type = ${value ? \"true\" : \"false\"}`\n : sql`type in ('integer', 'real') and value = ${value}`;\n return sql`exists (select 1 from json_each(${chats.subjectData}) where key = ${key} and ${typed})`;\n });\n}\n\n/** Строка сообщения в запись ядра: без служебных колонок; пустое состояние хука итога — отсутствие поля. */\nfunction toMessage(row: typeof messages.$inferSelect): StoredMessage {\n const { seq: _seq, aliveAt: _aliveAt, afterTurn, ...message } = row;\n return { ...message, ...(afterTurn !== null && { afterTurn }) };\n}\n\n/** Видимая запись памяти этого человека: чужая по тому же id и скрытый оригинал слияния не находятся. */\nfunction ownerNote(ownerId: string, id: string) {\n return and(eq(memoryNotes.ownerId, ownerId), eq(memoryNotes.id, id), isNull(memoryNotes.mergedInto));\n}\n\n/** Строка запуска в запись ядра: владельца наружу не отдаём, время — в ISO 8601. */\nfunction toOptimizationRun(row: typeof memoryOptimizationRuns.$inferSelect): MemoryOptimizationRun {\n return {\n id: row.id,\n startedAt: new Date(row.startedAt).toISOString(),\n finishedAt: row.finishedAt === null ? null : new Date(row.finishedAt).toISOString(),\n status: row.status,\n groups: row.groups.map((group) => ({ ...group, originalIds: [...group.originalIds] })),\n error: row.error,\n usageRecordId: row.usageRecordId,\n };\n}\n\n/** Строка памяти в запись ядра: владельца наружу не отдаём, время — в ISO 8601. */\nfunction toMemoryNote(row: typeof memoryNotes.$inferSelect): MemoryNote {\n return {\n id: row.id,\n categories: [...row.categories],\n content: row.content,\n version: row.version,\n createdAt: new Date(row.createdAt).toISOString(),\n updatedAt: new Date(row.updatedAt).toISOString(),\n };\n}\n\n/** Нарушен уникальный индекс (владелец, ключ объекта). */\nfunction isSubjectConflict(error: unknown): boolean {\n const { code, message, cause } = (error ?? {}) as { code?: unknown; message?: unknown; cause?: { code?: unknown; message?: unknown } };\n return (\n [code, cause?.code].includes(\"SQLITE_CONSTRAINT_UNIQUE\") &&\n [message, cause?.message].some((text) => typeof text === \"string\" && text.includes(\"chats.subject_key\"))\n );\n}\n\nfunction isPrimaryKeyConflict(error: unknown): boolean {\n const { code, cause } = (error ?? {}) as { code?: unknown; cause?: { code?: unknown } };\n return [code, cause?.code].includes(\"SQLITE_CONSTRAINT_PRIMARYKEY\");\n}\n","import type {\n AnswerStatus,\n ChatClosure,\n ChatErrorKind,\n MemoryMergeGroup,\n MemoryOptimizationStatus,\n StoredMessage,\n TokenUsage,\n TurnRequestContext,\n UsageSource,\n VoiceCut,\n} from \"@ykurilov/agent-chat-core\";\nimport { sql } from \"drizzle-orm\";\nimport { index, integer, real, sqliteTable, text, uniqueIndex } from \"drizzle-orm/sqlite-core\";\n\nexport const chats = sqliteTable(\n \"chats\",\n {\n id: text(\"id\").primaryKey(),\n ownerId: text(\"owner_id\").notNull(),\n modelId: text(\"model_id\").notNull(),\n providerId: text(\"provider_id\").notNull(),\n reasoning: text(\"reasoning\"),\n /** Название для списка чатов; пусто — чат без названия. */\n title: text(\"title\"),\n /** Мессенджер, из которого создан чат; пусто — чат создан в вебе. */\n origin: text(\"origin\", { enum: [\"telegram\", \"vk\", \"max\"] }),\n /** Ключ объекта приложения; пусто — обычный чат. У владельца ключ не повторяется. */\n subjectKey: text(\"subject_key\"),\n /** Данные объекта (JSON-объект); пусто — данных нет. */\n subjectData: text(\"subject_data\", { mode: \"json\" }).$type<Record<string, unknown>>(),\n /** Закрытие чата (JSON `{ code, message }`); пусто — чат открыт. */\n closed: text(\"closed\", { mode: \"json\" }).$type<ChatClosure>(),\n createdAt: text(\"created_at\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [\n index(\"chats_owner_updated_idx\").on(table.ownerId, table.updatedAt),\n uniqueIndex(\"chats_owner_subject_idx\").on(table.ownerId, table.subjectKey),\n ],\n);\n\nexport const messages = sqliteTable(\n \"messages\",\n {\n id: text(\"id\").primaryKey(),\n chatId: text(\"chat_id\")\n .notNull()\n .references(() => chats.id, { onDelete: \"cascade\" }),\n parentId: text(\"parent_id\"),\n role: text(\"role\", { enum: [\"user\", \"assistant\"] }).notNull(),\n parts: text(\"parts\", { mode: \"json\" }).$type<StoredMessage[\"parts\"]>().notNull(),\n formatVersion: integer(\"format_version\").notNull(),\n status: text(\"status\").$type<AnswerStatus>().notNull(),\n modelId: text(\"model_id\"),\n providerId: text(\"provider_id\"),\n usage: text(\"usage\", { mode: \"json\" }).$type<TokenUsage>(),\n reasoningDurationsMs: text(\"reasoning_durations_ms\", { mode: \"json\" }).$type<Record<string, number>>().notNull(),\n error: text(\"error\", { mode: \"json\" }).$type<{ kind: ChatErrorKind }>(),\n /** Отметка обрыва озвучки (голосовой режим); пусто — озвучку не обрывали. */\n voiceCut: text(\"voice_cut\", { mode: \"json\" }).$type<VoiceCut>(),\n /** Состояние хука итога хода; пусто — хук не зовётся. */\n afterTurn: text(\"after_turn\", { enum: [\"pending\", \"done\", \"failed\"] }),\n createdAt: text(\"created_at\").notNull(),\n /** Последний знак жизни идущего ответа (ISO); пусто — время создания. Только для восстановления, при чтении не отдаётся. */\n aliveAt: text(\"alive_at\"),\n /** Порядок записи: при равном `created_at` сообщения читаются по возрастанию `seq`. Задаётся при вставке. */\n seq: integer(\"seq\").notNull().default(0),\n },\n (table) => [\n index(\"messages_chat_created_idx\").on(table.chatId, table.createdAt, table.seq),\n uniqueIndex(\"messages_seq_idx\").on(table.seq),\n index(\"messages_streaming_idx\").on(table.status).where(sql`${table.status} = 'streaming'`),\n index(\"messages_after_turn_pending_idx\").on(table.afterTurn).where(sql`${table.afterTurn} = 'pending'`),\n ],\n);\n\n/** Записи сжатия: только добавляются. Порядок добавления — `seq`. */\nexport const compactions = sqliteTable(\n \"compactions\",\n {\n id: text(\"id\").primaryKey(),\n chatId: text(\"chat_id\")\n .notNull()\n .references(() => chats.id, { onDelete: \"cascade\" }),\n fromMessageId: text(\"from_message_id\").notNull(),\n throughMessageId: text(\"through_message_id\").notNull(),\n summary: text(\"summary\").notNull(),\n summaryTokens: integer(\"summary_tokens\").notNull(),\n modelId: text(\"model_id\").notNull(),\n providerId: text(\"provider_id\").notNull(),\n usage: text(\"usage\", { mode: \"json\" }).$type<TokenUsage>(),\n createdAt: text(\"created_at\").notNull(),\n seq: integer(\"seq\").notNull().default(0),\n },\n (table) => [\n index(\"compactions_chat_seq_idx\").on(table.chatId, table.seq),\n uniqueIndex(\"compactions_seq_idx\").on(table.seq),\n ],\n);\n\n/** Отметки выбора ветки: только добавляются. Порядок добавления — `seq`. */\nexport const branchSelections = sqliteTable(\n \"branch_selections\",\n {\n id: text(\"id\").primaryKey(),\n chatId: text(\"chat_id\")\n .notNull()\n .references(() => chats.id, { onDelete: \"cascade\" }),\n messageId: text(\"message_id\").notNull(),\n selectedAt: text(\"selected_at\").notNull(),\n seq: integer(\"seq\").notNull().default(0),\n },\n (table) => [\n index(\"branch_selections_chat_seq_idx\").on(table.chatId, table.seq),\n uniqueIndex(\"branch_selections_seq_idx\").on(table.seq),\n ],\n);\n\n/**\n * Журнал расхода токенов: только добавляется и не связан с чатами внешним ключом, чтобы переживать их удаление.\n * Месячный расход человека от удаления переписки не убывает.\n */\nexport const usageRecords = sqliteTable(\n \"usage_records\",\n {\n id: text(\"id\").primaryKey(),\n ownerId: text(\"owner_id\").notNull(),\n chatId: text(\"chat_id\").notNull(),\n messageId: text(\"message_id\"),\n source: text(\"source\").$type<UsageSource>().notNull(),\n modelId: text(\"model_id\").notNull(),\n providerId: text(\"provider_id\").notNull(),\n inputTokens: integer(\"input_tokens\").notNull(),\n cachedInputTokens: integer(\"cached_input_tokens\").notNull(),\n cacheWriteTokens: integer(\"cache_write_tokens\").notNull(),\n outputTokens: integer(\"output_tokens\").notNull(),\n reasoningTokens: integer(\"reasoning_tokens\").notNull(),\n costUsd: real(\"cost_usd\").notNull(),\n createdAt: text(\"created_at\").notNull(),\n /** Числа «примерно»: прикинуты по длине текста, а не сообщены провайдером. */\n estimated: integer(\"estimated\", { mode: \"boolean\" }).notNull().default(false),\n },\n (table) => [\n index(\"usage_records_owner_created_idx\").on(table.ownerId, table.createdAt),\n index(\"usage_records_chat_created_idx\").on(table.chatId, table.createdAt),\n ],\n);\n\n/** Последний выбор модели человека для новых чатов: одна строка на человека; с чатами не связан. */\nexport const userModelChoices = sqliteTable(\"user_model_choices\", {\n ownerId: text(\"owner_id\").primaryKey(),\n modelId: text(\"model_id\").notNull(),\n providerId: text(\"provider_id\").notNull(),\n /** Пусто — у модели нет уровней рассуждений. */\n reasoning: text(\"reasoning\"),\n updatedAt: text(\"updated_at\").notNull(),\n});\n\n/** Выбранный человеком голос озвучки: одна строка на человека; с чатами и выбором модели не связан. */\nexport const voiceChoices = sqliteTable(\"voice_choices\", {\n ownerId: text(\"owner_id\").primaryKey(),\n voiceId: text(\"voice_id\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n});\n\n/** Состояние лимитов расходов по ключу: значение — строка (JSON решает ядро); `version` растёт на 1 при каждой записи и служит замком. */\nexport const spendingLimitStates = sqliteTable(\"spending_limit_states\", {\n key: text(\"key\").primaryKey(),\n value: text(\"value\").notNull(),\n version: integer(\"version\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n});\n\n/**\n * Аренда хода чата между копиями сервера: кто держит (`holder`) и до какого времени (`until`, мс по часам машины с базой).\n * Внешним ключом с чатом не связана: удаление чата снимает её само.\n */\nexport const chatTurnLeases = sqliteTable(\"chat_turn_leases\", {\n chatId: text(\"chat_id\").primaryKey(),\n holder: text(\"holder\").notNull(),\n until: integer(\"until\").notNull(),\n});\n\n/**\n * Ждущие пачки сообщений человека: одна запись на чат. Сроки — мс по часам службы; `page` — JSON страницы хода.\n * Внешним ключом с чатом не связана: удаление чата снимает её само.\n */\nexport const pendingBursts = sqliteTable(\"pending_bursts\", {\n chatId: text(\"chat_id\").primaryKey(),\n ownerId: text(\"owner_id\").notNull(),\n messageId: text(\"message_id\").notNull(),\n dueAt: integer(\"due_at\").notNull(),\n holder: text(\"holder\").notNull(),\n heldUntil: integer(\"held_until\").notNull(),\n page: text(\"page\", { mode: \"json\" }).$type<TurnRequestContext>(),\n});\n\n/**\n * Долгая память: записи человека. С чатами внешним ключом не связаны — удаление чата память не трогает.\n * Время в миллисекундах; `categories` — JSON-список из 1–3 разделов.\n */\nexport const memoryNotes = sqliteTable(\n \"memory_notes\",\n {\n id: text(\"id\").primaryKey(),\n ownerId: text(\"owner_id\").notNull(),\n categories: text(\"categories\", { mode: \"json\" }).$type<string[]>().notNull(),\n content: text(\"content\").notNull(),\n version: integer(\"version\").notNull().default(1),\n createdAt: integer(\"created_at\").notNull(),\n updatedAt: integer(\"updated_at\").notNull(),\n /** Оптимизация дублей: id записи-результата у скрытого оригинала слияния; у обычных записей пусто. */\n mergedInto: text(\"merged_into\"),\n },\n (table) => [\n index(\"memory_notes_owner_updated_idx\").on(table.ownerId, table.updatedAt),\n index(\"memory_notes_merged_into_idx\").on(table.mergedInto),\n ],\n);\n\n/**\n * Оптимизация дублей: запуски человека. Время в миллисекундах; `groups` — JSON-список склеек\n * (результат, оригиналы, версия результата на момент слияния). Запуск `running` у человека не больше одного.\n */\nexport const memoryOptimizationRuns = sqliteTable(\n \"memory_optimization_runs\",\n {\n id: text(\"id\").primaryKey(),\n ownerId: text(\"owner_id\").notNull(),\n startedAt: integer(\"started_at\").notNull(),\n finishedAt: integer(\"finished_at\"),\n status: text(\"status\").$type<MemoryOptimizationStatus>().notNull(),\n groups: text(\"groups\", { mode: \"json\" }).$type<MemoryMergeGroup[]>().notNull().default(sql`'[]'`),\n error: text(\"error\"),\n usageRecordId: text(\"usage_record_id\"),\n },\n (table) => [\n index(\"memory_optimization_runs_owner_started_idx\").on(table.ownerId, table.startedAt),\n uniqueIndex(\"memory_optimization_runs_one_running_idx\").on(table.ownerId).where(sql`${table.status} = 'running'`),\n ],\n);\n"],"mappings":"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","names":["sql","sql","options","text"]}
|
|
1
|
+
{"version":3,"sources":["../src/sqlite-storage.ts","../src/schema.ts"],"sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport {\n aliveAtByLocalClock,\n assertChatDataFilter,\n assertKnownFormatVersion,\n ChatAlreadyExistsError,\n chatDataFields,\n chatDataOfInput,\n DuplicateChatSubjectError,\n DuplicateMessageError,\n isOptimizationBlocked,\n mergeChatData,\n MessageAlreadyFinishedError,\n MessageNotAwaitingError,\n revertRefusal,\n sameMessageParts,\n silenceBoundaryByLocalClock,\n} from \"@ykurilov/agent-chat-core\";\nimport type { AnswerAliveMark, Chat, ChatDataFilter, ChatListOptions, ChatStorage, ChatSubjectFilter, MemoryMergeGroup, MemoryNote, MemoryNoteInput, MemoryOptimizationRun, MergedMemoryNote, StoredMessage } from \"@ykurilov/agent-chat-core\";\nimport Database from \"better-sqlite3\";\nimport { and, asc, desc, eq, gte, inArray, isNotNull, isNull, lte, ne, sql } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/better-sqlite3\";\nimport { readMigrationFiles } from \"drizzle-orm/migrator\";\nimport { branchSelections, chats, chatTurnLeases, compactions, memoryNotes, memoryOptimizationRuns, messages, pendingBursts, spendingLimitStates, usageRecords, userModelChoices, voiceChoices } from \"./schema\";\n\nexport interface SqliteChatStorage extends ChatStorage {\n /** Закрывает файл базы. */\n close(): void;\n}\n\nconst migrationsFolder = fileURLToPath(new URL(\"../drizzle\", import.meta.url));\n/** Свой журнал миграций SDK: общий журнал drizzle в файле может вести и приложение. */\nconst MIGRATIONS_TABLE = \"__agent_chat_migrations\";\n/** Общий журнал drizzle: в нём SDK вёл свои миграции до 0.32. */\nconst SHARED_MIGRATIONS_TABLE = \"__drizzle_migrations\";\n\n/** В файле таблицы `chats` или `messages` создал не SDK: открывать такой файл нельзя, миграции испортили бы чужие данные. */\nexport class ForeignChatTablesError extends Error {\n constructor(\n readonly filePath: string,\n readonly tables: readonly string[],\n ) {\n super(\n `В файле ${filePath} чужие таблицы ${tables.join(\" и \")}: их создало не SDK чата. ` +\n `Дайте SDK отдельный файл (например, data/chat.sqlite): общий файл с таблицами приложения не поддерживается. Файл не тронут.`,\n );\n this.name = \"ForeignChatTablesError\";\n }\n}\n\n/**\n * Таблицы SDK узнаются по журналу миграций: в нём есть запись первой миграции SDK. Нет `chats`/`messages` — файл\n * пустой или со своими другими таблицами приложения, SDK создаст свои рядом. Есть, а записи нет — таблицы чужие.\n */\nfunction assertNoForeignChatTables(sqlite: Database.Database, filePath: string): void {\n const names = tableNames(sqlite);\n const found = [\"chats\", \"messages\"].filter((name) => names.has(name));\n if (found.length === 0) return;\n const firstMigrationHash = readMigrationFiles({ migrationsFolder })[0]?.hash;\n const ours = [MIGRATIONS_TABLE, SHARED_MIGRATIONS_TABLE].some((table) => {\n try {\n return names.has(table) && sqlite.prepare(`select 1 from \"${table}\" where hash = ?`).get(firstMigrationHash) !== undefined;\n } catch {\n // У журнала приложения другие колонки: он не наш.\n return false;\n }\n });\n if (!ours) throw new ForeignChatTablesError(filePath, found);\n}\n\nfunction tableNames(sqlite: Database.Database): Set<string> {\n return new Set(sqlite.prepare(\"select name from sqlite_master where type = 'table'\").pluck().all() as string[]);\n}\n\n/**\n * До 0.32 SDK вёл миграции в общем журнале drizzle. drizzle смотрит только на время последней записи: запись приложения\n * новее миграций SDK заставляла их пропускать. Записи SDK (узнаются по хешу или времени своих миграций) один раз\n * копируются в свой журнал; общий журнал не меняется. Под замком записи: две копии сервера не перенесут дважды.\n */\nfunction moveSharedMigrationJournal(sqlite: Database.Database): void {\n sqlite\n .transaction(() => {\n const names = tableNames(sqlite);\n if (names.has(MIGRATIONS_TABLE) || !names.has(SHARED_MIGRATIONS_TABLE)) return;\n let rows: Array<{ hash: string; created_at: number }>;\n try {\n rows = sqlite.prepare(`select hash, created_at from \"${SHARED_MIGRATIONS_TABLE}\"`).all() as typeof rows;\n } catch {\n // У журнала приложения другие колонки: записей SDK в нём нет.\n return;\n }\n const sdk = readMigrationFiles({ migrationsFolder });\n const ours = rows.filter((row) => sdk.some((migration) => migration.hash === row.hash || migration.folderMillis === Number(row.created_at)));\n if (ours.length === 0) return;\n // Та же таблица, что создаёт drizzle для журнала.\n sqlite.exec(`create table \"${MIGRATIONS_TABLE}\" (id SERIAL PRIMARY KEY, hash text NOT NULL, created_at numeric)`);\n const insert = sqlite.prepare(`insert into \"${MIGRATIONS_TABLE}\" (hash, created_at) values (?, ?)`);\n for (const row of ours) insert.run(row.hash, row.created_at);\n })\n .immediate();\n}\n\n/**\n * Применяет миграции SDK, которых нет в своём журнале. Применённой считается миграция, чей хеш или время есть в журнале\n * (drizzle пишет время миграции из `_journal.json`). drizzle сверяет только последнюю запись, поэтому дыру в середине,\n * оставленную общим журналом до 0.32, не видит; здесь она закрывается. Такие миграции идут не по порядку, и это безопасно:\n * пропасть могли только миграции до 0.32, а они лишь добавляют таблицы, столбцы и индексы (это проверяет тест).\n * Журнал тот же, что у drizzle. Всё — одной транзакцией под замком записи: две копии сервера не применят миграцию дважды.\n */\nfunction applyMigrations(sqlite: Database.Database): void {\n const migrations = readMigrationFiles({ migrationsFolder });\n sqlite\n .transaction(() => {\n sqlite.exec(`create table if not exists \"${MIGRATIONS_TABLE}\" (id SERIAL PRIMARY KEY, hash text NOT NULL, created_at numeric)`);\n const rows = sqlite.prepare(`select hash, created_at from \"${MIGRATIONS_TABLE}\"`).all() as Array<{ hash: string; created_at: number }>;\n const hashes = new Set(rows.map((row) => row.hash));\n const times = new Set(rows.map((row) => Number(row.created_at)));\n const record = sqlite.prepare(`insert into \"${MIGRATIONS_TABLE}\" (hash, created_at) values (?, ?)`);\n for (const migration of migrations) {\n if (hashes.has(migration.hash) || times.has(migration.folderMillis)) continue;\n for (const statement of migration.sql) if (statement.trim()) sqlite.exec(statement);\n record.run(migration.hash, migration.folderMillis);\n }\n })\n .immediate();\n}\n\n/** Хранилище в файле SQLite. Схема приводится к последней миграции при открытии. */\nexport function createSqliteChatStorage(options: { filePath: string }): SqliteChatStorage {\n const sqlite = new Database(options.filePath);\n try {\n assertNoForeignChatTables(sqlite, options.filePath);\n moveSharedMigrationJournal(sqlite);\n } catch (error) {\n sqlite.close();\n throw error;\n }\n sqlite.pragma(\"journal_mode = WAL\");\n sqlite.pragma(\"foreign_keys = ON\");\n const db = drizzle(sqlite, { schema: { chats, messages, compactions, branchSelections, usageRecords, userModelChoices, voiceChoices, spendingLimitStates, memoryNotes, memoryOptimizationRuns } });\n applyMigrations(sqlite);\n\n // Транзакции, которые пишут, — «immediate»: запись базы берётся сразу. Иначе чтение и запись разрывались бы, и вторая\n // копия сервера на том же файле роняла бы запись ошибкой «database is locked» вместо ожидания очереди.\n type Transaction = Parameters<Parameters<typeof db.transaction>[0]>[0];\n\n function visibleNotes(tx: Transaction, ownerId: string): MemoryNote[] {\n return tx\n .select()\n .from(memoryNotes)\n .where(and(eq(memoryNotes.ownerId, ownerId), isNull(memoryNotes.mergedInto)))\n .orderBy(desc(memoryNotes.updatedAt), desc(memoryNotes.createdAt), desc(memoryNotes.id))\n .all()\n .map(toMemoryNote);\n }\n\n function insertNotes(tx: Transaction, ownerId: string, inputs: MemoryNoteInput[]): MemoryNote[] {\n const now = Date.now();\n const rows = inputs.map(({ categories, content }): typeof memoryNotes.$inferInsert => ({\n id: crypto.randomUUID(),\n ownerId,\n categories,\n content,\n version: 1,\n createdAt: now,\n updatedAt: now,\n }));\n for (const row of rows) tx.insert(memoryNotes).values(row).run();\n return rows.map((row) => toMemoryNote(row as typeof memoryNotes.$inferSelect));\n }\n\n function updateNote(tx: Transaction, ownerId: string, id: string, expectedVersion: number, input: MemoryNoteInput): MemoryNote | \"not_found\" | \"stale_version\" {\n const row = tx.select().from(memoryNotes).where(ownerNote(ownerId, id)).get();\n if (!row) return \"not_found\";\n if (row.version !== expectedVersion) return \"stale_version\";\n const updated = tx\n .update(memoryNotes)\n .set({\n categories: input.categories,\n content: input.content,\n version: row.version + 1,\n // Часы не отстают от записи: время правки не убывает.\n updatedAt: Math.max(Date.now(), row.updatedAt),\n })\n .where(and(ownerNote(ownerId, id), eq(memoryNotes.version, expectedVersion)))\n .returning()\n .get();\n return updated ? toMemoryNote(updated) : \"stale_version\";\n }\n\n /** Знак жизни в колонку `alive_at`: SQLite живёт на одной машине с сервером, время — по её часам. */\n const aliveAtColumn = (alive: AnswerAliveMark | undefined) => (alive ? { aliveAt: aliveAtByLocalClock(alive) } : {});\n\n /** Пишет в идущий ответ; отличает «нет такого» от «уже в конечном состоянии». */\n function updateStreaming(messageId: string, { alive, ...values }: Partial<typeof messages.$inferInsert> & { alive?: AnswerAliveMark }): void {\n const result = db\n .update(messages)\n .set({ ...values, ...aliveAtColumn(alive) })\n .where(and(eq(messages.id, messageId), eq(messages.status, \"streaming\")))\n .run();\n if (result.changes > 0) return;\n const existing = db.select({ id: messages.id }).from(messages).where(eq(messages.id, messageId)).get();\n if (!existing) throw new Error(`Сообщения ${messageId} нет`);\n throw new MessageAlreadyFinishedError(messageId);\n }\n\n return {\n async createChat({ createdAt, ...input }) {\n const at = createdAt ?? new Date().toISOString();\n const row = chatRow({ ...input, createdAt: at, updatedAt: at });\n try {\n db.insert(chats).values(row).run();\n } catch (error) {\n if (isSubjectConflict(error)) throw new DuplicateChatSubjectError(input.ownerId, input.subjectKey!);\n throw error;\n }\n return toChat(row);\n },\n\n async findChatBySubject(ownerId, subjectKey) {\n const row = db.select().from(chats).where(and(eq(chats.ownerId, ownerId), eq(chats.subjectKey, subjectKey))).get();\n return row ? toChat(row) : null;\n },\n\n async importChat(chat, imported) {\n db.transaction((tx) => {\n try {\n tx.insert(chats).values(chatRow(chat)).run();\n } catch (error) {\n if (isSubjectConflict(error)) throw new DuplicateChatSubjectError(chat.ownerId, chat.subjectKey!);\n if (isPrimaryKeyConflict(error)) throw new ChatAlreadyExistsError(chat.id);\n throw error;\n }\n for (const message of imported) {\n const nextSeq = sql<number>`(select coalesce(max(${messages.seq}), 0) + 1 from ${messages})`;\n const { alive: _alive, ...stored } = message;\n try {\n tx.insert(messages).values({ ...stored, seq: nextSeq }).run();\n } catch (error) {\n if (isPrimaryKeyConflict(error)) throw new DuplicateMessageError(message.id);\n throw error;\n }\n }\n }, { behavior: \"immediate\" });\n },\n\n async setAfterTurnState(messageId, state, options) {\n // Чтение, проверка состояния и запись — одна транзакция с блокировкой записи: другая копия не вклинится.\n return db.transaction(\n (tx) => {\n const existing = tx.select({ parts: messages.parts, afterTurn: messages.afterTurn }).from(messages).where(eq(messages.id, messageId)).get();\n if (!existing || (state !== \"pending\" && existing.afterTurn !== \"pending\")) return false;\n tx.update(messages)\n .set({\n afterTurn: state,\n ...(options?.appendParts && { parts: [...existing.parts, ...options.appendParts] }),\n // Отметка ожидания хука — в колонке знака жизни: у законченного ответа она больше ни для чего.\n ...(state === \"pending\" && aliveAtColumn(\"now\")),\n })\n .where(eq(messages.id, messageId))\n .run();\n return true;\n },\n { behavior: \"immediate\" },\n );\n },\n\n async listPendingAfterTurn(filter) {\n return db\n .select({ id: messages.id })\n .from(messages)\n .where(\n filter?.pendingForMs === undefined\n ? eq(messages.afterTurn, \"pending\")\n : and(\n eq(messages.afterTurn, \"pending\"),\n sql`coalesce(${messages.aliveAt}, ${messages.createdAt}) < ${silenceBoundaryByLocalClock(filter.pendingForMs)}`,\n ),\n )\n .all()\n .map((row) => row.id);\n },\n\n async getChat(chatId) {\n const row = db.select().from(chats).where(eq(chats.id, chatId)).get();\n return row ? toChat(row) : null;\n },\n\n async updateChatModel(chatId, model) {\n db.update(chats)\n .set({ modelId: model.modelId, providerId: model.providerId, reasoning: model.reasoning ?? null })\n .where(eq(chats.id, chatId))\n .run();\n },\n\n async updateChatData(chatId, patch, { maxBytes }) {\n // Чтение, слияние и запись — одна транзакция с блокировкой на запись: параллельные правки не затирают друг друга.\n return db.transaction(\n (tx) => {\n const row = tx.select().from(chats).where(eq(chats.id, chatId)).get();\n if (!row) return null;\n const merged = mergeChatData(row.subjectData ?? undefined, patch, maxBytes);\n tx.update(chats).set({ subjectData: merged ?? null }).where(eq(chats.id, chatId)).run();\n return toChat({ ...row, subjectData: merged ?? null });\n },\n { behavior: \"immediate\" },\n );\n },\n\n async listChats(ownerId, options?: ChatListOptions) {\n if (options?.data) assertChatDataFilter(options.data);\n const rows = db\n .select()\n .from(chats)\n .where(and(eq(chats.ownerId, ownerId), subjectCondition(options?.subjects), ...dataConditions(options?.data)))\n .orderBy(desc(chats.updatedAt), desc(chats.createdAt), desc(chats.id))\n .all();\n return rows.map(toChat);\n },\n\n async renameChat(chatId, title) {\n db.update(chats).set({ title }).where(eq(chats.id, chatId)).run();\n },\n\n async setChatClosed(chatId, closed) {\n db.update(chats).set({ closed: closed && { code: closed.code, message: closed.message } }).where(eq(chats.id, chatId)).run();\n },\n\n async deleteChat(chatId) {\n db.transaction((tx) => {\n tx.delete(compactions).where(eq(compactions.chatId, chatId)).run();\n tx.delete(branchSelections).where(eq(branchSelections.chatId, chatId)).run();\n tx.delete(messages).where(eq(messages.chatId, chatId)).run();\n tx.delete(chats).where(eq(chats.id, chatId)).run();\n tx.delete(chatTurnLeases).where(eq(chatTurnLeases.chatId, chatId)).run();\n tx.delete(pendingBursts).where(eq(pendingBursts.chatId, chatId)).run();\n }, { behavior: \"immediate\" });\n },\n\n async claimChatTurn(chatId, holder, leaseMs) {\n const now = Date.now();\n // Одной записью: свободный чат — вставка; своя или просроченная чужая — замена; живая чужая — ничего.\n const claimed = db\n .insert(chatTurnLeases)\n .values({ chatId, holder, until: now + leaseMs })\n .onConflictDoUpdate({\n target: chatTurnLeases.chatId,\n set: { holder, until: now + leaseMs },\n setWhere: sql`${chatTurnLeases.holder} = ${holder} or ${chatTurnLeases.until} <= ${now}`,\n })\n .returning({ chatId: chatTurnLeases.chatId })\n .all();\n return claimed.length > 0;\n },\n\n async releaseChatTurn(chatId, holder) {\n db.delete(chatTurnLeases).where(and(eq(chatTurnLeases.chatId, chatId), eq(chatTurnLeases.holder, holder))).run();\n },\n\n async clearChatTurnLeases() {\n db.delete(chatTurnLeases).run();\n },\n\n async savePendingBurst(burst) {\n const row = {\n chatId: burst.chatId,\n ownerId: burst.ownerId,\n messageId: burst.messageId,\n dueAt: Date.parse(burst.dueAt),\n holder: burst.holder,\n heldUntil: Date.parse(burst.heldUntil),\n page: burst.page ?? null,\n };\n db.insert(pendingBursts).values(row).onConflictDoUpdate({ target: pendingBursts.chatId, set: row }).run();\n },\n\n async takeAbandonedBursts({ abandonedBefore, holder, heldUntil, limit, exceptHolder }) {\n // Выбор и захват — одной записью: другая копия на той же базе ждёт замка и видит пачку уже взятой.\n return db.transaction((tx) => {\n const abandoned = tx\n .select()\n .from(pendingBursts)\n .where(and(lte(pendingBursts.heldUntil, Date.parse(abandonedBefore)), exceptHolder === undefined ? undefined : ne(pendingBursts.holder, exceptHolder)))\n .orderBy(asc(pendingBursts.dueAt))\n .limit(limit)\n .all();\n const until = Date.parse(heldUntil);\n for (const row of abandoned) tx.update(pendingBursts).set({ holder, heldUntil: until }).where(eq(pendingBursts.chatId, row.chatId)).run();\n return abandoned.map((row) => ({\n chatId: row.chatId,\n ownerId: row.ownerId,\n messageId: row.messageId,\n dueAt: new Date(row.dueAt).toISOString(),\n holder,\n heldUntil,\n ...(row.page && { page: row.page }),\n }));\n }, { behavior: \"immediate\" });\n },\n\n async renewPendingBurst({ chatId, messageId, holder, heldUntil }) {\n const renewed = db\n .update(pendingBursts)\n .set({ heldUntil: Date.parse(heldUntil) })\n .where(and(eq(pendingBursts.chatId, chatId), eq(pendingBursts.messageId, messageId), eq(pendingBursts.holder, holder)))\n .run();\n return renewed.changes > 0;\n },\n\n async removePendingBurst(chatId, messageId) {\n db.delete(pendingBursts).where(and(eq(pendingBursts.chatId, chatId), eq(pendingBursts.messageId, messageId))).run();\n },\n\n async getMessage(messageId) {\n const row = db.select().from(messages).where(eq(messages.id, messageId)).get();\n if (!row) return null;\n const message = toMessage(row);\n assertKnownFormatVersion(message);\n return message;\n },\n\n // При равном времени порядок записи задаёт `seq`: `rowid` VACUUM вправе перенумеровать.\n async listMessages(chatId) {\n const rows = db\n .select()\n .from(messages)\n .where(eq(messages.chatId, chatId))\n .orderBy(asc(messages.createdAt), messages.seq)\n .all();\n const found: StoredMessage[] = rows.map(toMessage);\n found.forEach(assertKnownFormatVersion);\n return found;\n },\n\n async listMessageLinks(chatId) {\n return db\n .select({ id: messages.id, parentId: messages.parentId, createdAt: messages.createdAt })\n .from(messages)\n .where(eq(messages.chatId, chatId))\n .orderBy(asc(messages.createdAt), messages.seq)\n .all();\n },\n\n // Части нужных типов выбираются внутри базы: тексты и выводы инструментов в процесс не идут.\n async listMessagePartsOfTypes(chatId, types) {\n const wanted = JSON.stringify([...types]);\n const rows = db\n .select({\n id: messages.id,\n parentId: messages.parentId,\n createdAt: messages.createdAt,\n parts: sql<string>`(select coalesce(json_group_array(json(picked.value)), '[]') from (select part.value from json_each(${messages.parts}) as part where json_extract(part.value, '$.type') in (select value from json_each(${wanted})) order by part.key) as picked)`,\n })\n .from(messages)\n .where(eq(messages.chatId, chatId))\n .orderBy(asc(messages.createdAt), messages.seq)\n .all();\n return rows.map((row) => ({ ...row, parts: JSON.parse(row.parts) as StoredMessage[\"parts\"] }));\n },\n\n async insertMessage(message) {\n try {\n db.transaction((tx) => {\n const nextSeq = sql<number>`(select coalesce(max(${messages.seq}), 0) + 1 from ${messages})`;\n const { alive, ...stored } = message;\n tx.insert(messages).values({ ...stored, ...aliveAtColumn(alive), seq: nextSeq }).run();\n tx.update(chats).set({ updatedAt: message.createdAt }).where(eq(chats.id, message.chatId)).run();\n }, { behavior: \"immediate\" });\n } catch (error) {\n if (isPrimaryKeyConflict(error)) throw new DuplicateMessageError(message.id);\n throw error;\n }\n },\n\n updateStreamingMessage: async (messageId, patch) => updateStreaming(messageId, patch),\n\n markAnswerAlive: async (messageId) => updateStreaming(messageId, { alive: \"now\" }),\n\n finishMessage: async (messageId, final) => updateStreaming(messageId, { ...final, ...(final.afterTurn === \"pending\" && { alive: \"now\" as const }) }),\n\n async updateAwaitingMessage(messageId, patch) {\n // Чтение, сравнение частей и запись — одна транзакция с блокировкой записи: другая копия не вклинится между ними.\n db.transaction(\n (tx) => {\n const existing = tx.select({ status: messages.status, parts: messages.parts }).from(messages).where(eq(messages.id, messageId)).get();\n if (!existing) throw new Error(`Сообщения ${messageId} нет`);\n if (existing.status !== \"awaiting_approval\") throw new MessageNotAwaitingError(messageId);\n if (patch.expectedParts && !sameMessageParts(existing.parts, patch.expectedParts)) throw new MessageNotAwaitingError(messageId);\n tx.update(messages)\n .set({ parts: patch.parts, ...(patch.status && { status: patch.status }), ...aliveAtColumn(patch.alive) })\n .where(eq(messages.id, messageId))\n .run();\n },\n { behavior: \"immediate\" },\n );\n },\n\n async listStreamingMessageIds() {\n return db\n .select({ id: messages.id })\n .from(messages)\n .where(eq(messages.status, \"streaming\"))\n .all()\n .map((row) => row.id);\n },\n\n async listSilentAnswerIds({ silentForMs, chatId }) {\n const silent = sql`coalesce(${messages.aliveAt}, ${messages.createdAt}) < ${silenceBoundaryByLocalClock(silentForMs)}`;\n return db\n .select({ id: messages.id })\n .from(messages)\n .where(and(eq(messages.status, \"streaming\"), silent, chatId === undefined ? undefined : eq(messages.chatId, chatId)))\n .all()\n .map((row) => row.id);\n },\n\n async insertCompaction(record) {\n const nextSeq = sql<number>`(select coalesce(max(${compactions.seq}), 0) + 1 from ${compactions})`;\n db.insert(compactions).values({ ...record, seq: nextSeq }).run();\n },\n\n async listCompactions(chatId) {\n const rows = db.select().from(compactions).where(eq(compactions.chatId, chatId)).orderBy(asc(compactions.seq)).all();\n return rows.map(({ seq: _seq, ...record }) => record);\n },\n\n async insertBranchSelection(record) {\n const nextSeq = sql<number>`(select coalesce(max(${branchSelections.seq}), 0) + 1 from ${branchSelections})`;\n db.insert(branchSelections).values({ ...record, seq: nextSeq }).run();\n },\n\n async listBranchSelections(chatId) {\n const rows = db.select().from(branchSelections).where(eq(branchSelections.chatId, chatId)).orderBy(asc(branchSelections.seq)).all();\n return rows.map(({ seq: _seq, ...record }) => record);\n },\n\n async insertUsageRecord(record) {\n db.insert(usageRecords).values(record).run();\n },\n\n async hasUsageRecord(id) {\n return db.select({ id: usageRecords.id }).from(usageRecords).where(eq(usageRecords.id, id)).get() !== undefined;\n },\n\n async sumUsage({ ownerId, chatId, messageId, source, since }) {\n const filters = [\n ...(ownerId !== undefined ? [eq(usageRecords.ownerId, ownerId)] : []),\n ...(chatId !== undefined ? [eq(usageRecords.chatId, chatId)] : []),\n ...(messageId !== undefined ? [eq(usageRecords.messageId, messageId)] : []),\n ...(source !== undefined ? [eq(usageRecords.source, source)] : []),\n ...(since !== undefined ? [gte(usageRecords.createdAt, since)] : []),\n ];\n return db\n .select({\n modelId: usageRecords.modelId,\n providerId: usageRecords.providerId,\n inputTokens: sql<number>`sum(${usageRecords.inputTokens})`.mapWith(Number),\n cachedInputTokens: sql<number>`sum(${usageRecords.cachedInputTokens})`.mapWith(Number),\n cacheWriteTokens: sql<number>`sum(${usageRecords.cacheWriteTokens})`.mapWith(Number),\n outputTokens: sql<number>`sum(${usageRecords.outputTokens})`.mapWith(Number),\n reasoningTokens: sql<number>`sum(${usageRecords.reasoningTokens})`.mapWith(Number),\n costUsd: sql<number>`sum(${usageRecords.costUsd})`.mapWith(Number),\n })\n .from(usageRecords)\n .where(and(...filters))\n .groupBy(usageRecords.modelId, usageRecords.providerId)\n .all();\n },\n\n async sumUsageByChat({ chatIds, ownerId, source, since }) {\n if (chatIds.length === 0) return [];\n const filters = [\n inArray(usageRecords.chatId, [...chatIds]),\n ...(ownerId !== undefined ? [eq(usageRecords.ownerId, ownerId)] : []),\n ...(source !== undefined ? [eq(usageRecords.source, source)] : []),\n ...(since !== undefined ? [gte(usageRecords.createdAt, since)] : []),\n ];\n return db\n .select({\n chatId: usageRecords.chatId,\n modelId: usageRecords.modelId,\n providerId: usageRecords.providerId,\n inputTokens: sql<number>`sum(${usageRecords.inputTokens})`.mapWith(Number),\n cachedInputTokens: sql<number>`sum(${usageRecords.cachedInputTokens})`.mapWith(Number),\n cacheWriteTokens: sql<number>`sum(${usageRecords.cacheWriteTokens})`.mapWith(Number),\n outputTokens: sql<number>`sum(${usageRecords.outputTokens})`.mapWith(Number),\n reasoningTokens: sql<number>`sum(${usageRecords.reasoningTokens})`.mapWith(Number),\n costUsd: sql<number>`sum(${usageRecords.costUsd})`.mapWith(Number),\n })\n .from(usageRecords)\n .where(and(...filters))\n .groupBy(usageRecords.chatId, usageRecords.modelId, usageRecords.providerId)\n .all();\n },\n\n async getUserModelChoice(ownerId) {\n const row = db.select().from(userModelChoices).where(eq(userModelChoices.ownerId, ownerId)).get();\n if (!row) return null;\n return { modelId: row.modelId, providerId: row.providerId, ...(row.reasoning !== null && { reasoning: row.reasoning }) };\n },\n\n async saveUserModelChoice(ownerId, choice) {\n const values = { modelId: choice.modelId, providerId: choice.providerId, reasoning: choice.reasoning ?? null, updatedAt: new Date().toISOString() };\n db.insert(userModelChoices).values({ ownerId, ...values }).onConflictDoUpdate({ target: userModelChoices.ownerId, set: values }).run();\n },\n\n async setVoiceCut({ ownerId, chatId, messageId, voiceCut }) {\n db.update(messages)\n .set({ voiceCut })\n .where(\n and(\n eq(messages.id, messageId),\n eq(messages.chatId, chatId),\n sql`exists (select 1 from ${chats} where ${chats.id} = ${chatId} and ${chats.ownerId} = ${ownerId})`,\n ),\n )\n .run();\n },\n\n async getSpendingLimitState(key) {\n const row = db.select().from(spendingLimitStates).where(eq(spendingLimitStates.key, key)).get();\n return row ? { value: row.value, version: row.version } : null;\n },\n\n // Одна команда без чтения: вставка или правка срабатывает только при совпавшей версии, лишнего «вклинивания» нет.\n async saveSpendingLimitState(key, value, expectedVersion) {\n const updatedAt = new Date().toISOString();\n if (expectedVersion === null) {\n return db.insert(spendingLimitStates).values({ key, value, version: 1, updatedAt }).onConflictDoNothing().run().changes === 1;\n }\n const changed = db\n .update(spendingLimitStates)\n .set({ value, version: expectedVersion + 1, updatedAt })\n .where(and(eq(spendingLimitStates.key, key), eq(spendingLimitStates.version, expectedVersion)))\n .run().changes;\n return changed === 1;\n },\n\n async deleteSpendingLimitStates(keys) {\n if (keys.length > 0) db.delete(spendingLimitStates).where(inArray(spendingLimitStates.key, keys)).run();\n },\n\n async getVoiceChoice(ownerId) {\n return db.select().from(voiceChoices).where(eq(voiceChoices.ownerId, ownerId)).get()?.voiceId ?? null;\n },\n\n async setVoiceChoice(ownerId, voiceId) {\n const values = { voiceId, updatedAt: new Date().toISOString() };\n db.insert(voiceChoices).values({ ownerId, ...values }).onConflictDoUpdate({ target: voiceChoices.ownerId, set: values }).run();\n },\n\n async listMemoryNotes(ownerId) {\n return db.transaction((tx) => visibleNotes(tx, ownerId));\n },\n\n // Пакет вставляется одной транзакцией: негодная запись (NOT NULL) откатывает и остальные.\n async insertMemoryNotes(ownerId, inputs) {\n return db.transaction((tx) => insertNotes(tx, ownerId, inputs), { behavior: \"immediate\" });\n },\n\n async insertMemoryNotesChecked(ownerId, inputs, guard) {\n return db.transaction(\n (tx) => {\n const error = guard(visibleNotes(tx, ownerId));\n return error ?? insertNotes(tx, ownerId, inputs);\n },\n { behavior: \"immediate\" },\n );\n },\n\n async updateMemoryNote(ownerId, id, expectedVersion, input) {\n return db.transaction((tx) => updateNote(tx, ownerId, id, expectedVersion, input), { behavior: \"immediate\" });\n },\n\n async updateMemoryNoteChecked(ownerId, id, expectedVersion, input, guard) {\n return db.transaction((tx) => guard(visibleNotes(tx, ownerId)) ?? updateNote(tx, ownerId, id, expectedVersion, input), { behavior: \"immediate\" });\n },\n\n async deleteMemoryNote(ownerId, id, expectedVersion) {\n return db.transaction((tx) => {\n const row = tx.select({ version: memoryNotes.version }).from(memoryNotes).where(ownerNote(ownerId, id)).get();\n if (!row) return \"not_found\";\n if (row.version !== expectedVersion) return \"stale_version\";\n const result = tx.delete(memoryNotes).where(and(ownerNote(ownerId, id), eq(memoryNotes.version, expectedVersion))).run();\n if (result.changes === 0) return \"stale_version\";\n // Скрытые оригиналы слияния уходят вместе с результатом.\n tx.delete(memoryNotes).where(and(eq(memoryNotes.ownerId, ownerId), eq(memoryNotes.mergedInto, id))).run();\n return \"ok\";\n }, { behavior: \"immediate\" });\n },\n\n async clearMemoryNotes(ownerId) {\n return db.transaction((tx) => {\n const deleted = tx.delete(memoryNotes).where(eq(memoryNotes.ownerId, ownerId)).returning({ mergedInto: memoryNotes.mergedInto }).all();\n tx.delete(memoryOptimizationRuns).where(eq(memoryOptimizationRuns.ownerId, ownerId)).run();\n // Считаются записи, которые человек видел; скрытые оригиналы — служебные.\n return deleted.filter((row) => row.mergedInto === null).length;\n }, { behavior: \"immediate\" });\n },\n\n // Взятие запуска — одна транзакция: проверка правил и вставка не разрываются (SQLite пишет по одному).\n async claimMemoryOptimizationRun(ownerId, rules, now) {\n const nowMs = Date.parse(now);\n return db.transaction((tx) => {\n const runs = tx.select().from(memoryOptimizationRuns).where(eq(memoryOptimizationRuns.ownerId, ownerId)).all();\n for (const run of runs) {\n const leaseEnd = run.startedAt + rules.leaseMs;\n if (run.status !== \"running\" || nowMs < leaseEnd) continue;\n tx.update(memoryOptimizationRuns).set({ status: \"failed\", error: \"lease_expired\", finishedAt: leaseEnd }).where(eq(memoryOptimizationRuns.id, run.id)).run();\n Object.assign(run, { status: \"failed\", finishedAt: leaseEnd });\n }\n const blocked = isOptimizationBlocked(\n runs.map((run) => ({ status: run.status, startedAtMs: run.startedAt, endedAtMs: run.finishedAt })),\n rules,\n nowMs,\n );\n if (blocked) return null;\n const row = { id: crypto.randomUUID(), ownerId, startedAt: nowMs, finishedAt: null, status: \"running\" as const, groups: [], error: null, usageRecordId: null };\n tx.insert(memoryOptimizationRuns).values(row).run();\n return toOptimizationRun(row);\n }, { behavior: \"immediate\" });\n },\n\n async finishMemoryOptimizationRun(ownerId, runId, outcome) {\n const result = db\n .update(memoryOptimizationRuns)\n .set({ status: outcome.status, finishedAt: Date.parse(outcome.finishedAt), error: outcome.error ?? null, usageRecordId: outcome.usageRecordId ?? null })\n .where(and(eq(memoryOptimizationRuns.id, runId), eq(memoryOptimizationRuns.ownerId, ownerId), eq(memoryOptimizationRuns.status, \"running\")))\n .run();\n return result.changes > 0 ? \"ok\" : \"not_found\";\n },\n\n // Слияние — одна транзакция: любая неудача (в том числе негодный результат) откатывает всё.\n async applyMemoryMerge(ownerId, merge) {\n const { merges } = merge;\n if (merges.length === 0) throw new TypeError(\"Слияние без склеек\");\n const seen = new Set<string>();\n for (const { originals } of merges) {\n if (originals.length === 0) throw new TypeError(\"Склейка без оригиналов\");\n for (const { id } of originals) {\n if (seen.has(id)) throw new TypeError(`Запись ${id} названа в двух склейках`);\n seen.add(id);\n }\n }\n return db.transaction((tx) => {\n const run = tx.select().from(memoryOptimizationRuns).where(and(eq(memoryOptimizationRuns.id, merge.runId), eq(memoryOptimizationRuns.ownerId, ownerId))).get();\n if (run?.status !== \"running\") return \"run_not_active\";\n // Сначала проверка всех оригиналов, потом запись: откат в транзакции только по исключению.\n for (const { originals } of merges) {\n for (const { id, version } of originals) {\n const original = tx.select({ version: memoryNotes.version }).from(memoryNotes).where(ownerNote(ownerId, id)).get();\n if (original?.version !== version) return \"stale_version\";\n }\n }\n const now = Date.now();\n const groups: MemoryMergeGroup[] = merges.map(({ result, originals }) => {\n const created = { id: crypto.randomUUID(), ownerId, categories: result.categories, content: result.content, version: 1, createdAt: now, updatedAt: now };\n tx.insert(memoryNotes).values(created).run();\n for (const { id } of originals) tx.update(memoryNotes).set({ mergedInto: created.id }).where(ownerNote(ownerId, id)).run();\n return { resultId: created.id, originalIds: originals.map(({ id }) => id), resultVersion: 1 };\n });\n const finished = { status: \"applied\" as const, finishedAt: Date.parse(merge.finishedAt), groups, usageRecordId: merge.usageRecordId ?? null };\n tx.update(memoryOptimizationRuns).set(finished).where(eq(memoryOptimizationRuns.id, run.id)).run();\n return toOptimizationRun({ ...run, ...finished });\n }, { behavior: \"immediate\" });\n },\n\n async revertMemoryMerge(ownerId, runId, guard) {\n return db.transaction((tx) => {\n const run = tx.select().from(memoryOptimizationRuns).where(and(eq(memoryOptimizationRuns.id, runId), eq(memoryOptimizationRuns.ownerId, ownerId))).get();\n if (run?.status !== \"applied\") return \"not_found\";\n for (const { resultId, originalIds, resultVersion } of run.groups) {\n const result = tx.select({ version: memoryNotes.version }).from(memoryNotes).where(ownerNote(ownerId, resultId)).get();\n if (result?.version !== resultVersion) return \"conflict\";\n const hidden = tx\n .select({ id: memoryNotes.id })\n .from(memoryNotes)\n .where(and(eq(memoryNotes.ownerId, ownerId), eq(memoryNotes.mergedInto, resultId), inArray(memoryNotes.id, originalIds)))\n .all();\n if (hidden.length !== originalIds.length) return \"conflict\";\n }\n if (guard) {\n const resultIds = run.groups.map(({ resultId }) => resultId);\n const remaining = visibleNotes(tx, ownerId).filter((note) => !resultIds.includes(note.id));\n const restored = tx\n .select()\n .from(memoryNotes)\n .where(and(eq(memoryNotes.ownerId, ownerId), inArray(memoryNotes.mergedInto, resultIds)))\n .orderBy(desc(memoryNotes.updatedAt), desc(memoryNotes.createdAt), desc(memoryNotes.id))\n .all()\n .map(toMemoryNote);\n const error = guard(remaining, restored);\n if (error) return revertRefusal(error);\n }\n for (const { resultId } of run.groups) {\n tx.update(memoryNotes).set({ mergedInto: null }).where(and(eq(memoryNotes.ownerId, ownerId), eq(memoryNotes.mergedInto, resultId))).run();\n tx.delete(memoryNotes).where(ownerNote(ownerId, resultId)).run();\n }\n tx.update(memoryOptimizationRuns).set({ status: \"reverted\" }).where(eq(memoryOptimizationRuns.id, run.id)).run();\n return \"ok\";\n }, { behavior: \"immediate\" });\n },\n\n async listMemoryOptimizationRuns(ownerId, filter) {\n const rows = db\n .select()\n .from(memoryOptimizationRuns)\n .where(and(eq(memoryOptimizationRuns.ownerId, ownerId), ...(filter?.status ? [inArray(memoryOptimizationRuns.status, filter.status)] : [])))\n .orderBy(desc(memoryOptimizationRuns.startedAt), sql`rowid desc`)\n .limit(filter?.limit ?? -1)\n .all();\n return rows.map(toOptimizationRun);\n },\n\n async listMergedMemoryNotes(ownerId) {\n const rows = db\n .select()\n .from(memoryNotes)\n .where(and(eq(memoryNotes.ownerId, ownerId), isNotNull(memoryNotes.mergedInto)))\n .orderBy(desc(memoryNotes.updatedAt), desc(memoryNotes.createdAt), desc(memoryNotes.id))\n .all();\n return rows.map((row): MergedMemoryNote => ({ ...toMemoryNote(row), mergedInto: row.mergedInto! }));\n },\n\n close() {\n sqlite.close();\n },\n };\n}\n\n/** Запись чата в строку: поле без значения — пусто. */\nfunction chatRow(chat: Chat): typeof chats.$inferSelect {\n return {\n id: chat.id,\n ownerId: chat.ownerId,\n modelId: chat.modelId,\n providerId: chat.providerId,\n reasoning: chat.reasoning ?? null,\n title: chat.title ?? null,\n origin: chat.origin ?? null,\n subjectKey: chat.subjectKey ?? null,\n subjectData: chatDataOfInput(chat) ?? null,\n closed: chat.closed ?? null,\n createdAt: chat.createdAt,\n updatedAt: chat.updatedAt,\n };\n}\n\n/** Строка чата в запись ядра: пустые необязательные поля — отсутствие поля. */\nfunction toChat(row: typeof chats.$inferSelect): Chat {\n const { reasoning, title, origin, subjectKey, subjectData, closed, ...chat } = row;\n return {\n ...chat,\n ...(reasoning !== null && { reasoning }),\n ...(title !== null && { title }),\n ...(origin !== null && { origin }),\n ...(subjectKey !== null && { subjectKey }),\n ...chatDataFields(subjectData),\n ...(closed !== null && { closed }),\n };\n}\n\n/** Фильтр `listChats` по ключу объекта; по умолчанию — только чаты без ключа. */\nfunction subjectCondition(subjects: ChatSubjectFilter = \"exclude\") {\n if (subjects === \"include\") return undefined;\n return subjects === \"only\" ? isNotNull(chats.subjectKey) : isNull(chats.subjectKey);\n}\n\n/**\n * Фильтр `listChats` по данным чата: на каждый ключ — проверка через `json_each`: ключ как есть (точки и кавычки не\n * путаются с путём), тип значения важен (`true` не равно `1`, `\"1\"` не равно `1`).\n */\nfunction dataConditions(filter: ChatDataFilter | undefined) {\n return Object.entries(filter ?? {}).map(([key, value]) => {\n const typed =\n value === null\n ? sql`type = 'null'`\n : typeof value === \"string\"\n ? sql`type = 'text' and value = ${value}`\n : typeof value === \"boolean\"\n ? sql`type = ${value ? \"true\" : \"false\"}`\n : sql`type in ('integer', 'real') and value = ${value}`;\n return sql`exists (select 1 from json_each(${chats.subjectData}) where key = ${key} and ${typed})`;\n });\n}\n\n/** Строка сообщения в запись ядра: без служебных колонок; пустое состояние хука итога — отсутствие поля. */\nfunction toMessage(row: typeof messages.$inferSelect): StoredMessage {\n const { seq: _seq, aliveAt: _aliveAt, afterTurn, ...message } = row;\n return { ...message, ...(afterTurn !== null && { afterTurn }) };\n}\n\n/** Видимая запись памяти этого человека: чужая по тому же id и скрытый оригинал слияния не находятся. */\nfunction ownerNote(ownerId: string, id: string) {\n return and(eq(memoryNotes.ownerId, ownerId), eq(memoryNotes.id, id), isNull(memoryNotes.mergedInto));\n}\n\n/** Строка запуска в запись ядра: владельца наружу не отдаём, время — в ISO 8601. */\nfunction toOptimizationRun(row: typeof memoryOptimizationRuns.$inferSelect): MemoryOptimizationRun {\n return {\n id: row.id,\n startedAt: new Date(row.startedAt).toISOString(),\n finishedAt: row.finishedAt === null ? null : new Date(row.finishedAt).toISOString(),\n status: row.status,\n groups: row.groups.map((group) => ({ ...group, originalIds: [...group.originalIds] })),\n error: row.error,\n usageRecordId: row.usageRecordId,\n };\n}\n\n/** Строка памяти в запись ядра: владельца наружу не отдаём, время — в ISO 8601. */\nfunction toMemoryNote(row: typeof memoryNotes.$inferSelect): MemoryNote {\n return {\n id: row.id,\n categories: [...row.categories],\n content: row.content,\n version: row.version,\n createdAt: new Date(row.createdAt).toISOString(),\n updatedAt: new Date(row.updatedAt).toISOString(),\n };\n}\n\n/** Нарушен уникальный индекс (владелец, ключ объекта). */\nfunction isSubjectConflict(error: unknown): boolean {\n const { code, message, cause } = (error ?? {}) as { code?: unknown; message?: unknown; cause?: { code?: unknown; message?: unknown } };\n return (\n [code, cause?.code].includes(\"SQLITE_CONSTRAINT_UNIQUE\") &&\n [message, cause?.message].some((text) => typeof text === \"string\" && text.includes(\"chats.subject_key\"))\n );\n}\n\nfunction isPrimaryKeyConflict(error: unknown): boolean {\n const { code, cause } = (error ?? {}) as { code?: unknown; cause?: { code?: unknown } };\n return [code, cause?.code].includes(\"SQLITE_CONSTRAINT_PRIMARYKEY\");\n}\n","import type {\n AnswerStatus,\n ChatClosure,\n ChatError,\n MemoryMergeGroup,\n MemoryOptimizationStatus,\n StoredMessage,\n TokenUsage,\n TurnRequestContext,\n UsageSource,\n VoiceCut,\n} from \"@ykurilov/agent-chat-core\";\nimport { sql } from \"drizzle-orm\";\nimport { index, integer, real, sqliteTable, text, uniqueIndex } from \"drizzle-orm/sqlite-core\";\n\nexport const chats = sqliteTable(\n \"chats\",\n {\n id: text(\"id\").primaryKey(),\n ownerId: text(\"owner_id\").notNull(),\n modelId: text(\"model_id\").notNull(),\n providerId: text(\"provider_id\").notNull(),\n reasoning: text(\"reasoning\"),\n /** Название для списка чатов; пусто — чат без названия. */\n title: text(\"title\"),\n /** Мессенджер, из которого создан чат; пусто — чат создан в вебе. */\n origin: text(\"origin\", { enum: [\"telegram\", \"vk\", \"max\"] }),\n /** Ключ объекта приложения; пусто — обычный чат. У владельца ключ не повторяется. */\n subjectKey: text(\"subject_key\"),\n /** Данные объекта (JSON-объект); пусто — данных нет. */\n subjectData: text(\"subject_data\", { mode: \"json\" }).$type<Record<string, unknown>>(),\n /** Закрытие чата (JSON `{ code, message }`); пусто — чат открыт. */\n closed: text(\"closed\", { mode: \"json\" }).$type<ChatClosure>(),\n createdAt: text(\"created_at\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n },\n (table) => [\n index(\"chats_owner_updated_idx\").on(table.ownerId, table.updatedAt),\n uniqueIndex(\"chats_owner_subject_idx\").on(table.ownerId, table.subjectKey),\n ],\n);\n\nexport const messages = sqliteTable(\n \"messages\",\n {\n id: text(\"id\").primaryKey(),\n chatId: text(\"chat_id\")\n .notNull()\n .references(() => chats.id, { onDelete: \"cascade\" }),\n parentId: text(\"parent_id\"),\n role: text(\"role\", { enum: [\"user\", \"assistant\"] }).notNull(),\n parts: text(\"parts\", { mode: \"json\" }).$type<StoredMessage[\"parts\"]>().notNull(),\n formatVersion: integer(\"format_version\").notNull(),\n status: text(\"status\").$type<AnswerStatus>().notNull(),\n modelId: text(\"model_id\"),\n providerId: text(\"provider_id\"),\n usage: text(\"usage\", { mode: \"json\" }).$type<TokenUsage>(),\n reasoningDurationsMs: text(\"reasoning_durations_ms\", { mode: \"json\" }).$type<Record<string, number>>().notNull(),\n error: text(\"error\", { mode: \"json\" }).$type<ChatError>(),\n /** Отметка обрыва озвучки (голосовой режим); пусто — озвучку не обрывали. */\n voiceCut: text(\"voice_cut\", { mode: \"json\" }).$type<VoiceCut>(),\n /** Состояние хука итога хода; пусто — хук не зовётся. */\n afterTurn: text(\"after_turn\", { enum: [\"pending\", \"done\", \"failed\"] }),\n createdAt: text(\"created_at\").notNull(),\n /** Последний знак жизни идущего ответа (ISO); пусто — время создания. Только для восстановления, при чтении не отдаётся. */\n aliveAt: text(\"alive_at\"),\n /** Порядок записи: при равном `created_at` сообщения читаются по возрастанию `seq`. Задаётся при вставке. */\n seq: integer(\"seq\").notNull().default(0),\n },\n (table) => [\n index(\"messages_chat_created_idx\").on(table.chatId, table.createdAt, table.seq),\n uniqueIndex(\"messages_seq_idx\").on(table.seq),\n index(\"messages_streaming_idx\").on(table.status).where(sql`${table.status} = 'streaming'`),\n index(\"messages_after_turn_pending_idx\").on(table.afterTurn).where(sql`${table.afterTurn} = 'pending'`),\n ],\n);\n\n/** Записи сжатия: только добавляются. Порядок добавления — `seq`. */\nexport const compactions = sqliteTable(\n \"compactions\",\n {\n id: text(\"id\").primaryKey(),\n chatId: text(\"chat_id\")\n .notNull()\n .references(() => chats.id, { onDelete: \"cascade\" }),\n fromMessageId: text(\"from_message_id\").notNull(),\n throughMessageId: text(\"through_message_id\").notNull(),\n summary: text(\"summary\").notNull(),\n summaryTokens: integer(\"summary_tokens\").notNull(),\n modelId: text(\"model_id\").notNull(),\n providerId: text(\"provider_id\").notNull(),\n usage: text(\"usage\", { mode: \"json\" }).$type<TokenUsage>(),\n createdAt: text(\"created_at\").notNull(),\n seq: integer(\"seq\").notNull().default(0),\n },\n (table) => [\n index(\"compactions_chat_seq_idx\").on(table.chatId, table.seq),\n uniqueIndex(\"compactions_seq_idx\").on(table.seq),\n ],\n);\n\n/** Отметки выбора ветки: только добавляются. Порядок добавления — `seq`. */\nexport const branchSelections = sqliteTable(\n \"branch_selections\",\n {\n id: text(\"id\").primaryKey(),\n chatId: text(\"chat_id\")\n .notNull()\n .references(() => chats.id, { onDelete: \"cascade\" }),\n messageId: text(\"message_id\").notNull(),\n selectedAt: text(\"selected_at\").notNull(),\n seq: integer(\"seq\").notNull().default(0),\n },\n (table) => [\n index(\"branch_selections_chat_seq_idx\").on(table.chatId, table.seq),\n uniqueIndex(\"branch_selections_seq_idx\").on(table.seq),\n ],\n);\n\n/**\n * Журнал расхода токенов: только добавляется и не связан с чатами внешним ключом, чтобы переживать их удаление.\n * Месячный расход человека от удаления переписки не убывает.\n */\nexport const usageRecords = sqliteTable(\n \"usage_records\",\n {\n id: text(\"id\").primaryKey(),\n ownerId: text(\"owner_id\").notNull(),\n chatId: text(\"chat_id\").notNull(),\n messageId: text(\"message_id\"),\n source: text(\"source\").$type<UsageSource>().notNull(),\n modelId: text(\"model_id\").notNull(),\n providerId: text(\"provider_id\").notNull(),\n inputTokens: integer(\"input_tokens\").notNull(),\n cachedInputTokens: integer(\"cached_input_tokens\").notNull(),\n cacheWriteTokens: integer(\"cache_write_tokens\").notNull(),\n outputTokens: integer(\"output_tokens\").notNull(),\n reasoningTokens: integer(\"reasoning_tokens\").notNull(),\n costUsd: real(\"cost_usd\").notNull(),\n createdAt: text(\"created_at\").notNull(),\n /** Числа «примерно»: прикинуты по длине текста, а не сообщены провайдером. */\n estimated: integer(\"estimated\", { mode: \"boolean\" }).notNull().default(false),\n },\n (table) => [\n index(\"usage_records_owner_created_idx\").on(table.ownerId, table.createdAt),\n index(\"usage_records_chat_created_idx\").on(table.chatId, table.createdAt),\n ],\n);\n\n/** Последний выбор модели человека для новых чатов: одна строка на человека; с чатами не связан. */\nexport const userModelChoices = sqliteTable(\"user_model_choices\", {\n ownerId: text(\"owner_id\").primaryKey(),\n modelId: text(\"model_id\").notNull(),\n providerId: text(\"provider_id\").notNull(),\n /** Пусто — у модели нет уровней рассуждений. */\n reasoning: text(\"reasoning\"),\n updatedAt: text(\"updated_at\").notNull(),\n});\n\n/** Выбранный человеком голос озвучки: одна строка на человека; с чатами и выбором модели не связан. */\nexport const voiceChoices = sqliteTable(\"voice_choices\", {\n ownerId: text(\"owner_id\").primaryKey(),\n voiceId: text(\"voice_id\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n});\n\n/** Состояние лимитов расходов по ключу: значение — строка (JSON решает ядро); `version` растёт на 1 при каждой записи и служит замком. */\nexport const spendingLimitStates = sqliteTable(\"spending_limit_states\", {\n key: text(\"key\").primaryKey(),\n value: text(\"value\").notNull(),\n version: integer(\"version\").notNull(),\n updatedAt: text(\"updated_at\").notNull(),\n});\n\n/**\n * Аренда хода чата между копиями сервера: кто держит (`holder`) и до какого времени (`until`, мс по часам машины с базой).\n * Внешним ключом с чатом не связана: удаление чата снимает её само.\n */\nexport const chatTurnLeases = sqliteTable(\"chat_turn_leases\", {\n chatId: text(\"chat_id\").primaryKey(),\n holder: text(\"holder\").notNull(),\n until: integer(\"until\").notNull(),\n});\n\n/**\n * Ждущие пачки сообщений человека: одна запись на чат. Сроки — мс по часам службы; `page` — JSON страницы хода.\n * Внешним ключом с чатом не связана: удаление чата снимает её само.\n */\nexport const pendingBursts = sqliteTable(\"pending_bursts\", {\n chatId: text(\"chat_id\").primaryKey(),\n ownerId: text(\"owner_id\").notNull(),\n messageId: text(\"message_id\").notNull(),\n dueAt: integer(\"due_at\").notNull(),\n holder: text(\"holder\").notNull(),\n heldUntil: integer(\"held_until\").notNull(),\n page: text(\"page\", { mode: \"json\" }).$type<TurnRequestContext>(),\n});\n\n/**\n * Долгая память: записи человека. С чатами внешним ключом не связаны — удаление чата память не трогает.\n * Время в миллисекундах; `categories` — JSON-список из 1–3 разделов.\n */\nexport const memoryNotes = sqliteTable(\n \"memory_notes\",\n {\n id: text(\"id\").primaryKey(),\n ownerId: text(\"owner_id\").notNull(),\n categories: text(\"categories\", { mode: \"json\" }).$type<string[]>().notNull(),\n content: text(\"content\").notNull(),\n version: integer(\"version\").notNull().default(1),\n createdAt: integer(\"created_at\").notNull(),\n updatedAt: integer(\"updated_at\").notNull(),\n /** Оптимизация дублей: id записи-результата у скрытого оригинала слияния; у обычных записей пусто. */\n mergedInto: text(\"merged_into\"),\n },\n (table) => [\n index(\"memory_notes_owner_updated_idx\").on(table.ownerId, table.updatedAt),\n index(\"memory_notes_merged_into_idx\").on(table.mergedInto),\n ],\n);\n\n/**\n * Оптимизация дублей: запуски человека. Время в миллисекундах; `groups` — JSON-список склеек\n * (результат, оригиналы, версия результата на момент слияния). Запуск `running` у человека не больше одного.\n */\nexport const memoryOptimizationRuns = sqliteTable(\n \"memory_optimization_runs\",\n {\n id: text(\"id\").primaryKey(),\n ownerId: text(\"owner_id\").notNull(),\n startedAt: integer(\"started_at\").notNull(),\n finishedAt: integer(\"finished_at\"),\n status: text(\"status\").$type<MemoryOptimizationStatus>().notNull(),\n groups: text(\"groups\", { mode: \"json\" }).$type<MemoryMergeGroup[]>().notNull().default(sql`'[]'`),\n error: text(\"error\"),\n usageRecordId: text(\"usage_record_id\"),\n },\n (table) => [\n index(\"memory_optimization_runs_owner_started_idx\").on(table.ownerId, table.startedAt),\n uniqueIndex(\"memory_optimization_runs_one_running_idx\").on(table.ownerId).where(sql`${table.status} = 'running'`),\n ],\n);\n"],"mappings":"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","names":["sql","sql","options","text"]}
|
package/dist/types/schema.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnswerStatus, ChatClosure,
|
|
1
|
+
import type { AnswerStatus, ChatClosure, ChatError, MemoryMergeGroup, MemoryOptimizationStatus, TokenUsage, TurnRequestContext, UsageSource, VoiceCut } from "@ykurilov/agent-chat-core";
|
|
2
2
|
export declare const chats: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
3
3
|
name: "chats";
|
|
4
4
|
schema: undefined;
|
|
@@ -451,9 +451,7 @@ export declare const messages: import("drizzle-orm/sqlite-core").SQLiteTableWith
|
|
|
451
451
|
tableName: "messages";
|
|
452
452
|
dataType: "json";
|
|
453
453
|
columnType: "SQLiteTextJson";
|
|
454
|
-
data:
|
|
455
|
-
kind: ChatErrorKind;
|
|
456
|
-
};
|
|
454
|
+
data: ChatError;
|
|
457
455
|
driverParam: string;
|
|
458
456
|
notNull: false;
|
|
459
457
|
hasDefault: false;
|
|
@@ -465,9 +463,7 @@ export declare const messages: import("drizzle-orm/sqlite-core").SQLiteTableWith
|
|
|
465
463
|
identity: undefined;
|
|
466
464
|
generated: undefined;
|
|
467
465
|
}, {}, {
|
|
468
|
-
$type:
|
|
469
|
-
kind: ChatErrorKind;
|
|
470
|
-
};
|
|
466
|
+
$type: ChatError;
|
|
471
467
|
}>;
|
|
472
468
|
voiceCut: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
473
469
|
name: "voice_cut";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ykurilov/agent-chat-storage-sqlite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.64.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"better-sqlite3": "^13.0.3",
|
|
34
34
|
"drizzle-orm": "^0.45.3",
|
|
35
|
-
"@ykurilov/agent-chat-core": "0.
|
|
35
|
+
"@ykurilov/agent-chat-core": "0.64.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/better-sqlite3": "^9.6.0",
|