cornerstone-autonomous-agent 1.3.0 → 2.1.0

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.
@@ -1,259 +1,260 @@
1
- /**
2
- * Local tools for the agent: balance_aptos, balance_evm, get_wallet_addresses, create_aptos_wallet, create_evm_wallet.
3
- */
4
-
5
- import { tool } from '@langchain/core/tools';
6
- import { z } from 'zod';
7
- import { getAptosBalance } from '../../lib/aptos/balance.js';
8
- import {
9
- getWalletInfo as getAptosWalletInfo,
10
- getAllWalletInfos as getAptosAllWalletInfos,
11
- save as saveAptosWallet,
12
- exists as aptosWalletExists,
13
- } from '../../lib/aptos/wallet.js';
14
- import {
15
- getWalletInfo as getEvmWalletInfo,
16
- getAllWalletInfos as getEvmAllWalletInfos,
17
- getAddress,
18
- generate as generateEvmWallet,
19
- save as saveEvmWallet,
20
- exists as evmWalletExists,
21
- } from '../../lib/wallet.js';
22
- import { createPublicClientWithRetry } from '../../lib/rpc.js';
23
- import { getChain, getSupportedChains } from '../../lib/chains.js';
24
- import { formatEther } from 'viem';
25
- import { APTOS_FAUCET_TESTNET_PAGE } from '../../lib/aptos/config.js';
26
-
27
- export function createLocalTools() {
28
- const balance_aptos = tool(
29
- async () => {
30
- try {
31
- const info = getAptosWalletInfo();
32
- if (!info?.address) return JSON.stringify({ error: 'No Aptos wallet. Run setup-aptos.js.' });
33
- const bal = await getAptosBalance(info.address);
34
- return JSON.stringify(bal ?? { error: 'Could not fetch balance' });
35
- } catch (e) {
36
- return JSON.stringify({ error: e.message });
37
- }
38
- },
39
- {
40
- name: 'balance_aptos',
41
- description: 'Get Aptos USDC balance for the agent wallet. Use before calling paid Aptos tools (run_prediction, run_backtest).',
42
- schema: z.object({}),
43
- }
44
- );
45
-
46
- const balance_evm = tool(
47
- async ({ chain }) => {
48
- try {
49
- if (!evmWalletExists()) return JSON.stringify({ error: 'No EVM wallet. Run setup.js.' });
50
- const addr = getAddress();
51
- const chainName = (chain || 'base').toLowerCase();
52
- if (!getSupportedChains().includes(chainName)) {
53
- return JSON.stringify({ error: `Unsupported chain. Use one of: ${getSupportedChains().join(', ')}` });
54
- }
55
- const chainConfig = getChain(chainName);
56
- const client = createPublicClientWithRetry(chainName);
57
- const balance = await client.getBalance({ address: addr });
58
- return JSON.stringify({
59
- address: addr,
60
- chain: chainName,
61
- balance: formatEther(balance),
62
- symbol: chainConfig.nativeToken?.symbol || 'ETH',
63
- });
64
- } catch (e) {
65
- return JSON.stringify({ error: e.message });
66
- }
67
- },
68
- {
69
- name: 'balance_evm',
70
- description: 'Get EVM native token balance for the agent wallet on a chain (base, baseSepolia, ethereum, etc.).',
71
- schema: z.object({
72
- chain: z.string().default('base').describe('Chain name: base, baseSepolia, ethereum, polygon, arbitrum, optimism (default base)'),
73
- }),
74
- }
75
- );
76
-
77
- const get_wallet_addresses = tool(
78
- async () => {
79
- const aptosList = aptosWalletExists() ? getAptosAllWalletInfos() : [];
80
- const evmList = evmWalletExists() ? getEvmAllWalletInfos() : [];
81
- return JSON.stringify({
82
- aptos: aptosList.map((w) => ({ address: w.address, network: w.network || null })),
83
- evm: evmList.map((w) => ({ address: w.address, network: w.network || null })),
84
- });
85
- },
86
- {
87
- name: 'get_wallet_addresses',
88
- description: 'Get all agent wallet addresses (Aptos and EVM). Returns lists with optional network (testnet/mainnet). Use to check which wallets are configured and whitelist them.',
89
- schema: z.object({}),
90
- }
91
- );
92
-
93
- const create_aptos_wallet = tool(
94
- async ({ force, network }) => {
95
- try {
96
- const net = (network || '').toLowerCase() === 'mainnet' ? 'mainnet' : 'testnet';
97
- if (aptosWalletExists() && !force) {
98
- const infos = getAptosAllWalletInfos();
99
- return JSON.stringify({
100
- success: false,
101
- message: 'Aptos wallet(s) already exist. Use force: true to add another or overwrite. You can have multiple Aptos wallets (testnet and mainnet).',
102
- addresses: infos.map((w) => ({ address: w.address, network: w.network || null })),
103
- });
104
- }
105
- const { Account } = await import('@aptos-labs/ts-sdk');
106
- const account = Account.generate();
107
- const wallet = {
108
- address: account.accountAddress.toString(),
109
- privateKey: account.privateKey.toString(),
110
- network: net,
111
- createdAt: new Date().toISOString(),
112
- };
113
- saveAptosWallet(wallet);
114
- return JSON.stringify({
115
- success: true,
116
- message: `Aptos wallet created (${net}). Whitelist this address at http://localhost:4024/flow.html and fund with ${net} APT/USDC for run_prediction and run_backtest.`,
117
- address: wallet.address,
118
- network: net,
119
- });
120
- } catch (e) {
121
- if (e.code === 'ERR_MODULE_NOT_FOUND' || (e?.message?.includes?.('@aptos-labs/ts-sdk'))) {
122
- return JSON.stringify({ success: false, error: 'Aptos SDK not installed. Run: npm install @aptos-labs/ts-sdk' });
123
- }
124
- return JSON.stringify({ success: false, error: e.message });
125
- }
126
- },
127
- {
128
- name: 'create_aptos_wallet',
129
- description: 'Create a new Aptos wallet for the agent (optionally testnet or mainnet). Agent can have multiple Aptos wallets. Returns the address to whitelist and fund.',
130
- schema: z.object({
131
- force: z.boolean().default(false).describe('If true, add another wallet even when one exists; otherwise only one allowed per run without force.'),
132
- network: z.enum(['testnet', 'mainnet']).nullable().default(null).describe('Optional: testnet (default) or mainnet.'),
133
- }),
134
- }
135
- );
136
-
137
- const create_evm_wallet = tool(
138
- async ({ force, network }) => {
139
- try {
140
- const net = (network || '').toLowerCase() === 'mainnet' ? 'mainnet' : 'testnet';
141
- if (evmWalletExists() && !force) {
142
- const infos = getEvmAllWalletInfos();
143
- return JSON.stringify({
144
- success: false,
145
- message: 'EVM wallet(s) already exist. Use force: true to add another. You can have multiple EVM wallets (testnet and mainnet).',
146
- addresses: infos.map((w) => ({ address: w.address, network: w.network || null })),
147
- });
148
- }
149
- const wallet = generateEvmWallet();
150
- wallet.network = net;
151
- saveEvmWallet(wallet);
152
- return JSON.stringify({
153
- success: true,
154
- message: `EVM wallet created (${net}). Whitelist this address at http://localhost:4024/flow.html and fund with ETH on Base Sepolia (testnet) or Base (mainnet) for link_bank_account.`,
155
- address: wallet.address,
156
- network: net,
157
- });
158
- } catch (e) {
159
- return JSON.stringify({ success: false, error: e.message });
160
- }
161
- },
162
- {
163
- name: 'create_evm_wallet',
164
- description: 'Create a new EVM wallet for the agent (optionally testnet or mainnet). Agent can have multiple EVM wallets. Returns the address to whitelist and fund.',
165
- schema: z.object({
166
- force: z.boolean().default(false).describe('If true, add another wallet even when one exists.'),
167
- network: z.enum(['testnet', 'mainnet']).optional().describe('Optional: testnet (default) or mainnet.'),
168
- }),
169
- }
170
- );
171
-
172
- const credit_aptos_wallet = tool(
173
- async ({ amount_octas }) => {
174
- try {
175
- if (!aptosWalletExists()) {
176
- return JSON.stringify({
177
- success: false,
178
- error: 'No Aptos wallet. Use create_aptos_wallet first.',
179
- });
180
- }
181
- const info = getAptosWalletInfo();
182
- const address = info?.address;
183
- if (!address) {
184
- return JSON.stringify({ success: false, error: 'Could not read Aptos address.' });
185
- }
186
- const network = (process.env.APTOS_FAUCET_NETWORK || 'testnet').toLowerCase();
187
- const octas = amount_octas ?? 100_000_000; // 1 APT default
188
- if (network === 'devnet') {
189
- const { Aptos, AptosConfig, Network } = await import('@aptos-labs/ts-sdk');
190
- const aptosConfig = new AptosConfig({ network: Network.DEVNET });
191
- const aptos = new Aptos(aptosConfig);
192
- await aptos.fundAccount({ accountAddress: address, amount: octas });
193
- return JSON.stringify({
194
- success: true,
195
- message: `Funded Aptos wallet on devnet with ${octas} octas (${octas / 100_000_000} APT). Demo MCP uses testnet by default.`,
196
- address,
197
- });
198
- }
199
- return JSON.stringify({
200
- success: true,
201
- message: 'Aptos testnet has no programmatic faucet. Fund manually: open ' + APTOS_FAUCET_TESTNET_PAGE + ', sign in, enter address below, request APT. Also fund USDC for x402 payments if needed.',
202
- address,
203
- faucet_url: APTOS_FAUCET_TESTNET_PAGE,
204
- });
205
- } catch (e) {
206
- return JSON.stringify({ success: false, error: e.message });
207
- }
208
- },
209
- {
210
- name: 'credit_aptos_wallet',
211
- description: 'Fund the agent Aptos wallet. On devnet (APTOS_FAUCET_NETWORK=devnet) uses programmatic faucet; on testnet returns instructions and faucet URL. Use after create_aptos_wallet.',
212
- schema: z.object({
213
- amount_octas: z.number().nullable().default(100_000_000).describe('Amount in octas (1 APT = 100_000_000). Default 1 APT.'),
214
- }),
215
- }
216
- );
217
-
218
- const BASE_SEPOLIA_FAUCET = 'https://www.alchemy.com/faucets/base-sepolia';
219
- const fund_evm_wallet = tool(
220
- async () => {
221
- try {
222
- if (!evmWalletExists()) {
223
- return JSON.stringify({
224
- success: false,
225
- error: 'No EVM wallet. Use create_evm_wallet first.',
226
- });
227
- }
228
- const info = getEvmWalletInfo();
229
- const address = info?.address;
230
- if (!address) {
231
- return JSON.stringify({ success: false, error: 'Could not read EVM address.' });
232
- }
233
- return JSON.stringify({
234
- success: true,
235
- message: 'EVM (Base Sepolia) has no programmatic faucet in this agent. Fund manually: open a Base Sepolia faucet, enter the address below, request test ETH. Needed for link_bank_account (~$3.65). Whitelist this address at http://localhost:4024/flow.html.',
236
- address,
237
- faucet_url: BASE_SEPOLIA_FAUCET,
238
- });
239
- } catch (e) {
240
- return JSON.stringify({ success: false, error: e.message });
241
- }
242
- },
243
- {
244
- name: 'fund_evm_wallet',
245
- description: 'Get funding instructions and faucet URL for the agent EVM wallet (Base Sepolia). Use after create_evm_wallet. No programmatic funding; returns address and instructions.',
246
- schema: z.object({}),
247
- }
248
- );
249
-
250
- return [
251
- balance_aptos,
252
- balance_evm,
253
- get_wallet_addresses,
254
- create_aptos_wallet,
255
- create_evm_wallet,
256
- credit_aptos_wallet,
257
- fund_evm_wallet,
258
- ];
259
- }
1
+ /**
2
+ * Local tools (for agents using this skill): balance_aptos, balance_evm, get_wallet_addresses, create_aptos_wallet, create_evm_wallet.
3
+ */
4
+
5
+ import { tool } from '@langchain/core/tools';
6
+ import { z } from 'zod';
7
+ import { getAptosBalance } from '../../lib/aptos/balance.js';
8
+ import {
9
+ getWalletInfo as getAptosWalletInfo,
10
+ getAllWalletInfos as getAptosAllWalletInfos,
11
+ save as saveAptosWallet,
12
+ exists as aptosWalletExists,
13
+ } from '../../lib/aptos/wallet.js';
14
+ import {
15
+ getWalletInfo as getEvmWalletInfo,
16
+ getAllWalletInfos as getEvmAllWalletInfos,
17
+ getAddress,
18
+ generate as generateEvmWallet,
19
+ save as saveEvmWallet,
20
+ exists as evmWalletExists,
21
+ } from '../../lib/wallet.js';
22
+ import { createPublicClientWithRetry } from '../../lib/rpc.js';
23
+ import { getChain, getSupportedChains } from '../../lib/chains.js';
24
+ import { formatEther } from 'viem';
25
+ import { APTOS_FAUCET_TESTNET_PAGE } from '../../lib/aptos/config.js';
26
+
27
+ export function createLocalTools() {
28
+ const balance_aptos = tool(
29
+ async () => {
30
+ try {
31
+ const info = getAptosWalletInfo();
32
+ if (!info?.address) return JSON.stringify({ error: 'No Aptos wallet. Run setup-aptos.js.' });
33
+ const bal = await getAptosBalance(info.address);
34
+ return JSON.stringify(bal ?? { error: 'Could not fetch balance' });
35
+ } catch (e) {
36
+ return JSON.stringify({ error: e.message });
37
+ }
38
+ },
39
+ {
40
+ name: 'balance_aptos',
41
+ description: 'Get Aptos balance (USDC + APT) for the configured wallet. Returns { address, balances: { usdc, apt } } or { error }. Call before run_prediction, run_backtest, or score tools to confirm sufficient USDC.',
42
+ schema: z.object({}),
43
+ }
44
+ );
45
+
46
+ const balance_evm = tool(
47
+ async ({ chain }) => {
48
+ try {
49
+ if (!evmWalletExists()) return JSON.stringify({ error: 'No EVM wallet. Run setup.js.' });
50
+ const addr = getAddress();
51
+ const chainInput = (chain || 'base').toLowerCase();
52
+ const chainName = getSupportedChains().find((c) => c.toLowerCase() === chainInput);
53
+ if (!chainName) {
54
+ return JSON.stringify({ error: `Unsupported chain. Use one of: ${getSupportedChains().join(', ')}` });
55
+ }
56
+ const chainConfig = getChain(chainName);
57
+ const client = createPublicClientWithRetry(chainName);
58
+ const balance = await client.getBalance({ address: addr });
59
+ return JSON.stringify({
60
+ address: addr,
61
+ chain: chainName,
62
+ balance: formatEther(balance),
63
+ symbol: chainConfig.nativeToken?.symbol || 'ETH',
64
+ });
65
+ } catch (e) {
66
+ return JSON.stringify({ error: e.message });
67
+ }
68
+ },
69
+ {
70
+ name: 'balance_evm',
71
+ description: 'Get EVM native token balance. Returns { address, chain, balance, symbol } or { error }. Use chain "baseSepolia" before link_bank_account. Supported: base, baseSepolia, ethereum, polygon, arbitrum, optimism.',
72
+ schema: z.object({
73
+ chain: z.string().default('base').describe('Chain name: base, baseSepolia, ethereum, polygon, arbitrum, optimism (default base)'),
74
+ }),
75
+ }
76
+ );
77
+
78
+ const get_wallet_addresses = tool(
79
+ async () => {
80
+ const aptosList = aptosWalletExists() ? getAptosAllWalletInfos() : [];
81
+ const evmList = evmWalletExists() ? getEvmAllWalletInfos() : [];
82
+ return JSON.stringify({
83
+ aptos: aptosList.map((w) => ({ address: w.address, network: w.network || null })),
84
+ evm: evmList.map((w) => ({ address: w.address, network: w.network || null })),
85
+ });
86
+ },
87
+ {
88
+ name: 'get_wallet_addresses',
89
+ description: 'Get all configured wallet addresses. Returns { aptos: [{ address, network }], evm: [{ address, network }] } — arrays may be empty. ALWAYS call this first before any wallet or paid tool action to see what exists.',
90
+ schema: z.object({}),
91
+ }
92
+ );
93
+
94
+ const create_aptos_wallet = tool(
95
+ async ({ force, network }) => {
96
+ try {
97
+ const net = (network || '').toLowerCase() === 'mainnet' ? 'mainnet' : 'testnet';
98
+ if (aptosWalletExists() && !force) {
99
+ const infos = getAptosAllWalletInfos();
100
+ return JSON.stringify({
101
+ success: false,
102
+ message: 'Aptos wallet(s) already exist. Use force: true to add another or overwrite. You can have multiple Aptos wallets (testnet and mainnet).',
103
+ addresses: infos.map((w) => ({ address: w.address, network: w.network || null })),
104
+ });
105
+ }
106
+ const { Account } = await import('@aptos-labs/ts-sdk');
107
+ const account = Account.generate();
108
+ const wallet = {
109
+ address: account.accountAddress.toString(),
110
+ privateKey: account.privateKey.toString(),
111
+ network: net,
112
+ createdAt: new Date().toISOString(),
113
+ };
114
+ saveAptosWallet(wallet);
115
+ return JSON.stringify({
116
+ success: true,
117
+ message: `Aptos wallet created (${net}). Whitelist this address at https://arnstein.ch/flow.html and fund with ${net} APT/USDC for run_prediction and run_backtest.`,
118
+ address: wallet.address,
119
+ network: net,
120
+ });
121
+ } catch (e) {
122
+ if (e.code === 'ERR_MODULE_NOT_FOUND' || (e?.message?.includes?.('@aptos-labs/ts-sdk'))) {
123
+ return JSON.stringify({ success: false, error: 'Aptos SDK not installed. Run: npm install @aptos-labs/ts-sdk' });
124
+ }
125
+ return JSON.stringify({ success: false, error: e.message });
126
+ }
127
+ },
128
+ {
129
+ name: 'create_aptos_wallet',
130
+ description: 'Create a new Aptos wallet. Returns { success, address, network }. If wallet exists and force=false, returns existing addresses instead. After creating, call credit_aptos_wallet to fund, then tell the user to whitelist the address at https://arnstein.ch/flow.html.',
131
+ schema: z.object({
132
+ force: z.boolean().default(false).describe('If true, add another wallet even when one exists; otherwise only one allowed per run without force.'),
133
+ network: z.enum(['testnet', 'mainnet']).nullable().default(null).describe('Optional: testnet (default) or mainnet.'),
134
+ }),
135
+ }
136
+ );
137
+
138
+ const create_evm_wallet = tool(
139
+ async ({ force, network }) => {
140
+ try {
141
+ const net = (network || '').toLowerCase() === 'mainnet' ? 'mainnet' : 'testnet';
142
+ if (evmWalletExists() && !force) {
143
+ const infos = getEvmAllWalletInfos();
144
+ return JSON.stringify({
145
+ success: false,
146
+ message: 'EVM wallet(s) already exist. Use force: true to add another. You can have multiple EVM wallets (testnet and mainnet).',
147
+ addresses: infos.map((w) => ({ address: w.address, network: w.network || null })),
148
+ });
149
+ }
150
+ const wallet = generateEvmWallet();
151
+ wallet.network = net;
152
+ saveEvmWallet(wallet);
153
+ return JSON.stringify({
154
+ success: true,
155
+ message: `EVM wallet created (${net}). Whitelist this address at https://arnstein.ch/flow.html and fund with ETH on Base Sepolia (testnet) or Base (mainnet) for link_bank_account.`,
156
+ address: wallet.address,
157
+ network: net,
158
+ });
159
+ } catch (e) {
160
+ return JSON.stringify({ success: false, error: e.message });
161
+ }
162
+ },
163
+ {
164
+ name: 'create_evm_wallet',
165
+ description: 'Create a new EVM wallet. Returns { success, address, network }. If wallet exists and force=false, returns existing addresses instead. After creating, call fund_evm_wallet for funding instructions, then tell the user to whitelist at https://arnstein.ch/flow.html.',
166
+ schema: z.object({
167
+ force: z.boolean().default(false).describe('If true, add another wallet even when one exists.'),
168
+ network: z.enum(['testnet', 'mainnet']).optional().describe('Optional: testnet (default) or mainnet.'),
169
+ }),
170
+ }
171
+ );
172
+
173
+ const credit_aptos_wallet = tool(
174
+ async ({ amount_octas }) => {
175
+ try {
176
+ if (!aptosWalletExists()) {
177
+ return JSON.stringify({
178
+ success: false,
179
+ error: 'No Aptos wallet. Use create_aptos_wallet first.',
180
+ });
181
+ }
182
+ const info = getAptosWalletInfo();
183
+ const address = info?.address;
184
+ if (!address) {
185
+ return JSON.stringify({ success: false, error: 'Could not read Aptos address.' });
186
+ }
187
+ const network = (process.env.APTOS_FAUCET_NETWORK || 'testnet').toLowerCase();
188
+ const octas = amount_octas ?? 100_000_000; // 1 APT default
189
+ if (network === 'devnet') {
190
+ const { Aptos, AptosConfig, Network } = await import('@aptos-labs/ts-sdk');
191
+ const aptosConfig = new AptosConfig({ network: Network.DEVNET });
192
+ const aptos = new Aptos(aptosConfig);
193
+ await aptos.fundAccount({ accountAddress: address, amount: octas });
194
+ return JSON.stringify({
195
+ success: true,
196
+ message: `Funded Aptos wallet on devnet with ${octas} octas (${octas / 100_000_000} APT). Demo MCP uses testnet by default.`,
197
+ address,
198
+ });
199
+ }
200
+ return JSON.stringify({
201
+ success: true,
202
+ message: 'Aptos testnet has no programmatic faucet. Fund manually: open ' + APTOS_FAUCET_TESTNET_PAGE + ', sign in, enter address below, request APT. Also fund USDC for x402 payments if needed.',
203
+ address,
204
+ faucet_url: APTOS_FAUCET_TESTNET_PAGE,
205
+ });
206
+ } catch (e) {
207
+ return JSON.stringify({ success: false, error: e.message });
208
+ }
209
+ },
210
+ {
211
+ name: 'credit_aptos_wallet',
212
+ description: 'Fund the Aptos wallet. Devnet: programmatic faucet (funds directly). Testnet: returns { faucet_url, address } with manual instructions. Prerequisite: Aptos wallet must exist (call create_aptos_wallet first).',
213
+ schema: z.object({
214
+ amount_octas: z.number().nullable().default(100_000_000).describe('Amount in octas (1 APT = 100_000_000). Default 1 APT.'),
215
+ }),
216
+ }
217
+ );
218
+
219
+ const BASE_SEPOLIA_FAUCET = 'https://www.alchemy.com/faucets/base-sepolia';
220
+ const fund_evm_wallet = tool(
221
+ async () => {
222
+ try {
223
+ if (!evmWalletExists()) {
224
+ return JSON.stringify({
225
+ success: false,
226
+ error: 'No EVM wallet. Use create_evm_wallet first.',
227
+ });
228
+ }
229
+ const info = getEvmWalletInfo();
230
+ const address = info?.address;
231
+ if (!address) {
232
+ return JSON.stringify({ success: false, error: 'Could not read EVM address.' });
233
+ }
234
+ return JSON.stringify({
235
+ success: true,
236
+ message: 'EVM (Base Sepolia) has no programmatic faucet here. Fund manually: open a Base Sepolia faucet, enter the address below, request test ETH. Needed for link_bank_account (~$3.65). Whitelist this address at https://arnstein.ch/flow.html.',
237
+ address,
238
+ faucet_url: BASE_SEPOLIA_FAUCET,
239
+ });
240
+ } catch (e) {
241
+ return JSON.stringify({ success: false, error: e.message });
242
+ }
243
+ },
244
+ {
245
+ name: 'fund_evm_wallet',
246
+ description: 'Get funding instructions for the EVM wallet (Base Sepolia). Returns { faucet_url, address, message }. No programmatic faucet — user must fund manually. Prerequisite: EVM wallet must exist (call create_evm_wallet first).',
247
+ schema: z.object({}),
248
+ }
249
+ );
250
+
251
+ return [
252
+ balance_aptos,
253
+ balance_evm,
254
+ get_wallet_addresses,
255
+ create_aptos_wallet,
256
+ create_evm_wallet,
257
+ credit_aptos_wallet,
258
+ fund_evm_wallet,
259
+ ];
260
+ }