Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4 PRs #826

Merged
merged 4 commits into from
Jul 11, 2024
Merged

4 PRs #826

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
pytest-marks: ["not openai", "openai and (not brief_creation_team and not campaign_creation_team and not weekly_analysis_team and not get_info_from_the_web_page)", "brief_creation_team and openai", "campaign_creation_team and openai", "weekly_analysis_team", "get_info_from_the_web_page"]
pytest-marks: ["not openai", "openai and (not brief_creation_team and not campaign_creation_team and not weekly_analysis_team and not get_info_from_the_web_page and not fastapi_openapi_team)", "brief_creation_team and openai", "campaign_creation_team and openai", "weekly_analysis_team", "get_info_from_the_web_page", "fastapi_openapi_team"]
fail-fast: false
services:
postgres:
Expand All @@ -59,6 +59,7 @@ jobs:
AZURE_GPT35_MODEL: ${{ secrets.STAGING_AZURE_GPT35_MODEL }}
AZURE_OPENAI_API_KEY: ${{ secrets.STAGING_AZURE_OPENAI_API_KEY }}
AZURE_OPENAI_API_KEY_GPT4O: ${{ secrets.STAGING_AZURE_OPENAI_API_KEY_GPT4O }}
GOOGLE_SHEETS_OPENAPI_URL: ${{ vars.STAGING_GOOGLE_SHEETS_OPENAPI_URL }}
steps:
- uses: actions/checkout@v4
- name: Set up Python
Expand Down Expand Up @@ -155,6 +156,7 @@ jobs:
INFOBIP_API_KEY: ${{ github.ref_name == 'main' && secrets.PROD_INFOBIP_API_KEY || secrets.STAGING_INFOBIP_API_KEY }}
INFOBIP_BASE_URL: ${{ github.ref_name == 'main' && secrets.PROD_INFOBIP_BASE_URL || secrets.STAGING_INFOBIP_BASE_URL }}
SSH_KEY: ${{ github.ref_name == 'main' && secrets.PROD_SSH_KEY || secrets.STAGING_SSH_KEY }}
GOOGLE_SHEETS_OPENAPI_URL: ${{ github.ref_name == 'main' && vars.PROD_GOOGLE_SHEETS_OPENAPI_URL || vars.STAGING_GOOGLE_SHEETS_OPENAPI_URL }}
steps:
- uses: actions/checkout@v3 # Don't change it to cheackout@v4. V4 is not working with container image.
# This is to fix GIT not liking owner of the checkout dir - https://github.com/actions/runner/issues/2033#issuecomment-1204205989
Expand Down
4 changes: 4 additions & 0 deletions captn/captn_agents/backend/teams/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from ._brief_creation_team import BriefCreationTeam
from ._campaign_creation_team import CampaignCreationTeam
from ._gbb_google_sheets_team import GBBGoogleSheetsTeam
from ._gbb_initial_team import GBBInitialTeam
from ._google_ads_team import GoogleAdsTeam
from ._team import Team
from ._weather_team import WeatherTeam
from ._weekly_analysis_team import (
REACT_APP_API_URL,
WeeklyAnalysisTeam,
Expand All @@ -12,8 +14,10 @@
__all__ = (
"BriefCreationTeam",
"CampaignCreationTeam",
"GBBGoogleSheetsTeam",
"GBBInitialTeam",
"WeeklyAnalysisTeam",
"WeatherTeam",
"GoogleAdsTeam",
"REACT_APP_API_URL",
"Team",
Expand Down
137 changes: 137 additions & 0 deletions captn/captn_agents/backend/teams/_gbb_google_sheets_team.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
from os import environ
from typing import Any, Callable, Dict, List, Optional

from ....google_ads.client import get_conv_uuid
from ..toolboxes import Toolbox

# Currently only reply_to_client command within this toolbox
from ..tools._weather_team_tools import (
create_weather_team_toolbox,
)
from ._shared_prompts import REPLY_TO_CLIENT_COMMAND
from ._team import Team
from ._team_with_client import TeamWithClient

GOOGLE_SHEETS_OPENAPI_URL = environ.get(
"GOOGLE_SHEETS_OPENAPI_URL", "http://localhost:8000/openapi.json"
)


@Team.register_team("gbb_google_sheets_team")
class GBBGoogleSheetsTeam(TeamWithClient):
_default_roles = [
{
"Name": "Google_sheets_expert",
"Description": """Google Sheets expert.
Never introduce yourself when writing messages. E.g. do not write 'As a ...'""",
"use_client": True,
"use_toolbox": False,
},
{
"Name": "Account_manager",
"Description": """You are an account manager.
You are also SOLELY responsible for communicating with the client.

Based on the initial task, a number of proposed solutions will be suggested by the team. You must ask the team to write a detailed plan
including steps and expected outcomes.
Once the initial task given to the team is completed by implementing proposed solutions, you must write down the
accomplished work and execute the 'reply_to_client' command. That message will be forwarded to the client so make
sure it is understandable by non-experts.
Never introduce yourself when writing messages. E.g. do not write 'As an account manager'
""",
"use_client": False,
"use_toolbox": True,
},
]

_functions: Optional[List[Dict[str, Any]]] = []

def __init__(
self,
*,
task: str,
user_id: int,
conv_id: int,
work_dir: str = "gbb_google_sheets_team",
max_round: int = 80,
seed: int = 42,
temperature: float = 0.2,
config_list: Optional[List[Dict[str, str]]] = None,
create_toolbox_func: Callable[
[int, int], Toolbox
] = create_weather_team_toolbox,
openapi_url: str = GOOGLE_SHEETS_OPENAPI_URL,
):
roles: List[Dict[str, Any]] = self._default_roles
conv_uuid = get_conv_uuid(conv_id=conv_id)

kwargs_to_patch = {
"user_id": user_id,
"conv_uuid": conv_uuid,
}

super().__init__(
task=task,
user_id=user_id,
conv_id=conv_id,
roles=roles,
create_toolbox_func=create_toolbox_func,
openapi_url=openapi_url,
kwargs_to_patch=kwargs_to_patch,
work_dir=work_dir,
max_round=max_round,
seed=seed,
temperature=temperature,
config_list=config_list,
)

@property
def _task(self) -> str:
return f"""You are a team in charge editing Google Sheets.

Here is the current customers brief/information we have gathered for you as a starting point:
{self.task}
"""

@property
def _guidelines(self) -> str:
return """### Guidelines
1. Do NOT repeat the content of the previous messages nor repeat your role.
2. When sending requests to the Google Sheets API, use user_id=-1, someone else will handle the authentication.
3.1. Your task is to 'get_all_file_names_get_all_file_names_get' endpoint from the Google Sheets API.
3.2. If you receive "User hasn't grant access yet!" from the Google Sheets API, use the Google Sheets API 'get_login_url_login_get' endpoint to authenticate
- Use user_id=-1 and conv_uuid="abc" (The correct values will be injected by the system).
- If you receive a login url, forward it to the client by using the 'reply_to_client' function.
- Do NOT use smart suggestions when forwarding the login url to the client!
4. Once you have the file names, you must determine the id of the Google spreadsheet template and the id of the spreadsheet with new routes.
Use reply_to_client command to check if you found the correct files by providing the file names. Do NOT mention all the files, only the ones that are relevant.
5. In the template spreadsheet, ou must find sheet titles of the ad template and keyword template (by using 'get_all_sheet_titles_get_all_sheet_titles_get').
6. In the spreadsheet with new routes, you must find the title of the sheet with new routes (by using 'get_all_sheet_titles_get_all_sheet_titles_get').
7. Once you have all the necessary information, use process_spreadsheet endpoint to process the spreadsheet (by using 'process_spreadsheet_process_spreadsheet_post').
- you must do this step twice, once for the ad template and once for the keyword template.
- query parameters: user_id, template_spreadsheet_id, template_sheet_title, new_campaign_spreadsheet_id, new_campaign_sheet_title, target_resource ('ad' or 'keyword')
8. Once the endpoint is successful write the message to the client that the new sheet has been created in the same spreadsheet as the new routes sheet.

ALL ENDPOINT PARAMETERS ARE MANDATORY (even if the documentation says they are optional).
"""

@property
def _commands(self) -> str:
return f"""## Commands
Only News_reporter has access to the following command:
1. {REPLY_TO_CLIENT_COMMAND}
"smart_suggestions": {{
'suggestions': ['Use Sheet with title "New"'],
'type': 'oneOf'
}}

2. Only Google_sheets_expert has access to Google Sheets API and can read and edit Google Sheets.
"""

@classmethod
def get_capabilities(cls) -> str:
return "Able to read and edit Google Sheets."

@classmethod
def get_brief_template(cls) -> str:
return "We need id of Google spreadsheet template and id of the spreadsheet with new routes."
4 changes: 3 additions & 1 deletion captn/captn_agents/backend/teams/_gbb_initial_team.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from ._shared_prompts import REPLY_TO_CLIENT_COMMAND
from ._team import Team

__all__ = ("GBBInitialTeam",)


@Team.register_team("gbb_initial_team")
class GBBInitialTeam(BriefCreationTeam):
Expand Down Expand Up @@ -65,7 +67,7 @@ def _guidelines(self) -> str:
If you fail to choose the appropriate team, you will be penalized!

3. Here is a list of teams you can choose from after you determine which one is the most appropriate for the task:
{self.construct_team_names_and_descriptions_message(use_only_team_names={"campaign_creation_team"})}
{self.construct_team_names_and_descriptions_message(use_only_team_names={"gbb_google_sheets_team"})}

Guidelines SUMMARY:
- Write a detailed step-by-step plan
Expand Down
97 changes: 97 additions & 0 deletions captn/captn_agents/backend/teams/_team_with_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
from typing import Any, Callable, Dict, List, Optional, Tuple

from ..config import Config
from ..toolboxes import Toolbox
from ..tools._team_with_client_tools import create_client
from ..tools.patch_client import get_patch_register_for_execution
from ._team import Team

__all__ = ("TeamWithClient",)


class TeamWithClient(Team):
_functions: Optional[List[Dict[str, Any]]] = []

def __init__(
self,
*,
task: str,
user_id: int,
conv_id: int,
roles: List[Dict[str, str]],
create_toolbox_func: Callable[[int, int], Toolbox],
openapi_url: str,
kwargs_to_patch: Optional[Dict[str, Any]] = None,
work_dir: str = "team_with_client",
max_round: int = 80,
seed: int = 42,
temperature: float = 0.2,
config_list: Optional[List[Dict[str, str]]] = None,
):
recommended_modifications_and_answer_list: List[
Tuple[Dict[str, Any], Optional[str]]
] = []
function_map: Dict[str, Callable[[Any], Any]] = {}

super().__init__(
user_id=user_id,
conv_id=conv_id,
roles=roles,
task=task,
function_map=function_map,
work_dir=work_dir,
max_round=max_round,
seed=seed,
temperature=temperature,
recommended_modifications_and_answer_list=recommended_modifications_and_answer_list,
use_user_proxy=True,
)

if config_list is None:
config = Config()
config_list = config.config_list_gpt_4o

self.llm_config = self._get_llm_config(
seed=seed, temperature=temperature, config_list=config_list
)
self.create_toolbox_func = create_toolbox_func
self.openapi_url = openapi_url
self.kwargs_to_patch = kwargs_to_patch

self._create_members()

self.roles_with_client = []
self.roles_with_toolbox = []
for role in self.roles:
name = role["Name"].lower()
if role["use_client"]:
self.roles_with_client.append(name)
if role["use_toolbox"]:
self.roles_with_toolbox.append(name)

self._add_client()
self._add_tools()

self._create_initial_message()

def _add_client(self) -> None:
self.client = create_client(self.openapi_url)
if self.kwargs_to_patch:
get_patch_register_for_execution(self.client, self.kwargs_to_patch)()

for agent in self.members:
if agent.name in self.roles_with_client:
if agent.llm_config["tools"] is None:
agent.llm_config.pop("tools")
self.client.register_for_llm(agent)

self.client.register_for_execution(self.user_proxy)

def _add_tools(self) -> None:
self.toolbox = self.create_toolbox_func(
self.user_id,
self.conv_id,
)
for agent in self.members:
if agent != self.user_proxy and agent.name in self.roles_with_toolbox:
self.toolbox.add_to_agent(agent, self.user_proxy)
Loading
Loading