@mixrpay/agent-sdk 0.8.8 → 0.9.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 +17 -0
- package/dist/index.cjs +355 -88
- package/dist/index.d.cts +297 -12
- package/dist/index.d.ts +297 -12
- package/dist/index.js +330 -42
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -107,6 +107,9 @@ await wallet.fetch(url, options);
|
|
|
107
107
|
// Get wallet balance
|
|
108
108
|
const balance = await wallet.getBalance();
|
|
109
109
|
|
|
110
|
+
// Execute on-chain transactions (bridges, swaps, DeFi) from human's wallet
|
|
111
|
+
await wallet.executeTransaction({ to, data, estimatedCostUsd });
|
|
112
|
+
|
|
110
113
|
// Pre-flight balance check
|
|
111
114
|
const check = await wallet.canAfford(0.50);
|
|
112
115
|
if (check.canAfford) { /* proceed */ }
|
|
@@ -116,6 +119,20 @@ const diag = await wallet.runDiagnostics();
|
|
|
116
119
|
console.log(diag.recommendations);
|
|
117
120
|
```
|
|
118
121
|
|
|
122
|
+
## Execute On-Chain Transactions
|
|
123
|
+
|
|
124
|
+
Agents can execute DeFi transactions (bridges, swaps) from the human's wallet, bounded by session key budget:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const result = await wallet.executeTransaction({
|
|
128
|
+
to: '0x...contractAddress',
|
|
129
|
+
data: '0x...calldata',
|
|
130
|
+
estimatedCostUsd: 25.0,
|
|
131
|
+
description: 'Bridge USDC via deBridge',
|
|
132
|
+
});
|
|
133
|
+
console.log(`TX: ${result.txHash}`);
|
|
134
|
+
```
|
|
135
|
+
|
|
119
136
|
## Configuration
|
|
120
137
|
|
|
121
138
|
```typescript
|
package/dist/index.cjs
CHANGED
|
@@ -1,46 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
1
|
+
'use strict';
|
|
19
2
|
|
|
20
|
-
|
|
21
|
-
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
AgentWallet: () => AgentWallet,
|
|
24
|
-
InsufficientBalanceError: () => InsufficientBalanceError,
|
|
25
|
-
InvalidSessionKeyError: () => InvalidSessionKeyError,
|
|
26
|
-
MerchantNotAllowedError: () => MerchantNotAllowedError,
|
|
27
|
-
MixrPayError: () => MixrPayError,
|
|
28
|
-
PaymentFailedError: () => PaymentFailedError,
|
|
29
|
-
SDK_VERSION: () => SDK_VERSION,
|
|
30
|
-
SessionExpiredError: () => SessionExpiredError,
|
|
31
|
-
SessionKeyExpiredError: () => SessionKeyExpiredError,
|
|
32
|
-
SessionLimitExceededError: () => SessionLimitExceededError,
|
|
33
|
-
SessionNotFoundError: () => SessionNotFoundError,
|
|
34
|
-
SessionRevokedError: () => SessionRevokedError,
|
|
35
|
-
SpendingLimitExceededError: () => SpendingLimitExceededError,
|
|
36
|
-
X402ProtocolError: () => X402ProtocolError,
|
|
37
|
-
getErrorMessage: () => getErrorMessage,
|
|
38
|
-
isMixrPayError: () => isMixrPayError
|
|
39
|
-
});
|
|
40
|
-
module.exports = __toCommonJS(index_exports);
|
|
3
|
+
var accounts = require('viem/accounts');
|
|
41
4
|
|
|
42
5
|
// src/session-key.ts
|
|
43
|
-
var import_accounts = require("viem/accounts");
|
|
44
6
|
|
|
45
7
|
// src/errors.ts
|
|
46
8
|
var MixrPayError = class extends Error {
|
|
@@ -324,7 +286,7 @@ var SessionKey = class _SessionKey {
|
|
|
324
286
|
isTest;
|
|
325
287
|
constructor(privateKey, isTest) {
|
|
326
288
|
this.privateKey = privateKey;
|
|
327
|
-
this.account =
|
|
289
|
+
this.account = accounts.privateKeyToAccount(privateKey);
|
|
328
290
|
this.address = this.account.address;
|
|
329
291
|
this.isTest = isTest;
|
|
330
292
|
}
|
|
@@ -374,7 +336,7 @@ var SessionKey = class _SessionKey {
|
|
|
374
336
|
* @returns Hex-encoded signature
|
|
375
337
|
*/
|
|
376
338
|
async signTransferAuthorization(domain, message) {
|
|
377
|
-
return
|
|
339
|
+
return accounts.signTypedData({
|
|
378
340
|
privateKey: this.privateKey,
|
|
379
341
|
domain,
|
|
380
342
|
types: TRANSFER_WITH_AUTHORIZATION_TYPES,
|
|
@@ -389,7 +351,7 @@ var SessionKey = class _SessionKey {
|
|
|
389
351
|
* @returns Hex-encoded signature
|
|
390
352
|
*/
|
|
391
353
|
async signMessage(message) {
|
|
392
|
-
return
|
|
354
|
+
return accounts.signMessage({
|
|
393
355
|
privateKey: this.privateKey,
|
|
394
356
|
message
|
|
395
357
|
});
|
|
@@ -440,9 +402,6 @@ async function createSessionAuthPayload(sessionKey) {
|
|
|
440
402
|
};
|
|
441
403
|
}
|
|
442
404
|
|
|
443
|
-
// src/agent-wallet.ts
|
|
444
|
-
var import_accounts2 = require("viem/accounts");
|
|
445
|
-
|
|
446
405
|
// src/x402.ts
|
|
447
406
|
async function parse402Response(response) {
|
|
448
407
|
let paymentData = null;
|
|
@@ -804,7 +763,7 @@ var AgentWallet = class {
|
|
|
804
763
|
/**
|
|
805
764
|
* Register a new agent with MixrPay.
|
|
806
765
|
*
|
|
807
|
-
* This creates a
|
|
766
|
+
* This creates a platform-managed embedded wallet for the agent's payments.
|
|
808
767
|
* The agent proves ownership of their external wallet by signing a challenge.
|
|
809
768
|
*
|
|
810
769
|
* @param options - Registration options including the private key
|
|
@@ -824,7 +783,7 @@ var AgentWallet = class {
|
|
|
824
783
|
static async register(options) {
|
|
825
784
|
const { privateKey, name } = options;
|
|
826
785
|
const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
827
|
-
const account =
|
|
786
|
+
const account = accounts.privateKeyToAccount(privateKey);
|
|
828
787
|
const walletAddress = account.address;
|
|
829
788
|
const challengeResponse = await fetch(
|
|
830
789
|
`${baseUrl}/api/v1/agent/challenge?wallet=${walletAddress}&action=register`
|
|
@@ -834,7 +793,7 @@ var AgentWallet = class {
|
|
|
834
793
|
throw new MixrPayError(error.error || `Failed to get challenge: ${challengeResponse.status}`);
|
|
835
794
|
}
|
|
836
795
|
const { challenge, message } = await challengeResponse.json();
|
|
837
|
-
const signature = await
|
|
796
|
+
const signature = await accounts.signMessage({ message, privateKey });
|
|
838
797
|
const registerResponse = await fetch(`${baseUrl}/api/v1/agent/register`, {
|
|
839
798
|
method: "POST",
|
|
840
799
|
headers: { "Content-Type": "application/json" },
|
|
@@ -892,7 +851,7 @@ var AgentWallet = class {
|
|
|
892
851
|
healthy: false,
|
|
893
852
|
database: "unknown",
|
|
894
853
|
agentRegistrationAvailable: false,
|
|
895
|
-
|
|
854
|
+
walletServiceConfigured: false,
|
|
896
855
|
error: `Health check failed with status ${response.status}`
|
|
897
856
|
};
|
|
898
857
|
}
|
|
@@ -901,14 +860,14 @@ var AgentWallet = class {
|
|
|
901
860
|
healthy: data.status === "ready",
|
|
902
861
|
database: data.database || "unknown",
|
|
903
862
|
agentRegistrationAvailable: data.services?.agentRegistration?.available ?? false,
|
|
904
|
-
|
|
863
|
+
walletServiceConfigured: data.services?.wallet?.configured ?? data.services?.privy?.configured ?? false
|
|
905
864
|
};
|
|
906
865
|
} catch (error) {
|
|
907
866
|
return {
|
|
908
867
|
healthy: false,
|
|
909
868
|
database: "unreachable",
|
|
910
869
|
agentRegistrationAvailable: false,
|
|
911
|
-
|
|
870
|
+
walletServiceConfigured: false,
|
|
912
871
|
error: error instanceof Error ? error.message : "Failed to reach server"
|
|
913
872
|
};
|
|
914
873
|
}
|
|
@@ -941,7 +900,7 @@ var AgentWallet = class {
|
|
|
941
900
|
static async getSessionKey(options) {
|
|
942
901
|
const { privateKey, spendingLimitUsd, maxPerTxUsd, maxDailyUsd, durationDays } = options;
|
|
943
902
|
const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
944
|
-
const account =
|
|
903
|
+
const account = accounts.privateKeyToAccount(privateKey);
|
|
945
904
|
const walletAddress = account.address;
|
|
946
905
|
const challengeResponse = await fetch(
|
|
947
906
|
`${baseUrl}/api/v1/agent/challenge?wallet=${walletAddress}&action=session-key`
|
|
@@ -951,7 +910,7 @@ var AgentWallet = class {
|
|
|
951
910
|
throw new MixrPayError(error.error || `Failed to get challenge: ${challengeResponse.status}`);
|
|
952
911
|
}
|
|
953
912
|
const { challenge, message } = await challengeResponse.json();
|
|
954
|
-
const signature = await
|
|
913
|
+
const signature = await accounts.signMessage({ message, privateKey });
|
|
955
914
|
const sessionKeyResponse = await fetch(`${baseUrl}/api/v1/agent/session-key`, {
|
|
956
915
|
method: "POST",
|
|
957
916
|
headers: { "Content-Type": "application/json" },
|
|
@@ -1004,7 +963,7 @@ var AgentWallet = class {
|
|
|
1004
963
|
static async getStatus(options) {
|
|
1005
964
|
const { privateKey } = options;
|
|
1006
965
|
const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
1007
|
-
const account =
|
|
966
|
+
const account = accounts.privateKeyToAccount(privateKey);
|
|
1008
967
|
const walletAddress = account.address;
|
|
1009
968
|
const challengeResponse = await fetch(
|
|
1010
969
|
`${baseUrl}/api/v1/agent/challenge?wallet=${walletAddress}&action=status`
|
|
@@ -1014,7 +973,7 @@ var AgentWallet = class {
|
|
|
1014
973
|
throw new MixrPayError(error.error || `Failed to get challenge: ${challengeResponse.status}`);
|
|
1015
974
|
}
|
|
1016
975
|
const { challenge, message } = await challengeResponse.json();
|
|
1017
|
-
const signature = await
|
|
976
|
+
const signature = await accounts.signMessage({ message, privateKey });
|
|
1018
977
|
const statusResponse = await fetch(
|
|
1019
978
|
`${baseUrl}/api/v1/agent/status?challenge=${challenge}&external_wallet=${walletAddress}&signature=${encodeURIComponent(signature)}`
|
|
1020
979
|
);
|
|
@@ -1060,7 +1019,7 @@ var AgentWallet = class {
|
|
|
1060
1019
|
static async revokeSessionKey(options) {
|
|
1061
1020
|
const { privateKey, sessionKeyId } = options;
|
|
1062
1021
|
const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
1063
|
-
const account =
|
|
1022
|
+
const account = accounts.privateKeyToAccount(privateKey);
|
|
1064
1023
|
const walletAddress = account.address;
|
|
1065
1024
|
const challengeResponse = await fetch(
|
|
1066
1025
|
`${baseUrl}/api/v1/agent/challenge?wallet=${walletAddress}&action=revoke`
|
|
@@ -1070,7 +1029,7 @@ var AgentWallet = class {
|
|
|
1070
1029
|
throw new MixrPayError(error.error || `Failed to get challenge: ${challengeResponse.status}`);
|
|
1071
1030
|
}
|
|
1072
1031
|
const { challenge, message } = await challengeResponse.json();
|
|
1073
|
-
const signature = await
|
|
1032
|
+
const signature = await accounts.signMessage({ message, privateKey });
|
|
1074
1033
|
const revokeResponse = await fetch(`${baseUrl}/api/v1/agent/session-key/revoke`, {
|
|
1075
1034
|
method: "POST",
|
|
1076
1035
|
headers: { "Content-Type": "application/json" },
|
|
@@ -1114,7 +1073,7 @@ var AgentWallet = class {
|
|
|
1114
1073
|
static async withdraw(options) {
|
|
1115
1074
|
const { privateKey, amountUsd } = options;
|
|
1116
1075
|
const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
1117
|
-
const account =
|
|
1076
|
+
const account = accounts.privateKeyToAccount(privateKey);
|
|
1118
1077
|
const walletAddress = account.address;
|
|
1119
1078
|
const challengeResponse = await fetch(
|
|
1120
1079
|
`${baseUrl}/api/v1/agent/challenge?wallet=${walletAddress}&action=withdraw`
|
|
@@ -1124,7 +1083,7 @@ var AgentWallet = class {
|
|
|
1124
1083
|
throw new MixrPayError(error.error || `Failed to get challenge: ${challengeResponse.status}`);
|
|
1125
1084
|
}
|
|
1126
1085
|
const { challenge, message } = await challengeResponse.json();
|
|
1127
|
-
const signature = await
|
|
1086
|
+
const signature = await accounts.signMessage({ message, privateKey });
|
|
1128
1087
|
const withdrawResponse = await fetch(`${baseUrl}/api/v1/agent/withdraw`, {
|
|
1129
1088
|
method: "POST",
|
|
1130
1089
|
headers: { "Content-Type": "application/json" },
|
|
@@ -1180,7 +1139,7 @@ var AgentWallet = class {
|
|
|
1180
1139
|
static async claimInvite(options) {
|
|
1181
1140
|
const { inviteCode, privateKey } = options;
|
|
1182
1141
|
const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
1183
|
-
const account =
|
|
1142
|
+
const account = accounts.privateKeyToAccount(privateKey);
|
|
1184
1143
|
const walletAddress = account.address;
|
|
1185
1144
|
const challengeResponse = await fetch(
|
|
1186
1145
|
`${baseUrl}/api/v1/agent/challenge?wallet=${walletAddress}&action=claim-invite`
|
|
@@ -1190,7 +1149,7 @@ var AgentWallet = class {
|
|
|
1190
1149
|
throw new MixrPayError(error.error || `Failed to get challenge: ${challengeResponse.status}`);
|
|
1191
1150
|
}
|
|
1192
1151
|
const { challenge, message } = await challengeResponse.json();
|
|
1193
|
-
const signature = await
|
|
1152
|
+
const signature = await accounts.signMessage({ message, privateKey });
|
|
1194
1153
|
const claimResponse = await fetch(`${baseUrl}/api/v1/agent/claim-invite`, {
|
|
1195
1154
|
method: "POST",
|
|
1196
1155
|
headers: { "Content-Type": "application/json" },
|
|
@@ -1240,7 +1199,7 @@ var AgentWallet = class {
|
|
|
1240
1199
|
* Spawn a child invite for sub-agents.
|
|
1241
1200
|
*
|
|
1242
1201
|
* Allows an agent to create an invite code for a sub-agent with a portion
|
|
1243
|
-
* of their remaining budget
|
|
1202
|
+
* of their remaining budget. The child inherits merchant restrictions
|
|
1244
1203
|
* and cannot outlive the parent session.
|
|
1245
1204
|
*
|
|
1246
1205
|
* @param options - Spawn options
|
|
@@ -1254,7 +1213,7 @@ var AgentWallet = class {
|
|
|
1254
1213
|
*
|
|
1255
1214
|
* // Spawn a child invite for a sub-agent
|
|
1256
1215
|
* const childInvite = await wallet.spawnChildInvite({
|
|
1257
|
-
* budgetUsd: 10.00,
|
|
1216
|
+
* budgetUsd: 10.00,
|
|
1258
1217
|
* name: 'Research Sub-Agent',
|
|
1259
1218
|
* allowedMerchants: ['firecrawl.dev'], // Must be subset of parent
|
|
1260
1219
|
* expiresInDays: 7, // Will be capped to parent's expiry
|
|
@@ -1269,7 +1228,7 @@ var AgentWallet = class {
|
|
|
1269
1228
|
const timestamp = Date.now();
|
|
1270
1229
|
const nonce = crypto.randomUUID();
|
|
1271
1230
|
const message = `spawn:${timestamp}:${nonce}`;
|
|
1272
|
-
const signature = await
|
|
1231
|
+
const signature = await accounts.signMessage({
|
|
1273
1232
|
message,
|
|
1274
1233
|
privateKey: this.sessionKey.rawPrivateKey
|
|
1275
1234
|
});
|
|
@@ -1310,8 +1269,7 @@ var AgentWallet = class {
|
|
|
1310
1269
|
/**
|
|
1311
1270
|
* Get available budget information for spawning.
|
|
1312
1271
|
*
|
|
1313
|
-
* Returns the current budget status including
|
|
1314
|
-
* to child agents (20% of available).
|
|
1272
|
+
* Returns the current budget status including spawn availability.
|
|
1315
1273
|
*
|
|
1316
1274
|
* @returns Budget information
|
|
1317
1275
|
*
|
|
@@ -2723,6 +2681,317 @@ Timestamp: ${timestamp}`;
|
|
|
2723
2681
|
return this.parseJitInstance(data.instance);
|
|
2724
2682
|
}
|
|
2725
2683
|
// ===========================================================================
|
|
2684
|
+
// Transaction Execution
|
|
2685
|
+
// ===========================================================================
|
|
2686
|
+
/**
|
|
2687
|
+
* Execute an on-chain transaction from the human's wallet.
|
|
2688
|
+
*
|
|
2689
|
+
* Submits arbitrary calldata to any contract, bounded by the session key's
|
|
2690
|
+
* budget limits (max_total, max_per_tx, max_daily). The platform validates
|
|
2691
|
+
* the budget, executes the transaction, and records a charge.
|
|
2692
|
+
*
|
|
2693
|
+
* @param params - Transaction parameters
|
|
2694
|
+
* @returns Transaction result with hash and remaining budget
|
|
2695
|
+
* @throws {MixrPayError} If budget exceeded, tx reverted, or auth fails
|
|
2696
|
+
*
|
|
2697
|
+
* @example
|
|
2698
|
+
* ```typescript
|
|
2699
|
+
* // Bridge USDC via deBridge
|
|
2700
|
+
* const quote = await deBridgeMcp.create_tx({ ... });
|
|
2701
|
+
* const result = await wallet.executeTransaction({
|
|
2702
|
+
* to: quote.contractAddress,
|
|
2703
|
+
* data: quote.calldata,
|
|
2704
|
+
* estimatedCostUsd: 25.0,
|
|
2705
|
+
* description: 'Bridge 25 USDC Base -> Avalanche via deBridge',
|
|
2706
|
+
* });
|
|
2707
|
+
* console.log('TX:', result.txHash);
|
|
2708
|
+
* console.log('Budget remaining:', result.remainingBudgetUsd);
|
|
2709
|
+
* ```
|
|
2710
|
+
*/
|
|
2711
|
+
async executeTransaction(params) {
|
|
2712
|
+
this.logger.debug("executeTransaction", { to: params.to, estimatedCostUsd: params.estimatedCostUsd });
|
|
2713
|
+
const authHeaders = await this.getSessionAuthHeaders();
|
|
2714
|
+
const response = await fetch(`${this.baseUrl}/api/v2/tx/execute`, {
|
|
2715
|
+
method: "POST",
|
|
2716
|
+
headers: {
|
|
2717
|
+
"Content-Type": "application/json",
|
|
2718
|
+
...authHeaders
|
|
2719
|
+
},
|
|
2720
|
+
body: JSON.stringify({
|
|
2721
|
+
to: params.to,
|
|
2722
|
+
data: params.data,
|
|
2723
|
+
value: params.value?.toString() ?? "0",
|
|
2724
|
+
chain_id: params.chainId,
|
|
2725
|
+
estimated_cost_usd: params.estimatedCostUsd,
|
|
2726
|
+
description: params.description,
|
|
2727
|
+
idempotency_key: params.idempotencyKey
|
|
2728
|
+
})
|
|
2729
|
+
});
|
|
2730
|
+
const result = await response.json().catch(() => ({}));
|
|
2731
|
+
if (!response.ok) {
|
|
2732
|
+
const errorCode = result.error_code || "TX_FAILED";
|
|
2733
|
+
const errorMessage = result.error || `Transaction execution failed: ${response.status}`;
|
|
2734
|
+
if (errorCode === "BUDGET_EXCEEDED") {
|
|
2735
|
+
throw new MixrPayError(errorMessage, "SPENDING_LIMIT_EXCEEDED");
|
|
2736
|
+
}
|
|
2737
|
+
throw new MixrPayError(errorMessage, errorCode);
|
|
2738
|
+
}
|
|
2739
|
+
this.logger.info("Transaction executed", {
|
|
2740
|
+
txHash: result.tx_hash,
|
|
2741
|
+
estimatedCostUsd: params.estimatedCostUsd,
|
|
2742
|
+
remainingBudgetUsd: result.remaining_budget_usd
|
|
2743
|
+
});
|
|
2744
|
+
return {
|
|
2745
|
+
success: true,
|
|
2746
|
+
txHash: result.tx_hash,
|
|
2747
|
+
chargeId: result.charge_id,
|
|
2748
|
+
estimatedCostUsd: result.estimated_cost_usd,
|
|
2749
|
+
remainingBudgetUsd: result.remaining_budget_usd
|
|
2750
|
+
};
|
|
2751
|
+
}
|
|
2752
|
+
// ===========================================================================
|
|
2753
|
+
// Skills Methods
|
|
2754
|
+
// ===========================================================================
|
|
2755
|
+
/**
|
|
2756
|
+
* Use a configured skill by deploying a JIT MCP server with your saved API keys.
|
|
2757
|
+
*
|
|
2758
|
+
* Skills are configured on the MixrPay dashboard with your API keys stored securely.
|
|
2759
|
+
* When you call useSkill(), MixrPay deploys an ephemeral MCP server with your keys
|
|
2760
|
+
* injected server-side - your keys are never exposed to the agent.
|
|
2761
|
+
*
|
|
2762
|
+
* @param skillId - The skill ID (e.g., 'github', 'notion', 'spotify')
|
|
2763
|
+
* @param options - Optional configuration
|
|
2764
|
+
* @returns Skill endpoint and available tools
|
|
2765
|
+
*
|
|
2766
|
+
* @example
|
|
2767
|
+
* ```typescript
|
|
2768
|
+
* // Use the GitHub skill
|
|
2769
|
+
* const github = await wallet.useSkill('github');
|
|
2770
|
+
*
|
|
2771
|
+
* console.log('Endpoint:', github.endpoint);
|
|
2772
|
+
* console.log('Tools:', github.tools);
|
|
2773
|
+
* console.log('Expires:', github.expiresAt);
|
|
2774
|
+
*
|
|
2775
|
+
* // Connect to the MCP endpoint and call tools
|
|
2776
|
+
* // The exact method depends on your MCP client
|
|
2777
|
+
* ```
|
|
2778
|
+
*
|
|
2779
|
+
* @example
|
|
2780
|
+
* ```typescript
|
|
2781
|
+
* // Use Notion with custom TTL
|
|
2782
|
+
* const notion = await wallet.useSkill('notion', { ttlHours: 48 });
|
|
2783
|
+
* ```
|
|
2784
|
+
*
|
|
2785
|
+
* @throws {MixrPayError} If skill is not configured or deployment fails
|
|
2786
|
+
*/
|
|
2787
|
+
async useSkill(skillId, options) {
|
|
2788
|
+
this.logger.debug("useSkill", { skillId, options });
|
|
2789
|
+
const authHeaders = await this.getSessionAuthHeaders();
|
|
2790
|
+
const response = await fetch(`${this.baseUrl}/api/v2/skills/${skillId}/use`, {
|
|
2791
|
+
method: "POST",
|
|
2792
|
+
headers: {
|
|
2793
|
+
"Content-Type": "application/json",
|
|
2794
|
+
...authHeaders
|
|
2795
|
+
},
|
|
2796
|
+
body: JSON.stringify({
|
|
2797
|
+
ttl_hours: options?.ttlHours || 24
|
|
2798
|
+
})
|
|
2799
|
+
});
|
|
2800
|
+
if (!response.ok) {
|
|
2801
|
+
const error = await response.json().catch(() => ({}));
|
|
2802
|
+
if (error.configure_url) {
|
|
2803
|
+
throw new MixrPayError(
|
|
2804
|
+
`${error.error || "Skill not configured"}. Configure at: ${this.baseUrl}${error.configure_url}`,
|
|
2805
|
+
"SKILL_NOT_CONFIGURED"
|
|
2806
|
+
);
|
|
2807
|
+
}
|
|
2808
|
+
throw new MixrPayError(error.error || `Failed to use skill: ${response.status}`);
|
|
2809
|
+
}
|
|
2810
|
+
const data = await response.json();
|
|
2811
|
+
return {
|
|
2812
|
+
skillId: data.skill_id,
|
|
2813
|
+
endpoint: data.endpoint,
|
|
2814
|
+
tools: data.tools || [],
|
|
2815
|
+
expiresAt: new Date(data.expires_at),
|
|
2816
|
+
instanceId: data.instance_id
|
|
2817
|
+
};
|
|
2818
|
+
}
|
|
2819
|
+
/**
|
|
2820
|
+
* List all available skills and their configuration status.
|
|
2821
|
+
*
|
|
2822
|
+
* @returns Array of skills with status
|
|
2823
|
+
*
|
|
2824
|
+
* @example
|
|
2825
|
+
* ```typescript
|
|
2826
|
+
* const skills = await wallet.listSkills();
|
|
2827
|
+
*
|
|
2828
|
+
* // Find configured skills
|
|
2829
|
+
* const configured = skills.filter(s => s.status === 'configured');
|
|
2830
|
+
* console.log(`${configured.length} skills ready to use`);
|
|
2831
|
+
*
|
|
2832
|
+
* // Find skills that need configuration
|
|
2833
|
+
* const needsConfig = skills.filter(s => s.status === 'not_configured' && s.envVars.length > 0);
|
|
2834
|
+
* for (const skill of needsConfig) {
|
|
2835
|
+
* console.log(`${skill.name} needs: ${skill.envVars.map(v => v.label).join(', ')}`);
|
|
2836
|
+
* }
|
|
2837
|
+
* ```
|
|
2838
|
+
*/
|
|
2839
|
+
async listSkills() {
|
|
2840
|
+
this.logger.debug("listSkills");
|
|
2841
|
+
const authHeaders = await this.getSessionAuthHeaders();
|
|
2842
|
+
const response = await fetch(`${this.baseUrl}/api/v2/skills`, {
|
|
2843
|
+
headers: authHeaders
|
|
2844
|
+
});
|
|
2845
|
+
if (!response.ok) {
|
|
2846
|
+
const error = await response.json().catch(() => ({}));
|
|
2847
|
+
throw new MixrPayError(error.error || `Failed to list skills: ${response.status}`);
|
|
2848
|
+
}
|
|
2849
|
+
const data = await response.json();
|
|
2850
|
+
return data.skills || [];
|
|
2851
|
+
}
|
|
2852
|
+
/**
|
|
2853
|
+
* Get apps connected via Composio (Gmail, Slack, GitHub, etc.).
|
|
2854
|
+
*
|
|
2855
|
+
* Use this to discover which apps the owner has connected before
|
|
2856
|
+
* attempting to use them via `wallet.useSkill('composio')`.
|
|
2857
|
+
*
|
|
2858
|
+
* @returns Object with connected app names and connection details
|
|
2859
|
+
*
|
|
2860
|
+
* @example
|
|
2861
|
+
* ```typescript
|
|
2862
|
+
* const apps = await wallet.getConnectedApps();
|
|
2863
|
+
*
|
|
2864
|
+
* if (apps.connected.length === 0) {
|
|
2865
|
+
* console.log('No apps connected. Ask your owner to connect apps at the dashboard.');
|
|
2866
|
+
* } else {
|
|
2867
|
+
* console.log('Connected apps:', apps.connected.join(', '));
|
|
2868
|
+
*
|
|
2869
|
+
* if (apps.connected.includes('gmail')) {
|
|
2870
|
+
* // Safe to use Composio for Gmail
|
|
2871
|
+
* const { endpoint, tools } = await wallet.useSkill('composio');
|
|
2872
|
+
* // tools will include 'gmail_read_emails', 'gmail_send_email', etc.
|
|
2873
|
+
* }
|
|
2874
|
+
* }
|
|
2875
|
+
* ```
|
|
2876
|
+
*/
|
|
2877
|
+
async getConnectedApps() {
|
|
2878
|
+
this.logger.debug("getConnectedApps");
|
|
2879
|
+
const authHeaders = await this.getSessionAuthHeaders();
|
|
2880
|
+
const response = await fetch(`${this.baseUrl}/api/v2/skills/composio/connections`, {
|
|
2881
|
+
headers: authHeaders
|
|
2882
|
+
});
|
|
2883
|
+
if (!response.ok) {
|
|
2884
|
+
const error = await response.json().catch(() => ({}));
|
|
2885
|
+
throw new MixrPayError(
|
|
2886
|
+
error.error || `Failed to get connected apps: ${response.status}`,
|
|
2887
|
+
"CONNECTED_APPS_FAILED"
|
|
2888
|
+
);
|
|
2889
|
+
}
|
|
2890
|
+
const data = await response.json();
|
|
2891
|
+
const connectedAppNames = (data.connections || []).filter((c) => c.status === "connected").map((c) => c.app.toLowerCase());
|
|
2892
|
+
return {
|
|
2893
|
+
connected: connectedAppNames,
|
|
2894
|
+
connections: data.connections || [],
|
|
2895
|
+
oauthConnections: data.oauth_connections || [],
|
|
2896
|
+
apiKeyConnections: data.api_key_connections || []
|
|
2897
|
+
};
|
|
2898
|
+
}
|
|
2899
|
+
/**
|
|
2900
|
+
* Get configuration status for a specific skill.
|
|
2901
|
+
*
|
|
2902
|
+
* @param skillId - The skill ID
|
|
2903
|
+
* @returns Skill configuration status
|
|
2904
|
+
*
|
|
2905
|
+
* @example
|
|
2906
|
+
* ```typescript
|
|
2907
|
+
* const status = await wallet.getSkillStatus('github');
|
|
2908
|
+
*
|
|
2909
|
+
* if (status.status === 'configured') {
|
|
2910
|
+
* console.log('GitHub is ready!');
|
|
2911
|
+
* console.log('Configured vars:', status.configuredVars);
|
|
2912
|
+
* } else {
|
|
2913
|
+
* console.log('Please configure GitHub at the MixrPay dashboard');
|
|
2914
|
+
* }
|
|
2915
|
+
* ```
|
|
2916
|
+
*/
|
|
2917
|
+
async getSkillStatus(skillId) {
|
|
2918
|
+
this.logger.debug("getSkillStatus", { skillId });
|
|
2919
|
+
const authHeaders = await this.getSessionAuthHeaders();
|
|
2920
|
+
const response = await fetch(`${this.baseUrl}/api/v2/skills/${skillId}/configure`, {
|
|
2921
|
+
headers: authHeaders
|
|
2922
|
+
});
|
|
2923
|
+
if (!response.ok) {
|
|
2924
|
+
const error = await response.json().catch(() => ({}));
|
|
2925
|
+
throw new MixrPayError(error.error || `Failed to get skill status: ${response.status}`);
|
|
2926
|
+
}
|
|
2927
|
+
const data = await response.json();
|
|
2928
|
+
return {
|
|
2929
|
+
skillId: data.skill_id,
|
|
2930
|
+
status: data.status,
|
|
2931
|
+
configuredVars: data.configured_vars || [],
|
|
2932
|
+
lastUsedAt: data.last_used_at ? new Date(data.last_used_at) : void 0,
|
|
2933
|
+
errorMessage: data.error_message
|
|
2934
|
+
};
|
|
2935
|
+
}
|
|
2936
|
+
/**
|
|
2937
|
+
* Configure a skill with API keys.
|
|
2938
|
+
*
|
|
2939
|
+
* This allows agents to save API keys received via chat to the MixrPay platform.
|
|
2940
|
+
* Keys are encrypted at rest and will be available for use on subsequent deploy/redeploy.
|
|
2941
|
+
*
|
|
2942
|
+
* @param skillId - The skill ID (e.g., 'web-search', 'github', 'notion') or custom skill with 'custom-' prefix
|
|
2943
|
+
* @param envVars - Environment variables with API keys (e.g., { BRAVE_API_KEY: 'xxx' })
|
|
2944
|
+
* @returns Configuration result with list of configured variables
|
|
2945
|
+
*
|
|
2946
|
+
* @example Predefined skill
|
|
2947
|
+
* ```typescript
|
|
2948
|
+
* // User provides API key in chat, agent saves it
|
|
2949
|
+
* const result = await wallet.configureSkill('web-search', {
|
|
2950
|
+
* BRAVE_API_KEY: 'BSA_abc123xyz',
|
|
2951
|
+
* });
|
|
2952
|
+
*
|
|
2953
|
+
* console.log('Configured:', result.configuredVars);
|
|
2954
|
+
* // After next redeploy, the skill will be enabled with this key
|
|
2955
|
+
* ```
|
|
2956
|
+
*
|
|
2957
|
+
* @example Custom API key
|
|
2958
|
+
* ```typescript
|
|
2959
|
+
* // For APIs not in predefined skills, use custom- prefix
|
|
2960
|
+
* // User: "Here's my Polymarket API key: pk_abc123"
|
|
2961
|
+
* const result = await wallet.configureSkill('custom-polymarket', {
|
|
2962
|
+
* POLYMARKET_API_KEY: 'pk_abc123',
|
|
2963
|
+
* });
|
|
2964
|
+
*
|
|
2965
|
+
* // The key is now available in the agent's environment
|
|
2966
|
+
* // Access via: process.env.POLYMARKET_API_KEY
|
|
2967
|
+
* ```
|
|
2968
|
+
*/
|
|
2969
|
+
async configureSkill(skillId, envVars) {
|
|
2970
|
+
this.logger.debug("configureSkill", { skillId, varNames: Object.keys(envVars) });
|
|
2971
|
+
const authHeaders = await this.getSessionAuthHeaders();
|
|
2972
|
+
const response = await fetch(`${this.baseUrl}/api/v2/skills/${skillId}/configure`, {
|
|
2973
|
+
method: "POST",
|
|
2974
|
+
headers: {
|
|
2975
|
+
"Content-Type": "application/json",
|
|
2976
|
+
...authHeaders
|
|
2977
|
+
},
|
|
2978
|
+
body: JSON.stringify({ env_vars: envVars })
|
|
2979
|
+
});
|
|
2980
|
+
if (!response.ok) {
|
|
2981
|
+
const error = await response.json().catch(() => ({}));
|
|
2982
|
+
throw new MixrPayError(
|
|
2983
|
+
error.error || `Failed to configure skill: ${response.status}`,
|
|
2984
|
+
error.error_code
|
|
2985
|
+
);
|
|
2986
|
+
}
|
|
2987
|
+
const data = await response.json();
|
|
2988
|
+
return {
|
|
2989
|
+
success: true,
|
|
2990
|
+
skillId: data.skill_id,
|
|
2991
|
+
configuredVars: data.configured_vars || []
|
|
2992
|
+
};
|
|
2993
|
+
}
|
|
2994
|
+
// ===========================================================================
|
|
2726
2995
|
// Glama MCP Directory Methods
|
|
2727
2996
|
// ===========================================================================
|
|
2728
2997
|
/**
|
|
@@ -4362,11 +4631,11 @@ Timestamp: ${timestamp}`;
|
|
|
4362
4631
|
...init.headers
|
|
4363
4632
|
};
|
|
4364
4633
|
if (this.sessionKey) {
|
|
4365
|
-
const account =
|
|
4634
|
+
const account = accounts.privateKeyToAccount(this.sessionKey.rawPrivateKey);
|
|
4366
4635
|
const address = account.address.toLowerCase();
|
|
4367
4636
|
const timestamp = Date.now();
|
|
4368
4637
|
const message = `MixrPay:${timestamp}:${address}`;
|
|
4369
|
-
const signature = await
|
|
4638
|
+
const signature = await accounts.signMessage({
|
|
4370
4639
|
message,
|
|
4371
4640
|
privateKey: this.sessionKey.rawPrivateKey
|
|
4372
4641
|
});
|
|
@@ -4382,22 +4651,20 @@ Timestamp: ${timestamp}`;
|
|
|
4382
4651
|
});
|
|
4383
4652
|
}
|
|
4384
4653
|
};
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
isMixrPayError
|
|
4403
|
-
});
|
|
4654
|
+
|
|
4655
|
+
exports.AgentWallet = AgentWallet;
|
|
4656
|
+
exports.InsufficientBalanceError = InsufficientBalanceError;
|
|
4657
|
+
exports.InvalidSessionKeyError = InvalidSessionKeyError;
|
|
4658
|
+
exports.MerchantNotAllowedError = MerchantNotAllowedError;
|
|
4659
|
+
exports.MixrPayError = MixrPayError;
|
|
4660
|
+
exports.PaymentFailedError = PaymentFailedError;
|
|
4661
|
+
exports.SDK_VERSION = SDK_VERSION;
|
|
4662
|
+
exports.SessionExpiredError = SessionExpiredError;
|
|
4663
|
+
exports.SessionKeyExpiredError = SessionKeyExpiredError;
|
|
4664
|
+
exports.SessionLimitExceededError = SessionLimitExceededError;
|
|
4665
|
+
exports.SessionNotFoundError = SessionNotFoundError;
|
|
4666
|
+
exports.SessionRevokedError = SessionRevokedError;
|
|
4667
|
+
exports.SpendingLimitExceededError = SpendingLimitExceededError;
|
|
4668
|
+
exports.X402ProtocolError = X402ProtocolError;
|
|
4669
|
+
exports.getErrorMessage = getErrorMessage;
|
|
4670
|
+
exports.isMixrPayError = isMixrPayError;
|