deepagent-code 0.1.3__tar.gz → 0.1.4__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepagent-code
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: A Claude Code-style CLI for running LangGraph agents from the terminal
5
5
  Author-email: Kedar Dabhadkar <kdabhadk@gmail.com>
6
6
  License-Expression: MIT
@@ -95,7 +95,7 @@ In the interactive loop:
95
95
 
96
96
  ```bash
97
97
  # Agent location (path/to/file.py:variable_name or module:variable)
98
- export DEEPAGENT_AGENT_SPEC="my_agent.py:graph"
98
+ export DEEPAGENT_SPEC="my_agent.py:graph"
99
99
  deepagent-code
100
100
 
101
101
  # Working directory
@@ -63,7 +63,7 @@ In the interactive loop:
63
63
 
64
64
  ```bash
65
65
  # Agent location (path/to/file.py:variable_name or module:variable)
66
- export DEEPAGENT_AGENT_SPEC="my_agent.py:graph"
66
+ export DEEPAGENT_SPEC="my_agent.py:graph"
67
67
  deepagent-code
68
68
 
69
69
  # Working directory
@@ -7,6 +7,7 @@ import importlib.util
7
7
  import json
8
8
  import os
9
9
  import re
10
+ import subprocess
10
11
  import sys
11
12
  import threading
12
13
  import time
@@ -53,7 +54,7 @@ SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇",
53
54
 
54
55
 
55
56
  # Version info
56
- __version__ = "0.1.3"
57
+ __version__ = "0.1.4"
57
58
 
58
59
 
59
60
  # Slash command registry
@@ -256,8 +257,87 @@ def get_agent_name(graph) -> str:
256
257
  return "AgentCode"
257
258
 
258
259
 
