Skip to content

Commit

Permalink
Merge branct push
Browse files Browse the repository at this point in the history
h 'main' of https://github.com/agno-agi/agno into release-1.1.5
  • Loading branch information
dirkbrnd committed Feb 24, 2025
2 parents c6e462c + 6ac44df commit 0b28a7e
Show file tree
Hide file tree
Showing 14 changed files with 648 additions and 18 deletions.
30 changes: 30 additions & 0 deletions cookbook/agent_concepts/knowledge/vector_dbs/upstash_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# install upstash-vector - `uv pip install upstash-vector`
# Add OPENAI_API_KEY to your environment variables for the agent response

from agno.agent import Agent
from agno.knowledge.pdf_url import PDFUrlKnowledgeBase
from agno.vectordb.upstashdb.upstashdb import UpstashVectorDb

# How to connect to an Upstash Vector index
# - Create a new index in Upstash Console with the correct dimension
# - Fetch the URL and token from Upstash Console
# - Replace the values below or use environment variables

# Initialize Upstash DB
vector_db = UpstashVectorDb(
url="UPSTASH_VECTOR_REST_URL",
token="UPSTASH_VECTOR_REST_TOKEN",
)

# Create a new PDFUrlKnowledgeBase
knowledge_base = PDFUrlKnowledgeBase(
urls=["https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf"],
vector_db=vector_db,
)

# Load the knowledge base - after first run, comment out
knowledge_base.load(recreate=False, upsert=True)

