// Package transport defines the neutral boundary between an agent's core logic // and the messaging fabric it runs on. It carries NO Matrix (mautrix) types, so // the same agent code can be driven by Matrix today and by the unibus message // bus tomorrow, selected per bot behind a feature flag (branch by abstraction). // // The two pieces are: // // - InboundMessage: a transport-neutral description of an incoming message. // Both the Matrix listener and the unibus subscriber produce one of these. // - Transport: the capability an agent depends on to receive messages and // send replies. A Matrix adapter and a unibus adapter both implement it. package transport import "context" // InboundMessage is a transport-neutral incoming message. It is the single type // an agent's message handler receives, regardless of whether the underlying // fabric is Matrix or unibus. It deliberately avoids any mautrix type. type InboundMessage struct { // RoomID identifies the conversation on the transport (a Matrix room id or a // unibus room id). Replies are addressed back to it. RoomID string // Subject is the bus subject the message arrived on (unibus). Empty for // transports that do not have a subject address space (Matrix). Subject string SenderID string // stable id of the sender (Matrix user id / unibus endpoint id) SenderName string // human-friendly display name, when the transport knows it // MsgID is the unique id of this message on its transport: a Matrix event id // or a unibus frame MsgID. Used as the reply/thread anchor. MsgID string ThreadID string // root message id of the thread, empty if not threaded ReplyTo string // message id this message replies to, empty if none Body string // plaintext body / content of the message Command string // parsed command name (e.g. "deploy"), empty if not a command Args []string // parsed command arguments PowerLevel int // sender power level where the transport models one (Matrix); 0 otherwise IsDirectMsg bool // the message is a direct/1:1 message to the bot IsMention bool // the message addresses/mentions the bot } // OutboundReply is a transport-neutral outgoing reply. type OutboundReply struct { RoomID string // conversation to reply into Subject string // bus subject to publish to (unibus); ignored by Matrix ReplyTo string // message id being replied to (renders as a reply) ThreadID string // thread root to keep the reply inside, empty for top-level Markdown string // reply body, in markdown } // Handler processes one inbound message. It is the callback an agent registers // with a Transport via Run. type Handler func(ctx context.Context, in InboundMessage) // Transport is the messaging fabric an agent depends on. Implementations: // - a Matrix adapter wrapping the existing mautrix client + listener; // - a unibus adapter over github.com/enmanuel/unibus/pkg/client. // // An agent core that depends only on Transport (not on *mautrix.Client) can be // pointed at either fabric without code changes. type Transport interface { // Run delivers each inbound message to handler until ctx is cancelled. It // blocks for the lifetime of the subscription and returns ctx.Err() (or a // transport error) when it stops. Run(ctx context.Context, handler Handler) error // Reply sends a reply addressed by the OutboundReply envelope. Reply(ctx context.Context, out OutboundReply) error // Send posts a standalone markdown message to a conversation (no reply anchor). Send(ctx context.Context, roomID, markdown string) error // Close releases the underlying connection. Close() error } // PresenceController is an optional capability for transports that model online // presence (Matrix). unibus does not, so it simply does not implement this and // callers type-assert for it. type PresenceController interface { SetPresence(ctx context.Context, online bool) error } // TypingController is an optional capability for transports that model typing // indicators (Matrix). Callers type-assert for it. type TypingController interface { SetTyping(ctx context.Context, roomID string, typing bool) error }