docs: document server-side rendering pipeline, response timing middleware, and Telegram pairing API

- Add comprehensive documentation for backend content rendering in AGENTS.md, detailing the new `render_content` and `render_title` Jinja globals built on mistune with media processing, emoji shortcodes, and XSS protection
- Document the `X-Response-Time` header and bottom-left render time indicator in README.md
- Update bot token pricing documentation to clarify fallback vs gateway cost headers
- Add `email_accounts` to soft-delete tables and `idx_users_role` composite index in database schema
- Implement `telegram_pairings` and `telegram_links` table creation with column migration and indexes
- Add `/profile/{username}/telegram` endpoint to docs API with request/unpair actions
- Register `TelegramService` in main.py lifespan and add `response_timing` middleware emitting `X-Response-Time` header
- Introduce `TelegramPairForm` model and `guard_public_host_sync` synchronous host validation function
This commit is contained in:
2026-06-18 22:09:34 +00:00
parent 95dca73291
commit 6ceca3d0d4
146 changed files with 6079 additions and 392 deletions
+8 -2
View File
@@ -44,6 +44,7 @@ class DeviiHub:
api_key: str,
base_url: str,
is_admin: bool = False,
is_primary_admin: bool = False,
channel: str = "main",
) -> DeviiSession:
key = (owner_kind, owner_id, channel)
@@ -57,7 +58,11 @@ class DeviiHub:
# ephemeral stores so Devii's tasks, lessons, behavior and virtual tools never leak into it
# (and a Docii reflection never pollutes the user's Devii memory). Only the conversation
# thread persists, keyed per channel in the shared ConversationStore.
owned_db = db if (owner_kind == "user" and channel == "main") else memory_db()
owned_db = (
db
if (owner_kind == "user" and channel in ("main", "telegram"))
else memory_db()
)
task_store = TaskStore(owned_db, owner_kind, owner_id)
lessons = LessonStore(owned_db, owner_kind, owner_id)
virtual_tool_store = VirtualToolStore(owned_db, owner_kind, owner_id)
@@ -75,6 +80,7 @@ class DeviiHub:
behavior_store,
self._stores,
is_admin=is_admin,
is_primary_admin=is_primary_admin,
channel=channel,
)
if owner_kind == "user":
@@ -105,7 +111,7 @@ class DeviiHub:
async def gc_idle(self) -> int:
removed = 0
for key, session in list(self._sessions.items()):
if session.connection_count == 0:
if session.connection_count == 0 and not session.has_pending_tasks():
await session.aclose()
del self._sessions[key]
removed += 1