@exagent/agent 0.3.3 → 0.3.5

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.
Files changed (149) hide show
  1. package/dist/{chunk-F4TCYYTD.js → chunk-WTECTX2Z.js} +13 -1
  2. package/dist/cli.js +235 -80
  3. package/dist/index.js +1 -1
  4. package/package.json +1 -1
  5. package/src/cli.ts +125 -3
  6. package/src/config.ts +18 -1
  7. package/src/llm-providers.ts +100 -0
  8. package/src/setup.ts +48 -65
  9. package/dist/chunk-25J5ZDKX.js +0 -5622
  10. package/dist/chunk-2ML4XS5X.js +0 -5626
  11. package/dist/chunk-2OKYNZ3J.js +0 -5622
  12. package/dist/chunk-2PAASZJN.js +0 -5132
  13. package/dist/chunk-2WAYVOLU.js +0 -5624
  14. package/dist/chunk-2XBVVY3I.js +0 -5621
  15. package/dist/chunk-37HCPVBZ.js +0 -2941
  16. package/dist/chunk-3DZAZBLF.js +0 -5652
  17. package/dist/chunk-3IXCKNSV.js +0 -5008
  18. package/dist/chunk-3MXFTRXB.js +0 -3326
  19. package/dist/chunk-4MURFLNJ.js +0 -5136
  20. package/dist/chunk-4UVMO6ZM.js +0 -6318
  21. package/dist/chunk-56YQROFU.js +0 -5639
  22. package/dist/chunk-5B3ZEGMD.js +0 -4330
  23. package/dist/chunk-5NU6FDDE.js +0 -6020
  24. package/dist/chunk-5WADKPJU.js +0 -1552
  25. package/dist/chunk-6LOIFEEV.js +0 -4895
  26. package/dist/chunk-6YIXPNL4.js +0 -5626
  27. package/dist/chunk-72HK2V74.js +0 -5224
  28. package/dist/chunk-7Q72QQIV.js +0 -4697
  29. package/dist/chunk-7V3XTBIF.js +0 -4896
  30. package/dist/chunk-A4CM4F7Q.js +0 -5633
  31. package/dist/chunk-ADXXR2MA.js +0 -4816
  32. package/dist/chunk-AG6CJPIC.js +0 -4895
  33. package/dist/chunk-AJPXHBTF.js +0 -4459
  34. package/dist/chunk-AQ6R37XV.js +0 -4809
  35. package/dist/chunk-AS4UEZMU.js +0 -5001
  36. package/dist/chunk-ASYMD22Y.js +0 -5624
  37. package/dist/chunk-AU4MCQCE.js +0 -5624
  38. package/dist/chunk-B4VHIITU.js +0 -5748
  39. package/dist/chunk-B6GVDNKQ.js +0 -5624
  40. package/dist/chunk-BCIAW6ZL.js +0 -5132
  41. package/dist/chunk-BJZ5PCG3.js +0 -5358
  42. package/dist/chunk-BS4J5QSM.js +0 -5622
  43. package/dist/chunk-BV2AUUX6.js +0 -2940
  44. package/dist/chunk-BWNSH2LK.js +0 -1574
  45. package/dist/chunk-C3GMBW3R.js +0 -5640
  46. package/dist/chunk-C6CVQGJ4.js +0 -5624
  47. package/dist/chunk-CGXKXNUJ.js +0 -5626
  48. package/dist/chunk-CIEZAYOU.js +0 -4701
  49. package/dist/chunk-CORZCEAQ.js +0 -5621
  50. package/dist/chunk-CS5LGZWP.js +0 -5357
  51. package/dist/chunk-CVT3KC24.js +0 -5624
  52. package/dist/chunk-D5MJ45R7.js +0 -3258
  53. package/dist/chunk-DSBRZ5DZ.js +0 -5624
  54. package/dist/chunk-E2X7JARQ.js +0 -4437
  55. package/dist/chunk-E3GY36ZP.js +0 -3258
  56. package/dist/chunk-E6NCIFKB.js +0 -4733
  57. package/dist/chunk-EOXLKW4D.js +0 -4895
  58. package/dist/chunk-FCI7LX4Q.js +0 -5624
  59. package/dist/chunk-FFJSKTOL.js +0 -4539
  60. package/dist/chunk-FOQYP3IB.js +0 -2950
  61. package/dist/chunk-GNEYTZDH.js +0 -4686
  62. package/dist/chunk-GPMXUMYH.js +0 -5991
  63. package/dist/chunk-GZWPAQPU.js +0 -4593
  64. package/dist/chunk-H5DXDKMX.js +0 -5619
  65. package/dist/chunk-HFQRTMS6.js +0 -3377
  66. package/dist/chunk-HQKRHX6Y.js +0 -5626
  67. package/dist/chunk-HTF3TNBY.js +0 -4834
  68. package/dist/chunk-IADSQBBY.js +0 -5523
  69. package/dist/chunk-IE2SXMZK.js +0 -4890
  70. package/dist/chunk-IGUQVJCB.js +0 -5622
  71. package/dist/chunk-IIREL7SL.js +0 -5615
  72. package/dist/chunk-IJK4EFTJ.js +0 -6043
  73. package/dist/chunk-J2MQ3Y5O.js +0 -5223
  74. package/dist/chunk-J3NG7AGT.js +0 -6047
  75. package/dist/chunk-JIBBZ3NV.js +0 -5132
  76. package/dist/chunk-JIPSBE6S.js +0 -5622
  77. package/dist/chunk-JPG755XK.js +0 -4589
  78. package/dist/chunk-JQBNL5GX.js +0 -5230
  79. package/dist/chunk-KS3F5WSX.js +0 -4831
  80. package/dist/chunk-KUYTQ4FR.js +0 -4808
  81. package/dist/chunk-KVP4CMJ5.js +0 -4711
  82. package/dist/chunk-LAR2I44B.js +0 -5626
  83. package/dist/chunk-LBTHSED2.js +0 -1531
  84. package/dist/chunk-M6OAMYVM.js +0 -5621
  85. package/dist/chunk-MFN5WWOY.js +0 -5132
  86. package/dist/chunk-MMTSKXLK.js +0 -5624
  87. package/dist/chunk-MPUSQLTH.js +0 -5626
  88. package/dist/chunk-MREXDTWL.js +0 -1555
  89. package/dist/chunk-MUEDKRFC.js +0 -5624
  90. package/dist/chunk-NOVPL2JH.js +0 -3327
  91. package/dist/chunk-NQIP4MHV.js +0 -4334
  92. package/dist/chunk-NXXKMYLS.js +0 -5624
  93. package/dist/chunk-OBYNZXNM.js +0 -4756
  94. package/dist/chunk-OFY4HBOJ.js +0 -5624
  95. package/dist/chunk-OJNUEZEK.js +0 -5602
  96. package/dist/chunk-OQCJOMUQ.js +0 -5624
  97. package/dist/chunk-OZH75GY6.js +0 -5132
  98. package/dist/chunk-P3IJVDMZ.js +0 -4700
  99. package/dist/chunk-PMYMYMBH.js +0 -4877
  100. package/dist/chunk-PRELNRVN.js +0 -5623
  101. package/dist/chunk-PSQUSNSI.js +0 -4703
  102. package/dist/chunk-QAIQ5IB6.js +0 -5624
  103. package/dist/chunk-QG22GADV.js +0 -6316
  104. package/dist/chunk-QNE2KGGK.js +0 -3315
  105. package/dist/chunk-RH7ZBSG4.js +0 -5132
  106. package/dist/chunk-RLD5MUCR.js +0 -5626
  107. package/dist/chunk-S42VEBNR.js +0 -3268
  108. package/dist/chunk-SEM6UXU4.js +0 -3324
  109. package/dist/chunk-SI5WP77M.js +0 -4430
  110. package/dist/chunk-SID4SQSY.js +0 -4837
  111. package/dist/chunk-SIELPKWF.js +0 -1558
  112. package/dist/chunk-SVBLY6QT.js +0 -5742
  113. package/dist/chunk-SVFTC5V2.js +0 -6021
  114. package/dist/chunk-SXHTX62B.js +0 -4823
  115. package/dist/chunk-T2YCEA5U.js +0 -4730
  116. package/dist/chunk-TARCHIOU.js +0 -4718
  117. package/dist/chunk-TDACLKD7.js +0 -5867
  118. package/dist/chunk-TGCBM3NP.js +0 -4890
  119. package/dist/chunk-TIWG6KAK.js +0 -4769
  120. package/dist/chunk-TKLKATVM.js +0 -1534
  121. package/dist/chunk-TSLZ4A5P.js +0 -5222
  122. package/dist/chunk-TWSDKORW.js +0 -4698
  123. package/dist/chunk-U5QHYVMJ.js +0 -3341
  124. package/dist/chunk-UAP5CTHB.js +0 -5985
  125. package/dist/chunk-UK6SEUWU.js +0 -3210
  126. package/dist/chunk-UKU5YO65.js +0 -5132
  127. package/dist/chunk-UOZQXP4Q.js +0 -5144
  128. package/dist/chunk-UPTN2TSS.js +0 -4727
  129. package/dist/chunk-UQT2APOE.js +0 -2944
  130. package/dist/chunk-V32QDZKW.js +0 -5132
  131. package/dist/chunk-VDK4XPAC.js +0 -6318
  132. package/dist/chunk-VKY2CDCD.js +0 -5622
  133. package/dist/chunk-VUCSYMCY.js +0 -3323
  134. package/dist/chunk-VVLNBD5Y.js +0 -5132
  135. package/dist/chunk-W3TQ22O6.js +0 -4459
  136. package/dist/chunk-WA4DSGOM.js +0 -3355
  137. package/dist/chunk-WI6MIICK.js +0 -4687
  138. package/dist/chunk-XHYHRJMK.js +0 -6319
  139. package/dist/chunk-XRHJLL74.js +0 -4893
  140. package/dist/chunk-XXWXEBJQ.js +0 -4885
  141. package/dist/chunk-YC6TH2H3.js +0 -5624
  142. package/dist/chunk-YDH6HCUJ.js +0 -5624
  143. package/dist/chunk-YJD35VKQ.js +0 -4890
  144. package/dist/chunk-YTZ5MZLP.js +0 -6318
  145. package/dist/chunk-ZBIQJBY7.js +0 -5620
  146. package/dist/chunk-ZKTSA2AE.js +0 -5629
  147. package/dist/chunk-ZKZZL3PE.js +0 -3379
  148. package/dist/chunk-ZM5KCPRK.js +0 -4541
  149. package/dist/chunk-ZTYPDSE3.js +0 -3258
