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
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>
_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>
Add "⚙️ Configure Channel Common" menu option to allow users to
configure send_progress and send_tool_hints settings through the
interactive onboarding wizard.
- Add `_SELECT_FIELD_HINTS` for select fields with predefined choices
(e.g., reasoning_effort: low/medium/high with hint text)
- Add `_select_with_back()` using prompt_toolkit for custom key bindings
- Support Escape and Left arrow keys to go back in menus
- Apply to field config, provider selection, and channel selection menus
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
Register Mistral as a first-class provider with LiteLLM routing,
MISTRAL_API_KEY env var, and https://api.mistral.ai/v1 default base.
Includes schema field, registry entry, and tests.
- Add model_info.py module with litellm-based model lookup
- Provide autocomplete suggestions for model names
- Auto-fill context_window_tokens when model changes (only at default)
- Add "Get recommended value" option for manual context lookup
- Dynamically load provider keywords from registry (no hardcoding)
Resolves#2018