-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into u/xiaoyun/0206
- Loading branch information
Showing
12 changed files
with
358 additions
and
5 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
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,43 @@ | ||
<div align="center"> | ||
<img src="images/icon.png" alt="Repo Icon" width="100" height="100"> | ||
</div> | ||
|
||
# AutoAnny | ||
|
||
AutoAnny is a Discord bot built using AutoGen to help with AutoGen's Discord server. | ||
Actually Anny can help with any OSS GitHub project (set `ANNY_GH_REPO` below). | ||
|
||
## Features | ||
|
||
- **`/heyanny help`**: Lists commands. | ||
- **`/heyanny ghstatus`**: Summarizes GitHub activity. | ||
- **`/heyanny ghgrowth`**: Shows GitHub repo growth indicators. | ||
- **`/heyanny ghunattended`**: Lists unattended issues and PRs. | ||
|
||
## Installation | ||
|
||
1. Clone the AutoGen repository and `cd samples/apps/auto-anny` | ||
2. Install dependencies: `pip install -r requirements.txt` | ||
3. Export Discord token and GitHub API token, | ||
``` | ||
export OAI_CONFIG_LIST=your-autogen-config-list | ||
export DISCORD_TOKEN=your-bot-token | ||
export GH_TOKEN=your-gh-token | ||
export ANNY_GH_REPO=microsoft/autogen # you may choose a different repo name | ||
``` | ||
To get a Discord token, you will need to set up your Discord bot using these [instructions](https://discordpy.readthedocs.io/en/stable/discord.html). | ||
4. Start the bot: `python bot.py` | ||
Note: By default Anny will log data to `autoanny.log`. | ||
## Roadmap | ||
- Enable access control | ||
- Enable a richer set of commands | ||
- Enrich agents with tool use | ||
## Contributing | ||
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. |
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,36 @@ | ||
from autogen import AssistantAgent, UserProxyAgent, config_list_from_json | ||
|
||
|
||
async def solve_task(task): | ||
config_list = config_list_from_json(env_or_file="OAI_CONFIG_LIST") | ||
assistant = AssistantAgent("assistant", llm_config={"config_list": config_list}) | ||
user_proxy = UserProxyAgent( | ||
"user_proxy", | ||
code_execution_config={"work_dir": "coding", "use_docker": False}, | ||
human_input_mode="NEVER", | ||
is_termination_msg=lambda msg: "TERMINATE" in msg.get("content", ""), | ||
) | ||
await user_proxy.a_initiate_chat(assistant, message=task) | ||
|
||
await user_proxy.a_send( | ||
f"""Based on the results in above conversation, create a response for the user. | ||
While computing the response, remember that this conversation was your inner mono-logue. | ||
The user does not need to know every detail of the conversation. | ||
All they want to see is the appropriate result for their task (repeated below) in | ||
a manner that would be most useful. Response should be less than 1500 characters. | ||
The task was: {task} | ||
There is no need to use the word TERMINATE in this response. | ||
""", | ||
assistant, | ||
request_reply=False, | ||
silent=True, | ||
) | ||
response = await assistant.a_generate_reply(assistant.chat_messages[user_proxy], user_proxy) | ||
await assistant.a_send(response, user_proxy, request_reply=False, silent=True) | ||
|
||
last_message = assistant.chat_messages[user_proxy][-1]["content"] | ||
|
||
return last_message[:2000] |
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,153 @@ | ||
import os | ||
import logging | ||
import logging.handlers | ||
|
||
import discord | ||
from discord.ext import commands | ||
|
||
from agent_utils import solve_task | ||
|
||
logger = logging.getLogger("anny") | ||
logger.setLevel(logging.INFO) | ||
logging.getLogger("discord.http").setLevel(logging.INFO) | ||
|
||
handler = logging.handlers.RotatingFileHandler( | ||
filename="autoanny.log", | ||
encoding="utf-8", | ||
maxBytes=32 * 1024 * 1024, # 32 MiB | ||
backupCount=5, # Rotate through 5 files | ||
) | ||
dt_fmt = "%Y-%m-%d %H:%M:%S" | ||
formatter = logging.Formatter("[{asctime}] [{levelname:<8}] {name}: {message}", dt_fmt, style="{") | ||
handler.setFormatter(formatter) | ||
logger.addHandler(handler) | ||
|
||
required_env_vars = ["OAI_CONFIG_LIST", "DISCORD_TOKEN", "GH_TOKEN", "ANNY_GH_REPO"] | ||
for var in required_env_vars: | ||
if var not in os.environ: | ||
raise ValueError(f"{var} environment variable is not set.") | ||
|
||
# read token from environment variable | ||
DISCORD_TOKEN = os.environ["DISCORD_TOKEN"] | ||
REPO = os.environ["ANNY_GH_REPO"] | ||
|
||
intents = discord.Intents.default() | ||
intents.message_content = True | ||
intents.reactions = True | ||
bot = commands.Bot(command_prefix="/", intents=intents) | ||
|
||
|
||
@bot.event | ||
async def on_message(message): | ||
logger.info({"message": message.content, "author": message.author, "id": message.id}) | ||
await bot.process_commands(message) | ||
|
||
|
||
@bot.event | ||
async def on_reaction_add(reaction, user): | ||
message = reaction.message | ||
logger.info( | ||
{ | ||
"message": message.content, | ||
"author": message.author, | ||
"id": message.id, | ||
"reaction": reaction.emoji, | ||
"reactor": user, | ||
} | ||
) | ||
|
||
|
||
@bot.event | ||
async def on_ready(): | ||
logger.info("Logged in", extra={"user": bot.user}) | ||
|
||
|
||
@bot.command(description="Invoke Anny to solve a task.") | ||
async def heyanny(ctx, task: str = None): | ||
if not task or task == "help": | ||
response = help_msg() | ||
await ctx.send(response) | ||
return | ||
|
||
task_map = { | ||
"ghstatus": ghstatus, | ||
"ghgrowth": ghgrowth, | ||
"ghunattended": ghunattended, | ||
"ghstudio": ghstudio, | ||
} | ||
|
||
if task in task_map: | ||
await ctx.send("Working on it...") | ||
response = await task_map[task](ctx) | ||
await ctx.send(response) | ||
else: | ||
response = "Invalid command! Please type /heyanny help for the list of commands." | ||
await ctx.send(response) | ||
|
||
|
||
def help_msg(): | ||
response = f""" | ||
Hi this is Anny an AutoGen-powered Discord bot to help with `{REPO}`. I can help you with the following tasks: | ||
- ghstatus: Find the most recent issues and PRs from today. | ||
- ghgrowth: Find the number of stars, forks, and indicators of growth. | ||
- ghunattended: Find the most issues and PRs from today from today that haven't received a response/comment. | ||
You can invoke me by typing `/heyanny <task>`. | ||
""" | ||
return response | ||
|
||
|
||
async def ghstatus(ctx): | ||
response = await solve_task( | ||
f""" | ||
Find the most recent issues and PRs from `{REPO}` in last 24 hours. | ||
Separate issues and PRs. | ||
Final response should contains title, number, date/time, URLs of the issues and PRs. | ||
Markdown formatted response will make it look nice. | ||
Make sure date/time is in PST and readily readable. | ||
You can access github token from the environment variable called GH_TOKEN. | ||
""" | ||
) | ||
return response | ||
|
||
|
||
async def ghgrowth(ctx): | ||
response = await solve_task( | ||
f""" | ||
Find the number of stars, forks, and indicators of growth of `{REPO}`. | ||
Compare the stars of `{REPO}` this week vs last week. | ||
Make sure date/time is in PST and readily readable. | ||
You can access github token from the environment variable called GH_TOKEN. | ||
""" | ||
) | ||
return response | ||
|
||
|
||
async def ghunattended(ctx): | ||
response = await solve_task( | ||
f""" | ||
Find the issues *created* in the last 24 hours from `{REPO}` that haven't | ||
received a response/comment. Modified issues don't count. | ||
Final response should contains title, number, date/time, URLs of the issues and PRs. | ||
Make sure date/time is in PST and readily readable. | ||
You can access github token from the environment variable called GH_TOKEN. | ||
""" | ||
) | ||
return response | ||
|
||
|
||
async def ghstudio(ctx): | ||
# TODO: Generalize to feature name | ||
response = await solve_task( | ||
f""" | ||
Find issues and PRs from `{REPO}` that are related to the AutoGen Studio. | ||
The title or the body of the issue or PR should give you a hint whether its related. | ||
Summarize the top 5 common complaints or issues. Cite the issue/PR number and URL. | ||
Explain why you think this is a common issue in 2 sentences. | ||
You can access github token from the environment variable called GH_TOKEN. | ||
""" | ||
) | ||
return response | ||
|
||
|
||
bot.run(DISCORD_TOKEN, log_handler=None) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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,2 @@ | ||
discord.py | ||
pyautogen |
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.