@filigran/chatbot 3.9.0 → 3.10.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/README.md CHANGED
@@ -71,7 +71,9 @@ import { ChatPanel } from '@filigran/chatbot';
71
71
  | `apiBaseUrl` | `string` | **required** | Base URL for chat API endpoints |
72
72
  | `user` | `{ firstName: string }` | **required** | Current user info |
73
73
  | `topOffset` | `number` | `0` | Top offset in pixels (for sidebar/fullscreen with fixed headers) |
74
- | `agentDashboardUrl` | `string` | — | URL for "Browse agents" / "Create agent" links |
74
+ | `agentDashboardUrl` | `string` | — | XTM One URL for the "Browse agents" / "Create agent" links and the waiting panel's "Play Space Invaders in XTM One" link (`{url}/chat?arcade=play`, http(s) only) |
75
+ | `miniGameEnabled` | `boolean` | `true` | Show the waiting panel during longer waits: rotating messages and the invitation to play XTM One's arcade (the package ships no game of its own) |
76
+ | `onPlayWaitingGame` | `() => void` | — | Open the arcade in place instead of linking to XTM One, for a host that runs it itself (the XTM One floating assistant) |
75
77
  | `t` | `(key: string) => string` | identity | Translation function for i18n |
76
78
  | `accentColor` | `string` | `'#7b5cff'` | Primary accent color (hex) |
77
79
  | `logoIcon` | `React.ReactNode` | default icon | Custom logo/icon for the assistant |
@@ -121,13 +123,14 @@ import { ChatToggleButton } from '@filigran/chatbot';
121
123
 
122
124
  #### Props
123
125
 
124
- | Prop | Type | Default | Description |
125
- | ------------- | ----------------- | ------------ | ------------------------------ |
126
- | `isOpen` | `boolean` | **required** | Whether the chat panel is open |
127
- | `onToggle` | `() => void` | **required** | Called when button is clicked |
128
- | `label` | `string` | `'Chat'` | Tooltip/aria label |
129
- | `accentColor` | `string` | `'#7b5cff'` | Button background color |
130
- | `icon` | `React.ReactNode` | default icon | Custom icon |
126
+ | Prop | Type | Default | Description |
127
+ | ------------- | ------------------------- | ------------ | -------------------------------------------------------------------------- |
128
+ | `isOpen` | `boolean` | **required** | Whether the chat panel is open |
129
+ | `onToggle` | `() => void` | **required** | Called when button is clicked |
130
+ | `label` | `string` | built-in | Button text, already translated by the host; omit for `t('Ask Assistant')` |
131
+ | `t` | `(key: string) => string` | identity | Translation function, used for the default label |
132
+ | `accentColor` | `string` | `'#7b5cff'` | Button background color |
133
+ | `icon` | `React.ReactNode` | default icon | Custom icon |
131
134
 
132
135
  ## API Contract
133
136
 
@@ -571,59 +574,230 @@ function App() {
571
574
  }
