- Fix _read_media_bytes treating local paths as URLs: local file
handling code was dead code placed after an early return inside the
HTTP try/except block. Restructure to check for local paths (plain
path or file:// URI) before URL validation, so files like
/home/.../.nanobot/workspace/generated_image.svg can be read and
sent correctly.
- Add .svg to _IMAGE_EXTS so SVG files are uploaded as file_type=1
(image) instead of file_type=4 (file).
- Add tests for local path, file:// URI, and missing file cases.
Fixes: https://github.com/HKUDS/nanobot/pull/1667#issuecomment-4096400955
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
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
Keep onboarding edits in draft state until users choose Done or Save and
Exit,
so backing out or discarding the wizard no longer persists partial
changes.
Without this flag, a BaseException (e.g. CancelledError from /stop)
in one tool would propagate immediately and discard results from the
other concurrent tools, corrupting the OpenAI message format.
With return_exceptions=True, all tool results are collected; any
exception is converted to an error string for the LLM.
Made-with: Cursor
Tool calls from a single LLM response are independent by design —
the model batches them precisely because they can run concurrently.
Replace the serial for-loop with asyncio.gather so N tools complete
in max(time_i) instead of sum(time_i).
Made-with: Cursor
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>
--workspace and --config now work as initial defaults in interactive mode:
- The wizard starts with these values pre-filled
- Users can view and modify them in the wizard
- Final saved config reflects user's choices
This makes the CLI args more useful for interactive sessions while
still allowing full customization through the wizard.
Resolved conflicts in onboard command to support both interactive
and non-interactive modes:
- Added --non-interactive flag to skip wizard
- Kept --workspace and --config options
- Updated tests to use --non-interactive for non-interactive tests
- 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>