agno 2.2.6__py3-none-any.whl → 2.2.7__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 +430 -416
- agno/api/os.py +1 -1
- agno/culture/manager.py +9 -4
- agno/guardrails/prompt_injection.py +1 -0
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/knowledge.py +37 -5
- agno/models/base.py +62 -54
- agno/models/openai/chat.py +6 -5
- agno/models/openai/responses.py +1 -58
- agno/models/requesty/requesty.py +5 -2
- agno/os/app.py +13 -12
- agno/os/schema.py +11 -8
- agno/run/__init__.py +6 -0
- agno/run/base.py +18 -1
- agno/run/team.py +11 -9
- agno/team/team.py +258 -361
- agno/tools/exa.py +21 -16
- agno/tools/function.py +93 -16
- agno/tools/mcp/mcp.py +8 -1
- agno/tools/notion.py +14 -11
- agno/utils/agent.py +78 -0
- agno/utils/hooks.py +1 -1
- agno/utils/models/claude.py +25 -8
- agno/vectordb/__init__.py +2 -1
- agno/vectordb/redis/__init__.py +5 -0
- agno/vectordb/redis/redisdb.py +687 -0
- agno/workflow/agent.py +10 -9
- agno/workflow/step.py +13 -2
- agno/workflow/workflow.py +85 -53
- {agno-2.2.6.dist-info → agno-2.2.7.dist-info}/METADATA +7 -3
- {agno-2.2.6.dist-info → agno-2.2.7.dist-info}/RECORD +34 -31
- {agno-2.2.6.dist-info → agno-2.2.7.dist-info}/WHEEL +0 -0
- {agno-2.2.6.dist-info → agno-2.2.7.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.6.dist-info → agno-2.2.7.dist-info}/top_level.txt +0 -0
agno/models/openai/chat.py
CHANGED
|
@@ -14,6 +14,7 @@ from agno.models.message import Message
|
|
|
14
14
|
from agno.models.metrics import Metrics
|
|
15
15
|
from agno.models.response import ModelResponse
|
|
16
16
|
from agno.run.agent import RunOutput
|
|
17
|
+
from agno.run.team import TeamRunOutput
|
|
17
18
|
from agno.utils.log import log_debug, log_error, log_warning
|
|
18
19
|
from agno.utils.openai import _format_file_for_message, audio_to_message, images_to_message
|
|
19
20
|
from agno.utils.reasoning import extract_thinking_content
|
|
@@ -168,7 +169,7 @@ class OpenAIChat(Model):
|
|
|
168
169
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
169
170
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
170
171
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
171
|
-
run_response: Optional[RunOutput] = None,
|
|
172
|
+
run_response: Optional[Union[RunOutput, TeamRunOutput]] = None,
|
|
172
173
|
) -> Dict[str, Any]:
|
|
173
174
|
"""
|
|
174
175
|
Returns keyword arguments for API requests.
|
|
@@ -355,7 +356,7 @@ class OpenAIChat(Model):
|
|
|
355
356
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
356
357
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
357
358
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
358
|
-
run_response: Optional[RunOutput] = None,
|
|
359
|
+
run_response: Optional[Union[RunOutput, TeamRunOutput]] = None,
|
|
359
360
|
) -> ModelResponse:
|
|
360
361
|
"""
|
|
361
362
|
Send a chat completion request to the OpenAI API and parse the response.
|
|
@@ -435,7 +436,7 @@ class OpenAIChat(Model):
|
|
|
435
436
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
436
437
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
437
438
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
438
|
-
run_response: Optional[RunOutput] = None,
|
|
439
|
+
run_response: Optional[Union[RunOutput, TeamRunOutput]] = None,
|
|
439
440
|
) -> ModelResponse:
|
|
440
441
|
"""
|
|
441
442
|
Sends an asynchronous chat completion request to the OpenAI API.
|
|
@@ -514,7 +515,7 @@ class OpenAIChat(Model):
|
|
|
514
515
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
515
516
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
516
517
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
517
|
-
run_response: Optional[RunOutput] = None,
|
|
518
|
+
run_response: Optional[Union[RunOutput, TeamRunOutput]] = None,
|
|
518
519
|
) -> Iterator[ModelResponse]:
|
|
519
520
|
"""
|
|
520
521
|
Send a streaming chat completion request to the OpenAI API.
|
|
@@ -590,7 +591,7 @@ class OpenAIChat(Model):
|
|
|
590
591
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
591
592
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
592
593
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
593
|
-
run_response: Optional[RunOutput] = None,
|
|
594
|
+
run_response: Optional[Union[RunOutput, TeamRunOutput]] = None,
|
|
594
595
|
) -> AsyncIterator[ModelResponse]:
|
|
595
596
|
"""
|
|
596
597
|
Sends an asynchronous streaming chat completion request to the OpenAI API.
|
agno/models/openai/responses.py
CHANGED
|
@@ -8,7 +8,7 @@ from typing_extensions import Literal
|
|
|
8
8
|
|
|
9
9
|
from agno.exceptions import ModelProviderError
|
|
10
10
|
from agno.media import File
|
|
11
|
-
from agno.models.base import
|
|
11
|
+
from agno.models.base import Model
|
|
12
12
|
from agno.models.message import Citations, Message, UrlCitation
|
|
13
13
|
from agno.models.metrics import Metrics
|
|
14
14
|
from agno.models.response import ModelResponse
|
|
@@ -810,63 +810,6 @@ class OpenAIResponses(Model):
|
|
|
810
810
|
_fc_message.tool_call_id = tool_call_ids[_fc_message_index]
|
|
811
811
|
messages.append(_fc_message)
|
|
812
812
|
|
|
813
|
-
def process_response_stream(
|
|
814
|
-
self,
|
|
815
|
-
messages: List[Message],
|
|
816
|
-
assistant_message: Message,
|
|
817
|
-
stream_data: MessageData,
|
|
818
|
-
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
819
|
-
tools: Optional[List[Dict[str, Any]]] = None,
|
|
820
|
-
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
821
|
-
run_response: Optional[RunOutput] = None,
|
|
822
|
-
) -> Iterator[ModelResponse]:
|
|
823
|
-
"""Process the synchronous response stream."""
|
|
824
|
-
for model_response_delta in self.invoke_stream(
|
|
825
|
-
messages=messages,
|
|
826
|
-
assistant_message=assistant_message,
|
|
827
|
-
tools=tools,
|
|
828
|
-
response_format=response_format,
|
|
829
|
-
tool_choice=tool_choice,
|
|
830
|
-
run_response=run_response,
|
|
831
|
-
):
|
|
832
|
-
yield from self._populate_stream_data_and_assistant_message(
|
|
833
|
-
stream_data=stream_data,
|
|
834
|
-
assistant_message=assistant_message,
|
|
835
|
-
model_response_delta=model_response_delta,
|
|
836
|
-
)
|
|
837
|
-
|
|
838
|
-
# Add final metrics to assistant message
|
|
839
|
-
self._populate_assistant_message(assistant_message=assistant_message, provider_response=model_response_delta)
|
|
840
|
-
|
|
841
|
-
async def aprocess_response_stream(
|
|
842
|
-
self,
|
|
843
|
-
messages: List[Message],
|
|
844
|
-
assistant_message: Message,
|
|
845
|
-
stream_data: MessageData,
|
|
846
|
-
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
847
|
-
tools: Optional[List[Dict[str, Any]]] = None,
|
|
848
|
-
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
849
|
-
run_response: Optional[RunOutput] = None,
|
|
850
|
-
) -> AsyncIterator[ModelResponse]:
|
|
851
|
-
"""Process the asynchronous response stream."""
|
|
852
|
-
async for model_response_delta in self.ainvoke_stream(
|
|
853
|
-
messages=messages,
|
|
854
|
-
assistant_message=assistant_message,
|
|
855
|
-
tools=tools,
|
|
856
|
-
response_format=response_format,
|
|
857
|
-
tool_choice=tool_choice,
|
|
858
|
-
run_response=run_response,
|
|
859
|
-
):
|
|
860
|
-
for model_response in self._populate_stream_data_and_assistant_message(
|
|
861
|
-
stream_data=stream_data,
|
|
862
|
-
assistant_message=assistant_message,
|
|
863
|
-
model_response_delta=model_response_delta,
|
|
864
|
-
):
|
|
865
|
-
yield model_response
|
|
866
|
-
|
|
867
|
-
# Add final metrics to assistant message
|
|
868
|
-
self._populate_assistant_message(assistant_message=assistant_message, provider_response=model_response_delta)
|
|
869
|
-
|
|
870
813
|
def _parse_provider_response(self, response: Response, **kwargs) -> ModelResponse:
|
|
871
814
|
"""
|
|
872
815
|
Parse the OpenAI response into a ModelResponse.
|
agno/models/requesty/requesty.py
CHANGED
|
@@ -6,6 +6,7 @@ from pydantic import BaseModel
|
|
|
6
6
|
|
|
7
7
|
from agno.models.openai.like import OpenAILike
|
|
8
8
|
from agno.run.agent import RunOutput
|
|
9
|
+
from agno.run.team import TeamRunOutput
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
@dataclass
|
|
@@ -34,9 +35,11 @@ class Requesty(OpenAILike):
|
|
|
34
35
|
response_format: Optional[Union[Dict, Type[BaseModel]]] = None,
|
|
35
36
|
tools: Optional[List[Dict[str, Any]]] = None,
|
|
36
37
|
tool_choice: Optional[Union[str, Dict[str, Any]]] = None,
|
|
37
|
-
run_response: Optional[RunOutput] = None,
|
|
38
|
+
run_response: Optional[Union[RunOutput, TeamRunOutput]] = None,
|
|
38
39
|
) -> Dict[str, Any]:
|
|
39
|
-
params = super().get_request_params(
|
|
40
|
+
params = super().get_request_params(
|
|
41
|
+
response_format=response_format, tools=tools, tool_choice=tool_choice, run_response=run_response
|
|
42
|
+
)
|
|
40
43
|
|
|
41
44
|
if "extra_body" not in params:
|
|
42
45
|
params["extra_body"] = {}
|
agno/os/app.py
CHANGED
|
@@ -46,7 +46,7 @@ from agno.os.utils import (
|
|
|
46
46
|
update_cors_middleware,
|
|
47
47
|
)
|
|
48
48
|
from agno.team.team import Team
|
|
49
|
-
from agno.utils.log import
|
|
49
|
+
from agno.utils.log import log_debug, log_error, log_warning
|
|
50
50
|
from agno.utils.string import generate_id, generate_id_from_name
|
|
51
51
|
from agno.workflow.workflow import Workflow
|
|
52
52
|
|
|
@@ -454,21 +454,22 @@ class AgentOS:
|
|
|
454
454
|
|
|
455
455
|
@fastapi_app.exception_handler(HTTPException)
|
|
456
456
|
async def http_exception_handler(_, exc: HTTPException) -> JSONResponse:
|
|
457
|
+
log_error(f"HTTP exception: {exc.status_code} {exc.detail}")
|
|
457
458
|
return JSONResponse(
|
|
458
459
|
status_code=exc.status_code,
|
|
459
460
|
content={"detail": str(exc.detail)},
|
|
460
461
|
)
|
|
461
462
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
status_code=e.status_code if hasattr(e, "status_code") else 500, # type: ignore
|
|
468
|
-
content={"detail": str(e)},
|
|
469
|
-
)
|
|
463
|
+
@fastapi_app.exception_handler(Exception)
|
|
464
|
+
async def general_exception_handler(_: Request, exc: Exception) -> JSONResponse:
|
|
465
|
+
import traceback
|
|
466
|
+
|
|
467
|
+
log_error(f"Unhandled exception:\n{traceback.format_exc(limit=5)}")
|
|
470
468
|
|
|
471
|
-
|
|
469
|
+
return JSONResponse(
|
|
470
|
+
status_code=getattr(exc, "status_code", 500),
|
|
471
|
+
content={"detail": str(exc)},
|
|
472
|
+
)
|
|
472
473
|
|
|
473
474
|
# Update CORS middleware
|
|
474
475
|
update_cors_middleware(fastapi_app, self.settings.cors_origin_list) # type: ignore
|
|
@@ -500,7 +501,7 @@ class AgentOS:
|
|
|
500
501
|
# Skip conflicting AgentOS routes, prefer user's existing routes
|
|
501
502
|
for conflict in conflicts:
|
|
502
503
|
methods_str = ", ".join(conflict["methods"]) # type: ignore
|
|
503
|
-
|
|
504
|
+
log_debug(
|
|
504
505
|
f"Skipping conflicting AgentOS route: {methods_str} {conflict['path']} - "
|
|
505
506
|
f"Using existing custom route instead"
|
|
506
507
|
)
|
|
@@ -519,7 +520,7 @@ class AgentOS:
|
|
|
519
520
|
# Log warnings but still add all routes (AgentOS routes will override)
|
|
520
521
|
for conflict in conflicts:
|
|
521
522
|
methods_str = ", ".join(conflict["methods"]) # type: ignore
|
|
522
|
-
|
|
523
|
+
log_warning(
|
|
523
524
|
f"Route conflict detected: {methods_str} {conflict['path']} - "
|
|
524
525
|
f"AgentOS route will override existing custom route"
|
|
525
526
|
)
|
agno/os/schema.py
CHANGED
|
@@ -19,6 +19,7 @@ from agno.os.utils import (
|
|
|
19
19
|
get_team_input_schema_dict,
|
|
20
20
|
get_workflow_input_schema_dict,
|
|
21
21
|
)
|
|
22
|
+
from agno.run import RunContext
|
|
22
23
|
from agno.run.agent import RunOutput
|
|
23
24
|
from agno.run.team import TeamRunOutput
|
|
24
25
|
from agno.session import AgentSession, TeamSession, WorkflowSession
|
|
@@ -186,9 +187,6 @@ class AgentResponse(BaseModel):
|
|
|
186
187
|
metadata: Optional[Dict[str, Any]] = None
|
|
187
188
|
input_schema: Optional[Dict[str, Any]] = None
|
|
188
189
|
|
|
189
|
-
class Config:
|
|
190
|
-
exclude_none = True
|
|
191
|
-
|
|
192
190
|
@classmethod
|
|
193
191
|
async def from_agent(cls, agent: Agent) -> "AgentResponse":
|
|
194
192
|
def filter_meaningful_config(d: Dict[str, Any], defaults: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
@@ -250,9 +248,12 @@ class AgentResponse(BaseModel):
|
|
|
250
248
|
"stream_intermediate_steps": False,
|
|
251
249
|
}
|
|
252
250
|
|
|
251
|
+
session_id = str(uuid4())
|
|
252
|
+
run_id = str(uuid4())
|
|
253
253
|
agent_tools = await agent.aget_tools(
|
|
254
|
-
session=AgentSession(session_id=
|
|
255
|
-
run_response=RunOutput(run_id=
|
|
254
|
+
session=AgentSession(session_id=session_id, session_data={}),
|
|
255
|
+
run_response=RunOutput(run_id=run_id, session_id=session_id),
|
|
256
|
+
run_context=RunContext(run_id=run_id, session_id=session_id, user_id=agent.user_id),
|
|
256
257
|
check_mcp_tools=False,
|
|
257
258
|
)
|
|
258
259
|
formatted_tools = format_tools(agent_tools) if agent_tools else None
|
|
@@ -474,12 +475,14 @@ class TeamResponse(BaseModel):
|
|
|
474
475
|
"stream_member_events": False,
|
|
475
476
|
}
|
|
476
477
|
|
|
478
|
+
run_id = str(uuid4())
|
|
479
|
+
session_id = str(uuid4())
|
|
477
480
|
_tools = team._determine_tools_for_model(
|
|
478
481
|
model=team.model, # type: ignore
|
|
479
|
-
session=TeamSession(session_id=
|
|
480
|
-
run_response=TeamRunOutput(run_id=
|
|
482
|
+
session=TeamSession(session_id=session_id, session_data={}),
|
|
483
|
+
run_response=TeamRunOutput(run_id=run_id),
|
|
484
|
+
run_context=RunContext(run_id=run_id, session_id=session_id, session_state={}),
|
|
481
485
|
async_mode=True,
|
|
482
|
-
session_state={},
|
|
483
486
|
team_run_context={},
|
|
484
487
|
check_mcp_tools=False,
|
|
485
488
|
)
|
agno/run/__init__.py
CHANGED
agno/run/base.py
CHANGED
|
@@ -7,11 +7,22 @@ from pydantic import BaseModel
|
|
|
7
7
|
from agno.media import Audio, Image, Video
|
|
8
8
|
from agno.models.message import Citations, Message, MessageReferences
|
|
9
9
|
from agno.models.metrics import Metrics
|
|
10
|
-
from agno.models.response import ToolExecution
|
|
11
10
|
from agno.reasoning.step import ReasoningStep
|
|
12
11
|
from agno.utils.log import log_error
|
|
13
12
|
|
|
14
13
|
|
|
14
|
+
@dataclass
|
|
15
|
+
class RunContext:
|
|
16
|
+
run_id: str
|
|
17
|
+
session_id: str
|
|
18
|
+
user_id: Optional[str] = None
|
|
19
|
+
|
|
20
|
+
dependencies: Optional[Dict[str, Any]] = None
|
|
21
|
+
knowledge_filters: Optional[Dict[str, Any]] = None
|
|
22
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
23
|
+
session_state: Optional[Dict[str, Any]] = None
|
|
24
|
+
|
|
25
|
+
|
|
15
26
|
@dataclass
|
|
16
27
|
class BaseRunOutputEvent:
|
|
17
28
|
def to_dict(self) -> Dict[str, Any]:
|
|
@@ -98,6 +109,8 @@ class BaseRunOutputEvent:
|
|
|
98
109
|
_dict["content"] = self.content.model_dump(exclude_none=True)
|
|
99
110
|
|
|
100
111
|
if hasattr(self, "tools") and self.tools is not None:
|
|
112
|
+
from agno.models.response import ToolExecution
|
|
113
|
+
|
|
101
114
|
_dict["tools"] = []
|
|
102
115
|
for tool in self.tools:
|
|
103
116
|
if isinstance(tool, ToolExecution):
|
|
@@ -106,6 +119,8 @@ class BaseRunOutputEvent:
|
|
|
106
119
|
_dict["tools"].append(tool)
|
|
107
120
|
|
|
108
121
|
if hasattr(self, "tool") and self.tool is not None:
|
|
122
|
+
from agno.models.response import ToolExecution
|
|
123
|
+
|
|
109
124
|
if isinstance(self.tool, ToolExecution):
|
|
110
125
|
_dict["tool"] = self.tool.to_dict()
|
|
111
126
|
else:
|
|
@@ -139,6 +154,8 @@ class BaseRunOutputEvent:
|
|
|
139
154
|
def from_dict(cls, data: Dict[str, Any]):
|
|
140
155
|
tool = data.pop("tool", None)
|
|
141
156
|
if tool:
|
|
157
|
+
from agno.models.response import ToolExecution
|
|
158
|
+
|
|
142
159
|
data["tool"] = ToolExecution.from_dict(tool)
|
|
143
160
|
|
|
144
161
|
images = data.pop("images", None)
|
agno/run/team.py
CHANGED
|
@@ -469,8 +469,19 @@ def team_run_output_event_from_dict(data: dict) -> BaseTeamRunEvent:
|
|
|
469
469
|
class TeamRunOutput:
|
|
470
470
|
"""Response returned by Team.run() functions"""
|
|
471
471
|
|
|
472
|
+
run_id: Optional[str] = None
|
|
473
|
+
team_id: Optional[str] = None
|
|
474
|
+
team_name: Optional[str] = None
|
|
475
|
+
session_id: Optional[str] = None
|
|
476
|
+
parent_run_id: Optional[str] = None
|
|
477
|
+
user_id: Optional[str] = None
|
|
478
|
+
|
|
479
|
+
# Input media and messages from user
|
|
480
|
+
input: Optional[TeamRunInput] = None
|
|
481
|
+
|
|
472
482
|
content: Optional[Any] = None
|
|
473
483
|
content_type: str = "str"
|
|
484
|
+
|
|
474
485
|
messages: Optional[List[Message]] = None
|
|
475
486
|
metrics: Optional[Metrics] = None
|
|
476
487
|
model: Optional[str] = None
|
|
@@ -478,12 +489,6 @@ class TeamRunOutput:
|
|
|
478
489
|
|
|
479
490
|
member_responses: List[Union["TeamRunOutput", RunOutput]] = field(default_factory=list)
|
|
480
491
|
|
|
481
|
-
run_id: Optional[str] = None
|
|
482
|
-
team_id: Optional[str] = None
|
|
483
|
-
team_name: Optional[str] = None
|
|
484
|
-
session_id: Optional[str] = None
|
|
485
|
-
parent_run_id: Optional[str] = None
|
|
486
|
-
|
|
487
492
|
tools: Optional[List[ToolExecution]] = None
|
|
488
493
|
|
|
489
494
|
images: Optional[List[Image]] = None # Images from member runs
|
|
@@ -493,9 +498,6 @@ class TeamRunOutput:
|
|
|
493
498
|
|
|
494
499
|
response_audio: Optional[Audio] = None # Model audio response
|
|
495
500
|
|
|
496
|
-
# Input media and messages from user
|
|
497
|
-
input: Optional[TeamRunInput] = None
|
|
498
|
-
|
|
499
501
|
reasoning_content: Optional[str] = None
|
|
500
502
|
|
|
501
503
|
citations: Optional[Citations] = None
|