- 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
Appends a strict instruction to background task prompts (cron and heartbeat)
directing the agent to return a `<SILENT_OK>` token if there is nothing
material to report. Adds conditional logic to intercept this token and
suppress the outbound message to the user, preventing notification spam
from autonomous background checks.
Appends a strict instruction to background task prompts (cron and heartbeat)
directing the agent to return a `<SILENT_OK>` token if there is nothing
material to report. Adds conditional logic to intercept this token and
suppress the outbound message to the user, preventing notification spam
from autonomous background checks.
Replace platform-specific shell=True logic with shutil.which('npm') to
resolve the full path to the npm executable. This is cleaner because:
- No shell=True needed (safer, no shell injection risk)
- No platform-specific branching (sys.platform checks removed)
- Works identically on Windows, macOS, and Linux
- shutil.which() resolves npm.cmd on Windows automatically
The npm path check that already existed in _get_bridge_dir() is now
reused as the resolved path for subprocess calls. The same pattern is
applied to channels_login().
On Windows, npm is installed as npm.cmd (a batch script), not a direct
executable. When subprocess.run() is called with a list like
['npm', 'install'] without shell=True, Python's CreateProcess cannot
locate npm.cmd, resulting in:
FileNotFoundError: [WinError 2] The system cannot find the file specified
This fix adds a sys.platform == 'win32' check before each npm subprocess
call. On Windows, it uses shell=True with a string command so the shell
can resolve npm.cmd. On other platforms, the original list-based call is
preserved unchanged.
Affected locations:
- _get_bridge_dir(): npm install, npm run build
- channels_login(): npm start
No behavioral change on Linux/macOS.
Merge the latest main branch into the Telegram media filename fix and keep the file_unique_id-based download path on top of the refactored media handling and newer Telegram tests.
Made-with: Cursor
- test_channel_plugins: fix assertion logic for discoverable channels
- test_filesystem_tools: normalize path separators for Windows
- test_tool_validation: use python to generate output, avoid cmd line limits
- Add `reply_to_message: bool = False` config to `FeishuConfig`
- Parse `parent_id` and `root_id` from incoming events into metadata
- Fetch quoted message content via `im.v1.message.get` and prepend
`[Reply to: ...]` context for the LLM when a user quotes a message
- Add `_reply_message_sync` using `im.v1.message.reply` API so the
bot's response appears as a threaded quote in Feishu
- First outbound message uses reply API; subsequent chunks fall back
to `create` to avoid duplicate quote bubbles; progress messages
always use `create`
- Add 19 unit tests covering all new code paths
- 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
On Windows, sys.argv[0] may be just "nanobot" without full path when
running from PATH. os.execv() doesn't search PATH, causing restart to
fail with "No such file or directory".
Fix by using `python -m nanobot` instead of relying on sys.argv[0].
Fixes#1937