@filigran/chatbot 3.21.0 → 3.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,16 +8,135 @@ the versions follow [semantic versioning](https://semver.org/spec/v2.0.0.html).
8
8
  This file starts at 3.10.0; earlier releases are on the
9
9
  [releases page](https://github.com/FiligranHQ/filigran-ui/releases).
10
10
 
11
- ## 3.21.0 — unreleased
11
+ ## 3.23.0 — 2026-11-11
12
+
13
+ ### Changed
14
+
15
+ - The composer draws its border as the design system's Textarea: none at
16
+ rest, `theme.inputBorderHover` (`--filigran-chat-input-border-hover`, the
17
+ panel border unset) under the pointer. Dictation keeps its red border and
18
+ the focus keeps its 2 px ring.
19
+ - The panel's own look (no host theme) is the design system's palette: dark
20
+ surfaces grayblue 850 / 700 / 600 instead of three ad-hoc navy shades, the
21
+ tooltip, scrollbar and context usage colours from its scale, and every
22
+ floating surface (menus, the floating panel, the reasoning dialog, the row
23
+ actions bar) takes its one elevation shadow, `--shadow-global-shadow`. Host
24
+ tokens still win. The code colours stay GitHub's (the design system has no
25
+ syntax palette). A stylesheet test refuses any other colour literal and any
26
+ hand-written shadow in a component.
27
+ - Every chat text uses the design system's type scale: meta lines, labels,
28
+ chips and counts are `text-content-compact` (12 px, was 9.6 to 12 px in
29
+ seven ad-hoc sizes), titles, rows, the composer and the message text
30
+ `text-content-base` (14 px, was 13 px), the welcome emoji
31
+ `text-title-jumbo`. Host tokens still win. A stylesheet test refuses any
32
+ arbitrary `text-[..rem]` or `text-[..px]` in a component.
33
+ - Every error, warning and success colour reads the panel's feedback tones
34
+ instead of a Tailwind red, amber or emerald: the approval card and its
35
+ verdict badge, the context and quota gauges, the trace steps, the agent
36
+ list warnings, the voice call error ring, the delete confirmation. New theme
37
+ entry `theme.success` (`--filigran-chat-success`, a green unset) beside
38
+ `danger` and `warning`. A stylesheet test refuses any Tailwind palette shade
39
+ in a component.
40
+
41
+ ## 3.22.0 — 2026-11-11
12
42
 
13
43
  ### Added
14
44
 
45
+ - `renderAgentIcon(name, { size })`: the host draws an agent icon given by
46
+ name (an icon library's, such as `brain-circuit`) in the conversation rows,
47
+ the agent switcher and its trigger; `null` keeps the panel's glyph. Image
48
+ URLs and emoji are still drawn by the panel.
49
+
50
+ ### Changed
51
+
52
+ - A row's workspace marker keeps a readable minimum width and shows the whole
53
+ workspace name in the panel's tooltip when it is cut.
54
+ - Error and warning states take the host's design-system tones: `theme.danger`
55
+ and `theme.warning` (`--filigran-chat-danger`, `--filigran-chat-warning`)
56
+ colour the notices, a failed upload, dictation and the stop button; unset, a
57
+ red and an amber per mode (red-700 and amber-800 in the light mode, which
58
+ read at 4.5:1 under a notice's wash). No Tailwind red or amber is left in the
59
+ notice or the composer.
60
+ - A notice's close button shows the panel's tooltip instead of a native title,
61
+ with a 24 px hit area.
62
+ - The agent switcher hands the focus back to its trigger on Escape and when an
63
+ agent is chosen, and the trigger is 32 px high like the other header controls.
64
+
65
+ - Answers render their Markdown at the old chat page's quality and past it.
66
+ Fenced code is coloured by language (Python, TypeScript and JavaScript, JSON,
67
+ shell, SQL, YAML and their usual aliases) in light and dark, with no new
68
+ dependency; an unknown language stays plain. Tables read at the prose's size
69
+ with a filled header row, ruled and striped rows, cells that keep a readable
70
+ width and a frame that scrolls sideways when the table is wider than the
71
+ answer. Nested lists tighten and change bullet by level, task lists show
72
+ read-only boxes, h4 to h6, strikethrough and footnotes are styled.
73
+ - Conversations come first in the list. The workspaces fold into one
74
+ "Workspaces" line above the conversations (with their count and the New
75
+ workspace button), opened on demand and remembered per browser
76
+ (`filigran-chat-workspaces-open`). Below it, every conversation is listed most
77
+ recent first, a filed one naming its workspace on its row. The "Not in a
78
+ workspace" heading becomes "Conversations"; dropping a row there still takes
79
+ it out of its workspace. Creating, opening, renaming and deleting a workspace,
80
+ filing a conversation, the default marker and the counts all work as before
81
+ inside the open line.
82
+
83
+ ### Changed
84
+
85
+ - The new-conversation screen is short: the agent's mark, one greeting line
86
+ naming the agent, and the agent's own suggestions as compact chips. The
87
+ agent's description is no longer shown there (`ChatWelcome`'s
88
+ `agentDescription` is deprecated and ignored), the "Suggestions" heading is
89
+ gone, and the package's four generic fallback suggestions are removed: an
90
+ agent the suggestions route answers nothing for, with no host
91
+ `promptSuggestions`, shows no suggestion.
92
+ - The header's agent control is one switcher: a click anywhere on the icon,
93
+ the name or the chevron opens a searchable list of the agents (always
94
+ searchable, ArrowUp / ArrowDown move, Enter switches, Escape closes, the
95
+ current agent checked). With `agentHref` or `onAgentNameClick`, the agent's
96
+ page moves to an "Open agent page" item of that menu, with the same rules
97
+ (in place, a modifier key left to the browser); the name is no longer a link.
98
+ - Every error, warning and notice of the panel renders through one notice
99
+ block (`ChatNotice`): a tone (error, warning, info) with its icon, a tinted
100
+ container at the panel's radius, and a close button where the notice is not
101
+ tied to a live state. The composer's refused attachment and refused steer
102
+ or Stop notices close on a click; no notice is raw coloured text any more.
103
+ `useChat` returns `dismissNotice` and `dismissFileNotice`, and `ChatInput`
104
+ takes `onDismissNotice` and `onDismissFileNotice`.
105
+ - While the agent thinks or acts, the composer's working glow plays whether the
106
+ field has the focus or not: the focus ring stands aside for the turn (the box
107
+ carries `data-working`) and comes back when the turn ends or is stopped. The
108
+ field keeps the focus after Enter, as before.
109
+
110
+ ### Added
111
+
112
+ - A conversation row shows its agent's own icon (`agent_icon` of the list,
113
+ `ChatConversationSummary.agentIcon`: an image URL or an emoji, as
114
+ `XtmAgent.icon`) in place of the bot glyph, and its last line is the agent as
115
+ a small pill followed by the relative time, the time never cut. A backend
116
+ without `agent_icon`, or one the panel cannot draw, keeps the bot glyph.
15
117
  - `onConversationChange` says why the conversation changed: its second argument
16
118
  is `{ created }`, true for a conversation the panel has just created from a
17
119
  new chat (its first message or file), false for one opened from the list, on
18
120
  a reload or in place of a deleted one, and when it is left for a new chat. A
19
121
  host could not tell an opened conversation from a created one, as both came
20
122
  after a new chat.
123
+ - The composer takes the host's field tokens: `theme.inputRadius`,
124
+ `theme.inputMinHeight` and `theme.focusRing` set its corners, its height at
125
+ rest and its focus ring, so a host draws it with its design system and no
126
+ local override.
127
+ - The conversation list of fullscreen and inline modes is resizable: drag its
128
+ right edge between 224 and 480 px, or move it with the arrow keys, Home and
129
+ End once focused; a double-click puts back the 256 px it always had. The
130
+ width is remembered per browser (`filigranChatConversationListWidth`,
131
+ namespaced by `storageKeyPrefix`) and kept while the list is collapsed.
132
+
133
+ ### Changed
134
+
135
+ - The composer opens at two lines instead of one, and still grows with the
136
+ text up to its maximum: at one line it did not read as the place to write.
137
+ - The composer's focus is a 2 px ring around its box instead of an accent
138
+ border, the text-field focus of a design system; the border keeps its colour,
139
+ so dictation's red border still reads.
21
140
 
22
141
  ## 3.20.0 — 2026-11-10
23
142
 
package/README.md CHANGED
@@ -80,6 +80,7 @@ import { ChatPanel } from '@filigran/chatbot';
80
80
  | `t` | `(key: string) => string` | — | The host's translations; a key it returns unchanged falls back to the panel's catalog in `locale` (none without `locale`) — see [Internationalization](#internationalization) |
81
81
  | `accentColor` | `string` | `'#7b5cff'` | Primary accent color (hex) |
82
82
  | `logoIcon` | `React.ReactNode` | default icon | Custom logo/icon for the assistant |
83
+ | `renderAgentIcon` | `(name: string, { size }) => ReactNode` | — | Draws an agent icon given by name (`brain-circuit`) in the conversation rows, the switcher and its trigger; `null` keeps the panel's glyph. Image URLs and emoji are drawn by the panel |
83
84
  | `promptSuggestions` | `string[]` | default list | Prompt suggestions shown on welcome screen |
84
85
  | `draftBorderColor` | `string` | — | Color of the line above the composer (e.g. a draft context) |
85
86
  | `draftLabel` | `string` | — | Accepted, and not shown |
@@ -146,8 +147,8 @@ import { ChatPanel } from '@filigran/chatbot';
146
147
  | `sidebarSearchThreshold` | `number` | `7` | The conversation list's search box shows above this many conversations; `0` shows it from the first |
147
148
  | `channelLabel` | `(channel: string) => string \| null \| undefined` | — | Names the channel a conversation was started in, on its row (`Started in {channel}`) and in the header (`Agent · {channel}`); `null` shows nothing, `undefined` keeps the panel's names (Slack, Teams, WhatsApp, Telegram, Discord, Google Chat) |
148
149
  | `headerTitle` / `headerSubtitle` | `React.ReactNode \| ((context: ChatHeaderContext) => React.ReactNode)` | — | A title beside the header's agent name and a line under it, or functions of the conversation on screen (as the list holds it) and the agent. Without `headerSubtitle`, the line reads `Agent · {channel}` for a conversation started in a channel its row names |
149
- | `agentHref` | `(agent: XtmAgent) => string \| undefined` | — | Links the header's agent name to this address (http(s) or a path of the host's origin), in place; the chevron beside it opens the picker |
150
- | `onAgentNameClick` | `(agent: XtmAgent) => void` | — | Takes a plain click on the header's agent name (over `agentHref`); the chevron beside it opens the picker |
150
+ | `agentHref` | `(agent: XtmAgent) => string \| undefined` | — | The agent's page (http(s) or a path of the host's origin), followed in place from the "Open agent page" item of the agent switcher; the header's agent control itself always opens the switcher |
151
+ | `onAgentNameClick` | `(agent: XtmAgent) => void` | — | Takes a plain click on the switcher's "Open agent page" item (over `agentHref`) |
151
152
  | `clearAllAction` | `'delete' \| 'archive'` | `'delete'` | What Clear all does, for its wording (`Archive all conversations`) |