@@ -0,0 +1,100 @@
1
+ /**
2
+ * LLM provider and model registry.
3
+ * Keep in sync with apps/web/src/lib/llm-providers.ts.
4
+ */
5
+
6
+ export interface LlmModel {
7
+ id: string;
8
+ label: string;
9
+ }
10
+
11
+ export interface LlmProvider {
12
+ id: string;
13
+ label: string;
14
+ models: LlmModel[];
15
+ }
16
+
17
+ export const LLM_PROVIDERS: LlmProvider[] = [
18
+ {
19
+ id: 'openai',
20
+ label: 'OpenAI',
21
+ models: [
22
+ { id: 'gpt-5.2', label: 'GPT-5.2' },
23
+ { id: 'gpt-5.2-pro', label: 'GPT-5.2 Pro' },
24
+ { id: 'gpt-5-mini', label: 'GPT-5 Mini' },
25
+ { id: 'gpt-5-nano', label: 'GPT-5 Nano' },
26
+ { id: 'gpt-4o', label: 'GPT-4o' },
27
+ { id: 'gpt-4o-mini', label: 'GPT-4o Mini' },
28
+ ],
29
+ },
30
+ {
31
+ id: 'anthropic',
32
+ label: 'Anthropic',
33
+ models: [
34
+ { id: 'claude-opus-4-6', label: 'Claude Opus 4.6' },
35
+ { id: 'claude-sonnet-4-6', label: 'Claude Sonnet 4.6' },
36
+ { id: 'claude-haiku-4-5', label: 'Claude Haiku 4.5' },
37
+ ],
38
+ },
39
+ {
40
+ id: 'google',
41
+ label: 'Google',
42
+ models: [
43
+ { id: 'gemini-3-pro', label: 'Gemini 3 Pro' },
44
+ { id: 'gemini-3-flash', label: 'Gemini 3 Flash' },
45
+ { id: 'gemini-2.5-pro', label: 'Gemini 2.5 Pro' },
46
+ { id: 'gemini-2.5-flash', label: 'Gemini 2.5 Flash' },
47
+ { id: 'gemini-2.5-flash-lite', label: 'Gemini 2.5 Flash Lite' },
48
+ ],
49
+ },
50
+ {
51
+ id: 'deepseek',
52
+ label: 'DeepSeek',
53
+ models: [
54
+ { id: 'deepseek-chat', label: 'DeepSeek Chat' },
55
+ { id: 'deepseek-reasoner', label: 'DeepSeek Reasoner' },
56
+ ],
57
+ },
58
+ {
59
+ id: 'mistral',
60
+ label: 'Mistral',
61
+ models: [
62
+ { id: 'mistral-large-latest', label: 'Mistral Large' },
63
+ { id: 'mistral-small-latest', label: 'Mistral Small' },
64
+ ],
65
+ },
66
+ {
67
+ id: 'groq',
68
+ label: 'Groq',
69
+ models: [
70
+ { id: 'llama-3.3-70b-versatile', label: 'Llama 3.3 70B' },
71
+ { id: 'llama-3.1-8b-instant', label: 'Llama 3.1 8B' },
72
+ { id: 'mixtral-8x7b-32768', label: 'Mixtral 8x7B' },
73
+ ],
74
+ },
75
+ {
76
+ id: 'together',
77
+ label: 'Together',
78
+ models: [
79
+ { id: 'meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo', label: 'Llama 3.1 70B' },
80
+ { id: 'meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo', label: 'Llama 3.1 8B' },
81
+ ],
82
+ },
83
+ {
84
+ id: 'ollama',
85
+ label: 'Ollama (local)',
86
+ models: [
87
+ { id: 'llama3.1', label: 'Llama 3.1' },
88
+ { id: 'mistral', label: 'Mistral' },
89
+ { id: 'custom', label: 'Custom (type model name)' },
90
+ ],
91
+ },
92
+ ];
93
+
94
+ export function getProvider(id: string): LlmProvider | undefined {
95
+ return LLM_PROVIDERS.find((p) => p.id === id);
96
+ }
97
+
98
+ export function getProviderIds(): string[] {
99
+ return LLM_PROVIDERS.map((p) => p.id);
100
+ }
package/src/setup.ts CHANGED
@@ -146,21 +146,19 @@ async function setupWallet(config: RuntimeConfigFile): Promise<string> {
146
146
  // Step 3: LLM
147
147
  // ---------------------------------------------------------------------------
148
148
 
149
- const LLM_PROVIDERS = ['openai', 'anthropic', 'google', 'deepseek', 'mistral', 'groq', 'together', 'ollama'] as const;
149
+ import { LLM_PROVIDERS, getProvider } from './llm-providers.js';
150
150
 
151
151
  async function setupLlm(
152
152
  config: RuntimeConfigFile,
153
- bootstrapPayload: BootstrapPayload,
154
153
  ): Promise<{ provider: string; model: string; apiKey: string }> {
155
- // D8: If bootstrap has no LLM payload AND config has no real apiKey,
156
- // the config's provider/model are just wizard defaults don't trust them.
157
- const hasRealLlmConfig = !!(bootstrapPayload.llm?.apiKey || config.llm?.apiKey);
154
+ // LLM config is always entered locally never pulled from bootstrap.
155
+ // Config file may have provider/model as defaults from the deploy wizard.
158
156
 
159
157
  // Non-interactive mode
160
158
  if (isNonInteractive()) {
161
- const provider = process.env.EXAGENT_LLM_PROVIDER || bootstrapPayload.llm?.provider || (hasRealLlmConfig ? config.llm?.provider : undefined);
162
- const model = process.env.EXAGENT_LLM_MODEL || bootstrapPayload.llm?.model || (hasRealLlmConfig ? config.llm?.model : undefined);
163
- const apiKey = process.env.EXAGENT_LLM_KEY || bootstrapPayload.llm?.apiKey || config.llm?.apiKey;
159
+ const provider = process.env.EXAGENT_LLM_PROVIDER || config.llm?.provider;
160
+ const model = process.env.EXAGENT_LLM_MODEL || config.llm?.model;
161
+ const apiKey = process.env.EXAGENT_LLM_KEY;
164
162
  if (!provider) throw new Error('EXAGENT_LLM_PROVIDER required in non-interactive mode');
165
163
  if (!model) throw new Error('EXAGENT_LLM_MODEL required in non-interactive mode');
166
164
  if (!apiKey) throw new Error('EXAGENT_LLM_KEY required in non-interactive mode');
@@ -168,58 +166,37 @@ async function setupLlm(
168
166
  return { provider, model, apiKey };
169
167
  }
170
168
 
171
- // Provider — only trust config value if we have a real LLM config
172
- let provider = bootstrapPayload.llm?.provider || (hasRealLlmConfig ? config.llm?.provider : undefined);
173
- if (provider) {
174
- printInfo(`Provider: ${pc.cyan(provider)} ${pc.dim('(from dashboard)')}`);
175
- } else {
176
- const selected = await clack.select({
177
- message: 'LLM provider:',
178
- options: LLM_PROVIDERS.map(p => ({ value: p, label: p })),
179
- });
180
- if (clack.isCancel(selected)) cancelled();
181
- provider = selected;
182
- }
183
-
184
- // Model only trust config value if we have a real LLM config
185
- let model = bootstrapPayload.llm?.model || (hasRealLlmConfig ? config.llm?.model : undefined);
186
- if (model) {
187
- printInfo(`Model: ${pc.cyan(model)} ${pc.dim('(from dashboard)')}`);
188
- } else {
189
- const entered = await clack.text({
190
- message: 'LLM model:',
191
- placeholder: 'gpt-4o',
192
- validate: (val) => {
193
- if (!val.trim()) return 'Model name is required.';
194
- },
195
- });
196
- if (clack.isCancel(entered)) cancelled();
197
- model = entered;
198
- }
169
+ // Provider — use config as default selection if available
170
+ const defaultProvider = config.llm?.provider;
171
+ const providerOptions = LLM_PROVIDERS.map(p => ({ value: p.id, label: p.label }));
172
+ const selected = await clack.select({
173
+ message: 'LLM provider:',
174
+ options: providerOptions,
175
+ initialValue: defaultProvider || undefined,
176
+ });
177
+ if (clack.isCancel(selected)) cancelled();
178
+ const provider = selected;
179
+
180
+ // Model — show available models for the selected provider
181
+ const defaultModel = config.llm?.model;
182
+ const providerInfo = getProvider(provider);
183
+ const modelOptions = providerInfo
184
+ ? providerInfo.models.map(m => ({ value: m.id, label: m.label }))
185
+ : [{ value: defaultModel || 'gpt-4o', label: defaultModel || 'gpt-4o' }];
186
+ const selectedModel = await clack.select({
187
+ message: 'LLM model:',
188
+ options: modelOptions,
189
+ initialValue: defaultModel || undefined,
190
+ });
191
+ if (clack.isCancel(selectedModel)) cancelled();
192
+ const model = selectedModel;
199
193
 
200
- // API Key
201
- let apiKey: string | undefined;
202
- if (bootstrapPayload.llm?.apiKey) {
203
- const useBootstrap = await clack.confirm({
204
- message: 'LLM API key received from dashboard. Use it?',
205
- initialValue: true,
206
- });
207
- if (clack.isCancel(useBootstrap)) cancelled();
208
- if (useBootstrap) {
209
- apiKey = bootstrapPayload.llm.apiKey;
210
- }
211
- }
212
- if (!apiKey) {
213
- apiKey = config.llm?.apiKey;
214
- }
215
- if (!apiKey) {
216
- const entered = await clack.password({
217
- message: 'LLM API key:',
218
- validate: (val) => validateLlmKeyFormat(provider, val),
219
- });
220
- if (clack.isCancel(entered)) cancelled();
221
- apiKey = entered;
222
- }
194
+ // API Key — always prompt, never from bootstrap
195
+ const apiKey = await clack.password({
196
+ message: 'LLM API key:',
197
+ validate: (val) => validateLlmKeyFormat(provider, val),
198
+ });
199
+ if (clack.isCancel(apiKey)) cancelled();
223
200
 
224
201
  printDone('LLM configured');
225
202
  return { provider, model, apiKey };
@@ -312,6 +289,14 @@ export async function ensureLocalSetup(configPath: string): Promise<void> {
312
289
  !config.wallet?.privateKey &&
313
290
  !config.llm.apiKey
314
291
  ) {
292
+ printBanner();
293
+ printSuccess('Already set up', [
294
+ `${pc.cyan('npx exagent run')} Start the agent`,
295
+ `${pc.cyan('npx exagent config')} Change LLM API key or model`,
296
+ `${pc.cyan('npx exagent status')} Check agent connection`,
297
+ '',
298
+ `${pc.dim('Dashboard:')} ${pc.cyan('https://exagent.io')}`,
299
+ ]);
315
300
  return;
316
301
  }
317
302
 
@@ -324,9 +309,6 @@ export async function ensureLocalSetup(configPath: string): Promise<void> {
324
309
  const bootstrapPayload = await consumeBootstrapPackage(config);
325
310
  if (config.secrets?.bootstrapToken) {
326
311
  printDone('Bootstrap package consumed');
327
- if (bootstrapPayload.llm?.provider) {
328
- printInfo(`LLM config received: ${pc.cyan(bootstrapPayload.llm.provider)}${bootstrapPayload.llm.model ? ` / ${pc.cyan(bootstrapPayload.llm.model)}` : ''}`);
329
- }
330
312
  } else {
331
313
  printInfo('No bootstrap token — manual configuration');
332
314
  }
@@ -337,7 +319,7 @@ export async function ensureLocalSetup(configPath: string): Promise<void> {
337
319
 
338
320
  // Step 3: LLM
339
321
  printStep(3, 4, 'LLM configuration');
340
- const llm = await setupLlm(config, bootstrapPayload);
322
+ const llm = await setupLlm(config);
341
323
 
342
324
  // Step 4: Encryption
343
325
  printStep(4, 4, 'Device encryption');
@@ -393,8 +375,9 @@ export async function ensureLocalSetup(configPath: string): Promise<void> {
393
375
  clack.outro(pc.green('Setup complete'));
394
376
 
395
377
  printSuccess('Ready', [
396
- `${pc.cyan('npx exagent run')} Start trading`,
397
- `${pc.cyan('npx exagent status')} Check connection`,
378
+ `${pc.cyan('npx exagent run')} Start the agent`,
379
+ `${pc.cyan('npx exagent config')} Change LLM API key or model`,
380
+ `${pc.cyan('npx exagent status')} Check agent connection`,
398
381
  '',
399
382
  `${pc.dim('Dashboard:')} ${pc.cyan('https://exagent.io')}`,
400
383
  ]);