# @memberjunction/ng-conversations
A comprehensive Angular component library for building conversation-based interfaces in MemberJunction, including messaging, artifact management, collections, projects, tasks, agent interaction panels, and collaboration features.
> **Layering note.** The orchestration logic (agent dispatch, default-agent resolution, mention parsing, bridge state, streaming, client tools, sessions observability) lives in **`@memberjunction/conversations-runtime`** — a pure-TS, framework-agnostic package. This widget is one consumer of the runtime; React/Vue/Node hosts are also intended consumers. The widget is automatically wired to the runtime via `ConversationsRuntimeBootstrap` (registered `providedIn: 'root'`), which injects adapters for notifications, active-task tracking, and realtime sessions. See [`guides/CONVERSATIONS_UX_STACK_GUIDE.md`](../../../../guides/CONVERSATIONS_UX_STACK_GUIDE.md) for the full architecture.
## Customization without forking
The widget exposes three layers of extension:
| Surface | What it lets you do |
|---|---|
| **6 named slots** (`mjChatSlot` directive) | Replace the `header`, `emptyState`, `agentPresence`, `messageRenderer`, `messageExtra`, or `demonstrationSurface` regions with your own templates. Three consumption modes: project an ad-hoc template, wrap the exported default for containment, or subclass the default. |
| **Before/After cancelable events** | `(beforeAgentTurn)`, `(beforeToolInvoked)`, `(beforeResponseFormSubmitted)` let you observe AND veto (`event.Cancel = true`) before the action runs. Plus informational `(sessionStarted)` / `(sessionChannelStateChanged)` / `(sessionEnded)` for realtime lifecycle. |
| **`--mj-chat-*` design tokens** | Override bubble colors, composer chrome, character accents, and voice-state hues via standard CSS custom-property overrides. Defaults adapt to dark mode through semantic `--mj-*` tokens. |
Slot interfaces + cloneable default components + the `ChatSlotDirective` are exported — see the public API.
## Overview
The `@memberjunction/ng-conversations` package is a large, feature-rich module that powers MemberJunction's conversation UI. It provides 40+ components covering the entire conversation lifecycle: message composition and rendering (with markdown, mentions, code blocks, and artifacts), conversation navigation and history, threaded discussions, artifact collections and libraries, project/task management, agent execution panels, sharing/permission modals, search, notifications, and export.
```mermaid
graph TD
A[ConversationsModule] --> B[Messaging]
A --> C[Navigation]
A --> D[Collections & Library]
A --> E[Agent & Tasks]
A --> F[Collaboration]
B --> B1[MessageItemComponent]
B --> B2[MessageListComponent]
B --> B3[MessageInputComponent]
B --> B4[MentionEditorComponent]
B --> B5[SuggestedResponsesComponent]
B --> B6[ConversationMessageRatingComponent]
C --> C1[ConversationWorkspaceComponent]
C --> C2[ConversationNavigationComponent]
C --> C3[ConversationSidebarComponent]
C --> C4[ConversationListComponent]
C --> C5[ConversationChatAreaComponent]
C --> C6[ThreadPanelComponent]
D --> D1[CollectionTreeComponent]
D --> D2[CollectionViewComponent]
D --> D3[LibraryFullViewComponent]
D --> D4[ArtifactCreateModalComponent]
E --> E1[AgentProcessPanelComponent]
E --> E2[ActiveAgentIndicatorComponent]
E --> E3[TasksFullViewComponent]
E --> E4[GlobalTasksPanelComponent]
F --> F1[ShareModalComponent]
F --> F2[MembersModalComponent]
F --> F3[ExportModalComponent]
F --> F4[SearchPanelComponent]
style A fill:#2d6a9f,stroke:#1a4971,color:#fff
style B fill:#7c5295,stroke:#563a6b,color:#fff
style C fill:#2d8659,stroke:#1a5c3a,color:#fff
style D fill:#b8762f,stroke:#8a5722,color:#fff
style E fill:#7c5295,stroke:#563a6b,color:#fff
style F fill:#2d8659,stroke:#1a5c3a,color:#fff
```
## Installation
```bash
npm install @memberjunction/ng-conversations
```
## Usage
### Import the Module
```typescript
import { ConversationsModule } from '@memberjunction/ng-conversations';
@NgModule({
imports: [ConversationsModule]
})
export class YourModule { }
```
### Full Conversation Workspace
The top-level workspace component provides a complete conversation experience with sidebar, chat area, and thread panel:
```html
```
### Chat Area
The chat area handles message display, input, and agent interactions:
```html
```
### Chat Overlay
A floating chat panel (bottom-right corner) that wraps the chat area for persistent agent access across the application. Collapses to a bubble icon, expands to a full chat panel.
```html
```
The overlay is generic — it raises events for navigation and tool execution. The consuming application (e.g., MJExplorer) handles those events with app-specific logic like `NavigationService.OpenEntityRecord()`.
**Related packages:**
- [`@memberjunction/ai-agent-client`](../../../AI/AgentsClient/README.md) — Core agent SDK (framework-agnostic, GraphQL transport, tool registry)
- [`@memberjunction/ng-agent-client`](../agent-client/README.md) — Angular wrapper for the agent SDK
- [`@memberjunction/core-entities`](../../../MJCoreEntities/readme.md) — ConversationEngine for centralized conversation data
### Message Components
#### Message List
```html
```
#### Message Input with Mentions
```html
```
#### Mention Editor
```html
```
### Collections and Library
```html
```
### Project and Task Management
```html
```
### Agent Components
```html
```
### Real-Time Voice (Co-Agent) UX
The package hosts the full client UX for MJ's real-time co-agent sessions — live voice calls with the conversation's agent, with interactive channel surfaces (the live Whiteboard) docked beside the call. Architecture background: [guides/REALTIME_CO_AGENTS_GUIDE.md](../../../../guides/REALTIME_CO_AGENTS_GUIDE.md).
**`RealtimeSessionService`** (`services/realtime-session.service.ts`) is the provider-agnostic orchestrator, injectable at root. It drives a **client-direct** session: it calls the `StartRealtimeClientSession` mutation to mint a server-scoped ephemeral credential, resolves the matching `BaseRealtimeClient` driver (from `@memberjunction/ai-realtime-client` — OpenAI, Gemini, ElevenLabs, or AssemblyAI) through the ClassFactory by the server-reported `Provider` key, and connects the browser **directly** to the realtime provider — audio frames never transit the MJ server; only tool calls, final transcripts, channel state, and usage telemetry relay back over GraphQL. It exposes the reactive session state hosts consume: `ConnectionState$` (`connecting | listening | speaking | thinking | error | closed`), `Captions$`, `Active$`, `DelegationProgress$` / `DelegationResult$` / `DelegationNarration$`, `ActiveChannels$`, `ChannelFocus$`, `Minimized$`, plus `SendText` (typed input into the live call), `ToggleMute`, `RegisterClientToolHandler` (prefix-routed, client-executed UI tools), and the explicit delegation cancel channel — `CancelDelegation(callId)` / `CancelInFlightDelegations()` call the `CancelRealtimeSessionTool` mutation and flip the card to "Cancelled by user" (deliberate policy: **true barge-in never aborts delegated work** — only the per-card ✕ does). The client driver's `OnUsage` token deltas are accumulated and relayed onto the co-agent's observability prompt run via `RelayRealtimeUsage`, debounced (10 s) plus a teardown flush.
**Co-agent selection, pairing constraints & authorization-gated overrides**: the composer's voice picker (`mj-voice-agent-picker`, opened by the caret next to the phone button — or automatically on a conversation with no prior agent participation) lets every user choose which **co-agent** (ACTIVE Realtime-type agent, from the same run-permission-filtered cache the @mention routing uses) fronts the call when more than one exists; the choice rides the mint's `coAgentId` and persists cross-device via `UserInfoEngine` (`mj.realtimeVoice.coAgent.v1`), so the friction-free instant start honors it too. A co-agent with rows in `MJ: AI Agent Paired Agents` may only front its paired targets — the picker constrains the target list to those rows (Sequence order, `IsDefault` preselected; pure helpers in `services/voice-pairing.ts`) — while a co-agent with zero rows stays universal (today's flow untouched; pairings constrain a chosen co-agent, they never mandate one). The **voice-model selector** (and any future session-config override, carried as the mint's `configOverridesJson`, e.g. `{"realtime":{"modelPreference":…}}`) renders only for users holding the **`Realtime: Advanced Session Controls`** MJ Authorization — evaluated client-side by the pure `UserHoldsAuthorization` helper (`services/user-authorization.ts`) from cached metadata as a *disclosure* gate; the server independently enforces the authorization on the mint, and unauthorized users silently get server defaults. (The gear popover's interface-density control is UX disclosure, not session config — it is not gated.)
**The call overlay** (`components/realtime/`): `RealtimeSessionOverlayComponent` (`mj-realtime-session-overlay`) fills the conversation panel in place while a session is active — hosted by `ConversationChatAreaComponent` behind `Active$`, started from the mic button in `MessageInputComponent`. Two columns:
- **Main column** — the unified APP-BAR (`RealtimeAgentBannerComponent`: identity + turn state + model name + the disclosure-gated action cluster — captions, the gear popover hosting the interface-density escape hatch and developer links, minimize, End call; in review the Start-live + Close actions live here too), then the pure-audio hero orb OR the unified session thread (`RealtimeSessionThreadComponent`, fed by the shared `RealtimeSessionState` merge of caption/delegation/narration streams), the channel strip, and the bottom dock (`RealtimeComposerComponent`: phone-call strip at low disclosure levels ⇄ fused mute/captions minis + typed composer at level 2+; typed turns behave identically to spoken ones).
- **Right panel** — `RealtimeSurfaceTabsComponent`, the tabbed surface panel (`RealtimeSurfaceTabsModel` is the framework-free, unit-tested tab state): channel tabs lead the strip, then **one tab per artifact** a delegated run produces (added UNFOCUSED with a persistent violet "unseen" glow until visited — content never steals the screen), with the Activity rail pinned LAST.
**Progressive disclosure** (`realtime-disclosure.ts`): the console *grows with the user*. A first-ever call is PURE AUDIO — a breathing hero orb, mute / Details / End, nothing to read; the caption thread, composer dock, surface panel and gear unlock by level (0–4) as the user acts (the hero's "Show the conversation", the T-to-type hotkey, the Details peek) or across sessions via the per-user milestones ratchet (UserInfoEngine, `mj.realtimeVoice.uxMilestones.v1`; the gear's Simple/Standard/Pro/Auto density control is the manual escape hatch). Content never flips the console open — **the one auto-reveal is a channel's first agent activity** (`RealtimeSessionService.ChannelActivity$`): the panel opens as a peek with that channel's tab focused + flashed, while the left column stays exactly as it was. Review mode bypasses disclosure entirely.
**Audio-reactive visuals** (`realtime-audio-visuals.ts`): when the active driver meters its audio planes (`BaseRealtimeClient.GetAudioActivity()` — all four current drivers do, both directions), the overlay samples it on a requestAnimationFrame loop *outside Angular* and writes CSS variables directly: the hero orb scales with the smoothed output envelope (speaker-cone attack/decay), the EQ bars render the true 9-bin spectrum, and the visuals recolor by speaking direction (agent = brand, user = green) with hysteresis so syllable gaps never flicker. Un-metered drivers gracefully keep the turn-state-driven animations. See the guide's §11 for the full pipeline.
**Interactive channels are plugins** — the shell is channel-agnostic. `BaseRealtimeChannelClient` (`components/realtime/channels/base-realtime-channel-client.ts`) is the contract: a client-executed tool set declared to the realtime model at session mint, a perception serializer feeding coalesced state deltas into the model as context notes, a dynamically-created Angular surface component the plugin binds itself, a persisted state of record, prior-session restore (`RestoreState`), artifact snapshots (`SaveAsArtifact`), and focus-mode layout requests. Plugins resolve at session start from the `MJ: AI Agent Channels` registry by `ClientPluginClass` key.
**The live Whiteboard is a thin consumer of [`@memberjunction/ng-whiteboard`](../whiteboard/README.md)** — the board itself (the `WhiteboardState` engine, the `Whiteboard_*` tool API, the host/board/toolbar/zoom/popover/snapshot components, exports, the sandboxed-HTML-widget input bridge, the context menu) lives in that generic package; read its README for whiteboard details. This package contributes only the integration glue (`components/realtime/whiteboard/`): `RealtimeWhiteboardChannel`, the ~200-line channel plugin that declares `WHITEBOARD_TOOL_DEFINITIONS` to the model, routes `Whiteboard_*` calls to the bound host (or the pure engine call when the pane is collapsed), pipes the coalesced `SceneDelta` stream into the model as `[whiteboard]` context notes (with do-not-narrate-minor-edits etiquette inline), forwards widget submissions (`MJWhiteboard.submit` — the tutoring loop) and agent-undo events, persists/restores the board as the channel's state of record, and snapshots it to versioned `MJ: Artifacts`; plus `WhiteboardArtifactViewerPlugin` (`mj-whiteboard-artifact-viewer`), the saved-board artifact viewer rendered through the package's read-only snapshot component.
**Session review & resume carryover**: a past session replays through the same overlay in review mode — `ConversationChatAreaComponent.OpenRealtimeSessionReview(agentSessionId)` loads a `RealtimeSessionReview` via `RealtimeSessionReviewService`. The loader is **chain-aware**: a session resumed via `lastSessionId` chains legs, and the loader walks the chain backwards (capped, cycle-guarded), rendering every leg chronologically with a divider between legs that carries the previous leg's `CloseReason` as a chip; the chain's conversation-history artifacts load as unfocused artifact tabs, and a read-only Whiteboard tab appears when a board was saved. "Start live session" resumes as a new session chained via `lastSessionId` — saved channel states restore *and* the prior legs' transcript is hydrated into the new model's prompt server-side. The conversations resource also accepts a `realtimeSessionId` query param (the deep link the custom `MJ: AI Agent Sessions` form emits) and opens review mode directly.
This package never navigates (no Router): developer links emit a `RealtimeNavigateRequest` the host converts onto its `openEntityRecord` chain, and minimizing the call shows the host's floating "on call" pill while the session stays live.
### Collaboration
```html
```
## Component Reference
### Messaging Components
| Component | Selector | Description |
|-----------|----------|-------------|
| `MessageItemComponent` | `mj-message-item` | Single message display with markdown, artifacts, and rating |
| `MessageListComponent` | `mj-message-list` | Scrollable message list with auto-scroll |
| `MessageInputComponent` | `mj-message-input` | Message input with attachment support |
| `MessageInputBoxComponent` | `mj-message-input-box` | Core input box with auto-resize |
| `SuggestedResponsesComponent` | `mj-suggested-responses` | Quick response buttons |
| `FormQuestionComponent` | `mj-form-question` | Structured form input within conversations |
| `AgentResponseFormComponent` | `mj-agent-response-form` | Agent-generated form responses |
| `ActionableCommandsComponent` | `mj-actionable-commands` | Clickable command suggestions |
| `MentionDropdownComponent` | `mj-mention-dropdown` | @-mention autocomplete dropdown |
| `MentionEditorComponent` | `mj-mention-editor` | Rich text input with mention support |
| `ConversationMessageRatingComponent` | `mj-conversation-message-rating` | Message feedback (thumbs up/down) |
### Navigation Components
| Component | Selector | Description |
|-----------|----------|-------------|
| `ConversationWorkspaceComponent` | `mj-conversation-workspace` | Full workspace layout |
| `ConversationNavigationComponent` | `mj-conversation-navigation` | Top-level navigation |
| `ConversationSidebarComponent` | `mj-conversation-sidebar` | Left sidebar with conversation list |
| `ConversationListComponent` | `mj-conversation-list` | Scrollable conversation history |
| `ConversationChatAreaComponent` | `mj-conversation-chat-area` | Main chat area |
| `ConversationEmptyStateComponent` | `mj-conversation-empty-state` | Empty state display |
| `ThreadPanelComponent` | `mj-thread-panel` | Threaded discussion panel |
### Collection and Library Components
| Component | Selector | Description |
|-----------|----------|-------------|
| `CollectionTreeComponent` | `mj-collection-tree` | Hierarchical collection browser |
| `CollectionViewComponent` | `mj-collection-view` | Collection detail view |
| `CollectionArtifactCardComponent` | `mj-collection-artifact-card` | Artifact card within collections |
| `LibraryFullViewComponent` | `mj-library-full-view` | Full library interface |
| `CollectionFormModalComponent` | `mj-collection-form-modal` | Create/edit collection |
| `ArtifactCreateModalComponent` | `mj-artifact-create-modal` | Create new artifact |
| `CollectionsFullViewComponent` | `mj-collections-full-view` | All collections browser |
### Project and Task Components
| Component | Selector | Description |
|-----------|----------|-------------|
| `ProjectSelectorComponent` | `mj-project-selector` | Project selection dropdown |
| `ProjectFormModalComponent` | `mj-project-form-modal` | Create/edit project |
| `TasksFullViewComponent` | `mj-tasks-full-view` | Full tasks management view (standalone) |
| `TasksDropdownComponent` | `mj-tasks-dropdown` | Task quick-access dropdown |
| `TaskWidgetComponent` | `mj-task-widget` | Compact task widget |
| `GlobalTasksPanelComponent` | `mj-global-tasks-panel` | Global tasks panel |
### Agent Components
| Component | Selector | Description |
|-----------|----------|-------------|
| `AgentProcessPanelComponent` | `mj-agent-process-panel` | Agent execution panel |
| `ActiveAgentIndicatorComponent` | `mj-active-agent-indicator` | Active processing indicator |
| `ActiveTasksPanelComponent` | `mj-active-tasks-panel` | Active tasks panel |
### Real-Time Voice Components
| Component | Selector | Description |
|-----------|----------|-------------|
| `RealtimeSessionOverlayComponent` | `mj-realtime-session-overlay` | The in-place "call mode" overlay for a live voice session (progressive-disclosure console: pure-audio hero → full two-column; audio-reactive orb/EQ) |
| `RealtimeAgentBannerComponent` | `mj-realtime-agent-banner` | The unified app-bar: identity + turn-state + disclosure-gated actions (captions, gear popover w/ density + dev links, minimize, End; review Start-live + Close) |
| `RealtimeSessionThreadComponent` | `mj-realtime-session-thread` | Unified live thread (captions, delegation cards, ephemeral narration) |
| `RealtimeActivityRailComponent` | `mj-realtime-activity-rail` | Session activity rail (the surface panel's pinned-last tab) |
| `RealtimeDelegationCardComponent` | `mj-realtime-delegation-card` | "Working on it" → result card for a delegated agent run |
| `RealtimeChannelStripComponent` | `mj-realtime-channel-strip` | Chip-per-channel strip |
| `RealtimeComposerComponent` | `mj-realtime-composer` | The bottom dock: phone-call strip (levels 0–1: mute / captions / Details peek / End) ⇄ fused minis + typed composer (level 2+) |
| `RealtimeSurfaceTabsComponent` | `mj-realtime-surface-tabs` | Tabbed surface panel: channel tabs first, glowing unfocused artifact tabs, Activity pinned last (backed by the framework-free, unit-tested `RealtimeSurfaceTabsModel`) |
| `WhiteboardArtifactViewerComponent` | `mj-whiteboard-artifact-viewer` | Saved-board artifact viewer (registered as `WhiteboardArtifactViewerPlugin`); renders via `@memberjunction/ng-whiteboard`'s snapshot component |
> The live whiteboard surface itself (`mj-realtime-whiteboard-host`, board, toolbar, zoom, "What the agent sees" popover) ships in [`@memberjunction/ng-whiteboard`](../whiteboard/README.md); the `RealtimeWhiteboardChannel` plugin here creates it dynamically in a channel tab.
### Utility Components
| Component | Selector | Description |
|-----------|----------|-------------|
| `ShareModalComponent` | `mj-share-modal` | Resource sharing modal |
| `MembersModalComponent` | `mj-members-modal` | Members management |
| `ExportModalComponent` | `mj-export-modal` | Data export modal |
| `SearchPanelComponent` | `mj-search-panel` | Search across conversations |
| `NotificationBadgeComponent` | `mj-notification-badge` | Unread notification count |
| `ActivityIndicatorComponent` | `mj-activity-indicator` | Active processing indicator |
| `ToastComponent` | `mj-toast` | Toast notification display |
| `InputDialogComponent` | `mj-input-dialog` | Generic text input dialog |
| `ImageViewerComponent` | `mj-image-viewer` | Image attachment viewer |
## Directives
| Directive | Selector | Description |
|-----------|----------|-------------|
| `SearchShortcutDirective` | `[mjSearchShortcut]` | Keyboard shortcut for search |
## Key Design Patterns
### Performance Optimization
Message components use dynamic component creation (`ViewContainerRef.createComponent`) instead of Angular template binding to minimize render cycles and improve performance with large message lists.
### MJ Entity Integration
All data operations use the MemberJunction entity system:
- `Metadata.GetEntityObject()` for entity creation
- `RunView` for efficient data loading
- Proper generic typing throughout
### Reactive State Management
RxJS `BehaviorSubject` instances for all state, with derived observables using `combineLatest` and `shareReplay(1)` for efficient caching.
## Dependencies
### MemberJunction Packages
| Package | Description |
|---------|-------------|
| `@memberjunction/core` | Core framework |
| `@memberjunction/core-entities` | Entity type definitions |
| `@memberjunction/global` | Global utilities |
| `@memberjunction/graphql-dataprovider` | GraphQL data access |
| `@memberjunction/ng-artifacts` | Artifact viewer components |
| `@memberjunction/ng-code-editor` | Code editor component |
| `@memberjunction/ng-container-directives` | Container directives |
| `@memberjunction/ng-markdown` | Markdown rendering |
| `@memberjunction/ng-shared-generic` | Shared generic components |
| `@memberjunction/ng-testing` | Testing framework components |
| `@memberjunction/ng-whiteboard` | The generic collaborative whiteboard (consumed by the realtime Whiteboard channel + artifact viewer) |
| `@memberjunction/ai-realtime-client` | Browser-side realtime drivers (OpenAI / Gemini / ElevenLabs / AssemblyAI) used by `RealtimeSessionService` |
### Kendo UI Packages
Uses `@progress/kendo-angular-dialog`, `@progress/kendo-angular-buttons`, `@progress/kendo-angular-inputs`, `@progress/kendo-angular-layout`, `@progress/kendo-angular-indicators`, `@progress/kendo-angular-dropdowns`, `@progress/kendo-angular-notification`, `@progress/kendo-angular-upload`, `@progress/kendo-angular-dateinputs`.
### Peer Dependencies
- `@angular/common` ^21.x
- `@angular/core` ^21.x
- `@angular/forms` ^21.x
- `@angular/router` ^21.x
## Build
```bash
cd packages/Angular/Generic/conversations
npm run build
```
## License
ISC