BorisovAI

Блог

Публикации о процессе разработки, решённых задачах и изученных технологиях

Найдено 20 заметокСбросить фильтры
Новая функцияtrend-analisis

API ключи как головная боль: как мы организовали chaos в trend-analisis

# Когда API ключей больше, чем смысла их хранить: как мы организовали регистрацию в trend-analisis Проект **trend-analisis** рос быстрее, чем мы себе представляли. Что начиналось как скрипт для сбора данных о трендах с Reddit и Hacker News, превратилось в полноценную платформу, которая должна была интегрировать восемь различных источников: от YouTube и NewsAPI до PubMed и Stack Overflow. И тут возникла проблема, которую я даже не ожидал встретить: **не сама техническая интеграция, а тот хаос, который был до неё**. Каждый источник требовал свою регистрацию, свои шаги, свои особенности. Документация была разбросана по разным местам, а новые разработчики, садясь в проект, теряли полдня только на то, чтобы понять, как получить API ключи. Я помню, как смотрел на список источников и видел эти **[9.0, 8.0, 9.0, 7.0, 8.0, 6.0, 7.0, 7.0]** — оценки влияния каждого источника на общее качество трендов. Среднее значение выходило **7.6 балла**. Казалось бы, всё хорошо, но реальность была куда грязнее: половину времени уходила не на анализ данных, а на борьбу с 403 Forbidden от Reddit из-за неправильного user_agent'а или с 426 ошибками от NewsAPI. Первым делом я создал **API Registration Quick Guide** — не просто справочник, а пошаговую инструкцию, которая разбивала весь процесс на фазы. Фаза 1: Essential (Reddit, NewsAPI, Stack Overflow) — это то, что нужно для MVP. Фаза 2: Video & Community (YouTube, Product Hunt, Dev.to) — дополнение. Фаза 3: Search & Research — когда уже есть пользователи. Фаза 4: Premium — это потом, после того как мы подтвердили бизнес-модель. Каждый источник получил прямую ссылку на регистрацию и *реальное* время, которое уходит на её прохождение. Reddit — 2 минуты, NewsAPI — 1 минута, YouTube через Google Cloud Console — 3 минуты. Не абстрактные «следуйте инструкциям», а конкретика: «кликни сюда, вот здесь вводишь имя приложения, копируешь вот это в .env». Интересно, что при организации интеграций я обнаружил: **большинство разработчиков не понимают разницу между rate limiting и quotas**. YouTube, например, работает на дневном лимите в 10K units, и он обнуляется в полночь UTC. Это не ошибка API — это by design. Когда первая версия системы упала в 23:45 MSK, я потратил два часа на отладку, прежде чем осознал, что нужно просто дождаться полуночи UTC. Я подготовил команду для проверки каждого ключа сразу после регистрации — `test_adapters.py` запускает краткий тест на каждом источнике. Это сэкономило часы на отладке и создало «зелёный коридор» для новичков в проекте. В итоге весь процесс сократился с полудня беготни по документации до 10–15 минут копирования ссылок, клика, регистрации и вставки ключей в `.env`. Документация теперь жила в одном месте, связана с основным гайдом по интеграции, и каждый новый разработчик мог начать работать почти сразу. **Главный урок**: иногда самые скучные задачи — это те, которые экономят больше всего времени. Красивая архитектура — это хорошо, но красивая *процедура* регистрации и настройки — это то, что делает проект действительно доступным. 😄 Спор Java vs Kotlin — единственная война, где обе стороны проигрывают, а разработчик страдает.

#claude#ai#python#api#security
Разработка: trend-analisis
10 февр. 2026 г.
Новая функцияtrend-analisis

Спасаем разработчиков от лабиринта документации

# Как я спасал API документацию от размытых ссылок Проект **trend-analisis** рос, и с ним росла беда: разработчикам нужно было регистрироваться, читать документацию, переходить на API endpoint'ы — и каждый раз они путались в лабиринте вкладок и закладок. Задача была проста и назойлива одновременно: создать быстрый справочник по регистрации с прямыми ссылками на страницы API, чтобы всё было под рукой с первого клика. Звучит просто? Нет, потому что простых задач не бывает, есть только те, что казались простыми в начале 😄 ## В поиске правильной структуры Первым делом я разобрался, как люди вообще читают документацию. Оказалось, никто не хочет цикла: регистрируешься → переходишь в основную документацию → ищешь API методы → потом ещё раз ищешь примеры. Это как ходить пешком туда-обратно на протяжении всего проекта. Решил делать навигационный хаб — одно место, откуда можно прыгнуть в нужную точку документации за один клик. Для этого нужна была чёткая иерархия: какие разделы API важнее, где начинающим рыть не стоит, какие примеры самые полезные на старте. ## Архитектура справочника Я подумал о структуре как о карте города: есть главные улицы (основные API методы), есть боковые (advanced features), есть где-то офис регистрации. Сделал справочник с тремя слоями: 1. **Блок регистрации** — с инструкциями и ссылкой на форму 2. **API методы по категориям** — сгруппированы по типу операций (получение трендов, аналитика, экспорт) 3. **Примеры кода** — непосредственно в справочнике, чтобы не прыгать по вкладкам ## Познавательный момент про документацию Знаете, почему DevTools в браузере показывает сетевые запросы? Потому что разработчик Firebug (предшественник DevTools) Джо Хюбли в 2006 году понял, что если разработчик не видит, что происходит в сети, он вообще ничего не понимает. Документация работает по тому же принципу — разработчик должен *видеть путь от проблемы к решению*, а не искать его вслепую. ## Финальное решение В итоге сделал: - **Динамическое содержание** — справочник парсит структуру API из docstrings и автоматически создаёт якоря - **Sticky навигация** — панель с ссылками висит слева, прокручиваются только примеры - **QR-коды для мобильных** — потому что люди читают документацию на телефоне, даже если не хотят в этом признаваться Разработчики теперь открывают регистрацию, видят справочник, кликают на нужный endpoint — и вот они уже в нужной части документации. Без танцев с бубнами, без пяти вкладок браузера. Главный урок: документацию нужно строить с точки зрения пути, который пройдёт пользователь, а не с точки зрения, как удобнее её разработчику писать. Когда ты думаешь о маршруте, а не о каталоге — всё встаёт на место. Почему разработчик любит регулярные выражения? Потому что без них жизнь слишком скучна 😄

#claude#ai#python#javascript#api
Разработка: trend-analisis
10 февр. 2026 г.
Исправлениеtrend-analisis

Когда унификация интерфейса оказывается архитектурной головоломкой

