@bytexbyte/nxtlinq-ai-agent-ui-react-development 0.4.0 → 0.4.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/dist/context/ChatBotContext.d.ts.map +1 -1
- package/dist/context/ChatBotContext.js +84 -405
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- 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 +0 -5
- package/dist/types/ChatBotTypes.d.ts.map +1 -1
- package/dist/ui/ChatBotHeader.d.ts.map +1 -1
- package/dist/ui/ChatBotHeader.js +6 -2
- package/dist/ui/ChatBotUI.d.ts.map +1 -1
- package/dist/ui/ChatBotUI.js +13 -4
- package/dist/ui/MessageList.d.ts.map +1 -1
- package/dist/ui/MessageList.js +11 -6
- package/dist/ui/PermissionForm.d.ts.map +1 -1
- package/dist/ui/PermissionForm.js +6 -9
- package/dist/ui/styles/isolatedStyles.d.ts.map +1 -1
- package/dist/ui/styles/isolatedStyles.js +1 -0
- package/package.json +3 -3
- package/src/context/ChatBotContext.tsx +92 -437
- package/src/index.ts +5 -0
- package/src/types/ChatBotTypes.ts +2 -6
- package/src/ui/ChatBotHeader.tsx +9 -3
- package/src/ui/ChatBotUI.tsx +14 -5
- package/src/ui/MessageList.tsx +6 -0
- package/src/ui/PermissionForm.tsx +7 -12
- package/src/ui/styles/isolatedStyles.ts +1 -0
- package/dist/NxtlinqAgentChat.d.ts +0 -26
- package/dist/NxtlinqAgentChat.d.ts.map +0 -1
- package/dist/NxtlinqAgentChat.js +0 -28
- package/dist/components/AgentAssistantShell.d.ts +0 -5
- package/dist/components/AgentAssistantShell.d.ts.map +0 -1
- package/dist/components/AgentAssistantShell.js +0 -52
- package/dist/components/AgentComposer.d.ts +0 -3
- package/dist/components/AgentComposer.d.ts.map +0 -1
- package/dist/components/AgentComposer.js +0 -60
- package/dist/components/AgentMessageList.d.ts +0 -3
- package/dist/components/AgentMessageList.d.ts.map +0 -1
- package/dist/components/AgentMessageList.js +0 -37
- package/dist/components/AgentRemoteAudio.d.ts +0 -4
- package/dist/components/AgentRemoteAudio.d.ts.map +0 -1
- package/dist/components/AgentRemoteAudio.js +0 -34
- package/dist/components/AgentVoiceBar.d.ts +0 -3
- package/dist/components/AgentVoiceBar.d.ts.map +0 -1
- package/dist/components/AgentVoiceBar.js +0 -91
- package/dist/components/PresetMessageChips.d.ts +0 -3
- package/dist/components/PresetMessageChips.d.ts.map +0 -1
- package/dist/components/PresetMessageChips.js +0 -23
- package/dist/context/AgentAssistantContext.d.ts +0 -32
- package/dist/context/AgentAssistantContext.d.ts.map +0 -1
- package/dist/context/AgentAssistantContext.js +0 -179
- package/dist/legacy/assets/images/adiSideItalicDataUri.d.ts +0 -2
- package/dist/legacy/assets/images/adiSideItalicDataUri.d.ts.map +0 -1
- package/dist/legacy/assets/images/adiSideItalicDataUri.js +0 -1
- package/dist/legacy/chatbot/ChatBot.d.ts +0 -5
- package/dist/legacy/chatbot/ChatBot.d.ts.map +0 -1
- package/dist/legacy/chatbot/ChatBot.js +0 -35
- package/dist/legacy/chatbot/context/ChatBotContext.d.ts +0 -5
- package/dist/legacy/chatbot/context/ChatBotContext.d.ts.map +0 -1
- package/dist/legacy/chatbot/context/ChatBotContext.js +0 -2922
- package/dist/legacy/chatbot/types/ChatBotTypes.d.ts +0 -166
- package/dist/legacy/chatbot/types/ChatBotTypes.d.ts.map +0 -1
- package/dist/legacy/chatbot/types/ChatBotTypes.js +0 -1
- package/dist/legacy/chatbot/ui/BerifyMeModal.d.ts +0 -17
- package/dist/legacy/chatbot/ui/BerifyMeModal.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/BerifyMeModal.js +0 -110
- package/dist/legacy/chatbot/ui/ChatBotHeader.d.ts +0 -15
- package/dist/legacy/chatbot/ui/ChatBotHeader.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/ChatBotHeader.js +0 -62
- package/dist/legacy/chatbot/ui/ChatBotUI.d.ts +0 -3
- package/dist/legacy/chatbot/ui/ChatBotUI.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/ChatBotUI.js +0 -557
- package/dist/legacy/chatbot/ui/MessageInput.d.ts +0 -3
- package/dist/legacy/chatbot/ui/MessageInput.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/MessageInput.js +0 -321
- package/dist/legacy/chatbot/ui/MessageList.d.ts +0 -4
- package/dist/legacy/chatbot/ui/MessageList.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/MessageList.js +0 -455
- package/dist/legacy/chatbot/ui/ModelSelector.d.ts +0 -4
- package/dist/legacy/chatbot/ui/ModelSelector.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/ModelSelector.js +0 -122
- package/dist/legacy/chatbot/ui/NotificationModal.d.ts +0 -15
- package/dist/legacy/chatbot/ui/NotificationModal.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/NotificationModal.js +0 -53
- package/dist/legacy/chatbot/ui/PermissionForm.d.ts +0 -8
- package/dist/legacy/chatbot/ui/PermissionForm.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/PermissionForm.js +0 -465
- package/dist/legacy/chatbot/ui/PresetMessages.d.ts +0 -4
- package/dist/legacy/chatbot/ui/PresetMessages.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/PresetMessages.js +0 -33
- package/dist/legacy/chatbot/ui/VoiceModePanel.d.ts +0 -3
- package/dist/legacy/chatbot/ui/VoiceModePanel.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/VoiceModePanel.js +0 -95
- package/dist/legacy/chatbot/ui/chatBotHeaderParts.d.ts +0 -15
- package/dist/legacy/chatbot/ui/chatBotHeaderParts.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/chatBotHeaderParts.js +0 -50
- package/dist/legacy/chatbot/ui/styles/isolatedStyles.d.ts +0 -73
- package/dist/legacy/chatbot/ui/styles/isolatedStyles.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/styles/isolatedStyles.js +0 -985
- package/dist/legacy/index.d.ts +0 -14
- package/dist/legacy/index.d.ts.map +0 -1
- package/dist/legacy/index.js +0 -12
- package/dist/theme/defaultTheme.d.ts +0 -3
- package/dist/theme/defaultTheme.d.ts.map +0 -1
- package/dist/theme/defaultTheme.js +0 -20
- package/dist/types.d.ts +0 -62
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -1
- package/dist/voice/useVoiceConnectOrchestration.d.ts +0 -21
- package/dist/voice/useVoiceConnectOrchestration.d.ts.map +0 -1
- package/dist/voice/useVoiceConnectOrchestration.js +0 -86
- package/dist/voice/useVoiceMicState.d.ts +0 -15
- package/dist/voice/useVoiceMicState.d.ts.map +0 -1
- package/dist/voice/useVoiceMicState.js +0 -94
- package/dist/voice/useVoiceSilenceCommit.d.ts +0 -10
- package/dist/voice/useVoiceSilenceCommit.d.ts.map +0 -1
- package/dist/voice/useVoiceSilenceCommit.js +0 -67
- package/dist/voice/useVoiceTranscriptMessages.d.ts +0 -18
- package/dist/voice/useVoiceTranscriptMessages.d.ts.map +0 -1
- package/dist/voice/useVoiceTranscriptMessages.js +0 -132
- package/dist/voice/useWsRealtimeAudio.d.ts +0 -18
- package/dist/voice/useWsRealtimeAudio.d.ts.map +0 -1
- package/dist/voice/useWsRealtimeAudio.js +0 -102
- package/dist/voice/voiceMicConstants.d.ts +0 -4
- package/dist/voice/voiceMicConstants.d.ts.map +0 -1
- package/dist/voice/voiceMicConstants.js +0 -10
- package/dist/voice/voiceUserBubble.d.ts +0 -10
- package/dist/voice/voiceUserBubble.d.ts.map +0 -1
- package/dist/voice/voiceUserBubble.js +0 -52
- package/dist/voice/ws/BrowserWsPcmPlayer.d.ts +0 -23
- package/dist/voice/ws/BrowserWsPcmPlayer.d.ts.map +0 -1
- package/dist/voice/ws/BrowserWsPcmPlayer.js +0 -137
- package/dist/voice/ws/BrowserWsPcmRecorder.d.ts +0 -17
- package/dist/voice/ws/BrowserWsPcmRecorder.d.ts.map +0 -1
- package/dist/voice/ws/BrowserWsPcmRecorder.js +0 -71
- package/dist/voice/ws/float32ToPcm16.d.ts +0 -2
- package/dist/voice/ws/float32ToPcm16.d.ts.map +0 -1
- package/dist/voice/ws/float32ToPcm16.js +0 -8
- package/dist/voice/ws/voiceSilenceConstants.d.ts +0 -5
- package/dist/voice/ws/voiceSilenceConstants.d.ts.map +0 -1
- package/dist/voice/ws/voiceSilenceConstants.js +0 -4
- package/dist/voice/ws/wsRealtimeConstants.d.ts +0 -2
- package/dist/voice/ws/wsRealtimeConstants.d.ts.map +0 -1
- package/dist/voice/ws/wsRealtimeConstants.js +0 -1
|
@@ -25,6 +25,10 @@ import type {
|
|
|
25
25
|
Message,
|
|
26
26
|
ServicePermission,
|
|
27
27
|
} from '@bytexbyte/nxtlinq-ai-agent-core-development';
|
|
28
|
+
import {
|
|
29
|
+
authorizeTextFrontendTool,
|
|
30
|
+
hasRecordedWalletVerification,
|
|
31
|
+
} from '@bytexbyte/nxtlinq-ai-agent-core-development';
|
|
28
32
|
import {
|
|
29
33
|
AIModel,
|
|
30
34
|
ChatBotContextType,
|
|
@@ -79,8 +83,6 @@ export const ChatBotProvider: React.FC<ChatBotProps> = ({
|
|
|
79
83
|
isStopRecordingOnSend = false,
|
|
80
84
|
// Custom error message to display in chat
|
|
81
85
|
customError,
|
|
82
|
-
// PII display mode
|
|
83
|
-
piiDisplayMode = 'redacted',
|
|
84
86
|
voiceThresholds,
|
|
85
87
|
debugVoiceRms = false,
|
|
86
88
|
sttGlossary,
|
|
@@ -894,6 +896,12 @@ export const ChatBotProvider: React.FC<ChatBotProps> = ({
|
|
|
894
896
|
const [modelsFromApi, setModelsFromApi] = React.useState<AIModel[]>([]);
|
|
895
897
|
const [selectedModelIndex, setSelectedModelIndex] = useLocalStorage<number>('selectedAIModelIndex', 0);
|
|
896
898
|
|
|
899
|
+
// PII protection status: fetched from the service's own config (via serviceId + credentials
|
|
900
|
+
// already provided to the SDK), not passed in by the host app. Defaults to off until the fetch
|
|
901
|
+
// below resolves, matching how modelsFromApi starts empty.
|
|
902
|
+
const [enablePiiProtection, setEnablePiiProtection] = React.useState(false);
|
|
903
|
+
const piiDisplayMode: 'plain' | 'redacted' = enablePiiProtection ? 'redacted' : 'plain';
|
|
904
|
+
|
|
897
905
|
// Use models from API only (no default fallback)
|
|
898
906
|
// This ensures SDK always uses Dashboard-configured models
|
|
899
907
|
const effectiveAvailableModels = React.useMemo(() => {
|
|
@@ -915,6 +923,9 @@ export const ChatBotProvider: React.FC<ChatBotProps> = ({
|
|
|
915
923
|
if ('availableModels' in result && Array.isArray(result.availableModels)) {
|
|
916
924
|
setModelsFromApi(result.availableModels);
|
|
917
925
|
}
|
|
926
|
+
if ('enablePiiProtection' in result) {
|
|
927
|
+
setEnablePiiProtection(!!result.enablePiiProtection);
|
|
928
|
+
}
|
|
918
929
|
} catch (error) {
|
|
919
930
|
console.error('Failed to fetch available models from API:', error);
|
|
920
931
|
// Silently fail and use default models
|
|
@@ -999,13 +1010,18 @@ export const ChatBotProvider: React.FC<ChatBotProps> = ({
|
|
|
999
1010
|
|
|
1000
1011
|
setIsAITLoading(true);
|
|
1001
1012
|
try {
|
|
1013
|
+
let walletAllowsAITLookup = !requireWalletIDVVerification;
|
|
1014
|
+
|
|
1002
1015
|
// Get wallet info first - always try to get wallet info if we have a token
|
|
1003
1016
|
if (nxtlinqAITServiceAccessToken) {
|
|
1004
1017
|
try {
|
|
1005
1018
|
const walletResponse = await nxtlinqApi.wallet.getWallet({ address: hitAddress }, nxtlinqAITServiceAccessToken);
|
|
1006
1019
|
if (!('error' in walletResponse)) {
|
|
1007
1020
|
setWalletInfo(walletResponse);
|
|
1021
|
+
walletAllowsAITLookup = !requireWalletIDVVerification
|
|
1022
|
+
|| hasRecordedWalletVerification(walletResponse);
|
|
1008
1023
|
} else {
|
|
1024
|
+
setWalletInfo(null);
|
|
1009
1025
|
// Check if the error is due to invalid/expired token
|
|
1010
1026
|
if (walletResponse.error.includes('Invalid or expired token')) {
|
|
1011
1027
|
console.log('Token appears to be invalid during wallet info fetch, clearing it');
|
|
@@ -1013,10 +1029,19 @@ export const ChatBotProvider: React.FC<ChatBotProps> = ({
|
|
|
1013
1029
|
}
|
|
1014
1030
|
}
|
|
1015
1031
|
} catch (error) {
|
|
1032
|
+
setWalletInfo(null);
|
|
1016
1033
|
console.error('Failed to fetch wallet info:', error);
|
|
1017
1034
|
}
|
|
1018
1035
|
}
|
|
1019
1036
|
|
|
1037
|
+
// AIT existence is not identity verification. In strict mode, stop before
|
|
1038
|
+
// the legacy AIT lookup can synthesize a custom wallet record.
|
|
1039
|
+
if (nxtlinqAITServiceAccessToken && !walletAllowsAITLookup) {
|
|
1040
|
+
setAit(null);
|
|
1041
|
+
setPermissions([]);
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1020
1045
|
// Only try to fetch AIT if we have a token
|
|
1021
1046
|
if (nxtlinqAITServiceAccessToken) {
|
|
1022
1047
|
const response = await nxtlinqApi.ait.getAITByServiceIdAndController({
|
|
@@ -1267,363 +1292,70 @@ export const ChatBotProvider: React.FC<ChatBotProps> = ({
|
|
|
1267
1292
|
};
|
|
1268
1293
|
|
|
1269
1294
|
// Check permissions
|
|
1270
|
-
const hasPermission = async (
|
|
1295
|
+
const hasPermission = async (
|
|
1296
|
+
requiredPermission: string,
|
|
1297
|
+
): Promise<boolean> => {
|
|
1271
1298
|
// Use refs to get latest state values
|
|
1272
1299
|
const currentHitAddress = hitAddressRef.current;
|
|
1273
|
-
const currentAit = aitRef.current;
|
|
1274
|
-
const currentPermissions = permissionsRef.current;
|
|
1275
1300
|
const currentToken = nxtlinqAITServiceAccessTokenRef.current;
|
|
1276
1301
|
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
await connectWallet(false); // Don't show sign-in message yet
|
|
1291
|
-
setIsAutoConnecting(false); // Clear auto-connecting state
|
|
1292
|
-
|
|
1293
|
-
// Show brief success message for auto-connect
|
|
1294
|
-
showSuccess(walletTextUtils.getWalletText('Auto wallet connection successful', serviceId));
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
onAutoConnect?.(); // Call callback if provided
|
|
1298
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
1299
|
-
|
|
1300
|
-
// After auto connect, if not signed in, then auto sign-in
|
|
1301
|
-
const tokenAfterConnect = nxtlinqAITServiceAccessTokenRef.current;
|
|
1302
|
-
if (!tokenAfterConnect) {
|
|
1303
|
-
setIsAutoConnecting(true);
|
|
1304
|
-
await signInWallet(false);
|
|
1305
|
-
onAutoSignIn?.(); // Call callback if provided
|
|
1306
|
-
setIsAutoConnecting(false);
|
|
1307
|
-
showSuccess(walletTextUtils.getWalletText('Auto sign-in successful after wallet connect', serviceId));
|
|
1308
|
-
await refreshAIT();
|
|
1309
|
-
// Wait for AIT to be fully loaded with polling
|
|
1310
|
-
let attempts = 0;
|
|
1311
|
-
const maxAttempts = 5;
|
|
1312
|
-
while (!aitRef.current && attempts < maxAttempts) {
|
|
1313
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
1314
|
-
attempts++;
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
// If connection (and sign-in if needed) successful, continue with permission check
|
|
1319
|
-
const result = await hasPermission(requiredPermission, false);
|
|
1320
|
-
return result;
|
|
1321
|
-
} catch (error) {
|
|
1322
|
-
console.error('Failed to auto-connect wallet:', error);
|
|
1323
|
-
setIsAutoConnecting(false); // Clear auto-connecting state on error
|
|
1324
|
-
return false;
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
// If autoRetry is false, don't show message again, just return false
|
|
1328
|
-
return false;
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
if (!currentToken) {
|
|
1332
|
-
if (autoRetry) {
|
|
1333
|
-
setIsLoading(false); // Stop thinking before showing message
|
|
1334
|
-
setMessages(prev => [...prev, {
|
|
1335
|
-
id: Date.now().toString(),
|
|
1336
|
-
content: walletTextUtils.getWalletText('Please sign in with your HIT wallet to continue.', serviceId),
|
|
1337
|
-
role: 'assistant',
|
|
1338
|
-
timestamp: new Date().toISOString(),
|
|
1339
|
-
button: 'signIn'
|
|
1340
|
-
}]);
|
|
1341
|
-
|
|
1342
|
-
try {
|
|
1343
|
-
setIsAutoConnecting(true); // Mark as auto-signing
|
|
1344
|
-
await signInWallet(false); // Don't show success message yet
|
|
1345
|
-
onAutoSignIn?.(); // Call callback if provided
|
|
1346
|
-
setIsAutoConnecting(false); // Clear auto-signing state
|
|
1347
|
-
|
|
1348
|
-
// Show brief success message for auto-sign-in
|
|
1349
|
-
showSuccess('Auto sign-in successful');
|
|
1350
|
-
|
|
1351
|
-
// Ensure AIT is refreshed after sign-in
|
|
1352
|
-
await refreshAIT();
|
|
1353
|
-
|
|
1354
|
-
// Wait for AIT to be fully loaded with polling
|
|
1355
|
-
let attempts = 0;
|
|
1356
|
-
const maxAttempts = 5; // Wait up to 10 seconds (5 * 2000ms)
|
|
1357
|
-
while (!aitRef.current && attempts < maxAttempts) {
|
|
1358
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
1359
|
-
attempts++;
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
// Only continue if AIT is actually loaded
|
|
1363
|
-
if (aitRef.current) {
|
|
1364
|
-
// Wait a bit more to ensure permissions are also loaded
|
|
1365
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
1366
|
-
// If sign-in successful, continue with permission check
|
|
1367
|
-
const result = await hasPermission(requiredPermission, false);
|
|
1368
|
-
return result;
|
|
1369
|
-
} else {
|
|
1370
|
-
return false;
|
|
1371
|
-
}
|
|
1372
|
-
} catch (error) {
|
|
1373
|
-
console.error('Failed to auto-sign-in wallet:', error);
|
|
1374
|
-
setIsAutoConnecting(false); // Clear auto-signing state on error
|
|
1375
|
-
return false;
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
// If autoRetry is false, don't show message again, just return false
|
|
1379
|
-
return false;
|
|
1380
|
-
}
|
|
1381
|
-
|
|
1382
|
-
try {
|
|
1383
|
-
const payload = JSON.parse(atob(currentToken.split('.')[1]));
|
|
1384
|
-
const address = payload.address;
|
|
1385
|
-
if (address !== currentHitAddress) {
|
|
1386
|
-
setNxtlinqAITServiceAccessToken('');
|
|
1387
|
-
if (autoRetry) {
|
|
1388
|
-
setIsLoading(false); // Stop thinking before showing message
|
|
1389
|
-
setMessages(prev => [...prev, {
|
|
1390
|
-
id: Date.now().toString(),
|
|
1391
|
-
content: walletTextUtils.getWalletText('Wallet address mismatch. Please sign in with the correct wallet.', serviceId),
|
|
1392
|
-
role: 'assistant',
|
|
1393
|
-
timestamp: new Date().toISOString(),
|
|
1394
|
-
button: 'signIn'
|
|
1395
|
-
}]);
|
|
1396
|
-
|
|
1397
|
-
try {
|
|
1398
|
-
setIsAutoConnecting(true); // Mark as auto-signing
|
|
1399
|
-
await signInWallet(false); // Don't show success message yet
|
|
1400
|
-
onAutoSignIn?.(); // Call callback if provided
|
|
1401
|
-
setIsAutoConnecting(false); // Clear auto-signing state
|
|
1402
|
-
|
|
1403
|
-
// Show brief success message for auto-sign-in after address mismatch
|
|
1404
|
-
showSuccess('Auto sign-in successful after address mismatch');
|
|
1405
|
-
|
|
1406
|
-
// Ensure AIT is refreshed after sign-in
|
|
1407
|
-
await refreshAIT();
|
|
1408
|
-
|
|
1409
|
-
// Wait for AIT to be fully loaded with polling
|
|
1410
|
-
let attempts = 0;
|
|
1411
|
-
const maxAttempts = 5; // Wait up to 10 seconds (5 * 2000ms)
|
|
1412
|
-
while (!aitRef.current && attempts < maxAttempts) {
|
|
1413
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
1414
|
-
attempts++;
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
|
-
// Only continue if AIT is actually loaded
|
|
1418
|
-
if (aitRef.current) {
|
|
1419
|
-
// Wait a bit more to ensure permissions are also loaded
|
|
1420
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
1421
|
-
// If sign-in successful, continue with permission check
|
|
1422
|
-
const result = await hasPermission(requiredPermission, false);
|
|
1423
|
-
return result;
|
|
1424
|
-
} else {
|
|
1425
|
-
return false;
|
|
1426
|
-
}
|
|
1427
|
-
} catch (error) {
|
|
1428
|
-
console.error('Failed to auto-sign-in after address mismatch:', error);
|
|
1429
|
-
setIsAutoConnecting(false); // Clear auto-signing state on error
|
|
1430
|
-
return false;
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
// If autoRetry is false, don't show message again, just return false
|
|
1434
|
-
return false;
|
|
1435
|
-
}
|
|
1436
|
-
} catch (error) {
|
|
1437
|
-
console.error('Error parsing token:', error);
|
|
1438
|
-
setNxtlinqAITServiceAccessToken('');
|
|
1439
|
-
if (autoRetry) {
|
|
1440
|
-
setIsLoading(false); // Stop thinking before showing message
|
|
1441
|
-
setMessages(prev => [...prev, {
|
|
1442
|
-
id: Date.now().toString(),
|
|
1443
|
-
content: walletTextUtils.getWalletText('Invalid wallet session. Please sign in again.', serviceId),
|
|
1444
|
-
role: 'assistant',
|
|
1445
|
-
timestamp: new Date().toISOString(),
|
|
1446
|
-
button: 'signIn'
|
|
1447
|
-
}]);
|
|
1448
|
-
|
|
1449
|
-
try {
|
|
1450
|
-
setIsAutoConnecting(true); // Mark as auto-signing
|
|
1451
|
-
await signInWallet(false); // Don't show success message yet
|
|
1452
|
-
onAutoSignIn?.(); // Call callback if provided
|
|
1453
|
-
setIsAutoConnecting(false); // Clear auto-signing state
|
|
1454
|
-
|
|
1455
|
-
// Show brief success message for auto-sign-in after token parse error
|
|
1456
|
-
showSuccess('Auto sign-in successful after token error');
|
|
1457
|
-
|
|
1458
|
-
// Ensure AIT is refreshed after sign-in
|
|
1459
|
-
await refreshAIT();
|
|
1460
|
-
|
|
1461
|
-
// Wait for AIT to be fully loaded with polling
|
|
1462
|
-
let attempts = 0;
|
|
1463
|
-
const maxAttempts = 5; // Wait up to 10 seconds (5 * 2000ms)
|
|
1464
|
-
while (!aitRef.current && attempts < maxAttempts) {
|
|
1465
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
1466
|
-
attempts++;
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1469
|
-
// Only continue if AIT is actually loaded
|
|
1470
|
-
if (aitRef.current) {
|
|
1471
|
-
// Wait a bit more to ensure permissions are also loaded
|
|
1472
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
1473
|
-
// If sign-in successful, continue with permission check
|
|
1474
|
-
const result = await hasPermission(requiredPermission, false);
|
|
1475
|
-
return result;
|
|
1476
|
-
} else {
|
|
1477
|
-
return false;
|
|
1478
|
-
}
|
|
1479
|
-
} catch (signInError) {
|
|
1480
|
-
console.error('Failed to auto-sign-in after token parse error:', signInError);
|
|
1481
|
-
setIsAutoConnecting(false); // Clear auto-signing state on error
|
|
1482
|
-
return false;
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
// If autoRetry is false, don't show message again, just return false
|
|
1486
|
-
return false;
|
|
1487
|
-
}
|
|
1488
|
-
|
|
1489
|
-
if (!currentAit) {
|
|
1490
|
-
// Show loading message if AIT is still loading
|
|
1491
|
-
if (isAITLoading) {
|
|
1492
|
-
setIsLoading(false); // Stop thinking before showing message
|
|
1493
|
-
setMessages(prev => [...prev, {
|
|
1494
|
-
id: Date.now().toString(),
|
|
1495
|
-
content: walletTextUtils.getWalletText('Loading your wallet configuration... Please wait a moment.', serviceId),
|
|
1496
|
-
role: 'assistant',
|
|
1497
|
-
timestamp: new Date().toISOString()
|
|
1498
|
-
}]);
|
|
1499
|
-
return false;
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
// If AIT is not loaded but we have a token, try to refresh it once
|
|
1503
|
-
if (currentToken && !isAITLoading) {
|
|
1504
|
-
try {
|
|
1505
|
-
await refreshAIT();
|
|
1506
|
-
// Wait for AIT to be loaded with polling
|
|
1507
|
-
let attempts = 0;
|
|
1508
|
-
const maxAttempts = 5; // Wait up to 10 seconds (5 * 2000ms)
|
|
1509
|
-
while (!aitRef.current && attempts < maxAttempts) {
|
|
1510
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
1511
|
-
attempts++;
|
|
1512
|
-
}
|
|
1513
|
-
// Check again after refresh
|
|
1514
|
-
if (!aitRef.current) {
|
|
1515
|
-
setIsLoading(false); // Stop thinking before showing message
|
|
1516
|
-
setMessages(prev => [...prev, {
|
|
1517
|
-
id: Date.now().toString(),
|
|
1518
|
-
content: walletTextUtils.getWalletText('No AIT found for your wallet. Please click the settings button (⚙️) to configure your AIT permissions.', serviceId),
|
|
1519
|
-
role: 'assistant',
|
|
1520
|
-
timestamp: new Date().toISOString()
|
|
1521
|
-
}]);
|
|
1522
|
-
return false;
|
|
1523
|
-
}
|
|
1524
|
-
} catch (error) {
|
|
1525
|
-
console.error('Failed to refresh AIT during permission check:', error);
|
|
1526
|
-
setIsLoading(false); // Stop thinking before showing message
|
|
1527
|
-
setMessages(prev => [...prev, {
|
|
1528
|
-
id: Date.now().toString(),
|
|
1529
|
-
content: 'No AIT found for your wallet. Please click the settings button (⚙️) to configure your AIT permissions.',
|
|
1530
|
-
role: 'assistant',
|
|
1531
|
-
timestamp: new Date().toISOString()
|
|
1532
|
-
}]);
|
|
1533
|
-
return false;
|
|
1534
|
-
}
|
|
1535
|
-
} else {
|
|
1536
|
-
setIsLoading(false); // Stop thinking before showing message
|
|
1537
|
-
setMessages(prev => [...prev, {
|
|
1538
|
-
id: Date.now().toString(),
|
|
1539
|
-
content: 'No AIT found for your wallet. Please click the settings button (⚙️) to configure your AIT permissions.',
|
|
1540
|
-
role: 'assistant',
|
|
1541
|
-
timestamp: new Date().toISOString()
|
|
1542
|
-
}]);
|
|
1543
|
-
return false;
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
if (availablePermissions.length === 0) {
|
|
1548
|
-
setIsLoading(false); // Stop thinking before showing message
|
|
1549
|
-
setMessages(prev => [...prev, {
|
|
1550
|
-
id: Date.now().toString(),
|
|
1551
|
-
content: `No permissions available for your current identity provider. Please check your service configuration or contact support. Service ID: ${serviceId}, Permission Group: ${permissionGroup || 'None'}`,
|
|
1552
|
-
role: 'assistant',
|
|
1553
|
-
timestamp: new Date().toISOString()
|
|
1554
|
-
}]);
|
|
1555
|
-
return false;
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
|
-
const checkToolPermissionResult = await nxtlinqApi.agent.checkToolPermission({
|
|
1302
|
+
const authorization = await authorizeTextFrontendTool({
|
|
1303
|
+
api: nxtlinqApi,
|
|
1304
|
+
serviceId,
|
|
1305
|
+
toolName: requiredPermission,
|
|
1306
|
+
snapshot: {
|
|
1307
|
+
walletAddress: currentHitAddress,
|
|
1308
|
+
walletToken: currentToken,
|
|
1309
|
+
// Legacy AIT issuance is unscoped (`externalId=''`). Do not impose a
|
|
1310
|
+
// wallet-address subject until issuance/migration supports it.
|
|
1311
|
+
externalId: undefined,
|
|
1312
|
+
requireWalletIDVVerification,
|
|
1313
|
+
loading: isAITLoading || isAutoConnecting,
|
|
1314
|
+
},
|
|
1559
1315
|
...authFields(),
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
})
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
role: 'assistant',
|
|
1604
|
-
timestamp: new Date().toISOString()
|
|
1605
|
-
}]);
|
|
1606
|
-
return false;
|
|
1607
|
-
}
|
|
1608
|
-
|
|
1609
|
-
// User has AIT but hasn't enabled this permission → prompt to enable
|
|
1610
|
-
setIsLoading(false); // Stop thinking before showing message
|
|
1611
|
-
const permissionMsg = `You don't have the required AIT permission: ${requiredPermission}. Would you like to enable AIT permission?`;
|
|
1612
|
-
setMessages(prev => [
|
|
1613
|
-
...prev,
|
|
1614
|
-
{
|
|
1615
|
-
id: Date.now().toString(),
|
|
1616
|
-
content: permissionMsg,
|
|
1617
|
-
role: 'assistant',
|
|
1618
|
-
timestamp: new Date().toISOString(),
|
|
1619
|
-
button: 'enableAIT',
|
|
1620
|
-
metadata: { requiredPermission }
|
|
1621
|
-
}
|
|
1622
|
-
]);
|
|
1623
|
-
return false;
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
return true;
|
|
1316
|
+
customUsername: (!requireWalletIDVVerification && customUsername)
|
|
1317
|
+
? getFinalCustomUsername(customUsername)
|
|
1318
|
+
: undefined,
|
|
1319
|
+
});
|
|
1320
|
+
if (authorization.status === 'allowed') return true;
|
|
1321
|
+
|
|
1322
|
+
setIsLoading(false);
|
|
1323
|
+
const recovery: Message = {
|
|
1324
|
+
id: Date.now().toString(),
|
|
1325
|
+
content: 'Authorization is temporarily unavailable. Please try again.',
|
|
1326
|
+
role: 'assistant',
|
|
1327
|
+
timestamp: new Date().toISOString(),
|
|
1328
|
+
};
|
|
1329
|
+
switch (authorization.status) {
|
|
1330
|
+
case 'wallet_disconnected':
|
|
1331
|
+
recovery.content = walletTextUtils.getWalletText('Please connect your HIT wallet to continue.', serviceId);
|
|
1332
|
+
recovery.button = 'connectWallet';
|
|
1333
|
+
break;
|
|
1334
|
+
case 'wallet_signed_out':
|
|
1335
|
+
recovery.content = walletTextUtils.getWalletText('Please sign in with your HIT wallet to continue.', serviceId);
|
|
1336
|
+
recovery.button = 'signIn';
|
|
1337
|
+
break;
|
|
1338
|
+
case 'wallet_session_invalid':
|
|
1339
|
+
recovery.content = walletTextUtils.getWalletText('Invalid wallet session. Please sign in again.', serviceId);
|
|
1340
|
+
recovery.button = 'signIn';
|
|
1341
|
+
break;
|
|
1342
|
+
case 'wallet_verification_required':
|
|
1343
|
+
recovery.content = 'Please verify your wallet identity before using this tool.';
|
|
1344
|
+
recovery.button = 'verifyWallet';
|
|
1345
|
+
break;
|
|
1346
|
+
case 'ait_not_found':
|
|
1347
|
+
recovery.content = 'No AIT found for your wallet. Please open settings to configure your AIT.';
|
|
1348
|
+
break;
|
|
1349
|
+
case 'permission_denied':
|
|
1350
|
+
recovery.content = `You don't have the required AIT permission: ${authorization.requiredPermission}. Would you like to enable AIT permission?`;
|
|
1351
|
+
recovery.button = 'enableAIT';
|
|
1352
|
+
recovery.metadata = { requiredPermission: authorization.requiredPermission };
|
|
1353
|
+
break;
|
|
1354
|
+
case 'authorization_unavailable':
|
|
1355
|
+
break;
|
|
1356
|
+
}
|
|
1357
|
+
setMessages(prev => [...prev, recovery]);
|
|
1358
|
+
return false;
|
|
1627
1359
|
};
|
|
1628
1360
|
|
|
1629
1361
|
// AI Model related functions
|
|
@@ -1679,6 +1411,9 @@ export const ChatBotProvider: React.FC<ChatBotProps> = ({
|
|
|
1679
1411
|
const hasContent = content.trim() || (attachments && attachments.length > 0);
|
|
1680
1412
|
if (!hasContent || isLoading) return;
|
|
1681
1413
|
setPendingAutoTts(null);
|
|
1414
|
+
const turnExternalId = typeof window !== 'undefined'
|
|
1415
|
+
? localStorage.getItem('walletAddress') || undefined
|
|
1416
|
+
: hitAddressRef.current || undefined;
|
|
1682
1417
|
|
|
1683
1418
|
const currentModel = getCurrentModel();
|
|
1684
1419
|
// Initialize with current model, will be updated with actual model from backend response
|
|
@@ -1757,7 +1492,7 @@ export const ChatBotProvider: React.FC<ChatBotProps> = ({
|
|
|
1757
1492
|
model: currentModel.value,
|
|
1758
1493
|
...authFields(),
|
|
1759
1494
|
pseudoId: pseudoId,
|
|
1760
|
-
externalId:
|
|
1495
|
+
externalId: turnExternalId,
|
|
1761
1496
|
customUserInfo,
|
|
1762
1497
|
customUsername,
|
|
1763
1498
|
message: content || (attachments && attachments.length > 0 ? `Uploaded ${attachments.length} file(s)` : ''),
|
|
@@ -1987,93 +1722,13 @@ export const ChatBotProvider: React.FC<ChatBotProps> = ({
|
|
|
1987
1722
|
|
|
1988
1723
|
let toolMsg = '';
|
|
1989
1724
|
if (onToolUse) {
|
|
1990
|
-
let wasAutoConnected = false;
|
|
1991
|
-
let wasAutoSignedIn = false;
|
|
1992
|
-
// Added: Mark if permission denied due to missing AIT permission
|
|
1993
|
-
let permissionDenied = false;
|
|
1994
|
-
// Use requiredPermission from response if available, otherwise fall back to toolUse.name
|
|
1995
|
-
const permissionToCheck = (response as any)?.requiredPermission || toolUse.name;
|
|
1996
|
-
|
|
1997
1725
|
const isToolAllowed = await hasPermission(
|
|
1998
|
-
|
|
1999
|
-
true,
|
|
2000
|
-
() => { wasAutoConnected = true },
|
|
2001
|
-
() => { wasAutoSignedIn = true }
|
|
1726
|
+
toolUse.name,
|
|
2002
1727
|
);
|
|
2003
1728
|
|
|
2004
|
-
//
|
|
2005
|
-
if (!isToolAllowed && !permissions.includes(permissionToCheck) && availablePermissions.map(p => p.label).includes(permissionToCheck)) {
|
|
2006
|
-
permissionDenied = true;
|
|
2007
|
-
}
|
|
1729
|
+
// Typed preflight already emitted the only permitted recovery UI.
|
|
2008
1730
|
if (!isToolAllowed) {
|
|
2009
|
-
// If permission denied due to missing AIT permission return
|
|
2010
|
-
if (permissionDenied) {
|
|
2011
|
-
setIsLoading(false);
|
|
2012
|
-
return;
|
|
2013
|
-
}
|
|
2014
|
-
|
|
2015
|
-
if (isSemiAutomaticMode) {
|
|
2016
|
-
setIsLoading(false);
|
|
2017
|
-
setMessages(prev => [...prev, {
|
|
2018
|
-
id: Date.now().toString(),
|
|
2019
|
-
content: 'Click button to continue using tool',
|
|
2020
|
-
role: 'assistant',
|
|
2021
|
-
timestamp: new Date().toISOString(),
|
|
2022
|
-
button: 'continue'
|
|
2023
|
-
}]);
|
|
2024
|
-
return;
|
|
2025
|
-
} else {
|
|
2026
|
-
// Only retry for auto-connect/auto-sign-in scenarios
|
|
2027
|
-
if (wasAutoConnected && retryCount < 1) {
|
|
2028
|
-
// Clear loading state and retry immediately
|
|
2029
|
-
setIsLoading(false);
|
|
2030
|
-
|
|
2031
|
-
// Check if wallet is already signed in
|
|
2032
|
-
const currentToken = nxtlinqAITServiceAccessTokenRef.current;
|
|
2033
|
-
|
|
2034
|
-
if (!currentToken) {
|
|
2035
|
-
// If not signed in, directly retry the message without waiting for AIT
|
|
2036
|
-
setTimeout(() => {
|
|
2037
|
-
sendMessage(content, retryCount + 1, isPresetMessage);
|
|
2038
|
-
}, 2000);
|
|
2039
|
-
} else {
|
|
2040
|
-
// If already signed in, wait for AIT to be fully loaded before retrying
|
|
2041
|
-
setTimeout(async () => {
|
|
2042
|
-
// Wait for AIT to be loaded if needed
|
|
2043
|
-
if (!aitRef.current && nxtlinqAITServiceAccessTokenRef.current) {
|
|
2044
|
-
await refreshAIT();
|
|
2045
|
-
}
|
|
2046
|
-
|
|
2047
|
-
// Wait for AIT to be fully loaded with polling
|
|
2048
|
-
let attempts = 0;
|
|
2049
|
-
const maxAttempts = 5; // Wait up to 10 seconds (5 * 2000ms)
|
|
2050
|
-
while (!aitRef.current && attempts < maxAttempts) {
|
|
2051
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
2052
|
-
attempts++;
|
|
2053
|
-
}
|
|
2054
|
-
|
|
2055
|
-
// Only retry if AIT is actually loaded
|
|
2056
|
-
if (aitRef.current) {
|
|
2057
|
-
// Wait a bit more to ensure permissions are also loaded
|
|
2058
|
-
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
2059
|
-
sendMessage(content, retryCount + 1, isPresetMessage);
|
|
2060
|
-
}
|
|
2061
|
-
}, 2000);
|
|
2062
|
-
}
|
|
2063
|
-
}
|
|
2064
|
-
return;
|
|
2065
|
-
}
|
|
2066
|
-
}
|
|
2067
|
-
|
|
2068
|
-
if (isSemiAutomaticMode && wasAutoSignedIn) {
|
|
2069
1731
|
setIsLoading(false);
|
|
2070
|
-
setMessages(prev => [...prev, {
|
|
2071
|
-
id: Date.now().toString(),
|
|
2072
|
-
content: 'Click button to continue using tool',
|
|
2073
|
-
role: 'assistant',
|
|
2074
|
-
timestamp: new Date().toISOString(),
|
|
2075
|
-
button: 'continue'
|
|
2076
|
-
}]);
|
|
2077
1732
|
return;
|
|
2078
1733
|
}
|
|
2079
1734
|
|
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 {
|
|
@@ -81,11 +81,6 @@ export interface ChatBotProps {
|
|
|
81
81
|
isStopRecordingOnSend?: boolean; // Stop recording automatically when sending message (default: false)
|
|
82
82
|
// Custom error message to display in chat
|
|
83
83
|
customError?: string; // Custom error message to display as a chat message when provided
|
|
84
|
-
/** PII display mode: how PII protection is visualized in chat messages
|
|
85
|
-
* - 'plain': No visualization, messages look like normal chat
|
|
86
|
-
* - 'redacted': Anonymized text with PII tokens displayed (default)
|
|
87
|
-
*/
|
|
88
|
-
piiDisplayMode?: 'plain' | 'redacted';
|
|
89
84
|
/** Override mic VAD thresholds. Useful for tuning sensitivity per deployment. */
|
|
90
85
|
voiceThresholds?: {
|
|
91
86
|
speechRmsThreshold?: number;
|
|
@@ -139,7 +134,8 @@ export interface ChatBotContextType {
|
|
|
139
134
|
selectedModelIndex: number;
|
|
140
135
|
showModelSelector: boolean;
|
|
141
136
|
suggestions: PresetMessage[];
|
|
142
|
-
// PII Protection visualization
|
|
137
|
+
// PII Protection visualization — derived internally from the service's own config
|
|
138
|
+
// (fetched via serviceId + credentials), never settable from outside the provider.
|
|
143
139
|
piiDisplayMode: 'plain' | 'redacted';
|
|
144
140
|
// Realtime voice mode (WebRTC)
|
|
145
141
|
isVoiceMode: boolean;
|