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
Tests the helpers directly without needing CronService, covering all
schedule kinds, edge cases (missing fields, unknown status), and
combined state output.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addresses review feedback: moves schedule formatting and state
formatting into dedicated static methods, removes duplicate
in-loop imports, and simplifies _list_jobs() to a clean loop.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Covers all three schedule kinds (cron/every/at), human-readable interval
formatting, run state display (last run, status, errors, next run),
and disabled job filtering.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
_list_jobs() only displayed job name, id, and schedule kind (e.g. "cron"),
omitting the actual timing and run state. The agent couldn't answer
"when does this run?" or "did it run?" even though CronSchedule and
CronJobState had all the data.
Now surfaces:
- Cron expression + timezone for cron jobs
- Human-readable interval for every jobs
- ISO timestamp for one-shot at jobs
- Enabled/disabled status
- Last run time + status (ok/error/skipped) + error message
- Next scheduled run time
Fixes#1496
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix double bold markers (****) when heading text already contains **
- Strip markdown formatting (**bold**, *italic*, ~~strike~~) from table cells
since Feishu table elements do not support markdown rendering
Fixes rendering issues where:
1. Headings like '**text**' were rendered as '****text****'
2. Table cells with '**bold**' showed raw markdown instead of plain text
Remove the in-progress reaction (reactEmoji) and optionally add a
done reaction (doneEmoji) when the final response is sent, so users
get visual feedback that processing has finished.
Signed-off-by: Sihyeon Jang <sihyeon.jang@navercorp.com>
Replace manual _active_spinner + _pause_spinner/_resume_spinner with
_ThinkingSpinner class that owns the spinner lifecycle via __enter__/
__exit__ and provides a pause() context manager for temporarily
stopping the spinner during progress output.
Benefits:
- Restores Pythonic context manager pattern matching original code
- Eliminates duplicated start/stop boilerplate between single-message
and interactive modes
- pause() context manager guarantees resume even if print raises
- _active flag prevents post-teardown resume from async callbacks
The Rich console.status() spinner ('nanobot is thinking...') was not
cleared when tool call progress lines were printed during processing,
causing overlapping/garbled terminal output.
Replace the context-manager approach with explicit start/stop lifecycle:
- _pause_spinner() stops the spinner before any progress line is printed
- _resume_spinner() restarts it after printing
- Applied to both single-message mode (_cli_progress) and interactive
mode (_consume_outbound)
Closes#1956
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.