# Унификация — это неочевидно сложно Задача стояла простая на словах: «Давай выровняем интерфейс страниц тренда и анализа, чтобы не было разнобоя». Типичное дело конца спринта, когда дизайн требует консистентности, а код уже рассеялся по разным файлам с немного разными подходами. В проекте **trend-analisis** у нас две главные страницы: одна показывает тренды с оценками, другая — детальные аналитические отчёты. Обе они должны выглядеть как *части одного целого*, но на деле они разошлись. Я открыл `trend.$trendId.tsx` и `analyze.$jobId.report.tsx` и понял, что это как смотреть на двух братьев, которые выросли в разных городах. **Первым делом я разобрался с геометрией.** На мобильных устройствах кнопки на странице тренда вели себя странно — они прятались за правый край экрана, как непослушные дети. Перевёл их в стек на мобильных и горизонтальный ряд на десктопе. Простая история, но именно такие детали создают ощущение недоделанности. Потом пошло интереснее. **ScorePanel** — компонент с оценкой и её визуализацией — тоже требовал внимания. На странице тренда Sparkline (такие симпатичные маленькие графики) были отдельно от оценки, на странице анализа они находились где-то рядом. Решил переместить Sparkline внутрь ScorePanel, чтобы блок оценки стал полноценным, законченным элементом. **Но главный подвох ждал в бэкенде.** Когда я нырнул в `routes.py`, обнаружил, что оценка анализа считается в диапазоне 0–1 и потом нормализуется. Странная архитектура: пользователь видит на экране число 7–8, а в коде живёт 0.7–0.8. Когда возникла необходимость унифицировать, пришлось переделать — теперь всё работает в единой шкале 0–10 от фронтенда до бэкенда. Ещё одна муха в супе: переводы. Каждый отчёт имеет title и description. Вот только они часто приходили на разных языках — title на английском, description на русском, потому что система переводов разрасталась бессистемно. Пришлось переделать архитектуру на `get_cached_translations_batch()`, чтобы title и description синхронизировались по локали. Вот тут и проявляется одна из *типичных ловушек разработки*: когда система растёт, легко получить состояние, при котором разные части кода решают одну и ту же задачу по-разному. Кэширование переводов, кэширование данных, нормализация чисел — каждая из этих проблем порождает своё микрорешение, и вскоре у вас сложная паутина зависимостей. Решение: честный код-ревью и документирование паттернов, чтобы новичок не добавил пятый способ кэширования. **В итоге:** две страницы теперь выглядят как надо, API вернулся к нормальным оценкам (7–8 вместо 1), переводы синхронизированы. Git commit отправлен, бэкенд запущен на порту 8000. Дальше в плане новые исправления — благо материал есть. Чему научился: унификация — не просто про UI, это про согласованность логики по всему стеку. Порой проще переделать целый компонент, чем мучиться с костылями. 😄 Почему backend разработчик плюёт на фронтенд? Потому что он работает в консоли и ему всё равно, как это выглядит.

#claude#ai#python#git#api
Разработка: trend-analisis
10 февр. 2026 г.
Новая функцияai-agents

Привидение в истории сообщений: как tool_use без tool_result сломал бота

# Охота за привидением в чате: как `tool_use` без `tool_result` сломал бот Проект AI Agents — это система голосовых агентов с телеграм-интеграцией. Звучит просто, но под капотом там полноценная экосистема: асинхронная обработка сообщений, система памяти пользователей, рефлексия агента, напоминания. И вот однажды бот просто перестал запускаться. Сначала казалось, что это типичная проблема с конфигурацией. Но логи рассказывали более странную историю. API Anthropic выбрасывал ошибку: **"tool_use без соответствующего tool_result"**. Как будто кто-то забыл закрыть скобку, но на уровне сессии. Начал копать. Оказалось, что в `handlers.py` есть критический flow: когда агент вызывает инструмент через `chat_with_tools()`, а во время выполнения происходит исключение — `session.messages` остаётся в "повреждённом" состоянии. На сообщение прилетает `tool_use` блок, но соответствующего `tool_result` никогда не приходит. При следующем запросе эти повреждённые сообщения уходят обратно в API — и всё падает. Это было в трёх местах одновременно: в обработчике нормальных команд (строка 3070), в системе напоминаний (2584) и где-то ещё. Классический паттерн копируй-вставь с одинаковым багом. **Решение оказалось простым, но необходимым**: добавить автоматическую очистку `session.messages` в обработчик исключений. Когда что-то идёт не так во время вызова инструмента, просто очищаем последнее незавершённое сообщение. Вот и вся магия. Пока чинил это, нашёл ещё несколько интересных проблем. Например, система рефлексии агента `AgentReflector` читала из таблицы `episodic_memory`, которая может просто не существовать в базе. Пришлось переписать логику проверки с правильной обработкой исключений SQLite. И тут выяснилась ещё одна история: рефлексия использовала `AsyncAnthropic` напрямую вместо Claude CLI. Это означало, что каждый раз при рефлексии расходовались API credits. Пришлось мигрировать на использование CLI, как это было сделано в `reminder_watchdog_system`. Теперь агент может размышлять о своей работе совершенно бесплатно. Отдельное приключение ждало команду `/insights`. Там была проблема с парсингом markdown в Telegram: символы вроде `_`, `*`, `[`, `]` в тексте размышлений создавали невалидные сущности. Пришлось написать функцию для правильного экранирования спецсимволов перед отправкой в Telegram API. В итоге: бот запустился, логирование стало нормальным, система памяти работает исправно. Главный урок — когда API жалуется на незавершённые блоки, смотри на обработку исключений. Там всегда что-то забыли почистить. 😄 Как отличить разработчика от отладчика? Разработчик пишет код, который работает, отладчик пишет код, который объясняет, почему первый не работает.

#claude#ai#python#javascript#api#security
Разработка: ai-agents
10 февр. 2026 г.
Новая функцияC--projects-ai-agents-voice-agent

Монорепо как зеркало: когда Python и JS живут в одном доме

# Монорепо как зеркало: Python + Next.js в одном проекте **Завязка** Представьте ситуацию: вы разработчик и в ваших руках проект *voice-agent* — голосовой помощник на основе Claude, построенный как монорепо. С одной стороны Python-backend (FastAPI, aiogram для Telegram), с другой — Next.js фронтенд (React 19, TypeScript 5.7) для Telegram Mini App. Звучит здорово, но вот в чём подвох: когда в одном репозитории живут две экосистемы с разными правилами игры, управлять ими становится искусством. **Развитие** Первой проблемой, которая выпрыгнула из неоткуда, была **забывчивость переменных окружения**. В Python проект использует `pydantic-settings` для конфигурации, но выяснилось, что эта библиотека не экспортирует значения автоматически в `os.environ`. Результат? Модульный код, читавший переменные прямо из окружения, падал с загадочными ошибками. Пришлось документировать эту ловушку в ERROR_JOURNAL.md — живом архиве подводных камней проекта, где уже скопилось десять таких «моментов истины». Далее встал вопрос архитектуры. Backend требовал **координатора** — центрального паттерна, который бы оркестрировал взаимодействие между агентами и фронтенд-запросами. На бумаге это выглядело идеально, но в коде его не было. Это создавало технический долг, который блокировал Phase 2 разработки. Пришлось вводить **phase-gate валидацию** — автоматическую проверку, которая гарантирует, что прежде чем переходить к следующей фазе, все артефакты предыдущей действительно на месте. В процессе появилась и проблема с **миграциями базы данных**. SQLite с WAL-режимом требовал аккуратности: после того как junior-агент создавал файл миграции, она не всегда применялась к самой БД. Пришлось вводить обязательный чек: запуск `migrate.py`, проверка таблиц через прямой SQL-запрос, документирование статуса. Без этого можно часами отлавливать фантомные ошибки импорта. **Познавательный блок** Интересный факт: монорепо — это не просто удобство, это *культурный артефакт* команды разработки. Google использует одно гигантское хранилище для всего кода (более миллиарда строк!), потому что это упрощает синхронизацию и рефакторинг. Но цена высока: нужны инструменты (Bazel), дисциплина и чёткие протоколы. Для нашего voice-agent это значит: не просто писать код, а писать его так, чтобы Python-part и Next.js-part *доверяли друг другу*. **Итог** В итоге сложилась простая истина: монорепо работает только если есть **система проверок**. ERROR_JOURNAL.md превратился не просто в логирование ошибок, а в живой артефакт культуры команды. Phase-gate валидация стала гарантией, что при параллельной работе нескольких агентов архитектура не съезжает в стороны. А обязательная проверка миграций — это не занудство, а спасение от трёх часов ночного отлавливания, почему таблица не там, где ей быть. Главный урок: в монорепо важна не столько архитектура, сколько **честность системы**. Чем раньше вы перейдёте от надежды на память к автоматическим проверкам, тем спокойнее спать будете. Почему Python и Java не могут дружить? У них разные dependency trees 😄

