feature: add hermes adapter#5924
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cb8b5efcdb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -0,0 +1,11 @@ | |||
| { | |||
| "name": "@tloncorp/hermes-tlon-adapter", | |||
| "version": "0.2.0", | |||
There was a problem hiding this comment.
Align adapter version metadata
With this value at 0.2.0 while plugin.yaml still declares version: 0.1.0, the adapter reports a different version through plugin_version()//tlon-version than Hermes plugin metadata. The checked-in unit suite also encodes the plugin metadata expectation (python -m unittest discover . -p 'test_*.py' now fails the version tests), so either the manifest/tests need to be bumped together or this package version should stay at 0.1.0.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0005c38be2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| await sendReply({ | ||
| channelId: nest, | ||
| parentId: formatUd(extractNumericId(postId)), | ||
| parentAuthor: parentAuthor ?? authorId, |
There was a problem hiding this comment.
Use the DM partner as the default parent author
When posts reply is used against a 1:1 DM target (~ship, which this file now routes through the chat app), omitting --author defaults parentAuthor to the bot's own ship. sendReply constructs DM reply diffs from parentAuthor/parentId, so replying to an inbound DM thread without --author ~sender addresses the wrong parent writ and the reply will not attach to the user's message; default to the DM target or require --author for DM replies.
Useful? React with 👍 / 👎.
| if thread_id and not _is_dm_chat_id(chat_id): | ||
| parent_author = chat_id if str(chat_id).startswith("~") else None | ||
| result = await cli.send_reply(chat_id, thread_id, message, parent_author=parent_author) |
There was a problem hiding this comment.
Preserve thread replies for standalone DMs
When standalone delivery is asked to send to a 1:1 DM thread (chat_id is ~ship and thread_id is set), this condition is false and the code falls through to send_message, dropping the thread id and posting top-level. The next line's parent_author = chat_id branch is unreachable for DMs, so threaded DM deliveries from the standalone sender cannot be preserved.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fb2e591aec
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if nest: | ||
| if is_channel_open(self._channel_rules, nest): | ||
| return True | ||
| if normalized in channel_allowed_ships(self._channel_rules, nest): | ||
| return True |
There was a problem hiding this comment.
Check native bans before channel grants
When a ship is banned with /ban, the adapter only writes to %chat's blocked list and removes DM/pending state, but channel dispatch authorization here still accepts any sender in an open channel or in channelRules.allowedShips. For group-channel events coming from the channels subscription, a previously channel-approved ship (or anyone in an open channel) can keep waking the bot after being banned because _user_authorized never consults the blocked list on the dispatch path.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5f472b48fb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| self._settings_group_channels = settings_group_channels(bucket) | ||
| self._monitored_channels.update(self._settings_group_channels) |
There was a problem hiding this comment.
Drop stale settings channels on reload
When settings are reloaded after an SSE reconnect, deletions that happened while disconnected are not replayed, but this full-load path only updates _settings_group_channels and unions the new set into _monitored_channels. If a channel was removed from the groupChannels settings entry while the gateway was offline, it remains monitored for the rest of the process even though the store no longer includes it; mirror the live-event removal logic here by subtracting the old settings-only channels before adding the new set.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b12bae9606
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| { | ||
| "name": "@tloncorp/tlon-skill", | ||
| "version": "0.4.0", | ||
| "version": "0.4.1", |
There was a problem hiding this comment.
Bump native tlon-skill packages too
Bumping the wrapper to 0.4.1 while leaving optionalDependencies and the packages/tlon-skill/npm/*/package.json native packages at 0.4.0 means an npm install of @tloncorp/tlon-skill@0.4.1 will still resolve and execute the 0.4.0 platform binary via bin/tlon.js. In that installed path the new posts send/posts reply implementation is absent, so the Hermes adapter's outbound delivery through tlon posts send/reply fails even though the root package advertises the new version; the existing scripts/bump-version.js is set up to keep these versions aligned.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8e869ba103
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| user_name=ship, | ||
| text=text, | ||
| message_id=str(original.get("messageId") or approval_id(approval)), | ||
| reply_to_message_id=None if is_dm else parent_id, |
There was a problem hiding this comment.
Preserve DM thread parent when replaying approvals
When the message that queued a DM approval was itself a DM-thread reply, _original_message_payload() stores its parentId, but this replay path explicitly clears reply_to_message_id for all DM approvals. After the owner allows the request, Hermes sees the replay as a top-level DM instead of a threaded DM, so the bot's answer lands in the main conversation even though the original unauthorized message came from a thread.
Useful? React with 👍 / 👎.
Summary
Adds an adapter for the Hermes harness to the mono repo.
Usage should be largely analogous to Openclaw. Custom commands for
/tlon-versionand/owner-listenare carried over. Existing A2UI templates are used for approval/deny requests.Changes
packages/hermes-tlon-adapter%settingsstore, etc)pnpm devsetup similar toopenclaw-tlonfor developing locallyHow did I test?
pnpm dev/tlon-versionand look for Harness: Hermes to confirm)Risks and impact
The changes are almost entirely isolated to the Hermes adaptor itself. But obviously it's a massive amount of new code.
Rollback plan
Reverting from the codebase is straightforward, but we'll need to think about how to migrate nodes back to Openclaw after swapping temporarily.