Slack has no native table support, so Markdown tables are passed
through verbatim by slackify-markdown. Pre-process tables into
readable key-value rows before converting to mrkdwn.
Assisted-by: Claude 4.6 Opus (Anthropic)
Replace the regex-based Markdown-to-Slack converter with the
slackify-markdown library, which uses a proper Markdown parser
(markdown-it-py, already a dependency) to correctly handle headings,
bold/italic, code blocks, links, bullet lists, and strikethrough.
The regex approach didn't handle headings (###), bullet lists (* ),
or code block protection, causing raw Markdown to leak into Slack
messages.
Net -40 lines.
Assisted-by: Claude 4.6 Opus (Anthropic)
- Added _split_message() helper for cleaner separation of concerns
- Simplified send() method by using the helper
- Net -18 lines for the message splitting feature
Telegram has a 4096 character limit per message. This fix:
- Splits messages longer than 4000 chars into multiple chunks
- Prefers breaking at newline boundaries to preserve formatting
- Falls back to space boundaries if no newlines available
- Forces split at max length if no good boundaries exist
- Adds comprehensive tests for message splitting logic
Slack doesn't accept an empty string in the `text` parameter. However, Nanobot sometimes sends an empty response. This may need a change in the bot's logic as well; still, it should also be handled by the channel. I suggest changing the default message to '<empty_response_from_the_bot>' when the content is empty, so the user will know that the bot was trying to respond with an empty message.
File tools now resolve relative paths (e.g., "test.txt") against the
workspace directory instead of the current working directory. This fixes
failures when models use simple filenames instead of full paths.
- Add workspace parameter to _resolve_path() in filesystem.py
- Update all file tools to accept workspace in constructor
- Pass workspace when registering tools in AgentLoop
Fix TypeError when LLM returns JSON objects instead of strings for
history_entry or memory_update.
Changes:
- Update prompt to explicitly require string values with example
- Add type checking and conversion for non-string values
- Use json.dumps() for consistent JSON formatting
Fixes potential memory consolidation failures when LLM interprets
the prompt loosely and returns structured objects instead of strings.
Add SiliconFlow (硅基流动) as an OpenAI-compatible gateway provider.
SiliconFlow hosts multiple models (Qwen, DeepSeek, etc.) via an
OpenAI-compatible API at https://api.siliconflow.cn/v1.
Changes:
- Add ProviderSpec for siliconflow in providers/registry.py
- Add siliconflow field to ProvidersConfig in config/schema.py
Co-authored-by: Cursor <cursoragent@cursor.com>
Newly added the _extract_post_text function to extract plain text content from Feishu rich text messages, supporting the parsing of titles, text, links, and @mentions.
With tz: Use the specified timezone (e.g., "Asia/Shanghai").
Without tz: Use the local timezone (datetime.now().astimezone().tzinfo) instead of defaulting to UTC
When schedule.tz is present, use the specified timezone to calculate the next execution time, ensuring scheduled tasks trigger correctly across different timezones.