@thirdfy/agent-cli 0.2.76 → 0.2.78

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.
@@ -3,6 +3,7 @@ import { createHash } from 'node:crypto';
3
3
  import { CLI_MANIFEST } from '../../cli/manifest.mjs';
4
4
  import { validateParamsSchema, sanitizeParamsForSchemaValidation } from '../validation/paramsSchema.mjs';
5
5
  import { VENUE_WRITE_ACTION_FIXTURES } from './venueActionSchemas.mjs';
6
+ import { toLegacyVenueActionKey } from '../../core/venueBrand.mjs';
6
7
 
7
8
  const require = createRequire(import.meta.url);
8
9
 
@@ -23,7 +24,8 @@ const AUTHORITY_INPUT_CHECKS = [
23
24
  ];
24
25
 
25
26
  function normalizeActionKey(action) {
26
- return String(action || '').trim().replace(/_/g, '-').toLowerCase();
27
+ // Brand-insensitive: a live `place_veranta_perps_order` row replaces the `place_avantis_perps_order` fixture.
28
+ return toLegacyVenueActionKey(action).replace(/_/g, '-');
27
29
  }
28
30
 
29
31
  function isWriteAction(action) {
@@ -218,8 +218,10 @@ export const VENUE_WRITE_ACTION_FIXTURES = [
218
218
  validSample: { orderId: '0xabc' },
219
219
  },
220
220
  {
221
+ // Veranta (formerly Avantis). Fixture ids keep the Avantis spelling so the default schema digest
222
+ // is unchanged; the Veranta names are aliases.
221
223
  action: 'place_avantis_perps_order',
222
- aliases: ['place-avantis-perps-order'],
224
+ aliases: ['place-avantis-perps-order', 'place_veranta_perps_order', 'place-veranta-perps-order'],
223
225
  provider: 'avantis',
224
226
  authorityInputs: ['agentApiKey', 'estimatedAmountUsd'],
225
227
  paramsSchema: {
@@ -249,7 +251,7 @@ export const VENUE_WRITE_ACTION_FIXTURES = [
249
251
  },
250
252
  {
251
253
  action: 'cancel_avantis_perps_order',
252
- aliases: ['cancel-avantis-perps-order'],
254
+ aliases: ['cancel-avantis-perps-order', 'cancel_veranta_perps_order', 'cancel-veranta-perps-order'],
253
255
  provider: 'avantis',
254
256
  authorityInputs: ['agentApiKey'],
255
257
  paramsSchema: {
@@ -267,7 +269,7 @@ export const VENUE_WRITE_ACTION_FIXTURES = [
267
269
  },
268
270
  {
269
271
  action: 'close_avantis_position',
270
- aliases: ['close-avantis-position'],
272
+ aliases: ['close-avantis-position', 'close_veranta_position', 'close-veranta-position'],
271
273
  provider: 'avantis',
272
274
  authorityInputs: ['agentApiKey', 'estimatedAmountUsd'],
273
275
  paramsSchema: {
@@ -3,7 +3,62 @@ import { createCliError } from '../../core/envelope.mjs';
3
3
  export function createExecutionAmounts() {
4
4
  function shouldApplySwapAmountContract(actionName) {
5
5
  const action = String(actionName || '').trim().toLowerCase();
6
- return action === 'swap' || /(^|:|-)swap$/.test(action);
6
+ return action === 'swap' || action === 'execute_optimal_swap' || /(^|:|-)swap$/.test(action);
7
+ }
8
+
9
+ function normalizeContractActionKey(actionName) {
10
+ return String(actionName || '').trim().toLowerCase().replace(/_/g, '-');
11
+ }
12
+
13
+ /** `deposit_earn_position` takes `amount` as a decimal token-unit string (contract `earn_deposit_decimal_amount`). */
14
+ function shouldApplyEarnDepositAmountContract(actionName) {
15
+ return /(^|:)deposit-earn-position$/.test(normalizeContractActionKey(actionName));
16
+ }
17
+
18
+ function hasParamValue(value) {
19
+ return value !== undefined && value !== null && String(value).trim() !== '';
20
+ }
21
+
22
+ /**
23
+ * Accepts `amountHuman` or `amountInHuman` in place of `amount`, as thirdfy-mcp's params gate does
24
+ * (`earn_deposit_decimal_amount`). Exactly one decimal amount; raw base units are refused, because
25
+ * the API reads `amount` as token units.
26
+ */
27
+ function normalizeEarnDepositAmountContract(params) {
28
+ const hasAmount = hasParamValue(params.amount);
29
+ const hasAmountHuman = hasParamValue(params.amountHuman);
30
+ const hasAmountInHuman = hasParamValue(params.amountInHuman);
31
+ const humanInputs = [hasAmount, hasAmountHuman, hasAmountInHuman].filter(Boolean).length;
32
+ if (humanInputs > 1) {
33
+ throw createCliError(
34
+ 'EARN_AMOUNT_AMBIGUOUS',
35
+ 'Provide exactly one earn deposit amount: amount, amountHuman, or amountInHuman.'
36
+ );
37
+ }
38
+ if (humanInputs === 1) {
39
+ if (hasParamValue(params.amountInRaw) || hasParamValue(params.amountIn)) {
40
+ throw createCliError(
41
+ 'EARN_AMOUNT_UNIT_AMBIGUOUS',
42
+ 'Provide exactly one earn deposit amount; do not combine amount/amountHuman/amountInHuman with amountInRaw or amountIn.'
43
+ );
44
+ }
45
+ const amount = String(hasAmount ? params.amount : hasAmountHuman ? params.amountHuman : params.amountInHuman).trim();
46
+ if (!/^\d+(\.\d+)?$/.test(amount)) {
47
+ throw createCliError(
48
+ 'EARN_AMOUNT_INVALID',
49
+ 'Earn deposits require amount as a decimal token-unit string (example: "100.5").'
50
+ );
51
+ }
52
+ const { amountHuman: _amountHuman, amountInHuman: _amountInHuman, ...rest } = params;
53
+ return { ...rest, amount };
54
+ }
55
+ if (hasParamValue(params.amountInRaw) || hasParamValue(params.amountIn)) {
56
+ throw createCliError(
57
+ 'EARN_AMOUNT_UNIT_INVALID',
58
+ 'deposit_earn_position expects amount as a decimal token-unit string. Do not pass raw base-unit amountInRaw/amountIn for earn deposits.'
59
+ );
60
+ }
61
+ return params;
7
62
  }
8
63
 
9
64
  function normalizeIntegerRawAmount(input, code = 'AMOUNT_UNIT_INVALID') {
@@ -164,6 +219,11 @@ function normalizeSwapAmountContract(params) {
164
219
 
165
220
  function prepareActionParamsForFlags(flags, resolvedAction) {
166
221
  const parsedParams = parseJsonFlag(flags, 'params');
222
+ if (shouldApplyEarnDepositAmountContract(resolvedAction)) {
223
+ flags.__preparedParams = normalizeEarnDepositAmountContract(parsedParams || {});
224
+ flags.__swapInput = null;
225
+ return;
226
+ }
167
227
  if (!shouldApplySwapAmountContract(resolvedAction)) {
168
228
  flags.__preparedParams = parsedParams;
169
229
  flags.__swapInput = null;
@@ -187,6 +247,8 @@ function getPreparedParams(flags) {
187
247
  decimalToRawUnits,
188
248
  rawUnitsToDecimalString,
189
249
  normalizeSwapAmountContract,
250
+ shouldApplyEarnDepositAmountContract,
251
+ normalizeEarnDepositAmountContract,
190
252
  prepareActionParamsForFlags,
191
253
  getPreparedParams,
192
254
  };
@@ -1,4 +1,5 @@
1
1
  import { createCliError } from '../../core/envelope.mjs';
2
+ import { toLegacyVenueActionKey } from '../../core/venueBrand.mjs';
2
3
  export function createExecutionLanes() {
3
4
  const OFFCHAIN_VENUE_ORDER_ACTIONS = new Set([
4
5
  'place_hyperliquid_perps_order',
@@ -29,6 +30,7 @@ const OFFCHAIN_VENUE_ORDER_ACTIONS = new Set([
29
30
  'condor-executor-create',
30
31
  'condor_executor_stop',
31
32
  'condor-executor-stop',
33
+ // Veranta (formerly Avantis): keyed by the Avantis spelling; Veranta names map onto it below.
32
34
  'place_avantis_perps_order',
33
35
  'place-avantis-perps-order',
34
36
  'cancel_avantis_perps_order',
@@ -57,11 +59,11 @@ const OFFCHAIN_VENUE_ORDER_ACTIONS = new Set([
57
59
  'cancel-avantis-mm-order',
58
60
  ]);
59
61
  function enforceOffchainVenueLaneCompatibility(action, runMode) {
60
- const normalizedAction = String(action || '').trim().toLowerCase();
62
+ const normalizedAction = toLegacyVenueActionKey(action);
61
63
  if (runMode !== 'self' || !OFFCHAIN_VENUE_ORDER_ACTIONS.has(normalizedAction)) return;
62
64
  throw createCliError(
63
65
  'OFFCHAIN_VENUE_ORDER_SELF_UNSUPPORTED',
64
- 'Polymarket CLOB, Hyperliquid perps, Lighter perps, Avantis perps, Hummingbot executor, and Condor executor actions are offchain signed API actions, not EVM build-tx actions. Use self for setup/funding signatures, then run venue orders with --run-mode thirdfy, --run-mode hybrid, or --run-mode agent_wallet.',
66
+ 'Polymarket CLOB, Hyperliquid perps, Lighter perps, Veranta perps, Hummingbot executor, and Condor executor actions are offchain signed API actions, not EVM build-tx actions. Use self for setup/funding signatures, then run venue orders with --run-mode thirdfy, --run-mode hybrid, or --run-mode agent_wallet.',
65
67
  {
66
68
  recommendedRunModes: ['thirdfy', 'hybrid', 'agent_wallet'],
67
69
  setupOnlyRunMode: 'self',
@@ -4,6 +4,7 @@ import { resolveExecutionContextFromEnv } from '../../core/executionContext.mjs'
4
4
  import { requireFlag, parseJsonFlag } from '../../core/args.mjs';
5
5
  import { loadProfileConfig } from '../../core/context.mjs';
6
6
  import { createCliError } from '../../core/envelope.mjs';
7
+ import { toLegacyVenueActionKey } from '../../core/venueBrand.mjs';
7
8
  import { normalizeRunMode, normalizeManagedRunMode, normalizeHybridWalletMode } from '../../core/runMode.mjs';
8
9
  import { assertHostedRuntimePolymarketWriteIdempotency } from './hostedRuntimeWriteGate.mjs';
9
10
  import { resolveTokenInForFunding } from '../../core/fundingTokenIn.mjs';
@@ -29,10 +30,8 @@ export function mergeConfirmWritesIntoParams(params, flags) {
29
30
  export function resolveExecuteEstimatedAmountUsd(action, flags) {
30
31
  const fromFlags = Number(flags?.estimatedAmountUsd);
31
32
  if (Number.isFinite(fromFlags) && fromFlags > 0) return fromFlags;
32
- const key = String(action || '')
33
- .trim()
34
- .toLowerCase()
35
- .replace(/-/g, '_');
33
+ const key = toLegacyVenueActionKey(action).replace(/-/g, '_');
34
+ // Veranta onboarding (either spelling).
36
35
  if (key === 'complete_avantis_onboarding') return 1;
37
36
  return undefined;
38
37
  }
@@ -9,7 +9,8 @@ import {
9
9
  getEffectiveRunMode,
10
10
  parseBooleanFlag,
11
11
  } from '../../core/runMode.mjs';
12
- import { apiGet, apiPost } from '../../core/http.mjs';
12
+ import { apiGet, apiPost, responseHeadersFor } from '../../core/http.mjs';
13
+ import { idempotentReplayFields } from '../../core/hostedRuntimeIdempotency.mjs';
13
14
  import { withActionTimeout } from '../../core/actionTimeouts.mjs';
14
15
  import { isReadOnlyResolvedAction } from '../../core/readOnlyActions.mjs';
15
16
  import { resolveWalletExecuteChainId } from '../../core/walletExecuteChainId.mjs';
@@ -32,6 +33,7 @@ export function createExecutionRunners(deps) {
32
33
  buildBitfinexOnboardingCommand,
33
34
  inferBitfinexPermissionProfileFromAction,
34
35
  resolveAgentApiKey,
36
+ resolveAgentKey,
35
37
  loadEthers,
36
38
  signAndBroadcastWithOws,
37
39
  readEffectBalances,
@@ -146,9 +148,52 @@ function normalizeManagedExecuteResponse(response, { preflight, payload, isRead
146
148
  shaped?.amountNormalization || shaped?.data?.amountNormalization || null;
147
149
  normalized.raw = shaped;
148
150
  normalized.idempotencyKey = payload.executionIdempotencyKey || null;
151
+ // A replay means nothing new ran; say so, or the caller reads it as a fresh fill.
152
+ if (!isRead) {
153
+ Object.assign(
154
+ normalized,
155
+ idempotentReplayFields(response, responseHeadersFor(response), 'executionIdempotencyKey'),
156
+ );
157
+ }
149
158
  return normalized;
150
159
  }
151
160
 
161
+ const ROBINHOOD_MAINNET_CHAIN_ID = 4663;
162
+
163
+ /** Marker a read on the fast path carries instead of an execution-wallet preflight. */
164
+ const READ_FAST_PATH_PREFLIGHT = Object.freeze({ success: true, skipped: 'read_fast_path' });
165
+
166
+ /**
167
+ * agent_wallet reads skip the /execution-wallet preflight: the API resolves the agent's execution
168
+ * wallet itself, so the extra round trip only matters when a read uses its answer: a strict wallet
169
+ * match, a funding check, or the Robinhood delegated lane. An expected wallet equal to the agent key
170
+ * is not a separate wallet to match first; the wallet the API reports is checked after the read.
171
+ * Mirrors thirdfy-mcp `walletExecute` readFastPath.
172
+ */
173
+ function shouldUseManagedReadFastPath(flags, resolved, options = {}) {
174
+ if (!isReadOnlyAction(resolved)) return false;
175
+ if (options.requireFundingCheck === true) return false;
176
+ const runMode = String(flags.runMode || 'agent_wallet').trim().toLowerCase();
177
+ if (runMode !== 'agent_wallet') return false;
178
+ const expectedWallet = String(flags.walletAddress || flags.executionWalletAddress || '').trim().toLowerCase();
179
+ const agentKey = String(typeof resolveAgentKey === 'function' ? resolveAgentKey(flags) : flags.agentKey || '')
180
+ .trim()
181
+ .toLowerCase();
182
+ if (expectedWallet && expectedWallet !== agentKey) return false;
183
+ let chainId;
184
+ try {
185
+ chainId = resolveWalletExecuteChainId({
186
+ action: String(resolved?.resolvedAction || flags.action || '').trim(),
187
+ chainId: flags.chainId,
188
+ params: getPreparedParams(flags),
189
+ });
190
+ } catch {
191
+ // Unresolvable chain (e.g. a CCTP quote without sourceChainId): the preflight path reports it.
192
+ return false;
193
+ }
194
+ return Number(chainId) !== ROBINHOOD_MAINNET_CHAIN_ID;
195
+ }
196
+
152
197
  async function runPreflightByMode(runMode, ctx, flags, resolved, options = {}) {
153
198
  const resolvedAction = resolved.resolvedAction;
154
199
  if (runMode === 'agent_wallet') {
@@ -439,6 +484,9 @@ async function executeThirdfyRun(ctx, flags, resolved, options, runMode = 'third
439
484
  const response = await apiPost(actionCtx, '/api/v1/agent/execute-intent', payload);
440
485
  const normalized = normalizeIntentResponse(response);
441
486
  normalized.idempotencyKey = payload.idempotencyKey;
487
+ if (!isReadOnlyAction(resolved)) {
488
+ Object.assign(normalized, idempotentReplayFields(response, responseHeadersFor(response), 'idempotencyKey'));
489
+ }
442
490
  return normalized;
443
491
  }
444
492
 
@@ -465,7 +513,7 @@ async function runReadOnlyActionViaIntentRail(ctx, flags, resolved, options, pre
465
513
  intentResult.routeFallback = 'execute_intent_read_only';
466
514
  if (preflight) {
467
515
  intentResult.executionWalletPreflight = preflight;
468
- intentResult.executionWalletAddress = preflight.executionWalletAddress || null;
516
+ intentResult.executionWalletAddress = preflight.executionWalletAddress || intentResult.executionWalletAddress || null;
469
517
  }
470
518
  intentResult.signerMethod = 'managed_wallet_server';
471
519
  return intentResult;
@@ -479,8 +527,11 @@ async function executeManagedWalletRun(ctx, flags, resolved, options) {
479
527
  // (often as a JSON string under data.result). Reads skip funding gates; routing still fails closed.
480
528
  const isRead = isReadOnlyAction(resolved);
481
529
  const skipPreflight = Boolean(options?.skipPreflight);
482
- let preflight = null;
483
- if (!skipPreflight) {
530
+ // A seeded preflight (Hyperliquid/Lighter/Veranta address defaults) already ran; reuse it.
531
+ const readFastPath =
532
+ !skipPreflight && !options?.managedPreflight && shouldUseManagedReadFastPath(flags, resolved, options);
533
+ let preflight = readFastPath ? READ_FAST_PATH_PREFLIGHT : null;
534
+ if (!skipPreflight && !readFastPath) {
484
535
  preflight = await resolveManagedExecutionPreflight(ctx, flags, resolved, {
485
536
  runMode: 'agent_wallet',
486
537
  requireFundingCheck: !isRead,
@@ -510,8 +561,19 @@ async function executeManagedWalletRun(ctx, flags, resolved, options) {
510
561
  });
511
562
  const actionCtx = withActionTimeout(ctx, resolved);
512
563
  const response = await apiPost(actionCtx, '/api/v1/agent/execute', payload);
564
+ if (readFastPath) {
565
+ const mismatch = fastPathWalletMismatch(flags, response);
566
+ if (mismatch) return mismatch;
567
+ }
513
568
  if (shouldFallbackAgentWalletToExecuteIntent(resolved, response)) {
514
- const intentResult = await runReadOnlyActionViaIntentRail(ctx, flags, resolved, options, preflight);
569
+ // On the fast path the wallet comes from the /execute answer, not a preflight.
570
+ const fallbackPreflight = readFastPath
571
+ ? {
572
+ ...READ_FAST_PATH_PREFLIGHT,
573
+ executionWalletAddress: response?.executionWalletAddress || response?.data?.executionWalletAddress || null,
574
+ }
575
+ : preflight;
576
+ const intentResult = await runReadOnlyActionViaIntentRail(ctx, flags, resolved, options, fallbackPreflight);
515
577
  if (isEmptyQueuedExecuteIntent(intentResult.raw || intentResult)) {
516
578
  intentResult.success = false;
517
579
  intentResult.status = 'failed';
@@ -527,6 +589,33 @@ async function executeManagedWalletRun(ctx, flags, resolved, options) {
527
589
  return normalizeManagedExecuteResponse(response, { preflight, payload, isRead });
528
590
  }
529
591
 
592
+ /**
593
+ * The fast path only runs when the expected wallet is empty or equals the agent key. The preflight
594
+ * path refuses a wallet that differs from the execution wallet, so apply the same rule to the wallet
595
+ * the API reports for the read.
596
+ */
597
+ function fastPathWalletMismatch(flags, response) {
598
+ const expectedWallet = String(flags.walletAddress || flags.executionWalletAddress || '').trim().toLowerCase();
599
+ if (!expectedWallet || parseBooleanFlag(flags.allowWalletMismatch, false)) return null;
600
+ const apiWallet = String(response?.executionWalletAddress || response?.data?.executionWalletAddress || '')
601
+ .trim()
602
+ .toLowerCase();
603
+ if (!apiWallet || apiWallet === expectedWallet) return null;
604
+ const normalized = normalizeIntentResponse({
605
+ success: false,
606
+ status: 'failed',
607
+ mode: 'agent_wallet',
608
+ blockedReason: 'EXECUTION_WALLET_MISMATCH',
609
+ blockedStage: 'routing',
610
+ error: `Funded wallet (${expectedWallet}) does not match execution wallet (${apiWallet}). Use --allow-wallet-mismatch to override.`,
611
+ preflightBlocked: true,
612
+ executionWalletAddress: apiWallet,
613
+ });
614
+ normalized.executionWalletAddress = apiWallet;
615
+ normalized.executionWalletPreflight = READ_FAST_PATH_PREFLIGHT;
616
+ return normalized;
617
+ }
618
+
530
619
  async function executeSelfRun(ctx, flags, resolved, options) {
531
620
  const skipPreflight = Boolean(options?.skipPreflight);
532
621
  const blockedReasonCode = String(options?.blockedReasonCode || 'SELF_MODE_REQUIRES_BUILD_TX');
@@ -6,6 +6,7 @@ import {
6
6
  collectRootFlags,
7
7
  handleRootOnlyFlows,
8
8
  collectVersionFlagsFromArgv,
9
+ normalizeLegacyShortFlags,
9
10
  } from '../cli/program.mjs';
10
11
  import { createInitialRuntimeContext, applyFlagsToRuntimeContext } from './context.mjs';
11
12
  import { createProviderHints } from './providerHints.mjs';
@@ -87,6 +88,7 @@ export function createThirdfyAgentRuntime() {
87
88
  buildBitfinexOnboardingCommand: onboarding.buildBitfinexOnboardingCommand,
88
89
  inferBitfinexPermissionProfileFromAction: onboarding.inferBitfinexPermissionProfileFromAction,
89
90
  resolveAgentApiKey: payloads.resolveAgentApiKey,
91
+ resolveAgentKey: payloads.resolveAgentKey,
90
92
  loadEthers: ows.loadEthers,
91
93
  signAndBroadcastWithOws: ows.signAndBroadcastWithOws,
92
94
  readEffectBalances: ows.readEffectBalances,
@@ -154,7 +156,7 @@ export function createThirdfyAgentRuntime() {
154
156
  }
155
157
 
156
158
  try {
157
- await cliProgram.parseAsync(process.argv, { from: 'node' });
159
+ await cliProgram.parseAsync(normalizeLegacyShortFlags(process.argv), { from: 'node' });
158
160
  const versionHandled = await handleRootOnlyFlows(cliProgram, rootFlowDeps);
159
161
  if (versionHandled) return;
160
162
  } catch (error) {
@@ -1,9 +1,27 @@
1
+ import { normalizeVenueProviderId } from '../core/venueBrand.mjs';
2
+
3
+ /**
4
+ * Veranta (formerly Avantis) naming for the `avantis` / `avantis-vault` hints, static or from the
5
+ * capabilities manifest. Empty for every other provider.
6
+ */
7
+ function verantaNamingFields(provider) {
8
+ if (provider !== 'avantis' && provider !== 'avantis-vault') return {};
9
+ const alias = provider === 'avantis' ? 'veranta' : 'veranta-vault';
10
+ return {
11
+ displayName: 'Veranta',
12
+ formerName: 'Avantis',
13
+ providerAliases: [alias],
14
+ actionNaming: `Veranta (formerly Avantis). Veranta action names (*_veranta_*) are canonical; Avantis names (*_avantis_*) still resolve. Provider id stays ${provider}; --provider ${alias} is an alias.`,
15
+ };
16
+ }
17
+
1
18
  /**
2
19
  * Static and capabilities-backed provider discovery hints for CLI actions filtering.
3
20
  */
4
21
  export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
5
22
  function getTradingProviderHint(providerId) {
6
- const provider = String(providerId || '').trim().toLowerCase();
23
+ // `veranta` / `veranta-vault` resolve to the internal `avantis` / `avantis-vault` hints.
24
+ const provider = normalizeVenueProviderId(providerId || '');
7
25
  const manifestHint = getCachedProviderHintFromCapabilities(provider);
8
26
  const setupHints =
9
27
  manifestHint?.setupHints && typeof manifestHint.setupHints === 'object' ? manifestHint.setupHints : {};
@@ -206,68 +224,69 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
206
224
  if (provider === 'avantis') {
207
225
  return {
208
226
  provider,
227
+ ...verantaNamingFields(provider),
209
228
  category: 'leveraged_perps',
210
- canonicalWriteAction: 'place_avantis_perps_order',
229
+ canonicalWriteAction: 'place_veranta_perps_order',
211
230
  readActions: [
212
- 'get_avantis_markets',
213
- 'get_avantis_pair',
214
- 'get_avantis_price',
215
- 'get_avantis_spread',
216
- 'get_avantis_positions',
217
- 'get_avantis_open_orders',
218
- 'get_avantis_allowance',
219
- 'get_avantis_delegation_status',
220
- 'get_avantis_funding_status',
221
- 'get_avantis_setup_status',
222
- 'get_avantis_onboarding_plan',
223
- 'get_avantis_builder_fee_status',
224
- 'get_avantis_referral_status',
225
- 'get_avantis_referral_stats',
231
+ 'get_veranta_markets',
232
+ 'get_veranta_pair',
233
+ 'get_veranta_price',
234
+ 'get_veranta_spread',
235
+ 'get_veranta_positions',
236
+ 'get_veranta_open_orders',
237
+ 'get_veranta_allowance',
238
+ 'get_veranta_delegation_status',
239
+ 'get_veranta_funding_status',
240
+ 'get_veranta_setup_status',
241
+ 'get_veranta_onboarding_plan',
242
+ 'get_veranta_builder_fee_status',
243
+ 'get_veranta_referral_status',
244
+ 'get_veranta_referral_stats',
226
245
  ],
227
246
  orderManagementActions: [
228
- 'place_avantis_perps_order',
229
- 'cancel_avantis_perps_order',
230
- 'close_avantis_position',
231
- 'update_avantis_tp_sl',
232
- 'cancel_avantis_tp_sl',
233
- 'place_avantis_twap_order',
234
- 'close_avantis_twap_order',
235
- 'cancel_avantis_twap_order',
236
- 'place_avantis_coin_perps_order',
237
- 'increase_avantis_coin_position',
238
- 'close_avantis_coin_position',
239
- 'place_avantis_mm_order',
240
- 'cancel_avantis_mm_order',
241
- 'get_avantis_open_orders',
242
- 'get_avantis_positions',
247
+ 'place_veranta_perps_order',
248
+ 'cancel_veranta_perps_order',
249
+ 'close_veranta_position',
250
+ 'update_veranta_tp_sl',
251
+ 'cancel_veranta_tp_sl',
252
+ 'place_veranta_twap_order',
253
+ 'close_veranta_twap_order',
254
+ 'cancel_veranta_twap_order',
255
+ 'place_veranta_coin_perps_order',
256
+ 'increase_veranta_coin_position',
257
+ 'close_veranta_coin_position',
258
+ 'place_veranta_mm_order',
259
+ 'cancel_veranta_mm_order',
260
+ 'get_veranta_open_orders',
261
+ 'get_veranta_positions',
243
262
  ],
244
263
  setupActions: [
245
- 'get_avantis_funding_status',
246
- 'get_avantis_setup_status',
247
- 'get_avantis_onboarding_plan',
248
- 'prepare_avantis_onboarding',
249
- 'complete_avantis_onboarding',
250
- 'approve_avantis_builder_fee',
251
- 'revoke_avantis_builder_fee',
252
- 'set_avantis_referral_code',
253
- 'register_avantis_referral_code',
254
- 'claim_avantis_referral_rebate',
264
+ 'get_veranta_funding_status',
265
+ 'get_veranta_setup_status',
266
+ 'get_veranta_onboarding_plan',
267
+ 'prepare_veranta_onboarding',
268
+ 'complete_veranta_onboarding',
269
+ 'approve_veranta_builder_fee',
270
+ 'revoke_veranta_builder_fee',
271
+ 'set_veranta_referral_code',
272
+ 'register_veranta_referral_code',
273
+ 'claim_veranta_referral_rebate',
255
274
  ],
256
275
  statusActions: [
257
- 'get_avantis_funding_status',
258
- 'get_avantis_setup_status',
259
- 'get_avantis_builder_fee_status',
260
- 'get_avantis_delegation_status',
276
+ 'get_veranta_funding_status',
277
+ 'get_veranta_setup_status',
278
+ 'get_veranta_builder_fee_status',
279
+ 'get_veranta_delegation_status',
261
280
  ],
262
281
  recoveryActions: [
263
- 'get_avantis_positions',
264
- 'close_avantis_position',
282
+ 'get_veranta_positions',
283
+ 'close_veranta_position',
265
284
  ],
266
285
  decommissionExample:
267
- 'get_avantis_positions -> close_avantis_position -> withdraw-to-user on execution wallet (Base USDC)',
286
+ 'get_veranta_positions -> close_veranta_position -> withdraw-to-user on execution wallet (Base USDC)',
268
287
  credentialType: 'avantis_delegate',
269
288
  credentialUx:
270
- 'Thirdfy mints and stores the encrypted Avantis delegate. CLI callers use Thirdfy auth only. Do not paste a private key.',
289
+ 'Thirdfy mints and stores the encrypted Veranta delegate. CLI callers use Thirdfy auth only. Do not paste a private key.',
271
290
  recommendedFundingChainId: 8453,
272
291
  supportedFundingSourceChains: [
273
292
  { chainId: 8453, name: 'Base', path: 'native USDC in managed execution wallet (recommended)' },
@@ -283,32 +302,33 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
283
302
  funding:
284
303
  'Fund the managed execution wallet on Base (8453) with native USDC. Minimum collateral follows the live catalog notional floor.',
285
304
  laneCompatibility:
286
- 'Use agent_wallet for solo managed-wallet onboarding and perps writes after avantis_delegate credential is stored. Use thirdfy or hybrid for delegated capital. Thirdfy builds EIP-712 intents; the delegate credential signs batched-market submissions. Relayer is default. Builder-fee collection stays unwired until Avantis supplies a fee-enabled template.',
305
+ 'Use agent_wallet for solo managed-wallet onboarding and perps writes after avantis_delegate credential is stored. Use thirdfy or hybrid for delegated capital. Thirdfy builds EIP-712 intents; the delegate credential signs batched-market submissions. Relayer is default. Builder-fee collection stays unwired until Veranta supplies a fee-enabled template.',
287
306
  setupExample:
288
- 'actions --provider avantis -> get_avantis_funding_status -> complete_avantis_onboarding (agent_wallet on Base 8453) -> get_avantis_setup_status before place_avantis_perps_order. Do not call approve_avantis_builder_fee until setup status shows a wired template.',
307
+ 'actions --provider veranta -> get_veranta_funding_status -> complete_veranta_onboarding (agent_wallet on Base 8453) -> get_veranta_setup_status before place_veranta_perps_order. Do not call approve_veranta_builder_fee until setup status shows a wired template.',
289
308
  example:
290
- 'thirdfy-agent actions --provider avantis && thirdfy-agent preflight --action place_avantis_perps_order --params \'{"pairIndex":0,"side":"long","collateralUsdc":10,"leverage":10,"orderType":"market"}\'',
309
+ 'thirdfy-agent actions --provider veranta && thirdfy-agent preflight --action place_veranta_perps_order --params \'{"pairIndex":0,"side":"long","collateralUsdc":10,"leverage":10,"orderType":"market"}\'',
291
310
  };
292
311
  }
293
312
  if (provider === 'avantis-vault') {
294
313
  return {
295
314
  provider,
315
+ ...verantaNamingFields(provider),
296
316
  category: 'earn',
297
- canonicalReadAction: 'get_avantis_vault_info',
298
- canonicalWriteAction: 'deposit_avantis_vault',
299
- readActions: ['get_avantis_vault_info', 'get_avantis_vault_position'],
317
+ canonicalReadAction: 'get_veranta_vault_info',
318
+ canonicalWriteAction: 'deposit_veranta_vault',
319
+ readActions: ['get_veranta_vault_info', 'get_veranta_vault_position'],
300
320
  orderManagementActions: [
301
- 'deposit_avantis_vault',
302
- 'request_avantis_vault_withdrawal',
303
- 'redeem_avantis_vault',
304
- 'claim_avantis_vault',
321
+ 'deposit_veranta_vault',
322
+ 'request_veranta_vault_withdrawal',
323
+ 'redeem_veranta_vault',
324
+ 'claim_veranta_vault',
305
325
  ],
306
326
  recommendedFundingChainId: 8453,
307
327
  supportedChains: [8453],
308
328
  funding: 'Fund the managed execution wallet on Base with native USDC before vault deposit.',
309
- laneCompatibility: 'Avantis LP vault on Base. Use agent_wallet, thirdfy, or hybrid. Relayer is default.',
329
+ laneCompatibility: 'Veranta (formerly Avantis) LP vault on Base. Use agent_wallet, thirdfy, or hybrid. Relayer is default.',
310
330
  example:
311
- 'thirdfy-agent actions --provider avantis-vault && thirdfy-agent run --action get_avantis_vault_info --provider avantis-vault --json',
331
+ 'thirdfy-agent actions --provider veranta-vault && thirdfy-agent run --action get_veranta_vault_info --provider veranta-vault --json',
312
332
  };
313
333
  }
314
334
  if (provider === 'bitfinex') {
@@ -901,12 +921,12 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
901
921
  }
902
922
 
903
923
  function getCachedProviderHintFromCapabilities(provider) {
904
- const normalizedProvider = String(provider || '').trim().toLowerCase();
924
+ const normalizedProvider = normalizeVenueProviderId(provider || '');
905
925
  if (!normalizedProvider) return null;
906
926
  const manifests = Array.isArray(getNegotiatedCapabilitiesCache()?.providers?.manifests)
907
927
  ? getNegotiatedCapabilitiesCache().providers.manifests
908
928
  : [];
909
- const match = manifests.find((entry) => String(entry?.providerId || '').trim().toLowerCase() === normalizedProvider);
929
+ const match = manifests.find((entry) => normalizeVenueProviderId(entry?.providerId || '') === normalizedProvider);
910
930
  if (!match) return null;
911
931
  const canonicalWriteActions = {
912
932
  trading: 'swap',
@@ -958,13 +978,20 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
958
978
  custodyMode: match.custodyMode || null,
959
979
  description: match.description || null,
960
980
  source: 'cli_capabilities_manifest',
981
+ ...verantaNamingFields(normalizedProvider),
961
982
  ...(match.setupHints && typeof match.setupHints === 'object' ? { setupHints: match.setupHints } : {}),
962
983
  };
963
984
  }
964
985
 
986
+ // Veranta hints carry `providerAliases`; show the public name in messages (`--provider veranta`).
987
+ function providerLabelForHint(providerHint) {
988
+ const alias = Array.isArray(providerHint?.providerAliases) ? providerHint.providerAliases[0] : null;
989
+ return alias || providerHint.provider;
990
+ }
991
+
965
992
  function formatProviderAmbiguousActionHint(providerHint) {
966
993
  if (!providerHint) return '';
967
- const p = providerHint.provider;
994
+ const p = providerLabelForHint(providerHint);
968
995
  const w = providerHint.canonicalWriteAction;
969
996
  if (w) return ` Provider ${p} expects ${w}.`;
970
997
  return ` Provider ${p} did not declare a canonical write action in capabilities; run actions --provider ${p} first.`;
@@ -972,7 +999,7 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
972
999
 
973
1000
  function formatProviderUnknownActionHint(providerHint) {
974
1001
  if (!providerHint) return '';
975
- const p = providerHint.provider;
1002
+ const p = providerLabelForHint(providerHint);
976
1003
  const w = providerHint.canonicalWriteAction;
977
1004
  if (w) return ` Provider ${p} expects ${w}; run actions --provider ${p} first.`;
978
1005
  return ` Provider ${p} did not declare a canonical write action in capabilities; run actions --provider ${p} first.`;