Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions libs/deepagents-cli/deepagents_cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ cli/
- `cli_main()` - Console script entry point (called when you run `deepagents`)
- `main()` - Async main function that orchestrates agent creation and CLI
- `simple_cli()` - Main interactive loop handling user input
- Executes optional initial prompt before entering interactive mode
- `parse_args()` - Command-line argument parsing
- Accepts optional positional `prompt` argument for piping prompts
- `check_cli_dependencies()` - Validates required packages are installed

### `config.py` - Configuration & Constants
Expand Down Expand Up @@ -127,6 +129,18 @@ Display output via ui.py (TokenTracker, console)

## Key Features

### Command-Line Prompt Execution
Pass a prompt as a command-line argument to execute it and then enter interactive mode:
```bash
deepagents "create a hello.py file"
deepagents --agent mybot "review the last commit"
```

This is useful for:
- Quick tasks that you want to follow up on
- Starting a session with initial context
- Automating the first step of a workflow

### File Context Injection
Type `@filename` and press Tab to autocomplete and inject file content into your prompt.

Expand Down Expand Up @@ -181,9 +195,13 @@ To modify the CLI:
# From project root
uv run python -m deepagents.cli

# With initial prompt
uv run python -m deepagents.cli "analyze this codebase"

# Or install in editable mode
uv pip install -e .
deepagents
deepagents "create a test file"
```

## Entry Point
Expand Down
86 changes: 78 additions & 8 deletions libs/deepagents-cli/deepagents_cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,58 @@ def check_cli_dependencies():

def parse_args():
"""Parse command line arguments."""
# Check if we have a subcommand or interactive mode with prompt
# Strategy: Look at the arguments to determine which parser to use
known_commands = {"list", "help", "reset"}

# Scan through argv to find first argument that's not an option or option value
# We need to skip --option value pairs
skip_next = False
first_positional = None

for arg in sys.argv[1:]:
if skip_next:
skip_next = False
continue

if arg.startswith("-"):
# Check if this option takes a value (--agent, but not --auto-approve)
if arg in ["--agent", "--target"]:
skip_next = True
continue

# Found first positional argument
first_positional = arg
break

# Determine which parser to use
use_subparser = first_positional is None or first_positional in known_commands

if not use_subparser:
# Interactive mode with prompt - use simple parser
parser = argparse.ArgumentParser(
description="DeepAgents - AI Coding Assistant",
formatter_class=argparse.RawDescriptionHelpFormatter,
add_help=False,
)
parser.add_argument(
"--agent",
default="agent",
help="Agent identifier for separate memory stores (default: agent).",
)
parser.add_argument(
"--auto-approve",
action="store_true",
help="Auto-approve tool usage without prompting (disables human-in-the-loop)",
)
parser.add_argument(
"prompt",
nargs="?",
help="Optional prompt to execute before entering interactive mode",
)
return parser.parse_args()

# Use parser with subcommands
parser = argparse.ArgumentParser(
description="DeepAgents - AI Coding Assistant",
formatter_class=argparse.RawDescriptionHelpFormatter,
Expand All @@ -78,7 +130,7 @@ def parse_args():
"--target", dest="source_agent", help="Copy prompt from another agent"
)

# Default interactive mode
# Default interactive mode arguments (for when no subcommand is given)
parser.add_argument(
"--agent",
default="agent",
Expand All @@ -89,11 +141,18 @@ def parse_args():
action="store_true",
help="Auto-approve tool usage without prompting (disables human-in-the-loop)",
)
parser.add_argument(
"prompt",
nargs="?",
help="Optional prompt to execute before entering interactive mode",
)

return parser.parse_args()


async def simple_cli(agent, assistant_id: str | None, session_state, baseline_tokens: int = 0):
async def simple_cli(
agent, assistant_id: str | None, session_state, baseline_tokens: int = 0, initial_prompt: str | None = None
):
"""Main CLI loop."""
console.clear()
console.print(DEEP_AGENTS_ASCII, style=f"bold {COLORS['primary']}")
Expand Down Expand Up @@ -133,6 +192,11 @@ async def simple_cli(agent, assistant_id: str | None, session_state, baseline_to
token_tracker = TokenTracker()
token_tracker.set_baseline(baseline_tokens)

# Execute initial prompt if provided
if initial_prompt:
console.print(f"[bold {COLORS['user']}]>[/bold {COLORS['user']}] {initial_prompt}")
execute_task(initial_prompt, agent, assistant_id, session_state, token_tracker)

while True:
try:
user_input = await session.prompt_async()
Expand Down Expand Up @@ -170,7 +234,7 @@ async def simple_cli(agent, assistant_id: str | None, session_state, baseline_to
execute_task(user_input, agent, assistant_id, session_state, token_tracker)


async def main(assistant_id: str, session_state):
async def main(assistant_id: str, session_state, initial_prompt: str | None = None):
"""Main entry point."""
# Create the model (checks API keys)
model = create_model()
Expand All @@ -191,7 +255,7 @@ async def main(assistant_id: str, session_state):
baseline_tokens = calculate_baseline_tokens(model, agent_dir, system_prompt)

try:
await simple_cli(agent, assistant_id, session_state, baseline_tokens)
await simple_cli(agent, assistant_id, session_state, baseline_tokens, initial_prompt)
except Exception as e:
console.print(f"\n[bold red]❌ Error:[/bold red] {e}\n")

Expand All @@ -204,18 +268,24 @@ def cli_main():
try:
args = parse_args()

if args.command == "help":
# Check if we have a subcommand (command attribute only exists when using subparser)
command = getattr(args, "command", None)

if command == "help":
show_help()
elif args.command == "list":
elif command == "list":
list_agents()
elif args.command == "reset":
elif command == "reset":
reset_agent(args.agent, args.source_agent)
else:
# Create session state from args
session_state = SessionState(auto_approve=args.auto_approve)

# Get initial prompt if provided
initial_prompt = getattr(args, "prompt", None)

# API key validation happens in create_model()
asyncio.run(main(args.agent, session_state))
asyncio.run(main(args.agent, session_state, initial_prompt))
except KeyboardInterrupt:
# Clean exit on Ctrl+C - suppress ugly traceback
console.print("\n\n[yellow]Interrupted[/yellow]")
Expand Down
14 changes: 9 additions & 5 deletions libs/deepagents-cli/deepagents_cli/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,13 +414,13 @@ def show_help():
console.print()

console.print("[bold]Usage:[/bold]", style=COLORS["primary"])
console.print(" deepagents [--agent NAME] [--auto-approve] Start interactive session")
console.print(" deepagents list List all available agents")
console.print(" deepagents reset --agent AGENT Reset agent to default prompt")
console.print(" deepagents [--agent NAME] [--auto-approve] [PROMPT] Start interactive session")
console.print(" deepagents list List all available agents")
console.print(" deepagents reset --agent AGENT Reset agent to default prompt")
console.print(
" deepagents reset --agent AGENT --target SOURCE Reset agent to copy of another agent"
" deepagents reset --agent AGENT --target SOURCE Reset agent to copy of another agent"
)
console.print(" deepagents help Show this help message")
console.print(" deepagents help Show this help message")
console.print()

console.print("[bold]Examples:[/bold]", style=COLORS["primary"])
Expand All @@ -435,6 +435,10 @@ def show_help():
" deepagents --auto-approve # Start with auto-approve enabled",
style=COLORS["dim"],
)
console.print(
' deepagents "create hello.py" # Execute prompt then enter interactive mode',
style=COLORS["dim"],
)
console.print(
" deepagents list # List all agents", style=COLORS["dim"]
)
Expand Down