152
153
 
153
154
  Plain-data props (`requestHeaders`, `apiEndpoints`, `pageContext`, `promptSuggestions`) are compared by content and callback props are called
@@ -444,7 +445,7 @@ import { ChatToggleButton } from '@filigran/chatbot';
444
445
  | `label` | `string` | built-in | Button text, already translated by the host; omit for `t('Ask Assistant')` |
445
446
  | `t` | `(key: string) => string` | — | The host's translations; the panel's catalog in `locale` answers the rest |
446
447
  | `locale` | `string` | browser's | The default label's language, by the panel's rule (see Internationalization) |
447
- | `accentColor` | `string` | `'#7b5cff'` | Button background color |
448
+ | `accentColor` | `string` | ignored | Deprecated since 3.23.0: the toggle is the design system's secondary Button |
448
449
  | `icon` | `React.ReactNode` | default icon | Custom icon |
449
450
 
450
451
  ## API Contract
@@ -1287,6 +1288,13 @@ both. The same variables may be set in CSS on an ancestor instead.
1287
1288
  | `surfaceSubtle` | `--filigran-chat-surface-subtle` | Cards, search boxes, a table's or a code block's header |
1288
1289
  | `surfaceHover` | `--filigran-chat-surface-hover` | A row or a button under the pointer |
