Skip to content

Using sockets rather than print#1290

Closed
joshkyh wants to merge 9 commits into
mainfrom
use-sockets
Closed

Using sockets rather than print#1290
joshkyh wants to merge 9 commits into
mainfrom
use-sockets

Conversation

@joshkyh

@joshkyh joshkyh commented Jan 16, 2024

Copy link
Copy Markdown
Contributor

Reviewers:
@ekzhu on navigating the refactoring efforts in #1240
@victordibia regarding the generalized approach in #394 (comment)

Why are these changes needed?

This PR allows the output of Agents like ConversableAgent to be emitted through socket rather than print to console, allowing integration with other front end tools that could sit outside of Autogen. This PR is co-authored by @ragyabraham and myself. Tagging @tomlynchRNA for awareness.

Related issue number

Closes #394
Associated #1199 for emitting to Teams front end. @tyler-suard-parker
Dependent on #1240 for cleaner/easier implementation.

Checks

@codecov-commenter

codecov-commenter commented Jan 16, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 54.76190% with 19 lines in your changes missing coverage. Please review.

Project coverage is 41.92%. Comparing base (260e0cf) to head (e9af709).
Report is 1697 commits behind head on main.

Files with missing lines Patch % Lines
autogen/agentchat/contrib/stream_handler.py 60.00% 10 Missing ⚠️
autogen/agentchat/conversable_agent.py 30.00% 6 Missing and 1 partial ⚠️
autogen/agentchat/groupchat.py 71.42% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1290      +/-   ##
==========================================
+ Coverage   31.98%   41.92%   +9.93%     
==========================================
  Files          33       34       +1     
  Lines        4415     4456      +41     
  Branches     1030     1095      +65     
==========================================
+ Hits         1412     1868     +456     
+ Misses       2887     2437     -450     
- Partials      116      151      +35     
Flag Coverage Δ
unittests 41.85% <54.76%> (+9.91%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@ekzhu

ekzhu commented Jan 16, 2024

Copy link
Copy Markdown
Contributor

This is a great addition. I am trying to get a good understanding of the design.

  1. Is this aiming to move agent-to-agent communication on to websocket/streaming? There is a parallel effort on this front from Add RemoteAgent and Receiver #1289
  2. To handle printing to a stream, could this be done with a special logging middleware as proposed in the middleware design in Refactorization of ConversableAgent to unify async and sync code and better extensibility #1240?

@joshkyh

joshkyh commented Jan 16, 2024

Copy link
Copy Markdown
Contributor Author

This is a great addition. I am trying to get a good understanding of the design.

  1. Is this aiming to move agent-to-agent communication on to websocket/streaming? There is a parallel effort on this front from Add RemoteAgent and Receiver #1289

Thanks! I'm glad you're excited by it too.

@ragyabraham please feel free to add.

I think the fundamental difference to #1289 is that here, we're not trying to move the agent-to-agent message transmission to socket, nor have an Agent hosted elsewhere. If my understanding is correct
jacks_cal = RemoteAgent("jacks_cal", host="localhost", port=45554)
means that jacks_cal can be hosted at another IP address. This PR is not concerned with that. Instead, this PR is about emitting messages of what each Agent said onto the socket, so that another front-end tool can display it and not for the purpose of sending it to another agent. In our use case, the front-end is a web browser, there seems to be another use case of displaying it in Teams in #1199.

  1. To handle printing to a stream, could this be done with a special logging middleware as proposed in the middleware design in Refactorization study with design patterns (was refactorization of hooks) #1240?

I think so, however, I'm not very familiar with hooks, and would need to work with you or @davorrunje to iterate on how to implement it properly through the reviews. If there's any tips anyone can share before we start developing, that might help reduce reviews/rework! :)

@ekzhu

ekzhu commented Jan 16, 2024

Copy link
Copy Markdown
Contributor

need to work with you or @davorrunje to iterate on how to implement it properly through the reviews

Certainly! I am here to make sure us don't have to redo a lot of work. I am just thinking if #1240 go through first, it will be much easier for us to implement something like logging and emitting to a frontend.