# Create and use the agent
agent = Agent(knowledge=knowledge_base, show_tool_calls=True)
agent.print_response("What are some tips for cooking glass noodles?", markdown=True)
31 changes: 31 additions & 0 deletions cookbook/tools/webex_tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
Run `pip install openai webexpythonsdk` to install dependencies.
To get the Webex Teams Access token refer to - https://developer.webex.com/docs/bots
Steps:
1. Sign up for Webex Teams and go to the Webex [Developer Portal](https://developer.webex.com/)
2. Create the Bot
2.1 Click in the top-right on your profile → My Webex Apps → Create a Bot.
2.2 Enter Bot Name, Username, Icon, and Description, then click Add Bot.
3. Get the Access Token
3.1 Copy the Access Token shown on the confirmation page (displayed once).
3.2 If lost, regenerate it via My Webex Apps → Edit Bot → Regenerate Access Token.
4. Set the WEBEX_ACCESS_TOKEN environment variable
5. Launch Webex itself and add your bot to a space like the Welcome space. Use the bot's email address (e.g. [email protected])
"""

import os

from agno.agent import Agent
from agno.tools.webex import WebexTools

agent = Agent(tools=[WebexTools()], show_tool_calls=True)

# List all space in Webex
agent.print_response("List all space on our Webex", markdown=True)

# Send a message to a Space in Webex
agent.print_response(
"Send a funny ice-breaking message to the webex Welcome space", markdown=True
)
2 changes: 1 addition & 1 deletion libs/agno/agno/agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -2284,7 +2284,7 @@ def deep_copy(self, *, update: Optional[Dict[str, Any]] = None) -> Agent:
from dataclasses import fields

# Do not copy agent_session and session_name to the new agent
excluded_fields = ["agent_session", "session_name", "memory"]
excluded_fields = ["agent_session", "session_name"]
# Extract the fields to set for the new Agent
fields_for_new_agent: Dict[str, Any] = {}

Expand Down
1 change: 1 addition & 0 deletions libs/agno/agno/document/reader/website_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ def crawl(self, url: str, starting_depth: int = 1) -> Dict[str, str]:
try:
logger.debug(f"Crawling: {current_url}")
response = httpx.get(current_url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.content, "html.parser")

# Extract main content
Expand Down
4 changes: 4 additions & 0 deletions libs/agno/agno/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ class AgnoError(Exception):

def __init__(self, message: str, status_code: int = 500):
super().__init__(message)
self.message = message
self.status_code = status_code

def __str__(self) -> str:
return str(self.message)


class ModelProviderError(AgnoError):
"""Exception raised when a model provider returns an error."""
Expand Down
16 changes: 8 additions & 8 deletions libs/agno/agno/models/openai/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,15 +297,15 @@ def invoke(self, messages: List[Message]) -> Union[ChatCompletion, ParsedChatCom
except RateLimitError as e:
logger.error(f"Rate limit error from OpenAI API: {e}")
raise ModelProviderError(
message=e.response.text, status_code=e.response.status_code, model_name=self.name, model_id=self.id
message=e.response.json().get("error", {}).get("message", "Unknown model error"), status_code=e.response.status_code, model_name=self.name, model_id=self.id
) from e
except APIConnectionError as e:
logger.error(f"API connection error from OpenAI API: {e}")
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
except APIStatusError as e:
logger.error(f"API status error from OpenAI API: {e}")
raise ModelProviderError(
message=e.response.text, status_code=e.response.status_code, model_name=self.name, model_id=self.id
message=e.response.json().get("error", {}).get("message", "Unknown model error"), status_code=e.response.status_code, model_name=self.name, model_id=self.id
) from e
except Exception as e:
logger.error(f"Error from OpenAI API: {e}")
Expand Down Expand Up @@ -339,15 +339,15 @@ async def ainvoke(self, messages: List[Message]) -> Union[ChatCompletion, Parsed
except RateLimitError as e:
logger.error(f"Rate limit error from OpenAI API: {e}")
raise ModelProviderError(
message=e.response.text, status_code=e.response.status_code, model_name=self.name, model_id=self.id
message=e.response.json().get("error", {}).get("message", "Unknown model error"), status_code=e.response.status_code, model_name=self.name, model_id=self.id
) from e
except APIConnectionError as e:
logger.error(f"API connection error from OpenAI API: {e}")
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
except APIStatusError as e:
logger.error(f"API status error from OpenAI API: {e}")
raise ModelProviderError(
message=e.response.text, status_code=e.response.status_code, model_name=self.name, model_id=self.id
message=e.response.json().get("error", {}).get("message", "Unknown model error"), status_code=e.response.status_code, model_name=self.name, model_id=self.id
) from e
except Exception as e:
logger.error(f"Error from OpenAI API: {e}")
Expand All @@ -374,15 +374,15 @@ def invoke_stream(self, messages: List[Message]) -> Iterator[ChatCompletionChunk
except RateLimitError as e:
logger.error(f"Rate limit error from OpenAI API: {e}")
raise ModelProviderError(
message=e.response.text, status_code=e.response.status_code, model_name=self.name, model_id=self.id
message=e.response.json().get("error", {}).get("message", "Unknown model error"), status_code=e.response.status_code, model_name=self.name, model_id=self.id
) from e
except APIConnectionError as e:
logger.error(f"API connection error from OpenAI API: {e}")
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
except APIStatusError as e:
logger.error(f"API status error from OpenAI API: {e}")
raise ModelProviderError(
message=e.response.text, status_code=e.response.status_code, model_name=self.name, model_id=self.id
message=e.response.json().get("error", {}).get("message", "Unknown model error"), status_code=e.response.status_code, model_name=self.name, model_id=self.id
) from e
except Exception as e:
logger.error(f"Error from OpenAI API: {e}")
Expand Down Expand Up @@ -411,15 +411,15 @@ async def ainvoke_stream(self, messages: List[Message]) -> AsyncIterator[ChatCom
except RateLimitError as e:
logger.error(f"Rate limit error from OpenAI API: {e}")
raise ModelProviderError(
message=e.response.text, status_code=e.response.status_code, model_name=self.name, model_id=self.id
message=e.response.json().get("error", {}).get("message", "Unknown model error"), status_code=e.response.status_code, model_name=self.name, model_id=self.id
) from e
except APIConnectionError as e:
logger.error(f"API connection error from OpenAI API: {e}")
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
except APIStatusError as e:
logger.error(f"API status error from OpenAI API: {e}")
raise ModelProviderError(
message=e.response.text, status_code=e.response.status_code, model_name=self.name, model_id=self.id
message=e.response.json().get("error", {}).get("message", "Unknown model error"), status_code=e.response.status_code, model_name=self.name, model_id=self.id
) from e
except Exception as e:
logger.error(f"Error from OpenAI API: {e}")
Expand Down
4 changes: 2 additions & 2 deletions libs/agno/agno/playground/playground.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def get_app(self, use_async: bool = True, prefix: str = "/v1") -> FastAPI:
async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse:
return JSONResponse(
status_code=exc.status_code,
content={"message": str(exc.detail)},
content={"detail": str(exc.detail)},
)

async def general_exception_handler(request: Request, call_next):
Expand All @@ -65,7 +65,7 @@ async def general_exception_handler(request: Request, call_next):
except Exception as e:
return JSONResponse(
status_code=e.status_code if hasattr(e, "status_code") else 500,
content={"message": str(e)},
content={"detail": str(e)},
)

self.api_app.middleware("http")(general_exception_handler)
Expand Down
67 changes: 67 additions & 0 deletions libs/agno/agno/tools/webex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import json
import os
from typing import Optional

from agno.tools.toolkit import Toolkit
from agno.utils.log import logger

try:
from webexpythonsdk import WebexAPI
from webexpythonsdk.exceptions import ApiError
except ImportError:
logger.error("Webex tools require the `webexpythonsdk` package. Run `pip install webexpythonsdk` to install it.")


class WebexTools(Toolkit):
def __init__(self, send_message: bool = True, list_rooms: bool = True, access_token: Optional[str] = None):
super().__init__(name="webex")
if access_token is None:
access_token = os.getenv("WEBEX_ACCESS_TOKEN")
if access_token is None:
raise ValueError("Webex access token is not set. Please set the WEBEX_ACCESS_TOKEN environment variable.")

self.client = WebexAPI(access_token=access_token)
if send_message:
self.register(self.send_message)
if list_rooms:
self.register(self.list_rooms)

def send_message(self, room_id: str, text: str) -> str:
"""
Send a message to a Webex Room.
Args:
room_id (str): The Room ID to send the message to.
text (str): The text of the message to send.
Returns:
str: A JSON string containing the response from the Webex.
"""
try:
response = self.client.messages.create(roomId=room_id, text=text)
return json.dumps(response.json_data)
except ApiError as e:
logger.error(f"Error sending message: {e} in room: {room_id}")
return json.dumps({"error": str(e)})

def list_rooms(self) -> str:
"""
List all rooms in the Webex.
Returns:
str: A JSON string containing the list of rooms.
"""
try:
response = self.client.rooms.list()
rooms_list = [
{
"id": room.id,
"title": room.title,
"type": room.type,
"isPublic": room.isPublic,
"isReadOnly": room.isReadOnly,
}
for room in response
]

return json.dumps({"rooms": rooms_list}, indent=4)
except ApiError as e:
logger.error(f"Error listing rooms: {e}")
return json.dumps({"error": str(e)})
1 change: 1 addition & 0 deletions libs/agno/agno/vectordb/upstashdb/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from agno.vectordb.upstashdb.upstashdb import UpstashVectorDb
Loading

0 comments on commit 0b28a7e

Please sign in to comment.