ndf-chat
v0.0.34
Published
**ndf-chat** is a publishable Angular 19 library that embeds an AI chat assistant into host applications. It supports RAG (retrieval-augmented generation) conversations with streaming answers, citations, chat history, and an optional knowledge-graph featu
Readme
ndf-chat
ndf-chat is a publishable Angular 19 library that embeds an AI chat assistant into host applications. It supports RAG (retrieval-augmented generation) conversations with streaming answers, citations, chat history, and an optional knowledge-graph feature.
The library ships two main UI surfaces for general chat (widget and full page), plus a separate document chat widget for asking questions about a single document. All surfaces share styling tokens, i18n, and composable UI building blocks.
What is inside
UI surfaces
| Component | Selector | Purpose |
| --- | --- | --- |
| NdfChatWidgetComponent | ndf-chat-widget | Floating launcher + compact chat panel (bottom-left or bottom-right). Loads chat data when opened. Citations open in a new tab by default. |
| NdfChatPageComponent | ndf-chat-page | Full-page assistant with sidebar (chat list), welcome hero, messages, sources panel, and optional graph dialog. Loads data on init. |
| NdfChatDocWidgetComponent | ndf-chat-doc-widget | Document-scoped chat widget. Supports Ask and Translate modes, streaming answers, citations, suggestions, and history for one document. |
Optional feature modules (secondary entry points)
These are registered at app bootstrap via with* helpers passed to provideNdfChat():
| Import path | Helper | What it adds |
| --- | --- | --- |
| ndf-chat/graph | withGraph() | Knowledge graph panel (2D / 3D) using force-graph, 3d-force-graph, and three peer deps |
| ndf-chat/rename-dialog | withRenameDialog() | Material dialog to rename a chat |
| ndf-chat/feedback-dialog | withFeedbackDialog() | Thumbs-down feedback dialog with reason codes |
| ndf-chat/feedback-dialog | withDeleteConfirmDialog() | Confirm dialog before deleting a chat or doc history |
| ndf-chat/doc-chat | — | Document chat widget (NdfChatDocWidgetComponent), store, and API. Self-contained; registers its own providers on the component. |
Project structure
projects/ndf-chat/
├── src/
│ ├── public-api.ts # Main library entry
│ └── lib/
│ ├── core/ # Config, types, defaults, feature tokens
│ ├── data/ # HTTP client, CRUD, streaming, hooks port
│ ├── display/ # Citation pipes, markdown/chart rendering
│ ├── features/
│ │ ├── doc-chat/ # Document chat widget, API, shell store
│ │ ├── graph/ # Knowledge graph feature
│ │ ├── rename-dialog/
│ │ ├── feedback-dialog/
│ │ └── delete-confirm-dialog/
│ ├── i18n/ # Locale strings (en / ar), RTL support
│ ├── page/ # Full-page assistant
│ ├── shared/ # Reusable chat UI components
│ ├── shell/ # Shell store, sessions, base directive
│ ├── styles/ # SCSS tokens and shared styles (published as assets)
│ ├── testing/ # Test helpers
│ └── widget/ # Floating widget + launcher + body
├── graph/ # Secondary ng-packagr entry → ndf-chat/graph
├── rename-dialog/
├── feedback-dialog/
├── doc-chat/
└── ng-package.jsonLayer overview
flowchart TB
subgraph surfaces [UI Surfaces]
Widget[NdfChatWidgetComponent]
Page[NdfChatPageComponent]
DocWidget[NdfChatDocWidgetComponent]
end
subgraph shell [Shell layer]
Base[NdfChatBase directive]
Store[NdfChatShellStore]
DocStore[DocChatShellStore]
end
subgraph api [API layer]
Service[NdfChatService]
DocApi[DocChatApiService]
HTTP[Chat HTTP / Stream clients]
end
Widget --> Base
Page --> Base
Base --> Store
DocWidget --> DocStore
Store --> Service
DocStore --> DocApi
Service --> HTTP
DocApi --> HTTPShared components (lib/shared/)
Reusable building blocks used by widget, page, and doc-chat:
- chat-composer / chat-composer-bar — message input, send, stop streaming
- chat-messages — user and assistant message list (general RAG chat)
- chat-list — sidebar chat history with search, pin, rename, delete
- chat-suggestions — clickable starter prompts
- chat-welcome-hero — empty-state welcome message
- chat-sources-panel — citation / sources drawer
- chat-widget-header — title bar, close, mode toggles
- chat-alert — inline error / retry banners
Shell & state (lib/shell/)
NdfChatBase— abstract directive shared by widget and page; exposes store signals and actions to templates.NdfChatShellStore— central state for chat list, active thread, streaming, citations, graph, and dialogs. Split into session services:NdfChatListSession— chat CRUD, pin, searchNdfChatThreadSession— messages, send, stream cancelNdfChatCitationSession— citation preview and graph from sourcesNdfChatDialogSession— rename / feedback / delete dialogs via registered features
DocChatShellStore— separate store for document chat (history, ask/translate, suggestions).
API layer (lib/api/)
NdfChatService— facade for ask (REST + SSE stream), chat list/history CRUD, feedback, document URLs, and knowledge graph fetch.ChatStreamClient— parses CTS SSE (meta,sources,token,usage,done).NdfChatHooksService— default hooks port; hosts can override viaNDF_CHAT_HOOKS_PORT.DocChatApiService— facade over pluggable doc-chat transports (correspondence, demo, or custom viaNDF_DOC_CHAT_ADAPTER).
Default doc-chat adapter is correspondence (POST /open, POST /ask/stream).
| Endpoint key | Correspondence default |
| --- | --- |
| open | /open |
| askStream | /ask/stream |
| historyOps | /conversations/:convId/history |
| conversationMessages | /conversations/:convId/messages |
General chat default paths (Nuxeo CTS chatbot, overridable via root endpoints):
| Endpoint key | Default path |
| --- | --- |
| createChat | POST /sessions |
| listChats | GET /sessions |
| getChat | GET /sessions/:chatId |
| updateChat | PATCH /sessions/:chatId |
| deleteChat | DELETE /sessions/:chatId |
| history | GET /sessions/:chatId/messages |
| ask | POST /sessions/:chatId/messages |
| askStream | POST /sessions/:chatId/messages/stream |
Feedback UI and submitFeedback stay in place. endpoints.feedback is empty until CTS publishes that route.
Streaming is used when rag.useStreaming !== false and endpoints.askStream is set.
Configuration
Bootstrap the library in your app:
import { provideHttpClient } from '@angular/common/http';
import { provideNdfChat } from 'ndf-chat';
import { withGraph } from 'ndf-chat/graph'; // etc.
export const appConfig = {
providers: [
provideHttpClient(),
provideNdfChat(
{
apiBaseUrl: 'https://api.example.com',
getAccessToken: () => inject(AuthService).getToken(),
rag: {
useStreaming: true,
enableReferences: true
},
i18n: { locale: 'en' }
},
withGraph()
)
]
};Per-component overrides are supported via the [config] input on ndf-chat-widget, ndf-chat-page, and ndf-chat-doc-widget.
Doc-chat adapter
// Correspondence (default) — Nuxeo ask-correspondence
docChat: {
adapter: 'correspondence',
apiBaseUrl: 'https://<nuxeo>/nuxeo/site/ai/ask-correspondence'
}
// Live translation (when backend endpoints exist)
docChat: {
adapter: 'correspondence',
apiBaseUrl: 'https://<nuxeo>/nuxeo/site/ai/ask-correspondence',
endpoints: {
translationAttachments: '/translation/attachments',
translationLanguages: '/translation/languages',
translationStream: '/translation/stream'
}
}Custom backends can register NDF_DOC_CHAT_ADAPTER with a DocChatTransportPort implementation.
Migration (breaking)
| Before | After |
| --- | --- |
| docChat.provider: 'correspondence' | docChat.adapter: 'correspondence' (or omit) |
| docChat.adapter: 'knowledgeAsset' / ndf-chat/knowledge-asset | Removed — use correspondence or a custom NDF_DOC_CHAT_ADAPTER |
| Implicit default adapter = knowledgeAsset | Implicit default adapter = correspondence |
Key config areas (NdfChatBaseConfig for bootstrap, NdfChatConfig for [config] overrides):
| Area | Description |
| --- | --- |
| apiBaseUrl | Base URL for all chat API calls (required) |
| endpoints | Partial override of REST / stream paths |
| rag | Collection names, chat ID factory, streaming, references, think mode |
| graph | Enable graph, document UUID, max nodes/edges, 2D vs 3D default |
| feedback | Show thumbs-up/down actions and allow feedback submission |
| citations | Show citation / sources UI in widget and doc-chat |
| rename | Show rename in chat list (requires withRenameDialog()) |
| page | Viewport fill height for full-page layout |
| watermark | Opt-in tiled canvas watermark on widget, page, and doc-chat |
| docChat | Doc-chat adapter (correspondence), API base, and translation endpoints |
| i18n | Locale, direction (LTR/RTL), labels, welcome copy |
| Callbacks | onOpen, onClose, onError, onCitationClick, onOpenAssistantPage |
Background watermark (opt-in; copy falls back to the i18n title):
provideNdfChat({
apiBaseUrl: 'https://api.example.com',
watermark: {
enabled: true,
content: 'Confidential',
globalAlpha: 0.1
}
})Internationalization
Built-in English and Arabic copy in lib/i18n/chat-i18n.ts. Supports:
- RTL layout via
i18n.diror locale detection - Overridable title, welcome message, placeholders, and label map
NdfI18nPipeandNdfChatI18nServicefor templates
Doc-chat suggestions are bilingual (ar / en) and picked by locale.
Styles
Shared SCSS lives in lib/styles/ and is published to ndf-chat/styles when the library is built. Includes design tokens (_tokens.scss), message layout, typing indicator, and icon helpers.
Include shared styles in the host app as needed after building the library.
Build & test
From the monorepo root:
npm run build:lib
# output: dist/ndf-chat
npx ng test ndf-chat --watch=false --browsers=ChromeHeadlessImport surfaces
// Main package
import {
NdfChatWidgetComponent,
NdfChatPageComponent,
NdfChatService,
provideNdfChat
} from 'ndf-chat';
// Optional secondary packages
import { NdfChatDocWidgetComponent } from 'ndf-chat/doc-chat';
import { withGraph } from 'ndf-chat/graph';
import { withRenameDialog } from 'ndf-chat/rename-dialog';
import { withFeedbackDialog, withDeleteConfirmDialog } from 'ndf-chat/feedback-dialog';Peer dependencies
Host apps should provide:
@angular/common,@angular/core,@angular/forms,@angular/material,@angular/cdk@angular/common/httpviaprovideHttpClient()- Material Icons (for toolbar / dialog icons)
- For graph feature:
three,force-graph,3d-force-graph
Typical usage in templates
Floating widget
<ndf-chat-widget [config]="{ rag: { useStreaming: true } }" />Full page
<ndf-chat-page [config]="{ page: { fillViewportHeight: true } }" />Document chat
<ndf-chat-doc-widget
[docId]="documentUuid"
[docTitle]="documentTitle"
[showAsk]="true"
[showTranslate]="true"
(citationClick)="onCitation($event)"
/>Related
- Monorepo root: README.md
- Demo app: run
npm startfrom the workspace root to try widget, page, and doc chat with demo data