Comment on lines +65 to +67
use_agent_stream: Optional[bool] = False,
get_socket_client_function: Optional[Callable] = None,
sid: Optional[str] = None,

@gagb gagb Jan 21, 2024

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add docstring for new arguments.
Consider choosing more descriptive name than sid?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree

llm_config: Optional[Union[Dict, Literal[False]]] = None,
default_auto_reply: Optional[Union[str, Dict, None]] = "",
description: Optional[str] = None,
use_agent_stream: Optional[bool] = False,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can easily imagine more than just two types of output stream because there are so many different ways to stream data on the internet. Why don't we define AgentOutput protocol for outputting data and implement two initial classes: PrintAgentOutput and SocketAgentOutput implementing the protocol? That way we would be extensible in future without being forced to change the ConversableClient class.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 On the suggestion.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this approach, should we plan for mutually exclusive outputs or a list of outputs? E.g. both print and socket outputs happening.


if self.use_agent_stream:
# Generate sid if None
if self.sid is None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These implementation details can be refactored out to a separate delegate class to avoid bloating the ConversableAgent.

)

if use_agent_stream:
# Generate sid if None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor out to delegate to avoid bloating

@joshkyh

joshkyh commented Jan 21, 2024

Copy link
Copy Markdown
Contributor Author

@ekzhu @victordibia
@ragyabraham and I discussed this during our stand-up. We have to withdraw working on this due to other priorities. Can I assign this to the MSFT team?

@ekzhu

ekzhu commented Jan 23, 2024

Copy link
Copy Markdown
Contributor

@joshkyh no worries. I just unassigned you from the PR.

@sonichi sonichi requested a review from Tylersuard January 27, 2024 16:53
@Tylersuard

Copy link
Copy Markdown

@ekzhu can we have some simple example code for how to implement this on our own?

# Upper, digits. 5chars - 5chars - 5chars
candidates = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
sid = "-".join(
[

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we choosing random letters here? Could we just use uuid?

@Tylersuard Tylersuard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add example code for how to use streaming with agents. This is a really cool feature, and I'm sure a lot of people will want to know how to use it.

sid = "-".join(
[
"".join(random.choices(candidates, k=5)),
"".join(random.choices(candidates, k=5)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, why are we using random letters here instead of using uuid?

autogen.agentchat.Agent(name="Agent2"),
autogen.agentchat.Agent(name="Agent3")]

with pytest.raises(ValueError, match="get_socket_client_function is required if use_agent_stream is True"):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also have a test that assures streaming is working?
Also, some example code which instantiates an agent and sets up socket streaming would be helpful.

@ekzhu

ekzhu commented Jan 28, 2024

Copy link
Copy Markdown
Contributor

@Tylersuard Thanks for your interest. This is surely a feature we hope to have but don't have cycle to work on. If you are interested, you can take a look at it. A good place to start is in the conversable_agent.py file, in the method generate_reply. Before the reply message gets sent out you can intercept there and add an async write to a stream, which can be passed in as part of the constructor.

#1240 will refactor ConversableAgent to make this type of extension very easy to do. i.e., it will be a middleware class that you put inside ConversableAgent. You can also choose to work from that branch.

@bitnom

bitnom commented Feb 14, 2024

Copy link
Copy Markdown
Contributor

I have implemented this sort of thing in autogen multiple times so far. IMO the best 'official' way to handle it would be to introduce an input Queue and an output Queue, allowing the user to specify and/or override them.

@ekzhu

ekzhu commented Feb 14, 2024

Copy link
Copy Markdown
Contributor

@joshkyh shall we close this one for now? The code base has moved a lot since.

@ekzhu

ekzhu commented Feb 14, 2024

Copy link
Copy Markdown
Contributor

I have implemented this sort of thing in autogen multiple times so far. IMO the best 'official' way to handle it would be to introduce an input Queue and an output Queue, allowing the user to specify and/or override them.

Great, you are welcome to go to #1551 to check it out. And there will be follow-up efforts on how to integrate it with frontend.

@joshkyh joshkyh closed this Feb 14, 2024
@joshkyh joshkyh deleted the use-sockets branch February 14, 2024 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

use sockets rather than print messages to terminal

9 participants