@thirdfy/agent-cli 0.2.17 → 0.2.20

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 CHANGED
@@ -4,6 +4,24 @@ All notable changes to `@thirdfy/agent-cli` are documented here. The format is b
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.2.20] - 2026-07-04
8
+
9
+ ### Added
10
+
11
+ - `brain` command group: `sections`, `suggest`, `preflight`, `graduate` for Console Brain read/preflight-first strategy lanes (pairs with Thirdfy API **v3.10.0** Brain routes).
12
+
13
+ ## [0.2.19] - 2026-07-04
14
+
15
+ ### Changed
16
+
17
+ - Release packaging and docs alignment (no Brain commands in this tag; use **v0.2.20** for `brain`).
18
+
19
+ ## [0.2.18] - 2026-07-02
20
+
21
+ ### Changed
22
+
23
+ - `credits balance`, `credits models list`, and `credits models estimate` human-readable summaries lead with USD when the API returns `availableUsd`, `estimatedUsdPerTurn`, or `chargedUsd` (Thirdfy API **v3.9.5+** USD credits Phase 1). JSON output unchanged. Pairs with `thirdfy-mcp` **v0.0.67+**.
24
+
7
25
  ## [0.2.17] - 2026-07-02
8
26
 
9
27
  ### Changed
package/README.md CHANGED
@@ -40,9 +40,11 @@ Run without global install:
40
40
  npx @thirdfy/agent-cli --help
