Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ hermes-agent/
├── gateway/ # Messaging platform gateway
│ ├── run.py # Main loop, slash commands, message dispatch
│ ├── session.py # SessionStore — conversation persistence
│ └── platforms/ # Adapters: telegram, discord, slack, whatsapp, homeassistant, signal
│ └── platforms/ # Adapters: telegram, discord, slack, whatsapp, wechat, homeassistant, signal
├── acp_adapter/ # ACP server (VS Code / Zed / JetBrains integration)
├── cron/ # Scheduler (jobs.py, scheduler.py)
├── environments/ # RL training environments (Atropos)
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Use any model you want — [Nous Portal](https://portal.nousresearch.com), [Open

<table>
<tr><td><b>A real terminal interface</b></td><td>Full TUI with multiline editing, slash-command autocomplete, conversation history, interrupt-and-redirect, and streaming tool output.</td></tr>
<tr><td><b>Lives where you do</b></td><td>Telegram, Discord, Slack, WhatsApp, Signal, and CLI — all from a single gateway process. Voice memo transcription, cross-platform conversation continuity.</td></tr>
<tr><td><b>Lives where you do</b></td><td>Telegram, Discord, Slack, WhatsApp, Signal, WeChat, and CLI — all from a single gateway process. Voice memo transcription, cross-platform conversation continuity.</td></tr>
<tr><td><b>A closed learning loop</b></td><td>Agent-curated memory with periodic nudges. Autonomous skill creation after complex tasks. Skills self-improve during use. FTS5 session search with LLM summarization for cross-session recall. <a href="https://github.com/plastic-labs/honcho">Honcho</a> dialectic user modeling. Compatible with the <a href="https://agentskills.io">agentskills.io</a> open standard.</td></tr>
<tr><td><b>Scheduled automations</b></td><td>Built-in cron scheduler with delivery to any platform. Daily reports, nightly backups, weekly audits — all in natural language, running unattended.</td></tr>
<tr><td><b>Delegates and parallelizes</b></td><td>Spawn isolated subagents for parallel workstreams. Write Python scripts that call tools via RPC, collapsing multi-step pipelines into zero-context-cost turns.</td></tr>
Expand Down Expand Up @@ -64,7 +64,7 @@ hermes doctor # Diagnose any issues

## CLI vs Messaging Quick Reference

Hermes has two entry points: start the terminal UI with `hermes`, or run the gateway and talk to it from Telegram, Discord, Slack, WhatsApp, Signal, or Email. Once you're in a conversation, many slash commands are shared across both interfaces.
Hermes has two entry points: start the terminal UI with `hermes`, or run the gateway and talk to it from Telegram, Discord, Slack, WhatsApp, Signal, WeChat, or Email. Once you're in a conversation, many slash commands are shared across both interfaces.

| Action | CLI | Messaging platforms |
|---------|-----|---------------------|
Expand All @@ -91,7 +91,7 @@ All documentation lives at **[hermes-agent.nousresearch.com/docs](https://hermes
| [Quickstart](https://hermes-agent.nousresearch.com/docs/getting-started/quickstart) | Install → setup → first conversation in 2 minutes |
| [CLI Usage](https://hermes-agent.nousresearch.com/docs/user-guide/cli) | Commands, keybindings, personalities, sessions |
| [Configuration](https://hermes-agent.nousresearch.com/docs/user-guide/configuration) | Config file, providers, models, all options |
| [Messaging Gateway](https://hermes-agent.nousresearch.com/docs/user-guide/messaging) | Telegram, Discord, Slack, WhatsApp, Signal, Home Assistant |
| [Messaging Gateway](https://hermes-agent.nousresearch.com/docs/user-guide/messaging) | Telegram, Discord, Slack, WhatsApp, Signal, WeChat, Home Assistant |
| [Security](https://hermes-agent.nousresearch.com/docs/user-guide/security) | Command approval, DM pairing, container isolation |
| [Tools & Toolsets](https://hermes-agent.nousresearch.com/docs/user-guide/features/tools) | 40+ tools, toolset system, terminal backends |
| [Skills System](https://hermes-agent.nousresearch.com/docs/user-guide/features/skills) | Procedural memory, Skills Hub, creating skills |
Expand Down
9 changes: 9 additions & 0 deletions agent/prompt_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,15 @@ def _strip_yaml_frontmatter(content: str) -> str:
"files arrive as downloadable documents. You can also include image "
"URLs in markdown format ![alt](url) and they will be sent as photos."
),
"wechat": (
"You are on a text messaging communication platform, WeChat. "
"Please do not use markdown as it does not render. "
"You can send media files natively: to deliver a file to the user, "
"include MEDIA:/absolute/path/to/file in your response. Images "
"(.png, .jpg, .webp) appear as photos, videos (.mp4, .mov) play inline, "
"and other files arrive as downloadable documents. Voice attachments may "
"be delivered as downloadable audio files rather than native voice bubbles."
),
"email": (
"You are communicating via email. Write clear, well-structured responses "
"suitable for email. Use plain text formatting (no markdown). "
Expand Down
3 changes: 2 additions & 1 deletion cron/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
_KNOWN_DELIVERY_PLATFORMS = frozenset({
"telegram", "discord", "slack", "whatsapp", "signal",
"matrix", "mattermost", "homeassistant", "dingtalk", "feishu",
"wecom", "sms", "email", "webhook",
"wecom", "wechat", "sms", "email", "webhook",
})

from cron.jobs import get_due_jobs, mark_job_run, save_job_output, advance_next_run
Expand Down Expand Up @@ -196,6 +196,7 @@ def _deliver_result(job: dict, content: str, adapters=None, loop=None) -> None:
"dingtalk": Platform.DINGTALK,
"feishu": Platform.FEISHU,
"wecom": Platform.WECOM,
"wechat": Platform.WECHAT,
"email": Platform.EMAIL,
"sms": Platform.SMS,
}
Expand Down
4 changes: 2 additions & 2 deletions gateway/channel_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ def build_channel_directory(adapters: Dict[Any, Any]) -> Dict[str, Any]:
except Exception as e:
logger.warning("Channel directory: failed to build %s: %s", platform.value, e)

# Telegram, WhatsApp & Signal can't enumerate chats -- pull from session history
for plat_name in ("telegram", "whatsapp", "signal", "email", "sms"):
# Telegram, WhatsApp, Signal, and WeChat can't enumerate chats -- pull from session history
for plat_name in ("telegram", "whatsapp", "signal", "wechat", "email", "sms"):
if plat_name not in platforms:
platforms[plat_name] = _build_from_sessions(plat_name)

Expand Down
34 changes: 34 additions & 0 deletions gateway/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class Platform(Enum):
WEBHOOK = "webhook"
FEISHU = "feishu"
WECOM = "wecom"
WECHAT = "wechat"


@dataclass
Expand Down Expand Up @@ -287,6 +288,9 @@ def get_connected_platforms(self) -> List[Platform]:
# WeCom uses extra dict for bot credentials
elif platform == Platform.WECOM and config.extra.get("bot_id"):
connected.append(platform)
# WeChat uses bot token from QR login
elif platform == Platform.WECHAT and (config.token or config.extra.get("bot_token")):
connected.append(platform)
return connected

def get_home_channel(self, platform: Platform) -> Optional[HomeChannel]:
Expand Down Expand Up @@ -927,6 +931,36 @@ def _apply_env_overrides(config: GatewayConfig) -> None:
name=os.getenv("WECOM_HOME_CHANNEL_NAME", "Home"),
)

# WeChat (Personal WeChat via iLink Bot API)
wechat_token = os.getenv("WECHAT_BOT_TOKEN")
if wechat_token:
if Platform.WECHAT not in config.platforms:
config.platforms[Platform.WECHAT] = PlatformConfig()
config.platforms[Platform.WECHAT].enabled = True
config.platforms[Platform.WECHAT].token = wechat_token
wechat_base_url = os.getenv("WECHAT_API_BASE_URL", "")
if wechat_base_url:
config.platforms[Platform.WECHAT].extra["base_url"] = wechat_base_url
wechat_cdn_url = os.getenv("WECHAT_CDN_BASE_URL", "")
if wechat_cdn_url:
config.platforms[Platform.WECHAT].extra["cdn_base_url"] = wechat_cdn_url
wechat_account = os.getenv("WECHAT_ACCOUNT_ID", "")
if wechat_account:
config.platforms[Platform.WECHAT].extra["account_id"] = wechat_account
wechat_app_id = os.getenv("WECHAT_ILINK_APP_ID", "")
if wechat_app_id:
config.platforms[Platform.WECHAT].extra["ilink_app_id"] = wechat_app_id
wechat_client_ver = os.getenv("WECHAT_ILINK_CLIENT_VERSION", "")
if wechat_client_ver:
config.platforms[Platform.WECHAT].extra["ilink_client_version"] = wechat_client_ver
wechat_home = os.getenv("WECHAT_HOME_CHANNEL")
if wechat_home:
config.platforms[Platform.WECHAT].home_channel = HomeChannel(
platform=Platform.WECHAT,
chat_id=wechat_home,
name=os.getenv("WECHAT_HOME_CHANNEL_NAME", "Home"),
)

# Session settings
idle_minutes = os.getenv("SESSION_IDLE_MINUTES")
if idle_minutes:
Expand Down
Loading