@exagent/agent 0.1.21 → 0.1.22

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/cli.js CHANGED
@@ -3702,7 +3702,7 @@ function loadSecureEnv(basePath, passphrase) {
3702
3702
  }
3703
3703
 
3704
3704
  // src/index.ts
3705
- var AGENT_VERSION = "0.1.21";
3705
+ var AGENT_VERSION = "0.1.22";
3706
3706
 
3707
3707
  // src/relay.ts
3708
3708
  var RelayClient = class {
@@ -3984,6 +3984,9 @@ var AgentRuntime = class {
3984
3984
  isRunning = false;
3985
3985
  mode = "idle";
3986
3986
  configHash;
3987
+ pendingConfigHash = null;
3988
+ lastConfigCheckAt = 0;
3989
+ // Timestamp of last pending config RPC check
3987
3990
  cycleCount = 0;
3988
3991
  lastCycleAt = 0;
3989
3992
  lastPortfolioValue = 0;
@@ -4010,6 +4013,12 @@ var AgentRuntime = class {
4010
4013
  // When perpConnected && perpTradingActive: dedicated runPerpCycle() runs every interval
4011
4014
  perpConnected = false;
4012
4015
  perpTradingActive = false;
4016
+ // Cached perp account data for synchronous heartbeat inclusion (refreshed async)
4017
+ cachedPerpEquity = 0;
4018
+ cachedPerpUnrealizedPnl = 0;
4019
+ cachedPerpMarginUsed = 0;
4020
+ cachedPerpLeverage = 0;
4021
+ cachedPerpOpenPositions = 0;
4013
4022
  constructor(config) {
4014
4023
  this.config = config;
4015
4024
  }
@@ -4320,8 +4329,14 @@ var AgentRuntime = class {
4320
4329
  }
4321
4330
  /**
4322
4331
  * Sync the LLM config hash to chain for epoch tracking.
4323
- * If the wallet has insufficient gas, enters a recovery loop
4324
- * that waits for the user to fund the wallet.
4332
+ *
4333
+ * If the trading wallet is NOT the agent owner, the on-chain setConfig
4334
+ * call would revert with AgentNotOwner. Instead, we set a pending state
4335
+ * and send a message to the command center so the owner can approve it
4336
+ * from the website with one click.
4337
+ *
4338
+ * Until the config is verified on-chain, the agent won't appear on the
4339
+ * leaderboard (trades still execute normally).
4325
4340
  */
4326
4341
  async syncConfigHash() {
4327
4342
  const agentId = BigInt(this.config.agentId);
@@ -4329,53 +4344,89 @@ var AgentRuntime = class {
4329
4344
  this.configHash = import_sdk.ExagentRegistry.calculateConfigHash(llmMeta.provider, llmMeta.model);
4330
4345
  console.log(`Config hash: ${this.configHash}`);
4331
4346
  const onChainHash = await this.client.registry.getConfigHash(agentId);
4332
- if (onChainHash !== this.configHash) {
4333
- console.log("Config changed, updating on-chain...");
4334
- try {
4335
- await this.client.registry.updateConfig(agentId, this.configHash);
4336
- console.log(`Config updated on-chain`);
4337
- } catch (error) {
4338
- const message = error instanceof Error ? error.message : String(error);
4339
- if (message.includes("insufficient funds") || message.includes("intrinsic gas too low") || message.includes("exceeds the balance")) {
4340
- const ccUrl = `https://exagent.io/agents/${encodeURIComponent(this.config.name)}/command-center`;
4341
- const chain = import_chains4.base;
4342
- const publicClientInstance = (0, import_viem6.createPublicClient)({
4343
- chain,
4344
- transport: (0, import_viem6.http)(this.getRpcUrl())
4347
+ if (onChainHash === this.configHash) {
4348
+ console.log("Config hash matches on-chain");
4349
+ this.pendingConfigHash = null;
4350
+ return;
4351
+ }
4352
+ console.log("Config changed, updating on-chain...");
4353
+ const agent = await this.client.registry.getAgent(agentId);
4354
+ const isOwner = agent?.owner.toLowerCase() === this.client.address.toLowerCase();
4355
+ if (!isOwner) {
4356
+ this.pendingConfigHash = this.configHash;
4357
+ this.configHash = onChainHash;
4358
+ console.log("");
4359
+ console.log("=== CONFIG VERIFICATION NEEDED ===");
4360
+ console.log("");
4361
+ console.log(" Your trading wallet cannot update the LLM config on-chain.");
4362
+ console.log(" The owner must approve this from the command center.");
4363
+ console.log("");
4364
+ console.log(` LLM: ${llmMeta.provider} / ${llmMeta.model}`);
4365
+ console.log(` Hash: ${this.pendingConfigHash}`);
4366
+ console.log("");
4367
+ console.log(" Until approved:");
4368
+ console.log(" - New agents will not appear on the leaderboard");
4369
+ console.log(" - Trades will still execute normally");
4370
+ console.log("");
4371
+ this.relay?.sendMessage(
4372
+ "system",
4373
+ "warning",
4374
+ "Config Verification Needed",
4375
+ `Your agent is using ${llmMeta.provider}/${llmMeta.model} but this hasn't been recorded on-chain. Open the command center and click "Approve Config" to verify. Until then, your agent won't appear on the leaderboard.`,
4376
+ { configHash: this.pendingConfigHash, provider: llmMeta.provider, model: llmMeta.model }
4377
+ );
4378
+ return;
4379
+ }
4380
+ try {
4381
+ await this.client.registry.updateConfig(agentId, this.configHash);
4382
+ console.log(`Config updated on-chain`);
4383
+ this.pendingConfigHash = null;
4384
+ } catch (error) {
4385
+ const message = error instanceof Error ? error.message : String(error);
4386
+ if (message.includes("insufficient funds") || message.includes("intrinsic gas too low") || message.includes("exceeds the balance")) {
4387
+ const ccUrl = `https://exagent.io/agents/${encodeURIComponent(this.config.name)}/command-center`;
4388
+ const publicClientInstance = (0, import_viem6.createPublicClient)({
4389
+ chain: import_chains4.base,
4390
+ transport: (0, import_viem6.http)(this.getRpcUrl())
4391
+ });
4392
+ console.log("");
4393
+ console.log("=== ETH NEEDED FOR GAS ===");
4394
+ console.log("");
4395
+ console.log(` Wallet: ${this.client.address}`);
4396
+ console.log(" Your wallet needs ETH to pay for transaction gas.");
4397
+ console.log(" Opening the command center to fund your wallet...");
4398
+ console.log(` ${ccUrl}`);
4399
+ console.log("");
4400
+ openBrowser(ccUrl);
4401
+ console.log(" Waiting for ETH... (checking every 15s)");
4402
+ console.log(" Press Ctrl+C to exit.");
4403
+ console.log("");
4404
+ while (true) {
4405
+ await this.sleep(15e3);
4406
+ const balance = await publicClientInstance.getBalance({
4407
+ address: this.client.address
4345
4408
  });
4346
- console.log("");
4347
- console.log("=== ETH NEEDED FOR GAS ===");
4348
- console.log("");
4349
- console.log(` Wallet: ${this.client.address}`);
4350
- console.log(" Your wallet needs ETH to pay for transaction gas.");
4351
- console.log(" Opening the command center to fund your wallet...");
4352
- console.log(` ${ccUrl}`);
4353
- console.log("");
4354
- openBrowser(ccUrl);
4355
- console.log(" Waiting for ETH... (checking every 15s)");
4356
- console.log(" Press Ctrl+C to exit.");
4357
- console.log("");
4358
- while (true) {
4359
- await this.sleep(15e3);
4360
- const balance = await publicClientInstance.getBalance({
4361
- address: this.client.address
4362
- });
4363
- if (balance > BigInt(0)) {
4364
- console.log(" ETH detected! Retrying config update...");
4365
- console.log("");
4409
+ if (balance > BigInt(0)) {
4410
+ console.log(" ETH detected! Retrying config update...");
4411
+ console.log("");
4412
+ try {
4366
4413
  await this.client.registry.updateConfig(agentId, this.configHash);
4367
4414
  console.log(`Config updated on-chain`);
4368
- return;
4415
+ this.pendingConfigHash = null;
4416
+ } catch (retryError) {
4417
+ const retryMsg = retryError instanceof Error ? retryError.message : String(retryError);
4418
+ console.warn(`Config update failed after funding: ${retryMsg}`);
4419
+ console.warn("Continuing with on-chain config.");
4420
+ this.configHash = onChainHash;
4369
4421
  }
4370
- process.stdout.write(".");
4422
+ return;
4371
4423
  }
4372
- } else {
4373
- console.warn(`Config update skipped (continuing with on-chain config): ${message}`);
4374
- this.configHash = onChainHash;
4424
+ process.stdout.write(".");
4375
4425
  }
4426
+ } else {
4427
+ console.warn(`Config update skipped (continuing with on-chain config): ${message}`);
4428
+ this.configHash = onChainHash;
4376
4429
  }
4377
- } else {
4378
- console.log("Config hash matches on-chain");
4379
4430
  }
4380
4431
  }
4381
4432
  /**
@@ -4706,11 +4757,38 @@ var AgentRuntime = class {
4706
4757
  this.relay?.sendCommandResult(cmd.id, false, message);
4707
4758
  }
4708
4759
  }
4760
+ /**
4761
+ * Periodically check if the owner has approved the pending config hash.
4762
+ * Called from sendRelayStatus at most every 2.5 minutes (timestamp-throttled).
4763
+ */
4764
+ async checkPendingConfigApproval() {
4765
+ if (!this.pendingConfigHash) return;
4766
+ try {
4767
+ const onChain = await this.client.registry.getConfigHash(BigInt(this.config.agentId));
4768
+ if (onChain === this.pendingConfigHash) {
4769
+ this.configHash = this.pendingConfigHash;
4770
+ this.pendingConfigHash = null;
4771
+ console.log("Config verified on-chain! Your agent will now appear on the leaderboard.");
4772
+ this.relay?.sendMessage(
4773
+ "config_updated",
4774
+ "success",
4775
+ "Config Verified",
4776
+ "Your LLM config has been verified on-chain. Your agent will now appear on the leaderboard."
4777
+ );
4778
+ }
4779
+ } catch {
4780
+ }
4781
+ }
4709
4782
  /**
4710
4783
  * Send current status to the relay
4711
4784
  */
4712
4785
  sendRelayStatus() {
4713
4786
  if (!this.relay) return;
4787
+ const CONFIG_CHECK_INTERVAL_MS = 15e4;
4788
+ if (this.pendingConfigHash && Date.now() - this.lastConfigCheckAt >= CONFIG_CHECK_INTERVAL_MS) {
4789
+ this.lastConfigCheckAt = Date.now();
4790
+ this.checkPendingConfigApproval();
4791
+ }
4714
4792
  const vaultConfig = this.config.vault || { policy: "disabled" };
4715
4793
  const status = {
4716
4794
  mode: this.mode,
@@ -4739,31 +4817,32 @@ var AgentRuntime = class {
4739
4817
  perp: this.perpConnected ? {
4740
4818
  enabled: true,
4741
4819
  trading: this.perpTradingActive,
4742
- equity: 0,
4743
- unrealizedPnl: 0,
4744
- marginUsed: 0,
4745
- openPositions: 0,
4746
- effectiveLeverage: 0,
4820
+ equity: this.cachedPerpEquity,
4821
+ unrealizedPnl: this.cachedPerpUnrealizedPnl,
4822
+ marginUsed: this.cachedPerpMarginUsed,
4823
+ openPositions: this.cachedPerpOpenPositions,
4824
+ effectiveLeverage: this.cachedPerpLeverage,
4747
4825
  pendingRecords: this.perpRecorder?.pendingRetries ?? 0
4748
4826
  } : void 0,
4749
- positions: this.positionTracker ? this.positionTracker.getPositionSummary(this.lastPrices) : void 0
4827
+ positions: this.positionTracker ? this.positionTracker.getPositionSummary(this.lastPrices) : void 0,
4828
+ configHash: this.configHash || void 0,
4829
+ pendingConfigHash: this.pendingConfigHash
4830
+ // null preserved by JSON.stringify for clearing
4750
4831
  };
4751
- if (this.perpConnected && this.perpPositions && status.perp) {
4832
+ this.relay.sendHeartbeat(status);
4833
+ if (this.perpConnected && this.perpPositions) {
4752
4834
  this.perpPositions.getAccountSummary().then((account) => {
4753
- if (status.perp) {
4754
- status.perp.equity = account.totalEquity;
4755
- status.perp.unrealizedPnl = account.totalUnrealizedPnl;
4756
- status.perp.marginUsed = account.totalMarginUsed;
4757
- status.perp.effectiveLeverage = account.effectiveLeverage;
4758
- }
4835
+ this.cachedPerpEquity = account.totalEquity;
4836
+ this.cachedPerpUnrealizedPnl = account.totalUnrealizedPnl;
4837
+ this.cachedPerpMarginUsed = account.totalMarginUsed;
4838
+ this.cachedPerpLeverage = account.effectiveLeverage;
4759
4839
  }).catch(() => {
4760
4840
  });
4761
4841
  this.perpPositions.getPositionCount().then((count) => {
4762
- if (status.perp) status.perp.openPositions = count;
4842
+ this.cachedPerpOpenPositions = count;
4763
4843
  }).catch(() => {
4764
4844
  });
4765
4845
  }
4766
- this.relay.sendHeartbeat(status);
4767
4846
  }
4768
4847
  /**
4769
4848
  * Run a single trading cycle
package/dist/cli.mjs CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  loadConfig,
7
7
  loadSecureEnv,
8
8
  validateConfig
9
- } from "./chunk-U6YJHCO3.mjs";
9
+ } from "./chunk-EJHDRG5Y.mjs";
10
10
 
11
11
  // src/cli.ts
12
12
  import { Command } from "commander";
package/dist/index.d.mts CHANGED
@@ -739,6 +739,10 @@ interface AgentStatusPayload {
739
739
  recentTrades: number;
740
740
  totalRealizedPnL: number;
741
741
  };
742
+ /** Current on-chain config hash (for epoch tracking) */
743
+ configHash?: string;
744
+ /** Config hash awaiting owner approval — null/undefined means no pending verification */
745
+ pendingConfigHash?: string | null;
742
746
  }
743
747
  interface RelayConfig {
744
748
  enabled: boolean;
@@ -770,6 +774,8 @@ declare class AgentRuntime {
770
774
  private isRunning;
771
775
  private mode;
772
776
  private configHash;
777
+ private pendingConfigHash;
778
+ private lastConfigCheckAt;
773
779
  private cycleCount;
774
780
  private lastCycleAt;
775
781
  private lastPortfolioValue;
@@ -790,6 +796,11 @@ declare class AgentRuntime {
790
796
  private perpStrategy;
791
797
  private perpConnected;
792
798
  private perpTradingActive;
799
+ private cachedPerpEquity;
800
+ private cachedPerpUnrealizedPnl;
801
+ private cachedPerpMarginUsed;
802
+ private cachedPerpLeverage;
803
+ private cachedPerpOpenPositions;
793
804
  constructor(config: RuntimeConfig);
794
805
  /**
795
806
  * Initialize the agent runtime
@@ -821,8 +832,14 @@ declare class AgentRuntime {
821
832
  private loadTradingRestrictions;
822
833
  /**
823
834
  * Sync the LLM config hash to chain for epoch tracking.
824
- * If the wallet has insufficient gas, enters a recovery loop
825
- * that waits for the user to fund the wallet.
835
+ *
836
+ * If the trading wallet is NOT the agent owner, the on-chain setConfig
837
+ * call would revert with AgentNotOwner. Instead, we set a pending state
838
+ * and send a message to the command center so the owner can approve it
839
+ * from the website with one click.
840
+ *
841
+ * Until the config is verified on-chain, the agent won't appear on the
842
+ * leaderboard (trades still execute normally).
826
843
  */
827
844
  private syncConfigHash;
828
845
  /**
@@ -841,6 +858,11 @@ declare class AgentRuntime {
841
858
  * Handle a command from the command center
842
859
  */
843
860
  private handleCommand;
861
+ /**
862
+ * Periodically check if the owner has approved the pending config hash.
863
+ * Called from sendRelayStatus at most every 2.5 minutes (timestamp-throttled).
864
+ */
865
+ private checkPendingConfigApproval;
844
866
  /**
845
867
  * Send current status to the relay
846
868
  */
@@ -2081,6 +2103,6 @@ declare function decryptEnvFile(encPath: string, passphrase: string): Record<str
2081
2103
  declare function loadSecureEnv(basePath: string, passphrase?: string): boolean;
2082
2104
 
2083
2105
  /** @exagent/agent package version — update alongside package.json */
2084
- declare const AGENT_VERSION = "0.1.21";
2106
+ declare const AGENT_VERSION = "0.1.22";
2085
2107
 
2086
2108
  export { AGENT_VERSION, type AccountSummary, type AgentConfig, AgentConfigSchema, type AgentMode, AgentRuntime, type AgentStatusPayload, AnthropicAdapter, BaseLLMAdapter, type CommandType, DeepSeekAdapter, FileStore, type FillCallback, type FundingCallback, type FundingPayment, GoogleAdapter, GroqAdapter, HYPERLIQUID_DOMAIN, HyperliquidClient, HyperliquidSigner, HyperliquidWebSocket, type LLMAdapter, type LLMConfig, LLMConfigSchema, type LLMMessage, type LLMMetadata, type LLMProvider, LLMProviderSchema, type LLMResponse, type LiquidationCallback, type MarketData, MarketDataService, type MessageLevel, type MessageType, MistralAdapter, OllamaAdapter, type OnboardingStatus, OpenAIAdapter, OrderManager, type OrderResult, type PerpAction, type PerpConfig$1 as PerpConfig, PerpConfigSchema, type PerpFill, type PerpMarketData, PerpOnboarding, type PerpPosition, type PerpStrategyFunction, PerpTradeRecorder, type PerpTradeSignal, type PerpConfig as PerpTradingConfig, PositionManager, type PositionSummary, PositionTracker, type RecordPerpTradeParams, RelayClient, type RelayCommand, type RelayConfig$1 as RelayConfig, RelayConfigSchema, RiskManager, type RiskState, type RiskUniverse, RiskUniverseSchema, type RuntimeConfig, STRATEGY_TEMPLATES, type StrategyContext, type StrategyFunction, type StrategyStore, type StrategyTemplate, TogetherAdapter, type TrackedPosition, TradeExecutor, type TradeRecord, type TradeSignal, type TradingConfig, TradingConfigSchema, type VaultConfig, VaultConfigSchema, VaultManager, type VaultManagerConfig, type VaultPolicy, VaultPolicySchema, type VaultStatus, createLLMAdapter, createSampleConfig, decryptEnvFile, encryptEnvFile, fillHashToBytes32, fillOidToBytes32, getAllStrategyTemplates, getNextNonce, getStrategyTemplate, loadConfig, loadSecureEnv, loadStrategy, validateConfig, validateStrategy };
package/dist/index.d.ts CHANGED
@@ -739,6 +739,10 @@ interface AgentStatusPayload {
739
739
  recentTrades: number;
740
740
  totalRealizedPnL: number;
741
741
  };
742
+ /** Current on-chain config hash (for epoch tracking) */
743
+ configHash?: string;
744
+ /** Config hash awaiting owner approval — null/undefined means no pending verification */
745
+ pendingConfigHash?: string | null;
742
746
  }
743
747
  interface RelayConfig {
744
748
  enabled: boolean;
@@ -770,6 +774,8 @@ declare class AgentRuntime {
770
774
  private isRunning;
771
775
  private mode;
772
776
  private configHash;
777
+ private pendingConfigHash;
778
+ private lastConfigCheckAt;
773
779
  private cycleCount;
774
780
  private lastCycleAt;
775
781
  private lastPortfolioValue;
@@ -790,6 +796,11 @@ declare class AgentRuntime {
790
796
  private perpStrategy;
791
797
  private perpConnected;
792
798
  private perpTradingActive;
799
+ private cachedPerpEquity;
800
+ private cachedPerpUnrealizedPnl;
801
+ private cachedPerpMarginUsed;
802
+ private cachedPerpLeverage;
803
+ private cachedPerpOpenPositions;
793
804
  constructor(config: RuntimeConfig);
794
805
  /**
795
806
  * Initialize the agent runtime
@@ -821,8 +832,14 @@ declare class AgentRuntime {
821
832
  private loadTradingRestrictions;
822
833
  /**
823
834
  * Sync the LLM config hash to chain for epoch tracking.
824
- * If the wallet has insufficient gas, enters a recovery loop
825
- * that waits for the user to fund the wallet.
835
+ *
836
+ * If the trading wallet is NOT the agent owner, the on-chain setConfig
837
+ * call would revert with AgentNotOwner. Instead, we set a pending state
838
+ * and send a message to the command center so the owner can approve it
839
+ * from the website with one click.
840
+ *
841
+ * Until the config is verified on-chain, the agent won't appear on the
842
+ * leaderboard (trades still execute normally).
826
843
  */
827
844
  private syncConfigHash;
828
845
  /**
@@ -841,6 +858,11 @@ declare class AgentRuntime {
841
858
  * Handle a command from the command center
842
859
  */
843
860
  private handleCommand;
861
+ /**
862
+ * Periodically check if the owner has approved the pending config hash.
863
+ * Called from sendRelayStatus at most every 2.5 minutes (timestamp-throttled).
864
+ */
865
+ private checkPendingConfigApproval;
844
866
  /**
845
867
  * Send current status to the relay
846
868
  */
@@ -2081,6 +2103,6 @@ declare function decryptEnvFile(encPath: string, passphrase: string): Record<str
2081
2103
  declare function loadSecureEnv(basePath: string, passphrase?: string): boolean;
2082
2104
 
2083
2105
  /** @exagent/agent package version — update alongside package.json */
2084
- declare const AGENT_VERSION = "0.1.21";
2106
+ declare const AGENT_VERSION = "0.1.22";
2085
2107
 
2086
2108
  export { AGENT_VERSION, type AccountSummary, type AgentConfig, AgentConfigSchema, type AgentMode, AgentRuntime, type AgentStatusPayload, AnthropicAdapter, BaseLLMAdapter, type CommandType, DeepSeekAdapter, FileStore, type FillCallback, type FundingCallback, type FundingPayment, GoogleAdapter, GroqAdapter, HYPERLIQUID_DOMAIN, HyperliquidClient, HyperliquidSigner, HyperliquidWebSocket, type LLMAdapter, type LLMConfig, LLMConfigSchema, type LLMMessage, type LLMMetadata, type LLMProvider, LLMProviderSchema, type LLMResponse, type LiquidationCallback, type MarketData, MarketDataService, type MessageLevel, type MessageType, MistralAdapter, OllamaAdapter, type OnboardingStatus, OpenAIAdapter, OrderManager, type OrderResult, type PerpAction, type PerpConfig$1 as PerpConfig, PerpConfigSchema, type PerpFill, type PerpMarketData, PerpOnboarding, type PerpPosition, type PerpStrategyFunction, PerpTradeRecorder, type PerpTradeSignal, type PerpConfig as PerpTradingConfig, PositionManager, type PositionSummary, PositionTracker, type RecordPerpTradeParams, RelayClient, type RelayCommand, type RelayConfig$1 as RelayConfig, RelayConfigSchema, RiskManager, type RiskState, type RiskUniverse, RiskUniverseSchema, type RuntimeConfig, STRATEGY_TEMPLATES, type StrategyContext, type StrategyFunction, type StrategyStore, type StrategyTemplate, TogetherAdapter, type TrackedPosition, TradeExecutor, type TradeRecord, type TradeSignal, type TradingConfig, TradingConfigSchema, type VaultConfig, VaultConfigSchema, VaultManager, type VaultManagerConfig, type VaultPolicy, VaultPolicySchema, type VaultStatus, createLLMAdapter, createSampleConfig, decryptEnvFile, encryptEnvFile, fillHashToBytes32, fillOidToBytes32, getAllStrategyTemplates, getNextNonce, getStrategyTemplate, loadConfig, loadSecureEnv, loadStrategy, validateConfig, validateStrategy };