agent-tank 0.9.6 → 0.9.8

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/README.md CHANGED
@@ -7,7 +7,7 @@ Agent Tank is a local dashboard and HTTP API for monitoring usage limits in AI c
7
7
  It supports:
8
8
 
9
9
  - Claude Code
10
- - Gemini CLI
10
+ - Antigravity CLI
11
11
  - OpenAI Codex
12
12
 
13
13
  ## How It Gets the Data
@@ -17,7 +17,7 @@ This is the part that matters.
17
17
  Agent Tank reads usage directly from the local CLI tools you already use. It launches the installed CLIs locally, runs their built-in usage commands, and parses the output into a unified web UI and JSON API.
18
18
 
19
19
  - Claude: runs `/usage`
20
- - Gemini: runs `/stats`
20
+ - Antigravity: runs `/usage`
21
21
  - Codex: prefers JSON-RPC `account/rateLimits/read`, falls back to `/status`
22
22
 
23
23
  What it does not do:
@@ -37,7 +37,7 @@ Agent Tank is meant for subscription-based coding agent products where the CLI i
37
37
  Examples:
38
38
 
39
39
  - Claude Code Pro / Max
40
- - Gemini CLI with supported subscription plans
40
+ - Antigravity CLI with supported subscription plans
41
41
  - ChatGPT Codex with supported plans
42
42
 
43
43
  It is not for:
@@ -62,6 +62,47 @@ Or run it directly:
62
62
  npx agent-tank