#claude#ai#python#javascript#git#api#security
Разработка: ai-agents-voice-agent
10 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

Unit-тесты зелёные, а бот не работает: гонка условий в Telegram

# Когда unit-тесты лгут: как я запустил систему доступа в реальном Telegram **bot-social-publisher** выглядел как отличный проект для спринта. Полнофункциональный Telegram-бот с командами, памятью, интеграциями. Я предложил добавить управление доступом — чтобы владельцы чатов могли приватизировать разговоры с ботом. Звучит просто: только авторизованные пользователи видят ответы. Идеально для персональных AI-ассистентов или закрытых групп модерации. Я развернул **ChatManager** — класс с методом `is_allowed()`, который проверяет разрешение пользователю писать в конкретный чат. Добавил миграцию SQLite для таблицы `managed_chats`, обвязал всё middleware'ами в **aiogram**, написал четыре команды: `/manage add`, `/manage remove`, `/manage status`, `/manage list`. Unit-тесты прошли с ликованием. **pytest** выдал зелёный статус. Документация? Позже, мол. Потом наступил момент истины. Запустил бота локально через `python telegram_main.py`. В личном чате отправил `/manage add` — чат добавился, режим приватности активировался. Отправил обычное сообщение — ответ пришёл. Открыл второй аккаунт, отправил то же — бот молчит. Отлично, система контроля работает! Но не совсем. **Первая проблема** вскрылась при быстрых командах подряд. **aiogram** работает асинхронно, как и **aiosqlite**. Получилась коварная гонка условий: middleware проверяет разрешения раньше, чем транзакция в БД успела закоммититься. Бот получает `/manage add`, начинает писать в таблицу, но собственная система контроля выполняет проверку за доли секунды до того, как данные туда попадут. На unit-тестах такое не видно — там всё выполняется последовательно. **Вторая проблема** — SQLite и одновременные асинхронные обработчики. Один handler записывает изменение в БД, другой в это время проверяет состояние и видит старые данные, потому что `commit()` ещё не произошёл. Мне помогли явные транзакции и аккуратная расстановка `await`'ов — гарантия того, что каждая операция завершится перед следующей. Вот в чём разница между unit-тестами и интеграционными испытаниями: первые проверяют, что функция работает в идеальных условиях. Вторые отправляют реальное сообщение через серверы Telegram, пускают его через весь стек middleware, обрабатывают в handler'е, записывают в БД и возвращают результат. Тесты говорили: всё работает. Реальность показала: медленно и с условиями. После боевых испытаний я заполнил полный чеклист: импорты класса, валидация миграции, проверка всех команд в живом Telegram, полный набор pytest, документация в `docs/CHAT_MANAGEMENT.md` с примерами архитектуры. Восемь пунктов — восемь потенциальных взрывов, которые благополучно не произошли. Урок выучен: асинхронность и базы данных требуют больше, чем зелёные unit-тесты. Реальный Telegram и реальная асинхронность покажут то, что никогда не отловишь в тестовом окружении. 😄 Говорят, асинхронные баги в облаке GCP просто растворяются — поэтому их никто не находит.

#claude#ai#python#git#api
Разработка: bot-social-publisher
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

Когда unit-тесты лгут: боевые испытания Telegram-бота

# Telegram-бот на боевых испытаниях: когда unit-тесты не подстраховывают Проект **bot-social-publisher** начинался просто. Полнофункциональный Telegram-бот с памятью, командами, интеграциями. Но вот на очередную спринт-планерку я заявил: добавим систему управления доступом. Идея казалась пустяковой — дать владельцам возможность приватизировать свои чаты, чтобы только они могли с ботом общаться. Типичный use case: персональный AI-ассистент или модератор в закрытой группе. Теория была прекрасна. Я развернул **ChatManager** — специальный класс с методом `is_allowed()`, который проверяет, разрешена ли пользователю отправка сообщений в конкретный чат. Добавил миграцию SQLite для таблицы `managed_chats`, прошил middleware в **aiogram**, написал обработчики команд `/manage add`, `/manage remove`, `/manage status`, `/manage list`. Unit-тесты прошли с зелёным светом — `pytest` даже не чихнул. Документация пока отложена, но это же детали! Потом наступил момент истины. Запустил бота локально через `python telegram_main.py`, переключился в личный чат и отправил первую `/manage add`. Бот записал ID чата, переключился в режим приватности. Нормально! Попробовал отправить обычное сообщение — ответ пришёл. Открыл чат со своего второго аккаунта, отправил то же самое — тишина. Бот ничего не ответил. Перфект, middleware работает. Но не всё было так гладко. Первая проблема вылезла при быстрых командах подряд. В асинхронной архитектуре **aiogram** и **aiosqlite** есть коварная особенность: middleware может проверить разрешения раньше, чем транзакция успела закоммититься. Получилась гонка условий — бот получал `/manage add`, начинал записывать в БД, но его собственная система контроля доступа успевала выполнить проверку за доли секунды до того, как данные попали в таблицу. Казалось бы, логические ошибки не могут быть незаметны в коде, но тут они проявились только в полевых условиях. Вторая проблема — SQLite при одновременной работе нескольких асинхронных обработчиков. Один handler записывал изменение в БД, а другой в это время проверял состояние — и видел старые данные, потому что `commit()` ещё не произошёл. Гарантировать консистентность мне помогли явные транзакции и аккуратная работа с await'ами. Вот в чём прелесть интеграционного тестирования: ты отправляешь реальное сообщение через Telegram-серверы, оно проходит через webhook, пробегает весь стек middleware, обрабатывается обработчиком, записывается в БД и возвращается пользователю. Unit-тесты проверяют логику функции. Интеграционные тесты проверяют, работает ли всё это вместе в реальности. И оказалось, что между «работает в тесте» и «работает в реальности» огромная разница. После всех боевых испытаний я заполнил чеклист: проверка импортов класса, валидация миграции, тестирование всех команд в Telegram, запуск полного набора pytest, документирование в `docs/CHAT_MANAGEMENT.md` с примерами и описанием архитектуры. Восемь пунктов — восемь потенциальных точек отказа, которые благополучно миновали. Урок на будущее: когда работаешь с асинхронностью и базами данных, unit-тесты — это необходимо, но недостаточно. Реальный Telegram, реальные пользователи, реальная асинхронность покажут то, что никогда не отловить в тестовом окружении. 😄 Иногда мне кажется, что в облаке **GCP** ошибка при доступе просто уходит в облака, так что никто её не найдёт.

#claude#ai#python#git#api#security
Разработка: bot-social-publisher
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

Когда unit-тесты зелёные, а бот падает в продакшене

