Skip to content

feat(session): add headerless session-bridge pair - #197

Merged
BegoniaHe merged 2 commits into
masterfrom
feat/session-bridge-pair-194
Sep 15, 2026
Merged

BegoniaHe merged 2 commits into
masterfrom
feat/session-bridge-pair-194

Conversation

@BegoniaHe

Copy link
Copy Markdown
Collaborator

Summary

Add /session pair / /session unpair so two sessions can exchange human messages as the destination Bot, without a source header and without binding /send.

Related issue

Fixes #194

Behavior

  • pair writes two reverse directed edges that share a 12-hex pair_id, with header=false and no TTL.
  • Only human ingress is forwarded through send_by_session. Bot speech, LLM replies, and delivery echoes stay suppressed via is_self_message.
  • Both UMOs must already be loaded and proactive; other delivery limits still degrade through MessageDeliveryCapabilities.
  • /send without a UMO still uses connect only.
  • unpair [UMO] deletes both edges. Omit the UMO only when the current session has exactly one pair.
  • unlink on a pair edge is refused; both edges remain.
  • watch / connect on a pair direction is refused. Pairing over existing watch/connect replaces those two directions.
  • A duration token on /session pair is rejected.
  • Pairs restore with S1 and are reauthorized on startup.

Non-goals

  • Filters (S3), Dashboard, inbound injection, self-message forwarding, history replay, native card reconstruction.
  • Making pair the default /send target.
  • TTL on pair, or letting unlink delete one pair edge.

Implementation notes

  • No schema change. Reuses S1 kind / header / pair_id columns.
  • Quota is 8 pairs (16 edges) per subject, alongside 16 connects, and does not consume the watch quota.
  • pair / unpair are IM commands only in this stage; SessionBridgeCapability is unchanged.
  • Bilingual updates: docs/zh|en/use/command.md, authorization.md, and docs/zh|en/dev/star/guides/send-message.md.

Validation

uv run ruff check astrbot/core/platform/session_bridge.py astrbot/core/platform/session_bridge_state.py astrbot/builtin_stars/builtin_commands/commands/session.py tests/unit/test_session_bridge.py tests/unit/test_session_commands.py
uv run ruff format --check astrbot/core/platform/session_bridge.py astrbot/core/platform/session_bridge_state.py astrbot/builtin_stars/builtin_commands/commands/session.py tests/unit/test_session_bridge.py tests/unit/test_session_commands.py
uv run pyright astrbot/core/platform/session_bridge.py astrbot/core/platform/session_bridge_state.py astrbot/builtin_stars/builtin_commands/commands/session.py astrbot/builtin_stars/builtin_commands/main.py
uv run pytest tests/unit/test_session_bridge.py tests/unit/test_session_commands.py tests/unit/test_builtin_command_extensions.py tests/unit/test_builtin_command_i18n.py tests/unit/test_message_protocol.py tests/unit/test_import_boundaries.py

make check and make test-blocking were 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 loads kind=pair and reauthorizes those edges.

Checklist

  • A Feature request Issue exists for large work, or this is a small, obvious addition.
  • The change is focused and does not include unrelated refactoring.
  • I added or updated tests, or explained why tests are not practical.
  • User-visible behavior updates both docs/zh/ and docs/en/.
  • OpenAPI, generated client, docs/public/openapi.json, and tests change together when routes or schemas change.
  • No secrets committed. Runtime Python deps update pyproject.toml, requirements.txt, and uv.lock together.
  • I did not restore legacy shims, Python <3.14 fallbacks, or upstream publish/docs URLs as fork artifacts.
  • Breaking API or behavior changes use ! and a BREAKING CHANGE: footer.
  • I will not merge this PR myself. Merge needs a human maintainer review plus a separate AI-assisted review (AI_POLICY.md).
  • AI use follows AI_POLICY.md. Keep exactly one author note below. Do not fabricate the other.

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 unpair or a retry. make check / make test-blocking were not run in this session.

Tools: OpenCode / grok-4.6 against the local checkout and gh for this PR.

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
@BegoniaHe
BegoniaHe merged commit 8c94b6b into master Sep 15, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] add headerless session-bridge pair

1 participant