🐈 nanobot v0.1.4.post2 is here — 32 PRs merged, 14 new contributors! The community is on fire 🔥
This release focuses on reliability: a completely redesigned heartbeat, prompt caching for lower API costs, hardened provider compatibility, and dozens of channel-level fixes. Fewer surprises, more stability.
Highlights
- Heartbeat Overhaul — Replaced fragile token detection with a virtual tool-call decision mechanism; heartbeat is now truly silent when idle (#1102, #1054, #1039, #1036)
- Prompt Cache Optimization — Dynamic context (time, session) moved from system prompt to user message, enabling persistent prompt cache hits (#1115)
- Agent Reliability — Behavioral constraints, full tool history in context, and actionable error hints (#1046)
- Slack — Thread-isolated sessions, mrkdwn post-processing for bold/header artifacts, socket error handling (#1048, #1107, #957)
- Feishu — Rich-text image extraction in post messages, file download API fix (#1090, #986)
- Email — Proactive sends work even when autoReply is disabled, smarter dedup eviction (#1077, #959)
- Provider Fixes — DeepSeek
reasoning_contentnormalization, empty content block filtering, API key hot-reload via@property(#947, #955, #949, #1071, #1098) - Security — Path traversal prevention using
relative_to()instead ofstartswith()(#956) - MCP — Configurable timeouts to prevent agent hangs, removed conflicting defaults for HTTP transport (#950, #1062)
- Memory — Fixed TypeError when LLM returns dict arguments during consolidation (#1061)
- Discord — Break typing indicator loop on persistent HTTP failure (#1029)
- CLI — DingTalk, QQ, Email added to
nanobot statusoutput (#982) - Packaging — Workspace templates moved to
nanobot/templates/for proper pip packaging (#1043) - Docs — systemd user service deployment guide (#968)
What's Changed
- fix: change VolcEngine litellm prefix from openai to volcengine by @init-new-world in #951
- fix(context): Fix 'Missing
reasoning_contentfield' error for deepseek provider. by @homorunner in #947 - Remove redundant tools description by @vincentchen0x2-dev in #939
- feat(cli): add DingTalk, QQ, and Email to channels status output by @luoyingwen in #982
- fix(security): prevent path traversal bypass via startswith check by @nghiahsgs in #956
- fix(slack): add exception handling to socket listener by @nghiahsgs in #957
- fix(session): handle errors in legacy session migration by @nghiahsgs in #958
- fix(email): evict oldest half of dedup set instead of clearing entirely by @nghiahsgs in #959
- fix(loop): serialize /new consolidation and preserve session on archival failure by @Athemis in #881
- fix(qq): make start() long-running per base channel contract by @nghiahsgs in #962
- docs: add systemd user service instructions to README by @katafractari in #968
- fix(mcp): add 30s timeout to MCP tool calls to prevent agent hangs by @eliumusk in #950
- fix(providers): normalize empty reasoning_content to None at provider level by @nghiahsgs in #955
- fix(feishu): replace file.get with message_resource.get to fix feishu file download problem by @FloRainRJY in #986
- fix(provider): filter empty text content blocks causing API 400 by @eliumusk in #949
- feat(channels): add send_progress option to control progress message … by @luoyingwen in #1000
- fix(heartbeat): route heartbeat runs to enabled chat context by @KimGLee in #1036
- refactor: move workspace/ to nanobot/templates/ for packaging by @Re-bin in #1043
- improve agent reliability: behavioral constraints, full tool history, error hints by @Re-bin in #1046
- feat(slack): isolate session context per thread by @pjbakker in #1048
- fix(heartbeat): deliver agent response to user and fix HEARTBEAT_OK detection by @Re-bin in #1054
- fix(heartbeat): make start idempotent and require exact HEARTBEAT_OK by @cyzlmh in #1039
- fix: break Discord typing loop on persistent HTTP failure by @nikolasdehor in #1029
- fix(heartbeat): replace HEARTBEAT_OK token with virtual tool-call decision by @Re-bin in #1102
- fix(web): resolve API key on each call + improve error message by @coldxiangyu163 in #1098
- Fix: memory consolidation TypeError when LLM returns dict arguments by @suportly in #1061
- feat(feishu): support images in post (rich text) messages by @xzq-xu in #1090
- fix(email): allow proactive sends when autoReplyEnabled is false by @chengyongru in #1077
- **fix(mcp): Remove default timeout for HTTP transport to avoid tool imeout conflicts by @dulltackle in #1062
- fix: resolve API key at call time so config changes take effect without restart by @haosenwang1018 in #1071
- fix: stabilize prompt prefix for better cache reuse by @pikaxinge in #1115
- fix(slack): post-process slackify_markdown to fix leftover bold artifacts by @devops-tomorrow-io in #1107
New Contributors
- @homorunner made their first contribution in #947
- @vincentchen0x2-dev made their first contribution in #939
- @luoyingwen made their first contribution in #982
- @nghiahsgs made their first contribution in #956
- @katafractari made their first contribution in #968
- @eliumusk made their first contribution in #950
- @FloRainRJY made their first contribution in #986
- @cyzlmh made their first contribution in #1039
- @suportly made their first contribution in #1061
- @xzq-xu made their first contribution in #1090
- @dulltackle made their first contribution in #1062
- @haosenwang1018 made their first contribution in #1071
- @pikaxinge made their first contribution in #1115
- @devops-tomorrow-io made their first contribution in #1107
Full Changelog: v0.1.4.post1...v0.1.4.post2