Skip to content

Commit

Permalink
Add user proxy docs. Make user proxy's default impl cancellable (micr…
Browse files Browse the repository at this point in the history
…osoft#4459)

* Add user proxy docs. Make user proxy's default impl cancellable

* remove unnecessary import

* revert accidental change

* address PR comments

* uv sync

* Fix bugs

* poe format

* fixing mypy issues

* poe format

* ignore pyright errors for ainput

* fix example code

* remove unused import

* fix accidental reversion, example code

* formatting

* fix typing

* Update python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/agents.ipynb

Co-authored-by: Copilot <[email protected]>

* Update python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/agents.ipynb

---------

Co-authored-by: Jack Gerrits <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Eric Zhu <[email protected]>
  • Loading branch information
4 people authored Dec 6, 2024
1 parent 8dac072 commit c5c3444
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from inspect import iscoroutinefunction
from typing import Awaitable, Callable, List, Optional, Sequence, Union, cast

from aioconsole import ainput # type: ignore
from autogen_core import CancellationToken

from ..base import Response
Expand All @@ -14,6 +15,15 @@
InputFuncType = Union[SyncInputFunc, AsyncInputFunc]


# TODO: ainput doesn't seem to play nicely with jupyter.
# No input window appears in this case.
async def cancellable_input(prompt: str, cancellation_token: Optional[CancellationToken]) -> str:
task = asyncio.Task[str](asyncio.create_task(ainput(prompt))) # type: ignore
if cancellation_token is not None:
cancellation_token.link_future(task)
return await task


class UserProxyAgent(BaseChatAgent):
"""An agent that can represent a human user through an input function.
Expand All @@ -40,6 +50,63 @@ class UserProxyAgent(BaseChatAgent):
See `Pause for User Input <https://microsoft.github.io/autogen/dev/user-guide/agentchat-user-guide/tutorial/teams.html#pause-for-user-input>`_ for more information.
Example:
Simple usage case::
import asyncio
from autogen_core import CancellationToken
from autogen_agentchat.agents import UserProxyAgent
from autogen_agentchat.messages import TextMessage
async def simple_user_agent():
agent = UserProxyAgent("user_proxy")
response = await asyncio.create_task(
agent.on_messages(
[TextMessage(content="What is your name? ", source="user")],
cancellation_token=CancellationToken(),
)
)
print(f"Your name is {response.chat_message.content}")
Example:
Cancellable usage case::
import asyncio
from typing import Any
from autogen_core import CancellationToken
from autogen_agentchat.agents import UserProxyAgent
from autogen_agentchat.messages import TextMessage
token = CancellationToken()
agent = UserProxyAgent("user_proxy")
async def timeout(delay: float):
await asyncio.sleep(delay)
def cancellation_callback(task: asyncio.Task[Any]):
token.cancel()
async def cancellable_user_agent():
try:
timeout_task = asyncio.create_task(timeout(3))
timeout_task.add_done_callback(cancellation_callback)
agent_task = asyncio.create_task(
agent.on_messages(
[TextMessage(content="What is your name? ", source="user")],
cancellation_token=CancellationToken(),
)
)
response = await agent_task
print(f"Your name is {response.chat_message.content}")
except Exception as e:
print(f"Exception: {e}")
except BaseException as e:
print(f"BaseException: {e}")
"""

def __init__(
Expand All @@ -51,7 +118,7 @@ def __init__(
) -> None:
"""Initialize the UserProxyAgent."""
super().__init__(name=name, description=description)
self.input_func = input_func or input
self.input_func = input_func or cancellable_input
self._is_async = iscoroutinefunction(self.input_func)

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -101,6 +101,39 @@
"as well as a list of inner messages in the {py:attr}`~autogen_agentchat.base.Response.inner_messages` attribute,\n",
"which stores the agent's \"thought process\" that led to the final response.\n",
"\n",
"## User Proxy Agent\n",
"\n",
"{py:class}`~autogen_agentchat.agents.UserProxyAgent` is a built-in agent that\n",
"provides one way for a user to intervene in the process. This agent will put the team in a temporary blocking state, and thus any exceptions or runtime failures while in the blocked state will result in a deadlock. It is strongly advised that this agent be coupled with a timeout mechanic and that all errors and exceptions emanating from it are handled."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from autogen_agentchat.agents import UserProxyAgent\n",
"\n",
"\n",
"async def user_proxy_run() -> None:\n",
" user_proxy_agent = UserProxyAgent(\"user_proxy\")\n",
" response = await user_proxy_agent.on_messages(\n",
" [TextMessage(content=\"What is your name? \", source=\"user\")], cancellation_token=CancellationToken()\n",
" )\n",
" print(f\"Your name is {response.chat_message.content}\")\n",
"\n",
"\n",
"# Use asyncio.run(user_proxy_run()) when running in a script.\n",
"await user_proxy_run()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The User Proxy agent is ideally used for on-demand human-in-the-loop interactions for scenarios such as Just In Time approvals, human feedback, alerts, etc. For slower user interactions, consider terminating the session using a termination condition and start another one from run or run_stream with another message.\n",
"\n",
"### Stream Messages\n",
"\n",
"We can also stream each message as it is generated by the agent by using the\n",
Expand Down
1 change: 1 addition & 0 deletions python/packages/autogen-core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ classifiers = [
dependencies = [
"openai>=1.3",
"pillow",
"aioconsole",
"aiohttp",
"typing-extensions",
"pydantic<3.0.0,>=2.0.0",
Expand Down
11 changes: 11 additions & 0 deletions python/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c5c3444

Please sign in to comment.