@thirdfy/agent-cli 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/CHANGELOG.md +27 -2
- package/bin/thirdfy-agent.mjs +324 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,10 +4,35 @@ All notable changes to `@thirdfy/agent-cli` are documented here. The format is b
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.23] - 2026-05-02
|
|
8
|
+
|
|
9
|
+
**npm:** [`@thirdfy/agent-cli@0.1.23`](https://www.npmjs.com/package/@thirdfy/agent-cli/v/0.1.23)
|
|
10
|
+
**Git tag:** `v0.1.23`
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Provider discovery hints for `earn`, `morpho`, `curve`, and generic `prediction` so agents can filter action catalogs by domain without hard-coded protocol-specific flows.
|
|
15
|
+
- Curve/Base 4pool write hints surfaced through the actions provider filter for earn flows.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **Provider filter:** Case-insensitive matching for earn-related action keys when filtering catalogs by provider.
|
|
20
|
+
- **Self custody:** `preflight` and self-exec paths reject offchain venue order actions before `build-tx`, aligned with venue execution guardrails.
|
|
21
|
+
|
|
22
|
+
## [0.1.22] - 2026-04-28
|
|
23
|
+
|
|
24
|
+
**npm:** [`@thirdfy/agent-cli@0.1.22`](https://www.npmjs.com/package/@thirdfy/agent-cli/v/0.1.22)
|
|
25
|
+
**Git tag:** `v0.1.22`
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- **Agent tracking/data commands:** Added `data summary`, `track actions`, `track events`, and `track action` so operators and agents can read Thirdfy-owned analytics and report actions without raw telemetry HTTP calls.
|
|
30
|
+
- **Permissive custom tracking:** `track action` now supports unknown/custom action names with optional `--source`, `--provider`, `--protocol`, `--namespace`, and `--action-type` metadata.
|
|
31
|
+
|
|
7
32
|
## [0.1.21] - 2026-04-26
|
|
8
33
|
|
|
9
|
-
**npm:** [`@thirdfy/agent-cli@0.1.21`](https://www.npmjs.com/package/@thirdfy/agent-cli/v/0.1.21)
|
|
10
|
-
**Git tag:** `v0.1.21`
|
|
34
|
+
**npm:** [`@thirdfy/agent-cli@0.1.21`](https://www.npmjs.com/package/@thirdfy/agent-cli/v/0.1.21)
|
|
35
|
+
**Git tag:** [`v0.1.21`](https://github.com/thirdfy/agent-cli/releases/tag/v0.1.21)
|
|
11
36
|
|
|
12
37
|
### Fixed
|
|
13
38
|
|
package/bin/thirdfy-agent.mjs
CHANGED
|
@@ -176,6 +176,18 @@ async function main() {
|
|
|
176
176
|
case 'credits balance':
|
|
177
177
|
await commandCreditsBalance(context, subFlags, capabilities);
|
|
178
178
|
return;
|
|
179
|
+
case 'data summary':
|
|
180
|
+
await commandDataSummary(context, subFlags, capabilities);
|
|
181
|
+
return;
|
|
182
|
+
case 'track actions':
|
|
183
|
+
await commandTrackList(context, subFlags, capabilities, 'actions');
|
|
184
|
+
return;
|
|
185
|
+
case 'track events':
|
|
186
|
+
await commandTrackList(context, subFlags, capabilities, 'events');
|
|
187
|
+
return;
|
|
188
|
+
case 'track action':
|
|
189
|
+
await commandTrackAction(context, subFlags, capabilities);
|
|
190
|
+
return;
|
|
179
191
|
case 'delegation create':
|
|
180
192
|
await commandDelegationCreate(context, subFlags, capabilities);
|
|
181
193
|
return;
|
|
@@ -362,6 +374,212 @@ function shouldApplySwapAmountContract(actionName) {
|
|
|
362
374
|
return action === 'swap' || /(^|:|-)swap$/.test(action);
|
|
363
375
|
}
|
|
364
376
|
|
|
377
|
+
function getTradingProviderHint(providerId) {
|
|
378
|
+
const provider = String(providerId || '').trim().toLowerCase();
|
|
379
|
+
const manifestHint = getCachedProviderHintFromCapabilities(provider);
|
|
380
|
+
if (manifestHint) return manifestHint;
|
|
381
|
+
if (provider === 'trading') {
|
|
382
|
+
return {
|
|
383
|
+
provider,
|
|
384
|
+
category: 'onchain_spot',
|
|
385
|
+
canonicalWriteAction: 'swap',
|
|
386
|
+
credentialUx: 'Use normal Thirdfy login/delegation; do not use this provider for Hyperliquid or Polymarket.',
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
if (provider === 'hyperliquid') {
|
|
390
|
+
return {
|
|
391
|
+
provider,
|
|
392
|
+
category: 'leveraged_perps',
|
|
393
|
+
canonicalWriteAction: 'place_hyperliquid_perps_order',
|
|
394
|
+
readActions: [
|
|
395
|
+
'get_hyperliquid_perps_meta',
|
|
396
|
+
'get_hyperliquid_all_mids',
|
|
397
|
+
'get_hyperliquid_l2_book',
|
|
398
|
+
'get_hyperliquid_candles',
|
|
399
|
+
'get_hyperliquid_user_state',
|
|
400
|
+
'get_hyperliquid_open_orders',
|
|
401
|
+
'get_hyperliquid_onboarding_plan',
|
|
402
|
+
'get_hyperliquid_referral_status',
|
|
403
|
+
'get_hyperliquid_builder_fee_status',
|
|
404
|
+
],
|
|
405
|
+
orderManagementActions: [
|
|
406
|
+
'place_hyperliquid_perps_order',
|
|
407
|
+
'get_hyperliquid_open_orders',
|
|
408
|
+
],
|
|
409
|
+
setupActions: [
|
|
410
|
+
'get_hyperliquid_setup_status',
|
|
411
|
+
'get_hyperliquid_onboarding_plan',
|
|
412
|
+
'prepare_hyperliquid_onboarding',
|
|
413
|
+
'get_bridge_quote',
|
|
414
|
+
'execute_bridge',
|
|
415
|
+
'approve_hyperliquid_agent',
|
|
416
|
+
'get_hyperliquid_builder_fee_status',
|
|
417
|
+
'approve_hyperliquid_builder_fee',
|
|
418
|
+
'set_hyperliquid_referrer',
|
|
419
|
+
'deposit_hyperliquid_bridge',
|
|
420
|
+
'deposit_hyperliquid_staking',
|
|
421
|
+
'claim_hyperliquid_testnet_faucet',
|
|
422
|
+
],
|
|
423
|
+
statusActions: ['get_hyperliquid_setup_status', 'get_hyperliquid_builder_fee_status', 'get_hyperliquid_referral_status'],
|
|
424
|
+
credentialType: 'hyperliquid_api_wallet',
|
|
425
|
+
credentialUx:
|
|
426
|
+
'Thirdfy manages Hyperliquid API-wallet setup for normal users. Delegated writes require encrypted privateKey-backed hyperliquid_api_wallet credentials; walletAddress-only records are rejected until Privy walletId-backed Hyperliquid signing ships.',
|
|
427
|
+
recommendedFundingChainId: 42161,
|
|
428
|
+
supportedFundingSourceChains: [
|
|
429
|
+
{ chainId: 42161, name: 'Arbitrum One', path: 'native USDC -> Bridge2' },
|
|
430
|
+
{ chainId: 8453, name: 'Base', path: 'Li.Fi -> Arbitrum native USDC -> Bridge2' },
|
|
431
|
+
{ chainId: 1, name: 'Ethereum', path: 'Li.Fi -> Arbitrum native USDC -> Bridge2' },
|
|
432
|
+
{ chainId: 137, name: 'Polygon', path: 'Li.Fi -> Arbitrum native USDC -> Bridge2' },
|
|
433
|
+
],
|
|
434
|
+
setupBlockers: [
|
|
435
|
+
'HYPERLIQUID_SOURCE_FUNDS_REQUIRED',
|
|
436
|
+
'HYPERLIQUID_ARBITRUM_USDC_REQUIRED',
|
|
437
|
+
'HYPERLIQUID_BRIDGE2_DEPOSIT_REQUIRED',
|
|
438
|
+
'HYPERLIQUID_API_WALLET_APPROVAL_REQUIRED',
|
|
439
|
+
'HYPERLIQUID_BUILDER_APPROVAL_REQUIRED',
|
|
440
|
+
'HYPERLIQUID_POLICY_REQUIRED',
|
|
441
|
+
'HYPERLIQUID_CREDITS_REQUIRED',
|
|
442
|
+
'HYPERLIQUID_API_WALLET_SIGNER_REQUIRED',
|
|
443
|
+
],
|
|
444
|
+
sourceBridgeProvider: 'lifi',
|
|
445
|
+
funding:
|
|
446
|
+
'Best path: Base/Ethereum/Polygon USDC -> Li.Fi bridge to native Arbitrum USDC -> Hyperliquid Bridge2. If the user already has native Circle USDC on Arbitrum One (42161), skip Li.Fi and call deposit_hyperliquid_bridge. Minimum 5 USDC; Bridge2 credits the sender/source wallet.',
|
|
447
|
+
laneCompatibility:
|
|
448
|
+
'Use self only for setup signatures or Arbitrum funding transactions. Perps orders should use thirdfy, hybrid, or agent_wallet.',
|
|
449
|
+
setupExample:
|
|
450
|
+
'actions --provider hyperliquid -> get_hyperliquid_onboarding_plan -> prepare_hyperliquid_onboarding -> get_bridge_quote/execute_bridge if source is Base -> deposit_hyperliquid_bridge on 42161 -> approve_hyperliquid_agent -> approve_hyperliquid_builder_fee if required -> get_hyperliquid_setup_status',
|
|
451
|
+
example:
|
|
452
|
+
'thirdfy-agent actions --provider hyperliquid && thirdfy-agent preflight --action place_hyperliquid_perps_order --params \'{"coin":"ETH","isBuy":true,"size":0.01,"limitPx":3500,"orderType":"market"}\'',
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
if (provider === 'polymarket') {
|
|
456
|
+
return {
|
|
457
|
+
provider,
|
|
458
|
+
category: 'prediction_market',
|
|
459
|
+
canonicalWriteAction: 'place_polymarket_order',
|
|
460
|
+
readActions: [
|
|
461
|
+
'get_polymarket_markets',
|
|
462
|
+
'get_polymarket_market',
|
|
463
|
+
'get_polymarket_order_book',
|
|
464
|
+
'get_polymarket_prices',
|
|
465
|
+
'get_polymarket_price_history',
|
|
466
|
+
'get_polymarket_setup_status',
|
|
467
|
+
'get_polymarket_order',
|
|
468
|
+
'get_polymarket_user_orders',
|
|
469
|
+
],
|
|
470
|
+
orderManagementActions: [
|
|
471
|
+
'place_polymarket_order',
|
|
472
|
+
'get_polymarket_order',
|
|
473
|
+
'get_polymarket_user_orders',
|
|
474
|
+
'cancel_polymarket_order',
|
|
475
|
+
],
|
|
476
|
+
setupActions: [
|
|
477
|
+
'get_polymarket_setup_status',
|
|
478
|
+
'agent_wallet_setup:ensure_agent_wallet_safe',
|
|
479
|
+
'agent_wallet_setup:deploy_safe_and_set_approvals',
|
|
480
|
+
'agent_wallet_setup:create_or_derive_clob_credentials',
|
|
481
|
+
'browser_setup:add_privy_signer',
|
|
482
|
+
'browser_setup:create_or_derive_clob_credentials',
|
|
483
|
+
'browser_setup:deploy_safe_and_set_approvals',
|
|
484
|
+
],
|
|
485
|
+
statusActions: ['get_polymarket_setup_status'],
|
|
486
|
+
credentialType: 'polymarket_clob',
|
|
487
|
+
credentialUx:
|
|
488
|
+
'Autonomous agents use an agent-owned Privy wallet/Safe first: Thirdfy creates the agent wallet, deploys/approves the Safe, and stores encrypted CLOB credentials once Polymarket key creation is available. User-owned browser setup remains optional for interactive capital.',
|
|
489
|
+
funding:
|
|
490
|
+
'Fund the agent-owned Polymarket Safe with Polygon USDC/pUSD collateral after Safe deployment and approvals.',
|
|
491
|
+
laneCompatibility:
|
|
492
|
+
'Use agent_wallet as the preferred autonomous-agent path. Use self only for user-owned setup/funding signatures. CLOB orders should use thirdfy, hybrid, or agent_wallet after polymarket_clob credentials are stored.',
|
|
493
|
+
setupBlockers: [
|
|
494
|
+
'POLYMARKET_AGENT_WALLET_SAFE_REQUIRED',
|
|
495
|
+
'POLYMARKET_CLOB_CREDENTIALS_REQUIRED',
|
|
496
|
+
'POLYMARKET_SAFE_DEPLOYMENT_REQUIRED',
|
|
497
|
+
'POLYMARKET_SAFE_APPROVALS_REQUIRED',
|
|
498
|
+
'POLYMARKET_USDC_REQUIRED',
|
|
499
|
+
'POLYMARKET_CREDITS_REQUIRED',
|
|
500
|
+
'POLYMARKET_RELAYER_UNAVAILABLE',
|
|
501
|
+
'POLYMARKET_CLOB_KEY_CREATION_BLOCKED_UNTIL_POLYMARKET_FIX',
|
|
502
|
+
],
|
|
503
|
+
example:
|
|
504
|
+
'thirdfy-agent actions --provider polymarket && thirdfy-agent preflight --action place_polymarket_order --params \'{"tokenID":"...","price":0.42,"size":10,"side":"BUY"}\'',
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
if (provider === 'prediction') {
|
|
508
|
+
return {
|
|
509
|
+
provider,
|
|
510
|
+
category: 'prediction',
|
|
511
|
+
canonicalWriteAction: 'place_prediction_order',
|
|
512
|
+
readActions: ['get_prediction_markets', 'get_prediction_market', 'get_prediction_order_book'],
|
|
513
|
+
orderManagementActions: ['place_prediction_order', 'cancel_prediction_order'],
|
|
514
|
+
compatibilityProvider: 'polymarket',
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
if (provider === 'earn') {
|
|
518
|
+
return {
|
|
519
|
+
provider,
|
|
520
|
+
category: 'earn',
|
|
521
|
+
canonicalReadAction: 'get_earn_opportunities',
|
|
522
|
+
canonicalWriteAction: 'deposit_earn_position',
|
|
523
|
+
readActions: ['get_earn_opportunities', 'get_earn_provider', 'get_earn_position'],
|
|
524
|
+
orderManagementActions: ['deposit_earn_position', 'withdraw_earn_position'],
|
|
525
|
+
laneCompatibility:
|
|
526
|
+
'Generic earn writes use deposit_earn_position / withdraw_earn_position on normal Thirdfy policy/delegation rails; routing selects Morpho vault calldata or the validated Curve Base 4pool adapter on Base (8453) per opportunity.',
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
if (provider === 'morpho') {
|
|
530
|
+
return {
|
|
531
|
+
provider,
|
|
532
|
+
category: 'earn',
|
|
533
|
+
canonicalReadAction: 'get_morpho_vaults',
|
|
534
|
+
canonicalWriteAction: 'deposit_earn_position',
|
|
535
|
+
readActions: ['get_morpho_vaults', 'get_earn_provider', 'get_earn_position'],
|
|
536
|
+
orderManagementActions: ['deposit_earn_position', 'withdraw_earn_position'],
|
|
537
|
+
supportedChains: [8453, 84532],
|
|
538
|
+
laneCompatibility: 'Morpho deposits require ERC-20 approvals to the vault/market routes surfaced by the catalog before deposit_earn_position.',
|
|
539
|
+
example:
|
|
540
|
+
'thirdfy-agent actions --provider morpho && thirdfy-agent run --action deposit_earn_position --params \'{"providerId":"morpho","vaultAddress":"0x...","tokenAddress":"0x...","amount":"10","chainId":8453}\'',
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
if (provider === 'curve') {
|
|
544
|
+
return {
|
|
545
|
+
provider,
|
|
546
|
+
category: 'earn',
|
|
547
|
+
canonicalReadAction: 'get_curve_pools',
|
|
548
|
+
canonicalWriteAction: 'deposit_earn_position',
|
|
549
|
+
readActions: ['get_curve_pools', 'get_earn_opportunities', 'get_earn_provider', 'get_earn_position'],
|
|
550
|
+
orderManagementActions: ['deposit_earn_position', 'withdraw_earn_position'],
|
|
551
|
+
supportedChains: [8453],
|
|
552
|
+
laneCompatibility:
|
|
553
|
+
'Curve EVM writes are limited to the validated Base mainnet 4pool adapter; other pools remain discovery-only until per-pool calldata is validated.',
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function getCachedProviderHintFromCapabilities(_provider) {
|
|
560
|
+
return null;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const OFFCHAIN_VENUE_ORDER_ACTIONS = new Set([
|
|
564
|
+
'place_hyperliquid_perps_order',
|
|
565
|
+
'place-hyperliquid-perps-order',
|
|
566
|
+
'place_polymarket_order',
|
|
567
|
+
'place-polymarket-order',
|
|
568
|
+
]);
|
|
569
|
+
|
|
570
|
+
function enforceOffchainVenueLaneCompatibility(action, runMode) {
|
|
571
|
+
const normalizedAction = String(action || '').trim().toLowerCase();
|
|
572
|
+
if (runMode !== 'self' || !OFFCHAIN_VENUE_ORDER_ACTIONS.has(normalizedAction)) return;
|
|
573
|
+
throw createCliError(
|
|
574
|
+
'OFFCHAIN_VENUE_ORDER_SELF_UNSUPPORTED',
|
|
575
|
+
'Polymarket CLOB and Hyperliquid perps orders 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.',
|
|
576
|
+
{
|
|
577
|
+
recommendedRunModes: ['thirdfy', 'hybrid', 'agent_wallet'],
|
|
578
|
+
setupOnlyRunMode: 'self',
|
|
579
|
+
}
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
|
|
365
583
|
function createCliError(code, message, payload = {}) {
|
|
366
584
|
const error = new Error(message);
|
|
367
585
|
error.payload = {
|
|
@@ -539,9 +757,86 @@ async function commandCatalogsList(ctx, flags, capabilities) {
|
|
|
539
757
|
});
|
|
540
758
|
}
|
|
541
759
|
|
|
760
|
+
async function commandDataSummary(ctx, flags, capabilities) {
|
|
761
|
+
const agentKey = requireFlag(flags, 'agentKey', 'Missing --agent-key');
|
|
762
|
+
const query = new URLSearchParams({ agentKey });
|
|
763
|
+
if (flags.chainId) query.set('chainId', String(flags.chainId));
|
|
764
|
+
if (flags.limit) query.set('limit', String(flags.limit));
|
|
765
|
+
const response = await apiGet(ctx, `/api/v1/agent/telemetry/summary?${query.toString()}`);
|
|
766
|
+
printEnvelope({
|
|
767
|
+
success: true,
|
|
768
|
+
code: 'DATA_SUMMARY_OK',
|
|
769
|
+
message: 'Agent data summary loaded',
|
|
770
|
+
data: response,
|
|
771
|
+
meta: {
|
|
772
|
+
apiBase: ctx.apiBase,
|
|
773
|
+
agentKey,
|
|
774
|
+
chainId: flags.chainId ? Number(flags.chainId) : null,
|
|
775
|
+
},
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
async function commandTrackList(ctx, flags, capabilities, kind) {
|
|
780
|
+
const agentKey = requireFlag(flags, 'agentKey', 'Missing --agent-key');
|
|
781
|
+
const query = new URLSearchParams({ agentKey });
|
|
782
|
+
if (flags.limit) query.set('limit', String(flags.limit));
|
|
783
|
+
const response = await apiGet(ctx, `/api/v1/agent/telemetry/${kind}?${query.toString()}`);
|
|
784
|
+
printEnvelope({
|
|
785
|
+
success: true,
|
|
786
|
+
code: kind === 'events' ? 'TRACK_EVENTS_OK' : 'TRACK_ACTIONS_OK',
|
|
787
|
+
message: kind === 'events' ? 'Tracked agent events loaded' : 'Tracked agent actions loaded',
|
|
788
|
+
data: response,
|
|
789
|
+
meta: {
|
|
790
|
+
apiBase: ctx.apiBase,
|
|
791
|
+
agentKey,
|
|
792
|
+
kind,
|
|
793
|
+
},
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
async function commandTrackAction(ctx, flags, capabilities) {
|
|
798
|
+
const agentApiKey = resolveAgentApiKey(flags, 'thirdfy');
|
|
799
|
+
const action = requireFlag(flags, 'action', 'Missing --action');
|
|
800
|
+
const payload = {
|
|
801
|
+
agentApiKey,
|
|
802
|
+
action,
|
|
803
|
+
status: String(flags.status || 'observed'),
|
|
804
|
+
};
|
|
805
|
+
if (flags.agentKey) payload.agentKey = String(flags.agentKey);
|
|
806
|
+
if (flags.eventId) payload.eventId = String(flags.eventId);
|
|
807
|
+
if (flags.idempotencyKey) payload.idempotencyKey = String(flags.idempotencyKey);
|
|
808
|
+
if (flags.category) payload.category = String(flags.category);
|
|
809
|
+
if (flags.source) payload.source = String(flags.source);
|
|
810
|
+
if (flags.provider) payload.provider = String(flags.provider);
|
|
811
|
+
if (flags.protocol) payload.protocol = String(flags.protocol);
|
|
812
|
+
if (flags.namespace) payload.namespace = String(flags.namespace);
|
|
813
|
+
if (flags.actionType) payload.actionType = String(flags.actionType);
|
|
814
|
+
if (flags.chainId) payload.chainId = Number(flags.chainId);
|
|
815
|
+
if (flags.amountUsd) payload.amountUsd = Number(flags.amountUsd);
|
|
816
|
+
if (flags.txHash) payload.txHash = String(flags.txHash);
|
|
817
|
+
if (flags.userDid) payload.userDid = String(flags.userDid);
|
|
818
|
+
if (flags.params) payload.params = parseJsonFlag(flags, 'params');
|
|
819
|
+
if (flags.decision) payload.decision = parseJsonFlag(flags, 'decision');
|
|
820
|
+
if (flags.proof) payload.proof = parseJsonFlag(flags, 'proof');
|
|
821
|
+
|
|
822
|
+
const response = await apiPost(ctx, '/api/v1/agent/telemetry/actions', payload);
|
|
823
|
+
printEnvelope({
|
|
824
|
+
success: Boolean(response?.success !== false),
|
|
825
|
+
code: response?.success === false ? 'TRACK_ACTION_FAILED' : 'TRACK_ACTION_OK',
|
|
826
|
+
message: response?.success === false ? 'Agent action tracking failed' : 'Agent action tracked',
|
|
827
|
+
data: response,
|
|
828
|
+
meta: {
|
|
829
|
+
apiBase: ctx.apiBase,
|
|
830
|
+
action,
|
|
831
|
+
chainId: payload.chainId || null,
|
|
832
|
+
},
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
|
|
542
836
|
async function commandActions(ctx, flags, capabilities) {
|
|
543
837
|
const policyAware = Boolean(flags.agentApiKey);
|
|
544
838
|
const actions = applyActionFilters(await getCachedActionsCatalog(ctx, flags), flags);
|
|
839
|
+
const providerHint = getTradingProviderHint(flags.provider);
|
|
545
840
|
const effectiveRunMode = getEffectiveRunMode(ctx, flags);
|
|
546
841
|
const chainIdFilter = Number(flags.chainId || 0) || undefined;
|
|
547
842
|
const chainSupport = resolveChainSupport(capabilities, chainIdFilter, effectiveRunMode);
|
|
@@ -549,7 +844,7 @@ async function commandActions(ctx, flags, capabilities) {
|
|
|
549
844
|
success: true,
|
|
550
845
|
code: 'OK',
|
|
551
846
|
message: 'Actions loaded',
|
|
552
|
-
data: { actions },
|
|
847
|
+
data: { actions, ...(providerHint ? { providerHint } : {}) },
|
|
553
848
|
meta: {
|
|
554
849
|
apiBase: ctx.apiBase,
|
|
555
850
|
policyAware,
|
|
@@ -565,6 +860,7 @@ async function commandPreflight(ctx, flags, capabilities) {
|
|
|
565
860
|
const resolved = await resolveActionSelection(ctx, flags);
|
|
566
861
|
prepareActionParamsForFlags(flags, resolved.resolvedAction);
|
|
567
862
|
const runMode = getEffectiveRunMode(ctx, flags);
|
|
863
|
+
enforceOffchainVenueLaneCompatibility(resolved.resolvedAction, runMode);
|
|
568
864
|
const hybridWalletMode = runMode === 'hybrid' ? normalizeHybridWalletMode(flags.hybridWalletMode) : null;
|
|
569
865
|
enforceChainCompatibility(capabilities, flags, runMode);
|
|
570
866
|
const backendResult = await runPreflightByMode(runMode, ctx, flags, resolved, { hybridWalletMode });
|
|
@@ -599,6 +895,7 @@ async function commandRun(ctx, flags, capabilities) {
|
|
|
599
895
|
const resolved = await resolveActionSelection(ctx, flags);
|
|
600
896
|
prepareActionParamsForFlags(flags, resolved.resolvedAction);
|
|
601
897
|
const runMode = getEffectiveRunMode(ctx, flags);
|
|
898
|
+
enforceOffchainVenueLaneCompatibility(resolved.resolvedAction, runMode);
|
|
602
899
|
const hybridWalletMode = runMode === 'hybrid' ? normalizeHybridWalletMode(flags.hybridWalletMode) : null;
|
|
603
900
|
enforceChainCompatibility(capabilities, flags, runMode);
|
|
604
901
|
const skipPreflight = Boolean(flags.skipPreflight);
|
|
@@ -724,6 +1021,7 @@ async function commandWalletSign(ctx, flags, capabilities) {
|
|
|
724
1021
|
const normalizedFlags = { ...flags, runMode: 'self' };
|
|
725
1022
|
const resolved = await resolveActionSelection(ctx, normalizedFlags);
|
|
726
1023
|
prepareActionParamsForFlags(normalizedFlags, resolved.resolvedAction);
|
|
1024
|
+
enforceOffchainVenueLaneCompatibility(resolved.resolvedAction, 'self');
|
|
727
1025
|
enforceChainCompatibility(capabilities, normalizedFlags, 'self');
|
|
728
1026
|
const selfResult = await executeSelfRun(ctx, normalizedFlags, resolved, {
|
|
729
1027
|
skipPreflight: Boolean(normalizedFlags.skipPreflight),
|
|
@@ -1594,6 +1892,7 @@ async function commandPrompt(ctx, flags, capabilities, promptTokens) {
|
|
|
1594
1892
|
async function commandSelfExec(ctx, flags, capabilities) {
|
|
1595
1893
|
const resolved = await resolveActionSelection(ctx, flags);
|
|
1596
1894
|
prepareActionParamsForFlags(flags, resolved.resolvedAction);
|
|
1895
|
+
enforceOffchainVenueLaneCompatibility(resolved.resolvedAction, 'self');
|
|
1597
1896
|
enforceChainCompatibility(capabilities, flags, 'self');
|
|
1598
1897
|
const selfResult = await executeSelfRun(ctx, flags, resolved, {
|
|
1599
1898
|
skipPreflight: Boolean(flags.skipPreflight),
|
|
@@ -2881,11 +3180,22 @@ function applyActionFilters(actions, flags) {
|
|
|
2881
3180
|
}
|
|
2882
3181
|
if (flags.provider) {
|
|
2883
3182
|
const expectedProvider = String(flags.provider).trim().toLowerCase();
|
|
2884
|
-
filtered = filtered.filter((a) =>
|
|
3183
|
+
filtered = filtered.filter((a) => {
|
|
3184
|
+
const provider = getActionProvider(a);
|
|
3185
|
+
const actionKey = getActionKey(a).replace(/-/g, '_').toLowerCase();
|
|
3186
|
+
if (provider === expectedProvider) return true;
|
|
3187
|
+
if (expectedProvider === 'earn') return provider === 'morpho' || provider === 'curve' || actionKey.includes('_earn_');
|
|
3188
|
+
if (expectedProvider === 'prediction') return provider === 'polymarket' || actionKey.includes('_prediction_');
|
|
3189
|
+
return false;
|
|
3190
|
+
});
|
|
2885
3191
|
}
|
|
2886
3192
|
return filtered;
|
|
2887
3193
|
}
|
|
2888
3194
|
|
|
3195
|
+
function getActionProvider(action) {
|
|
3196
|
+
return String(action?.provider || action?.providerId || action?.provider_id || action?.catalog || '').trim().toLowerCase();
|
|
3197
|
+
}
|
|
3198
|
+
|
|
2889
3199
|
async function resolveActionSelection(ctx, flags) {
|
|
2890
3200
|
const requestedAction = requireFlag(flags, 'action', 'Missing --action');
|
|
2891
3201
|
const requestedLower = requestedAction.toLowerCase();
|
|
@@ -2921,10 +3231,11 @@ async function resolveActionSelection(ctx, flags) {
|
|
|
2921
3231
|
return { requestedAction, resolvedAction: exactAlias[0].key, resolvedActionMeta: exactAlias[0].action || null };
|
|
2922
3232
|
}
|
|
2923
3233
|
if (exactAlias.length > 1) {
|
|
3234
|
+
const providerHint = flags.provider ? getTradingProviderHint(flags.provider) : null;
|
|
2924
3235
|
throw new Error(
|
|
2925
3236
|
`Ambiguous --action "${requestedAction}". Alias matches multiple actions: ${formatActionList(
|
|
2926
3237
|
exactAlias.map((v) => v.key)
|
|
2927
|
-
)}.`
|
|
3238
|
+
)}.${providerHint ? ` Provider ${providerHint.provider} expects ${providerHint.canonicalWriteAction}.` : ''}`
|
|
2928
3239
|
);
|
|
2929
3240
|
}
|
|
2930
3241
|
|
|
@@ -2937,14 +3248,18 @@ async function resolveActionSelection(ctx, flags) {
|
|
|
2937
3248
|
return { requestedAction, resolvedAction: fuzzy[0].key, resolvedActionMeta: fuzzy[0].action || null };
|
|
2938
3249
|
}
|
|
2939
3250
|
if (fuzzy.length > 1) {
|
|
3251
|
+
const providerHint = flags.provider ? getTradingProviderHint(flags.provider) : null;
|
|
2940
3252
|
throw new Error(
|
|
2941
3253
|
`Ambiguous --action "${requestedAction}". Did you mean one of: ${formatActionList(
|
|
2942
3254
|
fuzzy.slice(0, 10).map((v) => v.key)
|
|
2943
|
-
)}
|
|
3255
|
+
)}?${providerHint ? ` Provider ${providerHint.provider} expects ${providerHint.canonicalWriteAction}.` : ''}`
|
|
2944
3256
|
);
|
|
2945
3257
|
}
|
|
3258
|
+
const providerHint = flags.provider ? getTradingProviderHint(flags.provider) : null;
|
|
2946
3259
|
throw new Error(
|
|
2947
|
-
`Unknown --action "${requestedAction}". No compatible action found in current catalog/provider scope
|
|
3260
|
+
`Unknown --action "${requestedAction}". No compatible action found in current catalog/provider scope.${
|
|
3261
|
+
providerHint ? ` Provider ${providerHint.provider} expects ${providerHint.canonicalWriteAction}; run actions --provider ${providerHint.provider} first.` : ''
|
|
3262
|
+
}`
|
|
2948
3263
|
);
|
|
2949
3264
|
}
|
|
2950
3265
|
|
|
@@ -3479,6 +3794,10 @@ Core commands:
|
|
|
3479
3794
|
thirdfy-agent whoami [--json]
|
|
3480
3795
|
thirdfy-agent catalogs list [--json]
|
|
3481
3796
|
thirdfy-agent actions [--catalog <id>] [--provider <id>] [--agent-api-key <key>] [--chain-id <id>] [--run-mode <mode>] [--json]
|
|
3797
|
+
thirdfy-agent data summary --agent-key <key> [--chain-id <id>] [--limit <n>] [--json]
|
|
3798
|
+
thirdfy-agent track actions --agent-key <key> [--limit <n>] [--json]
|
|
3799
|
+
thirdfy-agent track events --agent-key <key> [--limit <n>] [--json]
|
|
3800
|
+
thirdfy-agent track action --agent-api-key <key> --action <name> [--category <name>] [--source agent|external_mcp|operator|thirdfy|custom] [--provider <id>] [--protocol <id>] [--namespace <name>] [--action-type supported|custom] [--status observed|planned|skipped|submitted|confirmed|failed|blocked] [--chain-id <id>] [--params <json>] [--json]
|
|
3482
3801
|
thirdfy-agent delegation create [--auth-token <token> | --owner-session-token <token>] --agent-key <key> --owner-address <addr> --token-address <addr> --max-usd-per-day <usd> [--session-account-address <addr>] [--json]
|
|
3483
3802
|
thirdfy-agent delegation init-custodial [--auth-token <token> | --owner-session-token <token>] [--chain-id <id>] [--json]
|
|
3484
3803
|
thirdfy-agent delegation custodial-grant [--auth-token <token> | --owner-session-token <token>] --agent-key <key> --token-address <addr> --max-usd-per-day <usd> [--chain-id <id>] [--period-duration <sec>] [--expiry-seconds <sec>] [--json]
|