Skip to content

Commit b2d8652

Browse files
dirkbrndLockeysama
authored andcommitted
Release 1.4.5 (agno-agi#3086)
# Changelog ## New Features: - **Embedder Support via AWS Bedrock**: `AwsBedrockEmbedder` has been added with a default embedding model of `cohere.embed-multilingual-v3`. ## Bug Fixes: - **Tools with Optional Parameters on Llama API**: Fixed edge cases with functions
1 parent 31b5e43 commit b2d8652

File tree

12 files changed

+97
-78
lines changed

12 files changed

+97
-78
lines changed

.github/workflows/test_on_release.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ jobs:
580580
working-directory: .
581581
run: |
582582
./scripts/dev_setup.sh
583-
- name: Run remaining integration tests
583+
- name: Run agent integration tests
584584
working-directory: .
585585
run: |
586586
source .venv/bin/activate
@@ -609,7 +609,7 @@ jobs:
609609
working-directory: .
610610
run: |
611611
./scripts/dev_setup.sh
612-
- name: Run remaining integration tests
612+
- name: Run teams integration tests
613613
working-directory: .
614614
run: |
615615
source .venv/bin/activate
@@ -638,7 +638,7 @@ jobs:
638638
working-directory: .
639639
run: |
640640
./scripts/dev_setup.sh
641-
- name: Run remaining integration tests
641+
- name: Run knowledge integration tests
642642
working-directory: .
643643
run: |
644644
source .venv/bin/activate
@@ -672,4 +672,4 @@ jobs:
672672
working-directory: .
673673
run: |
674674
source .venv/bin/activate
675-
python -m pytest --ignore=./libs/agno/tests/integration/models --ignore=./libs/agno/tests/integration/agents --ignore=./libs/agno/tests/integration/knowledge --ignore=./libs/agno/tests/integration/teams ./libs/agno/tests/integration
675+
python -m pytest --ignore=./libs/agno/tests/integration/models --ignore=./libs/agno/tests/integration/agent --ignore=./libs/agno/tests/integration/knowledge --ignore=./libs/agno/tests/integration/teams ./libs/agno/tests/integration

libs/agno/agno/agent/agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2060,7 +2060,7 @@ def add_tools_to_model(
20602060
if name not in _functions_for_model:
20612061
func._agent = self
20622062
func.process_entrypoint(strict=strict)
2063-
if strict:
2063+
if strict and func.strict is None:
20642064
func.strict = True
20652065
if self.tool_hooks is not None:
20662066
func.tool_hooks = self.tool_hooks

libs/agno/agno/memory/v2/memory.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,7 @@ def add_run(self, session_id: str, run: Union[RunResponse, TeamRunResponse]) ->
673673
"""Adds a RunResponse to the runs list."""
674674
if not self.runs:
675675
self.runs = {}
676+
676677
self.runs.setdefault(session_id, []).append(run)
677678
log_debug("Added RunResponse to Memory")
678679

libs/agno/agno/models/openai/chat.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,6 @@ async def ainvoke(self, messages: List[Message]) -> Union[ChatCompletion, Parsed
386386
Returns:
387387
ChatCompletion: The chat completion response from the API.
388388
"""
389-
390389
try:
391390
if self.response_format is not None and self.structured_outputs:
392391
if isinstance(self.response_format, type) and issubclass(self.response_format, BaseModel):

libs/agno/agno/team/team.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6220,13 +6220,13 @@ def load_team_session(self, session: TeamSession):
62206220
try:
62216221
if self.memory.runs is None:
62226222
self.memory.runs = {}
6223+
self.memory.runs[session.session_id] = []
62236224
for run in session.memory["runs"]:
6224-
session_id = run["session_id"]
6225-
self.memory.runs[session_id] = []
6225+
run_session_id = run["session_id"]
62266226
if "team_id" in run:
6227-
self.memory.runs[session_id].append(TeamRunResponse.from_dict(run))
6227+
self.memory.runs[run_session_id].append(TeamRunResponse.from_dict(run))
62286228
else:
6229-
self.memory.runs[session_id].append(RunResponse.from_dict(run))
6229+
self.memory.runs[run_session_id].append(RunResponse.from_dict(run))
62306230
except Exception as e:
62316231
log_warning(f"Failed to load runs from memory: {e}")
62326232
if "team_context" in session.memory:

libs/agno/agno/tools/apify.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616

1717
class ApifyTools(Toolkit):
18-
def __init__(self, actors: Union[str, List[str]] = None, apify_api_token: Optional[str] = None):
18+
def __init__(self, actors: Optional[Union[str, List[str]]] = None, apify_api_token: Optional[str] = None):
1919
"""Initialize ApifyTools with specific Actors.
2020
2121
Args:
@@ -173,7 +173,7 @@ def actor_function(**kwargs) -> str:
173173

174174
# Utility functions
175175
def props_to_json_schema(input_dict, required_fields=None):
176-
schema = {"type": "object", "properties": {}, "required": required_fields or []}
176+
schema: Dict[str, Any] = {"type": "object", "properties": {}, "required": required_fields or []}
177177

178178
def infer_array_item_type(prop):
179179
type_map = {
@@ -194,7 +194,7 @@ def infer_array_item_type(prop):
194194
return "string" # Fallback for arrays like searchStringsArray
195195

196196
for key, value in input_dict.items():
197-
prop_schema = {}
197+
prop_schema: Dict[str, Any] = {}
198198
prop_type = value.get("type")
199199

200200
if "enum" in value:

libs/agno/agno/tools/function.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ def process_entrypoint(self, strict: bool = False):
169169
from agno.utils.json_schema import get_json_schema
170170

171171
if self.skip_entrypoint_processing:
172+
if strict:
173+
self.process_schema_for_strict()
172174
return
173175

174176
if self.entrypoint is None:
@@ -260,6 +262,10 @@ def process_entrypoint(self, strict: bool = False):
260262
except Exception as e:
261263
log_warning(f"Failed to add validate decorator to entrypoint: {e}")
262264

265+
def process_schema_for_strict(self):
266+
self.parameters["additionalProperties"] = False
267+
self.parameters["required"] = [name for name in self.parameters["properties"] if name not in ["agent", "team"]]
268+
263269
def get_type_name(self, t: Type[T]):
264270
name = str(t)
265271
if "list" in name or "dict" in name:

libs/agno/agno/tools/mcp.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,6 @@ async def initialize(self) -> None:
203203
try:
204204
# Get an entrypoint for the tool
205205
entrypoint = get_entrypoint_for_tool(tool, self.session)
206-
207206
# Create a Function for the tool
208207
f = Function(
209208
name=tool.name,

libs/agno/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "agno"
3-
version = "1.4.4"
3+
version = "1.4.5"
44
description = "Agno: a lightweight library for building Reasoning Agents"
55
requires-python = ">=3.7,<4"
66
readme = "README.md"

libs/agno/tests/integration/agent/test_reasoning_content_knowledge_tools.py

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,21 @@ def test_knowledge_tools_non_streaming(knowledge_base):
7070
# Run the agent in non-streaming mode
7171
response = agent.run("What does Paul Graham explain about reading in his essay?", stream=False)
7272

73-
# Print the reasoning_content when received
74-
if hasattr(response, "reasoning_content") and response.reasoning_content:
75-
print("\n=== KnowledgeTools (non-streaming) reasoning_content ===")
76-
print(response.reasoning_content)
77-
print("=========================================================\n")
78-
79-
# Assert that reasoning_content exists and is populated
80-
assert hasattr(response, "reasoning_content"), "Response should have reasoning_content attribute"
81-
assert response.reasoning_content is not None, "reasoning_content should not be None"
82-
assert len(response.reasoning_content) > 0, "reasoning_content should not be empty"
73+
think_called = False
74+
for tool_call in response.formatted_tool_calls:
75+
if "think" in tool_call:
76+
think_called = True
77+
if think_called:
78+
# Print the reasoning_content when received
79+
if hasattr(response, "reasoning_content") and response.reasoning_content:
80+
print("\n=== KnowledgeTools (non-streaming) reasoning_content ===")
81+
print(response.reasoning_content)
82+
print("=========================================================\n")
83+
84+
# Assert that reasoning_content exists and is populated
85+
assert hasattr(response, "reasoning_content"), "Response should have reasoning_content attribute"
86+
assert response.reasoning_content is not None, "reasoning_content should not be None"
87+
assert len(response.reasoning_content) > 0, "reasoning_content should not be empty"
8388

8489

8590
@pytest.mark.integration
@@ -102,20 +107,25 @@ def test_knowledge_tools_streaming(knowledge_base):
102107
agent.run("What are Paul Graham's suggestions on what to read?", stream=True, stream_intermediate_steps=True)
103108
)
104109

105-
# Print the reasoning_content when received
106-
if (
107-
hasattr(agent, "run_response")
108-
and agent.run_response
109-
and hasattr(agent.run_response, "reasoning_content")
110-
and agent.run_response.reasoning_content
111-
):
112-
print("\n=== KnowledgeTools (streaming) reasoning_content ===")
113-
print(agent.run_response.reasoning_content)
114-
print("====================================================\n")
115-
116-
# Check the agent's run_response directly after streaming is complete
117-
assert hasattr(agent, "run_response"), "Agent should have run_response after streaming"
118-
assert agent.run_response is not None, "Agent's run_response should not be None"
119-
assert hasattr(agent.run_response, "reasoning_content"), "Response should have reasoning_content attribute"
120-
assert agent.run_response.reasoning_content is not None, "reasoning_content should not be None"
121-
assert len(agent.run_response.reasoning_content) > 0, "reasoning_content should not be empty"
110+
think_called = False
111+
for tool_call in agent.run_response.formatted_tool_calls:
112+
if "think" in tool_call:
113+
think_called = True
114+
if think_called:
115+
# Print the reasoning_content when received
116+
if (
117+
hasattr(agent, "run_response")
118+
and agent.run_response
119+
and hasattr(agent.run_response, "reasoning_content")
120+
and agent.run_response.reasoning_content
121+
):
122+
print("\n=== KnowledgeTools (streaming) reasoning_content ===")
123+
print(agent.run_response.reasoning_content)
124+
print("====================================================\n")
125+
126+
# Check the agent's run_response directly after streaming is complete
127+
assert hasattr(agent, "run_response"), "Agent should have run_response after streaming"
128+
assert agent.run_response is not None, "Agent's run_response should not be None"
129+
assert hasattr(agent.run_response, "reasoning_content"), "Response should have reasoning_content attribute"
130+
assert agent.run_response.reasoning_content is not None, "reasoning_content should not be None"
131+
assert len(agent.run_response.reasoning_content) > 0, "reasoning_content should not be empty"

0 commit comments

Comments
 (0)