完整的 agentic loop: 1. 用户输入 → 消息列表 2. 调 API → 得到 assistant 回复 3. 有工具调用? → 权限检查 → 执行 → 结果回消息 4. 没有工具调用? → 返回文本 5. 重复 2-4 直到无工具调用或达到上限
(self, user_input: str)
| 971 | self.messages: list[dict] = [] |
| 972 | |
| 973 | def run_turn(self, user_input: str) -> str: |
| 974 | """ |
| 975 | 完整的 agentic loop: |
| 976 | 1. 用户输入 → 消息列表 |
| 977 | 2. 调 API → 得到 assistant 回复 |
| 978 | 3. 有工具调用? → 权限检查 → 执行 → 结果回消息 |
| 979 | 4. 没有工具调用? → 返回文本 |
| 980 | 5. 重复 2-4 直到无工具调用或达到上限 |
| 981 | """ |
| 982 | self.messages.append({"role": "user", "content": user_input}) |
| 983 | log = [] |
| 984 | |
| 985 | for iteration in range(1, self.max_iterations + 1): |
| 986 | # 调 API |
| 987 | events = self.api.stream(self.system_prompt, self.messages) |
| 988 | |
| 989 | # 解析 events |
| 990 | text_parts = [] |
| 991 | tool_calls = [] |
| 992 | for event in events: |
| 993 | if event["type"] == "text": |
| 994 | text_parts.append(event["text"]) |
| 995 | elif event["type"] == "tool_use": |
| 996 | tool_calls.append(event) |
| 997 | |
| 998 | assistant_text = "".join(text_parts) |
| 999 | self.messages.append({ |
| 1000 | "role": "assistant", |
| 1001 | "content": assistant_text, |
| 1002 | "tool_calls": tool_calls, |
| 1003 | }) |
| 1004 | |
| 1005 | # 无工具调用 → 结束 |
| 1006 | if not tool_calls: |
| 1007 | log.append(f" [迭代 {iteration}] 纯文本回答, 循环结束") |
| 1008 | for line in log: |
| 1009 | print(line) |
| 1010 | return assistant_text |
| 1011 | |
| 1012 | # 有工具调用 → 权限 + 执行 |
| 1013 | for call in tool_calls: |
| 1014 | allowed, reason = self.permission.check(call["name"]) |
| 1015 | |
| 1016 | if allowed: |
| 1017 | result = self.tools.execute(call["name"], call["input"]) |
| 1018 | is_error = result.startswith("ERROR:") |
| 1019 | log.append( |
| 1020 | f" [迭代 {iteration}] {call['name']}" |
| 1021 | f"({call['input'][:30]}) → {result[:50]}" |
| 1022 | ) |
| 1023 | else: |
| 1024 | result = reason |
| 1025 | is_error = True |
| 1026 | log.append( |
| 1027 | f" [迭代 {iteration}] {call['name']} → 拒绝: {reason}" |
| 1028 | ) |
| 1029 | |
| 1030 | self.messages.append({ |
no test coverage detected