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
52 changes: 47 additions & 5 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,21 +287,21 @@ def parse_args() -> argparse.Namespace:
parser.add_argument(
"--base-url",
type=str,
default=os.getenv("PHONE_AGENT_BASE_URL", "http://localhost:8000/v1"),
default=os.getenv("PHONE_AGENT_BASE_URL", "https://open.bigmodel.cn/api/paas/v4"),
help="Model API base URL",
)

parser.add_argument(
"--model",
type=str,
default=os.getenv("PHONE_AGENT_MODEL", "autoglm-phone-9b"),
default=os.getenv("PHONE_AGENT_MODEL", "autoglm-phone"),
help="Model name",
)

parser.add_argument(
"--apikey",
type=str,
default=os.getenv("PHONE_AGENT_API_KEY", "EMPTY"),
default=os.getenv("PHONE_AGENT_API_KEY", "590af9e737b04858bc891cea879913b1.jGxAfNjDG8Tsl8PB"),
help="API key for model authentication",
)

Expand Down Expand Up @@ -368,6 +368,25 @@ def parse_args() -> argparse.Namespace:
help="Language for system prompt (cn or en, default: cn)",
)

# History options
parser.add_argument(
"--history-id",
type=str,
help="History ID to reuse for this task",
)

parser.add_argument(
"--list-history",
action="store_true",
help="List all saved history records",
)

parser.add_argument(
"--clear-history",
action="store_true",
help="Clear all saved history records",
)

parser.add_argument(
"task",
nargs="?",
Expand Down Expand Up @@ -491,6 +510,29 @@ def main():
agent_config=agent_config,
)

# Handle history commands (these need agent to be created)
if args.list_history:
print("Saved history records:")
print("-" * 80)
history_records = agent.list_history()
if not history_records:
print(" No history records found.")
else:
for i, record in enumerate(history_records):
print(f" {i+1}. ID: {record.id}")
print(f" Task: {record.task[:60]}{'...' if len(record.task) > 60 else ''}")
print(f" Result: {record.result}")
print(f" Steps: {record.metadata.get('step_count', 0)}")
print(f" Success: {record.metadata.get('success', False)}")
print(f" Timestamp: {record.metadata.get('timestamp', 0)}")
print()
return

if args.clear_history:
agent.clear_history()
print("All history records cleared.")
return

# Print header
print("=" * 50)
print("Phone Agent - AI-powered phone automation")
Expand All @@ -512,7 +554,7 @@ def main():
# Run with provided task or enter interactive mode
if args.task:
print(f"\nTask: {args.task}\n")
result = agent.run(args.task)
result = agent.run(args.task, history_id=args.history_id)
print(f"\nResult: {result}")
else:
# Interactive mode
Expand All @@ -532,7 +574,7 @@ def main():
print()
result = agent.run(task)
print(f"\nResult: {result}\n")
agent.reset()
# Don't reset agent in interactive mode to preserve history

except KeyboardInterrupt:
print("\n\nInterrupted. Goodbye!")
Expand Down
116 changes: 110 additions & 6 deletions phone_agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@
import json
import traceback
from dataclasses import dataclass
from typing import Any, Callable
from typing import Any, Callable, Optional

from phone_agent.actions import ActionHandler
from phone_agent.actions.handler import do, finish, parse_action
from phone_agent.adb import get_current_app, get_screenshot
from phone_agent.config import get_messages, get_system_prompt
from phone_agent.history import (
ContextReuseStrategy,
HistoryConfig,
HistoryManager,
strategy_registry,
)
from phone_agent.model import ModelClient, ModelConfig
from phone_agent.model.client import MessageBuilder

Expand Down Expand Up @@ -65,48 +71,115 @@ def __init__(
self,
model_config: ModelConfig | None = None,
agent_config: AgentConfig | None = None,
history_config: HistoryConfig | None = None,
confirmation_callback: Callable[[str], bool] | None = None,
takeover_callback: Callable[[str], None] | None = None,
):
self.model_config = model_config or ModelConfig()
self.agent_config = agent_config or AgentConfig()
self.history_config = history_config or HistoryConfig()

