agno 2.3.5__py3-none-any.whl → 2.3.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno/agent/agent.py +7 -4
- agno/db/postgres/async_postgres.py +14 -4
- agno/db/postgres/postgres.py +9 -3
- agno/db/sqlite/async_sqlite.py +1 -1
- agno/db/sqlite/sqlite.py +3 -4
- agno/eval/accuracy.py +8 -4
- agno/integrations/discord/client.py +1 -1
- agno/models/cerebras/cerebras.py +11 -12
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/schema.py +2 -1
- agno/session/team.py +0 -1
- agno/table.py +1 -1
- agno/team/team.py +7 -4
- agno/tools/google_drive.py +4 -3
- agno/tools/spotify.py +922 -0
- agno/utils/agent.py +2 -2
- agno/utils/mcp.py +1 -1
- agno/workflow/workflow.py +5 -2
- {agno-2.3.5.dist-info → agno-2.3.6.dist-info}/METADATA +37 -32
- {agno-2.3.5.dist-info → agno-2.3.6.dist-info}/RECORD +23 -22
- {agno-2.3.5.dist-info → agno-2.3.6.dist-info}/WHEEL +0 -0
- {agno-2.3.5.dist-info → agno-2.3.6.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.5.dist-info → agno-2.3.6.dist-info}/top_level.txt +0 -0
agno/agent/agent.py
CHANGED
|
@@ -1645,7 +1645,10 @@ class Agent:
|
|
|
1645
1645
|
|
|
1646
1646
|
# Initialize session state
|
|
1647
1647
|
session_state = self._initialize_session_state(
|
|
1648
|
-
session_state=session_state
|
|
1648
|
+
session_state=session_state if session_state is not None else {},
|
|
1649
|
+
user_id=user_id,
|
|
1650
|
+
session_id=session_id,
|
|
1651
|
+
run_id=run_id,
|
|
1649
1652
|
)
|
|
1650
1653
|
# Update session state from DB
|
|
1651
1654
|
session_state = self._load_session_state(session=agent_session, session_state=session_state)
|
|
@@ -1866,7 +1869,7 @@ class Agent:
|
|
|
1866
1869
|
self._update_metadata(session=agent_session)
|
|
1867
1870
|
# Initialize session state
|
|
1868
1871
|
run_context.session_state = self._initialize_session_state(
|
|
1869
|
-
session_state=run_context.session_state
|
|
1872
|
+
session_state=run_context.session_state if run_context.session_state is not None else {},
|
|
1870
1873
|
user_id=user_id,
|
|
1871
1874
|
session_id=session_id,
|
|
1872
1875
|
run_id=run_response.run_id,
|
|
@@ -2144,7 +2147,7 @@ class Agent:
|
|
|
2144
2147
|
self._update_metadata(session=agent_session)
|
|
2145
2148
|
# Initialize session state
|
|
2146
2149
|
run_context.session_state = self._initialize_session_state(
|
|
2147
|
-
session_state=run_context.session_state
|
|
2150
|
+
session_state=run_context.session_state if run_context.session_state is not None else {},
|
|
2148
2151
|
user_id=user_id,
|
|
2149
2152
|
session_id=session_id,
|
|
2150
2153
|
run_id=run_response.run_id,
|
|
@@ -6988,7 +6991,7 @@ class Agent:
|
|
|
6988
6991
|
|
|
6989
6992
|
# Should already be resolved and passed from run() method
|
|
6990
6993
|
format_variables = ChainMap(
|
|
6991
|
-
session_state
|
|
6994
|
+
session_state if session_state is not None else {},
|
|
6992
6995
|
dependencies or {},
|
|
6993
6996
|
metadata or {},
|
|
6994
6997
|
{"user_id": user_id} if user_id is not None else {},
|
|
@@ -32,6 +32,7 @@ from agno.utils.log import log_debug, log_error, log_info, log_warning
|
|
|
32
32
|
try:
|
|
33
33
|
from sqlalchemy import Index, String, Table, UniqueConstraint, func, update
|
|
34
34
|
from sqlalchemy.dialects import postgresql
|
|
35
|
+
from sqlalchemy.exc import ProgrammingError
|
|
35
36
|
from sqlalchemy.ext.asyncio import AsyncEngine, async_sessionmaker, create_async_engine
|
|
36
37
|
from sqlalchemy.schema import Column, MetaData
|
|
37
38
|
from sqlalchemy.sql.expression import select, text
|
|
@@ -897,10 +898,19 @@ class AsyncPostgresDb(AsyncBaseDb):
|
|
|
897
898
|
table = await self._get_table(table_type="memories")
|
|
898
899
|
|
|
899
900
|
async with self.async_session_factory() as sess, sess.begin():
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
901
|
+
try:
|
|
902
|
+
stmt = select(func.jsonb_array_elements_text(table.c.topics))
|
|
903
|
+
if user_id is not None:
|
|
904
|
+
stmt = stmt.where(table.c.user_id == user_id)
|
|
905
|
+
result = await sess.execute(stmt)
|
|
906
|
+
except ProgrammingError:
|
|
907
|
+
# Retrying with json_array_elements_text. This works in older versions,
|
|
908
|
+
# where the topics column was of type JSON instead of JSONB
|
|
909
|
+
stmt = select(func.json_array_elements_text(table.c.topics))
|
|
910
|
+
if user_id is not None:
|
|
911
|
+
stmt = stmt.where(table.c.user_id == user_id)
|
|
912
|
+
result = await sess.execute(stmt)
|
|
913
|
+
|
|
904
914
|
records = result.fetchall()
|
|
905
915
|
|
|
906
916
|
return list(set([record[0] for record in records]))
|
agno/db/postgres/postgres.py
CHANGED
|
@@ -33,6 +33,7 @@ try:
|
|
|
33
33
|
from sqlalchemy import ForeignKey, Index, String, UniqueConstraint, func, select, update
|
|
34
34
|
from sqlalchemy.dialects import postgresql
|
|
35
35
|
from sqlalchemy.engine import Engine, create_engine
|
|
36
|
+
from sqlalchemy.exc import ProgrammingError
|
|
36
37
|
from sqlalchemy.orm import scoped_session, sessionmaker
|
|
37
38
|
from sqlalchemy.schema import Column, MetaData, Table
|
|
38
39
|
from sqlalchemy.sql.expression import text
|
|
@@ -1082,9 +1083,14 @@ class PostgresDb(BaseDb):
|
|
|
1082
1083
|
return []
|
|
1083
1084
|
|
|
1084
1085
|
with self.Session() as sess, sess.begin():
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1086
|
+
try:
|
|
1087
|
+
stmt = select(func.jsonb_array_elements_text(table.c.topics))
|
|
1088
|
+
result = sess.execute(stmt).fetchall()
|
|
1089
|
+
except ProgrammingError:
|
|
1090
|
+
# Retrying with json_array_elements_text. This works in older versions,
|
|
1091
|
+
# where the topics column was of type JSON instead of JSONB
|
|
1092
|
+
stmt = select(func.json_array_elements_text(table.c.topics))
|
|
1093
|
+
result = sess.execute(stmt).fetchall()
|
|
1088
1094
|
|
|
1089
1095
|
return list(set([record[0] for record in result]))
|
|
1090
1096
|
|
agno/db/sqlite/async_sqlite.py
CHANGED
|
@@ -1114,7 +1114,7 @@ class AsyncSqliteDb(AsyncBaseDb):
|
|
|
1114
1114
|
|
|
1115
1115
|
async with self.async_session_factory() as sess, sess.begin():
|
|
1116
1116
|
# Select topics from all results
|
|
1117
|
-
stmt = select(
|
|
1117
|
+
stmt = select(table.c.topics)
|
|
1118
1118
|
result = (await sess.execute(stmt)).fetchall()
|
|
1119
1119
|
|
|
1120
1120
|
return list(set([record[0] for record in result]))
|
agno/db/sqlite/sqlite.py
CHANGED
|
@@ -245,9 +245,9 @@ class SqliteDb(BaseDb):
|
|
|
245
245
|
return table
|
|
246
246
|
|
|
247
247
|
except Exception as e:
|
|
248
|
-
from traceback import
|
|
248
|
+
from traceback import print_exc
|
|
249
249
|
|
|
250
|
-
|
|
250
|
+
print_exc()
|
|
251
251
|
log_error(f"Could not create table '{table_name}': {e}")
|
|
252
252
|
raise e
|
|
253
253
|
|
|
@@ -1109,9 +1109,8 @@ class SqliteDb(BaseDb):
|
|
|
1109
1109
|
|
|
1110
1110
|
with self.Session() as sess, sess.begin():
|
|
1111
1111
|
# Select topics from all results
|
|
1112
|
-
stmt = select(
|
|
1112
|
+
stmt = select(table.c.topics)
|
|
1113
1113
|
result = sess.execute(stmt).fetchall()
|
|
1114
|
-
|
|
1115
1114
|
return list(set([record[0] for record in result]))
|
|
1116
1115
|
|
|
1117
1116
|
except Exception as e:
|
agno/eval/accuracy.py
CHANGED
|
@@ -359,10 +359,12 @@ Remember: You must only compare the agent_output to the expected_output. The exp
|
|
|
359
359
|
status = Status(f"Running evaluation {i + 1}...", spinner="dots", speed=1.0, refresh_per_second=10)
|
|
360
360
|
live_log.update(status)
|
|
361
361
|
|
|
362
|
+
agent_session_id = f"eval_{self.eval_id}_{i + 1}"
|
|
363
|
+
|
|
362
364
|
if self.agent is not None:
|
|
363
|
-
output = self.agent.run(input=eval_input).content
|
|
365
|
+
output = self.agent.run(input=eval_input, session_id=agent_session_id).content
|
|
364
366
|
elif self.team is not None:
|
|
365
|
-
output = self.team.run(input=eval_input).content
|
|
367
|
+
output = self.team.run(input=eval_input, session_id=agent_session_id).content
|
|
366
368
|
|
|
367
369
|
if not output:
|
|
368
370
|
logger.error(f"Failed to generate a valid answer on iteration {i + 1}: {output}")
|
|
@@ -500,11 +502,13 @@ Remember: You must only compare the agent_output to the expected_output. The exp
|
|
|
500
502
|
status = Status(f"Running evaluation {i + 1}...", spinner="dots", speed=1.0, refresh_per_second=10)
|
|
501
503
|
live_log.update(status)
|
|
502
504
|
|
|
505
|
+
agent_session_id = f"eval_{self.eval_id}_{i + 1}"
|
|
506
|
+
|
|
503
507
|
if self.agent is not None:
|
|
504
|
-
response = await self.agent.arun(input=eval_input)
|
|
508
|
+
response = await self.agent.arun(input=eval_input, session_id=agent_session_id)
|
|
505
509
|
output = response.content
|
|
506
510
|
elif self.team is not None:
|
|
507
|
-
response = await self.team.arun(input=eval_input) # type: ignore
|
|
511
|
+
response = await self.team.arun(input=eval_input, session_id=agent_session_id) # type: ignore
|
|
508
512
|
output = response.content
|
|
509
513
|
|
|
510
514
|
if not output:
|
|
@@ -14,7 +14,7 @@ try:
|
|
|
14
14
|
import discord
|
|
15
15
|
|
|
16
16
|
except (ImportError, ModuleNotFoundError):
|
|
17
|
-
|
|
17
|
+
raise ImportError("`discord.py` not installed. Please install using `pip install discord.py`")
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class RequiresConfirmationView(discord.ui.View):
|
agno/models/cerebras/cerebras.py
CHANGED
|
@@ -512,14 +512,16 @@ class Cerebras(Model):
|
|
|
512
512
|
|
|
513
513
|
# Extend the list if needed
|
|
514
514
|
while len(tool_calls) <= index:
|
|
515
|
-
tool_calls.append(
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
"
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
515
|
+
tool_calls.append(
|
|
516
|
+
{
|
|
517
|
+
"id": None,
|
|
518
|
+
"type": None,
|
|
519
|
+
"function": {
|
|
520
|
+
"name": "",
|
|
521
|
+
"arguments": "",
|
|
522
|
+
},
|
|
523
|
+
}
|
|
524
|
+
)
|
|
523
525
|
|
|
524
526
|
tool_call_entry = tool_calls[index]
|
|
525
527
|
|
|
@@ -540,10 +542,7 @@ class Cerebras(Model):
|
|
|
540
542
|
tool_call_entry["function"]["arguments"] += func_delta["arguments"]
|
|
541
543
|
|
|
542
544
|
# Filter out any incomplete tool calls (missing id or function name)
|
|
543
|
-
complete_tool_calls = [
|
|
544
|
-
tc for tc in tool_calls
|
|
545
|
-
if tc.get("id") and tc.get("function", {}).get("name")
|
|
546
|
-
]
|
|
545
|
+
complete_tool_calls = [tc for tc in tool_calls if tc.get("id") and tc.get("function", {}).get("name")]
|
|
547
546
|
|
|
548
547
|
return complete_tool_calls
|
|
549
548
|
|
|
@@ -3,6 +3,8 @@ import hmac
|
|
|
3
3
|
import os
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
|
+
from agno.utils.log import log_warning
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
def is_development_mode() -> bool:
|
|
8
10
|
"""Check if the application is running in development mode."""
|
|
@@ -36,7 +38,7 @@ def validate_webhook_signature(payload: bytes, signature_header: Optional[str])
|
|
|
36
38
|
"""
|
|
37
39
|
# In development mode, we can bypass signature validation
|
|
38
40
|
if is_development_mode():
|
|
39
|
-
|
|
41
|
+
log_warning("Bypassing signature validation in development mode")
|
|
40
42
|
return True
|
|
41
43
|
|
|
42
44
|
if not signature_header or not signature_header.startswith("sha256="):
|
agno/os/schema.py
CHANGED
|
@@ -742,10 +742,11 @@ class SessionSchema(BaseModel):
|
|
|
742
742
|
@classmethod
|
|
743
743
|
def from_dict(cls, session: Dict[str, Any]) -> "SessionSchema":
|
|
744
744
|
session_name = get_session_name(session)
|
|
745
|
+
session_data = session.get("session_data", {}) or {}
|
|
745
746
|
return cls(
|
|
746
747
|
session_id=session.get("session_id", ""),
|
|
747
748
|
session_name=session_name,
|
|
748
|
-
session_state=
|
|
749
|
+
session_state=session_data.get("session_state", None),
|
|
749
750
|
created_at=datetime.fromtimestamp(session.get("created_at", 0), tz=timezone.utc)
|
|
750
751
|
if session.get("created_at")
|
|
751
752
|
else None,
|
agno/session/team.py
CHANGED
|
@@ -46,7 +46,6 @@ class TeamSession:
|
|
|
46
46
|
session_dict = asdict(self)
|
|
47
47
|
|
|
48
48
|
session_dict["runs"] = [run.to_dict() for run in self.runs] if self.runs else None
|
|
49
|
-
print(session_dict["runs"])
|
|
50
49
|
session_dict["summary"] = self.summary.to_dict() if self.summary else None
|
|
51
50
|
|
|
52
51
|
return session_dict
|
agno/table.py
CHANGED
agno/team/team.py
CHANGED
|
@@ -2060,7 +2060,10 @@ class Team:
|
|
|
2060
2060
|
|
|
2061
2061
|
# Initialize session state
|
|
2062
2062
|
session_state = self._initialize_session_state(
|
|
2063
|
-
session_state=session_state
|
|
2063
|
+
session_state=session_state if session_state is not None else {},
|
|
2064
|
+
user_id=user_id,
|
|
2065
|
+
session_id=session_id,
|
|
2066
|
+
run_id=run_id,
|
|
2064
2067
|
)
|
|
2065
2068
|
# Update session state from DB
|
|
2066
2069
|
session_state = self._load_session_state(session=team_session, session_state=session_state)
|
|
@@ -2293,7 +2296,7 @@ class Team:
|
|
|
2293
2296
|
self._update_metadata(session=team_session)
|
|
2294
2297
|
# Initialize session state
|
|
2295
2298
|
run_context.session_state = self._initialize_session_state(
|
|
2296
|
-
session_state=run_context.session_state
|
|
2299
|
+
session_state=run_context.session_state if run_context.session_state is not None else {},
|
|
2297
2300
|
user_id=user_id,
|
|
2298
2301
|
session_id=session_id,
|
|
2299
2302
|
run_id=run_response.run_id,
|
|
@@ -2533,7 +2536,7 @@ class Team:
|
|
|
2533
2536
|
self._update_metadata(session=team_session)
|
|
2534
2537
|
# Initialize session state
|
|
2535
2538
|
run_context.session_state = self._initialize_session_state(
|
|
2536
|
-
session_state=run_context.session_state
|
|
2539
|
+
session_state=run_context.session_state if run_context.session_state is not None else {},
|
|
2537
2540
|
user_id=user_id,
|
|
2538
2541
|
session_id=session_id,
|
|
2539
2542
|
run_id=run_response.run_id,
|
|
@@ -6877,7 +6880,7 @@ class Team:
|
|
|
6877
6880
|
return message
|
|
6878
6881
|
# Should already be resolved and passed from run() method
|
|
6879
6882
|
format_variables = ChainMap(
|
|
6880
|
-
session_state
|
|
6883
|
+
session_state if session_state is not None else {},
|
|
6881
6884
|
dependencies or {},
|
|
6882
6885
|
metadata or {},
|
|
6883
6886
|
{"user_id": user_id} if user_id is not None else {},
|
agno/tools/google_drive.py
CHANGED
|
@@ -69,6 +69,7 @@ from pathlib import Path
|
|
|
69
69
|
from typing import Any, List, Optional, Union
|
|
70
70
|
|
|
71
71
|
from agno.tools import Toolkit
|
|
72
|
+
from agno.utils.log import log_error
|
|
72
73
|
|
|
73
74
|
try:
|
|
74
75
|
from google.auth.transport.requests import Request
|
|
@@ -202,7 +203,7 @@ class GoogleDriveTools(Toolkit):
|
|
|
202
203
|
items = results.get("files", [])
|
|
203
204
|
return items
|
|
204
205
|
except Exception as error:
|
|
205
|
-
|
|
206
|
+
log_error(f"Could not list files: {error}")
|
|
206
207
|
return []
|
|
207
208
|
|
|
208
209
|
@authenticate
|
|
@@ -238,7 +239,7 @@ class GoogleDriveTools(Toolkit):
|
|
|
238
239
|
)
|
|
239
240
|
return uploaded_file
|
|
240
241
|
except Exception as error:
|
|
241
|
-
|
|
242
|
+
log_error(f"Could not upload file '{file_path}': {error}")
|
|
242
243
|
return None
|
|
243
244
|
|
|
244
245
|
@authenticate
|
|
@@ -266,5 +267,5 @@ class GoogleDriveTools(Toolkit):
|
|
|
266
267
|
print(f"Download progress: {int(status.progress() * 100)}%.")
|
|
267
268
|
return dest_path
|
|
268
269
|
except Exception as error:
|
|
269
|
-
|
|
270
|
+
log_error(f"Could not download file '{file_id}': {error}")
|
|
270
271
|
return None
|