572
575
  ```
573
576
 
574
- **Translation keys used:**
577
+ `t` is only ever asked for a lookup — key in, translated string out — so any
578
+ i18n library works and the package never carries a dictionary of its own.
579
+ Untranslated hosts can omit it: the default is the identity function, so every
580
+ key is its own English text.
575
581
 
576
- - `'Thinking...'`
577
- - `'Using tools…'`
578
- - `'Analyzing results…'`
579
- - `'Composing answer…'`
580
- - `'Incorporating your message…'`
581
- - `'Ask a question...'`
582
- - `'Stop generating'`
583
- - `'Send now'`
584
- - `'Enter to send now · Esc to stop'`
585
- - `'Attachments wait for the current response'`
586
- - `'New chat'`
582
+ #### Values inside sentences
583
+
584
+ A key is always a **whole sentence**, with `{placeholder}` slots for the values.
585
+ The panel fills the slots in _after_ the lookup, so a locale is free to move the
586
+ value, and a translator sees the sentence rather than a fragment of one:
587
+
588
+ | Key | Renders as |
589
+ | --- | --- |
590
+ | `'Waiting for {count} background tasks…'` | Waiting for 3 background tasks… |
591
+ | `'Transferred from {agent}'` | Transferred from Threat Analyst |
592
+ | `'{percent}% full'` | 84% full |
593
+ | `'How can {agent} help you, {name}?'` | How can **Threat Analyst** help you, John? |
594
+
595
+ Two consequences worth knowing when writing the locale files:
596
+
597
+ - **Plurals are separate keys** — `'1 tool call'` and `'{count} tool calls'`,
598
+ `'Delegating one task…'` and `'Delegating {count} tasks…'`. A lookup cannot
599
+ select a plural form, so the panel picks the sentence and the locale
600
+ translates it whole; a language with more plural forms than English can route
601
+ the plural key through its own rules.
602
+ - **A missing slot is not fatal** — a translation that drops a `{placeholder}`
603
+ renders the rest of the sentence as it is, and the value is simply absent.
604
+ That includes the greeting, where the agent's name is markup: a locale that
605
+ rewords the sentence without `{agent}` gets the sentence, not a name dangling
606
+ off the end of it.
607
+
608
+ `promptSuggestions` (and any suggestions the backend serves) also go through
609
+ `t`, so a host may pass either keys or final text.
610
+
611
+ #### Translation keys used
612
+
613
+ Every key the package can ask for, grouped by where it appears:
614
+
615
+ **Toggle button**
616
+
617
+ - `'Ask Assistant'`
618
+
619
+ **Header, agent menu and history**
620
+
621
+ - `'Agent switching is not available here'`
622
+ - `'Browse agents'`
623
+ - `'Close'`
587
624
  - `'Conversation history'`
588
- - `'No conversations yet'`
589
- - `'Untitled conversation'`
590
- - `'New conversation'`
625
+ - `'Could not reach the assistant service. Check the connection and try again.'`
626
+ - `'Create agent'`
591
627
  - `'Delete conversation'`
592
- - `'just now'` / `'m ago'` / `'h ago'` / `'d ago'`
593
- - `'Switch view'`
594
- - `'Close'`
628
+ - `'Floating'`
629
+ - `'Full screen'`
630
+ - `'New chat'`
631
+ - `'New conversation'`
632
+ - `'No agent matches'`
633
+ - `'No conversations yet'`
634
+ - `'Search agents...'`
635
+ - `'Sidebar'`
636
+ - `'Switch to'`
595
637
  - `'Switch to another agent'`
596
- - `'Browse agents'`
597
- - `'Create agent'`
638
+ - `'Switch view'`
639
+ - `'Transferred from {agent}'`
640
+ - `'Untitled conversation'`
641
+
642
+ **Conversation sidebar**
643
+
644
+ - `'Conversation title'`
645
+ - `'Hide conversations'`
646
+ - `'No conversation matches'`
647
+ - `'Rename conversation'`
648
+ - `'Search conversations...'`
649
+ - `'Show conversations'`
650
+
651
+ **Welcome screen**
652
+
653
+ - `'Assistant'`
654
+ - `'Help me create a new simulation scenario'`
655
+ - `'How can I help you, {name}?'`
656
+ - `'How can {agent} help you, {name}?'`
657
+ - `'How do I configure detection rules?'`
658
+ - `'Suggestions'`
659
+ - `'Summarize my recent findings'`
660
+ - `'What are the latest attack patterns?'`
661
+
662
+ **Composer**
663
+
664
+ - `'Ask a question...'`
665
+ - `'Attachments wait for the current response'`
666
+ - `'Dictate a message'`
667
+ - `'Enter to send now · Esc to stop'`
668
+ - `'Files uploading...'`
669
+ - `'Insert prompt template'`
670
+ - `'No prompt matches'`
671
+ - `'Search prompts...'`
672
+ - `'Send now'`
673
+ - `'Stop dictation'`
674
+ - `'Stop generating'`
675
+ - `'Uses AI. Verify results.'`
676
+
677
+ **Messages, markdown and files**
678
+
679
+ - `'Bad response'`
680
+ - `'Copied'`
681
+ - `'Copied!'`
682
+ - `'Copy code'`
683
+ - `'Copy response'`
684
+ - `'Download'`
685
+ - `'Expand image'`
686
+ - `'Good response'`
687
+ - `'Image could not be loaded'`
688
+ - `'Image preview'`
689
+ - `'Load earlier messages'`
690
+ - `'Loading image…'`
598
691
  - `'Reasoning details'`
599
692
  - `'Reasoning details — turn limit reached'`
693
+
694
+ **Agent status**
695
+
696
+ - `'Analyzing results…'`
697
+ - `'Collecting results from one task…'`
698
+ - `'Collecting results from {count} tasks…'`
699
+ - `'Composing answer…'`
700
+ - `'Consulting {agent}…'`
701
+ - `'Delegating one task…'`
702
+ - `'Delegating {count} tasks…'`
703
+ - `'Incorporating your message…'`
704
+ - `'Thinking...'`
705
+ - `'Transferring to {agent}…'`
706
+ - `'Using tools…'`
707
+ - `'Waiting for one background task…'`
708
+ - `'Waiting for your approval…'`
709
+ - `'Waiting for {count} background tasks…'`
710
+ - `'the agent'`
711
+ - `'{tool} (+{count} more)…'`
712
+
713
+ **Waiting panel**
714
+
715
+ - `'Almost there'`
716
+ - `'Analyzing the details'`
717
+ - `'Connecting the dots'`
718
+ - `'Consulting the sources'`
719
+ - `'Crunching the data'`
720
+ - `'Play Space Invaders'`
721
+ - `'Play Space Invaders in XTM One'`
722
+ - `'Polishing the answer'`
723
+ - `'Putting it together'`
724
+ - `'Reticulating splines'`
725
+ - `'Thinking it through'`
726
+ - `'Wrapping things up'`
727
+
728
+ **Reasoning details**
729
+
730
+ - `'(no output)'`
731
+ - `'1 tool call'`
732
+ - `'1 transfer'`
733
+ - `'Input'`
600
734
  - `'Model reasoning'`
601
- - `'iterations'`
602
- - `'transfer'` / `'transfers'`
735
+ - `'Output'`
736
+ - `"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."`
603
737
  - `'Transfer chain'`
604
738
  - `'Turn limit reached.'`
605
- - `"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."`
606
- - `'Input'` / `'Output'` / `'(no output)'`
607
- - `'Download'`
608
- - `'tool call'` / `'tool calls'`
609
- - `'Uses AI. Verify results.'`
610
- - `'How can I help you, '`
611
- - `'Suggestions'`
612
- - `'Waiting for your approval…'`
613
- - `'The agent needs your approval to run a tool:'` / `'The agent needs your approval to run these tools:'`
614
- - `'Yes'` / `'No'` / `'Yes, always'` / `'Back'` / `'Confirm'` / `'Sending…'` / `'decided'`
615
- - `'Approved'` / `'Declined'` / `'Always allowed'`
739
+ - `'{count} iterations'`
740
+ - `'{count} tool calls'`
741
+ - `'{count} transfers'`
742
+
743
+ **Tool approval**
744
+
745
+ - `'Also applies to your scheduled runs, until you revoke it'`
746
+ - `'Always allowed'`
747
+ - `'Approved'`
748
+ - `'Back'`
749
+ - `'Confirm'`
616
750
  - `'Decline this call'`
751
+ - `'Declined'`
752
+ - `'No'`
753
+ - `'Sending…'`
754
+ - `'The agent needs your approval to run a tool:'`
755
+ - `'The agent needs your approval to run these tools:'`
617
756
  - `'Why not? The agent sees this and can adapt (optional)'`
757
+ - `'Yes'`
758
+ - `'Yes, always'`
618
759
  - `'e.g. wrong environment — use staging instead'`
619
- - `'Also applies to your scheduled runs, until you revoke it'`
760
+ - `'unknown tool'`
761
+ - `'{decided}/{total} decided'`
620
762
  - `'“Yes, always” saves a preference for you. That tool will then run without asking — including on scheduled runs nobody is watching — until you revoke it.'`
621
- - `'This turn is no longer waiting for a decision.'`
763
+
764
+ **Context gauge**
765
+
766
+ - `'Context full — older turns are being dropped'`
767
+ - `'Context nearly full — older turns are being summarized'`
768
+ - `'Context used'`
769
+ - `'Conversation'`
770
+ - `'MCP & dynamic tools'`
771
+ - `'Summarized conversation'`
772
+ - `'System prompt'`
773
+ - `'Tool definitions'`
774
+ - `'Tool results'`
775
+ - `'{counts} tokens'`
776
+ - `'{percent}% full'`
777
+ - `'{summary} — click for details'`
778
+
779
+ **Quota**
780
+
781
+ - `'Quota'`
782
+ - `'Quota reached'`
783
+ - `'Usage'`
784
+ - `'Usage · {period}'`
785
+
786
+ **Notices, errors and timestamps**
787
+
622
788
  - `'Could not send your decision. Please try again.'`
789
+ - `'No response.'`
790
+ - `'Response ready'`
791
+ - `'Sorry, an error occurred. Please try again.'`
623
792
  - `'This decision could not be sent. Reload the chat and try again.'`
624
- - `'Floating'`
625
- - `'Sidebar'`
626
- - `'Full screen'`
793
+ - `'This turn is no longer waiting for a decision.'`
794
+ - `'Unable to connect. Please check the configuration.'`
795
+ - `'Your answer is ready'`
796
+ - `'just now'`
797
+ - `'{agent} has finished'`
798
+ - `'{count}d ago'`
799
+ - `'{count}h ago'`
800
+ - `'{count}m ago'`
627
801
 
628
802
  ## Styling
629
803
 
package/dist/index.d.ts CHANGED
@@ -1,6 +1,14 @@
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';
5
13
  /** A user's rating of one assistant answer. */
6
14
  type MessageFeedback = 'up' | 'down';
@@ -156,6 +164,7 @@ interface ToolApprovalProposal {
156
164
  * different arguments.
157
165
  */
158
166
  toolCallId: string;
167
+ /** Empty when the backend named no tool; the UI labels that case itself. */
159
168
  toolName: string;
160
169
  toolDescription?: string;
161
170
  arguments: Record<string, unknown>;
@@ -236,11 +245,16 @@ interface ChatPanelProps {
236
245
  apiBaseUrl: string;
237
246
  /** Custom API endpoint configuration. */
238
247
  apiEndpoints?: ApiEndpoints;
248
+ /**
249
+ * The XTM One URL: the header's "Browse agents" / "Create agent" links, and
250
+ * the waiting panel's invitation to play the arcade there
251
+ * (`{agentDashboardUrl}/chat?arcade=play`). Only an http(s) URL is linked.
252
+ */
239
253
  agentDashboardUrl?: string;
240
254
  user: {
241
255
  firstName: string;
242
256
  };
243
- t?: (key: string) => string;
257
+ t?: Translate;
244
258
  accentColor?: string;
245
259
  logoIcon?: React.ReactNode;
246
260
  promptSuggestions?: string[];
@@ -305,12 +319,17 @@ interface ChatPanelProps {
305
319
  */
306
320
  backendType?: BackendType;
307
321
  /**
308
- * Show the waiting experience during longer waits: dynamic rotating status
309
- * messages plus an optional Space Invader mini-game that shoots the message
310
- * letters away one by one. Users can still toggle the game off per browser
311
- * from the panel; this prop is a host-level master switch. Default: true.
322
+ * Show the waiting panel during longer waits: rotating status messages and
323
+ * an invitation to play XTM One's Space Invaders arcade, in a new tab
324
+ * through `agentDashboardUrl` or in place through `onPlayWaitingGame`. The
325
+ * package ships no game of its own. Host-level master switch. Default: true.
312
326
  */
313
327
  miniGameEnabled?: boolean;
328
+ /**
329
+ * Opens the arcade in place instead of linking to XTM One, for a host that
330
+ * runs it itself (the XTM One floating assistant). Wins over the link.
331
+ */
332
+ onPlayWaitingGame?: () => void;
314
333
  /**
315
334
  * Notify the user when a long-running turn finishes while they are not
316
335
  * watching the chat — away (tab hidden / another window) via a document-title
@@ -365,7 +384,9 @@ interface ChatPanelProps {
365
384
  interface ChatToggleButtonProps {
366
385
  isOpen: boolean;
367
386
  onToggle: () => void;
387
+ /** Overrides the built-in label; already translated by the host. */
368
388
  label?: string;
389
+ t?: Translate;
369
390
  accentColor?: string;
370
391
  icon?: React.ReactNode;
371
392
  }
@@ -495,4 +516,4 @@ interface TransferredAgent {
495
516
  }
496
517
 
497
518
  export { ChatPanel, ChatToggleButton };
498
- export type { ApiEndpoints, BackendType, ChatAttachment, ChatContextBreakdown, ChatContextUsage, ChatConversationSummary, ChatFile, ChatMessage, ChatMode, ChatPanelProps, ChatPromptTemplate, ChatQuotaStatus, ChatToggleButtonProps, MessageFeedback, ToolApprovalDecision, ToolApprovalProposal, ToolApprovalVerdict, TransferredAgent, XtmAgent };
519
+ export type { ApiEndpoints, BackendType, ChatAttachment, ChatContextBreakdown, ChatContextUsage, ChatConversationSummary, ChatFile, ChatMessage, ChatMode, ChatPanelProps, ChatPromptTemplate, ChatQuotaStatus, ChatToggleButtonProps, MessageFeedback, ToolApprovalDecision, ToolApprovalProposal, ToolApprovalVerdict, TransferredAgent, Translate, XtmAgent };