Member Junction
    Preparing search index...

    Base class for all Angular components in the MemberJunction system.

    Hierarchy (View Summary)

    Implements

    • OnInit
    • OnDestroy
    • OnChanges
    • AfterViewInit
    Index

    Constructors

    Properties

    AcceptedFileTypes afterAgentTurn AfterAgentTurn AgentConfigurationPresetId AgentHistoryFrom AgentReplyMode agentResponse AgentResponse agentRunDetected AgentRunDetected AgentRunsByDetailId? agentRunUpdate AgentRunUpdate AgentTurnHandler AllowedAgentIDs AppContext ApplicationId artifactCreated ArtifactCreated ArtifactsByDetailId? AutoNameConversation beforeAgentTurn BeforeAgentTurn ComposerBlurred ConverationManagerAgent ConversationDefaultAgentId ConversationId ConversationName? conversationRenamed ConversationRenamed CurrentUser DefaultAgentId Disabled DraftStateChanged EmptyStateMode emptyStateSubmit EmptyStateSubmit EnableAgentMentions EnableAttachments EnableDecisionRouting EnableEntityMentions EnableMentions EnablePlanMode EnableRealtime EnableSkillCommands initialDraftApplied InitialDraftApplied initialMessageAutoSendFailed InitialMessageAutoSendFailed initialMessageAutoSendStarted InitialMessageAutoSendStarted InputBox intentCheckCompleted IntentCheckCompleted intentCheckStarted IntentCheckStarted IsProcessing IsSending IsUploadingAttachments MaxAttachments MaxAttachmentSizeBytes MentionPeople messageComplete MessageComplete messageSent MessageSent MessageStreamed ParentMessageId? PickerOverlayPositions Placeholder ProcessingMessage Provider ReadOnly ResolveTargetBranch SendSlotMode ShowRealtimeAgentPicker StatusElapsed StatusText StopClicked StopCount StopLabel SystemArtifactsByDetailId? TargetBranchID UploadingMessage uploadStateChanged UploadStateChanged VoiceActive VoicePickerDefaultCoAgentId ɵdir ɵfac

    Accessors

    Methods

    Constructors

    Properties

    AcceptedFileTypes: string = 'image/*'
    afterAgentTurn: EventEmitter<AfterAgentTurnEventArgs> = ...

    Use AfterAgentTurn.

    The same emitter under the old binding name, so a template still binding (afterAgentTurn) keeps working. Must stay AFTER AfterAgentTurn: class fields initialise in order, and the other way round this captures undefined.

    AfterAgentTurn: EventEmitter<AfterAgentTurnEventArgs> = ...

    Fired AFTER a successful agent turn, on every route. Carries the agent run id and the full agent result. Not fired when BeforeAgentTurn was canceled, when the turn failed, or when a host AgentTurnHandler reported no result.

    AgentConfigurationPresetId: string | null = null

    The MJ: AI Agent Configurations.ID selected via the chat header's mode picker (Draft / Standard / High). Applied to non-mention routes — when the user types without @mention, this preset rides along on the next invokeSubAgent call so the server resolves the agent's Fast / Standard / High Power AI configuration accordingly.

    Mentioned-route turns still use the preset embedded in the mention (e.g. @Form Builder /high) because that's a per-message intent the user just expressed. Continuity-route turns (last responder agent) also honor this input as the fallback when the prior message itself doesn't carry an explicit configuration preset.

    Picker writes are forward-only: changing the mode does NOT re-route messages already in flight or already in history. Affects "what happens next."

    AgentHistoryFrom: Date | null = null

    The first moment of the conversation an agent turn may read. The server loads the agent's history from there and uses no summary of earlier messages; the run's own reads of the conversation (history tools, attached artifacts, the previous output it continues from) start there too, and so does the continuity route, which considers only replies written at or after it. Sent to the server only when set, so leaving it null keeps working against an MJAPI that predates it (one that predates it rejects a turn that sets it, rather than reading past the floor). Null (the default) reads the whole conversation.

    AgentReplyMode: AgentReplyMode = 'Always'

    When a message starts an agent turn. 'Always' (the default) answers every message, as before. 'MentionOnly' answers only a message that tags an agent; any other message is posted with no turn at all — no reply row, no placeholder, no turn events — which is what a chat between several people needs.

    agentResponse: EventEmitter<
        { agentResult: any; message: MJConversationDetailEntity },
    > = ...

    Use AgentResponse.

    The same emitter under the old binding name, so a template still binding (agentResponse) keeps working. Must stay AFTER AgentResponse: class fields initialise in order, and the other way round this captures undefined.

    AgentResponse: EventEmitter<
        { agentResult: any; message: MJConversationDetailEntity },
    > = ...
    agentRunDetected: EventEmitter<
        {
            agentRunId: string;
            conversationDetailId: string;
            conversationId: string;
        },
    > = ...

    Use AgentRunDetected.

    The same emitter under the old binding name, so a template still binding (agentRunDetected) keeps working. Must stay AFTER AgentRunDetected: class fields initialise in order, and the other way round this captures undefined.

    AgentRunDetected: EventEmitter<
        {
            agentRunId: string;
            conversationDetailId: string;
            conversationId: string;
        },
    > = ...
    AgentRunsByDetailId?: Map<string, MJAIAgentRunEntityExtended>
    agentRunUpdate: EventEmitter<
        {
            agentRun?: any;
            agentRunId?: string;
            conversationDetailId: string;
            conversationId: string;
        },
    > = ...

    Use AgentRunUpdate.

    The same emitter under the old binding name, so a template still binding (agentRunUpdate) keeps working. Must stay AFTER AgentRunUpdate: class fields initialise in order, and the other way round this captures undefined.

    AgentRunUpdate: EventEmitter<
        {
            agentRun?: any;
            agentRunId?: string;
            conversationDetailId: string;
            conversationId: string;
        },
    > = ...
    AgentTurnHandler: AgentTurnHandler | null = null

    Runs agent turns on the host's server instead of MJ's own path. The chat area still picks the agent and fires BeforeAgentTurn; it then calls the handler once per turn, before any reply row exists, and shows the rows the handler reports. Null (the default) runs turns on MJ's path.

    AllowedAgentIDs: readonly string[] | null = null

    The agents that may answer here. Narrows the composer's '@' list, every route (a tagged agent, continuity, the pinned and host default agents, the conversation manager) and the conversation manager's delegation, including each agent step of a workflow it plans. A tagged agent outside the list is ignored. Null (the default) allows every agent the user can run; an empty list allows none.

    AppContext: Record<string, unknown> | null = null
    ApplicationId: string | null = null

    Application context for the current conversation. Threaded through from the chat-area component for inclusion in the beforeAgentTurn event payload — lets listeners reason about which app's chat surface is invoking the agent. Optional; defaults to null for surfaces with no app context.

    artifactCreated: EventEmitter<
        {
            artifactId: string;
            conversationDetailId: string;
            conversationId: string;
            name: string;
            versionId: string;
            versionNumber: number;
        },
    > = ...

    Use ArtifactCreated.

    The same emitter under the old binding name, so a template still binding (artifactCreated) keeps working. Must stay AFTER ArtifactCreated: class fields initialise in order, and the other way round this captures undefined.

    ArtifactCreated: EventEmitter<
        {
            artifactId: string;
            conversationDetailId: string;
            conversationId: string;
            name: string;
            versionId: string;
            versionNumber: number;
        },
    > = ...
    ArtifactsByDetailId?: Map<string, LazyArtifactInfo[]>
    AutoNameConversation: boolean = true

    Whether MJ names a new conversation from its first message. True (the default) keeps today's behavior; a host that names its own chats turns it off.

    beforeAgentTurn: EventEmitter<BeforeAgentTurnEventArgs> = ...

    Use BeforeAgentTurn.

    The same emitter under the old binding name, so a template still binding (beforeAgentTurn) keeps working. Must stay AFTER BeforeAgentTurn: class fields initialise in order, and the other way round this captures undefined.

    BeforeAgentTurn: EventEmitter<BeforeAgentTurnEventArgs> = ...

    Cancelable — fired once per agent turn, on every route, after routing has picked the agent and BEFORE any reply row exists. Listeners may set event.Cancel = true to stop the turn (nothing more is written, and AfterAgentTurn does not fire) or set event.RedirectAgentId to send it to another allowed agent. A message that starts no turn fires nothing. Follows MJ's established Before/After cancelable event pattern.

    ComposerBlurred: EventEmitter<void> = ...

    The composer lost focus — hosts flush persisted drafts on this.

    ConverationManagerAgent: MJAIAgentEntityExtended | null = null
    ConversationDefaultAgentId: string | null = null

    Per-conversation pinned default agent — sourced from the loaded MJConversationEntity.DefaultAgentID. When set, this agent is used in preference to the embedder-supplied defaultAgentId so a user who pins a conversation to e.g. Research Agent gets that routing even inside an embedded surface whose embedder defaults to a different specialist. Routing precedence: 1.

    1. continuity (last responder)
    2. conversationDefaultAgentId (this input — user's per-conversation pin)
    3. defaultAgentId (embedder-supplied)
    4. Sage fallback
    ConversationId: string
    ConversationName?: string | null
    conversationRenamed: EventEmitter<
        { conversationId: string; description: string; name: string },
    > = ...

    Use ConversationRenamed.

    The same emitter under the old binding name, so a template still binding (conversationRenamed) keeps working. Must stay AFTER ConversationRenamed: class fields initialise in order, and the other way round this captures undefined.

    ConversationRenamed: EventEmitter<
        { conversationId: string; description: string; name: string },
    > = ...
    CurrentUser: UserInfo
    DefaultAgentId: string | null = null

    Optional default agent ID for the conversation. When set, the FIRST message routes directly to this agent — skipping Sage's default delegation — provided the user did not

    a different agent and there is no prior agent in the conversation history. After the first message, the existing "last non-Sage agent" continuity rule keeps subsequent messages on the same agent.

    Used by embedded chat surfaces (Form Builder cockpit, future domain-specific chats) that have an obvious specialist agent for the context and don't need Sage to route. Leave unset to preserve the standard Sage-fronted UX of the main Chat app.

    Disabled: boolean = false
    DraftStateChanged: EventEmitter<string> = ...

    Live draft-state signal: fires on every composer value change with the SERIALIZED content (mention pills encoded via getPlainTextWithJsonMentions, so hosts can persist drafts losslessly). Empty string = draft cleared.

    EmptyStateMode: boolean = false
    emptyStateSubmit: EventEmitter<
        { attachments: PendingAttachment[]; text: string },
    > = ...

    Use EmptyStateSubmit.

    The same emitter under the old binding name, so a template still binding (emptyStateSubmit) keeps working. Must stay AFTER EmptyStateSubmit: class fields initialise in order, and the other way round this captures undefined.

    EmptyStateSubmit: EventEmitter<
        { attachments: PendingAttachment[]; text: string },
    > = ...
    EnableAgentMentions: boolean = true
    EnableAttachments: boolean = true
    EnableDecisionRouting: boolean = false

    Whether an unmentioned message asks one typed decision which agent in the conversation should answer it, instead of always going back to the last agent that answered. The same call can name the artifact version the message modifies. The answer replaces continuity only when it is confident and arrives in time; an error, a slow or unsure answer keeps today's routing, and a tagged message or a form response makes no call (see decision-routing.ts). False (the default) changes nothing: no call, and today's routing.

    What goes to the model: each qualifying message sends these to the model behind the Default Decision prompt, which can be a different vendor from the agents' own: the first 1,000 characters of the new message, the last 6 turns (150 characters each), each participant's name, description and last reply, and the names of their artifact versions. Each call writes an MJ: AI Prompt Runs row, even when the answer comes too late to be used.

    EnableEntityMentions: boolean = true
    EnableMentions: boolean = true
    EnablePlanMode: boolean = true
    EnableRealtime: boolean = true
    EnableSkillCommands: boolean = true
    initialDraftApplied: EventEmitter<void> = ...

    Use InitialDraftApplied.

    The same emitter under the old binding name, so a template still binding (initialDraftApplied) keeps working. Must stay AFTER InitialDraftApplied: class fields initialise in order, and the other way round this captures undefined.

    InitialDraftApplied: EventEmitter<void> = ...
    initialMessageAutoSendFailed: EventEmitter<{ conversationId: string }> = ...

    Use InitialMessageAutoSendFailed.

    The same emitter under the old binding name, so a template still binding (initialMessageAutoSendFailed) keeps working. Must stay AFTER InitialMessageAutoSendFailed: class fields initialise in order, and the other way round this captures undefined.

    InitialMessageAutoSendFailed: EventEmitter<{ conversationId: string }> = ...
    initialMessageAutoSendStarted: EventEmitter<{ conversationId: string }> = ...

    Use InitialMessageAutoSendStarted.

    The same emitter under the old binding name, so a template still binding (initialMessageAutoSendStarted) keeps working. Must stay AFTER InitialMessageAutoSendStarted: class fields initialise in order, and the other way round this captures undefined.

    InitialMessageAutoSendStarted: EventEmitter<{ conversationId: string }> = ...
    intentCheckCompleted: EventEmitter<{ conversationId: string }> = ...

    Use IntentCheckCompleted.

    The same emitter under the old binding name, so a template still binding (intentCheckCompleted) keeps working. Must stay AFTER IntentCheckCompleted: class fields initialise in order, and the other way round this captures undefined.

    IntentCheckCompleted: EventEmitter<{ conversationId: string }> = ...
    intentCheckStarted: EventEmitter<{ conversationId: string }> = ...

    Use IntentCheckStarted.

    The same emitter under the old binding name, so a template still binding (intentCheckStarted) keeps working. Must stay AFTER IntentCheckStarted: class fields initialise in order, and the other way round this captures undefined.

    IntentCheckStarted: EventEmitter<{ conversationId: string }> = ...
    IsProcessing: boolean = false
    IsSending: boolean = false
    IsUploadingAttachments: boolean = false
    MaxAttachments: number = 10
    MaxAttachmentSizeBytes: number = ...
    MentionPeople: readonly MentionPerson[] | null = null

    The people the composer's '@' list offers, such as the chat's members. Null (the default) offers only the current user, as before.

    messageComplete: EventEmitter<
        {
            agentId?: string;
            conversationDetailId: string;
            conversationId: string;
        },
    > = ...

    Use MessageComplete.

    The same emitter under the old binding name, so a template still binding (messageComplete) keeps working. Must stay AFTER MessageComplete: class fields initialise in order, and the other way round this captures undefined.

    MessageComplete: EventEmitter<
        {
            agentId?: string;
            conversationDetailId: string;
            conversationId: string;
        },
    > = ...
    messageSent: EventEmitter<MJConversationDetailEntity> = ...

    Use MessageSent.

    The same emitter under the old binding name, so a template still binding (messageSent) keeps working. Must stay AFTER MessageSent: class fields initialise in order, and the other way round this captures undefined.

    MessageSent: EventEmitter<MJConversationDetailEntity> = ...
    MessageStreamed: EventEmitter<MJConversationDetailEntity> = ...

    A streamed final-response delta was applied to an in-progress message: Message holds the full reply so far. Informational, so no Before/After pair; coalesced to at most one emission per animation frame; silent once the message has settled, because the completion path owns the final render. Hosts refresh the bubble in place on this, while MessageSent keeps announcing new and status-changed messages.

    ParentMessageId?: string
    PickerOverlayPositions: ConnectedPosition[] = ...

    CDK connected-overlay positions for the voice agent picker. Preferred: open UPWARD, right edge aligned to the composer's right edge (matching the old absolute placement). Fallback: open downward when there isn't room above. Because the popover renders in the body-level CDK overlay container (with cdkConnectedOverlayPush), it escapes the chat overlay's overflow: hidden border and can never clip at the top of a narrow overlay.

    Placeholder: string = 'Type a message... (Ctrl+Enter to send)'
    ProcessingMessage: string = 'AI is responding...'
    Provider: IMetadataProvider | null

    If specified, this provider will be used for communication and for all metadata purposes. By default, if not provided, the Metadata and RunView classes are used for this and the default GraphQLDataProvider is used which is connected to the same back-end MJAPI instance as the Metadata and RunView classes. If you want to have this component connect to a different MJAPI back-end, create an instance of a ProviderBase sub-class like GraphQLDataProvider/etc, and configure it as appropriate to connect to the MJAPI back-end you want to use, and then pass it in here.

    ReadOnly: boolean = false

    Blocks sending. Distinct from Disabled, which means the composer is busy.

    ResolveTargetBranch: (() => Promise<string | null | undefined>) | null = null

    When set, called once at the start of each send to get the branch of the new user row; undefined stops the send and nothing is written. A host uses it to create a draft fork on its first send.

    SendSlotMode: SendSlotMode = 'send'

    What the send slot is doing; see SendSlotMode in @memberjunction/ng-composer.

    ShowRealtimeAgentPicker: boolean = false

    True while the "Start a voice call with…" agent picker popover is open.

    StatusElapsed: string | null = null

    Elapsed time after the status text, kept out of the live region and dropped on narrow screens.

    StatusText: string | null = null

    Status line shown bottom-left inside the composer while non-null.

    StopClicked: EventEmitter<void> = ...

    The send slot was clicked in stop mode; the chat area stops the run(s).

    StopCount: number = 0

    How many things a stop would stop; above 1 the slot reads "Stop all".

    StopLabel: string = 'Stop'

    Tooltip and accessible name of the slot in stop mode.

    SystemArtifactsByDetailId?: Map<string, LazyArtifactInfo[]>
    TargetBranchID: string | null = null

    The fork new messages from this composer go to; null (the default) is Main. The agent turn of a message, and the agent-history reads it makes, use the message's branch.

    UploadingMessage: string = 'Uploading attachments...'
    uploadStateChanged: EventEmitter<{ isUploading: boolean; message: string }> = ...

    Use UploadStateChanged.

    The same emitter under the old binding name, so a template still binding (uploadStateChanged) keeps working. Must stay AFTER UploadStateChanged: class fields initialise in order, and the other way round this captures undefined.

    UploadStateChanged: EventEmitter<{ isUploading: boolean; message: string }> = ...
    VoiceActive: boolean = false

    True while a live voice session is active — drives the overlay + mic state.

    VoicePickerDefaultCoAgentId: string | null = null

    The persisted co-agent preference, loaded just before the picker opens (and read by the instant-start path). null = no preference / explicit "Auto".

    "ɵdir": unknown
    "ɵfac": ɵɵFactoryDeclaration<BaseAngularComponent, never>

    Accessors

    • get MessageText(): string

      The composer's text. An accessor pair rather than a plain field because every write reaches the editor through [value] -> ngModel.writeValue, which rebuilds or empties the chip DOM WITHOUT emitting valueChange — so a write is exactly the event mentionedAgentId has to hear about, and the setter is the one place that cannot be bypassed.

      Bypassing it is not hypothetical: handleSuccessfulSend and the empty-state submit clear the text without touching the editor, and conversation-chat-area assigns messageText on this component from the outside (three call sites). Invalidating at the individual call sites instead would leave every future one to remember.

      Read is a plain field read; there is no two-way ngModel on this property (the template binds [value]="messageText" one-way), so the pair is transparent to callers.

      Returns string

    • set MessageText(value: string): void
    • get PlanModeEnabled(): boolean

      Plan Mode toggle state — sticky PER CONVERSATION, OFF by default (no behavior change unless the user turns it on). When on, the user's next message(s) in THIS conversation request Plan Mode: the routed root agent must present a plan for approval before executing Actions/ Sub-Agents. The toggle is always shown and the server enforces the AIAgent.SupportsPlanMode capability — a plan-mode request to an agent that doesn't support it simply no-ops the gate (see resolvePlanModeGate), so we don't need to resolve "the current agent" client-side.

      IMPORTANT: this is a GETTER over PlanModePreference (UserInfoEngine-backed), NOT a local field. The composer is mounted in multiple places at once (empty-state, chat-area, thread panel) — a local boolean per instance goes stale the moment another instance toggles. On the new-conversation composer (no conversationId yet) the value lives in a pending bucket that transfers to the real conversation on its first message. Approving a plan turns the conversation's flag OFF automatically (see message-item's plan-decision handling).

      Returns boolean

    • get ProviderToUse(): IMetadataProvider

      Returns either the default Metadata provider or the one specified in the Provider property, if it was specified

      Returns IMetadataProvider

    • get RunQueryToUse(): IRunQueryProvider

      Returns either the default RunQuery provider or the one specified in the Provider property, if it was specified

      Returns IRunQueryProvider

    • get RunViewToUse(): IRunViewProvider

      Returns either the default RunView provider or the one specified in the Provider property, if it was specified

      Returns IRunViewProvider

    Methods

    • Pre-addresses the composer to an agent as a RESOLVED mention pill (+ trailing space, caret after, focused) — identical to the user typing '@agent' and picking it from the dropdown. Resolves the agent through MentionAutocompleteService so the chip carries the agent's real id/icon/presets; falls back to a plain-text '@Name ' draft when the agent can't be resolved (e.g. name mismatch).

      Parameters

      • agentName: string
      • focus: boolean = true
      • clearExisting: boolean = true

      Returns Promise<boolean>

      false while the composer view isn't mounted yet — callers may retry.

    • A callback method that is invoked immediately after the default change detector has checked data-bound properties if at least one has changed, and before the view and content children are checked.

      Parameters

      • changes: { [propName: string]: SimpleChange<any> }

        The changed properties.

      Returns void

    • Caret-next-to-the-phone click: open the agent/co-agent/model picker ON DEMAND, even when the conversation already has agent history (where the plain phone click instant-starts). The resolved agent is preselected, so "open → Start" matches the instant path while keeping the co-agent (and, for authorized users, voice-model) choice one click away. Falls through to the instant path when there is nothing to pick from.

      Returns Promise<void>

    • Start a real-time voice session fronting the conversation's current agent. Client-direct: the RealtimeSessionService mints an ephemeral token and connects the browser straight to the realtime provider over WebRTC. The "call mode" overlay itself is hosted by the conversation chat area (driven by Active$).

      NEW vs EXISTING conversation:

      • When an agent has already participated (a prior non-Sage AI turn exists), start immediately with the resolved agent — zero added friction.
      • When the conversation has NO prior agent participation (new / empty conversation), the resolution would silently fall through to a default the user never chose — so show a compact agent picker instead and start with whichever agent they pick.

      Returns Promise<void>

    • Routes an existing user message through the agent path again, so the agent writes a new reply on targetBranchId (default: the message's own branch). No message is saved, and the composer's draft and pending attachments are left alone. The rerun never counts as the conversation's first message. IsSending stays true until the agent turn ends, so no other send starts meanwhile.

      Parameters

      Returns Promise<boolean>

      false, with no agent turn, when the composer is read-only or already sending.

    • Send a message with custom text WITHOUT modifying the visible messageText input Used for suggested responses and initial messages from empty state. Also saves any pending attachments.

      extraAttachments is an escape hatch for callers that programmatically attached something via AddArtifactAttachment and want to send in the same tick — the attachmentsChanged event chain hasn't propagated yet, so this.pendingAttachments may not contain the attachment. Pass it in explicitly and we merge + dedupe (by id) before saving.

      options.IsResend sends an edited copy of an earlier message. The composer's draft is left alone: only extraAttachments are saved with the message, and the pending attachments and editor text are not cleared. The send never counts as the conversation's first message, so it does not name the conversation or claim a pending Plan Mode choice.

      options.TargetBranchID writes the message to that fork (null is Main) instead of the composer's own target.

      Parameters

      • text: string
      • OptionalextraAttachments: PendingAttachment[]
      • Optionaloptions: { IsResend?: boolean; TargetBranchID?: string | null }

      Returns Promise<boolean>