@paymanai/payman-ask-sdk 4.0.0 → 4.0.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 CHANGED
@@ -167,7 +167,7 @@ Turn features on with booleans, and only reach for the full object form when you
167
167
 
168
168
  Use `ui.emptyState.suggestions` when an app wants SDK-rendered prompt shortcuts on the first screen. Apps own the content; the SDK owns rendering, accessibility, click handling, responsive layout, and styling.
169
169
 
170
- The SDK renders categories as compact bubbles first. Clicking a category reveals that category's prompts below it; clicking a prompt sends the prompt text verbatim. On narrow screens and React Native, categories become a horizontal touch scroller so the empty state stays compact.
170
+ The SDK renders categories as compact bubbles first. Clicking a category reveals that category's prompts below it; clicking a prompt sends the prompt text verbatim. On narrow screens, categories become a horizontal touch scroller so the empty state stays compact.
171
171
 
172
172
  ```tsx
173
173
  const isProd = process.env.NEXT_PUBLIC_ENV === "production";
@@ -203,7 +203,7 @@ const suggestions = {
203
203
 
204
204
  `icon` is optional. When omitted, the SDK chooses a small built-in glyph from the category label for common labels like payments, accounts, insights, and products.
205
205
 
206
- Suggested prompts use the same `--payman-v2-*` CSS variables as the rest of the chat surface, so app-level theme overrides automatically apply to bubble background, text, border, hover, radius, and focus states. The React Native renderer uses native `Pressable` and `ScrollView` controls with the same category-first behavior.
206
+ Suggested prompts use the same `--payman-v2-*` CSS variables as the rest of the chat surface, so app-level theme overrides automatically apply to bubble background, text, border, hover, radius, and focus states.
207
207
 
208
208
  ## Session history
209
209
 
@@ -309,10 +309,6 @@ type ChatCallbacks = {
309
309
  - `listSessions` / `listConversations` REST helpers (from the core SDK).
310
310
  - `buildScopeKey(config)` — compose the client-side state-scope key from `session.userId + workflow.id + workflow.version + workflow.stage`.
311
311
 
312
- ## React Native
313
-
314
- v2 ships web-only for the moment. `PaymanChat` on React Native renders a placeholder — pin `@paymanai/payman-ask-sdk@^1` if you need the v1 native renderer while the v2 RN rewrite lands.
315
-
316
312
  ## License
317
313
 
318
314
  MIT
package/dist/index.d.mts CHANGED
@@ -26,6 +26,16 @@ type MessageActionsConfig = {
26
26
  userMessageActions?: UserMessageActionsConfig;
27
27
  assistantMessageActions?: AssistantMessageActionsConfig;
28
28
  };
29
+ type SlashCommandConfig = {
30
+ /** Slash command token, including the leading slash. Example: /draft-knowledge */
31
+ name: string;
32
+ /** One-line description shown in autocomplete. */
33
+ description: string;
34
+ /** Text inserted into the input. Defaults to `${name} `. */
35
+ insertText?: string;
36
+ /** Show only when at least one permission is present. */
37
+ requiredAnyPermissions?: string[];
38
+ };
29
39
  type ChatConfig = ChatConfig$1 & {
30
40
  /** Custom React component to render above the empty state text (e.g. logo, illustration). */
31
41
  emptyStateComponent?: React__default.ReactNode;
@@ -47,6 +57,12 @@ type ChatConfig = ChatConfig$1 & {
47
57
  showAttachFileButton?: boolean;
48
58
  /** Configure which per-message actions are visible in the v2 UI */
49
59
  messageActions?: MessageActionsConfig;
60
+ /** Enable slash command autocomplete in the chat input. Default: true. */
61
+ enableSlashCommands?: boolean;
62
+ /** Optional command list. Defaults to Knowledge Vault's /draft-knowledge command. */
63
+ slashCommands?: SlashCommandConfig[];
64
+ /** Current caller permissions used to hide commands they cannot run. */
65
+ commandPermissions?: string[];
50
66
  /** Sentry DSN for error monitoring. */
51
67
  sentryDsn?: string;
52
68
  /**
@@ -186,8 +202,6 @@ type ChatInputProps = {
186
202
  onUploadImageClick?: () => void;
187
203
  /** Handler called when the "Attach file" option is clicked */
188
204
  onAttachFileClick?: () => void;
189
- /** React Native: called when the text input is focused (e.g. to scroll messages above the keyboard). */
190
- onInputFocus?: () => void;
191
205
  };
192
206
  type MessageListProps = {
193
207
  /** Messages to display */
@@ -240,10 +254,6 @@ type MessageListProps = {
240
254
  isLoadingMoreMessages?: boolean;
241
255
  /** Whether there are more messages to load */
242
256
  hasMoreMessages?: boolean;
243
- /** React Native: while true, keep scrolling to the end as layout updates. */
244
- isWaitingForResponse?: boolean;
245
- /** React Native: ref to register a no-arg function that scrolls the message list to the end. */
246
- scrollToEndHandleRef?: React__default.MutableRefObject<(() => void) | null>;
247
257
  };
248
258
  type MessageListV2Props = {
249
259
  /** Messages to display */
@@ -528,4 +538,4 @@ interface ChatSessionContext {
528
538
  */
529
539
  declare function captureSentryError(error: Error | string, context: ChatSessionContext): void;
530
540
 
531
- export { type AgentMessageProps, type AssistantMessageActionsConfig, type ChatCallbacks, type ChatConfig, type ChatHeaderProps, type ChatInputProps, type ChatSessionContext, type MessageActionsConfig, type MessageListProps, type MessageListV2Props, type MessageRowProps, type OtpInputProps, PaymanChat, PaymanChatContext, type PaymanChatContextValue, type PaymanChatProps, type PaymanChatRef, type StreamingMessageProps, type UserActionModalProps, type UserMessageActionsConfig, type UserMessageProps, captureSentryError, cn, formatDate, usePaymanChat };
541
+ export { type AgentMessageProps, type AssistantMessageActionsConfig, type ChatCallbacks, type ChatConfig, type ChatHeaderProps, type ChatInputProps, type ChatSessionContext, type MessageActionsConfig, type MessageListProps, type MessageListV2Props, type MessageRowProps, type OtpInputProps, PaymanChat, PaymanChatContext, type PaymanChatContextValue, type PaymanChatProps, type PaymanChatRef, type SlashCommandConfig, type StreamingMessageProps, type UserActionModalProps, type UserMessageActionsConfig, type UserMessageProps, captureSentryError, cn, formatDate, usePaymanChat };
package/dist/index.d.ts CHANGED
@@ -26,6 +26,16 @@ type MessageActionsConfig = {
26
26
  userMessageActions?: UserMessageActionsConfig;
27
27
  assistantMessageActions?: AssistantMessageActionsConfig;
28
28
  };
29
+ type SlashCommandConfig = {
30
+ /** Slash command token, including the leading slash. Example: /draft-knowledge */
31
+ name: string;
32
+ /** One-line description shown in autocomplete. */
33
+ description: string;
34
+ /** Text inserted into the input. Defaults to `${name} `. */
35
+ insertText?: string;
36
+ /** Show only when at least one permission is present. */
37
+ requiredAnyPermissions?: string[];
38
+ };
29
39
  type ChatConfig = ChatConfig$1 & {
30
40
  /** Custom React component to render above the empty state text (e.g. logo, illustration). */
31
41
  emptyStateComponent?: React__default.ReactNode;
@@ -47,6 +57,12 @@ type ChatConfig = ChatConfig$1 & {
47
57
  showAttachFileButton?: boolean;
48
58
  /** Configure which per-message actions are visible in the v2 UI */
49
59
  messageActions?: MessageActionsConfig;
60
+ /** Enable slash command autocomplete in the chat input. Default: true. */
61
+ enableSlashCommands?: boolean;
62
+ /** Optional command list. Defaults to Knowledge Vault's /draft-knowledge command. */
63
+ slashCommands?: SlashCommandConfig[];
64
+ /** Current caller permissions used to hide commands they cannot run. */
65
+ commandPermissions?: string[];
50
66
  /** Sentry DSN for error monitoring. */
51
67
  sentryDsn?: string;
52
68
  /**
@@ -186,8 +202,6 @@ type ChatInputProps = {
186
202
  onUploadImageClick?: () => void;
187
203
  /** Handler called when the "Attach file" option is clicked */
188
204
  onAttachFileClick?: () => void;
189
- /** React Native: called when the text input is focused (e.g. to scroll messages above the keyboard). */
190
- onInputFocus?: () => void;
191
205
  };
192
206
  type MessageListProps = {
193
207
  /** Messages to display */
@@ -240,10 +254,6 @@ type MessageListProps = {
240
254
  isLoadingMoreMessages?: boolean;
241
255
  /** Whether there are more messages to load */
242
256
  hasMoreMessages?: boolean;
243
- /** React Native: while true, keep scrolling to the end as layout updates. */
244
- isWaitingForResponse?: boolean;
245
- /** React Native: ref to register a no-arg function that scrolls the message list to the end. */
246
- scrollToEndHandleRef?: React__default.MutableRefObject<(() => void) | null>;
247
257
  };
248
258
  type MessageListV2Props = {
249
259
  /** Messages to display */
@@ -528,4 +538,4 @@ interface ChatSessionContext {
528
538
  */
529
539
  declare function captureSentryError(error: Error | string, context: ChatSessionContext): void;
530
540
 
531
- export { type AgentMessageProps, type AssistantMessageActionsConfig, type ChatCallbacks, type ChatConfig, type ChatHeaderProps, type ChatInputProps, type ChatSessionContext, type MessageActionsConfig, type MessageListProps, type MessageListV2Props, type MessageRowProps, type OtpInputProps, PaymanChat, PaymanChatContext, type PaymanChatContextValue, type PaymanChatProps, type PaymanChatRef, type StreamingMessageProps, type UserActionModalProps, type UserMessageActionsConfig, type UserMessageProps, captureSentryError, cn, formatDate, usePaymanChat };
541
+ export { type AgentMessageProps, type AssistantMessageActionsConfig, type ChatCallbacks, type ChatConfig, type ChatHeaderProps, type ChatInputProps, type ChatSessionContext, type MessageActionsConfig, type MessageListProps, type MessageListV2Props, type MessageRowProps, type OtpInputProps, PaymanChat, PaymanChatContext, type PaymanChatContextValue, type PaymanChatProps, type PaymanChatRef, type SlashCommandConfig, type StreamingMessageProps, type UserActionModalProps, type UserMessageActionsConfig, type UserMessageProps, captureSentryError, cn, formatDate, usePaymanChat };
package/dist/index.js CHANGED
@@ -149,6 +149,36 @@ function subscribeToCfRay(urlPattern, listener) {
149
149
  };
150
150
  }
151
151
 
152
+ // src/utils/slashCommands.ts
153
+ var DEFAULT_SLASH_COMMANDS = [
154
+ {
155
+ name: "/draft-knowledge",
156
+ description: "Create a Knowledge Vault draft for admin review",
157
+ requiredAnyPermissions: ["vault:author", "vault:publish"]
158
+ }
159
+ ];
160
+ function filterSlashCommands(commands, permissions) {
161
+ const granted = new Set(permissions ?? []);
162
+ return commands.filter((command) => {
163
+ const required = command.requiredAnyPermissions ?? [];
164
+ return required.length === 0 || required.some((permission) => granted.has(permission));
165
+ });
166
+ }
167
+ function parseSlashCommand(content) {
168
+ const trimmedStart = content.trimStart();
169
+ if (!trimmedStart.startsWith("/")) return null;
170
+ const match = trimmedStart.match(/^(\/[a-z][a-z0-9-]*)(?:\s+([\s\S]*))?$/i);
171
+ if (!match) return null;
172
+ return {
173
+ command: match[1],
174
+ body: match[2] ?? ""
175
+ };
176
+ }
177
+ function slashCommandBodyIsEmpty(content) {
178
+ const parsed = parseSlashCommand(content);
179
+ return parsed?.command === "/draft-knowledge" && parsed.body.trim().length === 0;
180
+ }
181
+
152
182
  // src/utils/errorMessages.ts
153
183
  var WORKFLOW_FAILED = "WORKFLOW_FAILED";
154
184
  var STREAM_NOT_STARTED = "STREAM_NOT_STARTED";
@@ -789,6 +819,7 @@ function UserMessage({
789
819
  animated = false,
790
820
  showAvatar = false
791
821
  }) {
822
+ const parsedCommand = parseSlashCommand(message.content);
792
823
  const content = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 justify-end w-full", children: [
793
824
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-[80%] min-w-0 flex flex-col items-end", children: [
794
825
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -799,7 +830,10 @@ function UserMessage({
799
830
  "bg-primary text-primary-foreground",
800
831
  "shadow-sm"
801
832
  ),
802
- children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm leading-relaxed whitespace-pre-wrap break-words", children: message.content })
833
+ children: parsedCommand ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
834
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex rounded-md bg-black/15 px-2 py-0.5 font-mono text-xs", children: parsedCommand.command }),
835
+ parsedCommand.body.trim() ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm leading-relaxed whitespace-pre-wrap break-words", children: parsedCommand.body }) : null
836
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm leading-relaxed whitespace-pre-wrap break-words", children: message.content })
803
837
  }
804
838
  ),
805
839
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] mt-1.5 mr-1 text-muted-foreground/70 select-none", children: formatDate(message.timestamp) })
@@ -940,7 +974,7 @@ function MessageList({
940
974
  messages,
941
975
  isLoading = false,
942
976
  emptyStateText = "What can I help with?",
943
- showEmptyStateIcon = true,
977
+ showEmptyStateIcon: _showEmptyStateIcon = true,
944
978
  emptyStateComponent,
945
979
  layout = "full-width",
946
980
  showTimestamps = false,
@@ -1315,6 +1349,7 @@ function UserMessageV2({
1315
1349
  }
1316
1350
  };
1317
1351
  const timestamp = formatMessageTime(message.timestamp);
1352
+ const parsedCommand = parseSlashCommand(message.content);
1318
1353
  const hasVisibleActions = showCopyAction || showEditAction && !!onEdit || showRetryAction && !!onRetry;
1319
1354
  const toastPortal = typeof document !== "undefined" ? reactDom.createPortal(
1320
1355
  /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: toast && /* @__PURE__ */ jsxRuntime.jsx(
@@ -1359,7 +1394,10 @@ function UserMessageV2({
1359
1394
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1360
1395
  toastPortal,
1361
1396
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-user-msg payman-v2-fade-in", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-user-msg-group", children: [
1362
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-user-msg-bubble", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-user-msg-text", children: message.content }) }),
1397
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-user-msg-bubble", children: parsedCommand ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-user-msg-command", children: [
1398
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-user-msg-command-chip", children: parsedCommand.command }),
1399
+ parsedCommand.body.trim() ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-user-msg-text", children: parsedCommand.body }) : null
1400
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-user-msg-text", children: message.content }) }),
1363
1401
  message.isError && message.errorDetails && (() => {
1364
1402
  const resolvedError = getConflictErrorMessage(message.errorDetails) ?? message.errorDetails;
1365
1403
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-user-msg-error", children: [
@@ -2497,7 +2535,6 @@ var MessageListV2 = react.forwardRef(
2497
2535
  var ChatInputV2 = react.forwardRef(
2498
2536
  function ChatInputV22({
2499
2537
  onSend,
2500
- onCancel,
2501
2538
  disabled = false,
2502
2539
  isStreaming = false,
2503
2540
  placeholder = "Reply...",
@@ -2516,12 +2553,16 @@ var ChatInputV2 = react.forwardRef(
2516
2553
  editingMessageId = null,
2517
2554
  onClearEditing,
2518
2555
  analysisMode,
2519
- onAnalysisModeChange
2556
+ onAnalysisModeChange,
2557
+ slashCommands = []
2520
2558
  }, ref) {
2521
2559
  const [value, setValue] = react.useState("");
2522
2560
  const [isFocused, setIsFocused] = react.useState(false);
2523
2561
  const [showActions, setShowActions] = react.useState(false);
2524
2562
  const [showVoiceTooltip, setShowVoiceTooltip] = react.useState(false);
2563
+ const [selectedCommandIndex, setSelectedCommandIndex] = react.useState(0);
2564
+ const [inlineHint, setInlineHint] = react.useState(null);
2565
+ const [commandMenuDismissed, setCommandMenuDismissed] = react.useState(false);
2525
2566
  const textareaRef = react.useRef(null);
2526
2567
  const actionsRef = react.useRef(null);
2527
2568
  const preRecordTextRef = react.useRef("");
@@ -2534,6 +2575,11 @@ var ChatInputV2 = react.forwardRef(
2534
2575
  const showAttachmentMenuButton = showAttachmentButton && hasAttachmentOptions;
2535
2576
  const showVoiceButton = enableVoice && onVoicePress != null;
2536
2577
  const isVoiceButtonDisabled = disabled || !voiceAvailable;
2578
+ const commandQuery = value.startsWith("/") && !value.includes("\n") && !/\s/.test(value) ? value.toLowerCase() : null;
2579
+ const commandSuggestions = commandQuery == null ? [] : slashCommands.filter(
2580
+ (command) => command.name.toLowerCase().startsWith(commandQuery)
2581
+ );
2582
+ const showCommandSuggestions = !commandMenuDismissed && !isRecording && !disabled && commandSuggestions.length > 0;
2537
2583
  react.useEffect(() => {
2538
2584
  if (textareaRef.current) {
2539
2585
  textareaRef.current.style.height = "auto";
@@ -2583,6 +2629,10 @@ var ChatInputV2 = react.forwardRef(
2583
2629
  setShowActions(false);
2584
2630
  }
2585
2631
  }, [showAttachmentMenuButton]);
2632
+ react.useEffect(() => {
2633
+ setSelectedCommandIndex(0);
2634
+ setCommandMenuDismissed(false);
2635
+ }, [commandQuery]);
2586
2636
  react.useEffect(() => {
2587
2637
  return () => {
2588
2638
  if (voiceTooltipTimerRef.current) {
@@ -2598,8 +2648,13 @@ var ChatInputV2 = react.forwardRef(
2598
2648
  }, [isRecording, transcribedText]);
2599
2649
  const handleSend = react.useCallback(() => {
2600
2650
  if (!value.trim() || disabled) return;
2651
+ if (slashCommandBodyIsEmpty(value)) {
2652
+ setInlineHint("Add markdown content below the command line.");
2653
+ return;
2654
+ }
2601
2655
  voiceDraftSyncActiveRef.current = false;
2602
2656
  preRecordTextRef.current = "";
2657
+ setInlineHint(null);
2603
2658
  onClearEditing?.();
2604
2659
  onSend(value.trim());
2605
2660
  setValue("");
@@ -2610,7 +2665,48 @@ var ChatInputV2 = react.forwardRef(
2610
2665
  }
2611
2666
  });
2612
2667
  }, [value, disabled, onClearEditing, onSend]);
2668
+ const selectCommand = react.useCallback(
2669
+ (command) => {
2670
+ const insertText = command.insertText ?? `${command.name} `;
2671
+ setValue(insertText);
2672
+ setInlineHint(null);
2673
+ setShowActions(false);
2674
+ requestAnimationFrame(() => {
2675
+ const textarea = textareaRef.current;
2676
+ if (!textarea) return;
2677
+ textarea.focus();
2678
+ textarea.setSelectionRange(insertText.length, insertText.length);
2679
+ });
2680
+ },
2681
+ []
2682
+ );
2613
2683
  const handleKeyDown = (e) => {
2684
+ if (showCommandSuggestions) {
2685
+ if (e.key === "ArrowDown") {
2686
+ e.preventDefault();
2687
+ setSelectedCommandIndex(
2688
+ (current) => Math.min(current + 1, commandSuggestions.length - 1)
2689
+ );
2690
+ return;
2691
+ }
2692
+ if (e.key === "ArrowUp") {
2693
+ e.preventDefault();
2694
+ setSelectedCommandIndex((current) => Math.max(current - 1, 0));
2695
+ return;
2696
+ }
2697
+ if (e.key === "Enter" || e.key === "Tab") {
2698
+ e.preventDefault();
2699
+ const command = commandSuggestions[selectedCommandIndex];
2700
+ if (command) selectCommand(command);
2701
+ return;
2702
+ }
2703
+ if (e.key === "Escape") {
2704
+ e.preventDefault();
2705
+ setSelectedCommandIndex(0);
2706
+ setCommandMenuDismissed(true);
2707
+ return;
2708
+ }
2709
+ }
2614
2710
  if (e.key === "Enter" && !e.shiftKey) {
2615
2711
  e.preventDefault();
2616
2712
  if (isStreaming) return;
@@ -2655,6 +2751,35 @@ var ChatInputV2 = react.forwardRef(
2655
2751
  const canSend = value.trim().length > 0 && !disabled;
2656
2752
  const sendDisabled = !canSend || isStreaming;
2657
2753
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-input-container", children: [
2754
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: showCommandSuggestions && /* @__PURE__ */ jsxRuntime.jsx(
2755
+ framerMotion.motion.div,
2756
+ {
2757
+ initial: { opacity: 0, y: 6, scale: 0.98 },
2758
+ animate: { opacity: 1, y: 0, scale: 1 },
2759
+ exit: { opacity: 0, y: 6, scale: 0.98 },
2760
+ transition: { duration: 0.12 },
2761
+ className: "payman-v2-command-menu",
2762
+ children: commandSuggestions.map((command, index) => /* @__PURE__ */ jsxRuntime.jsxs(
2763
+ "button",
2764
+ {
2765
+ type: "button",
2766
+ onMouseDown: (event) => {
2767
+ event.preventDefault();
2768
+ selectCommand(command);
2769
+ },
2770
+ className: cn(
2771
+ "payman-v2-command-option",
2772
+ index === selectedCommandIndex && "payman-v2-command-option-active"
2773
+ ),
2774
+ children: [
2775
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-command-name", children: command.name }),
2776
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-command-description", children: command.description })
2777
+ ]
2778
+ },
2779
+ command.name
2780
+ ))
2781
+ }
2782
+ ) }),
2658
2783
  /* @__PURE__ */ jsxRuntime.jsxs(
2659
2784
  "div",
2660
2785
  {
@@ -2699,6 +2824,8 @@ var ChatInputV2 = react.forwardRef(
2699
2824
  if (isRecording) return;
2700
2825
  const nextValue = e.target.value;
2701
2826
  voiceDraftSyncActiveRef.current = false;
2827
+ setInlineHint(null);
2828
+ setCommandMenuDismissed(false);
2702
2829
  setValue(nextValue);
2703
2830
  if (editingMessageId && nextValue.length === 0) {
2704
2831
  onClearEditing?.();
@@ -2913,6 +3040,7 @@ var ChatInputV2 = react.forwardRef(
2913
3040
  ]
2914
3041
  }
2915
3042
  ),
3043
+ inlineHint && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-input-inline-hint", children: inlineHint }),
2916
3044
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-input-disclaimer", children: "AI can make mistakes. Please double-check responses." })
2917
3045
  ] });
2918
3046
  }
@@ -3379,7 +3507,10 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3379
3507
  showAttachmentButton = true,
3380
3508
  showUploadImageButton = true,
3381
3509
  showAttachFileButton = true,
3382
- messageActions: messageActionsConfig
3510
+ messageActions: messageActionsConfig,
3511
+ enableSlashCommands = true,
3512
+ slashCommands: slashCommandsConfig,
3513
+ commandPermissions
3383
3514
  } = config;
3384
3515
  const messageActions = react.useMemo(
3385
3516
  () => ({
@@ -3397,6 +3528,13 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3397
3528
  }),
3398
3529
  [messageActionsConfig]
3399
3530
  );
3531
+ const slashCommands = react.useMemo(
3532
+ () => enableSlashCommands ? filterSlashCommands(
3533
+ slashCommandsConfig ?? DEFAULT_SLASH_COMMANDS,
3534
+ commandPermissions
3535
+ ) : [],
3536
+ [commandPermissions, enableSlashCommands, slashCommandsConfig]
3537
+ );
3400
3538
  const isSessionParamsConfigured = react.useMemo(() => {
3401
3539
  if (!sessionParams) return false;
3402
3540
  return !!(sessionParams.id?.trim() && sessionParams.name?.trim());
@@ -3594,7 +3732,8 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3594
3732
  editingMessageId,
3595
3733
  onClearEditing: handleClearEditing,
3596
3734
  analysisMode,
3597
- onAnalysisModeChange: setAnalysisMode
3735
+ onAnalysisModeChange: setAnalysisMode,
3736
+ slashCommands
3598
3737
  }
3599
3738
  )
3600
3739
  }
@@ -3669,7 +3808,8 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
3669
3808
  editingMessageId,
3670
3809
  onClearEditing: handleClearEditing,
3671
3810
  analysisMode,
3672
- onAnalysisModeChange: setAnalysisMode
3811
+ onAnalysisModeChange: setAnalysisMode,
3812
+ slashCommands
3673
3813
  }
3674
3814
  )
3675
3815
  ]