- Track last_summary in maybe_consolidate_by_tokens() to persist the summary
- Change return to break in the consolidation loop to allow summary persistence
- Save summary to session.metadata['_last_summary'] for consistency with AutoCompact._archive()
- Ensures compressed content remains visible to the model via prepare_session() injection
Fixes#3274
The previous setuptools.backends._legacy:_Backend has been removed in
Python 3.14 and newer setuptools, causing 'Cannot import setuptools.backends.legacy' error.
Using hatchling (same as main project) ensures compatibility across Python versions.
Closes#3188
- Use .get('cursor') instead of direct dict access to prevent KeyError
- Skip entries without cursor and log a warning
- Fix _next_cursor fallback to safely check for cursor existence
Fixes#3190
- Add explicit error logging for missing file_key and message_id
- Add logging for download failures
- Change audio extension from .opus to .ogg for better Whisper compatibility
- Feishu voice messages are opus in OGG container; .ogg is more widely recognized
Add CI step to detect unused imports (F401) and unused variables (F841)
with ruff. Clean up existing violations:
- Remove unused Consolidator import in agent/__init__.py
- Remove unused re import in agent/loop.py
- Remove unused Path import in channels/feishu.py
- Remove unused ContentRepositoryConfigError import in channels/matrix.py
- Remove unused field and CommandHandler imports in channels/telegram.py
- Remove unused exception variable in channels/weixin.py
- _add_reaction now returns reaction_id on success
- Add _remove_reaction_sync and _remove_reaction methods
- Remove reaction when stream ends to clear processing indicator
- Store reaction_id in metadata for later removal
Fixes#2591
The "nanobot is thinking..." spinner was printing ANSI escape codes
literally in some terminals, causing garbled output like:
?[2K?[32m⠧?[0m ?[2mnanobot is thinking...?[0m
Root causes:
1. Console created without force_terminal=True, so Rich couldn't
reliably detect terminal capabilities
2. Spinner continued running during user input prompt, conflicting
with prompt_toolkit
Changes:
- Set force_terminal=True in _make_console() for proper ANSI handling
- Add stop_for_input() method to StreamRenderer
- Call stop_for_input() before reading user input in interactive mode
- Add tests for the new functionality
- nanobot/channels/matrix.py: Add keyword-only parameters restrict_to_workspace/workspace to MatrixChannel.__init__ and assign them to _restrict_to_workspace/_workspace with proper type conversion and path resolution
- tests/test_commands.py: Add _strip_ansi() function to remove ANSI escape codes, use regex assertions for --workspace/--config parameters to allow 1 or 2 dashes