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/agent/remote.py
ADDED
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, List, Literal, Optional, Sequence, Tuple, Union, overload
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
from agno.media import Audio, File, Image, Video
|
|
8
|
+
from agno.models.base import Model
|
|
9
|
+
from agno.models.message import Message
|
|
10
|
+
from agno.models.response import ToolExecution
|
|
11
|
+
from agno.remote.base import BaseRemote, RemoteDb, RemoteKnowledge
|
|
12
|
+
from agno.run.agent import RunOutput, RunOutputEvent
|
|
13
|
+
from agno.utils.agent import validate_input
|
|
14
|
+
from agno.utils.log import log_warning
|
|
15
|
+
from agno.utils.remote import serialize_input
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from agno.os.routers.agents.schema import AgentResponse
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class RemoteAgent(BaseRemote):
|
|
23
|
+
# Private cache for agent config with TTL: (config, timestamp)
|
|
24
|
+
_cached_agent_config: Optional[Tuple["AgentResponse", float]] = field(default=None, init=False, repr=False)
|
|
25
|
+
|
|
26
|
+
knowledge_filters: Optional[Dict[str, Any]] = None
|
|
27
|
+
enable_agentic_knowledge_filters: Optional[bool] = False
|
|
28
|
+
output_schema: Optional[Any] = None
|
|
29
|
+
store_media: bool = True
|
|
30
|
+
store_tool_messages: bool = True
|
|
31
|
+
store_history_messages: bool = True
|
|
32
|
+
send_media_to_model: bool = True
|
|
33
|
+
add_history_to_context: bool = False
|
|
34
|
+
num_history_runs: Optional[int] = None
|
|
35
|
+
num_history_messages: Optional[int] = None
|
|
36
|
+
debug_mode: bool = False
|
|
37
|
+
debug_level: Literal[1, 2] = 1
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
base_url: str,
|
|
42
|
+
agent_id: str,
|
|
43
|
+
timeout: float = 60.0,
|
|
44
|
+
protocol: Literal["agentos", "a2a"] = "agentos",
|
|
45
|
+
a2a_protocol: Literal["json-rpc", "rest"] = "rest",
|
|
46
|
+
config_ttl: float = 300.0,
|
|
47
|
+
):
|
|
48
|
+
"""Initialize RemoteAgent for remote execution.
|
|
49
|
+
|
|
50
|
+
Supports two protocols:
|
|
51
|
+
- "agentos": Agno's proprietary AgentOS REST API (default)
|
|
52
|
+
- "a2a": A2A (Agent-to-Agent) protocol for cross-framework communication
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
base_url: Base URL for remote instance (e.g., "http://localhost:7777")
|
|
56
|
+
agent_id: ID of remote agent on the remote server
|
|
57
|
+
timeout: Request timeout in seconds (default: 60)
|
|
58
|
+
protocol: Communication protocol - "agentos" (default) or "a2a"
|
|
59
|
+
a2a_protocol: For A2A protocol only - Whether to use JSON-RPC or REST protocol.
|
|
60
|
+
config_ttl: Time-to-live for cached config in seconds (default: 300)
|
|
61
|
+
"""
|
|
62
|
+
super().__init__(base_url, timeout, protocol, a2a_protocol, config_ttl)
|
|
63
|
+
self.agent_id = agent_id
|
|
64
|
+
self._cached_agent_config = None
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def id(self) -> str:
|
|
68
|
+
return self.agent_id
|
|
69
|
+
|
|
70
|
+
async def get_agent_config(self) -> "AgentResponse":
|
|
71
|
+
"""
|
|
72
|
+
Get the agent config from remote.
|
|
73
|
+
|
|
74
|
+
For A2A protocol, returns a minimal AgentResponse since A2A servers
|
|
75
|
+
don't expose the same config endpoints as AgentOS. For AgentOS, always fetches fresh config.
|
|
76
|
+
"""
|
|
77
|
+
from agno.os.routers.agents.schema import AgentResponse
|
|
78
|
+
|
|
79
|
+
if self.a2a_client:
|
|
80
|
+
from agno.client.a2a.schemas import AgentCard
|
|
81
|
+
|
|
82
|
+
agent_card: Optional[AgentCard] = await self.a2a_client.aget_agent_card()
|
|
83
|
+
|
|
84
|
+
return AgentResponse(
|
|
85
|
+
id=self.agent_id,
|
|
86
|
+
name=agent_card.name if agent_card else self.agent_id,
|
|
87
|
+
description=agent_card.description if agent_card else f"A2A agent: {self.agent_id}",
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
return await self.agentos_client.aget_agent(self.agent_id) # type: ignore
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def _agent_config(self) -> Optional["AgentResponse"]:
|
|
94
|
+
"""
|
|
95
|
+
Get the agent config from remote, cached with TTL.
|
|
96
|
+
Returns None for A2A protocol since A2A servers don't expose agent config endpoints.
|
|
97
|
+
"""
|
|
98
|
+
import time
|
|
99
|
+
|
|
100
|
+
from agno.os.routers.agents.schema import AgentResponse
|
|
101
|
+
|
|
102
|
+
if self.a2a_client:
|
|
103
|
+
from agno.client.a2a.schemas import AgentCard
|
|
104
|
+
|
|
105
|
+
agent_card: Optional[AgentCard] = self.a2a_client.get_agent_card()
|
|
106
|
+
|
|
107
|
+
return AgentResponse(
|
|
108
|
+
id=self.agent_id,
|
|
109
|
+
name=agent_card.name if agent_card else self.agent_id,
|
|
110
|
+
description=agent_card.description if agent_card else f"A2A agent: {self.agent_id}",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
current_time = time.time()
|
|
114
|
+
|
|
115
|
+
# Check if cache is valid
|
|
116
|
+
if self._cached_agent_config is not None:
|
|
117
|
+
config, cached_at = self._cached_agent_config
|
|
118
|
+
if current_time - cached_at < self.config_ttl:
|
|
119
|
+
return config
|
|
120
|
+
|
|
121
|
+
# Fetch fresh config
|
|
122
|
+
config: AgentResponse = self.agentos_client.get_agent(self.agent_id) # type: ignore
|
|
123
|
+
self._cached_agent_config = (config, current_time)
|
|
124
|
+
return config
|
|
125
|
+
|
|
126
|
+
async def refresh_config(self) -> Optional["AgentResponse"]:
|
|
127
|
+
"""
|
|
128
|
+
Force refresh the cached agent config.
|
|
129
|
+
Returns None for A2A protocol.
|
|
130
|
+
"""
|
|
131
|
+
import time
|
|
132
|
+
|
|
133
|
+
from agno.os.routers.agents.schema import AgentResponse
|
|
134
|
+
|
|
135
|
+
if self.a2a_client:
|
|
136
|
+
self._cached_agent_config = None
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
config: AgentResponse = await self.agentos_client.aget_agent(self.agent_id) # type: ignore
|
|
140
|
+
self._cached_agent_config = (config, time.time())
|
|
141
|
+
return config
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def name(self) -> Optional[str]:
|
|
145
|
+
if self._agent_config is not None:
|
|
146
|
+
return self._agent_config.name
|
|
147
|
+
return self.agent_id
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def description(self) -> Optional[str]:
|
|
151
|
+
if self._agent_config is not None:
|
|
152
|
+
return self._agent_config.description
|
|
153
|
+
return ""
|
|
154
|
+
|
|
155
|
+
def role(self) -> Optional[str]:
|
|
156
|
+
if self._agent_config is not None:
|
|
157
|
+
return self._agent_config.role
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def tools(self) -> Optional[List[Dict[str, Any]]]:
|
|
162
|
+
if self._agent_config is not None:
|
|
163
|
+
try:
|
|
164
|
+
return json.loads(self._agent_config.tools["tools"]) if self._agent_config.tools else None
|
|
165
|
+
except Exception as e:
|
|
166
|
+
log_warning(f"Failed to load tools for agent {self.agent_id}: {e}")
|
|
167
|
+
return None
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
@property
|
|
171
|
+
def db(self) -> Optional[RemoteDb]:
|
|
172
|
+
if (
|
|
173
|
+
self.agentos_client
|
|
174
|
+
and self._config
|
|
175
|
+
and self._agent_config is not None
|
|
176
|
+
and self._agent_config.db_id is not None
|
|
177
|
+
):
|
|
178
|
+
return RemoteDb.from_config(
|
|
179
|
+
db_id=self._agent_config.db_id,
|
|
180
|
+
client=self.agentos_client,
|
|
181
|
+
config=self._config,
|
|
182
|
+
)
|
|
183
|
+
return None
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def knowledge(self) -> Optional[RemoteKnowledge]:
|
|
187
|
+
if self.agentos_client and self._agent_config is not None and self._agent_config.knowledge is not None:
|
|
188
|
+
return RemoteKnowledge(
|
|
189
|
+
client=self.agentos_client,
|
|
190
|
+
contents_db=RemoteDb(
|
|
191
|
+
id=self._agent_config.knowledge.get("db_id"), # type: ignore
|
|
192
|
+
client=self.agentos_client,
|
|
193
|
+
knowledge_table_name=self._agent_config.knowledge.get("knowledge_table"),
|
|
194
|
+
)
|
|
195
|
+
if self._agent_config.knowledge.get("db_id") is not None
|
|
196
|
+
else None,
|
|
197
|
+
)
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def model(self) -> Optional[Model]:
|
|
202
|
+
# We don't expose the remote agent's models, since they can't be used by other services in AgentOS.
|
|
203
|
+
return None
|
|
204
|
+
|
|
205
|
+
async def aget_tools(self, **kwargs: Any) -> List[Dict]:
|
|
206
|
+
if self._agent_config is not None and self._agent_config.tools is not None:
|
|
207
|
+
return json.loads(self._agent_config.tools["tools"])
|
|
208
|
+
return []
|
|
209
|
+
|
|
210
|
+
@overload
|
|
211
|
+
async def arun(
|
|
212
|
+
self,
|
|
213
|
+
input: Union[str, List, Dict, Message, BaseModel, List[Message]],
|
|
214
|
+
*,
|
|
215
|
+
stream: Literal[False] = False,
|
|
216
|
+
user_id: Optional[str] = None,
|
|
217
|
+
session_id: Optional[str] = None,
|
|
218
|
+
session_state: Optional[Dict[str, Any]] = None,
|
|
219
|
+
audio: Optional[Sequence[Audio]] = None,
|
|
220
|
+
images: Optional[Sequence[Image]] = None,
|
|
221
|
+
videos: Optional[Sequence[Video]] = None,
|
|
222
|
+
files: Optional[Sequence[File]] = None,
|
|
223
|
+
stream_events: Optional[bool] = None,
|
|
224
|
+
retries: Optional[int] = None,
|
|
225
|
+
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
226
|
+
add_history_to_context: Optional[bool] = None,
|
|
227
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
228
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
229
|
+
dependencies: Optional[Dict[str, Any]] = None,
|
|
230
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
231
|
+
auth_token: Optional[str] = None,
|
|
232
|
+
**kwargs: Any,
|
|
233
|
+
) -> RunOutput: ...
|
|
234
|
+
|
|
235
|
+
@overload
|
|
236
|
+
def arun(
|
|
237
|
+
self,
|
|
238
|
+
input: Union[str, List, Dict, Message, BaseModel, List[Message]],
|
|
239
|
+
*,
|
|
240
|
+
stream: Literal[True] = True,
|
|
241
|
+
user_id: Optional[str] = None,
|
|
242
|
+
session_id: Optional[str] = None,
|
|
243
|
+
audio: Optional[Sequence[Audio]] = None,
|
|
244
|
+
images: Optional[Sequence[Image]] = None,
|
|
245
|
+
videos: Optional[Sequence[Video]] = None,
|
|
246
|
+
files: Optional[Sequence[File]] = None,
|
|
247
|
+
stream_events: Optional[bool] = None,
|
|
248
|
+
retries: Optional[int] = None,
|
|
249
|
+
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
250
|
+
add_history_to_context: Optional[bool] = None,
|
|
251
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
252
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
253
|
+
dependencies: Optional[Dict[str, Any]] = None,
|
|
254
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
255
|
+
auth_token: Optional[str] = None,
|
|
256
|
+
**kwargs: Any,
|
|
257
|
+
) -> AsyncIterator[RunOutputEvent]: ...
|
|
258
|
+
|
|
259
|
+
def arun( # type: ignore
|
|
260
|
+
self,
|
|
261
|
+
input: Union[str, List, Dict, Message, BaseModel, List[Message]],
|
|
262
|
+
*,
|
|
263
|
+
stream: Optional[bool] = None,
|
|
264
|
+
user_id: Optional[str] = None,
|
|
265
|
+
session_id: Optional[str] = None,
|
|
266
|
+
session_state: Optional[Dict[str, Any]] = None,
|
|
267
|
+
audio: Optional[Sequence[Audio]] = None,
|
|
268
|
+
images: Optional[Sequence[Image]] = None,
|
|
269
|
+
videos: Optional[Sequence[Video]] = None,
|
|
270
|
+
files: Optional[Sequence[File]] = None,
|
|
271
|
+
stream_events: Optional[bool] = None,
|
|
272
|
+
retries: Optional[int] = None,
|
|
273
|
+
knowledge_filters: Optional[Dict[str, Any]] = None,
|
|
274
|
+
add_history_to_context: Optional[bool] = None,
|
|
275
|
+
add_dependencies_to_context: Optional[bool] = None,
|
|
276
|
+
add_session_state_to_context: Optional[bool] = None,
|
|
277
|
+
dependencies: Optional[Dict[str, Any]] = None,
|
|
278
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
279
|
+
auth_token: Optional[str] = None,
|
|
280
|
+
**kwargs: Any,
|
|
281
|
+
) -> Union[
|
|
282
|
+
RunOutput,
|
|
283
|
+
AsyncIterator[RunOutputEvent],
|
|
284
|
+
]:
|
|
285
|
+
validated_input = validate_input(input)
|
|
286
|
+
serialized_input = serialize_input(validated_input)
|
|
287
|
+
headers = self._get_auth_headers(auth_token)
|
|
288
|
+
|
|
289
|
+
# A2A protocol path
|
|
290
|
+
if self.a2a_client:
|
|
291
|
+
return self._arun_a2a( # type: ignore[return-value]
|
|
292
|
+
message=serialized_input,
|
|
293
|
+
stream=stream or False,
|
|
294
|
+
user_id=user_id,
|
|
295
|
+
context_id=session_id, # Map session_id → context_id for A2A
|
|
296
|
+
audio=audio,
|
|
297
|
+
images=images,
|
|
298
|
+
videos=videos,
|
|
299
|
+
files=files,
|
|
300
|
+
headers=headers,
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
# AgentOS protocol path (default)
|
|
304
|
+
if self.agentos_client:
|
|
305
|
+
if stream:
|
|
306
|
+
# Handle streaming response
|
|
307
|
+
return self.agentos_client.run_agent_stream(
|
|
308
|
+
agent_id=self.agent_id,
|
|
309
|
+
message=serialized_input,
|
|
310
|
+
session_id=session_id,
|
|
311
|
+
user_id=user_id,
|
|
312
|
+
audio=audio,
|
|
313
|
+
images=images,
|
|
314
|
+
videos=videos,
|
|
315
|
+
files=files,
|
|
316
|
+
session_state=session_state,
|
|
317
|
+
stream_events=stream_events,
|
|
318
|
+
retries=retries,
|
|
319
|
+
knowledge_filters=knowledge_filters,
|
|
320
|
+
add_history_to_context=add_history_to_context,
|
|
321
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
322
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
323
|
+
dependencies=dependencies,
|
|
324
|
+
metadata=metadata,
|
|
325
|
+
headers=headers,
|
|
326
|
+
**kwargs,
|
|
327
|
+
)
|
|
328
|
+
else:
|
|
329
|
+
return self.agentos_client.run_agent( # type: ignore
|
|
330
|
+
agent_id=self.agent_id,
|
|
331
|
+
message=serialized_input,
|
|
332
|
+
session_id=session_id,
|
|
333
|
+
user_id=user_id,
|
|
334
|
+
audio=audio,
|
|
335
|
+
images=images,
|
|
336
|
+
videos=videos,
|
|
337
|
+
files=files,
|
|
338
|
+
session_state=session_state,
|
|
339
|
+
stream_events=stream_events,
|
|
340
|
+
retries=retries,
|
|
341
|
+
knowledge_filters=knowledge_filters,
|
|
342
|
+
add_history_to_context=add_history_to_context,
|
|
343
|
+
add_dependencies_to_context=add_dependencies_to_context,
|
|
344
|
+
add_session_state_to_context=add_session_state_to_context,
|
|
345
|
+
dependencies=dependencies,
|
|
346
|
+
metadata=metadata,
|
|
347
|
+
headers=headers,
|
|
348
|
+
**kwargs,
|
|
349
|
+
)
|
|
350
|
+
else:
|
|
351
|
+
raise ValueError("No client available")
|
|
352
|
+
|
|
353
|
+
def _arun_a2a(
|
|
354
|
+
self,
|
|
355
|
+
message: str,
|
|
356
|
+
stream: bool,
|
|
357
|
+
user_id: Optional[str],
|
|
358
|
+
context_id: Optional[str],
|
|
359
|
+
audio: Optional[Sequence[Audio]],
|
|
360
|
+
images: Optional[Sequence[Image]],
|
|
361
|
+
videos: Optional[Sequence[Video]],
|
|
362
|
+
files: Optional[Sequence[File]],
|
|
363
|
+
headers: Optional[Dict[str, str]],
|
|
364
|
+
) -> Union[RunOutput, AsyncIterator[RunOutputEvent]]:
|
|
365
|
+
"""Execute via A2A protocol.
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
message: Serialized message string
|
|
369
|
+
stream: Whether to stream the response
|
|
370
|
+
user_id: User identifier
|
|
371
|
+
context_id: Session/context ID (maps to session_id)
|
|
372
|
+
audio: Audio files to include
|
|
373
|
+
images: Images to include
|
|
374
|
+
videos: Videos to include
|
|
375
|
+
files: Files to include
|
|
376
|
+
headers: HTTP headers to include in the request (optional)
|
|
377
|
+
|
|
378
|
+
Returns:
|
|
379
|
+
RunOutput for non-streaming, AsyncIterator[RunOutputEvent] for streaming
|
|
380
|
+
"""
|
|
381
|
+
if not self.a2a_client:
|
|
382
|
+
raise ValueError("A2A client not available")
|
|
383
|
+
from agno.client.a2a.utils import map_stream_events_to_run_events
|
|
384
|
+
|
|
385
|
+
if stream:
|
|
386
|
+
# Return async generator for streaming
|
|
387
|
+
event_stream = self.a2a_client.stream_message(
|
|
388
|
+
message=message,
|
|
389
|
+
context_id=context_id,
|
|
390
|
+
user_id=user_id,
|
|
391
|
+
images=list(images) if images else None,
|
|
392
|
+
audio=list(audio) if audio else None,
|
|
393
|
+
videos=list(videos) if videos else None,
|
|
394
|
+
files=list(files) if files else None,
|
|
395
|
+
headers=headers,
|
|
396
|
+
)
|
|
397
|
+
return map_stream_events_to_run_events(event_stream, agent_id=self.agent_id)
|
|
398
|
+
else:
|
|
399
|
+
# Return coroutine for non-streaming
|
|
400
|
+
return self._arun_a2a_send( # type: ignore[return-value]
|
|
401
|
+
message=message,
|
|
402
|
+
user_id=user_id,
|
|
403
|
+
context_id=context_id,
|
|
404
|
+
audio=audio,
|
|
405
|
+
images=images,
|
|
406
|
+
videos=videos,
|
|
407
|
+
files=files,
|
|
408
|
+
headers=headers,
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
async def _arun_a2a_send(
|
|
412
|
+
self,
|
|
413
|
+
message: str,
|
|
414
|
+
user_id: Optional[str],
|
|
415
|
+
context_id: Optional[str],
|
|
416
|
+
audio: Optional[Sequence[Audio]],
|
|
417
|
+
images: Optional[Sequence[Image]],
|
|
418
|
+
videos: Optional[Sequence[Video]],
|
|
419
|
+
files: Optional[Sequence[File]],
|
|
420
|
+
headers: Optional[Dict[str, str]],
|
|
421
|
+
) -> RunOutput:
|
|
422
|
+
"""Send a non-streaming A2A message and convert response to RunOutput."""
|
|
423
|
+
if not self.a2a_client:
|
|
424
|
+
raise ValueError("A2A client not available")
|
|
425
|
+
from agno.client.a2a.utils import map_task_result_to_run_output
|
|
426
|
+
|
|
427
|
+
task_result = await self.a2a_client.send_message(
|
|
428
|
+
message=message,
|
|
429
|
+
context_id=context_id,
|
|
430
|
+
user_id=user_id,
|
|
431
|
+
images=list(images) if images else None,
|
|
432
|
+
audio=list(audio) if audio else None,
|
|
433
|
+
videos=list(videos) if videos else None,
|
|
434
|
+
files=list(files) if files else None,
|
|
435
|
+
headers=headers,
|
|
436
|
+
)
|
|
437
|
+
return map_task_result_to_run_output(task_result, agent_id=self.agent_id, user_id=user_id)
|
|
438
|
+
|
|
439
|
+
@overload
|
|
440
|
+
async def acontinue_run(
|
|
441
|
+
self,
|
|
442
|
+
run_id: str,
|
|
443
|
+
updated_tools: List[ToolExecution],
|
|
444
|
+
stream: Literal[False] = False,
|
|
445
|
+
user_id: Optional[str] = None,
|
|
446
|
+
session_id: Optional[str] = None,
|
|
447
|
+
auth_token: Optional[str] = None,
|
|
448
|
+
**kwargs: Any,
|
|
449
|
+
) -> RunOutput: ...
|
|
450
|
+
|
|
451
|
+
@overload
|
|
452
|
+
def acontinue_run(
|
|
453
|
+
self,
|
|
454
|
+
run_id: str,
|
|
455
|
+
updated_tools: List[ToolExecution],
|
|
456
|
+
stream: Literal[True] = True,
|
|
457
|
+
user_id: Optional[str] = None,
|
|
458
|
+
session_id: Optional[str] = None,
|
|
459
|
+
auth_token: Optional[str] = None,
|
|
460
|
+
**kwargs: Any,
|
|
461
|
+
) -> AsyncIterator[RunOutputEvent]: ...
|
|
462
|
+
|
|
463
|
+
def acontinue_run( # type: ignore
|
|
464
|
+
self,
|
|
465
|
+
run_id: str, # type: ignore
|
|
466
|
+
updated_tools: List[ToolExecution],
|
|
467
|
+
stream: Optional[bool] = None,
|
|
468
|
+
user_id: Optional[str] = None,
|
|
469
|
+
session_id: Optional[str] = None,
|
|
470
|
+
auth_token: Optional[str] = None,
|
|
471
|
+
**kwargs: Any,
|
|
472
|
+
) -> Union[
|
|
473
|
+
RunOutput,
|
|
474
|
+
AsyncIterator[RunOutputEvent],
|
|
475
|
+
]:
|
|
476
|
+
headers = self._get_auth_headers(auth_token)
|
|
477
|
+
|
|
478
|
+
if self.agentos_client:
|
|
479
|
+
if stream:
|
|
480
|
+
# Handle streaming response
|
|
481
|
+
return self.agentos_client.continue_agent_run_stream( # type: ignore
|
|
482
|
+
agent_id=self.agent_id,
|
|
483
|
+
run_id=run_id,
|
|
484
|
+
user_id=user_id,
|
|
485
|
+
session_id=session_id,
|
|
486
|
+
tools=updated_tools,
|
|
487
|
+
headers=headers,
|
|
488
|
+
**kwargs,
|
|
489
|
+
)
|
|
490
|
+
else:
|
|
491
|
+
return self.agentos_client.continue_agent_run( # type: ignore
|
|
492
|
+
agent_id=self.agent_id,
|
|
493
|
+
run_id=run_id,
|
|
494
|
+
tools=updated_tools,
|
|
495
|
+
user_id=user_id,
|
|
496
|
+
session_id=session_id,
|
|
497
|
+
headers=headers,
|
|
498
|
+
**kwargs,
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
else:
|
|
502
|
+
raise ValueError("No client available")
|
|
503
|
+
|
|
504
|
+
async def acancel_run(self, run_id: str, auth_token: Optional[str] = None) -> bool:
|
|
505
|
+
"""Cancel a running agent execution.
|
|
506
|
+
|
|
507
|
+
Args:
|
|
508
|
+
run_id (str): The run_id to cancel.
|
|
509
|
+
auth_token: Optional JWT token for authentication.
|
|
510
|
+
|
|
511
|
+
Returns:
|
|
512
|
+
bool: True if the run was successfully cancelled, False otherwise.
|
|
513
|
+
"""
|
|
514
|
+
headers = self._get_auth_headers(auth_token)
|
|
515
|
+
if not self.agentos_client:
|
|
516
|
+
raise ValueError("AgentOS client not available")
|
|
517
|
+
try:
|
|
518
|
+
await self.agentos_client.cancel_agent_run(
|
|
519
|
+
agent_id=self.agent_id,
|
|
520
|
+
run_id=run_id,
|
|
521
|
+
headers=headers,
|
|
522
|
+
)
|
|
523
|
+
return True
|
|
524
|
+
except Exception:
|
|
525
|
+
return False
|
agno/api/api.py
CHANGED
|
@@ -19,6 +19,7 @@ class Api:
|
|
|
19
19
|
base_url=agno_api_settings.api_url,
|
|
20
20
|
headers=self.headers,
|
|
21
21
|
timeout=60,
|
|
22
|
+
http2=True,
|
|
22
23
|
)
|
|
23
24
|
|
|
24
25
|
def AsyncClient(self) -> HttpxAsyncClient:
|
|
@@ -26,6 +27,7 @@ class Api:
|
|
|
26
27
|
base_url=agno_api_settings.api_url,
|
|
27
28
|
headers=self.headers,
|
|
28
29
|
timeout=60,
|
|
30
|
+
http2=True,
|
|
29
31
|
)
|
|
30
32
|
|
|
31
33
|
|
agno/client/__init__.py
ADDED