@bytexbyte/nxtlinq-ai-agent-sdk 1.1.9 → 1.2.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
@@ -13,15 +13,17 @@ A powerful SDK for building intelligent conversation applications with Nxtlinq A
13
13
  - 🔌 Easy integration with React applications
14
14
  - 🔒 Secure authentication and API key management
15
15
  - 👛 MetaMask wallet integration
16
- - 🔐 AIT (AI Token) management
16
+ - 🔐 AIT (AI Identity Token) management
17
17
  - 🔑 Permission-based access control
18
+ - 🔍 Enhanced error handling and debugging
19
+ - ⚡ Improved async operation handling
18
20
 
19
21
  ## Installation
20
22
 
21
23
  ```bash
22
- npm install @bytexbyte/nxtlinq-ai-agent-sdk
24
+ npm install @bytexbyte/nxtlinq-ai-agent-sdk@1.1.9
23
25
  # or
24
- yarn add @bytexbyte/nxtlinq-ai-agent-sdk
26
+ yarn add @bytexbyte/nxtlinq-ai-agent-sdk@1.1.9
25
27
  ```
26
28
 
27
29
  ## Quick Start
@@ -59,8 +61,8 @@ function App() {
59
61
  onMessage={handleMessage}
60
62
  onToolUse={handleToolUse}
61
63
  presetMessages={presetMessages}
62
- onVerifyWallet={async (address) => {
63
- // Implement your wallet verification logic here
64
+ onVerifyWallet={async () => {
65
+ // Implement Berify.me verification
64
66
  return { token: 'verification-token' };
65
67
  }}
66
68
  />
@@ -68,47 +70,47 @@ function App() {
68
70
  }
69
71
  ```
70
72
 
71
- ## API Reference
72
-
73
- ### NxtlinqAITSDK
74
-
75
- | Method | Description |
76
- |--------|-------------|
77
- | `connectWallet()` | Connect to MetaMask wallet |
78
- | `verifyWallet(token: string, method: string)` | Verify wallet ownership |
79
- | `signInWithWallet()` | Sign in using wallet |
80
- | `generateAndRegisterAIT(permissions: string[])` | Generate and register a new AIT |
81
- | `getAIT()` | Get AIT information |
82
- | `getWalletInfo()` | Get wallet information |
83
-
84
- ### NxtlinqAIAgent
85
-
86
- | Method | Description |
87
- |--------|-------------|
88
- | `setAIT(ait: AIT, signer?: ethers.Signer)` | Set AIT for the agent |
89
- | `generateAIT(options: GenerateAITOptions)` | Generate a new AIT |
90
- | `getAITInfo(serviceId: string, controller: string, signer?: ethers.Signer)` | Get AIT information |
91
- | `sendMessage(message: string, toolName?: string)` | Send a message to the agent |
92
-
93
- ### API Endpoints
73
+ ## Berify.me Integration
94
74
 
95
- #### AIT API
96
- - `getAITByServiceIdAndController`: Get AIT by service ID and controller
97
- - `createAIT`: Create a new AIT
75
+ The SDK supports Berify.me wallet verification for enhanced security:
98
76
 
99
- #### Wallet API
100
- - `verifyWallet`: Verify wallet ownership
101
- - `getWallet`: Get wallet information
77
+ ```tsx
78
+ import { ChatBot } from '@bytexbyte/nxtlinq-ai-agent-sdk';
102
79
 
103
- #### Metadata API
104
- - `createMetadata`: Create metadata for AIT
80
+ function App() {
81
+ const handleVerifyWallet = async () => {
82
+ // Open Berify.me verification modal
83
+ const modal = window.open(
84
+ 'https://berify.me/verify',
85
+ 'BerifyMeModal',
86
+ 'width=500,height=600'
87
+ );
88
+
89
+ return new Promise((resolve) => {
90
+ const handleMessage = (event) => {
91
+ if (event.origin === 'https://berify.me' && event.data.type === 'VERIFICATION_SUCCESS') {
92
+ window.removeEventListener('message', handleMessage);
93
+ modal?.close();
94
+ resolve({ token: event.data.token });
95
+ }
96
+ };
97
+
98
+ window.addEventListener('message', handleMessage);
99
+ });
100
+ };
105
101
 
106
- #### Auth API
107
- - `getNonce`: Get nonce for wallet sign-in
108
- - `signIn`: Sign in with wallet
102
+ return (
103
+ <ChatBot
104
+ serviceId="your-service-id"
105
+ apiKey="your-api-key"
106
+ apiSecret="your-api-secret"
107
+ onVerifyWallet={handleVerifyWallet}
108
+ />
109
+ );
110
+ }
111
+ ```
109
112
 
110
- #### Agent API
111
- - `sendMessage`: Send message to AI agent
113
+ ## API Reference
112
114
 
113
115
  ### ChatBot Component Props
114
116
 
@@ -120,12 +122,13 @@ function App() {
120
122
  | onMessage | (message: Message) => void | No | Callback when a new message is received |
121
123
  | onError | (error: Error) => void | No | Callback when an error occurs |
122
124
  | onToolUse | (toolUse: ToolUse) => Promise<Message \| void> | No | Callback for handling tool usage |
123
- | onVerifyWallet | (address: string) => Promise<{ token: string }> | Yes | Callback for wallet verification |
125
+ | onVerifyWallet | () => Promise<{ token: string } \| undefined> | Yes | Callback for wallet verification |
124
126
  | presetMessages | PresetMessage[] | No | Array of preset messages to display |
125
127
  | placeholder | string | No | Input placeholder text (default: "Type a message...") |
126
128
  | className | string | No | Additional CSS class name |
127
129
  | maxRetries | number | No | Maximum number of retry attempts (default: 3) |
128
130
  | retryDelay | number | No | Delay between retries in milliseconds (default: 1000) |
131
+ | permissionGroup | string | No | Permission group name for filtering permissions |
129
132
 
130
133
  ## Types
131
134
 
@@ -136,7 +139,7 @@ interface Message {
136
139
  content: string;
137
140
  role: 'user' | 'assistant';
138
141
  timestamp: string;
139
- button?: boolean;
142
+ button?: string;
140
143
  error?: string;
141
144
  }
142
145
  ```
@@ -165,7 +168,6 @@ interface AIT {
165
168
  metadata: AITMetadata;
166
169
  metadataHash: string;
167
170
  metadataCid: string;
168
- signature: string;
169
171
  }
170
172
 
171
173
  interface AITMetadata {
@@ -174,39 +176,15 @@ interface AITMetadata {
174
176
  issuedBy: string;
175
177
  serviceId?: string;
176
178
  }
179
+ ```
177
180
 
178
- interface AITInfo {
179
- aitId: string;
180
- controller: string;
181
- metadata: AITMetadata;
182
- metadataHash: string;
183
- metadataCid: string;
184
- signature: string;
185
- }
186
-
187
- interface AITPermission {
188
- hasPermission: boolean;
189
- reason?: string;
190
- permissions?: string[];
191
- }
192
-
193
- interface GenerateAITOptions {
194
- hitAddress: string;
195
- signer: ethers.Signer;
196
- permissions: string[];
197
- serviceId: string;
198
- }
199
-
200
- interface WalletInfo {
181
+ ### ServicePermission
182
+ ```typescript
183
+ interface ServicePermission {
201
184
  id: string;
202
- address: string;
203
- verified: boolean;
204
- method?: string;
205
- }
206
-
207
- interface MessageContext {
208
- aitId?: string;
209
- walletAddress?: string | null;
185
+ label: string;
186
+ description: string;
187
+ groups: string[];
210
188
  }
211
189
  ```
212
190
 
@@ -214,30 +192,32 @@ interface MessageContext {
214
192
 
215
193
  ### Wallet Integration
216
194
  - MetaMask wallet connection
217
- - Wallet verification
195
+ - Berify.me wallet verification
218
196
  - Wallet-based authentication
219
- - AIT (AI Token) generation and management
220
-
221
- ### Available Permissions
222
- - Set User Name
223
- - Navigate To Page
224
- - Add Member
197
+ - AIT (AI Identity Token) generation and management
225
198
 
226
199
  ### Authentication Flow
227
200
  1. Connect MetaMask wallet
228
- 2. Verify wallet ownership
201
+ 2. Verify wallet ownership (optional, via Berify.me)
229
202
  3. Sign in with wallet
230
203
  4. Generate and register AIT with required permissions
231
204
  5. Use AIT for authenticated operations
232
205
 
206
+ ### Enhanced Error Handling
207
+ - Improved async operation handling
208
+ - Better state management
209
+ - Detailed error messages
210
+ - Comprehensive debugging logs
211
+
233
212
  ## Error Handling
234
213
 
235
- The SDK includes built-in error handling with:
214
+ The SDK includes enhanced error handling with:
236
215
  - Automatic retry mechanism for failed requests
237
216
  - Error callback for custom error handling
238
217
  - User-friendly error messages
239
218
  - Wallet connection error handling
240
219
  - Authentication error handling
220
+ - Detailed console logging for debugging
241
221
 
242
222
  ## Best Practices
243
223
 
@@ -248,6 +228,32 @@ The SDK includes built-in error handling with:
248
228
  5. Use context management to maintain conversation coherence
249
229
  6. Handle wallet connection errors gracefully
250
230
  7. Implement proper error handling for authentication flow
231
+ 8. Monitor console logs for debugging
232
+
233
+ ## Troubleshooting
234
+
235
+ Having issues? Check our [Troubleshooting Guide](./TROUBLESHOOTING.md) which includes:
236
+
237
+ - Common problems and solutions
238
+ - Authentication debugging steps
239
+ - Permission issue resolution
240
+ - Best practice recommendations
241
+
242
+ ### Common Issues
243
+
244
+ **Q: Still need to sign in after connecting wallet?**
245
+ A: This is usually due to expired authentication tokens or address mismatches. Check browser console logs and refer to the [Troubleshooting Guide](./TROUBLESHOOTING.md) for detailed solutions.
246
+
247
+ **Q: Cannot use specific AI tool features?**
248
+ A: Check AIT permission settings to ensure required tool permissions are included. See [Troubleshooting Guide](./TROUBLESHOOTING.md) for details.
249
+
250
+ ## Changelog
251
+
252
+ ### v1.1.9
253
+ - 🔧 Fixed async operation timing issues in wallet connection
254
+ - 🐛 Improved state management for AIT validation
255
+ - 📝 Enhanced error messages and debugging logs
256
+ - ⚡ Better handling of authentication flow
251
257
 
252
258
  ## License
253
259
 
@@ -1 +1 @@
1
- {"version":3,"file":"ChatBot.d.ts","sourceRoot":"","sources":["../../src/components/ChatBot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,OAAO,EAAE,OAAO,EAAkC,MAAM,kBAAkB,CAAC;AAE3E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC1D,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC;QAC7B,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,SAAS,CAAC,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AA0VD,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAk8B1C,CAAC"}
1
+ {"version":3,"file":"ChatBot.d.ts","sourceRoot":"","sources":["../../src/components/ChatBot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,OAAO,EAAE,OAAO,EAAkC,MAAM,kBAAkB,CAAC;AAE3E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC1D,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC;QAC7B,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,SAAS,CAAC,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AA2cD,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAogC1C,CAAC"}
@@ -5,8 +5,9 @@ import { createNxtlinqApi } from '../api/nxtlinq-api';
5
5
  import stringify from 'fast-json-stable-stringify';
6
6
  import metakeepClient from '../core/metakeepClient';
7
7
  import useLocalStorage from '../core/lib/useLocalStorage';
8
- const PermissionForm = ({ hitAddress, permissions, setPermissions, setIsDisabled, onClose, onSave, onConnectWallet, onSignIn, isNeedSignInWithWallet, walletInfo, onVerifyWallet, serviceId, nxtlinqApi, permissionGroup }) => {
8
+ const PermissionForm = ({ hitAddress, permissions, setPermissions, setIsDisabled, onClose, onSave, onConnectWallet, onSignIn, isNeedSignInWithWallet, walletInfo, onVerifyWallet, serviceId, nxtlinqApi, permissionGroup, isAITLoading, isWalletLoading = false }) => {
9
9
  const [availablePermissions, setAvailablePermissions] = React.useState([]);
10
+ const [isSaving, setIsSaving] = React.useState(false);
10
11
  const fetchAvailablePermissions = async () => {
11
12
  if (!serviceId)
12
13
  return;
@@ -28,7 +29,72 @@ const PermissionForm = ({ hitAddress, permissions, setPermissions, setIsDisabled
28
29
  React.useEffect(() => {
29
30
  fetchAvailablePermissions();
30
31
  }, [serviceId, nxtlinqApi, permissionGroup]);
31
- const isWalletVerified = walletInfo?.id;
32
+ const isWalletVerified = Boolean(walletInfo?.id);
33
+ const handleSave = async () => {
34
+ setIsSaving(true);
35
+ try {
36
+ await onSave();
37
+ }
38
+ finally {
39
+ setIsSaving(false);
40
+ }
41
+ };
42
+ // Show loading state while checking wallet status
43
+ if (isWalletLoading) {
44
+ return (_jsxs("div", { style: {
45
+ backgroundColor: 'white',
46
+ padding: '24px',
47
+ borderRadius: '12px',
48
+ width: '480px',
49
+ maxWidth: '90%',
50
+ boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)'
51
+ }, children: [_jsxs("div", { style: {
52
+ display: 'flex',
53
+ justifyContent: 'space-between',
54
+ alignItems: 'center',
55
+ marginBottom: '24px'
56
+ }, children: [_jsx("h3", { style: {
57
+ margin: 0,
58
+ fontSize: '20px',
59
+ fontWeight: '600',
60
+ color: '#1a1a1a'
61
+ }, children: "AIT Settings" }), _jsx("button", { onClick: onClose, style: {
62
+ background: 'none',
63
+ border: 'none',
64
+ fontSize: '24px',
65
+ cursor: 'pointer',
66
+ color: '#666',
67
+ padding: '4px',
68
+ display: 'flex',
69
+ alignItems: 'center',
70
+ justifyContent: 'center'
71
+ }, children: "\u00D7" })] }), _jsxs("div", { style: { textAlign: 'center', padding: '32px 0' }, children: [_jsx("div", { style: {
72
+ width: '64px',
73
+ height: '64px',
74
+ margin: '0 auto 16px',
75
+ backgroundColor: '#f5f5f5',
76
+ borderRadius: '50%',
77
+ display: 'flex',
78
+ alignItems: 'center',
79
+ justifyContent: 'center'
80
+ }, children: _jsx("div", { style: {
81
+ width: '32px',
82
+ height: '32px',
83
+ border: '3px solid #e3e3e3',
84
+ borderTop: '3px solid #007bff',
85
+ borderRadius: '50%',
86
+ animation: 'spin 1s linear infinite'
87
+ } }) }), _jsx("p", { style: {
88
+ marginBottom: '24px',
89
+ fontSize: '16px',
90
+ color: '#666'
91
+ }, children: "Checking wallet status..." })] }), _jsx("style", { children: `
92
+ @keyframes spin {
93
+ 0% { transform: rotate(0deg); }
94
+ 100% { transform: rotate(360deg); }
95
+ }
96
+ ` })] }));
97
+ }
32
98
  return (_jsxs("div", { style: {
33
99
  backgroundColor: 'white',
34
100
  padding: '24px',
@@ -147,7 +213,14 @@ const PermissionForm = ({ hitAddress, permissions, setPermissions, setIsDisabled
147
213
  marginBottom: '12px',
148
214
  fontSize: '16px',
149
215
  color: '#666'
150
- }, children: "Permissions" }), _jsx("div", { style: {
216
+ }, children: "Permissions" }), isAITLoading ? (_jsx("div", { style: {
217
+ backgroundColor: '#f8f9fa',
218
+ padding: '16px',
219
+ borderRadius: '8px',
220
+ border: '1px solid #e9ecef',
221
+ textAlign: 'center',
222
+ color: '#666'
223
+ }, children: "Loading permissions..." })) : (_jsx("div", { style: {
151
224
  backgroundColor: '#f8f9fa',
152
225
  padding: '16px',
153
226
  borderRadius: '8px',
@@ -156,25 +229,36 @@ const PermissionForm = ({ hitAddress, permissions, setPermissions, setIsDisabled
156
229
  display: 'flex',
157
230
  alignItems: 'center',
158
231
  gap: '12px',
159
- cursor: 'pointer',
232
+ cursor: isAITLoading ? 'not-allowed' : 'pointer',
160
233
  padding: '8px',
161
234
  borderRadius: '6px',
162
- transition: 'background-color 0.2s'
163
- }, onMouseOver: (e) => e.currentTarget.style.backgroundColor = '#e9ecef', onMouseOut: (e) => e.currentTarget.style.backgroundColor = 'transparent', children: [_jsx("input", { type: "checkbox", checked: permissions.includes(permission.label), onChange: () => {
164
- const newPermissions = permissions.includes(permission.label)
165
- ? permissions.filter(p => p !== permission.label)
166
- : [...permissions, permission.label].sort();
167
- setPermissions(newPermissions);
168
- setIsDisabled(false);
169
- }, style: {
235
+ transition: 'background-color 0.2s',
236
+ opacity: isAITLoading ? 0.6 : 1
237
+ }, onMouseOver: (e) => {
238
+ if (!isAITLoading) {
239
+ e.currentTarget.style.backgroundColor = '#e9ecef';
240
+ }
241
+ }, onMouseOut: (e) => {
242
+ if (!isAITLoading) {
243
+ e.currentTarget.style.backgroundColor = 'transparent';
244
+ }
245
+ }, children: [_jsx("input", { type: "checkbox", checked: permissions.includes(permission.label), onChange: () => {
246
+ if (!isAITLoading) {
247
+ const newPermissions = permissions.includes(permission.label)
248
+ ? permissions.filter(p => p !== permission.label)
249
+ : [...permissions, permission.label].sort();
250
+ setPermissions(newPermissions);
251
+ setIsDisabled(false);
252
+ }
253
+ }, disabled: isAITLoading, style: {
170
254
  margin: 0,
171
255
  width: '18px',
172
256
  height: '18px',
173
- cursor: 'pointer'
257
+ cursor: isAITLoading ? 'not-allowed' : 'pointer'
174
258
  } }), _jsx("span", { style: {
175
259
  fontSize: '14px',
176
260
  color: '#333'
177
- }, children: permission.label })] }) }, permission.id))) })] }), _jsxs("div", { style: {
261
+ }, children: permission.label })] }) }, permission.id))) }))] }), _jsxs("div", { style: {
178
262
  display: 'flex',
179
263
  justifyContent: 'flex-end',
180
264
  gap: '12px',
@@ -196,25 +280,25 @@ const PermissionForm = ({ hitAddress, permissions, setPermissions, setIsDisabled
196
280
  }, onMouseOut: (e) => {
197
281
  e.currentTarget.style.backgroundColor = '#f8f9fa';
198
282
  e.currentTarget.style.borderColor = '#dee2e6';
199
- }, children: "Cancel" }), _jsx("button", { onClick: onSave, disabled: permissions.length === 0, style: {
283
+ }, children: "Cancel" }), _jsx("button", { onClick: handleSave, disabled: permissions.length === 0 || isSaving || isAITLoading, style: {
200
284
  padding: '10px 20px',
201
- backgroundColor: permissions.length === 0 ? '#e9ecef' : '#007bff',
202
- color: 'white',
285
+ backgroundColor: permissions.length === 0 || isSaving || isAITLoading ? '#e9ecef' : '#007bff',
286
+ color: permissions.length === 0 || isSaving || isAITLoading ? '#6c757d' : 'white',
203
287
  border: 'none',
204
288
  borderRadius: '8px',
205
- cursor: permissions.length === 0 ? 'not-allowed' : 'pointer',
289
+ cursor: permissions.length === 0 || isSaving || isAITLoading ? 'not-allowed' : 'pointer',
206
290
  fontSize: '14px',
207
291
  fontWeight: '500',
208
292
  transition: 'background-color 0.2s'
209
293
  }, onMouseOver: (e) => {
210
- if (permissions.length > 0) {
294
+ if (permissions.length > 0 && !isSaving && !isAITLoading) {
211
295
  e.currentTarget.style.backgroundColor = '#0056b3';
212
296
  }
213
297
  }, onMouseOut: (e) => {
214
- if (permissions.length > 0) {
298
+ if (permissions.length > 0 && !isSaving && !isAITLoading) {
215
299
  e.currentTarget.style.backgroundColor = '#007bff';
216
300
  }
217
- }, children: "Save" })] })] }))] }));
301
+ }, children: isSaving ? 'Saving...' : 'Save' })] })] }))] }));
218
302
  };
219
303
  export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], placeholder = 'Type a message...', className = '', maxRetries = 3, retryDelay = 1000, serviceId, apiKey, apiSecret, onVerifyWallet, permissionGroup }) => {
220
304
  const [messages, setMessages] = React.useState([]);
@@ -227,12 +311,15 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
227
311
  const [availablePermissions, setAvailablePermissions] = React.useState([]);
228
312
  const [showPermissionForm, setShowPermissionForm] = React.useState(false);
229
313
  const [success, setSuccess] = React.useState(false);
314
+ const [isPermissionFormOpen, setIsPermissionFormOpen] = React.useState(false);
315
+ const [isAITLoading, setIsAITLoading] = React.useState(false);
230
316
  const messagesEndRef = React.useRef(null);
231
317
  const [isDisabled, setIsDisabled] = React.useState(true);
232
318
  const [signer, setSigner] = React.useState(null);
233
319
  const [walletInfo, setWalletInfo] = React.useState(null);
234
320
  const verifyWalletBtnRef = React.useRef(null);
235
321
  const [nxtlinqAITServiceAccessToken, setNxtlinqAITServiceAccessToken] = useLocalStorage('nxtlinqAITServiceAccessToken', '');
322
+ const [isWalletLoading, setIsWalletLoading] = React.useState(false);
236
323
  const nxtlinqApi = React.useMemo(() => createNxtlinqApi(apiKey, apiSecret), [apiKey, apiSecret]);
237
324
  const fetchAvailablePermissions = async () => {
238
325
  if (!serviceId)
@@ -252,7 +339,7 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
252
339
  console.error('Error fetching permissions:', error);
253
340
  }
254
341
  };
255
- const refreshAIT = async () => {
342
+ const refreshAIT = async (forceUpdatePermissions = false) => {
256
343
  console.log('refreshAIT called');
257
344
  console.log('hitAddress:', hitAddress);
258
345
  console.log('nxtlinqAITServiceAccessToken:', nxtlinqAITServiceAccessToken);
@@ -261,6 +348,7 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
261
348
  setPermissions([]);
262
349
  return;
263
350
  }
351
+ setIsAITLoading(true);
264
352
  try {
265
353
  const response = await nxtlinqApi.ait.getAITByServiceIdAndController({
266
354
  serviceId,
@@ -274,13 +362,19 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
274
362
  }
275
363
  console.log('AIT response:', response);
276
364
  setAit(response);
277
- setPermissions(response.metadata?.permissions || []);
365
+ // Update permissions if form is not open OR if force update is requested
366
+ if (!isPermissionFormOpen || forceUpdatePermissions) {
367
+ setPermissions(response.metadata?.permissions || []);
368
+ }
278
369
  }
279
370
  catch (error) {
280
371
  console.error('Failed to fetch AIT:', error);
281
372
  setAit(null);
282
373
  setPermissions([]);
283
374
  }
375
+ finally {
376
+ setIsAITLoading(false);
377
+ }
284
378
  };
285
379
  React.useEffect(() => {
286
380
  console.log('hitAddress:', hitAddress);
@@ -313,20 +407,19 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
313
407
  if (address !== hitAddress) {
314
408
  return true;
315
409
  }
316
- // Check if AIT exists - if not, user needs to sign in to generate AIT
317
- if (!ait) {
318
- return true;
319
- }
410
+ // If user has valid token but no AIT, they don't need to sign in again
411
+ // They just need to generate AIT through the permission form
320
412
  return false;
321
413
  }
322
414
  catch (error) {
323
415
  console.error('Error parsing token:', error);
324
416
  return true;
325
417
  }
326
- }, [hitAddress, nxtlinqAITServiceAccessToken, ait]);
418
+ }, [hitAddress, nxtlinqAITServiceAccessToken]);
327
419
  const handleVerifySuccess = (address) => {
328
420
  localStorage.setItem(`wallet_verified_${address}`, 'true');
329
421
  const getWalletInfo = async () => {
422
+ setIsWalletLoading(true);
330
423
  try {
331
424
  const token = JSON.parse(localStorage.getItem('nxtlinqAITServiceAccessToken') || '');
332
425
  const walletResponse = await nxtlinqApi.wallet.getWallet({ address }, token);
@@ -346,6 +439,9 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
346
439
  catch (error) {
347
440
  console.error('Failed to update wallet info after verification:', error);
348
441
  }
442
+ finally {
443
+ setIsWalletLoading(false);
444
+ }
349
445
  };
350
446
  getWalletInfo();
351
447
  };
@@ -357,16 +453,25 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
357
453
  if (isNeedSignInWithWallet) {
358
454
  return;
359
455
  }
360
- const getWalletResponse = await nxtlinqApi.wallet.getWallet({ address: hitAddress }, nxtlinqAITServiceAccessToken);
361
- if ('error' in getWalletResponse) {
362
- if (getWalletResponse.error === 'Wallet not found') {
363
- console.log('Wallet not found - this is expected for new users');
456
+ setIsWalletLoading(true);
457
+ try {
458
+ const getWalletResponse = await nxtlinqApi.wallet.getWallet({ address: hitAddress }, nxtlinqAITServiceAccessToken);
459
+ if ('error' in getWalletResponse) {
460
+ if (getWalletResponse.error === 'Wallet not found') {
461
+ console.log('Wallet not found - this is expected for new users');
462
+ return;
463
+ }
464
+ console.error(getWalletResponse.error);
364
465
  return;
365
466
  }
366
- console.error(getWalletResponse.error);
367
- return;
467
+ setWalletInfo(getWalletResponse);
468
+ }
469
+ catch (error) {
470
+ console.error('Error getting wallet info:', error);
471
+ }
472
+ finally {
473
+ setIsWalletLoading(false);
368
474
  }
369
- setWalletInfo(getWalletResponse);
370
475
  };
371
476
  getWalletInfo();
372
477
  }, [hitAddress, isNeedSignInWithWallet]);
@@ -405,19 +510,29 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
405
510
  if ('error' in verifyWalletResponse) {
406
511
  if (verifyWalletResponse.error === 'Wallet already exists') {
407
512
  // If wallet exists, get wallet info directly
408
- const walletResponse = await nxtlinqApi.wallet.getWallet({ address }, token);
409
- if (!('error' in walletResponse)) {
410
- setWalletInfo(walletResponse);
411
- const aitResponse = await nxtlinqApi.ait.getAITByServiceIdAndController({ serviceId, controller: address }, token);
412
- if (!('error' in aitResponse)) {
413
- setAit(aitResponse);
513
+ setIsWalletLoading(true);
514
+ try {
515
+ const walletResponse = await nxtlinqApi.wallet.getWallet({ address }, token);
516
+ if (!('error' in walletResponse)) {
517
+ setWalletInfo(walletResponse);
518
+ const aitResponse = await nxtlinqApi.ait.getAITByServiceIdAndController({ serviceId, controller: address }, token);
519
+ if (!('error' in aitResponse)) {
520
+ setAit(aitResponse);
521
+ }
414
522
  }
415
523
  }
416
- // Clean up token from URL
524
+ finally {
525
+ setIsWalletLoading(false);
526
+ }
527
+ // Clean up URL parameters after wallet verification
417
528
  if (typeof window !== 'undefined') {
418
529
  try {
419
530
  const url = new URL(window.location.href);
531
+ // Clean up all Berify.me related parameters
420
532
  url.searchParams.delete('token');
533
+ url.searchParams.delete('isAutoConnect');
534
+ url.searchParams.delete('method');
535
+ url.searchParams.delete('returnUrl');
421
536
  window.history.replaceState({}, '', url.toString());
422
537
  }
423
538
  catch (e) {
@@ -434,19 +549,29 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
434
549
  return;
435
550
  }
436
551
  // Verification successful, get wallet info
437
- const walletResponse = await nxtlinqApi.wallet.getWallet({ address }, token);
438
- if (!('error' in walletResponse)) {
439
- setWalletInfo(walletResponse);
440
- const aitResponse = await nxtlinqApi.ait.getAITByServiceIdAndController({ serviceId, controller: address }, token);
441
- if (!('error' in aitResponse)) {
442
- setAit(aitResponse);
552
+ setIsWalletLoading(true);
553
+ try {
554
+ const walletResponse = await nxtlinqApi.wallet.getWallet({ address }, token);
555
+ if (!('error' in walletResponse)) {
556
+ setWalletInfo(walletResponse);
557
+ const aitResponse = await nxtlinqApi.ait.getAITByServiceIdAndController({ serviceId, controller: address }, token);
558
+ if (!('error' in aitResponse)) {
559
+ setAit(aitResponse);
560
+ }
443
561
  }
444
562
  }
445
- // Clean up token from URL
563
+ finally {
564
+ setIsWalletLoading(false);
565
+ }
566
+ // Clean up URL parameters after wallet verification
446
567
  if (typeof window !== 'undefined') {
447
568
  try {
448
569
  const url = new URL(window.location.href);
570
+ // Clean up all Berify.me related parameters
449
571
  url.searchParams.delete('token');
572
+ url.searchParams.delete('isAutoConnect');
573
+ url.searchParams.delete('method');
574
+ url.searchParams.delete('returnUrl');
450
575
  window.history.replaceState({}, '', url.toString());
451
576
  }
452
577
  catch (e) {
@@ -639,16 +764,26 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
639
764
  }]);
640
765
  return false;
641
766
  }
642
- if (!ait) {
767
+ // Check if user has signed in with wallet
768
+ if (!nxtlinqAITServiceAccessToken) {
643
769
  setMessages(prev => [...prev, {
644
770
  id: Date.now().toString(),
645
- content: 'Please sign in with your wallet to continue.',
771
+ content: 'Please sign in with your HIT wallet to continue.',
646
772
  role: 'assistant',
647
773
  timestamp: new Date().toISOString(),
648
774
  button: 'signIn'
649
775
  }]);
650
776
  return false;
651
777
  }
778
+ if (!ait) {
779
+ setMessages(prev => [...prev, {
780
+ id: Date.now().toString(),
781
+ content: 'No AIT found for your wallet. Please click the settings button (⚙️) to configure your AIT permissions.',
782
+ role: 'assistant',
783
+ timestamp: new Date().toISOString()
784
+ }]);
785
+ return false;
786
+ }
652
787
  // Check if the tool permission is available for current identity provider
653
788
  const availablePermissionLabels = availablePermissions.map(p => p.label);
654
789
  if (!availablePermissionLabels.includes(toolName)) {
@@ -664,7 +799,7 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
664
799
  if (!permissions.includes(toolName)) {
665
800
  setMessages(prev => [...prev, {
666
801
  id: Date.now().toString(),
667
- content: `You do not have the required AIT permission: ${toolName}`,
802
+ content: `You do not have the required AIT permission: ${toolName}. Please click the settings button (⚙️) to update your permissions.`,
668
803
  role: 'assistant',
669
804
  timestamp: new Date().toISOString()
670
805
  }]);
@@ -805,17 +940,15 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
805
940
  setAit(aitInfo);
806
941
  };
807
942
  const savePermissions = async () => {
808
- setIsLoading(true);
809
943
  setIsDisabled(true);
810
944
  try {
811
945
  await generateAndRegisterAIT();
812
- setIsLoading(false);
813
946
  setSuccess(true);
814
947
  setShowPermissionForm(false);
948
+ setIsPermissionFormOpen(false);
815
949
  }
816
950
  catch (error) {
817
951
  console.error('Failed to generate AIT:', error);
818
- setIsLoading(false);
819
952
  setIsDisabled(false);
820
953
  if (error instanceof Error) {
821
954
  alert(error.message);
@@ -838,6 +971,15 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
838
971
  onMessage?.(lastMessage);
839
972
  }
840
973
  }, [messages, onMessage]);
974
+ // Auto hide success message after 3 seconds
975
+ React.useEffect(() => {
976
+ if (success) {
977
+ const timer = setTimeout(() => {
978
+ setSuccess(false);
979
+ }, 3000);
980
+ return () => clearTimeout(timer);
981
+ }
982
+ }, [success]);
841
983
  return (_jsxs("div", { style: {
842
984
  position: 'fixed',
843
985
  bottom: '20px',
@@ -864,7 +1006,12 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
864
1006
  display: 'flex',
865
1007
  justifyContent: 'space-between',
866
1008
  alignItems: 'center'
867
- }, children: [_jsx("h3", { style: { margin: 0 }, children: "AI Agent" }), _jsxs("div", { style: { display: 'flex', gap: '10px' }, children: [_jsx("button", { onClick: () => setShowPermissionForm(true), style: {
1009
+ }, children: [_jsx("h3", { style: { margin: 0 }, children: "AI Agent" }), _jsxs("div", { style: { display: 'flex', gap: '10px' }, children: [_jsx("button", { onClick: async () => {
1010
+ setShowPermissionForm(true);
1011
+ setIsPermissionFormOpen(true);
1012
+ // Force refresh AIT data when opening the form to show latest permissions
1013
+ await refreshAIT(true);
1014
+ }, style: {
868
1015
  background: 'none',
869
1016
  border: 'none',
870
1017
  color: 'white',
@@ -973,7 +1120,10 @@ export const ChatBot = ({ onMessage, onError, onToolUse, presetMessages = [], pl
973
1120
  alignItems: 'center',
974
1121
  justifyContent: 'center',
975
1122
  zIndex: 2000
976
- }, children: _jsx(PermissionForm, { hitAddress: hitAddress, permissions: permissions, setPermissions: setPermissions, setIsDisabled: setIsDisabled, onClose: () => setShowPermissionForm(false), onConnectWallet: () => connectWallet(false), onSignIn: () => signInWallet(false), onSave: savePermissions, isNeedSignInWithWallet: isNeedSignInWithWallet, walletInfo: walletInfo, onVerifyWallet: handleVerifyWalletClick, serviceId: serviceId, nxtlinqApi: nxtlinqApi, permissionGroup: permissionGroup }) })), success && (_jsxs("div", { style: {
1123
+ }, children: _jsx(PermissionForm, { hitAddress: hitAddress, permissions: permissions, setPermissions: setPermissions, setIsDisabled: setIsDisabled, onClose: () => {
1124
+ setShowPermissionForm(false);
1125
+ setIsPermissionFormOpen(false);
1126
+ }, onConnectWallet: () => connectWallet(false), onSignIn: () => signInWallet(false), onSave: savePermissions, isNeedSignInWithWallet: isNeedSignInWithWallet, walletInfo: walletInfo, onVerifyWallet: handleVerifyWalletClick, serviceId: serviceId, nxtlinqApi: nxtlinqApi, permissionGroup: permissionGroup, isAITLoading: isAITLoading, isWalletLoading: isWalletLoading }) })), success && (_jsxs("div", { style: {
977
1127
  position: 'fixed',
978
1128
  bottom: 100,
979
1129
  right: 40,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bytexbyte/nxtlinq-ai-agent-sdk",
3
- "version": "1.1.9",
4
- "description": "Nxtlinq AI Agent SDK - Proprietary Software",
3
+ "version": "1.2.1",
4
+ "description": "Nxtlinq AI Agent SDK - Proprietary Software with enhanced async operation handling",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "files": [
@@ -16,7 +16,10 @@
16
16
  "nxtlinq",
17
17
  "ai",
18
18
  "agent",
19
- "sdk"
19
+ "sdk",
20
+ "wallet",
21
+ "authentication",
22
+ "berify"
20
23
  ],
21
24
  "author": "ByteXByte",
22
25
  "license": "MIT",