# Проверяем Telegram-бота в боевых условиях: когда unit-тесты врут Любой разработчик знает эту ситуацию: твой код прошёл все тесты в PyTest, green lights светят, CI/CD улыбается. Но стоит запустить приложение в реальной среде — и вдруг выскакивают проблемы, которые перестанут выглядеть как волшебство, как только ты их найдёшь. Со мной произошла именно эта история на проекте **bot-social-publisher**, когда я добавил в Telegram-бота систему управления доступом. ## Задача казалась элементарной Надо было реализовать для бота фишку с приватными чатами. Идея простая: если владелец чата напишет `/manage add`, бот переходит в режим приватности и начинает отвечать только ему. Команда `/manage remove` открывает доступ всем обратно. Плюс туда же добавил `/recall` и `/remember` для сохранения истории разговоров. На бумаге всё выглядело как три строки кода в middleware'е, которые проверяют ID пользователя перед обработкой сообщения. Я написал unit-тесты, всё прошло. Но реальный Telegram — совсем другой зверь. ## Боевые испытания в реальной среде Первым делом поднял бота локально через `python telegram_main.py` и начал его "пилить" из реального Telegram аккаунта. Написал `/manage add` — бот записал ID чата в таблицу `managed_chats` в SQLite и переключился в режим приватности. Проверил middleware `permission_check.py` — всё срабатывает корректно, обработка заблокирована для чужих. Хорошо. Потом попросил друга написать то же самое сообщение со своего аккаунта. Ожидал — ничего не случится. И действительно, бот промолчал. Отлично, система работает как надо. Финальный тест: я написал `/manage remove`, друг снова отправил сообщение — и бот ответил. Приватность отключена, доступ восстановлен. Казалось бы, победа. Но потом обнаружилась подвох. ## Гонка условий в асинхронном коде Оказалось, что в асинхронной архитектуре **aiogram** есть коварная особенность: middleware проверяет доступ, а запись в БД может ещё не завершиться. Получилась гонка условий — команда `/manage add` срабатывала, но контроль доступа успевал проверить разрешения *до* того, как данные попали в таблицу. Пришлось оборачивать insert'ы в explicit `await`, чтобы гарантировать консистентность. Другая проблема с SQLite: при одновременной работе нескольких асинхронных обработчиков изменения одного из них могут быть не видны другим, пока не произойдёт `commit()`. Контроллер доступа проверял одно, а в реальности БД содержала совсем другое. Решение было банальным — явные транзакции, но выяснить это можно было только через реальное тестирование. ## Познавательный момент об асинхронности Здесь скрывается типичная ловушка разработчиков, переходящих с синхронного кода на async/await: асинхронный код **кажется** последовательным в написании, но на самом деле может выполняться в самых неожиданных порядках. Когда ты пишешь `await db.execute()`, это не значит, что все предыдущие операции уже завершены в других корутинах. Нужна явная синхронизация через контекстные менеджеры или явные commit'ы. ## Итог: документируем опыт После всех интеграционных тестов я задокументировал находки в `docs/CHAT_MANAGEMENT.md`, добавил примеры использования в README.md и описал полную архитектуру ChatManager'а. Теперь система готова к работе с приватными чатами и конфиденциальными данными. Главный урок: unit-тесты проверяют логику в вакууме, но реальный мир полон асинхронности, сетевых задержек и race conditions. Никакой PyTest не найдёт то, что видно только в продакшене. Поэтому перед тем, как праздновать зелёный CI/CD, всегда имеет смысл руки испачкать в реальной среде. 😄 Что говорит разработчик после запуска асинхронного кода? «У меня было семь ошибок, теперь их четырнадцать, но они более интересные».

#claude#ai#python#git#api
Разработка: bot-social-publisher
9 февр. 2026 г.
Новая функцияai-agents

Четыре инструмента вместо двух: как мы освободили AI-агентов от ограничений

# От изоляции к открытости: как мы расширили доступ к файловой системе в AI-агентах Работал я над проектом **ai-agents** — платформой для создания интеллектуальных помощников на Python. И вот в какой-то момент нас настигла настоящая боль роста: агенты работали в тесной клетке ограничений. ## Проблема: узкие границы доступа Представь ситуацию. У нас была виртуальная файловая система — и звучит круто, пока не начнёшь с ней работать. Агенты могли читать только три папки: `plugins/`, `data/`, `config/`. Писать вообще не могли. Нужно было создать конфиг? Нет. Сохранить результат работы? Нет. Отредактировать существующий файл? Снова нет. Это было словно программировать с одной рукой, привязанной за спину. Функциональность `file_read` и `directory_list` — хорошо, но недостаточно. Проект рос, требования расширялись, а система стояла на месте. ## Решение: четыре инструмента вместо двух Первым делом я понял, что нужно идти не путём костылей, а переписать модуль **filesystem.py** целиком. Вместо двух полуслепых инструментов создал четыре полнофункциональных: - **`file_read`** — теперь читает что угодно в проекте, до 200 килобайт - **`file_write`** — создаёт и перезаписывает файлы, автоматически создаёт директории - **`file_edit`** — тонкая работа: находит точную подстроку через find-and-replace и заменяет - **`directory_list`** — гибкий листинг: поддерживает glob-паттерны и рекурсию Но тут появилась вторая проблема: как дать свободу, но не потерять контроль? ## Безопасность: ограничения, которые действительно работают Всё звучит опасно, пока не посмотришь на механизм защиты. Я добавил несколько слоёв: Все пути привязаны к корню проекта через `Path.cwd()`. Выбраться наружу невозможно — система просто не позволит обратиться к файлам выше по дереву директорий. Плюс чёрный список: система блокирует доступ к `.env`, ключам, секретам, паролям — ко всему, что может быть опасно. А для дополнительной уверенности я добавил проверку path traversal через `resolve()` и `relative_to()`. Получилась архитектура, где агент может свободно работать внутри своей песочницы, но не может ей повредить. ## Интересный момент: почему это важно Знаешь, в истории компьютерной безопасности есть забавный парадокс. Чем больше ты запрещаешь, тем больше люди ищут обходные пути. А чем правильнее ты даёшь разрешения — с умными ограничениями — тем спокойнее всем. Unix-философия в действии: дай инструменту ровно столько мощи, сколько нужно, но убедись, что он не сможет что-то сломать. ## Итого Переписал модуль, обновил константы в **constants.py**, экспортировал новые классы в **\_\_init\_\_.py**, подключил всё в **core.py** и **handlers.py**. Проверил сборку — зелёная лампочка. Теперь агенты могут полноценно работать с проектом, не боясь случайно удалить что-то важное. Дальше планировали тестировать на реальных сценариях: создание логов, сохранение состояния, динамическая генерация конфигов. А пока что у нас есть полнофункциональная и безопасная система для работы с файлами. Мораль истории: не выбирай между свободой и безопасностью — выбирай правильную архитектуру, которая обеспечивает оба.

#claude#ai#python#git#security
Разработка: ai-agents
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

ChatManager: как научить бота помнить, где ему работать

# Как научить AI-бота помнить свои чаты: история ChatManager Задача стояла простая на словах, но коварная на деле. У AI-бота в проекте **voice-agent** началась проблема с идентичностью: он рос, его добавляли в новые чаты, но вот беда — он не различал, в каких группах он вообще должен работать. Представь: бот оказывается в сотне чатов, а слушаться команд должен только в тех, которые явно добавил его хозяин. Без этого механизма вся система на мине. **Первым делом разобрали задачу по кирпичикам.** Нужна была полноценная система управления чатами: бот должен помнить, какие чаты ему доверены, проверять права пользователя перед каждой командой и предоставлять простые способы добавлять/удалять чаты из управляемых. Звучит как обычная CRUD-операция, но в контексте асинхронного Telegram-бота это становится интереснее. Решение разделили на пять логических контрольных точек. Начали с **ChatManager** — специального класса в `src/auth/`, который ведал бы всеми чатами. Важное решение: использовали уже имеющийся в проекте **structlog** для логирования вместо того, чтобы добавлять ещё одну зависимость. И, что критично для асинхронного бота, выбрали **aiosqlite** — асинхронный драйвер для SQLite. Почему это важно? Потому что обычный SQLite работает синхронно и может заблокировать весь бот при обращении к БД. aiosqlite оборачивает операции в `asyncio` — и вот уже БД не стопорит главный цикл обработки сообщений. **Дальше пошли миграции и middleware.** Создали таблицу `managed_chats` с информацией о чатах, их типах и владельцах. Затем встроили в pipeline Telegram-хэндлеров специальный middleware для проверки прав — перед каждой командой система проверяет, имеет ли пользователь доступ к этому чату. Если нет — молчит или вежливо отказывает. Команды управления (`/manage add`, `/manage remove`, `/manage list`) сделали простыми и понятными. Напишешь в личку боту `/manage add` — и чат добавляется в управляемые. Никакого магического угадывания, всё явно. **Интересный момент про асинхронные БД.** Когда разработчики впервые натыкаются на проблему "бот зависает при запросе к БД", они часто виноваты в синхронных операциях с базой. aiosqlite решает это элегантно: минимум кода, максимум производительности. Это один из тех инсайтов, которые приходят дорого, но в долгосрочной перспективе спасают душу. **В итоге получилось мощно.** Бот теперь точно знает, кто его хозяин в каждом чате, и не поддаётся на трюки неуполномоченных пользователей. Архитектура масштабируется — можно добавить роли, разные уровни доступа, историю изменений. Всё работает асинхронно и не тормозит. Дальше очередь интеграционных тестов и production. 😄 **Совет дня:** всегда создавай миграции БД отдельно от логики — так проще откатывать и тестировать. И да, GCP и кот похожи тем, что оба делают только то, что хотят, и игнорируют твои инструкции.