self.model_client = ModelClient(self.model_config)
self.action_handler = ActionHandler(
device_id=self.agent_config.device_id,
confirmation_callback=confirmation_callback,
takeover_callback=takeover_callback,
)
self.history_manager = HistoryManager(self.history_config)

self._context: list[dict[str, Any]] = []
self._step_count = 0

def run(self, task: str) -> str:
def run(self, task: str, history_id: Optional[str] = None, reuse_strategy: Optional[ContextReuseStrategy] = None) -> str:
"""
Run the agent to complete a task.

Args:
task: Natural language description of the task.
history_id: Optional history ID to reuse. If provided, ignores auto-reuse.
reuse_strategy: Optional custom reuse strategy.

Returns:
Final message from the agent.
"""
self._context = []
# 确定是否复用历史
reuse_history = False
target_history = None

if history_id:
# 使用指定的历史记录
reuse_history = True
target_history = self.history_manager.get(history_id)
elif self.history_manager.should_reuse(task):
# 自动检测到需要复用历史
reuse_history = True
target_history = self.history_manager.get() # 获取最近的历史

# 构建上下文
if reuse_history and target_history:
# 使用默认的完整复用策略
strategy = reuse_strategy or strategy_registry.get("full")
if strategy:
self._context = strategy.build_context(task, target_history)
else:
self._context = []
else:
# 重置上下文
self._context = []

self._step_count = 0

# First step with user prompt
result = self._execute_step(task, is_first=True)
final_result = result.message or "Task completed"

if result.finished:
return result.message or "Task completed"
# 任务完成后保存历史记录
if self.history_config.enable_auto_save:
self.history_manager.save(
task=task,
context=self._context,
result=final_result,
metadata={
"step_count": self._step_count,
"success": True,
"timestamp": 0
}
)
return final_result

# Continue until finished or max steps reached
while self._step_count < self.agent_config.max_steps:
result = self._execute_step(is_first=False)
final_result = result.message or "Task completed"

if result.finished:
return result.message or "Task completed"

# 任务完成后保存历史记录
if self.history_config.enable_auto_save:
self.history_manager.save(
task=task,
context=self._context,
result=final_result,
metadata={
"step_count": self._step_count,
"success": True,
"timestamp": 0
}
)
return final_result

# 任务未完成但达到最大步骤数,也保存历史记录
if self.history_config.enable_auto_save:
self.history_manager.save(
task=task,
context=self._context,
result="Max steps reached",
metadata={
"step_count": self._step_count,
"success": False,
"timestamp": 0
}
)
return "Max steps reached"

def step(self, task: str | None = None) -> StepResult:
Expand Down Expand Up @@ -250,3 +323,34 @@ def context(self) -> list[dict[str, Any]]:
def step_count(self) -> int:
"""Get the current step count."""
return self._step_count

def get_history(self, history_id: Optional[str] = None, index: int = 0):
"""
Get a specific history record.

Args:
history_id: Optional history ID to retrieve.
index: Optional index to retrieve (0 for most recent).

Returns:
HistoryItem or None if not found.
"""
return self.history_manager.get(history_id, index)

def list_history(self, limit: Optional[int] = None):
"""
List all saved history records.

Args:
limit: Optional limit on the number of records to return.

Returns:
List of HistoryItem objects.
"""
return self.history_manager.list(limit)

def clear_history(self):
"""
Clear all saved history records.
"""
self.history_manager.clear()
21 changes: 21 additions & 0 deletions phone_agent/history/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""History management module for Phone Agent."""

from phone_agent.history.manager import HistoryItem, HistoryManager, HistoryConfig
from phone_agent.history.strategy import (
ContextReuseStrategy,
FullReuseStrategy,
TaskBasedReuseStrategy,
CustomReuseStrategy,
strategy_registry,
)

__all__ = [
"HistoryItem",
"HistoryManager",
"HistoryConfig",
"ContextReuseStrategy",
"FullReuseStrategy",
"TaskBasedReuseStrategy",
"CustomReuseStrategy",
"strategy_registry",
]
Loading