You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Added
New jina_read web tool: reads pages through the Jina Reader API with return_format (text/markdown/html/screenshot/pageshot), target_selector, link summaries and a configurable timeout. Works without an API key on the free 20 RPM tier; with JINA_API_KEY the limit rises to 500 RPM. Handles JS-heavy and anti-bot pages that plain extraction cannot.
New jina_search web tool (key-gated): searches the web via the Jina Search API and returns top results with titles, URLs and content truncated to ~2000 characters per result (title and URL always preserved). Registered only when JINA_API_KEY is configured — the Search API hard-requires a key and bills ≥10k tokens per request.
Hybrid read_web_page with quality gating and a circuit breaker: the tool is now a smart orchestrator. With JINA_API_KEY the Jina Reader path is tried first; without it, trafilatura goes first and the free r.jina.ai tier acts as the fallback. Every result passes a quality gate (minimum length, raw-HTML fallback detection, JavaScript-garbage heuristics); each path is guarded by an in-memory circuit breaker (3 consecutive failures → 5-minute cooldown → single half-open trial). When both paths fail the gate, the better raw result is returned with a warning instead of nothing. The return contract is unchanged.
JINA_API_KEY setting documented in the generated configuration reference (Section 12, Search Capabilities).
New read_telegram_file tool: reads the content of a text-based file (e.g. .md, .txt, .py, .json) previously sent as a document to the Telegram chat. The file_id comes from upload captions or the get_file_info tool; content is served by the new TelegramFileStorage.get_text backed by a shared text-file detector (MIME allowlist first, file-extension fallback — Telegram often reports application/octet-stream for plain-text files it cannot classify). Non-text files (images, binaries) and oversized files are rejected; very long files may be truncated with an explicit marker at the end of the content; tool-level errors (ValueError, FileNotFoundError, StorageError) propagate per the tool error conventions. Only works when file storage is set to Telegram; covered by 10 new tool tests.
Document upload captions now include file readability hints: the caption metadata exposed to the model for every uploaded document gains file_name, mime_type and an is_text_file flag (computed by the shared detector), so the agent knows upfront whether a file can be read with read_telegram_file.
Mandatory imperative context-size warning in the system prompt: the advisory warning was replaced with a mandatory instruction to summarize or drop stale tool results before answering.
Volume-based tool-results warning: when background tool results exceed 25% of the context size, the system prompt lists the top-3 largest offenders (tool name + estimated tokens) and suggests clear_tool_call_history.
Fixed
Legacy retention_cleanup-<timestamp> scheduler job duplicates are now removed automatically at startup: the old registration code created a uniquely-named retention-cleanup job on every restart (retention_cleanup-YYYYMMDDHHMMSS), leaving dozens of redundant copies in the persistent store that would each fire and run perform_retention_cleanup again. register_retention_cleanup_job now performs a one-shot O(jobs) self-heal pass that deletes any job id matching retention_cleanup-\d{14} from the persistent store (Redis or SQLite) before registering the fixed-id job — system:* and agent:* jobs are never touched — so affected deployments clean themselves up on the next restart without manual intervention.
LLM thoughts in scheduler-triggered turns now render as native Telegram thinking drafts instead of plain "💡💭" text messages:SchedulerInterface no longer inherits the base implementation that spammed the chat with plain text; it mirrors TelegramInterface by sending an ephemeral <tg-thinking>sendRichMessageDraft through the shared scheduler Bot and clearing it before the final message. Draft failures are logged and swallowed — thoughts are deliberately never delivered as plain chat content.
Scheduled/self-wake turns can now deliver media and chat actions to Telegram:SchedulerInterface.send_audio, send_video, send_images and send_document no longer raise NotImplementedError (which crashed the job into a generic "Scheduled job failed" note) — they mirror TelegramInterface delivery through the shared scheduler Bot with the payload-fixed chat_id/message_thread_id. Typing / uploading-photo / recording-voice chat actions are sent as best-effort cosmetic hints whose failures are logged and swallowed instead of failing the job; image URL lists fall back to a plain text message with the URLs when the media group upload fails.
Web pages are no longer returned as mojibake when a server negotiates brotli compression: the shared HTTP helper manually advertised Accept-Encoding: gzip, deflate, br, but httpx has no brotli decoder installed, so servers honoring the header returned brotli-compressed bytes that were passed through undecoded. The header now advertises only the encodings httpx can actually decode (gzip, deflate).
Selecting an image model no longer overwrites the thread's LLM model: tapping "← Back to providers" in the /image_models menu (shown when a provider has more than 12 image models) previously switched the inline-keyboard state to the LLM flow, so the next tap stored the image model as the thread's chat model until it was re-selected manually.
Semantic history saving and search no longer fail with a ChromaDB embedding-function conflict error: the custom FastEmbed embedding function did not implement the embedding-function protocol expected by chromadb 1.5.9, so every write to semantic memory failed — background archival tasks died silently and the affected threads' conversation history was lost from semantic memory. A legacy silent fallback to ChromaDB's default (English-only ONNX) embedding model could additionally poison collections.
The FastEmbed embedding function now fully implements the ChromaDB embedding-function protocol (name / get_config / build_from_config, registered in the Chroma embedding-function registry): collections now persist the embedding function as "known", and its configuration round-trips through save/load.
Embedding-function-conflict ValueErrors are now wrapped and logged instead of silently killing background archival tasks.
The fastembed mean-pooling deprecation notice no longer leaks into logs: the store is homogeneous — fastembed 0.8.0 has been pinned since the memory subsystem landed, so the notice is factually inapplicable and was suppressed narrowly (by message and category).
Emergency summarization now uses the thread's active model instead of the provider default model: previously the request could hit a different, separately-billed model and fail with rate-limit errors that were swallowed by the reactive recovery path, leaving the conversation permanently over the context limit.
Emergency summarization requests now fit the context window: the summarizer input is truncated under a token budget (background tool-response blobs dropped largest-first, then the oldest turns; the latest turn is never dropped, and in-loop tool-call pairs are excluded as before), and the completion cap is raised to 130% of the configured max_tokens (threaded as an explicit per-call parameter through all provider completion paths).
The token usage cache is invalidated after a successful emergency summarization (previously stale usage data could re-trigger summarization pointlessly).
Changed
The silent fallback to ChromaDB's default embedding model is removed: when fastembed is unavailable, semantic memory is now disabled loudly instead of silently switching to an incompatible model (a different vector space that would corrupt search results).
The embedding model now loads lazily (once, on the first embed) instead of on every get_or_create_collection call (~0.3 s saved per archived message).
The default local embedding model is unified as sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 — an intentional multilingual default; ChromaDB's built-in default model is English-only.