@filigran/chatbot 3.14.0 → 3.15.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 +277 -0
- package/README.md +542 -290
- package/dist/index.d.ts +468 -12
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/markdown.d.ts +58 -1
- package/dist/markdown.js +1 -1
- package/dist/markdown.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/workspaces.d.ts +99 -0
- package/dist/workspaces.js +2 -0
- package/dist/workspaces.js.map +1 -0
- package/package.json +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,283 @@ 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.15.0 — unreleased
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `mode="inline"`: the panel fills the host's container instead of floating
|
|
16
|
+
over the page, laid out like fullscreen (conversation list beside the
|
|
17
|
+
thread), with no view switcher and no close button. For a host that gives
|
|
18
|
+
the chat a page of its own.
|
|
19
|
+
- A host can own the conversation on screen (`conversationId`,
|
|
20
|
+
`onConversationChange`), pick the agent selected first (`initialAgent`,
|
|
21
|
+
`onAgentChange`) and drive the panel through its `ref`, a handle that is the
|
|
22
|
+
same object for the panel's life:
|
|
23
|
+
- `send(text, { extras, displayText })`: the backend receives *text* with
|
|
24
|
+
`extras` in its body, and the user's bubble shows `displayText` (as with
|
|
25
|
+
`onBeforeSend`'s, which wins when it gives one). It resolves to what
|
|
26
|
+
became of the message: `'sent'` once the backend takes it, `'steered'`,
|
|
27
|
+
`'held'`, `'dropped'` (empty, taken over, read-only, or the panel
|
|
28
|
+
unmounted first) or `'failed'` (the backend refused it).
|
|
29
|
+
- `newConversation`, `selectConversation`, `setDraft`, `focusComposer` and
|
|
30
|
+
`stop`.
|
|
31
|
+
- `getDraft()` reads the composer's text as it stands (typed, or set by
|
|
32
|
+
`setDraft`), e.g. for a host taking over a held message (`draft.held`)
|
|
33
|
+
to tell whether the composer still holds what was typed.
|
|
34
|
+
- `scrollToMessage` jumps to a message and highlights it.
|
|
35
|
+
- `reloadAgents()` reads the agent list again, keeping the agent picked
|
|
36
|
+
unless it is gone (none is picked once the list is empty). A failed
|
|
37
|
+
reload keeps the list it had, and only the latest reload lands.
|
|
38
|
+
- `startVoiceCall()` starts a voice call (below).
|
|
39
|
+
- `onClose` and `onModeChange` are optional: the header shows the close
|
|
40
|
+
button and the view switcher only when they are given.
|
|
41
|
+
- `storageKeyPrefix` namespaces every key the panel keeps in browser storage,
|
|
42
|
+
for a host that mounts more than one panel.
|
|
43
|
+
- `readOnly` hides the composer, with `readOnlyNotice` in its place, and
|
|
44
|
+
the panel then sends nothing, from the handle or the welcome screen's
|
|
45
|
+
suggestions.
|
|
46
|
+
- `getRequestExtras` adds the host's own fields to each message body (the
|
|
47
|
+
panel's own fields, set by it or not, are never taken from there), and
|
|
48
|
+
`onStreamEvent` hands the host every frame received, including those the
|
|
49
|
+
panel does not render, with what the panel read in it: `end`
|
|
50
|
+
(`'provisional'` on an `error` or `cancelled` marked `provisional: true`,
|
|
51
|
+
`'stored'` on an end naming the stored answer's `message_id`: a
|
|
52
|
+
`done` that is not intermediate, a `cancelled`, an `error`) and `replayed`
|
|
53
|
+
(the `thinking` frame of a turn replayed from its start, `resumed: true`).
|
|
54
|
+
- The panel renders the frames of a backend whose turns outlive their stream:
|
|
55
|
+
a turn re-attached mid-way (`thinking.resumed`), an announced wait
|
|
56
|
+
(`status: wait_start`, with a countdown, kept through what it reports
|
|
57
|
+
meanwhile: `wait_status`, `tool_heartbeat`, `tool_progress`,
|
|
58
|
+
`consult_progress`; streamed text or any other status ends it), `cancelled`,
|
|
59
|
+
an intermediate `done` and the agent that `answered_by` a segment. A
|
|
60
|
+
provisional end (an `error` or `cancelled` marked `provisional: true`; any
|
|
61
|
+
other is final) ends the turn at once; the stored end that follows gives the
|
|
62
|
+
answer its id and a `done`'s content.
|
|
63
|
+
- History is restored with no agent list (`apiEndpoints.agents: null`).
|
|
64
|
+
- A host can render its own cards for the `[[KIND:args]]` markers of an
|
|
65
|
+
answer (`markerRenderers`), by marker name, and take over the built-in
|
|
66
|
+
`FILE`, `PRESENTATION`, `REPORT` and `VIDEO` ones, including the items an
|
|
67
|
+
answer carries with no marker. A card that throws, or a renderer that does,
|
|
68
|
+
shows `This item could not be loaded.` and leaves the rest of the answer
|
|
69
|
+
alone. A marker no renderer names stays text, as before.
|
|
70
|
+
- `transformMessageText` rewrites a message's text before it is shown, copied
|
|
71
|
+
or read aloud (masking secrets, converting a channel's syntax); one that
|
|
72
|
+
throws leaves the text as it came.
|
|
73
|
+
- `codeBlockRenderers` renders a fenced code block of a language the host
|
|
74
|
+
names (`(code, { streaming }) => ReactNode`, matched case-insensitively) in
|
|
75
|
+
place of the code block, e.g. a chart drawn from the block's data. A
|
|
76
|
+
renderer that throws shows `This item could not be loaded.`, as a marker
|
|
77
|
+
card does; a language no renderer names, or a renderer returning `null`,
|
|
78
|
+
stays a code block.
|
|
79
|
+
- `onArtifactOpen` opens a deck, report or video in the host, in place of the
|
|
80
|
+
link to XTM One.
|
|
81
|
+
- Slots for the host's own content: `headerActions`, `banner`,
|
|
82
|
+
`composerHeader`, `transcriptFooter`, `welcome`, `renderMessageExtras` and
|
|
83
|
+
`messageFooterActions` (given the message and `{ streaming }`,
|
|
84
|
+
`ChatMessageSlotContext`: the message is the answer still being written),
|
|
85
|
+
`sidebarRowActions`, `sidebarHeaderActions` and `sidebarSections`.
|
|
86
|
+
- `statusLabel`, `waitingMessages` and `renderWaitingPanel` adapt the status
|
|
87
|
+
line and the waiting panel; `fontFamily` sets the panel's font.
|
|
88
|
+
- An agent's `icon` shows in the picker when it is an `https:` or
|
|
89
|
+
`data:image/` URL, or emoji, and agents carrying a `group` are listed under
|
|
90
|
+
its heading.
|
|
91
|
+
- `@` in the composer can mention agents (`agentMentions`): the agents of
|
|
92
|
+
the agent list are offered above the conversations, and the message carries
|
|
93
|
+
the ids of those it still mentions as `mentioned_agent_ids`, in mention
|
|
94
|
+
order. A message that mentions an agent never steers the running turn.
|
|
95
|
+
- `steerAttachments` lets uploaded files steer the running turn (the steer
|
|
96
|
+
route then takes `file_ids`), and `holdSendsDuringTurn` holds a message that
|
|
97
|
+
cannot steer (files, references, mentions, body fields of its own, a turn
|
|
98
|
+
that has just ended) and sends it as the next turn, with a way to cancel it
|
|
99
|
+
meanwhile. Messages held one after another go together, keeping their body
|
|
100
|
+
fields, and Stop gives back to the composer what the user typed for them;
|
|
101
|
+
a message sent once the stopped turn ended goes out as it winds down.
|
|
102
|
+
- A voice call over the panel, started with `startVoiceCall()` on the handle
|
|
103
|
+
(`voiceCallSupported()` tells a host whether to offer it): the browser's
|
|
104
|
+
speech recognition listens, a phrase is sent after one second of silence
|
|
105
|
+
(`onBeforeSend` sees `source: 'voice'`, a `ChatSendDraft.source` of its
|
|
106
|
+
own), and the answer is said through `apiEndpoints.tts` in pieces of about
|
|
107
|
+
200 characters, each requested while the one before plays, in the browser's
|
|
108
|
+
voice where the route fails, the browser cannot play a piece, or no route is
|
|
109
|
+
named. Only the final answer of the turn that answers the question is said
|
|
110
|
+
(the panel's own, or the one a fold or a steer names), and only the
|
|
111
|
+
addressed agent's: the other agents' replies show by name, `Did not answer`
|
|
112
|
+
beside a failed one. Speaking over the answer, a tap or Skip stops it; a tap
|
|
113
|
+
while it is awaited cancels the question and its turn, as `stop()` does; a turn silent for 120 s is checked through
|
|
114
|
+
`apiEndpoints.pendingApprovals` and given up on once over.
|
|
115
|
+
- Stable `data-testid`s for host tests: `filigran-chat-panel`,
|
|
116
|
+
`filigran-chat-transcript`, `filigran-chat-user-message`,
|
|
117
|
+
`filigran-chat-assistant-message`, `filigran-chat-composer`,
|
|
118
|
+
`filigran-chat-approval`, `filigran-chat-disclaimer`.
|
|
119
|
+
- `onReady` tells the host when the panel has chosen its agent and read back
|
|
120
|
+
the conversation on screen; calls through the handle made before then wait
|
|
121
|
+
for it, and all of them run in order (a new conversation's agent is in
|
|
122
|
+
place before the send that follows it).
|
|
123
|
+
- `onBeforeSend` sees every send first, from the composer or the handle: it
|
|
124
|
+
can take a send over, or reword it and add fields to its body. It can also
|
|
125
|
+
return `displayText`: the backend receives `text`, and the user's bubble
|
|
126
|
+
(live, steered or held) shows `displayText`, for a host that wraps what the
|
|
127
|
+
user typed in context of its own. A message held while a turn ran is asked
|
|
128
|
+
about again as it leaves (`turnRunning: false`, `held: true`), each send
|
|
129
|
+
held with it on its own; taken over then, what the user typed for it goes
|
|
130
|
+
back to the composer, after what they typed since, and a message all of
|
|
131
|
+
whose sends are taken over is settled `'returned'`.
|
|
132
|
+
- `hideConversationList` hides the conversation list of inline and fullscreen
|
|
133
|
+
modes, for a rail or a task pane: the header, thread and composer hold from
|
|
134
|
+
320 px wide, and the header's history menu stands in for the list (open,
|
|
135
|
+
delete, Clear all), while a referenced conversation still opens in the panel.
|
|
136
|
+
- `onHeldSendSettled(text, outcome)` tells the host what became of a message
|
|
137
|
+
held until the turn ended: `'sent'`, `'failed'`, `'dropped'`, `'returned'`
|
|
138
|
+
(given back to the composer by Stop, or by `onBeforeSend` taking it over as
|
|
139
|
+
it leaves; told once the composer shows it, so `getDraft()` reads it) or
|
|
140
|
+
`'cancelled'`.
|
|
141
|
+
- `onTurnRunningChange(running, info)` tells the host when a turn starts or
|
|
142
|
+
stops running, own or relayed, and with `false` how it ended
|
|
143
|
+
(`info.ended`: `'answered'`, `'stopped'` or `'failed'`): see
|
|
144
|
+
[Host extensions](README.md#host-extensions) and
|
|
145
|
+
[Turns that outlive their stream](README.md#turns-that-outlive-their-stream).
|
|
146
|
+
- `ChatMessage.answeredBy` (`{ agentId, agentName, agentIcon }`) and
|
|
147
|
+
`ChatMessage.mentionFailed`, from the `answered_by` and `mention_failed` of
|
|
148
|
+
each `done` frame (intermediate ones included) and of each restored entry,
|
|
149
|
+
for a host's own rendering of a turn several agents answer. The panel's own
|
|
150
|
+
rendering is unchanged.
|
|
151
|
+
- A `session_expired` frame on the message stream or the event stream ends
|
|
152
|
+
the turn on screen at once, keeping what it wrote.
|
|
153
|
+
- `@filigran/chatbot/markdown` also exports the answer-marker helpers the
|
|
154
|
+
panel reads markers with: `splitAnswerMarkers`, `stripAnswerMarkers`,
|
|
155
|
+
`markerKinds` and the `AnswerPart` type (and `ChatArtifactKind`), still free
|
|
156
|
+
of React and side effects, so a host renders, previews or strips markers
|
|
157
|
+
exactly as the panel does.
|
|
158
|
+
- `onSessionEnded(reason)` tells the host the user's session ended: a
|
|
159
|
+
`session_expired` frame on either stream, or a `401` whose body's
|
|
160
|
+
`detail.code` is `session_expired` on any request the panel makes, with the
|
|
161
|
+
frame's or the `detail`'s `reason`. It comes once per set of
|
|
162
|
+
`requestHeaders`.
|
|
163
|
+
- `ChatMessage.raw`: the backend's own object for the message, a plain copy
|
|
164
|
+
(the restored, paged or relayed entry; the `done` frame of a live answer,
|
|
165
|
+
or the stored end after a provisional one), for the fields the panel does
|
|
166
|
+
not read.
|
|
167
|
+
- `@filigran/chatbot/workspaces`, a React-free entry point with the panel's
|
|
168
|
+
grouping of a conversation list by workspace: `parseWorkspaces` (which,
|
|
169
|
+
given `userId`, tells the caller's own workspaces by `user_id` where the
|
|
170
|
+
backend sends no `is_own`), `sortWorkspaces`, `groupConversations`
|
|
171
|
+
(generic over the host's conversation and workspace types),
|
|
172
|
+
`fileableWorkspaces`, `groupIsOpen`, `groupCanToggle`, `ELSEWHERE_GROUP`
|
|
173
|
+
and the `WorkspaceGroup`, `GroupableConversation` and `ChatWorkspace` types.
|
|
174
|
+
- `prepareMarkdown` on `@filigran/chatbot/markdown`: the panel's markdown
|
|
175
|
+
normalisation in its order, for a host's own markdown component.
|
|
176
|
+
- `waitingGameUrl` says where the waiting panel's invitation to play leads
|
|
177
|
+
(an http(s) URL or a path of the host's origin), over
|
|
178
|
+
`{agentDashboardUrl}/chat?arcade=play`.
|
|
179
|
+
- New exported types: `ChatPanelHandle`, `ChatPanelMode`, `ChatSendOptions`,
|
|
180
|
+
`ChatSendOutcome`, `ChatSendDraft`, `ChatSendDecision`, `ChatHeldOutcome`,
|
|
181
|
+
`ChatTurnEnd`, `ChatTurnOutcome`, `ChatMarkerRenderer`, `ChatMarkerContext`,
|
|
182
|
+
`ChatCodeBlockRenderer`, `ChatCodeBlockContext`, `ChatStreamEventInfo`,
|
|
183
|
+
`ChatMessageSlotContext`, `ChatAnsweredBy` and `AgentStatusState`.
|
|
184
|
+
|
|
185
|
+
### Changed
|
|
186
|
+
|
|
187
|
+
- The panel ships its own translations (es, fr, ja, beside English) and
|
|
188
|
+
speaks `locale`'s language without the host translating anything. `t` is
|
|
189
|
+
now an override: the host's wording wins where it translates a key, the
|
|
190
|
+
panel's catalog answers where it returns the key. A host translating every
|
|
191
|
+
key, as before, sees no change. `ChatToggleButton` takes `locale` too.
|
|
192
|
+
A host that passes `t` but no `locale` keeps the panel in English where its
|
|
193
|
+
`t` returns the key; a host passing neither now gets the browser's
|
|
194
|
+
language where the panel has it, rather than English.
|
|
195
|
+
- A stopped answer says `Stopped`, rather than vanishing when nothing was
|
|
196
|
+
written yet.
|
|
197
|
+
- The Send, attach, close and view-switcher buttons have accessible names.
|
|
198
|
+
- Files dragged over the thread attach on drop (wherever uploads are on), and
|
|
199
|
+
the drop does not reach the host's own drop zones.
|
|
200
|
+
- A conversation being read back shows a skeleton rather than the welcome
|
|
201
|
+
screen.
|
|
202
|
+
- A conversation whose restore fails because the backend is unreachable or
|
|
203
|
+
answers 502, 503 or 504 keeps its id, rather than being dropped for a new
|
|
204
|
+
chat, and is read back once the backend answers (retried with backoff, and
|
|
205
|
+
at once when the browser is back online or the page is shown again, never
|
|
206
|
+
over a turn in progress); any other error still resets it.
|
|
207
|
+
- A conversation whose restore answers 401 or 403 (expired credentials) keeps
|
|
208
|
+
its id too, rather than being dropped for a new chat (a host's `?c=`
|
|
209
|
+
survives): the panel shows the response's `detail` (or `This conversation
|
|
210
|
+
could not be loaded.`) with a Retry button, and reads the conversation back
|
|
211
|
+
as soon as `requestHeaders` change.
|
|
212
|
+
- A message the backend refuses before streaming (a non-2xx answer) shows the
|
|
213
|
+
response's `detail` (a string, or the `message` or `detail` of an object)
|
|
214
|
+
instead of `Unable to connect. Please check the configuration.`, which stays
|
|
215
|
+
for a refusal that says nothing; `send` still resolves `'failed'`.
|
|
216
|
+
- The stylesheet declares Tailwind's theme variables (`--color-*`,
|
|
217
|
+
`--radius-*`, `--shadow-*`, ...) on the panel root only, no longer on
|
|
218
|
+
`:root` and `:host`, so loading it never redeclares a host's own variables;
|
|
219
|
+
the `@property` fallbacks of browsers without it are kept to the panel's
|
|
220
|
+
elements too. A host element outside the panel no longer inherits them.
|
|
221
|
+
- A fenced code block's language label shows the whole language
|
|
222
|
+
(`objective-c`, not `objective`).
|
|
223
|
+
- A long agent name in the header is cut short rather than pushing the
|
|
224
|
+
header's controls off a narrow panel.
|
|
225
|
+
- A steer the backend refuses shows the refusal's `detail` above the composer,
|
|
226
|
+
the text going back to the composer as before; a `409` (the turn has just
|
|
227
|
+
ended, an ordinary race) shows nothing. A steer stored that the backend
|
|
228
|
+
says no turn will answer (`"answered": false`) stays, with a notice that it
|
|
229
|
+
will be read with the next message, until that send.
|
|
230
|
+
- The composer's footer under a message that waits for the running turn
|
|
231
|
+
(a reference, a mention) says `This message waits for the current response`,
|
|
232
|
+
a new key, in place of `Referenced conversations wait for the current
|
|
233
|
+
response`.
|
|
234
|
+
|
|
235
|
+
### Fixed
|
|
236
|
+
|
|
237
|
+
- A conversation read back after the user has already sent a message no
|
|
238
|
+
longer replaces that turn: its history joins the thread in place once the
|
|
239
|
+
turn ends (a stored message missing from the screen after the one stored
|
|
240
|
+
before it), and its agent's name shows at once.
|
|
241
|
+
- Sending no longer throws on a page served over plain http, where
|
|
242
|
+
`crypto.randomUUID` does not exist.
|
|
243
|
+
|
|
244
|
+
### Host opt-in
|
|
245
|
+
|
|
246
|
+
- `apiEndpoints.cancel` (no default): Stop asks the backend to end the turn and
|
|
247
|
+
waits for the stream's `cancelled` frame, instead of dropping the stream. An
|
|
248
|
+
answer of `{ "turn": "none" }` lets go of the turn at once and reads the
|
|
249
|
+
conversation back, unless the Stop went before the panel's own send started
|
|
250
|
+
its turn: it then carries `"awaiting_send": true`, and on `none` stays
|
|
251
|
+
pending and is sent again, without the flag, as the turn starts; any other
|
|
252
|
+
answer reached a turn, and nothing goes again. A refused Stop (e.g. `503`)
|
|
253
|
+
keeps the turn running and says why above the composer; the status line
|
|
254
|
+
keeps what the turn reported since the click.
|
|
255
|
+
- `apiEndpoints.skipWait` (no default): `Continue now` on an agent's wait.
|
|
256
|
+
- `apiEndpoints.events` (no default): the panel follows the conversation's
|
|
257
|
+
event stream and renders turns started in another tab or before a reload,
|
|
258
|
+
user messages sent elsewhere, new titles and approvals answered elsewhere;
|
|
259
|
+
a panel whose own stream drops mid-turn picks the turn up from it, keeping
|
|
260
|
+
the segments it closed. Stop during the handover ends the turn. A relayed
|
|
261
|
+
turn the stream let go of while the page was hidden holds sends, and runs
|
|
262
|
+
on for `onTurnRunningChange`, until the reopened stream replays it, or, 5 s
|
|
263
|
+
after the page shows again or at once on a refused stream, until the
|
|
264
|
+
conversation read back says how it ended. Every frame of a turn names it
|
|
265
|
+
(`turn_id`): on the event stream, and on the message stream from its
|
|
266
|
+
`turn_started` on; an event stream frame of a turn naming none is not read,
|
|
267
|
+
and the console warns of it once per frame type. See
|
|
268
|
+
[Turns that outlive their stream](README.md#turns-that-outlive-their-stream)
|
|
269
|
+
for reconnection, the client id and replays.
|
|
270
|
+
- With `cancel`, `skipWait` or `events` named, a send made while a turn ended
|
|
271
|
+
provisionally still winds down is held, as during a turn, until its stored
|
|
272
|
+
end or its stream's close (the panel's own, for its own turn; another turn
|
|
273
|
+
starting ends it too), at most 5 s: the backend still holds the
|
|
274
|
+
conversation, and the message would join the ending turn unanswered. A
|
|
275
|
+
relayed turn winds down across the event stream's reopening.
|
|
276
|
+
- With `cancel`, `skipWait` or `events` named, a new chat's conversation is
|
|
277
|
+
created before its first message, so Stop, "Continue now" and steering
|
|
278
|
+
reach the backend from the first turn.
|
|
279
|
+
- `apiEndpoints.messagesPage` (no default): "Load earlier messages" fetches
|
|
280
|
+
older messages from the backend a page at a time, when the restore says
|
|
281
|
+
there are some (`has_more`), and keeps the reader where they were.
|
|
282
|
+
- `apiEndpoints.clearAll` (no default): the conversation list and the
|
|
283
|
+
header's history menu offer "Clear all conversations", confirmed first.
|
|
284
|
+
- `apiEndpoints.tts` (no default): read aloud uses the backend's voice, a
|
|
285
|
+
long answer in several bounded requests played in turn, and the browser's
|
|
286
|
+
voice for what is left when the route fails.
|
|
287
|
+
|
|
11
288
|
## 3.14.0 — 2026-10-19
|
|
12
289
|
|
|
13
290
|
### Added
|