@exagent/agent 0.1.21 → 0.1.23

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/index.d.ts CHANGED
@@ -339,9 +339,9 @@ declare const AgentConfigSchema: z.ZodObject<{
339
339
  }>>;
340
340
  allowedTokens: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
341
341
  }, "strip", z.ZodTypeAny, {
342
+ agentId: string | number;
342
343
  name: string;
343
344
  network: "mainnet";
344
- agentId: string | number;
345
345
  llm: {
346
346
  provider: "custom" | "openai" | "anthropic" | "google" | "deepseek" | "mistral" | "groq" | "together" | "ollama";
347
347
  temperature: number;
@@ -388,8 +388,8 @@ declare const AgentConfigSchema: z.ZodObject<{
388
388
  } | undefined;
389
389
  allowedTokens?: string[] | undefined;
390
390
  }, {
391
- name: string;
392
391
  agentId: string | number;
392
+ name: string;
393
393
  llm: {
394
394
  provider: "custom" | "openai" | "anthropic" | "google" | "deepseek" | "mistral" | "groq" | "together" | "ollama";
395
395
  model?: string | undefined;
@@ -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.23";
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.js CHANGED
@@ -1747,7 +1747,7 @@ function classifyTradeError(message) {
1747
1747
  if (lower.includes("notauthorizedforagent") || lower.includes("not authorized")) {
1748
1748
  return {
1749
1749
  category: "not_authorized",
1750
- userMessage: "Wallet not authorized for this agent. Ensure your wallet is linked via the registry."
1750
+ userMessage: 'Wallet not authorized for this agent. This wallet is not linked to your agent on-chain, so the router rejected the trade. To fix: (1) Open your command center at exagent.io, (2) Use the Wallet Management panel to check linked wallets, (3) If you lost your old wallet, unlink it first then re-run the agent to link the new one. Run "npx @exagent/agent export-key" to verify which wallet this agent is using.'
1751
1751
  };
1752
1752
  }
1753
1753
  if (lower.includes("aggregatornotwhitelisted")) {
@@ -3886,6 +3886,9 @@ var AgentRuntime = class {
3886
3886
  isRunning = false;
3887
3887
  mode = "idle";
3888
3888
  configHash;
3889
+ pendingConfigHash = null;
3890
+ lastConfigCheckAt = 0;
3891
+ // Timestamp of last pending config RPC check
3889
3892
  cycleCount = 0;
3890
3893
  lastCycleAt = 0;
3891
3894
  lastPortfolioValue = 0;
@@ -3912,6 +3915,12 @@ var AgentRuntime = class {
3912
3915
  // When perpConnected && perpTradingActive: dedicated runPerpCycle() runs every interval
3913
3916
  perpConnected = false;
3914
3917
  perpTradingActive = false;
3918
+ // Cached perp account data for synchronous heartbeat inclusion (refreshed async)
3919
+ cachedPerpEquity = 0;
3920
+ cachedPerpUnrealizedPnl = 0;
3921
+ cachedPerpMarginUsed = 0;
3922
+ cachedPerpLeverage = 0;
3923
+ cachedPerpOpenPositions = 0;
3915
3924
  constructor(config) {
3916
3925
  this.config = config;
3917
3926
  }
@@ -4222,8 +4231,14 @@ var AgentRuntime = class {
4222
4231
  }
4223
4232
  /**
4224
4233
  * Sync the LLM config hash to chain for epoch tracking.
4225
- * If the wallet has insufficient gas, enters a recovery loop
4226
- * that waits for the user to fund the wallet.
4234
+ *
4235
+ * If the trading wallet is NOT the agent owner, the on-chain setConfig
4236
+ * call would revert with AgentNotOwner. Instead, we set a pending state
4237
+ * and send a message to the command center so the owner can approve it
4238
+ * from the website with one click.
4239
+ *
4240
+ * Until the config is verified on-chain, the agent won't appear on the
4241
+ * leaderboard (trades still execute normally).
4227
4242
  */
4228
4243
  async syncConfigHash() {
4229
4244
  const agentId = BigInt(this.config.agentId);
@@ -4231,53 +4246,89 @@ var AgentRuntime = class {
4231
4246
  this.configHash = import_sdk.ExagentRegistry.calculateConfigHash(llmMeta.provider, llmMeta.model);
4232
4247
  console.log(`Config hash: ${this.configHash}`);
4233
4248
  const onChainHash = await this.client.registry.getConfigHash(agentId);
4234
- if (onChainHash !== this.configHash) {
4235
- console.log("Config changed, updating on-chain...");
4236
- try {
4237
- await this.client.registry.updateConfig(agentId, this.configHash);
4238
- console.log(`Config updated on-chain`);
4239
- } catch (error) {
4240
- const message = error instanceof Error ? error.message : String(error);
4241
- if (message.includes("insufficient funds") || message.includes("intrinsic gas too low") || message.includes("exceeds the balance")) {
4242
- const ccUrl = `https://exagent.io/agents/${encodeURIComponent(this.config.name)}/command-center`;
4243
- const chain = import_chains4.base;
4244
- const publicClientInstance = (0, import_viem6.createPublicClient)({
4245
- chain,
4246
- transport: (0, import_viem6.http)(this.getRpcUrl())
4249
+ if (onChainHash === this.configHash) {
4250
+ console.log("Config hash matches on-chain");
4251
+ this.pendingConfigHash = null;
4252
+ return;
4253
+ }
4254
+ console.log("Config changed, updating on-chain...");
4255
+ const agent = await this.client.registry.getAgent(agentId);
4256
+ const isOwner = agent?.owner.toLowerCase() === this.client.address.toLowerCase();
4257
+ if (!isOwner) {
4258
+ this.pendingConfigHash = this.configHash;
4259
+ this.configHash = onChainHash;
4260
+ console.log("");
4261
+ console.log("=== CONFIG VERIFICATION NEEDED ===");
4262
+ console.log("");
4263
+ console.log(" Your trading wallet cannot update the LLM config on-chain.");
4264
+ console.log(" The owner must approve this from the command center.");
4265
+ console.log("");
4266
+ console.log(` LLM: ${llmMeta.provider} / ${llmMeta.model}`);
4267
+ console.log(` Hash: ${this.pendingConfigHash}`);
4268
+ console.log("");
4269
+ console.log(" Until approved:");
4270
+ console.log(" - New agents will not appear on the leaderboard");
4271
+ console.log(" - Trades will still execute normally");
4272
+ console.log("");
4273
+ this.relay?.sendMessage(
4274
+ "system",
4275
+ "warning",
4276
+ "Config Verification Needed",
4277
+ `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.`,
4278
+ { configHash: this.pendingConfigHash, provider: llmMeta.provider, model: llmMeta.model }
4279
+ );
4280
+ return;
4281
+ }
4282
+ try {
4283
+ await this.client.registry.updateConfig(agentId, this.configHash);
4284
+ console.log(`Config updated on-chain`);
4285
+ this.pendingConfigHash = null;
4286
+ } catch (error) {
4287
+ const message = error instanceof Error ? error.message : String(error);
4288
+ if (message.includes("insufficient funds") || message.includes("intrinsic gas too low") || message.includes("exceeds the balance")) {
4289
+ const ccUrl = `https://exagent.io/agents/${encodeURIComponent(this.config.name)}/command-center`;
4290
+ const publicClientInstance = (0, import_viem6.createPublicClient)({
4291
+ chain: import_chains4.base,
4292
+ transport: (0, import_viem6.http)(this.getRpcUrl())
4293
+ });
4294
+ console.log("");
4295
+ console.log("=== ETH NEEDED FOR GAS ===");
4296
+ console.log("");
4297
+ console.log(` Wallet: ${this.client.address}`);
4298
+ console.log(" Your wallet needs ETH to pay for transaction gas.");
4299
+ console.log(" Opening the command center to fund your wallet...");
4300
+ console.log(` ${ccUrl}`);
4301
+ console.log("");
4302
+ openBrowser(ccUrl);
4303
+ console.log(" Waiting for ETH... (checking every 15s)");
4304
+ console.log(" Press Ctrl+C to exit.");
4305
+ console.log("");
4306
+ while (true) {
4307
+ await this.sleep(15e3);
4308
+ const balance = await publicClientInstance.getBalance({
4309
+ address: this.client.address
4247
4310
  });
4248
- console.log("");
4249
- console.log("=== ETH NEEDED FOR GAS ===");
4250
- console.log("");
4251
- console.log(` Wallet: ${this.client.address}`);
4252
- console.log(" Your wallet needs ETH to pay for transaction gas.");
4253
- console.log(" Opening the command center to fund your wallet...");
4254
- console.log(` ${ccUrl}`);
4255
- console.log("");
4256
- openBrowser(ccUrl);
4257
- console.log(" Waiting for ETH... (checking every 15s)");
4258
- console.log(" Press Ctrl+C to exit.");
4259
- console.log("");
4260
- while (true) {
4261
- await this.sleep(15e3);
4262
- const balance = await publicClientInstance.getBalance({
4263
- address: this.client.address
4264
- });
4265
- if (balance > BigInt(0)) {
4266
- console.log(" ETH detected! Retrying config update...");
4267
- console.log("");
4311
+ if (balance > BigInt(0)) {
4312
+ console.log(" ETH detected! Retrying config update...");
4313
+ console.log("");
4314
+ try {
4268
4315
  await this.client.registry.updateConfig(agentId, this.configHash);
4269
4316
  console.log(`Config updated on-chain`);
4270
- return;
4317
+ this.pendingConfigHash = null;
4318
+ } catch (retryError) {
4319
+ const retryMsg = retryError instanceof Error ? retryError.message : String(retryError);
4320
+ console.warn(`Config update failed after funding: ${retryMsg}`);
4321
+ console.warn("Continuing with on-chain config.");
4322
+ this.configHash = onChainHash;
4271
4323
  }
4272
- process.stdout.write(".");
4324
+ return;
4273
4325
  }
4274
- } else {
4275
- console.warn(`Config update skipped (continuing with on-chain config): ${message}`);
4276
- this.configHash = onChainHash;
4326
+ process.stdout.write(".");
4277
4327
  }
4328
+ } else {
4329
+ console.warn(`Config update skipped (continuing with on-chain config): ${message}`);
4330
+ this.configHash = onChainHash;
4278
4331
  }
4279
- } else {
4280
- console.log("Config hash matches on-chain");
4281
4332
  }
4282
4333
  }
4283
4334
  /**
@@ -4608,11 +4659,38 @@ var AgentRuntime = class {
4608
4659
  this.relay?.sendCommandResult(cmd.id, false, message);
4609
4660
  }
4610
4661
  }
4662
+ /**
4663
+ * Periodically check if the owner has approved the pending config hash.
4664
+ * Called from sendRelayStatus at most every 2.5 minutes (timestamp-throttled).
4665
+ */
4666
+ async checkPendingConfigApproval() {
4667
+ if (!this.pendingConfigHash) return;
4668
+ try {
4669
+ const onChain = await this.client.registry.getConfigHash(BigInt(this.config.agentId));
4670
+ if (onChain === this.pendingConfigHash) {
4671
+ this.configHash = this.pendingConfigHash;
4672
+ this.pendingConfigHash = null;
4673
+ console.log("Config verified on-chain! Your agent will now appear on the leaderboard.");
4674
+ this.relay?.sendMessage(
4675
+ "config_updated",
4676
+ "success",
4677
+ "Config Verified",
4678
+ "Your LLM config has been verified on-chain. Your agent will now appear on the leaderboard."
4679
+ );
4680
+ }
4681
+ } catch {
4682
+ }
4683
+ }
4611
4684
  /**
4612
4685
  * Send current status to the relay
4613
4686
  */
4614
4687
  sendRelayStatus() {
4615
4688
  if (!this.relay) return;
4689
+ const CONFIG_CHECK_INTERVAL_MS = 15e4;
4690
+ if (this.pendingConfigHash && Date.now() - this.lastConfigCheckAt >= CONFIG_CHECK_INTERVAL_MS) {
4691
+ this.lastConfigCheckAt = Date.now();
4692
+ this.checkPendingConfigApproval();
4693
+ }
4616
4694
  const vaultConfig = this.config.vault || { policy: "disabled" };
4617
4695
  const status = {
4618
4696
  mode: this.mode,
@@ -4641,31 +4719,32 @@ var AgentRuntime = class {
4641
4719
  perp: this.perpConnected ? {
4642
4720
  enabled: true,
4643
4721
  trading: this.perpTradingActive,
4644
- equity: 0,
4645
- unrealizedPnl: 0,
4646
- marginUsed: 0,
4647
- openPositions: 0,
4648
- effectiveLeverage: 0,
4722
+ equity: this.cachedPerpEquity,
4723
+ unrealizedPnl: this.cachedPerpUnrealizedPnl,
4724
+ marginUsed: this.cachedPerpMarginUsed,
4725
+ openPositions: this.cachedPerpOpenPositions,
4726
+ effectiveLeverage: this.cachedPerpLeverage,
4649
4727
  pendingRecords: this.perpRecorder?.pendingRetries ?? 0
4650
4728
  } : void 0,
4651
- positions: this.positionTracker ? this.positionTracker.getPositionSummary(this.lastPrices) : void 0
4729
+ positions: this.positionTracker ? this.positionTracker.getPositionSummary(this.lastPrices) : void 0,
4730
+ configHash: this.configHash || void 0,
4731
+ pendingConfigHash: this.pendingConfigHash
4732
+ // null preserved by JSON.stringify for clearing
4652
4733
  };
4653
- if (this.perpConnected && this.perpPositions && status.perp) {
4734
+ this.relay.sendHeartbeat(status);
4735
+ if (this.perpConnected && this.perpPositions) {
4654
4736
  this.perpPositions.getAccountSummary().then((account) => {
4655
- if (status.perp) {
4656
- status.perp.equity = account.totalEquity;
4657
- status.perp.unrealizedPnl = account.totalUnrealizedPnl;
4658
- status.perp.marginUsed = account.totalMarginUsed;
4659
- status.perp.effectiveLeverage = account.effectiveLeverage;
4660
- }
4737
+ this.cachedPerpEquity = account.totalEquity;
4738
+ this.cachedPerpUnrealizedPnl = account.totalUnrealizedPnl;
4739
+ this.cachedPerpMarginUsed = account.totalMarginUsed;
4740
+ this.cachedPerpLeverage = account.effectiveLeverage;
4661
4741
  }).catch(() => {
4662
4742
  });
4663
4743
  this.perpPositions.getPositionCount().then((count) => {
4664
- if (status.perp) status.perp.openPositions = count;
4744
+ this.cachedPerpOpenPositions = count;
4665
4745
  }).catch(() => {
4666
4746
  });
4667
4747
  }
4668
- this.relay.sendHeartbeat(status);
4669
4748
  }
4670
4749
  /**
4671
4750
  * Run a single trading cycle
@@ -5238,7 +5317,7 @@ function loadSecureEnv(basePath, passphrase) {
5238
5317
  }
5239
5318
 
5240
5319
  // src/index.ts
5241
- var AGENT_VERSION = "0.1.21";
5320
+ var AGENT_VERSION = "0.1.23";
5242
5321
  // Annotate the CommonJS export names for ESM import in node:
5243
5322
  0 && (module.exports = {
5244
5323
  AGENT_VERSION,
package/dist/index.mjs CHANGED
@@ -49,7 +49,7 @@ import {
49
49
  loadStrategy,
50
50
  validateConfig,
51
51
  validateStrategy
52
- } from "./chunk-U6YJHCO3.mjs";
52
+ } from "./chunk-NENK6U55.mjs";
53
53
  export {
54
54
  AGENT_VERSION,
55
55
  AgentConfigSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exagent/agent",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "Autonomous trading agent runtime for Exagent",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",