ag2 0.9.9__py3-none-any.whl → 0.10.0__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.
Potentially problematic release.
This version of ag2 might be problematic. Click here for more details.
- {ag2-0.9.9.dist-info → ag2-0.10.0.dist-info}/METADATA +243 -214
- {ag2-0.9.9.dist-info → ag2-0.10.0.dist-info}/RECORD +113 -87
- autogen/_website/generate_mkdocs.py +3 -3
- autogen/_website/notebook_processor.py +1 -1
- autogen/_website/utils.py +1 -1
- autogen/a2a/__init__.py +36 -0
- autogen/a2a/agent_executor.py +105 -0
- autogen/a2a/client.py +280 -0
- autogen/a2a/errors.py +18 -0
- autogen/a2a/httpx_client_factory.py +79 -0
- autogen/a2a/server.py +221 -0
- autogen/a2a/utils.py +165 -0
- autogen/agentchat/__init__.py +3 -0
- autogen/agentchat/agent.py +0 -2
- autogen/agentchat/assistant_agent.py +15 -15
- autogen/agentchat/chat.py +57 -41
- autogen/agentchat/contrib/agent_eval/criterion.py +1 -1
- autogen/agentchat/contrib/capabilities/text_compressors.py +5 -5
- autogen/agentchat/contrib/capabilities/tools_capability.py +1 -1
- autogen/agentchat/contrib/capabilities/transforms.py +1 -1
- autogen/agentchat/contrib/captainagent/agent_builder.py +1 -1
- autogen/agentchat/contrib/captainagent/captainagent.py +20 -19
- autogen/agentchat/contrib/graph_rag/falkor_graph_query_engine.py +2 -5
- autogen/agentchat/contrib/graph_rag/graph_rag_capability.py +5 -5
- autogen/agentchat/contrib/graph_rag/neo4j_graph_query_engine.py +18 -17
- autogen/agentchat/contrib/llava_agent.py +1 -13
- autogen/agentchat/contrib/rag/mongodb_query_engine.py +2 -2
- autogen/agentchat/contrib/rag/query_engine.py +11 -11
- autogen/agentchat/contrib/retrieve_assistant_agent.py +3 -0
- autogen/agentchat/contrib/swarm_agent.py +3 -2
- autogen/agentchat/contrib/vectordb/couchbase.py +1 -1
- autogen/agentchat/contrib/vectordb/mongodb.py +1 -1
- autogen/agentchat/contrib/web_surfer.py +1 -1
- autogen/agentchat/conversable_agent.py +359 -150
- autogen/agentchat/group/context_expression.py +21 -21
- autogen/agentchat/group/group_tool_executor.py +46 -15
- autogen/agentchat/group/guardrails.py +41 -33
- autogen/agentchat/group/handoffs.py +11 -11
- autogen/agentchat/group/multi_agent_chat.py +56 -2
- autogen/agentchat/group/on_condition.py +11 -11
- autogen/agentchat/group/safeguards/__init__.py +21 -0
- autogen/agentchat/group/safeguards/api.py +241 -0
- autogen/agentchat/group/safeguards/enforcer.py +1158 -0
- autogen/agentchat/group/safeguards/events.py +119 -0
- autogen/agentchat/group/safeguards/validator.py +435 -0
- autogen/agentchat/groupchat.py +102 -49
- autogen/agentchat/realtime/experimental/clients/realtime_client.py +2 -2
- autogen/agentchat/realtime/experimental/function_observer.py +2 -3
- autogen/agentchat/realtime/experimental/realtime_agent.py +2 -3
- autogen/agentchat/realtime/experimental/realtime_swarm.py +22 -13
- autogen/agentchat/user_proxy_agent.py +55 -53
- autogen/agents/experimental/document_agent/document_agent.py +1 -10
- autogen/agents/experimental/document_agent/parser_utils.py +5 -1
- autogen/browser_utils.py +4 -4
- autogen/cache/abstract_cache_base.py +2 -6
- autogen/cache/disk_cache.py +1 -6
- autogen/cache/in_memory_cache.py +2 -6
- autogen/cache/redis_cache.py +1 -5
- autogen/coding/__init__.py +10 -2
- autogen/coding/base.py +2 -1
- autogen/coding/docker_commandline_code_executor.py +1 -6
- autogen/coding/factory.py +9 -0
- autogen/coding/jupyter/docker_jupyter_server.py +1 -7
- autogen/coding/jupyter/jupyter_client.py +2 -9
- autogen/coding/jupyter/jupyter_code_executor.py +2 -7
- autogen/coding/jupyter/local_jupyter_server.py +2 -6
- autogen/coding/local_commandline_code_executor.py +0 -65
- autogen/coding/yepcode_code_executor.py +197 -0
- autogen/environments/docker_python_environment.py +3 -3
- autogen/environments/system_python_environment.py +5 -5
- autogen/environments/venv_python_environment.py +5 -5
- autogen/events/agent_events.py +1 -1
- autogen/events/client_events.py +1 -1
- autogen/fast_depends/utils.py +10 -0
- autogen/graph_utils.py +5 -7
- autogen/import_utils.py +3 -1
- autogen/interop/pydantic_ai/pydantic_ai.py +8 -5
- autogen/io/processors/console_event_processor.py +8 -3
- autogen/llm_config/client.py +3 -2
- autogen/llm_config/config.py +168 -91
- autogen/llm_config/entry.py +38 -26
- autogen/llm_config/types.py +35 -0
- autogen/llm_config/utils.py +223 -0
- autogen/mcp/mcp_proxy/operation_grouping.py +48 -39
- autogen/messages/agent_messages.py +1 -1
- autogen/messages/client_messages.py +1 -1
- autogen/oai/__init__.py +8 -1
- autogen/oai/bedrock.py +0 -13
- autogen/oai/client.py +25 -11
- autogen/oai/client_utils.py +31 -1
- autogen/oai/cohere.py +4 -14
- autogen/oai/gemini.py +4 -6
- autogen/oai/gemini_types.py +1 -0
- autogen/oai/openai_utils.py +44 -115
- autogen/remote/__init__.py +18 -0
- autogen/remote/agent.py +199 -0
- autogen/remote/agent_service.py +142 -0
- autogen/remote/errors.py +17 -0
- autogen/remote/httpx_client_factory.py +131 -0
- autogen/remote/protocol.py +37 -0
- autogen/remote/retry.py +102 -0
- autogen/remote/runtime.py +96 -0
- autogen/testing/__init__.py +12 -0
- autogen/testing/messages.py +45 -0
- autogen/testing/test_agent.py +111 -0
- autogen/tools/dependency_injection.py +4 -8
- autogen/tools/experimental/reliable/reliable.py +3 -2
- autogen/tools/experimental/web_search_preview/web_search_preview.py +1 -1
- autogen/tools/function_utils.py +2 -1
- autogen/version.py +1 -1
- {ag2-0.9.9.dist-info → ag2-0.10.0.dist-info}/WHEEL +0 -0
- {ag2-0.9.9.dist-info → ag2-0.10.0.dist-info}/licenses/LICENSE +0 -0
- {ag2-0.9.9.dist-info → ag2-0.10.0.dist-info}/licenses/NOTICE.md +0 -0
autogen/agentchat/groupchat.py
CHANGED
|
@@ -48,6 +48,7 @@ SELECT_SPEAKER_PROMPT_TEMPLATE = (
|
|
|
48
48
|
@export_module("autogen")
|
|
49
49
|
class GroupChat:
|
|
50
50
|
"""(In preview) A group chat class that contains the following data fields:
|
|
51
|
+
|
|
51
52
|
- agents: a list of participating agents.
|
|
52
53
|
- messages: a list of messages in the group chat.
|
|
53
54
|
- max_round: the maximum number of rounds.
|
|
@@ -103,9 +104,9 @@ class GroupChat:
|
|
|
103
104
|
Default is 2.
|
|
104
105
|
- select_speaker_transform_messages: (optional) the message transformations to apply to the nested select speaker agent-to-agent chat messages.
|
|
105
106
|
Takes a TransformMessages object, defaults to None and is only utilised when the speaker selection method is "auto".
|
|
106
|
-
- select_speaker_auto_verbose: whether to output the select speaker responses and selections
|
|
107
|
+
- select_speaker_auto_verbose: whether to output the select speaker responses and selections.
|
|
107
108
|
If set to True, the outputs from the two agents in the nested select speaker chat will be output, along with
|
|
108
|
-
whether the responses were successful, or not, in selecting an agent
|
|
109
|
+
whether the responses were successful, or not, in selecting an agent.
|
|
109
110
|
Applies only to "auto" speaker selection method.
|
|
110
111
|
- allow_repeat_speaker: whether to allow the same speaker to speak consecutively.
|
|
111
112
|
Default is True, in which case all speakers are allowed to speak consecutively.
|
|
@@ -174,6 +175,7 @@ class GroupChat:
|
|
|
174
175
|
)
|
|
175
176
|
|
|
176
177
|
allowed_speaker_transitions_dict: dict[str, list[Agent]] = field(init=False)
|
|
178
|
+
_inter_agent_guardrails: list = field(default_factory=list, init=False)
|
|
177
179
|
|
|
178
180
|
def __post_init__(self):
|
|
179
181
|
# Post init steers clears of the automatically generated __init__ method from dataclass
|
|
@@ -1000,7 +1002,7 @@ class GroupChat:
|
|
|
1000
1002
|
message_content = message_content["content"]
|
|
1001
1003
|
message_content = content_str(message_content)
|
|
1002
1004
|
|
|
1003
|
-
mentions =
|
|
1005
|
+
mentions = {}
|
|
1004
1006
|
for agent in agents:
|
|
1005
1007
|
# Finds agent mentions, taking word boundaries into account,
|
|
1006
1008
|
# accommodates escaping underscores and underscores as spaces
|
|
@@ -1019,9 +1021,7 @@ class GroupChat:
|
|
|
1019
1021
|
return mentions
|
|
1020
1022
|
|
|
1021
1023
|
def _run_input_guardrails(
|
|
1022
|
-
self,
|
|
1023
|
-
agent: "ConversableAgent",
|
|
1024
|
-
messages: list[dict[str, Any]] | None = None,
|
|
1024
|
+
self, agent: "ConversableAgent", messages: list[dict[str, Any]] | None = None
|
|
1025
1025
|
) -> str | None:
|
|
1026
1026
|
"""Run input guardrails for an agent before the reply is generated.
|
|
1027
1027
|
|
|
@@ -1029,27 +1029,45 @@ class GroupChat:
|
|
|
1029
1029
|
agent (ConversableAgent): The agent whose input guardrails to run.
|
|
1030
1030
|
messages (Optional[list[dict[str, Any]]]): The messages to check against the guardrails.
|
|
1031
1031
|
"""
|
|
1032
|
-
|
|
1033
|
-
guardrail_result
|
|
1034
|
-
|
|
1035
|
-
if guardrail_result.activated:
|
|
1036
|
-
guardrail.target.activate_target(self)
|
|
1037
|
-
return f"{guardrail.activation_message}\nJustification: {guardrail_result.justification}"
|
|
1032
|
+
if guardrail_result := agent.run_input_guardrails(messages):
|
|
1033
|
+
guardrail_result.guardrail.target.activate_target(self)
|
|
1034
|
+
return guardrail_result.reply
|
|
1038
1035
|
return None
|
|
1039
1036
|
|
|
1040
|
-
def _run_output_guardrails(self, agent: "ConversableAgent", reply: str) -> None:
|
|
1037
|
+
def _run_output_guardrails(self, agent: "ConversableAgent", reply: str | dict[str, Any]) -> str | None:
|
|
1041
1038
|
"""Run output guardrails for an agent after the reply is generated.
|
|
1042
1039
|
|
|
1043
1040
|
Args:
|
|
1044
1041
|
agent (ConversableAgent): The agent whose output guardrails to run.
|
|
1045
|
-
reply (str): The reply generated by the agent.
|
|
1042
|
+
reply (str | dict[str, Any]): The reply generated by the agent.
|
|
1046
1043
|
"""
|
|
1047
|
-
|
|
1048
|
-
guardrail_result
|
|
1044
|
+
if guardrail_result := agent.run_output_guardrails(reply):
|
|
1045
|
+
guardrail_result.guardrail.target.activate_target(self)
|
|
1046
|
+
return guardrail_result.reply
|
|
1047
|
+
return None
|
|
1048
|
+
|
|
1049
|
+
def _run_inter_agent_guardrails(
|
|
1050
|
+
self,
|
|
1051
|
+
*,
|
|
1052
|
+
src_agent_name: str,
|
|
1053
|
+
dst_agent_name: str,
|
|
1054
|
+
message_content: str,
|
|
1055
|
+
) -> str | None:
|
|
1056
|
+
"""Run policy-driven inter-agent guardrails, if any are configured.
|
|
1049
1057
|
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1058
|
+
Returns optional replacement content when a guardrail triggers.
|
|
1059
|
+
"""
|
|
1060
|
+
guardrails = getattr(self, "_inter_agent_guardrails", None)
|
|
1061
|
+
if not guardrails:
|
|
1062
|
+
return None
|
|
1063
|
+
for gr in guardrails:
|
|
1064
|
+
reply = gr.check_and_act(
|
|
1065
|
+
src_agent_name=src_agent_name,
|
|
1066
|
+
dst_agent_name=dst_agent_name,
|
|
1067
|
+
message_content=message_content,
|
|
1068
|
+
)
|
|
1069
|
+
if reply is not None:
|
|
1070
|
+
return reply
|
|
1053
1071
|
return None
|
|
1054
1072
|
|
|
1055
1073
|
|
|
@@ -1208,7 +1226,21 @@ class GroupChatManager(ConversableAgent):
|
|
|
1208
1226
|
# broadcast the message to all agents except the speaker
|
|
1209
1227
|
for agent in groupchat.agents:
|
|
1210
1228
|
if agent != speaker:
|
|
1211
|
-
|
|
1229
|
+
inter_reply = groupchat._run_inter_agent_guardrails(
|
|
1230
|
+
src_agent_name=speaker.name,
|
|
1231
|
+
dst_agent_name=agent.name,
|
|
1232
|
+
message_content=message,
|
|
1233
|
+
)
|
|
1234
|
+
if inter_reply is not None:
|
|
1235
|
+
replacement = (
|
|
1236
|
+
{"content": inter_reply, "name": speaker.name}
|
|
1237
|
+
if not isinstance(inter_reply, dict)
|
|
1238
|
+
else inter_reply
|
|
1239
|
+
)
|
|
1240
|
+
self.send(replacement, agent, request_reply=False, silent=True)
|
|
1241
|
+
else:
|
|
1242
|
+
self.send(message, agent, request_reply=False, silent=True)
|
|
1243
|
+
|
|
1212
1244
|
if self._is_termination_msg(message):
|
|
1213
1245
|
# The conversation is over
|
|
1214
1246
|
termination_reason = f"Termination message condition on the GroupChatManager '{self.name}' met"
|
|
@@ -1263,13 +1295,16 @@ class GroupChatManager(ConversableAgent):
|
|
|
1263
1295
|
reply = guardrails_reply
|
|
1264
1296
|
|
|
1265
1297
|
# check for "clear history" phrase in reply and activate clear history function if found
|
|
1266
|
-
if (
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1298
|
+
if groupchat.enable_clear_history and isinstance(reply, dict) and reply.get("content"):
|
|
1299
|
+
raw_content = reply.get("content")
|
|
1300
|
+
normalized_content = (
|
|
1301
|
+
content_str(raw_content)
|
|
1302
|
+
if isinstance(raw_content, (str, list)) or raw_content is None
|
|
1303
|
+
else str(raw_content)
|
|
1304
|
+
)
|
|
1305
|
+
if "CLEAR HISTORY" in normalized_content.upper():
|
|
1306
|
+
reply["content"] = normalized_content
|
|
1307
|
+
reply["content"] = self.clear_agents_history(reply, groupchat)
|
|
1273
1308
|
|
|
1274
1309
|
# The speaker sends the message without requesting a reply
|
|
1275
1310
|
speaker.send(reply, self, request_reply=False, silent=silent)
|
|
@@ -1380,13 +1415,16 @@ class GroupChatManager(ConversableAgent):
|
|
|
1380
1415
|
reply = guardrails_reply
|
|
1381
1416
|
|
|
1382
1417
|
# check for "clear history" phrase in reply and activate clear history function if found
|
|
1383
|
-
if (
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1418
|
+
if groupchat.enable_clear_history and isinstance(reply, dict) and reply.get("content"):
|
|
1419
|
+
raw_content = reply.get("content")
|
|
1420
|
+
normalized_content = (
|
|
1421
|
+
content_str(raw_content)
|
|
1422
|
+
if isinstance(raw_content, (str, list)) or raw_content is None
|
|
1423
|
+
else str(raw_content)
|
|
1424
|
+
)
|
|
1425
|
+
if "CLEAR HISTORY" in normalized_content.upper():
|
|
1426
|
+
reply["content"] = normalized_content
|
|
1427
|
+
reply["content"] = self.clear_agents_history(reply, groupchat)
|
|
1390
1428
|
|
|
1391
1429
|
# The speaker sends the message without requesting a reply
|
|
1392
1430
|
await speaker.a_send(reply, self, request_reply=False, silent=silent)
|
|
@@ -1661,7 +1699,13 @@ class GroupChatManager(ConversableAgent):
|
|
|
1661
1699
|
_remove_termination_string = remove_termination_string
|
|
1662
1700
|
|
|
1663
1701
|
if _remove_termination_string and messages[-1].get("content"):
|
|
1664
|
-
|
|
1702
|
+
content_value = messages[-1]["content"]
|
|
1703
|
+
if isinstance(content_value, str):
|
|
1704
|
+
messages[-1]["content"] = _remove_termination_string(content_value)
|
|
1705
|
+
elif isinstance(content_value, list):
|
|
1706
|
+
messages[-1]["content"] = _remove_termination_string(content_str(content_value))
|
|
1707
|
+
else:
|
|
1708
|
+
messages[-1]["content"] = _remove_termination_string(str(content_value))
|
|
1665
1709
|
|
|
1666
1710
|
# Check if the last message meets termination (if it has one)
|
|
1667
1711
|
if self._is_termination_msg and self._is_termination_msg(last_message):
|
|
@@ -1707,23 +1751,32 @@ class GroupChatManager(ConversableAgent):
|
|
|
1707
1751
|
agent._raise_exception_on_async_reply_functions()
|
|
1708
1752
|
|
|
1709
1753
|
def clear_agents_history(self, reply: dict[str, Any], groupchat: GroupChat) -> str:
|
|
1710
|
-
"""Clears history of messages for all agents or selected one. Can preserve selected number of last messages
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
When "clear history
|
|
1714
|
-
When "clear history `<
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1754
|
+
"""Clears history of messages for all agents or a selected one. Can preserve a selected number of last messages.\n
|
|
1755
|
+
\n
|
|
1756
|
+
This function is called when the user manually provides the "clear history" phrase in their reply.\n
|
|
1757
|
+
When "clear history" is provided, the history of messages for all agents is cleared.\n
|
|
1758
|
+
When "clear history `<agent_name>`" is provided, the history of messages for the selected agent is cleared.\n
|
|
1759
|
+
When "clear history `<nr_of_messages_to_preserve>`" is provided, the history of messages for all agents is cleared\n
|
|
1760
|
+
except for the last `<nr_of_messages_to_preserve>` messages.\n
|
|
1761
|
+
When "clear history `<agent_name>` `<nr_of_messages_to_preserve>`" is provided, the history of messages for the selected\n
|
|
1762
|
+
agent is cleared except for the last `<nr_of_messages_to_preserve>` messages.\n
|
|
1763
|
+
The phrase "clear history" and optional arguments are cut out from the reply before it is passed to the chat.\n
|
|
1764
|
+
\n
|
|
1765
|
+
Args:\n
|
|
1766
|
+
reply (dict): reply message dict to analyze.\n
|
|
1767
|
+
groupchat (GroupChat): GroupChat object.\n
|
|
1723
1768
|
"""
|
|
1724
1769
|
iostream = IOStream.get_default()
|
|
1725
1770
|
|
|
1726
|
-
|
|
1771
|
+
raw_reply_content = reply.get("content")
|
|
1772
|
+
if isinstance(raw_reply_content, str):
|
|
1773
|
+
reply_content = raw_reply_content
|
|
1774
|
+
elif isinstance(raw_reply_content, (list, type(None))):
|
|
1775
|
+
reply_content = content_str(raw_reply_content)
|
|
1776
|
+
reply["content"] = reply_content
|
|
1777
|
+
else:
|
|
1778
|
+
reply_content = str(raw_reply_content)
|
|
1779
|
+
reply["content"] = reply_content
|
|
1727
1780
|
# Split the reply into words
|
|
1728
1781
|
words = reply_content.split()
|
|
1729
1782
|
# Find the position of "clear" to determine where to start processing
|
|
@@ -8,7 +8,7 @@ from contextlib import AbstractAsyncContextManager
|
|
|
8
8
|
from logging import Logger
|
|
9
9
|
from typing import Any, Literal, Protocol, TypeVar, runtime_checkable
|
|
10
10
|
|
|
11
|
-
from
|
|
11
|
+
from anyio import create_task_group
|
|
12
12
|
|
|
13
13
|
from .....doc_utils import export_module
|
|
14
14
|
from .....llm_config import LLMConfig
|
|
@@ -140,7 +140,7 @@ class RealtimeClientBase:
|
|
|
140
140
|
Args:
|
|
141
141
|
audio (str): The audio.
|
|
142
142
|
"""
|
|
143
|
-
await self.add_event(InputAudioBufferDelta(delta=audio, item_id=None, raw_message=
|
|
143
|
+
await self.add_event(InputAudioBufferDelta(delta=audio, item_id=None, raw_message={}))
|
|
144
144
|
|
|
145
145
|
|
|
146
146
|
_realtime_client_classes: dict[str, type[RealtimeClientProtocol]] = {}
|
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
|
-
import asyncio
|
|
6
5
|
import json
|
|
7
6
|
from typing import TYPE_CHECKING, Any, Optional
|
|
8
7
|
|
|
9
|
-
from asyncer import asyncify
|
|
10
8
|
from pydantic import BaseModel
|
|
11
9
|
|
|
12
10
|
from ....doc_utils import export_module
|
|
11
|
+
from ....fast_depends.utils import asyncify
|
|
13
12
|
from .realtime_events import FunctionCall, RealtimeEvent
|
|
14
13
|
from .realtime_observer import RealtimeObserver
|
|
15
14
|
|
|
@@ -49,7 +48,7 @@ class FunctionObserver(RealtimeObserver):
|
|
|
49
48
|
"""
|
|
50
49
|
if name in self.agent.registered_realtime_tools:
|
|
51
50
|
func = self.agent.registered_realtime_tools[name].func
|
|
52
|
-
func =
|
|
51
|
+
func = asyncify(func)
|
|
53
52
|
try:
|
|
54
53
|
result = await func(**kwargs)
|
|
55
54
|
except Exception:
|
|
@@ -7,8 +7,7 @@ from dataclasses import dataclass
|
|
|
7
7
|
from logging import Logger, getLogger
|
|
8
8
|
from typing import Any, TypeVar
|
|
9
9
|
|
|
10
|
-
from anyio import lowlevel
|
|
11
|
-
from asyncer import create_task_group
|
|
10
|
+
from anyio import create_task_group, lowlevel
|
|
12
11
|
|
|
13
12
|
from ....doc_utils import export_module
|
|
14
13
|
from ....llm_config import LLMConfig
|
|
@@ -102,7 +101,7 @@ class RealtimeAgent:
|
|
|
102
101
|
|
|
103
102
|
async def start_observers(self) -> None:
|
|
104
103
|
for observer in self._observers:
|
|
105
|
-
self._tg.
|
|
104
|
+
self._tg.start_soon(observer.run, self)
|
|
106
105
|
|
|
107
106
|
# wait for the observers to be ready
|
|
108
107
|
for observer in self._observers:
|
|
@@ -3,18 +3,21 @@
|
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
|
+
import uuid
|
|
6
7
|
import warnings
|
|
7
8
|
from collections import defaultdict
|
|
8
9
|
from collections.abc import Callable
|
|
10
|
+
from functools import partial
|
|
9
11
|
from typing import TYPE_CHECKING, Any, Optional, TypeVar
|
|
10
12
|
|
|
11
13
|
import anyio
|
|
12
|
-
from
|
|
14
|
+
from anyio import create_task_group, from_thread
|
|
13
15
|
|
|
14
16
|
from ....agentchat.contrib.swarm_agent import AfterWorkOption, initiate_swarm_chat
|
|
15
17
|
from ....cache import AbstractCache
|
|
16
18
|
from ....code_utils import content_str
|
|
17
19
|
from ....doc_utils import export_module
|
|
20
|
+
from ....fast_depends.utils import asyncify
|
|
18
21
|
from ... import Agent, ChatResult, ConversableAgent, LLMAgent
|
|
19
22
|
from ...utils import consolidate_chat_info, gather_usage_summary
|
|
20
23
|
|
|
@@ -182,7 +185,6 @@ class SwarmableAgent(Agent):
|
|
|
182
185
|
self,
|
|
183
186
|
messages: list[dict[str, Any]] | None = None,
|
|
184
187
|
sender: Optional["Agent"] = None,
|
|
185
|
-
**kwargs: Any,
|
|
186
188
|
) -> str | dict[str, Any] | None:
|
|
187
189
|
if messages is None:
|
|
188
190
|
if sender is None:
|
|
@@ -211,6 +213,7 @@ class SwarmableAgent(Agent):
|
|
|
211
213
|
summary_args: dict[str, Any] | None = {},
|
|
212
214
|
**kwargs: dict[str, Any],
|
|
213
215
|
) -> ChatResult:
|
|
216
|
+
chat_id = uuid.uuid4().int
|
|
214
217
|
_chat_info = locals().copy()
|
|
215
218
|
_chat_info["sender"] = self
|
|
216
219
|
consolidate_chat_info(_chat_info, uniform_sender=self)
|
|
@@ -226,6 +229,7 @@ class SwarmableAgent(Agent):
|
|
|
226
229
|
recipient.previous_cache = None # type: ignore[attr-defined]
|
|
227
230
|
|
|
228
231
|
chat_result = ChatResult(
|
|
232
|
+
chat_id=chat_id,
|
|
229
233
|
chat_history=self.chat_messages[recipient],
|
|
230
234
|
summary=summary,
|
|
231
235
|
cost=gather_usage_summary([self, recipient]), # type: ignore[arg-type]
|
|
@@ -237,9 +241,8 @@ class SwarmableAgent(Agent):
|
|
|
237
241
|
self,
|
|
238
242
|
messages: list[dict[str, Any]] | None = None,
|
|
239
243
|
sender: Optional["Agent"] = None,
|
|
240
|
-
**kwargs: Any,
|
|
241
244
|
) -> str | dict[str, Any] | None:
|
|
242
|
-
return self.generate_reply(messages=messages, sender=sender
|
|
245
|
+
return self.generate_reply(messages=messages, sender=sender)
|
|
243
246
|
|
|
244
247
|
async def a_receive(
|
|
245
248
|
self,
|
|
@@ -349,7 +352,7 @@ class SwarmableRealtimeAgent(SwarmableAgent):
|
|
|
349
352
|
self._agents = agents
|
|
350
353
|
self._realtime_agent = realtime_agent
|
|
351
354
|
|
|
352
|
-
self._answer_event
|
|
355
|
+
self._answer_event = anyio.Event()
|
|
353
356
|
self._answer: str = ""
|
|
354
357
|
self.question_message = question_message or QUESTION_MESSAGE
|
|
355
358
|
|
|
@@ -419,12 +422,13 @@ class SwarmableRealtimeAgent(SwarmableAgent):
|
|
|
419
422
|
|
|
420
423
|
async def get_input() -> None:
|
|
421
424
|
async with create_task_group() as tg:
|
|
422
|
-
tg.
|
|
425
|
+
tg.start_soon(
|
|
426
|
+
self.ask_question,
|
|
423
427
|
self.question_message.format(messages[-1]["content"]),
|
|
424
428
|
question_timeout=QUESTION_TIMEOUT_SECONDS,
|
|
425
429
|
)
|
|
426
430
|
|
|
427
|
-
|
|
431
|
+
from_thread.run_sync(get_input)
|
|
428
432
|
|
|
429
433
|
return True, {"role": "user", "content": self._answer} # type: ignore[return-value]
|
|
430
434
|
|
|
@@ -449,12 +453,17 @@ class SwarmableRealtimeAgent(SwarmableAgent):
|
|
|
449
453
|
)(self.set_answer)
|
|
450
454
|
|
|
451
455
|
async def on_observers_ready() -> None:
|
|
452
|
-
self._realtime_agent._tg.
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
456
|
+
self._realtime_agent._tg.start_soon(
|
|
457
|
+
asyncify(
|
|
458
|
+
partial(
|
|
459
|
+
initiate_swarm_chat,
|
|
460
|
+
initial_agent=self._initial_agent,
|
|
461
|
+
agents=self._agents,
|
|
462
|
+
user_agent=self, # type: ignore[arg-type]
|
|
463
|
+
messages="Find out what the user wants.",
|
|
464
|
+
after_work=AfterWorkOption.REVERT_TO_USER,
|
|
465
|
+
)
|
|
466
|
+
)
|
|
458
467
|
)
|
|
459
468
|
|
|
460
469
|
self._realtime_agent.callbacks.on_observers_ready = on_observers_ready
|
|
@@ -15,15 +15,15 @@ from .conversable_agent import ConversableAgent
|
|
|
15
15
|
|
|
16
16
|
@export_module("autogen")
|
|
17
17
|
class UserProxyAgent(ConversableAgent):
|
|
18
|
-
"""(In preview) A proxy agent for the user, that can execute code and provide feedback to the other agents
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
"""(In preview) A proxy agent for the user, that can execute code and provide feedback to the other agents.\n
|
|
19
|
+
\n
|
|
20
|
+
UserProxyAgent is a subclass of ConversableAgent configured with `human_input_mode` to ALWAYS\n
|
|
21
|
+
and `llm_config` to False. By default, the agent will prompt for human input every time a message is received.\n
|
|
22
|
+
Code execution is enabled by default. LLM-based auto reply is disabled by default.\n
|
|
23
|
+
To modify auto reply, register a method with [`register_reply`](../ConversableAgent#register-reply).\n
|
|
24
|
+
To modify the way to get human input, override `get_human_input` method.\n
|
|
25
|
+
To modify the way to execute code blocks, single code block, or function call, override `execute_code_blocks`,\n
|
|
26
|
+
`run_code`, and `execute_function` methods respectively.\n
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
29
|
# Default UserProxyAgent.description values, based on human_input_mode
|
|
@@ -47,50 +47,52 @@ class UserProxyAgent(ConversableAgent):
|
|
|
47
47
|
description: str | None = None,
|
|
48
48
|
**kwargs: Any,
|
|
49
49
|
):
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
If
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
50
|
+
"""Initialize a UserProxyAgent.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
name (str): name of the agent.\n
|
|
54
|
+
is_termination_msg (function): a function that takes a message in the form of a dictionary\n
|
|
55
|
+
and returns a boolean value indicating if this received message is a termination message.\n
|
|
56
|
+
The dict can contain the following keys: "content", "role", "name", "function_call".\n
|
|
57
|
+
max_consecutive_auto_reply (int): the maximum number of consecutive auto replies.\n
|
|
58
|
+
default to None (no limit provided, class attribute MAX_CONSECUTIVE_AUTO_REPLY will be used as the limit in this case).\n
|
|
59
|
+
The limit only plays a role when human_input_mode is not "ALWAYS".\n
|
|
60
|
+
human_input_mode (str): whether to ask for human inputs every time a message is received.\n
|
|
61
|
+
Possible values are "ALWAYS", "TERMINATE", "NEVER".\n
|
|
62
|
+
(1) When "ALWAYS", the agent prompts for human input every time a message is received.\n
|
|
63
|
+
Under this mode, the conversation stops when the human input is "exit",\n
|
|
64
|
+
or when is_termination_msg is True and there is no human input.\n
|
|
65
|
+
(2) When "TERMINATE", the agent only prompts for human input only when a termination message is received or\n
|
|
66
|
+
the number of auto reply reaches the max_consecutive_auto_reply.\n
|
|
67
|
+
(3) When "NEVER", the agent will never prompt for human input. Under this mode, the conversation stops\n
|
|
68
|
+
when the number of auto reply reaches the max_consecutive_auto_reply or when is_termination_msg is True.\n
|
|
69
|
+
function_map (dict[str, callable]): Mapping function names (passed to openai) to callable functions.\n
|
|
70
|
+
code_execution_config (dict or False): config for the code execution.\n
|
|
71
|
+
To disable code execution, set to False. Otherwise, set to a dictionary with the following keys:\n
|
|
72
|
+
- work_dir (Optional, str): The working directory for the code execution.\n
|
|
73
|
+
If None, a default working directory will be used.\n
|
|
74
|
+
The default working directory is the "extensions" directory under\n
|
|
75
|
+
"path_to_autogen".\n
|
|
76
|
+
- use_docker (Optional, list, str or bool): The docker image to use for code execution.\n
|
|
77
|
+
Default is True, which means the code will be executed in a docker container. A default list of images will be used.\n
|
|
78
|
+
If a list or a str of image name(s) is provided, the code will be executed in a docker container\n
|
|
79
|
+
with the first image successfully pulled.\n
|
|
80
|
+
If False, the code will be executed in the current environment.\n
|
|
81
|
+
We strongly recommend using docker for code execution.\n
|
|
82
|
+
- timeout (Optional, int): The maximum execution time in seconds.\n
|
|
83
|
+
- last_n_messages (Experimental, Optional, int): The number of messages to look back for code execution. Default to 1.\n
|
|
84
|
+
default_auto_reply (str or dict or None): the default auto reply message when no code execution or llm based reply is generated.\n
|
|
85
|
+
llm_config (LLMConfig or dict or False or None): llm inference configuration.\n
|
|
86
|
+
Please refer to [OpenAIWrapper.create](https://docs.ag2.ai/latest/docs/api-reference/autogen/OpenAIWrapper/#autogen.OpenAIWrapper.create)\n
|
|
87
|
+
for available options.\n
|
|
88
|
+
Default to False, which disables llm-based auto reply.\n
|
|
89
|
+
When set to None, will use self.DEFAULT_CONFIG, which defaults to False.\n
|
|
90
|
+
system_message (str or List): system message for ChatCompletion inference.\n
|
|
91
|
+
Only used when llm_config is not False. Use it to reprogram the agent.\n
|
|
92
|
+
description (str): a short description of the agent. This description is used by other agents\n
|
|
93
|
+
(e.g. the GroupChatManager) to decide when to call upon this agent. (Default: system_message)\n
|
|
94
|
+
**kwargs (dict): Please refer to other kwargs in\n
|
|
95
|
+
[ConversableAgent](https://docs.ag2.ai/latest/docs/api-reference/autogen/ConversableAgent).\n
|
|
94
96
|
"""
|
|
95
97
|
super().__init__(
|
|
96
98
|
name=name,
|
|
@@ -198,15 +198,6 @@ class DocAgent(ConversableAgent):
|
|
|
198
198
|
)
|
|
199
199
|
self.register_reply([ConversableAgent, None], self.generate_inner_group_chat_reply, position=0)
|
|
200
200
|
|
|
201
|
-
self.context_variables: ContextVariables = ContextVariables(
|
|
202
|
-
data={
|
|
203
|
-
"DocumentsToIngest": [],
|
|
204
|
-
"DocumentsIngested": [],
|
|
205
|
-
"QueriesToRun": [],
|
|
206
|
-
"QueryResults": [],
|
|
207
|
-
}
|
|
208
|
-
)
|
|
209
|
-
|
|
210
201
|
self._triage_agent = DocumentTriageAgent(llm_config=llm_config)
|
|
211
202
|
|
|
212
203
|
def create_error_agent_prompt(agent: ConversableAgent, messages: list[dict[str, Any]]) -> str:
|
|
@@ -396,7 +387,7 @@ class DocAgent(ConversableAgent):
|
|
|
396
387
|
else:
|
|
397
388
|
# First time initialization - no deduplication needed
|
|
398
389
|
context_variables["DocumentsToIngest"] = ingestions
|
|
399
|
-
context_variables["QueriesToRun"] =
|
|
390
|
+
context_variables["QueriesToRun"] = list(queries)
|
|
400
391
|
context_variables["TaskInitiated"] = True
|
|
401
392
|
response_message = "Updated context variables with task decisions"
|
|
402
393
|
|
|
@@ -15,7 +15,11 @@ from .document_utils import handle_input
|
|
|
15
15
|
|
|
16
16
|
with optional_import_block():
|
|
17
17
|
from docling.datamodel.base_models import InputFormat
|
|
18
|
-
from docling.datamodel.pipeline_options import
|
|
18
|
+
from docling.datamodel.pipeline_options import ( # type: ignore[attr-defined]
|
|
19
|
+
AcceleratorDevice,
|
|
20
|
+
AcceleratorOptions,
|
|
21
|
+
PdfPipelineOptions,
|
|
22
|
+
)
|
|
19
23
|
from docling.document_converter import DocumentConverter, PdfFormatOption
|
|
20
24
|
|
|
21
25
|
__all__ = ["docling_parse_docs"]
|
autogen/browser_utils.py
CHANGED
|
@@ -58,10 +58,10 @@ class SimpleTextBrowser:
|
|
|
58
58
|
self.start_page: str = start_page if start_page else "about:blank"
|
|
59
59
|
self.viewport_size = viewport_size # Applies only to the standard uri types
|
|
60
60
|
self.downloads_folder = downloads_folder
|
|
61
|
-
self.history: list[str] =
|
|
61
|
+
self.history: list[str] = []
|
|
62
62
|
self.page_title: str | None = None
|
|
63
63
|
self.viewport_current_page = 0
|
|
64
|
-
self.viewport_pages: list[tuple[int, int]] =
|
|
64
|
+
self.viewport_pages: list[tuple[int, int]] = []
|
|
65
65
|
self.set_address(self.start_page)
|
|
66
66
|
self.bing_base_url = bing_base_url
|
|
67
67
|
self.bing_api_key = bing_api_key
|
|
@@ -182,7 +182,7 @@ class SimpleTextBrowser:
|
|
|
182
182
|
def _bing_search(self, query: str) -> None:
|
|
183
183
|
results = self._bing_api_call(query)
|
|
184
184
|
|
|
185
|
-
web_snippets: list[str] =
|
|
185
|
+
web_snippets: list[str] = []
|
|
186
186
|
idx = 0
|
|
187
187
|
for page in results["webPages"]["value"]:
|
|
188
188
|
idx += 1
|
|
@@ -194,7 +194,7 @@ class SimpleTextBrowser:
|
|
|
194
194
|
f"{idx}. [{dl['name']}]({dl['url']})\n{dl.get('snippet', '')}" # type: ignore[index]
|
|
195
195
|
)
|
|
196
196
|
|
|
197
|
-
news_snippets =
|
|
197
|
+
news_snippets = []
|
|
198
198
|
if "news" in results:
|
|
199
199
|
for page in results["news"]["value"]:
|
|
200
200
|
idx += 1
|
|
@@ -4,16 +4,12 @@
|
|
|
4
4
|
#
|
|
5
5
|
# Portions derived from https://github.com/microsoft/autogen are under the MIT License.
|
|
6
6
|
# SPDX-License-Identifier: MIT
|
|
7
|
-
import sys
|
|
8
7
|
from types import TracebackType
|
|
9
8
|
from typing import Any, Protocol
|
|
10
9
|
|
|
11
|
-
from
|
|
10
|
+
from typing_extensions import Self
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
from typing import Self
|
|
15
|
-
else:
|
|
16
|
-
from typing_extensions import Self
|
|
12
|
+
from ..doc_utils import export_module
|
|
17
13
|
|
|
18
14
|
|
|
19
15
|
@export_module("autogen.cache")
|