@ykurilov/agent-chat-storage-sqlite 0.82.1 → 0.83.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 CHANGED
@@ -1,5 +1,28 @@
1
1
  # @ykurilov/agent-chat-storage-sqlite
2
2
 
3
+ ## 0.83.0
4
+
5
+ ### Minor Changes
6
+
7
+ - bad76a9: Инструмент выполняется только после успешной записи полного намерения вызова. Сбой или зависшая запись больше не пропускает внешнее действие. Потеря аренды останавливает ход; атомарная проверка поколения защищает записи ответа от запоздалой копии. Безопасный обход брошенных ответов включён при создании службы и не продолжает модель или инструменты.
8
+
9
+ Ломает приложения со своим ChatStorage, у которого есть распределённая аренда без атомарной ограды записей.
10
+
11
+ ### Как обновить приложение
12
+
13
+ Обновите все установленные пакеты SDK одной версией. Встроенные хранилища готовы, SQL-схемы и обычные настройки приложений не меняются. Сохраните существующий startup-вызов recoverInterruptedAnswers и штатный flush при завершении.
14
+
15
+ Собственный адаптер с claimChatTurn/releaseChatTurn обязан реализовать ChatTurnWriteGuard.expectedTurnHolder в одной операции с записью и объявить guardedTurnWrites: true. Условие применяется к insertMessage, updateStreamingMessage, finishMessage, updateAwaitingMessage и markAnswerAlive (если он есть); при утрате поколения бросается ChatTurnLeaseLostError. Guard не сохраняется в сообщении. Без capability служба не запускается. Подробный договор и проверка через describeChatStorageContract — docs/turn-durability.md.
16
+
17
+ Одновременный последний ответ на approval/widget при чужой аренде может получить существующий ChatBusyError: этот ввод не записывается и остаётся для повтора. Частичные решения, которые ещё не запускают ход, принимаются как прежде.
18
+
19
+ Проверьте обычный ответ, инструмент, отказ записи намерения без внешнего эффекта и сохранность ожидающего подтверждения после перезапуска. Это не exactly-once внешнего API и не автопродолжение оборванного хода.
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [bad76a9]
24
+ - @ykurilov/agent-chat-core@0.83.0
25
+
3
26
  ## 0.82.1
4
27
 
5
28
  ### Patch Changes
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  DuplicateMessageError,
12
12
  isOptimizationBlocked,
13
13
  mergeChatData,
14
+ ChatTurnLeaseLostError,
14
15
  MessageAlreadyFinishedError,
15
16
  MessageNotAwaitingError,
16
17
  revertRefusal,
@@ -321,14 +322,25 @@ function createSqliteChatStorage(options) {
321
322
  return updated ? toMemoryNote(updated) : "stale_version";
322
323
  }
323
324
  const aliveAtColumn = (alive) => alive ? { aliveAt: aliveAtByLocalClock(alive) } : {};
