Skip to content

Commit 0b47cd4

Browse files
ianhodgewarp-agent
andcommitted
Add CLI demo app example
Add an example CLI application that demonstrates how to use the Warp Python SDK to: - Run agent tasks with custom prompts and configurations - Check the status of running tasks - List recent tasks with filtering options Co-Authored-By: Warp <agent@warp.dev>
1 parent dd7a9b7 commit 0b47cd4

File tree

3 files changed

+345
-0
lines changed

3 files changed

+345
-0
lines changed

examples/README.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Warp Agent CLI Demo
2+
3+
A demo CLI application built with the [Warp Python SDK](https://github.com/warpdotdev/warp-sdk-python) that demonstrates how to interact with the Warp Agent API.
4+
5+
## Features
6+
7+
- **Run Tasks**: Submit new agent tasks with custom prompts
8+
- **Monitor Tasks**: Check the status of running tasks with real-time polling
9+
- **List Tasks**: View recent tasks with filtering options
10+
11+
## Installation
12+
13+
```bash
14+
# From the examples directory
15+
pip install warp-agent-sdk
16+
pip install -e .
17+
```
18+
19+
## Configuration
20+
21+
Set your Warp API key as an environment variable:
22+
23+
```bash
24+
export WARP_API_KEY='your-api-key'
25+
```
26+
27+
## Usage
28+
29+
### Run a new task
30+
31+
```bash
32+
# Basic usage
33+
warp-cli run "Fix the bug in auth.go"
34+
35+
# Wait for completion
36+
warp-cli run "Write tests for utils.py" --wait
37+
38+
# Specify a model
39+
warp-cli run "Refactor the database module" --model claude-sonnet-4
40+
41+
# Use a specific environment
42+
warp-cli run "Deploy to staging" --environment your-env-id
43+
44+
# Custom base prompt
45+
warp-cli run "Review this PR" --base-prompt "You are a senior code reviewer."
46+
```
47+
48+
### Get task details
49+
50+
```bash
51+
warp-cli get <task-id>
52+
```
53+
54+
### List recent tasks
55+
56+
```bash
57+
# List last 10 tasks (default)
58+
warp-cli list
59+
60+
# Limit results
61+
warp-cli list --limit 5
62+
63+
# Filter by state
64+
warp-cli list --state INPROGRESS
65+
warp-cli list --state SUCCEEDED
66+
```
67+
68+
## Example Output
69+
70+
```
71+
$ warp-cli run "Fix the bug in auth.go"
72+
🚀 Submitting task: Fix the bug in auth.go
73+
--------------------------------------------------
74+
Task ID: abc123-def456-ghi789
75+
State: ⏳ QUEUED
76+
77+
$ warp-cli list
78+
📋 Listing recent tasks
79+
--------------------------------------------------------------------------------
80+
ID State Title
81+
--------------------------------------------------------------------------------
82+
abc123-def456-ghi789 ▶️ INPROGRESS Fix the bug in auth.go
83+
xyz789-uvw456-rst123 ✅ SUCCEEDED Add unit tests
84+
--------------------------------------------------------------------------------
85+
Total: 2 tasks
86+
```
87+
88+
## API Reference
89+
90+
This CLI demonstrates the following SDK capabilities:
91+
92+
- `client.agent.run()` - Run a new agent task
93+
- `client.agent.tasks.retrieve()` - Get details of a specific task
94+
- `client.agent.tasks.list()` - List recent tasks
95+
96+
For more details, see the [Warp SDK documentation](https://github.com/warpdotdev/warp-sdk-python).

examples/pyproject.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[project]
2+
name = "warp-agent-demo"
3+
version = "0.1.0"
4+
description = "A demo CLI application using the Warp Python SDK"
5+
readme = "README.md"
6+
requires-python = ">=3.9"
7+
dependencies = [
8+
"warp-agent-sdk",
9+
]
10+
11+
[project.scripts]
12+
warp-cli = "warp_cli:main"
13+
14+
[build-system]
15+
requires = ["hatchling"]
16+
build-backend = "hatchling.build"
17+
18+
[tool.hatch.build]
19+
include = ["warp_cli.py"]

examples/warp_cli.py

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Warp Agent CLI - A demo application using the Warp Python SDK.
4+
5+
This CLI allows you to:
6+
- Run agent tasks with custom prompts
7+
- Check the status of running tasks
8+
- List recent tasks
9+
"""
10+
11+
import argparse
12+
import os
13+
import sys
14+
import time
15+
from datetime import datetime
16+
17+
from warp_agent_sdk import WarpAPI
18+
from warp_agent_sdk.types.agent import TaskState
19+
20+
21+
def create_client() -> WarpAPI:
22+
"""Create and return a Warp API client."""
23+
api_key = os.environ.get("WARP_API_KEY")
24+
if not api_key:
25+
print("Error: WARP_API_KEY environment variable is not set.")
26+
print("Please set it with: export WARP_API_KEY='your-api-key'")
27+
sys.exit(1)
28+
return WarpAPI(api_key=api_key)
29+
30+
31+
def format_timestamp(dt: datetime) -> str:
32+
"""Format a datetime object for display."""
33+
return dt.strftime("%Y-%m-%d %H:%M:%S")
34+
35+
36+
def format_state(state: TaskState) -> str:
37+
"""Format task state with color indicators."""
38+
state_icons = {
39+
"QUEUED": "⏳",
40+
"PENDING": "🔄",
41+
"CLAIMED": "🔒",
42+
"INPROGRESS": "▶️",
43+
"SUCCEEDED": "✅",
44+
"FAILED": "❌",
45+
}
46+
return f"{state_icons.get(state, '❓')} {state}"
47+
48+
49+
def run_task(args: argparse.Namespace) -> None:
50+
"""Run a new agent task."""
51+
client = create_client()
52+
53+
print(f"🚀 Submitting task: {args.prompt}")
54+
print("-" * 50)
55+
56+
config = {}
57+
if args.model:
58+
config["model_id"] = args.model
59+
if args.environment:
60+
config["environment_id"] = args.environment
61+
if args.base_prompt:
62+
config["base_prompt"] = args.base_prompt
63+
64+
response = client.agent.run(
65+
prompt=args.prompt,
66+
config=config if config else None,
67+
)
68+
69+
print(f"Task ID: {response.task_id}")
70+
print(f"State: {format_state(response.state)}")
71+
72+
if args.wait:
73+
print("\n⏳ Waiting for task to complete...")
74+
wait_for_task(client, response.task_id)
75+
76+
77+
def wait_for_task(client: WarpAPI, task_id: str) -> None:
78+
"""Poll task status until completion."""
79+
terminal_states = {"SUCCEEDED", "FAILED"}
80+
81+
while True:
82+
task = client.agent.tasks.retrieve(task_id)
83+
print(f" Status: {format_state(task.state)}", end="\r")
84+
85+
if task.state in terminal_states:
86+
print() # New line after status
87+
print("-" * 50)
88+
print(f"Task completed with state: {format_state(task.state)}")
89+
if task.session_link:
90+
print(f"Session link: {task.session_link}")
91+
if task.status_message and task.status_message.message:
92+
print(f"Message: {task.status_message.message}")
93+
break
94+
95+
time.sleep(2)
96+
97+
98+
def get_task(args: argparse.Namespace) -> None:
99+
"""Get details of a specific task."""
100+
client = create_client()
101+
102+
print(f"🔍 Fetching task: {args.task_id}")
103+
print("-" * 50)
104+
105+
task = client.agent.tasks.retrieve(args.task_id)
106+
107+
print(f"Task ID: {task.task_id}")
108+
print(f"Title: {task.title}")
109+
print(f"State: {format_state(task.state)}")
110+
print(f"Created: {format_timestamp(task.created_at)}")
111+
print(f"Updated: {format_timestamp(task.updated_at)}")
112+
print(f"Prompt: {task.prompt[:100]}{'...' if len(task.prompt) > 100 else ''}")
113+
114+
if task.source:
115+
print(f"Source: {task.source}")
116+
if task.session_link:
117+
print(f"Session: {task.session_link}")
118+
if task.status_message and task.status_message.message:
119+
print(f"Message: {task.status_message.message}")
120+
121+
122+
def list_tasks(args: argparse.Namespace) -> None:
123+
"""List recent tasks."""
124+
client = create_client()
125+
126+
print("📋 Listing recent tasks")
127+
print("-" * 80)
128+
129+
params = {}
130+
if args.limit:
131+
params["limit"] = args.limit
132+
if args.state:
133+
params["state"] = args.state
134+
135+
response = client.agent.tasks.list(**params)
136+
137+
if not response.items:
138+
print("No tasks found.")
139+
return
140+
141+
# Print header
142+
print(f"{'ID':<36} {'State':<15} {'Title':<30}")
143+
print("-" * 80)
144+
145+
for task in response.items:
146+
title = task.title[:28] + ".." if len(task.title) > 30 else task.title
147+
print(f"{task.task_id:<36} {format_state(task.state):<15} {title:<30}")
148+
149+
print("-" * 80)
150+
print(f"Total: {len(response.items)} tasks")
151+
152+
153+
def main() -> None:
154+
"""Main entry point for the CLI."""
155+
parser = argparse.ArgumentParser(
156+
description="Warp Agent CLI - Interact with the Warp API",
157+
formatter_class=argparse.RawDescriptionHelpFormatter,
158+
epilog="""
159+
Examples:
160+
%(prog)s run "Fix the bug in auth.go"
161+
%(prog)s run "Write tests for utils.py" --wait
162+
%(prog)s run "Refactor the database module" --model claude-sonnet-4
163+
%(prog)s get abc123-task-id
164+
%(prog)s list --limit 10
165+
%(prog)s list --state INPROGRESS
166+
""",
167+
)
168+
169+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
170+
171+
# Run command
172+
run_parser = subparsers.add_parser("run", help="Run a new agent task")
173+
run_parser.add_argument("prompt", help="The task prompt/instruction for the agent")
174+
run_parser.add_argument(
175+
"--wait", "-w",
176+
action="store_true",
177+
help="Wait for the task to complete",
178+
)
179+
run_parser.add_argument(
180+
"--model", "-m",
181+
help="LLM model to use (e.g., claude-sonnet-4)",
182+
)
183+
run_parser.add_argument(
184+
"--environment", "-e",
185+
help="Environment ID to run the agent in",
186+
)
187+
run_parser.add_argument(
188+
"--base-prompt", "-b",
189+
help="Custom base prompt for the agent",
190+
)
191+
run_parser.set_defaults(func=run_task)
192+
193+
# Get command
194+
get_parser = subparsers.add_parser("get", help="Get details of a specific task")
195+
get_parser.add_argument("task_id", help="The task ID to retrieve")
196+
get_parser.set_defaults(func=get_task)
197+
198+
# List command
199+
list_parser = subparsers.add_parser("list", help="List recent tasks")
200+
list_parser.add_argument(
201+
"--limit", "-l",
202+
type=int,
203+
default=10,
204+
help="Maximum number of tasks to return (default: 10)",
205+
)
206+
list_parser.add_argument(
207+
"--state", "-s",
208+
choices=["QUEUED", "PENDING", "CLAIMED", "INPROGRESS", "SUCCEEDED", "FAILED"],
209+
help="Filter tasks by state",
210+
)
211+
list_parser.set_defaults(func=list_tasks)
212+
213+
args = parser.parse_args()
214+
215+
if args.command is None:
216+
parser.print_help()
217+
sys.exit(1)
218+
219+
try:
220+
args.func(args)
221+
except KeyboardInterrupt:
222+
print("\n\nOperation cancelled.")
223+
sys.exit(130)
224+
except Exception as e:
225+
print(f"\n❌ Error: {e}")
226+
sys.exit(1)
227+
228+
229+
if __name__ == "__main__":
230+
main()

0 commit comments

Comments
 (0)