@paymanai/payman-ask-sdk 4.0.0 → 4.0.2
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 +2 -6
- package/dist/index.d.mts +17 -7
- package/dist/index.d.ts +17 -7
- package/dist/index.js +148 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +148 -8
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +63 -0
- package/dist/styles.css.map +1 -1
- package/package.json +4 -31
- package/dist/index.native.js +0 -2476
- package/dist/index.native.js.map +0 -1
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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
]
|