1289
1290
  | `inputSurface` | `--filigran-chat-input-surface` | A text field: the composer (no fill unless set), a rename field, the feedback and approval comments |
1291
+ | `inputRadius` | `--filigran-chat-input-radius` | The composer's corners (0.75rem unset) |
1292
+ | `inputBorderHover` | `--filigran-chat-input-border-hover` | The composer's border under the pointer; none at rest, as the design system's Textarea (`border` unset) |
1293
+ | `inputMinHeight` | `--filigran-chat-input-min-height` | The composer field's height at rest, before it grows with the text (two lines unset) |
1294
+ | `focusRing` | `--filigran-chat-focus-ring` | The 2 px ring around the composer while it has the focus (the accent unset) |
1295
+ | `danger` | `--filigran-chat-danger` | The tone of every error state: error notices, a failed upload, dictation, stop (a red unset, e.g. `var(--color-error)`) |
1296
+ | `warning` | `--filigran-chat-warning` | The tone of every warning notice (an amber unset, e.g. `var(--color-warning)`) |
1297
+ | `success` | `--filigran-chat-success` | The tone of an approved tool call and a successful trace step (a green unset, e.g. `var(--color-success)`) |
1290
1298
  | `headerBackground` | `--filigran-chat-header-background` | The header's background, a colour or an image (`none` for the surface alone) |
