Display a chat conversation thread between an end-user and an AI model.
Reference → Controls → Interaction → ChatSession
The ChatSession control belongs to the Interaction category and runs on TChatSession control (shown in the Designer Components Panel under the Interaction category as "ChatSession") is the FrameworX surface for an AI chat panel inside a Display. It belongs to the Portable rendering target (WPF rich client and HTML5/WASM). Place it on a Display from the Components Panel and configure the properties listed below.ChatSession renders a vertical, auto-scrolling list of message bubbles, visually distinguishing user messages from AI messages. It is the standard FrameworX surface for an operator chat or LLM-assistant pane inside a SCADA/HMI Display— the same control renders identically in the WPF Rich Client and in the HTML5/WASM Web Client.
In FrameworX 10.1.5 the control is zero-substrate for the standard pattern: drop a TChatSession on a Display, drop a TextBox bound to a Query tag, drop a Button with the ChatRequest Action, and the live conversation appears multi-turn and role-bubbled without any DataTable, UserType, or Script wiring on the adopter side.
| Table of Contents | ||||
|---|---|---|---|---|
|
Overview
ChatSession is the FrameworX Display control for conversational AI inside a process-control or operator console. It renders a scrolling thread of message bubbles bound to an items source — typically the platform-managed TChatSession renders an auto-scrolling vertical thread of per-role message bubbles. The control pulls the conversation directly from the runtime's per-Display-panel transcript from cache — the same cache the ChatRequest Action Reference action , a Dataset table, a List-typed Tag, or a Script-returned collection — where each item carries a role (user vs AI) and a body text. The control inspects each item's role value, compares it against UserRoleValue and AIRoleValue, and styles the bubble accordingly (alignment, colors, corner shaping).
Primary pattern — ChatRequest with auto-managed transcript
In FrameworX 10.1.5, the standard operator chat panel pairs ChatSession with the ChatRequest Display Action. No scripting is required:
A TextBox for the user prompt and a Button whose Action is set to
ChatRequest(Query tag, Return tag configured in the Action editor).A ChatSession control bound to the same Display panel. The platform automatically maintains the per-Display-panel transcript — each turn the operator sends is appended to the conversation history server-side; the AI reply is appended after the model responds. The customer does not need to write Script code to manage this collection.
The per-Display-panel transcript is keyed internally by the client connection and resets transparently on operator login change (shift change). It can be disabled solution-wide via the EnableChatHistory bit on SolutionSettings.ModelOptions. See ChatRequest Action Reference for full transcript semantics.
Alternative pattern — Script-managed collection
When the conversation source is not the platform-managed transcript — for example, a persisted chat log driven by a Dataset, or a custom in-memory collection a Script assembles — a typical assistant pane wires three pieces:
A TextBox for the user prompt and a Button whose Action invokes a Script.
A Server-side Script that appends the user message to the conversation collection, then calls an LLM via the FrameworX HTTP
CHATverb (routed through the in-product ChatSession orchestrator and theChatRequestAPI). On response, the Script appends the AI reply to the same collection.A ChatSession control bound to that collection. The control re-renders on any collection change, and — when
AutoScrollToBottomistrue— brings the newest message into view automatically.
Because the control runs on the Portable target, the same Display works in the WPF Rich Client and in the HTML5/WASM Smart Client without modification.
Bindings
ChatSession uses the standard FrameworX itemized-source pattern. The conversation collection is provided through three coordinated properties:
Property
Use in an AI chat pattern
ItemsSourceType
Selects the kind of source. Use DataTable when conversations are persisted (Dataset Query or Table holding one row per message); use ArrayTag when the conversation lives in memory as a List-typed Tag; use Text for a static seeded thread.
ItemsSourceLink
The actual source reference, interpreted per ItemsSourceType. For persisted chats: @Dataset.Query.ConversationByUser (or similar). For in-memory chats: @Tag.ChatThread where ChatThread is a List Tag whose item members include a role field and a body field. The control re-renders on collection change.
ItemsSourceOption
Legacy source-selection mode kept for compatibility; new Displays should prefer ItemsSourceType + ItemsSourceLink.
UserRoleValue / AIRoleValue and a body text. For Dataset sources, name the role column and body column to match what the Script appends; for List-Tag sources, define a UserType with at least Role and Body memberspopulates on every chat turn. There is no transcript Tag to bind, no DataTable to configure, no UserType to define, and no Server Script glue to write.
This is the standard pattern for every chat surface in FrameworX: operator chat, knowledge-graph assistant, SupportAI debug, partner portal, training tutor. Each surface composes the same five elements (TChatSession + Input TextBox + Send/Clear/Compress Buttons + scalar Query/Reply Tags) and re-skins independently.
Minimum operator chat panel — the zero-substrate pattern
Three elements, two scalar tags, one Action. No scripting:
A TextBox whose write binding is a String tag (e.g.
@Tag.Chat/Query).A Button with an Action dynamic of type
ChatRequest. Set the Action's Query field to the Query tag and the Return field to a JSON tag (e.g.@Tag.Chat/Reply).A TChatSession control on the same Display panel. Leave
ItemsSourceLinkempty — the control auto-resolves to the live transcript for the current client.
When the operator clicks the Button, the live conversation appears in the TChatSession: the user's question lands immediately as an accent-tinted bubble (no waiting for the LLM), a rotating ? pending indicator with an elapsed-seconds counter follows it, and the assistant reply bubble replaces the indicator when the model finishes. Follow-up questions on the same panel retain context — the model sees the full transcript and can refer back to earlier turns.
For a complete working solution showing this pattern end-to-end — six live plant tags as grounding context, three quick-prompt buttons, the AI Engine tile configured for a local Ollama model — see Local AI Chat Example.
Visual contract
The control's render surface is opinionated — the visual shape is pinned by the platform so every chat surface in FrameworX reads consistently. Authors do not style the bubbles individually; they style the control's outer chrome (background, border) and the platform paints the bubbles per role.
Layout — single-column-left
Every bubble — user, assistant, and unknown-role — left-edges in a single column. Color discriminates role; alignment does not. The layout follows the conversational-AI cluster convention (Claude Code, Claude.ai, ChatGPT, Cursor, GitHub Copilot, Linear AI) rather than the peer-to-peer messenger convention (iMessage, WhatsApp, Slack DMs). Each bubble caps at ~75 % of the control's rendered width; the rest of the row is empty so the eye scans one ragged-right margin instead of two.
Bubble shape — selectable TTextBlock
Bubble bodies render as T.Wpf.RunControls.TTextBlock elements (the FrameworX-native control that inherits System.Windows.Controls.TextBlock). Chrome is suppressed by the control — no border, no focus rectangle, no caret, no keyboard tab-stop.
Bubble text is selectable. Operators drag-select bubble text with the mouse, then press Ctrl-C to copy to the clipboard, or right-click and pick Copy from the context menu. Selection works symmetrically on user and assistant bubbles. The capability is enabled via TextBlock.IsTextSelectionEnabled on WPF .NET 4.8; on HTML5/WASM (OpenSilver) it degrades gracefully — the bubbles render correctly and selection activates as soon as OpenSilver surfaces the underlying property.
Color palette — theme tokens, not RGB
Role | Background | Foreground (text) | Border |
|---|---|---|---|
User | AccentBrush (platform accent surface) | ThemeWhiteBrush (high-contrast text on accent) | DefaultBorder |
Assistant | ShadeBrush (neutral shade) | TextForeground | DefaultBorder |
Unknown (Role matches neither | ShadeBrush | TextForeground | DefaultBorder |
The control resolves these theme tokens dynamically — a live theme switch repaints every bubble without a transcript reload, via the platform's ThemeDP attached-property surface. Authors should not hardcode bubble RGB values; the theme tokens are the contract.
Sizing — auto-size to wrapped content
Bubbles auto-size to their wrapped content (Height = NaN, MinHeight = 22) so multi-line replies grow vertically without being clipped. The horizontal cap is ~75 % of TChatSession.ActualWidth (the outer control), so wide screens render correctly without re-skinning and narrow screens wrap rather than horizontally scroll.
Corner shaping — BubbleCornerRadius
Default 14 pixels. Set to 0 for square bubbles, higher values for a more conversational appearance. Applies uniformly to user and assistant bubbles.
Auto-scroll — AutoScrollToBottom
Default true. On every transcript update (new turn lands, ChatCompress replaces, initial open with non-empty cache) the inner ScrollViewer scrolls to the bottom so the freshest message is in view. Set to false when the user is reviewing historical transcript and the scroll position should be preserved.
Pending-indicator UX
When the operator clicks the Send Button (ChatRequest), TChatSession appends two visuals immediately — before the LLM round-trip begins:
An immediate user-echo bubble carrying the operator's typed query, styled with the user-role palette. The operator sees their message land at once instead of staring at an empty panel for 3–10 seconds.
A pending row with a rotating ? glyph (one revolution per ~1.2 seconds) and an elapsed-seconds counter that ticks
0s, 1s, 2s, ….
Both visuals are replaced by the authoritative server-emitted bubble pair when the LLM reply lands — no flicker between the echo and the server-snapshot bubble.
Role discrimination — tolerant matching
The control declares two role-marker properties:
UserRoleValue— defaultuser. Identifies user-role bubbles.AIRoleValue— defaultassistant. Identifies assistant-role bubbles.
Matching is case-insensitive (OrdinalIgnoreCase) and also tolerates common alias synonyms on each side. A bubble whose Role column matches the declared property OR appears in the role's alias set renders with that role's palette; bubbles whose Role matches neither fall through to the unknown-role branch (neutral palette).
Side | Default property value | Alias set (case-insensitive) |
|---|---|---|
User |
|
|
Assistant |
|
|
The defaults plus the alias whitelist mean most adopters never need to set UserRoleValue or AIRoleValue explicitly — the runtime writes user and assistant on every row, and both defaults match. Override the properties only when feeding the control from a custom transcript whose role labels do not match the defaults or any alias.
For persona labels visible on the Display (e.g. "Operator", "Plant AI"), add a separate TextBlock above the transcript — do not push the persona text into UserRoleValue / AIRoleValue. The control's contract is to match what the runtime writes; the persona is a Display-level affordance.
Multiple chat sessions on one Display
A Display panel may carry several TChatSession controls — for example, a primary operator chat plus a side-panel diagnostic chat against a different model. Each control's transcript cache is keyed by its Name property, so distinct instances on the same Display address distinct cache entries automatically with no author wiring.
When you wire the ChatRequest Action and want it to refresh a specific TChatSession (rather than refreshing every TChatSession on the panel), set the Action's optional ChatSessionUid field to the target control's Uid. Empty ChatSessionUid falls back to enumerating every TChatSession descendant of the Display — the correct default for single-session panels.
Cross-target — WPF and HTML5
TChatSession is shared source — the same control compiles into the WPF Rich Client (.NET 4.8) and into the HTML5 Web Client (OpenSilver / WASM). Author wiring does NOT differ between the two targets. Visual parity holds for the full layout, the color palette, the auto-scroll, the auto-size height, and the pending-indicator. Selection + Ctrl-C copy is active today on the WPF target; on the HTML5 target it degrades gracefully — no error, just no selection — until the underlying OpenSilver TextBlock surfaces the relevant property.
Lifecycle actions
TChatSession is a rendering control. The three Display Actions below operate on the per-Display-panel transcript that TChatSession displays. Attach them to Buttons on the same Display panel for a complete operator chat surface.
Action | What it does |
|---|---|
Sends the operator's query to the LLM, maintains the per-Display-panel transcript across turns, dispatches platform tools the model may request, refreshes the TChatSession surface on reply landing. The primary action for an operator chat panel. | |
Wipes the transcript for the addressed chat session immediately, without calling the LLM. Use for "Start new conversation" buttons and shift-handover resets. Synchronous and idempotent. | |
Summarises the current transcript via one LLM call and atomically replaces it with the summary. Preserves semantic continuity while reducing token cost on long conversations. Asynchronous; takes 3–10 seconds on a local model. |
Properties
Property set auto-extracted from ControlSchemas.json (build fx-10.1.5.2000, schema 1.0, generated 2026-05-17T21:29:29.5050227Z).
Property | Type | Default | Description | ||||
|---|---|---|---|---|---|---|---|
|
| 0 | X position from left edge (unit: pixels) | ||||
|
| 0 | Y position from top edge (unit: pixels) | ||||
|
| 100 | Element width (unit: pixels). Cleared to auto-size on Loaded. | ||||
|
| 100 | Element height (unit: pixels). Cleared to auto-size on Loaded. | ||||
|
| (none) |
| When | |||
|
| (none) |
| String the control treats as the user-role marker. Case-insensitive + alias whitelist (see "Role discrimination" above).(no description in schema) | |||
|
| (none) |
| String the control treats as the assistant-role marker. Case-insensitive + alias whitelist (see "Role discrimination" above).(no description in schema) | |||
|
| (none) | (no description in schema) | ||||
|
| (none) | (no description in schema) | ||||
|
| (none) | (no description in schema) | ||||
|
| (none) | (no description in schema) | ||||
|
| (none) | (no description in schema) | ||||
|
| (none) | (no description in schema) | ||||
|
| (none) | (no description in schema) | ||||
|
| (none) | (no description in schema) | ||||
|
| (none) | (no description in schema) | ||||
|
| 100 | (no description in schema) | ||||
|
| (none) | (no description in schema) | ||||
|
| 100 | (no description in schema) | ||||
|
| (none) | (no description in schema) | ||||
|
| 5 | (no description in schema) | ||||
|
| (none) | (no description in schema) | ||||
|
| (none) | (no description in schema) | ||||
|
| 0 | Data source type: Designer (static list), ArrayTag (tag array), DataTable | ||||
|
| (none) | Source kind: Text (static list via ItemsList), ArrayTag (array tag values), DataTable (Dataset Query or Table — FK pattern). For FK dropdowns use DataTable + ItemsSourceLink='@Dataset.Query.X' + DisplayMemberPath + SelectedValuePath. | ||||
|
| (none) | Source for populating list items. Interpretation depends on ItemsSourceType: Text → @Tag.OptionsList (array or CSV tag) ArrayTag → @Tag.ArrayOfStrings DataTable → @Dataset.Query.NameOfQuery (RECOMMENDED for FK dropdowns) In DataTable mode the ComboBox auto-fires the backing query at display-open — no script Select() needed. | ||||
|
| (none) | Tag that triggers list refresh when its value changes | ||||
|
| 0 | (no description in schema) | ||||
14 | Corner rounding of each message bubble, in pixels. Applies uniformly to user and assistant bubbles. | ||||||
|
| (empty) | Advanced. When empty, the control auto-resolves to the live server-side transcript for the current client (recommended). When set to a custom DataTable Tag reference (e.g. | ||||
|
|
| Pinned to | ||||
|
| (themed) | Background color of the control's outer chrome |
|
| (none) | Background color (#AARRGGBB). Themed by default — OMIT to use theme. |
|
| (nonethemed) | TextDefault text/foreground color of the outer chrome (#AARRGGBB). Themed by default — OMIT to use theme. Note: bubble foreground is driven by the per-role palette and is NOT controlled by this property. | ||||
|
| (nonethemed) | Border Outer border color (#AARRGGBB). | ||||
|
| (nonethemed) | Border Outer border thickness (single value or ' |
ChatSession-specific properties
The auto-generated table above ships with empty descriptions for several ChatSession-specific properties. Until the next schema regeneration carries the descriptions through, use the editorial notes below.
Property
Description
AutoScrollToBottom
When true, the viewport scrolls to the newest message as soon as the bound collection grows. Recommended for live operator chat panes so a new AI reply is visible without user interaction. Set to false when reviewing historical transcripts where the user expects the scroll position to be preserved.
UserRoleValue
The string the control treats as the user role marker. Each item in the bound collection whose role field equals this value is rendered as a user bubble (right-aligned by default). May be a literal (e.g. user) or a tag-bound expression. Must match exactly what the Script writes when appending user messages.
AIRoleValue
The string the control treats as the AI role marker. Items whose role field equals this value render as AI bubbles (left-aligned by default). May be a literal (e.g. assistant) or a tag-bound expression. Items whose role matches neither marker fall back to the default bubble style.
BubbleCornerRadius
Corner rounding of each message bubble, in pixels. 0 renders square bubbles; higher values produce a more conversational, mobile-style appearance. Applies uniformly to user and AI bubbles.
|
|
| Caps the maximum number of bubbles the control renders. Useful for very long transcripts where the visible history must be bounded. Fresh-drop default is |
Inherited properties not authored on this control
The control inherits a Designer-canvas / preview-mode sample-rendering surface from its parent class (DesignQuantity, PreviewQuantity, DesignElements, PreviewElements, PreviewMargin, DesignSingleType, PreviewSingleType, PreviewSettings, DesignWidth, PreviewWidth, DesignHeight, PreviewHeight, DesignMargin, DesignSettings, ReloadItemsLink, ContainerPanel). These properties are not authored on TChatSession — they describe a generic list-of-elements panel surface, not a chat session whose container shape and data source are pinned by the control itself. The Designer property panel suppresses them by default.
Advanced — bring-your-own transcript
The zero-substrate path is the recommended pattern for ~95 % of chat surfaces. The bring-your-own-transcript escape hatch exists for the remaining cases — a frozen archive Display, a filtered conversation view, a cross-solution merge.
Set ItemsSourceLink to a DataTable Tag reference (e.g. @Tag.MyDataTable). The control bypasses the zero-substrate auto-resolve and reads from that Tag instead. The DataTable schema must contain at minimum:
An
Elementcolumn carrying the fully-qualified element type name (e.g.T.Wpf.RunControls.TTextBlock) — identifies the per-row bubble shape.A
LinkedValuecolumn carrying the message text (each cell is the bubble's content).A
Rolecolumn carrying the role string —user,assistant, or any value in the alias whitelist.
When the DataTable updates (rows added, rows removed, contents changed), bind ReloadItemsLink to a pulse tag so the control re-reads on demand.
Adopters using a custom DataTable Tag continue to work unchanged against the zero-substrate ship — the escape hatch is purely additive.
See also
Local AI Chat Example — the canonical minimal solution demonstrating the zero-substrate pattern end-to-end.
ChatRequest Action Reference — the primary Action paired with this control.
ChatClear Action Reference — transcript wipe action.
ChatCompress Action Reference — transcript summarization action.
Local AI — parent reference covering the full Local AI feature surface.
Local AI Configuration — endpoint configuration, ModelOptions bits, tool-category gates.
Local AI Reply Envelope Schema — the JSON shape that lands on the Reply tag
Additional Properties
The properties below also ship with empty descriptions in the auto-generated table. They configure Designer-time and Preview-mode rendering of sample items inside the ChatSession surface. Behaviors are conservative best-effort from the schema shape; consult ControlSchemas.json for the current default value.
Property
Description
DesignQuantity
Number of sample items rendered in the Designer canvas when no live source is bound. Used so the control occupies meaningful space while the Display is being authored.
PreviewQuantity
Number of sample items rendered in Preview mode. Lets the author validate scrolling and bubble layout against a representative item count before going live.
DesignElements
Comma- or newline-separated sample items rendered inside the control at design time. Each entry produces one preview bubble. Use to visualize the bubble styling without binding a source.
PreviewElements
Same shape as DesignElements but rendered while the Display is in Preview mode. Lets the author drive the live rendering path with a known sample set.
PreviewMargin
Outer spacing around preview items, in pixels. Single value applies uniformly; left,top,right,bottom applies per side. Controls how preview items pack inside the ChatSession frame.
DesignSingleType
When true, restricts the Designer preview to a single role — user OR AI — so the author can validate one bubble style in isolation. When false, design preview alternates roles.
PreviewSingleType
Same as DesignSingleType but applied in Preview mode. Useful when the live source is mocked with a single-role sample.
PreviewSettings
Serialized render settings applied to Preview-mode items (typography, color overrides, spacing). Edited through the Designer property editor rather than by hand; consult ControlSchemas.json for the current default value.
PreviewWidth
Width of the preview frame within the control, in pixels. Controls how wide each preview bubble may stretch before wrapping. Defaults to the auto-generated design-mode width when unset.
PreviewHeight
Height of the preview frame within the control, in pixels. Combined with PreviewQuantity determines whether preview content scrolls.
DesignSettings
Serialized render settings applied to Designer-canvas items (counterpart to PreviewSettings). Controls typography, colors, and spacing while the Display is being authored. Edited through the Designer property editor; consult ControlSchemas.json for the current default value.
MaxItemsLink
Tag expression that caps the maximum number of items the control will render from the bound source. When unset, the full bound collection is rendered. Use for live operator chat panes where the visible history must be bounded to keep the bubble list responsive.
Related actions
ChatSession is a rendering control. The Display Actions listed below operate on the server-side transcript that ChatSession displays. Attach them to Buttons on the same Display panel to give operators full control of the conversation lifecycle.
Action
What it does
Sends the operator’s query to the LLM, manages the per-panel transcript across turns, and dispatches platform tools the model may request. The primary action for an operator chat panel.
Wipes the transcript for the addressed chat session immediately, without calling the LLM. Use for “Start new conversation” buttons and shift-handover resets.
.
In this section...
| Page Tree | ||
|---|---|---|
|