Record run_at_ms, status, duration_ms and error for each execution,
keeping the last 20 entries per job in jobs.json. Adds CronRunRecord
dataclass, get_job() lookup, and four regression tests covering
success, error, trimming and persistence.
Closes#1837
Made-with: Cursor
- wire tools.exec.enable and deny_patterns into the current AgentLoop
- preserve the current WebSearchTool config-based registration path
- treat deny_patterns=[] as an explicit override instead of falling back
to the default blacklist
- add regression coverage for disabled exec registration and custom deny
patterns
Made-with: Cursor
- Mask sensitive fields (api_key/token/secret/password) in all display
surfaces, showing only the last 4 characters
- Replace all emoji with pure ASCII labels for consistent cross-platform
terminal rendering
- Extract _print_summary_panel helper, eliminating 5x duplicate table
construction in _show_summary
- Replace 3 one-line wrapper functions with declarative _SETTINGS_SECTIONS
dispatch tables and _MENU_DISPATCH in run_onboard
- Extract _handle_model_field / _handle_context_window_field into a
_FIELD_HANDLERS registry, shrinking _configure_pydantic_model
- Return FieldTypeInfo NamedTuple from _get_field_type_info for clarity
- Replace global mutable _PROVIDER_INFO / _CHANNEL_INFO with @lru_cache
- Use vars() instead of dir() in _get_channel_info for reliable config
class discovery
- Defer litellm import in model_info.py so non-wizard CLI paths stay fast
- Clarify README Quick Start wording (Add -> Configure)
Adjust the spawn tool description to keep the workspace-organizing hint while
avoiding language that sounds like the system automatically assigns a dedicated
working directory for subagents.
Made-with: Cursor
The root cause of "Pool timeout" errors is that long-polling (getUpdates)
and outbound API calls (send_message, send_photo, etc.) shared the same
HTTPXRequest pool — polling holds connections indefinitely, starving sends
under concurrent load (e.g. cron jobs + user chat).
- Split into two independent pools: API calls (default 32) and polling (4)
- Expose connection_pool_size / pool_timeout in TelegramConfig for tuning
- Add _call_with_retry() with exponential backoff (3 attempts) on TimedOut
- Apply retry to _send_text and remote media URL sends
Replace fire-and-forget consolidation with archive_messages(), which
retries until the raw-dump fallback triggers — making it effectively
infallible. /new now clears the session immediately and archives in
the background. Pending archive tasks are drained on shutdown via
close_mcp() so no data is lost on process exit.
Instead of adding a separate load_skill tool to bypass workspace restrictions,
extend ReadFileTool with extra_allowed_dirs so it can read builtin skill paths
while keeping write/edit tools locked to the workspace. Fixes the original issue
for both main agent and subagents.
Made-with: Cursor
Replace the static provider-level supports_vision check with a
reactive fallback: when a model returns an image-unsupported error,
strip image_url blocks from messages and retry once. This avoids
maintaining an inaccurate vision capability table and correctly
handles gateway/unknown model scenarios.
Also extract _safe_chat() to deduplicate try/except boilerplate
in chat_with_retry().
With custom_llm_provider kwarg handling routing, the openrouter/ prefix
caused model names like anthropic/claude-sonnet-4-6 to become
openrouter/anthropic/claude-sonnet-4-6, which OpenRouter API rejects.
- Add nanobot/utils/evaluator.py: lightweight LLM tool-call to decide notify/silent after background task execution
- Remove magic token injection from heartbeat and cron prompts
- Clean session history (no more <SILENT_OK> pollution)
- Add tests for evaluator and updated heartbeat three-phase flow
- Require both history_entry and memory_update, reject null/empty values
- Fallback to tool_choice=auto when provider rejects forced function call
- After 3 consecutive consolidation failures, raw-archive messages to
HISTORY.md without LLM summarization to prevent context window overflow
Some providers (e.g. Dashscope in thinking mode) reject object-style
tool_choice with "does not support being set to required or object".
Retry once with tool_choice="auto" instead of failing silently.
Made-with: Cursor