@exagent/agent 0.3.5 → 0.3.7
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/chunk-7UGLJO6W.js +6392 -0
- package/dist/chunk-EHAOPCTJ.js +6406 -0
- package/dist/chunk-FGMXTW5I.js +6540 -0
- package/dist/chunk-IVA2SCSN.js +6756 -0
- package/dist/chunk-JHXCSGPC.js +6352 -0
- package/dist/chunk-V6O4UXVN.js +6345 -0
- package/dist/chunk-ZRAOPQQW.js +6406 -0
- package/dist/cli.js +40 -98
- package/dist/index.d.ts +24 -2
- package/dist/index.js +1 -1
- package/package.json +17 -14
- package/.turbo/turbo-build.log +0 -17
- package/src/bridge/across.ts +0 -240
- package/src/bridge/bridge-manager.ts +0 -87
- package/src/bridge/index.ts +0 -9
- package/src/bridge/types.ts +0 -77
- package/src/chains.ts +0 -105
- package/src/cli.ts +0 -244
- package/src/config.ts +0 -499
- package/src/diagnostics.ts +0 -335
- package/src/index.ts +0 -98
- package/src/llm/anthropic.ts +0 -63
- package/src/llm/base.ts +0 -264
- package/src/llm/deepseek.ts +0 -48
- package/src/llm/google.ts +0 -63
- package/src/llm/groq.ts +0 -48
- package/src/llm/index.ts +0 -42
- package/src/llm/mistral.ts +0 -48
- package/src/llm/ollama.ts +0 -52
- package/src/llm/openai.ts +0 -51
- package/src/llm/together.ts +0 -48
- package/src/llm-providers.ts +0 -100
- package/src/logger.ts +0 -137
- package/src/paper/executor.ts +0 -201
- package/src/paper/index.ts +0 -1
- package/src/perp/client.ts +0 -200
- package/src/perp/index.ts +0 -12
- package/src/perp/msgpack.ts +0 -272
- package/src/perp/orders.ts +0 -234
- package/src/perp/positions.ts +0 -126
- package/src/perp/signer.ts +0 -277
- package/src/perp/types.ts +0 -192
- package/src/perp/websocket.ts +0 -274
- package/src/position-tracker.ts +0 -243
- package/src/prediction/client.ts +0 -281
- package/src/prediction/index.ts +0 -3
- package/src/prediction/order-manager.ts +0 -297
- package/src/prediction/types.ts +0 -151
- package/src/relay.ts +0 -254
- package/src/runtime.ts +0 -1755
- package/src/scrub-secrets.ts +0 -39
- package/src/setup.ts +0 -384
- package/src/signal.ts +0 -212
- package/src/spot/aerodrome.ts +0 -158
- package/src/spot/client.ts +0 -138
- package/src/spot/index.ts +0 -11
- package/src/spot/swap-manager.ts +0 -219
- package/src/spot/types.ts +0 -203
- package/src/spot/uniswap.ts +0 -150
- package/src/store.ts +0 -50
- package/src/strategy/index.ts +0 -2
- package/src/strategy/loader.ts +0 -191
- package/src/strategy/templates.ts +0 -125
- package/src/trading/index.ts +0 -2
- package/src/trading/market.ts +0 -120
- package/src/trading/risk.ts +0 -107
- package/src/ui.ts +0 -75
- package/test-bridge-arb-to-base.mjs +0 -223
- package/test-funded-check.mjs +0 -79
- package/test-funded-phase19.mjs +0 -933
- package/test-hl-deposit-recover.mjs +0 -281
- package/test-hl-withdraw.mjs +0 -372
- package/test-live-signing.mjs +0 -374
- package/test-phase7.mjs +0 -416
- package/test-recover-arb.mjs +0 -206
- package/test-spot-bridge.mjs +0 -248
- package/test-wallet-setup.mjs +0 -126
- package/tsconfig.json +0 -8
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { getChainConfig } from '../chains.js';
|
|
2
|
-
import type { SpotDEXClient } from '../spot/client.js';
|
|
3
|
-
import { AcrossAdapter } from './across.js';
|
|
4
|
-
import type { BridgeConfig, BridgeRequest, BridgeFeeEstimate, BridgeResult } from './types.js';
|
|
5
|
-
|
|
6
|
-
const MIN_GAS_WEI = 100_000_000_000_000n; // 0.0001 ETH/POL
|
|
7
|
-
|
|
8
|
-
export class BridgeManager {
|
|
9
|
-
private across: AcrossAdapter;
|
|
10
|
-
private client: SpotDEXClient;
|
|
11
|
-
private config: BridgeConfig;
|
|
12
|
-
|
|
13
|
-
constructor(client: SpotDEXClient, config: BridgeConfig) {
|
|
14
|
-
this.config = config;
|
|
15
|
-
this.client = client;
|
|
16
|
-
this.across = new AcrossAdapter(client, config);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async estimateFee(request: BridgeRequest): Promise<BridgeFeeEstimate> {
|
|
20
|
-
const bridge = request.bridge ?? this.config.defaultBridge;
|
|
21
|
-
if (bridge !== 'across') {
|
|
22
|
-
throw new Error(`Unsupported bridge: ${bridge}. Only "across" is currently supported.`);
|
|
23
|
-
}
|
|
24
|
-
return this.across.estimateFee(request);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async bridge(request: BridgeRequest): Promise<BridgeResult> {
|
|
28
|
-
const bridge = request.bridge ?? this.config.defaultBridge;
|
|
29
|
-
if (bridge !== 'across') {
|
|
30
|
-
return {
|
|
31
|
-
success: false,
|
|
32
|
-
depositTxHash: '0x0' as `0x${string}`,
|
|
33
|
-
fromChain: request.fromChain,
|
|
34
|
-
toChain: request.toChain,
|
|
35
|
-
token: request.token,
|
|
36
|
-
amount: request.amount,
|
|
37
|
-
fee: 0n,
|
|
38
|
-
error: `Unsupported bridge: ${bridge}. Only "across" is currently supported.`,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Enforce max bridge value cap
|
|
43
|
-
// Bridge amounts are in token decimals — estimate USD for common tokens (USDC = 6 decimals)
|
|
44
|
-
try {
|
|
45
|
-
const decimals = await this.client.getDecimals(request.token, request.fromChain);
|
|
46
|
-
const amountFloat = Number(request.amount) / 10 ** decimals;
|
|
47
|
-
if (amountFloat > this.config.maxBridgeValueUSD) {
|
|
48
|
-
return {
|
|
49
|
-
success: false,
|
|
50
|
-
depositTxHash: '0x0' as `0x${string}`,
|
|
51
|
-
fromChain: request.fromChain,
|
|
52
|
-
toChain: request.toChain,
|
|
53
|
-
token: request.token,
|
|
54
|
-
amount: request.amount,
|
|
55
|
-
fee: 0n,
|
|
56
|
-
error: `Bridge value ${amountFloat.toFixed(2)} exceeds max $${this.config.maxBridgeValueUSD}. Reduce amount or increase maxBridgeValueUSD.`,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
} catch {
|
|
60
|
-
// If decimals lookup fails, proceed — let the bridge itself validate
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Pre-check native gas balance on origin chain
|
|
64
|
-
try {
|
|
65
|
-
const nativeBalance = await this.client.getNativeBalance(request.fromChain);
|
|
66
|
-
if (nativeBalance < MIN_GAS_WEI) {
|
|
67
|
-
const chainConfig = getChainConfig(request.fromChain);
|
|
68
|
-
const nativeName = chainConfig?.nativeCurrency ?? 'ETH';
|
|
69
|
-
return {
|
|
70
|
-
success: false,
|
|
71
|
-
depositTxHash: '0x0' as `0x${string}`,
|
|
72
|
-
fromChain: request.fromChain,
|
|
73
|
-
toChain: request.toChain,
|
|
74
|
-
token: request.token,
|
|
75
|
-
amount: request.amount,
|
|
76
|
-
fee: 0n,
|
|
77
|
-
error: `Insufficient ${nativeName} for gas on ${request.fromChain}. Balance: ${nativeBalance} wei. Need at least 0.0001 ${nativeName}.`,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
} catch {
|
|
81
|
-
// Non-critical — proceed and let the bridge itself surface the error
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
console.log(`[bridge] Bridging via Across: ${request.fromChain} → ${request.toChain} (${request.amount})`);
|
|
85
|
-
return this.across.deposit(request);
|
|
86
|
-
}
|
|
87
|
-
}
|
package/src/bridge/index.ts
DELETED
package/src/bridge/types.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
// ─── Bridge Config ──────────────────────────────────────────────
|
|
2
|
-
|
|
3
|
-
export interface BridgeConfig {
|
|
4
|
-
enabled: boolean;
|
|
5
|
-
defaultBridge: string;
|
|
6
|
-
maxBridgeValueUSD: number;
|
|
7
|
-
fillTimeoutMs: number;
|
|
8
|
-
pollIntervalMs: number;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const DEFAULT_BRIDGE_CONFIG: BridgeConfig = {
|
|
12
|
-
enabled: false,
|
|
13
|
-
defaultBridge: 'across',
|
|
14
|
-
maxBridgeValueUSD: 10_000,
|
|
15
|
-
fillTimeoutMs: 300_000, // 5 minutes
|
|
16
|
-
pollIntervalMs: 2_000, // 2 seconds
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
// ─── Bridge Request & Results ───────────────────────────────────
|
|
20
|
-
|
|
21
|
-
export interface BridgeRequest {
|
|
22
|
-
token: `0x${string}`;
|
|
23
|
-
amount: bigint;
|
|
24
|
-
fromChain: string;
|
|
25
|
-
toChain: string;
|
|
26
|
-
recipient?: `0x${string}`;
|
|
27
|
-
bridge?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface BridgeFeeEstimate {
|
|
31
|
-
totalRelayFeePct: number;
|
|
32
|
-
capitalFeePct: number;
|
|
33
|
-
lpFeePct: number;
|
|
34
|
-
relayGasFeePct: number;
|
|
35
|
-
timestamp: number;
|
|
36
|
-
estimatedFillTimeSec: number;
|
|
37
|
-
isAmountTooLow: boolean;
|
|
38
|
-
outputAmount: bigint;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface BridgeResult {
|
|
42
|
-
success: boolean;
|
|
43
|
-
depositTxHash: `0x${string}`;
|
|
44
|
-
fromChain: string;
|
|
45
|
-
toChain: string;
|
|
46
|
-
token: `0x${string}`;
|
|
47
|
-
amount: bigint;
|
|
48
|
-
fee: bigint;
|
|
49
|
-
fillTxHash?: `0x${string}`;
|
|
50
|
-
fillTimestamp?: number;
|
|
51
|
-
error?: string;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// ─── Across SpokePool ABI Fragment ──────────────────────────────
|
|
55
|
-
|
|
56
|
-
export const ACROSS_SPOKE_POOL_ABI = [
|
|
57
|
-
{
|
|
58
|
-
type: 'function' as const,
|
|
59
|
-
name: 'depositV3' as const,
|
|
60
|
-
inputs: [
|
|
61
|
-
{ name: 'depositor', type: 'address' as const },
|
|
62
|
-
{ name: 'recipient', type: 'address' as const },
|
|
63
|
-
{ name: 'inputToken', type: 'address' as const },
|
|
64
|
-
{ name: 'outputToken', type: 'address' as const },
|
|
65
|
-
{ name: 'inputAmount', type: 'uint256' as const },
|
|
66
|
-
{ name: 'outputAmount', type: 'uint256' as const },
|
|
67
|
-
{ name: 'destinationChainId', type: 'uint256' as const },
|
|
68
|
-
{ name: 'exclusiveRelayer', type: 'address' as const },
|
|
69
|
-
{ name: 'quoteTimestamp', type: 'uint32' as const },
|
|
70
|
-
{ name: 'fillDeadline', type: 'uint32' as const },
|
|
71
|
-
{ name: 'exclusivityDeadline', type: 'uint32' as const },
|
|
72
|
-
{ name: 'message', type: 'bytes' as const },
|
|
73
|
-
],
|
|
74
|
-
outputs: [],
|
|
75
|
-
stateMutability: 'payable' as const,
|
|
76
|
-
},
|
|
77
|
-
] as const;
|
package/src/chains.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { type Chain, base, arbitrum, polygon, mainnet } from 'viem/chains';
|
|
2
|
-
|
|
3
|
-
export interface ChainConfig {
|
|
4
|
-
chainId: number;
|
|
5
|
-
name: string;
|
|
6
|
-
viemChain: Chain;
|
|
7
|
-
rpcUrl: string;
|
|
8
|
-
nativeCurrency: string;
|
|
9
|
-
blockExplorer: string;
|
|
10
|
-
wethAddress: `0x${string}`;
|
|
11
|
-
usdcAddress: `0x${string}`;
|
|
12
|
-
dexRouters: Record<string, `0x${string}`>;
|
|
13
|
-
uniswapQuoter?: `0x${string}`;
|
|
14
|
-
acrossSpokePool?: `0x${string}`;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const CHAIN_CONFIGS: Record<string, ChainConfig> = {
|
|
18
|
-
base: {
|
|
19
|
-
chainId: 8453,
|
|
20
|
-
name: 'base',
|
|
21
|
-
viemChain: base,
|
|
22
|
-
rpcUrl: 'https://mainnet.base.org',
|
|
23
|
-
nativeCurrency: 'ETH',
|
|
24
|
-
blockExplorer: 'https://basescan.org',
|
|
25
|
-
wethAddress: '0x4200000000000000000000000000000000000006',
|
|
26
|
-
usdcAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
27
|
-
dexRouters: {
|
|
28
|
-
uniswap: '0x2626664c2603336E57B271c5C0b26F421741e481',
|
|
29
|
-
aerodrome: '0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43',
|
|
30
|
-
},
|
|
31
|
-
uniswapQuoter: '0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a',
|
|
32
|
-
acrossSpokePool: '0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64',
|
|
33
|
-
},
|
|
34
|
-
ethereum: {
|
|
35
|
-
chainId: 1,
|
|
36
|
-
name: 'ethereum',
|
|
37
|
-
viemChain: mainnet,
|
|
38
|
-
rpcUrl: 'https://eth.llamarpc.com',
|
|
39
|
-
nativeCurrency: 'ETH',
|
|
40
|
-
blockExplorer: 'https://etherscan.io',
|
|
41
|
-
wethAddress: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
42
|
-
usdcAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
43
|
-
dexRouters: {
|
|
44
|
-
uniswap: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45',
|
|
45
|
-
},
|
|
46
|
-
uniswapQuoter: '0x61fFE014bA17989E743c5F6cB21bF9697530B21e',
|
|
47
|
-
acrossSpokePool: '0x5c7BCd6E7De5423a257D81B442095A1a6ced35C5',
|
|
48
|
-
},
|
|
49
|
-
arbitrum: {
|
|
50
|
-
chainId: 42161,
|
|
51
|
-
name: 'arbitrum',
|
|
52
|
-
viemChain: arbitrum,
|
|
53
|
-
rpcUrl: 'https://arb1.arbitrum.io/rpc',
|
|
54
|
-
nativeCurrency: 'ETH',
|
|
55
|
-
blockExplorer: 'https://arbiscan.io',
|
|
56
|
-
wethAddress: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
|
|
57
|
-
usdcAddress: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
|
|
58
|
-
dexRouters: {
|
|
59
|
-
uniswap: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45',
|
|
60
|
-
},
|
|
61
|
-
uniswapQuoter: '0x61fFE014bA17989E743c5F6cB21bF9697530B21e',
|
|
62
|
-
acrossSpokePool: '0xe35e9842fceaCA96570B734083f4a58e8F7C5f2A',
|
|
63
|
-
},
|
|
64
|
-
polygon: {
|
|
65
|
-
chainId: 137,
|
|
66
|
-
name: 'polygon',
|
|
67
|
-
viemChain: polygon,
|
|
68
|
-
rpcUrl: 'https://polygon-bor-rpc.publicnode.com',
|
|
69
|
-
nativeCurrency: 'POL',
|
|
70
|
-
blockExplorer: 'https://polygonscan.com',
|
|
71
|
-
wethAddress: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270',
|
|
72
|
-
usdcAddress: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
|
|
73
|
-
dexRouters: {
|
|
74
|
-
uniswap: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45',
|
|
75
|
-
},
|
|
76
|
-
uniswapQuoter: '0x61fFE014bA17989E743c5F6cB21bF9697530B21e',
|
|
77
|
-
acrossSpokePool: '0x9295ee1d8C5b022Be115A2AD3c30C72E34e7F096',
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Apply custom RPC endpoint overrides. Call once at startup.
|
|
83
|
-
* Accepts a map of chain name (or chain ID string) → RPC URL.
|
|
84
|
-
*/
|
|
85
|
-
export function applyRpcOverrides(overrides: Record<string, string>): void {
|
|
86
|
-
for (const [key, url] of Object.entries(overrides)) {
|
|
87
|
-
// Support both chain name ("base") and chain ID ("8453")
|
|
88
|
-
const chain = CHAIN_CONFIGS[key.toLowerCase()]
|
|
89
|
-
?? Object.values(CHAIN_CONFIGS).find(c => c.chainId.toString() === key);
|
|
90
|
-
|
|
91
|
-
if (chain) {
|
|
92
|
-
chain.rpcUrl = url;
|
|
93
|
-
console.log(`[chains] RPC override: ${chain.name} → ${url}`);
|
|
94
|
-
} else {
|
|
95
|
-
console.warn(`[chains] Unknown chain for RPC override: ${key}`);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function getChainConfig(nameOrId: string | number): ChainConfig | undefined {
|
|
101
|
-
if (typeof nameOrId === 'number') {
|
|
102
|
-
return Object.values(CHAIN_CONFIGS).find(c => c.chainId === nameOrId);
|
|
103
|
-
}
|
|
104
|
-
return CHAIN_CONFIGS[nameOrId.toLowerCase()];
|
|
105
|
-
}
|
package/src/cli.ts
DELETED
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Command } from 'commander';
|
|
3
|
-
import { loadConfig, readConfigFile, writeConfigFile, updateSecureStore, writeSampleConfig } from './config.js';
|
|
4
|
-
import { AgentRuntime } from './runtime.js';
|
|
5
|
-
import { listTemplates } from './strategy/index.js';
|
|
6
|
-
import { ensureLocalSetup, promptSecretPassword } from './setup.js';
|
|
7
|
-
import { printBanner, printDone, printError, printInfo, printSuccess, pc } from './ui.js';
|
|
8
|
-
import * as clack from '@clack/prompts';
|
|
9
|
-
|
|
10
|
-
const program = new Command();
|
|
11
|
-
|
|
12
|
-
program
|
|
13
|
-
.name('exagent')
|
|
14
|
-
.description('Exagent — LLM trading agent runtime')
|
|
15
|
-
.version('0.3.5');
|
|
16
|
-
|
|
17
|
-
program
|
|
18
|
-
.command('init')
|
|
19
|
-
.description('Create a sample agent configuration file')
|
|
20
|
-
.option('--agent-id <id>', 'Agent ID (from dashboard)', 'my-agent')
|
|
21
|
-
.option('--api-url <url>', 'API server URL', 'http://localhost:3002')
|
|
22
|
-
.option('--config <path>', 'Config file path', 'agent-config.json')
|
|
23
|
-
.action((opts) => {
|
|
24
|
-
printBanner();
|
|
25
|
-
writeSampleConfig(opts.agentId, opts.apiUrl, opts.config);
|
|
26
|
-
printDone(`Created ${pc.cyan(opts.config)}`);
|
|
27
|
-
console.log();
|
|
28
|
-
console.log(` Edit only the public strategy/venue/risk settings.`);
|
|
29
|
-
console.log(` Then run: ${pc.cyan(`exagent setup --config ${opts.config}`)}`);
|
|
30
|
-
console.log();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
program
|
|
34
|
-
.command('setup')
|
|
35
|
-
.description('Run first-time secure local setup for agent secrets')
|
|
36
|
-
.option('--config <path>', 'Config file path', 'agent-config.json')
|
|
37
|
-
.action(async (opts) => {
|
|
38
|
-
try {
|
|
39
|
-
await ensureLocalSetup(opts.config);
|
|
40
|
-
} catch (err) {
|
|
41
|
-
printError((err as Error).message);
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
program
|
|
47
|
-
.command('run')
|
|
48
|
-
.description('Start the agent')
|
|
49
|
-
.option('--config <path>', 'Config file path', 'agent-config.json')
|
|
50
|
-
.action(async (opts) => {
|
|
51
|
-
try {
|
|
52
|
-
await ensureLocalSetup(opts.config);
|
|
53
|
-
printBanner();
|
|
54
|
-
const config = await loadConfig(opts.config, {
|
|
55
|
-
getSecretPassword: async () => promptSecretPassword(),
|
|
56
|
-
});
|
|
57
|
-
printDone(`Agent ${pc.cyan(config.agentId)} starting...`);
|
|
58
|
-
console.log();
|
|
59
|
-
const runtime = new AgentRuntime(config);
|
|
60
|
-
await runtime.start();
|
|
61
|
-
|
|
62
|
-
// Keep the process running
|
|
63
|
-
await new Promise(() => {});
|
|
64
|
-
} catch (err) {
|
|
65
|
-
printError((err as Error).message);
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
program
|
|
71
|
-
.command('templates')
|
|
72
|
-
.description('List available strategy templates')
|
|
73
|
-
.action(() => {
|
|
74
|
-
printBanner();
|
|
75
|
-
const templates = listTemplates();
|
|
76
|
-
console.log(pc.bold(' Strategy Templates'));
|
|
77
|
-
console.log();
|
|
78
|
-
for (const t of templates) {
|
|
79
|
-
console.log(` ${pc.cyan(t.id)}`);
|
|
80
|
-
console.log(` ${t.name} — ${pc.dim(t.description)}`);
|
|
81
|
-
console.log(` ${pc.dim(`Risk: ${t.riskLevel} | Venues: ${t.venues.join(', ') || 'any'}`)}`);
|
|
82
|
-
console.log();
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
program
|
|
87
|
-
.command('status')
|
|
88
|
-
.description('Check agent status')
|
|
89
|
-
.option('--config <path>', 'Config file path', 'agent-config.json')
|
|
90
|
-
.action(async (opts) => {
|
|
91
|
-
try {
|
|
92
|
-
await ensureLocalSetup(opts.config);
|
|
93
|
-
printBanner();
|
|
94
|
-
const config = await loadConfig(opts.config, {
|
|
95
|
-
getSecretPassword: async () => promptSecretPassword(),
|
|
96
|
-
});
|
|
97
|
-
const res = await fetch(`${config.apiUrl}/v1/agents/${config.agentId}`, {
|
|
98
|
-
headers: { Authorization: `Bearer ${config.apiToken}` },
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
if (!res.ok) {
|
|
102
|
-
printError(`API error: ${res.status}`);
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const agent = await res.json() as Record<string, unknown>;
|
|
107
|
-
const name = (agent.name as string) || config.agentId;
|
|
108
|
-
const status = (agent.status as string) || 'unknown';
|
|
109
|
-
|
|
110
|
-
const statusColor = status === 'online' ? pc.green : status === 'error' ? pc.red : pc.yellow;
|
|
111
|
-
|
|
112
|
-
printSuccess(name, [
|
|
113
|
-
`${pc.dim('Status:')} ${statusColor(status)}`,
|
|
114
|
-
`${pc.dim('Agent:')} ${pc.cyan(config.agentId)}`,
|
|
115
|
-
`${pc.dim('API:')} ${pc.dim(config.apiUrl)}`,
|
|
116
|
-
]);
|
|
117
|
-
} catch (err) {
|
|
118
|
-
printError((err as Error).message);
|
|
119
|
-
process.exit(1);
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
import { LLM_PROVIDERS, getProvider } from './llm-providers.js';
|
|
124
|
-
|
|
125
|
-
program
|
|
126
|
-
.command('config')
|
|
127
|
-
.description('Change LLM provider, model, or API key')
|
|
128
|
-
.option('--config <path>', 'Config file path', 'agent-config.json')
|
|
129
|
-
.action(async (opts) => {
|
|
130
|
-
try {
|
|
131
|
-
printBanner();
|
|
132
|
-
const config = readConfigFile(opts.config);
|
|
133
|
-
const secureStorePath = config.secrets?.secureStorePath;
|
|
134
|
-
|
|
135
|
-
if (!secureStorePath) {
|
|
136
|
-
printError('No secure store found. Run setup first: npx exagent setup');
|
|
137
|
-
process.exit(1);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
clack.intro(pc.bold('Agent Configuration'));
|
|
141
|
-
|
|
142
|
-
// Decrypt current secrets
|
|
143
|
-
const password = await promptSecretPassword();
|
|
144
|
-
const currentConfig = await loadConfig(opts.config, {
|
|
145
|
-
getSecretPassword: async () => password,
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
// Show current LLM settings
|
|
149
|
-
const currentProvider = currentConfig.llm.provider;
|
|
150
|
-
const currentModel = currentConfig.llm.model || 'not set';
|
|
151
|
-
const currentKey = currentConfig.llm.apiKey;
|
|
152
|
-
const maskedKey = currentKey
|
|
153
|
-
? `${currentKey.slice(0, 7)}...${currentKey.slice(-4)}`
|
|
154
|
-
: 'not set';
|
|
155
|
-
|
|
156
|
-
printInfo(`Provider: ${pc.cyan(currentProvider)}`);
|
|
157
|
-
printInfo(`Model: ${pc.cyan(currentModel)}`);
|
|
158
|
-
printInfo(`API key: ${pc.dim(maskedKey)}`);
|
|
159
|
-
console.log();
|
|
160
|
-
|
|
161
|
-
const action = await clack.select({
|
|
162
|
-
message: 'What would you like to change?',
|
|
163
|
-
options: [
|
|
164
|
-
{ value: 'key', label: 'LLM API key' },
|
|
165
|
-
{ value: 'all', label: 'Provider, model, and API key' },
|
|
166
|
-
],
|
|
167
|
-
});
|
|
168
|
-
if (clack.isCancel(action)) {
|
|
169
|
-
clack.cancel('Cancelled.');
|
|
170
|
-
process.exit(0);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
let newProvider: string = currentProvider;
|
|
174
|
-
let newModel: string = currentModel;
|
|
175
|
-
|
|
176
|
-
if (action === 'all') {
|
|
177
|
-
const selectedProvider = await clack.select({
|
|
178
|
-
message: 'LLM provider:',
|
|
179
|
-
options: LLM_PROVIDERS.map(p => ({ value: p.id, label: p.label })),
|
|
180
|
-
initialValue: currentProvider || undefined,
|
|
181
|
-
});
|
|
182
|
-
if (clack.isCancel(selectedProvider)) {
|
|
183
|
-
clack.cancel('Cancelled.');
|
|
184
|
-
process.exit(0);
|
|
185
|
-
}
|
|
186
|
-
newProvider = selectedProvider;
|
|
187
|
-
|
|
188
|
-
const provider = getProvider(newProvider);
|
|
189
|
-
const modelOptions = provider
|
|
190
|
-
? provider.models.map(m => ({ value: m.id, label: m.label }))
|
|
191
|
-
: [{ value: currentModel, label: currentModel }];
|
|
192
|
-
|
|
193
|
-
const selectedModel = await clack.select({
|
|
194
|
-
message: 'LLM model:',
|
|
195
|
-
options: modelOptions,
|
|
196
|
-
initialValue: currentModel || undefined,
|
|
197
|
-
});
|
|
198
|
-
if (clack.isCancel(selectedModel)) {
|
|
199
|
-
clack.cancel('Cancelled.');
|
|
200
|
-
process.exit(0);
|
|
201
|
-
}
|
|
202
|
-
newModel = selectedModel;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const newKey = await clack.password({
|
|
206
|
-
message: 'New LLM API key:',
|
|
207
|
-
validate: (val) => {
|
|
208
|
-
if (!val?.trim()) return 'API key is required.';
|
|
209
|
-
if (val.length < 10) return 'API key seems too short.';
|
|
210
|
-
},
|
|
211
|
-
});
|
|
212
|
-
if (clack.isCancel(newKey)) {
|
|
213
|
-
clack.cancel('Cancelled.');
|
|
214
|
-
process.exit(0);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Update secure store with new API key
|
|
218
|
-
updateSecureStore(secureStorePath, password, { llmApiKey: newKey });
|
|
219
|
-
|
|
220
|
-
// Update config file with new provider/model
|
|
221
|
-
const updatedConfig = readConfigFile(opts.config);
|
|
222
|
-
updatedConfig.llm = {
|
|
223
|
-
...updatedConfig.llm,
|
|
224
|
-
provider: newProvider as typeof updatedConfig.llm.provider,
|
|
225
|
-
model: newModel,
|
|
226
|
-
};
|
|
227
|
-
writeConfigFile(opts.config, updatedConfig);
|
|
228
|
-
|
|
229
|
-
clack.outro(pc.green('Configuration updated'));
|
|
230
|
-
|
|
231
|
-
printSuccess('Updated', [
|
|
232
|
-
`${pc.dim('Provider:')} ${pc.cyan(newProvider)}`,
|
|
233
|
-
`${pc.dim('Model:')} ${pc.cyan(newModel)}`,
|
|
234
|
-
`${pc.dim('API key:')} ${pc.dim(`${newKey.slice(0, 7)}...${newKey.slice(-4)}`)}`,
|
|
235
|
-
'',
|
|
236
|
-
`Run ${pc.cyan('npx exagent run')} to start with the new configuration.`,
|
|
237
|
-
]);
|
|
238
|
-
} catch (err) {
|
|
239
|
-
printError((err as Error).message);
|
|
240
|
-
process.exit(1);
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
program.parse();
|