41
41
  ```
42
42
 
43
- ## What's new in v0.2.17
43
+ ## What's new in v0.2.20
44
44
 
45
- - Lighter onboarding writes (`complete_lighter_onboarding`, `setup_lighter_api_key`, `register_lighter_api_key`) use a 180s HTTP timeout by default so `run` and `wallet execute` do not abort before CCTP credit or Ethereum `changePubKey` completes. Override with `THIRDFY_CLI_LONG_TIMEOUT_MS`. Pairs with Thirdfy API **v3.9.4+** and `thirdfy-mcp` **v0.0.66+**.
45
+ - **Console Brain:** `thirdfy-agent brain sections|suggest|preflight|graduate` read ranked Trading, Yield, and Prediction lanes from Thirdfy API (no local ranking).
46
+ - Brain commands support `--strategy`, `--section`, `--capital-usd`, `--risk`, and `--target earnclaw` for read/preflight-first strategy workflows.
47
+ - Pairs with Thirdfy API **v3.10.0** Brain routes (`GET /api/v1/console/brain-*`). See [`docs/command-reference.md`](./docs/command-reference.md).
46
48
 
47
49
  Older versions: see [CHANGELOG.md](./CHANGELOG.md) and [GitHub Releases](https://github.com/thirdfy/agent-cli/releases).
48
50
 
@@ -312,6 +314,7 @@ Provider and venue guides are kept outside `README` so this page stays stable as
312
314
  - Delegation operations: `delegation show`, `delegation inspect`, `delegation revoke`
313
315
  - Delegation execution helpers: `delegation balance`, `delegation redeem`
314
316
  - Account: `credits balance`
317
+ - Console Brain: `brain sections`, `brain suggest`, `brain preflight`, `brain graduate` (read/preflight-first; see [`docs/command-reference.md`](./docs/command-reference.md))
315
318
 
316
319
  ## CLI routing (Commander + runtime)
317
320
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thirdfy/agent-cli",
3
- "version": "0.2.17",
3
+ "version": "0.2.20",
4
4
  "description": "Thirdfy Agent CLI for onboarding, governance preflight, execute-intent, and status polling.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,6 +11,7 @@
11
11
  "src/core/",
12
12
  "src/commands/",
13
13
  "src/cli/",
14
+ "src/lib/",
14
15
  "src/runtime/",
15
16
  "src/utils/cli/",
16
17
  "src/contracts/cli/schemas/",
@@ -92,6 +92,30 @@ export const CLI_MANIFEST = [
92
92
  options: ['auth', 'execution', 'polymarket'],
93
93
  description: 'Polymarket dry-run preflight',
94
94
  },
95
+ {
96
+ path: ['venue', 'readiness'],
97
+ handler: 'commandVenueReadiness',
98
+ options: ['auth', 'venue'],
99
+ description: 'Normalized venue readiness (polymarket, hyperliquid, lighter)',
100
+ args: { query: true },
101
+ tier: 'online',
102
+ },
103
+ {
104
+ path: ['venue', 'setup'],
105
+ handler: 'commandVenueSetup',
106
+ options: ['auth', 'venue'],
107
+ description: 'Prepare or complete venue onboarding via shared API contract',
108
+ args: { query: true },
109
+ tier: 'online',
110
+ },
111
+ {
112
+ path: ['venue', 'fund'],
113
+ handler: 'commandVenueFund',
114
+ options: ['auth', 'venue'],
115
+ description: 'Return venue funding plan (does not move funds implicitly)',
116
+ args: { query: true },
117
+ tier: 'online',
118
+ },
95
119
  {
96
120
  path: ['hummingbot', 'status'],
97
121
  handler: 'commandHummingbotStatus',
@@ -196,6 +220,56 @@ export const CLI_MANIFEST = [
196
220
  options: ['auth', 'execution'],
197
221
  description: 'Quote action-tier credits for a catalog action',
198
222
  },
223
+ {
224
+ path: ['chat', 'send'],
225
+ handler: 'commandChatSend',
226
+ tier: 'online',
227
+ options: ['auth', 'chat', 'chains'],
228
+ description: 'Send a Console chat message (streaming)',
229
+ args: { message: '[message...]' },
230
+ },
231
+ {
232
+ path: ['chat', 'threads'],
233
+ handler: 'commandChatThreads',
234
+ tier: 'online',
235
+ options: ['auth'],
236
+ description: 'List Console chat threads',
237
+ },
238
+ {
239
+ path: ['chat', 'models'],
240
+ handler: 'commandChatModels',
241
+ tier: 'online',
242
+ options: ['auth'],
243
+ description: 'List Console chat models from catalog',
244
+ },
245
+ {
246
+ path: ['brain', 'sections'],
247
+ handler: 'commandBrainSections',
248
+ tier: 'online',
249
+ options: ['auth', 'chains', 'brain'],
250
+ description: 'Read Console Brain sections for trading, yield, and prediction',
251
+ },
252
+ {
253
+ path: ['brain', 'suggest'],
254
+ handler: 'commandBrainSuggest',
255
+ tier: 'online',
256
+ options: ['auth', 'chains', 'brain'],
257
+ description: 'Return a structured Brain strategy draft from current signals',
258
+ },
259
+ {
260
+ path: ['brain', 'preflight'],
261
+ handler: 'commandBrainPreflight',
262
+ tier: 'online',
263
+ options: ['auth', 'chains', 'brain'],
264
+ description: 'Run read-only Brain preflight checks for a strategy',
265
+ },
266
+ {
267
+ path: ['brain', 'graduate'],
268
+ handler: 'commandBrainGraduate',
269
+ tier: 'online',
270
+ options: ['auth', 'brain'],
271
+ description: 'Prepare an EarnClaw handoff proposal without deploying',
272
+ },
199
273
  {
200
274
  path: ['data', 'summary'],
201
275
  handler: 'commandDataSummary',
@@ -0,0 +1,10 @@
1
+ export function attachBrainOptions(cmd) {
2
+ return cmd
3
+ .option('--strategy <id>', 'Brain strategy id (default base-usdc-yield)')
4
+ .option('--strategy-id <id>', 'alias for --strategy')
5
+ .option('--section <lane>', 'yield | trading | prediction')
6
+ .option('--capital-usd <amount>', 'optional capital size for strategy draft')
7
+ .option('--risk <level>', 'low | medium | high')
8
+ .option('--target <name>', 'handoff target (earnclaw)')
9
+ .option('--include-degraded', 'include degraded Brain sections', false);
10
+ }
@@ -0,0 +1,9 @@
1
+ export function attachChatOptions(cmd) {
2
+ return cmd
3
+ .option('--network <id>', 'network id (for example base-mainnet)')
4
+ .option('--model <key>', 'chat model key from catalog')
5
+ .option('--thread <id>', 'existing chat thread id')
6
+ .option('--continue', 'continue the last persisted thread')
7
+ .option('--persona <mode>', 'chat persona mode', 'thirdfy')
8
+ .option('--tool-domains <list>', 'comma-separated tool pack ids (prediction, earn, perps_hl, ...)');
9
+ }
@@ -12,6 +12,9 @@ import { attachHummingbotOptions } from './hummingbot.mjs';
12
12
  import { attachAgentRegisterOptions } from './agent.mjs';
13
13
  import { attachChainOptions } from './chains.mjs';
14
14
  import { attachCreditsOptions } from './credits.mjs';
15
+ import { attachChatOptions } from './chat.mjs';
16
+ import { attachVenueOptions } from './venue.mjs';
17
+ import { attachBrainOptions } from './brain.mjs';
15
18
 
16
19
  const BUNDLES = {
17
20
  auth: attachAuthOptions,
@@ -27,6 +30,9 @@ const BUNDLES = {
27
30
  agent: attachAgentRegisterOptions,
28
31
  chains: attachChainOptions,
29
32
  credits: attachCreditsOptions,
33
+ chat: attachChatOptions,
34
+ venue: attachVenueOptions,
35
+ brain: attachBrainOptions,
30
36
  };
31
37
 
32
38
  /** @param {import('commander').Command} cmd */
@@ -0,0 +1,12 @@
1
+ export function attachVenueOptions(cmd) {
2
+ return cmd
3
+ .option('--amount <usd>', 'Funding amount in USD')
4
+ .option('--amount-usd <usd>', 'Alias for --amount')
5
+ .option('--main-wallet-address <address>', 'Hyperliquid main wallet address')
6
+ .option('--api-wallet-address <address>', 'Hyperliquid API wallet address')
7
+ .option('--l1-address <address>', 'Lighter L1 address')
8
+ .option('--include-geoblock', 'Include Polymarket geoblock probes', true)
9
+ .option('--no-include-geoblock', 'Skip Polymarket geoblock probes')
10
+ .option('--complete', 'Run complete onboarding writes (setup command only)')
11
+ .option('--confirm-writes', 'Confirm onboarding writes');
12
+ }
@@ -50,6 +50,9 @@ function registerManifestEntry(program, entry, nodeByPath, deps) {
50
50
  if (entry.args?.query) {
51
51
  leaf.argument(entry.args.query);
52
52
  }
53
+ if (entry.args?.message) {
54
+ leaf.argument(entry.args.message);
55
+ }
53
56
 
54
57
  const handler = handlers[entry.handler];
55
58
  if (!handler) {
@@ -62,6 +65,11 @@ function registerManifestEntry(program, entry, nodeByPath, deps) {
62
65
 
63
66
  if (entry.args?.address) {
64
67
  extra.address = actionArgs[0];
68
+ } else if (entry.args?.message) {
69
+ const messageArg = actionArgs[0];
70
+ extra.message = Array.isArray(messageArg)
71
+ ? messageArg.join(' ')
72
+ : String(messageArg || '').trim();
65
73
  } else if (entry.args?.query) {
66
74
  const queryArg = actionArgs[0];
67
75
  extra.query = Array.isArray(queryArg) ? queryArg : queryArg !== undefined ? [queryArg] : [];
@@ -78,6 +86,8 @@ function registerManifestEntry(program, entry, nodeByPath, deps) {
78
86
  } else if (entry.handler === 'commandPrompt') {
79
87
  const tokens = Array.isArray(extra.query) ? extra.query : [];
80
88
  await handler(ctx, flags, capabilities, tokens);
89
+ } else if (entry.handler === 'commandChatSend') {
90
+ await handler(ctx, flags, capabilities, extra.message);
81
91
  } else {
82
92
  await handler(ctx, flags, capabilities);
83
93
  }
@@ -26,6 +26,8 @@ export function createBootstrapCommands(deps) {
26
26
  printEnvelope,
27
27
  extractAgentApiKey,
28
28
  extractAgentKey,
29
+ maskSecret,
30
+ buildOwnerAuthHeaders,
29
31
  buildOnboardingHelp,
30
32
  buildWalletChallengePayload,
31
33
  issueBootstrapToken,
@@ -162,12 +164,47 @@ async function commandHelpOnboarding(ctx, _flags) {
162
164
  }
163
165
 
164
166
 
165
- async function commandWhoami(ctx, _flags) {
167
+ async function commandWhoami(ctx, flags) {
166
168
  const config = loadProfileConfig();
167
169
  const auth = config.auth && typeof config.auth === 'object' ? config.auth : {};
168
170
  const agent = config.agent && typeof config.agent === 'object' ? config.agent : {};
169
171
  const wallets = config.wallets && typeof config.wallets === 'object' ? config.wallets : {};
172
+ const chat = config.chat && typeof config.chat === 'object' ? config.chat : {};
170
173
  const runMode = ctx.runMode || config.runMode || 'agent_wallet';
174
+
175
+ let mandateSummary = null;
176
+ let mandateSummaryError = null;
177
+ const hasPrivyAuth = Boolean(
178
+ auth.authToken ||
179
+ auth.ownerSessionToken ||
180
+ process.env.THIRDFY_AUTH_TOKEN ||
181
+ process.env.THIRDFY_OWNER_SESSION_TOKEN ||
182
+ flags.authToken,
183
+ );
184
+ const hasAgentApiKey = Boolean(agent.apiKey || process.env.THIRDFY_AGENT_API_KEY);
185
+
186
+ if (hasPrivyAuth) {
187
+ try {
188
+ const headers = buildOwnerAuthHeaders(
189
+ flags,
190
+ 'Missing credentials for mandate summary (auth token or owner session required).',
191
+ );
192
+ const chainId = Number(chat.chainId || flags.chainId || 8453);
193
+ const query = new URLSearchParams({ chainId: String(chainId) });
194
+ const walletAddress = String(
195
+ wallets.primaryEvmWallet || flags.walletAddress || '',
196
+ ).trim();
197
+ if (walletAddress) query.set('walletAddress', walletAddress);
198
+ mandateSummary = await apiGet(
199
+ ctx,
200
+ `/api/v1/console/mandate-summary?${query.toString()}`,
201
+ headers,
202
+ );
203
+ } catch (error) {
204
+ mandateSummaryError = error?.message || 'MANDATE_SUMMARY_FAILED';
205
+ }
206
+ }
207
+
171
208
  printEnvelope({
172
209
  success: true,
173
210
  code: 'WHOAMI_OK',
@@ -188,6 +225,14 @@ async function commandWhoami(ctx, _flags) {
188
225
  agentApiKey: maskSecret(agent.apiKey),
189
226
  agentKey: agent.agentKey || null,
190
227
  },
228
+ chat: {
229
+ lastThreadId: chat.lastThreadId || null,
230
+ defaultChatModel: chat.defaultChatModel || null,
231
+ chainId: chat.chainId || null,
232
+ },
233
+ mandateSummary,
234
+ mandateSummaryError,
235
+ mandateSummarySkipped: !hasPrivyAuth && hasAgentApiKey ? 'requires_privy_auth' : null,
191
236
  wallets: {
192
237
  userDid: wallets.userDid || config.identity?.userDid || null,
193
238
  primaryEvmWallet: wallets.primaryEvmWallet || null,
@@ -0,0 +1,135 @@
1
+ import { loadProfileConfig } from '../core/context.mjs';
2
+ import { apiGet } from '../core/http.mjs';
3
+
4
+ function buildAuthHeaders(flags) {
5
+ const config = loadProfileConfig();
6
+ const explicitOwner = String(flags.ownerSessionToken || '').trim();
7
+ const explicitAuth = String(flags.authToken || '').trim();
8
+ const ownerSession = String(
9
+ process.env.THIRDFY_OWNER_SESSION_TOKEN || config?.auth?.ownerSessionToken || '',
10
+ ).trim();
11
+ const authToken = String(process.env.THIRDFY_AUTH_TOKEN || config?.auth?.authToken || '').trim();
12
+
13
+ if (explicitOwner || ownerSession) {
14
+ return { 'x-owner-session-token': explicitOwner || ownerSession };
15
+ }
16
+ const token = explicitAuth || authToken;
17
+ if (token) {
18
+ return { Authorization: `Bearer ${token}` };
19
+ }
20
+ throw new Error(
21
+ 'Missing credentials: provide --auth-token, THIRDFY_AUTH_TOKEN, or --owner-session-token.',
22
+ );
23
+ }
24
+
25
+ function resolveChainId(flags, config) {
26
+ if (flags.chainId) {
27
+ const parsed = Number(flags.chainId);
28
+ if (Number.isFinite(parsed) && parsed > 0) return parsed;
29
+ }
30
+ const fromConfig = Number(config?.chat?.chainId || 0);
31
+ if (Number.isFinite(fromConfig) && fromConfig > 0) return fromConfig;
32
+ return 8453;
33
+ }
34
+
35
+ function resolveWalletAddress(flags, config) {
36
+ const explicit = String(flags.walletAddress || '').trim();
37
+ if (explicit) return explicit;
38
+ const wallets = config?.wallets && typeof config.wallets === 'object' ? config.wallets : {};
39
+ return String(wallets.primaryEvmWallet || '').trim() || undefined;
40
+ }
41
+
42
+ function buildQuery(params) {
43
+ const search = new URLSearchParams();
44
+ for (const [key, value] of Object.entries(params)) {
45
+ if (value == null || value === '') continue;
46
+ search.set(key, String(value));
47
+ }
48
+ const query = search.toString();
49
+ return query ? `?${query}` : '';
50
+ }
51
+
52
+ function printBrainEnvelope(printEnvelope, flags, code, message, data) {
53
+ printEnvelope(
54
+ {
55
+ success: true,
56
+ code,
57
+ message,
58
+ data,
59
+ meta: { readOnly: true },
60
+ },
61
+ flags,
62
+ );
63
+ }
64
+
65
+ export function createBrainCommands({ printEnvelope }) {
66
+ async function commandBrainSections(ctx, flags) {
67
+ const config = loadProfileConfig();
68
+ const chainId = resolveChainId(flags, config);
69
+ const walletAddress = resolveWalletAddress(flags, config);
70
+ const query = buildQuery({
71
+ chainId,
72
+ walletAddress,
73
+ includeDegraded: flags.includeDegraded === false ? 'false' : 'true',
74
+ });
75
+ const data = await apiGet(ctx, `/api/v1/console/brain-sections${query}`, buildAuthHeaders(flags));
76
+ printBrainEnvelope(printEnvelope, flags, 'OK', 'Brain sections loaded', data);
77
+ return data;
78
+ }
79
+
80
+ async function commandBrainSuggest(ctx, flags) {
81
+ const config = loadProfileConfig();
82
+ const chainId = resolveChainId(flags, config);
83
+ const walletAddress = resolveWalletAddress(flags, config);
84
+ const strategyId = String(flags.strategy || flags.strategyId || '').trim();
85
+ const section = String(flags.section || '').trim();
86
+ const queryParams = {
87
+ capitalUsd: flags.capitalUsd,
88
+ risk: flags.risk,
89
+ chainId,
90
+ walletAddress,
91
+ };
92
+ if (strategyId) {
93
+ queryParams.strategyId = strategyId;
94
+ } else if (section) {
95
+ queryParams.section = section;
96
+ } else {
97
+ queryParams.strategyId = 'base-usdc-yield';
98
+ }
99
+ const query = buildQuery(queryParams);
100
+ const data = await apiGet(ctx, `/api/v1/console/brain/suggest${query}`, buildAuthHeaders(flags));
101
+ printBrainEnvelope(printEnvelope, flags, 'OK', 'Brain strategy draft loaded', data);
102
+ return data;
103
+ }
104
+
105
+ async function commandBrainPreflight(ctx, flags) {
106
+ const config = loadProfileConfig();
107
+ const chainId = resolveChainId(flags, config);
108
+ const walletAddress = resolveWalletAddress(flags, config);
109
+ const query = buildQuery({
110
+ strategyId: flags.strategy || flags.strategyId || 'base-usdc-yield',
111
+ chainId,
112
+ walletAddress,
113
+ });
114
+ const data = await apiGet(ctx, `/api/v1/console/brain/preflight${query}`, buildAuthHeaders(flags));
115
+ printBrainEnvelope(printEnvelope, flags, 'OK', 'Brain preflight loaded', data);
116
+ return data;
117
+ }
118
+
119
+ async function commandBrainGraduate(ctx, flags) {
120
+ const query = buildQuery({
121
+ strategyId: flags.strategy || flags.strategyId || 'base-usdc-yield',
122
+ target: flags.target || 'earnclaw',
123
+ });
124
+ const data = await apiGet(ctx, `/api/v1/console/brain/graduate${query}`, buildAuthHeaders(flags));
125
+ printBrainEnvelope(printEnvelope, flags, 'OK', 'Brain EarnClaw handoff proposal loaded', data);
126
+ return data;
127
+ }
128
+
129
+ return {
130
+ commandBrainSections,
131
+ commandBrainSuggest,
132
+ commandBrainPreflight,
133
+ commandBrainGraduate,
134
+ };
135
+ }
@@ -0,0 +1,404 @@
1
+ import { parseBooleanFlag } from '../core/runMode.mjs';
2
+ import { loadProfileConfig, persistProfileConfig } from '../core/context.mjs';
3
+ import { apiGet, safeJsonParse } from '../core/http.mjs';
4
+
5
+ const NETWORK_CHAIN_IDS = {
6
+ 'base-mainnet': 8453,
7
+ 'base-sepolia': 84532,
8
+ };
9
+
10
+ const DEFAULT_CHAT_CHAIN_ID = 8453;
11
+ const CHAT_STREAM_TIMEOUT_MS = 180_000;
12
+
13
+ function resolveChatChainId(flags, config) {
14
+ if (flags.chainId) {
15
+ const parsed = Number(flags.chainId);
16
+ if (Number.isFinite(parsed) && parsed > 0) return parsed;
17
+ }
18
+ const network = String(flags.network || '').trim().toLowerCase();
19
+ if (network && NETWORK_CHAIN_IDS[network]) return NETWORK_CHAIN_IDS[network];
20
+ const fromConfig = Number(config?.chat?.chainId || 0);
21
+ if (Number.isFinite(fromConfig) && fromConfig > 0) return fromConfig;
22
+ return DEFAULT_CHAT_CHAIN_ID;
23
+ }
24
+
25
+ function buildChatAuthHeaders(flags) {
26
+ const config = loadProfileConfig();
27
+ const explicitOwner = String(flags.ownerSessionToken || '').trim();
28
+ const explicitAuth = String(flags.authToken || '').trim();
29
+ const ownerSession = String(
30
+ process.env.THIRDFY_OWNER_SESSION_TOKEN || config?.auth?.ownerSessionToken || '',
31
+ ).trim();
32
+ const authToken = String(process.env.THIRDFY_AUTH_TOKEN || config?.auth?.authToken || '').trim();
33
+
34
+ if (explicitOwner || ownerSession) {
35
+ return { 'x-owner-session-token': explicitOwner || ownerSession };
36
+ }
37
+ const token = explicitAuth || authToken;
38
+ if (token) {
39
+ return { Authorization: `Bearer ${token}` };
40
+ }
41
+ throw new Error(
42
+ 'Missing chat credentials: provide --auth-token, THIRDFY_AUTH_TOKEN, or --owner-session-token.',
43
+ );
44
+ }
45
+
46
+ function buildChatRequestHeaders(flags, modelKey) {
47
+ const headers = {
48
+ 'content-type': 'application/json',
49
+ Accept: 'text/plain; charset=utf-8',
50
+ ...buildChatAuthHeaders(flags),
51
+ };
52
+ if (modelKey) {
53
+ headers['x-thirdfy-chat-model'] = modelKey;
54
+ }
55
+ const persona = String(flags.persona || 'thirdfy').trim();
56
+ if (persona) {
57
+ headers['x-thirdfy-chat-persona'] = persona;
58
+ }
59
+ return headers;
60
+ }
61
+
62
+ function resolveChatModelKey(flags, config) {
63
+ return (
64
+ String(flags.model || '').trim() ||
65
+ String(config?.chat?.defaultChatModel || '').trim() ||
66
+ ''
67
+ );
68
+ }
69
+
70
+ function resolveChatThreadId(flags, config) {
71
+ const explicit = String(flags.thread || flags.threadId || '').trim();
72
+ if (explicit) return explicit;
73
+ if (parseBooleanFlag(flags.continue, false)) {
74
+ return String(config?.chat?.lastThreadId || '').trim() || undefined;
75
+ }
76
+ return undefined;
77
+ }
78
+
79
+ function resolveUserAddress(flags, config) {
80
+ const explicit = String(flags.walletAddress || '').trim();
81
+ if (explicit) return explicit;
82
+ const wallets = config?.wallets && typeof config.wallets === 'object' ? config.wallets : {};
83
+ return String(wallets.primaryEvmWallet || '').trim() || undefined;
84
+ }
85
+
86
+ function parseToolDomains(flags) {
87
+ const raw = String(flags.toolDomains || '').trim();
88
+ if (!raw) return undefined;
89
+ const domains = raw
90
+ .split(',')
91
+ .map((entry) => entry.trim())
92
+ .filter(Boolean);
93
+ return domains.length ? domains : undefined;
94
+ }
95
+
96
+ function parseDataStreamLine(line) {
97
+ const trimmed = line.trim();
98
+ if (!trimmed) return null;
99
+
100
+ if (trimmed.startsWith('data: ')) {
101
+ try {
102
+ return safeJsonParse(trimmed.slice(6));
103
+ } catch {
104
+ return null;
105
+ }
106
+ }
107
+
108
+ const colonIndex = trimmed.indexOf(':');
109
+ if (colonIndex <= 0) return null;
110
+ const prefix = trimmed.slice(0, colonIndex);
111
+ const payload = trimmed.slice(colonIndex + 1);
112
+
113
+ if (prefix === '0') {
114
+ try {
115
+ return { type: 'text', value: String(JSON.parse(payload)) };
116
+ } catch {
117
+ return { type: 'text', value: payload };
118
+ }
119
+ }
120
+
121
+ if (prefix === '2') {
122
+ try {
123
+ const data = JSON.parse(payload);
124
+ return { type: 'data', value: Array.isArray(data) ? data : [data] };
125
+ } catch {
126
+ return null;
127
+ }
128
+ }
129
+
130
+ if (prefix === '3') {
131
+ try {
132
+ return { type: 'error', value: JSON.parse(payload) };
133
+ } catch {
134
+ return { type: 'error', value: payload };
135
+ }
136
+ }
137
+
138
+ return null;
139
+ }
140
+
141
+ function extractThreadMetaFromDataItems(items) {
142
+ if (!Array.isArray(items)) return null;
143
+ for (const item of items) {
144
+ if (item && typeof item === 'object' && item.type === 'thread_meta' && item.threadId) {
145
+ return item;
146
+ }
147
+ }
148
+ return null;
149
+ }
150
+
151
+ function parseThreadMetaHeader(raw) {
152
+ if (!raw) return null;
153
+ try {
154
+ const parsed = JSON.parse(raw);
155
+ if (parsed && typeof parsed === 'object' && parsed.type === 'thread_meta') {
156
+ return parsed;
157
+ }
158
+ if (parsed && typeof parsed === 'object' && parsed.threadId) {
159
+ return { type: 'thread_meta', ...parsed };
160
+ }
161
+ } catch {
162
+ return null;
163
+ }
164
+ return null;
165
+ }
166
+
167
+ async function requestChatStream(ctx, body, headers) {
168
+ const controller = new AbortController();
169
+ const timeoutMs = Math.max(Number(ctx.timeoutMs || 0), CHAT_STREAM_TIMEOUT_MS);
170
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
171
+
172
+ try {
173
+ const response = await fetch(`${ctx.apiBase}/api/v1/chat/stream`, {
174
+ method: 'POST',
175
+ headers,
176
+ body: JSON.stringify(body),
177
+ signal: controller.signal,
178
+ });
179
+
180
+ if (!response.ok) {
181
+ const text = await response.text().catch(() => '');
182
+ const data = text ? safeJsonParse(text) : {};
183
+ const error = new Error(data?.error || data?.message || `HTTP ${response.status}`);
184
+ error.statusCode = response.status;
185
+ error.payload = data;
186
+ throw error;
187
+ }
188
+
189
+ let threadMeta =
190
+ parseThreadMetaHeader(response.headers.get('X-Thirdfy-Chat-Thread-Meta')) || null;
191
+ let threadId = response.headers.get('X-Thirdfy-Chat-Thread-Id') || undefined;
192
+ let content = '';
193
+ let streamError = null;
194
+ const toolCalls = [];
195
+
196
+ if (response.body) {
197
+ const reader = response.body.getReader();
198
+ const decoder = new TextDecoder();
199
+ let lineBuffer = '';
200
+
201
+ while (true) {
202
+ const { done, value } = await reader.read();
203
+ if (done) break;
204
+ lineBuffer += decoder.decode(value, { stream: true });
205
+ const lines = lineBuffer.split('\n');
206
+ lineBuffer = lines.pop() ?? '';
207
+
208
+ for (const line of lines) {
209
+ const parsedLine = parseDataStreamLine(line);
210
+ if (!parsedLine) continue;
211
+
212
+ if (parsedLine.type === 'text') {
213
+ content += parsedLine.value;
214
+ continue;
215
+ }
216
+
217
+ if (parsedLine.type === 'error') {
218
+ streamError = String(parsedLine.value || 'stream error');
219
+ continue;
220
+ }
221
+
222
+ if (parsedLine.type === 'data') {
223
+ const meta = extractThreadMetaFromDataItems(parsedLine.value);
224
+ if (meta) {
225
+ threadMeta = meta;
226
+ if (meta.threadId) threadId = String(meta.threadId);
227
+ }
228
+ continue;
229
+ }
230
+
231
+ if (parsedLine.type === 'content' || parsedLine.type === 'text-delta') {
232
+ content += String(parsedLine.content || parsedLine.textDelta || parsedLine.text || '');
233
+ }
234
+ if (parsedLine.type === 'tool-call' && parsedLine.toolName) {
235
+ toolCalls.push(String(parsedLine.toolName));
236
+ }
237
+ if (parsedLine.type === 'data' && Array.isArray(parsedLine.data)) {
238
+ const meta = extractThreadMetaFromDataItems(parsedLine.data);
239
+ if (meta) {
240
+ threadMeta = meta;
241
+ if (meta.threadId) threadId = String(meta.threadId);
242
+ }
243
+ }
244
+ if (parsedLine.type === 'error') {
245
+ streamError = String(parsedLine.error || parsedLine.message || 'stream error');
246
+ }
247
+ if (parsedLine.type === 'done') {
248
+ const meta = parsedLine.thread_meta || parsedLine.threadMeta;
249
+ if (meta && typeof meta === 'object') {
250
+ threadMeta = meta;
251
+ if (meta.threadId) threadId = String(meta.threadId);
252
+ }
253
+ if (parsedLine.threadId) threadId = String(parsedLine.threadId);
254
+ }
255
+ const debug = parsedLine.debug;
256
+ if (debug && Array.isArray(debug.toolCallsList)) {
257
+ for (const item of debug.toolCallsList) toolCalls.push(String(item));
258
+ }
259
+ }
260
+ }
261
+
262
+ const tail = lineBuffer.trim();
263
+ if (tail) {
264
+ const parsedLine = parseDataStreamLine(tail);
265
+ if (parsedLine?.type === 'text') content += parsedLine.value;
266
+ if (parsedLine?.type === 'data') {
267
+ const meta = extractThreadMetaFromDataItems(parsedLine.value);
268
+ if (meta) {
269
+ threadMeta = meta;
270
+ if (meta.threadId) threadId = String(meta.threadId);
271
+ }
272
+ }
273
+ }
274
+ }
275
+
276
+ if (streamError) {
277
+ const error = new Error(streamError);
278
+ error.statusCode = 502;
279
+ throw error;
280
+ }
281
+
282
+ return {
283
+ content,
284
+ threadId: threadId || threadMeta?.threadId || body.threadId,
285
+ threadMeta,
286
+ toolCalls,
287
+ };
288
+ } finally {
289
+ clearTimeout(timeout);
290
+ }
291
+ }
292
+
293
+ function persistChatPreferences(config, { threadId, modelKey, chainId }) {
294
+ const next = {
295
+ ...config,
296
+ chat: {
297
+ ...(config.chat && typeof config.chat === 'object' ? config.chat : {}),
298
+ },
299
+ };
300
+ if (threadId) next.chat.lastThreadId = String(threadId);
301
+ if (modelKey) next.chat.defaultChatModel = String(modelKey);
302
+ if (chainId) next.chat.chainId = Number(chainId);
303
+ persistProfileConfig(next);
304
+ return next.chat;
305
+ }
306
+
307
+ export function createChatCommands({ printEnvelope }) {
308
+ async function commandChatSend(ctx, flags, _capabilities, messageArg) {
309
+ const message = String(messageArg || flags.message || '').trim();
310
+ if (!message) {
311
+ throw new Error('Missing message. Use: thirdfy-agent chat send "<message>"');
312
+ }
313
+
314
+ const config = loadProfileConfig();
315
+ const chainId = resolveChatChainId(flags, config);
316
+ const modelKey = resolveChatModelKey(flags, config);
317
+ const threadId = resolveChatThreadId(flags, config);
318
+ const userAddress = resolveUserAddress(flags, config);
319
+ const toolDomains = parseToolDomains(flags);
320
+
321
+ const body = {
322
+ messages: [{ role: 'user', content: message }],
323
+ chainId,
324
+ personaMode: String(flags.persona || 'thirdfy').trim() || 'thirdfy',
325
+ ...(threadId ? { threadId } : {}),
326
+ ...(modelKey ? { modelKey } : {}),
327
+ ...(userAddress ? { userAddress } : {}),
328
+ ...(toolDomains ? { toolDomains } : {}),
329
+ };
330
+
331
+ const headers = buildChatRequestHeaders(flags, modelKey);
332
+ const stream = await requestChatStream(ctx, body, headers);
333
+
334
+ const resolvedThreadId = stream.threadId || threadId;
335
+ const resolvedModelKey = stream.threadMeta?.modelKey || modelKey;
336
+ const persisted = persistChatPreferences(config, {
337
+ threadId: resolvedThreadId,
338
+ modelKey: resolvedModelKey,
339
+ chainId,
340
+ });
341
+
342
+ if (!flags.json && stream.content) {
343
+ process.stdout.write(stream.content);
344
+ if (!stream.content.endsWith('\n')) process.stdout.write('\n');
345
+ }
346
+
347
+ const threadLabel = resolvedThreadId ? ` (thread ${resolvedThreadId})` : '';
348
+ printEnvelope({
349
+ success: true,
350
+ code: 'CHAT_SEND_OK',
351
+ message: flags.json ? 'Chat response completed' : `Chat response completed${threadLabel}`,
352
+ data: {
353
+ ...(flags.json ? { content: stream.content } : {}),
354
+ threadId: resolvedThreadId || null,
355
+ threadMeta: stream.threadMeta || null,
356
+ toolCalls: stream.toolCalls,
357
+ modelKey: resolvedModelKey || null,
358
+ chainId,
359
+ persisted,
360
+ },
361
+ meta: {
362
+ apiBase: ctx.apiBase,
363
+ continued: parseBooleanFlag(flags.continue, false),
364
+ network: flags.network || null,
365
+ },
366
+ });
367
+ }
368
+
369
+ async function commandChatThreads(ctx, flags) {
370
+ const headers = buildChatAuthHeaders(flags);
371
+ const query = new URLSearchParams();
372
+ if (flags.limit) query.set('limit', String(flags.limit));
373
+ if (flags.status) query.set('status', String(flags.status));
374
+ const route = query.size
375
+ ? `/api/v1/chat/threads?${query.toString()}`
376
+ : '/api/v1/chat/threads';
377
+ const response = await apiGet(ctx, route, headers);
378
+ printEnvelope({
379
+ success: true,
380
+ code: 'CHAT_THREADS_OK',
381
+ message: 'Chat threads loaded',
382
+ data: response,
383
+ meta: { apiBase: ctx.apiBase },
384
+ });
385
+ }
386
+
387
+ async function commandChatModels(ctx, flags) {
388
+ const headers = buildChatAuthHeaders(flags);
389
+ const response = await apiGet(ctx, '/api/v1/chat/models', headers);
390
+ printEnvelope({
391
+ success: true,
392
+ code: 'CHAT_MODELS_OK',
393
+ message: 'Chat models loaded',
394
+ data: response,
395
+ meta: { apiBase: ctx.apiBase },
396
+ });
397
+ }
398
+
399
+ return {
400
+ commandChatSend,
401
+ commandChatThreads,
402
+ commandChatModels,
403
+ };
404
+ }
@@ -1,5 +1,9 @@
1
1
  import { requireFlag } from '../core/args.mjs';
2
2
  import { apiGet, apiPost } from '../core/http.mjs';
3
+ import {
4
+ formatCreditsEstimateSummary,
5
+ formatCreditsModelsSummary,
6
+ } from '../lib/creditsUsdSummary.mjs';
3
7
 
4
8
  function resolveToolCallsEstimate(flags) {
5
9
  const raw = flags.toolCalls ?? flags.toolCallsList;
@@ -67,10 +71,7 @@ export function createCreditsCommands({ printEnvelope, getAuthToken }) {
67
71
  const response = await apiGet(ctx, '/api/v1/credits/pricing/models', {
68
72
  Authorization: `Bearer ${authToken}`,
69
73
  });
70
- const firstModel = response?.models?.[0];
71
- const summary = firstModel?.estimatedUsdPerTurn != null
72
- ? `${response?.models?.length ?? 0} models · e.g. ${firstModel.modelKey} ~$${Number(firstModel.estimatedUsdPerTurn).toFixed(2)}/turn`
73
- : `${response?.models?.length ?? 0} models loaded`;
74
+ const summary = formatCreditsModelsSummary(response);
74
75
  printEnvelope({
75
76
  success: true,
76
77
  code: 'OK',
@@ -99,9 +100,7 @@ export function createCreditsCommands({ printEnvelope, getAuthToken }) {
99
100
  { Authorization: `Bearer ${authToken}` },
100
101
  );
101
102
  const estimate = response?.estimate;
102
- const summary = estimate?.chargedUsd != null
103
- ? `~$${Number(estimate.chargedUsd).toFixed(2)} charged (${estimate.chargedCredits ?? estimate.totalCredits} credits)`
104
- : `${estimate?.chargedCredits ?? estimate?.totalCredits ?? '?'} credits`;
103
+ const summary = formatCreditsEstimateSummary(estimate);
105
104
  printEnvelope({
106
105
  success: true,
107
106
  code: 'OK',
@@ -2,6 +2,7 @@ import { requireFlag, parseJsonFlag } from '../core/args.mjs';
2
2
  import { apiGet, apiPost } from '../core/http.mjs';
3
3
  import { extractActions, getCachedActionsCatalog } from '../core/context.mjs';
4
4
  import { getEffectiveRunMode } from '../core/runMode.mjs';
5
+ import { formatCreditsBalanceSummary } from '../lib/creditsUsdSummary.mjs';
5
6
  export function createDiscoveryCommands({ printEnvelope, applyActionFilters, getTradingProviderHint, resolveChainSupport, getAuthToken, resolveAgentApiKey }) {
6
7
  async function commandCatalogsList(ctx, flags, capabilities) {
7
8
  const response = await apiGet(ctx, '/api/v1/agent/actions/catalog');
@@ -57,10 +58,7 @@ async function commandCreditsBalance(ctx, flags, capabilities) {
57
58
  const response = await apiGet(ctx, '/api/v1/credits/balance', {
58
59
  Authorization: `Bearer ${authToken}`,
59
60
  });
60
- const summary =
61
- typeof response?.availableUsd === 'number'
62
- ? `$${response.availableUsd.toFixed(2)} available (${response.balance ?? 0} credits)`
63
- : `${response?.balance ?? 0} credits`;
61
+ const summary = formatCreditsBalanceSummary(response);
64
62
  printEnvelope({
65
63
  success: true,
66
64
  code: 'OK',
@@ -0,0 +1,110 @@
1
+ import { apiGet, apiPost } from '../core/http.mjs';
2
+ import { loadProfileConfig } from '../core/context.mjs';
3
+
4
+ const VENUES = new Set(['polymarket', 'hyperliquid', 'lighter']);
5
+
6
+ function resolveVenue(flags) {
7
+ const fromQuery = Array.isArray(flags.query) ? flags.query[0] : flags.query;
8
+ const venue = String(flags.venue || fromQuery || '').trim().toLowerCase();
9
+ if (!VENUES.has(venue)) {
10
+ throw new Error(`Unsupported venue "${venue}". Use polymarket, hyperliquid, or lighter.`);
11
+ }
12
+ return venue;
13
+ }
14
+
15
+ function extractAgentKey(value) {
16
+ if (!value || typeof value !== 'object') return '';
17
+ const candidates = [
18
+ value.agentKey,
19
+ value.data?.agentKey,
20
+ value.bootstrap?.agentKey,
21
+ value.registration?.agentKey,
22
+ value.registration?.registration?.agentKey,
23
+ value.data?.registration?.agentKey,
24
+ value.data?.registration?.registration?.agentKey,
25
+ value.owner?.creatorWallet,
26
+ value.data?.owner?.creatorWallet,
27
+ ];
28
+ return String(candidates.find((candidate) => String(candidate || '').trim()) || '').trim();
29
+ }
30
+
31
+ function resolveVenueAgentKey(flags) {
32
+ const fromFlags = String(flags.agentKey || '').trim();
33
+ if (fromFlags) return fromFlags;
34
+ const config = loadProfileConfig();
35
+ const fromAgent = String(config?.agent?.agentKey || '').trim();
36
+ if (fromAgent) return fromAgent;
37
+ const fromConfig = extractAgentKey(config);
38
+ if (fromConfig) return fromConfig;
39
+ throw new Error('Missing --agent-key (or config.agent.agentKey). Venue tooling uses --agent-api-key only for authentication.');
40
+ }
41
+
42
+ function buildAgentQuery(agentKey, flags) {
43
+ const query = new URLSearchParams({ agentKey });
44
+ if (flags.mainWalletAddress) query.set('mainWalletAddress', String(flags.mainWalletAddress));
45
+ if (flags.apiWalletAddress) query.set('apiWalletAddress', String(flags.apiWalletAddress));
46
+ if (flags.l1Address) query.set('l1Address', String(flags.l1Address));
47
+ if (flags.amountUsd) query.set('amountUsd', String(flags.amountUsd));
48
+ if (flags.includeGeoblock === false) query.set('includeGeoblock', 'false');
49
+ return query;
50
+ }
51
+
52
+ export function createVenueCommands({ printEnvelope, resolveAgentApiKey }) {
53
+ function buildAuthHeaders(flags) {
54
+ const agentApiKey = resolveAgentApiKey(flags, flags.runMode || 'agent_wallet');
55
+ return { 'x-agent-api-key': agentApiKey };
56
+ }
57
+
58
+ async function commandVenueReadiness(ctx, flags) {
59
+ const venue = resolveVenue(flags);
60
+ const agentKey = resolveVenueAgentKey(flags);
61
+ const query = buildAgentQuery(agentKey, flags);
62
+ query.set('venue', venue);
63
+ const response = await apiGet(ctx, `/api/v1/agent/venue/readiness?${query.toString()}`, buildAuthHeaders(flags));
64
+ printEnvelope(response);
65
+ }
66
+
67
+ async function commandVenueSetup(ctx, flags) {
68
+ const venue = resolveVenue(flags);
69
+ const agentKey = resolveVenueAgentKey(flags);
70
+ const complete = Boolean(flags.complete);
71
+ const confirmWrites = Boolean(flags.confirmWrites);
72
+ const body = {
73
+ venue,
74
+ agentKey,
75
+ dryRun: complete ? false : !confirmWrites,
76
+ confirmWrites,
77
+ ...(flags.mainWalletAddress ? { mainWalletAddress: String(flags.mainWalletAddress) } : {}),
78
+ ...(flags.apiWalletAddress ? { apiWalletAddress: String(flags.apiWalletAddress) } : {}),
79
+ ...(flags.l1Address ? { l1Address: String(flags.l1Address) } : {}),
80
+ ...(flags.amountUsd ? { amountUsd: Number(flags.amountUsd) } : {}),
81
+ };
82
+ const path = flags.complete ? '/api/v1/agent/venue/complete' : '/api/v1/agent/venue/prepare';
83
+ const response = await apiPost(ctx, path, body, buildAuthHeaders(flags));
84
+ printEnvelope(response);
85
+ }
86
+
87
+ async function commandVenueFund(ctx, flags) {
88
+ const venue = resolveVenue(flags);
89
+ const agentKey = resolveVenueAgentKey(flags);
90
+ const amountUsd = Number(flags.amount || flags.amountUsd || 0);
91
+ if (!Number.isFinite(amountUsd) || amountUsd <= 0) {
92
+ throw new Error('Provide --amount with a positive USD value.');
93
+ }
94
+ const response = await apiPost(ctx, '/api/v1/agent/venue/fund', {
95
+ venue,
96
+ agentKey,
97
+ amountUsd,
98
+ ...(flags.mainWalletAddress ? { mainWalletAddress: String(flags.mainWalletAddress) } : {}),
99
+ ...(flags.apiWalletAddress ? { apiWalletAddress: String(flags.apiWalletAddress) } : {}),
100
+ ...(flags.l1Address ? { l1Address: String(flags.l1Address) } : {}),
101
+ }, buildAuthHeaders(flags));
102
+ printEnvelope(response);
103
+ }
104
+
105
+ return {
106
+ commandVenueReadiness,
107
+ commandVenueSetup,
108
+ commandVenueFund,
109
+ };
110
+ }
@@ -0,0 +1,21 @@
1
+ export function formatCreditsBalanceSummary(response) {
2
+ if (typeof response?.availableUsd === 'number') {
3
+ return `$${response.availableUsd.toFixed(2)} available (${response.balance ?? 0} credits)`;
4
+ }
5
+ return `${response?.balance ?? 0} credits`;
6
+ }
7
+
8
+ export function formatCreditsModelsSummary(response) {
9
+ const firstModel = response?.models?.[0];
10
+ if (firstModel?.estimatedUsdPerTurn != null) {
11
+ return `${response?.models?.length ?? 0} models · e.g. ${firstModel.modelKey} ~$${Number(firstModel.estimatedUsdPerTurn).toFixed(2)}/turn`;
12
+ }
13
+ return `${response?.models?.length ?? 0} models loaded`;
14
+ }
15
+
16
+ export function formatCreditsEstimateSummary(estimate) {
17
+ if (estimate?.chargedUsd != null) {
18
+ return `~$${Number(estimate.chargedUsd).toFixed(2)} charged (${estimate.chargedCredits ?? estimate.totalCredits} credits)`;
19
+ }
20
+ return `${estimate?.chargedCredits ?? estimate?.totalCredits ?? '?'} credits`;
21
+ }
@@ -9,11 +9,14 @@ import { createDelegationCommands } from '../commands/delegation.mjs';
9
9
  import { createBootstrapCommands } from '../commands/bootstrap.mjs';
10
10
  import { createDiscoveryCommands } from '../commands/discovery.mjs';
11
11
  import { createCreditsCommands } from '../commands/credits.mjs';
12
+ import { createChatCommands } from '../commands/chat.mjs';
13
+ import { createBrainCommands } from '../commands/brain.mjs';
12
14
  import { createTelemetryCommands } from '../commands/telemetry.mjs';
13
15
  import { createCredentialsCommands } from '../commands/credentials.mjs';
14
16
  import { createAgentCommands } from '../commands/agent.mjs';
15
17
  import { createDoctorCommands } from '../commands/doctor.mjs';
16
18
  import { createPromptCommands } from '../commands/prompt.mjs';
19
+ import { createVenueCommands } from '../commands/venue.mjs';
17
20
 
18
21
  /**
19
22
  * Wire command-module factories and local handlers for Commander manifest registration.
@@ -62,6 +65,14 @@ export function createRuntimeHandlers(deps) {
62
65
  getAuthToken,
63
66
  });
64
67
 
68
+ const __chat = createChatCommands({
69
+ printEnvelope,
70
+ });
71
+
72
+ const __brain = createBrainCommands({
73
+ printEnvelope,
74
+ });
75
+
65
76
  const __telemetry = createTelemetryCommands({
66
77
  printEnvelope,
67
78
  resolveAgentApiKey,
@@ -94,6 +105,7 @@ export function createRuntimeHandlers(deps) {
94
105
  });
95
106
 
96
107
  const __prompt = createPromptCommands({ printEnvelope });
108
+ const __venue = createVenueCommands({ printEnvelope, resolveAgentApiKey });
97
109
 
98
110
  const __hyperliquid = createHyperliquidHelpers({
99
111
  getPreparedParams,
@@ -157,6 +169,8 @@ export function createRuntimeHandlers(deps) {
157
169
  printEnvelope,
158
170
  extractAgentApiKey,
159
171
  extractAgentKey,
172
+ maskSecret,
173
+ buildOwnerAuthHeaders,
160
174
  buildOnboardingHelp: __doctor.buildOnboardingHelp,
161
175
  buildWalletChallengePayload: __agent.buildWalletChallengePayload,
162
176
  issueBootstrapToken: __agent.issueBootstrapToken,
@@ -179,6 +193,7 @@ export function createRuntimeHandlers(deps) {
179
193
  ...__agent,
180
194
  ...__doctor,
181
195
  ...__prompt,
196
+ ...__venue,
182
197
  commandDoctorSelf: __doctor.commandDoctorSelf,
183
198
  commandDoctorAuth: __doctor.commandDoctorAuth,
184
199
  commandManagedSetup: __doctor.commandManagedSetup,
@@ -190,6 +205,13 @@ export function createRuntimeHandlers(deps) {
190
205
  commandModelsList: __credits.commandModelsList,
191
206
  commandModelsEstimate: __credits.commandModelsEstimate,
192
207
  commandPricingQuote: __credits.commandPricingQuote,
208
+ commandChatSend: __chat.commandChatSend,
209
+ commandChatThreads: __chat.commandChatThreads,
210
+ commandChatModels: __chat.commandChatModels,
211
+ commandBrainSections: __brain.commandBrainSections,
212
+ commandBrainSuggest: __brain.commandBrainSuggest,
213
+ commandBrainPreflight: __brain.commandBrainPreflight,
214
+ commandBrainGraduate: __brain.commandBrainGraduate,
193
215
  commandDataSummary: __telemetry.commandDataSummary,
194
216
  commandTrackList: __telemetry.commandTrackList,
195
217
  commandTrackAction: __telemetry.commandTrackAction,
@@ -203,5 +225,8 @@ export function createRuntimeHandlers(deps) {
203
225
  commandAnalyticsPortfolio: __telemetry.commandAnalyticsPortfolio,
204
226
  commandAnalyticsLeaderboard: __telemetry.commandAnalyticsLeaderboard,
205
227
  commandPrompt: __prompt.commandPrompt,
228
+ commandVenueReadiness: __venue.commandVenueReadiness,
229
+ commandVenueSetup: __venue.commandVenueSetup,
230
+ commandVenueFund: __venue.commandVenueFund,
206
231
  };
207
232
  }