Coverage for agentos/core/context.py: 56%
81 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-06 19:15 +0800
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-06 19:15 +0800
1"""
2上下文管理器 — 构建Agent所需的完整上下文。
3"""
5from __future__ import annotations
7from dataclasses import dataclass
8from typing import Any
11@dataclass
12class ToolCall:
13 """模型请求的工具调用。"""
15 name: str
16 arguments: dict[str, Any]
19@dataclass
20class ToolResult:
21 """工具调用的返回结果。"""
23 call_id: str
24 output: str | None = None
25 error: str | None = None
26 exit_code: int | None = None
28 @property
29 def is_error(self) -> bool:
30 return self.error is not None
33@dataclass
34class Message:
35 """对话中的单条消息。"""
37 role: str # system | user | assistant | tool
38 content: str
39 tool_calls: list[ToolCall] | None = None
40 tool_call_id: str | None = None
43@dataclass
44class AgentContext:
45 """传给模型的完整上下文。"""
47 messages: list[Message]
48 tools: list[dict] | None = None
49 model_type: str = "openai"
52class ContextManager:
53 """管理Agent会话的全部消息历史。"""
55 def __init__(self, system_prompt: str = "", max_history: int = 200):
56 self.system_prompt = system_prompt
57 self.max_history = max_history
58 self._messages: list[Message] = []
59 self.session_id: str = ""
60 self._current_task: str = ""
61 self._step_count: int = 0
62 self._plan: str = ""
64 async def init_session(self, session_id: str, task: str):
65 self.session_id = session_id
66 self._current_task = task
67 self._step_count = 0
68 self._plan = ""
69 self._messages = []
70 if self.system_prompt:
71 self._messages.append(Message(role="system", content=self.system_prompt))
72 self._messages.append(Message(role="user", content=task))
74 def build_context(
75 self, model_type: str = "openai", tools: list[dict] | None = None
76 ) -> AgentContext:
77 self._step_count += 1
78 messages = self._messages[-self.max_history :]
79 return AgentContext(messages=messages, tools=tools, model_type=model_type)
81 def update_plan(self, new_plan: str):
82 self._plan = new_plan
83 self._messages.append(Message(role="system", content=f"[计划更新] {new_plan}"))
85 def append_tool_results(self, results: list[ToolResult]):
86 for r in results:
87 self._messages.append(
88 Message(
89 role="tool",
90 content=r.error or r.output or "",
91 tool_call_id=r.call_id,
92 )
93 )
95 def add_assistant_message(self, content: str, tool_calls: list[ToolCall] | None = None):
96 self._messages.append(Message(role="assistant", content=content, tool_calls=tool_calls))
98 def add_user_message(self, content: str):
99 self._messages.append(Message(role="user", content=content))
101 def estimate_context_usage(self) -> float:
102 """估算上下文使用比例 (0.0-1.0)。按 max_history 消息数 vs 最大 Token 估算。"""
103 if len(self._messages) == 0:
104 return 0.0
105 estimated_tokens = sum(len(m.content) for m in self._messages) // 4
106 max_tokens = self.max_history * 200 # 每消息 ~200 token 粗估
107 return min(estimated_tokens / max_tokens if max_tokens > 0 else 0.0, 1.0)
109 @property
110 def current_task(self) -> str:
111 return self._current_task
113 @property
114 def step_count(self) -> int:
115 return self._step_count
117 @property
118 def plan(self) -> str:
119 return self._plan
121 @property
122 def message_count(self) -> int:
123 return len(self._messages)
125 @property
126 def estimated_tokens(self) -> int:
127 """粗略估算当前上下文的总token数(按每4字符≈1token)。"""
128 total_chars = sum(len(m.content) for m in self._messages)
129 return total_chars // 4