259
- def print_header_box(agent_name: str, cwd: str):
260
- """Print an elegant header with the agent name and version."""
260
+ def get_agent_description(graph) -> Optional[str]:
261
+ """Extract agent description from graph object, if available."""
262
+ # Try common attribute names for agent description
263
+ for attr in ('description', 'agent_description', '_description', '__doc__'):
264
+ if hasattr(graph, attr):
265
+ desc = getattr(graph, attr)
266
+ if desc and isinstance(desc, str) and desc.strip():
267
+ return desc.strip()
268
+ # Check if it's a compiled graph with a description in builder
269
+ if hasattr(graph, 'builder') and hasattr(graph.builder, 'description'):
270
+ desc = graph.builder.description
271
+ if desc and isinstance(desc, str) and desc.strip():
272
+ return desc.strip()
273
+ return None
274
+
275
+
276
+ def text_to_ascii_art(text: str) -> List[str]:
277
+ """Convert text to ASCII art using a clean block font.
278
+
279
+ Returns a list of strings, one per line of the ASCII art.
280
+ All characters are exactly 3 chars wide for consistent spacing.
281
+ """
282
+ # Clean 3-line block font - each char is exactly 3 wide
283
+ FONT = {
284
+ 'A': ['▄▀▄', '█▀█', '▀ ▀'],
285
+ 'B': ['█▀▄', '█▀▄', '▀▀▀'],
286
+ 'C': ['▄▀▀', '█ ', '▀▀▀'],
287
+ 'D': ['█▀▄', '█ █', '▀▀▀'],
288
+ 'E': ['█▀▀', '█▀▀', '▀▀▀'],
289
+ 'F': ['█▀▀', '█▀▀', '▀ '],
290
+ 'G': ['▄▀▀', '█▀█', '▀▀▀'],
291
+ 'H': ['█ █', '█▀█', '▀ ▀'],
292
+ 'I': ['▀█▀', ' █ ', '▀▀▀'],
293
+ 'J': ['▀▀█', ' █', '▀▀▀'],
294
+ 'K': ['█ █', '█▀▄', '▀ ▀'],
295
+ 'L': ['█ ', '█ ', '▀▀▀'],
296
+ 'M': ['█▄█', '█ █', '▀ ▀'],
297
+ 'N': ['█▀█', '█ █', '▀ ▀'],
298
+ 'O': ['▄▀▄', '█ █', '▀▀▀'],
299
+ 'P': ['█▀▄', '█▀▀', '▀ '],
300
+ 'Q': ['▄▀▄', '█ █', '▀▀█'],
301
+ 'R': ['█▀▄', '█▀▄', '▀ ▀'],
302
+ 'S': ['▄▀▀', '▀▀▄', '▀▀▀'],
303
+ 'T': ['▀█▀', ' █ ', ' ▀ '],
304
+ 'U': ['█ █', '█ █', '▀▀▀'],
305
+ 'V': ['█ █', '█ █', ' ▀ '],
306
+ 'W': ['█ █', '█▀█', '▀ ▀'],
307
+ 'X': ['▀▄▀', ' █ ', '▀ ▀'],
308
+ 'Y': ['█ █', ' █ ', ' ▀ '],
309
+ 'Z': ['▀▀█', ' █ ', '█▀▀'],
310
+ '0': ['▄▀▄', '█ █', '▀▀▀'],
311
+ '1': ['▄█ ', ' █ ', '▀▀▀'],
312
+ '2': ['▀▀█', '▄▀▀', '▀▀▀'],
313
+ '3': ['▀▀█', ' ▀█', '▀▀▀'],
314
+ '4': ['█ █', '▀▀█', ' ▀'],
315
+ '5': ['█▀▀', '▀▀▄', '▀▀▀'],
316
+ '6': ['▄▀▀', '█▀█', '▀▀▀'],
317
+ '7': ['▀▀█', ' █', ' ▀'],
318
+ '8': ['▄▀▄', '█▀█', '▀▀▀'],
319
+ '9': ['▄▀█', '▀▀█', '▀▀▀'],
320
+ ' ': [' ', ' ', ' '],
321
+ '-': [' ', '▀▀▀', ' '],
322
+ '_': [' ', ' ', '▀▀▀'],
323
+ '.': [' ', ' ', ' ▀ '],
324
+ }
325
+
326
+ # Default char for unknown characters
327
+ DEFAULT = [' ', ' █ ', ' ']
328
+
329
+ lines = ['', '', '']
330
+ for char in text.upper():
331
+ char_art = FONT.get(char, DEFAULT)
332
+ for i in range(3):
333
+ lines[i] += char_art[i] + ' '
334
+
335
+ # Remove only the final trailing space we added (not internal spaces from chars like T, P)
336
+ return [line[:-1] if line.endswith(' ') else line for line in lines]
337
+
338
+
339
+ def print_header_box(agent_name: str, cwd: str, description: Optional[str] = None):
340
+ """Print an elegant header with ASCII art agent name, optional description, and cwd."""
261
341
  term_width = get_terminal_width()
262
342
 
263
343
  # Box drawing characters
@@ -267,15 +347,41 @@ def print_header_box(agent_name: str, cwd: str):
267
347
  # Calculate inner width (accounting for borders and padding)
268
348
  inner_width = term_width - 4 # 2 for borders, 2 for padding
269
349
 
270
- # Build the header content
271
- title_line = agent_name.center(inner_width)
272
- cwd_display = cwd if len(cwd) <= inner_width else "..." + cwd[-(inner_width - 3):]
273
- cwd_line = cwd_display.center(inner_width)
350
+ # Generate ASCII art for agent name
351
+ ascii_lines = text_to_ascii_art(agent_name)
352
+ ascii_width = max(len(line) for line in ascii_lines) if ascii_lines else 0
353
+
354
+ # Use ASCII art if it fits in terminal width
355
+ use_ascii = ascii_width <= inner_width
356
+
357
+ # Build cwd line with label
358
+ cwd_label = "cwd: "
359
+ max_cwd_len = inner_width - len(cwd_label)
360
+ cwd_display = cwd if len(cwd) <= max_cwd_len else "..." + cwd[-(max_cwd_len - 3):]
361
+ cwd_with_label = f"{cwd_label}{cwd_display}"
362
+ cwd_line = cwd_with_label.center(inner_width)
274
363
 
