@bytexbyte/nxtlinq-ai-agent-sdk 1.0.8 → 1.0.9
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/api/nxtlinq-api.d.ts +3 -0
- package/dist/api/nxtlinq-api.d.ts.map +1 -0
- package/dist/api/nxtlinq-api.js +126 -0
- package/dist/components/ChatBot.d.ts +49 -0
- package/dist/components/ChatBot.d.ts.map +1 -0
- package/dist/components/ChatBot.js +836 -0
- package/dist/core/metakeepClient.d.ts +4 -0
- package/dist/core/metakeepClient.d.ts.map +1 -0
- package/dist/core/metakeepClient.js +11 -0
- package/dist/hooks/useNxtlinqAIT.d.ts +14 -0
- package/dist/hooks/useNxtlinqAIT.d.ts.map +1 -0
- package/dist/hooks/useNxtlinqAIT.js +98 -0
- package/dist/index.d.ts +114 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -126
- package/dist/types/ait-api.d.ts +127 -0
- package/dist/types/ait-api.d.ts.map +1 -0
- package/dist/types/ait-api.js +1 -0
- package/package.json +5 -5
- package/src/components/ChatBot.tsx +0 -1192
- package/src/core/metakeepClient.ts +0 -13
- package/src/hooks/useNxtlinqAIT.ts +0 -99
- package/src/index.ts +0 -557
- package/src/types/ait-api.ts +0 -103
- package/src/types/window.d.ts +0 -9
- package/tsconfig.json +0 -25
- package/tsup.config.ts +0 -15
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { MetaKeep } from 'metakeep';
|
|
2
|
-
|
|
3
|
-
const metakeepClient = new MetaKeep({
|
|
4
|
-
appId: 'e7d521f7-3eea-42d7-af42-4d8b962d9a6d',
|
|
5
|
-
chainId: 80002,
|
|
6
|
-
/* RPC node urls map */
|
|
7
|
-
rpcNodeUrls: {
|
|
8
|
-
// Update with your node API key
|
|
9
|
-
80002: 'https://rpc-amoy.polygon.technology'
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
export default metakeepClient;
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
import { NxtlinqAITSDK } from '../index';
|
|
3
|
-
import { AITInfo, WalletInfo } from '../types/ait-api';
|
|
4
|
-
|
|
5
|
-
export function useNxtlinqAIT(sdk: NxtlinqAITSDK) {
|
|
6
|
-
const [walletAddress, setWalletAddress] = useState<string | null>(null);
|
|
7
|
-
const [walletInfo, setWalletInfo] = useState<WalletInfo | null>(null);
|
|
8
|
-
const [ait, setAit] = useState<AITInfo | null>(null);
|
|
9
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
10
|
-
const [error, setError] = useState<string | null>(null);
|
|
11
|
-
|
|
12
|
-
const connectWallet = async () => {
|
|
13
|
-
try {
|
|
14
|
-
setIsLoading(true);
|
|
15
|
-
setError(null);
|
|
16
|
-
const address = await sdk.connectWallet();
|
|
17
|
-
setWalletAddress(address);
|
|
18
|
-
} catch (err) {
|
|
19
|
-
setError(err instanceof Error ? err.message : 'Failed to connect wallet');
|
|
20
|
-
} finally {
|
|
21
|
-
setIsLoading(false);
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const verifyWallet = async (token: string, method: string) => {
|
|
26
|
-
try {
|
|
27
|
-
setIsLoading(true);
|
|
28
|
-
setError(null);
|
|
29
|
-
const info = await sdk.verifyWallet(token, method);
|
|
30
|
-
setWalletInfo(info);
|
|
31
|
-
return info;
|
|
32
|
-
} catch (err) {
|
|
33
|
-
setError(err instanceof Error ? err.message : 'Failed to verify wallet');
|
|
34
|
-
throw err;
|
|
35
|
-
} finally {
|
|
36
|
-
setIsLoading(false);
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const signInWithWallet = async () => {
|
|
41
|
-
try {
|
|
42
|
-
setIsLoading(true);
|
|
43
|
-
setError(null);
|
|
44
|
-
const token = await sdk.signInWithWallet();
|
|
45
|
-
return token;
|
|
46
|
-
} catch (err) {
|
|
47
|
-
setError(err instanceof Error ? err.message : 'Failed to sign in with wallet');
|
|
48
|
-
throw err;
|
|
49
|
-
} finally {
|
|
50
|
-
setIsLoading(false);
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const generateAndRegisterAIT = async (permissions: string[]) => {
|
|
55
|
-
try {
|
|
56
|
-
setIsLoading(true);
|
|
57
|
-
setError(null);
|
|
58
|
-
const aitInfo = await sdk.generateAndRegisterAIT(permissions);
|
|
59
|
-
setAit(aitInfo);
|
|
60
|
-
return aitInfo;
|
|
61
|
-
} catch (err) {
|
|
62
|
-
setError(err instanceof Error ? err.message : 'Failed to generate AIT');
|
|
63
|
-
throw err;
|
|
64
|
-
} finally {
|
|
65
|
-
setIsLoading(false);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
useEffect(() => {
|
|
70
|
-
const loadData = async () => {
|
|
71
|
-
if (walletAddress) {
|
|
72
|
-
try {
|
|
73
|
-
const [walletInfo, aitInfo] = await Promise.all([
|
|
74
|
-
sdk.getWalletInfo(),
|
|
75
|
-
sdk.getAIT()
|
|
76
|
-
]);
|
|
77
|
-
setWalletInfo(walletInfo);
|
|
78
|
-
setAit(aitInfo);
|
|
79
|
-
} catch (err) {
|
|
80
|
-
console.error('Failed to load wallet info or AIT:', err);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
loadData();
|
|
86
|
-
}, [walletAddress, sdk]);
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
walletAddress,
|
|
90
|
-
walletInfo,
|
|
91
|
-
ait,
|
|
92
|
-
isLoading,
|
|
93
|
-
error,
|
|
94
|
-
connectWallet,
|
|
95
|
-
verifyWallet,
|
|
96
|
-
signInWithWallet,
|
|
97
|
-
generateAndRegisterAIT
|
|
98
|
-
};
|
|
99
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,557 +0,0 @@
|
|
|
1
|
-
import { ethers } from 'ethers';
|
|
2
|
-
import stringify from 'json-stable-stringify';
|
|
3
|
-
import { AITInfo, AITMetadata, PermissionGroup, PermissionOption, WalletInfo, CreateAITParams, CreateMetadataParams, VerifyWalletParams, SignInParams, AITApi } from './types/ait-api';
|
|
4
|
-
|
|
5
|
-
const AI_AGENT_API_HOST = 'https://ai-agent.nxtlinq.ai';
|
|
6
|
-
const AIT_SERVICE_API_HOST = 'https://staging-ait-service.nxtlinq.ai';
|
|
7
|
-
|
|
8
|
-
export const createNxtlinqApi = (apiKey: string, apiSecret: string): AITApi => {
|
|
9
|
-
const getAuthHeader = (): Record<string, string> => {
|
|
10
|
-
const token = localStorage.getItem('nxtlinqAITServiceAccessToken');
|
|
11
|
-
return token ? { 'Authorization': `Bearer ${JSON.parse(token)}` } : {};
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
ait: {
|
|
16
|
-
getAITByServiceIdAndController: async (params: { serviceId: string; controller: string }, token: string) => {
|
|
17
|
-
const response = await fetch(`${AIT_SERVICE_API_HOST}/api/ait/service/${params.serviceId}/controller/${params.controller}`, {
|
|
18
|
-
method: 'GET',
|
|
19
|
-
headers: {
|
|
20
|
-
'X-API-Key': apiKey,
|
|
21
|
-
'X-API-Secret': apiSecret,
|
|
22
|
-
...getAuthHeader()
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
return response.json();
|
|
26
|
-
},
|
|
27
|
-
createAIT: async (params: any, token: string) => {
|
|
28
|
-
const response = await fetch(`${AIT_SERVICE_API_HOST}/api/ait`, {
|
|
29
|
-
method: 'POST',
|
|
30
|
-
headers: {
|
|
31
|
-
'X-API-Key': apiKey,
|
|
32
|
-
'X-API-Secret': apiSecret,
|
|
33
|
-
'Content-Type': 'application/json',
|
|
34
|
-
...getAuthHeader()
|
|
35
|
-
},
|
|
36
|
-
body: JSON.stringify(params)
|
|
37
|
-
});
|
|
38
|
-
return response.json();
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
wallet: {
|
|
42
|
-
verifyWallet: async (params: any, token: string) => {
|
|
43
|
-
const response = await fetch(`${AIT_SERVICE_API_HOST}/api/wallet`, {
|
|
44
|
-
method: 'POST',
|
|
45
|
-
headers: {
|
|
46
|
-
'X-API-Key': apiKey,
|
|
47
|
-
'X-API-Secret': apiSecret,
|
|
48
|
-
'Content-Type': 'application/json',
|
|
49
|
-
...getAuthHeader()
|
|
50
|
-
},
|
|
51
|
-
body: JSON.stringify(params)
|
|
52
|
-
});
|
|
53
|
-
return response.json();
|
|
54
|
-
},
|
|
55
|
-
getWallet: async (params: { address: string }, token: string) => {
|
|
56
|
-
const response = await fetch(`${AIT_SERVICE_API_HOST}/api/wallet/address/${params.address}`, {
|
|
57
|
-
method: 'GET',
|
|
58
|
-
headers: {
|
|
59
|
-
'X-API-Key': apiKey,
|
|
60
|
-
'X-API-Secret': apiSecret,
|
|
61
|
-
...getAuthHeader()
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
return response.json();
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
metadata: {
|
|
68
|
-
createMetadata: async (metadata: any, token: string) => {
|
|
69
|
-
const response = await fetch(`${AIT_SERVICE_API_HOST}/api/metadata`, {
|
|
70
|
-
method: 'POST',
|
|
71
|
-
headers: {
|
|
72
|
-
'X-API-Key': apiKey,
|
|
73
|
-
'X-API-Secret': apiSecret,
|
|
74
|
-
'Content-Type': 'application/json',
|
|
75
|
-
...getAuthHeader()
|
|
76
|
-
},
|
|
77
|
-
body: JSON.stringify(metadata)
|
|
78
|
-
});
|
|
79
|
-
return response.json();
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
auth: {
|
|
83
|
-
getNonce: async (params: { address: string }) => {
|
|
84
|
-
const response = await fetch(`${AIT_SERVICE_API_HOST}/api/auth/address/${params.address}/nonce`, {
|
|
85
|
-
method: 'GET',
|
|
86
|
-
headers: {
|
|
87
|
-
'X-API-Key': apiKey,
|
|
88
|
-
'X-API-Secret': apiSecret,
|
|
89
|
-
...getAuthHeader()
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
return response.json();
|
|
93
|
-
},
|
|
94
|
-
signIn: async (params: any) => {
|
|
95
|
-
const response = await fetch(`${AIT_SERVICE_API_HOST}/api/auth`, {
|
|
96
|
-
method: 'POST',
|
|
97
|
-
headers: {
|
|
98
|
-
'X-API-Key': apiKey,
|
|
99
|
-
'X-API-Secret': apiSecret,
|
|
100
|
-
'Content-Type': 'application/json',
|
|
101
|
-
...getAuthHeader()
|
|
102
|
-
},
|
|
103
|
-
body: JSON.stringify(params)
|
|
104
|
-
});
|
|
105
|
-
return response.json();
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
agent: {
|
|
109
|
-
sendMessage: async (params) => {
|
|
110
|
-
try {
|
|
111
|
-
const response = await fetch(`${AI_AGENT_API_HOST}/api/agent/message`, {
|
|
112
|
-
method: 'POST',
|
|
113
|
-
headers: {
|
|
114
|
-
'X-API-Key': apiKey,
|
|
115
|
-
'X-API-Secret': apiSecret,
|
|
116
|
-
'Content-Type': 'application/json',
|
|
117
|
-
...getAuthHeader()
|
|
118
|
-
},
|
|
119
|
-
body: JSON.stringify(params)
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
if (!response.ok) {
|
|
123
|
-
throw new Error('发送消息失败');
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return await response.json();
|
|
127
|
-
} catch (error) {
|
|
128
|
-
return { error: error instanceof Error ? error.message : '发送消息失败' };
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
export { ChatBot } from './components/ChatBot';
|
|
136
|
-
export type { Message, PresetMessage, ToolUse, ChatBotProps } from './components/ChatBot';
|
|
137
|
-
|
|
138
|
-
// 导出类型
|
|
139
|
-
export type {
|
|
140
|
-
AITInfo,
|
|
141
|
-
AITMetadata,
|
|
142
|
-
PermissionGroup,
|
|
143
|
-
PermissionOption,
|
|
144
|
-
WalletInfo,
|
|
145
|
-
CreateAITParams,
|
|
146
|
-
CreateMetadataParams,
|
|
147
|
-
VerifyWalletParams,
|
|
148
|
-
SignInParams
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
export interface AITPermission {
|
|
152
|
-
hasPermission: boolean;
|
|
153
|
-
reason?: string;
|
|
154
|
-
permissions?: string[];
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export interface AIT {
|
|
158
|
-
aitId: string;
|
|
159
|
-
controller: string;
|
|
160
|
-
metadata: AITMetadata;
|
|
161
|
-
metadataHash: string;
|
|
162
|
-
metadataCid: string;
|
|
163
|
-
signature: string;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export interface GenerateAITOptions {
|
|
167
|
-
hitAddress: string;
|
|
168
|
-
signer: ethers.Signer;
|
|
169
|
-
permissions: string[];
|
|
170
|
-
serviceId: string;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export interface MessageResponse {
|
|
174
|
-
reply: string;
|
|
175
|
-
timestamp: string;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
export class NxtlinqAITSDK {
|
|
179
|
-
private serviceId: string;
|
|
180
|
-
private signer: ethers.Signer | null = null;
|
|
181
|
-
private walletAddress: string | null = null;
|
|
182
|
-
private api: AITApi;
|
|
183
|
-
|
|
184
|
-
constructor(serviceId: string, apiKey: string, apiSecret: string) {
|
|
185
|
-
this.serviceId = serviceId;
|
|
186
|
-
this.api = createNxtlinqApi(apiKey, apiSecret);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
async connectWallet(): Promise<string> {
|
|
190
|
-
if (typeof window === 'undefined' || !window.ethereum) {
|
|
191
|
-
throw new Error('MetaMask is not installed');
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const provider = new ethers.BrowserProvider(window.ethereum);
|
|
195
|
-
this.signer = await provider.getSigner();
|
|
196
|
-
this.walletAddress = await this.signer.getAddress();
|
|
197
|
-
return this.walletAddress;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
async verifyWallet(token: string, method: string): Promise<WalletInfo> {
|
|
201
|
-
if (!this.walletAddress) {
|
|
202
|
-
throw new Error('Please connect wallet first');
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const response = await this.api.wallet.verifyWallet({
|
|
206
|
-
address: this.walletAddress,
|
|
207
|
-
token,
|
|
208
|
-
method,
|
|
209
|
-
timestamp: Date.now()
|
|
210
|
-
}, token);
|
|
211
|
-
|
|
212
|
-
if ('error' in response) {
|
|
213
|
-
throw new Error(response.error);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return response;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
async signInWithWallet(): Promise<string> {
|
|
220
|
-
if (!this.walletAddress || !this.signer) {
|
|
221
|
-
throw new Error('Please connect wallet first');
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const nonceResponse = await this.api.auth.getNonce({ address: this.walletAddress });
|
|
225
|
-
if ('error' in nonceResponse) {
|
|
226
|
-
throw new Error(nonceResponse.error);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const payload = {
|
|
230
|
-
address: this.walletAddress,
|
|
231
|
-
code: nonceResponse.code,
|
|
232
|
-
timestamp: nonceResponse.timestamp
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
const stringToSign = stringify(payload);
|
|
236
|
-
const signature = await this.signer.signMessage(stringToSign || '');
|
|
237
|
-
|
|
238
|
-
const response = await this.api.auth.signIn({
|
|
239
|
-
...payload,
|
|
240
|
-
signature
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
if ('error' in response) {
|
|
244
|
-
throw new Error(response.error);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return response.accessToken;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
async generateAndRegisterAIT(permissions: string[]): Promise<AITInfo> {
|
|
251
|
-
if (!this.signer || !this.walletAddress) {
|
|
252
|
-
throw new Error('Please connect wallet first');
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const token = localStorage.getItem('nxtlinqAITServiceAccessToken');
|
|
256
|
-
if (!token) {
|
|
257
|
-
throw new Error('未找到访问令牌');
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const timestamp = Math.floor(Date.now() / 1000);
|
|
261
|
-
const aitId = `did:polygon:ike-dashboard:${this.walletAddress}:${timestamp}`;
|
|
262
|
-
|
|
263
|
-
const metadata: AITMetadata = {
|
|
264
|
-
model: 'gpt-4',
|
|
265
|
-
permissions,
|
|
266
|
-
issuedBy: this.walletAddress
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
const metadataStr = stringify(metadata);
|
|
270
|
-
const metadataHash = ethers.keccak256(ethers.toUtf8Bytes(metadataStr || ''));
|
|
271
|
-
|
|
272
|
-
// Upload metadata
|
|
273
|
-
const uploadResponse = await this.api.metadata.createMetadata({
|
|
274
|
-
...metadata,
|
|
275
|
-
controller: this.walletAddress
|
|
276
|
-
}, token);
|
|
277
|
-
|
|
278
|
-
if ('error' in uploadResponse) {
|
|
279
|
-
throw new Error(`Failed to upload metadata: ${uploadResponse.error}`);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
const { metadataCid } = uploadResponse;
|
|
283
|
-
|
|
284
|
-
// Sign the message
|
|
285
|
-
const messageHash = ethers.solidityPackedKeccak256(
|
|
286
|
-
['string', 'address', 'string', 'bytes32', 'uint256'],
|
|
287
|
-
[aitId, this.walletAddress, this.serviceId, metadataHash, timestamp]
|
|
288
|
-
);
|
|
289
|
-
|
|
290
|
-
const signature = await this.signer.signMessage(ethers.getBytes(messageHash));
|
|
291
|
-
|
|
292
|
-
// Register AIT
|
|
293
|
-
const response = await this.api.ait.createAIT({
|
|
294
|
-
aitId,
|
|
295
|
-
controller: this.walletAddress,
|
|
296
|
-
serviceId: this.serviceId,
|
|
297
|
-
metadataHash,
|
|
298
|
-
metadataCid,
|
|
299
|
-
timestamp,
|
|
300
|
-
signature
|
|
301
|
-
}, token);
|
|
302
|
-
|
|
303
|
-
if ('error' in response) {
|
|
304
|
-
throw new Error(response.error);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
return response;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
async getAIT(): Promise<AITInfo | null> {
|
|
311
|
-
if (!this.walletAddress) {
|
|
312
|
-
return null;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const token = localStorage.getItem('nxtlinqAITServiceAccessToken');
|
|
316
|
-
if (!token) {
|
|
317
|
-
throw new Error('未找到访问令牌');
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
const response = await this.api.ait.getAITByServiceIdAndController({
|
|
321
|
-
serviceId: this.serviceId,
|
|
322
|
-
controller: this.walletAddress
|
|
323
|
-
}, token);
|
|
324
|
-
|
|
325
|
-
if ('error' in response) {
|
|
326
|
-
return null;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return response;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
async getWalletInfo(): Promise<WalletInfo | null> {
|
|
333
|
-
if (!this.walletAddress) {
|
|
334
|
-
return null;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
const token = localStorage.getItem('nxtlinqAITServiceAccessToken');
|
|
338
|
-
if (!token) {
|
|
339
|
-
throw new Error('未找到访问令牌');
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
const response = await this.api.wallet.getWallet({ address: this.walletAddress }, token);
|
|
343
|
-
if ('error' in response) {
|
|
344
|
-
return null;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
return response;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
createPermissionForm(permissionGroups: PermissionGroup[]): PermissionGroup[] {
|
|
351
|
-
return permissionGroups.map(group => ({
|
|
352
|
-
label: group.label,
|
|
353
|
-
options: group.options.map((option: PermissionOption) => ({
|
|
354
|
-
...option,
|
|
355
|
-
isChecked: false,
|
|
356
|
-
}))
|
|
357
|
-
}));
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
getSelectedPermissions(form: PermissionGroup[]): string[] {
|
|
361
|
-
return form.flatMap(group =>
|
|
362
|
-
group.options.filter((opt: PermissionOption) => opt.isChecked).map((opt: PermissionOption) => opt.value)
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
export class NxtlinqAIAgent {
|
|
368
|
-
private projectId: string;
|
|
369
|
-
private apiKey?: string;
|
|
370
|
-
private ait?: AIT;
|
|
371
|
-
private permissions: string[] = [];
|
|
372
|
-
private signer?: ethers.Signer;
|
|
373
|
-
private api: AITApi;
|
|
374
|
-
|
|
375
|
-
constructor(projectId: string, apiKey: string, apiSecret: string) {
|
|
376
|
-
this.projectId = projectId;
|
|
377
|
-
this.apiKey = apiKey;
|
|
378
|
-
this.api = createNxtlinqApi(apiKey, apiSecret);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
setAIT(ait: AIT, signer?: ethers.Signer) {
|
|
382
|
-
this.ait = ait;
|
|
383
|
-
this.permissions = ait.metadata.permissions;
|
|
384
|
-
if (signer) {
|
|
385
|
-
this.signer = signer;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
private async hasPermission(toolName: string): Promise<boolean> {
|
|
390
|
-
if (!this.ait) {
|
|
391
|
-
throw new Error('请先连接钱包以访问权限');
|
|
392
|
-
}
|
|
393
|
-
return this.permissions.includes(toolName);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
private async checkAITPermission(toolName?: string): Promise<AITPermission> {
|
|
397
|
-
try {
|
|
398
|
-
if (!this.ait) {
|
|
399
|
-
return {
|
|
400
|
-
hasPermission: false,
|
|
401
|
-
reason: '请先连接钱包以访问权限'
|
|
402
|
-
};
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
if (!toolName) {
|
|
406
|
-
return {
|
|
407
|
-
hasPermission: true,
|
|
408
|
-
permissions: this.permissions
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
const hasPermission = await this.hasPermission(toolName);
|
|
413
|
-
return {
|
|
414
|
-
hasPermission,
|
|
415
|
-
reason: hasPermission ? undefined : '没有权限使用该工具',
|
|
416
|
-
permissions: this.permissions
|
|
417
|
-
};
|
|
418
|
-
} catch (error) {
|
|
419
|
-
return {
|
|
420
|
-
hasPermission: false,
|
|
421
|
-
reason: error instanceof Error ? error.message : '未知错误',
|
|
422
|
-
permissions: this.permissions
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
async generateAIT(options: GenerateAITOptions): Promise<AIT> {
|
|
428
|
-
const { hitAddress, signer, permissions, serviceId } = options;
|
|
429
|
-
const token = localStorage.getItem('nxtlinqAITServiceAccessToken');
|
|
430
|
-
if (!token) {
|
|
431
|
-
throw new Error('未找到访问令牌');
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const timestamp = Math.floor(Date.now() / 1000);
|
|
435
|
-
const aitId = `did:polygon:ike-dashboard:${hitAddress}:${timestamp}`;
|
|
436
|
-
|
|
437
|
-
const metadata: AITMetadata = {
|
|
438
|
-
model: 'gpt-4',
|
|
439
|
-
permissions,
|
|
440
|
-
issuedBy: hitAddress
|
|
441
|
-
};
|
|
442
|
-
|
|
443
|
-
const metadataStr = stringify(metadata);
|
|
444
|
-
const metadataHash = ethers.keccak256(ethers.toUtf8Bytes(metadataStr || ''));
|
|
445
|
-
|
|
446
|
-
// Upload metadata
|
|
447
|
-
const uploadResponse = await this.api.metadata.createMetadata({
|
|
448
|
-
...metadata,
|
|
449
|
-
controller: hitAddress
|
|
450
|
-
}, token);
|
|
451
|
-
|
|
452
|
-
if ('error' in uploadResponse) {
|
|
453
|
-
throw new Error(`Failed to upload metadata: ${uploadResponse.error}`);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
const { metadataCid } = uploadResponse;
|
|
457
|
-
|
|
458
|
-
// Sign the message
|
|
459
|
-
const messageHash = ethers.solidityPackedKeccak256(
|
|
460
|
-
['string', 'address', 'string', 'bytes32', 'uint256'],
|
|
461
|
-
[aitId, hitAddress, serviceId, metadataHash, timestamp]
|
|
462
|
-
);
|
|
463
|
-
|
|
464
|
-
const signature = await signer.signMessage(ethers.getBytes(messageHash));
|
|
465
|
-
|
|
466
|
-
// Register AIT
|
|
467
|
-
const response = await this.api.ait.createAIT({
|
|
468
|
-
aitId,
|
|
469
|
-
controller: hitAddress,
|
|
470
|
-
serviceId,
|
|
471
|
-
metadataHash,
|
|
472
|
-
metadataCid,
|
|
473
|
-
timestamp,
|
|
474
|
-
signature
|
|
475
|
-
}, token);
|
|
476
|
-
|
|
477
|
-
if ('error' in response) {
|
|
478
|
-
throw new Error(response.error);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
return {
|
|
482
|
-
aitId: response.aitId,
|
|
483
|
-
controller: response.controller,
|
|
484
|
-
metadata: response.metadata,
|
|
485
|
-
metadataHash: response.metadataHash,
|
|
486
|
-
metadataCid: response.metadataCid,
|
|
487
|
-
signature: response.signature
|
|
488
|
-
};
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
async getAITInfo(serviceId: string, controller: string, signer?: ethers.Signer): Promise<AIT | null> {
|
|
492
|
-
const token = localStorage.getItem('nxtlinqAITServiceAccessToken');
|
|
493
|
-
if (!token) {
|
|
494
|
-
throw new Error('未找到访问令牌');
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
const response = await this.api.ait.getAITByServiceIdAndController({
|
|
498
|
-
serviceId,
|
|
499
|
-
controller
|
|
500
|
-
}, token);
|
|
501
|
-
|
|
502
|
-
if ('error' in response) {
|
|
503
|
-
return null;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
if (signer) {
|
|
507
|
-
this.signer = signer;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
return {
|
|
511
|
-
aitId: response.aitId,
|
|
512
|
-
controller: response.controller,
|
|
513
|
-
metadata: response.metadata,
|
|
514
|
-
metadataHash: response.metadataHash,
|
|
515
|
-
metadataCid: response.metadataCid,
|
|
516
|
-
signature: response.signature
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
async sendMessage(message: string, toolName?: string): Promise<MessageResponse> {
|
|
521
|
-
const permission = await this.checkAITPermission(toolName);
|
|
522
|
-
if (!permission.hasPermission) {
|
|
523
|
-
throw new Error(permission.reason || '没有权限使用该工具');
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
if (!this.ait || !this.signer) {
|
|
527
|
-
throw new Error('请先连接钱包以访问权限');
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
const timestamp = Math.floor(Date.now() / 1000);
|
|
531
|
-
const stringToSign = stringify({
|
|
532
|
-
message,
|
|
533
|
-
aitId: this.ait.aitId,
|
|
534
|
-
controller: this.ait.controller,
|
|
535
|
-
metadata: this.ait.metadata,
|
|
536
|
-
metadataHash: this.ait.metadataHash,
|
|
537
|
-
serviceId: this.projectId,
|
|
538
|
-
timestamp
|
|
539
|
-
}) || '';
|
|
540
|
-
|
|
541
|
-
const signature = await this.signer.signMessage(stringToSign);
|
|
542
|
-
|
|
543
|
-
const response = await this.api.agent.sendMessage({
|
|
544
|
-
message,
|
|
545
|
-
serviceId: this.projectId,
|
|
546
|
-
});
|
|
547
|
-
|
|
548
|
-
if ('error' in response) {
|
|
549
|
-
throw new Error(response.error);
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
return {
|
|
553
|
-
reply: response.reply,
|
|
554
|
-
timestamp: new Date().toISOString()
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
}
|