324
- function updateStreaming(messageId, { alive, ...values }) {
325
- const result = db.update(messages).set({ ...values, ...aliveAtColumn(alive) }).where(and(eq(messages.id, messageId), eq(messages.status, "streaming"))).run();
325
+ function assertTurnHolder(tx, chatId, holder, messageId) {
326
+ if (holder === void 0) return;
327
+ const row = tx.select({ chatId: chatTurnLeases.chatId }).from(chatTurnLeases).where(and(eq(chatTurnLeases.chatId, chatId), eq(chatTurnLeases.holder, holder), sql2`${chatTurnLeases.until} > ${Date.now()}`)).get();
328
+ if (!row) throw new ChatTurnLeaseLostError(messageId);
329
+ }
330
+ function turnLeaseCondition(holder) {
331
+ if (holder === void 0) return void 0;
332
+ return sql2`exists (select 1 from ${chatTurnLeases} where ${chatTurnLeases.chatId} = ${messages.chatId} and ${chatTurnLeases.holder} = ${holder} and ${chatTurnLeases.until} > ${Date.now()})`;
333
+ }
334
+ function updateStreaming(messageId, { alive, expectedTurnHolder, ...values }) {
335
+ const result = db.update(messages).set({ ...values, ...aliveAtColumn(alive) }).where(and(eq(messages.id, messageId), eq(messages.status, "streaming"), turnLeaseCondition(expectedTurnHolder))).run();
326
336
  if (result.changes > 0) return;
327
- const existing = db.select({ id: messages.id }).from(messages).where(eq(messages.id, messageId)).get();
337
+ const existing = db.select({ id: messages.id, status: messages.status }).from(messages).where(eq(messages.id, messageId)).get();
328
338
  if (!existing) throw new Error(`\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F ${messageId} \u043D\u0435\u0442`);
339
+ if (expectedTurnHolder !== void 0 && existing.status === "streaming") throw new ChatTurnLeaseLostError(messageId);
329
340
  throw new MessageAlreadyFinishedError(messageId);
330
341
  }
331
342
  return {
343
+ guardedTurnWrites: true,
332
344
  async createChat({ createdAt, ...input }) {
333
345
  const at = createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
334
346
  const row = chatRow({ ...input, createdAt: at, updatedAt: at });
@@ -507,9 +519,10 @@ function createSqliteChatStorage(options) {
507
519
  }).from(messages).where(eq(messages.chatId, chatId)).orderBy(asc(messages.createdAt), messages.seq).all();
508
520
  return rows.map((row) => ({ ...row, parts: JSON.parse(row.parts) }));
509
521
  },
510
- async insertMessage(message) {
522
+ async insertMessage(message, guard) {
511
523
  try {
512
524
  db.transaction((tx) => {
525
+ assertTurnHolder(tx, message.chatId, guard?.expectedTurnHolder, message.id);
513
526
  const nextSeq = sql2`(select coalesce(max(${messages.seq}), 0) + 1 from ${messages})`;
514
527
  const { alive, ...stored } = message;
515
528
  tx.insert(messages).values({ ...stored, ...aliveAtColumn(alive), seq: nextSeq }).run();
@@ -521,14 +534,15 @@ function createSqliteChatStorage(options) {
521
534
  }
522
535
  },
523
536
  updateStreamingMessage: async (messageId, patch) => updateStreaming(messageId, patch),
524
- markAnswerAlive: async (messageId) => updateStreaming(messageId, { alive: "now" }),
537
+ markAnswerAlive: async (messageId, guard) => updateStreaming(messageId, { alive: "now", ...guard }),
525
538
  finishMessage: async (messageId, final) => updateStreaming(messageId, { ...final, ...final.afterTurn === "pending" && { alive: "now" } }),
526
539
  async updateAwaitingMessage(messageId, patch) {
527
540
  db.transaction(
528
541
  (tx) => {
529
- const existing = tx.select({ status: messages.status, parts: messages.parts }).from(messages).where(eq(messages.id, messageId)).get();
542
+ const existing = tx.select({ status: messages.status, parts: messages.parts, chatId: messages.chatId }).from(messages).where(eq(messages.id, messageId)).get();
530
543
  if (!existing) throw new Error(`\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F ${messageId} \u043D\u0435\u0442`);
531
544
  if (existing.status !== "awaiting_approval") throw new MessageNotAwaitingError(messageId);
545
+ assertTurnHolder(tx, existing.chatId, patch.expectedTurnHolder, messageId);
532
546
  if (patch.expectedParts && !sameMessageParts(existing.parts, patch.expectedParts)) throw new MessageNotAwaitingError(messageId);
533
547
  tx.update(messages).set({ parts: patch.parts, ...patch.status && { status: patch.status }, ...aliveAtColumn(patch.alive) }).where(eq(messages.id, messageId)).run();
534
548
  },
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 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":";AAAA,SAAS,qBAAqB;AAC9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,OAAO,cAAc;AACrB,SAAS,KAAK,KAAK,MAAM,IAAI,KAAK,SAAS,WAAW,QAAQ,KAAK,IAAI,OAAAA,YAAW;AAClF,SAAS,eAAe;AACxB,SAAS,0BAA0B;;;ACVnC,SAAS,WAAW;AACpB,SAAS,OAAO,SAAS,MAAM,aAAa,MAAM,mBAAmB;AAE9D,IAAM,QAAQ;AAAA,EACnB;AAAA,EACA;AAAA,IACE,IAAI,KAAK,IAAI,EAAE,WAAW;AAAA,IAC1B,SAAS,KAAK,UAAU,EAAE,QAAQ;AAAA,IAClC,SAAS,KAAK,UAAU,EAAE,QAAQ;AAAA,IAClC,YAAY,KAAK,aAAa,EAAE,QAAQ;AAAA,IACxC,WAAW,KAAK,WAAW;AAAA;AAAA,IAE3B,OAAO,KAAK,OAAO;AAAA;AAAA,IAEnB,QAAQ,KAAK,UAAU,EAAE,MAAM,CAAC,YAAY,MAAM,KAAK,EAAE,CAAC;AAAA;AAAA,IAE1D,YAAY,KAAK,aAAa;AAAA;AAAA,IAE9B,aAAa,KAAK,gBAAgB,EAAE,MAAM,OAAO,CAAC,EAAE,MAA+B;AAAA;AAAA,IAEnF,QAAQ,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC,EAAE,MAAmB;AAAA,IAC5D,WAAW,KAAK,YAAY,EAAE,QAAQ;AAAA,IACtC,WAAW,KAAK,YAAY,EAAE,QAAQ;AAAA,EACxC;AAAA,EACA,CAAC,UAAU;AAAA,IACT,MAAM,yBAAyB,EAAE,GAAG,MAAM,SAAS,MAAM,SAAS;AAAA,IAClE,YAAY,yBAAyB,EAAE,GAAG,MAAM,SAAS,MAAM,UAAU;AAAA,EAC3E;AACF;AAEO,IAAM,WAAW;AAAA,EACtB;AAAA,EACA;AAAA,IACE,IAAI,KAAK,IAAI,EAAE,WAAW;AAAA,IAC1B,QAAQ,KAAK,SAAS,EACnB,QAAQ,EACR,WAAW,MAAM,MAAM,IAAI,EAAE,UAAU,UAAU,CAAC;AAAA,IACrD,UAAU,KAAK,WAAW;AAAA,IAC1B,MAAM,KAAK,QAAQ,EAAE,MAAM,CAAC,QAAQ,WAAW,EAAE,CAAC,EAAE,QAAQ;AAAA,IAC5D,OAAO,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC,EAAE,MAA8B,EAAE,QAAQ;AAAA,IAC/E,eAAe,QAAQ,gBAAgB,EAAE,QAAQ;AAAA,IACjD,QAAQ,KAAK,QAAQ,EAAE,MAAoB,EAAE,QAAQ;AAAA,IACrD,SAAS,KAAK,UAAU;AAAA,IACxB,YAAY,KAAK,aAAa;AAAA,IAC9B,OAAO,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC,EAAE,MAAkB;AAAA,IACzD,sBAAsB,KAAK,0BAA0B,EAAE,MAAM,OAAO,CAAC,EAAE,MAA8B,EAAE,QAAQ;AAAA,IAC/G,OAAO,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC,EAAE,MAAiB;AAAA;AAAA,IAExD,UAAU,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC,EAAE,MAAgB;AAAA;AAAA,IAE9D,WAAW,KAAK,cAAc,EAAE,MAAM,CAAC,WAAW,QAAQ,QAAQ,EAAE,CAAC;AAAA,IACrE,WAAW,KAAK,YAAY,EAAE,QAAQ;AAAA;AAAA,IAEtC,SAAS,KAAK,UAAU;AAAA;AAAA,IAExB,KAAK,QAAQ,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC;AAAA,EACzC;AAAA,EACA,CAAC,UAAU;AAAA,IACT,MAAM,2BAA2B,EAAE,GAAG,MAAM,QAAQ,MAAM,WAAW,MAAM,GAAG;AAAA,IAC9E,YAAY,kBAAkB,EAAE,GAAG,MAAM,GAAG;AAAA,IAC5C,MAAM,wBAAwB,EAAE,GAAG,MAAM,MAAM,EAAE,MAAM,MAAM,MAAM,MAAM,gBAAgB;AAAA,IACzF,MAAM,iCAAiC,EAAE,GAAG,MAAM,SAAS,EAAE,MAAM,MAAM,MAAM,SAAS,cAAc;AAAA,EACxG;AACF;AAGO,IAAM,cAAc;AAAA,EACzB;AAAA,EACA;AAAA,IACE,IAAI,KAAK,IAAI,EAAE,WAAW;AAAA,IAC1B,QAAQ,KAAK,SAAS,EACnB,QAAQ,EACR,WAAW,MAAM,MAAM,IAAI,EAAE,UAAU,UAAU,CAAC;AAAA,IACrD,eAAe,KAAK,iBAAiB,EAAE,QAAQ;AAAA,IAC/C,kBAAkB,KAAK,oBAAoB,EAAE,QAAQ;AAAA,IACrD,SAAS,KAAK,SAAS,EAAE,QAAQ;AAAA,IACjC,eAAe,QAAQ,gBAAgB,EAAE,QAAQ;AAAA,IACjD,SAAS,KAAK,UAAU,EAAE,QAAQ;AAAA,IAClC,YAAY,KAAK,aAAa,EAAE,QAAQ;AAAA,IACxC,OAAO,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC,EAAE,MAAkB;AAAA,IACzD,WAAW,KAAK,YAAY,EAAE,QAAQ;AAAA,IACtC,KAAK,QAAQ,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC;AAAA,EACzC;AAAA,EACA,CAAC,UAAU;AAAA,IACT,MAAM,0BAA0B,EAAE,GAAG,MAAM,QAAQ,MAAM,GAAG;AAAA,IAC5D,YAAY,qBAAqB,EAAE,GAAG,MAAM,GAAG;AAAA,EACjD;AACF;AAGO,IAAM,mBAAmB;AAAA,EAC9B;AAAA,EACA;AAAA,IACE,IAAI,KAAK,IAAI,EAAE,WAAW;AAAA,IAC1B,QAAQ,KAAK,SAAS,EACnB,QAAQ,EACR,WAAW,MAAM,MAAM,IAAI,EAAE,UAAU,UAAU,CAAC;AAAA,IACrD,WAAW,KAAK,YAAY,EAAE,QAAQ;AAAA,IACtC,YAAY,KAAK,aAAa,EAAE,QAAQ;AAAA,IACxC,KAAK,QAAQ,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC;AAAA,EACzC;AAAA,EACA,CAAC,UAAU;AAAA,IACT,MAAM,gCAAgC,EAAE,GAAG,MAAM,QAAQ,MAAM,GAAG;AAAA,IAClE,YAAY,2BAA2B,EAAE,GAAG,MAAM,GAAG;AAAA,EACvD;AACF;AAMO,IAAM,eAAe;AAAA,EAC1B;AAAA,EACA;AAAA,IACE,IAAI,KAAK,IAAI,EAAE,WAAW;AAAA,IAC1B,SAAS,KAAK,UAAU,EAAE,QAAQ;AAAA,IAClC,QAAQ,KAAK,SAAS,EAAE,QAAQ;AAAA,IAChC,WAAW,KAAK,YAAY;AAAA,IAC5B,QAAQ,KAAK,QAAQ,EAAE,MAAmB,EAAE,QAAQ;AAAA,IACpD,SAAS,KAAK,UAAU,EAAE,QAAQ;AAAA,IAClC,YAAY,KAAK,aAAa,EAAE,QAAQ;AAAA,IACxC,aAAa,QAAQ,cAAc,EAAE,QAAQ;AAAA,IAC7C,mBAAmB,QAAQ,qBAAqB,EAAE,QAAQ;AAAA,IAC1D,kBAAkB,QAAQ,oBAAoB,EAAE,QAAQ;AAAA,IACxD,cAAc,QAAQ,eAAe,EAAE,QAAQ;AAAA,IAC/C,iBAAiB,QAAQ,kBAAkB,EAAE,QAAQ;AAAA,IACrD,SAAS,KAAK,UAAU,EAAE,QAAQ;AAAA,IAClC,WAAW,KAAK,YAAY,EAAE,QAAQ;AAAA;AAAA,IAEtC,WAAW,QAAQ,aAAa,EAAE,MAAM,UAAU,CAAC,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAC9E;AAAA,EACA,CAAC,UAAU;AAAA,IACT,MAAM,iCAAiC,EAAE,GAAG,MAAM,SAAS,MAAM,SAAS;AAAA,IAC1E,MAAM,gCAAgC,EAAE,GAAG,MAAM,QAAQ,MAAM,SAAS;AAAA,EAC1E;AACF;AAGO,IAAM,mBAAmB,YAAY,sBAAsB;AAAA,EAChE,SAAS,KAAK,UAAU,EAAE,WAAW;AAAA,EACrC,SAAS,KAAK,UAAU,EAAE,QAAQ;AAAA,EAClC,YAAY,KAAK,aAAa,EAAE,QAAQ;AAAA;AAAA,EAExC,WAAW,KAAK,WAAW;AAAA,EAC3B,WAAW,KAAK,YAAY,EAAE,QAAQ;AACxC,CAAC;AAGM,IAAM,eAAe,YAAY,iBAAiB;AAAA,EACvD,SAAS,KAAK,UAAU,EAAE,WAAW;AAAA,EACrC,SAAS,KAAK,UAAU,EAAE,QAAQ;AAAA,EAClC,WAAW,KAAK,YAAY,EAAE,QAAQ;AACxC,CAAC;AAGM,IAAM,sBAAsB,YAAY,yBAAyB;AAAA,EACtE,KAAK,KAAK,KAAK,EAAE,WAAW;AAAA,EAC5B,OAAO,KAAK,OAAO,EAAE,QAAQ;AAAA,EAC7B,SAAS,QAAQ,SAAS,EAAE,QAAQ;AAAA,EACpC,WAAW,KAAK,YAAY,EAAE,QAAQ;AACxC,CAAC;AAMM,IAAM,iBAAiB,YAAY,oBAAoB;AAAA,EAC5D,QAAQ,KAAK,SAAS,EAAE,WAAW;AAAA,EACnC,QAAQ,KAAK,QAAQ,EAAE,QAAQ;AAAA,EAC/B,OAAO,QAAQ,OAAO,EAAE,QAAQ;AAClC,CAAC;AAMM,IAAM,gBAAgB,YAAY,kBAAkB;AAAA,EACzD,QAAQ,KAAK,SAAS,EAAE,WAAW;AAAA,EACnC,SAAS,KAAK,UAAU,EAAE,QAAQ;AAAA,EAClC,WAAW,KAAK,YAAY,EAAE,QAAQ;AAAA,EACtC,OAAO,QAAQ,QAAQ,EAAE,QAAQ;AAAA,EACjC,QAAQ,KAAK,QAAQ,EAAE,QAAQ;AAAA,EAC/B,WAAW,QAAQ,YAAY,EAAE,QAAQ;AAAA,EACzC,MAAM,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAC,EAAE,MAA0B;AACjE,CAAC;AAMM,IAAM,cAAc;AAAA,EACzB;AAAA,EACA;AAAA,IACE,IAAI,KAAK,IAAI,EAAE,WAAW;AAAA,IAC1B,SAAS,KAAK,UAAU,EAAE,QAAQ;AAAA,IAClC,YAAY,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC,EAAE,MAAgB,EAAE,QAAQ;AAAA,IAC3E,SAAS,KAAK,SAAS,EAAE,QAAQ;AAAA,IACjC,SAAS,QAAQ,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC;AAAA,IAC/C,WAAW,QAAQ,YAAY,EAAE,QAAQ;AAAA,IACzC,WAAW,QAAQ,YAAY,EAAE,QAAQ;AAAA;AAAA,IAEzC,YAAY,KAAK,aAAa;AAAA,EAChC;AAAA,EACA,CAAC,UAAU;AAAA,IACT,MAAM,gCAAgC,EAAE,GAAG,MAAM,SAAS,MAAM,SAAS;AAAA,IACzE,MAAM,8BAA8B,EAAE,GAAG,MAAM,UAAU;AAAA,EAC3D;AACF;AAMO,IAAM,yBAAyB;AAAA,EACpC;AAAA,EACA;AAAA,IACE,IAAI,KAAK,IAAI,EAAE,WAAW;AAAA,IAC1B,SAAS,KAAK,UAAU,EAAE,QAAQ;AAAA,IAClC,WAAW,QAAQ,YAAY,EAAE,QAAQ;AAAA,IACzC,YAAY,QAAQ,aAAa;AAAA,IACjC,QAAQ,KAAK,QAAQ,EAAE,MAAgC,EAAE,QAAQ;AAAA,IACjE,QAAQ,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC,EAAE,MAA0B,EAAE,QAAQ,EAAE,QAAQ,SAAS;AAAA,IAChG,OAAO,KAAK,OAAO;AAAA,IACnB,eAAe,KAAK,iBAAiB;AAAA,EACvC;AAAA,EACA,CAAC,UAAU;AAAA,IACT,MAAM,4CAA4C,EAAE,GAAG,MAAM,SAAS,MAAM,SAAS;AAAA,IACrF,YAAY,0CAA0C,EAAE,GAAG,MAAM,OAAO,EAAE,MAAM,MAAM,MAAM,MAAM,cAAc;AAAA,EAClH;AACF;;;ADnNA,IAAM,mBAAmB,cAAc,IAAI,IAAI,cAAc,YAAY,GAAG,CAAC;AAE7E,IAAM,mBAAmB;AAEzB,IAAM,0BAA0B;AAGzB,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAChD,YACW,UACA,QACT;AACA;AAAA,MACE,yCAAW,QAAQ,8EAAkB,OAAO,KAAK,UAAK,CAAC;AAAA,IAEzD;AANS;AACA;AAMT,SAAK,OAAO;AAAA,EACd;AAAA,EARW;AAAA,EACA;AAQb;AAMA,SAAS,0BAA0B,QAA2B,UAAwB;AACpF,QAAM,QAAQ,WAAW,MAAM;AAC/B,QAAM,QAAQ,CAAC,SAAS,UAAU,EAAE,OAAO,CAAC,SAAS,MAAM,IAAI,IAAI,CAAC;AACpE,MAAI,MAAM,WAAW,EAAG;AACxB,QAAM,qBAAqB,mBAAmB,EAAE,iBAAiB,CAAC,EAAE,CAAC,GAAG;AACxE,QAAM,OAAO,CAAC,kBAAkB,uBAAuB,EAAE,KAAK,CAAC,UAAU;AACvE,QAAI;AACF,aAAO,MAAM,IAAI,KAAK,KAAK,OAAO,QAAQ,kBAAkB,KAAK,kBAAkB,EAAE,IAAI,kBAAkB,MAAM;AAAA,IACnH,QAAQ;AAEN,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACD,MAAI,CAAC,KAAM,OAAM,IAAI,uBAAuB,UAAU,KAAK;AAC7D;AAEA,SAAS,WAAW,QAAwC;AAC1D,SAAO,IAAI,IAAI,OAAO,QAAQ,qDAAqD,EAAE,MAAM,EAAE,IAAI,CAAa;AAChH;AAOA,SAAS,2BAA2B,QAAiC;AACnE,SACG,YAAY,MAAM;AACjB,UAAM,QAAQ,WAAW,MAAM;AAC/B,QAAI,MAAM,IAAI,gBAAgB,KAAK,CAAC,MAAM,IAAI,uBAAuB,EAAG;AACxE,QAAI;AACJ,QAAI;AACF,aAAO,OAAO,QAAQ,iCAAiC,uBAAuB,GAAG,EAAE,IAAI;AAAA,IACzF,QAAQ;AAEN;AAAA,IACF;AACA,UAAM,MAAM,mBAAmB,EAAE,iBAAiB,CAAC;AACnD,UAAM,OAAO,KAAK,OAAO,CAAC,QAAQ,IAAI,KAAK,CAAC,cAAc,UAAU,SAAS,IAAI,QAAQ,UAAU,iBAAiB,OAAO,IAAI,UAAU,CAAC,CAAC;AAC3I,QAAI,KAAK,WAAW,EAAG;AAEvB,WAAO,KAAK,iBAAiB,gBAAgB,mEAAmE;AAChH,UAAM,SAAS,OAAO,QAAQ,gBAAgB,gBAAgB,oCAAoC;AAClG,eAAW,OAAO,KAAM,QAAO,IAAI,IAAI,MAAM,IAAI,UAAU;AAAA,EAC7D,CAAC,EACA,UAAU;AACf;AASA,SAAS,gBAAgB,QAAiC;AACxD,QAAM,aAAa,mBAAmB,EAAE,iBAAiB,CAAC;AAC1D,SACG,YAAY,MAAM;AACjB,WAAO,KAAK,+BAA+B,gBAAgB,mEAAmE;AAC9H,UAAM,OAAO,OAAO,QAAQ,iCAAiC,gBAAgB,GAAG,EAAE,IAAI;AACtF,UAAM,SAAS,IAAI,IAAI,KAAK,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC;AAClD,UAAM,QAAQ,IAAI,IAAI,KAAK,IAAI,CAAC,QAAQ,OAAO,IAAI,UAAU,CAAC,CAAC;AAC/D,UAAM,SAAS,OAAO,QAAQ,gBAAgB,gBAAgB,oCAAoC;AAClG,eAAW,aAAa,YAAY;AAClC,UAAI,OAAO,IAAI,UAAU,IAAI,KAAK,MAAM,IAAI,UAAU,YAAY,EAAG;AACrE,iBAAW,aAAa,UAAU,IAAK,KAAI,UAAU,KAAK,EAAG,QAAO,KAAK,SAAS;AAClF,aAAO,IAAI,UAAU,MAAM,UAAU,YAAY;AAAA,IACnD;AAAA,EACF,CAAC,EACA,UAAU;AACf;AAGO,SAAS,wBAAwB,SAAkD;AACxF,QAAM,SAAS,IAAI,SAAS,QAAQ,QAAQ;AAC5C,MAAI;AACF,8BAA0B,QAAQ,QAAQ,QAAQ;AAClD,+BAA2B,MAAM;AAAA,EACnC,SAAS,OAAO;AACd,WAAO,MAAM;AACb,UAAM;AAAA,EACR;AACA,SAAO,OAAO,oBAAoB;AAClC,SAAO,OAAO,mBAAmB;AACjC,QAAM,KAAK,QAAQ,QAAQ,EAAE,QAAQ,EAAE,OAAO,UAAU,aAAa,kBAAkB,cAAc,kBAAkB,cAAc,qBAAqB,aAAa,uBAAuB,EAAE,CAAC;AACjM,kBAAgB,MAAM;AAMtB,WAAS,aAAa,IAAiB,SAA+B;AACpE,WAAO,GACJ,OAAO,EACP,KAAK,WAAW,EAChB,MAAM,IAAI,GAAG,YAAY,SAAS,OAAO,GAAG,OAAO,YAAY,UAAU,CAAC,CAAC,EAC3E,QAAQ,KAAK,YAAY,SAAS,GAAG,KAAK,YAAY,SAAS,GAAG,KAAK,YAAY,EAAE,CAAC,EACtF,IAAI,EACJ,IAAI,YAAY;AAAA,EACrB;AAEA,WAAS,YAAY,IAAiB,SAAiB,QAAyC;AAC9F,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,OAAO,OAAO,IAAI,CAAC,EAAE,YAAY,QAAQ,OAAwC;AAAA,MACrF,IAAI,OAAO,WAAW;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,WAAW;AAAA,MACX,WAAW;AAAA,IACb,EAAE;AACF,eAAW,OAAO,KAAM,IAAG,OAAO,WAAW,EAAE,OAAO,GAAG,EAAE,IAAI;AAC/D,WAAO,KAAK,IAAI,CAAC,QAAQ,aAAa,GAAsC,CAAC;AAAA,EAC/E;AAEA,WAAS,WAAW,IAAiB,SAAiB,IAAY,iBAAyB,OAAoE;AAC7J,UAAM,MAAM,GAAG,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,SAAS,EAAE,CAAC,EAAE,IAAI;AAC5E,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI,IAAI,YAAY,gBAAiB,QAAO;AAC5C,UAAM,UAAU,GACb,OAAO,WAAW,EAClB,IAAI;AAAA,MACH,YAAY,MAAM;AAAA,MAClB,SAAS,MAAM;AAAA,MACf,SAAS,IAAI,UAAU;AAAA;AAAA,MAEvB,WAAW,KAAK,IAAI,KAAK,IAAI,GAAG,IAAI,SAAS;AAAA,IAC/C,CAAC,EACA,MAAM,IAAI,UAAU,SAAS,EAAE,GAAG,GAAG,YAAY,SAAS,eAAe,CAAC,CAAC,EAC3E,UAAU,EACV,IAAI;AACP,WAAO,UAAU,aAAa,OAAO,IAAI;AAAA,EAC3C;AAGA,QAAM,gBAAgB,CAAC,UAAwC,QAAQ,EAAE,SAAS,oBAAoB,KAAK,EAAE,IAAI,CAAC;AAGlH,WAAS,gBAAgB,WAAmB,EAAE,OAAO,GAAG,OAAO,GAA8E;AAC3I,UAAM,SAAS,GACZ,OAAO,QAAQ,EACf,IAAI,EAAE,GAAG,QAAQ,GAAG,cAAc,KAAK,EAAE,CAAC,EAC1C,MAAM,IAAI,GAAG,SAAS,IAAI,SAAS,GAAG,GAAG,SAAS,QAAQ,WAAW,CAAC,CAAC,EACvE,IAAI;AACP,QAAI,OAAO,UAAU,EAAG;AACxB,UAAM,WAAW,GAAG,OAAO,EAAE,IAAI,SAAS,GAAG,CAAC,EAAE,KAAK,QAAQ,EAAE,MAAM,GAAG,SAAS,IAAI,SAAS,CAAC,EAAE,IAAI;AACrG,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,0DAAa,SAAS,qBAAM;AAC3D,UAAM,IAAI,4BAA4B,SAAS;AAAA,EACjD;AAEA,SAAO;AAAA,IACL,MAAM,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG;AACxC,YAAM,KAAK,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC/C,YAAM,MAAM,QAAQ,EAAE,GAAG,OAAO,WAAW,IAAI,WAAW,GAAG,CAAC;AAC9D,UAAI;AACF,WAAG,OAAO,KAAK,EAAE,OAAO,GAAG,EAAE,IAAI;AAAA,MACnC,SAAS,OAAO;AACd,YAAI,kBAAkB,KAAK,EAAG,OAAM,IAAI,0BAA0B,MAAM,SAAS,MAAM,UAAW;AAClG,cAAM;AAAA,MACR;AACA,aAAO,OAAO,GAAG;AAAA,IACnB;AAAA,IAEA,MAAM,kBAAkB,SAAS,YAAY;AAC3C,YAAM,MAAM,GAAG,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,IAAI,GAAG,MAAM,SAAS,OAAO,GAAG,GAAG,MAAM,YAAY,UAAU,CAAC,CAAC,EAAE,IAAI;AACjH,aAAO,MAAM,OAAO,GAAG,IAAI;AAAA,IAC7B;AAAA,IAEA,MAAM,WAAW,MAAM,UAAU;AAC/B,SAAG,YAAY,CAAC,OAAO;AACrB,YAAI;AACF,aAAG,OAAO,KAAK,EAAE,OAAO,QAAQ,IAAI,CAAC,EAAE,IAAI;AAAA,QAC7C,SAAS,OAAO;AACd,cAAI,kBAAkB,KAAK,EAAG,OAAM,IAAI,0BAA0B,KAAK,SAAS,KAAK,UAAW;AAChG,cAAI,qBAAqB,KAAK,EAAG,OAAM,IAAI,uBAAuB,KAAK,EAAE;AACzE,gBAAM;AAAA,QACR;AACA,mBAAW,WAAW,UAAU;AAC9B,gBAAM,UAAUC,4BAAmC,SAAS,GAAG,kBAAkB,QAAQ;AACzF,gBAAM,EAAE,OAAO,QAAQ,GAAG,OAAO,IAAI;AACrC,cAAI;AACF,eAAG,OAAO,QAAQ,EAAE,OAAO,EAAE,GAAG,QAAQ,KAAK,QAAQ,CAAC,EAAE,IAAI;AAAA,UAC9D,SAAS,OAAO;AACd,gBAAI,qBAAqB,KAAK,EAAG,OAAM,IAAI,sBAAsB,QAAQ,EAAE;AAC3E,kBAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF,GAAG,EAAE,UAAU,YAAY,CAAC;AAAA,IAC9B;AAAA,IAEA,MAAM,kBAAkB,WAAW,OAAOC,UAAS;AAEjD,aAAO,GAAG;AAAA,QACR,CAAC,OAAO;AACN,gBAAM,WAAW,GAAG,OAAO,EAAE,OAAO,SAAS,OAAO,WAAW,SAAS,UAAU,CAAC,EAAE,KAAK,QAAQ,EAAE,MAAM,GAAG,SAAS,IAAI,SAAS,CAAC,EAAE,IAAI;AAC1I,cAAI,CAAC,YAAa,UAAU,aAAa,SAAS,cAAc,UAAY,QAAO;AACnF,aAAG,OAAO,QAAQ,EACf,IAAI;AAAA,YACH,WAAW;AAAA,YACX,GAAIA,UAAS,eAAe,EAAE,OAAO,CAAC,GAAG,SAAS,OAAO,GAAGA,SAAQ,WAAW,EAAE;AAAA;AAAA,YAEjF,GAAI,UAAU,aAAa,cAAc,KAAK;AAAA,UAChD,CAAC,EACA,MAAM,GAAG,SAAS,IAAI,SAAS,CAAC,EAChC,IAAI;AACP,iBAAO;AAAA,QACT;AAAA,QACA,EAAE,UAAU,YAAY;AAAA,MAC1B;AAAA,IACF;AAAA,IAEA,MAAM,qBAAqB,QAAQ;AACjC,aAAO,GACJ,OAAO,EAAE,IAAI,SAAS,GAAG,CAAC,EAC1B,KAAK,QAAQ,EACb;AAAA,QACC,QAAQ,iBAAiB,SACrB,GAAG,SAAS,WAAW,SAAS,IAChC;AAAA,UACE,GAAG,SAAS,WAAW,SAAS;AAAA,UAChCD,gBAAe,SAAS,OAAO,KAAK,SAAS,SAAS,OAAO,4BAA4B,OAAO,YAAY,CAAC;AAAA,QAC/G;AAAA,MACN,EACC,IAAI,EACJ,IAAI,CAAC,QAAQ,IAAI,EAAE;AAAA,IACxB;AAAA,IAEA,MAAM,QAAQ,QAAQ;AACpB,YAAM,MAAM,GAAG,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,GAAG,MAAM,IAAI,MAAM,CAAC,EAAE,IAAI;AACpE,aAAO,MAAM,OAAO,GAAG,IAAI;AAAA,IAC7B;AAAA,IAEA,MAAM,gBAAgB,QAAQ,OAAO;AACnC,SAAG,OAAO,KAAK,EACZ,IAAI,EAAE,SAAS,MAAM,SAAS,YAAY,MAAM,YAAY,WAAW,MAAM,aAAa,KAAK,CAAC,EAChG,MAAM,GAAG,MAAM,IAAI,MAAM,CAAC,EAC1B,IAAI;AAAA,IACT;AAAA,IAEA,MAAM,eAAe,QAAQ,OAAO,EAAE,SAAS,GAAG;AAEhD,aAAO,GAAG;AAAA,QACR,CAAC,OAAO;AACN,gBAAM,MAAM,GAAG,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,GAAG,MAAM,IAAI,MAAM,CAAC,EAAE,IAAI;AACpE,cAAI,CAAC,IAAK,QAAO;AACjB,gBAAM,SAAS,cAAc,IAAI,eAAe,QAAW,OAAO,QAAQ;AAC1E,aAAG,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,UAAU,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI,MAAM,CAAC,EAAE,IAAI;AACtF,iBAAO,OAAO,EAAE,GAAG,KAAK,aAAa,UAAU,KAAK,CAAC;AAAA,QACvD;AAAA,QACA,EAAE,UAAU,YAAY;AAAA,MAC1B;AAAA,IACF;AAAA,IAEA,MAAM,UAAU,SAASC,UAA2B;AAClD,UAAIA,UAAS,KAAM,sBAAqBA,SAAQ,IAAI;AACpD,YAAM,OAAO,GACV,OAAO,EACP,KAAK,KAAK,EACV,MAAM,IAAI,GAAG,MAAM,SAAS,OAAO,GAAG,iBAAiBA,UAAS,QAAQ,GAAG,GAAG,eAAeA,UAAS,IAAI,CAAC,CAAC,EAC5G,QAAQ,KAAK,MAAM,SAAS,GAAG,KAAK,MAAM,SAAS,GAAG,KAAK,MAAM,EAAE,CAAC,EACpE,IAAI;AACP,aAAO,KAAK,IAAI,MAAM;AAAA,IACxB;AAAA,IAEA,MAAM,WAAW,QAAQ,OAAO;AAC9B,SAAG,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI,MAAM,CAAC,EAAE,IAAI;AAAA,IAClE;AAAA,IAEA,MAAM,cAAc,QAAQ,QAAQ;AAClC,SAAG,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,UAAU,EAAE,MAAM,OAAO,MAAM,SAAS,OAAO,QAAQ,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI,MAAM,CAAC,EAAE,IAAI;AAAA,IAC7H;AAAA,IAEA,MAAM,WAAW,QAAQ;AACvB,SAAG,YAAY,CAAC,OAAO;AACrB,WAAG,OAAO,WAAW,EAAE,MAAM,GAAG,YAAY,QAAQ,MAAM,CAAC,EAAE,IAAI;AACjE,WAAG,OAAO,gBAAgB,EAAE,MAAM,GAAG,iBAAiB,QAAQ,MAAM,CAAC,EAAE,IAAI;AAC3E,WAAG,OAAO,QAAQ,EAAE,MAAM,GAAG,SAAS,QAAQ,MAAM,CAAC,EAAE,IAAI;AAC3D,WAAG,OAAO,KAAK,EAAE,MAAM,GAAG,MAAM,IAAI,MAAM,CAAC,EAAE,IAAI;AACjD,WAAG,OAAO,cAAc,EAAE,MAAM,GAAG,eAAe,QAAQ,MAAM,CAAC,EAAE,IAAI;AACvE,WAAG,OAAO,aAAa,EAAE,MAAM,GAAG,cAAc,QAAQ,MAAM,CAAC,EAAE,IAAI;AAAA,MACvE,GAAG,EAAE,UAAU,YAAY,CAAC;AAAA,IAC9B;AAAA,IAEA,MAAM,cAAc,QAAQ,QAAQ,SAAS;AAC3C,YAAM,MAAM,KAAK,IAAI;AAErB,YAAM,UAAU,GACb,OAAO,cAAc,EACrB,OAAO,EAAE,QAAQ,QAAQ,OAAO,MAAM,QAAQ,CAAC,EAC/C,mBAAmB;AAAA,QAClB,QAAQ,eAAe;AAAA,QACvB,KAAK,EAAE,QAAQ,OAAO,MAAM,QAAQ;AAAA,QACpC,UAAUD,OAAM,eAAe,MAAM,MAAM,MAAM,OAAO,eAAe,KAAK,OAAO,GAAG;AAAA,MACxF,CAAC,EACA,UAAU,EAAE,QAAQ,eAAe,OAAO,CAAC,EAC3C,IAAI;AACP,aAAO,QAAQ,SAAS;AAAA,IAC1B;AAAA,IAEA,MAAM,gBAAgB,QAAQ,QAAQ;AACpC,SAAG,OAAO,cAAc,EAAE,MAAM,IAAI,GAAG,eAAe,QAAQ,MAAM,GAAG,GAAG,eAAe,QAAQ,MAAM,CAAC,CAAC,EAAE,IAAI;AAAA,IACjH;AAAA,IAEA,MAAM,sBAAsB;AAC1B,SAAG,OAAO,cAAc,EAAE,IAAI;AAAA,IAChC;AAAA,IAEA,MAAM,iBAAiB,OAAO;AAC5B,YAAM,MAAM;AAAA,QACV,QAAQ,MAAM;AAAA,QACd,SAAS,MAAM;AAAA,QACf,WAAW,MAAM;AAAA,QACjB,OAAO,KAAK,MAAM,MAAM,KAAK;AAAA,QAC7B,QAAQ,MAAM;AAAA,QACd,WAAW,KAAK,MAAM,MAAM,SAAS;AAAA,QACrC,MAAM,MAAM,QAAQ;AAAA,MACtB;AACA,SAAG,OAAO,aAAa,EAAE,OAAO,GAAG,EAAE,mBAAmB,EAAE,QAAQ,cAAc,QAAQ,KAAK,IAAI,CAAC,EAAE,IAAI;AAAA,IAC1G;AAAA,IAEA,MAAM,oBAAoB,EAAE,iBAAiB,QAAQ,WAAW,OAAO,aAAa,GAAG;AAErF,aAAO,GAAG,YAAY,CAAC,OAAO;AAC5B,cAAM,YAAY,GACf,OAAO,EACP,KAAK,aAAa,EAClB,MAAM,IAAI,IAAI,cAAc,WAAW,KAAK,MAAM,eAAe,CAAC,GAAG,iBAAiB,SAAY,SAAY,GAAG,cAAc,QAAQ,YAAY,CAAC,CAAC,EACrJ,QAAQ,IAAI,cAAc,KAAK,CAAC,EAChC,MAAM,KAAK,EACX,IAAI;AACP,cAAM,QAAQ,KAAK,MAAM,SAAS;AAClC,mBAAW,OAAO,UAAW,IAAG,OAAO,aAAa,EAAE,IAAI,EAAE,QAAQ,WAAW,MAAM,CAAC,EAAE,MAAM,GAAG,cAAc,QAAQ,IAAI,MAAM,CAAC,EAAE,IAAI;AACxI,eAAO,UAAU,IAAI,CAAC,SAAS;AAAA,UAC7B,QAAQ,IAAI;AAAA,UACZ,SAAS,IAAI;AAAA,UACb,WAAW,IAAI;AAAA,UACf,OAAO,IAAI,KAAK,IAAI,KAAK,EAAE,YAAY;AAAA,UACvC;AAAA,UACA;AAAA,UACA,GAAI,IAAI,QAAQ,EAAE,MAAM,IAAI,KAAK;AAAA,QACnC,EAAE;AAAA,MACJ,GAAG,EAAE,UAAU,YAAY,CAAC;AAAA,IAC9B;AAAA,IAEA,MAAM,kBAAkB,EAAE,QAAQ,WAAW,QAAQ,UAAU,GAAG;AAChE,YAAM,UAAU,GACb,OAAO,aAAa,EACpB,IAAI,EAAE,WAAW,KAAK,MAAM,SAAS,EAAE,CAAC,EACxC,MAAM,IAAI,GAAG,cAAc,QAAQ,MAAM,GAAG,GAAG,cAAc,WAAW,SAAS,GAAG,GAAG,cAAc,QAAQ,MAAM,CAAC,CAAC,EACrH,IAAI;AACP,aAAO,QAAQ,UAAU;AAAA,IAC3B;AAAA,IAEA,MAAM,mBAAmB,QAAQ,WAAW;AAC1C,SAAG,OAAO,aAAa,EAAE,MAAM,IAAI,GAAG,cAAc,QAAQ,MAAM,GAAG,GAAG,cAAc,WAAW,SAAS,CAAC,CAAC,EAAE,IAAI;AAAA,IACpH;AAAA,IAEA,MAAM,WAAW,WAAW;AAC1B,YAAM,MAAM,GAAG,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,GAAG,SAAS,IAAI,SAAS,CAAC,EAAE,IAAI;AAC7E,UAAI,CAAC,IAAK,QAAO;AACjB,YAAM,UAAU,UAAU,GAAG;AAC7B,+BAAyB,OAAO;AAChC,aAAO;AAAA,IACT;AAAA;AAAA,IAGA,MAAM,aAAa,QAAQ;AACzB,YAAM,OAAO,GACV,OAAO,EACP,KAAK,QAAQ,EACb,MAAM,GAAG,SAAS,QAAQ,MAAM,CAAC,EACjC,QAAQ,IAAI,SAAS,SAAS,GAAG,SAAS,GAAG,EAC7C,IAAI;AACP,YAAM,QAAyB,KAAK,IAAI,SAAS;AACjD,YAAM,QAAQ,wBAAwB;AACtC,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,iBAAiB,QAAQ;AAC7B,aAAO,GACJ,OAAO,EAAE,IAAI,SAAS,IAAI,UAAU,SAAS,UAAU,WAAW,SAAS,UAAU,CAAC,EACtF,KAAK,QAAQ,EACb,MAAM,GAAG,SAAS,QAAQ,MAAM,CAAC,EACjC,QAAQ,IAAI,SAAS,SAAS,GAAG,SAAS,GAAG,EAC7C,IAAI;AAAA,IACT;AAAA;AAAA,IAGA,MAAM,wBAAwB,QAAQ,OAAO;AAC3C,YAAM,SAAS,KAAK,UAAU,CAAC,GAAG,KAAK,CAAC;AACxC,YAAM,OAAO,GACV,OAAO;AAAA,QACN,IAAI,SAAS;AAAA,QACb,UAAU,SAAS;AAAA,QACnB,WAAW,SAAS;AAAA,QACpB,OAAOA,2GAAkH,SAAS,KAAK,sFAAsF,MAAM;AAAA,MACrO,CAAC,EACA,KAAK,QAAQ,EACb,MAAM,GAAG,SAAS,QAAQ,MAAM,CAAC,EACjC,QAAQ,IAAI,SAAS,SAAS,GAAG,SAAS,GAAG,EAC7C,IAAI;AACP,aAAO,KAAK,IAAI,CAAC,SAAS,EAAE,GAAG,KAAK,OAAO,KAAK,MAAM,IAAI,KAAK,EAA4B,EAAE;AAAA,IAC/F;AAAA,IAEA,MAAM,cAAc,SAAS;AAC3B,UAAI;AACF,WAAG,YAAY,CAAC,OAAO;AACrB,gBAAM,UAAUA,4BAAmC,SAAS,GAAG,kBAAkB,QAAQ;AACzF,gBAAM,EAAE,OAAO,GAAG,OAAO,IAAI;AAC7B,aAAG,OAAO,QAAQ,EAAE,OAAO,EAAE,GAAG,QAAQ,GAAG,cAAc,KAAK,GAAG,KAAK,QAAQ,CAAC,EAAE,IAAI;AACrF,aAAG,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,QAAQ,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,IAAI,QAAQ,MAAM,CAAC,EAAE,IAAI;AAAA,QACjG,GAAG,EAAE,UAAU,YAAY,CAAC;AAAA,MAC9B,SAAS,OAAO;AACd,YAAI,qBAAqB,KAAK,EAAG,OAAM,IAAI,sBAAsB,QAAQ,EAAE;AAC3E,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IAEA,wBAAwB,OAAO,WAAW,UAAU,gBAAgB,WAAW,KAAK;AAAA,IAEpF,iBAAiB,OAAO,cAAc,gBAAgB,WAAW,EAAE,OAAO,MAAM,CAAC;AAAA,IAEjF,eAAe,OAAO,WAAW,UAAU,gBAAgB,WAAW,EAAE,GAAG,OAAO,GAAI,MAAM,cAAc,aAAa,EAAE,OAAO,MAAe,EAAG,CAAC;AAAA,IAEnJ,MAAM,sBAAsB,WAAW,OAAO;AAE5C,SAAG;AAAA,QACD,CAAC,OAAO;AACN,gBAAM,WAAW,GAAG,OAAO,EAAE,QAAQ,SAAS,QAAQ,OAAO,SAAS,MAAM,CAAC,EAAE,KAAK,QAAQ,EAAE,MAAM,GAAG,SAAS,IAAI,SAAS,CAAC,EAAE,IAAI;AACpI,cAAI,CAAC,SAAU,OAAM,IAAI,MAAM,0DAAa,SAAS,qBAAM;AAC3D,cAAI,SAAS,WAAW,oBAAqB,OAAM,IAAI,wBAAwB,SAAS;AACxF,cAAI,MAAM,iBAAiB,CAAC,iBAAiB,SAAS,OAAO,MAAM,aAAa,EAAG,OAAM,IAAI,wBAAwB,SAAS;AAC9H,aAAG,OAAO,QAAQ,EACf,IAAI,EAAE,OAAO,MAAM,OAAO,GAAI,MAAM,UAAU,EAAE,QAAQ,MAAM,OAAO,GAAI,GAAG,cAAc,MAAM,KAAK,EAAE,CAAC,EACxG,MAAM,GAAG,SAAS,IAAI,SAAS,CAAC,EAChC,IAAI;AAAA,QACT;AAAA,QACA,EAAE,UAAU,YAAY;AAAA,MAC1B;AAAA,IACF;AAAA,IAEA,MAAM,0BAA0B;AAC9B,aAAO,GACJ,OAAO,EAAE,IAAI,SAAS,GAAG,CAAC,EAC1B,KAAK,QAAQ,EACb,MAAM,GAAG,SAAS,QAAQ,WAAW,CAAC,EACtC,IAAI,EACJ,IAAI,CAAC,QAAQ,IAAI,EAAE;AAAA,IACxB;AAAA,IAEA,MAAM,oBAAoB,EAAE,aAAa,OAAO,GAAG;AACjD,YAAM,SAASA,gBAAe,SAAS,OAAO,KAAK,SAAS,SAAS,OAAO,4BAA4B,WAAW,CAAC;AACpH,aAAO,GACJ,OAAO,EAAE,IAAI,SAAS,GAAG,CAAC,EAC1B,KAAK,QAAQ,EACb,MAAM,IAAI,GAAG,SAAS,QAAQ,WAAW,GAAG,QAAQ,WAAW,SAAY,SAAY,GAAG,SAAS,QAAQ,MAAM,CAAC,CAAC,EACnH,IAAI,EACJ,IAAI,CAAC,QAAQ,IAAI,EAAE;AAAA,IACxB;AAAA,IAEA,MAAM,iBAAiB,QAAQ;AAC7B,YAAM,UAAUA,4BAAmC,YAAY,GAAG,kBAAkB,WAAW;AAC/F,SAAG,OAAO,WAAW,EAAE,OAAO,EAAE,GAAG,QAAQ,KAAK,QAAQ,CAAC,EAAE,IAAI;AAAA,IACjE;AAAA,IAEA,MAAM,gBAAgB,QAAQ;AAC5B,YAAM,OAAO,GAAG,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,GAAG,YAAY,QAAQ,MAAM,CAAC,EAAE,QAAQ,IAAI,YAAY,GAAG,CAAC,EAAE,IAAI;AACnH,aAAO,KAAK,IAAI,CAAC,EAAE,KAAK,MAAM,GAAG,OAAO,MAAM,MAAM;AAAA,IACtD;AAAA,IAEA,MAAM,sBAAsB,QAAQ;AAClC,YAAM,UAAUA,4BAAmC,iBAAiB,GAAG,kBAAkB,gBAAgB;AACzG,SAAG,OAAO,gBAAgB,EAAE,OAAO,EAAE,GAAG,QAAQ,KAAK,QAAQ,CAAC,EAAE,IAAI;AAAA,IACtE;AAAA,IAEA,MAAM,qBAAqB,QAAQ;AACjC,YAAM,OAAO,GAAG,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,GAAG,iBAAiB,QAAQ,MAAM,CAAC,EAAE,QAAQ,IAAI,iBAAiB,GAAG,CAAC,EAAE,IAAI;AAClI,aAAO,KAAK,IAAI,CAAC,EAAE,KAAK,MAAM,GAAG,OAAO,MAAM,MAAM;AAAA,IACtD;AAAA,IAEA,MAAM,kBAAkB,QAAQ;AAC9B,SAAG,OAAO,YAAY,EAAE,OAAO,MAAM,EAAE,IAAI;AAAA,IAC7C;AAAA,IAEA,MAAM,eAAe,IAAI;AACvB,aAAO,GAAG,OAAO,EAAE,IAAI,aAAa,GAAG,CAAC,EAAE,KAAK,YAAY,EAAE,MAAM,GAAG,aAAa,IAAI,EAAE,CAAC,EAAE,IAAI,MAAM;AAAA,IACxG;AAAA,IAEA,MAAM,SAAS,EAAE,SAAS,QAAQ,WAAW,QAAQ,MAAM,GAAG;AAC5D,YAAM,UAAU;AAAA,QACd,GAAI,YAAY,SAAY,CAAC,GAAG,aAAa,SAAS,OAAO,CAAC,IAAI,CAAC;AAAA,QACnE,GAAI,WAAW,SAAY,CAAC,GAAG,aAAa,QAAQ,MAAM,CAAC,IAAI,CAAC;AAAA,QAChE,GAAI,cAAc,SAAY,CAAC,GAAG,aAAa,WAAW,SAAS,CAAC,IAAI,CAAC;AAAA,QACzE,GAAI,WAAW,SAAY,CAAC,GAAG,aAAa,QAAQ,MAAM,CAAC,IAAI,CAAC;AAAA,QAChE,GAAI,UAAU,SAAY,CAAC,IAAI,aAAa,WAAW,KAAK,CAAC,IAAI,CAAC;AAAA,MACpE;AACA,aAAO,GACJ,OAAO;AAAA,QACN,SAAS,aAAa;AAAA,QACtB,YAAY,aAAa;AAAA,QACzB,aAAaA,WAAkB,aAAa,WAAW,IAAI,QAAQ,MAAM;AAAA,QACzE,mBAAmBA,WAAkB,aAAa,iBAAiB,IAAI,QAAQ,MAAM;AAAA,QACrF,kBAAkBA,WAAkB,aAAa,gBAAgB,IAAI,QAAQ,MAAM;AAAA,QACnF,cAAcA,WAAkB,aAAa,YAAY,IAAI,QAAQ,MAAM;AAAA,QAC3E,iBAAiBA,WAAkB,aAAa,eAAe,IAAI,QAAQ,MAAM;AAAA,QACjF,SAASA,WAAkB,aAAa,OAAO,IAAI,QAAQ,MAAM;AAAA,MACnE,CAAC,EACA,KAAK,YAAY,EACjB,MAAM,IAAI,GAAG,OAAO,CAAC,EACrB,QAAQ,aAAa,SAAS,aAAa,UAAU,EACrD,IAAI;AAAA,IACT;AAAA,IAEA,MAAM,eAAe,EAAE,SAAS,SAAS,QAAQ,MAAM,GAAG;AACxD,UAAI,QAAQ,WAAW,EAAG,QAAO,CAAC;AAClC,YAAM,UAAU;AAAA,QACd,QAAQ,aAAa,QAAQ,CAAC,GAAG,OAAO,CAAC;AAAA,QACzC,GAAI,YAAY,SAAY,CAAC,GAAG,aAAa,SAAS,OAAO,CAAC,IAAI,CAAC;AAAA,QACnE,GAAI,WAAW,SAAY,CAAC,GAAG,aAAa,QAAQ,MAAM,CAAC,IAAI,CAAC;AAAA,QAChE,GAAI,UAAU,SAAY,CAAC,IAAI,aAAa,WAAW,KAAK,CAAC,IAAI,CAAC;AAAA,MACpE;AACA,aAAO,GACJ,OAAO;AAAA,QACN,QAAQ,aAAa;AAAA,QACrB,SAAS,aAAa;AAAA,QACtB,YAAY,aAAa;AAAA,QACzB,aAAaA,WAAkB,aAAa,WAAW,IAAI,QAAQ,MAAM;AAAA,QACzE,mBAAmBA,WAAkB,aAAa,iBAAiB,IAAI,QAAQ,MAAM;AAAA,QACrF,kBAAkBA,WAAkB,aAAa,gBAAgB,IAAI,QAAQ,MAAM;AAAA,QACnF,cAAcA,WAAkB,aAAa,YAAY,IAAI,QAAQ,MAAM;AAAA,QAC3E,iBAAiBA,WAAkB,aAAa,eAAe,IAAI,QAAQ,MAAM;AAAA,QACjF,SAASA,WAAkB,aAAa,OAAO,IAAI,QAAQ,MAAM;AAAA,MACnE,CAAC,EACA,KAAK,YAAY,EACjB,MAAM,IAAI,GAAG,OAAO,CAAC,EACrB,QAAQ,aAAa,QAAQ,aAAa,SAAS,aAAa,UAAU,EAC1E,IAAI;AAAA,IACT;AAAA,IAEA,MAAM,mBAAmB,SAAS;AAChC,YAAM,MAAM,GAAG,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,GAAG,iBAAiB,SAAS,OAAO,CAAC,EAAE,IAAI;AAChG,UAAI,CAAC,IAAK,QAAO;AACjB,aAAO,EAAE,SAAS,IAAI,SAAS,YAAY,IAAI,YAAY,GAAI,IAAI,cAAc,QAAQ,EAAE,WAAW,IAAI,UAAU,EAAG;AAAA,IACzH;AAAA,IAEA,MAAM,oBAAoB,SAAS,QAAQ;AACzC,YAAM,SAAS,EAAE,SAAS,OAAO,SAAS,YAAY,OAAO,YAAY,WAAW,OAAO,aAAa,MAAM,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AAClJ,SAAG,OAAO,gBAAgB,EAAE,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,EAAE,mBAAmB,EAAE,QAAQ,iBAAiB,SAAS,KAAK,OAAO,CAAC,EAAE,IAAI;AAAA,IACvI;AAAA,IAEA,MAAM,YAAY,EAAE,SAAS,QAAQ,WAAW,SAAS,GAAG;AAC1D,SAAG,OAAO,QAAQ,EACf,IAAI,EAAE,SAAS,CAAC,EAChB;AAAA,QACC;AAAA,UACE,GAAG,SAAS,IAAI,SAAS;AAAA,UACzB,GAAG,SAAS,QAAQ,MAAM;AAAA,UAC1BA,6BAA4B,KAAK,UAAU,MAAM,EAAE,MAAM,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO;AAAA,QACnG;AAAA,MACF,EACC,IAAI;AAAA,IACT;AAAA,IAEA,MAAM,sBAAsB,KAAK;AAC/B,YAAM,MAAM,GAAG,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,GAAG,oBAAoB,KAAK,GAAG,CAAC,EAAE,IAAI;AAC9F,aAAO,MAAM,EAAE,OAAO,IAAI,OAAO,SAAS,IAAI,QAAQ,IAAI;AAAA,IAC5D;AAAA;AAAA,IAGA,MAAM,uBAAuB,KAAK,OAAO,iBAAiB;AACxD,YAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,UAAI,oBAAoB,MAAM;AAC5B,eAAO,GAAG,OAAO,mBAAmB,EAAE,OAAO,EAAE,KAAK,OAAO,SAAS,GAAG,UAAU,CAAC,EAAE,oBAAoB,EAAE,IAAI,EAAE,YAAY;AAAA,MAC9H;AACA,YAAM,UAAU,GACb,OAAO,mBAAmB,EAC1B,IAAI,EAAE,OAAO,SAAS,kBAAkB,GAAG,UAAU,CAAC,EACtD,MAAM,IAAI,GAAG,oBAAoB,KAAK,GAAG,GAAG,GAAG,oBAAoB,SAAS,eAAe,CAAC,CAAC,EAC7F,IAAI,EAAE;AACT,aAAO,YAAY;AAAA,IACrB;AAAA,IAEA,MAAM,0BAA0B,MAAM;AACpC,UAAI,KAAK,SAAS,EAAG,IAAG,OAAO,mBAAmB,EAAE,MAAM,QAAQ,oBAAoB,KAAK,IAAI,CAAC,EAAE,IAAI;AAAA,IACxG;AAAA,IAEA,MAAM,eAAe,SAAS;AAC5B,aAAO,GAAG,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,GAAG,aAAa,SAAS,OAAO,CAAC,EAAE,IAAI,GAAG,WAAW;AAAA,IACnG;AAAA,IAEA,MAAM,eAAe,SAAS,SAAS;AACrC,YAAM,SAAS,EAAE,SAAS,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AAC9D,SAAG,OAAO,YAAY,EAAE,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,EAAE,mBAAmB,EAAE,QAAQ,aAAa,SAAS,KAAK,OAAO,CAAC,EAAE,IAAI;AAAA,IAC/H;AAAA,IAEA,MAAM,gBAAgB,SAAS;AAC7B,aAAO,GAAG,YAAY,CAAC,OAAO,aAAa,IAAI,OAAO,CAAC;AAAA,IACzD;AAAA;AAAA,IAGA,MAAM,kBAAkB,SAAS,QAAQ;AACvC,aAAO,GAAG,YAAY,CAAC,OAAO,YAAY,IAAI,SAAS,MAAM,GAAG,EAAE,UAAU,YAAY,CAAC;AAAA,IAC3F;AAAA,IAEA,MAAM,yBAAyB,SAAS,QAAQ,OAAO;AACrD,aAAO,GAAG;AAAA,QACR,CAAC,OAAO;AACN,gBAAM,QAAQ,MAAM,aAAa,IAAI,OAAO,CAAC;AAC7C,iBAAO,SAAS,YAAY,IAAI,SAAS,MAAM;AAAA,QACjD;AAAA,QACA,EAAE,UAAU,YAAY;AAAA,MAC1B;AAAA,IACF;AAAA,IAEA,MAAM,iBAAiB,SAAS,IAAI,iBAAiB,OAAO;AAC1D,aAAO,GAAG,YAAY,CAAC,OAAO,WAAW,IAAI,SAAS,IAAI,iBAAiB,KAAK,GAAG,EAAE,UAAU,YAAY,CAAC;AAAA,IAC9G;AAAA,IAEA,MAAM,wBAAwB,SAAS,IAAI,iBAAiB,OAAO,OAAO;AACxE,aAAO,GAAG,YAAY,CAAC,OAAO,MAAM,aAAa,IAAI,OAAO,CAAC,KAAK,WAAW,IAAI,SAAS,IAAI,iBAAiB,KAAK,GAAG,EAAE,UAAU,YAAY,CAAC;AAAA,IAClJ;AAAA,IAEA,MAAM,iBAAiB,SAAS,IAAI,iBAAiB;AACnD,aAAO,GAAG,YAAY,CAAC,OAAO;AAC5B,cAAM,MAAM,GAAG,OAAO,EAAE,SAAS,YAAY,QAAQ,CAAC,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,SAAS,EAAE,CAAC,EAAE,IAAI;AAC5G,YAAI,CAAC,IAAK,QAAO;AACjB,YAAI,IAAI,YAAY,gBAAiB,QAAO;AAC5C,cAAM,SAAS,GAAG,OAAO,WAAW,EAAE,MAAM,IAAI,UAAU,SAAS,EAAE,GAAG,GAAG,YAAY,SAAS,eAAe,CAAC,CAAC,EAAE,IAAI;AACvH,YAAI,OAAO,YAAY,EAAG,QAAO;AAEjC,WAAG,OAAO,WAAW,EAAE,MAAM,IAAI,GAAG,YAAY,SAAS,OAAO,GAAG,GAAG,YAAY,YAAY,EAAE,CAAC,CAAC,EAAE,IAAI;AACxG,eAAO;AAAA,MACT,GAAG,EAAE,UAAU,YAAY,CAAC;AAAA,IAC9B;AAAA,IAEA,MAAM,iBAAiB,SAAS;AAC9B,aAAO,GAAG,YAAY,CAAC,OAAO;AAC5B,cAAM,UAAU,GAAG,OAAO,WAAW,EAAE,MAAM,GAAG,YAAY,SAAS,OAAO,CAAC,EAAE,UAAU,EAAE,YAAY,YAAY,WAAW,CAAC,EAAE,IAAI;AACrI,WAAG,OAAO,sBAAsB,EAAE,MAAM,GAAG,uBAAuB,SAAS,OAAO,CAAC,EAAE,IAAI;AAEzF,eAAO,QAAQ,OAAO,CAAC,QAAQ,IAAI,eAAe,IAAI,EAAE;AAAA,MAC1D,GAAG,EAAE,UAAU,YAAY,CAAC;AAAA,IAC9B;AAAA;AAAA,IAGA,MAAM,2BAA2B,SAAS,OAAO,KAAK;AACpD,YAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,aAAO,GAAG,YAAY,CAAC,OAAO;AAC5B,cAAM,OAAO,GAAG,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,GAAG,uBAAuB,SAAS,OAAO,CAAC,EAAE,IAAI;AAC7G,mBAAW,OAAO,MAAM;AACtB,gBAAM,WAAW,IAAI,YAAY,MAAM;AACvC,cAAI,IAAI,WAAW,aAAa,QAAQ,SAAU;AAClD,aAAG,OAAO,sBAAsB,EAAE,IAAI,EAAE,QAAQ,UAAU,OAAO,iBAAiB,YAAY,SAAS,CAAC,EAAE,MAAM,GAAG,uBAAuB,IAAI,IAAI,EAAE,CAAC,EAAE,IAAI;AAC3J,iBAAO,OAAO,KAAK,EAAE,QAAQ,UAAU,YAAY,SAAS,CAAC;AAAA,QAC/D;AACA,cAAM,UAAU;AAAA,UACd,KAAK,IAAI,CAAC,SAAS,EAAE,QAAQ,IAAI,QAAQ,aAAa,IAAI,WAAW,WAAW,IAAI,WAAW,EAAE;AAAA,UACjG;AAAA,UACA;AAAA,QACF;AACA,YAAI,QAAS,QAAO;AACpB,cAAM,MAAM,EAAE,IAAI,OAAO,WAAW,GAAG,SAAS,WAAW,OAAO,YAAY,MAAM,QAAQ,WAAoB,QAAQ,CAAC,GAAG,OAAO,MAAM,eAAe,KAAK;AAC7J,WAAG,OAAO,sBAAsB,EAAE,OAAO,GAAG,EAAE,IAAI;AAClD,eAAO,kBAAkB,GAAG;AAAA,MAC9B,GAAG,EAAE,UAAU,YAAY,CAAC;AAAA,IAC9B;AAAA,IAEA,MAAM,4BAA4B,SAAS,OAAO,SAAS;AACzD,YAAM,SAAS,GACZ,OAAO,sBAAsB,EAC7B,IAAI,EAAE,QAAQ,QAAQ,QAAQ,YAAY,KAAK,MAAM,QAAQ,UAAU,GAAG,OAAO,QAAQ,SAAS,MAAM,eAAe,QAAQ,iBAAiB,KAAK,CAAC,EACtJ,MAAM,IAAI,GAAG,uBAAuB,IAAI,KAAK,GAAG,GAAG,uBAAuB,SAAS,OAAO,GAAG,GAAG,uBAAuB,QAAQ,SAAS,CAAC,CAAC,EAC1I,IAAI;AACP,aAAO,OAAO,UAAU,IAAI,OAAO;AAAA,IACrC;AAAA;AAAA,IAGA,MAAM,iBAAiB,SAAS,OAAO;AACrC,YAAM,EAAE,OAAO,IAAI;AACnB,UAAI,OAAO,WAAW,EAAG,OAAM,IAAI,UAAU,oGAAoB;AACjE,YAAM,OAAO,oBAAI,IAAY;AAC7B,iBAAW,EAAE,UAAU,KAAK,QAAQ;AAClC,YAAI,UAAU,WAAW,EAAG,OAAM,IAAI,UAAU,4HAAwB;AACxE,mBAAW,EAAE,GAAG,KAAK,WAAW;AAC9B,cAAI,KAAK,IAAI,EAAE,EAAG,OAAM,IAAI,UAAU,wCAAU,EAAE,8HAA0B;AAC5E,eAAK,IAAI,EAAE;AAAA,QACb;AAAA,MACF;AACA,aAAO,GAAG,YAAY,CAAC,OAAO;AAC5B,cAAM,MAAM,GAAG,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,IAAI,GAAG,uBAAuB,IAAI,MAAM,KAAK,GAAG,GAAG,uBAAuB,SAAS,OAAO,CAAC,CAAC,EAAE,IAAI;AAC7J,YAAI,KAAK,WAAW,UAAW,QAAO;AAEtC,mBAAW,EAAE,UAAU,KAAK,QAAQ;AAClC,qBAAW,EAAE,IAAI,QAAQ,KAAK,WAAW;AACvC,kBAAM,WAAW,GAAG,OAAO,EAAE,SAAS,YAAY,QAAQ,CAAC,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,SAAS,EAAE,CAAC,EAAE,IAAI;AACjH,gBAAI,UAAU,YAAY,QAAS,QAAO;AAAA,UAC5C;AAAA,QACF;AACA,cAAM,MAAM,KAAK,IAAI;AACrB,cAAM,SAA6B,OAAO,IAAI,CAAC,EAAE,QAAQ,UAAU,MAAM;AACvE,gBAAM,UAAU,EAAE,IAAI,OAAO,WAAW,GAAG,SAAS,YAAY,OAAO,YAAY,SAAS,OAAO,SAAS,SAAS,GAAG,WAAW,KAAK,WAAW,IAAI;AACvJ,aAAG,OAAO,WAAW,EAAE,OAAO,OAAO,EAAE,IAAI;AAC3C,qBAAW,EAAE,GAAG,KAAK,UAAW,IAAG,OAAO,WAAW,EAAE,IAAI,EAAE,YAAY,QAAQ,GAAG,CAAC,EAAE,MAAM,UAAU,SAAS,EAAE,CAAC,EAAE,IAAI;AACzH,iBAAO,EAAE,UAAU,QAAQ,IAAI,aAAa,UAAU,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,eAAe,EAAE;AAAA,QAC9F,CAAC;AACD,cAAM,WAAW,EAAE,QAAQ,WAAoB,YAAY,KAAK,MAAM,MAAM,UAAU,GAAG,QAAQ,eAAe,MAAM,iBAAiB,KAAK;AAC5I,WAAG,OAAO,sBAAsB,EAAE,IAAI,QAAQ,EAAE,MAAM,GAAG,uBAAuB,IAAI,IAAI,EAAE,CAAC,EAAE,IAAI;AACjG,eAAO,kBAAkB,EAAE,GAAG,KAAK,GAAG,SAAS,CAAC;AAAA,MAClD,GAAG,EAAE,UAAU,YAAY,CAAC;AAAA,IAC9B;AAAA,IAEA,MAAM,kBAAkB,SAAS,OAAO,OAAO;AAC7C,aAAO,GAAG,YAAY,CAAC,OAAO;AAC5B,cAAM,MAAM,GAAG,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,IAAI,GAAG,uBAAuB,IAAI,KAAK,GAAG,GAAG,uBAAuB,SAAS,OAAO,CAAC,CAAC,EAAE,IAAI;AACvJ,YAAI,KAAK,WAAW,UAAW,QAAO;AACtC,mBAAW,EAAE,UAAU,aAAa,cAAc,KAAK,IAAI,QAAQ;AACjE,gBAAM,SAAS,GAAG,OAAO,EAAE,SAAS,YAAY,QAAQ,CAAC,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,SAAS,QAAQ,CAAC,EAAE,IAAI;AACrH,cAAI,QAAQ,YAAY,cAAe,QAAO;AAC9C,gBAAM,SAAS,GACZ,OAAO,EAAE,IAAI,YAAY,GAAG,CAAC,EAC7B,KAAK,WAAW,EAChB,MAAM,IAAI,GAAG,YAAY,SAAS,OAAO,GAAG,GAAG,YAAY,YAAY,QAAQ,GAAG,QAAQ,YAAY,IAAI,WAAW,CAAC,CAAC,EACvH,IAAI;AACP,cAAI,OAAO,WAAW,YAAY,OAAQ,QAAO;AAAA,QACnD;AACA,YAAI,OAAO;AACT,gBAAM,YAAY,IAAI,OAAO,IAAI,CAAC,EAAE,SAAS,MAAM,QAAQ;AAC3D,gBAAM,YAAY,aAAa,IAAI,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,UAAU,SAAS,KAAK,EAAE,CAAC;AACzF,gBAAM,WAAW,GACd,OAAO,EACP,KAAK,WAAW,EAChB,MAAM,IAAI,GAAG,YAAY,SAAS,OAAO,GAAG,QAAQ,YAAY,YAAY,SAAS,CAAC,CAAC,EACvF,QAAQ,KAAK,YAAY,SAAS,GAAG,KAAK,YAAY,SAAS,GAAG,KAAK,YAAY,EAAE,CAAC,EACtF,IAAI,EACJ,IAAI,YAAY;AACnB,gBAAM,QAAQ,MAAM,WAAW,QAAQ;AACvC,cAAI,MAAO,QAAO,cAAc,KAAK;AAAA,QACvC;AACA,mBAAW,EAAE,SAAS,KAAK,IAAI,QAAQ;AACrC,aAAG,OAAO,WAAW,EAAE,IAAI,EAAE,YAAY,KAAK,CAAC,EAAE,MAAM,IAAI,GAAG,YAAY,SAAS,OAAO,GAAG,GAAG,YAAY,YAAY,QAAQ,CAAC,CAAC,EAAE,IAAI;AACxI,aAAG,OAAO,WAAW,EAAE,MAAM,UAAU,SAAS,QAAQ,CAAC,EAAE,IAAI;AAAA,QACjE;AACA,WAAG,OAAO,sBAAsB,EAAE,IAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,MAAM,GAAG,uBAAuB,IAAI,IAAI,EAAE,CAAC,EAAE,IAAI;AAC/G,eAAO;AAAA,MACT,GAAG,EAAE,UAAU,YAAY,CAAC;AAAA,IAC9B;AAAA,IAEA,MAAM,2BAA2B,SAAS,QAAQ;AAChD,YAAM,OAAO,GACV,OAAO,EACP,KAAK,sBAAsB,EAC3B,MAAM,IAAI,GAAG,uBAAuB,SAAS,OAAO,GAAG,GAAI,QAAQ,SAAS,CAAC,QAAQ,uBAAuB,QAAQ,OAAO,MAAM,CAAC,IAAI,CAAC,CAAE,CAAC,EAC1I,QAAQ,KAAK,uBAAuB,SAAS,GAAGA,gBAAe,EAC/D,MAAM,QAAQ,SAAS,EAAE,EACzB,IAAI;AACP,aAAO,KAAK,IAAI,iBAAiB;AAAA,IACnC;AAAA,IAEA,MAAM,sBAAsB,SAAS;AACnC,YAAM,OAAO,GACV,OAAO,EACP,KAAK,WAAW,EAChB,MAAM,IAAI,GAAG,YAAY,SAAS,OAAO,GAAG,UAAU,YAAY,UAAU,CAAC,CAAC,EAC9E,QAAQ,KAAK,YAAY,SAAS,GAAG,KAAK,YAAY,SAAS,GAAG,KAAK,YAAY,EAAE,CAAC,EACtF,IAAI;AACP,aAAO,KAAK,IAAI,CAAC,SAA2B,EAAE,GAAG,aAAa,GAAG,GAAG,YAAY,IAAI,WAAY,EAAE;AAAA,IACpG;AAAA,IAEA,QAAQ;AACN,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AACF;AAGA,SAAS,QAAQ,MAAuC;AACtD,SAAO;AAAA,IACL,IAAI,KAAK;AAAA,IACT,SAAS,KAAK;AAAA,IACd,SAAS,KAAK;AAAA,IACd,YAAY,KAAK;AAAA,IACjB,WAAW,KAAK,aAAa;AAAA,IAC7B,OAAO,KAAK,SAAS;AAAA,IACrB,QAAQ,KAAK,UAAU;AAAA,IACvB,YAAY,KAAK,cAAc;AAAA,IAC/B,aAAa,gBAAgB,IAAI,KAAK;AAAA,IACtC,QAAQ,KAAK,UAAU;AAAA,IACvB,WAAW,KAAK;AAAA,IAChB,WAAW,KAAK;AAAA,EAClB;AACF;AAGA,SAAS,OAAO,KAAsC;AACpD,QAAM,EAAE,WAAW,OAAO,QAAQ,YAAY,aAAa,QAAQ,GAAG,KAAK,IAAI;AAC/E,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAI,cAAc,QAAQ,EAAE,UAAU;AAAA,IACtC,GAAI,UAAU,QAAQ,EAAE,MAAM;AAAA,IAC9B,GAAI,WAAW,QAAQ,EAAE,OAAO;AAAA,IAChC,GAAI,eAAe,QAAQ,EAAE,WAAW;AAAA,IACxC,GAAG,eAAe,WAAW;AAAA,IAC7B,GAAI,WAAW,QAAQ,EAAE,OAAO;AAAA,EAClC;AACF;AAGA,SAAS,iBAAiB,WAA8B,WAAW;AACjE,MAAI,aAAa,UAAW,QAAO;AACnC,SAAO,aAAa,SAAS,UAAU,MAAM,UAAU,IAAI,OAAO,MAAM,UAAU;AACpF;AAMA,SAAS,eAAe,QAAoC;AAC1D,SAAO,OAAO,QAAQ,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;AACxD,UAAM,QACJ,UAAU,OACNA,sBACA,OAAO,UAAU,WACfA,iCAAgC,KAAK,KACrC,OAAO,UAAU,YACfA,cAAa,QAAQ,SAAS,OAAO,KACrCA,+CAA8C,KAAK;AAC7D,WAAOA,uCAAsC,MAAM,WAAW,iBAAiB,GAAG,QAAQ,KAAK;AAAA,EACjG,CAAC;AACH;AAGA,SAAS,UAAU,KAAkD;AACnE,QAAM,EAAE,KAAK,MAAM,SAAS,UAAU,WAAW,GAAG,QAAQ,IAAI;AAChE,SAAO,EAAE,GAAG,SAAS,GAAI,cAAc,QAAQ,EAAE,UAAU,EAAG;AAChE;AAGA,SAAS,UAAU,SAAiB,IAAY;AAC9C,SAAO,IAAI,GAAG,YAAY,SAAS,OAAO,GAAG,GAAG,YAAY,IAAI,EAAE,GAAG,OAAO,YAAY,UAAU,CAAC;AACrG;AAGA,SAAS,kBAAkB,KAAwE;AACjG,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,WAAW,IAAI,KAAK,IAAI,SAAS,EAAE,YAAY;AAAA,IAC/C,YAAY,IAAI,eAAe,OAAO,OAAO,IAAI,KAAK,IAAI,UAAU,EAAE,YAAY;AAAA,IAClF,QAAQ,IAAI;AAAA,IACZ,QAAQ,IAAI,OAAO,IAAI,CAAC,WAAW,EAAE,GAAG,OAAO,aAAa,CAAC,GAAG,MAAM,WAAW,EAAE,EAAE;AAAA,IACrF,OAAO,IAAI;AAAA,IACX,eAAe,IAAI;AAAA,EACrB;AACF;AAGA,SAAS,aAAa,KAAkD;AACtE,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,YAAY,CAAC,GAAG,IAAI,UAAU;AAAA,IAC9B,SAAS,IAAI;AAAA,IACb,SAAS,IAAI;AAAA,IACb,WAAW,IAAI,KAAK,IAAI,SAAS,EAAE,YAAY;AAAA,IAC/C,WAAW,IAAI,KAAK,IAAI,SAAS,EAAE,YAAY;AAAA,EACjD;AACF;AAGA,SAAS,kBAAkB,OAAyB;AAClD,QAAM,EAAE,MAAM,SAAS,MAAM,IAAK,SAAS,CAAC;AAC5C,SACE,CAAC,MAAM,OAAO,IAAI,EAAE,SAAS,0BAA0B,KACvD,CAAC,SAAS,OAAO,OAAO,EAAE,KAAK,CAACE,UAAS,OAAOA,UAAS,YAAYA,MAAK,SAAS,mBAAmB,CAAC;AAE3G;AAEA,SAAS,qBAAqB,OAAyB;AACrD,QAAM,EAAE,MAAM,MAAM,IAAK,SAAS,CAAC;AACnC,SAAO,CAAC,MAAM,OAAO,IAAI,EAAE,SAAS,8BAA8B;AACpE;","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 ChatTurnLeaseLostError,\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 function assertTurnHolder(tx: Pick<typeof db, \"select\">, chatId: string, holder: string | undefined, messageId: string): void {\n if (holder === undefined) return;\n const row = tx.select({ chatId: chatTurnLeases.chatId }).from(chatTurnLeases)\n .where(and(eq(chatTurnLeases.chatId, chatId), eq(chatTurnLeases.holder, holder), sql`${chatTurnLeases.until} > ${Date.now()}`)).get();\n if (!row) throw new ChatTurnLeaseLostError(messageId);\n }\n\n /** Проверка владельца входит в ту же атомарную запись SQLite. */\n function turnLeaseCondition(holder: string | undefined) {\n if (holder === undefined) return undefined;\n return sql`exists (select 1 from ${chatTurnLeases} where ${chatTurnLeases.chatId} = ${messages.chatId} and ${chatTurnLeases.holder} = ${holder} and ${chatTurnLeases.until} > ${Date.now()})`;\n }\n\n /** Пишет в идущий ответ; отличает «нет такого» от «уже в конечном состоянии». */\n function updateStreaming(messageId: string, { alive, expectedTurnHolder, ...values }: Partial<typeof messages.$inferInsert> & { alive?: AnswerAliveMark; expectedTurnHolder?: string }): void {\n const result = db\n .update(messages)\n .set({ ...values, ...aliveAtColumn(alive) })\n .where(and(eq(messages.id, messageId), eq(messages.status, \"streaming\"), turnLeaseCondition(expectedTurnHolder)))\n .run();\n if (result.changes > 0) return;\n const existing = db.select({ id: messages.id, status: messages.status }).from(messages).where(eq(messages.id, messageId)).get();\n if (!existing) throw new Error(`Сообщения ${messageId} нет`);\n if (expectedTurnHolder !== undefined && existing.status === \"streaming\") throw new ChatTurnLeaseLostError(messageId);\n throw new MessageAlreadyFinishedError(messageId);\n }\n\n return {\n guardedTurnWrites: true,\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, guard) {\n try {\n db.transaction((tx) => {\n assertTurnHolder(tx, message.chatId, guard?.expectedTurnHolder, message.id);\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, guard) => updateStreaming(messageId, { alive: \"now\", ...guard }),\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, chatId: messages.chatId }).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 assertTurnHolder(tx, existing.chatId, patch.expectedTurnHolder, 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ykurilov/agent-chat-storage-sqlite",
3
- "version": "0.82.1",
3
+ "version": "0.83.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.82.1"
35
+ "@ykurilov/agent-chat-core": "0.83.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/better-sqlite3": "^9.6.0",