275
364
  # Print the box with gradient-style coloring
276
365
  print()
277
366
  print(f"{BRIGHT_CYAN}{TL}{H * (term_width - 2)}{TR}{RESET}")
278
- print(f"{BRIGHT_CYAN}{V}{RESET} {BOLD}{BRIGHT_CYAN}{title_line}{RESET} {BRIGHT_CYAN}{V}{RESET}")
367
+
368
+ if use_ascii:
369
+ # Print ASCII art lines centered
370
+ for line in ascii_lines:
371
+ centered_line = line.center(inner_width)
372
+ print(f"{BRIGHT_CYAN}{V}{RESET} {BOLD}{BRIGHT_CYAN}{centered_line}{RESET} {BRIGHT_CYAN}{V}{RESET}")
373
+ else:
374
+ # Fall back to plain text if ASCII art doesn't fit
375
+ title_line = agent_name.center(inner_width)
376
+ print(f"{BRIGHT_CYAN}{V}{RESET} {BOLD}{BRIGHT_CYAN}{title_line}{RESET} {BRIGHT_CYAN}{V}{RESET}")
377
+
378
+ # Print description line if available
379
+ if description:
380
+ # Truncate description if too long
381
+ desc_display = description if len(description) <= inner_width else description[:inner_width - 3] + "..."
382
+ desc_line = desc_display.center(inner_width)
383
+ print(f"{CYAN}{V}{RESET} {DIM}{ITALIC}{desc_line}{RESET} {CYAN}{V}{RESET}")
384
+
279
385
  print(f"{CYAN}{V}{RESET} {DIM}{cwd_line}{RESET} {CYAN}{V}{RESET}")
280
386
  print(f"{CYAN}{BL}{H * (term_width - 2)}{BR}{RESET}")
281
387
 
@@ -298,7 +404,7 @@ def render_markdown(text: str) -> str:
298
404
 
299
405
  def parse_agent_spec(agent_spec: str) -> Tuple[str, str]:
300
406
  """
301
- Parse DEEPAGENT_AGENT_SPEC format: path/to/file.py:variable_name.
407
+ Parse agent spec format: path/to/file.py:variable_name.
302
408
 
303
409
  Args:
304
410
  agent_spec: Agent specification string
@@ -1090,6 +1196,7 @@ def run_conversation_loop(
1090
1196
  graph,
1091
1197
  config: Dict[str, Any],
1092
1198
  agent_name: str = "AgentCode",
1199
+ agent_description: Optional[str] = None,
1093
1200
  use_async: bool = False,
1094
1201
  interactive: bool = True,
1095
1202
  verbose: bool = False,
@@ -1103,8 +1210,8 @@ def run_conversation_loop(
1103
1210
  # Set up tab completion for slash commands
1104
1211
  setup_readline_completion()
1105
1212
 
1106
- # Print box-drawn header with agent name
1107
- print_header_box(agent_name, os.getcwd())
1213
+ # Print box-drawn header with agent name and description
1214
+ print_header_box(agent_name, os.getcwd(), agent_description)
1108
1215
 
1109
1216
  # Print welcome message with tips
1110
1217
  print_welcome()
@@ -1167,6 +1274,28 @@ def run_conversation_loop(
1167
1274
  print(f"{DIM}Type /help to see available commands{RESET}")
1168
1275
  continue
1169
1276
 
1277
+ # Handle bang commands (!) - execute bash directly
1278
+ if user_input.startswith("!"):
1279
+ bash_cmd = user_input[1:].strip()
1280
+ if bash_cmd:
1281
+ print()
1282
+ try:
1283
+ result = subprocess.run(
1284
+ bash_cmd,
1285
+ shell=True,
1286
+ capture_output=True,
1287
+ text=True,
1288
+ )
1289
+ if result.stdout:
1290
+ print(result.stdout, end="")
1291
+ if result.stderr:
1292
+ print(f"{RED}{result.stderr}{RESET}", end="")
1293
+ if result.returncode != 0:
1294
+ print(f"{DIM}Exit code: {result.returncode}{RESET}")
1295
+ except Exception as e:
1296
+ print(f"{RED}Error executing command: {e}{RESET}")
1297
+ continue
1298
+
1170
1299
  # Handle "exit" as a special case (without slash)
1171
1300
  if user_input.lower() == "exit":
1172
1301
  break
@@ -1253,7 +1382,7 @@ def main(
1253
1382
  Supports environment variables for configuration:
1254
1383
 
1255
1384
  \b
1256
- - DEEPAGENT_AGENT_SPEC: Agent location (same formats as above)
1385
+ - DEEPAGENT_SPEC: Agent location (same formats as above)
1257
1386
  - DEEPAGENT_WORKSPACE_ROOT: Working directory for the agent
1258
1387
  - DEEPAGENT_CONFIG: Configuration JSON string or path to JSON file
1259
1388
  - DEEPAGENT_STREAM_MODE: Stream mode for LangGraph (updates or values)
@@ -1268,8 +1397,8 @@ def main(
1268
1397
  deepagent-code -m "Hello, agent!"
1269
1398
  """
