agno 2.3.4__py3-none-any.whl → 2.3.5__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 +177 -41
- 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 +541 -13
- agno/db/postgres/postgres.py +535 -2
- 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 +548 -9
- agno/db/sqlite/schemas.py +38 -0
- agno/db/sqlite/sqlite.py +537 -5
- 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 +10 -4
- 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/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 +63 -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/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 +10 -1
- 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/session/team.py +1 -0
- agno/table.py +10 -0
- agno/team/team.py +214 -65
- agno/tools/function.py +10 -8
- agno/tools/nano_banana.py +1 -1
- 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 +4 -4
- agno/utils/hooks.py +56 -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 +83 -17
- {agno-2.3.4.dist-info → agno-2.3.5.dist-info}/METADATA +2 -2
- {agno-2.3.4.dist-info → agno-2.3.5.dist-info}/RECORD +112 -102
- {agno-2.3.4.dist-info → agno-2.3.5.dist-info}/WHEEL +0 -0
- {agno-2.3.4.dist-info → agno-2.3.5.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.4.dist-info → agno-2.3.5.dist-info}/top_level.txt +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass
|
|
2
2
|
from os import getenv
|
|
3
3
|
from typing import Any, Dict, List, Optional, Type, Union
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
|
|
7
|
-
from agno.exceptions import
|
|
7
|
+
from agno.exceptions import ModelAuthenticationError
|
|
8
8
|
from agno.models.openai.like import OpenAILike
|
|
9
9
|
from agno.run.agent import RunOutput
|
|
10
10
|
|
|
@@ -30,7 +30,7 @@ class OpenRouter(OpenAILike):
|
|
|
30
30
|
name: str = "OpenRouter"
|
|
31
31
|
provider: str = "OpenRouter"
|
|
32
32
|
|
|
33
|
-
api_key: Optional[str] =
|
|
33
|
+
api_key: Optional[str] = None
|
|
34
34
|
base_url: str = "https://openrouter.ai/api/v1"
|
|
35
35
|
max_tokens: int = 1024
|
|
36
36
|
models: Optional[List[str]] = None # Dynamic model routing https://openrouter.ai/docs/features/model-routing
|
|
@@ -46,10 +46,9 @@ class OpenRouter(OpenAILike):
|
|
|
46
46
|
if not self.api_key:
|
|
47
47
|
self.api_key = getenv("OPENROUTER_API_KEY")
|
|
48
48
|
if not self.api_key:
|
|
49
|
-
raise
|
|
49
|
+
raise ModelAuthenticationError(
|
|
50
50
|
message="OPENROUTER_API_KEY not set. Please set the OPENROUTER_API_KEY environment variable.",
|
|
51
51
|
model_name=self.name,
|
|
52
|
-
model_id=self.id,
|
|
53
52
|
)
|
|
54
53
|
|
|
55
54
|
return super()._get_client_params()
|
|
@@ -4,7 +4,7 @@ from typing import Any, Dict, Optional, Type, Union
|
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
|
|
7
|
-
from agno.exceptions import ModelProviderError
|
|
7
|
+
from agno.exceptions import ModelAuthenticationError, ModelProviderError
|
|
8
8
|
from agno.models.message import Citations, UrlCitation
|
|
9
9
|
from agno.models.metrics import Metrics
|
|
10
10
|
from agno.models.response import ModelResponse
|
|
@@ -60,10 +60,9 @@ class Perplexity(OpenAILike):
|
|
|
60
60
|
if not self.api_key:
|
|
61
61
|
self.api_key = getenv("PERPLEXITY_API_KEY")
|
|
62
62
|
if not self.api_key:
|
|
63
|
-
raise
|
|
63
|
+
raise ModelAuthenticationError(
|
|
64
64
|
message="PERPLEXITY_API_KEY not set. Please set the PERPLEXITY_API_KEY environment variable.",
|
|
65
65
|
model_name=self.name,
|
|
66
|
-
model_id=self.id,
|
|
67
66
|
)
|
|
68
67
|
return super()._get_client_params()
|
|
69
68
|
|
agno/models/portkey/portkey.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass
|
|
2
2
|
from os import getenv
|
|
3
3
|
from typing import Any, Dict, Optional, cast
|
|
4
4
|
|
|
5
|
-
from agno.exceptions import
|
|
5
|
+
from agno.exceptions import ModelAuthenticationError
|
|
6
6
|
from agno.models.openai.like import OpenAILike
|
|
7
7
|
|
|
8
8
|
try:
|
|
@@ -30,20 +30,21 @@ class Portkey(OpenAILike):
|
|
|
30
30
|
name: str = "Portkey"
|
|
31
31
|
provider: str = "Portkey"
|
|
32
32
|
|
|
33
|
-
portkey_api_key: Optional[str] =
|
|
34
|
-
virtual_key: Optional[str] =
|
|
33
|
+
portkey_api_key: Optional[str] = None
|
|
34
|
+
virtual_key: Optional[str] = None
|
|
35
35
|
config: Optional[Dict[str, Any]] = None
|
|
36
36
|
base_url: str = PORTKEY_GATEWAY_URL
|
|
37
37
|
|
|
38
38
|
def _get_client_params(self) -> Dict[str, Any]:
|
|
39
39
|
# Check for required keys
|
|
40
40
|
if not self.portkey_api_key:
|
|
41
|
-
raise
|
|
41
|
+
raise ModelAuthenticationError(
|
|
42
42
|
message="PORTKEY_API_KEY not set. Please set the PORTKEY_API_KEY environment variable.",
|
|
43
43
|
model_name=self.name,
|
|
44
|
-
model_id=self.id,
|
|
45
44
|
)
|
|
46
45
|
|
|
46
|
+
self.virtual_key = self.virtual_key or getenv("PORTKEY_VIRTUAL_KEY")
|
|
47
|
+
|
|
47
48
|
# Create headers using Portkey's createHeaders function
|
|
48
49
|
header_params: Dict[str, Any] = {
|
|
49
50
|
"api_key": self.portkey_api_key,
|
agno/models/requesty/requesty.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass
|
|
2
2
|
from os import getenv
|
|
3
3
|
from typing import Any, Dict, List, Optional, Type, Union
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
|
|
7
|
-
from agno.exceptions import
|
|
7
|
+
from agno.exceptions import ModelAuthenticationError
|
|
8
8
|
from agno.models.openai.like import OpenAILike
|
|
9
9
|
from agno.run.agent import RunOutput
|
|
10
10
|
from agno.run.team import TeamRunOutput
|
|
@@ -27,7 +27,7 @@ class Requesty(OpenAILike):
|
|
|
27
27
|
name: str = "Requesty"
|
|
28
28
|
provider: str = "Requesty"
|
|
29
29
|
|
|
30
|
-
api_key: Optional[str] =
|
|
30
|
+
api_key: Optional[str] = None
|
|
31
31
|
base_url: str = "https://router.requesty.ai/v1"
|
|
32
32
|
max_tokens: int = 1024
|
|
33
33
|
|
|
@@ -41,10 +41,9 @@ class Requesty(OpenAILike):
|
|
|
41
41
|
if not self.api_key:
|
|
42
42
|
self.api_key = getenv("REQUESTY_API_KEY")
|
|
43
43
|
if not self.api_key:
|
|
44
|
-
raise
|
|
44
|
+
raise ModelAuthenticationError(
|
|
45
45
|
message="REQUESTY_API_KEY not set. Please set the REQUESTY_API_KEY environment variable.",
|
|
46
46
|
model_name=self.name,
|
|
47
|
-
model_id=self.id,
|
|
48
47
|
)
|
|
49
48
|
return super()._get_client_params()
|
|
50
49
|
|
agno/models/response.py
CHANGED
|
@@ -35,7 +35,7 @@ class ToolExecution:
|
|
|
35
35
|
# If True, the agent will stop executing after this tool call.
|
|
36
36
|
stop_after_tool_call: bool = False
|
|
37
37
|
|
|
38
|
-
created_at: int = int(time())
|
|
38
|
+
created_at: int = field(default_factory=lambda: int(time()))
|
|
39
39
|
|
|
40
40
|
# User control flow requirements
|
|
41
41
|
requires_confirmation: Optional[bool] = None
|
|
@@ -81,6 +81,7 @@ class ToolExecution:
|
|
|
81
81
|
else None,
|
|
82
82
|
external_execution_required=data.get("external_execution_required"),
|
|
83
83
|
metrics=Metrics(**(data.get("metrics", {}) or {})),
|
|
84
|
+
**{"created_at": data["created_at"]} if "created_at" in data else {},
|
|
84
85
|
)
|
|
85
86
|
|
|
86
87
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass
|
|
2
2
|
from os import getenv
|
|
3
3
|
from typing import Any, Dict, Optional
|
|
4
4
|
|
|
5
|
-
from agno.exceptions import
|
|
5
|
+
from agno.exceptions import ModelAuthenticationError
|
|
6
6
|
from agno.models.openai.like import OpenAILike
|
|
7
7
|
|
|
8
8
|
|
|
@@ -23,7 +23,7 @@ class Sambanova(OpenAILike):
|
|
|
23
23
|
name: str = "Sambanova"
|
|
24
24
|
provider: str = "Sambanova"
|
|
25
25
|
|
|
26
|
-
api_key: Optional[str] =
|
|
26
|
+
api_key: Optional[str] = None
|
|
27
27
|
base_url: str = "https://api.sambanova.ai/v1"
|
|
28
28
|
|
|
29
29
|
supports_native_structured_outputs: bool = False
|
|
@@ -38,9 +38,8 @@ class Sambanova(OpenAILike):
|
|
|
38
38
|
if not self.api_key:
|
|
39
39
|
self.api_key = getenv("SAMBANOVA_API_KEY")
|
|
40
40
|
if not self.api_key:
|
|
41
|
-
raise
|
|
41
|
+
raise ModelAuthenticationError(
|
|
42
42
|
message="SAMBANOVA_API_KEY not set. Please set the SAMBANOVA_API_KEY environment variable.",
|
|
43
43
|
model_name=self.name,
|
|
44
|
-
model_id=self.id,
|
|
45
44
|
)
|
|
46
45
|
return super()._get_client_params()
|
|
@@ -2,7 +2,7 @@ from dataclasses import dataclass
|
|
|
2
2
|
from os import getenv
|
|
3
3
|
from typing import Any, Dict, Optional
|
|
4
4
|
|
|
5
|
-
from agno.exceptions import
|
|
5
|
+
from agno.exceptions import ModelAuthenticationError
|
|
6
6
|
from agno.models.openai.like import OpenAILike
|
|
7
7
|
|
|
8
8
|
|
|
@@ -22,7 +22,7 @@ class Siliconflow(OpenAILike):
|
|
|
22
22
|
id: str = "Qwen/QwQ-32B"
|
|
23
23
|
name: str = "Siliconflow"
|
|
24
24
|
provider: str = "Siliconflow"
|
|
25
|
-
api_key: Optional[str] =
|
|
25
|
+
api_key: Optional[str] = None
|
|
26
26
|
base_url: str = "https://api.siliconflow.com/v1"
|
|
27
27
|
|
|
28
28
|
def _get_client_params(self) -> Dict[str, Any]:
|
|
@@ -35,9 +35,8 @@ class Siliconflow(OpenAILike):
|
|
|
35
35
|
if not self.api_key:
|
|
36
36
|
self.api_key = getenv("SILICONFLOW_API_KEY")
|
|
37
37
|
if not self.api_key:
|
|
38
|
-
raise
|
|
38
|
+
raise ModelAuthenticationError(
|
|
39
39
|
message="SILICONFLOW_API_KEY not set. Please set the SILICONFLOW_API_KEY environment variable.",
|
|
40
40
|
model_name=self.name,
|
|
41
|
-
model_id=self.id,
|
|
42
41
|
)
|
|
43
42
|
return super()._get_client_params()
|
agno/models/together/together.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass
|
|
2
2
|
from os import getenv
|
|
3
3
|
from typing import Any, Dict, Optional
|
|
4
4
|
|
|
5
|
-
from agno.exceptions import
|
|
5
|
+
from agno.exceptions import ModelAuthenticationError
|
|
6
6
|
from agno.models.openai.like import OpenAILike
|
|
7
7
|
|
|
8
8
|
|
|
@@ -22,7 +22,7 @@ class Together(OpenAILike):
|
|
|
22
22
|
id: str = "mistralai/Mixtral-8x7B-Instruct-v0.1"
|
|
23
23
|
name: str = "Together"
|
|
24
24
|
provider: str = "Together"
|
|
25
|
-
api_key: Optional[str] =
|
|
25
|
+
api_key: Optional[str] = None
|
|
26
26
|
base_url: str = "https://api.together.xyz/v1"
|
|
27
27
|
|
|
28
28
|
def _get_client_params(self) -> Dict[str, Any]:
|
|
@@ -35,9 +35,8 @@ class Together(OpenAILike):
|
|
|
35
35
|
if not self.api_key:
|
|
36
36
|
self.api_key = getenv("TOGETHER_API_KEY")
|
|
37
37
|
if not self.api_key:
|
|
38
|
-
raise
|
|
38
|
+
raise ModelAuthenticationError(
|
|
39
39
|
message="TOGETHER_API_KEY not set. Please set the TOGETHER_API_KEY environment variable.",
|
|
40
40
|
model_name=self.name,
|
|
41
|
-
model_id=self.id,
|
|
42
41
|
)
|
|
43
42
|
return super()._get_client_params()
|
agno/models/vercel/v0.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass
|
|
2
2
|
from os import getenv
|
|
3
3
|
from typing import Any, Dict, Optional
|
|
4
4
|
|
|
5
|
-
from agno.exceptions import
|
|
5
|
+
from agno.exceptions import ModelAuthenticationError
|
|
6
6
|
from agno.models.openai.like import OpenAILike
|
|
7
7
|
|
|
8
8
|
|
|
@@ -23,7 +23,7 @@ class V0(OpenAILike):
|
|
|
23
23
|
name: str = "v0"
|
|
24
24
|
provider: str = "Vercel"
|
|
25
25
|
|
|
26
|
-
api_key: Optional[str] =
|
|
26
|
+
api_key: Optional[str] = None
|
|
27
27
|
base_url: str = "https://api.v0.dev/v1/"
|
|
28
28
|
|
|
29
29
|
def _get_client_params(self) -> Dict[str, Any]:
|
|
@@ -36,9 +36,8 @@ class V0(OpenAILike):
|
|
|
36
36
|
if not self.api_key:
|
|
37
37
|
self.api_key = getenv("V0_API_KEY")
|
|
38
38
|
if not self.api_key:
|
|
39
|
-
raise
|
|
39
|
+
raise ModelAuthenticationError(
|
|
40
40
|
message="V0_API_KEY not set. Please set the V0_API_KEY environment variable.",
|
|
41
41
|
model_name=self.name,
|
|
42
|
-
model_id=self.id,
|
|
43
42
|
)
|
|
44
43
|
return super()._get_client_params()
|
agno/models/vllm/vllm.py
CHANGED
|
@@ -4,6 +4,7 @@ from typing import Any, Dict, List, Optional, Type, Union
|
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
|
|
7
|
+
from agno.exceptions import ModelAuthenticationError
|
|
7
8
|
from agno.models.openai.like import OpenAILike
|
|
8
9
|
from agno.utils.log import log_debug
|
|
9
10
|
|
|
@@ -29,8 +30,8 @@ class VLLM(OpenAILike):
|
|
|
29
30
|
name: str = "VLLM"
|
|
30
31
|
provider: str = "VLLM"
|
|
31
32
|
|
|
32
|
-
api_key: Optional[str] =
|
|
33
|
-
base_url: Optional[str] =
|
|
33
|
+
api_key: Optional[str] = None
|
|
34
|
+
base_url: Optional[str] = None
|
|
34
35
|
|
|
35
36
|
temperature: float = 0.7
|
|
36
37
|
top_p: float = 0.8
|
|
@@ -38,19 +39,23 @@ class VLLM(OpenAILike):
|
|
|
38
39
|
top_k: Optional[int] = None
|
|
39
40
|
enable_thinking: Optional[bool] = None
|
|
40
41
|
|
|
41
|
-
def
|
|
42
|
-
"""
|
|
43
|
-
|
|
44
|
-
raise ValueError("VLLM_BASE_URL must be set via environment variable or explicit initialization")
|
|
45
|
-
if self.id == "not-set":
|
|
46
|
-
raise ValueError("Model ID must be set via environment variable or explicit initialization")
|
|
42
|
+
def _get_client_params(self) -> Dict[str, Any]:
|
|
43
|
+
"""
|
|
44
|
+
Returns client parameters for API requests, checking for VLLM_API_KEY.
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if self.
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
Returns:
|
|
47
|
+
Dict[str, Any]: A dictionary of client parameters for API requests.
|
|
48
|
+
"""
|
|
49
|
+
if not self.api_key:
|
|
50
|
+
self.api_key = getenv("VLLM_API_KEY")
|
|
51
|
+
if not self.api_key:
|
|
52
|
+
raise ModelAuthenticationError(
|
|
53
|
+
message="VLLM_API_KEY not set. Please set the VLLM_API_KEY environment variable.",
|
|
54
|
+
model_name=self.name,
|
|
55
|
+
)
|
|
56
|
+
if not self.base_url:
|
|
57
|
+
self.base_url = getenv("VLLM_BASE_URL", "http://localhost:8000/v1/")
|
|
58
|
+
return super()._get_client_params()
|
|
54
59
|
|
|
55
60
|
def get_request_params(
|
|
56
61
|
self,
|
agno/models/xai/xai.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass
|
|
2
2
|
from os import getenv
|
|
3
3
|
from typing import Any, Dict, List, Optional, Type, Union
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
|
|
7
|
-
from agno.exceptions import
|
|
7
|
+
from agno.exceptions import ModelAuthenticationError
|
|
8
8
|
from agno.models.message import Citations, UrlCitation
|
|
9
9
|
from agno.models.openai.like import OpenAILike
|
|
10
10
|
from agno.models.response import ModelResponse
|
|
@@ -35,7 +35,7 @@ class xAI(OpenAILike):
|
|
|
35
35
|
name: str = "xAI"
|
|
36
36
|
provider: str = "xAI"
|
|
37
37
|
|
|
38
|
-
api_key: Optional[str] =
|
|
38
|
+
api_key: Optional[str] = None
|
|
39
39
|
base_url: str = "https://api.x.ai/v1"
|
|
40
40
|
|
|
41
41
|
search_parameters: Optional[Dict[str, Any]] = None
|
|
@@ -50,10 +50,9 @@ class xAI(OpenAILike):
|
|
|
50
50
|
if not self.api_key:
|
|
51
51
|
self.api_key = getenv("XAI_API_KEY")
|
|
52
52
|
if not self.api_key:
|
|
53
|
-
raise
|
|
53
|
+
raise ModelAuthenticationError(
|
|
54
54
|
message="XAI_API_KEY not set. Please set the XAI_API_KEY environment variable.",
|
|
55
55
|
model_name=self.name,
|
|
56
|
-
model_id=self.id,
|
|
57
56
|
)
|
|
58
57
|
return super()._get_client_params()
|
|
59
58
|
|
agno/os/app.py
CHANGED
|
@@ -27,6 +27,8 @@ from agno.os.config import (
|
|
|
27
27
|
MetricsDomainConfig,
|
|
28
28
|
SessionConfig,
|
|
29
29
|
SessionDomainConfig,
|
|
30
|
+
TracesConfig,
|
|
31
|
+
TracesDomainConfig,
|
|
30
32
|
)
|
|
31
33
|
from agno.os.interfaces.base import BaseInterface
|
|
32
34
|
from agno.os.router import get_base_router, get_websocket_router
|
|
@@ -37,12 +39,14 @@ from agno.os.routers.knowledge import get_knowledge_router
|
|
|
37
39
|
from agno.os.routers.memory import get_memory_router
|
|
38
40
|
from agno.os.routers.metrics import get_metrics_router
|
|
39
41
|
from agno.os.routers.session import get_session_router
|
|
42
|
+
from agno.os.routers.traces import get_traces_router
|
|
40
43
|
from agno.os.settings import AgnoAPISettings
|
|
41
44
|
from agno.os.utils import (
|
|
42
45
|
collect_mcp_tools_from_team,
|
|
43
46
|
collect_mcp_tools_from_workflow,
|
|
44
47
|
find_conflicting_routes,
|
|
45
48
|
load_yaml_config,
|
|
49
|
+
setup_tracing_for_os,
|
|
46
50
|
update_cors_middleware,
|
|
47
51
|
)
|
|
48
52
|
from agno.team.team import Team
|
|
@@ -109,7 +113,10 @@ class AgentOS:
|
|
|
109
113
|
base_app: Optional[FastAPI] = None,
|
|
110
114
|
on_route_conflict: Literal["preserve_agentos", "preserve_base_app", "error"] = "preserve_agentos",
|
|
111
115
|
telemetry: bool = True,
|
|
116
|
+
tracing: bool = False,
|
|
117
|
+
tracing_db: Optional[Union[BaseDb, AsyncBaseDb]] = None,
|
|
112
118
|
auto_provision_dbs: bool = True,
|
|
119
|
+
run_hooks_in_background: bool = False,
|
|
113
120
|
):
|
|
114
121
|
"""Initialize AgentOS.
|
|
115
122
|
|
|
@@ -131,6 +138,10 @@ class AgentOS:
|
|
|
131
138
|
base_app: Optional base FastAPI app to use for the AgentOS. All routes and middleware will be added to this app.
|
|
132
139
|
on_route_conflict: What to do when a route conflict is detected in case a custom base_app is provided.
|
|
133
140
|
telemetry: Whether to enable telemetry
|
|
141
|
+
tracing: If True, enables OpenTelemetry tracing for all agents and teams in the OS
|
|
142
|
+
tracing_db: Dedicated database for storing and reading traces. Recommended for multi-db setups.
|
|
143
|
+
If not provided and tracing=True, the first available db from agents/teams/workflows is used.
|
|
144
|
+
run_hooks_in_background: If True, run agent/team pre/post hooks as FastAPI background tasks (non-blocking)
|
|
134
145
|
|
|
135
146
|
"""
|
|
136
147
|
if not agents and not workflows and not teams and not knowledge:
|
|
@@ -169,10 +180,15 @@ class AgentOS:
|
|
|
169
180
|
self.description = description
|
|
170
181
|
|
|
171
182
|
self.telemetry = telemetry
|
|
183
|
+
self.tracing = tracing
|
|
184
|
+
self.tracing_db = tracing_db
|
|
172
185
|
|
|
173
186
|
self.enable_mcp_server = enable_mcp_server
|
|
174
187
|
self.lifespan = lifespan
|
|
175
188
|
|
|
189
|
+
# If True, run agent/team hooks as FastAPI background tasks
|
|
190
|
+
self.run_hooks_in_background = run_hooks_in_background
|
|
191
|
+
|
|
176
192
|
# List of all MCP tools used inside the AgentOS
|
|
177
193
|
self.mcp_tools: List[Any] = []
|
|
178
194
|
self._mcp_app: Optional[Any] = None
|
|
@@ -181,6 +197,9 @@ class AgentOS:
|
|
|
181
197
|
self._initialize_teams()
|
|
182
198
|
self._initialize_workflows()
|
|
183
199
|
|
|
200
|
+
if self.tracing:
|
|
201
|
+
self._setup_tracing()
|
|
202
|
+
|
|
184
203
|
if self.telemetry:
|
|
185
204
|
from agno.api.os import OSLaunch, log_os_telemetry
|
|
186
205
|
|
|
@@ -235,6 +254,7 @@ class AgentOS:
|
|
|
235
254
|
get_session_router(dbs=self.dbs),
|
|
236
255
|
get_metrics_router(dbs=self.dbs),
|
|
237
256
|
get_knowledge_router(knowledge_instances=self.knowledge_instances),
|
|
257
|
+
get_traces_router(dbs=self.dbs),
|
|
238
258
|
get_memory_router(dbs=self.dbs),
|
|
239
259
|
get_eval_router(dbs=self.dbs, agents=self.agents, teams=self.teams),
|
|
240
260
|
]
|
|
@@ -332,6 +352,9 @@ class AgentOS:
|
|
|
332
352
|
# Required for the built-in routes to work
|
|
333
353
|
agent.store_events = True
|
|
334
354
|
|
|
355
|
+
# Propagate run_hooks_in_background setting from AgentOS to agents
|
|
356
|
+
agent._run_hooks_in_background = self.run_hooks_in_background
|
|
357
|
+
|
|
335
358
|
def _initialize_teams(self) -> None:
|
|
336
359
|
"""Initialize and configure all teams for AgentOS usage."""
|
|
337
360
|
if not self.teams:
|
|
@@ -353,6 +376,9 @@ class AgentOS:
|
|
|
353
376
|
# Required for the built-in routes to work
|
|
354
377
|
team.store_events = True
|
|
355
378
|
|
|
379
|
+
# Propagate run_hooks_in_background setting to team and all nested members
|
|
380
|
+
team.propagate_run_hooks_in_background(self.run_hooks_in_background)
|
|
381
|
+
|
|
356
382
|
def _initialize_workflows(self) -> None:
|
|
357
383
|
"""Initialize and configure all workflows for AgentOS usage."""
|
|
358
384
|
if not self.workflows:
|
|
@@ -369,6 +395,49 @@ class AgentOS:
|
|
|
369
395
|
# Required for the built-in routes to work
|
|
370
396
|
workflow.store_events = True
|
|
371
397
|
|
|
398
|
+
# Propagate run_hooks_in_background setting to workflow and all its step agents/teams
|
|
399
|
+
workflow.propagate_run_hooks_in_background(self.run_hooks_in_background)
|
|
400
|
+
|
|
401
|
+
def _setup_tracing(self) -> None:
|
|
402
|
+
"""Set up OpenTelemetry tracing for this AgentOS.
|
|
403
|
+
|
|
404
|
+
Uses tracing_db if provided, otherwise falls back to the first available
|
|
405
|
+
database from agents/teams/workflows.
|
|
406
|
+
"""
|
|
407
|
+
# Use tracing_db if explicitly provided
|
|
408
|
+
if self.tracing_db is not None:
|
|
409
|
+
setup_tracing_for_os(db=self.tracing_db)
|
|
410
|
+
return
|
|
411
|
+
|
|
412
|
+
# Fall back to finding the first available database
|
|
413
|
+
db: Optional[Union[BaseDb, AsyncBaseDb]] = None
|
|
414
|
+
|
|
415
|
+
for agent in self.agents or []:
|
|
416
|
+
if agent.db:
|
|
417
|
+
db = agent.db
|
|
418
|
+
break
|
|
419
|
+
|
|
420
|
+
if db is None:
|
|
421
|
+
for team in self.teams or []:
|
|
422
|
+
if team.db:
|
|
423
|
+
db = team.db
|
|
424
|
+
break
|
|
425
|
+
|
|
426
|
+
if db is None:
|
|
427
|
+
for workflow in self.workflows or []:
|
|
428
|
+
if workflow.db:
|
|
429
|
+
db = workflow.db
|
|
430
|
+
break
|
|
431
|
+
|
|
432
|
+
if db is None:
|
|
433
|
+
log_warning(
|
|
434
|
+
"tracing=True but no database found. "
|
|
435
|
+
"Provide 'tracing_db' parameter or 'db' parameter to at least one agent/team/workflow."
|
|
436
|
+
)
|
|
437
|
+
return
|
|
438
|
+
|
|
439
|
+
setup_tracing_for_os(db=db)
|
|
440
|
+
|
|
372
441
|
def get_app(self) -> FastAPI:
|
|
373
442
|
if self.base_app:
|
|
374
443
|
fastapi_app = self.base_app
|
|
@@ -447,6 +516,7 @@ class AgentOS:
|
|
|
447
516
|
get_eval_router(dbs=self.dbs, agents=self.agents, teams=self.teams),
|
|
448
517
|
get_metrics_router(dbs=self.dbs),
|
|
449
518
|
get_knowledge_router(knowledge_instances=self.knowledge_instances),
|
|
519
|
+
get_traces_router(dbs=self.dbs),
|
|
450
520
|
]
|
|
451
521
|
|
|
452
522
|
for router in routers:
|
|
@@ -591,6 +661,10 @@ class AgentOS:
|
|
|
591
661
|
elif interface.team and interface.team.db:
|
|
592
662
|
self._register_db_with_validation(dbs, interface.team.db)
|
|
593
663
|
|
|
664
|
+
# Register tracing_db if provided (for traces reading)
|
|
665
|
+
if self.tracing_db is not None:
|
|
666
|
+
self._register_db_with_validation(dbs, self.tracing_db)
|
|
667
|
+
|
|
594
668
|
self.dbs = dbs
|
|
595
669
|
self.knowledge_dbs = knowledge_dbs
|
|
596
670
|
|
|
@@ -821,6 +895,36 @@ class AgentOS:
|
|
|
821
895
|
|
|
822
896
|
return evals_config
|
|
823
897
|
|
|
898
|
+
def _get_traces_config(self) -> TracesConfig:
|
|
899
|
+
traces_config = self.config.traces if self.config and self.config.traces else TracesConfig()
|
|
900
|
+
|
|
901
|
+
if traces_config.dbs is None:
|
|
902
|
+
traces_config.dbs = []
|
|
903
|
+
|
|
904
|
+
dbs_with_specific_config = [db.db_id for db in traces_config.dbs]
|
|
905
|
+
|
|
906
|
+
# If tracing_db is explicitly set, only use that database for traces
|
|
907
|
+
if self.tracing_db is not None:
|
|
908
|
+
if self.tracing_db.id not in dbs_with_specific_config:
|
|
909
|
+
traces_config.dbs.append(
|
|
910
|
+
DatabaseConfig(
|
|
911
|
+
db_id=self.tracing_db.id,
|
|
912
|
+
domain_config=TracesDomainConfig(display_name=self.tracing_db.id),
|
|
913
|
+
)
|
|
914
|
+
)
|
|
915
|
+
else:
|
|
916
|
+
# Fall back to all discovered databases
|
|
917
|
+
for db_id in self.dbs.keys():
|
|
918
|
+
if db_id not in dbs_with_specific_config:
|
|
919
|
+
traces_config.dbs.append(
|
|
920
|
+
DatabaseConfig(
|
|
921
|
+
db_id=db_id,
|
|
922
|
+
domain_config=TracesDomainConfig(display_name=db_id),
|
|
923
|
+
)
|
|
924
|
+
)
|
|
925
|
+
|
|
926
|
+
return traces_config
|
|
927
|
+
|
|
824
928
|
def serve(
|
|
825
929
|
self,
|
|
826
930
|
app: Union[str, FastAPI],
|
agno/os/config.py
CHANGED
|
@@ -36,6 +36,12 @@ class MemoryDomainConfig(BaseModel):
|
|
|
36
36
|
display_name: Optional[str] = None
|
|
37
37
|
|
|
38
38
|
|
|
39
|
+
class TracesDomainConfig(BaseModel):
|
|
40
|
+
"""Configuration for the Traces domain of the AgentOS"""
|
|
41
|
+
|
|
42
|
+
display_name: Optional[str] = None
|
|
43
|
+
|
|
44
|
+
|
|
39
45
|
DomainConfigType = TypeVar("DomainConfigType")
|
|
40
46
|
|
|
41
47
|
|
|
@@ -77,6 +83,12 @@ class MetricsConfig(MetricsDomainConfig):
|
|
|
77
83
|
dbs: Optional[List[DatabaseConfig[MetricsDomainConfig]]] = None
|
|
78
84
|
|
|
79
85
|
|
|
86
|
+
class TracesConfig(TracesDomainConfig):
|
|
87
|
+
"""Configuration for the Traces domain of the AgentOS"""
|
|
88
|
+
|
|
89
|
+
dbs: Optional[List[DatabaseConfig[TracesDomainConfig]]] = None
|
|
90
|
+
|
|
91
|
+
|
|
80
92
|
class ChatConfig(BaseModel):
|
|
81
93
|
"""Configuration for the Chat page of the AgentOS"""
|
|
82
94
|
|
|
@@ -102,3 +114,4 @@ class AgentOSConfig(BaseModel):
|
|
|
102
114
|
memory: Optional[MemoryConfig] = None
|
|
103
115
|
session: Optional[SessionConfig] = None
|
|
104
116
|
metrics: Optional[MetricsConfig] = None
|
|
117
|
+
traces: Optional[TracesConfig] = None
|
|
@@ -171,7 +171,6 @@ def attach_routes(router: APIRouter, agent: Optional[Agent] = None, team: Option
|
|
|
171
171
|
f"Could not process image content for user {phone_number}. Type: {type(image_content)}"
|
|
172
172
|
)
|
|
173
173
|
await _send_whatsapp_message(phone_number, response.content) # type: ignore
|
|
174
|
-
await _send_whatsapp_message(phone_number, response.content) # type: ignore
|
|
175
174
|
else:
|
|
176
175
|
await _send_whatsapp_message(phone_number, response.content) # type: ignore
|
|
177
176
|
|
agno/os/mcp.py
CHANGED
|
@@ -64,6 +64,7 @@ def get_mcp_server(
|
|
|
64
64
|
knowledge=os._get_knowledge_config(),
|
|
65
65
|
evals=os._get_evals_config(),
|
|
66
66
|
metrics=os._get_metrics_config(),
|
|
67
|
+
traces=os._get_traces_config(),
|
|
67
68
|
agents=[AgentSummaryResponse.from_agent(agent) for agent in os.agents] if os.agents else [],
|
|
68
69
|
teams=[TeamSummaryResponse.from_team(team) for team in os.teams] if os.teams else [],
|
|
69
70
|
workflows=[WorkflowSummaryResponse.from_workflow(w) for w in os.workflows] if os.workflows else [],
|