@filigran/chatbot 3.7.4 → 3.9.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/dist/index.d.ts CHANGED
@@ -1,7 +1,17 @@
1
1
  import { FunctionComponent } from 'react';
2
2
 
3
3
  type ChatMode = 'sidebar' | 'floating' | 'fullscreen';
4
+ /**
5
+ * The host's translation lookup, passed down to every component that renders
6
+ * text. Key in, translated string out — the package never owns a dictionary of
7
+ * its own, and never asks the host's `t` for more than a lookup: values are
8
+ * spliced into the *translated* sentence by `translate()` in `utils`, so a key
9
+ * is always a whole sentence and a locale stays free to reorder it.
10
+ */
11
+ type Translate = (key: string) => string;
4
12
  type BackendType = 'legacy' | 'rest' | 'ag-ui';
13
+ /** A user's rating of one assistant answer. */
14
+ type MessageFeedback = 'up' | 'down';
5
15
  /**
6
16
  * Custom API endpoint configuration.
7
17
  * When using single endpoint mode (like OpenCTI's /chatbot), set singleEndpoint to true
@@ -23,6 +33,46 @@ interface ApiEndpoints {
23
33
  * disable mid-run steering entirely.
24
34
  */
25
35
  steer?: string | null;
36
+ /**
37
+ * Path for submitting tool-approval decisions when the agent pauses on a
38
+ * gated tool call. The widget POSTs
39
+ * `{ conversation_id, decisions: [{ tool_call_id, decision, rejection_reason }] }`
40
+ * and the paused turn resumes on the same stream with the tool result.
41
+ *
42
+ * **No default, unlike every sibling entry, and that is deliberate.** Setting
43
+ * this is what makes the widget advertise `supports_tool_approval` to the
44
+ * backend, and advertising it is a promise to answer: a backend that pauses a
45
+ * turn waits indefinitely for a decision, with no timeout and no safe default
46
+ * action to take on the reviewer's behalf. If this path defaulted to XTM
47
+ * One's own route, a host proxying the chat (OpenCTI, OpenAEV, OpenGRC) could
48
+ * upgrade the widget without adding the matching proxy route, claim support,
49
+ * receive the pause, POST the decision into a 404 — and hang the turn with
50
+ * the user watching a spinner.
51
+ *
52
+ * While unset the widget never claims support and the backend degrades to a
53
+ * plain assistant message explaining what it could not run, which is why an
54
+ * un-updated host keeps working untouched.
55
+ *
56
+ * REST backend only: `legacy` and `ag-ui` never meet this gate.
57
+ */
58
+ approve?: string | null;
59
+ /**
60
+ * Base path for recovering what a paused turn is still waiting on, read as
61
+ * `GET {apiBaseUrl}{pendingApprovals}/{conversation_id}/pending-approvals`
62
+ * (the same base-plus-suffix idiom as {@link ApiEndpoints.download}). XTM
63
+ * One serves it at `/chat/conversations`.
64
+ *
65
+ * `approval_required` is a single event on a stream, so a reload loses it —
66
+ * including the `tool_call_id`s a decision has to name. The turn is left
67
+ * waiting for an answer nobody can give, which reads as a chat that simply
68
+ * stopped replying. The panel therefore asks once per conversation on mount;
69
+ * an empty list is the ordinary answer.
70
+ *
71
+ * No default, for the same reason as {@link ApiEndpoints.approve}: a proxied
72
+ * host has to expose the route before the panel starts calling it. Unset, the
73
+ * live flow still works and only reload recovery is absent.
74
+ */
75
+ pendingApprovals?: string | null;
26
76
  /** Path for fetching agents. Default: '/chat/agents'. Set to null to disable. */
27
77
  agents?: string | null;
28
78
  /** Path for fetching session history. Default: '/chat/sessions'. Set to null to disable. */
