Skip to content

Commit eb29490

Browse files
authored
Merge pull request #3 from agno-agi/v1.4.6
V1.4.6
2 parents a34acd7 + 0d12644 commit eb29490

14 files changed

+239
-86
lines changed

README.md

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## Agent Api
1+
## Agent API
22

33
This repo contains the code for a production-grade agentic system built with:
44

@@ -42,13 +42,7 @@ Required: Set the `OPENAI_API_KEY` environment variable using
4242
export OPENAI_API_KEY=***
4343
```
4444

45-
> you may use any model provider, just need to update the agents in the /agents folder
46-
47-
Optional: Set the `EXA_API_KEY` if you'd like to use Exa search
48-
49-
```sh
50-
export EXA_API_KEY=***
51-
```
45+
> You may use any supported model provider, just need to update the respective Agent, Team or Workflow.
5246
5347
3. Start the workspace:
5448

agents/sage.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
from agno.tools.duckduckgo import DuckDuckGoTools
88
from agno.vectordb.pgvector import PgVector, SearchType
99

10+
from agents.settings import agent_settings
1011
from db.session import db_url
1112

1213

1314
def get_sage(
14-
model_id: str = "gpt-4o",
15+
model_id: Optional[str] = None,
1516
user_id: Optional[str] = None,
1617
session_id: Optional[str] = None,
1718
debug_mode: bool = True,
@@ -22,12 +23,18 @@ def get_sage(
2223
additional_context += f"You are interacting with the user: {user_id}"
2324
additional_context += "</context>"
2425

26+
model_id = model_id or agent_settings.gpt_4
27+
2528
return Agent(
2629
name="Sage",
2730
agent_id="sage",
2831
user_id=user_id,
2932
session_id=session_id,
30-
model=OpenAIChat(id=model_id),
33+
model=OpenAIChat(
34+
id=model_id,
35+
max_tokens=agent_settings.default_max_completion_tokens,
36+
temperature=agent_settings.default_temperature,
37+
),
3138
# Tools available to the agent
3239
tools=[DuckDuckGoTools()],
3340
# Storage for the agent

agents/scholar.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@
66
from agno.storage.agent.postgres import PostgresAgentStorage
77
from agno.tools.duckduckgo import DuckDuckGoTools
88

9+
from agents.settings import agent_settings
910
from db.session import db_url
1011

1112

1213
def get_scholar(
13-
model_id: str = "gpt-4o",
14+
model_id: Optional[str] = None,
1415
user_id: Optional[str] = None,
1516
session_id: Optional[str] = None,
1617
debug_mode: bool = True,
1718
) -> Agent:
19+
model_id = model_id or agent_settings.gpt_4
20+
1821
additional_context = ""
1922
if user_id:
2023
additional_context += "<context>"
@@ -26,7 +29,11 @@ def get_scholar(
2629
agent_id="scholar",
2730
user_id=user_id,
2831
session_id=session_id,
29-
model=OpenAIChat(id=model_id),
32+
model=OpenAIChat(
33+
id=model_id,
34+
max_tokens=agent_settings.default_max_completion_tokens,
35+
temperature=agent_settings.default_temperature,
36+
),
3037
# Tools available to the agent
3138
tools=[DuckDuckGoTools()],
3239
# Storage for the agent

agents/settings.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from pydantic_settings import BaseSettings
2+
3+
4+
class AgentSettings(BaseSettings):
5+
"""Agent settings that can be set using environment variables.
6+
7+
Reference: https://pydantic-docs.helpmanual.io/usage/settings/
8+
"""
9+
10+
gpt_4_mini: str = "gpt-4o-mini"
11+
gpt_4: str = "gpt-4o"
12+
embedding_model: str = "text-embedding-3-small"
13+
default_max_completion_tokens: int = 16000
14+
default_temperature: float = 0
15+
16+
17+
# Create an TeamSettings object
18+
agent_settings = AgentSettings()

api/routes/playground.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
from agents.sage import get_sage
66
from agents.scholar import get_scholar
7-
from teams.finance_researcher_team import get_finance_researcher_team
8-
from teams.multi_language_team import get_multi_language_team
7+
from teams.finance_researcher import get_finance_researcher_team
8+
from teams.multi_language import get_multi_language_team
99
from workflows.blog_post_generator import get_blog_post_generator
1010
from workflows.investment_report_generator import get_investment_report_generator
1111
from workspace.dev_resources import dev_fastapi

api/routes/teams.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
from enum import Enum
2+
from typing import AsyncGenerator, List, Optional
3+
4+
from agno.team import Team
5+
from fastapi import APIRouter, HTTPException, status
6+
from fastapi.responses import StreamingResponse
7+
from pydantic import BaseModel
8+
9+
from teams.operator import TeamType, get_available_teams, get_team
10+
from utils.log import logger
11+
12+
######################################################
13+
## Router for the Agent Interface
14+
######################################################
15+
16+
teams_router = APIRouter(prefix="/teams", tags=["Teams"])
17+
18+
19+
class Model(str, Enum):
20+
gpt_4o = "gpt-4o"
21+
o3_mini = "o3-mini"
22+
23+
24+
@teams_router.get("", response_model=List[str])
25+
async def list_teams():
26+
"""
27+
Returns a list of all available team IDs.
28+
29+
Returns:
30+
List[str]: List of team identifiers
31+
"""
32+
return get_available_teams()
33+
34+
35+
async def chat_response_streamer(team: Team, message: str) -> AsyncGenerator:
36+
"""
37+
Stream team responses chunk by chunk.
38+
39+
Args:
40+
team: The team instance to interact with
41+
message: User message to process
42+
43+
Yields:
44+
Text chunks from the team response
45+
"""
46+
run_response = await team.arun(message, stream=True)
47+
async for chunk in run_response:
48+
# chunk.content only contains the text response from the Agent.
49+
# For advanced use cases, we should yield the entire chunk
50+
# that contains the tool calls and intermediate steps.
51+
yield chunk.content
52+
53+
54+
class RunRequest(BaseModel):
55+
"""Request model for an running an team"""
56+
57+
message: str
58+
stream: bool = True
59+
model: Model = Model.gpt_4o
60+
user_id: Optional[str] = None
61+
session_id: Optional[str] = None
62+
63+
64+
@teams_router.post("/{team_id}/runs", status_code=status.HTTP_200_OK)
65+
async def run_team(team_id: TeamType, body: RunRequest):
66+
"""
67+
Sends a message to a specific team and returns the response.
68+
69+
Args:
70+
team_id: The ID of the team to interact with
71+
body: Request parameters including the message
72+
73+
Returns:
74+
Either a streaming response or the complete team response
75+
"""
76+
logger.debug(f"RunRequest: {body}")
77+
78+
try:
79+
team: Team = get_team(
80+
model_id=body.model.value,
81+
team_id=team_id,
82+
user_id=body.user_id,
83+
session_id=body.session_id,
84+
)
85+
except Exception as e:
86+
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Team not found: {str(e)}")
87+
88+
if body.stream:
89+
return StreamingResponse(
90+
chat_response_streamer(team, body.message),
91+
media_type="text/event-stream",
92+
)
93+
else:
94+
response = await team.arun(body.message, stream=False)
95+
# response.content only contains the text response from the Agent.
96+
# For advanced use cases, we should yield the entire response
97+
# that contains the tool calls and intermediate steps.
98+
return response.content

api/routes/v1_router.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
from api.routes.agents import agents_router
44
from api.routes.playground import playground_router
55
from api.routes.status import status_router
6+
from api.routes.teams import teams_router
67

78
v1_router = APIRouter(prefix="/v1")
89
v1_router.include_router(status_router)
910
v1_router.include_router(agents_router)
11+
v1_router.include_router(teams_router)
1012
v1_router.include_router(playground_router)

pyproject.toml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@ readme = "README.md"
66
authors = [{ name = "Agno", email = "hello@agno.com" }]
77

88
dependencies = [
9-
"agno[aws]==1.3.5",
9+
"agno[aws]==1.4.6",
1010
"aiofiles",
1111
"alembic",
1212
"beautifulsoup4",
1313
"duckduckgo-search",
14-
"exa_py",
1514
"fastapi[standard]",
1615
"googlesearch-python",
1716
"lxml_html_clean",
@@ -20,10 +19,7 @@ dependencies = [
2019
"pgvector",
2120
"psycopg[binary]",
2221
"pycountry",
23-
"pypdf",
2422
"sqlalchemy",
25-
"streamlit",
26-
"tiktoken",
2723
"typer",
2824
"yfinance",
2925
]

requirements.txt

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
11
# This file was autogenerated by uv via the following command:
22
# ./scripts/generate_requirements.sh
3-
agno==1.3.5
3+
agno==1.4.6
44
agno-aws==0.0.1
55
agno-docker==0.0.1
66
aiofiles==24.1.0
77
alembic==1.15.1
8-
altair==5.5.0
98
annotated-types==0.7.0
109
anyio==4.9.0
11-
attrs==25.3.0
1210
beautifulsoup4==4.13.3
13-
blinker==1.9.0
1411
boto3==1.37.19
1512
botocore==1.37.19
16-
cachetools==5.5.2
1713
certifi==2025.1.31
1814
charset-normalizer==3.4.1
1915
click==8.1.8
@@ -23,7 +19,6 @@ docker==7.1.0
2319
docstring-parser==0.16
2420
duckduckgo-search==7.5.3
2521
email-validator==2.2.0
26-
exa-py==1.9.1
2722
fastapi==0.115.12
2823
fastapi-cli==0.0.7
2924
feedparser==6.0.11
@@ -37,58 +32,44 @@ httpcore==1.0.7
3732
httptools==0.6.4
3833
httpx==0.28.1
3934
idna==3.10
40-
iniconfig==2.1.0
4135
jinja2==3.1.6
4236
jiter==0.9.0
4337
jmespath==1.0.1
4438
joblib==1.4.2
45-
jsonschema==4.23.0
46-
jsonschema-specifications==2024.10.1
4739
lxml==5.3.1
4840
lxml-html-clean==0.4.2
4941
mako==1.3.9
5042
markdown-it-py==3.0.0
5143
markupsafe==3.0.2
5244
mdurl==0.1.2
5345
multitasking==0.0.11
54-
narwhals==1.32.0
5546
newspaper4k==0.9.3.1
5647
nltk==3.9.1
5748
numpy==2.2.4
5849
openai==1.68.2
59-
packaging==24.2
6050
pandas==2.2.3
6151
peewee==3.17.9
6252
pgvector==0.4.0
6353
pillow==11.1.0
6454
platformdirs==4.3.7
65-
pluggy==1.5.0
6655
primp==0.14.0
67-
protobuf==5.29.4
6856
psycopg==3.2.6
6957
psycopg-binary==3.2.6
70-
pyarrow==19.0.1
7158
pycountry==24.6.1
7259
pydantic==2.10.6
7360
pydantic-core==2.27.2
7461
pydantic-settings==2.8.1
75-
pydeck==0.9.1
7662
pygments==2.19.1
77-
pypdf==5.4.0
78-
pytest==8.3.5
79-
pytest-mock==3.14.0
8063
python-dateutil==2.9.0.post0
8164
python-dotenv==1.1.0
8265
python-multipart==0.0.20
8366
pytz==2025.2
8467
pyyaml==6.0.2
85-
referencing==0.36.2
8668
regex==2024.11.6
8769
requests==2.32.3
8870
requests-file==2.1.0
8971
rich==13.9.4
9072
rich-toolkit==0.13.2
91-
rpds-py==0.23.1
9273
s3transfer==0.11.4
9374
sgmllib3k==1.0.0
9475
shellingham==1.5.4
@@ -98,13 +79,8 @@ sniffio==1.3.1
9879
soupsieve==2.6
9980
sqlalchemy==2.0.39
10081
starlette==0.46.1
101-
streamlit==1.43.2
102-
tenacity==9.0.0
103-
tiktoken==0.9.0
10482
tldextract==5.2.0
105-
toml==0.10.2
10683
tomli==2.2.1
107-
tornado==6.4.2
10884
tqdm==4.67.1
10985
typer==0.15.2
11086
typing-extensions==4.12.2

0 commit comments

Comments
 (0)