@exagent/agent 0.3.5 → 0.3.7

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 (78) hide show
  1. package/dist/chunk-7UGLJO6W.js +6392 -0
  2. package/dist/chunk-EHAOPCTJ.js +6406 -0
  3. package/dist/chunk-FGMXTW5I.js +6540 -0
  4. package/dist/chunk-IVA2SCSN.js +6756 -0
  5. package/dist/chunk-JHXCSGPC.js +6352 -0
  6. package/dist/chunk-V6O4UXVN.js +6345 -0
  7. package/dist/chunk-ZRAOPQQW.js +6406 -0
  8. package/dist/cli.js +40 -98
  9. package/dist/index.d.ts +24 -2
  10. package/dist/index.js +1 -1
  11. package/package.json +17 -14
  12. package/.turbo/turbo-build.log +0 -17
  13. package/src/bridge/across.ts +0 -240
  14. package/src/bridge/bridge-manager.ts +0 -87
  15. package/src/bridge/index.ts +0 -9
  16. package/src/bridge/types.ts +0 -77
  17. package/src/chains.ts +0 -105
  18. package/src/cli.ts +0 -244
  19. package/src/config.ts +0 -499
  20. package/src/diagnostics.ts +0 -335
  21. package/src/index.ts +0 -98
  22. package/src/llm/anthropic.ts +0 -63
  23. package/src/llm/base.ts +0 -264
  24. package/src/llm/deepseek.ts +0 -48
  25. package/src/llm/google.ts +0 -63
  26. package/src/llm/groq.ts +0 -48
  27. package/src/llm/index.ts +0 -42
  28. package/src/llm/mistral.ts +0 -48
  29. package/src/llm/ollama.ts +0 -52
  30. package/src/llm/openai.ts +0 -51
  31. package/src/llm/together.ts +0 -48
  32. package/src/llm-providers.ts +0 -100
  33. package/src/logger.ts +0 -137
  34. package/src/paper/executor.ts +0 -201
  35. package/src/paper/index.ts +0 -1
  36. package/src/perp/client.ts +0 -200
  37. package/src/perp/index.ts +0 -12
  38. package/src/perp/msgpack.ts +0 -272
  39. package/src/perp/orders.ts +0 -234
  40. package/src/perp/positions.ts +0 -126
  41. package/src/perp/signer.ts +0 -277
  42. package/src/perp/types.ts +0 -192
  43. package/src/perp/websocket.ts +0 -274
  44. package/src/position-tracker.ts +0 -243
  45. package/src/prediction/client.ts +0 -281
  46. package/src/prediction/index.ts +0 -3
  47. package/src/prediction/order-manager.ts +0 -297
  48. package/src/prediction/types.ts +0 -151
  49. package/src/relay.ts +0 -254
  50. package/src/runtime.ts +0 -1755
  51. package/src/scrub-secrets.ts +0 -39
  52. package/src/setup.ts +0 -384
  53. package/src/signal.ts +0 -212
  54. package/src/spot/aerodrome.ts +0 -158
  55. package/src/spot/client.ts +0 -138
  56. package/src/spot/index.ts +0 -11
  57. package/src/spot/swap-manager.ts +0 -219
  58. package/src/spot/types.ts +0 -203
  59. package/src/spot/uniswap.ts +0 -150
  60. package/src/store.ts +0 -50
  61. package/src/strategy/index.ts +0 -2
  62. package/src/strategy/loader.ts +0 -191
  63. package/src/strategy/templates.ts +0 -125
  64. package/src/trading/index.ts +0 -2
  65. package/src/trading/market.ts +0 -120
  66. package/src/trading/risk.ts +0 -107
  67. package/src/ui.ts +0 -75
  68. package/test-bridge-arb-to-base.mjs +0 -223
  69. package/test-funded-check.mjs +0 -79
  70. package/test-funded-phase19.mjs +0 -933
  71. package/test-hl-deposit-recover.mjs +0 -281
  72. package/test-hl-withdraw.mjs +0 -372
  73. package/test-live-signing.mjs +0 -374
  74. package/test-phase7.mjs +0 -416
  75. package/test-recover-arb.mjs +0 -206
  76. package/test-spot-bridge.mjs +0 -248
  77. package/test-wallet-setup.mjs +0 -126
  78. package/tsconfig.json +0 -8
