feat(session): add headerless session-bridge pair - #197
Merged
Merged
Conversation
Fixes #194 AI-Generated: true Generated-At: 2026-09-15T02:48:53Z
Write both pair rows and occupying-edge deletes in one SQLite transaction so a failed pair no longer leaves a half pair or drops a replaced watch. Discard incomplete pair edges on restore, correct the destination-Bot confirmation copy, and fix the Ruff format failure. AI-Generated: true Generated-At: 2026-09-15T03:03:39Z
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add
/session pair//session unpairso two sessions can exchange human messages as the destination Bot, without a source header and without binding/send.Related issue
Fixes #194
Behavior
pairwrites two reverse directed edges that share a 12-hexpair_id, withheader=falseand no TTL.send_by_session. Bot speech, LLM replies, and delivery echoes stay suppressed viais_self_message.proactive; other delivery limits still degrade throughMessageDeliveryCapabilities./sendwithout a UMO still usesconnectonly.unpair [UMO]deletes both edges. Omit the UMO only when the current session has exactly one pair.unlinkon a pair edge is refused; both edges remain.watch/connecton a pair direction is refused. Pairing over existing watch/connect replaces those two directions./session pairis rejected.Non-goals
pairthe default/sendtarget.unlinkdelete one pair edge.Implementation notes
kind/header/pair_idcolumns.pair/unpairare IM commands only in this stage;SessionBridgeCapabilityis unchanged.docs/zh|en/use/command.md,authorization.md, anddocs/zh|en/dev/star/guides/send-message.md.Validation
make checkandmake test-blockingwere not run.Compatibility and risk
Public IM commands gain
pair/unpair. Existing watch/connect behavior is unchanged except that a pair direction now refuses those commands instead of being split. Restart restore now loadskind=pairand reauthorizes those edges.Checklist
docs/zh/anddocs/en/.docs/public/openapi.json, and tests change together when routes or schemas change.pyproject.toml,requirements.txt, anduv.locktogether.!and aBREAKING CHANGE:footer.Agent note
Goal: implement S2 of #192 as specified in #194 — headerless bidirectional pair edges on the existing session-bridge table.
Touched:
session_bridge.py,session_bridge_state.py, builtin/session pair|unpair|links|unlink|watch|connect, i18n catalogs, and bilingual command/authorization/send-message docs.Checks run: focused Ruff, Pyright on the edited Python modules, and the listed pytest files. Residual risk: insert of the second pair edge still uses compensating delete rather than one SQLite transaction; a crash between the two inserts could leave a half pair until
unpairor a retry.make check/make test-blockingwere not run in this session.Tools: OpenCode / grok-4.6 against the local checkout and
ghfor this PR.