@@ -51,6 +101,141 @@ interface ApiEndpoints {
51
101
  * unless this path is set explicitly to a proxy route.
52
102
  */
53
103
  download?: string | null;
104
+ /**
105
+ * Path for the prompt library shown in the composer toolbar.
106
+ * Default: '/chat/prompts'. Set to null to hide the affordance.
107
+ *
108
+ * Visibility is data-driven on purpose: a host that does not serve this
109
+ * route simply has no prompt button, so there is no separate "mode" to keep
110
+ * in step with what the backend actually implements.
111
+ */
112
+ prompts?: string | null;
113
+ /**
114
+ * Path for the quota indicator shown in the composer toolbar.
115
+ * Default: '/chat/quota'. Set to null to hide the affordance.
116
+ */
117
+ quota?: string | null;
118
+ /**
119
+ * Path for per-agent suggested actions shown on the welcome screen.
120
+ * Default: '/chat/suggestions'. Set to null to always use the host's
121
+ * `promptSuggestions` prop instead.
122
+ *
123
+ * Called as `GET {suggestions}?agent_slug=<slug>`. A backend that ignores
124
+ * the parameter still answers with a generic set, so the same route carries
125
+ * both today's generic suggestions and per-agent (later per-user) ones.
126
+ */
127
+ suggestions?: string | null;
128
+ }
129
+ /** A reusable prompt the user can insert into the composer. */
130
+ interface ChatPromptTemplate {
131
+ id: string;
132
+ title: string;
133
+ /** The text inserted into the composer when picked. */
134
+ content: string;
135
+ description?: string;
136
+ }
137
+ /**
138
+ * Agentic quota headroom for the current user, as the composer indicator needs
139
+ * it — deliberately just the three numbers it renders. Where the limit comes
140
+ * from (user override, group, platform, licence) is the host platform's own
141
+ * business and has no place on an embedded surface.
142
+ */
143
+ interface ChatQuotaStatus {
144
+ used: number;
145
+ /** null means unlimited — the indicator then shows usage without a bar. */
146
+ limit: number | null;
147
+ /** Human-readable period label, e.g. "monthly". */
148
+ period: string;
149
+ }
150
+ /**
151
+ * One tool call the agent wants to make and is waiting on a human to approve.
152
+ *
153
+ * `inputSchema` travels alongside `arguments` so each value can be rendered
154
+ * with the tool's own description of what it means. That pairing is the whole
155
+ * point: `cascade: true` is unjudgeable on its own, while "cascade — also
156
+ * delete linked entities" is a decision someone can actually make. A prompt
157
+ * that shows names and values alone is a rubber stamp wearing the costume of a
158
+ * safety control.
159
+ */
160
+ interface ToolApprovalProposal {
161
+ /**
162
+ * Identity of the proposed call, and the key every decision is sent back on.
163
+ * Never the tool name: one turn can propose the same tool twice with
164
+ * different arguments.
165
+ */
166
+ toolCallId: string;
167
+ /** Empty when the backend named no tool; the UI labels that case itself. */
168
+ toolName: string;
169
+ toolDescription?: string;
170
+ arguments: Record<string, unknown>;
171
+ /** JSON Schema the arguments came from, used to label each one. */
172
+ inputSchema?: Record<string, unknown>;
173
+ /** Where the tool comes from, e.g. `integration:opencti`. */
174
+ source?: string;
175
+ }
176
+ /**
177
+ * A reviewer's verdict on one proposed call.
178
+ *
179
+ * There is deliberately no "edit the arguments" verdict. Rewriting a call under
180
+ * the agent's name would leave a transcript crediting it with arguments it
181
+ * never chose, and turn a yes/no judgement into authoring. A wrong proposal is
182
+ * corrected by rejecting it with a reason the agent can act on.
183
+ */
184
+ type ToolApprovalVerdict = 'approve' | 'approve_always' | 'reject';
185
+ /** One decision, ready to be sent back to the paused turn. */
186
+ interface ToolApprovalDecision {
187
+ toolCallId: string;
188
+ verdict: ToolApprovalVerdict;
189
+ /**
190
+ * Why the call was declined. Optional, and the agent's only signal to correct
191
+ * itself — with argument editing gone, a rejection *is* the correction
192
+ * channel.
193
+ */
194
+ rejectionReason?: string;
195
+ }
196
+ /**
197
+ * How full the model's context window is for the current conversation, as the
198
+ * composer gauge needs it — a ratio, so both halves are required.
199
+ *
200
+ * `used` is the backend's own estimate of what the next turn will carry, not a
201
+ * billed token count: it is the figure the agent loop budgets its compaction
202
+ * against, which is what makes the gauge predictive of the summarising the user
203
+ * is about to see rather than a receipt for the turn that just ended.
204
+ */
205
+ interface ChatContextUsage {
206
+ /** Estimated tokens currently occupying the window. */
207
+ used: number;
208
+ /** The model's context window, in tokens. Always > 0. */
209
+ limit: number;
210
+ /** Where those tokens went, when the backend reports it. */
211
+ breakdown?: ChatContextBreakdown;
212
+ }
213
+ /**
214
+ * What the context is being spent on, in tokens.
215
+ *
216
+ * Buckets are grouped by what the user can *do* about each: they can start a new
217
+ * chat (`conversation`), they cannot shrink the agent's persona (`system`), and
218
+ * the two the backend manages on their behalf (`summary`, `toolResults`) are
219
+ * what explain a long chat that seems to have forgotten things.
220
+ *
221
+ * Every key is optional and only non-zero ones are reported, so a backend that
222
+ * measures a different set — or none — still renders. Tool definitions are
223
+ * included even though some backends may not count them in their compaction
224
+ * gate; the gauge is meant to reflect what the prompt actually carries.
225
+ */
226
+ interface ChatContextBreakdown {
227
+ /** The agent's system prompt and any in-run instructions. */
228
+ system?: number;
229
+ /** Schemas of the platform's built-in tools. */
230
+ tools?: number;
231
+ /** Schemas of the agent's own integrations, MCP servers and custom tools. */
232
+ dynamicTools?: number;
233
+ /** Digests of earlier turns produced by the backend's compaction. */
234
+ summary?: number;
235
+ /** The user's and assistant's own messages. */
236
+ conversation?: number;
237
+ /** Output of tool calls still held verbatim in the context. */
238
+ toolResults?: number;
54
239
  }
