@bytexbyte/nxtlinq-ai-agent-ui-react-development 0.4.1 → 0.4.3
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/context/ChatBotContext.d.ts.map +1 -1
- package/dist/context/ChatBotContext.js +134 -426
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/pendingTextToolRetry.d.ts +16 -0
- package/dist/pendingTextToolRetry.d.ts.map +1 -0
- package/dist/pendingTextToolRetry.js +30 -0
- package/dist/permissionState.d.ts +53 -0
- package/dist/permissionState.d.ts.map +1 -0
- package/dist/permissionState.js +217 -0
- package/dist/types/ChatBotTypes.d.ts +4 -3
- package/dist/types/ChatBotTypes.d.ts.map +1 -1
- package/dist/ui/ChatBotUI.d.ts.map +1 -1
- package/dist/ui/ChatBotUI.js +6 -4
- package/dist/ui/MessageList.d.ts.map +1 -1
- package/dist/ui/MessageList.js +23 -14
- package/dist/ui/PermissionForm.d.ts.map +1 -1
- package/dist/ui/PermissionForm.js +6 -9
- package/package.json +4 -4
- package/src/context/ChatBotContext.tsx +151 -460
- package/src/index.ts +5 -0
- package/src/pendingTextToolRetry.ts +39 -0
- package/src/types/ChatBotTypes.ts +5 -4
- package/src/ui/ChatBotUI.tsx +6 -4
- package/src/ui/MessageList.tsx +17 -8
- package/src/ui/PermissionForm.tsx +7 -12
package/src/index.ts
CHANGED
|
@@ -32,6 +32,8 @@ export type {
|
|
|
32
32
|
Message,
|
|
33
33
|
SendMessageOptions,
|
|
34
34
|
NxtlinqAgentSnapshot,
|
|
35
|
+
TextToolAuthorizationSnapshot,
|
|
36
|
+
TextToolAuthorizationOutcome,
|
|
35
37
|
VoiceSession,
|
|
36
38
|
VoiceStatus,
|
|
37
39
|
} from '@bytexbyte/nxtlinq-ai-agent-core-development';
|
|
@@ -41,6 +43,9 @@ export {
|
|
|
41
43
|
setApiHosts,
|
|
42
44
|
VoiceNotSupportedError,
|
|
43
45
|
STORAGE_KEYS,
|
|
46
|
+
authorizeTextFrontendTool,
|
|
47
|
+
hasRecordedWalletVerification,
|
|
48
|
+
validateWalletSession,
|
|
44
49
|
} from '@bytexbyte/nxtlinq-ai-agent-core-development';
|
|
45
50
|
|
|
46
51
|
export {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Attachment } from '@bytexbyte/nxtlinq-ai-agent-core-development';
|
|
2
|
+
|
|
3
|
+
export type PendingTextToolRequest = {
|
|
4
|
+
content: string;
|
|
5
|
+
isPresetMessage: boolean;
|
|
6
|
+
attachments?: Attachment[];
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/** Keeps one interrupted text-tool request and serializes all resume attempts. */
|
|
10
|
+
export class PendingTextToolRetryController {
|
|
11
|
+
private pending: PendingTextToolRequest | null = null;
|
|
12
|
+
private inFlight: Promise<boolean> | null = null;
|
|
13
|
+
|
|
14
|
+
set(request: PendingTextToolRequest): void {
|
|
15
|
+
this.pending = request;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
clear(): void {
|
|
19
|
+
this.pending = null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
hasPending(): boolean {
|
|
23
|
+
return this.pending !== null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
retry(execute: (request: PendingTextToolRequest) => Promise<void>): Promise<boolean> {
|
|
27
|
+
if (this.inFlight) return this.inFlight;
|
|
28
|
+
if (!this.pending) return Promise.resolve(false);
|
|
29
|
+
|
|
30
|
+
const request = this.pending;
|
|
31
|
+
this.inFlight = (async () => {
|
|
32
|
+
await execute(request);
|
|
33
|
+
return true;
|
|
34
|
+
})().finally(() => {
|
|
35
|
+
this.inFlight = null;
|
|
36
|
+
});
|
|
37
|
+
return this.inFlight;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -163,8 +163,9 @@ export interface ChatBotContextType {
|
|
|
163
163
|
|
|
164
164
|
// Functions
|
|
165
165
|
connectWallet: (autoShowSignInMessage?: boolean) => Promise<string | false | undefined>;
|
|
166
|
-
signInWallet: (autoShowSuccessMessage?: boolean) => Promise<
|
|
167
|
-
|
|
166
|
+
signInWallet: (autoShowSuccessMessage?: boolean) => Promise<boolean>;
|
|
167
|
+
retryPendingTextTool: () => Promise<boolean>;
|
|
168
|
+
sendMessage: (content: string, retryCount?: number, isPresetMessage?: boolean, attachments?: Attachment[]) => Promise<void>;
|
|
168
169
|
handleSubmit: (e: React.FormEvent, attachments?: Attachment[]) => Promise<void>;
|
|
169
170
|
handlePresetMessage: (message: PresetMessage) => void;
|
|
170
171
|
savePermissions: (newPermissions?: string[]) => Promise<void>;
|
|
@@ -194,7 +195,7 @@ export interface ChatBotContextType {
|
|
|
194
195
|
// Additional properties for PermissionForm
|
|
195
196
|
onSave: (newPermissions?: string[]) => Promise<void>;
|
|
196
197
|
onConnectWallet: () => Promise<string | false | undefined>;
|
|
197
|
-
onSignIn: () => Promise<
|
|
198
|
+
onSignIn: () => Promise<boolean>;
|
|
198
199
|
isNeedSignInWithWallet: boolean;
|
|
199
200
|
onVerifyWallet: (method: 'berifyme' | 'custom') => Promise<void>;
|
|
200
201
|
serviceId: string;
|
|
@@ -203,4 +204,4 @@ export interface ChatBotContextType {
|
|
|
203
204
|
// Props
|
|
204
205
|
props: ChatBotProps;
|
|
205
206
|
nxtlinqApi: AITApi;
|
|
206
|
-
}
|
|
207
|
+
}
|
package/src/ui/ChatBotUI.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** @jsxImportSource @emotion/react */
|
|
2
2
|
import { css } from '@emotion/react';
|
|
3
3
|
import * as React from 'react';
|
|
4
|
+
import { hasRecordedWalletVerification } from '@bytexbyte/nxtlinq-ai-agent-core-development';
|
|
4
5
|
import { useDraggable, useLocalStorage, useResizable, walletTextUtils } from '@bytexbyte/nxtlinq-ai-agent-web-development';
|
|
5
6
|
import { useChatBot } from '../context/ChatBotContext';
|
|
6
7
|
import { ChatBotHeader } from './ChatBotHeader';
|
|
@@ -161,7 +162,8 @@ export const ChatBotUI: React.FC = () => {
|
|
|
161
162
|
const urlParams = new URLSearchParams(window.location.search);
|
|
162
163
|
const hasBerifymeToken = urlParams.get('token') && urlParams.get('method') === 'berifyme';
|
|
163
164
|
|
|
164
|
-
const
|
|
165
|
+
const hasRecordedVerification = Boolean(walletInfo?.id)
|
|
166
|
+
&& hasRecordedWalletVerification(walletInfo);
|
|
165
167
|
|
|
166
168
|
// Helper function to update IDV suggestion state based on storage value
|
|
167
169
|
const updateIDVSuggestionState = React.useCallback((dismissedValue: string | null) => {
|
|
@@ -221,7 +223,7 @@ export const ChatBotUI: React.FC = () => {
|
|
|
221
223
|
const shouldShowBanner = hitAddress &&
|
|
222
224
|
!props.requireWalletIDVVerification &&
|
|
223
225
|
!hasBerifymeToken &&
|
|
224
|
-
!
|
|
226
|
+
!hasRecordedVerification &&
|
|
225
227
|
!isNeedSignInWithWallet;
|
|
226
228
|
|
|
227
229
|
if (shouldShowBanner) {
|
|
@@ -229,7 +231,7 @@ export const ChatBotUI: React.FC = () => {
|
|
|
229
231
|
const shouldShowBannerAfterDelay = hitAddress &&
|
|
230
232
|
!props.requireWalletIDVVerification &&
|
|
231
233
|
!hasBerifymeToken &&
|
|
232
|
-
!
|
|
234
|
+
!hasRecordedVerification &&
|
|
233
235
|
!isNeedSignInWithWallet;
|
|
234
236
|
|
|
235
237
|
if (shouldShowBannerAfterDelay) {
|
|
@@ -728,7 +730,7 @@ export const ChatBotUI: React.FC = () => {
|
|
|
728
730
|
onClose={handleClose}
|
|
729
731
|
/>
|
|
730
732
|
|
|
731
|
-
{showIDVSuggestion && hitAddress && !props.requireWalletIDVVerification && !hasBerifymeToken && !
|
|
733
|
+
{showIDVSuggestion && hitAddress && !props.requireWalletIDVVerification && !hasBerifymeToken && !hasRecordedVerification && (
|
|
732
734
|
<div
|
|
733
735
|
data-idv-banner
|
|
734
736
|
css={idvBanner}>
|
package/src/ui/MessageList.tsx
CHANGED
|
@@ -319,6 +319,7 @@ export const MessageList: React.FC = () => {
|
|
|
319
319
|
retryTtsWithGesture,
|
|
320
320
|
connectWallet,
|
|
321
321
|
signInWallet,
|
|
322
|
+
retryPendingTextTool,
|
|
322
323
|
hitAddress,
|
|
323
324
|
isAutoConnecting,
|
|
324
325
|
isNeedSignInWithWallet,
|
|
@@ -330,6 +331,8 @@ export const MessageList: React.FC = () => {
|
|
|
330
331
|
availableModels,
|
|
331
332
|
serviceId,
|
|
332
333
|
piiDisplayMode,
|
|
334
|
+
setShowPermissionForm,
|
|
335
|
+
setIsPermissionFormOpen,
|
|
333
336
|
} = useChatBot();
|
|
334
337
|
const messagesEndRef = React.useRef<HTMLDivElement>(null);
|
|
335
338
|
|
|
@@ -351,22 +354,27 @@ export const MessageList: React.FC = () => {
|
|
|
351
354
|
}
|
|
352
355
|
|
|
353
356
|
if (buttonType === 'connectWallet') {
|
|
354
|
-
connectWallet(
|
|
357
|
+
const connected = await connectWallet(false);
|
|
358
|
+
if (connected) {
|
|
359
|
+
// Continue the interrupted flow immediately. This opens the wallet
|
|
360
|
+
// signature UI instead of leaving the user on a stale connect prompt.
|
|
361
|
+
const signedIn = await signInWallet(true);
|
|
362
|
+
if (signedIn) await retryPendingTextTool();
|
|
363
|
+
}
|
|
355
364
|
} else if (buttonType === 'signIn') {
|
|
356
|
-
signInWallet(true);
|
|
365
|
+
const signedIn = await signInWallet(true);
|
|
366
|
+
if (signedIn) await retryPendingTextTool();
|
|
357
367
|
} else if (buttonType === 'enableAIT') {
|
|
358
368
|
const requiredPermission = message.metadata?.requiredPermission;
|
|
359
369
|
if (requiredPermission) {
|
|
360
370
|
const success = await enableAIT(requiredPermission);
|
|
361
371
|
if (success) {
|
|
362
|
-
|
|
363
|
-
const lastUserMsg = [...messages].reverse().find(m => m.role === 'user');
|
|
364
|
-
if (lastUserMsg && lastUserMsg.content) {
|
|
365
|
-
// Re-execute the previous user message (retryCount=1 to skip duplicate PII log)
|
|
366
|
-
await sendMessage(lastUserMsg.content, 1);
|
|
367
|
-
}
|
|
372
|
+
await retryPendingTextTool();
|
|
368
373
|
}
|
|
369
374
|
}
|
|
375
|
+
} else if (buttonType === 'verifyWallet') {
|
|
376
|
+
setIsPermissionFormOpen(true);
|
|
377
|
+
setShowPermissionForm(true);
|
|
370
378
|
} else if (buttonType === 'continue') {
|
|
371
379
|
const lastUserMsg = [...messages].reverse().find(m => m.role === 'user');
|
|
372
380
|
if (lastUserMsg && lastUserMsg.content) {
|
|
@@ -672,6 +680,7 @@ export const MessageList: React.FC = () => {
|
|
|
672
680
|
{isAutoConnecting ? 'Connecting...' :
|
|
673
681
|
message.button === 'connectWallet' ? (Boolean(hitAddress) ? 'Connected' : walletTextUtils.getWalletText('Connect Wallet', serviceId)) :
|
|
674
682
|
message.button === 'signIn' ? (!isNeedSignInWithWallet ? 'Signed In' : 'Sign In') :
|
|
683
|
+
message.button === 'verifyWallet' ? 'Verify Wallet' :
|
|
675
684
|
message.button === 'continue' ? 'Continue' :
|
|
676
685
|
message.button === 'enableAIT' ?
|
|
677
686
|
((isAITLoading || isAITEnabling) ? 'Enabling...' :
|
|
@@ -3,6 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import { css } from '@emotion/react';
|
|
4
4
|
import { useChatBot } from '../context/ChatBotContext';
|
|
5
5
|
import { walletTextUtils } from '@bytexbyte/nxtlinq-ai-agent-web-development';
|
|
6
|
+
import { hasRecordedWalletVerification } from '@bytexbyte/nxtlinq-ai-agent-core-development';
|
|
6
7
|
import { actionButton, modalOverlay } from './styles/isolatedStyles';
|
|
7
8
|
|
|
8
9
|
interface PermissionFormProps {
|
|
@@ -103,13 +104,10 @@ export const PermissionForm: React.FC<PermissionFormProps> = ({ onClose }) => {
|
|
|
103
104
|
|
|
104
105
|
// Check if wallet IDV verification is required based on configuration
|
|
105
106
|
const requireWalletIDVVerification = props.requireWalletIDVVerification ?? true; // Default to true
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// 1. IDV verification is required AND wallet is not verified, OR
|
|
111
|
-
// 2. IDV verification is required AND wallet is verified but not with Berifyme
|
|
112
|
-
const shouldShowVerificationPrompt = requireWalletIDVVerification && (!isWalletVerified || !isWalletVerifiedWithBerifyme);
|
|
107
|
+
// Any recorded verification source is valid. Custom additionally requires
|
|
108
|
+
// its explicit username evidence so synthetic AIT-provisioned rows do not count.
|
|
109
|
+
const shouldShowVerificationPrompt = requireWalletIDVVerification
|
|
110
|
+
&& (!walletInfo?.id || !hasRecordedWalletVerification(walletInfo));
|
|
113
111
|
|
|
114
112
|
const handleSave = async () => {
|
|
115
113
|
setIsSaving(true);
|
|
@@ -415,10 +413,7 @@ export const PermissionForm: React.FC<PermissionFormProps> = ({ onClose }) => {
|
|
|
415
413
|
font-size: 16px !important;
|
|
416
414
|
color: #666 !important;
|
|
417
415
|
`}>
|
|
418
|
-
{
|
|
419
|
-
? walletTextUtils.getWalletText('Your wallet is verified with custom method, but Berify.me verification is required to continue.', serviceId)
|
|
420
|
-
: walletTextUtils.getWalletText('Please verify your wallet with Berify.me to continue', serviceId)
|
|
421
|
-
}
|
|
416
|
+
{walletTextUtils.getWalletText('Please verify your wallet identity to continue', serviceId)}
|
|
422
417
|
</p>
|
|
423
418
|
<button
|
|
424
419
|
onClick={() => onVerifyWallet('berifyme')}
|
|
@@ -629,4 +624,4 @@ export const PermissionForm: React.FC<PermissionFormProps> = ({ onClose }) => {
|
|
|
629
624
|
)}
|
|
630
625
|
</div>
|
|
631
626
|
);
|
|
632
|
-
};
|
|
627
|
+
};
|