agno 2.2.13__py3-none-any.whl → 2.4.3__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/__init__.py +6 -0
- agno/agent/agent.py +5252 -3145
- agno/agent/remote.py +525 -0
- agno/api/api.py +2 -0
- agno/client/__init__.py +3 -0
- agno/client/a2a/__init__.py +10 -0
- agno/client/a2a/client.py +554 -0
- agno/client/a2a/schemas.py +112 -0
- agno/client/a2a/utils.py +369 -0
- agno/client/os.py +2669 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/manager.py +2 -2
- agno/db/base.py +927 -6
- agno/db/dynamo/dynamo.py +788 -2
- agno/db/dynamo/schemas.py +128 -0
- agno/db/dynamo/utils.py +26 -3
- agno/db/firestore/firestore.py +674 -50
- agno/db/firestore/schemas.py +41 -0
- agno/db/firestore/utils.py +25 -10
- agno/db/gcs_json/gcs_json_db.py +506 -3
- agno/db/gcs_json/utils.py +14 -2
- agno/db/in_memory/in_memory_db.py +203 -4
- agno/db/in_memory/utils.py +14 -2
- agno/db/json/json_db.py +498 -2
- agno/db/json/utils.py +14 -2
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/utils.py +19 -0
- agno/db/migrations/v1_to_v2.py +54 -16
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +977 -0
- agno/db/mongo/async_mongo.py +1013 -39
- agno/db/mongo/mongo.py +684 -4
- agno/db/mongo/schemas.py +48 -0
- agno/db/mongo/utils.py +17 -0
- agno/db/mysql/__init__.py +2 -1
- agno/db/mysql/async_mysql.py +2958 -0
- agno/db/mysql/mysql.py +722 -53
- agno/db/mysql/schemas.py +77 -11
- agno/db/mysql/utils.py +151 -8
- agno/db/postgres/async_postgres.py +1254 -137
- agno/db/postgres/postgres.py +2316 -93
- agno/db/postgres/schemas.py +153 -21
- agno/db/postgres/utils.py +22 -7
- agno/db/redis/redis.py +531 -3
- agno/db/redis/schemas.py +36 -0
- agno/db/redis/utils.py +31 -15
- agno/db/schemas/evals.py +1 -0
- agno/db/schemas/memory.py +20 -9
- agno/db/singlestore/schemas.py +70 -1
- agno/db/singlestore/singlestore.py +737 -74
- agno/db/singlestore/utils.py +13 -3
- agno/db/sqlite/async_sqlite.py +1069 -89
- agno/db/sqlite/schemas.py +133 -1
- agno/db/sqlite/sqlite.py +2203 -165
- agno/db/sqlite/utils.py +21 -11
- agno/db/surrealdb/models.py +25 -0
- agno/db/surrealdb/surrealdb.py +603 -1
- agno/db/utils.py +60 -0
- agno/eval/__init__.py +26 -3
- agno/eval/accuracy.py +25 -12
- agno/eval/agent_as_judge.py +871 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +10 -4
- agno/eval/reliability.py +22 -13
- agno/eval/utils.py +2 -1
- agno/exceptions.py +42 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/client.py +13 -2
- agno/knowledge/__init__.py +4 -0
- agno/knowledge/chunking/code.py +90 -0
- agno/knowledge/chunking/document.py +65 -4
- agno/knowledge/chunking/fixed.py +4 -1
- agno/knowledge/chunking/markdown.py +102 -11
- agno/knowledge/chunking/recursive.py +2 -2
- agno/knowledge/chunking/semantic.py +130 -48
- agno/knowledge/chunking/strategy.py +18 -0
- agno/knowledge/embedder/azure_openai.py +0 -1
- agno/knowledge/embedder/google.py +1 -1
- agno/knowledge/embedder/mistral.py +1 -1
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/openai.py +16 -12
- agno/knowledge/filesystem.py +412 -0
- agno/knowledge/knowledge.py +4261 -1199
- agno/knowledge/protocol.py +134 -0
- agno/knowledge/reader/arxiv_reader.py +3 -2
- agno/knowledge/reader/base.py +9 -7
- agno/knowledge/reader/csv_reader.py +91 -42
- agno/knowledge/reader/docx_reader.py +9 -10
- agno/knowledge/reader/excel_reader.py +225 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +38 -48
- agno/knowledge/reader/firecrawl_reader.py +3 -2
- agno/knowledge/reader/json_reader.py +16 -22
- agno/knowledge/reader/markdown_reader.py +15 -14
- agno/knowledge/reader/pdf_reader.py +33 -28
- agno/knowledge/reader/pptx_reader.py +9 -10
- agno/knowledge/reader/reader_factory.py +135 -1
- agno/knowledge/reader/s3_reader.py +8 -16
- agno/knowledge/reader/tavily_reader.py +3 -3
- agno/knowledge/reader/text_reader.py +15 -14
- agno/knowledge/reader/utils/__init__.py +17 -0
- agno/knowledge/reader/utils/spreadsheet.py +114 -0
- agno/knowledge/reader/web_search_reader.py +8 -65
- agno/knowledge/reader/website_reader.py +16 -13
- agno/knowledge/reader/wikipedia_reader.py +36 -3
- agno/knowledge/reader/youtube_reader.py +3 -2
- agno/knowledge/remote_content/__init__.py +33 -0
- agno/knowledge/remote_content/config.py +266 -0
- agno/knowledge/remote_content/remote_content.py +105 -17
- agno/knowledge/utils.py +76 -22
- agno/learn/__init__.py +71 -0
- agno/learn/config.py +463 -0
- agno/learn/curate.py +185 -0
- agno/learn/machine.py +725 -0
- agno/learn/schemas.py +1114 -0
- agno/learn/stores/__init__.py +38 -0
- agno/learn/stores/decision_log.py +1156 -0
- agno/learn/stores/entity_memory.py +3275 -0
- agno/learn/stores/learned_knowledge.py +1583 -0
- agno/learn/stores/protocol.py +117 -0
- agno/learn/stores/session_context.py +1217 -0
- agno/learn/stores/user_memory.py +1495 -0
- agno/learn/stores/user_profile.py +1220 -0
- agno/learn/utils.py +209 -0
- agno/media.py +22 -6
- agno/memory/__init__.py +14 -1
- agno/memory/manager.py +223 -8
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/aimlapi.py +17 -0
- agno/models/anthropic/claude.py +434 -59
- agno/models/aws/bedrock.py +121 -20
- agno/models/aws/claude.py +131 -274
- agno/models/azure/ai_foundry.py +10 -6
- agno/models/azure/openai_chat.py +33 -10
- agno/models/base.py +1162 -561
- agno/models/cerebras/cerebras.py +120 -24
- agno/models/cerebras/cerebras_openai.py +21 -2
- agno/models/cohere/chat.py +65 -6
- agno/models/cometapi/cometapi.py +18 -1
- agno/models/dashscope/dashscope.py +2 -3
- agno/models/deepinfra/deepinfra.py +18 -1
- agno/models/deepseek/deepseek.py +69 -3
- agno/models/fireworks/fireworks.py +18 -1
- agno/models/google/gemini.py +959 -89
- agno/models/google/utils.py +22 -0
- agno/models/groq/groq.py +48 -18
- agno/models/huggingface/huggingface.py +17 -6
- agno/models/ibm/watsonx.py +16 -6
- agno/models/internlm/internlm.py +18 -1
- agno/models/langdb/langdb.py +13 -1
- agno/models/litellm/chat.py +88 -9
- agno/models/litellm/litellm_openai.py +18 -1
- agno/models/message.py +24 -5
- agno/models/meta/llama.py +40 -13
- agno/models/meta/llama_openai.py +22 -21
- agno/models/metrics.py +12 -0
- agno/models/mistral/mistral.py +8 -4
- agno/models/n1n/__init__.py +3 -0
- agno/models/n1n/n1n.py +57 -0
- agno/models/nebius/nebius.py +6 -7
- agno/models/nvidia/nvidia.py +20 -3
- agno/models/ollama/__init__.py +2 -0
- agno/models/ollama/chat.py +17 -6
- agno/models/ollama/responses.py +100 -0
- agno/models/openai/__init__.py +2 -0
- agno/models/openai/chat.py +117 -26
- agno/models/openai/open_responses.py +46 -0
- agno/models/openai/responses.py +110 -32
- agno/models/openrouter/__init__.py +2 -0
- agno/models/openrouter/openrouter.py +67 -2
- agno/models/openrouter/responses.py +146 -0
- agno/models/perplexity/perplexity.py +19 -1
- agno/models/portkey/portkey.py +7 -6
- agno/models/requesty/requesty.py +19 -2
- agno/models/response.py +20 -2
- agno/models/sambanova/sambanova.py +20 -3
- agno/models/siliconflow/siliconflow.py +19 -2
- agno/models/together/together.py +20 -3
- agno/models/vercel/v0.py +20 -3
- agno/models/vertexai/claude.py +124 -4
- agno/models/vllm/vllm.py +19 -14
- agno/models/xai/xai.py +19 -2
- agno/os/app.py +467 -137
- agno/os/auth.py +253 -5
- agno/os/config.py +22 -0
- agno/os/interfaces/a2a/a2a.py +7 -6
- agno/os/interfaces/a2a/router.py +635 -26
- agno/os/interfaces/a2a/utils.py +32 -33
- agno/os/interfaces/agui/agui.py +5 -3
- agno/os/interfaces/agui/router.py +26 -16
- agno/os/interfaces/agui/utils.py +97 -57
- agno/os/interfaces/base.py +7 -7
- agno/os/interfaces/slack/router.py +16 -7
- agno/os/interfaces/slack/slack.py +7 -7
- agno/os/interfaces/whatsapp/router.py +35 -7
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/interfaces/whatsapp/whatsapp.py +11 -8
- agno/os/managers.py +326 -0
- agno/os/mcp.py +652 -79
- agno/os/middleware/__init__.py +4 -0
- agno/os/middleware/jwt.py +718 -115
- agno/os/middleware/trailing_slash.py +27 -0
- agno/os/router.py +105 -1558
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +655 -0
- agno/os/routers/agents/schema.py +288 -0
- agno/os/routers/components/__init__.py +3 -0
- agno/os/routers/components/components.py +475 -0
- agno/os/routers/database.py +155 -0
- agno/os/routers/evals/evals.py +111 -18
- agno/os/routers/evals/schemas.py +38 -5
- agno/os/routers/evals/utils.py +80 -11
- agno/os/routers/health.py +3 -3
- agno/os/routers/knowledge/knowledge.py +284 -35
- agno/os/routers/knowledge/schemas.py +14 -2
- agno/os/routers/memory/memory.py +274 -11
- agno/os/routers/memory/schemas.py +44 -3
- agno/os/routers/metrics/metrics.py +30 -15
- agno/os/routers/metrics/schemas.py +10 -6
- agno/os/routers/registry/__init__.py +3 -0
- agno/os/routers/registry/registry.py +337 -0
- agno/os/routers/session/session.py +143 -14
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +550 -0
- agno/os/routers/teams/schema.py +280 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +549 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +757 -0
- agno/os/routers/workflows/schema.py +139 -0
- agno/os/schema.py +157 -584
- agno/os/scopes.py +469 -0
- agno/os/settings.py +3 -0
- agno/os/utils.py +574 -185
- agno/reasoning/anthropic.py +85 -1
- agno/reasoning/azure_ai_foundry.py +93 -1
- agno/reasoning/deepseek.py +102 -2
- agno/reasoning/default.py +6 -7
- agno/reasoning/gemini.py +87 -3
- agno/reasoning/groq.py +109 -2
- agno/reasoning/helpers.py +6 -7
- agno/reasoning/manager.py +1238 -0
- agno/reasoning/ollama.py +93 -1
- agno/reasoning/openai.py +115 -1
- agno/reasoning/vertexai.py +85 -1
- agno/registry/__init__.py +3 -0
- agno/registry/registry.py +68 -0
- agno/remote/__init__.py +3 -0
- agno/remote/base.py +581 -0
- agno/run/__init__.py +2 -4
- agno/run/agent.py +134 -19
- agno/run/base.py +49 -1
- agno/run/cancel.py +65 -52
- agno/run/cancellation_management/__init__.py +9 -0
- agno/run/cancellation_management/base.py +78 -0
- agno/run/cancellation_management/in_memory_cancellation_manager.py +100 -0
- agno/run/cancellation_management/redis_cancellation_manager.py +236 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +111 -19
- agno/run/workflow.py +2 -1
- agno/session/agent.py +57 -92
- agno/session/summary.py +1 -1
- agno/session/team.py +62 -115
- agno/session/workflow.py +353 -57
- agno/skills/__init__.py +17 -0
- agno/skills/agent_skills.py +377 -0
- agno/skills/errors.py +32 -0
- agno/skills/loaders/__init__.py +4 -0
- agno/skills/loaders/base.py +27 -0
- agno/skills/loaders/local.py +216 -0
- agno/skills/skill.py +65 -0
- agno/skills/utils.py +107 -0
- agno/skills/validator.py +277 -0
- agno/table.py +10 -0
- agno/team/__init__.py +5 -1
- agno/team/remote.py +447 -0
- agno/team/team.py +3769 -2202
- agno/tools/brandfetch.py +27 -18
- agno/tools/browserbase.py +225 -16
- agno/tools/crawl4ai.py +3 -0
- agno/tools/duckduckgo.py +25 -71
- agno/tools/exa.py +0 -21
- agno/tools/file.py +14 -13
- agno/tools/file_generation.py +12 -6
- agno/tools/firecrawl.py +15 -7
- agno/tools/function.py +94 -113
- agno/tools/google_bigquery.py +11 -2
- agno/tools/google_drive.py +4 -3
- agno/tools/knowledge.py +9 -4
- agno/tools/mcp/mcp.py +301 -18
- agno/tools/mcp/multi_mcp.py +269 -14
- agno/tools/mem0.py +11 -10
- agno/tools/memory.py +47 -46
- agno/tools/mlx_transcribe.py +10 -7
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/nano_banana.py +151 -0
- agno/tools/parallel.py +0 -7
- agno/tools/postgres.py +76 -36
- agno/tools/python.py +14 -6
- agno/tools/reasoning.py +30 -23
- agno/tools/redshift.py +406 -0
- agno/tools/shopify.py +1519 -0
- agno/tools/spotify.py +919 -0
- agno/tools/tavily.py +4 -1
- agno/tools/toolkit.py +253 -18
- agno/tools/websearch.py +93 -0
- agno/tools/website.py +1 -1
- agno/tools/wikipedia.py +1 -1
- agno/tools/workflow.py +56 -48
- agno/tools/yfinance.py +12 -11
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +161 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +112 -0
- agno/utils/agent.py +251 -10
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +264 -7
- agno/utils/hooks.py +111 -3
- agno/utils/http.py +161 -2
- agno/utils/mcp.py +49 -8
- agno/utils/media.py +22 -1
- agno/utils/models/ai_foundry.py +9 -2
- agno/utils/models/claude.py +20 -5
- agno/utils/models/cohere.py +9 -2
- agno/utils/models/llama.py +9 -2
- agno/utils/models/mistral.py +4 -2
- agno/utils/os.py +0 -0
- agno/utils/print_response/agent.py +99 -16
- agno/utils/print_response/team.py +223 -24
- agno/utils/print_response/workflow.py +0 -2
- agno/utils/prompts.py +8 -6
- agno/utils/remote.py +23 -0
- agno/utils/response.py +1 -13
- agno/utils/string.py +91 -2
- agno/utils/team.py +62 -12
- agno/utils/tokens.py +657 -0
- agno/vectordb/base.py +15 -2
- agno/vectordb/cassandra/cassandra.py +1 -1
- agno/vectordb/chroma/__init__.py +2 -1
- agno/vectordb/chroma/chromadb.py +468 -23
- agno/vectordb/clickhouse/clickhousedb.py +1 -1
- agno/vectordb/couchbase/couchbase.py +6 -2
- agno/vectordb/lancedb/lance_db.py +7 -38
- agno/vectordb/lightrag/lightrag.py +7 -6
- agno/vectordb/milvus/milvus.py +118 -84
- agno/vectordb/mongodb/__init__.py +2 -1
- agno/vectordb/mongodb/mongodb.py +14 -31
- agno/vectordb/pgvector/pgvector.py +120 -66
- agno/vectordb/pineconedb/pineconedb.py +2 -19
- agno/vectordb/qdrant/__init__.py +2 -1
- agno/vectordb/qdrant/qdrant.py +33 -56
- agno/vectordb/redis/__init__.py +2 -1
- agno/vectordb/redis/redisdb.py +19 -31
- agno/vectordb/singlestore/singlestore.py +17 -9
- agno/vectordb/surrealdb/surrealdb.py +2 -38
- agno/vectordb/weaviate/__init__.py +2 -1
- agno/vectordb/weaviate/weaviate.py +7 -3
- agno/workflow/__init__.py +5 -1
- agno/workflow/agent.py +2 -2
- agno/workflow/condition.py +12 -10
- agno/workflow/loop.py +28 -9
- agno/workflow/parallel.py +21 -13
- agno/workflow/remote.py +362 -0
- agno/workflow/router.py +12 -9
- agno/workflow/step.py +261 -36
- agno/workflow/steps.py +12 -8
- agno/workflow/types.py +40 -77
- agno/workflow/workflow.py +939 -213
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/METADATA +134 -181
- agno-2.4.3.dist-info/RECORD +677 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/WHEEL +1 -1
- agno/tools/googlesearch.py +0 -98
- agno/tools/memori.py +0 -339
- agno-2.2.13.dist-info/RECORD +0 -575
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/top_level.txt +0 -0
agno/team/remote.py
ADDED
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, List, Literal, Optional, Sequence, Tuple, Union, overload
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
from agno.media import Audio, File, Image, Video
|
|
7
|
+
from agno.models.base import Model
|
|
8
|
+
from agno.models.message import Message
|
|
9
|
+
from agno.remote.base import BaseRemote, RemoteDb, RemoteKnowledge
|
|
10
|
+
from agno.run.agent import RunOutputEvent
|
|
11
|
+
from agno.run.team import TeamRunOutput, TeamRunOutputEvent
|
|
12
|
+
from agno.utils.agent import validate_input
|
|
13
|
+
from agno.utils.log import log_warning
|
|
14
|
+
from agno.utils.remote import serialize_input
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from agno.os.routers.teams.schema import TeamResponse
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class RemoteTeam(BaseRemote):
|
|
21
|
+
# Private cache for team config with TTL: (config, timestamp)
|
|
22
|
+
_cached_team_config: Optional[Tuple["TeamResponse", float]] = None
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
base_url: str,
|
|
27
|
+
team_id: str,
|
|
28
|
+
timeout: float = 300.0,
|
|
29
|
+
protocol: Literal["agentos", "a2a"] = "agentos",
|
|
30
|
+
a2a_protocol: Literal["json-rpc", "rest"] = "rest",
|
|
31
|
+
config_ttl: float = 300.0,
|
|
32
|
+
):
|
|
33
|
+
"""Initialize RemoteTeam for remote execution.
|
|
34
|
+
|
|
35
|
+
Supports two protocols:
|
|
36
|
+
- "agentos": Agno's proprietary AgentOS REST API (default)
|
|
37
|
+
- "a2a": A2A (Agent-to-Agent) protocol for cross-framework communication
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
base_url: Base URL for remote instance (e.g., "http://localhost:7777")
|
|
41
|
+
team_id: ID of remote team on the remote server
|
|
42
|
+
timeout: Request timeout in seconds (default: 300)
|
|
43
|
+
protocol: Communication protocol - "agentos" (default) or "a2a"
|
|
44
|
+
a2a_protocol: For A2A protocol only - Whether to use JSON-RPC or REST protocol.
|
|
45
|
+
config_ttl: Time-to-live for cached config in seconds (default: 300)
|
|
46
|
+
"""
|
|
47
|
+
super().__init__(base_url, timeout, protocol, a2a_protocol, config_ttl)
|
|
48
|
+
self.team_id = team_id
|
|
49
|
+
self._cached_team_config = None
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def id(self) -> str:
|
|
53
|
+
return self.team_id
|
|
54
|
+
|
|
55
|
+
async def get_team_config(self) -> "TeamResponse":
|
|
56
|
+
"""
|
|
57
|
+
Get the team config from remote.
|
|
58
|
+
|
|
59
|
+
- For AgentOS protocol, always fetches fresh config from the remote.
|
|
60
|
+
- For A2A protocol, returns a minimal TeamResponse because A2A servers
|
|
61
|
+
do not expose detailed config endpoints.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
TeamResponse: The remote team configuration.
|
|
65
|
+
"""
|
|
66
|
+
from agno.os.routers.teams.schema import TeamResponse
|
|
67
|
+
|
|
68
|
+
if self.a2a_client:
|
|
69
|
+
from agno.client.a2a.schemas import AgentCard
|
|
70
|
+
|
|
71
|
+
agent_card: Optional[AgentCard] = await self.a2a_client.aget_agent_card()
|
|
72
|
+
|
|
73
|
+
return TeamResponse(
|
|
74
|
+
id=self.team_id,
|
|
75
|
+
name=agent_card.name if agent_card else self.team_id,
|
|
76
|
+
description=agent_card.description if agent_card else f"A2A team: {self.team_id}",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Fetch fresh config from remote for AgentOS
|
|
80
|
+
return await self.agentos_client.aget_team(self.team_id) # type: ignore
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def _team_config(self) -> Optional["TeamResponse"]:
|
|
84
|
+
"""
|
|
85
|
+
Get the team config from remote, cached with TTL.
|
|
86
|
+
|
|
87
|
+
- Returns None for A2A protocol (no config available).
|
|
88
|
+
- For AgentOS protocol, uses TTL caching for efficiency.
|
|
89
|
+
"""
|
|
90
|
+
import time
|
|
91
|
+
|
|
92
|
+
from agno.os.routers.teams.schema import TeamResponse
|
|
93
|
+
|
|
94
|
+
if self.a2a_client:
|
|
95
|
+
from agno.client.a2a.schemas import AgentCard
|
|
96
|
+
|
|
97
|
+
agent_card: Optional[AgentCard] = self.a2a_client.get_agent_card()
|
|
98
|
+
|
|
99
|
+
return TeamResponse(
|
|
100
|
+
id=self.team_id,
|
|
101
|
+
name=agent_card.name if agent_card else self.team_id,
|
|
102
|
+
description=agent_card.description if agent_card else f"A2A team: {self.team_id}",
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
current_time = time.time()
|
|
106
|
+
if self._cached_team_config is not None:
|
|
107
|
+
config, cached_at = self._cached_team_config
|
|
108
|
+
if current_time - cached_at < self.config_ttl:
|
|
109
|
+
return config
|
|
110
|
+
|
|
111
|
+
# Fetch fresh config and update cache
|
|
112
|
+
config: TeamResponse = self.agentos_client.get_team(self.team_id) # type: ignore
|
|
113
|
+
self._cached_team_config = (config, current_time)
|
|
114
|
+
return config
|
|
115
|
+
|
|
116
|
+
async def refresh_config(self) -> Optional["TeamResponse"]:
|
|
117
|
+
"""
|
|
118
|
+
Force refresh the cached team config from remote.
|
|
119
|
+
"""
|
|
120
|
+
import time
|
|
121
|
+
|
|
122
|
+
from agno.os.routers.teams.schema import TeamResponse
|
|
123
|
+
|
|
124
|
+
if self.a2a_client:
|
|
125
|
+
return None
|
|
126
|
+
|
|
127
|
+
config: TeamResponse = await self.agentos_client.aget_team(self.team_id) # type: ignore
|
|
128
|
+
self._cached_team_config = (config, time.time())
|
|
129
|
+
return config
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def name(self) -> Optional[str]:
|
|
133
|
+
config = self._team_config
|
|
134
|
+
if config is not None:
|
|
135
|
+
return config.name
|
|
136
|
+
return self.team_id
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def description(self) -> Optional[str]:
|
|
140
|
+
config = self._team_config
|
|
141
|
+
if config is not None:
|
|
142
|
+
return config.description
|
|
143
|
+
return ""
|
|
144
|
+
|
|
145
|
+
def role(self) -> Optional[str]:
|
|
146
|
+
if self._team_config is not None:
|
|
147
|
+
return self._team_config.role
|
|
148
|
+
return None
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
def tools(self) -> Optional[List[Dict[str, Any]]]:
|
|
152
|
+
if self._team_config is not None:
|
|
153
|
+
try:
|
|
154
|
+
return json.loads(self._team_config.tools["tools"]) if self._team_config.tools else None
|
|
155
|
+
except Exception as e:
|
|
156
|
+
log_warning(f"Failed to load tools for team {self.team_id}: {e}")
|
|
157
|
+
return None
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def db(self) -> Optional[RemoteDb]:
|
|
162
|
+
if (
|
|
163
|
+
self.agentos_client
|
|
164
|
+
and self._config
|
|
165
|
+
and self._team_config is not None
|
|
166
|
+
and self._team_config.db_id is not None
|
|
167
|
+
):
|
|
168
|
+
return RemoteDb.from_config(
|
|
169
|
+
db_id=self._team_config.db_id,
|
|
170
|
+
client=self.agentos_client,
|
|
171
|
+
config=self._config,
|
|
172
|
+
)
|
|
173
|
+
return None
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def knowledge(self) -> Optional[RemoteKnowledge]:
|
|
177
|
+
"""Whether the team has knowledge enabled."""
|
|
178
|
+
if self.agentos_client and self._team_config is not None and self._team_config.knowledge is not None:
|
|
179
|
+
return RemoteKnowledge(
|
|
180
|
+
client=self.agentos_client,
|
|
181
|
+
contents_db=RemoteDb(
|
|
182
|
+
id=self._team_config.knowledge.get("db_id"), # type: ignore
|
|
183
|
+
client=self.agentos_client,
|
|
184
|
+
knowledge_table_name=self._team_config.knowledge.get("knowledge_table"),
|
|
185
|
+
)
|
|
186
|
+
if self._team_config.knowledge.get("db_id") is not None
|
|
187
|
+
else None,
|
|
188
|
+
)
|
|
189
|
+
return None
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def model(self) -> Optional[Model]:
|
|
193
|
+
# We don't expose the remote team's models, since they can't be used by other services in AgentOS.
|
|
194
|
+
return None
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def user_id(self) -> Optional[str]:
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
@overload
|
|
201
|
+
async def arun(
|
|
202
|
+
self,
|
|
203
|
+
input: Union[str, List, Dict, Message, BaseModel, List[Message]],
|
|
204
|
+
*,
|
|
205
|
+
stream: Literal[False] = False,
|
|
206
|
+
user_id: Optional[str] = None,
|
|
207
|
+
session_id: Optional[str] = None,
|
|
208
|
+
session_state: Optional[Dict[str, Any]] = None,
|
|
209
|
+
audio: Optional[Sequence[Audio]] = None,
|
|
210
|
+
images: Optional[Sequence[Image]] = None,
|
|
211
|
+
videos: Optional[Sequence[Video]] = None,
|
|
212
|
+
files: Optional[Sequence[File]] = None,
|
|
213
|
+
stream_events: Optional[bool] = None,
|
|
214
|
+
retries: Optional[int] = None,
|
|
215
|
+
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
216
|
+
add_history_to_context: Optional[bool] = None,
|
|
217
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
218
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
219
|
+
dependencies: Optional[Dict[str, Any]] = None,
|
|
220
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
221
|
+
auth_token: Optional[str] = None,
|
|
222
|
+
**kwargs: Any,
|
|
223
|
+
) -> TeamRunOutput: ...
|
|
224
|
+
|
|
225
|
+
@overload
|
|
226
|
+
def arun(
|
|
227
|
+
self,
|
|
228
|
+
input: Union[str, List, Dict, Message, BaseModel, List[Message]],
|
|
229
|
+
*,
|
|
230
|
+
stream: Literal[True] = True,
|
|
231
|
+
user_id: Optional[str] = None,
|
|
232
|
+
session_id: Optional[str] = None,
|
|
233
|
+
audio: Optional[Sequence[Audio]] = None,
|
|
234
|
+
images: Optional[Sequence[Image]] = None,
|
|
235
|
+
videos: Optional[Sequence[Video]] = None,
|
|
236
|
+
files: Optional[Sequence[File]] = None,
|
|
237
|
+
stream_events: Optional[bool] = None,
|
|
238
|
+
retries: Optional[int] = None,
|
|
239
|
+
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
240
|
+
add_history_to_context: Optional[bool] = None,
|
|
241
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
242
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
243
|
+
dependencies: Optional[Dict[str, Any]] = None,
|
|
244
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
245
|
+
auth_token: Optional[str] = None,
|
|
246
|
+
**kwargs: Any,
|
|
247
|
+
) -> AsyncIterator[TeamRunOutputEvent]: ...
|
|
248
|
+
|
|
249
|
+
def arun( # type: ignore
|
|
250
|
+
self,
|
|
251
|
+
input: Union[str, List, Dict, Message, BaseModel, List[Message]],
|
|
252
|
+
*,
|
|
253
|
+
stream: Optional[bool] = None,
|
|
254
|
+
user_id: Optional[str] = None,
|
|
255
|
+
session_id: Optional[str] = None,
|
|
256
|
+
session_state: Optional[Dict[str, Any]] = None,
|
|
257
|
+
audio: Optional[Sequence[Audio]] = None,
|
|
258
|
+
images: Optional[Sequence[Image]] = None,
|
|
259
|
+
videos: Optional[Sequence[Video]] = None,
|
|
260
|
+
files: Optional[Sequence[File]] = None,
|
|
261
|
+
stream_events: Optional[bool] = None,
|
|
262
|
+
retries: Optional[int] = None,
|
|
263
|
+
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
264
|
+
add_history_to_context: Optional[bool] = None,
|
|
265
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
266
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
267
|
+
dependencies: Optional[Dict[str, Any]] = None,
|
|
268
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
269
|
+
auth_token: Optional[str] = None,
|
|
270
|
+
**kwargs: Any,
|
|
271
|
+
) -> Union[
|
|
272
|
+
TeamRunOutput,
|
|
273
|
+
AsyncIterator[RunOutputEvent],
|
|
274
|
+
]:
|
|
275
|
+
validated_input = validate_input(input)
|
|
276
|
+
serialized_input = serialize_input(validated_input)
|
|
277
|
+
headers = self._get_auth_headers(auth_token)
|
|
278
|
+
|
|
279
|
+
# A2A protocol path
|
|
280
|
+
if self.a2a_client:
|
|
281
|
+
return self._arun_a2a( # type: ignore[return-value]
|
|
282
|
+
message=serialized_input,
|
|
283
|
+
stream=stream or False,
|
|
284
|
+
user_id=user_id,
|
|
285
|
+
context_id=session_id, # Map session_id → context_id for A2A
|
|
286
|
+
audio=audio,
|
|
287
|
+
images=images,
|
|
288
|
+
videos=videos,
|
|
289
|
+
files=files,
|
|
290
|
+
headers=headers,
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
# AgentOS protocol path (default)
|
|
294
|
+
if self.agentos_client:
|
|
295
|
+
if stream:
|
|
296
|
+
# Handle streaming response
|
|
297
|
+
return self.agentos_client.run_team_stream( # type: ignore
|
|
298
|
+
team_id=self.team_id,
|
|
299
|
+
message=serialized_input,
|
|
300
|
+
session_id=session_id,
|
|
301
|
+
user_id=user_id,
|
|
302
|
+
audio=audio,
|
|
303
|
+
images=images,
|
|
304
|
+
videos=videos,
|
|
305
|
+
files=files,
|
|
306
|
+
session_state=session_state,
|
|
307
|
+
stream_events=stream_events,
|
|
308
|
+
retries=retries,
|
|
309
|
+
knowledge_filters=knowledge_filters,
|
|
310
|
+
add_history_to_context=add_history_to_context,
|
|
311
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
312
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
313
|
+
dependencies=dependencies,
|
|
314
|
+
metadata=metadata,
|
|
315
|
+
headers=headers,
|
|
316
|
+
**kwargs,
|
|
317
|
+
)
|
|
318
|
+
else:
|
|
319
|
+
return self.agentos_client.run_team( # type: ignore
|
|
320
|
+
team_id=self.team_id,
|
|
321
|
+
message=serialized_input,
|
|
322
|
+
session_id=session_id,
|
|
323
|
+
user_id=user_id,
|
|
324
|
+
audio=audio,
|
|
325
|
+
images=images,
|
|
326
|
+
videos=videos,
|
|
327
|
+
files=files,
|
|
328
|
+
session_state=session_state,
|
|
329
|
+
stream_events=stream_events,
|
|
330
|
+
retries=retries,
|
|
331
|
+
knowledge_filters=knowledge_filters,
|
|
332
|
+
add_history_to_context=add_history_to_context,
|
|
333
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
334
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
335
|
+
dependencies=dependencies,
|
|
336
|
+
metadata=metadata,
|
|
337
|
+
headers=headers,
|
|
338
|
+
**kwargs,
|
|
339
|
+
)
|
|
340
|
+
else:
|
|
341
|
+
raise ValueError("No client available")
|
|
342
|
+
|
|
343
|
+
def _arun_a2a(
|
|
344
|
+
self,
|
|
345
|
+
message: str,
|
|
346
|
+
stream: bool,
|
|
347
|
+
user_id: Optional[str],
|
|
348
|
+
context_id: Optional[str],
|
|
349
|
+
audio: Optional[Sequence[Audio]],
|
|
350
|
+
images: Optional[Sequence[Image]],
|
|
351
|
+
videos: Optional[Sequence[Video]],
|
|
352
|
+
files: Optional[Sequence[File]],
|
|
353
|
+
headers: Optional[Dict[str, str]],
|
|
354
|
+
) -> Union[TeamRunOutput, AsyncIterator[TeamRunOutputEvent]]:
|
|
355
|
+
"""Execute via A2A protocol.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
message: Serialized message string
|
|
359
|
+
stream: Whether to stream the response
|
|
360
|
+
user_id: User identifier
|
|
361
|
+
context_id: Session/context ID (maps to session_id)
|
|
362
|
+
audio: Audio files to include
|
|
363
|
+
images: Images to include
|
|
364
|
+
videos: Videos to include
|
|
365
|
+
files: Files to include
|
|
366
|
+
headers: HTTP headers to include in the request (optional)
|
|
367
|
+
Returns:
|
|
368
|
+
TeamRunOutput for non-streaming, AsyncIterator[TeamRunOutputEvent] for streaming
|
|
369
|
+
"""
|
|
370
|
+
from agno.client.a2a.utils import map_stream_events_to_team_run_events
|
|
371
|
+
|
|
372
|
+
if not self.a2a_client:
|
|
373
|
+
raise ValueError("A2A client not available")
|
|
374
|
+
if stream:
|
|
375
|
+
# Return async generator for streaming
|
|
376
|
+
event_stream = self.a2a_client.stream_message(
|
|
377
|
+
message=message,
|
|
378
|
+
context_id=context_id,
|
|
379
|
+
user_id=user_id,
|
|
380
|
+
audio=list(audio) if audio else None,
|
|
381
|
+
images=list(images) if images else None,
|
|
382
|
+
videos=list(videos) if videos else None,
|
|
383
|
+
files=list(files) if files else None,
|
|
384
|
+
headers=headers,
|
|
385
|
+
)
|
|
386
|
+
return map_stream_events_to_team_run_events(event_stream, team_id=self.team_id)
|
|
387
|
+
else:
|
|
388
|
+
# Return coroutine for non-streaming
|
|
389
|
+
return self._arun_a2a_send( # type: ignore[return-value]
|
|
390
|
+
message=message,
|
|
391
|
+
user_id=user_id,
|
|
392
|
+
context_id=context_id,
|
|
393
|
+
audio=audio,
|
|
394
|
+
images=images,
|
|
395
|
+
videos=videos,
|
|
396
|
+
files=files,
|
|
397
|
+
headers=headers,
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
async def _arun_a2a_send(
|
|
401
|
+
self,
|
|
402
|
+
message: str,
|
|
403
|
+
user_id: Optional[str],
|
|
404
|
+
context_id: Optional[str],
|
|
405
|
+
audio: Optional[Sequence[Audio]],
|
|
406
|
+
images: Optional[Sequence[Image]],
|
|
407
|
+
videos: Optional[Sequence[Video]],
|
|
408
|
+
files: Optional[Sequence[File]],
|
|
409
|
+
headers: Optional[Dict[str, str]],
|
|
410
|
+
) -> TeamRunOutput:
|
|
411
|
+
"""Send a non-streaming A2A message and convert response to TeamRunOutput."""
|
|
412
|
+
if not self.a2a_client:
|
|
413
|
+
raise ValueError("A2A client not available")
|
|
414
|
+
from agno.client.a2a.utils import map_task_result_to_team_run_output
|
|
415
|
+
|
|
416
|
+
task_result = await self.a2a_client.send_message(
|
|
417
|
+
message=message,
|
|
418
|
+
context_id=context_id,
|
|
419
|
+
user_id=user_id,
|
|
420
|
+
images=list(images) if images else None,
|
|
421
|
+
audio=list(audio) if audio else None,
|
|
422
|
+
videos=list(videos) if videos else None,
|
|
423
|
+
files=list(files) if files else None,
|
|
424
|
+
headers=headers,
|
|
425
|
+
)
|
|
426
|
+
return map_task_result_to_team_run_output(task_result, team_id=self.team_id, user_id=user_id)
|
|
427
|
+
|
|
428
|
+
async def acancel_run(self, run_id: str, auth_token: Optional[str] = None) -> bool:
|
|
429
|
+
"""Cancel a running team execution.
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
run_id (str): The run_id to cancel.
|
|
433
|
+
auth_token: Optional JWT token for authentication.
|
|
434
|
+
|
|
435
|
+
Returns:
|
|
436
|
+
bool: True if the run was found and marked for cancellation, False otherwise.
|
|
437
|
+
"""
|
|
438
|
+
headers = self._get_auth_headers(auth_token)
|
|
439
|
+
try:
|
|
440
|
+
await self.agentos_client.cancel_team_run( # type: ignore
|
|
441
|
+
team_id=self.team_id,
|
|
442
|
+
run_id=run_id,
|
|
443
|
+
headers=headers,
|
|
444
|
+
)
|
|
445
|
+
return True
|
|
446
|
+
except Exception:
|
|
447
|
+
return False
|