@filigran/chatbot 3.5.2 β 3.6.1
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/README.md +130 -1
- package/dist/index.d.ts +66 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,8 @@ Filigran chat panel β a standalone React + Tailwind chatbot component with SSE
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- π **SSE Message Streaming** β Real-time response streaming with status indicators
|
|
8
|
+
- β‘ **Mid-Run Steering** β Send messages while the agent is generating; they are injected into the running agentic loop instead of waiting for the turn to finish
|
|
9
|
+
- ποΈ **Conversation History** β Switch between (and delete) past conversations from a history menu in the header
|
|
8
10
|
- π€ **Multi-Agent Support** β Switch between different AI agents
|
|
9
11
|
- π **File Attachments** β Upload and paste files (PDF, TXT, images)
|
|
10
12
|
- π₯ **Agent-Generated Files** β Renders downloadable file cards from agent output and strips the `[[FILE:id]]` markers from the prose
|
|
@@ -192,6 +194,37 @@ even though streaming downloads work:
|
|
|
192
194
|
}
|
|
193
195
|
```
|
|
194
196
|
|
|
197
|
+
### `GET {apiBaseUrl}/chat/sessions`
|
|
198
|
+
|
|
199
|
+
Lists the user's past conversations for the history menu in the chat header.
|
|
200
|
+
|
|
201
|
+
**Response** (a bare array or `{ "conversations": [...] }`):
|
|
202
|
+
|
|
203
|
+
```json
|
|
204
|
+
[
|
|
205
|
+
{
|
|
206
|
+
"conversation_id": "uuid-here",
|
|
207
|
+
"title": "What is the weather?",
|
|
208
|
+
"updated_at": "2026-06-10T08:30:00Z",
|
|
209
|
+
"message_count": 12
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Selecting a conversation restores it through the existing
|
|
215
|
+
`POST /chat/sessions` contract above. The endpoint is fetched lazily when the
|
|
216
|
+
history menu opens; a backend that doesn't implement it yet (404/405) simply
|
|
217
|
+
yields an empty list, so the menu shows its empty state instead of breaking
|
|
218
|
+
the chat. Set `apiEndpoints.history` to `null` to hide the history menu
|
|
219
|
+
entirely, or point it at a dedicated path if your proxy can't route `GET` on
|
|
220
|
+
the sessions path.
|
|
221
|
+
|
|
222
|
+
### `DELETE {apiBaseUrl}/chat/sessions/{conversation_id}`
|
|
223
|
+
|
|
224
|
+
Deletes a conversation from the history menu. Any 2xx response counts as
|
|
225
|
+
success; deleting the active conversation resets the panel to a fresh chat so
|
|
226
|
+
the next message never targets a dead conversation id.
|
|
227
|
+
|
|
195
228
|
### `POST {apiBaseUrl}/chat/messages`
|
|
196
229
|
|
|
197
230
|
Sends a message and streams the response via SSE.
|
|
@@ -223,9 +256,40 @@ data: {"type": "status", "status": "analyzing"}
|
|
|
223
256
|
data: {"type": "status", "status": "streaming"}
|
|
224
257
|
data: {"type": "stream", "content": "The weather "}
|
|
225
258
|
data: {"type": "stream", "content": "today is sunny."}
|
|
226
|
-
data: {"type": "done", "content": "The weather today is sunny.", "conversation_id": "new-uuid", "tool_names": ["search_web"], "tool_call_count": 1, "iterations": 1}
|
|
259
|
+
data: {"type": "done", "content": "The weather today is sunny.", "conversation_id": "new-uuid", "tool_names": ["search_web"], "tool_call_count": 1, "iterations": 1, "reasoning": "Let me check the weather data first.", "tool_call_trace": [{"name": "search_web", "input": "{\"query\": \"weather\"}", "output": "Sunny, 24C", "success": true}], "transfer_chain": [{"agent_id": "uuid", "agent_name": "General"}], "is_truncated": false}
|
|
227
260
|
```
|
|
228
261
|
|
|
262
|
+
The optional `reasoning` field on `done` (and on restored session messages)
|
|
263
|
+
carries the accumulated model reasoning / pre-tool preamble prose for the
|
|
264
|
+
turn. When present it is surfaced in the per-message reasoning-details dialog
|
|
265
|
+
(the "i" button), mirroring the XTM One web chat.
|
|
266
|
+
|
|
267
|
+
The reasoning-details dialog also consumes three more optional `done` fields
|
|
268
|
+
(all parsed defensively β older backends without them fall back to the flat
|
|
269
|
+
tool-name list and the plain "i" affordance):
|
|
270
|
+
|
|
271
|
+
- `tool_call_trace` β array of `{ name, input, output, success }` entries
|
|
272
|
+
rendered as expandable rows (numbered, success/failure icon, pretty-printed
|
|
273
|
+
JSON input, output)
|
|
274
|
+
- `transfer_chain` β array of `{ agent_id, agent_name }` hops rendered as the
|
|
275
|
+
agent transfer chain
|
|
276
|
+
- `is_truncated` β `true` when the agent's iteration budget was exhausted;
|
|
277
|
+
the message then shows an always-visible amber warning triangle instead of
|
|
278
|
+
the hover-only "i" and the dialog opens with a "Turn limit reached" banner
|
|
279
|
+
|
|
280
|
+
The same fields are read from restored session messages, so the dialog
|
|
281
|
+
survives a page reload.
|
|
282
|
+
|
|
283
|
+
#### Internal links
|
|
284
|
+
|
|
285
|
+
Assistant markdown links are routed through `onRelativeLinkClick` when they
|
|
286
|
+
are **internal to the host application**: relative hrefs (`/dashboard/...`)
|
|
287
|
+
and absolute http(s) hrefs on the **same origin** as the embedding page
|
|
288
|
+
(backends emit absolute links so they work from any chat surface β when the
|
|
289
|
+
chatbot is embedded in that very platform, e.g. the OpenCTI link inside
|
|
290
|
+
OpenCTI, the link is reduced to `pathname + search + hash` and navigates
|
|
291
|
+
in-app instead of opening a new tab). All other links open in a new tab.
|
|
292
|
+
|
|
229
293
|
#### Agent-generated file attachments
|
|
230
294
|
|
|
231
295
|
When an agent produces a downloadable file, the `done` event carries an `attachments` array and the streamed prose embeds `[[FILE:<file_id>]]` markers. The component strips those markers and renders a download card per attachment:
|
|
@@ -257,9 +321,11 @@ Download failures (403/404/5xx/network) are reported through the optional `onDow
|
|
|
257
321
|
|
|
258
322
|
- `thinking` β Agent is processing
|
|
259
323
|
- `tool_start` β Agent is using tools (with `tools` array)
|
|
324
|
+
- `tool_heartbeat` β Liveness signal during a long tool execution (with `tools` and `elapsed_s`). The widget keeps the current status label and renders a live elapsed-time indicator next to it once the execution exceeds ~15 s, so long operations (background tasks, agent consults) never look stuck
|
|
260
325
|
- `analyzing` β Agent is analyzing tool results
|
|
261
326
|
- `composing` β Agent is composing the response
|
|
262
327
|
- `streaming` β Content is being streamed
|
|
328
|
+
- `steering` β A mid-run steering message is being incorporated (see below)
|
|
263
329
|
|
|
264
330
|
**Error event:**
|
|
265
331
|
|
|
@@ -267,6 +333,51 @@ Download failures (403/404/5xx/network) are reported through the optional `onDow
|
|
|
267
333
|
data: {"type": "error", "content": "Something went wrong"}
|
|
268
334
|
```
|
|
269
335
|
|
|
336
|
+
### `POST {apiBaseUrl}/chat/messages/steer`
|
|
337
|
+
|
|
338
|
+
Steers the agent mid-run: while a response is still streaming, Enter / the
|
|
339
|
+
accent Send button dispatches the typed text immediately instead of blocking
|
|
340
|
+
until the turn finishes. The widget POSTs:
|
|
341
|
+
|
|
342
|
+
```json
|
|
343
|
+
{
|
|
344
|
+
"conversation_id": "uuid-here",
|
|
345
|
+
"content": "Actually, filter by subregion instead",
|
|
346
|
+
"agent_slug": "general"
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
A 2xx response means the message was persisted and will be injected into the
|
|
351
|
+
running agentic loop at the next iteration boundary. On a non-2xx response or
|
|
352
|
+
a network error the optimistic user bubble is rolled back and the text is
|
|
353
|
+
restored into the composer (prepended on its own line if the user already
|
|
354
|
+
typed something new) β so a backend without steering support degrades
|
|
355
|
+
gracefully and the message is never silently lost. Set `apiEndpoints.steer`
|
|
356
|
+
to `null` to disable the steering affordances entirely.
|
|
357
|
+
|
|
358
|
+
Steering only applies to text-only sends on the `rest` backend with a known
|
|
359
|
+
`conversation_id` (the first turn of a fresh conversation only receives its id
|
|
360
|
+
on `done`). Sends with attachments keep the legacy wait behavior. Esc stops
|
|
361
|
+
generating.
|
|
362
|
+
|
|
363
|
+
#### Multi-segment responses
|
|
364
|
+
|
|
365
|
+
A steered turn can produce **multiple response segments** on one SSE stream:
|
|
366
|
+
when the steering message arrives too late to be folded into the current
|
|
367
|
+
pass, the backend completes the current segment (an intermediate `done`
|
|
368
|
+
event) and then runs a follow-up pass for the steering message (a fresh
|
|
369
|
+
`thinking` status followed by more `stream` events and a final `done`). The
|
|
370
|
+
widget renders each segment as its own assistant message:
|
|
371
|
+
|
|
372
|
+
```
|
|
373
|
+
data: {"type": "status", "status": "steering"}
|
|
374
|
+
data: {"type": "stream", "content": "...current answer keeps streaming..."}
|
|
375
|
+
data: {"type": "done", "content": "First segment answer", "conversation_id": "uuid"}
|
|
376
|
+
data: {"type": "status", "status": "thinking"}
|
|
377
|
+
data: {"type": "stream", "content": "Follow-up answer to the steering message"}
|
|
378
|
+
data: {"type": "done", "content": "Follow-up answer to the steering message", "conversation_id": "uuid"}
|
|
379
|
+
```
|
|
380
|
+
|
|
270
381
|
## Customization
|
|
271
382
|
|
|
272
383
|
### Custom Logo
|
|
@@ -321,15 +432,33 @@ function App() {
|
|
|
321
432
|
- `'Using toolsβ¦'`
|
|
322
433
|
- `'Analyzing resultsβ¦'`
|
|
323
434
|
- `'Composing answerβ¦'`
|
|
435
|
+
- `'Incorporating your messageβ¦'`
|
|
324
436
|
- `'Ask a question...'`
|
|
325
437
|
- `'Stop generating'`
|
|
438
|
+
- `'Send now'`
|
|
439
|
+
- `'Enter to send now Β· Esc to stop'`
|
|
440
|
+
- `'Attachments wait for the current response'`
|
|
326
441
|
- `'New chat'`
|
|
442
|
+
- `'Conversation history'`
|
|
443
|
+
- `'No conversations yet'`
|
|
444
|
+
- `'Untitled conversation'`
|
|
445
|
+
- `'New conversation'`
|
|
446
|
+
- `'Delete conversation'`
|
|
447
|
+
- `'just now'` / `'m ago'` / `'h ago'` / `'d ago'`
|
|
327
448
|
- `'Switch view'`
|
|
328
449
|
- `'Close'`
|
|
329
450
|
- `'Switch to another agent'`
|
|
330
451
|
- `'Browse agents'`
|
|
331
452
|
- `'Create agent'`
|
|
332
453
|
- `'Reasoning details'`
|
|
454
|
+
- `'Reasoning details β turn limit reached'`
|
|
455
|
+
- `'Model reasoning'`
|
|
456
|
+
- `'iterations'`
|
|
457
|
+
- `'transfer'` / `'transfers'`
|
|
458
|
+
- `'Transfer chain'`
|
|
459
|
+
- `'Turn limit reached.'`
|
|
460
|
+
- `"The agent's iteration budget was exhausted - execution stopped before completing all planned steps. The final response is a best-effort summary of work done so far."`
|
|
461
|
+
- `'Input'` / `'Output'` / `'(no output)'`
|
|
333
462
|
- `'Download'`
|
|
334
463
|
- `'tool call'` / `'tool calls'`
|
|
335
464
|
- `'Uses AI. Verify results.'`
|
package/dist/index.d.ts
CHANGED
|
@@ -12,10 +12,29 @@ interface ApiEndpoints {
|
|
|
12
12
|
singleEndpoint?: boolean;
|
|
13
13
|
/** Path for sending messages. Default: '/chat/messages' */
|
|
14
14
|
messages?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Path for steering the agent mid-run (sending a message while a response
|
|
17
|
+
* is still streaming). Default: '/chat/messages/steer'. The widget POSTs
|
|
18
|
+
* `{ conversation_id, content, agent_slug }`; a 2xx response means the
|
|
19
|
+
* message was persisted and will be injected into the running agentic loop
|
|
20
|
+
* at the next iteration boundary. On a non-2xx response the optimistic
|
|
21
|
+
* bubble is rolled back and the text is restored into the composer, so a
|
|
22
|
+
* backend without steering support degrades gracefully. Set to null to
|
|
23
|
+
* disable mid-run steering entirely.
|
|
24
|
+
*/
|
|
25
|
+
steer?: string | null;
|
|
15
26
|
/** Path for fetching agents. Default: '/chat/agents'. Set to null to disable. */
|
|
16
27
|
agents?: string | null;
|
|
17
28
|
/** Path for fetching session history. Default: '/chat/sessions'. Set to null to disable. */
|
|
18
29
|
sessions?: string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Path for the multi-conversation history menu. Defaults to the sessions
|
|
32
|
+
* path: the widget lists past conversations via `GET {history}` and deletes
|
|
33
|
+
* one via `DELETE {history}/{conversation_id}`. Set to null to hide the
|
|
34
|
+
* history menu (e.g. when the backend only implements the session-restore
|
|
35
|
+
* POST contract).
|
|
36
|
+
*/
|
|
37
|
+
history?: string | null;
|
|
19
38
|
/** Path for uploading files. Default: '/chat/upload'. Set to null to disable file uploads. */
|
|
20
39
|
upload?: string | null;
|
|
21
40
|
/**
|
|
@@ -128,6 +147,39 @@ interface ChatMessage {
|
|
|
128
147
|
toolNames?: string[];
|
|
129
148
|
toolCallCount?: number;
|
|
130
149
|
iterations?: number;
|
|
150
|
+
/**
|
|
151
|
+
* Accumulated model reasoning / pre-tool preamble prose for the turn
|
|
152
|
+
* (from `thinking_text` events), surfaced in the reasoning-details dialog
|
|
153
|
+
* after the answer completes β mirroring the XTM One web chat.
|
|
154
|
+
*/
|
|
155
|
+
reasoning?: string;
|
|
156
|
+
/**
|
|
157
|
+
* Per-tool-call execution trace (name, input, output, success) for the
|
|
158
|
+
* reasoning-details dialog β same shape the XTM One web chat renders as
|
|
159
|
+
* expandable rows. Optional: backends without trace support fall back to
|
|
160
|
+
* the flat `toolNames` list.
|
|
161
|
+
*/
|
|
162
|
+
toolCallTrace?: ToolCallTraceEntry[];
|
|
163
|
+
/** Agent transfer chain for the turn (reasoning-details dialog). */
|
|
164
|
+
transferChain?: TransferChainEntry[];
|
|
165
|
+
/**
|
|
166
|
+
* True when the agent's iteration budget was exhausted and the final
|
|
167
|
+
* response is a best-effort summary β surfaced as an amber warning on the
|
|
168
|
+
* reasoning-details affordance, mirroring the XTM One web chat.
|
|
169
|
+
*/
|
|
170
|
+
isTruncated?: boolean;
|
|
171
|
+
}
|
|
172
|
+
/** One tool call in the reasoning-details execution trace. */
|
|
173
|
+
interface ToolCallTraceEntry {
|
|
174
|
+
name: string;
|
|
175
|
+
input?: string;
|
|
176
|
+
output?: string;
|
|
177
|
+
success: boolean;
|
|
178
|
+
}
|
|
179
|
+
/** One hop in the agent transfer chain shown in the reasoning-details dialog. */
|
|
180
|
+
interface TransferChainEntry {
|
|
181
|
+
agentId: string;
|
|
182
|
+
agentName: string;
|
|
131
183
|
}
|
|
132
184
|
/**
|
|
133
185
|
* An agent-generated file produced during a chat turn (via the backend
|
|
@@ -162,6 +214,19 @@ interface ChatFile {
|
|
|
162
214
|
/** Upload status: 'pending' while uploading, 'done' when uploaded, 'error' on failure. */
|
|
163
215
|
uploadStatus?: 'pending' | 'done' | 'error';
|
|
164
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* A past conversation surfaced in the history menu (REST backend only).
|
|
219
|
+
* Listed via `GET {apiBaseUrl}{apiEndpoints.history ?? apiEndpoints.sessions ?? '/chat/sessions'}`
|
|
220
|
+
* β the optional `apiEndpoints.history` override takes precedence when the
|
|
221
|
+
* proxy cannot route GET/DELETE on the sessions path.
|
|
222
|
+
*/
|
|
223
|
+
interface ChatConversationSummary {
|
|
224
|
+
conversationId: string;
|
|
225
|
+
title: string;
|
|
226
|
+
/** ISO timestamp of the last activity, used for the relative-time label. */
|
|
227
|
+
updatedAt?: string;
|
|
228
|
+
messageCount?: number;
|
|
229
|
+
}
|
|
165
230
|
interface XtmAgent {
|
|
166
231
|
id: string;
|
|
167
232
|
name: string;
|
|
@@ -180,4 +245,4 @@ interface TransferredAgent {
|
|
|
180
245
|
}
|
|
181
246
|
|
|
182
247
|
export { ChatPanel, ChatToggleButton };
|
|
183
|
-
export type { ApiEndpoints, BackendType, ChatAttachment, ChatFile, ChatMessage, ChatMode, ChatPanelProps, ChatToggleButtonProps, TransferredAgent, XtmAgent };
|
|
248
|
+
export type { ApiEndpoints, BackendType, ChatAttachment, ChatConversationSummary, ChatFile, ChatMessage, ChatMode, ChatPanelProps, ChatToggleButtonProps, TransferredAgent, XtmAgent };
|