@ykurilov/agent-chat-core 0.58.0 → 0.59.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/dist/index.js CHANGED
@@ -28,6 +28,7 @@ import {
28
28
  CHAT_CLOSED_PART_TYPE,
29
29
  CHAT_DATA_MAX_BYTES,
30
30
  CLOSED_STATE_KEY,
31
+ CORE_SERVICE_BLOCKS,
31
32
  CURRENT_FORMAT_VERSION,
32
33
  ChatAlreadyExistsError,
33
34
  ChatBusyError,
@@ -101,6 +102,7 @@ import {
101
102
  chatDataMatches,
102
103
  chatDataOfInput,
103
104
  chatHasExternalContent,
105
+ checkServiceBlockFormats,
104
106
  costOfUsage,
105
107
  createAppStateWriter,
106
108
  createChatEvents,
@@ -112,6 +114,7 @@ import {
112
114
  createTogetherProvider,
113
115
  currentChildOf,
114
116
  cutAtCharBoundary,
117
+ cutForgedBlocks,
115
118
  declareToolTimeout,
116
119
  defineWidget,
117
120
  deliverableParts,
@@ -152,6 +155,7 @@ import {
152
155
  sameVoiceTagSet,
153
156
  scrubSecrets,
154
157
  selectCurrentBranch,
158
+ serviceBlockName,
155
159
  silenceBoundaryByLocalClock,
156
160
  soundsOfMessage,
157
161
  splitVoiceTags,
@@ -168,7 +172,7 @@ import {
168
172
  withoutFileParts,
169
173
  withoutGlueFragments,
170
174
  withoutResetSteps
171
- } from "./chunk-KAG3QTZC.js";
175
+ } from "./chunk-QA5DVEXF.js";
172
176
  import {
173
177
  APP_EVENT_DATA_MAX_BYTES,
174
178
  APP_EVENT_TYPE_MAX_LENGTH,
@@ -891,6 +895,7 @@ export {
891
895
  CHAT_CLOSED_PART_TYPE,
892
896
  CHAT_DATA_MAX_BYTES,
893
897
  CLOSED_STATE_KEY,
898
+ CORE_SERVICE_BLOCKS,
894
899
  CURRENT_FORMAT_VERSION,
895
900
  ChatAlreadyExistsError,
896
901
  ChatBusyError,
@@ -968,6 +973,7 @@ export {
968
973
  chatDataMatches,
969
974
  chatDataOfInput,
970
975
  chatHasExternalContent,
976
+ checkServiceBlockFormats,
971
977
  costOfUsage,
972
978
  createAppStateWriter,
973
979
  createChatEvents,
@@ -981,6 +987,7 @@ export {
981
987
  createTogetherProvider,
982
988
  currentChildOf,
983
989
  cutAtCharBoundary,
990
+ cutForgedBlocks,
984
991
  declareToolTimeout,
985
992
  defineWidget,
986
993
  deliverableParts,
@@ -1029,6 +1036,7 @@ export {
1029
1036
  sameVoiceTagSet,
1030
1037
  scrubSecrets,
1031
1038
  selectCurrentBranch,
1039
+ serviceBlockName,
1032
1040
  silenceBoundaryByLocalClock,
1033
1041
  soundsOfMessage,
1034
1042
  splitVoiceTags,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/memory/memory-optimization.ts","../src/storage/postgres-migrations.ts","../src/request-origin/request-origin.ts","../src/storage/in-memory-storage.ts"],"sourcesContent":["import type { MemoryError, MemoryNote, MemoryNoteInput } from \"./long-term-memory\";\n\n/**\n * Состояние запуска оптимизации дублей: идёт → слито / нечего сливать / не удалось; слитое можно вернуть (`reverted`).\n * Запуск `running` у человека не больше одного.\n */\nexport type MemoryOptimizationStatus = \"running\" | \"applied\" | \"no_changes\" | \"failed\" | \"reverted\";\n\n/** Одна склейка: записи `originalIds` скрыты и подчинены новой записи `resultId`. */\nexport interface MemoryMergeGroup {\n resultId: string;\n originalIds: string[];\n /** Версия результата на момент слияния: пока она та же, результат не менялся и слияние можно вернуть. */\n resultVersion: number;\n}\n\n/** Запуск оптимизации. Владелец (`ownerId`) — свойство хранилища и наружу не выдаётся. */\nexport interface MemoryOptimizationRun {\n id: string;\n /** Время в формате ISO 8601. Часы даёт вызывающий: от них считаются срок между запусками и пауза после сбоя. */\n startedAt: string;\n finishedAt: string | null;\n status: MemoryOptimizationStatus;\n /** Склейки запуска; у не слитых запусков пусто. */\n groups: MemoryMergeGroup[];\n /** Причина сбоя одним словом-кодом; у остальных `null`. */\n error: string | null;\n /** Запись расхода модели, если вызывающий её знает. */\n usageRecordId: string | null;\n}\n\n/** Правила запуска: их проверяет хранилище в той же операции, что и берёт запуск, чтобы два процесса не начали его вдвоём. */\nexport interface MemoryOptimizationRules {\n /** Сколько должно пройти после законченного запуска (слито, нечего сливать, отменено) до следующего. */\n minIntervalMs: number;\n /**\n * Сколько должно пройти после неудачного запуска до повтора. Число — одна пауза на все неудачи; список — паузы после\n * 1-й, 2-й, … неудачи подряд (последняя держится дальше). Успешный, пустой или отменённый запуск начинает счёт заново.\n */\n retryAfterFailureMs: number | readonly number[];\n /** Сколько запуск `running` считается живым; после этого срока он становится неудачным (`failed`, ошибка `lease_expired`). */\n leaseMs: number;\n}\n\n/** Чем закончился запуск без слияния. */\nexport interface MemoryOptimizationOutcome {\n status: \"no_changes\" | \"failed\";\n finishedAt: string;\n error?: string | null;\n usageRecordId?: string | null;\n}\n\n/** Что слить: новая запись-результат вместо оригиналов; версии оригиналов — те, что видел планировщик. */\nexport interface MemoryMergeInput {\n runId: string;\n finishedAt: string;\n usageRecordId?: string | null;\n merges: { result: MemoryNoteInput; originals: { id: string; version: number }[] }[];\n}\n\n/** Скрытая запись слияния: оригинал, подчинённый результату. Список, блок памяти и поиск таких записей не видят. */\nexport interface MergedMemoryNote extends MemoryNote {\n mergedInto: string;\n}\n\nexport type MemoryMergeApplyResult = MemoryOptimizationRun | \"stale_version\" | \"run_not_active\";\n/** `limit_reached` и `duplicate` — возврат вышел бы за пределы памяти или вернул бы повтор записи, сделанной за это время. */\nexport type MemoryMergeRevertResult = \"ok\" | \"not_found\" | \"conflict\" | \"limit_reached\" | \"duplicate\";\n\n/** Запуск в том виде, что нужен для решения «можно ли начать новый»; время — миллисекунды. */\nexport interface OptimizationRunTiming {\n status: MemoryOptimizationStatus;\n startedAtMs: number;\n /** Конец запуска; у идущего его нет. */\n endedAtMs: number | null;\n}\n\n/** Пауза после неудачи с номером `failuresInRow` (с 1) подряд. */\nexport function pauseAfterFailure(rules: Pick<MemoryOptimizationRules, \"retryAfterFailureMs\">, failuresInRow: number): number {\n const { retryAfterFailureMs } = rules;\n if (typeof retryAfterFailureMs === \"number\") return retryAfterFailureMs;\n return retryAfterFailureMs[Math.min(failuresInRow, retryAfterFailureMs.length) - 1] ?? 0;\n}\n\n/**\n * Мешает ли история запусков начать новый: идёт другой, или не вышла пауза после последнего. Пауза после неудачи\n * растёт с числом неудач подряд. Все три хранилища решают этим одним правилом.\n */\nexport function isOptimizationBlocked(runs: readonly OptimizationRunTiming[], rules: MemoryOptimizationRules, nowMs: number): boolean {\n const ordered = [...runs].sort((left, right) => left.startedAtMs - right.startedAtMs);\n let failuresInRow = 0;\n for (const run of ordered) {\n if (run.status === \"running\") return true;\n failuresInRow = run.status === \"failed\" ? failuresInRow + 1 : 0;\n const pause = run.status === \"failed\" ? pauseAfterFailure(rules, failuresInRow) : rules.minIntervalMs;\n if (nowMs - (run.endedAtMs ?? run.startedAtMs) < pause) return true;\n }\n return false;\n}\n\n/** Ответ отката слияния на ошибку проверки: повтор записи — `duplicate`, всё остальное (число, объём) — `limit_reached`. */\nexport function revertRefusal(error: MemoryError): \"limit_reached\" | \"duplicate\" {\n return error.kind === \"duplicate\" ? \"duplicate\" : \"limit_reached\";\n}\n","/** Соединение PostgreSQL, которое нужно помощнику миграций. Подходит `PoolClient` из `pg`: core от `pg` не зависит. */\nexport interface PostgresMigrationConnection {\n query(text: string, values?: unknown[]): Promise<{ rows: unknown[] }>;\n release(): void;\n}\n\nexport interface PostgresMigrationOptions<Connection extends PostgresMigrationConnection> {\n /** Новое соединение из пула, например `() => pool.connect()`; на каждую попытку — своё. */\n connect(): Promise<Connection>;\n /** Своя блокировка пакета: одновременно мигрирует только одна копия этого пакета. */\n lockKey: number;\n /** Миграции пакета на этом соединении, например `migrate(drizzle(connection), …)`. */\n migrate(connection: Connection): Promise<void>;\n /** Паузы перед повторами, если всё же столкнулись с соседом. */\n retryDelaysMs?: readonly number[];\n}\n\n/** Схема всех пакетов SDK. */\nexport const AGENT_CHAT_SCHEMA = \"agent_chat\";\n\n/** Общая блокировка на создание схемы: одна на все пакеты, держится только на `create schema`. */\nexport const AGENT_CHAT_SCHEMA_LOCK_KEY = 7_311_900_441;\n\nconst DEFAULT_RETRY_DELAYS_MS = [25, 50, 100, 200];\n\n/** Коды PostgreSQL «такое уже есть»: сосед создал то же самое одновременно с нами. */\nconst DUPLICATE_CODES = new Set([\"23505\", \"42P06\", \"42P07\", \"42710\"]);\n\n/**\n * Создаёт схему `agent_chat` и применяет миграции пакета так, чтобы пакеты могли стартовать одновременно на пустой базе.\n * Схема создаётся под общей блокировкой, затем она отпускается и берётся своя блокировка пакета: блокировки не\n * вложены, поэтому взаимной блокировки нет, а разные пакеты ждут друг друга только на создании схемы.\n * Столкнулись всё же («уже есть») — повтор с начала на новом соединении.\n */\nexport async function migratePostgresSchema<Connection extends PostgresMigrationConnection>(options: PostgresMigrationOptions<Connection>): Promise<void> {\n const delays = options.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS;\n for (let attempt = 0; ; attempt++) {\n try {\n return await migrateOnce(options);\n } catch (error) {\n if (attempt >= delays.length || !isDuplicateError(error)) throw error;\n await new Promise((resolve) => setTimeout(resolve, delays[attempt]));\n }\n }\n}\n\nasync function migrateOnce<Connection extends PostgresMigrationConnection>(options: PostgresMigrationOptions<Connection>): Promise<void> {\n const connection = await options.connect();\n try {\n if (!(await schemaExists(connection))) {\n await underLock(connection, AGENT_CHAT_SCHEMA_LOCK_KEY, () => connection.query(`create schema if not exists \"${AGENT_CHAT_SCHEMA}\"`));\n }\n await underLock(connection, options.lockKey, () => options.migrate(connection));\n } finally {\n connection.release();\n }\n}\n\nasync function schemaExists(connection: PostgresMigrationConnection): Promise<boolean> {\n const result = await connection.query(\"select 1 from pg_namespace where nspname = $1\", [AGENT_CHAT_SCHEMA]);\n return result.rows.length > 0;\n}\n\nasync function underLock(connection: PostgresMigrationConnection, key: number, work: () => Promise<unknown>): Promise<void> {\n await connection.query(\"select pg_advisory_lock($1)\", [key]);\n try {\n await work();\n } finally {\n await connection.query(\"select pg_advisory_unlock($1)\", [key]);\n }\n}\n\n/** Ошибка «уже есть» — у самой ошибки или в цепочке причин (drizzle заворачивает ошибку `pg` в свою). */\nfunction isDuplicateError(error: unknown): boolean {\n for (let current = error, depth = 0; current && depth < 5; current = (current as { cause?: unknown }).cause, depth++) {\n const code = (current as { code?: unknown }).code;\n if (typeof code === \"string\" && DUPLICATE_CODES.has(code)) return true;\n }\n return false;\n}\n","/**\n * Защита от запросов с чужих страниц. Браузер сам прикладывает к запросу куки человека, даже если запрос\n * отправила чужая страница (обычная HTML-форма, WebSocket). Отличить свою страницу от чужой помогают заголовки,\n * которые ставит только браузер: `Sec-Fetch-Site` и `Origin`. Порядок проверки как в Go 1.25 (CrossOriginProtection).\n */\n\nexport interface RequestOriginCheckOptions {\n /**\n * Чужие страницы, которым можно слать запросы с куками человека, например `[\"https://school.getcourse.ru\"]`\n * (схема, хост, порт). Шаблон `https://*.example.com` пускает все поддомены `example.com`, но не сам домен\n * и не `evil-example.com`. Свой сайт в список вносить не нужно.\n */\n allowedOrigins?: readonly string[] | undefined;\n /** Отказ: вызывается один раз на каждый новый адрес страницы, чтобы журнал не забивался. */\n onRefused?: (refusal: OriginRefusal) => void;\n}\n\n/**\n * Почему запрос отклонён. `cross_site` — браузер сам сказал, что страница чужая. `host_mismatch` — браузер старый\n * или адрес не https, и Origin не совпал ни с одним именем сервера (`hosts`): так бывает за прокси, который подменил Host.\n */\nexport type OriginRefusal = { origin: string; reason: \"cross_site\" } | { origin: string; reason: \"host_mismatch\"; hosts: string[] };\n\n/** Подсказка для журнала: что поправить, если отклонена своя страница. */\nexport function originRefusalHint(refusal: OriginRefusal): string {\n if (refusal.reason === \"host_mismatch\") {\n return (\n `отклонён запрос со страницы ${refusal.origin}: Origin не совпал с Host (${refusal.hosts.join(\", \")}). ` +\n \"Если сервер за прокси, за прокси передайте Host/X-Forwarded-Host (nginx: proxy_set_header Host $host; \" +\n \"proxy_set_header X-Forwarded-Host $host;). Если это чужая для сервера, но ваша страница, добавьте её адрес в allowedOrigins.\"\n );\n }\n return `отклонён запрос с чужой страницы ${refusal.origin}. Если это ваша страница, добавьте её адрес в allowedOrigins.`;\n}\n\n/** `true` — запрос со своей страницы, со страницы из списка или не из браузера. Метод запроса не смотрит. */\nexport type RequestOriginCheck = (request: Request) => boolean;\n\n/** Чтения (GET, HEAD, OPTIONS) не меняют данных: их ответ браузер чужой странице всё равно не покажет. */\nexport function isSafeMethod(method: string): boolean {\n const upper = method.toUpperCase();\n return upper === \"GET\" || upper === \"HEAD\" || upper === \"OPTIONS\";\n}\n\n/** Сколько разных отклонённых адресов запоминается для журнала. */\nconst MAX_REPORTED_ORIGINS = 100;\nconst MAX_REPORTED_LENGTH = 200;\n\nexport function createRequestOriginCheck(options: RequestOriginCheckOptions = {}): RequestOriginCheck {\n const isAllowed = allowedOriginsMatcher(options.allowedOrigins ?? []);\n const reported = new Set<string>();\n const refuse = (refusal: OriginRefusal): false => {\n const shown = refusal.origin.slice(0, MAX_REPORTED_LENGTH);\n if (options.onRefused && !reported.has(shown) && reported.size < MAX_REPORTED_ORIGINS) {\n reported.add(shown);\n options.onRefused({ ...refusal, origin: shown });\n }\n return false;\n };\n return (request) => {\n const origin = request.headers.get(\"origin\");\n if (origin !== null && isAllowed(origin)) return true;\n const site = request.headers.get(\"sec-fetch-site\");\n if (site !== null) {\n if (site === \"same-origin\" || site === \"none\") return true;\n return refuse({ origin: origin ?? `(без Origin, Sec-Fetch-Site: ${site})`, reason: \"cross_site\" });\n }\n // Нет ни того ни другого — не браузер (сервер, curl): куки человека чужая страница так не приложит.\n if (origin === null) return true;\n // Старый браузер без Sec-Fetch-Site: Origin должен совпасть с адресом самого сервера.\n const host = originHost(origin);\n const hosts = hostsOf(request);\n if (host !== null && hosts.has(host)) return true;\n return refuse({ origin, reason: \"host_mismatch\", hosts: [...hosts] });\n };\n}\n\n/** Метка вместо `*`: адрес с ней разбирает URL, а в настоящем имени хоста она не встречается. */\nconst WILDCARD_LABEL = \"wildcard-label-0\";\n\n/** Точные адреса и шаблоны поддоменов из `allowedOrigins`; неверная запись — ошибка сразу. */\nfunction allowedOriginsMatcher(entries: readonly string[]): (origin: string) => boolean {\n const exact = new Set<string>();\n const subdomainsOf: Array<{ protocol: string; port: string; suffix: string }> = [];\n for (const entry of entries) {\n const wildcard = /^(https?:\\/\\/)\\*\\.([^*]+)$/.exec(entry);\n const url = parsePageAddress(wildcard ? `${wildcard[1]}${WILDCARD_LABEL}.${wildcard[2]}` : entry);\n if (url === null || (!wildcard && entry.includes(\"*\"))) throw wrongEntry(entry);\n if (!wildcard) {\n exact.add(url.origin);\n continue;\n }\n const suffix = url.hostname.slice(WILDCARD_LABEL.length);\n // `*.com` пустил бы весь интернет: после звёздочки нужен домен хотя бы из двух частей (или localhost).\n // Точка в конце (`*.com.`) — тот же `*.com`. Общие суффиксы вроде `*.co.uk` так не отличить: вписывают свой домен.\n const tooBroad = suffix.endsWith(\".\") || (!suffix.slice(1).includes(\".\") && suffix !== \".localhost\");\n if (!url.hostname.startsWith(`${WILDCARD_LABEL}.`) || tooBroad) throw wrongEntry(entry);\n subdomainsOf.push({ protocol: url.protocol, port: url.port, suffix });\n }\n return (origin) => {\n const url = parseOrigin(origin);\n if (url === null) return false;\n if (exact.has(url.origin)) return true;\n return subdomainsOf.some(\n (pattern) =>\n url.protocol === pattern.protocol && url.port === pattern.port && url.hostname.endsWith(pattern.suffix) && url.hostname.length > pattern.suffix.length,\n );\n };\n}\n\n/** Адрес страницы: http(s), без пути, запроса, якоря и имени пользователя. Иначе `null`. */\nfunction parsePageAddress(entry: string): URL | null {\n try {\n const url = new URL(entry);\n const bare = url.pathname === \"/\" && !url.search && !url.hash && !url.username;\n return (url.protocol === \"http:\" || url.protocol === \"https:\") && bare ? url : null;\n } catch {\n return null;\n }\n}\n\nfunction wrongEntry(entry: string): Error {\n return new Error(\n `allowedOrigins: «${entry}» не адрес страницы; нужен вид https://app.example, http://localhost:5173 или https://*.example.com ` +\n \"(в шаблоне — свой домен: общие суффиксы вроде *.co.uk проверка не распознаёт)\",\n );\n}\n\nfunction parseOrigin(origin: string): URL | null {\n try {\n return new URL(origin);\n } catch {\n return null;\n }\n}\n\n/** Хост с портом из Origin; `null` и не адрес — `null`. */\nfunction originHost(origin: string): string | null {\n try {\n const url = new URL(origin);\n return url.protocol === \"http:\" || url.protocol === \"https:\" ? url.host : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Под какими именами сервер знает себя: `Host` и `X-Forwarded-Host` от прокси. Адрес запроса — только без `Host`:\n * при подъёме WebSocket в Node (`@hono/node-ws`) он собран как `http://localhost/…` и порта в нём нет.\n */\nfunction hostsOf(request: Request): Set<string> {\n const host = request.headers.get(\"host\");\n const hosts = new Set<string>([host ? host.trim().toLowerCase() : new URL(request.url).host]);\n for (const forwarded of request.headers.get(\"x-forwarded-host\")?.split(\",\") ?? []) {\n if (forwarded.trim()) hosts.add(forwarded.trim().toLowerCase());\n }\n return hosts;\n}\n","import type { ModelChoice } from \"../models/model-choice\";\nimport type { MemoryNote, MemoryNoteInput } from \"../memory/long-term-memory\";\nimport { isOptimizationBlocked, revertRefusal } from \"../memory/memory-optimization\";\nimport type { MemoryMergeGroup, MemoryOptimizationRun, MergedMemoryNote } from \"../memory/memory-optimization\";\nimport type { Chat, StoredBranchSelection, StoredCompaction, StoredMessage, UsageRecord, UsageSum } from \"../conversation/types\";\nimport {\n aliveAtByLocalClock,\n assertKnownFormatVersion,\n ChatAlreadyExistsError,\n DuplicateChatSubjectError,\n DuplicateMessageError,\n MessageAlreadyFinishedError,\n MessageNotAwaitingError,\n sameMessageParts,\n silenceBoundaryByLocalClock,\n} from \"./chat-storage\";\nimport { assertChatDataFilter, chatDataFields, chatDataMatches, chatDataOfInput, mergeChatData } from \"./chat-data\";\nimport type { ChatListOptions, ChatStorage, ChatSubjectFilter, SpendingLimitStateRecord, StoredPendingBurst } from \"./chat-storage\";\n\n/** Хранилище в памяти процесса — для тестов. Копирует данные на входе и выходе, как база. */\ntype StoredNote = MemoryNote & { mergedInto?: string };\n\n/** Сумма записей расхода по ключу (`group` — поля ключа: пара «модель × провайдер», у суммы по чатам — ещё чат). */\nfunction sumRecords<K extends Pick<UsageSum, \"modelId\" | \"providerId\">>(records: readonly UsageRecord[], group: (record: UsageRecord) => K): Array<K & UsageSum> {\n const sums = new Map<string, K & UsageSum>();\n for (const record of records) {\n const fields = group(record);\n const key = Object.values(fields).join(\"\\u0000\");\n const sum = sums.get(key) ?? { ...fields, inputTokens: 0, cachedInputTokens: 0, cacheWriteTokens: 0, outputTokens: 0, reasoningTokens: 0, costUsd: 0 };\n sum.inputTokens += record.inputTokens;\n sum.cachedInputTokens += record.cachedInputTokens;\n sum.cacheWriteTokens += record.cacheWriteTokens;\n sum.outputTokens += record.outputTokens;\n sum.reasoningTokens += record.reasoningTokens;\n sum.costUsd += record.costUsd;\n sums.set(key, sum);\n }\n return [...sums.values()];\n}\n\nexport function createInMemoryChatStorage(): ChatStorage {\n const chats = new Map<string, Chat>();\n const messages = new Map<string, StoredMessage>();\n /** Время последнего знака жизни идущих ответов по id: при чтении не отдаётся. */\n const aliveAt = new Map<string, string>();\n /** Аренды хода по чатам: кто держит и до какого времени (мс по часам этой машины). */\n const turnLeases = new Map<string, { holder: string; until: number }>();\n /** Ждущие пачки по чатам. */\n const pendingBursts = new Map<string, StoredPendingBurst>();\n const compactions: StoredCompaction[] = [];\n const branchSelections: StoredBranchSelection[] = [];\n const usageRecords: UsageRecord[] = [];\n const userModelChoices = new Map<string, ModelChoice>();\n const voiceChoices = new Map<string, string>();\n const spendingLimitStates = new Map<string, SpendingLimitStateRecord>();\n /** Долгая память: у каждого человека свои записи; у скрытых оригиналов слияния есть `mergedInto`. */\n const memoryNotes = new Map<string, Map<string, StoredNote>>();\n const optimizationRuns = new Map<string, MemoryOptimizationRun[]>();\n\n function streamingMessage(messageId: string): StoredMessage {\n const message = messages.get(messageId);\n if (!message) throw new Error(`Сообщения ${messageId} нет`);\n if (message.status !== \"streaming\") throw new MessageAlreadyFinishedError(messageId);\n return message;\n }\n\n /** Сообщение для чтения: копия, `voiceCut` — `null`, если не задан. */\n function readable(message: StoredMessage): StoredMessage {\n const copy = structuredClone(message);\n return { ...copy, voiceCut: copy.voiceCut ?? null };\n }\n\n function ownerNotes(ownerId: string): Map<string, StoredNote> {\n let notes = memoryNotes.get(ownerId);\n if (!notes) {\n notes = new Map();\n memoryNotes.set(ownerId, notes);\n }\n return notes;\n }\n\n function ownerRuns(ownerId: string): MemoryOptimizationRun[] {\n let runs = optimizationRuns.get(ownerId);\n if (!runs) {\n runs = [];\n optimizationRuns.set(ownerId, runs);\n }\n return runs;\n }\n\n /** Порядок списка по договору: `updatedAt`, затем `createdAt`, затем `id` — новее и больше первыми. */\n function newestFirst<T extends MemoryNote>(notes: T[]): T[] {\n return notes.sort(\n (left, right) =>\n right.updatedAt.localeCompare(left.updatedAt) ||\n right.createdAt.localeCompare(left.createdAt) ||\n (right.id > left.id ? 1 : right.id < left.id ? -1 : 0),\n );\n }\n\n /** Обычная запись без служебного признака скрытия. */\n function publicNote({ mergedInto: _hidden, ...note }: StoredNote): MemoryNote {\n return note;\n }\n\n /** Как база с NOT NULL: разделы — список строк, текст — строка. */\n function assertWellFormedNote(note: MemoryNoteInput): void {\n if (!Array.isArray(note?.categories) || !note.categories.every((category) => typeof category === \"string\")) {\n throw new TypeError(\"Разделы записи памяти — список строк\");\n }\n if (typeof note.content !== \"string\") throw new TypeError(\"Текст записи памяти — строка\");\n }\n\n /** Записи, которые видит человек: без скрытых оригиналов, копиями. */\n function visibleNotes(ownerId: string): MemoryNote[] {\n const visible = [...ownerNotes(ownerId).values()].filter((note) => !note.mergedInto);\n return structuredClone(newestFirst(visible).map(publicNote));\n }\n\n function insertNotes(ownerId: string, inputs: MemoryNoteInput[]): MemoryNote[] {\n // Сначала проверяем весь пакет: негодная запись не оставляет в памяти и остальных.\n inputs.forEach(assertWellFormedNote);\n const now = new Date().toISOString();\n const created = inputs.map(\n ({ categories, content }): MemoryNote => ({\n id: crypto.randomUUID(),\n categories: [...categories],\n content,\n version: 1,\n createdAt: now,\n updatedAt: now,\n }),\n );\n const notes = ownerNotes(ownerId);\n for (const note of created) notes.set(note.id, note);\n return structuredClone(created);\n }\n\n function updateNote(ownerId: string, id: string, expectedVersion: number, input: MemoryNoteInput): MemoryNote | \"not_found\" | \"stale_version\" {\n assertWellFormedNote(input);\n const notes = ownerNotes(ownerId);\n const note = notes.get(id);\n if (!note || note.mergedInto) return \"not_found\";\n if (note.version !== expectedVersion) return \"stale_version\";\n const updated: MemoryNote = {\n ...note,\n categories: [...input.categories],\n content: input.content,\n version: note.version + 1,\n updatedAt: new Date().toISOString(),\n };\n notes.set(id, updated);\n return structuredClone(updated);\n }\n\n /** Как уникальный индекс (владелец, ключ): чат без ключа не мешает никому. */\n function assertSubjectFree(chat: Pick<Chat, \"ownerId\" | \"subjectKey\">): void {\n if (chat.subjectKey === undefined) return;\n for (const existing of chats.values()) {\n if (existing.ownerId === chat.ownerId && existing.subjectKey === chat.subjectKey) {\n throw new DuplicateChatSubjectError(chat.ownerId, chat.subjectKey);\n }\n }\n }\n\n function sortedMessages(chatId: string): StoredMessage[] {\n return [...messages.values()]\n .filter((message) => message.chatId === chatId)\n .sort((left, right) => left.createdAt.localeCompare(right.createdAt));\n }\n\n return {\n async createChat({ createdAt, ...input }) {\n const at = createdAt ?? new Date().toISOString();\n const chat: Chat = withChatData(withoutUndefined({ ...structuredClone(input), createdAt: at, updatedAt: at }));\n assertSubjectFree(chat);\n chats.set(chat.id, chat);\n return structuredClone(chat);\n },\n\n async findChatBySubject(ownerId, subjectKey) {\n const chat = [...chats.values()].find((existing) => existing.ownerId === ownerId && existing.subjectKey === subjectKey);\n return chat ? structuredClone(chat) : null;\n },\n\n async importChat(input, imported) {\n // Сначала все проверки: при ошибке ничего не записано.\n if (chats.has(input.id)) throw new ChatAlreadyExistsError(input.id);\n const chat: Chat = withChatData(withoutUndefined(structuredClone(input)));\n assertSubjectFree(chat);\n const ids = new Set<string>();\n for (const message of imported) {\n if (messages.has(message.id) || ids.has(message.id)) throw new DuplicateMessageError(message.id);\n ids.add(message.id);\n }\n chats.set(chat.id, chat);\n for (const message of imported) {\n const { alive: _alive, ...stored } = message;\n messages.set(message.id, structuredClone(stored));\n }\n },\n\n async setAfterTurnState(messageId, state, options) {\n const message = messages.get(messageId);\n if (!message || (state !== \"pending\" && message.afterTurn !== \"pending\")) return false;\n const parts = options?.appendParts ? [...message.parts, ...structuredClone(options.appendParts)] : message.parts;\n messages.set(messageId, { ...message, parts, afterTurn: state });\n // Отметка ожидания хука — в той же колонке, что знак жизни: у законченного ответа она больше ни для чего.\n if (state === \"pending\") aliveAt.set(messageId, aliveAtByLocalClock(\"now\"));\n return true;\n },\n\n async listPendingAfterTurn(filter) {\n const boundary = filter?.pendingForMs === undefined ? null : silenceBoundaryByLocalClock(filter.pendingForMs);\n return [...messages.values()]\n .filter((message) => message.afterTurn === \"pending\")\n .filter((message) => boundary === null || (aliveAt.get(message.id) ?? message.createdAt) < boundary)\n .map((message) => message.id);\n },\n\n async getChat(chatId) {\n const chat = chats.get(chatId);\n return chat ? structuredClone(chat) : null;\n },\n\n async updateChatModel(chatId, model) {\n const chat = chats.get(chatId);\n if (!chat) return;\n const { reasoning: _dropped, ...rest } = chat;\n chats.set(chatId, { ...rest, ...model });\n },\n\n async listChats(ownerId, options?: ChatListOptions) {\n if (options?.data) assertChatDataFilter(options.data);\n const owned = [...chats.values()].filter(\n (chat) => chat.ownerId === ownerId && matchesSubjects(chat, options?.subjects) && (!options?.data || chatDataMatches(chat.data, options.data)),\n );\n owned.sort(\n (left, right) =>\n right.updatedAt.localeCompare(left.updatedAt) ||\n right.createdAt.localeCompare(left.createdAt) ||\n (right.id > left.id ? 1 : right.id < left.id ? -1 : 0),\n );\n return structuredClone(owned);\n },\n\n async updateChatData(chatId, patch, { maxBytes }) {\n const chat = chats.get(chatId);\n if (!chat) return null;\n // Слияние и проверка размера до записи: при ошибке данные прежние.\n const merged = mergeChatData(chat.data, patch, maxBytes);\n const { data: _data, subjectData: _subjectData, ...rest } = chat;\n const updated: Chat = { ...rest, ...chatDataFields(merged) };\n chats.set(chatId, updated);\n return structuredClone(updated);\n },\n\n async renameChat(chatId, title) {\n const chat = chats.get(chatId);\n if (!chat) return;\n const { title: _dropped, ...rest } = chat;\n chats.set(chatId, title === null ? rest : { ...rest, title });\n },\n\n async setChatClosed(chatId, closed) {\n const chat = chats.get(chatId);\n if (!chat) return;\n const { closed: _dropped, ...rest } = chat;\n chats.set(chatId, closed === null ? rest : { ...rest, closed: { code: closed.code, message: closed.message } });\n },\n\n async deleteChat(chatId) {\n if (!chats.delete(chatId)) return;\n turnLeases.delete(chatId);\n pendingBursts.delete(chatId);\n for (const message of [...messages.values()]) {\n if (message.chatId !== chatId) continue;\n messages.delete(message.id);\n aliveAt.delete(message.id);\n }\n // Записи сжатия — на месте, с обратным ходом, чтобы индексы не сдвигались.\n for (let index = compactions.length - 1; index >= 0; index -= 1) {\n if (compactions[index]!.chatId === chatId) compactions.splice(index, 1);\n }\n for (let index = branchSelections.length - 1; index >= 0; index -= 1) {\n if (branchSelections[index]!.chatId === chatId) branchSelections.splice(index, 1);\n }\n },\n\n async getMessage(messageId) {\n const message = messages.get(messageId);\n if (!message) return null;\n assertKnownFormatVersion(message);\n return readable(message);\n },\n\n async listMessages(chatId) {\n const found = sortedMessages(chatId);\n found.forEach(assertKnownFormatVersion);\n return found.map(readable);\n },\n\n async listMessageLinks(chatId) {\n return sortedMessages(chatId).map(({ id, parentId, createdAt }) => ({ id, parentId, createdAt }));\n },\n\n async listMessagePartsOfTypes(chatId, types) {\n return sortedMessages(chatId).map(({ id, parentId, createdAt, parts }) => ({\n id,\n parentId,\n createdAt,\n parts: structuredClone(parts.filter((part) => types.includes(part.type))),\n }));\n },\n\n async insertMessage(message) {\n if (messages.has(message.id)) throw new DuplicateMessageError(message.id);\n // Как внешний ключ в базе: сообщение без чата не пишется.\n const chat = chats.get(message.chatId);\n if (!chat) throw new Error(`Чата ${message.chatId} нет`);\n const { alive, ...stored } = message;\n messages.set(message.id, structuredClone(stored));\n if (alive) aliveAt.set(message.id, aliveAtByLocalClock(alive));\n chats.set(chat.id, { ...chat, updatedAt: message.createdAt });\n },\n\n async updateStreamingMessage(messageId, patch) {\n const message = streamingMessage(messageId);\n const { alive, ...rest } = structuredClone(patch);\n messages.set(messageId, { ...message, ...rest });\n if (alive) aliveAt.set(messageId, aliveAtByLocalClock(alive));\n },\n\n async markAnswerAlive(messageId) {\n streamingMessage(messageId);\n aliveAt.set(messageId, aliveAtByLocalClock(\"now\"));\n },\n\n async finishMessage(messageId, final) {\n const message = streamingMessage(messageId);\n messages.set(messageId, { ...message, ...structuredClone(final) });\n if (final.afterTurn === \"pending\") aliveAt.set(messageId, aliveAtByLocalClock(\"now\"));\n },\n\n async updateAwaitingMessage(messageId, patch) {\n const message = messages.get(messageId);\n if (!message) throw new Error(`Сообщения ${messageId} нет`);\n if (message.status !== \"awaiting_approval\") throw new MessageNotAwaitingError(messageId);\n if (patch.expectedParts && !sameMessageParts(message.parts, patch.expectedParts)) throw new MessageNotAwaitingError(messageId);\n messages.set(messageId, {\n ...message,\n parts: structuredClone(patch.parts),\n ...(patch.status && { status: patch.status }),\n });\n if (patch.alive) aliveAt.set(messageId, aliveAtByLocalClock(patch.alive));\n },\n\n async listStreamingMessageIds() {\n return [...messages.values()].filter((message) => message.status === \"streaming\").map((message) => message.id);\n },\n\n async listSilentAnswerIds({ silentForMs, chatId }) {\n const boundary = silenceBoundaryByLocalClock(silentForMs);\n return [...messages.values()]\n .filter((message) => message.status === \"streaming\" && (chatId === undefined || message.chatId === chatId))\n .filter((message) => (aliveAt.get(message.id) ?? message.createdAt) < boundary)\n .map((message) => message.id);\n },\n\n async claimChatTurn(chatId, holder, leaseMs) {\n const now = Date.now();\n const lease = turnLeases.get(chatId);\n if (lease && lease.holder !== holder && lease.until > now) return false;\n turnLeases.set(chatId, { holder, until: now + leaseMs });\n return true;\n },\n\n async releaseChatTurn(chatId, holder) {\n if (turnLeases.get(chatId)?.holder === holder) turnLeases.delete(chatId);\n },\n\n async clearChatTurnLeases() {\n turnLeases.clear();\n },\n\n async savePendingBurst(burst) {\n pendingBursts.set(burst.chatId, structuredClone(burst));\n },\n\n async takeAbandonedBursts({ abandonedBefore, holder, heldUntil, limit, exceptHolder }) {\n const abandoned = [...pendingBursts.values()]\n .filter((burst) => Date.parse(burst.heldUntil) <= Date.parse(abandonedBefore) && burst.holder !== exceptHolder)\n .sort((first, second) => Date.parse(first.dueAt) - Date.parse(second.dueAt))\n .slice(0, limit);\n return abandoned.map((burst) => {\n const taken = { ...burst, holder, heldUntil };\n pendingBursts.set(burst.chatId, taken);\n return structuredClone(taken);\n });\n },\n\n async renewPendingBurst({ chatId, messageId, holder, heldUntil }) {\n const burst = pendingBursts.get(chatId);\n if (burst?.messageId !== messageId || burst.holder !== holder) return false;\n pendingBursts.set(chatId, { ...burst, heldUntil });\n return true;\n },\n\n async removePendingBurst(chatId, messageId) {\n if (pendingBursts.get(chatId)?.messageId === messageId) pendingBursts.delete(chatId);\n },\n\n async insertCompaction(record) {\n if (compactions.some((existing) => existing.id === record.id)) throw new Error(`Запись сжатия ${record.id} уже есть`);\n compactions.push(structuredClone(record));\n },\n\n async listCompactions(chatId) {\n return structuredClone(compactions.filter((record) => record.chatId === chatId));\n },\n\n async insertBranchSelection(record) {\n if (branchSelections.some((existing) => existing.id === record.id)) throw new Error(`Выбор ветки ${record.id} уже есть`);\n branchSelections.push(structuredClone(record));\n },\n\n async listBranchSelections(chatId) {\n return structuredClone(branchSelections.filter((record) => record.chatId === chatId));\n },\n\n async insertUsageRecord(record) {\n if (usageRecords.some((existing) => existing.id === record.id)) throw new Error(`Запись расхода ${record.id} уже есть`);\n usageRecords.push(structuredClone(record));\n },\n\n async hasUsageRecord(id) {\n return usageRecords.some((record) => record.id === id);\n },\n\n async sumUsage({ ownerId, chatId, messageId, source, since }) {\n return sumRecords(\n usageRecords.filter(\n (record) =>\n (ownerId === undefined || record.ownerId === ownerId) &&\n (chatId === undefined || record.chatId === chatId) &&\n (messageId === undefined || record.messageId === messageId) &&\n (source === undefined || record.source === source) &&\n (since === undefined || record.createdAt >= since),\n ),\n (record) => ({ modelId: record.modelId, providerId: record.providerId }),\n );\n },\n\n async sumUsageByChat({ chatIds, ownerId, source, since }) {\n const wanted = new Set(chatIds);\n return sumRecords(\n usageRecords.filter(\n (record) =>\n wanted.has(record.chatId) &&\n (ownerId === undefined || record.ownerId === ownerId) &&\n (source === undefined || record.source === source) &&\n (since === undefined || record.createdAt >= since),\n ),\n (record) => ({ chatId: record.chatId, modelId: record.modelId, providerId: record.providerId }),\n );\n },\n\n async setVoiceCut({ ownerId, chatId, messageId, voiceCut }) {\n const message = messages.get(messageId);\n if (!message || message.chatId !== chatId || chats.get(chatId)?.ownerId !== ownerId) return;\n messages.set(messageId, { ...message, voiceCut: structuredClone(voiceCut) });\n },\n\n async getSpendingLimitState(key) {\n const record = spendingLimitStates.get(key);\n return record ? { ...record } : null;\n },\n\n async saveSpendingLimitState(key, value, expectedVersion) {\n const current = spendingLimitStates.get(key);\n if ((current?.version ?? null) !== expectedVersion) return false;\n spendingLimitStates.set(key, { value, version: (current?.version ?? 0) + 1 });\n return true;\n },\n\n async deleteSpendingLimitStates(keys) {\n for (const key of keys) spendingLimitStates.delete(key);\n },\n\n async getVoiceChoice(ownerId) {\n return voiceChoices.get(ownerId) ?? null;\n },\n\n async setVoiceChoice(ownerId, voiceId) {\n voiceChoices.set(ownerId, voiceId);\n },\n\n async getUserModelChoice(ownerId) {\n const choice = userModelChoices.get(ownerId);\n return choice ? structuredClone(choice) : null;\n },\n\n async saveUserModelChoice(ownerId, choice) {\n userModelChoices.set(ownerId, structuredClone(choice));\n },\n\n async listMemoryNotes(ownerId) {\n return visibleNotes(ownerId);\n },\n\n async insertMemoryNotes(ownerId, inputs) {\n return insertNotes(ownerId, inputs);\n },\n\n // Всё выполняется без ожидания, поэтому между проверкой и вставкой никто не успеет вклиниться.\n async insertMemoryNotesChecked(ownerId, inputs, guard) {\n const error = guard(visibleNotes(ownerId));\n return error ?? insertNotes(ownerId, inputs);\n },\n\n async updateMemoryNote(ownerId, id, expectedVersion, input) {\n return updateNote(ownerId, id, expectedVersion, input);\n },\n\n async updateMemoryNoteChecked(ownerId, id, expectedVersion, input, guard) {\n return guard(visibleNotes(ownerId)) ?? updateNote(ownerId, id, expectedVersion, input);\n },\n\n async deleteMemoryNote(ownerId, id, expectedVersion) {\n const notes = ownerNotes(ownerId);\n const note = notes.get(id);\n if (!note || note.mergedInto) return \"not_found\";\n if (note.version !== expectedVersion) return \"stale_version\";\n notes.delete(id);\n for (const [hiddenId, hidden] of notes) if (hidden.mergedInto === id) notes.delete(hiddenId);\n return \"ok\";\n },\n\n async clearMemoryNotes(ownerId) {\n const count = [...ownerNotes(ownerId).values()].filter((note) => !note.mergedInto).length;\n memoryNotes.delete(ownerId);\n optimizationRuns.delete(ownerId);\n return count;\n },\n\n async claimMemoryOptimizationRun(ownerId, rules, now) {\n const runs = ownerRuns(ownerId);\n const nowMs = Date.parse(now);\n for (const run of runs) {\n const leaseEnd = Date.parse(run.startedAt) + rules.leaseMs;\n if (run.status === \"running\" && nowMs >= leaseEnd) Object.assign(run, { status: \"failed\", error: \"lease_expired\", finishedAt: new Date(leaseEnd).toISOString() });\n }\n const blocked = isOptimizationBlocked(\n runs.map((run) => ({ status: run.status, startedAtMs: Date.parse(run.startedAt), endedAtMs: run.finishedAt ? Date.parse(run.finishedAt) : null })),\n rules,\n nowMs,\n );\n if (blocked) return null;\n const run: MemoryOptimizationRun = { id: crypto.randomUUID(), startedAt: now, finishedAt: null, status: \"running\", groups: [], error: null, usageRecordId: null };\n runs.push(run);\n return structuredClone(run);\n },\n\n async finishMemoryOptimizationRun(ownerId, runId, outcome) {\n const run = ownerRuns(ownerId).find((candidate) => candidate.id === runId);\n if (run?.status !== \"running\") return \"not_found\";\n Object.assign(run, { status: outcome.status, finishedAt: outcome.finishedAt, error: outcome.error ?? null, usageRecordId: outcome.usageRecordId ?? null });\n return \"ok\";\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 { result, originals } of merges) {\n assertWellFormedNote(result);\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 const run = ownerRuns(ownerId).find((candidate) => candidate.id === merge.runId);\n if (run?.status !== \"running\") return \"run_not_active\";\n const notes = ownerNotes(ownerId);\n for (const { originals } of merges) {\n for (const { id, version } of originals) {\n const original = notes.get(id);\n if (!original || original.mergedInto || original.version !== version) return \"stale_version\";\n }\n }\n const now = new Date().toISOString();\n const groups: MemoryMergeGroup[] = merges.map(({ result, originals }) => {\n const created: StoredNote = { id: crypto.randomUUID(), categories: [...result.categories], content: result.content, version: 1, createdAt: now, updatedAt: now };\n notes.set(created.id, created);\n for (const { id } of originals) notes.get(id)!.mergedInto = created.id;\n return { resultId: created.id, originalIds: originals.map(({ id }) => id), resultVersion: 1 };\n });\n Object.assign(run, { status: \"applied\", finishedAt: merge.finishedAt, groups, usageRecordId: merge.usageRecordId ?? null });\n return structuredClone(run);\n },\n\n async revertMemoryMerge(ownerId, runId, guard) {\n const run = ownerRuns(ownerId).find((candidate) => candidate.id === runId);\n if (run?.status !== \"applied\") return \"not_found\";\n const notes = ownerNotes(ownerId);\n const intact = run.groups.every(\n ({ resultId, originalIds, resultVersion }) =>\n notes.get(resultId)?.version === resultVersion && !notes.get(resultId)?.mergedInto && originalIds.every((id) => notes.get(id)?.mergedInto === resultId),\n );\n if (!intact) return \"conflict\";\n if (guard) {\n const resultIds = new Set(run.groups.map(({ resultId }) => resultId));\n const restoredIds = new Set(run.groups.flatMap(({ originalIds }) => originalIds));\n const inPlay = [...notes.values()];\n const remaining = newestFirst(inPlay.filter((note) => !note.mergedInto && !resultIds.has(note.id))).map(publicNote);\n const restored = newestFirst(inPlay.filter((note) => restoredIds.has(note.id))).map(publicNote);\n const error = guard(structuredClone(remaining), structuredClone(restored));\n if (error) return revertRefusal(error);\n }\n for (const { resultId, originalIds } of run.groups) {\n notes.delete(resultId);\n for (const id of originalIds) delete notes.get(id)!.mergedInto;\n }\n run.status = \"reverted\";\n return \"ok\";\n },\n\n async listMemoryOptimizationRuns(ownerId, filter) {\n const runs = ownerRuns(ownerId)\n .map((run, index) => ({ run, index }))\n .filter(({ run }) => !filter?.status || filter.status.includes(run.status))\n .sort((left, right) => right.run.startedAt.localeCompare(left.run.startedAt) || right.index - left.index)\n .map(({ run }) => run);\n return structuredClone(filter?.limit === undefined ? runs : runs.slice(0, filter.limit));\n },\n\n async listMergedMemoryNotes(ownerId) {\n const hidden = [...ownerNotes(ownerId).values()].filter((note): note is StoredNote & { mergedInto: string } => Boolean(note.mergedInto));\n return structuredClone(newestFirst(hidden) as MergedMemoryNote[]);\n },\n };\n}\n\n/** Подходит ли чат под фильтр `listChats` по ключу объекта. */\nfunction matchesSubjects(chat: Chat, subjects: ChatSubjectFilter = \"exclude\"): boolean {\n if (subjects === \"include\") return true;\n return subjects === \"only\" ? chat.subjectKey !== undefined : chat.subjectKey === undefined;\n}\n\n/** `data` и `subjectData` — один объект; данных нет — полей нет. */\nfunction withChatData<T extends Pick<Chat, \"data\" | \"subjectData\">>(chat: T): T {\n const { data: _data, subjectData: _subjectData, ...rest } = chat;\n return { ...rest, ...chatDataFields(chatDataOfInput(chat)) } as T;\n}\n\n/** Как база: поле без значения не хранится. */\nfunction withoutUndefined<T extends object>(value: T): T {\n return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined)) as T;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8EO,SAAS,kBAAkB,OAA6D,eAA+B;AAC5H,QAAM,EAAE,oBAAoB,IAAI;AAChC,MAAI,OAAO,wBAAwB,SAAU,QAAO;AACpD,SAAO,oBAAoB,KAAK,IAAI,eAAe,oBAAoB,MAAM,IAAI,CAAC,KAAK;AACzF;AAMO,SAAS,sBAAsB,MAAwC,OAAgC,OAAwB;AACpI,QAAM,UAAU,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,MAAM,UAAU,KAAK,cAAc,MAAM,WAAW;AACpF,MAAI,gBAAgB;AACpB,aAAW,OAAO,SAAS;AACzB,QAAI,IAAI,WAAW,UAAW,QAAO;AACrC,oBAAgB,IAAI,WAAW,WAAW,gBAAgB,IAAI;AAC9D,UAAM,QAAQ,IAAI,WAAW,WAAW,kBAAkB,OAAO,aAAa,IAAI,MAAM;AACxF,QAAI,SAAS,IAAI,aAAa,IAAI,eAAe,MAAO,QAAO;AAAA,EACjE;AACA,SAAO;AACT;AAGO,SAAS,cAAc,OAAmD;AAC/E,SAAO,MAAM,SAAS,cAAc,cAAc;AACpD;;;ACrFO,IAAM,oBAAoB;AAG1B,IAAM,6BAA6B;AAE1C,IAAM,0BAA0B,CAAC,IAAI,IAAI,KAAK,GAAG;AAGjD,IAAM,kBAAkB,oBAAI,IAAI,CAAC,SAAS,SAAS,SAAS,OAAO,CAAC;AAQpE,eAAsB,sBAAsE,SAA8D;AACxJ,QAAM,SAAS,QAAQ,iBAAiB;AACxC,WAAS,UAAU,KAAK,WAAW;AACjC,QAAI;AACF,aAAO,MAAM,YAAY,OAAO;AAAA,IAClC,SAAS,OAAO;AACd,UAAI,WAAW,OAAO,UAAU,CAAC,iBAAiB,KAAK,EAAG,OAAM;AAChE,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,OAAO,OAAO,CAAC,CAAC;AAAA,IACrE;AAAA,EACF;AACF;AAEA,eAAe,YAA4D,SAA8D;AACvI,QAAM,aAAa,MAAM,QAAQ,QAAQ;AACzC,MAAI;AACF,QAAI,CAAE,MAAM,aAAa,UAAU,GAAI;AACrC,YAAM,UAAU,YAAY,4BAA4B,MAAM,WAAW,MAAM,gCAAgC,iBAAiB,GAAG,CAAC;AAAA,IACtI;AACA,UAAM,UAAU,YAAY,QAAQ,SAAS,MAAM,QAAQ,QAAQ,UAAU,CAAC;AAAA,EAChF,UAAE;AACA,eAAW,QAAQ;AAAA,EACrB;AACF;AAEA,eAAe,aAAa,YAA2D;AACrF,QAAM,SAAS,MAAM,WAAW,MAAM,iDAAiD,CAAC,iBAAiB,CAAC;AAC1G,SAAO,OAAO,KAAK,SAAS;AAC9B;AAEA,eAAe,UAAU,YAAyC,KAAa,MAA6C;AAC1H,QAAM,WAAW,MAAM,+BAA+B,CAAC,GAAG,CAAC;AAC3D,MAAI;AACF,UAAM,KAAK;AAAA,EACb,UAAE;AACA,UAAM,WAAW,MAAM,iCAAiC,CAAC,GAAG,CAAC;AAAA,EAC/D;AACF;AAGA,SAAS,iBAAiB,OAAyB;AACjD,WAAS,UAAU,OAAO,QAAQ,GAAG,WAAW,QAAQ,GAAG,UAAW,QAAgC,OAAO,SAAS;AACpH,UAAM,OAAQ,QAA+B;AAC7C,QAAI,OAAO,SAAS,YAAY,gBAAgB,IAAI,IAAI,EAAG,QAAO;AAAA,EACpE;AACA,SAAO;AACT;;;ACvDO,SAAS,kBAAkB,SAAgC;AAChE,MAAI,QAAQ,WAAW,iBAAiB;AACtC,WACE,uJAA+B,QAAQ,MAAM,2EAA8B,QAAQ,MAAM,KAAK,IAAI,CAAC;AAAA,EAIvG;AACA,SAAO,gLAAoC,QAAQ,MAAM;AAC3D;AAMO,SAAS,aAAa,QAAyB;AACpD,QAAM,QAAQ,OAAO,YAAY;AACjC,SAAO,UAAU,SAAS,UAAU,UAAU,UAAU;AAC1D;AAGA,IAAM,uBAAuB;AAC7B,IAAM,sBAAsB;AAErB,SAAS,yBAAyB,UAAqC,CAAC,GAAuB;AACpG,QAAM,YAAY,sBAAsB,QAAQ,kBAAkB,CAAC,CAAC;AACpE,QAAM,WAAW,oBAAI,IAAY;AACjC,QAAM,SAAS,CAAC,YAAkC;AAChD,UAAM,QAAQ,QAAQ,OAAO,MAAM,GAAG,mBAAmB;AACzD,QAAI,QAAQ,aAAa,CAAC,SAAS,IAAI,KAAK,KAAK,SAAS,OAAO,sBAAsB;AACrF,eAAS,IAAI,KAAK;AAClB,cAAQ,UAAU,EAAE,GAAG,SAAS,QAAQ,MAAM,CAAC;AAAA,IACjD;AACA,WAAO;AAAA,EACT;AACA,SAAO,CAAC,YAAY;AAClB,UAAM,SAAS,QAAQ,QAAQ,IAAI,QAAQ;AAC3C,QAAI,WAAW,QAAQ,UAAU,MAAM,EAAG,QAAO;AACjD,UAAM,OAAO,QAAQ,QAAQ,IAAI,gBAAgB;AACjD,QAAI,SAAS,MAAM;AACjB,UAAI,SAAS,iBAAiB,SAAS,OAAQ,QAAO;AACtD,aAAO,OAAO,EAAE,QAAQ,UAAU,+CAAgC,IAAI,KAAK,QAAQ,aAAa,CAAC;AAAA,IACnG;AAEA,QAAI,WAAW,KAAM,QAAO;AAE5B,UAAM,OAAO,WAAW,MAAM;AAC9B,UAAM,QAAQ,QAAQ,OAAO;AAC7B,QAAI,SAAS,QAAQ,MAAM,IAAI,IAAI,EAAG,QAAO;AAC7C,WAAO,OAAO,EAAE,QAAQ,QAAQ,iBAAiB,OAAO,CAAC,GAAG,KAAK,EAAE,CAAC;AAAA,EACtE;AACF;AAGA,IAAM,iBAAiB;AAGvB,SAAS,sBAAsB,SAAyD;AACtF,QAAM,QAAQ,oBAAI,IAAY;AAC9B,QAAM,eAA0E,CAAC;AACjF,aAAW,SAAS,SAAS;AAC3B,UAAM,WAAW,6BAA6B,KAAK,KAAK;AACxD,UAAM,MAAM,iBAAiB,WAAW,GAAG,SAAS,CAAC,CAAC,GAAG,cAAc,IAAI,SAAS,CAAC,CAAC,KAAK,KAAK;AAChG,QAAI,QAAQ,QAAS,CAAC,YAAY,MAAM,SAAS,GAAG,EAAI,OAAM,WAAW,KAAK;AAC9E,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,IAAI,MAAM;AACpB;AAAA,IACF;AACA,UAAM,SAAS,IAAI,SAAS,MAAM,eAAe,MAAM;AAGvD,UAAM,WAAW,OAAO,SAAS,GAAG,KAAM,CAAC,OAAO,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,WAAW;AACvF,QAAI,CAAC,IAAI,SAAS,WAAW,GAAG,cAAc,GAAG,KAAK,SAAU,OAAM,WAAW,KAAK;AACtF,iBAAa,KAAK,EAAE,UAAU,IAAI,UAAU,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,EACtE;AACA,SAAO,CAAC,WAAW;AACjB,UAAM,MAAM,YAAY,MAAM;AAC9B,QAAI,QAAQ,KAAM,QAAO;AACzB,QAAI,MAAM,IAAI,IAAI,MAAM,EAAG,QAAO;AAClC,WAAO,aAAa;AAAA,MAClB,CAAC,YACC,IAAI,aAAa,QAAQ,YAAY,IAAI,SAAS,QAAQ,QAAQ,IAAI,SAAS,SAAS,QAAQ,MAAM,KAAK,IAAI,SAAS,SAAS,QAAQ,OAAO;AAAA,IACpJ;AAAA,EACF;AACF;AAGA,SAAS,iBAAiB,OAA2B;AACnD,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,KAAK;AACzB,UAAM,OAAO,IAAI,aAAa,OAAO,CAAC,IAAI,UAAU,CAAC,IAAI,QAAQ,CAAC,IAAI;AACtE,YAAQ,IAAI,aAAa,WAAW,IAAI,aAAa,aAAa,OAAO,MAAM;AAAA,EACjF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,WAAW,OAAsB;AACxC,SAAO,IAAI;AAAA,IACT,uBAAoB,KAAK;AAAA,EAE3B;AACF;AAEA,SAAS,YAAY,QAA4B;AAC/C,MAAI;AACF,WAAO,IAAI,IAAI,MAAM;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,SAAS,WAAW,QAA+B;AACjD,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,MAAM;AAC1B,WAAO,IAAI,aAAa,WAAW,IAAI,aAAa,WAAW,IAAI,OAAO;AAAA,EAC5E,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,SAAS,QAAQ,SAA+B;AAC9C,QAAM,OAAO,QAAQ,QAAQ,IAAI,MAAM;AACvC,QAAM,QAAQ,oBAAI,IAAY,CAAC,OAAO,KAAK,KAAK,EAAE,YAAY,IAAI,IAAI,IAAI,QAAQ,GAAG,EAAE,IAAI,CAAC;AAC5F,aAAW,aAAa,QAAQ,QAAQ,IAAI,kBAAkB,GAAG,MAAM,GAAG,KAAK,CAAC,GAAG;AACjF,QAAI,UAAU,KAAK,EAAG,OAAM,IAAI,UAAU,KAAK,EAAE,YAAY,CAAC;AAAA,EAChE;AACA,SAAO;AACT;;;ACtIA,SAAS,WAA+D,SAAiC,OAAwD;AAC/J,QAAM,OAAO,oBAAI,IAA0B;AAC3C,aAAW,UAAU,SAAS;AAC5B,UAAM,SAAS,MAAM,MAAM;AAC3B,UAAM,MAAM,OAAO,OAAO,MAAM,EAAE,KAAK,IAAQ;AAC/C,UAAM,MAAM,KAAK,IAAI,GAAG,KAAK,EAAE,GAAG,QAAQ,aAAa,GAAG,mBAAmB,GAAG,kBAAkB,GAAG,cAAc,GAAG,iBAAiB,GAAG,SAAS,EAAE;AACrJ,QAAI,eAAe,OAAO;AAC1B,QAAI,qBAAqB,OAAO;AAChC,QAAI,oBAAoB,OAAO;AAC/B,QAAI,gBAAgB,OAAO;AAC3B,QAAI,mBAAmB,OAAO;AAC9B,QAAI,WAAW,OAAO;AACtB,SAAK,IAAI,KAAK,GAAG;AAAA,EACnB;AACA,SAAO,CAAC,GAAG,KAAK,OAAO,CAAC;AAC1B;AAEO,SAAS,4BAAyC;AACvD,QAAM,QAAQ,oBAAI,IAAkB;AACpC,QAAM,WAAW,oBAAI,IAA2B;AAEhD,QAAM,UAAU,oBAAI,IAAoB;AAExC,QAAM,aAAa,oBAAI,IAA+C;AAEtE,QAAM,gBAAgB,oBAAI,IAAgC;AAC1D,QAAM,cAAkC,CAAC;AACzC,QAAM,mBAA4C,CAAC;AACnD,QAAM,eAA8B,CAAC;AACrC,QAAM,mBAAmB,oBAAI,IAAyB;AACtD,QAAM,eAAe,oBAAI,IAAoB;AAC7C,QAAM,sBAAsB,oBAAI,IAAsC;AAEtE,QAAM,cAAc,oBAAI,IAAqC;AAC7D,QAAM,mBAAmB,oBAAI,IAAqC;AAElE,WAAS,iBAAiB,WAAkC;AAC1D,UAAM,UAAU,SAAS,IAAI,SAAS;AACtC,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,0DAAa,SAAS,qBAAM;AAC1D,QAAI,QAAQ,WAAW,YAAa,OAAM,IAAI,4BAA4B,SAAS;AACnF,WAAO;AAAA,EACT;AAGA,WAAS,SAAS,SAAuC;AACvD,UAAM,OAAO,gBAAgB,OAAO;AACpC,WAAO,EAAE,GAAG,MAAM,UAAU,KAAK,YAAY,KAAK;AAAA,EACpD;AAEA,WAAS,WAAW,SAA0C;AAC5D,QAAI,QAAQ,YAAY,IAAI,OAAO;AACnC,QAAI,CAAC,OAAO;AACV,cAAQ,oBAAI,IAAI;AAChB,kBAAY,IAAI,SAAS,KAAK;AAAA,IAChC;AACA,WAAO;AAAA,EACT;AAEA,WAAS,UAAU,SAA0C;AAC3D,QAAI,OAAO,iBAAiB,IAAI,OAAO;AACvC,QAAI,CAAC,MAAM;AACT,aAAO,CAAC;AACR,uBAAiB,IAAI,SAAS,IAAI;AAAA,IACpC;AACA,WAAO;AAAA,EACT;AAGA,WAAS,YAAkC,OAAiB;AAC1D,WAAO,MAAM;AAAA,MACX,CAAC,MAAM,UACL,MAAM,UAAU,cAAc,KAAK,SAAS,KAC5C,MAAM,UAAU,cAAc,KAAK,SAAS,MAC3C,MAAM,KAAK,KAAK,KAAK,IAAI,MAAM,KAAK,KAAK,KAAK,KAAK;AAAA,IACxD;AAAA,EACF;AAGA,WAAS,WAAW,EAAE,YAAY,SAAS,GAAG,KAAK,GAA2B;AAC5E,WAAO;AAAA,EACT;AAGA,WAAS,qBAAqB,MAA6B;AACzD,QAAI,CAAC,MAAM,QAAQ,MAAM,UAAU,KAAK,CAAC,KAAK,WAAW,MAAM,CAAC,aAAa,OAAO,aAAa,QAAQ,GAAG;AAC1G,YAAM,IAAI,UAAU,iMAAsC;AAAA,IAC5D;AACA,QAAI,OAAO,KAAK,YAAY,SAAU,OAAM,IAAI,UAAU,sJAA8B;AAAA,EAC1F;AAGA,WAAS,aAAa,SAA+B;AACnD,UAAM,UAAU,CAAC,GAAG,WAAW,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK,UAAU;AACnF,WAAO,gBAAgB,YAAY,OAAO,EAAE,IAAI,UAAU,CAAC;AAAA,EAC7D;AAEA,WAAS,YAAY,SAAiB,QAAyC;AAE7E,WAAO,QAAQ,oBAAoB;AACnC,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,UAAU,OAAO;AAAA,MACrB,CAAC,EAAE,YAAY,QAAQ,OAAmB;AAAA,QACxC,IAAI,OAAO,WAAW;AAAA,QACtB,YAAY,CAAC,GAAG,UAAU;AAAA,QAC1B;AAAA,QACA,SAAS;AAAA,QACT,WAAW;AAAA,QACX,WAAW;AAAA,MACb;AAAA,IACF;AACA,UAAM,QAAQ,WAAW,OAAO;AAChC,eAAW,QAAQ,QAAS,OAAM,IAAI,KAAK,IAAI,IAAI;AACnD,WAAO,gBAAgB,OAAO;AAAA,EAChC;AAEA,WAAS,WAAW,SAAiB,IAAY,iBAAyB,OAAoE;AAC5I,yBAAqB,KAAK;AAC1B,UAAM,QAAQ,WAAW,OAAO;AAChC,UAAM,OAAO,MAAM,IAAI,EAAE;AACzB,QAAI,CAAC,QAAQ,KAAK,WAAY,QAAO;AACrC,QAAI,KAAK,YAAY,gBAAiB,QAAO;AAC7C,UAAM,UAAsB;AAAA,MAC1B,GAAG;AAAA,MACH,YAAY,CAAC,GAAG,MAAM,UAAU;AAAA,MAChC,SAAS,MAAM;AAAA,MACf,SAAS,KAAK,UAAU;AAAA,MACxB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AACA,UAAM,IAAI,IAAI,OAAO;AACrB,WAAO,gBAAgB,OAAO;AAAA,EAChC;AAGA,WAAS,kBAAkB,MAAkD;AAC3E,QAAI,KAAK,eAAe,OAAW;AACnC,eAAW,YAAY,MAAM,OAAO,GAAG;AACrC,UAAI,SAAS,YAAY,KAAK,WAAW,SAAS,eAAe,KAAK,YAAY;AAChF,cAAM,IAAI,0BAA0B,KAAK,SAAS,KAAK,UAAU;AAAA,MACnE;AAAA,IACF;AAAA,EACF;AAEA,WAAS,eAAe,QAAiC;AACvD,WAAO,CAAC,GAAG,SAAS,OAAO,CAAC,EACzB,OAAO,CAAC,YAAY,QAAQ,WAAW,MAAM,EAC7C,KAAK,CAAC,MAAM,UAAU,KAAK,UAAU,cAAc,MAAM,SAAS,CAAC;AAAA,EACxE;AAEA,SAAO;AAAA,IACL,MAAM,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG;AACxC,YAAM,KAAK,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC/C,YAAM,OAAa,aAAa,iBAAiB,EAAE,GAAG,gBAAgB,KAAK,GAAG,WAAW,IAAI,WAAW,GAAG,CAAC,CAAC;AAC7G,wBAAkB,IAAI;AACtB,YAAM,IAAI,KAAK,IAAI,IAAI;AACvB,aAAO,gBAAgB,IAAI;AAAA,IAC7B;AAAA,IAEA,MAAM,kBAAkB,SAAS,YAAY;AAC3C,YAAM,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,EAAE,KAAK,CAAC,aAAa,SAAS,YAAY,WAAW,SAAS,eAAe,UAAU;AACtH,aAAO,OAAO,gBAAgB,IAAI,IAAI;AAAA,IACxC;AAAA,IAEA,MAAM,WAAW,OAAO,UAAU;AAEhC,UAAI,MAAM,IAAI,MAAM,EAAE,EAAG,OAAM,IAAI,uBAAuB,MAAM,EAAE;AAClE,YAAM,OAAa,aAAa,iBAAiB,gBAAgB,KAAK,CAAC,CAAC;AACxE,wBAAkB,IAAI;AACtB,YAAM,MAAM,oBAAI,IAAY;AAC5B,iBAAW,WAAW,UAAU;AAC9B,YAAI,SAAS,IAAI,QAAQ,EAAE,KAAK,IAAI,IAAI,QAAQ,EAAE,EAAG,OAAM,IAAI,sBAAsB,QAAQ,EAAE;AAC/F,YAAI,IAAI,QAAQ,EAAE;AAAA,MACpB;AACA,YAAM,IAAI,KAAK,IAAI,IAAI;AACvB,iBAAW,WAAW,UAAU;AAC9B,cAAM,EAAE,OAAO,QAAQ,GAAG,OAAO,IAAI;AACrC,iBAAS,IAAI,QAAQ,IAAI,gBAAgB,MAAM,CAAC;AAAA,MAClD;AAAA,IACF;AAAA,IAEA,MAAM,kBAAkB,WAAW,OAAO,SAAS;AACjD,YAAM,UAAU,SAAS,IAAI,SAAS;AACtC,UAAI,CAAC,WAAY,UAAU,aAAa,QAAQ,cAAc,UAAY,QAAO;AACjF,YAAM,QAAQ,SAAS,cAAc,CAAC,GAAG,QAAQ,OAAO,GAAG,gBAAgB,QAAQ,WAAW,CAAC,IAAI,QAAQ;AAC3G,eAAS,IAAI,WAAW,EAAE,GAAG,SAAS,OAAO,WAAW,MAAM,CAAC;AAE/D,UAAI,UAAU,UAAW,SAAQ,IAAI,WAAW,oBAAoB,KAAK,CAAC;AAC1E,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,qBAAqB,QAAQ;AACjC,YAAM,WAAW,QAAQ,iBAAiB,SAAY,OAAO,4BAA4B,OAAO,YAAY;AAC5G,aAAO,CAAC,GAAG,SAAS,OAAO,CAAC,EACzB,OAAO,CAAC,YAAY,QAAQ,cAAc,SAAS,EACnD,OAAO,CAAC,YAAY,aAAa,SAAS,QAAQ,IAAI,QAAQ,EAAE,KAAK,QAAQ,aAAa,QAAQ,EAClG,IAAI,CAAC,YAAY,QAAQ,EAAE;AAAA,IAChC;AAAA,IAEA,MAAM,QAAQ,QAAQ;AACpB,YAAM,OAAO,MAAM,IAAI,MAAM;AAC7B,aAAO,OAAO,gBAAgB,IAAI,IAAI;AAAA,IACxC;AAAA,IAEA,MAAM,gBAAgB,QAAQ,OAAO;AACnC,YAAM,OAAO,MAAM,IAAI,MAAM;AAC7B,UAAI,CAAC,KAAM;AACX,YAAM,EAAE,WAAW,UAAU,GAAG,KAAK,IAAI;AACzC,YAAM,IAAI,QAAQ,EAAE,GAAG,MAAM,GAAG,MAAM,CAAC;AAAA,IACzC;AAAA,IAEA,MAAM,UAAU,SAAS,SAA2B;AAClD,UAAI,SAAS,KAAM,sBAAqB,QAAQ,IAAI;AACpD,YAAM,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,EAAE;AAAA,QAChC,CAAC,SAAS,KAAK,YAAY,WAAW,gBAAgB,MAAM,SAAS,QAAQ,MAAM,CAAC,SAAS,QAAQ,gBAAgB,KAAK,MAAM,QAAQ,IAAI;AAAA,MAC9I;AACA,YAAM;AAAA,QACJ,CAAC,MAAM,UACL,MAAM,UAAU,cAAc,KAAK,SAAS,KAC5C,MAAM,UAAU,cAAc,KAAK,SAAS,MAC3C,MAAM,KAAK,KAAK,KAAK,IAAI,MAAM,KAAK,KAAK,KAAK,KAAK;AAAA,MACxD;AACA,aAAO,gBAAgB,KAAK;AAAA,IAC9B;AAAA,IAEA,MAAM,eAAe,QAAQ,OAAO,EAAE,SAAS,GAAG;AAChD,YAAM,OAAO,MAAM,IAAI,MAAM;AAC7B,UAAI,CAAC,KAAM,QAAO;AAElB,YAAM,SAAS,cAAc,KAAK,MAAM,OAAO,QAAQ;AACvD,YAAM,EAAE,MAAM,OAAO,aAAa,cAAc,GAAG,KAAK,IAAI;AAC5D,YAAM,UAAgB,EAAE,GAAG,MAAM,GAAG,eAAe,MAAM,EAAE;AAC3D,YAAM,IAAI,QAAQ,OAAO;AACzB,aAAO,gBAAgB,OAAO;AAAA,IAChC;AAAA,IAEA,MAAM,WAAW,QAAQ,OAAO;AAC9B,YAAM,OAAO,MAAM,IAAI,MAAM;AAC7B,UAAI,CAAC,KAAM;AACX,YAAM,EAAE,OAAO,UAAU,GAAG,KAAK,IAAI;AACrC,YAAM,IAAI,QAAQ,UAAU,OAAO,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC;AAAA,IAC9D;AAAA,IAEA,MAAM,cAAc,QAAQ,QAAQ;AAClC,YAAM,OAAO,MAAM,IAAI,MAAM;AAC7B,UAAI,CAAC,KAAM;AACX,YAAM,EAAE,QAAQ,UAAU,GAAG,KAAK,IAAI;AACtC,YAAM,IAAI,QAAQ,WAAW,OAAO,OAAO,EAAE,GAAG,MAAM,QAAQ,EAAE,MAAM,OAAO,MAAM,SAAS,OAAO,QAAQ,EAAE,CAAC;AAAA,IAChH;AAAA,IAEA,MAAM,WAAW,QAAQ;AACvB,UAAI,CAAC,MAAM,OAAO,MAAM,EAAG;AAC3B,iBAAW,OAAO,MAAM;AACxB,oBAAc,OAAO,MAAM;AAC3B,iBAAW,WAAW,CAAC,GAAG,SAAS,OAAO,CAAC,GAAG;AAC5C,YAAI,QAAQ,WAAW,OAAQ;AAC/B,iBAAS,OAAO,QAAQ,EAAE;AAC1B,gBAAQ,OAAO,QAAQ,EAAE;AAAA,MAC3B;AAEA,eAAS,QAAQ,YAAY,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AAC/D,YAAI,YAAY,KAAK,EAAG,WAAW,OAAQ,aAAY,OAAO,OAAO,CAAC;AAAA,MACxE;AACA,eAAS,QAAQ,iBAAiB,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AACpE,YAAI,iBAAiB,KAAK,EAAG,WAAW,OAAQ,kBAAiB,OAAO,OAAO,CAAC;AAAA,MAClF;AAAA,IACF;AAAA,IAEA,MAAM,WAAW,WAAW;AAC1B,YAAM,UAAU,SAAS,IAAI,SAAS;AACtC,UAAI,CAAC,QAAS,QAAO;AACrB,+BAAyB,OAAO;AAChC,aAAO,SAAS,OAAO;AAAA,IACzB;AAAA,IAEA,MAAM,aAAa,QAAQ;AACzB,YAAM,QAAQ,eAAe,MAAM;AACnC,YAAM,QAAQ,wBAAwB;AACtC,aAAO,MAAM,IAAI,QAAQ;AAAA,IAC3B;AAAA,IAEA,MAAM,iBAAiB,QAAQ;AAC7B,aAAO,eAAe,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,UAAU,UAAU,OAAO,EAAE,IAAI,UAAU,UAAU,EAAE;AAAA,IAClG;AAAA,IAEA,MAAM,wBAAwB,QAAQ,OAAO;AAC3C,aAAO,eAAe,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,UAAU,WAAW,MAAM,OAAO;AAAA,QACzE;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,gBAAgB,MAAM,OAAO,CAAC,SAAS,MAAM,SAAS,KAAK,IAAI,CAAC,CAAC;AAAA,MAC1E,EAAE;AAAA,IACJ;AAAA,IAEA,MAAM,cAAc,SAAS;AAC3B,UAAI,SAAS,IAAI,QAAQ,EAAE,EAAG,OAAM,IAAI,sBAAsB,QAAQ,EAAE;AAExE,YAAM,OAAO,MAAM,IAAI,QAAQ,MAAM;AACrC,UAAI,CAAC,KAAM,OAAM,IAAI,MAAM,4BAAQ,QAAQ,MAAM,qBAAM;AACvD,YAAM,EAAE,OAAO,GAAG,OAAO,IAAI;AAC7B,eAAS,IAAI,QAAQ,IAAI,gBAAgB,MAAM,CAAC;AAChD,UAAI,MAAO,SAAQ,IAAI,QAAQ,IAAI,oBAAoB,KAAK,CAAC;AAC7D,YAAM,IAAI,KAAK,IAAI,EAAE,GAAG,MAAM,WAAW,QAAQ,UAAU,CAAC;AAAA,IAC9D;AAAA,IAEA,MAAM,uBAAuB,WAAW,OAAO;AAC7C,YAAM,UAAU,iBAAiB,SAAS;AAC1C,YAAM,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,KAAK;AAChD,eAAS,IAAI,WAAW,EAAE,GAAG,SAAS,GAAG,KAAK,CAAC;AAC/C,UAAI,MAAO,SAAQ,IAAI,WAAW,oBAAoB,KAAK,CAAC;AAAA,IAC9D;AAAA,IAEA,MAAM,gBAAgB,WAAW;AAC/B,uBAAiB,SAAS;AAC1B,cAAQ,IAAI,WAAW,oBAAoB,KAAK,CAAC;AAAA,IACnD;AAAA,IAEA,MAAM,cAAc,WAAW,OAAO;AACpC,YAAM,UAAU,iBAAiB,SAAS;AAC1C,eAAS,IAAI,WAAW,EAAE,GAAG,SAAS,GAAG,gBAAgB,KAAK,EAAE,CAAC;AACjE,UAAI,MAAM,cAAc,UAAW,SAAQ,IAAI,WAAW,oBAAoB,KAAK,CAAC;AAAA,IACtF;AAAA,IAEA,MAAM,sBAAsB,WAAW,OAAO;AAC5C,YAAM,UAAU,SAAS,IAAI,SAAS;AACtC,UAAI,CAAC,QAAS,OAAM,IAAI,MAAM,0DAAa,SAAS,qBAAM;AAC1D,UAAI,QAAQ,WAAW,oBAAqB,OAAM,IAAI,wBAAwB,SAAS;AACvF,UAAI,MAAM,iBAAiB,CAAC,iBAAiB,QAAQ,OAAO,MAAM,aAAa,EAAG,OAAM,IAAI,wBAAwB,SAAS;AAC7H,eAAS,IAAI,WAAW;AAAA,QACtB,GAAG;AAAA,QACH,OAAO,gBAAgB,MAAM,KAAK;AAAA,QAClC,GAAI,MAAM,UAAU,EAAE,QAAQ,MAAM,OAAO;AAAA,MAC7C,CAAC;AACD,UAAI,MAAM,MAAO,SAAQ,IAAI,WAAW,oBAAoB,MAAM,KAAK,CAAC;AAAA,IAC1E;AAAA,IAEA,MAAM,0BAA0B;AAC9B,aAAO,CAAC,GAAG,SAAS,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,QAAQ,WAAW,WAAW,EAAE,IAAI,CAAC,YAAY,QAAQ,EAAE;AAAA,IAC/G;AAAA,IAEA,MAAM,oBAAoB,EAAE,aAAa,OAAO,GAAG;AACjD,YAAM,WAAW,4BAA4B,WAAW;AACxD,aAAO,CAAC,GAAG,SAAS,OAAO,CAAC,EACzB,OAAO,CAAC,YAAY,QAAQ,WAAW,gBAAgB,WAAW,UAAa,QAAQ,WAAW,OAAO,EACzG,OAAO,CAAC,aAAa,QAAQ,IAAI,QAAQ,EAAE,KAAK,QAAQ,aAAa,QAAQ,EAC7E,IAAI,CAAC,YAAY,QAAQ,EAAE;AAAA,IAChC;AAAA,IAEA,MAAM,cAAc,QAAQ,QAAQ,SAAS;AAC3C,YAAM,MAAM,KAAK,IAAI;AACrB,YAAM,QAAQ,WAAW,IAAI,MAAM;AACnC,UAAI,SAAS,MAAM,WAAW,UAAU,MAAM,QAAQ,IAAK,QAAO;AAClE,iBAAW,IAAI,QAAQ,EAAE,QAAQ,OAAO,MAAM,QAAQ,CAAC;AACvD,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,gBAAgB,QAAQ,QAAQ;AACpC,UAAI,WAAW,IAAI,MAAM,GAAG,WAAW,OAAQ,YAAW,OAAO,MAAM;AAAA,IACzE;AAAA,IAEA,MAAM,sBAAsB;AAC1B,iBAAW,MAAM;AAAA,IACnB;AAAA,IAEA,MAAM,iBAAiB,OAAO;AAC5B,oBAAc,IAAI,MAAM,QAAQ,gBAAgB,KAAK,CAAC;AAAA,IACxD;AAAA,IAEA,MAAM,oBAAoB,EAAE,iBAAiB,QAAQ,WAAW,OAAO,aAAa,GAAG;AACrF,YAAM,YAAY,CAAC,GAAG,cAAc,OAAO,CAAC,EACzC,OAAO,CAAC,UAAU,KAAK,MAAM,MAAM,SAAS,KAAK,KAAK,MAAM,eAAe,KAAK,MAAM,WAAW,YAAY,EAC7G,KAAK,CAAC,OAAO,WAAW,KAAK,MAAM,MAAM,KAAK,IAAI,KAAK,MAAM,OAAO,KAAK,CAAC,EAC1E,MAAM,GAAG,KAAK;AACjB,aAAO,UAAU,IAAI,CAAC,UAAU;AAC9B,cAAM,QAAQ,EAAE,GAAG,OAAO,QAAQ,UAAU;AAC5C,sBAAc,IAAI,MAAM,QAAQ,KAAK;AACrC,eAAO,gBAAgB,KAAK;AAAA,MAC9B,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,kBAAkB,EAAE,QAAQ,WAAW,QAAQ,UAAU,GAAG;AAChE,YAAM,QAAQ,cAAc,IAAI,MAAM;AACtC,UAAI,OAAO,cAAc,aAAa,MAAM,WAAW,OAAQ,QAAO;AACtE,oBAAc,IAAI,QAAQ,EAAE,GAAG,OAAO,UAAU,CAAC;AACjD,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,mBAAmB,QAAQ,WAAW;AAC1C,UAAI,cAAc,IAAI,MAAM,GAAG,cAAc,UAAW,eAAc,OAAO,MAAM;AAAA,IACrF;AAAA,IAEA,MAAM,iBAAiB,QAAQ;AAC7B,UAAI,YAAY,KAAK,CAAC,aAAa,SAAS,OAAO,OAAO,EAAE,EAAG,OAAM,IAAI,MAAM,6EAAiB,OAAO,EAAE,8CAAW;AACpH,kBAAY,KAAK,gBAAgB,MAAM,CAAC;AAAA,IAC1C;AAAA,IAEA,MAAM,gBAAgB,QAAQ;AAC5B,aAAO,gBAAgB,YAAY,OAAO,CAAC,WAAW,OAAO,WAAW,MAAM,CAAC;AAAA,IACjF;AAAA,IAEA,MAAM,sBAAsB,QAAQ;AAClC,UAAI,iBAAiB,KAAK,CAAC,aAAa,SAAS,OAAO,OAAO,EAAE,EAAG,OAAM,IAAI,MAAM,iEAAe,OAAO,EAAE,8CAAW;AACvH,uBAAiB,KAAK,gBAAgB,MAAM,CAAC;AAAA,IAC/C;AAAA,IAEA,MAAM,qBAAqB,QAAQ;AACjC,aAAO,gBAAgB,iBAAiB,OAAO,CAAC,WAAW,OAAO,WAAW,MAAM,CAAC;AAAA,IACtF;AAAA,IAEA,MAAM,kBAAkB,QAAQ;AAC9B,UAAI,aAAa,KAAK,CAAC,aAAa,SAAS,OAAO,OAAO,EAAE,EAAG,OAAM,IAAI,MAAM,mFAAkB,OAAO,EAAE,8CAAW;AACtH,mBAAa,KAAK,gBAAgB,MAAM,CAAC;AAAA,IAC3C;AAAA,IAEA,MAAM,eAAe,IAAI;AACvB,aAAO,aAAa,KAAK,CAAC,WAAW,OAAO,OAAO,EAAE;AAAA,IACvD;AAAA,IAEA,MAAM,SAAS,EAAE,SAAS,QAAQ,WAAW,QAAQ,MAAM,GAAG;AAC5D,aAAO;AAAA,QACL,aAAa;AAAA,UACX,CAAC,YACE,YAAY,UAAa,OAAO,YAAY,aAC5C,WAAW,UAAa,OAAO,WAAW,YAC1C,cAAc,UAAa,OAAO,cAAc,eAChD,WAAW,UAAa,OAAO,WAAW,YAC1C,UAAU,UAAa,OAAO,aAAa;AAAA,QAChD;AAAA,QACA,CAAC,YAAY,EAAE,SAAS,OAAO,SAAS,YAAY,OAAO,WAAW;AAAA,MACxE;AAAA,IACF;AAAA,IAEA,MAAM,eAAe,EAAE,SAAS,SAAS,QAAQ,MAAM,GAAG;AACxD,YAAM,SAAS,IAAI,IAAI,OAAO;AAC9B,aAAO;AAAA,QACL,aAAa;AAAA,UACX,CAAC,WACC,OAAO,IAAI,OAAO,MAAM,MACvB,YAAY,UAAa,OAAO,YAAY,aAC5C,WAAW,UAAa,OAAO,WAAW,YAC1C,UAAU,UAAa,OAAO,aAAa;AAAA,QAChD;AAAA,QACA,CAAC,YAAY,EAAE,QAAQ,OAAO,QAAQ,SAAS,OAAO,SAAS,YAAY,OAAO,WAAW;AAAA,MAC/F;AAAA,IACF;AAAA,IAEA,MAAM,YAAY,EAAE,SAAS,QAAQ,WAAW,SAAS,GAAG;AAC1D,YAAM,UAAU,SAAS,IAAI,SAAS;AACtC,UAAI,CAAC,WAAW,QAAQ,WAAW,UAAU,MAAM,IAAI,MAAM,GAAG,YAAY,QAAS;AACrF,eAAS,IAAI,WAAW,EAAE,GAAG,SAAS,UAAU,gBAAgB,QAAQ,EAAE,CAAC;AAAA,IAC7E;AAAA,IAEA,MAAM,sBAAsB,KAAK;AAC/B,YAAM,SAAS,oBAAoB,IAAI,GAAG;AAC1C,aAAO,SAAS,EAAE,GAAG,OAAO,IAAI;AAAA,IAClC;AAAA,IAEA,MAAM,uBAAuB,KAAK,OAAO,iBAAiB;AACxD,YAAM,UAAU,oBAAoB,IAAI,GAAG;AAC3C,WAAK,SAAS,WAAW,UAAU,gBAAiB,QAAO;AAC3D,0BAAoB,IAAI,KAAK,EAAE,OAAO,UAAU,SAAS,WAAW,KAAK,EAAE,CAAC;AAC5E,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,0BAA0B,MAAM;AACpC,iBAAW,OAAO,KAAM,qBAAoB,OAAO,GAAG;AAAA,IACxD;AAAA,IAEA,MAAM,eAAe,SAAS;AAC5B,aAAO,aAAa,IAAI,OAAO,KAAK;AAAA,IACtC;AAAA,IAEA,MAAM,eAAe,SAAS,SAAS;AACrC,mBAAa,IAAI,SAAS,OAAO;AAAA,IACnC;AAAA,IAEA,MAAM,mBAAmB,SAAS;AAChC,YAAM,SAAS,iBAAiB,IAAI,OAAO;AAC3C,aAAO,SAAS,gBAAgB,MAAM,IAAI;AAAA,IAC5C;AAAA,IAEA,MAAM,oBAAoB,SAAS,QAAQ;AACzC,uBAAiB,IAAI,SAAS,gBAAgB,MAAM,CAAC;AAAA,IACvD;AAAA,IAEA,MAAM,gBAAgB,SAAS;AAC7B,aAAO,aAAa,OAAO;AAAA,IAC7B;AAAA,IAEA,MAAM,kBAAkB,SAAS,QAAQ;AACvC,aAAO,YAAY,SAAS,MAAM;AAAA,IACpC;AAAA;AAAA,IAGA,MAAM,yBAAyB,SAAS,QAAQ,OAAO;AACrD,YAAM,QAAQ,MAAM,aAAa,OAAO,CAAC;AACzC,aAAO,SAAS,YAAY,SAAS,MAAM;AAAA,IAC7C;AAAA,IAEA,MAAM,iBAAiB,SAAS,IAAI,iBAAiB,OAAO;AAC1D,aAAO,WAAW,SAAS,IAAI,iBAAiB,KAAK;AAAA,IACvD;AAAA,IAEA,MAAM,wBAAwB,SAAS,IAAI,iBAAiB,OAAO,OAAO;AACxE,aAAO,MAAM,aAAa,OAAO,CAAC,KAAK,WAAW,SAAS,IAAI,iBAAiB,KAAK;AAAA,IACvF;AAAA,IAEA,MAAM,iBAAiB,SAAS,IAAI,iBAAiB;AACnD,YAAM,QAAQ,WAAW,OAAO;AAChC,YAAM,OAAO,MAAM,IAAI,EAAE;AACzB,UAAI,CAAC,QAAQ,KAAK,WAAY,QAAO;AACrC,UAAI,KAAK,YAAY,gBAAiB,QAAO;AAC7C,YAAM,OAAO,EAAE;AACf,iBAAW,CAAC,UAAU,MAAM,KAAK,MAAO,KAAI,OAAO,eAAe,GAAI,OAAM,OAAO,QAAQ;AAC3F,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,iBAAiB,SAAS;AAC9B,YAAM,QAAQ,CAAC,GAAG,WAAW,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK,UAAU,EAAE;AACnF,kBAAY,OAAO,OAAO;AAC1B,uBAAiB,OAAO,OAAO;AAC/B,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,2BAA2B,SAAS,OAAO,KAAK;AACpD,YAAM,OAAO,UAAU,OAAO;AAC9B,YAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,iBAAWA,QAAO,MAAM;AACtB,cAAM,WAAW,KAAK,MAAMA,KAAI,SAAS,IAAI,MAAM;AACnD,YAAIA,KAAI,WAAW,aAAa,SAAS,SAAU,QAAO,OAAOA,MAAK,EAAE,QAAQ,UAAU,OAAO,iBAAiB,YAAY,IAAI,KAAK,QAAQ,EAAE,YAAY,EAAE,CAAC;AAAA,MAClK;AACA,YAAM,UAAU;AAAA,QACd,KAAK,IAAI,CAACA,UAAS,EAAE,QAAQA,KAAI,QAAQ,aAAa,KAAK,MAAMA,KAAI,SAAS,GAAG,WAAWA,KAAI,aAAa,KAAK,MAAMA,KAAI,UAAU,IAAI,KAAK,EAAE;AAAA,QACjJ;AAAA,QACA;AAAA,MACF;AACA,UAAI,QAAS,QAAO;AACpB,YAAM,MAA6B,EAAE,IAAI,OAAO,WAAW,GAAG,WAAW,KAAK,YAAY,MAAM,QAAQ,WAAW,QAAQ,CAAC,GAAG,OAAO,MAAM,eAAe,KAAK;AAChK,WAAK,KAAK,GAAG;AACb,aAAO,gBAAgB,GAAG;AAAA,IAC5B;AAAA,IAEA,MAAM,4BAA4B,SAAS,OAAO,SAAS;AACzD,YAAM,MAAM,UAAU,OAAO,EAAE,KAAK,CAAC,cAAc,UAAU,OAAO,KAAK;AACzE,UAAI,KAAK,WAAW,UAAW,QAAO;AACtC,aAAO,OAAO,KAAK,EAAE,QAAQ,QAAQ,QAAQ,YAAY,QAAQ,YAAY,OAAO,QAAQ,SAAS,MAAM,eAAe,QAAQ,iBAAiB,KAAK,CAAC;AACzJ,aAAO;AAAA,IACT;AAAA,IAEA,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,QAAQ,UAAU,KAAK,QAAQ;AAC1C,6BAAqB,MAAM;AAC3B,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,YAAM,MAAM,UAAU,OAAO,EAAE,KAAK,CAAC,cAAc,UAAU,OAAO,MAAM,KAAK;AAC/E,UAAI,KAAK,WAAW,UAAW,QAAO;AACtC,YAAM,QAAQ,WAAW,OAAO;AAChC,iBAAW,EAAE,UAAU,KAAK,QAAQ;AAClC,mBAAW,EAAE,IAAI,QAAQ,KAAK,WAAW;AACvC,gBAAM,WAAW,MAAM,IAAI,EAAE;AAC7B,cAAI,CAAC,YAAY,SAAS,cAAc,SAAS,YAAY,QAAS,QAAO;AAAA,QAC/E;AAAA,MACF;AACA,YAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,YAAM,SAA6B,OAAO,IAAI,CAAC,EAAE,QAAQ,UAAU,MAAM;AACvE,cAAM,UAAsB,EAAE,IAAI,OAAO,WAAW,GAAG,YAAY,CAAC,GAAG,OAAO,UAAU,GAAG,SAAS,OAAO,SAAS,SAAS,GAAG,WAAW,KAAK,WAAW,IAAI;AAC/J,cAAM,IAAI,QAAQ,IAAI,OAAO;AAC7B,mBAAW,EAAE,GAAG,KAAK,UAAW,OAAM,IAAI,EAAE,EAAG,aAAa,QAAQ;AACpE,eAAO,EAAE,UAAU,QAAQ,IAAI,aAAa,UAAU,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,eAAe,EAAE;AAAA,MAC9F,CAAC;AACD,aAAO,OAAO,KAAK,EAAE,QAAQ,WAAW,YAAY,MAAM,YAAY,QAAQ,eAAe,MAAM,iBAAiB,KAAK,CAAC;AAC1H,aAAO,gBAAgB,GAAG;AAAA,IAC5B;AAAA,IAEA,MAAM,kBAAkB,SAAS,OAAO,OAAO;AAC7C,YAAM,MAAM,UAAU,OAAO,EAAE,KAAK,CAAC,cAAc,UAAU,OAAO,KAAK;AACzE,UAAI,KAAK,WAAW,UAAW,QAAO;AACtC,YAAM,QAAQ,WAAW,OAAO;AAChC,YAAM,SAAS,IAAI,OAAO;AAAA,QACxB,CAAC,EAAE,UAAU,aAAa,cAAc,MACtC,MAAM,IAAI,QAAQ,GAAG,YAAY,iBAAiB,CAAC,MAAM,IAAI,QAAQ,GAAG,cAAc,YAAY,MAAM,CAAC,OAAO,MAAM,IAAI,EAAE,GAAG,eAAe,QAAQ;AAAA,MAC1J;AACA,UAAI,CAAC,OAAQ,QAAO;AACpB,UAAI,OAAO;AACT,cAAM,YAAY,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,EAAE,SAAS,MAAM,QAAQ,CAAC;AACpE,cAAM,cAAc,IAAI,IAAI,IAAI,OAAO,QAAQ,CAAC,EAAE,YAAY,MAAM,WAAW,CAAC;AAChF,cAAM,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC;AACjC,cAAM,YAAY,YAAY,OAAO,OAAO,CAAC,SAAS,CAAC,KAAK,cAAc,CAAC,UAAU,IAAI,KAAK,EAAE,CAAC,CAAC,EAAE,IAAI,UAAU;AAClH,cAAM,WAAW,YAAY,OAAO,OAAO,CAAC,SAAS,YAAY,IAAI,KAAK,EAAE,CAAC,CAAC,EAAE,IAAI,UAAU;AAC9F,cAAM,QAAQ,MAAM,gBAAgB,SAAS,GAAG,gBAAgB,QAAQ,CAAC;AACzE,YAAI,MAAO,QAAO,cAAc,KAAK;AAAA,MACvC;AACA,iBAAW,EAAE,UAAU,YAAY,KAAK,IAAI,QAAQ;AAClD,cAAM,OAAO,QAAQ;AACrB,mBAAW,MAAM,YAAa,QAAO,MAAM,IAAI,EAAE,EAAG;AAAA,MACtD;AACA,UAAI,SAAS;AACb,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,2BAA2B,SAAS,QAAQ;AAChD,YAAM,OAAO,UAAU,OAAO,EAC3B,IAAI,CAAC,KAAK,WAAW,EAAE,KAAK,MAAM,EAAE,EACpC,OAAO,CAAC,EAAE,IAAI,MAAM,CAAC,QAAQ,UAAU,OAAO,OAAO,SAAS,IAAI,MAAM,CAAC,EACzE,KAAK,CAAC,MAAM,UAAU,MAAM,IAAI,UAAU,cAAc,KAAK,IAAI,SAAS,KAAK,MAAM,QAAQ,KAAK,KAAK,EACvG,IAAI,CAAC,EAAE,IAAI,MAAM,GAAG;AACvB,aAAO,gBAAgB,QAAQ,UAAU,SAAY,OAAO,KAAK,MAAM,GAAG,OAAO,KAAK,CAAC;AAAA,IACzF;AAAA,IAEA,MAAM,sBAAsB,SAAS;AACnC,YAAM,SAAS,CAAC,GAAG,WAAW,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,SAAsD,QAAQ,KAAK,UAAU,CAAC;AACvI,aAAO,gBAAgB,YAAY,MAAM,CAAuB;AAAA,IAClE;AAAA,EACF;AACF;AAGA,SAAS,gBAAgB,MAAY,WAA8B,WAAoB;AACrF,MAAI,aAAa,UAAW,QAAO;AACnC,SAAO,aAAa,SAAS,KAAK,eAAe,SAAY,KAAK,eAAe;AACnF;AAGA,SAAS,aAA2D,MAAY;AAC9E,QAAM,EAAE,MAAM,OAAO,aAAa,cAAc,GAAG,KAAK,IAAI;AAC5D,SAAO,EAAE,GAAG,MAAM,GAAG,eAAe,gBAAgB,IAAI,CAAC,EAAE;AAC7D;AAGA,SAAS,iBAAmC,OAAa;AACvD,SAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,IAAI,MAAM,SAAS,MAAS,CAAC;AAC1F;","names":["run"]}
1
+ {"version":3,"sources":["../src/memory/memory-optimization.ts","../src/storage/postgres-migrations.ts","../src/request-origin/request-origin.ts","../src/storage/in-memory-storage.ts"],"sourcesContent":["import type { MemoryError, MemoryNote, MemoryNoteInput } from \"./long-term-memory\";\n\n/**\n * Состояние запуска оптимизации дублей: идёт → слито / нечего сливать / не удалось; слитое можно вернуть (`reverted`).\n * Запуск `running` у человека не больше одного.\n */\nexport type MemoryOptimizationStatus = \"running\" | \"applied\" | \"no_changes\" | \"failed\" | \"reverted\";\n\n/** Одна склейка: записи `originalIds` скрыты и подчинены новой записи `resultId`. */\nexport interface MemoryMergeGroup {\n resultId: string;\n originalIds: string[];\n /** Версия результата на момент слияния: пока она та же, результат не менялся и слияние можно вернуть. */\n resultVersion: number;\n}\n\n/** Запуск оптимизации. Владелец (`ownerId`) — свойство хранилища и наружу не выдаётся. */\nexport interface MemoryOptimizationRun {\n id: string;\n /** Время в формате ISO 8601. Часы даёт вызывающий: от них считаются срок между запусками и пауза после сбоя. */\n startedAt: string;\n finishedAt: string | null;\n status: MemoryOptimizationStatus;\n /** Склейки запуска; у не слитых запусков пусто. */\n groups: MemoryMergeGroup[];\n /** Причина сбоя одним словом-кодом; у остальных `null`. */\n error: string | null;\n /** Запись расхода модели, если вызывающий её знает. */\n usageRecordId: string | null;\n}\n\n/** Правила запуска: их проверяет хранилище в той же операции, что и берёт запуск, чтобы два процесса не начали его вдвоём. */\nexport interface MemoryOptimizationRules {\n /** Сколько должно пройти после законченного запуска (слито, нечего сливать, отменено) до следующего. */\n minIntervalMs: number;\n /**\n * Сколько должно пройти после неудачного запуска до повтора. Число — одна пауза на все неудачи; список — паузы после\n * 1-й, 2-й, … неудачи подряд (последняя держится дальше). Успешный, пустой или отменённый запуск начинает счёт заново.\n */\n retryAfterFailureMs: number | readonly number[];\n /** Сколько запуск `running` считается живым; после этого срока он становится неудачным (`failed`, ошибка `lease_expired`). */\n leaseMs: number;\n}\n\n/** Чем закончился запуск без слияния. */\nexport interface MemoryOptimizationOutcome {\n status: \"no_changes\" | \"failed\";\n finishedAt: string;\n error?: string | null;\n usageRecordId?: string | null;\n}\n\n/** Что слить: новая запись-результат вместо оригиналов; версии оригиналов — те, что видел планировщик. */\nexport interface MemoryMergeInput {\n runId: string;\n finishedAt: string;\n usageRecordId?: string | null;\n merges: { result: MemoryNoteInput; originals: { id: string; version: number }[] }[];\n}\n\n/** Скрытая запись слияния: оригинал, подчинённый результату. Список, блок памяти и поиск таких записей не видят. */\nexport interface MergedMemoryNote extends MemoryNote {\n mergedInto: string;\n}\n\nexport type MemoryMergeApplyResult = MemoryOptimizationRun | \"stale_version\" | \"run_not_active\";\n/** `limit_reached` и `duplicate` — возврат вышел бы за пределы памяти или вернул бы повтор записи, сделанной за это время. */\nexport type MemoryMergeRevertResult = \"ok\" | \"not_found\" | \"conflict\" | \"limit_reached\" | \"duplicate\";\n\n/** Запуск в том виде, что нужен для решения «можно ли начать новый»; время — миллисекунды. */\nexport interface OptimizationRunTiming {\n status: MemoryOptimizationStatus;\n startedAtMs: number;\n /** Конец запуска; у идущего его нет. */\n endedAtMs: number | null;\n}\n\n/** Пауза после неудачи с номером `failuresInRow` (с 1) подряд. */\nexport function pauseAfterFailure(rules: Pick<MemoryOptimizationRules, \"retryAfterFailureMs\">, failuresInRow: number): number {\n const { retryAfterFailureMs } = rules;\n if (typeof retryAfterFailureMs === \"number\") return retryAfterFailureMs;\n return retryAfterFailureMs[Math.min(failuresInRow, retryAfterFailureMs.length) - 1] ?? 0;\n}\n\n/**\n * Мешает ли история запусков начать новый: идёт другой, или не вышла пауза после последнего. Пауза после неудачи\n * растёт с числом неудач подряд. Все три хранилища решают этим одним правилом.\n */\nexport function isOptimizationBlocked(runs: readonly OptimizationRunTiming[], rules: MemoryOptimizationRules, nowMs: number): boolean {\n const ordered = [...runs].sort((left, right) => left.startedAtMs - right.startedAtMs);\n let failuresInRow = 0;\n for (const run of ordered) {\n if (run.status === \"running\") return true;\n failuresInRow = run.status === \"failed\" ? failuresInRow + 1 : 0;\n const pause = run.status === \"failed\" ? pauseAfterFailure(rules, failuresInRow) : rules.minIntervalMs;\n if (nowMs - (run.endedAtMs ?? run.startedAtMs) < pause) return true;\n }\n return false;\n}\n\n/** Ответ отката слияния на ошибку проверки: повтор записи — `duplicate`, всё остальное (число, объём) — `limit_reached`. */\nexport function revertRefusal(error: MemoryError): \"limit_reached\" | \"duplicate\" {\n return error.kind === \"duplicate\" ? \"duplicate\" : \"limit_reached\";\n}\n","/** Соединение PostgreSQL, которое нужно помощнику миграций. Подходит `PoolClient` из `pg`: core от `pg` не зависит. */\nexport interface PostgresMigrationConnection {\n query(text: string, values?: unknown[]): Promise<{ rows: unknown[] }>;\n release(): void;\n}\n\nexport interface PostgresMigrationOptions<Connection extends PostgresMigrationConnection> {\n /** Новое соединение из пула, например `() => pool.connect()`; на каждую попытку — своё. */\n connect(): Promise<Connection>;\n /** Своя блокировка пакета: одновременно мигрирует только одна копия этого пакета. */\n lockKey: number;\n /** Миграции пакета на этом соединении, например `migrate(drizzle(connection), …)`. */\n migrate(connection: Connection): Promise<void>;\n /** Паузы перед повторами, если всё же столкнулись с соседом. */\n retryDelaysMs?: readonly number[];\n}\n\n/** Схема всех пакетов SDK. */\nexport const AGENT_CHAT_SCHEMA = \"agent_chat\";\n\n/** Общая блокировка на создание схемы: одна на все пакеты, держится только на `create schema`. */\nexport const AGENT_CHAT_SCHEMA_LOCK_KEY = 7_311_900_441;\n\nconst DEFAULT_RETRY_DELAYS_MS = [25, 50, 100, 200];\n\n/** Коды PostgreSQL «такое уже есть»: сосед создал то же самое одновременно с нами. */\nconst DUPLICATE_CODES = new Set([\"23505\", \"42P06\", \"42P07\", \"42710\"]);\n\n/**\n * Создаёт схему `agent_chat` и применяет миграции пакета так, чтобы пакеты могли стартовать одновременно на пустой базе.\n * Схема создаётся под общей блокировкой, затем она отпускается и берётся своя блокировка пакета: блокировки не\n * вложены, поэтому взаимной блокировки нет, а разные пакеты ждут друг друга только на создании схемы.\n * Столкнулись всё же («уже есть») — повтор с начала на новом соединении.\n */\nexport async function migratePostgresSchema<Connection extends PostgresMigrationConnection>(options: PostgresMigrationOptions<Connection>): Promise<void> {\n const delays = options.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS;\n for (let attempt = 0; ; attempt++) {\n try {\n return await migrateOnce(options);\n } catch (error) {\n if (attempt >= delays.length || !isDuplicateError(error)) throw error;\n await new Promise((resolve) => setTimeout(resolve, delays[attempt]));\n }\n }\n}\n\nasync function migrateOnce<Connection extends PostgresMigrationConnection>(options: PostgresMigrationOptions<Connection>): Promise<void> {\n const connection = await options.connect();\n try {\n if (!(await schemaExists(connection))) {\n await underLock(connection, AGENT_CHAT_SCHEMA_LOCK_KEY, () => connection.query(`create schema if not exists \"${AGENT_CHAT_SCHEMA}\"`));\n }\n await underLock(connection, options.lockKey, () => options.migrate(connection));\n } finally {\n connection.release();\n }\n}\n\nasync function schemaExists(connection: PostgresMigrationConnection): Promise<boolean> {\n const result = await connection.query(\"select 1 from pg_namespace where nspname = $1\", [AGENT_CHAT_SCHEMA]);\n return result.rows.length > 0;\n}\n\nasync function underLock(connection: PostgresMigrationConnection, key: number, work: () => Promise<unknown>): Promise<void> {\n await connection.query(\"select pg_advisory_lock($1)\", [key]);\n try {\n await work();\n } finally {\n await connection.query(\"select pg_advisory_unlock($1)\", [key]);\n }\n}\n\n/** Ошибка «уже есть» — у самой ошибки или в цепочке причин (drizzle заворачивает ошибку `pg` в свою). */\nfunction isDuplicateError(error: unknown): boolean {\n for (let current = error, depth = 0; current && depth < 5; current = (current as { cause?: unknown }).cause, depth++) {\n const code = (current as { code?: unknown }).code;\n if (typeof code === \"string\" && DUPLICATE_CODES.has(code)) return true;\n }\n return false;\n}\n","/**\n * Защита от запросов с чужих страниц. Браузер сам прикладывает к запросу куки человека, даже если запрос\n * отправила чужая страница (обычная HTML-форма, WebSocket). Отличить свою страницу от чужой помогают заголовки,\n * которые ставит только браузер: `Sec-Fetch-Site` и `Origin`. Порядок проверки как в Go 1.25 (CrossOriginProtection).\n */\n\nexport interface RequestOriginCheckOptions {\n /**\n * Чужие страницы, которым можно слать запросы с куками человека, например `[\"https://school.getcourse.ru\"]`\n * (схема, хост, порт). Шаблон `https://*.example.com` пускает все поддомены `example.com`, но не сам домен\n * и не `evil-example.com`. Свой сайт в список вносить не нужно.\n */\n allowedOrigins?: readonly string[] | undefined;\n /** Отказ: вызывается один раз на каждый новый адрес страницы, чтобы журнал не забивался. */\n onRefused?: (refusal: OriginRefusal) => void;\n}\n\n/**\n * Почему запрос отклонён. `cross_site` — браузер сам сказал, что страница чужая. `host_mismatch` — браузер старый\n * или адрес не https, и Origin не совпал ни с одним именем сервера (`hosts`): так бывает за прокси, который подменил Host.\n */\nexport type OriginRefusal = { origin: string; reason: \"cross_site\" } | { origin: string; reason: \"host_mismatch\"; hosts: string[] };\n\n/** Подсказка для журнала: что поправить, если отклонена своя страница. */\nexport function originRefusalHint(refusal: OriginRefusal): string {\n if (refusal.reason === \"host_mismatch\") {\n return (\n `отклонён запрос со страницы ${refusal.origin}: Origin не совпал с Host (${refusal.hosts.join(\", \")}). ` +\n \"Если сервер за прокси, за прокси передайте Host/X-Forwarded-Host (nginx: proxy_set_header Host $host; \" +\n \"proxy_set_header X-Forwarded-Host $host;). Если это чужая для сервера, но ваша страница, добавьте её адрес в allowedOrigins.\"\n );\n }\n return `отклонён запрос с чужой страницы ${refusal.origin}. Если это ваша страница, добавьте её адрес в allowedOrigins.`;\n}\n\n/** `true` — запрос со своей страницы, со страницы из списка или не из браузера. Метод запроса не смотрит. */\nexport type RequestOriginCheck = (request: Request) => boolean;\n\n/** Чтения (GET, HEAD, OPTIONS) не меняют данных: их ответ браузер чужой странице всё равно не покажет. */\nexport function isSafeMethod(method: string): boolean {\n const upper = method.toUpperCase();\n return upper === \"GET\" || upper === \"HEAD\" || upper === \"OPTIONS\";\n}\n\n/** Сколько разных отклонённых адресов запоминается для журнала. */\nconst MAX_REPORTED_ORIGINS = 100;\nconst MAX_REPORTED_LENGTH = 200;\n\nexport function createRequestOriginCheck(options: RequestOriginCheckOptions = {}): RequestOriginCheck {\n const isAllowed = allowedOriginsMatcher(options.allowedOrigins ?? []);\n const reported = new Set<string>();\n const refuse = (refusal: OriginRefusal): false => {\n const shown = refusal.origin.slice(0, MAX_REPORTED_LENGTH);\n if (options.onRefused && !reported.has(shown) && reported.size < MAX_REPORTED_ORIGINS) {\n reported.add(shown);\n options.onRefused({ ...refusal, origin: shown });\n }\n return false;\n };\n return (request) => {\n const origin = request.headers.get(\"origin\");\n if (origin !== null && isAllowed(origin)) return true;\n const site = request.headers.get(\"sec-fetch-site\");\n if (site !== null) {\n if (site === \"same-origin\" || site === \"none\") return true;\n return refuse({ origin: origin ?? `(без Origin, Sec-Fetch-Site: ${site})`, reason: \"cross_site\" });\n }\n // Нет ни того ни другого — не браузер (сервер, curl): куки человека чужая страница так не приложит.\n if (origin === null) return true;\n // Старый браузер без Sec-Fetch-Site: Origin должен совпасть с адресом самого сервера.\n const host = originHost(origin);\n const hosts = hostsOf(request);\n if (host !== null && hosts.has(host)) return true;\n return refuse({ origin, reason: \"host_mismatch\", hosts: [...hosts] });\n };\n}\n\n/** Метка вместо `*`: адрес с ней разбирает URL, а в настоящем имени хоста она не встречается. */\nconst WILDCARD_LABEL = \"wildcard-label-0\";\n\n/** Точные адреса и шаблоны поддоменов из `allowedOrigins`; неверная запись — ошибка сразу. */\nfunction allowedOriginsMatcher(entries: readonly string[]): (origin: string) => boolean {\n const exact = new Set<string>();\n const subdomainsOf: Array<{ protocol: string; port: string; suffix: string }> = [];\n for (const entry of entries) {\n const wildcard = /^(https?:\\/\\/)\\*\\.([^*]+)$/.exec(entry);\n const url = parsePageAddress(wildcard ? `${wildcard[1]}${WILDCARD_LABEL}.${wildcard[2]}` : entry);\n if (url === null || (!wildcard && entry.includes(\"*\"))) throw wrongEntry(entry);\n if (!wildcard) {\n exact.add(url.origin);\n continue;\n }\n const suffix = url.hostname.slice(WILDCARD_LABEL.length);\n // `*.com` пустил бы весь интернет: после звёздочки нужен домен хотя бы из двух частей (или localhost).\n // Точка в конце (`*.com.`) — тот же `*.com`. Общие суффиксы вроде `*.co.uk` так не отличить: вписывают свой домен.\n const tooBroad = suffix.endsWith(\".\") || (!suffix.slice(1).includes(\".\") && suffix !== \".localhost\");\n if (!url.hostname.startsWith(`${WILDCARD_LABEL}.`) || tooBroad) throw wrongEntry(entry);\n subdomainsOf.push({ protocol: url.protocol, port: url.port, suffix });\n }\n return (origin) => {\n const url = parseOrigin(origin);\n if (url === null) return false;\n if (exact.has(url.origin)) return true;\n return subdomainsOf.some(\n (pattern) =>\n url.protocol === pattern.protocol && url.port === pattern.port && url.hostname.endsWith(pattern.suffix) && url.hostname.length > pattern.suffix.length,\n );\n };\n}\n\n/** Адрес страницы: http(s), без пути, запроса, якоря и имени пользователя. Иначе `null`. */\nfunction parsePageAddress(entry: string): URL | null {\n try {\n const url = new URL(entry);\n const bare = url.pathname === \"/\" && !url.search && !url.hash && !url.username;\n return (url.protocol === \"http:\" || url.protocol === \"https:\") && bare ? url : null;\n } catch {\n return null;\n }\n}\n\nfunction wrongEntry(entry: string): Error {\n return new Error(\n `allowedOrigins: «${entry}» не адрес страницы; нужен вид https://app.example, http://localhost:5173 или https://*.example.com ` +\n \"(в шаблоне — свой домен: общие суффиксы вроде *.co.uk проверка не распознаёт)\",\n );\n}\n\nfunction parseOrigin(origin: string): URL | null {\n try {\n return new URL(origin);\n } catch {\n return null;\n }\n}\n\n/** Хост с портом из Origin; `null` и не адрес — `null`. */\nfunction originHost(origin: string): string | null {\n try {\n const url = new URL(origin);\n return url.protocol === \"http:\" || url.protocol === \"https:\" ? url.host : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Под какими именами сервер знает себя: `Host` и `X-Forwarded-Host` от прокси. Адрес запроса — только без `Host`:\n * при подъёме WebSocket в Node (`@hono/node-ws`) он собран как `http://localhost/…` и порта в нём нет.\n */\nfunction hostsOf(request: Request): Set<string> {\n const host = request.headers.get(\"host\");\n const hosts = new Set<string>([host ? host.trim().toLowerCase() : new URL(request.url).host]);\n for (const forwarded of request.headers.get(\"x-forwarded-host\")?.split(\",\") ?? []) {\n if (forwarded.trim()) hosts.add(forwarded.trim().toLowerCase());\n }\n return hosts;\n}\n","import type { ModelChoice } from \"../models/model-choice\";\nimport type { MemoryNote, MemoryNoteInput } from \"../memory/long-term-memory\";\nimport { isOptimizationBlocked, revertRefusal } from \"../memory/memory-optimization\";\nimport type { MemoryMergeGroup, MemoryOptimizationRun, MergedMemoryNote } from \"../memory/memory-optimization\";\nimport type { Chat, StoredBranchSelection, StoredCompaction, StoredMessage, UsageRecord, UsageSum } from \"../conversation/types\";\nimport {\n aliveAtByLocalClock,\n assertKnownFormatVersion,\n ChatAlreadyExistsError,\n DuplicateChatSubjectError,\n DuplicateMessageError,\n MessageAlreadyFinishedError,\n MessageNotAwaitingError,\n sameMessageParts,\n silenceBoundaryByLocalClock,\n} from \"./chat-storage\";\nimport { assertChatDataFilter, chatDataFields, chatDataMatches, chatDataOfInput, mergeChatData } from \"./chat-data\";\nimport type { ChatListOptions, ChatStorage, ChatSubjectFilter, SpendingLimitStateRecord, StoredPendingBurst } from \"./chat-storage\";\n\n/** Хранилище в памяти процесса — для тестов. Копирует данные на входе и выходе, как база. */\ntype StoredNote = MemoryNote & { mergedInto?: string };\n\n/** Сумма записей расхода по ключу (`group` — поля ключа: пара «модель × провайдер», у суммы по чатам — ещё чат). */\nfunction sumRecords<K extends Pick<UsageSum, \"modelId\" | \"providerId\">>(records: readonly UsageRecord[], group: (record: UsageRecord) => K): Array<K & UsageSum> {\n const sums = new Map<string, K & UsageSum>();\n for (const record of records) {\n const fields = group(record);\n const key = Object.values(fields).join(\"\\u0000\");\n const sum = sums.get(key) ?? { ...fields, inputTokens: 0, cachedInputTokens: 0, cacheWriteTokens: 0, outputTokens: 0, reasoningTokens: 0, costUsd: 0 };\n sum.inputTokens += record.inputTokens;\n sum.cachedInputTokens += record.cachedInputTokens;\n sum.cacheWriteTokens += record.cacheWriteTokens;\n sum.outputTokens += record.outputTokens;\n sum.reasoningTokens += record.reasoningTokens;\n sum.costUsd += record.costUsd;\n sums.set(key, sum);\n }\n return [...sums.values()];\n}\n\nexport function createInMemoryChatStorage(): ChatStorage {\n const chats = new Map<string, Chat>();\n const messages = new Map<string, StoredMessage>();\n /** Время последнего знака жизни идущих ответов по id: при чтении не отдаётся. */\n const aliveAt = new Map<string, string>();\n /** Аренды хода по чатам: кто держит и до какого времени (мс по часам этой машины). */\n const turnLeases = new Map<string, { holder: string; until: number }>();\n /** Ждущие пачки по чатам. */\n const pendingBursts = new Map<string, StoredPendingBurst>();\n const compactions: StoredCompaction[] = [];\n const branchSelections: StoredBranchSelection[] = [];\n const usageRecords: UsageRecord[] = [];\n const userModelChoices = new Map<string, ModelChoice>();\n const voiceChoices = new Map<string, string>();\n const spendingLimitStates = new Map<string, SpendingLimitStateRecord>();\n /** Долгая память: у каждого человека свои записи; у скрытых оригиналов слияния есть `mergedInto`. */\n const memoryNotes = new Map<string, Map<string, StoredNote>>();\n const optimizationRuns = new Map<string, MemoryOptimizationRun[]>();\n\n function streamingMessage(messageId: string): StoredMessage {\n const message = messages.get(messageId);\n if (!message) throw new Error(`Сообщения ${messageId} нет`);\n if (message.status !== \"streaming\") throw new MessageAlreadyFinishedError(messageId);\n return message;\n }\n\n /** Сообщение для чтения: копия, `voiceCut` — `null`, если не задан. */\n function readable(message: StoredMessage): StoredMessage {\n const copy = structuredClone(message);\n return { ...copy, voiceCut: copy.voiceCut ?? null };\n }\n\n function ownerNotes(ownerId: string): Map<string, StoredNote> {\n let notes = memoryNotes.get(ownerId);\n if (!notes) {\n notes = new Map();\n memoryNotes.set(ownerId, notes);\n }\n return notes;\n }\n\n function ownerRuns(ownerId: string): MemoryOptimizationRun[] {\n let runs = optimizationRuns.get(ownerId);\n if (!runs) {\n runs = [];\n optimizationRuns.set(ownerId, runs);\n }\n return runs;\n }\n\n /** Порядок списка по договору: `updatedAt`, затем `createdAt`, затем `id` — новее и больше первыми. */\n function newestFirst<T extends MemoryNote>(notes: T[]): T[] {\n return notes.sort(\n (left, right) =>\n right.updatedAt.localeCompare(left.updatedAt) ||\n right.createdAt.localeCompare(left.createdAt) ||\n (right.id > left.id ? 1 : right.id < left.id ? -1 : 0),\n );\n }\n\n /** Обычная запись без служебного признака скрытия. */\n function publicNote({ mergedInto: _hidden, ...note }: StoredNote): MemoryNote {\n return note;\n }\n\n /** Как база с NOT NULL: разделы — список строк, текст — строка. */\n function assertWellFormedNote(note: MemoryNoteInput): void {\n if (!Array.isArray(note?.categories) || !note.categories.every((category) => typeof category === \"string\")) {\n throw new TypeError(\"Разделы записи памяти — список строк\");\n }\n if (typeof note.content !== \"string\") throw new TypeError(\"Текст записи памяти — строка\");\n }\n\n /** Записи, которые видит человек: без скрытых оригиналов, копиями. */\n function visibleNotes(ownerId: string): MemoryNote[] {\n const visible = [...ownerNotes(ownerId).values()].filter((note) => !note.mergedInto);\n return structuredClone(newestFirst(visible).map(publicNote));\n }\n\n function insertNotes(ownerId: string, inputs: MemoryNoteInput[]): MemoryNote[] {\n // Сначала проверяем весь пакет: негодная запись не оставляет в памяти и остальных.\n inputs.forEach(assertWellFormedNote);\n const now = new Date().toISOString();\n const created = inputs.map(\n ({ categories, content }): MemoryNote => ({\n id: crypto.randomUUID(),\n categories: [...categories],\n content,\n version: 1,\n createdAt: now,\n updatedAt: now,\n }),\n );\n const notes = ownerNotes(ownerId);\n for (const note of created) notes.set(note.id, note);\n return structuredClone(created);\n }\n\n function updateNote(ownerId: string, id: string, expectedVersion: number, input: MemoryNoteInput): MemoryNote | \"not_found\" | \"stale_version\" {\n assertWellFormedNote(input);\n const notes = ownerNotes(ownerId);\n const note = notes.get(id);\n if (!note || note.mergedInto) return \"not_found\";\n if (note.version !== expectedVersion) return \"stale_version\";\n const updated: MemoryNote = {\n ...note,\n categories: [...input.categories],\n content: input.content,\n version: note.version + 1,\n updatedAt: new Date().toISOString(),\n };\n notes.set(id, updated);\n return structuredClone(updated);\n }\n\n /** Как уникальный индекс (владелец, ключ): чат без ключа не мешает никому. */\n function assertSubjectFree(chat: Pick<Chat, \"ownerId\" | \"subjectKey\">): void {\n if (chat.subjectKey === undefined) return;\n for (const existing of chats.values()) {\n if (existing.ownerId === chat.ownerId && existing.subjectKey === chat.subjectKey) {\n throw new DuplicateChatSubjectError(chat.ownerId, chat.subjectKey);\n }\n }\n }\n\n function sortedMessages(chatId: string): StoredMessage[] {\n return [...messages.values()]\n .filter((message) => message.chatId === chatId)\n .sort((left, right) => left.createdAt.localeCompare(right.createdAt));\n }\n\n return {\n async createChat({ createdAt, ...input }) {\n const at = createdAt ?? new Date().toISOString();\n const chat: Chat = withChatData(withoutUndefined({ ...structuredClone(input), createdAt: at, updatedAt: at }));\n assertSubjectFree(chat);\n chats.set(chat.id, chat);\n return structuredClone(chat);\n },\n\n async findChatBySubject(ownerId, subjectKey) {\n const chat = [...chats.values()].find((existing) => existing.ownerId === ownerId && existing.subjectKey === subjectKey);\n return chat ? structuredClone(chat) : null;\n },\n\n async importChat(input, imported) {\n // Сначала все проверки: при ошибке ничего не записано.\n if (chats.has(input.id)) throw new ChatAlreadyExistsError(input.id);\n const chat: Chat = withChatData(withoutUndefined(structuredClone(input)));\n assertSubjectFree(chat);\n const ids = new Set<string>();\n for (const message of imported) {\n if (messages.has(message.id) || ids.has(message.id)) throw new DuplicateMessageError(message.id);\n ids.add(message.id);\n }\n chats.set(chat.id, chat);\n for (const message of imported) {\n const { alive: _alive, ...stored } = message;\n messages.set(message.id, structuredClone(stored));\n }\n },\n\n async setAfterTurnState(messageId, state, options) {\n const message = messages.get(messageId);\n if (!message || (state !== \"pending\" && message.afterTurn !== \"pending\")) return false;\n const parts = options?.appendParts ? [...message.parts, ...structuredClone(options.appendParts)] : message.parts;\n messages.set(messageId, { ...message, parts, afterTurn: state });\n // Отметка ожидания хука — в той же колонке, что знак жизни: у законченного ответа она больше ни для чего.\n if (state === \"pending\") aliveAt.set(messageId, aliveAtByLocalClock(\"now\"));\n return true;\n },\n\n async listPendingAfterTurn(filter) {\n const boundary = filter?.pendingForMs === undefined ? null : silenceBoundaryByLocalClock(filter.pendingForMs);\n return [...messages.values()]\n .filter((message) => message.afterTurn === \"pending\")\n .filter((message) => boundary === null || (aliveAt.get(message.id) ?? message.createdAt) < boundary)\n .map((message) => message.id);\n },\n\n async getChat(chatId) {\n const chat = chats.get(chatId);\n return chat ? structuredClone(chat) : null;\n },\n\n async updateChatModel(chatId, model) {\n const chat = chats.get(chatId);\n if (!chat) return;\n const { reasoning: _dropped, ...rest } = chat;\n chats.set(chatId, { ...rest, ...model });\n },\n\n async listChats(ownerId, options?: ChatListOptions) {\n if (options?.data) assertChatDataFilter(options.data);\n const owned = [...chats.values()].filter(\n (chat) => chat.ownerId === ownerId && matchesSubjects(chat, options?.subjects) && (!options?.data || chatDataMatches(chat.data, options.data)),\n );\n owned.sort(\n (left, right) =>\n right.updatedAt.localeCompare(left.updatedAt) ||\n right.createdAt.localeCompare(left.createdAt) ||\n (right.id > left.id ? 1 : right.id < left.id ? -1 : 0),\n );\n return structuredClone(owned);\n },\n\n async updateChatData(chatId, patch, { maxBytes }) {\n const chat = chats.get(chatId);\n if (!chat) return null;\n // Слияние и проверка размера до записи: при ошибке данные прежние.\n const merged = mergeChatData(chat.data, patch, maxBytes);\n const { data: _data, subjectData: _subjectData, ...rest } = chat;\n const updated: Chat = { ...rest, ...chatDataFields(merged) };\n chats.set(chatId, updated);\n return structuredClone(updated);\n },\n\n async renameChat(chatId, title) {\n const chat = chats.get(chatId);\n if (!chat) return;\n const { title: _dropped, ...rest } = chat;\n chats.set(chatId, title === null ? rest : { ...rest, title });\n },\n\n async setChatClosed(chatId, closed) {\n const chat = chats.get(chatId);\n if (!chat) return;\n const { closed: _dropped, ...rest } = chat;\n chats.set(chatId, closed === null ? rest : { ...rest, closed: { code: closed.code, message: closed.message } });\n },\n\n async deleteChat(chatId) {\n if (!chats.delete(chatId)) return;\n turnLeases.delete(chatId);\n pendingBursts.delete(chatId);\n for (const message of [...messages.values()]) {\n if (message.chatId !== chatId) continue;\n messages.delete(message.id);\n aliveAt.delete(message.id);\n }\n // Записи сжатия — на месте, с обратным ходом, чтобы индексы не сдвигались.\n for (let index = compactions.length - 1; index >= 0; index -= 1) {\n if (compactions[index]!.chatId === chatId) compactions.splice(index, 1);\n }\n for (let index = branchSelections.length - 1; index >= 0; index -= 1) {\n if (branchSelections[index]!.chatId === chatId) branchSelections.splice(index, 1);\n }\n },\n\n async getMessage(messageId) {\n const message = messages.get(messageId);\n if (!message) return null;\n assertKnownFormatVersion(message);\n return readable(message);\n },\n\n async listMessages(chatId) {\n const found = sortedMessages(chatId);\n found.forEach(assertKnownFormatVersion);\n return found.map(readable);\n },\n\n async listMessageLinks(chatId) {\n return sortedMessages(chatId).map(({ id, parentId, createdAt }) => ({ id, parentId, createdAt }));\n },\n\n async listMessagePartsOfTypes(chatId, types) {\n return sortedMessages(chatId).map(({ id, parentId, createdAt, parts }) => ({\n id,\n parentId,\n createdAt,\n parts: structuredClone(parts.filter((part) => types.includes(part.type))),\n }));\n },\n\n async insertMessage(message) {\n if (messages.has(message.id)) throw new DuplicateMessageError(message.id);\n // Как внешний ключ в базе: сообщение без чата не пишется.\n const chat = chats.get(message.chatId);\n if (!chat) throw new Error(`Чата ${message.chatId} нет`);\n const { alive, ...stored } = message;\n messages.set(message.id, structuredClone(stored));\n if (alive) aliveAt.set(message.id, aliveAtByLocalClock(alive));\n chats.set(chat.id, { ...chat, updatedAt: message.createdAt });\n },\n\n async updateStreamingMessage(messageId, patch) {\n const message = streamingMessage(messageId);\n const { alive, ...rest } = structuredClone(patch);\n messages.set(messageId, { ...message, ...rest });\n if (alive) aliveAt.set(messageId, aliveAtByLocalClock(alive));\n },\n\n async markAnswerAlive(messageId) {\n streamingMessage(messageId);\n aliveAt.set(messageId, aliveAtByLocalClock(\"now\"));\n },\n\n async finishMessage(messageId, final) {\n const message = streamingMessage(messageId);\n messages.set(messageId, { ...message, ...structuredClone(final) });\n if (final.afterTurn === \"pending\") aliveAt.set(messageId, aliveAtByLocalClock(\"now\"));\n },\n\n async updateAwaitingMessage(messageId, patch) {\n const message = messages.get(messageId);\n if (!message) throw new Error(`Сообщения ${messageId} нет`);\n if (message.status !== \"awaiting_approval\") throw new MessageNotAwaitingError(messageId);\n if (patch.expectedParts && !sameMessageParts(message.parts, patch.expectedParts)) throw new MessageNotAwaitingError(messageId);\n messages.set(messageId, {\n ...message,\n parts: structuredClone(patch.parts),\n ...(patch.status && { status: patch.status }),\n });\n if (patch.alive) aliveAt.set(messageId, aliveAtByLocalClock(patch.alive));\n },\n\n async listStreamingMessageIds() {\n return [...messages.values()].filter((message) => message.status === \"streaming\").map((message) => message.id);\n },\n\n async listSilentAnswerIds({ silentForMs, chatId }) {\n const boundary = silenceBoundaryByLocalClock(silentForMs);\n return [...messages.values()]\n .filter((message) => message.status === \"streaming\" && (chatId === undefined || message.chatId === chatId))\n .filter((message) => (aliveAt.get(message.id) ?? message.createdAt) < boundary)\n .map((message) => message.id);\n },\n\n async claimChatTurn(chatId, holder, leaseMs) {\n const now = Date.now();\n const lease = turnLeases.get(chatId);\n if (lease && lease.holder !== holder && lease.until > now) return false;\n turnLeases.set(chatId, { holder, until: now + leaseMs });\n return true;\n },\n\n async releaseChatTurn(chatId, holder) {\n if (turnLeases.get(chatId)?.holder === holder) turnLeases.delete(chatId);\n },\n\n async clearChatTurnLeases() {\n turnLeases.clear();\n },\n\n async savePendingBurst(burst) {\n pendingBursts.set(burst.chatId, structuredClone(burst));\n },\n\n async takeAbandonedBursts({ abandonedBefore, holder, heldUntil, limit, exceptHolder }) {\n const abandoned = [...pendingBursts.values()]\n .filter((burst) => Date.parse(burst.heldUntil) <= Date.parse(abandonedBefore) && burst.holder !== exceptHolder)\n .sort((first, second) => Date.parse(first.dueAt) - Date.parse(second.dueAt))\n .slice(0, limit);\n return abandoned.map((burst) => {\n const taken = { ...burst, holder, heldUntil };\n pendingBursts.set(burst.chatId, taken);\n return structuredClone(taken);\n });\n },\n\n async renewPendingBurst({ chatId, messageId, holder, heldUntil }) {\n const burst = pendingBursts.get(chatId);\n if (burst?.messageId !== messageId || burst.holder !== holder) return false;\n pendingBursts.set(chatId, { ...burst, heldUntil });\n return true;\n },\n\n async removePendingBurst(chatId, messageId) {\n if (pendingBursts.get(chatId)?.messageId === messageId) pendingBursts.delete(chatId);\n },\n\n async insertCompaction(record) {\n if (compactions.some((existing) => existing.id === record.id)) throw new Error(`Запись сжатия ${record.id} уже есть`);\n compactions.push(structuredClone(record));\n },\n\n async listCompactions(chatId) {\n return structuredClone(compactions.filter((record) => record.chatId === chatId));\n },\n\n async insertBranchSelection(record) {\n if (branchSelections.some((existing) => existing.id === record.id)) throw new Error(`Выбор ветки ${record.id} уже есть`);\n branchSelections.push(structuredClone(record));\n },\n\n async listBranchSelections(chatId) {\n return structuredClone(branchSelections.filter((record) => record.chatId === chatId));\n },\n\n async insertUsageRecord(record) {\n if (usageRecords.some((existing) => existing.id === record.id)) throw new Error(`Запись расхода ${record.id} уже есть`);\n usageRecords.push(structuredClone(record));\n },\n\n async hasUsageRecord(id) {\n return usageRecords.some((record) => record.id === id);\n },\n\n async sumUsage({ ownerId, chatId, messageId, source, since }) {\n return sumRecords(\n usageRecords.filter(\n (record) =>\n (ownerId === undefined || record.ownerId === ownerId) &&\n (chatId === undefined || record.chatId === chatId) &&\n (messageId === undefined || record.messageId === messageId) &&\n (source === undefined || record.source === source) &&\n (since === undefined || record.createdAt >= since),\n ),\n (record) => ({ modelId: record.modelId, providerId: record.providerId }),\n );\n },\n\n async sumUsageByChat({ chatIds, ownerId, source, since }) {\n const wanted = new Set(chatIds);\n return sumRecords(\n usageRecords.filter(\n (record) =>\n wanted.has(record.chatId) &&\n (ownerId === undefined || record.ownerId === ownerId) &&\n (source === undefined || record.source === source) &&\n (since === undefined || record.createdAt >= since),\n ),\n (record) => ({ chatId: record.chatId, modelId: record.modelId, providerId: record.providerId }),\n );\n },\n\n async setVoiceCut({ ownerId, chatId, messageId, voiceCut }) {\n const message = messages.get(messageId);\n if (!message || message.chatId !== chatId || chats.get(chatId)?.ownerId !== ownerId) return;\n messages.set(messageId, { ...message, voiceCut: structuredClone(voiceCut) });\n },\n\n async getSpendingLimitState(key) {\n const record = spendingLimitStates.get(key);\n return record ? { ...record } : null;\n },\n\n async saveSpendingLimitState(key, value, expectedVersion) {\n const current = spendingLimitStates.get(key);\n if ((current?.version ?? null) !== expectedVersion) return false;\n spendingLimitStates.set(key, { value, version: (current?.version ?? 0) + 1 });\n return true;\n },\n\n async deleteSpendingLimitStates(keys) {\n for (const key of keys) spendingLimitStates.delete(key);\n },\n\n async getVoiceChoice(ownerId) {\n return voiceChoices.get(ownerId) ?? null;\n },\n\n async setVoiceChoice(ownerId, voiceId) {\n voiceChoices.set(ownerId, voiceId);\n },\n\n async getUserModelChoice(ownerId) {\n const choice = userModelChoices.get(ownerId);\n return choice ? structuredClone(choice) : null;\n },\n\n async saveUserModelChoice(ownerId, choice) {\n userModelChoices.set(ownerId, structuredClone(choice));\n },\n\n async listMemoryNotes(ownerId) {\n return visibleNotes(ownerId);\n },\n\n async insertMemoryNotes(ownerId, inputs) {\n return insertNotes(ownerId, inputs);\n },\n\n // Всё выполняется без ожидания, поэтому между проверкой и вставкой никто не успеет вклиниться.\n async insertMemoryNotesChecked(ownerId, inputs, guard) {\n const error = guard(visibleNotes(ownerId));\n return error ?? insertNotes(ownerId, inputs);\n },\n\n async updateMemoryNote(ownerId, id, expectedVersion, input) {\n return updateNote(ownerId, id, expectedVersion, input);\n },\n\n async updateMemoryNoteChecked(ownerId, id, expectedVersion, input, guard) {\n return guard(visibleNotes(ownerId)) ?? updateNote(ownerId, id, expectedVersion, input);\n },\n\n async deleteMemoryNote(ownerId, id, expectedVersion) {\n const notes = ownerNotes(ownerId);\n const note = notes.get(id);\n if (!note || note.mergedInto) return \"not_found\";\n if (note.version !== expectedVersion) return \"stale_version\";\n notes.delete(id);\n for (const [hiddenId, hidden] of notes) if (hidden.mergedInto === id) notes.delete(hiddenId);\n return \"ok\";\n },\n\n async clearMemoryNotes(ownerId) {\n const count = [...ownerNotes(ownerId).values()].filter((note) => !note.mergedInto).length;\n memoryNotes.delete(ownerId);\n optimizationRuns.delete(ownerId);\n return count;\n },\n\n async claimMemoryOptimizationRun(ownerId, rules, now) {\n const runs = ownerRuns(ownerId);\n const nowMs = Date.parse(now);\n for (const run of runs) {\n const leaseEnd = Date.parse(run.startedAt) + rules.leaseMs;\n if (run.status === \"running\" && nowMs >= leaseEnd) Object.assign(run, { status: \"failed\", error: \"lease_expired\", finishedAt: new Date(leaseEnd).toISOString() });\n }\n const blocked = isOptimizationBlocked(\n runs.map((run) => ({ status: run.status, startedAtMs: Date.parse(run.startedAt), endedAtMs: run.finishedAt ? Date.parse(run.finishedAt) : null })),\n rules,\n nowMs,\n );\n if (blocked) return null;\n const run: MemoryOptimizationRun = { id: crypto.randomUUID(), startedAt: now, finishedAt: null, status: \"running\", groups: [], error: null, usageRecordId: null };\n runs.push(run);\n return structuredClone(run);\n },\n\n async finishMemoryOptimizationRun(ownerId, runId, outcome) {\n const run = ownerRuns(ownerId).find((candidate) => candidate.id === runId);\n if (run?.status !== \"running\") return \"not_found\";\n Object.assign(run, { status: outcome.status, finishedAt: outcome.finishedAt, error: outcome.error ?? null, usageRecordId: outcome.usageRecordId ?? null });\n return \"ok\";\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 { result, originals } of merges) {\n assertWellFormedNote(result);\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 const run = ownerRuns(ownerId).find((candidate) => candidate.id === merge.runId);\n if (run?.status !== \"running\") return \"run_not_active\";\n const notes = ownerNotes(ownerId);\n for (const { originals } of merges) {\n for (const { id, version } of originals) {\n const original = notes.get(id);\n if (!original || original.mergedInto || original.version !== version) return \"stale_version\";\n }\n }\n const now = new Date().toISOString();\n const groups: MemoryMergeGroup[] = merges.map(({ result, originals }) => {\n const created: StoredNote = { id: crypto.randomUUID(), categories: [...result.categories], content: result.content, version: 1, createdAt: now, updatedAt: now };\n notes.set(created.id, created);\n for (const { id } of originals) notes.get(id)!.mergedInto = created.id;\n return { resultId: created.id, originalIds: originals.map(({ id }) => id), resultVersion: 1 };\n });\n Object.assign(run, { status: \"applied\", finishedAt: merge.finishedAt, groups, usageRecordId: merge.usageRecordId ?? null });\n return structuredClone(run);\n },\n\n async revertMemoryMerge(ownerId, runId, guard) {\n const run = ownerRuns(ownerId).find((candidate) => candidate.id === runId);\n if (run?.status !== \"applied\") return \"not_found\";\n const notes = ownerNotes(ownerId);\n const intact = run.groups.every(\n ({ resultId, originalIds, resultVersion }) =>\n notes.get(resultId)?.version === resultVersion && !notes.get(resultId)?.mergedInto && originalIds.every((id) => notes.get(id)?.mergedInto === resultId),\n );\n if (!intact) return \"conflict\";\n if (guard) {\n const resultIds = new Set(run.groups.map(({ resultId }) => resultId));\n const restoredIds = new Set(run.groups.flatMap(({ originalIds }) => originalIds));\n const inPlay = [...notes.values()];\n const remaining = newestFirst(inPlay.filter((note) => !note.mergedInto && !resultIds.has(note.id))).map(publicNote);\n const restored = newestFirst(inPlay.filter((note) => restoredIds.has(note.id))).map(publicNote);\n const error = guard(structuredClone(remaining), structuredClone(restored));\n if (error) return revertRefusal(error);\n }\n for (const { resultId, originalIds } of run.groups) {\n notes.delete(resultId);\n for (const id of originalIds) delete notes.get(id)!.mergedInto;\n }\n run.status = \"reverted\";\n return \"ok\";\n },\n\n async listMemoryOptimizationRuns(ownerId, filter) {\n const runs = ownerRuns(ownerId)\n .map((run, index) => ({ run, index }))\n .filter(({ run }) => !filter?.status || filter.status.includes(run.status))\n .sort((left, right) => right.run.startedAt.localeCompare(left.run.startedAt) || right.index - left.index)\n .map(({ run }) => run);\n return structuredClone(filter?.limit === undefined ? runs : runs.slice(0, filter.limit));\n },\n\n async listMergedMemoryNotes(ownerId) {\n const hidden = [...ownerNotes(ownerId).values()].filter((note): note is StoredNote & { mergedInto: string } => Boolean(note.mergedInto));\n return structuredClone(newestFirst(hidden) as MergedMemoryNote[]);\n },\n };\n}\n\n/** Подходит ли чат под фильтр `listChats` по ключу объекта. */\nfunction matchesSubjects(chat: Chat, subjects: ChatSubjectFilter = \"exclude\"): boolean {\n if (subjects === \"include\") return true;\n return subjects === \"only\" ? chat.subjectKey !== undefined : chat.subjectKey === undefined;\n}\n\n/** `data` и `subjectData` — один объект; данных нет — полей нет. */\nfunction withChatData<T extends Pick<Chat, \"data\" | \"subjectData\">>(chat: T): T {\n const { data: _data, subjectData: _subjectData, ...rest } = chat;\n return { ...rest, ...chatDataFields(chatDataOfInput(chat)) } as T;\n}\n\n/** Как база: поле без значения не хранится. */\nfunction withoutUndefined<T extends object>(value: T): T {\n return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined)) as T;\n}\n"],"mappings":"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","names":["run"]}
@@ -13,7 +13,7 @@ import {
13
13
  extendCatalog,
14
14
  newStoredMessage,
15
15
  standardCatalog
16
- } from "./chunk-KAG3QTZC.js";
16
+ } from "./chunk-QA5DVEXF.js";
17
17
  import "./chunk-FOAIG4DY.js";
18
18
 
19
19
  // src/storage/storage-contract.ts
@@ -6,6 +6,7 @@ import type { ModelSilenceLimits } from "../provider-errors/model-silence.js";
6
6
  import type { ModelCallObservation } from "./observe-model-calls.js";
7
7
  import type { ModeNotes } from "./mode-notes.js";
8
8
  import type { FrozenContextData } from "../frozen-context/context-blocks.js";
9
+ import type { ServiceBlockFormat } from "./forged-blocks.js";
9
10
  export interface ModelRequest {
10
11
  model: LanguageModel;
11
12
  /** Строка; сообщением `system` — если провайдер просит метку кэша на инструкции. */
@@ -50,6 +51,11 @@ export declare function buildModelRequest(input: {
50
51
  */
51
52
  switchableTools?: ReadonlySet<string>;
52
53
  history: readonly AgentChatMessage[];
54
+ /**
55
+ * Служебные форматы (`CORE_SERVICE_BLOCKS` и форматы пакетов и приложения): поддельные блоки в прошлых ответах агента
56
+ * вырезаются только в запросе, хранилище не меняется; из той же истории — тот же запрос (кэш). Нет — ответы как есть.
57
+ */
58
+ serviceBlocks?: readonly ServiceBlockFormat[];
53
59
  /** Вложения: части `file` истории заменяются тем, что увидит выбранная модель. Нет расширения — части убираются. */
54
60
  attachments?: MessageAttachments;
55
61
  /**
@@ -0,0 +1,117 @@
1
+ import type { LanguageModel } from "ai";
2
+ import type { AgentChatMessage } from "../conversation/types.js";
3
+ type MessagePart = AgentChatMessage["parts"][number];
4
+ /**
5
+ * Формат служебного блока, который SDK или приложение кладёт в запрос модели. Модель иногда повторяет такой блок в своём
6
+ * ответе (дописала человеку «блок памяти» с номером заметки) — повтор вырезается.
7
+ * - `{ tag }` — блок `<tag …>…</tag>`. Открывающий тег — с начала строки (до трёх пробелов), а после него в той же
8
+ * строке — ничего, начало данных (`[`, `{`, `"`) или закрывающий тег: тег посреди фразы или с пояснением («— это …») —
9
+ * упоминание. Закрывающий — где угодно после; нет его — блок до первой пустой строки. Закрывающий тег без
10
+ * открывающего не трогается.
11
+ * - `{ name, line }` — служебная строка: начинается с `line` (с начала строки), а если задан `match` — вся строка (без
12
+ * отступа и пробелов в конце) подходит под него. `until: "paragraph"` — блок до пустой строки; `until: RegExp` — до
13
+ * строки, которая подходит под выражение, включительно.
14
+ * Код (блоки ```, отступ в 4 пробела) и цитаты (`> …`) не смотрятся: там блок — пример по просьбе. Теги не режутся
15
+ * и там, где ответ подаёт блок как пример (строка перед ним — «Формат такой:», «например:», «выглядит так:»), и в
16
+ * ответе на вопрос о тегах и форматах (`explainsServiceFormats`).
17
+ */
18
+ export type ServiceBlockFormat = {
19
+ tag: string;
20
+ } | {
21
+ name: string;
22
+ line: string;
23
+ match?: RegExp;
24
+ until?: RegExp | "paragraph";
25
+ };
26
+ /**
27
+ * Служебные блоки ядра. Пакеты добавляют свои (`LongTermMemory.serviceBlocks`, `MessageAttachments.serviceBlocks`,
28
+ * `withSkills`, `flow.withChat`), приложение — `agent.serviceBlocks`. Дата («Сегодня: …») и уведомления о фоновых
29
+ * задачах сюда не входят: такие слова модель законно пишет человеку сама.
30
+ */
31
+ export declare const CORE_SERVICE_BLOCKS: readonly ServiceBlockFormat[];
32
+ /** Имя формата для журнала: тег или имя служебной строки. */
33
+ export declare const serviceBlockName: (format: ServiceBlockFormat) => string;
34
+ /**
35
+ * Вопрос человека — о служебных тегах и форматах: называет тег (`agent_memory`) или говорит о тегах, формате, разметке.
36
+ * В ответе на такой вопрос блок — объяснение, а не подделка: теги не режутся (служебные строки — режутся).
37
+ */
38
+ export declare function explainsServiceFormats(question: string, formats: readonly ServiceBlockFormat[]): boolean;
39
+ /** Последний вопрос человека в истории (для ответа, который идёт следом). */
40
+ export declare function lastQuestionOf(history: readonly AgentChatMessage[]): string;
41
+ /** Форматы приложения и пакетов проверяются при создании службы: ошибка в списке — `TypeError` сразу, а не тихий пропуск. */
42
+ export declare function checkServiceBlockFormats(formats: readonly ServiceBlockFormat[]): void;
43
+ /** Кусок разобранного текста: обычный текст, вырезанный блок или пробелы после него (уходят вместе с блоком). */
44
+ export type ForgedPiece = {
45
+ kind: "text";
46
+ text: string;
47
+ } | {
48
+ kind: "block";
49
+ name: string;
50
+ text: string;
51
+ } | {
52
+ kind: "gap";
53
+ text: string;
54
+ };
55
+ /**
56
+ * Разбор текста одного ответа по частям потока. Обычный текст отдаётся сразу; начало строки, похожее на служебный блок,
57
+ * придерживается, пока не станет ясно. Служебный блок (с пробелами после него) отдаётся отдельным куском — что с ним
58
+ * делать, решает вызывающий. Разбор по частям даёт те же куски, что разбор законченного текста.
59
+ */
60
+ export declare function createForgedBlockScanner(formats: readonly ServiceBlockFormat[], options?: {
61
+ explaining?: boolean;
62
+ }): {
63
+ /** Следующий кусок текста → готовые куски. Начало возможного блока придерживается до следующего. */
64
+ push(delta: string): ForgedPiece[];
65
+ /**
66
+ * Текст кончился: придержанное решается на неполной строке. Незакрытый тег — блок до первой пустой строки, остальное
67
+ * разбирается дальше; строчный блок — до конца текста.
68
+ */
69
+ end(): ForgedPiece[];
70
+ };
71
+ /** Законченный текст без служебных блоков и вырезанные блоки по порядку (имена). */
72
+ export declare function cutForgedBlocks(text: string, formats: readonly ServiceBlockFormat[], options?: {
73
+ explaining?: boolean;
74
+ }): {
75
+ text: string;
76
+ blocks: string[];
77
+ };
78
+ /**
79
+ * Части ответа без служебных блоков в тексте. `null` — вырезать нечего или без блоков в ответе не осталось бы слов
80
+ * (пустой ответ хуже повтора). Части без блоков — те же объекты.
81
+ */
82
+ export declare function cutForgedBlocksInParts(parts: readonly MessagePart[], formats: readonly ServiceBlockFormat[], options?: {
83
+ explaining?: boolean;
84
+ }): {
85
+ parts: MessagePart[];
86
+ blocks: string[];
87
+ } | null;
88
+ /**
89
+ * История для модели без служебных блоков в ответах ассистента (ответы до этой версии, форматы, добавленные позже). Только
90
+ * в запросе: запись не меняется. Та же история и те же форматы — те же байты (кэш модели). Нечего вырезать — тот же
91
+ * массив; сообщения без блоков — те же объекты. Сообщения человека не трогаются.
92
+ */
93
+ export declare function withoutForgedBlocks(history: readonly AgentChatMessage[], formats: readonly ServiceBlockFormat[]): readonly AgentChatMessage[];
94
+ /**
95
+ * Вырезка служебных блоков, пока идёт поток ответа модели (каждый шаг попытки). Блок не уходит ни на экран, ни в запись,
96
+ * ни в следующий шаг. Пока у ответа нет ни одного слова, блок придерживается: появились слова или шаг кончился вызовом
97
+ * инструмента — блок выброшен; шаг кончился без слов и без вызовов — блок показывается как есть (пустой ответ хуже).
98
+ */
99
+ export declare function createForgedBlockGuard(formats: readonly ServiceBlockFormat[]): {
100
+ /**
101
+ * Новая попытка с последним вопросом человека: шаги прежней стёрты — слов у ответа снова нет. Вырезанное раньше
102
+ * остаётся в счёте для журнала.
103
+ */
104
+ reset(question?: string): void;
105
+ /** Законченный текст мимо потока (переписка проверкой) — по тем же правилам, что поток этой попытки. */
106
+ cutText: (text: string) => {
107
+ text: string;
108
+ blocks: string[];
109
+ };
110
+ /** Модель попытки под присмотром: каждый запрос — новый шаг. */
111
+ wrap(model: LanguageModel): LanguageModel;
112
+ /** Вырезанные блоки хода по порядку (имена) — для журнала. */
113
+ cutBlocks: () => readonly string[];
114
+ /** Блоки, оставленные ради непустого ответа. */
115
+ keptBlocks: () => readonly string[];
116
+ };
117
+ export {};
@@ -13,6 +13,7 @@ import type { CacheMissWatch } from "../usage/cache-miss-watch.js";
13
13
  import type { PendingBrowserCalls } from "./browser-tools.js";
14
14
  import type { TurnSpendingRules } from "../spending/spending-limits.js";
15
15
  import type { ModeNotes } from "./mode-notes.js";
16
+ import type { ServiceBlockFormat } from "./forged-blocks.js";
16
17
  import type { TurnReplyChecks } from "./reply-checks.js";
17
18
  import type { ProviderFallbackSetting } from "./next-attempt.js";
18
19
  import type { ResolvedSequentialTools, ToolQueue } from "./sequential-tools.js";
@@ -134,6 +135,11 @@ export interface AgentTurnInput {
134
135
  history: readonly AgentChatMessage[] | (() => Promise<readonly AgentChatMessage[]>);
135
136
  /** Вложения: что модель увидит вместо частей `file` истории. */
136
137
  attachments?: MessageAttachments;
138
+ /**
139
+ * Служебные форматы, уже проверенные: поддельный блок в ответе модели вырезается в потоке (экран, запись и следующий шаг
140
+ * его не видят), в прошлых ответах — только в запросе. Нет — форматы ядра (`CORE_SERVICE_BLOCKS`).
141
+ */
142
+ serviceBlocks?: readonly ServiceBlockFormat[];
137
143
  /** Пометки смены режима для модели; в историю не пишутся (см. `buildModelRequest`). */
138
144
  modeNotes?: ModeNotes;
139
145
  /**
@@ -1,3 +1,4 @@
1
+ import type { ServiceBlockFormat } from "../agent-run/forged-blocks.js";
1
2
  import type { AgentChatMessage } from "../conversation/types.js";
2
3
  import type { ModelProfile } from "../models/model-catalog.js";
3
4
  /** Часть `file` сообщения так, как её прислал клиент: верить в ней можно только ссылке. */
@@ -21,6 +22,8 @@ export interface MessageAttachments {
21
22
  * агента само (если приложение не добавило её раньше), чтобы вложения не приходилось подключать в двух местах.
22
23
  */
23
24
  instructions?: string;
25
+ /** Служебные форматы вложений (`<attachment>`): поддельный блок в ответе модели вырезается (`ServiceBlockFormat`). */
26
+ serviceBlocks?: readonly ServiceBlockFormat[];
24
27
  /**
25
28
  * Проверяет вложения нового сообщения (они принадлежат этому чату и этому человеку, лимиты соблюдены, срок
26
29
  * не вышел) и возвращает части для сохранения. Файлы ещё не прикреплены: сообщение может не записаться.