63
63
  ```
64
64
 
65
+ ### Run from Source
66
+
67
+ If you want to run the latest code from a checkout instead of the published package:
68
+
69
+ ```bash
70
+ # 1. Clone the repo
71
+ git clone https://github.com/integry/agent-tank.git
72
+ cd agent-tank
73
+
74
+ # 2. Install dependencies (compiles node-pty natively)
75
+ npm install
76
+
77
+ # 3. Run it
78
+ npm start # = node bin/agent-tank.js
79
+ ```
80
+
81
+ By default it auto-discovers installed CLIs and serves the dashboard + API at `http://127.0.0.1:3456`.
82
+
83
+ To pass flags, call the entry point directly (`npm start` does not forward arguments cleanly):
84
+
85
+ ```bash
86
+ node bin/agent-tank.js --claude --codex --port 8080
87
+ node bin/agent-tank.js --once --json # one-shot, prints JSON, no server
88
+ node bin/agent-tank.js --no-docker # localhost only
89
+ node bin/agent-tank.js --help # full option list
90
+ ```
91
+
92
+ Prerequisites:
93
+
94
+ - **Node.js 18+**
95
+ - `node-pty` is a native module, so `npm install` needs **Python 3.8+** and **C/C++ build tools**. See [Installation Notes](#installation-notes) if the build fails.
96
+ - At least one supported CLI installed and authenticated on your `PATH` (`claude`, `agy`, or `codex`).
97
+
98
+ Other useful scripts:
99
+
100
+ ```bash
101
+ npm test # run all tests
102
+ npm run lint # check code style
103
+ npm run rebuild # rebuild node-pty against a detected Python
104
+ ```
105
+
65
106
  ### First Run
66
107
 
67
108
  ```bash
@@ -87,14 +128,14 @@ agent-tank --no-docker
87
128
 
88
129
  ```bash
89
130
  # Monitor only specific agents
90
- agent-tank --claude --gemini
91
-
92
- # Prefer direct Gemini quota fetching
93
- agent-tank --gemini --gemini-mode direct
131
+ agent-tank --claude --agy
94
132
 
95
133
  # Use a custom port
96
134
  agent-tank --port 8080
97
135
 
136
+ # Keep Agent Tank running after closing this terminal
137
+ agent-tank --background
138
+
98
139
  # Fetch once and print JSON
99
140
  agent-tank --once --json
100
141
 
@@ -130,7 +171,7 @@ agent-tank --refresh-cooldown 60
130
171
  | Agent | Method | Metrics |
131
172
  |---|---|---|
132
173
  | Claude | PTY `/usage` or Anthropic OAuth API | Current session, weekly all-models, weekly Sonnet-only |
133
- | Gemini | PTY `/stats` | Per-model usage and reset windows |
174
+ | Antigravity | PTY `/usage` | Per-model quota availability and reset windows when reported |
134
175
  | Codex | JSON-RPC preferred, PTY fallback | 5-hour limits, weekly limits, model/account info |
135
176
 
136
177
  ## Basic Usage
@@ -153,6 +194,14 @@ agent-tank --claude --codex
153
194
  agent-tank --once --json
154
195
  ```
155
196
 
197
+ ### Background Server Mode
198
+
199
+ ```bash
200
+ agent-tank --background
201
+ ```
202
+
203
+ This starts Agent Tank as a detached process, prints the background PID, and exits the parent command.
204
+
156
205
  ### Bind to a Different Host or Port
157
206
 
158
207
  ```bash
@@ -186,9 +235,8 @@ Set it to `0` to disable the cooldown entirely.
186
235
  ```text
187
236
  Options:
188
237
  --claude Enable Claude monitoring
189
- --gemini Enable Gemini monitoring
238
+ --agy Enable Antigravity monitoring
190
239
  --codex Enable Codex monitoring
191
- --gemini-mode <mode> Gemini strategy: fallback, direct, pty (default: fallback)
192
240
  --port <port> HTTP server port (default: 3456)
193
241
  --host <host> Bind address (default: 127.0.0.1 + Docker bridge when available)
194
242
  --docker Enable Docker bridge bind when --host is omitted (default: true)
@@ -202,14 +250,15 @@ Options:
202
250
  --auto-discover Auto-discover available agents (default: true)
203
251
  --auto-refresh Enable/disable background auto-refresh (default: true)
204
252
  --auto-refresh-mode <mode> Refresh mode: none, interval, activity (default: activity)
205
- --auto-refresh-interval <seconds> Auto-refresh interval in seconds (default: 60)
253
+ --auto-refresh-interval <seconds> Auto-refresh interval in seconds (default: 60, 0 = disabled)
206
254
  --refresh-cooldown <seconds> Minimum time between refreshes per agent (default: 30, 0 = disabled)
207
255
  --activity-debounce <ms> Activity debounce interval in milliseconds (default: 5000)
208
256
  --keepalive Enable/disable session keepalive (default: true)
209
- --keepalive-interval <seconds> Session keepalive interval in seconds (default: 300)
257
+ --keepalive-interval <seconds> Session keepalive interval in seconds (default: 300, 0 = disabled)
210
258
  --history-retention-days <days> Days to retain usage history (default: 14)
211
259
  --once Fetch usage once and exit (no HTTP server)
212
260
  --json Output pure JSON (suppress logging, use with --once)
261
+ --background Start Agent Tank as a detached background process
213
262
  --help, -h Show this help message
214
263
  ```
215
264
 
@@ -217,7 +266,9 @@ Options:
217
266
 
218
267
  ### Environment Variables
219
268
 
220
- Environment variables override CLI flags and config file values.
269
+ Environment variables override CLI flags and config file values. Background mode has
270
+ three exceptions: `--no-background`, `--once`, and `--json` suppress
271
+ `AGENT_TANK_BACKGROUND=1` for that run.
221
272
 
222
273
  | Variable | Description |
223
274
  |---|---|
@@ -228,7 +279,6 @@ Environment variables override CLI flags and config file values.
228
279
  | `AGENT_TANK_DOCKER` | Enable/disable Docker bridge bind when `--host` is omitted |
229
280
  | `AGENT_TANK_FRESH_PROCESS` | Use fresh process per refresh (`1`/`true`) |
230
281
  | `AGENT_TANK_CLAUDE_API` | Use Claude API mode (`1`/`true`) |
231
- | `AGENT_TANK_GEMINI_MODE` | Gemini strategy: `fallback`, `direct`, or `pty` |
232
282
  | `AGENT_TANK_AUTO_REFRESH` | Enable/disable auto-refresh |
233
283
  | `AGENT_TANK_AUTO_REFRESH_MODE` | `none`, `interval`, or `activity` |
234
284
  | `AGENT_TANK_AUTO_REFRESH_INTERVAL` | Auto-refresh interval in seconds |
@@ -237,18 +287,20 @@ Environment variables override CLI flags and config file values.
237
287
  | `AGENT_TANK_KEEPALIVE` | Enable/disable keepalive |
238
288
  | `AGENT_TANK_KEEPALIVE_INTERVAL` | Keepalive interval in seconds |
239
289
  | `AGENT_TANK_HISTORY_RETENTION_DAYS` | History retention window |
290
+ | `AGENT_TANK_BACKGROUND` | Start as a detached background process (`1`/`true`) |
291
+ | `AGENT_TANK_BACKGROUND_LOG` | Background child stdout/stderr log path (defaults to a temp file) |
292
+ | `AGENT_TANK_BACKGROUND_GRACE_MS` | Parent startup grace period before reporting background success; success means the child survived this period |
240
293
 
241
294
  ### Config File
242
295
 
243
296
  ```json
244
297
  {
245
298
  "claude": true,
246
- "gemini": true,
299
+ "agy": true,
247
300
  "codex": false,
248
301
  "port": 8080,
249
302
  "dockerAccess": true,
250
303
  "claudeApi": false,
251
- "geminiMode": "fallback",
252
304
  "refreshCooldown": 30,
253
305
  "autoRefresh": {
254
306
  "mode": "activity",
@@ -272,26 +324,17 @@ Run with:
272
324
  agent-tank -c config.json
273
325
  ```
274
326
 
275
- ## Gemini Modes
276
-
277
- By default, Gemini runs in `fallback` mode:
278
-
279
- - try a direct quota fetch using the local Gemini OAuth session
280
- - fall back to PTY `/stats` if the direct path fails
281
-
282
- Available modes:
327
+ ## Antigravity
283
328
 
284
- - `fallback`: direct first, PTY fallback
285
- - `direct`: use the direct quota API only
286
- - `pty`: use interactive Gemini CLI `/stats` only
329
+ Antigravity support uses the `agy` CLI and reads the interactive `/usage` output.
287
330
 
288
331
  In `--once` mode, Agent Tank prints the result and exits immediately after the output is flushed.
289
332
 
290
333
  Examples:
291
334
 
292
335
  ```bash
293
- agent-tank --gemini --gemini-mode direct
294
- agent-tank --gemini --gemini-mode pty
336
+ agent-tank --agy
337
+ agent-tank --agy --once --json
295
338
  ```
296
339
 
297
340
  ## HTTP API
@@ -421,7 +464,7 @@ In activity mode, Agent Tank watches common local directories:
421
464
 
422
465
  - Claude: `~/.config/claude/projects/`, `~/.claude/`
423
466
  - Codex: `~/.codex/sessions/`, `~/.codex/`
424
- - Gemini: `~/.config/gemini/`, `~/.gemini/`
467
+ - Antigravity: `~/.gemini/antigravity-cli/`
425
468
 
426
469
  If no suitable directories are found, it falls back to interval mode.
427
470
 
@@ -509,15 +552,15 @@ You need at least one supported CLI installed and authenticated.
509
552
 
510
553
  - [Claude Code](https://claude.ai/download) as `claude`
511
554
  - Version 2.0+ required for `/usage`
512
- - Gemini CLI as `gemini`
513
- - Version 0.24.5+ required for `/stats`
555
+ - Antigravity CLI as `agy`
556
+ - `/usage` command support required
514
557
  - OpenAI Codex as `codex`
515
558
 
516
559
  Useful checks:
517
560
 
518
561
  ```bash
519
562
  claude --version
520
- gemini --version
563
+ agy --version
521
564
  codex --version
522
565
  ```
523
566
 
@@ -527,7 +570,7 @@ codex --version
527
570
  const { AgentTank } = require('agent-tank');
528
571
 
529
572
  const watcher = new AgentTank({
530
- agents: ['claude', 'gemini'],
573
+ agents: ['claude', 'agy'],
531
574
  port: 3456,
532
575
  autoDiscover: true
533
576
  });
package/bin/agent-tank.js CHANGED
@@ -1,17 +1,22 @@
1
1
  #!/usr/bin/env node
2
- /* eslint-disable complexity */
2
+ /* eslint-disable complexity -- CLI option merging is centralized here to preserve precedence behavior. */
3
+ /* eslint-disable max-lines -- Tracked in issue #90; CLI help text and option precedence stay together for now. */
3
4
 
4
5
  const { parseArgs } = require('node:util');
5
- const { AgentTank } = require('../src/index.js');
6
- const { installShutdownHandlers } = require('../src/shutdown-handler.js');
6
+ const {
7
+ isTruthyEnv,
8
+ } = require('../src/process-utils.js');
9
+ const {
10
+ spawnBackgroundProcess,
11
+ warnAboutRunningProcesses,
12
+ } = require('../src/cli-background.js');
7
13
  const pkg = require('../package.json');
8
14
 
9
15
  const options = {
10
16
  claude: { type: 'boolean', default: false },
11
- gemini: { type: 'boolean', default: false },
17
+ agy: { type: 'boolean', default: false },
12
18
  codex: { type: 'boolean', default: false },
13
19
  'claude-api': { type: 'boolean', default: false },
14
- 'gemini-mode': { type: 'string' },
15
20
  port: { type: 'string', default: '3456' },
16
21
  host: { type: 'string' },
17
22
  docker: { type: 'boolean', default: true },
@@ -33,9 +38,15 @@ const options = {
33
38
  'keepalive-interval': { type: 'string', default: '300' },
34
39
  once: { type: 'boolean', default: false },
35
40
  json: { type: 'boolean', default: false },
41
+ background: { type: 'boolean', default: false },
36
42
  };
37
43
 
38
- const { values } = parseArgs({ options, allowPositionals: false, allowNegative: true });
44
+ const { values, tokens } = parseArgs({
45
+ options,
46
+ allowPositionals: false,
47
+ allowNegative: true,
48
+ tokens: true,
49
+ });
39
50
 
40
51
  function exitWithCode(code, message, stream = process.stderr) {
41
52
  if (message) {
@@ -63,10 +74,9 @@ Usage: agent-tank [options]
63
74
 
64
75
  Options:
65
76
  --claude Enable Claude monitoring
66
- --gemini Enable Gemini monitoring
77
+ --agy Enable Antigravity monitoring
67
78
  --codex Enable Codex monitoring
68
79
  --claude-api Use direct Anthropic API for Claude usage (faster, 60s refresh)
69
- --gemini-mode <mode> Gemini strategy: fallback, direct, pty (default: fallback)
70
80
  --port <port> HTTP server port (default: 3456)
71
81
  --host <host> Bind address (default: 127.0.0.1 + Docker bridge when available)
72
82
  --docker Enable Docker bridge bind when --host is omitted (default: true)
@@ -87,6 +97,7 @@ Options:
87
97
  --history-retention-days <days> Days to retain usage history (default: 14)
88
98
  --once Fetch usage once and exit (no HTTP server)
89
99
  --json Output pure JSON (suppress logging, use with --once)
100
+ --background Start Agent Tank as a detached background process
90
101
  --help, -h Show this help message
91
102
 
92
103
  Auto-Refresh Modes:
@@ -103,7 +114,6 @@ Environment variables:
103
114
  AGENT_TANK_DOCKER Enable/disable Docker bridge bind ("1"/"true" or "0"/"false")
104
115
  AGENT_TANK_FRESH_PROCESS Use fresh process per refresh ("1" or "true")
105
116
  AGENT_TANK_CLAUDE_API Use direct Anthropic API for Claude usage ("1" or "true")
106
- AGENT_TANK_GEMINI_MODE Gemini strategy: fallback, direct, pty
107
117
  AGENT_TANK_AUTO_REFRESH Enable/disable background auto-refresh ("1" or "true" / "0" or "false")
108
118
  AGENT_TANK_AUTO_REFRESH_MODE Refresh mode: none, interval, activity
109
119
  AGENT_TANK_AUTO_REFRESH_INTERVAL Auto-refresh interval in seconds
@@ -112,14 +122,18 @@ Environment variables:
112
122
  AGENT_TANK_KEEPALIVE Enable/disable session keepalive ("1" or "true" / "0" or "false")
113
123
  AGENT_TANK_KEEPALIVE_INTERVAL Session keepalive interval in seconds
114
124
  AGENT_TANK_HISTORY_RETENTION_DAYS Days to retain usage history
125
+ AGENT_TANK_BACKGROUND Start as a detached background process ("1" or "true")
126
+ AGENT_TANK_BACKGROUND_LOG Log file for background child stdout/stderr
127
+ AGENT_TANK_BACKGROUND_GRACE_MS Parent startup grace period before reporting background success
128
+ (success means the child survived this period)
115
129
 
116
130
  Examples:
117
131
  agent-tank # Auto-discover and monitor all available
118
- agent-tank --claude --gemini # Monitor specific agents
132
+ agent-tank --background # Start in the background and print the PID
133
+ agent-tank --claude --agy # Monitor specific agents
119
134
  agent-tank --port 8080 # Use custom port
120
135
  agent-tank --host 0.0.0.0 # Expose on all interfaces
121
136
  agent-tank --no-docker # Bind localhost only when host is omitted
122
- agent-tank --gemini-mode direct # Prefer direct Gemini quota API calls
123
137
  agent-tank --auth-user admin --auth-pass secret # Enable basic auth
124
138
  agent-tank --auth-token mykey # Enable API key auth
125
139
  agent-tank -c ./config.json # Use config file
@@ -160,6 +174,37 @@ async function main() {
160
174
  return;
161
175
  }
162
176
 
177
+ const explicitNoBackground = tokens.some(token =>
178
+ token.kind === 'option' &&
179
+ token.name === 'background' &&
180
+ token.rawName === '--no-background');
181
+ const explicitBackground = tokens.some(token =>
182
+ token.kind === 'option' &&
183
+ token.name === 'background' &&
184
+ token.rawName === '--background');
185
+ const envBackgroundRequested = isTruthyEnv(process.env.AGENT_TANK_BACKGROUND) &&
186
+ !explicitNoBackground &&
187
+ !values.once &&
188
+ !values.json;
189
+ const backgroundRequested = explicitBackground || envBackgroundRequested;
190
+ const backgroundChild = isTruthyEnv(process.env.AGENT_TANK_BACKGROUND_CHILD);
191
+
192
+ if (backgroundRequested && !backgroundChild) {
193
+ for (const incompatibleFlag of ['once', 'json']) {
194
+ if (values[incompatibleFlag]) {
195
+ exitWithCode(1, `Error: --background cannot be combined with --${incompatibleFlag}`);
196
+ return;
197
+ }
198
+ }
199
+
200
+ const started = await spawnBackgroundProcess();
201
+ process.exitCode = started ? 0 : 1;
202
+ return;
203
+ }
204
+
205
+ const { AgentTank } = require('../src/index.js');
206
+ const { installShutdownHandlers } = require('../src/shutdown-handler.js');
207
+
163
208
  // Load config file if specified
164
209
  let config = {};
165
210
  if (values.config) {
@@ -174,7 +219,7 @@ async function main() {
174
219
  // Merge CLI options with config (env vars > CLI flags > config file)
175
220
  const agents = [];
176
221
  if (values.claude || config.claude) agents.push('claude');
177
- if (values.gemini || config.gemini) agents.push('gemini');
222
+ if (values.agy || config.agy) agents.push('agy');
178
223
  if (values.codex || config.codex) agents.push('codex');
179
224
 
180
225
  const auth = {
@@ -203,9 +248,6 @@ async function main() {
203
248
  config.claudeApi ||
204
249
  claudeApiEnv === '1' || claudeApiEnv === 'true';
205
250
 
206
- const geminiModeEnv = process.env.AGENT_TANK_GEMINI_MODE;
207
- const geminiMode = geminiModeEnv || values['gemini-mode'] || config.geminiMode || 'fallback';
208
-
209
251
  // Auto-refresh configuration (env > CLI > config file)
210
252
  const autoRefreshEnv = process.env.AGENT_TANK_AUTO_REFRESH;
211
253
  let autoRefreshEnabled = values['auto-refresh'];
@@ -298,7 +340,6 @@ async function main() {
298
340
  auth,
299
341
  freshProcess,
300
342
  claudeApi,
301
- geminiMode,
302
343
  autoRefreshEnabled: onceMode ? false : autoRefreshEnabled, // Disable auto-refresh in one-shot mode
303
344
  autoRefreshInterval,
304
345
  autoRefreshMode: onceMode ? 'none' : autoRefreshMode, // Disable auto-refresh in one-shot mode
@@ -354,7 +395,11 @@ async function main() {
354
395
  }
355
396
  }
356
397
 
398
+ const runningProcessWarning = (!jsonMode && !backgroundChild) ?
399
+ warnAboutRunningProcesses() :
400
+ Promise.resolve();
357
401
  await watcher.start();
402
+ await runningProcessWarning;
358
403
  } catch (err) {
359
404
  cleanupShutdownHandlers();
360
405
  if (jsonMode) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agent-tank",
3
- "version": "0.9.6",
4
- "description": "Monitor and query usage limits for LLM CLI tools (Claude, Gemini, Codex) via HTTP API",
3
+ "version": "0.9.8",
4
+ "description": "Monitor and query usage limits for LLM CLI tools (Claude, Antigravity, Codex) via HTTP API",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
7
  "agent-tank": "bin/agent-tank.js"
@@ -19,7 +19,8 @@
19
19
  "keywords": [
20
20
  "llm",
21
21
  "claude",
22
- "gemini",
22
+ "antigravity",
23
+ "agy",
23
24
  "codex",
24
25
  "openai",
25
26
  "anthropic",
@@ -42,6 +43,7 @@
42
43
  },
43
44
  "homepage": "https://agenttank.io",
44
45
  "dependencies": {
46
+ "chokidar": "^3.6.0",
45
47
  "node-pty": "^1.0.0",
46
48
  "source-map-support": "^0.5.21"
47
49
  },
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * ActivityMonitor - Monitors local log directories for LLM CLI activity
3
3
  *
4
- * Watches known log directories for Claude, Codex, and Gemini using fs.watch.
4
+ * Watches known log directories for Claude, Codex, and Antigravity using chokidar with polling.
5
5
  * When activity is detected (new log entries), it triggers usage refresh callbacks
6
6
  * with configurable debouncing to prevent excessive polling.
7
7
  */
@@ -9,6 +9,7 @@
9
9
  const fs = require('node:fs');
10
10
  const path = require('node:path');
11
11
  const os = require('node:os');
12
+ const chokidar = require('chokidar');
12
13
 
13
14
  /**
14
15
  * Default log directories for each agent.
@@ -23,9 +24,8 @@ const DEFAULT_LOG_DIRECTORIES = {
23
24
  path.join(os.homedir(), '.codex', 'sessions'),
24
25
  path.join(os.homedir(), '.codex'),
25
26
  ],
26
- gemini: [
27
- path.join(os.homedir(), '.config', 'gemini'),
28
- path.join(os.homedir(), '.gemini'),
27
+ agy: [
28
+ path.join(os.homedir(), '.gemini', 'antigravity-cli'),
29
29
  ],
30
30
  };
31
31
 
@@ -72,7 +72,7 @@ class ActivityMonitor {
72
72
 
73
73
  /**
74
74
  * Start monitoring log directories for activity.
75
- * Sets up fs.watch on each agent's log directories.
75
+ * Sets up chokidar polling watchers on each agent's log directories.
76
76
  *
77
77
  * @returns {Object} Status object with monitoring details
78
78
  */
@@ -92,7 +92,18 @@ class ActivityMonitor {
92
92
  for (const dir of dirs) {
93
93
  if (fs.existsSync(dir)) {
94
94
  try {
95
- const watcher = fs.watch(dir, { recursive: true }, (eventType, filename) => {
95
+ // Use chokidar with polling to avoid EMFILE errors from too many native watchers
96
+ const watcher = chokidar.watch(dir, {
97
+ persistent: true,
98
+ ignoreInitial: true,
99
+ usePolling: true,
100
+ interval: 1000,
101
+ depth: 99,
102
+ ignored: ['**/.git/**', '**/*.lock'],
103
+ });
104
+
105
+ watcher.on('all', (eventType, filepath) => {
106
+ const filename = path.relative(dir, filepath);
96
107
  this._handleFileChange(agent, eventType, filename);
97
108
  });
98
109
 
@@ -158,7 +169,7 @@ class ActivityMonitor {
158
169
  }
159
170
 
160
171
  /**
161
- * Handle a file change event from fs.watch.
172
+ * Handle a file change event from chokidar.
162
173
  * Debounces activity detection per agent.
163
174
  *
164
175
  * @param {string} agent - Agent name