Member Junction
    Preparing search index...

    Abstract base class for messaging platform adapters.

    Handles the common orchestration flow that is shared across all messaging platforms (Slack, Teams, Discord, etc.):

    1. Receive an incoming message
    2. Determine if the bot should respond (DM, @mention, etc.)
    3. Resolve the platform user to an MJ UserInfo
    4. Show a typing/thinking indicator
    5. Fetch thread history for conversation context
    6. Route to the correct agent (default or @mentioned)
    7. Run the agent via AgentRunner.RunAgent() with streaming
    8. Send progressive streaming updates to the platform
    9. Send the final formatted response

    Platform subclasses implement the abstract methods for platform-specific operations (sending messages, fetching threads, formatting responses).

    This class is NOT a BaseServerExtension itself — the platform-specific Extension classes (e.g., SlackMessagingExtension) own the Express route registration and delegate message handling to their adapter instance.

    Users can

    different agents in different messages within the same thread. Each message routes to exactly one agent. If multiple agents are mentioned in a single message, the first one is used and a note is included in the response.

    Agent names can be multi-word (e.g., "Research Agent"). At initialization, all active agents are loaded from the database. When parsing @mentions, known agent names are matched longest-first to avoid prefix collisions.

    The adapter resolves the platform user's email to an MJ UserInfo record. This gives proper per-user permission scoping without a separate auth flow. Falls back to the configured service account email if no MJ user matches.

    Hierarchy (View Summary)

    Index

    Constructors

    Properties

    availableAgents: MJAIAgentEntityExtended[] = []

    All active agents, loaded at init for multi-word name matching. Sorted longest-name-first.

    defaultAgent: MJAIAgentEntityExtended | null = null

    Default agent loaded from config DefaultAgentName.

    fallbackContextUser: UserInfo | null = null

    Fallback context user (service account) loaded from config email.

    Extension settings from mj.config.cjs.

    Accessors

    Methods

    • Collect the files an agent produced, from the run's own fileOutputs.

      This is the canonical source — fileOutputs is what MJ turns into file artifacts — and it carries the real filename and MIME type rather than leaving them to be guessed. Entries already saved to storage (fileId, no fileData) are skipped: those have a durable location, and re-uploading their bytes to chat is not this method's job.

      Preferred over collectInlineFileAttachments, which depends on the model choosing to emit a data: URI — it does so only sometimes, so relying on it meant a generated document reached chat on one run and not the next.

      Parameters

      Returns UploadableFile[]

    • Initialize the adapter: resolve the fallback context user, load the default MJ agent (using the fallback user as contextUser), load all available agents, then run platform init. Must be called before handling any messages.

      Returns Promise<void>

      Error if the configured agent or fallback user cannot be found.

    • Was this history message written by ANY bot (not just this one)?

      Thread affinity and conversation context must both ignore other bots' messages: an agent's reply names itself in prose, which the mention matcher would read as a user request, and as a 'user' turn it feeds one agent's self-description into another's context.

      The default is false because the marker is platform-specific — see SlackAdapter, which reads the Events API's bot_id/bot_profile/bot_message fields.

      Parameters

      Returns boolean

    • Was this message posted by THIS bot?

      Not a bare === getBotUserId(). A platform may publish more than one identifier for the same bot and return a different one depending on how the message was posted — on Slack a post carrying a username/icon_url override comes back with a bot_id and NO user, and this adapter sets that override on every agent reply so the agent answers under its own name. Platforms with that split override this; the default is a single-identifier compare.

      Parameters

      • senderId: string | null | undefined

      Returns boolean

    • Is this artifact meant for the user, rather than internal system state?

      Fails OPEN: an unreadable artifact keeps its link, since losing a working link on a transient read failure is worse than the rare case of surfacing an internal one.

      Parameters

      Returns Promise<boolean>

    • Look up the email address for a platform user ID. Used for mapping platform identity to MJ user.

      Parameters

      • platformUserId: string

        Platform-specific user ID.

      Returns Promise<string | null>

      Email address, or null if not available.

    • Match agent names mentioned in the message text against known agents.

      Strips the bot's platform mention, then checks for known agent names preceded by @ (case-insensitive). Names are checked longest-first to avoid prefix collisions (e.g., "Research Agent" before "Research").

      Parameters

      • text: string

        The raw message text.

      Returns string[]

      Array of matched agent names.

    • May this bot answer a thread reply that did not address it?

      false (the default) enables the multi-bot thread gate in HandleMessage: with one app per agent, an un-mentioned thread reply would otherwise be answered by every bot in the channel. Platforms that route a message only to its addressee — Teams, where a channel message reaches a bot solely via an

      Returns boolean

      — should return true, as the gate is both unnecessary and would suppress legitimate replies there.

    • Send or update a streaming progress message. Returns the message ID.

      If existingMessageId is null, posts a new message. If existingMessageId is provided, updates the existing message in place.

      Parameters

      • originalMessage: IncomingMessage

        The message being responded to.

      • currentContent: string

        Accumulated streamed content so far.

      • existingMessageId: string | null

        ID of an existing progress message to update, or null.

      • Optionalagent: MJAIAgentEntityExtended

        The agent generating the response (for per-agent identity).

      Returns Promise<string>

      The message ID of the progress message (new or existing).

    • Determine whether the bot should respond to this message.

      Responds to:

      • Direct messages (DMs)
      • Explicit

      Parameters

      Returns boolean

      (app_mention events)

      • Thread replies (any reply in a thread the bot is participating in)

      Thread replies are included because the bot only has threads it started (via slash commands or

      responses), so a reply in such a thread is implicitly directed at the bot.

      Subclasses can override for platform-specific logic.