agno 2.3.4__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 +184 -45
- agno/culture/manager.py +2 -2
- agno/db/base.py +330 -8
- agno/db/dynamo/dynamo.py +722 -2
- agno/db/dynamo/schemas.py +127 -0
- agno/db/firestore/firestore.py +573 -1
- agno/db/firestore/schemas.py +40 -0
- agno/db/gcs_json/gcs_json_db.py +446 -1
- agno/db/in_memory/in_memory_db.py +143 -1
- agno/db/json/json_db.py +438 -1
- agno/db/mongo/async_mongo.py +522 -0
- agno/db/mongo/mongo.py +523 -1
- agno/db/mongo/schemas.py +29 -0
- agno/db/mysql/mysql.py +536 -3
- agno/db/mysql/schemas.py +38 -0
- agno/db/postgres/async_postgres.py +553 -15
- agno/db/postgres/postgres.py +544 -5
- agno/db/postgres/schemas.py +38 -0
- agno/db/redis/redis.py +468 -1
- agno/db/redis/schemas.py +32 -0
- agno/db/singlestore/schemas.py +38 -0
- agno/db/singlestore/singlestore.py +523 -1
- agno/db/sqlite/async_sqlite.py +549 -10
- agno/db/sqlite/schemas.py +38 -0
- agno/db/sqlite/sqlite.py +540 -9
- agno/db/sqlite/utils.py +6 -8
- agno/db/surrealdb/models.py +25 -0
- agno/db/surrealdb/surrealdb.py +548 -1
- agno/eval/accuracy.py +18 -8
- agno/eval/performance.py +10 -4
- agno/eval/reliability.py +22 -13
- agno/exceptions.py +11 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/client.py +1 -1
- agno/knowledge/chunking/semantic.py +2 -2
- agno/models/aimlapi/aimlapi.py +2 -3
- agno/models/anthropic/claude.py +18 -13
- agno/models/aws/bedrock.py +3 -4
- agno/models/aws/claude.py +5 -1
- agno/models/azure/ai_foundry.py +2 -2
- agno/models/azure/openai_chat.py +8 -0
- agno/models/cerebras/cerebras.py +62 -11
- agno/models/cerebras/cerebras_openai.py +2 -3
- agno/models/cohere/chat.py +1 -5
- agno/models/cometapi/cometapi.py +2 -3
- agno/models/dashscope/dashscope.py +2 -3
- agno/models/deepinfra/deepinfra.py +2 -3
- agno/models/deepseek/deepseek.py +2 -3
- agno/models/fireworks/fireworks.py +2 -3
- agno/models/google/gemini.py +9 -7
- agno/models/groq/groq.py +2 -3
- agno/models/huggingface/huggingface.py +1 -5
- agno/models/ibm/watsonx.py +1 -5
- agno/models/internlm/internlm.py +2 -3
- agno/models/langdb/langdb.py +6 -4
- agno/models/litellm/chat.py +2 -2
- agno/models/litellm/litellm_openai.py +2 -3
- agno/models/meta/llama.py +1 -5
- agno/models/meta/llama_openai.py +4 -5
- agno/models/mistral/mistral.py +1 -5
- agno/models/nebius/nebius.py +2 -3
- agno/models/nvidia/nvidia.py +4 -5
- agno/models/openai/chat.py +14 -3
- agno/models/openai/responses.py +14 -3
- agno/models/openrouter/openrouter.py +4 -5
- agno/models/perplexity/perplexity.py +2 -3
- agno/models/portkey/portkey.py +7 -6
- agno/models/requesty/requesty.py +4 -5
- agno/models/response.py +2 -1
- agno/models/sambanova/sambanova.py +4 -5
- agno/models/siliconflow/siliconflow.py +3 -4
- agno/models/together/together.py +4 -5
- agno/models/vercel/v0.py +4 -5
- agno/models/vllm/vllm.py +19 -14
- agno/models/xai/xai.py +4 -5
- agno/os/app.py +104 -0
- agno/os/config.py +13 -0
- agno/os/interfaces/whatsapp/router.py +0 -1
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/mcp.py +1 -0
- agno/os/router.py +31 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +499 -0
- agno/os/schema.py +12 -2
- agno/os/utils.py +57 -0
- agno/run/agent.py +1 -0
- agno/run/base.py +17 -0
- agno/run/team.py +4 -0
- agno/table.py +10 -0
- agno/team/team.py +221 -69
- agno/tools/function.py +10 -8
- agno/tools/google_drive.py +4 -3
- agno/tools/nano_banana.py +1 -1
- agno/tools/spotify.py +922 -0
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +157 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +111 -0
- agno/utils/agent.py +6 -6
- agno/utils/hooks.py +56 -1
- agno/utils/mcp.py +1 -1
- agno/vectordb/qdrant/qdrant.py +22 -22
- agno/workflow/condition.py +8 -0
- agno/workflow/loop.py +8 -0
- agno/workflow/parallel.py +8 -0
- agno/workflow/router.py +8 -0
- agno/workflow/step.py +20 -0
- agno/workflow/steps.py +8 -0
- agno/workflow/workflow.py +88 -19
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/METADATA +38 -33
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/RECORD +116 -105
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/WHEEL +0 -0
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.4.dist-info → agno-2.3.6.dist-info}/top_level.txt +0 -0
agno/agent/agent.py
CHANGED
|
@@ -83,8 +83,8 @@ from agno.utils.agent import (
|
|
|
83
83
|
aget_session_state_util,
|
|
84
84
|
aset_session_name_util,
|
|
85
85
|
aupdate_session_state_util,
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
await_for_open_threads,
|
|
87
|
+
await_for_thread_tasks_stream,
|
|
88
88
|
collect_joint_audios,
|
|
89
89
|
collect_joint_files,
|
|
90
90
|
collect_joint_images,
|
|
@@ -103,8 +103,8 @@ from agno.utils.agent import (
|
|
|
103
103
|
store_media_util,
|
|
104
104
|
update_session_state_util,
|
|
105
105
|
validate_media_object_id,
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
wait_for_open_threads,
|
|
107
|
+
wait_for_thread_tasks_stream,
|
|
108
108
|
)
|
|
109
109
|
from agno.utils.common import is_typed_dict, validate_typed_dict
|
|
110
110
|
from agno.utils.events import (
|
|
@@ -131,7 +131,7 @@ from agno.utils.events import (
|
|
|
131
131
|
create_tool_call_started_event,
|
|
132
132
|
handle_event,
|
|
133
133
|
)
|
|
134
|
-
from agno.utils.hooks import filter_hook_args, normalize_hooks
|
|
134
|
+
from agno.utils.hooks import copy_args_for_background, filter_hook_args, normalize_hooks, should_run_hook_in_background
|
|
135
135
|
from agno.utils.knowledge import get_agentic_or_user_search_filters
|
|
136
136
|
from agno.utils.log import (
|
|
137
137
|
log_debug,
|
|
@@ -273,6 +273,8 @@ class Agent:
|
|
|
273
273
|
pre_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None
|
|
274
274
|
# Functions called after output is generated but before the response is returned
|
|
275
275
|
post_hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail]]] = None
|
|
276
|
+
# If True, run hooks as FastAPI background tasks (non-blocking). Set by AgentOS.
|
|
277
|
+
_run_hooks_in_background: Optional[bool] = None
|
|
276
278
|
|
|
277
279
|
# --- Agent Reasoning ---
|
|
278
280
|
# Enable reasoning by working through the problem step by step.
|
|
@@ -594,7 +596,6 @@ class Agent:
|
|
|
594
596
|
self.tool_choice = tool_choice
|
|
595
597
|
self.tool_hooks = tool_hooks
|
|
596
598
|
|
|
597
|
-
# Initialize hooks with backward compatibility
|
|
598
599
|
self.pre_hooks = pre_hooks
|
|
599
600
|
self.post_hooks = post_hooks
|
|
600
601
|
|
|
@@ -710,9 +711,13 @@ class Agent:
|
|
|
710
711
|
self.id = generate_id_from_name(self.name)
|
|
711
712
|
|
|
712
713
|
def _set_debug(self, debug_mode: Optional[bool] = None) -> None:
|
|
714
|
+
# Get the debug level from the environment variable or the default debug level
|
|
715
|
+
debug_level: Literal[1, 2] = (
|
|
716
|
+
cast(Literal[1, 2], int(env)) if (env := getenv("AGNO_DEBUG_LEVEL")) in ("1", "2") else self.debug_level
|
|
717
|
+
)
|
|
713
718
|
# If the default debug mode is set, or passed on run, or via environment variable, set the debug mode to True
|
|
714
719
|
if self.debug_mode or debug_mode or getenv("AGNO_DEBUG", "false").lower() == "true":
|
|
715
|
-
set_log_level_to_debug(level=
|
|
720
|
+
set_log_level_to_debug(level=debug_level)
|
|
716
721
|
else:
|
|
717
722
|
set_log_level_to_info()
|
|
718
723
|
|
|
@@ -967,6 +972,7 @@ class Agent:
|
|
|
967
972
|
add_session_state_to_context: Optional[bool] = None,
|
|
968
973
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
969
974
|
debug_mode: Optional[bool] = None,
|
|
975
|
+
background_tasks: Optional[Any] = None,
|
|
970
976
|
**kwargs: Any,
|
|
971
977
|
) -> RunOutput:
|
|
972
978
|
"""Run the Agent and return the RunOutput.
|
|
@@ -987,9 +993,6 @@ class Agent:
|
|
|
987
993
|
13. Cleanup and store the run response and session
|
|
988
994
|
"""
|
|
989
995
|
|
|
990
|
-
# Register run for cancellation tracking
|
|
991
|
-
register_run(run_response.run_id) # type: ignore
|
|
992
|
-
|
|
993
996
|
# 1. Execute pre-hooks
|
|
994
997
|
run_input = cast(RunInput, run_response.input)
|
|
995
998
|
self.model = cast(Model, self.model)
|
|
@@ -1003,6 +1006,7 @@ class Agent:
|
|
|
1003
1006
|
session=session,
|
|
1004
1007
|
user_id=user_id,
|
|
1005
1008
|
debug_mode=debug_mode,
|
|
1009
|
+
background_tasks=background_tasks,
|
|
1006
1010
|
**kwargs,
|
|
1007
1011
|
)
|
|
1008
1012
|
# Consume the generator without yielding
|
|
@@ -1105,9 +1109,7 @@ class Agent:
|
|
|
1105
1109
|
|
|
1106
1110
|
# We should break out of the run function
|
|
1107
1111
|
if any(tool_call.is_paused for tool_call in run_response.tools or []):
|
|
1108
|
-
|
|
1109
|
-
memory_future=memory_future, cultural_knowledge_future=cultural_knowledge_future
|
|
1110
|
-
)
|
|
1112
|
+
wait_for_open_threads(memory_future=memory_future, cultural_knowledge_future=cultural_knowledge_future)
|
|
1111
1113
|
|
|
1112
1114
|
return self._handle_agent_run_paused(run_response=run_response, session=session, user_id=user_id)
|
|
1113
1115
|
|
|
@@ -1127,6 +1129,7 @@ class Agent:
|
|
|
1127
1129
|
session=session,
|
|
1128
1130
|
user_id=user_id,
|
|
1129
1131
|
debug_mode=debug_mode,
|
|
1132
|
+
background_tasks=background_tasks,
|
|
1130
1133
|
**kwargs,
|
|
1131
1134
|
)
|
|
1132
1135
|
deque(post_hook_iterator, maxlen=0)
|
|
@@ -1135,7 +1138,7 @@ class Agent:
|
|
|
1135
1138
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
1136
1139
|
|
|
1137
1140
|
# 11. Wait for background memory creation and cultural knowledge creation
|
|
1138
|
-
|
|
1141
|
+
wait_for_open_threads(memory_future=memory_future, cultural_knowledge_future=cultural_knowledge_future)
|
|
1139
1142
|
|
|
1140
1143
|
# 12. Create session summary
|
|
1141
1144
|
if self.session_summary_manager is not None:
|
|
@@ -1188,6 +1191,7 @@ class Agent:
|
|
|
1188
1191
|
stream_events: bool = False,
|
|
1189
1192
|
yield_run_output: Optional[bool] = None,
|
|
1190
1193
|
debug_mode: Optional[bool] = None,
|
|
1194
|
+
background_tasks: Optional[Any] = None,
|
|
1191
1195
|
**kwargs: Any,
|
|
1192
1196
|
) -> Iterator[Union[RunOutputEvent, RunOutput]]:
|
|
1193
1197
|
"""Run the Agent and yield the RunOutput.
|
|
@@ -1205,9 +1209,6 @@ class Agent:
|
|
|
1205
1209
|
10. Cleanup and store the run response and session
|
|
1206
1210
|
"""
|
|
1207
1211
|
|
|
1208
|
-
# Register run for cancellation tracking
|
|
1209
|
-
register_run(run_response.run_id) # type: ignore
|
|
1210
|
-
|
|
1211
1212
|
# 1. Execute pre-hooks
|
|
1212
1213
|
run_input = cast(RunInput, run_response.input)
|
|
1213
1214
|
self.model = cast(Model, self.model)
|
|
@@ -1222,6 +1223,7 @@ class Agent:
|
|
|
1222
1223
|
user_id=user_id,
|
|
1223
1224
|
debug_mode=debug_mode,
|
|
1224
1225
|
stream_events=stream_events,
|
|
1226
|
+
background_tasks=background_tasks,
|
|
1225
1227
|
**kwargs,
|
|
1226
1228
|
)
|
|
1227
1229
|
for event in pre_hook_iterator:
|
|
@@ -1365,7 +1367,7 @@ class Agent:
|
|
|
1365
1367
|
|
|
1366
1368
|
# We should break out of the run function
|
|
1367
1369
|
if any(tool_call.is_paused for tool_call in run_response.tools or []):
|
|
1368
|
-
yield from
|
|
1370
|
+
yield from wait_for_thread_tasks_stream(
|
|
1369
1371
|
memory_future=memory_future,
|
|
1370
1372
|
cultural_knowledge_future=cultural_knowledge_future,
|
|
1371
1373
|
stream_events=stream_events,
|
|
@@ -1399,11 +1401,12 @@ class Agent:
|
|
|
1399
1401
|
user_id=user_id,
|
|
1400
1402
|
debug_mode=debug_mode,
|
|
1401
1403
|
stream_events=stream_events,
|
|
1404
|
+
background_tasks=background_tasks,
|
|
1402
1405
|
**kwargs,
|
|
1403
1406
|
)
|
|
1404
1407
|
|
|
1405
1408
|
# 8. Wait for background memory creation and cultural knowledge creation
|
|
1406
|
-
yield from
|
|
1409
|
+
yield from wait_for_thread_tasks_stream(
|
|
1407
1410
|
memory_future=memory_future,
|
|
1408
1411
|
cultural_knowledge_future=cultural_knowledge_future,
|
|
1409
1412
|
stream_events=stream_events,
|
|
@@ -1585,6 +1588,10 @@ class Agent:
|
|
|
1585
1588
|
"`run` method is not supported with an async database. Please use `arun` method instead."
|
|
1586
1589
|
)
|
|
1587
1590
|
|
|
1591
|
+
# Create a run_id for this specific run and register immediately for cancellation tracking
|
|
1592
|
+
run_id = str(uuid4())
|
|
1593
|
+
register_run(run_id)
|
|
1594
|
+
|
|
1588
1595
|
if (add_history_to_context or self.add_history_to_context) and not self.db and not self.team_id:
|
|
1589
1596
|
log_warning(
|
|
1590
1597
|
"add_history_to_context is True, but no database has been assigned to the agent. History will not be added to the context."
|
|
@@ -1597,8 +1604,11 @@ class Agent:
|
|
|
1597
1604
|
stacklevel=2,
|
|
1598
1605
|
)
|
|
1599
1606
|
|
|
1600
|
-
|
|
1601
|
-
|
|
1607
|
+
background_tasks = kwargs.pop("background_tasks", None)
|
|
1608
|
+
if background_tasks is not None:
|
|
1609
|
+
from fastapi import BackgroundTasks
|
|
1610
|
+
|
|
1611
|
+
background_tasks: BackgroundTasks = background_tasks # type: ignore
|
|
1602
1612
|
|
|
1603
1613
|
# Validate input against input_schema if provided
|
|
1604
1614
|
validated_input = self._validate_input(input)
|
|
@@ -1635,7 +1645,10 @@ class Agent:
|
|
|
1635
1645
|
|
|
1636
1646
|
# Initialize session state
|
|
1637
1647
|
session_state = self._initialize_session_state(
|
|
1638
|
-
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,
|
|
1639
1652
|
)
|
|
1640
1653
|
# Update session state from DB
|
|
1641
1654
|
session_state = self._load_session_state(session=agent_session, session_state=session_state)
|
|
@@ -1750,6 +1763,7 @@ class Agent:
|
|
|
1750
1763
|
stream_events=stream_events,
|
|
1751
1764
|
yield_run_output=yield_run_output,
|
|
1752
1765
|
debug_mode=debug_mode,
|
|
1766
|
+
background_tasks=background_tasks,
|
|
1753
1767
|
**kwargs,
|
|
1754
1768
|
)
|
|
1755
1769
|
return response_iterator
|
|
@@ -1764,6 +1778,7 @@ class Agent:
|
|
|
1764
1778
|
add_session_state_to_context=add_session_state,
|
|
1765
1779
|
response_format=response_format,
|
|
1766
1780
|
debug_mode=debug_mode,
|
|
1781
|
+
background_tasks=background_tasks,
|
|
1767
1782
|
**kwargs,
|
|
1768
1783
|
)
|
|
1769
1784
|
return response
|
|
@@ -1822,6 +1837,7 @@ class Agent:
|
|
|
1822
1837
|
add_session_state_to_context: Optional[bool] = None,
|
|
1823
1838
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
1824
1839
|
debug_mode: Optional[bool] = None,
|
|
1840
|
+
background_tasks: Optional[Any] = None,
|
|
1825
1841
|
**kwargs: Any,
|
|
1826
1842
|
) -> RunOutput:
|
|
1827
1843
|
"""Run the Agent and return the RunOutput.
|
|
@@ -1846,9 +1862,6 @@ class Agent:
|
|
|
1846
1862
|
"""
|
|
1847
1863
|
log_debug(f"Agent Run Start: {run_response.run_id}", center=True)
|
|
1848
1864
|
|
|
1849
|
-
# Register run for cancellation tracking
|
|
1850
|
-
register_run(run_response.run_id) # type: ignore
|
|
1851
|
-
|
|
1852
1865
|
# 1. Read or create session. Reads from the database if provided.
|
|
1853
1866
|
agent_session = await self._aread_or_create_session(session_id=session_id, user_id=user_id)
|
|
1854
1867
|
|
|
@@ -1856,7 +1869,7 @@ class Agent:
|
|
|
1856
1869
|
self._update_metadata(session=agent_session)
|
|
1857
1870
|
# Initialize session state
|
|
1858
1871
|
run_context.session_state = self._initialize_session_state(
|
|
1859
|
-
session_state=run_context.session_state
|
|
1872
|
+
session_state=run_context.session_state if run_context.session_state is not None else {},
|
|
1860
1873
|
user_id=user_id,
|
|
1861
1874
|
session_id=session_id,
|
|
1862
1875
|
run_id=run_response.run_id,
|
|
@@ -1884,6 +1897,7 @@ class Agent:
|
|
|
1884
1897
|
session=agent_session,
|
|
1885
1898
|
user_id=user_id,
|
|
1886
1899
|
debug_mode=debug_mode,
|
|
1900
|
+
background_tasks=background_tasks,
|
|
1887
1901
|
**kwargs,
|
|
1888
1902
|
)
|
|
1889
1903
|
# Consume the async iterator without yielding
|
|
@@ -1986,9 +2000,7 @@ class Agent:
|
|
|
1986
2000
|
|
|
1987
2001
|
# We should break out of the run function
|
|
1988
2002
|
if any(tool_call.is_paused for tool_call in run_response.tools or []):
|
|
1989
|
-
await
|
|
1990
|
-
memory_task=memory_task, cultural_knowledge_task=cultural_knowledge_task
|
|
1991
|
-
)
|
|
2003
|
+
await await_for_open_threads(memory_task=memory_task, cultural_knowledge_task=cultural_knowledge_task)
|
|
1992
2004
|
return await self._ahandle_agent_run_paused(
|
|
1993
2005
|
run_response=run_response, session=agent_session, user_id=user_id
|
|
1994
2006
|
)
|
|
@@ -2009,6 +2021,7 @@ class Agent:
|
|
|
2009
2021
|
session=agent_session,
|
|
2010
2022
|
user_id=user_id,
|
|
2011
2023
|
debug_mode=debug_mode,
|
|
2024
|
+
background_tasks=background_tasks,
|
|
2012
2025
|
**kwargs,
|
|
2013
2026
|
):
|
|
2014
2027
|
pass
|
|
@@ -2017,7 +2030,7 @@ class Agent:
|
|
|
2017
2030
|
raise_if_cancelled(run_response.run_id) # type: ignore
|
|
2018
2031
|
|
|
2019
2032
|
# 14. Wait for background memory creation
|
|
2020
|
-
await
|
|
2033
|
+
await await_for_open_threads(memory_task=memory_task, cultural_knowledge_task=cultural_knowledge_task)
|
|
2021
2034
|
|
|
2022
2035
|
# 15. Create session summary
|
|
2023
2036
|
if self.session_summary_manager is not None:
|
|
@@ -2096,6 +2109,7 @@ class Agent:
|
|
|
2096
2109
|
stream_events: bool = False,
|
|
2097
2110
|
yield_run_output: Optional[bool] = None,
|
|
2098
2111
|
debug_mode: Optional[bool] = None,
|
|
2112
|
+
background_tasks: Optional[Any] = None,
|
|
2099
2113
|
**kwargs: Any,
|
|
2100
2114
|
) -> AsyncIterator[Union[RunOutputEvent, RunOutput]]:
|
|
2101
2115
|
"""Run the Agent and yield the RunOutput.
|
|
@@ -2133,7 +2147,7 @@ class Agent:
|
|
|
2133
2147
|
self._update_metadata(session=agent_session)
|
|
2134
2148
|
# Initialize session state
|
|
2135
2149
|
run_context.session_state = self._initialize_session_state(
|
|
2136
|
-
session_state=run_context.session_state
|
|
2150
|
+
session_state=run_context.session_state if run_context.session_state is not None else {},
|
|
2137
2151
|
user_id=user_id,
|
|
2138
2152
|
session_id=session_id,
|
|
2139
2153
|
run_id=run_response.run_id,
|
|
@@ -2162,6 +2176,7 @@ class Agent:
|
|
|
2162
2176
|
user_id=user_id,
|
|
2163
2177
|
debug_mode=debug_mode,
|
|
2164
2178
|
stream_events=stream_events,
|
|
2179
|
+
background_tasks=background_tasks,
|
|
2165
2180
|
**kwargs,
|
|
2166
2181
|
)
|
|
2167
2182
|
async for event in pre_hook_iterator:
|
|
@@ -2220,9 +2235,6 @@ class Agent:
|
|
|
2220
2235
|
log_debug("Starting cultural knowledge creation in background task.")
|
|
2221
2236
|
cultural_knowledge_task = create_task(self._acreate_cultural_knowledge(run_messages=run_messages))
|
|
2222
2237
|
|
|
2223
|
-
# Register run for cancellation tracking
|
|
2224
|
-
register_run(run_response.run_id) # type: ignore
|
|
2225
|
-
|
|
2226
2238
|
try:
|
|
2227
2239
|
# 8. Reason about the task if reasoning is enabled
|
|
2228
2240
|
async for item in self._ahandle_reasoning_stream(
|
|
@@ -2304,7 +2316,7 @@ class Agent:
|
|
|
2304
2316
|
|
|
2305
2317
|
# Break out of the run function if a tool call is paused
|
|
2306
2318
|
if any(tool_call.is_paused for tool_call in run_response.tools or []):
|
|
2307
|
-
async for item in
|
|
2319
|
+
async for item in await_for_thread_tasks_stream(
|
|
2308
2320
|
memory_task=memory_task,
|
|
2309
2321
|
cultural_knowledge_task=cultural_knowledge_task,
|
|
2310
2322
|
stream_events=stream_events,
|
|
@@ -2328,12 +2340,13 @@ class Agent:
|
|
|
2328
2340
|
user_id=user_id,
|
|
2329
2341
|
debug_mode=debug_mode,
|
|
2330
2342
|
stream_events=stream_events,
|
|
2343
|
+
background_tasks=background_tasks,
|
|
2331
2344
|
**kwargs,
|
|
2332
2345
|
):
|
|
2333
2346
|
yield event
|
|
2334
2347
|
|
|
2335
2348
|
# 11. Wait for background memory creation
|
|
2336
|
-
async for item in
|
|
2349
|
+
async for item in await_for_thread_tasks_stream(
|
|
2337
2350
|
memory_task=memory_task,
|
|
2338
2351
|
cultural_knowledge_task=cultural_knowledge_task,
|
|
2339
2352
|
stream_events=stream_events,
|
|
@@ -2537,6 +2550,10 @@ class Agent:
|
|
|
2537
2550
|
) -> Union[RunOutput, AsyncIterator[RunOutputEvent]]:
|
|
2538
2551
|
"""Async Run the Agent and return the response."""
|
|
2539
2552
|
|
|
2553
|
+
# Create a run_id for this specific run and register immediately for cancellation tracking
|
|
2554
|
+
run_id = str(uuid4())
|
|
2555
|
+
register_run(run_id)
|
|
2556
|
+
|
|
2540
2557
|
if (add_history_to_context or self.add_history_to_context) and not self.db and not self.team_id:
|
|
2541
2558
|
log_warning(
|
|
2542
2559
|
"add_history_to_context is True, but no database has been assigned to the agent. History will not be added to the context."
|
|
@@ -2549,8 +2566,11 @@ class Agent:
|
|
|
2549
2566
|
stacklevel=2,
|
|
2550
2567
|
)
|
|
2551
2568
|
|
|
2552
|
-
|
|
2553
|
-
|
|
2569
|
+
background_tasks = kwargs.pop("background_tasks", None)
|
|
2570
|
+
if background_tasks is not None:
|
|
2571
|
+
from fastapi import BackgroundTasks
|
|
2572
|
+
|
|
2573
|
+
background_tasks: BackgroundTasks = background_tasks # type: ignore
|
|
2554
2574
|
|
|
2555
2575
|
# 2. Validate input against input_schema if provided
|
|
2556
2576
|
validated_input = self._validate_input(input)
|
|
@@ -2695,6 +2715,7 @@ class Agent:
|
|
|
2695
2715
|
add_dependencies_to_context=add_dependencies,
|
|
2696
2716
|
add_session_state_to_context=add_session_state,
|
|
2697
2717
|
debug_mode=debug_mode,
|
|
2718
|
+
background_tasks=background_tasks,
|
|
2698
2719
|
**kwargs,
|
|
2699
2720
|
) # type: ignore[assignment]
|
|
2700
2721
|
else:
|
|
@@ -2708,6 +2729,7 @@ class Agent:
|
|
|
2708
2729
|
add_dependencies_to_context=add_dependencies,
|
|
2709
2730
|
add_session_state_to_context=add_session_state,
|
|
2710
2731
|
debug_mode=debug_mode,
|
|
2732
|
+
background_tasks=background_tasks,
|
|
2711
2733
|
**kwargs,
|
|
2712
2734
|
)
|
|
2713
2735
|
|
|
@@ -2839,6 +2861,12 @@ class Agent:
|
|
|
2839
2861
|
if self._has_async_db():
|
|
2840
2862
|
raise Exception("continue_run() is not supported with an async DB. Please use acontinue_arun() instead.")
|
|
2841
2863
|
|
|
2864
|
+
background_tasks = kwargs.pop("background_tasks", None)
|
|
2865
|
+
if background_tasks is not None:
|
|
2866
|
+
from fastapi import BackgroundTasks
|
|
2867
|
+
|
|
2868
|
+
background_tasks: BackgroundTasks = background_tasks # type: ignore
|
|
2869
|
+
|
|
2842
2870
|
session_id = run_response.session_id if run_response else session_id
|
|
2843
2871
|
run_id: str = run_response.run_id if run_response else run_id # type: ignore
|
|
2844
2872
|
|
|
@@ -2982,6 +3010,7 @@ class Agent:
|
|
|
2982
3010
|
response_format=response_format,
|
|
2983
3011
|
stream_events=stream_events,
|
|
2984
3012
|
debug_mode=debug_mode,
|
|
3013
|
+
background_tasks=background_tasks,
|
|
2985
3014
|
**kwargs,
|
|
2986
3015
|
)
|
|
2987
3016
|
return response_iterator
|
|
@@ -2995,6 +3024,7 @@ class Agent:
|
|
|
2995
3024
|
session=agent_session,
|
|
2996
3025
|
response_format=response_format,
|
|
2997
3026
|
debug_mode=debug_mode,
|
|
3027
|
+
background_tasks=background_tasks,
|
|
2998
3028
|
**kwargs,
|
|
2999
3029
|
)
|
|
3000
3030
|
return response
|
|
@@ -3045,6 +3075,7 @@ class Agent:
|
|
|
3045
3075
|
user_id: Optional[str] = None,
|
|
3046
3076
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
3047
3077
|
debug_mode: Optional[bool] = None,
|
|
3078
|
+
background_tasks: Optional[Any] = None,
|
|
3048
3079
|
**kwargs,
|
|
3049
3080
|
) -> RunOutput:
|
|
3050
3081
|
"""Continue a previous run.
|
|
@@ -3109,6 +3140,7 @@ class Agent:
|
|
|
3109
3140
|
session=session,
|
|
3110
3141
|
user_id=user_id,
|
|
3111
3142
|
debug_mode=debug_mode,
|
|
3143
|
+
background_tasks=background_tasks,
|
|
3112
3144
|
**kwargs,
|
|
3113
3145
|
)
|
|
3114
3146
|
deque(post_hook_iterator, maxlen=0)
|
|
@@ -3164,6 +3196,7 @@ class Agent:
|
|
|
3164
3196
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
3165
3197
|
stream_events: bool = False,
|
|
3166
3198
|
debug_mode: Optional[bool] = None,
|
|
3199
|
+
background_tasks: Optional[Any] = None,
|
|
3167
3200
|
**kwargs,
|
|
3168
3201
|
) -> Iterator[RunOutputEvent]:
|
|
3169
3202
|
"""Continue a previous run.
|
|
@@ -3240,6 +3273,7 @@ class Agent:
|
|
|
3240
3273
|
user_id=user_id,
|
|
3241
3274
|
debug_mode=debug_mode,
|
|
3242
3275
|
stream_events=stream_events,
|
|
3276
|
+
background_tasks=background_tasks,
|
|
3243
3277
|
**kwargs,
|
|
3244
3278
|
)
|
|
3245
3279
|
|
|
@@ -3341,6 +3375,7 @@ class Agent:
|
|
|
3341
3375
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
3342
3376
|
metadata: Optional[Dict[str, Any]] = None,
|
|
3343
3377
|
debug_mode: Optional[bool] = None,
|
|
3378
|
+
**kwargs: Any,
|
|
3344
3379
|
) -> RunOutput: ...
|
|
3345
3380
|
|
|
3346
3381
|
@overload
|
|
@@ -3360,6 +3395,7 @@ class Agent:
|
|
|
3360
3395
|
dependencies: Optional[Dict[str, Any]] = None,
|
|
3361
3396
|
metadata: Optional[Dict[str, Any]] = None,
|
|
3362
3397
|
debug_mode: Optional[bool] = None,
|
|
3398
|
+
**kwargs: Any,
|
|
3363
3399
|
) -> AsyncIterator[Union[RunOutputEvent, RunOutput]]: ...
|
|
3364
3400
|
|
|
3365
3401
|
def acontinue_run( # type: ignore
|
|
@@ -3407,6 +3443,12 @@ class Agent:
|
|
|
3407
3443
|
if run_response is None and (run_id is not None and (session_id is None and self.session_id is None)):
|
|
3408
3444
|
raise ValueError("Session ID is required to continue a run from a run_id.")
|
|
3409
3445
|
|
|
3446
|
+
background_tasks = kwargs.pop("background_tasks", None)
|
|
3447
|
+
if background_tasks is not None:
|
|
3448
|
+
from fastapi import BackgroundTasks
|
|
3449
|
+
|
|
3450
|
+
background_tasks: BackgroundTasks = background_tasks # type: ignore
|
|
3451
|
+
|
|
3410
3452
|
session_id, user_id = self._initialize_session(
|
|
3411
3453
|
session_id=session_id,
|
|
3412
3454
|
user_id=user_id,
|
|
@@ -3491,6 +3533,7 @@ class Agent:
|
|
|
3491
3533
|
stream_events=stream_events,
|
|
3492
3534
|
yield_run_output=yield_run_output,
|
|
3493
3535
|
debug_mode=debug_mode,
|
|
3536
|
+
background_tasks=background_tasks,
|
|
3494
3537
|
**kwargs,
|
|
3495
3538
|
)
|
|
3496
3539
|
else:
|
|
@@ -3503,6 +3546,7 @@ class Agent:
|
|
|
3503
3546
|
user_id=user_id,
|
|
3504
3547
|
response_format=response_format,
|
|
3505
3548
|
debug_mode=debug_mode,
|
|
3549
|
+
background_tasks=background_tasks,
|
|
3506
3550
|
**kwargs,
|
|
3507
3551
|
)
|
|
3508
3552
|
except ModelProviderError as e:
|
|
@@ -3552,6 +3596,7 @@ class Agent:
|
|
|
3552
3596
|
user_id: Optional[str] = None,
|
|
3553
3597
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
3554
3598
|
debug_mode: Optional[bool] = None,
|
|
3599
|
+
background_tasks: Optional[Any] = None,
|
|
3555
3600
|
**kwargs,
|
|
3556
3601
|
) -> RunOutput:
|
|
3557
3602
|
"""Continue a previous run.
|
|
@@ -3694,6 +3739,7 @@ class Agent:
|
|
|
3694
3739
|
session=agent_session,
|
|
3695
3740
|
user_id=user_id,
|
|
3696
3741
|
debug_mode=debug_mode,
|
|
3742
|
+
background_tasks=background_tasks,
|
|
3697
3743
|
**kwargs,
|
|
3698
3744
|
):
|
|
3699
3745
|
pass
|
|
@@ -3763,6 +3809,7 @@ class Agent:
|
|
|
3763
3809
|
stream_events: bool = False,
|
|
3764
3810
|
yield_run_output: bool = False,
|
|
3765
3811
|
debug_mode: Optional[bool] = None,
|
|
3812
|
+
background_tasks: Optional[Any] = None,
|
|
3766
3813
|
**kwargs,
|
|
3767
3814
|
) -> AsyncIterator[Union[RunOutputEvent, RunOutput]]:
|
|
3768
3815
|
"""Continue a previous run.
|
|
@@ -3948,6 +3995,7 @@ class Agent:
|
|
|
3948
3995
|
user_id=user_id,
|
|
3949
3996
|
debug_mode=debug_mode,
|
|
3950
3997
|
stream_events=stream_events,
|
|
3998
|
+
background_tasks=background_tasks,
|
|
3951
3999
|
**kwargs,
|
|
3952
4000
|
):
|
|
3953
4001
|
yield event
|
|
@@ -4049,13 +4097,13 @@ class Agent:
|
|
|
4049
4097
|
user_id: Optional[str] = None,
|
|
4050
4098
|
debug_mode: Optional[bool] = None,
|
|
4051
4099
|
stream_events: bool = False,
|
|
4100
|
+
background_tasks: Optional[Any] = None,
|
|
4052
4101
|
**kwargs: Any,
|
|
4053
4102
|
) -> Iterator[RunOutputEvent]:
|
|
4054
4103
|
"""Execute multiple pre-hook functions in succession."""
|
|
4055
4104
|
if hooks is None:
|
|
4056
4105
|
return
|
|
4057
|
-
|
|
4058
|
-
# Prepare all possible arguments once
|
|
4106
|
+
# Prepare arguments for this hook
|
|
4059
4107
|
all_args = {
|
|
4060
4108
|
"run_input": run_input,
|
|
4061
4109
|
"run_context": run_context,
|
|
@@ -4067,9 +4115,32 @@ class Agent:
|
|
|
4067
4115
|
"user_id": user_id,
|
|
4068
4116
|
"debug_mode": debug_mode or self.debug_mode,
|
|
4069
4117
|
}
|
|
4118
|
+
|
|
4119
|
+
# Check if background_tasks is available and ALL hooks should run in background
|
|
4120
|
+
# Note: Pre-hooks running in background may not be able to modify run_input
|
|
4121
|
+
if self._run_hooks_in_background is True and background_tasks is not None:
|
|
4122
|
+
# Schedule ALL pre_hooks as background tasks
|
|
4123
|
+
# Copy args to prevent race conditions
|
|
4124
|
+
bg_args = copy_args_for_background(all_args)
|
|
4125
|
+
for hook in hooks:
|
|
4126
|
+
# Filter arguments to only include those that the hook accepts
|
|
4127
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
4128
|
+
|
|
4129
|
+
# Add to background tasks
|
|
4130
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
4131
|
+
return
|
|
4132
|
+
|
|
4070
4133
|
all_args.update(kwargs)
|
|
4071
4134
|
|
|
4072
4135
|
for i, hook in enumerate(hooks):
|
|
4136
|
+
# Check if this specific hook should run in background (via @hook decorator)
|
|
4137
|
+
if should_run_hook_in_background(hook) and background_tasks is not None:
|
|
4138
|
+
# Copy args to prevent race conditions
|
|
4139
|
+
bg_args = copy_args_for_background(all_args)
|
|
4140
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
4141
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
4142
|
+
continue
|
|
4143
|
+
|
|
4073
4144
|
if stream_events:
|
|
4074
4145
|
yield handle_event( # type: ignore
|
|
4075
4146
|
run_response=run_response,
|
|
@@ -4121,13 +4192,13 @@ class Agent:
|
|
|
4121
4192
|
user_id: Optional[str] = None,
|
|
4122
4193
|
debug_mode: Optional[bool] = None,
|
|
4123
4194
|
stream_events: bool = False,
|
|
4195
|
+
background_tasks: Optional[Any] = None,
|
|
4124
4196
|
**kwargs: Any,
|
|
4125
4197
|
) -> AsyncIterator[RunOutputEvent]:
|
|
4126
4198
|
"""Execute multiple pre-hook functions in succession (async version)."""
|
|
4127
4199
|
if hooks is None:
|
|
4128
4200
|
return
|
|
4129
|
-
|
|
4130
|
-
# Prepare all possible arguments once
|
|
4201
|
+
# Prepare arguments for this hook
|
|
4131
4202
|
all_args = {
|
|
4132
4203
|
"run_input": run_input,
|
|
4133
4204
|
"agent": self,
|
|
@@ -4139,9 +4210,32 @@ class Agent:
|
|
|
4139
4210
|
"user_id": user_id,
|
|
4140
4211
|
"debug_mode": debug_mode or self.debug_mode,
|
|
4141
4212
|
}
|
|
4213
|
+
|
|
4214
|
+
# Check if background_tasks is available and ALL hooks should run in background
|
|
4215
|
+
# Note: Pre-hooks running in background may not be able to modify run_input
|
|
4216
|
+
if self._run_hooks_in_background is True and background_tasks is not None:
|
|
4217
|
+
# Schedule ALL pre_hooks as background tasks
|
|
4218
|
+
# Copy args to prevent race conditions
|
|
4219
|
+
bg_args = copy_args_for_background(all_args)
|
|
4220
|
+
for hook in hooks:
|
|
4221
|
+
# Filter arguments to only include those that the hook accepts
|
|
4222
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
4223
|
+
|
|
4224
|
+
# Add to background tasks (both sync and async hooks supported)
|
|
4225
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
4226
|
+
return
|
|
4227
|
+
|
|
4142
4228
|
all_args.update(kwargs)
|
|
4143
4229
|
|
|
4144
4230
|
for i, hook in enumerate(hooks):
|
|
4231
|
+
# Check if this specific hook should run in background (via @hook decorator)
|
|
4232
|
+
if should_run_hook_in_background(hook) and background_tasks is not None:
|
|
4233
|
+
# Copy args to prevent race conditions
|
|
4234
|
+
bg_args = copy_args_for_background(all_args)
|
|
4235
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
4236
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
4237
|
+
continue
|
|
4238
|
+
|
|
4145
4239
|
if stream_events:
|
|
4146
4240
|
yield handle_event( # type: ignore
|
|
4147
4241
|
run_response=run_response,
|
|
@@ -4196,13 +4290,14 @@ class Agent:
|
|
|
4196
4290
|
user_id: Optional[str] = None,
|
|
4197
4291
|
debug_mode: Optional[bool] = None,
|
|
4198
4292
|
stream_events: bool = False,
|
|
4293
|
+
background_tasks: Optional[Any] = None,
|
|
4199
4294
|
**kwargs: Any,
|
|
4200
4295
|
) -> Iterator[RunOutputEvent]:
|
|
4201
4296
|
"""Execute multiple post-hook functions in succession."""
|
|
4202
4297
|
if hooks is None:
|
|
4203
4298
|
return
|
|
4204
4299
|
|
|
4205
|
-
# Prepare
|
|
4300
|
+
# Prepare arguments for this hook
|
|
4206
4301
|
all_args = {
|
|
4207
4302
|
"run_output": run_output,
|
|
4208
4303
|
"agent": self,
|
|
@@ -4214,9 +4309,31 @@ class Agent:
|
|
|
4214
4309
|
"run_context": run_context,
|
|
4215
4310
|
"debug_mode": debug_mode or self.debug_mode,
|
|
4216
4311
|
}
|
|
4312
|
+
|
|
4313
|
+
# Check if background_tasks is available and ALL hooks should run in background
|
|
4314
|
+
if self._run_hooks_in_background is True and background_tasks is not None:
|
|
4315
|
+
# Schedule ALL post_hooks as background tasks
|
|
4316
|
+
# Copy args to prevent race conditions
|
|
4317
|
+
bg_args = copy_args_for_background(all_args)
|
|
4318
|
+
for hook in hooks:
|
|
4319
|
+
# Filter arguments to only include those that the hook accepts
|
|
4320
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
4321
|
+
|
|
4322
|
+
# Add to background tasks
|
|
4323
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
4324
|
+
return
|
|
4325
|
+
|
|
4217
4326
|
all_args.update(kwargs)
|
|
4218
4327
|
|
|
4219
4328
|
for i, hook in enumerate(hooks):
|
|
4329
|
+
# Check if this specific hook should run in background (via @hook decorator)
|
|
4330
|
+
if should_run_hook_in_background(hook) and background_tasks is not None:
|
|
4331
|
+
# Copy args to prevent race conditions
|
|
4332
|
+
bg_args = copy_args_for_background(all_args)
|
|
4333
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
4334
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
4335
|
+
continue
|
|
4336
|
+
|
|
4220
4337
|
if stream_events:
|
|
4221
4338
|
yield handle_event( # type: ignore
|
|
4222
4339
|
run_response=run_output,
|
|
@@ -4261,13 +4378,14 @@ class Agent:
|
|
|
4261
4378
|
user_id: Optional[str] = None,
|
|
4262
4379
|
debug_mode: Optional[bool] = None,
|
|
4263
4380
|
stream_events: bool = False,
|
|
4381
|
+
background_tasks: Optional[Any] = None,
|
|
4264
4382
|
**kwargs: Any,
|
|
4265
4383
|
) -> AsyncIterator[RunOutputEvent]:
|
|
4266
4384
|
"""Execute multiple post-hook functions in succession (async version)."""
|
|
4267
4385
|
if hooks is None:
|
|
4268
4386
|
return
|
|
4269
4387
|
|
|
4270
|
-
# Prepare
|
|
4388
|
+
# Prepare arguments for this hook
|
|
4271
4389
|
all_args = {
|
|
4272
4390
|
"run_output": run_output,
|
|
4273
4391
|
"agent": self,
|
|
@@ -4279,9 +4397,29 @@ class Agent:
|
|
|
4279
4397
|
"user_id": user_id,
|
|
4280
4398
|
"debug_mode": debug_mode or self.debug_mode,
|
|
4281
4399
|
}
|
|
4400
|
+
# Check if background_tasks is available and ALL hooks should run in background
|
|
4401
|
+
if self._run_hooks_in_background is True and background_tasks is not None:
|
|
4402
|
+
# Copy args to prevent race conditions
|
|
4403
|
+
bg_args = copy_args_for_background(all_args)
|
|
4404
|
+
for hook in hooks:
|
|
4405
|
+
# Filter arguments to only include those that the hook accepts
|
|
4406
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
4407
|
+
|
|
4408
|
+
# Add to background tasks (both sync and async hooks supported)
|
|
4409
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
4410
|
+
return
|
|
4411
|
+
|
|
4282
4412
|
all_args.update(kwargs)
|
|
4283
4413
|
|
|
4284
4414
|
for i, hook in enumerate(hooks):
|
|
4415
|
+
# Check if this specific hook should run in background (via @hook decorator)
|
|
4416
|
+
if should_run_hook_in_background(hook) and background_tasks is not None:
|
|
4417
|
+
# Copy args to prevent race conditions
|
|
4418
|
+
bg_args = copy_args_for_background(all_args)
|
|
4419
|
+
filtered_args = filter_hook_args(hook, bg_args)
|
|
4420
|
+
background_tasks.add_task(hook, **filtered_args)
|
|
4421
|
+
continue
|
|
4422
|
+
|
|
4285
4423
|
if stream_events:
|
|
4286
4424
|
yield handle_event( # type: ignore
|
|
4287
4425
|
run_response=run_output,
|
|
@@ -6853,7 +6991,7 @@ class Agent:
|
|
|
6853
6991
|
|
|
6854
6992
|
# Should already be resolved and passed from run() method
|
|
6855
6993
|
format_variables = ChainMap(
|
|
6856
|
-
session_state
|
|
6994
|
+
session_state if session_state is not None else {},
|
|
6857
6995
|
dependencies or {},
|
|
6858
6996
|
metadata or {},
|
|
6859
6997
|
{"user_id": user_id} if user_id is not None else {},
|
|
@@ -8664,6 +8802,7 @@ class Agent:
|
|
|
8664
8802
|
# Update fields if provided
|
|
8665
8803
|
if update:
|
|
8666
8804
|
fields_for_new_agent.update(update)
|
|
8805
|
+
|
|
8667
8806
|
# Create a new Agent
|
|
8668
8807
|
new_agent = self.__class__(**fields_for_new_agent)
|
|
8669
8808
|
log_debug(f"Created new {self.__class__.__name__}")
|