@bytexbyte/nxtlinq-ai-agent-sdk 1.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 +262 -0
- package/dist/index.js +301 -0
- package/package.json +38 -0
- package/src/api/nxtlinq-api.ts +131 -0
- package/src/components/ChatBot.tsx +1192 -0
- package/src/core/metakeepClient.ts +13 -0
- package/src/hooks/useNxtlinqAIT.ts +99 -0
- package/src/index.ts +449 -0
- package/src/types/ait-api.ts +103 -0
- package/src/types/window.d.ts +9 -0
- package/tsconfig.json +21 -0
- package/tsup.config.ts +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# Nxtlinq AI Agent SDK
|
|
2
|
+
|
|
3
|
+
A powerful SDK for building intelligent conversation applications with Nxtlinq AI Agent.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 💬 Real-time chat interface with AI Agent
|
|
8
|
+
- 🎯 Preset messages for quick interactions
|
|
9
|
+
- 🛠️ Tool integration support
|
|
10
|
+
- 🔄 Automatic retry mechanism for failed requests
|
|
11
|
+
- 📱 Responsive and modern UI design
|
|
12
|
+
- 🎨 Customizable styling
|
|
13
|
+
- 🔌 Easy integration with React applications
|
|
14
|
+
- 🔒 Secure authentication and API key management
|
|
15
|
+
- 👛 MetaMask wallet integration
|
|
16
|
+
- 🔐 AIT (AI Token) management
|
|
17
|
+
- 🔑 Permission-based access control
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @bytexbyte/nxtlinq-ai-agent-sdk
|
|
23
|
+
# or
|
|
24
|
+
yarn add @bytexbyte/nxtlinq-ai-agent-sdk
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import { ChatBot } from '@bytexbyte/nxtlinq-ai-agent-sdk';
|
|
31
|
+
|
|
32
|
+
function App() {
|
|
33
|
+
const handleMessage = (message) => {
|
|
34
|
+
console.log('Received new message:', message);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const handleToolUse = async (toolUse) => {
|
|
38
|
+
console.log('Tool use:', toolUse);
|
|
39
|
+
return {
|
|
40
|
+
id: Date.now().toString(),
|
|
41
|
+
content: 'Tool execution response',
|
|
42
|
+
role: 'assistant',
|
|
43
|
+
timestamp: new Date().toISOString()
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const presetMessages = [
|
|
48
|
+
{ text: 'Hello, how can you help me?' },
|
|
49
|
+
{ text: 'I want to add a new member' },
|
|
50
|
+
{ text: 'I want to view the analytics page' },
|
|
51
|
+
{ text: 'I want to change my name' }
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<ChatBot
|
|
56
|
+
serviceId="your-service-id"
|
|
57
|
+
apiKey="your-api-key"
|
|
58
|
+
apiSecret="your-api-secret"
|
|
59
|
+
onMessage={handleMessage}
|
|
60
|
+
onToolUse={handleToolUse}
|
|
61
|
+
presetMessages={presetMessages}
|
|
62
|
+
onVerifyWallet={async (address) => {
|
|
63
|
+
// Implement your wallet verification logic here
|
|
64
|
+
return { token: 'verification-token' };
|
|
65
|
+
}}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
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
|
|
94
|
+
|
|
95
|
+
#### AIT API
|
|
96
|
+
- `getAITByServiceIdAndController`: Get AIT by service ID and controller
|
|
97
|
+
- `createAIT`: Create a new AIT
|
|
98
|
+
|
|
99
|
+
#### Wallet API
|
|
100
|
+
- `verifyWallet`: Verify wallet ownership
|
|
101
|
+
- `getWallet`: Get wallet information
|
|
102
|
+
|
|
103
|
+
#### Metadata API
|
|
104
|
+
- `createMetadata`: Create metadata for AIT
|
|
105
|
+
|
|
106
|
+
#### Auth API
|
|
107
|
+
- `getNonce`: Get nonce for wallet sign-in
|
|
108
|
+
- `signIn`: Sign in with wallet
|
|
109
|
+
|
|
110
|
+
#### Agent API
|
|
111
|
+
- `sendMessage`: Send message to AI agent
|
|
112
|
+
|
|
113
|
+
### ChatBot Component Props
|
|
114
|
+
|
|
115
|
+
| Prop | Type | Required | Description |
|
|
116
|
+
|------|------|----------|-------------|
|
|
117
|
+
| serviceId | string | Yes | Your Nxtlinq service ID |
|
|
118
|
+
| apiKey | string | Yes | Your Nxtlinq API key |
|
|
119
|
+
| apiSecret | string | Yes | Your Nxtlinq API secret |
|
|
120
|
+
| onMessage | (message: Message) => void | No | Callback when a new message is received |
|
|
121
|
+
| onError | (error: Error) => void | No | Callback when an error occurs |
|
|
122
|
+
| onToolUse | (toolUse: ToolUse) => Promise<Message \| void> | No | Callback for handling tool usage |
|
|
123
|
+
| onVerifyWallet | (address: string) => Promise<{ token: string }> | Yes | Callback for wallet verification |
|
|
124
|
+
| presetMessages | PresetMessage[] | No | Array of preset messages to display |
|
|
125
|
+
| placeholder | string | No | Input placeholder text (default: "Type a message...") |
|
|
126
|
+
| className | string | No | Additional CSS class name |
|
|
127
|
+
| maxRetries | number | No | Maximum number of retry attempts (default: 3) |
|
|
128
|
+
| retryDelay | number | No | Delay between retries in milliseconds (default: 1000) |
|
|
129
|
+
|
|
130
|
+
## Types
|
|
131
|
+
|
|
132
|
+
### Message
|
|
133
|
+
```typescript
|
|
134
|
+
interface Message {
|
|
135
|
+
id: string;
|
|
136
|
+
content: string;
|
|
137
|
+
role: 'user' | 'assistant';
|
|
138
|
+
timestamp: string;
|
|
139
|
+
button?: boolean;
|
|
140
|
+
error?: string;
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### PresetMessage
|
|
145
|
+
```typescript
|
|
146
|
+
interface PresetMessage {
|
|
147
|
+
text: string;
|
|
148
|
+
autoSend?: boolean;
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### ToolUse
|
|
153
|
+
```typescript
|
|
154
|
+
interface ToolUse {
|
|
155
|
+
name: string;
|
|
156
|
+
input: Record<string, any>;
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### AIT
|
|
161
|
+
```typescript
|
|
162
|
+
interface AIT {
|
|
163
|
+
aitId: string;
|
|
164
|
+
controller: string;
|
|
165
|
+
metadata: AITMetadata;
|
|
166
|
+
metadataHash: string;
|
|
167
|
+
metadataCid: string;
|
|
168
|
+
signature: string;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
interface AITMetadata {
|
|
172
|
+
model: string;
|
|
173
|
+
permissions: string[];
|
|
174
|
+
issuedBy: string;
|
|
175
|
+
serviceId?: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
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 {
|
|
201
|
+
id: string;
|
|
202
|
+
address: string;
|
|
203
|
+
verified: boolean;
|
|
204
|
+
method?: string;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
interface MessageContext {
|
|
208
|
+
aitId?: string;
|
|
209
|
+
walletAddress?: string | null;
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Features
|
|
214
|
+
|
|
215
|
+
### Wallet Integration
|
|
216
|
+
- MetaMask wallet connection
|
|
217
|
+
- Wallet verification
|
|
218
|
+
- 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
|
|
225
|
+
|
|
226
|
+
### Authentication Flow
|
|
227
|
+
1. Connect MetaMask wallet
|
|
228
|
+
2. Verify wallet ownership
|
|
229
|
+
3. Sign in with wallet
|
|
230
|
+
4. Generate and register AIT with required permissions
|
|
231
|
+
5. Use AIT for authenticated operations
|
|
232
|
+
|
|
233
|
+
## Error Handling
|
|
234
|
+
|
|
235
|
+
The SDK includes built-in error handling with:
|
|
236
|
+
- Automatic retry mechanism for failed requests
|
|
237
|
+
- Error callback for custom error handling
|
|
238
|
+
- User-friendly error messages
|
|
239
|
+
- Wallet connection error handling
|
|
240
|
+
- Authentication error handling
|
|
241
|
+
|
|
242
|
+
## Best Practices
|
|
243
|
+
|
|
244
|
+
1. Implement proper wallet verification logic
|
|
245
|
+
2. Handle AIT permissions appropriately
|
|
246
|
+
3. Set appropriate timeout values
|
|
247
|
+
4. Implement error retry mechanisms
|
|
248
|
+
5. Use context management to maintain conversation coherence
|
|
249
|
+
6. Handle wallet connection errors gracefully
|
|
250
|
+
7. Implement proper error handling for authentication flow
|
|
251
|
+
|
|
252
|
+
## License
|
|
253
|
+
|
|
254
|
+
Proprietary - All Rights Reserved
|
|
255
|
+
|
|
256
|
+
Copyright (c) 2025 ByteXByte. All rights reserved.
|
|
257
|
+
|
|
258
|
+
This software and associated documentation files (the "Software") are proprietary and confidential. The Software is protected by copyright laws and international copyright treaties, as well as other intellectual property laws and treaties.
|
|
259
|
+
|
|
260
|
+
Unauthorized copying, distribution, modification, public display, or public performance of the Software is strictly prohibited. The Software may only be used in accordance with the terms of a valid license agreement with ByteXByte.
|
|
261
|
+
|
|
262
|
+
For licensing inquiries, please contact: [Your Contact Information]
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
import stringify from 'json-stable-stringify';
|
|
3
|
+
import { createNxtlinqApi } from './api/nxtlinq-api';
|
|
4
|
+
export { ChatBot } from './components/ChatBot';
|
|
5
|
+
export class NxtlinqAITSDK {
|
|
6
|
+
constructor(serviceId, apiKey, apiSecret) {
|
|
7
|
+
this.signer = null;
|
|
8
|
+
this.walletAddress = null;
|
|
9
|
+
this.serviceId = serviceId;
|
|
10
|
+
this.api = createNxtlinqApi(apiKey, apiSecret);
|
|
11
|
+
}
|
|
12
|
+
async connectWallet() {
|
|
13
|
+
if (typeof window === 'undefined' || !window.ethereum) {
|
|
14
|
+
throw new Error('MetaMask is not installed');
|
|
15
|
+
}
|
|
16
|
+
const provider = new ethers.BrowserProvider(window.ethereum);
|
|
17
|
+
this.signer = await provider.getSigner();
|
|
18
|
+
this.walletAddress = await this.signer.getAddress();
|
|
19
|
+
return this.walletAddress;
|
|
20
|
+
}
|
|
21
|
+
async verifyWallet(token, method) {
|
|
22
|
+
if (!this.walletAddress) {
|
|
23
|
+
throw new Error('Please connect wallet first');
|
|
24
|
+
}
|
|
25
|
+
const response = await this.api.wallet.verifyWallet({
|
|
26
|
+
address: this.walletAddress,
|
|
27
|
+
token,
|
|
28
|
+
method,
|
|
29
|
+
timestamp: Date.now()
|
|
30
|
+
}, token);
|
|
31
|
+
if ('error' in response) {
|
|
32
|
+
throw new Error(response.error);
|
|
33
|
+
}
|
|
34
|
+
return response;
|
|
35
|
+
}
|
|
36
|
+
async signInWithWallet() {
|
|
37
|
+
if (!this.walletAddress || !this.signer) {
|
|
38
|
+
throw new Error('Please connect wallet first');
|
|
39
|
+
}
|
|
40
|
+
const nonceResponse = await this.api.auth.getNonce({ address: this.walletAddress });
|
|
41
|
+
if ('error' in nonceResponse) {
|
|
42
|
+
throw new Error(nonceResponse.error);
|
|
43
|
+
}
|
|
44
|
+
const payload = {
|
|
45
|
+
address: this.walletAddress,
|
|
46
|
+
code: nonceResponse.code,
|
|
47
|
+
timestamp: nonceResponse.timestamp
|
|
48
|
+
};
|
|
49
|
+
const stringToSign = stringify(payload);
|
|
50
|
+
const signature = await this.signer.signMessage(stringToSign || '');
|
|
51
|
+
const response = await this.api.auth.signIn({
|
|
52
|
+
...payload,
|
|
53
|
+
signature
|
|
54
|
+
});
|
|
55
|
+
if ('error' in response) {
|
|
56
|
+
throw new Error(response.error);
|
|
57
|
+
}
|
|
58
|
+
return response.accessToken;
|
|
59
|
+
}
|
|
60
|
+
async generateAndRegisterAIT(permissions) {
|
|
61
|
+
if (!this.signer || !this.walletAddress) {
|
|
62
|
+
throw new Error('Please connect wallet first');
|
|
63
|
+
}
|
|
64
|
+
const token = localStorage.getItem('nxtlinqAITServiceAccessToken');
|
|
65
|
+
if (!token) {
|
|
66
|
+
throw new Error('未找到访问令牌');
|
|
67
|
+
}
|
|
68
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
69
|
+
const aitId = `did:polygon:ike-dashboard:${this.walletAddress}:${timestamp}`;
|
|
70
|
+
const metadata = {
|
|
71
|
+
model: 'gpt-4',
|
|
72
|
+
permissions,
|
|
73
|
+
issuedBy: this.walletAddress
|
|
74
|
+
};
|
|
75
|
+
const metadataStr = stringify(metadata);
|
|
76
|
+
const metadataHash = ethers.keccak256(ethers.toUtf8Bytes(metadataStr || ''));
|
|
77
|
+
// Upload metadata
|
|
78
|
+
const uploadResponse = await this.api.metadata.createMetadata({
|
|
79
|
+
...metadata,
|
|
80
|
+
controller: this.walletAddress
|
|
81
|
+
}, token);
|
|
82
|
+
if ('error' in uploadResponse) {
|
|
83
|
+
throw new Error(`Failed to upload metadata: ${uploadResponse.error}`);
|
|
84
|
+
}
|
|
85
|
+
const { metadataCid } = uploadResponse;
|
|
86
|
+
// Sign the message
|
|
87
|
+
const messageHash = ethers.solidityPackedKeccak256(['string', 'address', 'string', 'bytes32', 'uint256'], [aitId, this.walletAddress, this.serviceId, metadataHash, timestamp]);
|
|
88
|
+
const signature = await this.signer.signMessage(ethers.getBytes(messageHash));
|
|
89
|
+
// Register AIT
|
|
90
|
+
const response = await this.api.ait.createAIT({
|
|
91
|
+
aitId,
|
|
92
|
+
controller: this.walletAddress,
|
|
93
|
+
serviceId: this.serviceId,
|
|
94
|
+
metadataHash,
|
|
95
|
+
metadataCid,
|
|
96
|
+
timestamp,
|
|
97
|
+
signature
|
|
98
|
+
}, token);
|
|
99
|
+
if ('error' in response) {
|
|
100
|
+
throw new Error(response.error);
|
|
101
|
+
}
|
|
102
|
+
return response;
|
|
103
|
+
}
|
|
104
|
+
async getAIT() {
|
|
105
|
+
if (!this.walletAddress) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const token = localStorage.getItem('nxtlinqAITServiceAccessToken');
|
|
109
|
+
if (!token) {
|
|
110
|
+
throw new Error('未找到访问令牌');
|
|
111
|
+
}
|
|
112
|
+
const response = await this.api.ait.getAITByServiceIdAndController({
|
|
113
|
+
serviceId: this.serviceId,
|
|
114
|
+
controller: this.walletAddress
|
|
115
|
+
}, token);
|
|
116
|
+
if ('error' in response) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
return response;
|
|
120
|
+
}
|
|
121
|
+
async getWalletInfo() {
|
|
122
|
+
if (!this.walletAddress) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
const token = localStorage.getItem('nxtlinqAITServiceAccessToken');
|
|
126
|
+
if (!token) {
|
|
127
|
+
throw new Error('未找到访问令牌');
|
|
128
|
+
}
|
|
129
|
+
const response = await this.api.wallet.getWallet({ address: this.walletAddress }, token);
|
|
130
|
+
if ('error' in response) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
return response;
|
|
134
|
+
}
|
|
135
|
+
createPermissionForm(permissionGroups) {
|
|
136
|
+
return permissionGroups.map(group => ({
|
|
137
|
+
label: group.label,
|
|
138
|
+
options: group.options.map((option) => ({
|
|
139
|
+
...option,
|
|
140
|
+
isChecked: false,
|
|
141
|
+
}))
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
getSelectedPermissions(form) {
|
|
145
|
+
return form.flatMap(group => group.options.filter((opt) => opt.isChecked).map((opt) => opt.value));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export class NxtlinqAIAgent {
|
|
149
|
+
constructor(projectId, apiKey, apiSecret) {
|
|
150
|
+
this.permissions = [];
|
|
151
|
+
this.projectId = projectId;
|
|
152
|
+
this.apiKey = apiKey;
|
|
153
|
+
this.api = createNxtlinqApi(apiKey, apiSecret);
|
|
154
|
+
}
|
|
155
|
+
setAIT(ait, signer) {
|
|
156
|
+
this.ait = ait;
|
|
157
|
+
this.permissions = ait.metadata.permissions;
|
|
158
|
+
if (signer) {
|
|
159
|
+
this.signer = signer;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
async hasPermission(toolName) {
|
|
163
|
+
if (!this.ait) {
|
|
164
|
+
throw new Error('请先连接钱包以访问权限');
|
|
165
|
+
}
|
|
166
|
+
return this.permissions.includes(toolName);
|
|
167
|
+
}
|
|
168
|
+
async checkAITPermission(toolName) {
|
|
169
|
+
try {
|
|
170
|
+
if (!this.ait) {
|
|
171
|
+
return {
|
|
172
|
+
hasPermission: false,
|
|
173
|
+
reason: '请先连接钱包以访问权限'
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
if (!toolName) {
|
|
177
|
+
return {
|
|
178
|
+
hasPermission: true,
|
|
179
|
+
permissions: this.permissions
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const hasPermission = await this.hasPermission(toolName);
|
|
183
|
+
return {
|
|
184
|
+
hasPermission,
|
|
185
|
+
reason: hasPermission ? undefined : '没有权限使用该工具',
|
|
186
|
+
permissions: this.permissions
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
return {
|
|
191
|
+
hasPermission: false,
|
|
192
|
+
reason: error instanceof Error ? error.message : '未知错误',
|
|
193
|
+
permissions: this.permissions
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async generateAIT(options) {
|
|
198
|
+
const { hitAddress, signer, permissions, serviceId } = options;
|
|
199
|
+
const token = localStorage.getItem('nxtlinqAITServiceAccessToken');
|
|
200
|
+
if (!token) {
|
|
201
|
+
throw new Error('未找到访问令牌');
|
|
202
|
+
}
|
|
203
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
204
|
+
const aitId = `did:polygon:ike-dashboard:${hitAddress}:${timestamp}`;
|
|
205
|
+
const metadata = {
|
|
206
|
+
model: 'gpt-4',
|
|
207
|
+
permissions,
|
|
208
|
+
issuedBy: hitAddress
|
|
209
|
+
};
|
|
210
|
+
const metadataStr = stringify(metadata);
|
|
211
|
+
const metadataHash = ethers.keccak256(ethers.toUtf8Bytes(metadataStr || ''));
|
|
212
|
+
// Upload metadata
|
|
213
|
+
const uploadResponse = await this.api.metadata.createMetadata({
|
|
214
|
+
...metadata,
|
|
215
|
+
controller: hitAddress
|
|
216
|
+
}, token);
|
|
217
|
+
if ('error' in uploadResponse) {
|
|
218
|
+
throw new Error(`Failed to upload metadata: ${uploadResponse.error}`);
|
|
219
|
+
}
|
|
220
|
+
const { metadataCid } = uploadResponse;
|
|
221
|
+
// Sign the message
|
|
222
|
+
const messageHash = ethers.solidityPackedKeccak256(['string', 'address', 'string', 'bytes32', 'uint256'], [aitId, hitAddress, serviceId, metadataHash, timestamp]);
|
|
223
|
+
const signature = await signer.signMessage(ethers.getBytes(messageHash));
|
|
224
|
+
// Register AIT
|
|
225
|
+
const response = await this.api.ait.createAIT({
|
|
226
|
+
aitId,
|
|
227
|
+
controller: hitAddress,
|
|
228
|
+
serviceId,
|
|
229
|
+
metadataHash,
|
|
230
|
+
metadataCid,
|
|
231
|
+
timestamp,
|
|
232
|
+
signature
|
|
233
|
+
}, token);
|
|
234
|
+
if ('error' in response) {
|
|
235
|
+
throw new Error(response.error);
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
aitId: response.aitId,
|
|
239
|
+
controller: response.controller,
|
|
240
|
+
metadata: response.metadata,
|
|
241
|
+
metadataHash: response.metadataHash,
|
|
242
|
+
metadataCid: response.metadataCid,
|
|
243
|
+
signature: response.signature
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
async getAITInfo(serviceId, controller, signer) {
|
|
247
|
+
const token = localStorage.getItem('nxtlinqAITServiceAccessToken');
|
|
248
|
+
if (!token) {
|
|
249
|
+
throw new Error('未找到访问令牌');
|
|
250
|
+
}
|
|
251
|
+
const response = await this.api.ait.getAITByServiceIdAndController({
|
|
252
|
+
serviceId,
|
|
253
|
+
controller
|
|
254
|
+
}, token);
|
|
255
|
+
if ('error' in response) {
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
if (signer) {
|
|
259
|
+
this.signer = signer;
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
aitId: response.aitId,
|
|
263
|
+
controller: response.controller,
|
|
264
|
+
metadata: response.metadata,
|
|
265
|
+
metadataHash: response.metadataHash,
|
|
266
|
+
metadataCid: response.metadataCid,
|
|
267
|
+
signature: response.signature
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
async sendMessage(message, toolName) {
|
|
271
|
+
const permission = await this.checkAITPermission(toolName);
|
|
272
|
+
if (!permission.hasPermission) {
|
|
273
|
+
throw new Error(permission.reason || '没有权限使用该工具');
|
|
274
|
+
}
|
|
275
|
+
if (!this.ait || !this.signer) {
|
|
276
|
+
throw new Error('请先连接钱包以访问权限');
|
|
277
|
+
}
|
|
278
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
279
|
+
const stringToSign = stringify({
|
|
280
|
+
message,
|
|
281
|
+
aitId: this.ait.aitId,
|
|
282
|
+
controller: this.ait.controller,
|
|
283
|
+
metadata: this.ait.metadata,
|
|
284
|
+
metadataHash: this.ait.metadataHash,
|
|
285
|
+
serviceId: this.projectId,
|
|
286
|
+
timestamp
|
|
287
|
+
}) || '';
|
|
288
|
+
const signature = await this.signer.signMessage(stringToSign);
|
|
289
|
+
const response = await this.api.agent.sendMessage({
|
|
290
|
+
message,
|
|
291
|
+
serviceId: this.projectId,
|
|
292
|
+
});
|
|
293
|
+
if ('error' in response) {
|
|
294
|
+
throw new Error(response.error);
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
reply: response.reply,
|
|
298
|
+
timestamp: new Date().toISOString()
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bytexbyte/nxtlinq-ai-agent-sdk",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Nxtlinq AI Agent SDK - Proprietary Software",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"test": "jest"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"nxtlinq",
|
|
13
|
+
"ai",
|
|
14
|
+
"agent",
|
|
15
|
+
"sdk"
|
|
16
|
+
],
|
|
17
|
+
"author": "ByteXByte",
|
|
18
|
+
"license": "UNLICENSED",
|
|
19
|
+
"private": false,
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"react": "^18.2.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/jest": "^29.5.12",
|
|
25
|
+
"@types/json-stable-stringify": "^1.0.34",
|
|
26
|
+
"@types/react": "^18.2.64",
|
|
27
|
+
"jest": "^29.7.0",
|
|
28
|
+
"typescript": "^5.4.2"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@emotion/react": "^11.11.4",
|
|
32
|
+
"@emotion/styled": "^11.11.0",
|
|
33
|
+
"@mui/material": "^5.15.12",
|
|
34
|
+
"ethers": "^6.11.1",
|
|
35
|
+
"json-stable-stringify": "^1.0.2",
|
|
36
|
+
"metakeep": "^2.2.8"
|
|
37
|
+
}
|
|
38
|
+
}
|