1291
1299
  | `text` | `--filigran-chat-text` | Text |
1292
1300
  | `textMuted` | `--filigran-chat-text-muted` | Times, labels, hints and placeholders |
@@ -1440,11 +1448,14 @@ A host behind its own proxy points the routes at it, relative to its
1440
1448
  `{ prompts: '/prompts', quota: '/quota', feedback: '/conversations' }`
1441
1449
  (`feedback`: see [Message feedback](#message-feedback)).
1442
1450
 
1443
- The welcome screen names the selected agent and shows its own suggestions —
1444
- which is also how switching agent is confirmed: the thread resets to that
1445
- screen, so without it nothing tells you who the next message will reach. When
1446
- the suggestions route is unavailable the host's `promptSuggestions` prop is used
1447
- instead, so the section is never empty.
1451
+ The welcome screen is short: the agent's mark, one greeting line naming the
1452
+ selected agent (which is also how switching agent is confirmed: the thread
1453
+ resets to that screen, so without it nothing tells you who the next message
1454
+ will reach), and the agent's own suggestions as compact chips. The agent's
1455
+ description is never shown there (it is picker and agent-page prose). When the
1456
+ suggestions route is unavailable the host's `promptSuggestions` prop is used
1457
+ instead; with neither, no suggestion is shown: the package carries no generic
1458
+ list of its own.
1448
1459
 
1449
1460
  Dictation needs no configuration at all: it uses the browser's own Web Speech
1450
1461
  API, so the mic button appears inside the text field, next to Send, wherever
package/dist/index.d.ts CHANGED
@@ -392,6 +392,24 @@ interface ChatPanelTheme {
392
392
  surfaceHover?: string;
393
393
  /** A text field: the composer (no fill unless set), a rename field, the feedback and approval comments (`--filigran-chat-input-surface`). */
394
394
  inputSurface?: string;
395
+ /** The composer's corners, as the host's text fields draw theirs (`--filigran-chat-input-radius`, `radiusMd` unset). */
396
+ inputRadius?: string;
397
+ /** The composer's border under the pointer, the design system's `--border-input-hover`; none at rest (`--filigran-chat-input-border-hover`, `border` unset). */
398
+ inputBorderHover?: string;
399
+ /** The small corner of every control, chip and avatar tile, the design system's `--radius-sm` (`--filigran-chat-radius-sm`, 4px unset). */
400
+ radiusSm?: string;
401
+ /** The card corner of every card, bubble, status indicator, menu and dialog, the design system's `--radius-md` (`--filigran-chat-radius-md`, 12px unset). */
402
+ radiusMd?: string;
403
+ /** The composer field's height at rest, before it grows with the text (`--filigran-chat-input-min-height`, two lines unset). */
404
+ inputMinHeight?: string;
405
+ /** The 2 px ring drawn around the composer while it has the focus (`--filigran-chat-focus-ring`, the accent unset). */
406
+ focusRing?: string;
407
+ /** The danger tone of every error state: notices, a failed upload, dictation, stop (`--filigran-chat-danger`, a red unset). */
408
+ danger?: string;
409
+ /** The warning tone of every warning notice (`--filigran-chat-warning`, an amber unset). */
410
+ warning?: string;
411
+ /** The success tone of an approved tool call and a successful trace step (`--filigran-chat-success`, a green unset). */
412
+ success?: string;
395
413
  /** The header's background, a colour or an image; `none` for the surface alone (`--filigran-chat-header-background`). */
396
414
  headerBackground?: string;
397
415
  /** Text (`--filigran-chat-text`). */
@@ -415,6 +433,10 @@ interface ChatPanelTheme {
415
433
  codeSize?: string;
416
434
  codeSurface?: string;
417
435
  }
436
+ /** Draws an agent icon given by name at `size` pixels; `null` when the host has no such icon. */
437
+ type ChatAgentIconRenderer = (name: string, options: {
438
+ size: number;
439
+ }) => React.ReactNode;
418
440
  interface ChatPanelProps {
419
441
  mode: ChatPanelMode;
420
442
  /** Shows the close button; inline mode has none. */
@@ -449,6 +471,13 @@ interface ChatPanelProps {
449
471
  t?: Translate;
450
472
  accentColor?: string;
451
473
  logoIcon?: React.ReactNode;
474
+ /**
475
+ * Draws an agent icon given by name (`XtmAgent.icon`,
476
+ * `ChatConversationSummary.agentIcon`, e.g. `brain-circuit`), which the
477
+ * panel cannot draw itself: in the conversation rows and the agent switcher.
478
+ * `null` keeps the panel's glyph. Image URLs and emoji are drawn by the panel.
479
+ */
480
+ renderAgentIcon?: ChatAgentIconRenderer;
452
481
  promptSuggestions?: string[];
453
482
  /** Accepted, and not shown. */
454
483
  draftLabel?: string;
@@ -638,6 +667,13 @@ interface ChatPanelProps {
638
667
  readOnly?: boolean;
639
668
  /** Shown in place of the composer while `readOnly`. */
640
669
  readOnlyNotice?: React.ReactNode;
670
+ /**
671
+ * A tip shown at the top of a voice call (for example which models answer
672
+ * fast enough to talk to), in an info notice the user can close. Once
673
+ * closed it stays closed for the browser session (`sessionStorage`, under
674
+ * `storageKeyPrefix`). Without it the call shows no tip.
675
+ */
676
+ voiceCallNotice?: React.ReactNode;
641
677
  /**
642
678
  * Fields merged into every REST message body, read at send time: the host's
643
679
  * own per-message options (tool selection, run mode). They never override
@@ -1092,6 +1128,11 @@ interface ChatToggleButtonProps {
1092
1128
  t?: Translate;
1093
1129
  /** BCP 47 tag of the label's language when the host does not translate it (see `ChatPanelProps.locale`). */
1094
1130
  locale?: string;
1131
+ /**
1132
+ * @deprecated since 3.23.0: the toggle is the design system's secondary
1133
+ * Button and takes its colours from the host's design-system tokens; the
1134
+ * value is ignored. Kept so a host that passes it still compiles.
1135
+ */
1095
1136
  accentColor?: string;
1096
1137
  icon?: React.ReactNode;
1097
1138
  }
@@ -1362,6 +1403,12 @@ interface ChatConversationSummary {
1362
1403
  * genuinely have no agent.
1363
1404
  */
1364
1405
  agentName?: string;
1406
+ /**
1407
+ * The conversation agent's icon (`agent_icon`), an image URL or an emoji as
1408
+ * `XtmAgent.icon`, when the backend reports one: the row draws it in place of
1409
+ * the panel's generic glyph.
1410
+ */
1411
+ agentIcon?: string;
1365
1412
  /**
1366
1413
  * The workspace the conversation is filed in (`null`: none), when the
1367
1414
  * backend reports it. Undefined on backends that do not.
@@ -1407,7 +1454,7 @@ interface XtmAgent {
1407
1454
  id: string;
1408
1455
  name: string;
1409
1456
  slug: string | null;
1410
- /** An image URL or an emoji; anything else shows the panel's logo. */
1457
+ /** An image URL, an emoji, or a name drawn by `ChatPanelProps.renderAgentIcon`; else the panel's logo. */
1411
1458
  icon: string | null;
1412
1459
  description: string | null;
1413
1460
  /** The heading the agent picker lists it under; ungrouped agents come first. */
@@ -1429,6 +1476,13 @@ interface XtmAgent {
1429
1476
  */
1430
1477
  declare const ChatPanel: react.ForwardRefExoticComponent<ChatPanelProps & react.RefAttributes<ChatPanelHandle>>;
1431
1478
 
1479
+ /**
1480
+ * The host's button that opens and closes the panel: the design system's
1481
+ * secondary Button (its border, hover, focus ring and pressed state come from
1482
+ * the host's design-system tokens). `accentColor` is no longer painted on it
1483
+ * (chatbot 3.23.0): the button follows the design system like every other
1484
+ * control of the panel.
1485
+ */
1432
1486
  declare const ChatToggleButton: FunctionComponent<ChatToggleButtonProps>;
1433
1487
 
1434
1488
  interface TransferredAgent {
@@ -1440,4 +1494,4 @@ interface TransferredAgent {
1440
1494
  declare const voiceCallSupported: () => boolean;
1441
1495
 
1442
1496
  export { ChatPanel, ChatToggleButton, voiceCallSupported };
1443
- export type { AgentStatusState, ApiEndpoints, BackendType, ChatAnsweredBy, ChatArtifact, ChatArtifactKind, ChatAttachment, ChatCodeBlockContext, ChatCodeBlockRenderer, ChatContextBreakdown, ChatContextUsage, ChatConversationAction, ChatConversationChange, ChatConversationRef, ChatConversationReferenceCandidate, ChatConversationSummary, ChatFile, ChatFileRefusal, ChatHeaderContext, ChatHeldOutcome, ChatMarkerContext, ChatMarkerRenderer, ChatMessage, ChatMessagePersistedFeedback, ChatMessageSlotContext, ChatMode, ChatPanelHandle, ChatPanelMode, ChatPanelProps, ChatPanelTheme, ChatPromptTemplate, ChatQuotaStatus, ChatSendDecision, ChatSendDraft, ChatSendOptions, ChatSendOutcome, ChatSidebarSearch, ChatStreamEventInfo, ChatToggleButtonProps, ChatToolLabels, ChatTurnEnd, ChatTurnOutcome, ChatWorkspace, ConsultStatus, MessageFeedback, ToolApprovalDecision, ToolApprovalProposal, ToolApprovalVerdict, TransferredAgent, Translate, XtmAgent };
1497
+ export type { AgentStatusState, ApiEndpoints, BackendType, ChatAgentIconRenderer, ChatAnsweredBy, ChatArtifact, ChatArtifactKind, ChatAttachment, ChatCodeBlockContext, ChatCodeBlockRenderer, ChatContextBreakdown, ChatContextUsage, ChatConversationAction, ChatConversationChange, ChatConversationRef, ChatConversationReferenceCandidate, ChatConversationSummary, ChatFile, ChatFileRefusal, ChatHeaderContext, ChatHeldOutcome, ChatMarkerContext, ChatMarkerRenderer, ChatMessage, ChatMessagePersistedFeedback, ChatMessageSlotContext, ChatMode, ChatPanelHandle, ChatPanelMode, ChatPanelProps, ChatPanelTheme, ChatPromptTemplate, ChatQuotaStatus, ChatSendDecision, ChatSendDraft, ChatSendOptions, ChatSendOutcome, ChatSidebarSearch, ChatStreamEventInfo, ChatToggleButtonProps, ChatToolLabels, ChatTurnEnd, ChatTurnOutcome, ChatWorkspace, ConsultStatus, MessageFeedback, ToolApprovalDecision, ToolApprovalProposal, ToolApprovalVerdict, TransferredAgent, Translate, XtmAgent };