agno 2.1.7__py3-none-any.whl → 2.1.9__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 +174 -37
- agno/knowledge/knowledge.py +4 -0
- agno/models/message.py +5 -0
- agno/os/routers/knowledge/knowledge.py +4 -4
- agno/os/schema.py +6 -6
- agno/team/team.py +111 -37
- agno/tools/googlecalendar.py +36 -8
- agno/tools/jira.py +20 -0
- agno/workflow/condition.py +31 -9
- agno/workflow/router.py +31 -9
- agno/workflow/step.py +51 -27
- {agno-2.1.7.dist-info → agno-2.1.9.dist-info}/METADATA +1 -1
- {agno-2.1.7.dist-info → agno-2.1.9.dist-info}/RECORD +16 -16
- {agno-2.1.7.dist-info → agno-2.1.9.dist-info}/WHEEL +0 -0
- {agno-2.1.7.dist-info → agno-2.1.9.dist-info}/licenses/LICENSE +0 -0
- {agno-2.1.7.dist-info → agno-2.1.9.dist-info}/top_level.txt +0 -0
agno/team/team.py
CHANGED
|
@@ -862,6 +862,9 @@ class Team:
|
|
|
862
862
|
run_response: TeamRunOutput,
|
|
863
863
|
run_input: TeamRunInput,
|
|
864
864
|
session: TeamSession,
|
|
865
|
+
session_state: Optional[Dict[str, Any]] = None,
|
|
866
|
+
dependencies: Optional[Dict[str, Any]] = None,
|
|
867
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
865
868
|
user_id: Optional[str] = None,
|
|
866
869
|
debug_mode: Optional[bool] = None,
|
|
867
870
|
**kwargs: Any,
|
|
@@ -876,6 +879,9 @@ class Team:
|
|
|
876
879
|
"team": self,
|
|
877
880
|
"session": session,
|
|
878
881
|
"user_id": user_id,
|
|
882
|
+
"metadata": metadata,
|
|
883
|
+
"session_state": session_state,
|
|
884
|
+
"dependencies": dependencies,
|
|
879
885
|
"debug_mode": debug_mode or self.debug_mode,
|
|
880
886
|
}
|
|
881
887
|
all_args.update(kwargs)
|
|
@@ -918,6 +924,9 @@ class Team:
|
|
|
918
924
|
run_response: TeamRunOutput,
|
|
919
925
|
run_input: TeamRunInput,
|
|
920
926
|
session: TeamSession,
|
|
927
|
+
session_state: Optional[Dict[str, Any]] = None,
|
|
928
|
+
dependencies: Optional[Dict[str, Any]] = None,
|
|
929
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
921
930
|
user_id: Optional[str] = None,
|
|
922
931
|
debug_mode: Optional[bool] = None,
|
|
923
932
|
**kwargs: Any,
|
|
@@ -932,6 +941,9 @@ class Team:
|
|
|
932
941
|
"team": self,
|
|
933
942
|
"session": session,
|
|
934
943
|
"user_id": user_id,
|
|
944
|
+
"session_state": session_state,
|
|
945
|
+
"dependencies": dependencies,
|
|
946
|
+
"metadata": metadata,
|
|
935
947
|
"debug_mode": debug_mode or self.debug_mode,
|
|
936
948
|
}
|
|
937
949
|
all_args.update(kwargs)
|
|
@@ -977,6 +989,9 @@ class Team:
|
|
|
977
989
|
hooks: Optional[List[Callable[..., Any]]],
|
|
978
990
|
run_output: TeamRunOutput,
|
|
979
991
|
session: TeamSession,
|
|
992
|
+
session_state: Optional[Dict[str, Any]] = None,
|
|
993
|
+
dependencies: Optional[Dict[str, Any]] = None,
|
|
994
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
980
995
|
user_id: Optional[str] = None,
|
|
981
996
|
debug_mode: Optional[bool] = None,
|
|
982
997
|
**kwargs: Any,
|
|
@@ -991,6 +1006,9 @@ class Team:
|
|
|
991
1006
|
"team": self,
|
|
992
1007
|
"session": session,
|
|
993
1008
|
"user_id": user_id,
|
|
1009
|
+
"session_state": session_state,
|
|
1010
|
+
"dependencies": dependencies,
|
|
1011
|
+
"metadata": metadata,
|
|
994
1012
|
"debug_mode": debug_mode or self.debug_mode,
|
|
995
1013
|
}
|
|
996
1014
|
all_args.update(kwargs)
|
|
@@ -1014,6 +1032,9 @@ class Team:
|
|
|
1014
1032
|
run_output: TeamRunOutput,
|
|
1015
1033
|
session: TeamSession,
|
|
1016
1034
|
user_id: Optional[str] = None,
|
|
1035
|
+
session_state: Optional[Dict[str, Any]] = None,
|
|
1036
|
+
dependencies: Optional[Dict[str, Any]] = None,
|
|
1037
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
1017
1038
|
debug_mode: Optional[bool] = None,
|
|
1018
1039
|
**kwargs: Any,
|
|
1019
1040
|
) -> None:
|
|
@@ -1027,6 +1048,9 @@ class Team:
|
|
|
1027
1048
|
"team": self,
|
|
1028
1049
|
"session": session,
|
|
1029
1050
|
"user_id": user_id,
|
|
1051
|
+
"session_state": session_state,
|
|
1052
|
+
"dependencies": dependencies,
|
|
1053
|
+
"metadata": metadata,
|
|
1030
1054
|
"debug_mode": debug_mode or self.debug_mode,
|
|
1031
1055
|
}
|
|
1032
1056
|
all_args.update(kwargs)
|
|
@@ -1091,6 +1115,9 @@ class Team:
|
|
|
1091
1115
|
run_response=run_response,
|
|
1092
1116
|
run_input=run_input,
|
|
1093
1117
|
session=session,
|
|
1118
|
+
session_state=session_state,
|
|
1119
|
+
dependencies=dependencies,
|
|
1120
|
+
metadata=metadata,
|
|
1094
1121
|
user_id=user_id,
|
|
1095
1122
|
debug_mode=debug_mode,
|
|
1096
1123
|
**kwargs,
|
|
@@ -1182,26 +1209,29 @@ class Team:
|
|
|
1182
1209
|
else:
|
|
1183
1210
|
self._scrub_media_from_run_output(run_response)
|
|
1184
1211
|
|
|
1185
|
-
run_response.status = RunStatus.completed
|
|
1186
|
-
|
|
1187
1212
|
# Parse team response model
|
|
1188
1213
|
self._convert_response_to_structured_format(run_response=run_response)
|
|
1189
1214
|
|
|
1190
|
-
# Set the run duration
|
|
1191
|
-
if run_response.metrics:
|
|
1192
|
-
run_response.metrics.stop_timer()
|
|
1193
|
-
|
|
1194
1215
|
# 6. Execute post-hooks after output is generated but before response is returned
|
|
1195
1216
|
if self.post_hooks is not None:
|
|
1196
1217
|
self._execute_post_hooks(
|
|
1197
1218
|
hooks=self.post_hooks, # type: ignore
|
|
1198
1219
|
run_output=run_response,
|
|
1199
1220
|
session=session,
|
|
1221
|
+
session_state=session_state,
|
|
1222
|
+
dependencies=dependencies,
|
|
1223
|
+
metadata=metadata,
|
|
1200
1224
|
user_id=user_id,
|
|
1201
1225
|
debug_mode=debug_mode,
|
|
1202
1226
|
**kwargs,
|
|
1203
1227
|
)
|
|
1204
1228
|
|
|
1229
|
+
run_response.status = RunStatus.completed
|
|
1230
|
+
|
|
1231
|
+
# Set the run duration
|
|
1232
|
+
if run_response.metrics:
|
|
1233
|
+
run_response.metrics.stop_timer()
|
|
1234
|
+
|
|
1205
1235
|
# 7. Add the RunOutput to Team Session
|
|
1206
1236
|
session.upsert_run(run_response=run_response)
|
|
1207
1237
|
|
|
@@ -1278,6 +1308,9 @@ class Team:
|
|
|
1278
1308
|
run_response=run_response,
|
|
1279
1309
|
run_input=run_input,
|
|
1280
1310
|
session=session,
|
|
1311
|
+
session_state=session_state,
|
|
1312
|
+
dependencies=dependencies,
|
|
1313
|
+
metadata=metadata,
|
|
1281
1314
|
user_id=user_id,
|
|
1282
1315
|
debug_mode=debug_mode,
|
|
1283
1316
|
**kwargs,
|
|
@@ -1396,14 +1429,25 @@ class Team:
|
|
|
1396
1429
|
session=session, run_response=run_response, stream_intermediate_steps=stream_intermediate_steps
|
|
1397
1430
|
)
|
|
1398
1431
|
|
|
1399
|
-
|
|
1432
|
+
# Execute post-hooks after output is generated but before response is returned
|
|
1433
|
+
if self.post_hooks is not None:
|
|
1434
|
+
self._execute_post_hooks(
|
|
1435
|
+
hooks=self.post_hooks, # type: ignore
|
|
1436
|
+
run_output=run_response,
|
|
1437
|
+
session_state=session_state,
|
|
1438
|
+
dependencies=dependencies,
|
|
1439
|
+
metadata=metadata,
|
|
1440
|
+
session=session,
|
|
1441
|
+
user_id=user_id,
|
|
1442
|
+
debug_mode=debug_mode,
|
|
1443
|
+
**kwargs,
|
|
1444
|
+
)
|
|
1400
1445
|
|
|
1446
|
+
run_response.status = RunStatus.completed
|
|
1401
1447
|
# Set the run duration
|
|
1402
1448
|
if run_response.metrics:
|
|
1403
1449
|
run_response.metrics.stop_timer()
|
|
1404
1450
|
|
|
1405
|
-
# TODO: For now we don't run post-hooks during streaming
|
|
1406
|
-
|
|
1407
1451
|
# 5. Add the run to Team Session
|
|
1408
1452
|
session.upsert_run(run_response=run_response)
|
|
1409
1453
|
|
|
@@ -1630,11 +1674,11 @@ class Team:
|
|
|
1630
1674
|
)
|
|
1631
1675
|
self.model = cast(Model, self.model)
|
|
1632
1676
|
|
|
1633
|
-
if metadata is not None:
|
|
1634
|
-
if
|
|
1635
|
-
merge_dictionaries(metadata, self.metadata)
|
|
1636
|
-
else:
|
|
1677
|
+
if self.metadata is not None:
|
|
1678
|
+
if metadata is None:
|
|
1637
1679
|
metadata = self.metadata
|
|
1680
|
+
else:
|
|
1681
|
+
merge_dictionaries(metadata, self.metadata)
|
|
1638
1682
|
|
|
1639
1683
|
# Create a new run_response for this attempt
|
|
1640
1684
|
run_response = TeamRunOutput(
|
|
@@ -1799,6 +1843,9 @@ class Team:
|
|
|
1799
1843
|
|
|
1800
1844
|
register_run(run_response.run_id) # type: ignore
|
|
1801
1845
|
|
|
1846
|
+
if dependencies is not None:
|
|
1847
|
+
await self._aresolve_run_dependencies(dependencies=dependencies)
|
|
1848
|
+
|
|
1802
1849
|
# 1. Read or create session. Reads from the database if provided.
|
|
1803
1850
|
if self._has_async_db():
|
|
1804
1851
|
team_session = await self._aread_or_create_session(session_id=session_id, user_id=user_id)
|
|
@@ -1820,6 +1867,9 @@ class Team:
|
|
|
1820
1867
|
session=team_session,
|
|
1821
1868
|
user_id=user_id,
|
|
1822
1869
|
debug_mode=debug_mode,
|
|
1870
|
+
session_state=session_state,
|
|
1871
|
+
dependencies=dependencies,
|
|
1872
|
+
metadata=metadata,
|
|
1823
1873
|
**kwargs,
|
|
1824
1874
|
)
|
|
1825
1875
|
|
|
@@ -1907,21 +1957,35 @@ class Team:
|
|
|
1907
1957
|
else:
|
|
1908
1958
|
self._scrub_media_from_run_output(run_response)
|
|
1909
1959
|
|
|
1910
|
-
#
|
|
1911
|
-
|
|
1960
|
+
# 11. Parse team response model
|
|
1961
|
+
self._convert_response_to_structured_format(run_response=run_response)
|
|
1912
1962
|
|
|
1913
|
-
#
|
|
1914
|
-
self.
|
|
1963
|
+
# Execute post-hooks after output is generated but before response is returned
|
|
1964
|
+
if self.post_hooks is not None:
|
|
1965
|
+
await self._aexecute_post_hooks(
|
|
1966
|
+
hooks=self.post_hooks, # type: ignore
|
|
1967
|
+
run_output=run_response,
|
|
1968
|
+
session=team_session,
|
|
1969
|
+
user_id=user_id,
|
|
1970
|
+
debug_mode=debug_mode,
|
|
1971
|
+
session_state=session_state,
|
|
1972
|
+
dependencies=dependencies,
|
|
1973
|
+
metadata=metadata,
|
|
1974
|
+
**kwargs,
|
|
1975
|
+
)
|
|
1915
1976
|
|
|
1916
1977
|
run_response.status = RunStatus.completed
|
|
1917
1978
|
|
|
1918
|
-
# 11. Parse team response model
|
|
1919
|
-
self._convert_response_to_structured_format(run_response=run_response)
|
|
1920
|
-
|
|
1921
1979
|
# Set the run duration
|
|
1922
1980
|
if run_response.metrics:
|
|
1923
1981
|
run_response.metrics.stop_timer()
|
|
1924
1982
|
|
|
1983
|
+
# 9. Add the run to memory
|
|
1984
|
+
team_session.upsert_run(run_response=run_response)
|
|
1985
|
+
|
|
1986
|
+
# 10. Calculate session metrics
|
|
1987
|
+
self._update_session_metrics(session=team_session)
|
|
1988
|
+
|
|
1925
1989
|
# 12. Update Team Memory
|
|
1926
1990
|
async for _ in self._amake_memories_and_summaries(
|
|
1927
1991
|
run_response=run_response,
|
|
@@ -1944,17 +2008,6 @@ class Team:
|
|
|
1944
2008
|
# Log Team Telemetry
|
|
1945
2009
|
await self._alog_team_telemetry(session_id=team_session.session_id, run_id=run_response.run_id)
|
|
1946
2010
|
|
|
1947
|
-
# 15. Execute post-hooks after output is generated but before response is returned
|
|
1948
|
-
if self.post_hooks is not None:
|
|
1949
|
-
await self._aexecute_post_hooks(
|
|
1950
|
-
hooks=self.post_hooks, # type: ignore
|
|
1951
|
-
run_output=run_response,
|
|
1952
|
-
session=team_session,
|
|
1953
|
-
user_id=user_id,
|
|
1954
|
-
debug_mode=debug_mode,
|
|
1955
|
-
**kwargs,
|
|
1956
|
-
)
|
|
1957
|
-
|
|
1958
2011
|
log_debug(f"Team Run End: {run_response.run_id}", center=True, symbol="*")
|
|
1959
2012
|
|
|
1960
2013
|
cleanup_run(run_response.run_id) # type: ignore
|
|
@@ -2005,7 +2058,7 @@ class Team:
|
|
|
2005
2058
|
|
|
2006
2059
|
# 1. Resolve dependencies
|
|
2007
2060
|
if dependencies is not None:
|
|
2008
|
-
self.
|
|
2061
|
+
await self._aresolve_run_dependencies(dependencies=dependencies)
|
|
2009
2062
|
|
|
2010
2063
|
# 2. Read or create session. Reads from the database if provided.
|
|
2011
2064
|
if self._has_async_db():
|
|
@@ -2028,6 +2081,9 @@ class Team:
|
|
|
2028
2081
|
session=team_session,
|
|
2029
2082
|
user_id=user_id,
|
|
2030
2083
|
debug_mode=debug_mode,
|
|
2084
|
+
session_state=session_state,
|
|
2085
|
+
dependencies=dependencies,
|
|
2086
|
+
metadata=metadata,
|
|
2031
2087
|
**kwargs,
|
|
2032
2088
|
)
|
|
2033
2089
|
async for pre_hook_event in pre_hook_iterator:
|
|
@@ -2143,6 +2199,24 @@ class Team:
|
|
|
2143
2199
|
):
|
|
2144
2200
|
yield event
|
|
2145
2201
|
|
|
2202
|
+
# Execute post-hooks after output is generated but before response is returned
|
|
2203
|
+
if self.post_hooks is not None:
|
|
2204
|
+
await self._aexecute_post_hooks(
|
|
2205
|
+
hooks=self.post_hooks, # type: ignore
|
|
2206
|
+
run_output=run_response,
|
|
2207
|
+
session_state=session_state,
|
|
2208
|
+
dependencies=dependencies,
|
|
2209
|
+
metadata=metadata,
|
|
2210
|
+
session=team_session,
|
|
2211
|
+
user_id=user_id,
|
|
2212
|
+
debug_mode=debug_mode,
|
|
2213
|
+
**kwargs,
|
|
2214
|
+
)
|
|
2215
|
+
|
|
2216
|
+
# Set the run duration
|
|
2217
|
+
if run_response.metrics:
|
|
2218
|
+
run_response.metrics.stop_timer()
|
|
2219
|
+
|
|
2146
2220
|
run_response.status = RunStatus.completed
|
|
2147
2221
|
|
|
2148
2222
|
# 10. Add the run to memory
|
|
@@ -2353,12 +2427,12 @@ class Team:
|
|
|
2353
2427
|
)
|
|
2354
2428
|
|
|
2355
2429
|
self.model = cast(Model, self.model)
|
|
2356
|
-
|
|
2357
|
-
if metadata is not None:
|
|
2358
|
-
if
|
|
2359
|
-
merge_dictionaries(metadata, self.metadata)
|
|
2360
|
-
else:
|
|
2430
|
+
|
|
2431
|
+
if self.metadata is not None:
|
|
2432
|
+
if metadata is None:
|
|
2361
2433
|
metadata = self.metadata
|
|
2434
|
+
else:
|
|
2435
|
+
merge_dictionaries(metadata, self.metadata)
|
|
2362
2436
|
|
|
2363
2437
|
# Get knowledge filters
|
|
2364
2438
|
effective_filters = knowledge_filters
|
agno/tools/googlecalendar.py
CHANGED
|
@@ -4,7 +4,7 @@ import uuid
|
|
|
4
4
|
from functools import wraps
|
|
5
5
|
from os import getenv
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Any, Dict, List, Optional
|
|
7
|
+
from typing import Any, Dict, List, Optional, cast
|
|
8
8
|
|
|
9
9
|
from agno.tools import Toolkit
|
|
10
10
|
from agno.utils.log import log_debug, log_error, log_info
|
|
@@ -164,8 +164,10 @@ class GoogleCalendarTools(Toolkit):
|
|
|
164
164
|
)
|
|
165
165
|
|
|
166
166
|
try:
|
|
167
|
+
service = cast(Resource, self.service)
|
|
168
|
+
|
|
167
169
|
events_result = (
|
|
168
|
-
|
|
170
|
+
service.events()
|
|
169
171
|
.list(
|
|
170
172
|
calendarId=self.calendar_id,
|
|
171
173
|
timeMin=start_date,
|
|
@@ -194,6 +196,7 @@ class GoogleCalendarTools(Toolkit):
|
|
|
194
196
|
timezone: Optional[str] = "UTC",
|
|
195
197
|
attendees: Optional[List[str]] = None,
|
|
196
198
|
add_google_meet_link: Optional[bool] = False,
|
|
199
|
+
notify_attendees: Optional[bool] = False,
|
|
197
200
|
) -> str:
|
|
198
201
|
"""
|
|
199
202
|
Create a new event in the Google Calendar.
|
|
@@ -207,6 +210,7 @@ class GoogleCalendarTools(Toolkit):
|
|
|
207
210
|
timezone (Optional[str]): Timezone for the event (default: UTC)
|
|
208
211
|
attendees (Optional[List[str]]): List of email addresses of the attendees
|
|
209
212
|
add_google_meet_link (Optional[bool]): Whether to add a Google Meet video link to the event
|
|
213
|
+
notify_attendees (Optional[bool]): Whether to send email notifications to attendees (default: False)
|
|
210
214
|
|
|
211
215
|
Returns:
|
|
212
216
|
str: JSON string containing the created Google Calendar event or error message
|
|
@@ -241,12 +245,18 @@ class GoogleCalendarTools(Toolkit):
|
|
|
241
245
|
# Remove None values
|
|
242
246
|
event = {k: v for k, v in event.items() if v is not None}
|
|
243
247
|
|
|
248
|
+
# Determine sendUpdates value based on notify_attendees parameter
|
|
249
|
+
send_updates = "all" if notify_attendees and attendees else "none"
|
|
250
|
+
|
|
251
|
+
service = cast(Resource, self.service)
|
|
252
|
+
|
|
244
253
|
event_result = (
|
|
245
|
-
|
|
254
|
+
service.events()
|
|
246
255
|
.insert(
|
|
247
256
|
calendarId=self.calendar_id,
|
|
248
257
|
body=event,
|
|
249
258
|
conferenceDataVersion=1 if add_google_meet_link else 0,
|
|
259
|
+
sendUpdates=send_updates,
|
|
250
260
|
)
|
|
251
261
|
.execute()
|
|
252
262
|
)
|
|
@@ -267,6 +277,7 @@ class GoogleCalendarTools(Toolkit):
|
|
|
267
277
|
end_date: Optional[str] = None,
|
|
268
278
|
timezone: Optional[str] = None,
|
|
269
279
|
attendees: Optional[List[str]] = None,
|
|
280
|
+
notify_attendees: Optional[bool] = False,
|
|
270
281
|
) -> str:
|
|
271
282
|
"""
|
|
272
283
|
Update an existing event in the Google Calendar.
|
|
@@ -280,13 +291,16 @@ class GoogleCalendarTools(Toolkit):
|
|
|
280
291
|
end_date (Optional[str]): New end date and time in ISO format (YYYY-MM-DDTHH:MM:SS)
|
|
281
292
|
timezone (Optional[str]): New timezone for the event
|
|
282
293
|
attendees (Optional[List[str]]): Updated list of attendee email addresses
|
|
294
|
+
notify_attendees (Optional[bool]): Whether to send email notifications to attendees (default: False)
|
|
283
295
|
|
|
284
296
|
Returns:
|
|
285
297
|
str: JSON string containing the updated Google Calendar event or error message
|
|
286
298
|
"""
|
|
287
299
|
try:
|
|
300
|
+
service = cast(Resource, self.service)
|
|
301
|
+
|
|
288
302
|
# First get the existing event to preserve its structure
|
|
289
|
-
event =
|
|
303
|
+
event = service.events().get(calendarId=self.calendar_id, eventId=event_id).execute()
|
|
290
304
|
|
|
291
305
|
# Update only the fields that are provided
|
|
292
306
|
if title is not None:
|
|
@@ -317,9 +331,15 @@ class GoogleCalendarTools(Toolkit):
|
|
|
317
331
|
except ValueError:
|
|
318
332
|
return json.dumps({"error": f"Invalid end datetime format: {end_date}. Use ISO format."})
|
|
319
333
|
|
|
334
|
+
# Determine sendUpdates value based on notify_attendees parameter
|
|
335
|
+
send_updates = "all" if notify_attendees and attendees else "none"
|
|
336
|
+
|
|
320
337
|
# Update the event
|
|
338
|
+
|
|
321
339
|
updated_event = (
|
|
322
|
-
|
|
340
|
+
service.events()
|
|
341
|
+
.update(calendarId=self.calendar_id, eventId=event_id, body=event, sendUpdates=send_updates)
|
|
342
|
+
.execute()
|
|
323
343
|
)
|
|
324
344
|
|
|
325
345
|
log_debug(f"Event {event_id} updated successfully.")
|
|
@@ -329,18 +349,24 @@ class GoogleCalendarTools(Toolkit):
|
|
|
329
349
|
return json.dumps({"error": f"An error occurred: {error}"})
|
|
330
350
|
|
|
331
351
|
@authenticate
|
|
332
|
-
def delete_event(self, event_id: str) -> str:
|
|
352
|
+
def delete_event(self, event_id: str, notify_attendees: Optional[bool] = True) -> str:
|
|
333
353
|
"""
|
|
334
354
|
Delete an event from the Google Calendar.
|
|
335
355
|
|
|
336
356
|
Args:
|
|
337
357
|
event_id (str): ID of the event to delete
|
|
358
|
+
notify_attendees (Optional[bool]): Whether to send email notifications to attendees (default: False)
|
|
338
359
|
|
|
339
360
|
Returns:
|
|
340
361
|
str: JSON string containing success message or error message
|
|
341
362
|
"""
|
|
342
363
|
try:
|
|
343
|
-
|
|
364
|
+
# Determine sendUpdates value based on notify_attendees parameter
|
|
365
|
+
send_updates = "all" if notify_attendees else "none"
|
|
366
|
+
|
|
367
|
+
service = cast(Resource, self.service)
|
|
368
|
+
|
|
369
|
+
service.events().delete(calendarId=self.calendar_id, eventId=event_id, sendUpdates=send_updates).execute()
|
|
344
370
|
|
|
345
371
|
log_debug(f"Event {event_id} deleted successfully.")
|
|
346
372
|
return json.dumps({"success": True, "message": f"Event {event_id} deleted successfully."})
|
|
@@ -366,6 +392,8 @@ class GoogleCalendarTools(Toolkit):
|
|
|
366
392
|
str: JSON string containing all Google Calendar events or error message
|
|
367
393
|
"""
|
|
368
394
|
try:
|
|
395
|
+
service = cast(Resource, self.service)
|
|
396
|
+
|
|
369
397
|
params = {
|
|
370
398
|
"calendarId": self.calendar_id,
|
|
371
399
|
"maxResults": min(max_results, 100),
|
|
@@ -412,7 +440,7 @@ class GoogleCalendarTools(Toolkit):
|
|
|
412
440
|
if page_token:
|
|
413
441
|
params["pageToken"] = page_token
|
|
414
442
|
|
|
415
|
-
events_result =
|
|
443
|
+
events_result = service.events().list(**params).execute()
|
|
416
444
|
all_events.extend(events_result.get("items", []))
|
|
417
445
|
|
|
418
446
|
page_token = events_result.get("nextPageToken")
|
agno/tools/jira.py
CHANGED
|
@@ -22,6 +22,7 @@ class JiraTools(Toolkit):
|
|
|
22
22
|
enable_create_issue: bool = True,
|
|
23
23
|
enable_search_issues: bool = True,
|
|
24
24
|
enable_add_comment: bool = True,
|
|
25
|
+
enable_add_worklog: bool = True,
|
|
25
26
|
all: bool = False,
|
|
26
27
|
**kwargs,
|
|
27
28
|
):
|
|
@@ -55,6 +56,8 @@ class JiraTools(Toolkit):
|
|
|
55
56
|
tools.append(self.search_issues)
|
|
56
57
|
if enable_add_comment or all:
|
|
57
58
|
tools.append(self.add_comment)
|
|
59
|
+
if enable_add_worklog or all:
|
|
60
|
+
tools.append(self.add_worklog)
|
|
58
61
|
|
|
59
62
|
super().__init__(name="jira_tools", tools=tools, **kwargs)
|
|
60
63
|
|
|
@@ -148,3 +151,20 @@ class JiraTools(Toolkit):
|
|
|
148
151
|
except Exception as e:
|
|
149
152
|
logger.error(f"Error adding comment to issue {issue_key}: {e}")
|
|
150
153
|
return json.dumps({"error": str(e)})
|
|
154
|
+
|
|
155
|
+
def add_worklog(self, issue_key: str, time_spent: str, comment: Optional[str] = None) -> str:
|
|
156
|
+
"""
|
|
157
|
+
Adds a worklog entry to log time spent on a specific Jira issue.
|
|
158
|
+
|
|
159
|
+
:param issue_key: The key of the issue to log work against (e.g., 'PROJ-123').
|
|
160
|
+
:param time_spent: The amount of time spent. Use Jira's format, e.g., '2h', '30m', '1d 4h'.
|
|
161
|
+
:param comment: An optional comment describing the work done.
|
|
162
|
+
:return: A JSON string indicating success or containing an error message.
|
|
163
|
+
"""
|
|
164
|
+
try:
|
|
165
|
+
self.jira.add_worklog(issue=issue_key, timeSpent=time_spent, comment=comment)
|
|
166
|
+
log_debug(f"Worklog of '{time_spent}' added to issue {issue_key}")
|
|
167
|
+
return json.dumps({"status": "success", "issue_key": issue_key, "time_spent": time_spent})
|
|
168
|
+
except Exception as e:
|
|
169
|
+
logger.error(f"Error adding worklog to issue {issue_key}: {e}")
|
|
170
|
+
return json.dumps({"error": str(e)})
|
agno/workflow/condition.py
CHANGED
|
@@ -111,13 +111,16 @@ class Condition:
|
|
|
111
111
|
audio=current_audio + all_audio,
|
|
112
112
|
)
|
|
113
113
|
|
|
114
|
-
def _evaluate_condition(self, step_input: StepInput) -> bool:
|
|
114
|
+
def _evaluate_condition(self, step_input: StepInput, session_state: Optional[Dict[str, Any]] = None) -> bool:
|
|
115
115
|
"""Evaluate the condition and return boolean result"""
|
|
116
116
|
if isinstance(self.evaluator, bool):
|
|
117
117
|
return self.evaluator
|
|
118
118
|
|
|
119
119
|
if callable(self.evaluator):
|
|
120
|
-
|
|
120
|
+
if session_state is not None and self._evaluator_has_session_state_param():
|
|
121
|
+
result = self.evaluator(step_input, session_state=session_state) # type: ignore[call-arg]
|
|
122
|
+
else:
|
|
123
|
+
result = self.evaluator(step_input)
|
|
121
124
|
|
|
122
125
|
if isinstance(result, bool):
|
|
123
126
|
return result
|
|
@@ -127,16 +130,24 @@ class Condition:
|
|
|
127
130
|
|
|
128
131
|
return False
|
|
129
132
|
|
|
130
|
-
async def _aevaluate_condition(self, step_input: StepInput) -> bool:
|
|
133
|
+
async def _aevaluate_condition(self, step_input: StepInput, session_state: Optional[Dict[str, Any]] = None) -> bool:
|
|
131
134
|
"""Async version of condition evaluation"""
|
|
132
135
|
if isinstance(self.evaluator, bool):
|
|
133
136
|
return self.evaluator
|
|
134
137
|
|
|
135
138
|
if callable(self.evaluator):
|
|
139
|
+
has_session_state = session_state is not None and self._evaluator_has_session_state_param()
|
|
140
|
+
|
|
136
141
|
if inspect.iscoroutinefunction(self.evaluator):
|
|
137
|
-
|
|
142
|
+
if has_session_state:
|
|
143
|
+
result = await self.evaluator(step_input, session_state=session_state) # type: ignore[call-arg]
|
|
144
|
+
else:
|
|
145
|
+
result = await self.evaluator(step_input)
|
|
138
146
|
else:
|
|
139
|
-
|
|
147
|
+
if has_session_state:
|
|
148
|
+
result = self.evaluator(step_input, session_state=session_state) # type: ignore[call-arg]
|
|
149
|
+
else:
|
|
150
|
+
result = self.evaluator(step_input)
|
|
140
151
|
|
|
141
152
|
if isinstance(result, bool):
|
|
142
153
|
return result
|
|
@@ -146,6 +157,17 @@ class Condition:
|
|
|
146
157
|
|
|
147
158
|
return False
|
|
148
159
|
|
|
160
|
+
def _evaluator_has_session_state_param(self) -> bool:
|
|
161
|
+
"""Check if the evaluator function has a session_state parameter"""
|
|
162
|
+
if not callable(self.evaluator):
|
|
163
|
+
return False
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
sig = inspect.signature(self.evaluator)
|
|
167
|
+
return "session_state" in sig.parameters
|
|
168
|
+
except Exception:
|
|
169
|
+
return False
|
|
170
|
+
|
|
149
171
|
def execute(
|
|
150
172
|
self,
|
|
151
173
|
step_input: StepInput,
|
|
@@ -166,7 +188,7 @@ class Condition:
|
|
|
166
188
|
self._prepare_steps()
|
|
167
189
|
|
|
168
190
|
# Evaluate the condition
|
|
169
|
-
condition_result = self._evaluate_condition(step_input)
|
|
191
|
+
condition_result = self._evaluate_condition(step_input, session_state)
|
|
170
192
|
log_debug(f"Condition {self.name} evaluated to: {condition_result}")
|
|
171
193
|
|
|
172
194
|
if not condition_result:
|
|
@@ -275,7 +297,7 @@ class Condition:
|
|
|
275
297
|
self._prepare_steps()
|
|
276
298
|
|
|
277
299
|
# Evaluate the condition
|
|
278
|
-
condition_result = self._evaluate_condition(step_input)
|
|
300
|
+
condition_result = self._evaluate_condition(step_input, session_state)
|
|
279
301
|
log_debug(f"Condition {self.name} evaluated to: {condition_result}")
|
|
280
302
|
|
|
281
303
|
if stream_intermediate_steps and workflow_run_response:
|
|
@@ -434,7 +456,7 @@ class Condition:
|
|
|
434
456
|
self._prepare_steps()
|
|
435
457
|
|
|
436
458
|
# Evaluate the condition
|
|
437
|
-
condition_result = await self._aevaluate_condition(step_input)
|
|
459
|
+
condition_result = await self._aevaluate_condition(step_input, session_state)
|
|
438
460
|
log_debug(f"Condition {self.name} evaluated to: {condition_result}")
|
|
439
461
|
|
|
440
462
|
if not condition_result:
|
|
@@ -543,7 +565,7 @@ class Condition:
|
|
|
543
565
|
self._prepare_steps()
|
|
544
566
|
|
|
545
567
|
# Evaluate the condition
|
|
546
|
-
condition_result = await self._aevaluate_condition(step_input)
|
|
568
|
+
condition_result = await self._aevaluate_condition(step_input, session_state)
|
|
547
569
|
log_debug(f"Condition {self.name} evaluated to: {condition_result}")
|
|
548
570
|
|
|
549
571
|
if stream_intermediate_steps and workflow_run_response:
|
agno/workflow/router.py
CHANGED
|
@@ -108,10 +108,13 @@ class Router:
|
|
|
108
108
|
audio=current_audio + all_audio,
|
|
109
109
|
)
|
|
110
110
|
|
|
111
|
-
def _route_steps(self, step_input: StepInput) -> List[Step]: # type: ignore[return-value]
|
|
111
|
+
def _route_steps(self, step_input: StepInput, session_state: Optional[Dict[str, Any]] = None) -> List[Step]: # type: ignore[return-value]
|
|
112
112
|
"""Route to the appropriate steps based on input"""
|
|
113
113
|
if callable(self.selector):
|
|
114
|
-
|
|
114
|
+
if session_state is not None and self._selector_has_session_state_param():
|
|
115
|
+
result = self.selector(step_input, session_state) # type: ignore[call-arg]
|
|
116
|
+
else:
|
|
117
|
+
result = self.selector(step_input)
|
|
115
118
|
|
|
116
119
|
# Handle the result based on its type
|
|
117
120
|
if isinstance(result, Step):
|
|
@@ -124,13 +127,21 @@ class Router:
|
|
|
124
127
|
|
|
125
128
|
return []
|
|
126
129
|
|
|
127
|
-
async def _aroute_steps(self, step_input: StepInput) -> List[Step]: # type: ignore[return-value]
|
|
130
|
+
async def _aroute_steps(self, step_input: StepInput, session_state: Optional[Dict[str, Any]] = None) -> List[Step]: # type: ignore[return-value]
|
|
128
131
|
"""Async version of step routing"""
|
|
129
132
|
if callable(self.selector):
|
|
133
|
+
has_session_state = session_state is not None and self._selector_has_session_state_param()
|
|
134
|
+
|
|
130
135
|
if inspect.iscoroutinefunction(self.selector):
|
|
131
|
-
|
|
136
|
+
if has_session_state:
|
|
137
|
+
result = await self.selector(step_input, session_state) # type: ignore[call-arg]
|
|
138
|
+
else:
|
|
139
|
+
result = await self.selector(step_input)
|
|
132
140
|
else:
|
|
133
|
-
|
|
141
|
+
if has_session_state:
|
|
142
|
+
result = self.selector(step_input, session_state) # type: ignore[call-arg]
|
|
143
|
+
else:
|
|
144
|
+
result = self.selector(step_input)
|
|
134
145
|
|
|
135
146
|
# Handle the result based on its type
|
|
136
147
|
if isinstance(result, Step):
|
|
@@ -143,6 +154,17 @@ class Router:
|
|
|
143
154
|
|
|
144
155
|
return []
|
|
145
156
|
|
|
157
|
+
def _selector_has_session_state_param(self) -> bool:
|
|
158
|
+
"""Check if the selector function has a session_state parameter"""
|
|
159
|
+
if not callable(self.selector):
|
|
160
|
+
return False
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
sig = inspect.signature(self.selector)
|
|
164
|
+
return "session_state" in sig.parameters
|
|
165
|
+
except Exception:
|
|
166
|
+
return False
|
|
167
|
+
|
|
146
168
|
def execute(
|
|
147
169
|
self,
|
|
148
170
|
step_input: StepInput,
|
|
@@ -163,7 +185,7 @@ class Router:
|
|
|
163
185
|
self._prepare_steps()
|
|
164
186
|
|
|
165
187
|
# Route to appropriate steps
|
|
166
|
-
steps_to_execute = self._route_steps(step_input)
|
|
188
|
+
steps_to_execute = self._route_steps(step_input, session_state)
|
|
167
189
|
log_debug(f"Router {self.name}: Selected {len(steps_to_execute)} steps to execute")
|
|
168
190
|
|
|
169
191
|
if not steps_to_execute:
|
|
@@ -263,7 +285,7 @@ class Router:
|
|
|
263
285
|
router_step_id = str(uuid4())
|
|
264
286
|
|
|
265
287
|
# Route to appropriate steps
|
|
266
|
-
steps_to_execute = self._route_steps(step_input)
|
|
288
|
+
steps_to_execute = self._route_steps(step_input, session_state)
|
|
267
289
|
log_debug(f"Router {self.name}: Selected {len(steps_to_execute)} steps to execute")
|
|
268
290
|
|
|
269
291
|
if stream_intermediate_steps and workflow_run_response:
|
|
@@ -413,7 +435,7 @@ class Router:
|
|
|
413
435
|
self._prepare_steps()
|
|
414
436
|
|
|
415
437
|
# Route to appropriate steps
|
|
416
|
-
steps_to_execute = await self._aroute_steps(step_input)
|
|
438
|
+
steps_to_execute = await self._aroute_steps(step_input, session_state)
|
|
417
439
|
log_debug(f"Router {self.name} selected: {len(steps_to_execute)} steps to execute")
|
|
418
440
|
|
|
419
441
|
if not steps_to_execute:
|
|
@@ -516,7 +538,7 @@ class Router:
|
|
|
516
538
|
router_step_id = str(uuid4())
|
|
517
539
|
|
|
518
540
|
# Route to appropriate steps
|
|
519
|
-
steps_to_execute = await self._aroute_steps(step_input)
|
|
541
|
+
steps_to_execute = await self._aroute_steps(step_input, session_state)
|
|
520
542
|
log_debug(f"Router {self.name} selected: {len(steps_to_execute)} steps to execute")
|
|
521
543
|
|
|
522
544
|
if stream_intermediate_steps and workflow_run_response:
|