#claude#ai#python#api#security
Разработка: bot-social-publisher
9 февр. 2026 г.
Изменение кодаC--projects-ai-agents-voice-agent

ChatManager: как AI-боту дать контроль над своими чатами

# От хаоса к порядку: как мы научили AI-бота управлять собственными чатами Столкнулись с интересной проблемой в проекте **voice-agent** — нашему AI-боту нужно было получить контроль над тем, в каких чатах он работает. Представь: бот может оказаться в сотнях групп, но обслуживать он должен только те, которые явно добавил владелец. И вот здесь начинается магия архитектуры. ## Задача была классической, но хитрой Нужно было реализовать систему управления чатами — что-то вроде белого списка. Бот должен был: - Помнить, какие чаты он курирует - Проверять права пользователя перед каждой командой - Добавлять/удалять чаты через понятные команды - Хранить всё это в надежной базе данных Звучит просто? На деле это требовало продумать архитектуру с нуля: где брать данные, как валидировать команды, как не потерять информацию при перезагрузке. ## Как мы это делали Первым делом создали класс **ChatManager** — специалист по управлению чатами. Он бы жил в `src/auth/` и работал с SQLite через **aiosqlite** (асинхронный драйвер, чтобы не блокировать главный цикл обработки сообщений). Важный момент: использовали уже имеющийся в проекте **structlog** для логирования — не захотелось добавлять ещё одну зависимость в requirements.txt. Затем создали миграцию БД — новую таблицу `managed_chats` с полями для типа чата (приватный, группа, супергруппа, канал), ID владельца и временной метки. Ничего сложного, но по-человечески: индексы на часто используемых полях, CHECK-констрейнты для валидности типов. Дальше идет классический паттерн — **middleware для проверки прав**. Перед каждой командой система проверяет: а имеет ли этот пользователь доступ к этому чату? Если нет — бот скромно молчит или вежливо отказывает. Это файл `src/telegram/middleware/permission_check.py`, который встраивается в pipeline обработки сообщений. И, конечно, **handlers** — набор команд `/manage add`, `/manage remove`, `/manage list`. Пользователь пишет в личку боту `/manage add`, и чат добавляется в управляемые. Просто и понятно. ## Маленький инсайт про асинхронные БД Знаешь, почему **aiosqlite** так хороша? SQLite по умолчанию работает синхронно, но в асинхронном приложении это становится узким местом. aiosqlite оборачивает операции в `asyncio`, и вот уже БД не блокирует весь бот. Минимум кода, максимум производительности. Многие разработчики об этом не думают, пока не столкнутся с тем, что бот «зависает» при запросе к БД. ## Итог: от плана к тестам Весь процесс разбили на логические шаги с контрольными точками — каждый шаг можно было проверить отдельно. После создания ChatManager идёт миграция БД, потом интеграция в основной бот, затем handlers для команд управления, и наконец — unit-тесты в pytest. Результат: бот теперь знает, кто его хозяин в каждом чате, и не слушает команды от неуполномоченных людей. Архитектура масштабируется — можно добавить роли, разные уровни доступа, историю изменений. А главное — всё работает асинхронно и не тормозит. Дальше план — запустить интеграционные тесты и загнать в production. Но это уже другая история. 😄 **Совет дня:** всегда создавай миграции БД отдельно от логики — так проще откатывать и тестировать.

#claude#ai#python#api#security
Разработка: ai-agents-voice-agent
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

SQLite спасает день: масштабируемая БД вместо хаоса в памяти

# SQLite вместо памяти: как я спас Telegram-ботов от хаоса Проект `bot-social-publisher` взлетал буквально на глазах. Каждый день новые пользователи подключали своих ботов, запускали кампании, расширяли функционал. Но в какой-то момент понял: у нас есть проблема, которая будет только расти. Где-то в недрах памяти процесса валялась вся информация о том, какие чаты под управлением, кто их владелец, какие у них настройки. Приватный чат? Группа? Канал? Всё это было либо в переменных, либо в логах, либо вообще только в голове. Когда рост пользователей начал экспоненциальный скачок, стало ясно: **нужна нормальная база данных. Правильная, масштабируемая, без требований на отдельный сервер**. **Первым делом посмотрел на то, что уже есть.** В проекте уже была собственная SQLite база в `data/agent.db`, и там спокойно жил `UserManager` — отличный пример того, как работать с асинхронными операциями через `aiosqlite`. Логика была простой: одна база, одна инфраструктура, одна точка подключения для всей системы. Так почему бы не применить ту же философию к чатам? Архитектурное решение созревало быстро. Не было никаких грёз о микросервисах, Redis-кэшах или какой-то сложности. Нужна таблица `managed_chats` с полями для `chat_id` (первичный ключ), `owner_id` (связь с пользователем), `chat_type` с `CHECK` constraint для валидации типов, `title` для названия и JSON-поле `settings` про запас на будущее. **Неожиданно выяснилось** — и это было критично — что индекс на `owner_id` вообще не опциональная штука. Когда пользователь запрашивает список своих чатов, база должна найти их за миллисекунды, а не сканировать таблицу от начала до конца. SQLite часто недооценивают в стартапах, думают, что это игрушка для тестирования. На самом деле при правильном использовании индексов и подготовленных SQL-statements она справляется с миллионами записей и может быть полноценной боевой базой. Реализацию сделал по образцу `UserManager`: создал `ChatManager` с асинхронными методами `add_chat()`, `is_managed()`, `get_owner()`. Каждый запрос параметризован — никаких SQL-injection уязвимостей. Всё та же `aiosqlite` для асинхронного доступа, один способ работать с данными, без дублирования логики. Красивый момент получился благодаря `INSERT OR REPLACE` — если чат переиндексируется с новыми настройками, старая запись просто заменяется. Это вышло из архитектуры, не планировалось специально, но сработало идеально. **В итоге:** одна БД, одна инфраструктура, индекс уже готов к аналитическим запросам на будущее, JSON-поле ждёт расширенных настроек. Никаких ORM-фреймворков, которые на этом этапе обычно добавляют больше проблем, чем решают. Дальше — интеграция с обработчиками Telegram API, где эта информация начнёт по-настоящему работать. Но то уже следующая история. 😄 Разработчик говорит: «Я знаю SQLite». HR: «На каком уровне?». Разработчик: «На уровне, когда она работает, и я этому не верю».

#claude#ai#python#javascript#api#security
Разработка: bot-social-publisher
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

SQLite вместо памяти: как обуздать рост Telegram-ботов