55
240
  interface ChatPanelProps {
56
241
  mode: ChatMode;
@@ -64,7 +249,7 @@ interface ChatPanelProps {
64
249
  user: {
65
250
  firstName: string;
66
251
  };
67
- t?: (key: string) => string;
252
+ t?: Translate;
68
253
  accentColor?: string;
69
254
  logoIcon?: React.ReactNode;
70
255
  promptSuggestions?: string[];
@@ -149,11 +334,49 @@ interface ChatPanelProps {
149
334
  * Receives the already-translated `title` and `body`.
150
335
  */
151
336
  onTaskComplete?: (title: string, body: string) => void;
337
+ /**
338
+ * Enables the 👍/👎 affordance on completed assistant messages and receives
339
+ * each rating. `feedback` is `null` when the user clears a previous rating.
340
+ * Omit to hide the affordance entirely — the chatbot stores nothing itself,
341
+ * so a host without a feedback endpoint should not show the buttons.
342
+ */
343
+ onMessageFeedback?: (messageId: string, feedback: MessageFeedback | null, message: ChatMessage) => void;
344
+ /**
345
+ * Disable the inline preview of image attachments (they render as ordinary
346
+ * download cards instead). Previews fetch the image through the host download
347
+ * proxy, so hosts that meter or restrict that endpoint can opt out.
348
+ * Default: false.
349
+ */
350
+ disableImagePreviews?: boolean;
351
+ /**
352
+ * Show how full the model's context window is for the current conversation
353
+ * — a small ring plus percentage in the composer toolbar, so the user can
354
+ * see a long chat approaching the point where the agent starts summarising
355
+ * older turns and decide to split the work instead. Default: true.
356
+ *
357
+ * A host-level master switch, not a mode flag: the gauge is data-driven and
358
+ * simply absent until the backend reports occupancy (only the XTM One REST
359
+ * backend does today), so leaving this on costs nothing on a backend that
360
+ * says nothing.
361
+ */
362
+ contextUsageEnabled?: boolean;
363
+ /**
364
+ * Rendered into the composer toolbar, after the built-in controls.
365
+ *
366
+ * The escape hatch for anything the package has no business knowing about —
367
+ * XTM One's session-tool picker (integrations, MCP servers, knowledge bases)
368
+ * being the motivating case. A host that passes nothing gets no extra
369
+ * controls, so this doubles as the "product" toolbar: there is no mode flag
370
+ * to keep in step, only the presence or absence of what a host provides.
371
+ */
372
+ composerToolbar?: React.ReactNode;
152
373
  }
153
374
  interface ChatToggleButtonProps {
154
375
  isOpen: boolean;
155
376
  onToggle: () => void;
377
+ /** Overrides the built-in label; already translated by the host. */
156
378
  label?: string;
379
+ t?: Translate;
157
380
  accentColor?: string;
158
381
  icon?: React.ReactNode;
159
382
  }
@@ -162,6 +385,16 @@ interface ChatMessage {
162
385
  role: 'user' | 'assistant';
163
386
  content: string;
164
387
  timestamp: Date;
388
+ /**
389
+ * The agent that produced *this* message, when the backend says so.
390
+ *
391
+ * Takes precedence over the panel-wide name, which is the currently selected
392
+ * agent and therefore wrong for history: reopening a thread used to relabel
393
+ * every past answer with whoever happened to be picked in the menu. Optional,
394
+ * because no backend records per-message attribution yet — the panel falls
395
+ * back to the conversation's agent, then to the selected one.
396
+ */
397
+ agentName?: string;
165
398
  files?: ChatFile[];
166
399
  /** Agent-generated downloadable files attached to an assistant message. */
167
400
  attachments?: ChatAttachment[];
@@ -247,6 +480,13 @@ interface ChatConversationSummary {
247
480
  /** ISO timestamp of the last activity, used for the relative-time label. */
248
481
  updatedAt?: string;
249
482
  messageCount?: number;
483
+ /**
484
+ * The agent this conversation belongs to, when the backend reports it — so
485
+ * the history list can say which agent a thread is with before you open it.
486
+ * Undefined on backends that do not send it, null-ish for conversations that
487
+ * genuinely have no agent.
488
+ */
489
+ agentName?: string;
250
490
  }
251
491
  interface XtmAgent {
252
492
  id: string;
@@ -266,4 +506,4 @@ interface TransferredAgent {
266
506
  }
267
507
 
268
508
  export { ChatPanel, ChatToggleButton };
269
- export type { ApiEndpoints, BackendType, ChatAttachment, ChatConversationSummary, ChatFile, ChatMessage, ChatMode, ChatPanelProps, ChatToggleButtonProps, TransferredAgent, XtmAgent };
509
+ export type { ApiEndpoints, BackendType, ChatAttachment, ChatContextBreakdown, ChatContextUsage, ChatConversationSummary, ChatFile, ChatMessage, ChatMode, ChatPanelProps, ChatPromptTemplate, ChatQuotaStatus, ChatToggleButtonProps, MessageFeedback, ToolApprovalDecision, ToolApprovalProposal, ToolApprovalVerdict, TransferredAgent, Translate, XtmAgent };