forked from wise-agents/wise-agents
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an example to interact with user. A new kind of coordinator (Sequ…
…entialMemoryCoordinatorWiseAgent) and collaboration type are added to support this. Fixes wise-agents#331 and wise-agents#122
- Loading branch information
Showing
7 changed files
with
332 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
|
||
# Perceive, ask and Act Example | ||
|
||
This guide walks you through running a practical example of a multi-agent system using Wise Agents. In this example, six agents (an agent interacting with a human with a text based interface, a sequential agent coordinator, and four intelligent agents) are started, allowing you to experiment with agents/humans communication and interaction in a simulated environment. It uses a sequential coordination able to share chat history between involved agents. | ||
|
||
|
||
## Example Overview | ||
|
||
The example consists of six agents: | ||
|
||
1. **PerceivingAgent**: This is an agent that can perceive file changes. In case of changes it send a message with the list of books contained in books_read.txt to the SequentialCoordinator. This agent code is not part of wise-agents framework, but it's defined for this example use only in `custom_agent.py` present in the example directory. | ||
2. **LiterateAgent**: Handles requests and provides intelligent responses. Its system message says: | ||
*"You are an english literature expert. The user will provide you with a list of books they have read. Suggest the next 5 books they should read and ask user for their favorite one in this list"* | ||
3. **UserQuestionAgent**: ask a question to the user and pass over the answer as part of the flow. This is not defined in the yaml, but started from `custom_agent.py` instantiating the agent from the code. It provides also a very simple text based interface to ask a question which is needed to complete the designed flow. | ||
4. **FinalLiterateAgent**: Handles requests and provides intelligent responses. Its system message says: | ||
*"You will receive a preference from the user. Considering the previous books read , the user's preference on your first list of suggestion, suggest the next 3 books they should read."* | ||
5. **ActionAgent**: This agent will write what received (the books suggested) in a file (books_suggested.txt). It will override the file each time. This agent code is not part of wise-agents framework, but it's defined for this example use only in `custom_agent.py` present in the example directory. | ||
6. **SequentialCoordinator**: Take care of coordinating the request handling from the user delagating the work to other agents in a predetermined order. Note the SequentialCoordinar here will use the `wiseagents.agents.SequentialMemoryCoordinatorWiseAgent` which share the chat history between all agents involved in the sequence, permitting them to make reasoning based on all the interaction with LLM happened in previous step. In this example, the **FinalLiterateAgent** will use info coming from **PerceivingAgent**, **LiterateAgent**, and **UserQuestionAgent** to produce the final list of 3 suggested books. | ||
|
||
These agents are defined in YAML configuration files located in the `examples/perceive_ask_and_act` directory. | ||
|
||
## Prerequisite For Running the Example | ||
1. Clone the repository | ||
2. Configure and start redis | ||
3. Start artemis | ||
4. Start Ollama | ||
|
||
For detailed instructions on how to satisfy those prerequisite please refer to [prerequisites.md](../prerequisites.md) | ||
|
||
|
||
### Step 1: Start the Intelligent Agent | ||
|
||
In a console, run the intelligent agents and coordinator agent. Having custom created agents in the directory of example you need to run the script from there after setting PYTHONPATH env variable. Here you have all the commands needed pretending you are in the project main directory: | ||
|
||
```bash | ||
cd examples/perceive_ask_and_act | ||
export PYTHONPATH="." | ||
python ../../src/wiseagents/cli/wise_agent_cli.py ./intelligent-agents.yaml | ||
``` | ||
|
||
This will initialize the intelligent agents and coordinator agent, which will be ready to watch `books_read.txt` for changes. | ||
|
||
### Step 2: Start UserQuestionAgent | ||
In a console, start the UserQuestionAgent. Having custom created agents in the directory of example you need to run the script from there after setting PYTHONPATH env variable. Here you have all the commands needed pretending you are in the project main directory: | ||
|
||
```bash | ||
cd examples/perceive_ask_and_act | ||
export PYTHONPATH="." | ||
python ./custom_agents.py | ||
``` | ||
|
||
This will initialize the UserQuestionAgent, and will be ready to show question and accept answer from the user. | ||
|
||
### Step 3: Interaction | ||
|
||
Once all agents are up and running, you can edit `books_read.txt` file and `PerceivingAgent` will start sending requests to the coordinator agent. The coordinator agent will take care to interact to the `LiterateAgent`. `Literate Agent` will create a list of 5 suggested books and a question asking the user for a preference. Then the message will be sent to `UserQuestionAgent` which will show the list and the question in the console, asking for an answer. The answer inserted by the user will be passed to the `ActionAgent` which will write the results to `books_suggested.txt`. You will be able to see the interaction between the agents through the logs in both consoles. | ||
|
||
|
||
### Step 4: Experiment | ||
|
||
You can experiment with different agent configurations or modify the agent behaviors by editing the YAML files located in the `examples/perceive_ask_and_act` directory. These configuration files define the agents' properties, including memory, communication methods, and response patterns. You can do that without restarting everything, just edit the yaml file(s) and use CLI's /reload command (see our documentation for more details on how to use CLI) | ||
|
||
## Understanding the YAML Configuration and custom_agents.py | ||
|
||
- **intelligent-agents.yaml**: Defines all the agents discussed in this document and needed to run the example | ||
- **custom_agents.py**: contain 3 custom agents defined for the purpose of this example. It has also a `main()` function which instantiate the `UserQuestionAgent` | ||
|
||
These YAML files include the specific `WiseAgent` classes and configuration needed to run the agents. Feel free to explore and modify these files to customize the agents' behavior. | ||
|
||
## Additional Resources | ||
|
||
For more information about the architecture and advanced configurations of wise-agents, refer to the [Wise Agents Architecture Document](wise_agents_architecture.md), which provides insights into how the system can be scaled and deployed in distributed environments. | ||
|
||
## Conclusion | ||
|
||
By following these steps, you have successfully run a simple sequential coordinated multi-agent chatbot using Wise Agents. You can now explore further by modifying agent behaviors, adding new agents, or experimenting with different message flows. | ||
|
||
For any further assistance, feel free to refer to the official Wise Agents documentation or reach out to the repository maintainers. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
King Lear |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import os | ||
import signal | ||
import threading | ||
import time | ||
from openai.types.chat import ChatCompletionToolParam, ChatCompletionMessageParam | ||
from typing import List, Optional | ||
from wiseagents import WiseAgent, WiseAgentEvent, WiseAgentMessage, WiseAgentTransport | ||
from wiseagents.transports.stomp import StompWiseAgentTransport | ||
from wiseagents.yaml import WiseAgentsLoader | ||
|
||
class PerceivingAgent(WiseAgent): | ||
yaml_tag = u'!custom_agents.PerceivingAgent' | ||
yaml_loader = WiseAgentsLoader | ||
|
||
stop_event = threading.Event() | ||
|
||
def __init__(self, name: str, description: str, transport: WiseAgentTransport, file_path: str, check_interval: float, destination_agent_name: str): | ||
self._file_path = file_path | ||
self._check_interval = check_interval | ||
self._destination_agent_name = destination_agent_name | ||
super().__init__(name=name, description=description, transport=transport) | ||
|
||
def start_agent(self): | ||
super().start_agent() | ||
self.stop_event.clear() | ||
self.perceive(self._file_path, self.on_file_change, self._check_interval) | ||
|
||
def stop_agent(self): | ||
self.stop_event.set() | ||
super().stop_agent() | ||
|
||
def process_request(self, request: WiseAgentMessage, | ||
conversation_history: List[ChatCompletionMessageParam]) -> Optional[str]: | ||
pass | ||
|
||
def process_response(self, response: WiseAgentMessage): | ||
pass | ||
|
||
def process_event(self, event: WiseAgentEvent): | ||
pass | ||
|
||
def process_error(self, error: WiseAgentMessage): | ||
pass | ||
|
||
def perceive(self, file_path, callback, check_interval=1.0): | ||
""" | ||
Monitors a file for any changes and invokes a callback with the file's content upon modification. | ||
Args: | ||
file_path (str): The path to the file to monitor. | ||
callback (callable): A function to call with the file's content when it changes. | ||
check_interval (float, optional): Time in seconds between checks. Defaults to 1.0. | ||
""" | ||
def watch(): | ||
try: | ||
last_mtime = os.path.getmtime(file_path) | ||
except FileNotFoundError: | ||
last_mtime = None | ||
|
||
while not self.stop_event.is_set(): | ||
try: | ||
print(f"Checking file {file_path}") | ||
current_mtime = os.path.getmtime(file_path) | ||
if last_mtime is None: | ||
last_mtime = current_mtime | ||
elif current_mtime != last_mtime: | ||
print(f"File {file_path} has changed") | ||
last_mtime = current_mtime | ||
with open(file_path, 'r') as f: | ||
content = f.read() | ||
callback(content) | ||
except FileNotFoundError: | ||
if last_mtime is not None: | ||
last_mtime = None | ||
except Exception as e: | ||
print(f"Error monitoring file: {e}") | ||
time.sleep(check_interval) | ||
|
||
thread = threading.Thread(target=watch, daemon=True) | ||
thread.start() | ||
|
||
def on_file_change(self, content): | ||
print(f"sending message: {content}, {self.name}, {self._destination_agent_name}") | ||
self.send_request(WiseAgentMessage(content, self.name), self._destination_agent_name) | ||
|
||
class ActionAgent(WiseAgent): | ||
yaml_tag = u'!custom_agents.ActionAgent' | ||
yaml_loader = WiseAgentsLoader | ||
|
||
def __init__(self, name: str, description: str, transport: WiseAgentTransport, destination_file_path: str): | ||
self._destination_file_path = destination_file_path | ||
super().__init__(name=name, description=description, transport=transport) | ||
|
||
|
||
def process_request(self, request: WiseAgentMessage, conversation_history: List[ChatCompletionMessageParam]) -> Optional[str]: | ||
with open(self._destination_file_path, 'w') as f: | ||
f.write(request.message) | ||
self.send_response(WiseAgentMessage("File updated", self.name), request.sender) | ||
|
||
|
||
def process_response(self, response: WiseAgentMessage): | ||
pass | ||
|
||
def process_event(self, event: WiseAgentEvent): | ||
pass | ||
|
||
def process_error(self, error: WiseAgentMessage): | ||
pass | ||
|
||
class UserQuestionAgent(WiseAgent): | ||
yaml_tag = u'!custom_agents.UserQuestionAgent' | ||
yaml_loader = WiseAgentsLoader | ||
|
||
def __init__(self, name: str, description: str, transport: WiseAgentTransport): | ||
super().__init__(name=name, description=description, transport=transport) | ||
|
||
|
||
def process_request(self, request: WiseAgentMessage, conversation_history: List[ChatCompletionMessageParam]) -> Optional[str]: | ||
print(f"User question: {request.message}") | ||
userAnswer = input("Answer: ") | ||
return userAnswer | ||
|
||
def process_response(self, response: WiseAgentMessage): | ||
pass | ||
|
||
def process_event(self, event: WiseAgentEvent): | ||
pass | ||
|
||
def process_error(self, error: WiseAgentMessage): | ||
pass | ||
|
||
|
||
def signal_handler(sig, frame): | ||
global user_question_agent | ||
print('You pressed Ctrl+C!') | ||
user_question_agent.stop_agent() | ||
exit(0) | ||
|
||
|
||
|
||
def main(): | ||
global user_question_agent | ||
stomp_transport = StompWiseAgentTransport("localhost", 61616, "UserQuestionAgent") | ||
#create and start the agent | ||
user_question_agent = UserQuestionAgent(name="UserQuestionAgent", description="Asks the user a question", transport=stomp_transport) | ||
|
||
signal.signal(signal.SIGINT, signal_handler) | ||
print('Press Ctrl+C to exit') | ||
signal.pause() | ||
while True: | ||
pass | ||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
--- | ||
!wiseagents.agents.ChatWiseAgent | ||
_description: This is an agent that can give suggestion on what to read next | ||
_llm: !wiseagents.llm.OpenaiAPIWiseAgentLLM | ||
_model_name: llama3.1 | ||
_remote_address: http://localhost:11434/v1 | ||
_system_message: You are an english literature expert. The user will provide you with a list of books they have read. Suggest the next 5 books they should read and ask user for their favorite one in this list | ||
_name: LiterateAgent | ||
_transport: !wiseagents.transports.StompWiseAgentTransport | ||
_host: localhost | ||
_port: 61616 | ||
_agent_name: LiterateAgent | ||
--- | ||
!custom_agents.PerceivingAgent | ||
_description: This is an agent that can perceive file changes | ||
_name: PerceivingAgent | ||
_file_path: ./books_read.txt | ||
_check_interval: 5 | ||
_destination_agent_name: SequentialCoordinator | ||
_transport: !wiseagents.transports.StompWiseAgentTransport | ||
_host: localhost | ||
_port: 61616 | ||
_agent_name: PerceivingAgent | ||
--- | ||
!custom_agents.ActionAgent | ||
_description: This is an agent that can write a file | ||
_name: ActionAgent | ||
_destination_file_path: ./books_suggested.txt | ||
_transport: !wiseagents.transports.StompWiseAgentTransport | ||
_host: localhost | ||
_port: 61616 | ||
_agent_name: ActionAgent | ||
--- | ||
!wiseagents.agents.ChatWiseAgent | ||
_description: This is an agent that can give suggestion on what to read next | ||
_llm: !wiseagents.llm.OpenaiAPIWiseAgentLLM | ||
_model_name: llama3.1 | ||
_remote_address: http://localhost:11434/v1 | ||
_system_message: You will receive a preference from the user. Considering the previous books read , the user's preference on your first list of suggestion, suggest the next 3 books they should read. | ||
_name: FinalLiterateAgent | ||
_transport: !wiseagents.transports.StompWiseAgentTransport | ||
_host: localhost | ||
_port: 61616 | ||
_agent_name: FinalLiterateAgent | ||
--- | ||
!wiseagents.agents.SequentialMemoryCoordinatorWiseAgent | ||
_description: This is a coordinator agent | ||
_name: SequentialCoordinator | ||
_agents: ["LiterateAgent", "UserQuestionAgent", "FinalLiterateAgent", "ActionAgent"] | ||
_transport: !wiseagents.transports.StompWiseAgentTransport | ||
_host: localhost | ||
_port: 61616 | ||
_agent_name: SequentialCoordinator |
Oops, something went wrong.