beswarm 0.1.58__py3-none-any.whl → 0.1.60__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
beswarm/aient/setup.py CHANGED
@@ -4,7 +4,7 @@ from setuptools import setup, find_packages
4
4
 
5
5
  setup(
6
6
  name="aient",
7
- version="1.1.13",
7
+ version="1.1.15",
8
8
  description="Aient: The Awakening of Agent.",
9
9
  long_description=Path.open(Path("README.md"), encoding="utf-8").read(),
10
10
  long_description_content_type="text/markdown",
@@ -241,7 +241,7 @@ async def get_gemini_payload(request, engine, provider, api_key=None):
241
241
  if key == request.model:
242
242
  for k, v in value.items():
243
243
  payload[k] = v
244
- elif all(_model not in request.model for _model in ["gemini", "gpt", "claude"]):
244
+ elif all(_model not in request.model.lower() for _model in ["gemini", "gpt", "claude"]):
245
245
  payload[key] = value
246
246
 
247
247
  return url, headers, payload
@@ -511,7 +511,7 @@ async def get_vertex_gemini_payload(request, engine, provider, api_key=None):
511
511
  if key == request.model:
512
512
  for k, v in value.items():
513
513
  payload[k] = v
514
- elif all(_model not in request.model for _model in ["gemini", "gpt", "claude"]):
514
+ elif all(_model not in request.model.lower() for _model in ["gemini", "gpt", "claude"]):
515
515
  payload[key] = value
516
516
 
517
517
  return url, headers, payload
@@ -935,6 +935,9 @@ async def get_gpt_payload(request, engine, provider, api_key=None):
935
935
  headers['Authorization'] = f"Bearer {api_key}"
936
936
 
937
937
  url = provider['base_url']
938
+ if "openrouter.ai" in url:
939
+ headers['HTTP-Referer'] = "https://github.com/yym68686/uni-api"
940
+ headers['X-Title'] = "Uni API"
938
941
 
939
942
  messages = []
940
943
  for msg in request.messages:
@@ -1055,7 +1058,7 @@ async def get_gpt_payload(request, engine, provider, api_key=None):
1055
1058
  if key == request.model:
1056
1059
  for k, v in value.items():
1057
1060
  payload[k] = v
1058
- elif all(_model not in request.model for _model in ["gemini", "gpt", "claude"]):
1061
+ elif all(_model not in request.model.lower() for _model in ["gemini", "gpt", "claude"]):
1059
1062
  payload[key] = value
1060
1063
 
1061
1064
  return url, headers, payload
@@ -1153,7 +1156,7 @@ async def get_azure_payload(request, engine, provider, api_key=None):
1153
1156
  if key == request.model:
1154
1157
  for k, v in value.items():
1155
1158
  payload[k] = v
1156
- elif all(_model not in request.model for _model in ["gemini", "gpt", "claude"]):
1159
+ elif all(_model not in request.model.lower() for _model in ["gemini", "gpt", "claude"]):
1157
1160
  payload[key] = value
1158
1161
 
1159
1162
  return url, headers, payload
@@ -1168,6 +1171,9 @@ async def get_openrouter_payload(request, engine, provider, api_key=None):
1168
1171
  headers['Authorization'] = f"Bearer {api_key}"
1169
1172
 
1170
1173
  url = provider['base_url']
1174
+ if "openrouter.ai" in url:
1175
+ headers['HTTP-Referer'] = "https://github.com/yym68686/uni-api"
1176
+ headers['X-Title'] = "Uni API"
1171
1177
 
1172
1178
  messages = []
1173
1179
  for msg in request.messages:
@@ -1215,6 +1221,14 @@ async def get_openrouter_payload(request, engine, provider, api_key=None):
1215
1221
  if field not in miss_fields and value is not None:
1216
1222
  payload[field] = value
1217
1223
 
1224
+ if safe_get(provider, "preferences", "post_body_parameter_overrides", default=None):
1225
+ for key, value in safe_get(provider, "preferences", "post_body_parameter_overrides", default={}).items():
1226
+ if key == request.model:
1227
+ for k, v in value.items():
1228
+ payload[k] = v
1229
+ elif all(_model not in request.model.lower() for _model in ["gemini", "gpt", "claude"]):
1230
+ payload[key] = value
1231
+
1218
1232
  return url, headers, payload
1219
1233
 
1220
1234
  async def get_cohere_payload(request, engine, provider, api_key=None):
@@ -1496,9 +1510,10 @@ async def get_claude_payload(request, engine, provider, api_key=None):
1496
1510
  payload = {
1497
1511
  "model": original_model,
1498
1512
  "messages": messages,
1499
- "system": system_prompt or "You are Claude, a large language model trained by Anthropic.",
1500
1513
  "max_tokens": max_tokens,
1501
1514
  }
1515
+ if system_prompt:
1516
+ payload["system"] = system_prompt
1502
1517
 
1503
1518
  if request.max_tokens:
1504
1519
  payload["max_tokens"] = int(request.max_tokens)
@@ -1546,7 +1561,7 @@ async def get_claude_payload(request, engine, provider, api_key=None):
1546
1561
  payload.pop("tools", None)
1547
1562
  payload.pop("tool_choice", None)
1548
1563
 
1549
- if "think" in request.model:
1564
+ if "think" in request.model.lower():
1550
1565
  payload["thinking"] = {
1551
1566
  "budget_tokens": 4096,
1552
1567
  "type": "enabled"
@@ -1572,6 +1587,14 @@ async def get_claude_payload(request, engine, provider, api_key=None):
1572
1587
  payload.pop("top_k", None)
1573
1588
  # print("payload", json.dumps(payload, indent=2, ensure_ascii=False))
1574
1589
 
1590
+ if safe_get(provider, "preferences", "post_body_parameter_overrides", default=None):
1591
+ for key, value in safe_get(provider, "preferences", "post_body_parameter_overrides", default={}).items():
1592
+ if key == request.model:
1593
+ for k, v in value.items():
1594
+ payload[k] = v
1595
+ elif all(_model not in request.model.lower() for _model in ["gemini", "gpt", "claude"]):
1596
+ payload[key] = value
1597
+
1575
1598
  return url, headers, payload
1576
1599
 
1577
1600
  async def get_dalle_payload(request, engine, provider, api_key=None):
@@ -172,7 +172,8 @@ def excute_command(command):
172
172
  process.stderr.close()
173
173
 
174
174
  new_output_lines = []
175
- output_lines = "".join(output_lines).strip().replace("\\u001b[A", "").replace("\\r", "\r").replace("\\\\", "").replace("\\n", "\n").replace("\r", "+++").replace("\n", "+++")
175
+ output_lines = "".join(output_lines).strip().replace("\\r", "\r").replace("\\\\", "").replace("\\n", "\n").replace("\r", "+++").replace("\n", "+++")
176
+ output_lines = re.sub(r'\\u001b\[[0-9;]*[a-zA-Z]', '', output_lines)
176
177
  for line in output_lines.split("+++"):
177
178
  if line.strip() == "":
178
179
  continue
@@ -667,7 +667,6 @@ def convert_functions_to_xml(functions_list):
667
667
 
668
668
  if __name__ == "__main__":
669
669
 
670
- # 运行本文件:python -m beswarm.aient.src.aient.utils.scripts
671
670
  os.system("clear")
672
671
  test_xml = """
673
672
  ✅ 好的,我现在读取 `README.md` 文件。
@@ -742,4 +741,6 @@ if __name__ == "__main__":
742
741
  请提供前两个 `excute_command` 的执行结果。
743
742
  """
744
743
 
745
- print(parse_function_xml(test_xml))
744
+ print(parse_function_xml(test_xml))
745
+
746
+ # 运行本文件:python -m beswarm.aient.src.aient.utils.scripts
beswarm/tools/__init__.py CHANGED
@@ -1,7 +1,6 @@
1
1
  from .think import think
2
2
  from .edit_file import edit_file
3
3
  from .worker import worker
4
- from .UIworker import UIworker
5
4
 
6
5
  from .search_arxiv import search_arxiv
7
6
  from .repomap import get_code_repo_map
@@ -44,6 +43,5 @@ __all__ = [
44
43
  "find_and_click_element",
45
44
  "scroll_screen",
46
45
  "register_tool",
47
- "UIworker",
48
46
  "search_web",
49
47
  ]
beswarm/tools/worker.py CHANGED
@@ -1,14 +1,13 @@
1
1
  import os
2
2
  import copy
3
+ import json
3
4
  import platform
4
5
  from datetime import datetime
5
- from ..aient.src.aient.plugins import register_tool
6
6
 
7
7
  from ..aient.src.aient.models import chatgpt
8
- from ..aient.src.aient.plugins import get_function_call_list
8
+ from ..aient.src.aient.plugins import register_tool, get_function_call_list
9
9
  from ..aient.src.aient.prompt import system_prompt, instruction_system_prompt
10
-
11
- from ..utils import extract_xml_content
10
+ from ..utils import extract_xml_content, get_current_screen_image_message
12
11
 
13
12
  @register_tool()
14
13
  async def worker(goal, tools, work_dir, cache_messages=None):
@@ -64,24 +63,6 @@ async def worker(goal, tools, work_dir, cache_messages=None):
64
63
  work_agent = chatgpt(**work_agent_config)
65
64
  async def instruction_agent_task():
66
65
  while True:
67
- # 获取工作agent的对话历史
68
- # conversation_history = copy.deepcopy(work_agent.conversation["default"])
69
- # conversation_history.pop(0)
70
-
71
- # conversation_len = len(conversation_history) - 1
72
- # message_index = 0
73
- # while message_index < conversation_len:
74
- # if isinstance(conversation_history[message_index]["content"], str) and conversation_history[message_index]["content"].strip() == "":
75
- # conversation_history.pop(message_index)
76
- # conversation_len = conversation_len - 1
77
- # elif isinstance(conversation_history[message_index]["content"], list) and \
78
- # len(conversation_history[message_index]["content"]) > 0 and \
79
- # conversation_history[message_index]["content"][0].get("type") == "text" and \
80
- # conversation_history[message_index]["content"][0].get("text").strip() == "":
81
- # conversation_history.pop(message_index)
82
- # conversation_len = conversation_len - 1
83
- # else:
84
- # message_index = message_index + 1
85
66
 
86
67
  instruction_prompt = f"""
87
68
  </work_agent_conversation_end>
@@ -94,8 +75,17 @@ async def worker(goal, tools, work_dir, cache_messages=None):
94
75
  # 让指令agent分析对话历史并生成新指令
95
76
  instruction_agent = chatgpt(**instruction_agent_config)
96
77
  conversation_history = copy.deepcopy(work_agent.conversation["default"])
78
+
79
+ cache_dir = os.path.join(work_dir, ".beswarm")
80
+ os.makedirs(cache_dir, exist_ok=True)
81
+ cache_file = os.path.join(cache_dir, "work_agent_conversation_history.json")
82
+ with open(cache_file, "w", encoding="utf-8") as f:
83
+ f.write(json.dumps(conversation_history, ensure_ascii=False, indent=4))
84
+
97
85
  conversation_history.pop(0)
98
86
  instruction_agent.conversation["default"][1:] = conversation_history
87
+ if "find_and_click_element" in str(tools_json):
88
+ instruction_prompt = await get_current_screen_image_message(instruction_prompt)
99
89
  next_instruction = await instruction_agent.ask_async(instruction_prompt)
100
90
  print("\n🤖 指令智能体生成的下一步指令:", next_instruction)
101
91
  if "fetch_gpt_response_stream HTTP Error', 'status_code': 404" in next_instruction:
@@ -107,6 +97,13 @@ async def worker(goal, tools, work_dir, cache_messages=None):
107
97
  print("\n❌ 指令智能体生成的指令不符合要求,请重新生成。")
108
98
  continue
109
99
  else:
100
+ if conversation_history == []:
101
+ next_instruction = (
102
+ "任务描述:\n"
103
+ f"{goal}\n\n"
104
+ "现在开始执行第一步:\n"
105
+ f"{next_instruction}"
106
+ )
110
107
  break
111
108
  return next_instruction
112
109
 
@@ -120,7 +117,8 @@ async def worker(goal, tools, work_dir, cache_messages=None):
120
117
  if "任务已完成" in next_instruction:
121
118
  print("\n✅ 任务已完成!")
122
119
  break
123
-
120
+ if "find_and_click_element" in str(tools_json):
121
+ next_instruction = await get_current_screen_image_message(next_instruction)
124
122
  result = await work_agent.ask_async(next_instruction)
125
123
  if result.strip() == '' or result.strip() == '</content>\n</write_to_file>':
126
124
  print("\n❌ 工作智能体回复为空,请重新生成指令。")
beswarm/utils.py CHANGED
@@ -8,4 +8,40 @@ def extract_xml_content(text, xml_tag):
8
8
  result = match.group(1)
9
9
  if not result:
10
10
  return ''
11
- return result
11
+ return result
12
+
13
+ import io
14
+ import base64
15
+ from .aient.src.aient.core.utils import get_image_message, get_text_message
16
+
17
+ async def get_current_screen_image_message(prompt):
18
+ print("instruction agent 正在截取当前屏幕...")
19
+ try:
20
+ import pyautogui
21
+ # 使用 pyautogui 截取屏幕,返回 PIL Image 对象
22
+ screenshot = pyautogui.screenshot()
23
+ # img_width, img_height = screenshot.size # 获取截图尺寸
24
+ img_width, img_height = pyautogui.size()
25
+ print(f"截图成功,尺寸: {img_width}x{img_height}")
26
+
27
+ # 将 PIL Image 对象转换为 Base64 编码的 PNG 字符串
28
+ buffered = io.BytesIO()
29
+ screenshot.save(buffered, format="PNG")
30
+ base64_encoded_image = base64.b64encode(buffered.getvalue()).decode("utf-8")
31
+ IMAGE_MIME_TYPE = "image/png" # 截图格式为 PNG
32
+
33
+ except ImportError:
34
+ # Pillow 也是 pyautogui 的依赖,但以防万一单独处理
35
+ print("\n❌ 请安装所需库: pip install Pillow pyautogui")
36
+ return False
37
+ except Exception as e:
38
+ print(f"\n❌ 截取屏幕或处理图像时出错: {e}")
39
+ return False
40
+
41
+ engine_type = "gpt"
42
+ message_list = []
43
+ text_message = await get_text_message(prompt, engine_type)
44
+ image_message = await get_image_message(f"data:{IMAGE_MIME_TYPE};base64," + base64_encoded_image, engine_type)
45
+ message_list.append(text_message)
46
+ message_list.append(image_message)
47
+ return message_list
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beswarm
3
- Version: 0.1.58
3
+ Version: 0.1.60
4
4
  Summary: MAS
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,12 +1,12 @@
1
1
  beswarm/__init__.py,sha256=HZjUOJtZR5QhMuDbq-wukQQn1VrBusNWai_ysGo-VVI,20
2
- beswarm/utils.py,sha256=AdDCcqAIIKQEMl7PfryVgeT9G5sHe7QNsZnrvmTGA8E,283
2
+ beswarm/utils.py,sha256=Z2Kuus2BLp9EHUC2ZNL9iUsb6NWnPj-MTA7SYzGyg24,1755
3
3
  beswarm/aient/main.py,sha256=SiYAIgQlLJqYusnTVEJOx1WNkSJKMImhgn5aWjfroxg,3814
4
- beswarm/aient/setup.py,sha256=5aE5yVcM8sk5NULSs8Y9sJi1pRQGKZwdscZVOzPGvB0,487
4
+ beswarm/aient/setup.py,sha256=A2q_i7Phzeh-ii_T_-TOguYtW3tJuV8qY-V5WowGCrk,487
5
5
  beswarm/aient/src/aient/__init__.py,sha256=SRfF7oDVlOOAi6nGKiJIUK6B_arqYLO9iSMp-2IZZps,21
6
6
  beswarm/aient/src/aient/core/__init__.py,sha256=NxjebTlku35S4Dzr16rdSqSTWUvvwEeACe8KvHJnjPg,34
7
7
  beswarm/aient/src/aient/core/log_config.py,sha256=kz2_yJv1p-o3lUQOwA3qh-LSc3wMHv13iCQclw44W9c,274
8
8
  beswarm/aient/src/aient/core/models.py,sha256=kF-HLi1I2k_G5r153ZHuiGH8_NmpTlFMfK0_myB28YQ,7366
9
- beswarm/aient/src/aient/core/request.py,sha256=AmTnQ_Ri_ACRxDsWmPhhD6e79hNfwLxbsyBnpbAnmNA,64490
9
+ beswarm/aient/src/aient/core/request.py,sha256=2u_vPJjoIqRsKOPOkPilGzM4iZXUpsx5xtouQy87Z4E,65693
10
10
  beswarm/aient/src/aient/core/response.py,sha256=Z0Bjl_QvpUguyky1LIcsVks4BKKqT0eYEpDmKa_cwpQ,31978
11
11
  beswarm/aient/src/aient/core/utils.py,sha256=-naFCv8V-qhnqvDUd8BNbW1HR9CVAPxISrXoAz464Qg,26580
12
12
  beswarm/aient/src/aient/core/test/test_base_api.py,sha256=pWnycRJbuPSXKKU9AQjWrMAX1wiLC_014Qc9hh5C2Pw,524
@@ -25,7 +25,7 @@ beswarm/aient/src/aient/models/vertex.py,sha256=qVD5l1Q538xXUPulxG4nmDjXE1VoV4yu
25
25
  beswarm/aient/src/aient/plugins/__init__.py,sha256=p3KO6Aa3Lupos4i2SjzLQw1hzQTigOAfEHngsldrsyk,986
26
26
  beswarm/aient/src/aient/plugins/arXiv.py,sha256=yHjb6PS3GUWazpOYRMKMzghKJlxnZ5TX8z9F6UtUVow,1461
27
27
  beswarm/aient/src/aient/plugins/config.py,sha256=Vp6CG9ocdC_FAlCMEGtKj45xamir76DFxdJVvURNtog,6539
28
- beswarm/aient/src/aient/plugins/excute_command.py,sha256=A3WmfZboEikU1EHvtMWhBv-xHxCyMxbDddQ982I_8wE,10482
28
+ beswarm/aient/src/aient/plugins/excute_command.py,sha256=huQSbNbeImV8BUIsQKE13BIhCAMr7aYRyXO4saE1dTI,10534
29
29
  beswarm/aient/src/aient/plugins/get_time.py,sha256=Ih5XIW5SDAIhrZ9W4Qe5Hs1k4ieKPUc_LAd6ySNyqZk,654
30
30
  beswarm/aient/src/aient/plugins/image.py,sha256=ZElCIaZznE06TN9xW3DrSukS7U3A5_cjk1Jge4NzPxw,2072
31
31
  beswarm/aient/src/aient/plugins/list_directory.py,sha256=JZVuImecMSfEv6jLqii-0uQJ1UCsrpMNmYlwW3PEDg4,1374
@@ -39,7 +39,7 @@ beswarm/aient/src/aient/prompt/__init__.py,sha256=GBtn6-JDT8KHFCcuPpfSNE_aGddg5p
39
39
  beswarm/aient/src/aient/prompt/agent.py,sha256=y2GETN6ScC5yQVs75VFfzm4YUWzblbqLYz0Sy6JnPRw,24950
40
40
  beswarm/aient/src/aient/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  beswarm/aient/src/aient/utils/prompt.py,sha256=UcSzKkFE4-h_1b6NofI6xgk3GoleqALRKY8VBaXLjmI,11311
42
- beswarm/aient/src/aient/utils/scripts.py,sha256=wutPtgbs-WXo5AACLpnCJaRQBOSKXWNnsf2grbYDzyQ,29098
42
+ beswarm/aient/src/aient/utils/scripts.py,sha256=LD8adnfuRrJoY2tWKseXOPJXaxbrUmz4czsnUvHswNY,29096
43
43
  beswarm/aient/test/chatgpt.py,sha256=Hvl7FuDt1c74N5TVBmhErOPvJbJJzA7FNp5VoZM4u30,4957
44
44
  beswarm/aient/test/claude.py,sha256=IyB4qI1eJLwlSfDNSnt2FhbQWYyBighHUjJxEXc3osQ,1095
45
45
  beswarm/aient/test/test.py,sha256=rldnoLQdtRR8IKFSIzTti7eIK2MpPMoi9gL5qD8_K44,29
@@ -119,8 +119,7 @@ beswarm/queries/tree-sitter-languages/ruby-tags.scm,sha256=vIidsCeE2A0vdFN18yXKq
119
119
  beswarm/queries/tree-sitter-languages/rust-tags.scm,sha256=9ljM1nzhfPs_ZTRw7cr2P9ToOyhGcKkCoN4_HPXSWi4,1451
120
120
  beswarm/queries/tree-sitter-languages/scala-tags.scm,sha256=UxQjz80JIrrJ7Pm56uUnQyThfmQNvwk7aQzPNypB-Ao,1761
121
121
  beswarm/queries/tree-sitter-languages/typescript-tags.scm,sha256=OMdCeedPiA24ky82DpgTMKXK_l2ySTuF2zrQ2fJAi9E,1253
122
- beswarm/tools/UIworker.py,sha256=1sEC76VGFwo48lSx6KOvhJwhgBj7UWAHAAH9BG_lp-M,6439
123
- beswarm/tools/__init__.py,sha256=jOfYY4EYkwmz-FTJGrI1CyaIYkGWsmGzZBGsoupeX9M,1088
122
+ beswarm/tools/__init__.py,sha256=oDsCE7Coy3TXM0pTRS_4mWTEyPnsKVK7Vco1idSVxJk,1041
124
123
  beswarm/tools/click.py,sha256=TygaekCXTmU3fIu6Uom7ZcyzEgYMlCC_GX-5SmWHuLI,20762
125
124
  beswarm/tools/edit_file.py,sha256=xlAD0HB_xM0yZYc0eJwLE-9mAkywXa2UQPNHzG1OaW4,7664
126
125
  beswarm/tools/planner.py,sha256=lguBCS6kpwNPoXQvqH-WySabVubT82iyWOkJnjt6dXw,1265
@@ -128,8 +127,8 @@ beswarm/tools/repomap.py,sha256=N09K0UgwjCN7Zjg_5TYlVsulp3n2fztYlS8twalChU8,4500
128
127
  beswarm/tools/search_arxiv.py,sha256=9slwBemXjEqrd7-YgVmyMijPXlkhZCybEDRVhWVQ9B0,7937
129
128
  beswarm/tools/search_web.py,sha256=B24amOnGHnmdV_6S8bw8O2PdhZRRIDtJjg-wXcfP7dQ,11859
130
129
  beswarm/tools/think.py,sha256=WLw-7jNIsnS6n8MMSYUin_f-BGLENFmnKM2LISEp0co,1760
131
- beswarm/tools/worker.py,sha256=b-FvSEP27-zMYNcqaQeVBoWxaSf2cX_7_1p1GAF6h04,6191
132
- beswarm-0.1.58.dist-info/METADATA,sha256=gquIkiIp96CLCAU56qpaYkmzPkGm3mGtsyDG8y9JzPQ,3553
133
- beswarm-0.1.58.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
134
- beswarm-0.1.58.dist-info/top_level.txt,sha256=pJw4O87wvt5882smuSO6DfByJz7FJ8SxxT8h9fHCmpo,8
135
- beswarm-0.1.58.dist-info/RECORD,,
130
+ beswarm/tools/worker.py,sha256=2EOag_yo8qC020jx32tcU9G_gzT3PeYasukLwuuOAJQ,5976
131
+ beswarm-0.1.60.dist-info/METADATA,sha256=H7moorce2OKfYVPmPizKxYp00P6vy4MH_uYyteAP0UE,3553
132
+ beswarm-0.1.60.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
133
+ beswarm-0.1.60.dist-info/top_level.txt,sha256=pJw4O87wvt5882smuSO6DfByJz7FJ8SxxT8h9fHCmpo,8
134
+ beswarm-0.1.60.dist-info/RECORD,,
beswarm/tools/UIworker.py DELETED
@@ -1,147 +0,0 @@
1
- import os
2
- import io
3
- import copy
4
- import base64
5
- import platform
6
- from datetime import datetime
7
- from ..aient.src.aient.plugins import register_tool, get_function_call_list
8
-
9
- from ..aient.src.aient.models import chatgpt
10
- from ..aient.src.aient.prompt import system_prompt, instruction_system_prompt
11
- from ..aient.src.aient.core.utils import get_image_message, get_text_message
12
-
13
- from ..utils import extract_xml_content
14
-
15
- async def get_current_screen_image_message(prompt):
16
- print("instruction agent 正在截取当前屏幕...")
17
- try:
18
- import pyautogui
19
- # 使用 pyautogui 截取屏幕,返回 PIL Image 对象
20
- screenshot = pyautogui.screenshot()
21
- # img_width, img_height = screenshot.size # 获取截图尺寸
22
- img_width, img_height = pyautogui.size()
23
- print(f"截图成功,尺寸: {img_width}x{img_height}")
24
-
25
- # 将 PIL Image 对象转换为 Base64 编码的 PNG 字符串
26
- buffered = io.BytesIO()
27
- screenshot.save(buffered, format="PNG")
28
- base64_encoded_image = base64.b64encode(buffered.getvalue()).decode("utf-8")
29
- IMAGE_MIME_TYPE = "image/png" # 截图格式为 PNG
30
-
31
- except ImportError:
32
- # Pillow 也是 pyautogui 的依赖,但以防万一单独处理
33
- print("\n❌ 请安装所需库: pip install Pillow pyautogui")
34
- return False
35
- except Exception as e:
36
- print(f"\n❌ 截取屏幕或处理图像时出错: {e}")
37
- return False
38
-
39
- engine_type = "gpt"
40
- message_list = []
41
- text_message = await get_text_message(prompt, engine_type)
42
- image_message = await get_image_message(f"data:{IMAGE_MIME_TYPE};base64," + base64_encoded_image, engine_type)
43
- message_list.append(text_message)
44
- message_list.append(image_message)
45
- return message_list
46
-
47
- @register_tool()
48
- async def UIworker(goal, tools, work_dir, cache_messages=None):
49
- """
50
- 启动一个 **工作智能体 (Worker Agent)** 来自动完成指定的任务目标 (`goal`)。
51
-
52
- 这个工作智能体接收一个清晰的任务描述、一组可供调用的工具 (`tools`),以及一个工作目录 (`work_dir`)。
53
- 它会利用语言模型的能力,结合可用的工具,自主规划并逐步执行必要的操作,直到最终完成指定的任务目标。
54
- 核心功能是根据输入的目标,驱动整个任务执行流程。
55
-
56
- Args:
57
- goal (str): 需要完成的具体任务目标描述。工作智能体将围绕此目标进行工作。必须清晰、具体。
58
- tools (list[str]): 一个包含可用工具函数对象的列表。工作智能体在执行任务时可能会调用这些工具来与环境交互(例如读写文件、执行命令等)。
59
- work_dir (str): 工作目录的绝对路径。工作智能体将在此目录上下文中执行操作。
60
-
61
- Returns:
62
- str: 当任务成功完成时,返回字符串 "任务已完成"。
63
- """
64
-
65
- tools_json = [value for _, value in get_function_call_list(tools).items()]
66
- work_agent_system_prompt = system_prompt.format(
67
- os_version=platform.platform(),
68
- workspace_path=work_dir,
69
- shell=os.getenv('SHELL', 'Unknown'),
70
- tools_list=tools_json
71
- )
72
-
73
- work_agent_config = {
74
- "api_key": os.getenv("API_KEY"),
75
- "api_url": os.getenv("BASE_URL"),
76
- "engine": os.getenv("MODEL"),
77
- "system_prompt": work_agent_system_prompt,
78
- "print_log": True,
79
- # "max_tokens": 8000,
80
- "temperature": 0.5,
81
- "function_call_max_loop": 100,
82
- }
83
- if cache_messages:
84
- work_agent_config["cache_messages"] = cache_messages
85
-
86
- instruction_agent_config = {
87
- "api_key": os.getenv("API_KEY"),
88
- "api_url": os.getenv("BASE_URL"),
89
- "engine": os.getenv("MODEL"),
90
- "system_prompt": instruction_system_prompt.format(os_version=platform.platform(), tools_list=tools_json, workspace_path=work_dir, current_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
91
- "print_log": False,
92
- # "max_tokens": 4000,
93
- "temperature": 0.7,
94
- "use_plugins": False,
95
- }
96
-
97
- # 工作agent初始化
98
- work_agent = chatgpt(**work_agent_config)
99
- async def instruction_agent_task():
100
- while True:
101
- instruction_prompt = f"""
102
- 任务目标: {goal}
103
-
104
- 以上对话都是工作智能体的对话历史。
105
-
106
- 根据以上对话历史和目标,请生成下一步指令。如果任务已完成,请回复"任务已完成"。
107
- """
108
- # 让指令agent分析对话历史并生成新指令
109
- instruction_agent = chatgpt(**instruction_agent_config)
110
- conversation_history = copy.deepcopy(work_agent.conversation["default"])
111
- conversation_history.pop(0)
112
- instruction_agent.conversation["default"][1:] = conversation_history
113
- new_prompt = await get_current_screen_image_message(instruction_prompt)
114
- next_instruction = await instruction_agent.ask_async(new_prompt)
115
- print("\n🤖 指令智能体生成的下一步指令:", next_instruction)
116
- if "fetch_gpt_response_stream HTTP Error', 'status_code': 404" in next_instruction:
117
- raise Exception(f"Model: {instruction_agent_config['engine']} not found!")
118
- if "'status_code': 413" in next_instruction:
119
- raise Exception(f"The request body is too long, please try again.")
120
- next_instruction = extract_xml_content(next_instruction, "instructions")
121
- if not next_instruction:
122
- print("\n❌ 指令智能体生成的指令不符合要求,请重新生成。")
123
- continue
124
- else:
125
- break
126
- return next_instruction
127
-
128
- need_instruction = True
129
- while True:
130
- next_instruction = ''
131
- if need_instruction:
132
- next_instruction = await instruction_agent_task()
133
-
134
- # 检查任务是否完成
135
- if "任务已完成" in next_instruction:
136
- print("\n✅ 任务已完成!")
137
- break
138
- new_prompt = await get_current_screen_image_message(next_instruction)
139
- result = await work_agent.ask_async(new_prompt)
140
- if result.strip() == '':
141
- print("\n❌ 工作智能体回复为空,请重新生成指令。")
142
- need_instruction = False
143
- continue
144
- print("✅ 工作智能体回复:", result)
145
- need_instruction = True
146
-
147
- return "任务已完成"