openai SDK для CLIProxy совместимостиopenai>=1.30 в requirements.inpip-compile requirements.in для обновления lock-файлаpip install -r requirements.txt ставит без конфликтовhttp://127.0.0.1:31337/v1)extra_headersapp/config.py:DIGEST_LLM_BASE_URL = http://127.0.0.1:31337/v1 — endpoint CLIProxyDIGEST_PROMPT_VERSION = "v1" — версия промптов, для A/B тестовDIGEST_CLASSIFY_MODEL = anthropic/claude-haiku-3.5 — дешёвая модель для Pass 1DIGEST_MAP_MODEL = anthropic/claude-sonnet-4-6 — основная модель для map stepDIGEST_REDUCE_MODEL = anthropic/claude-sonnet-4-6 — модель для reduce stepDIGEST_MAX_CHUNKS = 10 — максимум чанков на одно окноDIGEST_CHUNK_TOKEN_BUDGET = 7000 — целевой бюджет токенов на чанкos.getenv() с дефолтами — без env переменных работает из коробкиgatheringdiscord_digest — готовые дайджесты. Основные индексы: (server_id, window_end_at desc), (channel_id, window_end_at desc), unique (extraction_window_id, prompt_version), text index на overview + search_keywordsdiscord_digest_job — очередь задач. TTL 7 дней. Индексы: (status, created_at), (channel_id, created_at desc)digest_topic_profiles — профили тем (AI image gen, etc.). _id = строковый slugdigest_entity_dictionary — канонические сущности (Flux, SDXL, ComfyUI). Индекс по profile_idapp/db.py (как существующие discord_server_col(), discord_message_col())_ensure_indexes() — идемпотентные, создаются при стартеContentPointer — {message_id, char_start, char_end}. Ядро pointer extractionSignalQuality — {level: empty|low|medium|high, reason: str}KnowledgeItem — {kind, title, content_pointer?, content?, context_version?, entity_refs, source_url?, attachment_ref?, message_ids, supersedes?, conflicts_with?}Decision, ActionItem, OpenQuestion — без attribution полей (автор берётся из message_ids → исходное сообщение в базе)ChunkSummary — выход map step (topics, decisions, action_items, knowledge_items, etc.)Digest — финальный выход reduce step (всё из ChunkSummary + title, overview, highlights, coverage)DigestJob — задача в очереди (scope, trigger, status, window, token_usage, cost_estimate)TopicProfile — профиль темы с composable модулямиProfileModule — отдельный модуль (item kinds, prompt supplement, feature flags)EntityEntry — сущность в словаре (canonical_name, aliases, entity_type, version_tracked)ThreadClassification — выход Pass 1 (interesting, primary_kinds, profile_routing)content_pointer и content взаимоисключающие (pointer для verbatim, content для synthesized)message_ids при отображенииtype != 0): join/leave/pin/boost<@123> → @display_name + сохранить маппинг user_id → name<#123> → #channel-name:name:[image: file.png 1920x1080]), машиночитаемые файлы (JSON, YAML) — парсить детерминированноhas_link, has_attachment, has_embed, has_code_block, has_workflow_assetis_reply, reaction_count=N, attachment_parsed=trueexplicit_decision_phrase, explicit_action_phrase, explicit_question_phraseerror_or_failure_terms, deadline_or_time_commitmentdiscord_messagereferencedMessage.idsum(reactions.count) → 2.0 ⚠️ мемы скорят высокоdistinct(reactions.emoji) → 1.0@everyone / @here / role mention → 2.5importance_score: floatget_top_messages(n) возвращает top-N по скору…<message id="snowflake" ts="ISO" author="name" user_id="uid">features: has_link, has_code_block, reaction_count=4text: ...reply_to: snowflake | none</message>len(normalized_text) / 3.5 — достаточно для решений по чанкингу_id: str — канонический ID, напр. "flux-1-dev"canonical_name: str — "Flux.1-dev"entity_type: str — "model" | "tool" | "technique" | "parameter"aliases: list[str] — ["Flux", "flux-dev", "FluxDev"]version_tracked: bool — разные версии = разные сущности?profile_id: str — к какому профилю привязанаresolve_entity(text) → canonical_id | None — поиск по алиасамget_entities_for_profile(profile_id) → list_id: str — slug, напр. "ai-image-generation"name: str — человекочитаемое названиеmodules: list[str] — ID подключённых модулейprompt_supplement: str — собранный из модулей суппlement для system promptbase-chat — generic decisions, questions, links (всегда включён)creative-prompts — detection + pointer extraction промптов генерацииtraining-configs — конфиги обучения, датасеты, гиперпараметрыcomfyui-workflows — JSON workflow файлы, node graphstroubleshooting — пары ошибка → решениеdiscord_channel.digest_profile_id) — приоритетdiscord_server.digest_profile_id) — fallbackcandidate_kind items — новые типы, не вписывающиеся в схемуtest_digest_preprocess.py — фильтрация (system messages дропаются, нормальные остаются), нормализация (mentions → names, attachments → metadata), feature flags корректныtest_digest_threads.py — reply graph строит правильные группы, Layer 2 подбирает implicit связи, orphan'ы корректно изолированыtest_digest_chunking.py — треды не разрезаются, бюджет соблюдается, XML формат валиден, turn collapse работаетtests/fixtures/digest/Взять реальный канал, прогнать pipeline до чанков, получить well-formed XML блоки готовые для LLM.
Entity dictionary заполнен. Все Pydantic модели определены. Тестируемо без API ключей.