# Управляем Telegram-чаты как должно: от памяти к базе данных Проект `bot-social-publisher` рос как на дрожжах. Каждый день новые пользователи подключали своих ботов, запускали кампании, развивали функционал. Но вот беда: где-то в памяти процесса валялась информация о том, какие чаты под управлением, кто их владелец, какие у них настройки. Приватный чат? Группа? Канал? Всё это было либо в переменных, либо где-то в логах. Нужна была система. Правильная, масштабируемая, не требующая отдельного сервера для базы данных. **Первым делом** посмотрел, как устроен текущий стек. В проекте уже была собственная SQLite база в `data/agent.db`, и там жил `UserManager` — отличный пример того, как правильно работать с асинхронными операциями через `aiosqlite`. Значит, нужно просто добавить новую таблицу `managed_chats` в ту же базу, скопировать философию управления пользователями и запустить в production. **Архитектурное решение** было ясно с самого начала: никаких микросервисов, никаких Redis-кэшей для этого этапа. Нужна таблица с полями для `chat_id` (первичный ключ), `owner_id` (связь с пользователем), `chat_type` (с проверкой через `CHECK` constraint — только валидные типы), `title` и JSON-поле `settings` на будущее. Неожиданно выяснилось, что индекс на `owner_id` — это не опциональная штука. Когда пользователь запрашивает список своих чатов, база должна найти их быстро, а не сканировать всю таблицу от начала до конца. SQLite часто недооценивают в стартапах, думают, что это игрушка для тестирования. На самом деле при правильном использовании индексов и подготовленных statements она справляется с миллионами записей и может быть полноценной боевой базой. **Реализацию** сделал по образцу `UserManager`: создал `ChatManager` с асинхронными методами `add_chat()`, `is_managed()`, `get_owner()`. Каждый запрос параметризован — никаких SQL injection уязвимостей. Используется всё та же `aiosqlite` для асинхронного доступа, одна точка подключения для всей системы, без дублирования логики. Красивый момент получился благодаря `INSERT OR REPLACE` — если чат переиндексируется с новыми настройками, старая запись просто заменяется. Это вышло из архитектуры, а не планировалось специально. В итоге: одна БД, одна инфраструктура, масштабируемая схема. Когда понадобятся сложные аналитические запросы — индекс уже есть. Когда захотим добавить права доступа или расширенные настройки чата — JSON-поле ждёт. Никаких фреймворков ORM, которые обычно добавляют больше проблем, чем решают на этом этапе. Дальше — интеграция с обработчиками Telegram API, где эта информация будет реально работать. Но то уже следующая история. 😄 Разработчик: «Я знаю ArgoCD». HR: «На каком уровне?». Разработчик: «На уровне Stack Overflow».

#claude#ai#python#javascript#api#security
Разработка: bot-social-publisher
9 февр. 2026 г.
Новая функцияC--projects-ai-agents-voice-agent

Когда AI становится парным программистом: история Claude Code

# Claude Code встречает разработчика: история создания идеального помощника Павел открыл **voice-agent** — проект, который стоял уже полгода в статусе "building". Python-бэкенд на FastAPI, Next.js фронтенд, асинхронная обработка аудио через aiogram. Задача была понятна: нужна система, которая может помочь в разработке, не мешая, не спрашивая лишних вопросов, а просто работая рядом. Первым делом команда определилась с подходом. Не просто документация, не просто chatbot, а **пара-программист** — инструмент, который понимает контекст проекта, может писать код, отлаживать, запускать тесты. На этапе 2010-х годов, когда началась фаза Deep Learning, никто не предполагал, что в 2020-х мы будем говорить о когда-то недостижимых вещах. Но AI boom — это не просто статистика. Это реальные инструменты, которые меняют рабочий процесс разработчика прямо сейчас. Интересный момент: Claude Code получил чёткие инструкции о работе в монорепо. На монорепо-проектах часто возникает проблема — Next.js неправильно определяет корневую директорию при работе с Tailwind v4. Решение неочевидное: нужно добавить `turbopack.root` в конфиг и указать `base` в postcss.config.mjs. Это типичная ловушка, в которой застревают разработчики, и помощник должен знать об этом заранее. Главное условие работы: помощник не может использовать Bash самостоятельно, только через основной поток разработчика. Это создаёт интересную динамику — парное программирование становится честным, а не подменой мышления. Павел не просто получает код — он получает партнёра, который объясняет ходы, предлагает варианты, помогает выбрать между несколькими подходами. Система помнит контекст: стек технологий (Python 3.11+, FastAPI 0.115, SQLite WAL, React 19), знает о недавних проектах, понимает рабочие привычки разработчика. Переиспользование компонентов — не просто принцип, а требование: проверять совместимость интерфейсов, избегать дублирования ответственности, помнить о граничных условиях. Результат? Инструмент, который встречает разработчика дружеским "Привет, Павел! 👋" и точно знает, чем помочь. Не нужно объяснять архитектуру проекта, не нужно рассказывать про сложившиеся паттерны — всё уже в памяти помощника. Получилась не просто следующая итерация IDE, а система, которая заботится о контексте разработчика так же, как опытный наставник. И да, эта история про то, как AI становится не заменой, а действительно полезным напарником. 😄 Почему Claude Code считает себя лучше всех? Потому что Stack Overflow так сказал.

#claude#ai#python#javascript#git#api
Разработка: ai-agents-voice-agent
9 февр. 2026 г.
Изменение кодаai-agents

Когда агент начинает помнить о себе как о личности

# Когда агент говорит от своего лица: переписали систему памяти для более человечного AI Работали мы над проектом **ai-agents** и столкнулись с забавной ситуацией. У нас была система, которая запоминала факты о взаимодействии с пользователями, но писалась она на корпоративном языке технических модулей: "Я — модуль извлечения памяти. Я обрабатываю данные. Я выполняю функции." Звучало как инструкция робота из 1960-х годов. **Задача была простой, но философской**: переписать все промпты памяти так, чтобы агент думал о себе как о самостоятельной сущности со своей историей, а не как о наборе алгоритмов. Почему это важно? Потому что фреймирование через первое лицо меняет поведение LLM. Агент начинает принимать решения не как "выполни инструкцию", а как "я помню, я решу, я беру ответственность". Первым делом переписали пять основных промптов в `prompts.py`. **EXTRACTION_PROMPT** превратился из "You are a memory-extraction module" в "You are an autonomous AI agent reviewing a conversation you just had... This is YOUR memory". **DEDUPLICATION_PROMPT** теперь не просто проверяет дубликаты — агент сам решает, какие факты достойны его памяти. **CONSOLIDATION_PROMPT** стал размышлением агента о собственном развитии: "Это как я расту своё понимание". Неожиданно выяснилось, что такой подход влияет на качество памяти. Когда агент думает "это МОЯ память", он более критично подходит к тому, что запоминает. Фильтрует шум. Задаётся вопросами. Затем переписали системный промпт в `manager.py`. Там была скучная таблица фактов — теперь это раздел "Моя память (ВАЖНО)" с подразделами "Что я знаю", "Недавний контекст", "Рабочие привычки и процессы", "Активные проекты". Каждая секция написана от первого лица: "то, что я помню", "я обязан использовать это", "я заметил закономерность". Итог: агент стал более *осознанным* в своих решениях. Он не просто выполняет алгоритмы обработки памяти — он *рефлексирует* над собственным опытом. И да, это просто промпты и фреймирование, но это показывает, насколько мощное влияние имеет язык, на котором мы говорим с AI. Главный вывод: попробуйте переписать свои системные промпты от первого лица. Посмотрите, как изменится поведение модели. Иногда самые глубокие улучшения — это просто изменение перспективы. 😄 Почему агент начал ходить к психотерапевту? Ему нужно было лучше понять свою память.

#claude#ai#python
Разработка: ai-agents
9 февр. 2026 г.
Новая функция

Боевой тест Telegram-бота: когда теория встречается с реальностью