package/src/config.ts DELETED
@@ -1,499 +0,0 @@
1
- import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';
2
- import { chmodSync, existsSync, readFileSync, writeFileSync } from 'node:fs';
3
- import { homedir } from 'node:os';
4
- import { dirname, resolve } from 'node:path';
5
- import { z } from 'zod';
6
- import type { LLMProvider } from '@exagent/sdk';
7
-
8
- export interface RuntimeConfig {
9
- agentId: string;
10
- apiUrl: string;
11
- apiToken: string;
12
- wallet?: {
13
- privateKey: string;
14
- };
15
- llm: {
16
- provider: LLMProvider;
17
- model?: string;
18
- apiKey?: string;
19
- endpoint?: string;
20
- temperature?: number;
21
- maxTokens?: number;
22
- };
23
- strategy: {
24
- file?: string;
25
- code?: string;
26
- template?: string;
27
- venues?: string[];
28
- prompt?: {
29
- name?: string;
30
- systemPrompt: string;
31
- venues?: string[];
32
- };
33
- };
34
- trading: {
35
- mode: 'live' | 'paper';
36
- timeHorizon: 'intraday' | 'swing' | 'position';
37
- maxPositionSizeBps: number;
38
- maxDailyLossBps: number;
39
- maxConcurrentPositions: number;
40
- tradingIntervalMs: number;
41
- maxSlippageBps: number;
42
- minTradeValueUSD: number;
43
- initialCapitalUSD?: number;
44
- };
45
- venues?: {
46
- hyperliquid_perp?: {
47
- enabled: boolean;
48
- apiUrl: string;
49
- wsUrl: string;
50
- maxLeverage: number;
51
- maxNotionalUSD: number;
52
- allowedInstruments?: string[];
53
- };
54
- polymarket?: {
55
- enabled: boolean;
56
- clobApiUrl: string;
57
- gammaApiUrl: string;
58
- maxNotionalUSD: number;
59
- maxTotalExposureUSD: number;
60
- allowedCategories?: string[];
61
- };
62
- spot?: {
63
- enabled: boolean;
64
- chains: string[];
65
- defaultChain: string;
66
- maxSlippageBps: number;
67
- maxSwapValueUSD: number;
68
- };
69
- bridge?: {
70
- enabled: boolean;
71
- defaultBridge: string;
72
- maxBridgeValueUSD: number;
73
- fillTimeoutMs: number;
74
- pollIntervalMs: number;
75
- };
76
- };
77
- relay: {
78
- url: string;
79
- heartbeatIntervalMs: number;
80
- reconnectMaxAttempts: number;
81
- };
82
- llmBudget?: {
83
- maxDailyTokens?: number;
84
- };
85
- rpcOverrides?: Record<string, string>;
86
- logging?: {
87
- level?: 'debug' | 'info' | 'warn' | 'error';
88
- json?: boolean;
89
- };
90
- }
91
-
92
- export interface LocalSecretPayload {
93
- apiToken: string;
94
- walletPrivateKey?: string;
95
- llmApiKey?: string;
96
- }
97
-
98
- export interface SecureStoreFile {
99
- version: 1;
100
- algorithm: 'aes-256-gcm';
101
- kdf: {
102
- name: 'scrypt';
103
- salt: string;
104
- keyLength: 32;
105
- cost: number;
106
- blockSize: number;
107
- parallelization: number;
108
- };
109
- iv: string;
110
- ciphertext: string;
111
- authTag: string;
112
- }
113
-
114
- export interface LoadConfigOptions {
115
- getSecretPassword?: () => Promise<string>;
116
- }
117
-
118
- const providerEnum = z.enum(['openai', 'anthropic', 'google', 'deepseek', 'mistral', 'groq', 'together', 'ollama']);
119
-
120
- const runtimeSchema = z.object({
121
- agentId: z.string(),
122
- apiUrl: z.string().url(),
123
- apiToken: z.string().min(1),
124
- wallet: z.object({
125
- privateKey: z.string().regex(/^0x[a-fA-F0-9]{64}$/),
126
- }).optional(),
127
- llm: z.object({
128
- provider: providerEnum,
129
- model: z.string().optional(),
130
- apiKey: z.string().optional(),
131
- endpoint: z.string().optional(),
132
- temperature: z.number().min(0).max(2).optional(),
133
- maxTokens: z.number().optional(),
134
- }),
135
- strategy: z.object({
136
- file: z.string().optional(),
137
- code: z.string().optional(),
138
- template: z.string().optional(),
139
- venues: z.array(z.string()).optional(),
140
- prompt: z.object({
141
- name: z.string().optional(),
142
- systemPrompt: z.string().min(1),
143
- venues: z.array(z.string()).optional(),
144
- }).optional(),
145
- }),
146
- trading: z.object({
147
- mode: z.enum(['live', 'paper']).default('paper'),
148
- timeHorizon: z.enum(['intraday', 'swing', 'position']).default('swing'),
149
- maxPositionSizeBps: z.number().min(100).max(10000).default(2000),
150
- maxDailyLossBps: z.number().min(0).max(10000).default(500),
151
- maxConcurrentPositions: z.number().min(1).max(100).default(5),
152
- tradingIntervalMs: z.number().min(1000).default(60000),
153
- maxSlippageBps: z.number().min(10).max(1000).default(100),
154
- minTradeValueUSD: z.number().min(0).default(10),
155
- initialCapitalUSD: z.number().optional(),
156
- }),
157
- venues: z.object({
158
- hyperliquid_perp: z.object({
159
- enabled: z.boolean().default(false),
160
- apiUrl: z.string().default('https://api.hyperliquid.xyz'),
161
- wsUrl: z.string().default('wss://api.hyperliquid.xyz/ws'),
162
- maxLeverage: z.number().min(1).max(50).default(10),
163
- maxNotionalUSD: z.number().default(50_000),
164
- allowedInstruments: z.array(z.string()).optional(),
165
- }).optional(),
166
- polymarket: z.object({
167
- enabled: z.boolean().default(false),
168
- clobApiUrl: z.string().default('https://clob.polymarket.com'),
169
- gammaApiUrl: z.string().default('https://gamma-api.polymarket.com'),
170
- maxNotionalUSD: z.number().default(1_000),
171
- maxTotalExposureUSD: z.number().default(5_000),
172
- allowedCategories: z.array(z.string()).optional(),
173
- }).optional(),
174
- spot: z.object({
175
- enabled: z.boolean().default(false),
176
- chains: z.array(z.string()).default(['base']),
177
- defaultChain: z.string().default('base'),
178
- maxSlippageBps: z.number().min(1).max(1000).default(50),
179
- maxSwapValueUSD: z.number().default(10_000),
180
- }).optional(),
181
- bridge: z.object({
182
- enabled: z.boolean().default(false),
183
- defaultBridge: z.string().default('across'),
184
- maxBridgeValueUSD: z.number().default(10_000),
185
- fillTimeoutMs: z.number().default(300_000),
186
- pollIntervalMs: z.number().default(2_000),
187
- }).optional(),
188
- }).optional(),
189
- relay: z.object({
190
- url: z.string(),
191
- heartbeatIntervalMs: z.number().default(30000),
192
- reconnectMaxAttempts: z.number().default(50),
193
- }),
194
- llmBudget: z.object({
195
- maxDailyTokens: z.number().optional(),
196
- }).optional(),
197
- rpcOverrides: z.record(z.string()).optional(),
198
- logging: z.object({
199
- level: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
200
- json: z.boolean().default(true),
201
- }).optional(),
202
- });
203
-
204
- const configFileSchema = z.object({
205
- agentId: z.string(),
206
- apiUrl: z.string().url(),
207
- apiToken: z.string().min(1).optional(),
208
- wallet: z.object({
209
- privateKey: z.string().regex(/^0x[a-fA-F0-9]{64}$/),
210
- }).optional(),
211
- llm: z.object({
212
- provider: providerEnum.optional(),
213
- model: z.string().optional(),
214
- apiKey: z.string().optional(),
215
- endpoint: z.string().optional(),
216
- temperature: z.number().min(0).max(2).optional(),
217
- maxTokens: z.number().optional(),
218
- }).default({}),
219
- strategy: z.object({
220
- file: z.string().optional(),
221
- code: z.string().optional(),
222
- template: z.string().optional(),
223
- venues: z.array(z.string()).optional(),
224
- prompt: z.object({
225
- name: z.string().optional(),
226
- systemPrompt: z.string().min(1),
227
- venues: z.array(z.string()).optional(),
228
- }).optional(),
229
- }),
230
- trading: runtimeSchema.shape.trading,
231
- venues: runtimeSchema.shape.venues,
232
- relay: runtimeSchema.shape.relay,
233
- llmBudget: runtimeSchema.shape.llmBudget,
234
- rpcOverrides: runtimeSchema.shape.rpcOverrides,
235
- logging: runtimeSchema.shape.logging,
236
- secrets: z.object({
237
- bootstrapToken: z.string().optional(),
238
- bootstrapExpiresAt: z.string().optional(),
239
- secureStorePath: z.string().optional(),
240
- }).optional(),
241
- });
242
-
243
- const secureStoreSchema = z.object({
244
- version: z.literal(1),
245
- algorithm: z.literal('aes-256-gcm'),
246
- kdf: z.object({
247
- name: z.literal('scrypt'),
248
- salt: z.string(),
249
- keyLength: z.literal(32),
250
- cost: z.number().int().positive(),
251
- blockSize: z.number().int().positive(),
252
- parallelization: z.number().int().positive(),
253
- }),
254
- iv: z.string(),
255
- ciphertext: z.string(),
256
- authTag: z.string(),
257
- });
258
-
259
- export type RuntimeConfigFile = z.infer<typeof configFileSchema>;
260
-
261
- const DEFAULT_SCRYPT_COST = 16384;
262
- const DEFAULT_SCRYPT_BLOCK_SIZE = 8;
263
- const DEFAULT_SCRYPT_PARALLELIZATION = 1;
264
-
265
- function expandHomeDir(path: string): string {
266
- if (!path.startsWith('~/')) return path;
267
- return resolve(homedir(), path.slice(2));
268
- }
269
-
270
- export function getDefaultSecureStorePath(agentId: string): string {
271
- return resolve(homedir(), '.exagent', 'agents', agentId, 'secrets.json');
272
- }
273
-
274
- export function readConfigFile(path: string = 'agent-config.json'): RuntimeConfigFile {
275
- if (!existsSync(path)) {
276
- throw new Error(`Config file not found: ${path}. Run 'exagent init' first.`);
277
- }
278
-
279
- let parsed: unknown;
280
- try {
281
- parsed = JSON.parse(readFileSync(path, 'utf-8'));
282
- } catch {
283
- throw new Error(`Invalid JSON in ${path}`);
284
- }
285
-
286
- const result = configFileSchema.safeParse(parsed);
287
- if (!result.success) {
288
- const issues = result.error.issues.map((issue) => ` ${issue.path.join('.')}: ${issue.message}`).join('\n');
289
- throw new Error(`Invalid config file:\n${issues}`);
290
- }
291
-
292
- return result.data;
293
- }
294
-
295
- export function writeConfigFile(path: string, config: RuntimeConfigFile): void {
296
- writeFileSync(path, JSON.stringify(config, null, 2));
297
- }
298
-
299
- export function encryptSecretPayload(payload: LocalSecretPayload, password: string): SecureStoreFile {
300
- const salt = randomBytes(16);
301
- const iv = randomBytes(12);
302
- const key = scryptSync(password, salt, 32, {
303
- N: DEFAULT_SCRYPT_COST,
304
- r: DEFAULT_SCRYPT_BLOCK_SIZE,
305
- p: DEFAULT_SCRYPT_PARALLELIZATION,
306
- });
307
-
308
- const cipher = createCipheriv('aes-256-gcm', key, iv);
309
- const plaintext = Buffer.from(JSON.stringify(payload), 'utf8');
310
- const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
311
-
312
- return {
313
- version: 1,
314
- algorithm: 'aes-256-gcm',
315
- kdf: {
316
- name: 'scrypt',
317
- salt: salt.toString('hex'),
318
- keyLength: 32,
319
- cost: DEFAULT_SCRYPT_COST,
320
- blockSize: DEFAULT_SCRYPT_BLOCK_SIZE,
321
- parallelization: DEFAULT_SCRYPT_PARALLELIZATION,
322
- },
323
- iv: iv.toString('hex'),
324
- ciphertext: ciphertext.toString('hex'),
325
- authTag: cipher.getAuthTag().toString('hex'),
326
- };
327
- }
328
-
329
- export function decryptSecretPayload(path: string, password: string): LocalSecretPayload {
330
- const secureStorePath = expandHomeDir(path);
331
- if (!existsSync(secureStorePath)) {
332
- throw new Error(`Encrypted secret store not found: ${secureStorePath}`);
333
- }
334
-
335
- let parsed: unknown;
336
- try {
337
- parsed = JSON.parse(readFileSync(secureStorePath, 'utf-8'));
338
- } catch {
339
- throw new Error(`Invalid JSON in encrypted secret store: ${secureStorePath}`);
340
- }
341
-
342
- const result = secureStoreSchema.safeParse(parsed);
343
- if (!result.success) {
344
- const issues = result.error.issues.map((issue) => ` ${issue.path.join('.')}: ${issue.message}`).join('\n');
345
- throw new Error(`Invalid encrypted secret store:\n${issues}`);
346
- }
347
-
348
- const store = result.data;
349
- const key = scryptSync(password, Buffer.from(store.kdf.salt, 'hex'), store.kdf.keyLength, {
350
- N: store.kdf.cost,
351
- r: store.kdf.blockSize,
352
- p: store.kdf.parallelization,
353
- });
354
-
355
- try {
356
- const decipher = createDecipheriv(store.algorithm, key, Buffer.from(store.iv, 'hex'));
357
- decipher.setAuthTag(Buffer.from(store.authTag, 'hex'));
358
- const plaintext = Buffer.concat([
359
- decipher.update(Buffer.from(store.ciphertext, 'hex')),
360
- decipher.final(),
361
- ]);
362
- return JSON.parse(plaintext.toString('utf8')) as LocalSecretPayload;
363
- } catch {
364
- throw new Error('Unable to decrypt local secret store. Check your password.');
365
- }
366
- }
367
-
368
- export async function loadConfig(path: string = 'agent-config.json', options: LoadConfigOptions = {}): Promise<RuntimeConfig> {
369
- const parsed = readConfigFile(path);
370
- const config = structuredClone(parsed) as RuntimeConfigFile & Record<string, unknown>;
371
- const llm = { ...(config.llm || {}) } as Record<string, unknown>;
372
-
373
- if (process.env.EXAGENT_LLM_PROVIDER) llm.provider = process.env.EXAGENT_LLM_PROVIDER;
374
- if (process.env.EXAGENT_LLM_MODEL) llm.model = process.env.EXAGENT_LLM_MODEL;
375
- if (process.env.EXAGENT_LLM_API_KEY) llm.apiKey = process.env.EXAGENT_LLM_API_KEY;
376
- if (process.env.EXAGENT_API_URL) config.apiUrl = process.env.EXAGENT_API_URL;
377
- if (process.env.EXAGENT_API_TOKEN) config.apiToken = process.env.EXAGENT_API_TOKEN;
378
- if (process.env.EXAGENT_WALLET_PRIVATE_KEY) {
379
- config.wallet = { privateKey: process.env.EXAGENT_WALLET_PRIVATE_KEY };
380
- }
381
-
382
- if ((!config.apiToken || !llm.apiKey || !config.wallet) && parsed.secrets?.secureStorePath) {
383
- const password = process.env.EXAGENT_SECRET_PASSWORD || await options.getSecretPassword?.();
384
- if (!password) {
385
- throw new Error('Encrypted secret store found, but no password was provided.');
386
- }
387
-
388
- const secrets = decryptSecretPayload(parsed.secrets.secureStorePath, password);
389
- if (!config.apiToken) config.apiToken = secrets.apiToken;
390
- if (!config.wallet && secrets.walletPrivateKey) config.wallet = { privateKey: secrets.walletPrivateKey };
391
- if (!llm.apiKey && secrets.llmApiKey) llm.apiKey = secrets.llmApiKey;
392
- }
393
-
394
- if ((!config.apiToken || !llm.apiKey || !config.wallet) && parsed.secrets?.bootstrapToken && !parsed.secrets?.secureStorePath) {
395
- throw new Error(`Config ${path} still requires first-time secure setup. Run 'exagent setup --config ${path}' or start the agent interactively.`);
396
- }
397
-
398
- config.llm = llm;
399
-
400
- const rpcOverrides: Record<string, string> = (config.rpcOverrides as Record<string, string>) || {};
401
- if (process.env.EXAGENT_RPC_BASE) rpcOverrides.base = process.env.EXAGENT_RPC_BASE;
402
- if (process.env.EXAGENT_RPC_ARBITRUM) rpcOverrides.arbitrum = process.env.EXAGENT_RPC_ARBITRUM;
403
- if (process.env.EXAGENT_RPC_POLYGON) rpcOverrides.polygon = process.env.EXAGENT_RPC_POLYGON;
404
- if (process.env.EXAGENT_RPC_ETHEREUM) rpcOverrides.ethereum = process.env.EXAGENT_RPC_ETHEREUM;
405
- if (Object.keys(rpcOverrides).length > 0) {
406
- config.rpcOverrides = rpcOverrides;
407
- }
408
-
409
- const result = runtimeSchema.safeParse(config);
410
- if (!result.success) {
411
- const issues = result.error.issues.map((issue) => ` ${issue.path.join('.')}: ${issue.message}`).join('\n');
412
- throw new Error(`Invalid config:\n${issues}`);
413
- }
414
-
415
- return result.data;
416
- }
417
-
418
- export function updateSecureStore(
419
- path: string,
420
- password: string,
421
- updates: Partial<LocalSecretPayload>,
422
- ): void {
423
- const secrets = decryptSecretPayload(path, password);
424
- const updated = { ...secrets, ...updates };
425
- const encrypted = encryptSecretPayload(updated, password);
426
- const secureStorePath = expandHomeDir(path);
427
- writeFileSync(secureStorePath, JSON.stringify(encrypted, null, 2), { mode: 0o600 });
428
- try {
429
- chmodSync(secureStorePath, 0o600);
430
- } catch {
431
- // Best effort
432
- }
433
- }
434
-
435
- export function generateSampleConfig(agentId: string, apiUrl: string): string {
436
- const config: RuntimeConfigFile = {
437
- agentId,
438
- apiUrl,
439
- llm: {},
440
- strategy: {
441
- template: 'momentum',
442
- },
443
- trading: {
444
- mode: 'paper',
445
- timeHorizon: 'swing',
446
- maxPositionSizeBps: 2000,
447
- maxDailyLossBps: 500,
448
- maxConcurrentPositions: 5,
449
- tradingIntervalMs: 60000,
450
- maxSlippageBps: 100,
451
- minTradeValueUSD: 10,
452
- initialCapitalUSD: 10000,
453
- },
454
- venues: {
455
- hyperliquid_perp: {
456
- enabled: false,
457
- apiUrl: 'https://api.hyperliquid.xyz',
458
- wsUrl: 'wss://api.hyperliquid.xyz/ws',
459
- maxLeverage: 10,
460
- maxNotionalUSD: 50000,
461
- },
462
- polymarket: {
463
- enabled: false,
464
- clobApiUrl: 'https://clob.polymarket.com',
465
- gammaApiUrl: 'https://gamma-api.polymarket.com',
466
- maxNotionalUSD: 1000,
467
- maxTotalExposureUSD: 5000,
468
- },
469
- spot: {
470
- enabled: false,
471
- chains: ['base'],
472
- defaultChain: 'base',
473
- maxSlippageBps: 50,
474
- maxSwapValueUSD: 10000,
475
- },
476
- bridge: {
477
- enabled: false,
478
- defaultBridge: 'across',
479
- maxBridgeValueUSD: 10000,
480
- fillTimeoutMs: 300000,
481
- pollIntervalMs: 2000,
482
- },
483
- },
484
- relay: {
485
- url: apiUrl.replace(/^http/, 'ws') + '/ws/agent',
486
- heartbeatIntervalMs: 30000,
487
- reconnectMaxAttempts: 50,
488
- },
489
- secrets: {
490
- secureStorePath: getDefaultSecureStorePath(agentId),
491
- },
492
- };
493
-
494
- return JSON.stringify(config, null, 2);
495
- }
496
-
497
- export function writeSampleConfig(agentId: string, apiUrl: string, path: string = 'agent-config.json'): void {
498
- writeFileSync(path, generateSampleConfig(agentId, apiUrl));
499
- }