1270
1399
  try:
1271
- # Get environment variables
1272
- env_agent_spec = os.getenv('DEEPAGENT_AGENT_SPEC')
1400
+ # Get environment variables (DEEPAGENT_SPEC preferred, DEEPAGENT_AGENT_SPEC for backwards compat)
1401
+ env_agent_spec = os.getenv('DEEPAGENT_SPEC') or os.getenv('DEEPAGENT_AGENT_SPEC')
1273
1402
  env_workspace_root = os.getenv('DEEPAGENT_WORKSPACE_ROOT')
1274
1403
  env_config = os.getenv('DEEPAGENT_CONFIG')
1275
1404
  env_stream_mode = os.getenv('DEEPAGENT_STREAM_MODE', 'updates')
@@ -1288,7 +1417,7 @@ def main(
1288
1417
  print(f"\n{DIM}Usage:{RESET}")
1289
1418
  print(f" deepagent-code path/to/agent.py:graph")
1290
1419
  print(f" deepagent-code mypackage.module:agent")
1291
- print(f"\n{DIM}Or set DEEPAGENT_AGENT_SPEC environment variable{RESET}")
1420
+ print(f"\n{DIM}Or set DEEPAGENT_SPEC environment variable{RESET}")
1292
1421
  sys.exit(1)
1293
1422
 
1294
1423
  # Change to workspace root if specified
@@ -1331,14 +1460,16 @@ def main(
1331
1460
  if "thread_id" not in config_dict["configurable"]:
1332
1461
  config_dict["configurable"]["thread_id"] = str(uuid.uuid4())
1333
1462
 
1334
- # Extract agent name from graph object
1463
+ # Extract agent name and description from graph object
1335
1464
  agent_name = get_agent_name(graph)
1465
+ agent_description = get_agent_description(graph)
1336
1466
 
1337
1467
  # Run the conversation loop
1338
1468
  run_conversation_loop(
1339
1469
  graph=graph,
1340
1470
  config=config_dict,
1341
1471
  agent_name=agent_name,
1472
+ agent_description=agent_description,
1342
1473
  use_async=use_async,
1343
1474
  interactive=interactive,
1344
1475
  verbose=verbose,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepagent-code
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: A Claude Code-style CLI for running LangGraph agents from the terminal
5
5
  Author-email: Kedar Dabhadkar <kdabhadk@gmail.com>
6
6
  License-Expression: MIT
@@ -95,7 +95,7 @@ In the interactive loop:
95
95
 
96
96
  ```bash
97
97
  # Agent location (path/to/file.py:variable_name or module:variable)
98
- export DEEPAGENT_AGENT_SPEC="my_agent.py:graph"
98
+ export DEEPAGENT_SPEC="my_agent.py:graph"
99
99
  deepagent-code
100
100
 
101
101
  # Working directory
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "deepagent-code"
7
- version = "0.1.3"
7
+ version = "0.1.4"
8
8
  description = "A Claude Code-style CLI for running LangGraph agents from the terminal"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
File without changes
File without changes