Skip to content

Commit 5c7243f

Browse files
authored
Merge pull request #10 from All-Hands-AI/feature/simple-agent-interaction
Add simple agent interaction functionality
2 parents 56facb5 + bf1d7a1 commit 5c7243f

File tree

4 files changed

+345
-13
lines changed

4 files changed

+345
-13
lines changed

openhands_cli/agent_chat.py

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Agent chat functionality for OpenHands CLI.
4+
Provides a conversation interface with an AI agent using OpenHands patterns.
5+
"""
6+
7+
import logging
8+
import os
9+
import sys
10+
import traceback
11+
12+
# Ensure we use the agent-sdk openhands package, not the main OpenHands package
13+
# Remove the main OpenHands code path if it exists
14+
if "/openhands/code" in sys.path:
15+
sys.path.remove("/openhands/code")
16+
17+
from prompt_toolkit import PromptSession, print_formatted_text
18+
from prompt_toolkit.formatted_text import HTML
19+
from prompt_toolkit.shortcuts import clear
20+
from pydantic import SecretStr
21+
22+
try:
23+
from openhands.core.agent.codeact_agent import CodeActAgent
24+
from openhands.core.config import LLMConfig
25+
from openhands.core.conversation import Conversation
26+
from openhands.core.event import EventType
27+
from openhands.core.llm import LLM, Message, TextContent
28+
from openhands.core.tool import Tool
29+
from openhands.tools.execute_bash import BashExecutor, execute_bash_tool
30+
from openhands.tools.str_replace_editor import (
31+
FileEditorExecutor,
32+
str_replace_editor_tool,
33+
)
34+
except ImportError as e:
35+
print_formatted_text(HTML(f"<red>Error importing OpenHands SDK: {e}</red>"))
36+
print_formatted_text(
37+
HTML("<yellow>Please ensure the openhands-sdk is properly installed.</yellow>")
38+
)
39+
sys.exit(1)
40+
41+
42+
logger = logging.getLogger(__name__)
43+
44+
45+
def setup_agent() -> tuple[LLM | None, CodeActAgent | None, Conversation | None]:
46+
"""Setup the agent with environment variables."""
47+
try:
48+
# Get API configuration from environment
49+
api_key = os.getenv("LITELLM_API_KEY") or os.getenv("OPENAI_API_KEY")
50+
model = os.getenv("LITELLM_MODEL", "gpt-4o-mini")
51+
base_url = os.getenv("LITELLM_BASE_URL")
52+
53+
if not api_key:
54+
print_formatted_text(
55+
HTML(
56+
"<red>Error: No API key found. Please set LITELLM_API_KEY or OPENAI_API_KEY environment variable.</red>"
57+
)
58+
)
59+
return None, None, None
60+
61+
# Configure LLM
62+
llm_config = LLMConfig(
63+
model=model,
64+
api_key=SecretStr(api_key) if api_key else None,
65+
)
66+
67+
if base_url:
68+
llm_config.base_url = base_url
69+
70+
llm = LLM(config=llm_config)
71+
72+
# Setup tools
73+
cwd = os.getcwd()
74+
bash = BashExecutor(working_dir=cwd)
75+
file_editor = FileEditorExecutor()
76+
tools: list[Tool] = [
77+
execute_bash_tool.set_executor(executor=bash),
78+
str_replace_editor_tool.set_executor(executor=file_editor),
79+
]
80+
81+
# Create agent
82+
agent = CodeActAgent(llm=llm, tools=tools)
83+
84+
# Setup conversation with callback
85+
def conversation_callback(event: EventType) -> None:
86+
logger.debug(f"Conversation event: {str(event)[:200]}...")
87+
88+
conversation = Conversation(agent=agent, callbacks=[conversation_callback])
89+
90+
print_formatted_text(
91+
HTML(f"<green>✓ Agent initialized with model: {model}</green>")
92+
)
93+
return llm, agent, conversation
94+
95+
except Exception as e:
96+
print_formatted_text(HTML(f"<red>Error setting up agent: {str(e)}</red>"))
97+
traceback.print_exc()
98+
return None, None, None
99+
100+
101+
def display_welcome() -> None:
102+
"""Display welcome message."""
103+
clear()
104+
print_formatted_text(HTML("<gold>🤖 OpenHands Agent Chat</gold>"))
105+
print_formatted_text(HTML("<grey>AI Agent Conversation Interface</grey>"))
106+
print()
107+
print_formatted_text(HTML("<skyblue>Commands:</skyblue>"))
108+
print_formatted_text(HTML(" <white>/exit</white> - Exit the chat"))
109+
print_formatted_text(HTML(" <white>/clear</white> - Clear the screen"))
110+
print_formatted_text(HTML(" <white>/help</white> - Show this help"))
111+
print()
112+
print_formatted_text(
113+
HTML("<green>Type your message and press Enter to chat with the agent.</green>")
114+
)
115+
print()
116+
117+
118+
def run_agent_chat() -> None:
119+
"""Run the agent chat session using the agent SDK."""
120+
# Setup agent
121+
llm, agent, conversation = setup_agent()
122+
if not agent or not conversation:
123+
return
124+
125+
display_welcome()
126+
127+
# Create prompt session
128+
session = PromptSession()
129+
130+
# Main chat loop
131+
while True:
132+
try:
133+
# Get user input
134+
user_input = session.prompt(
135+
HTML("<blue>You: </blue>"),
136+
multiline=False,
137+
)
138+
139+
if not user_input.strip():
140+
continue
141+
142+
# Handle commands
143+
if user_input.strip().lower() == "/exit":
144+
print_formatted_text(HTML("<yellow>Goodbye! 👋</yellow>"))
145+
break
146+
elif user_input.strip().lower() == "/clear":
147+
clear()
148+
display_welcome()
149+
continue
150+
elif user_input.strip().lower() == "/help":
151+
display_welcome()
152+
continue
153+
154+
# Send message to agent
155+
print_formatted_text(HTML("<green>Agent: </green>"), end="")
156+
157+
try:
158+
# Create message and send to conversation
159+
message = Message(
160+
role="user",
161+
content=[TextContent(text=user_input)],
162+
)
163+
164+
conversation.send_message(message)
165+
conversation.run()
166+
167+
# Get the last response from the conversation
168+
# For simplicity, we'll just indicate the agent processed the request
169+
print_formatted_text(
170+
HTML("<green>✓ Agent has processed your request.</green>")
171+
)
172+
173+
except Exception as e:
174+
print_formatted_text(HTML(f"<red>Error: {str(e)}</red>"))
175+
176+
print() # Add spacing
177+
178+
except KeyboardInterrupt:
179+
print_formatted_text(
180+
HTML("\n<yellow>Chat interrupted. Type /exit to quit.</yellow>")
181+
)
182+
continue
183+
except EOFError:
184+
print_formatted_text(HTML("\n<yellow>Goodbye! 👋</yellow>"))
185+
break
186+
187+
188+
def main() -> None:
189+
"""Main entry point for agent chat."""
190+
try:
191+
run_agent_chat()
192+
except KeyboardInterrupt:
193+
print_formatted_text(HTML("\n<yellow>Goodbye! 👋</yellow>"))
194+
except Exception as e:
195+
print_formatted_text(HTML(f"<red>Unexpected error: {str(e)}</red>"))
196+
logger.error(f"Main error: {e}")
197+
198+
199+
if __name__ == "__main__":
200+
main()

openhands_cli/simple_main.py

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,108 @@
66

77
import sys
88

9-
from prompt_toolkit import print_formatted_text
9+
from prompt_toolkit import PromptSession, print_formatted_text
1010
from prompt_toolkit.formatted_text import HTML
1111

1212
from openhands_cli.tui import display_banner
1313

1414

15-
def main() -> int:
16-
"""Main entry point for the OpenHands CLI."""
15+
def show_menu() -> str:
16+
"""Show the main menu and get user choice."""
1717
print_formatted_text(HTML("<gold>OpenHands CLI</gold>"))
1818
print_formatted_text(
1919
HTML("<grey>Terminal User Interface for OpenHands AI Agent</grey>")
2020
)
2121
print()
2222

2323
print("🚀 Welcome to OpenHands CLI!")
24-
print("This is a simplified version of the OpenHands Terminal User Interface.")
2524
print()
25+
print("Available options:")
26+
print(" 1. Start Agent Chat - Interactive conversation with AI agent")
27+
print(" 2. Show TUI Demo - Display TUI components")
28+
print(" 3. Exit")
29+
print()
30+
31+
session = PromptSession()
32+
choice: str = session.prompt("Select an option (1-3): ")
33+
return choice.strip()
34+
35+
36+
def show_tui_demo() -> None:
37+
"""Show the TUI demo functionality."""
38+
print()
39+
print("📱 TUI Demo:")
2640
print("Available features:")
2741
print(" • Terminal User Interface (TUI) components")
2842
print(" • Prompt Toolkit integration")
2943
print(" • Agent SDK integration")
3044
print()
3145
print("To use the full functionality, ensure you have:")
3246
print(" 1. OpenHands agent SDK properly configured")
33-
print(" 2. Required environment variables set")
47+
print(" 2. Required environment variables set (LITELLM_API_KEY or OPENAI_API_KEY)")
3448
print(" 3. Proper authentication tokens")
3549
print()
3650

3751
# For now, just show that the CLI is working
3852
try:
39-
display_banner(session_id="setup")
53+
display_banner(session_id="demo")
4054
except ImportError as e:
4155
print(f"Note: Full TUI functionality requires additional setup: {e}")
4256

43-
print("CLI setup complete! 🎉")
57+
print("TUI demo complete! 🎉")
58+
59+
60+
def main() -> int:
61+
"""Main entry point for the OpenHands CLI."""
62+
while True:
63+
try:
64+
choice = show_menu()
65+
66+
if choice == "1":
67+
# Start agent chat
68+
try:
69+
from openhands_cli.agent_chat import main as run_agent_chat
70+
71+
run_agent_chat()
72+
except ImportError as e:
73+
print_formatted_text(
74+
HTML(
75+
f"<red>Error: Agent chat requires additional dependencies: {e}</red>"
76+
)
77+
)
78+
print_formatted_text(
79+
HTML(
80+
"<yellow>Please ensure the agent SDK is properly installed.</yellow>"
81+
)
82+
)
83+
except Exception as e:
84+
print_formatted_text(
85+
HTML(f"<red>Error starting agent chat: {e}</red>")
86+
)
87+
88+
elif choice == "2":
89+
# Show TUI demo
90+
show_tui_demo()
91+
92+
elif choice == "3":
93+
# Exit
94+
print_formatted_text(HTML("<yellow>Goodbye! 👋</yellow>"))
95+
break
96+
97+
else:
98+
print_formatted_text(
99+
HTML("<red>Invalid choice. Please select 1, 2, or 3.</red>")
100+
)
101+
102+
print() # Add spacing between menu iterations
103+
104+
except KeyboardInterrupt:
105+
print_formatted_text(HTML("\n<yellow>Goodbye! 👋</yellow>"))
106+
break
107+
except EOFError:
108+
print_formatted_text(HTML("\n<yellow>Goodbye! 👋</yellow>"))
109+
break
110+
44111
return 0
45112

46113

pyproject.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ classifiers = [
1717
"Programming Language :: Python :: 3.13",
1818
]
1919
dependencies = [
20-
"openhands-sdk @ git+https://github.com/All-Hands-AI/agent-sdk.git@37749a54c18bc628b6bf7517ad96286cecdb8a67#subdirectory=openhands/core",
20+
"openhands-sdk @ git+https://github.com/All-Hands-AI/agent-sdk.git@288e440b344c67c66e2093215521a1394b1509b6#subdirectory=openhands/core",
21+
"openhands-tools @ git+https://github.com/All-Hands-AI/agent-sdk.git@288e440b344c67c66e2093215521a1394b1509b6#subdirectory=openhands/tools",
2122
"prompt-toolkit>=3",
2223
]
2324

@@ -50,7 +51,8 @@ packages = [ { include = "openhands_cli" } ]
5051
[tool.poetry.dependencies]
5152
python = "^3.12"
5253
prompt-toolkit = "^3.0.0"
53-
openhands-sdk = { git = "https://github.com/All-Hands-AI/agent-sdk.git", rev = "37749a54c18bc628b6bf7517ad96286cecdb8a67", subdirectory = "openhands/core" }
54+
openhands-sdk = { git = "https://github.com/All-Hands-AI/agent-sdk.git", rev = "288e440b344c67c66e2093215521a1394b1509b6", subdirectory = "openhands/core" }
55+
openhands-tools = { git = "https://github.com/All-Hands-AI/agent-sdk.git", rev = "288e440b344c67c66e2093215521a1394b1509b6", subdirectory = "openhands/tools" }
5456

5557
[tool.poetry.group.dev.dependencies]
5658
pytest = "^7.0.0"

0 commit comments

Comments
 (0)