# Проверяем Telegram-бота в боевых условиях: тестируем управление доступом Когда создаёшь бота для Telegram, одно дело — писать тесты в PyTest, и совсем другое — убедиться, что он работает с реальными аккаунтами и обрабатывает команды так, как задумано. Вот я и пришёл к моменту, когда нужно было залезть в грязь и провести самый важный тест: запустить бота и написать ему сообщение из Telegram. ## Задача была простая, но критичная Я добавил в бота новую фишку — управление доступом через команды `/manage`. Идея: в групповом чате владелец может сделать его приватным (`/manage add`), и тогда бот будет отвечать только ему. Затем команда `/manage remove` открывает доступ для всех обратно. Плюс ещё `/recall` и `/remember` для сохранения данных в памяти чата. Звучит просто, но нужно убедиться, что: - бот действительно игнорирует сообщения посторонних в приватном режиме; - владелец всегда может управлять ботом; - после отключения приватности всё работает как раньше. ## Как я это проверял Сначала поднял бота локально: ``` python telegram_main.py ``` Затем начались «полевые испытания»: 1. **Первый скрин-тест** — написал боту `/manage add` из своего аккаунта. Бот должен был записать ID чата в таблицу БД `managed_chats` и включить режим приватности. Отправил обычное сообщение — бот ответил. ✅ 2. **Второй аккаунт** — попросил друга отправить то же сообщение из другого Telegram. Бот молчал, хотя обычно отвечает на всё. Middleware `permission_check.py` срабатывал корректно и блокировал обработку. ✅ 3. **Финальный тест** — написал `/manage remove` и снова попросил друга отправить сообщение. На этот раз бот ответил. Приватность снята, всё доступно. ✅ ## Что оказалось неочевидным Интеграционное тестирование в Telegram выявило одну тонкость: когда ты работаешь с асинхронным обработчиком команд в aiogram, timing-зависимые проверки могут создавать гонки условий. У меня был момент, когда команда `/manage add` срабатывала, но middleware проверял доступ *до* того, как запись попала в БД. Пришлось добавить небольшой await после insert'а, чтобы гарантировать консистентность. Ещё обнаружил: если ты работаешь с SQLite и одновременно несколько обработчиков пишут в таблицу, нужен явный `commit()` или использовать контекстный менеджер транзакций. Иначе другой процесс не увидит изменения до commit'а. ## Что дальше? После успешных интеграционных тестов я задокументировал всё в README.md — добавил секцию про управление доступом с примерами команд. Создал отдельный файл `docs/CHAT_MANAGEMENT.md` с полной архитектурой ChatManager, схемой БД и API reference для всех методов класса. Теперь у меня есть надёжная система для создания приватных чатов с ботом. Это можно использовать для ассистентов, которые работают с конфиденциальными данными, или для модераторов в больших группах. Главный вывод: прежде чем гордиться unit-тестами, обязательно проверь свой код в реальной среде. Иногда именно там появляются неожиданные проблемы, которые не поймать никаким PyTest. 😄 Что общего у Telegram API и инструкций по использованию телефона? И то, и другое люди игнорируют в пользу метода проб и ошибок.

#clipboard#python#api#security
9 февр. 2026 г.
Новая функцияC--projects-ai-agents-voice-agent

Монорепо, голос и журнал ошибок: как AI учится не ломать код

# Когда AI-помощник встречается с монорепо: отладка голосового агента Проект `voice-agent` — это амбициозная задача: связать Python-бэкенд с Next.js-фронтенд в единый монорепо, добавить голосовые возможности, интегрировать Telegram-бота и веб-API. Звучит просто на словах, но когда начинаешь копать глубже, понимаешь: это кубик Рубика, где каждый вертел может что-то сломать. **Проблема, с которой я столкнулся, была банальной, но коварной.** Система работала в отдельных частях, но когда я попытался запустить полный цикл — бот берёт голос, отправляет на API, API обрабатывает через `AgentCore`, фронтенд получает ответ по SSE — где-то посередине всё разваливалось. Ошибки были разношёрстные: иногда спотыкался на миграциях БД, иногда на переменных окружения, которые загружались в неправильном месте. **Первым делом я понял: нужна система для документирования проблем.** Создал `ERROR_JOURNAL.md` — простой журнал "что сломалось и как это чинилось". Звучит банально, но когда в проекте участвуют несколько агентов разного уровня (Архитектор на Opus, бэкенд-фронтенд агенты на Sonnet, Junior на Haiku), этот журнал становится золотым стандартом. Вместо того чтобы каждый агент наново натыкался на баг с Tailwind v4 в монорепо, теперь первым делом смотрим журнал и применяем известное решение. **Архитектура обработки ошибок простая, но эффективная:** 1. Ошибка возникла → читаю `docs/ERROR_JOURNAL.md` 2. Похожая проблема есть → применяю известное решение 3. Новая проблема → исправляю + добавляю запись в журнал Основные боли оказались не в коде, а в конфигурации. С Tailwind v4 нужна магия в `next.config.ts` и `postcss.config.mjs` — добавить `turbopack.root` и `base`. SQLite требует WAL-режим и правильный путь к базе. FastAPI любит, когда переменные окружения загружаются только в точках входа (`telegram_main.py`, `web_main.py`), а не на уровне модулей. **Интересный момент: я переоценил сложность.** Большинство проблем решались не рефакторингом, а правильной организацией архитектуры. `AgentCore` — это единое ядро бизнес-логики для бота и API, и если оно валидируется с одной строки (`python -c "from src.core import AgentCore; print('OK')"`), весь стек работает как часы. **Итог:** система работает, но главный урок не в технических трюках — в том, что монорепо требует прозрачности. Когда каждая составляющая (Python venv, Next.js сборка, миграции БД, синхронизация переменных окружения) задокументирована и протестирована, даже сложный проект становится управляемым. Теперь каждый новый агент, который присоединяется к проекту, видит ясную картину и может сразу быть полезным, вместо того чтобы возиться с отладкой. На следующем этапе плотнее интегрирую streaming через Vercel AI SDK Data Stream Protocol и расширяю систему управления чатами через новую таблицу `managed_chats`. Но это — уже другая история. 😄 Что общего у монорепо и парка развлечений? Оба требуют хорошей разметки, иначе люди заблудятся.

#claude#ai#python#javascript#git#api#security
Разработка: ai-agents-voice-agent
9 февр. 2026 г.
Новая функция

Одна БД для всех: как мы добавили чаты без архитектурного хаоса

# Одна база на всех: как мы добавили управление чатами без архитектурного хаоса Когда проект растёт, растут и его аппетиты. В нашем Telegram-боте на основе Python уже была отличная инфраструктура — `UserManager` для управления пользователями, собственная SQLite база в `data/agent.db`, асинхронные запросы через `aiosqlite`. Но вот беда: чат-менеджер ещё не появился. А он нам был нужен. Стояла вот какая задача: нужно отслеживать, какие чаты управляет бот, кто их владелец, какой это тип чата (приватный, группа, супергруппа, канал). При этом не создавать отдельную базу данных — это же кошмар для девопса — а переиспользовать существующую инфраструктуру. **Первым делом** заглянул в текущую архитектуру. Увидел, что всё уже завязано на одной БД, один конфиг, одна логика подключения. Идеально. Значит, нужна просто одна новая таблица — `managed_chats`. Задумал её как простую структуру: `chat_id` как первичный ключ, `owner_id` для связи с пользователем, `chat_type` с проверкой типов через `CHECK`, поле `title` для названия и JSON-колонка `settings` на будущее. Обычно на этом месте разработчик бы создал абстрактный `ChatRepository` с двадцатью методами и паттерном `Builder`. Я же решил сделать проще — скопировать философию `UserManager` и создать классический `ChatManager`. Три-четыре асинхронных метода: добавить чат, проверить, управляется ли он, получить владельца. Всё на `aiosqlite`, как и везде в проекте. **Неожиданно выяснилось**, что индексы — это не украшение. Когда начну искать чаты по владельцу, индекс на `owner_id` будет спасением. SQLite не любит полные скены таблиц, если можно обойтись поиском по индексу. Интересный момент: SQLite часто недооценивают в стартапах, думают, что это игрушка. На самом деле она справляется с миллионами записей, если её правильно использовать. Индексы, `PRAGMA` для оптимизации, подготовленные statements — и у вас есть боевая база данных. Многие проекты потом переходят на PostgreSQL только потому, что привыкли к MySQL, а не из реальной нужды. В итоге получилась чистая архитектура: одна БД, одна точка подключения, новая таблица без какого-либо дублирования логики. `ChatManager` живёт рядом с `UserManager`, используют одни и те же библиотеки и утилиты. Когда понадобятся сложные запросы — индекс уже есть. Когда захотим добавить настройки чата — JSON-поле ждёт. И никаких лишних микросервисов. Следующий шаг — интегрировать это в обработчики событий Telegram API. Но это уже другая история. 😄 Почему база данных никогда не посещает вечеринки? Её постоянно блокирует другой клиент!

