Repository navigation
Releases
Releases · axisrow/tg_content_factory
v0.2.4.2 — Analyzer in Seconds, DM Cycle & Content Curation
What's Changed
- feat(errors): classify TypeNotFoundError as schema drift, not missing entity (#1549) by @axisrow in #1553
- feat(web): QR login for account onboarding (#1551) by @axisrow in #1555
- fix(auth): QR login review fixes missing from #1555 by @axisrow in #1559
- chore(docs): standard AO review replaces dual Claude+Codex convention by @axisrow in #1560
- feat(collector): parse MessageEntity spans and flatten RichText iv-pages (#1547) by @axisrow in #1554
- feat(sanitize): anti-prompt-injection sanitizer for Telegram content entering LLM prompts (#1546) by @axisrow in #1558
- feat(runtime): cross-process session lock and AuthKeyDuplicatedError retries (#1548) by @axisrow in #1556
- feat(transcription): speech-to-text для голосовых — порт transcription.py из telegram-mcp by @axisrow in #1561
- fix(filters): label-only метки переживают apply; keep-тег гардирует все авто-пути фильтрации by @axisrow in #1565
- feat(collector): preserve masked-hyperlink URLs in entities_json (#1492) by @axisrow in #1564
- fix(agent-tools): default-phone ACL pick skips inactive/broken accounts (#1485) by @axisrow in #1563
- feat(scheduler): queue-status — live collection progress with measured ETA by @axisrow in #1562
- feat(dm): reply drafts with atomic claim against double-send (#1429) by @axisrow in #1566
- test(db): close every raw sqlite3 connection left open by test helpers (#1494) by @axisrow in #1567
- chore(deps): update fastapi requirement from <0.143,>=0.136.3 to >=0.136.3,<0.144 by @dependabot[bot] in #1543
- feat(filters): low_engagement — флаг мёртвого вовлечения (views <10% подписчиков, окно 100 постов) by @axisrow in #1550
- test(quality): pin quality-scoring tests to offline default stub (#1445) by @axisrow in #1572
- feat(messages): topic_title рядом с topic_id при выдаче (#1552) by @axisrow in #1575
- fix(cli): no parallel Telegram pools — scheduler start / channel stats / collect --channel-id (#1569) by @axisrow in #1574
- feat(filters): whitelist-режим «авторский контент» (#1490) + filter flag — sticky manual (#1499) by @axisrow in #1573
- feat(ping): friendly pings for dormant DM contacts (#1415) by @axisrow in #1576
- feat(scheduler): CLI status reads live runtime_snapshots; raw settings set reaches the worker by @axisrow in #1577
- feat(scheduler): live RPC for trigger/cancel/clear-pending over telegram_commands (#1568) by @axisrow in #1578
- packaging: wheel ships tg_agent package; tg-agent --version prints correct name (#1448, #1447) by @axisrow in #1582
- feat(search): date window + json/csv output; structured weekly digest workflow by @axisrow in #1584
- fix(cli): reject unknown permission boolean values by @axisrow in #1609
- fix(cli): preserve Typer exit codes in production entrypoints by @axisrow in #1610
- fix(account): load session encryption key for env-only onboarding by @axisrow in #1612
- fix(cli): recognize console-script and configured daemon processes by @axisrow in #1611
- fix(cli): apply new pipeline filters after message loading by @axisrow in #1613
- fix(pipeline): preserve DAG publication relations on edit by @axisrow in #1614
- feat(skills): channel discovery workflow by keywords by @axisrow in #1615
- feat(filters): channel probe — pre-add quality card from a LIVE sample by @axisrow in #1622
- fix(cli): recognize macOS framework Python binary in daemon detection by @axisrow in #1623
- fix(analytics): pipeline-stats publish rate inflated 100x (5000% instead of 50%) by @axisrow in #1625
- fix(cli): reject translate detect --batch-size <= 0 (infinite loop, #1618) by @axisrow in #1624
- fix(cli): keep full message text in CSV output (#1617) by @axisrow in #1627
- fix(pipeline): keep A/B settings through export/import (#1621) by @axisrow in #1628
- fix(pipeline): persist A/B flags on pipeline add --node (#1620) by @axisrow in #1629
- hotfix: remove duplicated A/B kwargs breaking import_json (main red at b731cf6) by @axisrow in #1634
- fix(search,analytics): validate and normalize non-canonical date bounds (#1593) by @axisrow in #1633
- fix(channel): clean not-found instead of FK traceback for tag set/get (#1600) by @axisrow in #1630
- fix(search-query): validate regex patterns; report unavailable counts honestly (#1607) by @axisrow in #1631
- fix(cli): messages read --format json/csv survives empty results and errors (#1598) by @axisrow in #1632
- fix(calendar): --limit must not reorder the upcoming queue head (#1619) by @axisrow in #1626
- fix(filters): use saved filter-criteria thresholds in ChannelAnalyzer (#1596) by @axisrow in #1636
- feat(tasks): lease/TTL recovery for stranded interop claims (#1468) by @axisrow in #1638
- feat(dm): incoming-DM journal readability + web/REST surfaces (#1579) by @axisrow in #1639
- feat(dm): catch-up settings validation, dm status CLI, mark_processed wiring, queue log phone (#1581) by @axisrow in #1640
- fix(settings): encrypt embeddings API key at rest; mask secrets in CLI output (#1597) by @axisrow in #1642
- fix(cli): clean abort on EOF and Ctrl-C at confirmation prompts (#1590) by @axisrow in #1641
- fix(pipeline): forward backend/mode/image flags on pipeline add --json-file (#1594) by @axisrow in #1643
- fix(photo-loader): batch-create is atomic — no partial HELD batch on error (#1601) by @axisrow in #1644
- fix(skills): align documented commands with the CLI tree; document dialogs delete (#1605) by @axisrow in #1635
- feat(filters): high_volume flag — P95 of 24h message volume with absolute floor by @axisrow in #1645
- fix(paths): anchor runtime data/log dirs to cwd, not the package dir (#1595) by @axisrow in #1637
- feat(dm): agent tools for the DM cycle — journal, drafts, approve/reject, archive (#1580) by @axisrow in #1646
- perf(test): speed up full pytest runs and fix isolation by @axisrow in #1647
- fix(cli): search-query toggle/run report not-found instead of fake success (#1606) by @axisrow in #1648
- feat(channels): approval queue core and gate (provenance stage 5.1) by @axisrow in #1654
- test(env): detect stale editable installs with one clear failure (#1649) by @axisrow in #1650
- feat(filters): analyzer and prefilters skip human channels — provenance stage 4 (#1312) by @axisrow in #1651
- feat(shared): tg-shared package scaffold — storage Protocol, boundary (#1420) by @axisrow in #1653
- test(cli): cover the full daemon-autorestart decision path; document local hook wiring by @axisrow in #1652
- fix(cli): errors exit non-zero with stderr via shared cli_error helper by @axisrow in #1655
- docs(skills): digest items must end with bare source links by @axisrow in #1656
- docs(skills): digest item = title, body, ONE primary-source URL by @axisrow in https://github.com/axisrow/tg_content...
v0.2.4.1 — Stability: Cancel Propagation, Spam-Farm Filters & Audit Hardening
What's Changed
- feat(cli): restart/worker are the managed daemon — no web panel by @axisrow in #1465
- feat(queue): collection progress line — tasks left after each finished task by @axisrow in #1466
- fix(queue): skip channel on unknown Telegram TL type with one warning by @axisrow in #1470
- feat(interop): make task creation and reports retry-safe by @axisrow in #1469
- feat(queue): end-of-run retry pass for failed channel collections by @axisrow in #1472
- fix(scheduler): CLI mutations notify the live worker via scheduler.reconcile by @axisrow in #1474
- feat(cli): auto-restart daemon when checked-out src/ is newer than the build by @axisrow in #1476
- fix(dm): make DmListener._on_event async — telethon awaits handler returns by @axisrow in #1478
- feat(cli): channel candidates — list search-discovered channels awaiting activation by @axisrow in #1479
- refactor(cli): channel candidates cleanup after #1479 review by @axisrow in #1481
- fix(filter): catch CamelCase+digits spam usernames by @axisrow in #1483
- fix(cli): default account is the DB primary, not the sorted-first connected (#1480) by @axisrow in #1484
- refactor(cli): drop dead None-branch in dialogs _resolve_phone by @axisrow in #1487
- refactor(cli): drop dead None-check in _resolve_phone (follow-up to #1484) by @axisrow in #1488
- fix(cli): show @username/title in search results, not bare numeric id by @axisrow in #1489
- feat(filters): auto_feed flag for template-generated link feeds by @axisrow in #1491
- chore(deps): update textual requirement from >=8.2.7 to >=8.2.8 by @dependabot[bot] in #1459
- chore(deps): update apscheduler requirement from >=3.11.2 to >=3.11.3 by @dependabot[bot] in #1460
- chore(deps-dev): update hypothesis requirement from >=6.100.0 to >=6.168.1 by @dependabot[bot] in #1461
- fix(tests): seal HTTP interception for openai 3.x (httpx2), adopt openai>=3.19.2 by @axisrow in #1495
- feat(filters): whitelist suspects report — filter suspects (#1490) by @axisrow in #1493
- fix(telegram): hourly volume budget for live username resolves by @axisrow in #1498
- feat(filters): non_cyrillic label-only + keep-tag escrow by @axisrow in #1497
- fix(queue): DB-side cancel stops a running collect (supervisor arms cancel_events) by @axisrow in #1500
- fix(queue): cancel sweep tail window — validation coverage, dispatch revival by @axisrow in #1503
- fix(dm_catchup): one broken dialog no longer kills the account pass by @axisrow in #1504
- fix(tests): close leaked cli_init_patch databases at teardown (safety net) by @axisrow in #1505
- ci(tests): shard parallel suite x2 — tests job wall −52% by @axisrow in #1506
- fix(ci): --cov-fail-under=0 on producers — 87 ratchet moves to coverage-combine by @axisrow in #1507
- fix(ci): include-hidden-files on coverage uploads — dotfiles excluded by default by @axisrow in #1508
- ci: drop coverage measurement, 5-minute budget on test jobs by @axisrow in #1509
- chore(deps): update fastapi requirement from <0.139,>=0.136.3 to >=0.136.3,<0.143 by @dependabot[bot] in #1496
- fix(tooling): mutmut sandbox copies conftest+scripts; document flat-src incompatibility by @axisrow in #1501
- fix(tooling): correct mutmut stats-run numbers — full suite is ~10.7k (follow-up to #1501) by @axisrow in #1512
- fix(filters): catch the short spam-farm wave — 8-9 char CAPS names with an internal digit by @axisrow in #1511
- tests: remove 55 vacuous/duplicate tests proven by control mutations by @axisrow in #1513
- test(messages): pin batch-insert behaviors that survived mutation testing by @axisrow in #1514
- test(accounts): pin migrate_sessions behaviors that survived mutation testing by @axisrow in #1515
- test(dispatcher): cover the EXPORT dispatch wiring (last uncovered dispatcher branch) by @axisrow in #1520
- test(content-generation): pin survivor behaviors from mutation slice #4 by @axisrow in #1522
- test(pipeline): pin update-injection and template-override behaviors from mutation slice #4 by @axisrow in #1523
- test(error-recovery): pin image-guard branches and retry bounds from mutation slice #4 by @axisrow in #1524
- test(templates): pin built-in catalog invariants from mutation slice #4 by @axisrow in #1525
- test(dialogs): pin delete_dialogs failure outcomes and sweep cache-mode defaults from mutation slice #5 by @axisrow in #1526
- test(collector): pin pre-collection filter boundaries and collect_all gates from mutation slice #5 by @axisrow in #1527
- test(collector,pool): pin stream cleanup and lease-acquire contracts from mutation slice #5 by @axisrow in #1528
- test(auth,identity): pin auth-flow contracts and sender-identity extraction from mutation slice #6 by @axisrow in #1529
- test(reactions,backends): pin reaction-user extraction and gate reservation from mutation slice #6 by @axisrow in #1530
- test(trend): pin trending pagination, rank order and SQL filter contracts from mutation slice #7 by @axisrow in #1531
- test(dispatcher): pin run-iteration handler update contracts from mutation slice #7 by @axisrow in #1532
- test(actions): pin download media failure codes and path-escape guard from mutation slice #7 by @axisrow in #1533
- fix(filters): bound user-supplied regex matching with a per-search timeout by @axisrow in #1534
- fix(audit): address the 8 backend regressions found by the red-test audit by @axisrow in #1544
Highlights
- Collection cancel and retry made real — A DB-side cancel now stops a running collect — the supervisor arms cancel_events instead of only flipping a status row (#1500); the cancel sweep covers the validation-phase tail window so revived tasks can't slip through (#1503); failed channel collections get an end-of-run retry pass (#1472); and task creation and reports are retry-safe for external agents (#1469).
- Spam-farm filter wave — The short CAPS-username spam wave (8-9 chars with an internal digit) and CamelCase+digits patterns are caught (#1511, #1483); template-generated link feeds get an auto_feed flag (#1491); a whitelist-suspects report shows what the filter would drop (#1493); non_cyrillic becomes label-only with keep-tag escrow instead of hard skipping (#1497); and
channel candidateslists search-discovered channels awaiting activation (#1479). - Audit fixes: 8 backend regressions closed — The red-test audit regressions are fixed with UNIQUE+OR IGNORE guards and RENAME-trigger reparsing (#1535-#1542, #1544), and user-supplied regex matching is bounded with a per-search timeout against ReDoS (#1534).
- Telegram layer resilience — Channels with unknown Telegram TL types are skipped with one warning instead of failing the pass (#1470); live username resolves run under an hourly volume budget (#1498); the DM listener handler is properly awaited by telethon (#1478); a catch-up pass survives one broken dialog (#1504); CLI scheduler mutations notify the live worker via scheduler.reconcile (#1474); the default account is the DB primary, not the sorted-first connected (#1484); and search results show @username/title instead of bare numeric ids (#1489).
- Ops and CI —
restart/workerare the managed daemon with no web panel (#1465); the daemon auto-restarts when checked-out src/ is newer than the build (#1476); collection logs a progress line after each finished task (#1466); CI test jobs are sharded under a 5-minute budget with cover...
v0.2.4 — CLI + Skill First: Coding-Agent Integration, DM Archive & Floodgate Safety
What's Changed
- feat(dm): persistent archive of full DM history, both directions (#1453) by @axisrow in #1455
- ci: measure coverage on main only — PRs skip the cov instrumentation by @axisrow in #1458
- fix(tests): drop the xdist load throttle — local -n auto is cpu - 1 by @axisrow in #1464
Highlights
- The primary mechanism: tg-agent CLI + skill for coding agents — The project is repositioned as a dependency for coding agents (Claude Code, OpenCode, Codex): every capability lands as a Typer CLI command first and is documented in the bundled tg-agent skill — setup checks, a task→command map and safety rules for acting on a real Telegram account (#1446). The argparse framework is fully gone (#959, #1120-1163) — one consistent CLI with uniform --help — and a plugin manifest ships alongside (#1406). Four agent backends (claude-agent-sdk, deepagents, Codex SDK #757, Google ADK #943) embed the same tools in-process. The web panel and TUI keep working but are frozen; the CLI is the contract.
- REST /api/tasks — external agents drive the worker over plain HTTP — A unified jobs read-model over collection tasks, scheduler jobs, telegram commands and dispatcher work (#963, #981), plus REST create/claim/complete/fail for task types like dm_reply and chat_answer (#960-961, #978). Coding agents get a clean HTTP surface instead of process embedding.
- Persistent DM Archive (both directions) — A real-time listener records every incoming and outgoing personal-chat message into a dedicated dm_messages store (#1438, #1427). A catch-up job recovers anything missed while offline, with three modes and staleness overrides (#1428), and
dialogs archive-historybackfills full history for people, bots and Saved Messages from a fresh dialog snapshot (#1455). Idempotent, resumable via per-chat cursors, survives restarts. - Flood safety rebuilt on the telethon-floodgate package — The hand-rolled flood stack was replaced by the external telethon-floodgate package: per-peer send limits, a proactive dialogs-page gate, a calibrated history category and a process-wide outgoing ceiling (#1432, #1433, #1441, #1444, #1405, #1372). Ban-prone patterns like repeated warm-ups are structurally prevented, and CLI commands hand Telegram work to the running worker instead of competing for sessions (#1324).
- TG_PROXY — SOCKS5/HTTP proxy for all MTProto traffic — On networks where Telegram IPs are blocked, set TG_PROXY=socks5://… or http://… and every connection (auth, pool, CLI, live-CLI tests) routes through it (#1450). Malformed proxy values fail fast at startup instead of being silently ignored.
- Resilient dialog cache and sweeps — Partial refreshes are preserved and surfaced instead of silently discarded (#1347, #1351, #1360), flood-degraded stale snapshots are flagged partial (#1358), truncated sweeps resume from a batch ledger (#1361, #1367), legacy groups resolve via PeerChat (#1353), and live dialog history is readable in CLI and web via tg_messenger (#1299).
- SSO: session-string export/import on every surface — Move an authorized account between machines and pools via account export-session / import in the CLI, the web login form, and agent tools (#828, #1150-1159). Encrypted-at-rest sessions require an explicit key, enforced at startup (#1363).
- AI channel ratings — LLM-judged channel quality: channel_ratings storage with CSV seed, an
analytics channel-ratingCLI command, a web table, and a read tool for agents (#966-1001). Filter analysis gains --quick sampling of the last N messages per channel (#1138). - Telegram-Desktop-style export — Build Telegram Desktop-compatible exports with size-aware media download, plus offline text export and a worker-driven EXPORT task (#834, #937-939).
- Security hardening — Web panel defaults locked down: 127.0.0.1 bind with weak-password fail-fast (#1305), password policy and auth throttling (#1339), CSV-injection/CSRF/ReDoS fixes (#846, #1256), and WAL-shared session materialization (#1323).
- Database performance — FTS backfill with a 21 GB index drop (#945), configurable cache/mmap with PRAGMA optimize on close (#940), exact-COUNT removal from search (#824), and reaction aggregation instead of JSON scanning (#827) — snappy on multi-GB archives.
Full Changelog: v0.2.3...v0.2.4
v0.2.3 — Agent Reliability — Grounded Diagnostics, Flood-Wait Fixes & Web Polish
What's Changed
- test: fail on pytest warnings by @axisrow in #503
- refactor(web): add shared response helpers by @axisrow in #512
- refactor(web): atomize settings routes by @axisrow in #513
- refactor(web): atomize photo loader routes by @axisrow in #514
- refactor(web): atomize pipeline routes by @axisrow in #515
- fix(web): use embedded worker agent manager by @axisrow in #517
- fix(agent): route zai through openai compatible endpoint by @axisrow in #518
- fix(agent): use zai coding endpoint by @axisrow in #519
- test(agent): cover provider runtime integration by @axisrow in #525
- fix(agent): default Z.AI to general endpoint by @axisrow in #526
- fix(agent): Z.AI Coding Plan support — required base_url + 1113/1309/1310/1311 hints by @axisrow in #528
- [codex] Ground account diagnostics in live runtime by @axisrow in #531
- [codex] Add graceful collection shutdown by @axisrow in #532
- refactor(cli): modularize parser registration by @axisrow in #533
- refactor(agent): add shared tool context helpers by @axisrow in #534
- refactor(agent): canonicalize provider metadata by @axisrow in #535
- refactor(tasks): split UnifiedDispatcher task handlers by @axisrow in #536
- Fix account runtime diagnostics and CLI parity by @axisrow in #538
- fix(agent): harden read-only tool contracts by @axisrow in #540
- fix(agent): cover read-only contract regressions by @axisrow in #541
- feat(analytics): support Chinese/CJK trending topics by @axisrow in #543
- fix(agent): share tool registry with deepagents by @axisrow in #544
- feat(agent): expose Telegram sender identity by @axisrow in #545
- fix(security): degrade wrong session key state by @axisrow in #546
- fix(collector): defer username resolve flood waits by @axisrow in #547
- fix(auth): retry startup with degraded sessions by @axisrow in #548
- fix(collector): defer queue when no clients by @axisrow in #549
- [codex] close issue 554 audit gaps by @axisrow in #555
- [codex] Centralize Telegram action contract by @axisrow in #558
- [codex] Add chat filters to search queries by @axisrow in #559
- [codex] Add reaction tool contract coverage by @axisrow in #560
- fix(cli,web,agent): cover reaction + filter cleanup gaps (#562) by @axisrow in #568
- fix(db): connection-wide write lock for shared aiosqlite (closes #569) by @axisrow in #570
- test(cli): real-Telegram integration suite + facade fix by @axisrow in #575
- test(cli): cover RO-DB group #576 — 41 new subprocess tests by @axisrow in #584
- test(cli): close RW-DB coverage gaps for issue #577 by @axisrow in #585
- test(cli): reorganize real-CLI tests by danger + PROC tests for #581 by @axisrow in #586
- test(cli): close TG-R coverage gaps for issue #578 by @axisrow in #587
- [codex] Harden real Telegram test policy by @axisrow in #588
- [codex] Harden live CLI test inventory by @axisrow in #589
- [codex] Add live mutation-safe CLI targets by @axisrow in #590
- [codex] Fix live CLI pin/unpin target selection by @axisrow in #591
- [codex] Add live CLI readiness and edit-message smokes by @axisrow in #592
- [codex] Request permission for missing agent tool ACLs by @axisrow in #595
- fix(agent): scope permission gate to interactive requests by @axisrow in #596
- fix(agent): harden permission dialog resolution by @axisrow in #598
- [codex] Retry locked SQLite writes for agent chat by @axisrow in #600
- Очередь агентских реакций с учетом flood-wait by @axisrow in #602
- [codex] Show reactions in read message outputs by @axisrow in #607
- feat(agent): показать статус очереди Telegram-заданий by @axisrow in #608
- [codex] read_messages: show reaction users behind flag by @axisrow in #609
- [codex] Queue agent permission prompts by @axisrow in #611
- fix(web): repair search translations and post stats by @axisrow in #612
- fix: validate Telegram reaction emoji by @axisrow in #614
- fix(web): repair calendar filters and open links by @axisrow in #615
- fix(web): repair analytics pipeline links by @axisrow in #616
- fix(web): repair scheduler collect-all redirect by @axisrow in #617
- fix(db): atomic task claiming via UPDATE...RETURNING (#450) by @etopro in #619
- fix(queue): cancellation path for reaction (telegram_commands) tasks (#621) by @etopro in #622
- feat: server time tool + live UTC clock in navbar (#620) by @axisrow in #623
- fix(search): graceful handling of unavailable search modes (#618) by @axisrow in #624
- docs(parity): fill real web endpoints the table marked missing (#565) by @axisrow in #625
- fix(cli): CLI-audit miscellany — images parity, broadcast-stats drift, export overwrite (#567) by @axisrow in #626
- docs(parity): add missing command pairs, drop duplicate react row (#566) by @axisrow in #628
- feat(notifier): circuit breaker for persistent send failures (#553) by @axisrow in #629
- feat(pipeline): per-node success logging + run completion audit (#468) by @axisrow in #631
- feat(pipeline): deduplicate react/forward/delete across runs (#471) by @axisrow in #634
- fix(settings): humanize degraded-session label + reconnect action (#550) by @axisrow in #627
- test(agent): lock web chat multi-turn + tool-event parity with CLI (#635) by @axisrow in #636
- fix(db): repair get_preferred_phone crash via execute+fetchone (#633) by @axisrow in #637
- fix(publish): avoid duplicate sends on multi-target publish retry (#633) by @axisrow in #638
- fix(633): CI serial-step gating, weak filter test, adapter double-read (#5/#6/#8) by @axisrow in #639
- fix(633): harden web against CSRF logout and XSS (#16/#21/#22/#23) by @axisrow in #640
- feat(settings): make reaction min-interval configurable via CLI and web UI by @axisrow in #641
- fix(telegram): bound first-run memory + PeerChat for legacy groups (#633) by @axisrow in #642
- feat(notifications): custom test-notification text in web (#563) by @axisrow in #630
- fix(search): proxy web premium/telegram search to the worker (#643) by @axisrow in #644
- fix(db): keep pipeline source/target replace inside the write-lock (#633) by @axisrow in #645
- fix(cli): persist account before pool warm-up in verify-code (#449) by @axisrow in https://gi...
v0.2.2 — Production Stability — Flood Wait Rotation, Auth Reliability & Web/Worker Sync
What's Changed
🚀 Features
🐛 Fixes
- fix: support non-ASCII passwords in login and Basic Auth by @Copilot in #431
- fix(agent): harden ACL and provider generation paths by @axisrow in #451
Other Changes
- test: add extended coverage for routes, services, and CLI commands by @axisrow in #353
- fix(pipelines): detect LLM providers configured via DB settings by @axisrow in #355
- fix(ui): replace HTML entities with Unicode emojis in filter reasons by @axisrow in #358
- fix(scheduler): single-row progress counter for stats update task by @axisrow in #359
- refactor(web): reduce duplication in Jinja templates and inline JS by @axisrow in #362
- feat(channels): rename detection, suspicious_username filter, proactive review UI by @axisrow in #363
- feat(web): centralize confirm/alert dialogs via window.TGConfirm by @axisrow in #364
- fix(channels): harden rename-review keep/filter endpoints and refactor collector helper by @axisrow in #366
- fix(pipelines): resolve LLM provider banner regression (#360) by @axisrow in #375
- fix(pipelines): per-pipeline LLM gate, stop hiding add-form by @axisrow in #378
- feat(analytics): per-channel statistics dashboard (#330) by @axisrow in #380
- feat: milestone v0.2.2 — forward normalization, channel age, docs, tests by @axisrow in #389
- fix(web): pre-render templates to prevent "No response returned" in middleware stack by @axisrow in #394
- feat(web): полный редизайн UI/UX раздела Пайплайны (#387) by @axisrow in #395
- fix(pipelines): add Anthropic and Z.AI adapters to provider system by @axisrow in #388
- refactor(web): централизация и унификация иконок UI by @axisrow in #396
- feat(web): wizard создания пайплайнов + AJAX picker (#387) by @axisrow in #397
- fix: #330 code review follow-up — migration guard, backfill created_at, test fix by @axisrow in #399
- feat(web): context-aware pipeline editor for DAG pipelines by @axisrow in #401
- feat(pipelines): UI redesign + three automation levels by @axisrow in #409
- fix(ui): replace Unicode emojis with Bootstrap Icons (#404) by @axisrow in #410
- fix(pipelines): inject source/target IDs into DAG node config (#405) by @axisrow in #411
- feat(pipelines): extend wizard with LLM action templates (#406) by @axisrow in #412
- feat(pipelines): implement real Agent Loop with tool execution (#407) by @axisrow in #413
- fix(pipelines): wire agent_tools into DAG runtime + fetch limit (#407) by @axisrow in #414
- refactor(web): web_login.html extends base.html by @etopro in #408
- fix(web): deduplicate flash message keys and move to server-side by @etopro in #415
- test: add 138 tests for agent tools registry, permissions & pipeline handlers by @axisrow in #416
- docs(web): document HTMX vs fetch() frontend policy by @axisrow in #418
- refactor(web): add status_dot and task_status_badge macros by @axisrow in #420
- refactor(web): add empty_state macro and replace inline patterns by @axisrow in #419
- refactor(web): normalize table CSS classes via .tga-table utilities by @axisrow in #417
- fix(test): anchor test_get_post_frequency to noon to avoid midnight flake by @axisrow in #421
- feat(logging): rotate logs to data/app.log, wire debug page to file by @axisrow in #423
- fix(web): surface collector flood wait state by @axisrow in #425
- feat(cli): unified pipeline add via --node DSL + auto-wiring by @axisrow in #429
- fix: pipeline generation — ZAI URL, empty context, provider fallback by @axisrow in #436
- perf(web): speed up /scheduler/ page and harden against pool stalls by @axisrow in #441
- test: +751 tests, coverage 79% to 82% (20 files) by @axisrow in #438
- fix(collector): select correct account for private groups by @axisrow in #443
- feat: finish web-mode cutover for accounts and /agent (#453) by @axisrow in #454
- feat(web): queue auth and scheduler actions through worker commands by @axisrow in #455
- feat(tests): achieve 90%+ test coverage by @axisrow in #456
- fix(web): embed worker in serve by default + e2e collection test (#457) by @axisrow in #458
- refactor(web): finish v0.2.2 — inline JS extraction + dialogs dedupe + test hardening by @axisrow in #459
- Fix/357 web refactor v0.2.2 by @axisrow in #460
- [codex] Fix pipeline dry-run refs and show ids by @axisrow in #461
- feat(scheduler): show flood wait countdown next to earliest unlock time by @axisrow in #465
- fix(auth): two-step CLI auth + fix 422 on web forms + persist StringSession by @axisrow in #467
- fix(pipeline,collector): wire client_pool in CLI; safe JSON for Telethon action payloads by @axisrow in #470
- fix: record errors on missing deps + safe JSON serialization (#472, #473) by @axisrow in #474
- test: add coverage for json, provider_service, dialogs, images, agent routes by @axisrow in #475
- fix(tests): eliminate AsyncMock coroutine-never-awaited warnings (#476) by @axisrow in #481
- fix(tests): wrap bare aiosqlite.connect calls in async with (#477) by @axisrow in #482
- fix(tests): close httpx AsyncClient after test to prevent PytestUnraisableExceptionWarning (#477) by @axisrow in #483
- fix(tests): use single event loop in cli_db fixture and TestInitPool to prevent unclosed loop warnings (#477) by @axisrow in #484
- fix(calendar): replace datetime.utcnow() with datetime.now(timezone.utc) by @axisrow in #485
- fix(logging): add log_path param to setup_logging to prevent ResourceWarning in tests by @axisrow in #486
- chore(tests): session-scoped event loop + xdist loadfile to drop gc.collect workaround by @axisrow in #488
- [codex] refactor test file names by @axisrow in #491
- fix(client-pool): round-robin account selection in AccountLeasePool by @axisrow in #497
- Handle Telegram flood waits by surfacing errors instead of silently sleeping by @axisrow in #498
- fix(web): periodic SnapshotRefresher to keep shim caches in sync by @axisrow in #492
- fix: close #472/#473 tail — record_error in FetchMessages + safe_json_dumps in two repos by @axisrow in #493
- fix(scheduler): periodic DB pull picks up freshly enqueued PENDING tasks by @axisrow in #494
- [codex] Centralize flood wait handling by @axisrow in #499
- fix: address quick migration and UI clarity issues by @axisrow in #500
- refactor(web): finish template asset cleanup for issue 357 by @axisrow in #501
- fix(collector): throttle username resolves on long FloodWait by @axisrow in https://github.com/axisrow/tg_content_facto...
v0.2.1 — Pipelines DAG, Z.AI Provider & Stability Fixes
What's Changed
- feat: initialize Telethon client pool in agent TUI by @axisrow in #286
- feat: settings/logout icons in navbar + auto theme mode by @axisrow in #287
- fix: rotate to other accounts on long flood wait, clear stale flood_wait_until by @axisrow in #288
- perf: critical performance optimization — agent, DB, dispatcher by @axisrow in #289
- feat(tui): Enter to send, Shift/Alt+Enter newline, native Cmd+C copy by @axisrow in #290
- feat: normalize_identifier() + fix agent search by @username / t.me link by @axisrow in #291
- feat: add 12 missing agent tools and fix ghost MODULE_GROUPS entries by @axisrow in #292
- feat: language detection & LLM translation for messages by @axisrow in #293
- feat: resolve_entity tool + AI Telegram client system prompt by @axisrow in #294
- fix(tui): native clipboard copy/paste via pbcopy/xclip by @axisrow in #295
- feat: resolve_entity tool + AI Telegram client system prompt + tests by @axisrow in #296
- test: add coverage tests for react_agent and s3_store modules by @axisrow in #297
- feat: interactive permission request dialog for agent TUI and web by @axisrow in #298
- test: add coverage for new agent tools modules (moderation, channels, settings, pipelines) by @axisrow in #299
- fix(agent): enable streaming text output in TUI and Web by @axisrow in #300
- refactor(tests): split test_agent_tools_newX into per-module files by @axisrow in #301
- fix(agent): streaming UX + elapsed timer + Telethon cleanup by @axisrow in #302
- feat(cli): implement all 14 missing CLI commands for CLI/Web parity by @axisrow in #304
- fix(pool): auto-reconnect disconnected Telegram clients by @axisrow in #305
- fix(tui): toggle Send button to Stop during streaming by @axisrow in #306
- feat(agent): real-time tool call visibility & debug status line by @axisrow in #308
- fix(agent): SDK typed errors & debug-to-stderr for connection diagnostics by @axisrow in #310
- feat(agent): atomic configurable timeouts with countdown & graceful shutdown by @axisrow in #312
- fix: centralize data dir creation & improve TUI logging by @axisrow in #313
- feat(agent): upgrade claude-agent-sdk 0.1.50 → 0.1.52 by @axisrow in #316
- fix(agent): activity-aware timeouts & countdown UX by @axisrow in #317
- fix(agent): unblock SDK event streaming with AsyncIterable prompt by @axisrow in #319
- fix(agent): surface stderr errors/warnings to user by @axisrow in #320
- fix(agent): auto-approve CLI tool permissions & improve error visibility by @axisrow in #321
- [codex] Remove my_telegram as the canonical dialogs surface by @axisrow in #323
- [codex] Handle Claude overload errors in agent manager by @axisrow in #324
- [codex] Log web error redirects and rejected overrides by @axisrow in #335
- feat(images): add dynamic HuggingFace model search via huggingface_hub SDK by @axisrow in #336
- feat(channels): add button to browse collected posts per channel by @axisrow in #337
- fix(trends): use TF-IDF to filter out low-signal words (#329) by @axisrow in #338
- fix(filters): check stats before filtering to avoid strange symbols by @axisrow in #340
- feat: add Z.AI provider support by @axisrow in #342
- refactor(scheduler): rename manager.py to service.py (#341) by @axisrow in #344
- feat(pipelines): node-based DAG pipeline redesign + fix semantic search fallback (#343, #270) by @axisrow in #346
- test: expand coverage for services, parsers, and flood wait handling by @axisrow in #345
- fix(zai): use native Z.AI API endpoint with Bearer auth for model list by @axisrow in #347
- Refactor duplicated test fixtures and CLI DB patching by @axisrow in #348
- Refactor test infrastructure to close issue 228 by @axisrow in #349
- test: add extended coverage tests for services, CLI, and routes by @axisrow in #350
- fix(telegram): add grace period in disconnect_all to prevent Task destroyed warnings by @axisrow in #351
- fix(pipelines): disable LLM sections when no provider is configured (#333) by @axisrow in #352
Highlights
- Node-based DAG Pipelines — Content pipelines redesigned as a node-based DAG, unlocking richer branching and reuse; includes a fix for semantic search fallback when no vector store is configured.
- Z.AI Provider Support — New Z.AI LLM provider with native API endpoint and Bearer auth, auto-registered from environment variables alongside the existing provider adapters.
- Dynamic HuggingFace Image Models — Image generation now discovers HuggingFace models dynamically via the huggingface_hub SDK and uses the new router.huggingface.co endpoint, replacing the deprecated api-inference host.
- Pipeline & Filter UX Polishing — LLM sections are disabled when no provider is configured, trending terms are filtered with TF-IDF to drop low-signal words, and channel filters now gate on stats to avoid dropping legitimate content.
- Per-channel Post Browsing — Channel list gains a quick button to browse all collected posts for a specific channel, making moderation and auditing faster.
- Telegram Client Stability — Grace period added to ClientPool.disconnect_all eliminates noisy 'Task was destroyed but it is pending' warnings during shutdown.
- Scheduler Module Rename — src/scheduler/manager.py renamed to service.py with a compatibility shim, aligning with the service-layer naming used elsewhere in the project.
- Test Infrastructure Overhaul — Deduplicated fixtures, centralized CLI DB patching, and expanded coverage across services, parsers, CLI, and web routes to close long-standing test-infra debt.
Full Changelog: v0.2.0...v0.2.1
v0.2.0 — Content Factory & TUI
What's Changed
- test: add 49 tests for agent tool permission system by @axisrow in #257
- fix: derive allowed tools from TOOL_CATEGORIES, remove hardcoded list by @axisrow in #259
- fix: use union permissions so agent sees tools allowed by any account by @axisrow in #260
- fix: add resolve_phone fallback and permission gates to all tool handlers by @axisrow in #261
- feat: sort Replicate models by run_count and display rank by @axisrow in #262
- feat: add read_messages agent tool for previewing chat content by @axisrow in #264
- feat: add interactive TUI chat for agent by @axisrow in #265
- test: add agent tools coverage tests by @axisrow in #266
- test: add CLI/web and domain-specific coverage tests by @axisrow in #267
- test: coverage batch tests to reach 90% by @axisrow in #268
- feat: RSS, tags, S3 storage, refinement pipeline, ReAct fallback, test fixes by @axisrow in #271
- refactor: rename list_dialogs → search_my_telegram, remove hardcoded limits by @axisrow in #273
- feat: add Telegram search agent tools by @axisrow in #275
- feat: add analytics agent tools by @axisrow in #276
- feat: add channel meta refresh and account info agent tools by @axisrow in #277
- feat: add scheduler agent tools by @axisrow in #278
- feat: add search query stats agent tool by @axisrow in #279
- feat: add notification and photo loader agent tools by @axisrow in #280
- fix: entity cache warming for numeric chat IDs + phone permissions default by @axisrow in #282
- feat: enable WebSearch and WebFetch built-in tools for agent by @axisrow in #283
- feat: improve agent tool descriptions with cross-references and remove duplicates by @axisrow in #284
Highlights
- 16 New Agent Tools — Analytics, scheduler, search queries, Telegram search, notifications, photo loader, channel meta refresh, account info — agent now covers 133+ operations with full CLI/Web parity.
- WebSearch & WebFetch for Agent — claude-agent-sdk backend gains built-in web search and fetch tools, enabling the agent to pull live data from the internet during conversations.
- Interactive TUI Chat — New
agent chatcommand launches a rich terminal UI for conversing with the agent directly from the command line. - RSS Feeds, Tags & S3 Storage — RSS feed generation for channels, tag system for content organization, S3-compatible object storage for media files, and refinement pipeline for content post-processing.
- ReAct Fallback Agent — When claude-agent-sdk is unavailable, the system falls back to a built-in ReAct agent loop with provider adapters — no external SDK dependency required.
- Agent Tool Permissions Hardening — Union-based permission model across accounts, dynamic tool derivation from TOOL_CATEGORIES, resolve_phone fallback and permission gates on all handlers.
- 90% Test Coverage — Three batches of coverage tests (agent tools, CLI/web, domain-specific) plus 49 dedicated permission system tests bring overall coverage to 90%.
- Entity Cache & Numeric Chat ID Fix — Fixed entity cache warming for channels referenced by numeric ID, and corrected default phone permissions to read-only.
Full Changelog: v0.1.19...v0.2.0
v0.1.19 — Telethon API Coverage & Chat Management
What's Changed
- feat: scheduler observability and notification dry-run by @axisrow in #198
- feat: unified button spinners across all pages by @axisrow in #199
- fix: persist scheduler autostart flag across redeployments by @axisrow in #200
- fix: load scheduler interval from DB on startup and add autostart tests by @axisrow in #201
- feat: per-job enable/disable checkboxes and interval editing in scheduler by @axisrow in #202
- feat: request timing middleware and /debug/timing page by @axisrow in #204
- feat: add ContentGenerate/ContentPublish payloads to CollectionTask and extend test coverage by @axisrow in #205
- feat: convert UTC dates to browser local time via local_dt filter by @axisrow in #206
- fix: FTS5 wildcard matching & dry-run disabled job filter by @axisrow in #207
- fix: graceful reconnect on ConnectionError during collection by @axisrow in #208
- fix: enable infinite connection retries for Telegram clients by @axisrow in #209
- feat: per-request DB profiling, parallel pool init, memory leak fixes by @axisrow in #210
- feat: image generation provider settings UI by @axisrow in #211
- feat: graceful Ctrl+C during startup & PR #211 test coverage by @axisrow in #212
- feat: images page — test generation, model catalog, CLI by @axisrow in #215
- feat: full agent toolset — 93 MCP tools covering all CLI/API operations by @axisrow in #217
- fix: agent tools — correct service constructors and CLI parity by @axisrow in #218
- fix: agent backend override bypass and false ImportError attribution by @axisrow in #219
- fix: harden error handling across codebase, bump dependencies by @axisrow in #220
- refactor: remove legacy langchain_adapters system by @axisrow in #221
- feat: agent tool permissions with read/write/delete grouping by @axisrow in #223
- fix: default agent tool permissions to read-only by @axisrow in #224
- fix: load image providers from DB in agent tools by @axisrow in #225
- fix: pass DB config to EmbeddingService, SearchEngine in agent tools by @axisrow in #227
- feat: add channel metadata — about, linked_chat_id, has_comments by @axisrow in #226
- feat: full CLI/Agent/Web parity (#241) by @axisrow in #242
- feat: add edit/delete message tools and fix _ALLOWED_TOOLS allowlist by @axisrow in #243
- feat: add t.me message link to search query notifications by @axisrow in #244
- feat: per-phone tool permissions, generated images DB, and bugfixes by @axisrow in #249
- chore: bump version to 0.1.18, fix image adapters and release script by @axisrow in #252
- feat: close milestone v0.1.19 — Telethon API coverage + GitHub Pages docs (#250) by @axisrow in #253
- fix: list_generated_images tool + CLI/Web parity gaps (#254) by @axisrow in #254
- feat: implement forward-messages for CLI, Web, and Agent (#184) by @axisrow in #256
Highlights
- Full Telethon API Coverage — CLI, Web, and Agent wrappers for all Telethon transport operations: forward, edit, delete, pin/unpin messages, download media, participants, admin/permissions management, broadcast stats.
- Chat Management Module — New permission group 'Управление чатом' with get-participants, edit-admin, edit-permissions, kick-participant, archive/unarchive, mark-read operations.
- Forward Messages — Full CLI/Web/Agent implementation for forwarding messages between Telegram chats with confirmation prompts and pool rotation.
- Agent Toolset Expansion — Agent now exposes 117 tools covering all CLI commands and API endpoints with per-phone tool permissions.
- list_generated_images Fix — Fixed CLI/Web parity gaps for generated images listing and corrected agent tool registration.
Full Changelog: v0.1.17...v0.1.19
v0.1.18 — Full Agent Toolset, Per-Phone Permissions & Scheduler UX
What's Changed
- feat: scheduler observability and notification dry-run by @axisrow in #198
- feat: unified button spinners across all pages by @axisrow in #199
- fix: persist scheduler autostart flag across redeployments by @axisrow in #200
- fix: load scheduler interval from DB on startup and add autostart tests by @axisrow in #201
- feat: per-job enable/disable checkboxes and interval editing in scheduler by @axisrow in #202
- feat: request timing middleware and /debug/timing page by @axisrow in #204
- feat: add ContentGenerate/ContentPublish payloads to CollectionTask by @axisrow in #205
- feat: convert UTC dates to browser local time via local_dt filter by @axisrow in #206
- fix: FTS5 wildcard matching & dry-run disabled job filter by @axisrow in #207
- fix: graceful reconnect on ConnectionError during collection by @axisrow in #208
- fix: enable infinite connection retries for Telegram clients by @axisrow in #209
- feat: per-request DB profiling, parallel pool init, memory leak fixes by @axisrow in #210
- feat: image generation provider settings UI by @axisrow in #211
- feat: graceful Ctrl+C during startup & test coverage by @axisrow in #212
- feat: images page — test generation, model catalog, CLI by @axisrow in #215
- feat: full agent toolset — 93 MCP tools covering all CLI/API operations by @axisrow in #217
- fix: agent tools — correct service constructors and CLI parity by @axisrow in #218
- fix: agent backend override bypass and false ImportError attribution by @axisrow in #219
- fix: harden error handling across codebase, bump dependencies by @axisrow in #220
- refactor: remove legacy langchain_adapters system by @axisrow in #221
- feat: agent tool permissions with read/write/delete grouping by @axisrow in #223
- fix: default agent tool permissions to read-only by @axisrow in #224
- fix: load image providers from DB in agent tools by @axisrow in #225
- feat: add channel metadata — about, linked_chat_id, has_comments by @axisrow in #226
- fix: pass DB config to EmbeddingService, SearchEngine in agent tools by @axisrow in #227
- feat: full CLI/Agent/Web parity (#241) by @axisrow in #242
- feat: add edit/delete message tools and fix _ALLOWED_TOOLS allowlist by @axisrow in #243
- feat: add t.me message link to search query notifications by @axisrow in #244
- feat: per-phone tool permissions, generated images DB, and bugfixes by @axisrow in #249
Highlights
- Full Agent Toolset — 93 MCP tools covering all CLI/API operations with read/write/delete permission grouping and per-phone access control
- Per-Phone Tool Permissions — granular agent tool access per Telegram account via Settings UI with nested tabs
- Image Generation UI — provider settings page, test generation, model catalog, and CLI commands for image providers
- Scheduler UX — per-job enable/disable, interval editing, autostart persistence, observability dashboard, and notification dry-run
- Channel Metadata — about text, linked_chat_id, and has_comments fields collected from Telegram
- CLI/Agent/Web Parity — all operations now available across CLI, agent tools, and web interface
- Edit/Delete Message Tools — agent can now edit and delete Telegram messages
- Request Timing & DB Profiling — middleware for per-request timing and /debug/timing page, parallel pool init
- Local Time Display — UTC dates converted to browser local time via local_dt Jinja filter
- Resilient Connections — infinite connection retries, graceful reconnect on ConnectionError, graceful Ctrl+C during startup
- Unified Button Spinners — consistent loading indicators across all web pages
Full Changelog: v0.1.17...v0.1.18
v0.1.17 — Content Pipelines, Image Generation & Auto-Publish
What's Changed
- perf: fix N+1 query in pipelines page, add batch job lookup (#151) by @axisrow in #161
- fix: resolve 6 remaining bugs (analyzer, csrf, queue, scheduler, logging) by @axisrow in #172
- db: extend generation_runs for moderation and publishing (#117) by @axisrow in #153
- feat: add PublishService for sending content to Telegram targets (#120) by @axisrow in #158
- feat: add moderation queue UI (#119) by @axisrow in #157
- feat: add CLI publish/queue/approve/reject commands (#122) by @axisrow in #160
- feat: add ContentGenerationService for pipeline orchestration (#115) by @axisrow in #154
- feat: add ProductionLimitsService for rate limiting and cost caps (#130) by @axisrow in #169
- feat: add ErrorRecoveryService with circuit breaker (#130) by @axisrow in #171
- feat: add ContentAnalyticsService and dashboard (#127 Phase 1) by @axisrow in #166
- feat: add CLI generate, runs, and run-show commands (#118) by @axisrow in #156
- feat: add DraftNotificationService for new draft notifications (#126) by @axisrow in #165
- feat: add QualityScoringService for content assessment (#128) by @axisrow in #167
- feat: add ABTestingService for variant generation (#129) by @axisrow in #168
- Fix session cursor cleanup and pipeline CLI test doubles by @axisrow in #177
- test: add DB assertions to filter purge/hard-delete tests by @axisrow in #181
- test: add web routes test coverage (~144 new tests) by @axisrow in #182
- feat: portable semantic backend — NumPy KNN without sqlite-vec by @axisrow in #183
- feat: full telethon-cli API coverage (63/63 commands) by @axisrow in #194
- test: increase coverage to 87% (+50 new tests) by @axisrow in #195
- feat: trend analyzer, channel creator & traffic analytics (#175) by @axisrow in #180
- feat: portable semantic backend via numpy fallback (#173) by @axisrow in #179
- perf: cache scheduler jobs with 5s TTL (#151) by @axisrow in #178
- Refactor Telegram flood-wait handling across runtime and live tests by @axisrow in #176
- feat: add ContentCalendarService and calendar UI (#124) by @axisrow in #170
- feat: add publish_times field to ContentPipeline (#125) by @axisrow in #164
- feat: add CONTENT_GENERATE and CONTENT_PUBLISH task types (#123) by @axisrow in #163
- feat: add DeepAgents researcher-writer backend for content generation (#152) by @axisrow in #162
- feat: add auto-publish mode for pipelines (#121) by @axisrow in #159
- feat: add ImageGenerationService stub (#116) by @axisrow in #155
- feat: implement image generation adapters (#116) by @axisrow in #196
Highlights
- Image Generation Adapters — HTTP adapters for Together AI (FLUX), HuggingFace (SDXL), OpenAI (DALL-E), and Replicate with auto-registration from env vars and provider:model_id routing.
- ContentGenerationService — Orchestration layer for pipeline-driven LLM text generation: resolve prompt template, fetch RAG source messages, call provider, and persist results.
- Auto-Publish Mode — Pipelines can now auto-publish generated content to target channels without manual moderation approval.
- PublishService — Transport layer to send text and media to Telegram target channels via the client pool.
- Moderation Queue UI — Web UI for reviewing, editing, approving and rejecting generated drafts before publishing.
- DeepAgents Backend — Researcher-writer agent backend for content generation using multi-step reasoning pipeline.
- CLI Pipeline Commands — Full CLI coverage for pipeline operations: generate, publish, queue management.
- Scheduler Cache — Cache scheduler jobs list with 5s TTL to eliminate N+1 queries in page context.
Full Changelog: v0.1.16...v0.1.17