Skip to content

Commit

Permalink
Add bedrock
Browse files Browse the repository at this point in the history
  • Loading branch information
dirkbrnd committed Feb 6, 2025
1 parent 421d224 commit 2012f68
Show file tree
Hide file tree
Showing 20 changed files with 589 additions and 765 deletions.
File renamed without changes.
File renamed without changes.
Empty file.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
from agno.agent import Agent
from agno.models.groq import Groq

assistant = Agent(
agent = Agent(
model=Groq(id="llama-3.3-70b-versatile"),
description="You help people with their health and fitness goals.",
instructions=["Recipes should be under 5 ingredients"],
)
# -*- Print a response to the cli
# -*- Print a response to the terminal
asyncio.run(
assistant.aprint_response("Share a breakfast recipe.", markdown=True, stream=True)
agent.aprint_response("Share a breakfast recipe.", markdown=True, stream=True)
)
28 changes: 28 additions & 0 deletions cookbook/models/groq/async_tool_use.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Please install dependencies using:
pip install openai duckduckgo-search newspaper4k lxml_html_clean agno
"""
import asyncio

from agno.agent import Agent
from agno.models.groq import Groq
from agno.tools.duckduckgo import DuckDuckGoTools
from agno.tools.newspaper4k import Newspaper4kTools

agent = Agent(
model=Groq(id="llama-3.3-70b-versatile"),
tools=[DuckDuckGoTools(), Newspaper4kTools()],
description="You are a senior NYT researcher writing an article on a topic.",
instructions=[
"For a given topic, search for the top 5 links.",
"Then read each URL and extract the article text, if a URL isn't available, ignore it.",
"Analyse and prepare an NYT worthy article based on the information.",
],
markdown=True,
show_tool_calls=True,
add_datetime_to_instructions=True,
)

# -*- Print a response to the cli
asyncio.run(
agent.aprint_response("Simulation theory", stream=True)
)
15 changes: 0 additions & 15 deletions cookbook/models/groq/web_search.py

This file was deleted.

4 changes: 2 additions & 2 deletions cookbook/models/ollama/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ python cookbook/models/ollama/basic.py
- DuckDuckGo Search

```shell
python cookbook/models/ollama/web_search.py
python cookbook/models/ollama/tool_use.py
```

### 6. Run Agent that returns structured output
Expand All @@ -63,7 +63,7 @@ python cookbook/models/ollama/storage.py
python cookbook/models/ollama/knowledge.py
```

### 9. Run Agent that uses memory
### 9. Run Agent that uses memory

```shell
python cookbook/models/ollama/memory.py
Expand Down
4 changes: 2 additions & 2 deletions libs/agno/agno/agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,7 @@ def run(
**kwargs,
)
return next(resp)
except AgentRunException as e:
except Exception as e:
logger.warning(f"Attempt {attempt + 1}/{num_attempts} failed: {str(e)}")
if isinstance(e, StopAgentRun):
raise e
Expand Down Expand Up @@ -1267,7 +1267,7 @@ async def arun(
**kwargs,
)
return await resp.__anext__()
except AgentRunException as e:
except Exception as e:
logger.warning(f"Attempt {attempt + 1}/{num_attempts} failed: {str(e)}")
if isinstance(e, StopAgentRun):
raise e
Expand Down
14 changes: 13 additions & 1 deletion libs/agno/agno/document/reader/csv_reader.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import csv
import io
import os
from time import sleep
from pathlib import Path
from typing import IO, Any, List, Union
from urllib.parse import urlparse
Expand Down Expand Up @@ -63,7 +64,18 @@ def read(self, url: str) -> List[Document]:
raise ImportError("`httpx` not installed")

logger.info(f"Reading: {url}")
response = httpx.get(url)
# Retry the request up to 3 times with exponential backoff
for attempt in range(3):
try:
response = httpx.get(url)
break
except httpx.RequestError as e:
if attempt == 2: # Last attempt
logger.error(f"Failed to fetch CSV after 3 attempts: {e}")
raise
wait_time = 2 ** attempt # Exponential backoff: 1, 2, 4 seconds
logger.warning(f"Request failed, retrying in {wait_time} seconds...")
sleep(wait_time)

try:
response.raise_for_status()
Expand Down
14 changes: 13 additions & 1 deletion libs/agno/agno/document/reader/pdf_reader.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from pathlib import Path
from time import sleep
from typing import IO, Any, List, Union

from agno.document.base import Document
Expand Down Expand Up @@ -59,7 +60,18 @@ def read(self, url: str) -> List[Document]:
raise ImportError("`httpx` not installed. Please install it via `pip install httpx`.")

logger.info(f"Reading: {url}")
response = httpx.get(url)
# Retry the request up to 3 times with exponential backoff
for attempt in range(3):
try:
response = httpx.get(url)
break
except httpx.RequestError as e:
if attempt == 2: # Last attempt
logger.error(f"Failed to fetch PDF after 3 attempts: {e}")
raise
wait_time = 2 ** attempt # Exponential backoff: 1, 2, 4 seconds
logger.warning(f"Request failed, retrying in {wait_time} seconds...")
sleep(wait_time)

try:
response.raise_for_status()
Expand Down
14 changes: 13 additions & 1 deletion libs/agno/agno/document/reader/url_reader.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import List
from urllib.parse import urlparse
from time import sleep

from agno.document.base import Document
from agno.document.reader.base import Reader
Expand All @@ -19,7 +20,18 @@ def read(self, url: str) -> List[Document]:
raise ImportError("`httpx` not installed. Please install it via `pip install httpx`.")

logger.info(f"Reading: {url}")
response = httpx.get(url)
# Retry the request up to 3 times with exponential backoff
for attempt in range(3):
try:
response = httpx.get(url)
break
except httpx.RequestError as e:
if attempt == 2: # Last attempt
logger.error(f"Failed to fetch PDF after 3 attempts: {e}")
raise
wait_time = 2 ** attempt # Exponential backoff: 1, 2, 4 seconds
logger.warning(f"Request failed, retrying in {wait_time} seconds...")
sleep(wait_time)

try:
logger.debug(f"Status: {response.status_code}")
Expand Down
123 changes: 93 additions & 30 deletions libs/agno/agno/models/anthropic/claude.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
try:
from anthropic import Anthropic as AnthropicClient
from anthropic import AsyncAnthropic as AsyncAnthropicClient
from anthropic import APIConnectionError, RateLimitError, APIStatusError

from anthropic.types import (
ContentBlockDeltaEvent,
MessageStopEvent,
Expand Down Expand Up @@ -290,15 +292,33 @@ def invoke(self, messages: List[Message]) -> AnthropicMessage:
Returns:
AnthropicMessage: The response from the model.
"""
chat_messages, system_message = _format_messages(messages)
request_kwargs = self._prepare_request_kwargs(system_message)
return self.get_client().messages.create(
model=self.id,
messages=chat_messages, # type: ignore
**request_kwargs,
)
Raises:
APIConnectionError: If there are network connectivity issues
RateLimitError: If the API rate limit is exceeded
APIStatusError: For other API-related errors
"""
try:
chat_messages, system_message = _format_messages(messages)
request_kwargs = self._prepare_request_kwargs(system_message)

return self.get_client().messages.create(
model=self.id,
messages=chat_messages, # type: ignore
**request_kwargs,
)
except APIConnectionError as e:
logger.error(f"Connection error while calling Claude API: {str(e)}")
raise
except RateLimitError as e:
logger.warning(f"Rate limit exceeded: {str(e)}")
raise
except APIStatusError as e:
logger.error(f"Claude API error (status {e.status_code}): {str(e)}")
raise
except Exception as e:
logger.error(f"Unexpected error calling Claude API: {str(e)}")
raise

def invoke_stream(self, messages: List[Message]) -> Any:
"""
Expand All @@ -313,11 +333,24 @@ def invoke_stream(self, messages: List[Message]) -> Any:
chat_messages, system_message = _format_messages(messages)
request_kwargs = self._prepare_request_kwargs(system_message)

return self.get_client().messages.stream(
model=self.id,
messages=chat_messages, # type: ignore
**request_kwargs,
).__enter__()
try:
return self.get_client().messages.stream(
model=self.id,
messages=chat_messages, # type: ignore
**request_kwargs,
).__enter__()
except APIConnectionError as e:
logger.error(f"Connection error while calling Claude API: {str(e)}")
raise
except RateLimitError as e:
logger.warning(f"Rate limit exceeded: {str(e)}")
raise
except APIStatusError as e:
logger.error(f"Claude API error (status {e.status_code}): {str(e)}")
raise
except Exception as e:
logger.error(f"Unexpected error calling Claude API: {str(e)}")
raise

async def ainvoke(self, messages: List[Message]) -> AnthropicMessage:
"""
Expand All @@ -328,15 +361,33 @@ async def ainvoke(self, messages: List[Message]) -> AnthropicMessage:
Returns:
AnthropicMessage: The response from the model.
"""
chat_messages, system_message = _format_messages(messages)
request_kwargs = self._prepare_request_kwargs(system_message)
return await self.get_async_client().messages.create(
model=self.id,
messages=chat_messages, # type: ignore
**request_kwargs,
)
Raises:
APIConnectionError: If there are network connectivity issues
RateLimitError: If the API rate limit is exceeded
APIStatusError: For other API-related errors
"""
try:
chat_messages, system_message = _format_messages(messages)
request_kwargs = self._prepare_request_kwargs(system_message)

return await self.get_async_client().messages.create(
model=self.id,
messages=chat_messages, # type: ignore
**request_kwargs,
)
except APIConnectionError as e:
logger.error(f"Connection error while calling Claude API: {str(e)}")
raise
except RateLimitError as e:
logger.warning(f"Rate limit exceeded: {str(e)}")
raise
except APIStatusError as e:
logger.error(f"Claude API error (status {e.status_code}): {str(e)}")
raise
except Exception as e:
logger.error(f"Unexpected error calling Claude API: {str(e)}")
raise

async def ainvoke_stream(self, messages: List[Message]) -> Any:
"""
Expand All @@ -348,15 +399,27 @@ async def ainvoke_stream(self, messages: List[Message]) -> Any:
Returns:
Any: The streamed response from the model.
"""
chat_messages, system_message = _format_messages(messages)
request_kwargs = self._prepare_request_kwargs(system_message)

return await self.get_async_client().messages.create(
model=self.id,
messages=chat_messages, # type: ignore
stream=True,
**request_kwargs,
)
try:
chat_messages, system_message = _format_messages(messages)
request_kwargs = self._prepare_request_kwargs(system_message)

return await self.get_async_client().messages.stream(
model=self.id,
messages=chat_messages, # type: ignore
**request_kwargs,
).__aenter__()
except APIConnectionError as e:
logger.error(f"Connection error while calling Claude API: {str(e)}")
raise
except RateLimitError as e:
logger.warning(f"Rate limit exceeded: {str(e)}")
raise
except APIStatusError as e:
logger.error(f"Claude API error (status {e.status_code}): {str(e)}")
raise
except Exception as e:
logger.error(f"Unexpected error calling Claude API: {str(e)}")
raise

# Overwrite the default from the base model
def format_function_call_results(
Expand Down
Loading

0 comments on commit 2012f68

Please sign in to comment.