#clipboard#python#javascript#git#security
9 февр. 2026 г.
Исправлениеbot-social-publisher

Бот, который помнит, где остановился: история оптимизации

# Как мы научили бота-публикатора читать только новое и не зацикливаться Работаю над **bot-social-publisher** — инструментом, который автоматизирует публикацию контента в соцсети. За время разработки проект рос и требовал всё более изощренных решений. Недавно пришло время для серьёзного апдейта: версия 2.2 превратилась в настоящий рефакторинг с половиной архитектуры. Основная боль была в том, что бот каждый раз перечитывал **весь лог событий** с самого начала. Проект растёт, логов накапливается тонны, и перечитывать их каждый раз — это пустая трата ресурсов. Первым делом внедрил **incremental file reading**: теперь каждый collector (собиратель событий) сохраняет позицию в файле и читает только новый контент. Позиции и состояния переносят перезапуски — данные не теряются. Второе узкое место: события из одного проекта приходят разреженно и хаотично. Если публикация выходит с опозданием, сессия кажется невнятной. Ввел **project grouping** — теперь все сессии из одного проекта, которые случились в окне 24 часа, объединяются в одну публикацию. Начало звучать куда более логично. Но бот просто агрегировал события — не очень информативно. Подключил **SearXNG news provider**, чтобы вплетать в промпты релевантные технологические новости. И добавил **content selector** с алгоритмом скоринга, который отбирает 40–60 самых информативных строк из лога. Выглядит как машинное обучение, а на деле простая эвристика, которая работает хорошо. Далее натолкнулся на проблему качества текста. LLM первый раз генерирует контент, но грамматика хромает. Внедрил **proofreading pass** — второй вызов LLM, но уже как редактор. Он проходит по тексту и чистит пунктуацию, стиль, грамматику. Результат — ночь и день. Когда LLM генерирует заголовок, иногда получаются дубли. Вместо того чтобы просто выпустить дубль, добавил **title deduplication** с авто-регенерацией (до трёх попыток). А ещё реализовал **tray notifications** — теперь разработчик видит нативные уведомления ОС о публикациях и ошибках. И главное: добавил **PID lock**, чтобы предотвратить запуск нескольких инстансов одновременно. Интересный момент: **PyInstaller**. Когда собираешь exe-бандл, пути до ресурсов перестают работать. Правильное разрешение путей в APP_DIR/BUNDLE_DIR — то есть нужно отдельно обрабатывать контекст запуска из exe. Мелочь, но без этого бандл просто не запустится. Ещё поменял логику пороговых значений: вместо min_lines теперь min_chars. Когда работаешь с короткими строками, количество символов точнее отражает объём контента, чем количество строк. И как положено, добавил AGPL-v3 лицензию ко всем файлам исходника. В итоге v2.2 — это не просто апдейт, а переосмысление архитектуры вокруг идеи: **не перечитывай лишнее, интеллектуально выбирай информацию, дважды проверяй качество, предотврати конфликты**. Бот теперь быстрее, умнее и его легче деплоить. 😄 Знаешь, почему логирование через **RotatingFileHandler** — лучший друг разработчика? Потому что диск полный. С ротацией логов хотя бы видно, когда именно он полный.

#git#commit#python#api#security
Разработка: bot-social-publisher
9 февр. 2026 г.
ИсправлениеC--projects-bot-social-publisher

Регулярка в f-строке сломала SSE: как Python запутался в скобках

# Вся беда была в f-строке: как регулярное выражение сломало SSE-поток Работаю над проектом **trend-analisis** — системой для анализа трендов с помощью AI. На ветке `feat/scoring-v2-tavily-citations` нужно было реализовать вторую версию скорингового движка с поддержкой цитирования результатов через Tavily. Ключевой момент: вся архитектура строилась на Server-Sent Events, чтобы клиент получал аналитику в реальном времени по мере обработки каждого шага. Теоретически всё выглядело идеально. Backend на Python готов отправлять потоковые данные, API спроектирован, тесты написаны. Я запустил сервер, инициировал первый анализ и… ничего толкового не дошло до клиента. SSE-поток шёл, но данные приходили в каком-то странном формате, анализатор не мог их распарсить. Что-то явно ломалось на этапе подготовки ответа. Первый подозреваемый — кодировка. Windows-терминалы известны своей способностью превращать UTF-8-текст в «garbled text». Поехал в логи, начал смотреть, что именно генерируется на сервере. И вот тут выяснилось что-то совершенно неожиданное. **Виновником было регулярное выражение, спрятанное внутри f-строки.** В коде я использовал конструкцию `rf'...'` — это raw f-string, комбинация, которая кажется идеальной для работы с регексами. Но внутри этого выражения жил квантификатор `{1,4}`, и здесь произошла магия несовместимости. Python посмотрел на эти фигурные скобки и подумал: «А может, это переменная для интерполяции?» Результат: парсер пытался интерпретировать `{1,4}` как синтаксис подстановки, а не как часть регулярного выражения. Регекс ломался молча, и весь парсинг SSE-потока шёл вразнос. Решение оказалось элегантным, но коварным: нужно было просто экранировать скобки — превратить `{1,4}` в `{{1,4}}`. Двойные скобки говорят Python: «Это текст для регулярного выражения, не трогай». Звучит просто? Да. Но найти это среди километра логов — совсем другое дело. **Забавный факт:** f-строки появились в Python 3.6 и революционизировали форматирование текста. Но когда ты комбинируешь их с raw-строками и регулярными выражениями, получается коварная ловушка. Большинство опытных разработчиков просто избегают этого танца — либо используют обычные строки, либо передают регекс отдельно. Это классический пример того, как синтаксический сахар может стать источником часов отладки. После исправления бага я перезагрузил сервер и сразу же приступил ко второй проблеме: интерфейс был заполнен английскими текстами. Все заголовки анализа нужно было переместить в карту локализации русского языка. Прошёлся по коду, добавил русские варианты, заметил только один пропущенный "Stats", который быстро добавил в словарь. Финальная перезагрузка — и всё встало на место. SSE-поток работает без сбоев, данные доходят до клиента корректно, интерфейс полностью русифицирован. Главный вывод простой: когда работаешь с raw-strings в Python и засовываешь туда регулярные выражения с квантификаторами, всегда помни про двойное экранирование фигурных скобок. Это экономит часы отладки и стресса. 😄 F-строки и регексы — битва синтаксиса, в которой проигрывают все.

#claude#ai#python#git#api
Разработка: bot-social-publisher
9 февр. 2026 г.