agno 2.0.1__py3-none-any.whl → 2.3.0__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 +6015 -2823
- agno/api/api.py +2 -0
- agno/api/os.py +1 -1
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +385 -6
- agno/db/dynamo/dynamo.py +388 -81
- agno/db/dynamo/schemas.py +47 -10
- agno/db/dynamo/utils.py +63 -4
- agno/db/firestore/firestore.py +435 -64
- agno/db/firestore/schemas.py +11 -0
- agno/db/firestore/utils.py +102 -4
- agno/db/gcs_json/gcs_json_db.py +384 -42
- agno/db/gcs_json/utils.py +60 -26
- agno/db/in_memory/in_memory_db.py +351 -66
- agno/db/in_memory/utils.py +60 -2
- agno/db/json/json_db.py +339 -48
- agno/db/json/utils.py +60 -26
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +510 -37
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +15 -1
- agno/db/mongo/async_mongo.py +2036 -0
- agno/db/mongo/mongo.py +653 -76
- agno/db/mongo/schemas.py +13 -0
- agno/db/mongo/utils.py +80 -8
- agno/db/mysql/mysql.py +687 -25
- agno/db/mysql/schemas.py +61 -37
- agno/db/mysql/utils.py +60 -2
- agno/db/postgres/__init__.py +2 -1
- agno/db/postgres/async_postgres.py +2001 -0
- agno/db/postgres/postgres.py +676 -57
- agno/db/postgres/schemas.py +43 -18
- agno/db/postgres/utils.py +164 -2
- agno/db/redis/redis.py +344 -38
- agno/db/redis/schemas.py +18 -0
- agno/db/redis/utils.py +60 -2
- agno/db/schemas/__init__.py +2 -1
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/memory.py +13 -0
- agno/db/singlestore/schemas.py +26 -1
- agno/db/singlestore/singlestore.py +687 -53
- agno/db/singlestore/utils.py +60 -2
- agno/db/sqlite/__init__.py +2 -1
- agno/db/sqlite/async_sqlite.py +2371 -0
- agno/db/sqlite/schemas.py +24 -0
- agno/db/sqlite/sqlite.py +774 -85
- agno/db/sqlite/utils.py +168 -5
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +309 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1361 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +50 -22
- agno/eval/accuracy.py +50 -43
- agno/eval/performance.py +6 -3
- agno/eval/reliability.py +6 -3
- agno/eval/utils.py +33 -16
- agno/exceptions.py +68 -1
- agno/filters.py +354 -0
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +52 -0
- agno/integrations/discord/client.py +1 -0
- agno/knowledge/chunking/agentic.py +13 -10
- agno/knowledge/chunking/fixed.py +1 -1
- agno/knowledge/chunking/semantic.py +40 -8
- agno/knowledge/chunking/strategy.py +59 -15
- agno/knowledge/embedder/aws_bedrock.py +9 -4
- agno/knowledge/embedder/azure_openai.py +54 -0
- agno/knowledge/embedder/base.py +2 -0
- agno/knowledge/embedder/cohere.py +184 -5
- agno/knowledge/embedder/fastembed.py +1 -1
- agno/knowledge/embedder/google.py +79 -1
- agno/knowledge/embedder/huggingface.py +9 -4
- agno/knowledge/embedder/jina.py +63 -0
- agno/knowledge/embedder/mistral.py +78 -11
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/ollama.py +13 -0
- agno/knowledge/embedder/openai.py +37 -65
- agno/knowledge/embedder/sentence_transformer.py +8 -4
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +69 -16
- agno/knowledge/knowledge.py +594 -186
- agno/knowledge/reader/base.py +9 -2
- agno/knowledge/reader/csv_reader.py +8 -10
- agno/knowledge/reader/docx_reader.py +5 -6
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/json_reader.py +6 -5
- agno/knowledge/reader/markdown_reader.py +13 -13
- agno/knowledge/reader/pdf_reader.py +43 -68
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +51 -6
- agno/knowledge/reader/s3_reader.py +3 -15
- agno/knowledge/reader/tavily_reader.py +194 -0
- agno/knowledge/reader/text_reader.py +13 -13
- agno/knowledge/reader/web_search_reader.py +2 -43
- agno/knowledge/reader/website_reader.py +43 -25
- agno/knowledge/reranker/__init__.py +2 -8
- agno/knowledge/types.py +9 -0
- agno/knowledge/utils.py +20 -0
- agno/media.py +72 -0
- agno/memory/manager.py +336 -82
- agno/models/aimlapi/aimlapi.py +2 -2
- agno/models/anthropic/claude.py +183 -37
- agno/models/aws/bedrock.py +52 -112
- agno/models/aws/claude.py +33 -1
- agno/models/azure/ai_foundry.py +33 -15
- agno/models/azure/openai_chat.py +25 -8
- agno/models/base.py +999 -519
- agno/models/cerebras/cerebras.py +19 -13
- agno/models/cerebras/cerebras_openai.py +8 -5
- agno/models/cohere/chat.py +27 -1
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +57 -0
- agno/models/dashscope/dashscope.py +1 -0
- agno/models/deepinfra/deepinfra.py +2 -2
- agno/models/deepseek/deepseek.py +2 -2
- agno/models/fireworks/fireworks.py +2 -2
- agno/models/google/gemini.py +103 -31
- agno/models/groq/groq.py +28 -11
- agno/models/huggingface/huggingface.py +2 -1
- agno/models/internlm/internlm.py +2 -2
- agno/models/langdb/langdb.py +4 -4
- agno/models/litellm/chat.py +18 -1
- agno/models/litellm/litellm_openai.py +2 -2
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/message.py +139 -0
- agno/models/meta/llama.py +27 -10
- agno/models/meta/llama_openai.py +5 -17
- agno/models/nebius/nebius.py +6 -6
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/nvidia.py +2 -2
- agno/models/ollama/chat.py +59 -5
- agno/models/openai/chat.py +69 -29
- agno/models/openai/responses.py +103 -106
- agno/models/openrouter/openrouter.py +41 -3
- agno/models/perplexity/perplexity.py +4 -5
- agno/models/portkey/portkey.py +3 -3
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +52 -0
- agno/models/response.py +77 -1
- agno/models/sambanova/sambanova.py +2 -2
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +25 -0
- agno/models/together/together.py +2 -2
- agno/models/utils.py +254 -8
- agno/models/vercel/v0.py +2 -2
- agno/models/vertexai/__init__.py +0 -0
- agno/models/vertexai/claude.py +96 -0
- agno/models/vllm/vllm.py +1 -0
- agno/models/xai/xai.py +3 -2
- agno/os/app.py +543 -178
- agno/os/auth.py +24 -14
- agno/os/config.py +1 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +250 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/agui.py +23 -7
- agno/os/interfaces/agui/router.py +27 -3
- agno/os/interfaces/agui/utils.py +242 -142
- agno/os/interfaces/base.py +6 -2
- agno/os/interfaces/slack/router.py +81 -23
- agno/os/interfaces/slack/slack.py +29 -14
- agno/os/interfaces/whatsapp/router.py +11 -4
- agno/os/interfaces/whatsapp/whatsapp.py +14 -7
- agno/os/mcp.py +111 -54
- agno/os/middleware/__init__.py +7 -0
- agno/os/middleware/jwt.py +233 -0
- agno/os/router.py +556 -139
- agno/os/routers/evals/evals.py +71 -34
- agno/os/routers/evals/schemas.py +31 -31
- agno/os/routers/evals/utils.py +6 -5
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/knowledge.py +185 -38
- agno/os/routers/knowledge/schemas.py +82 -22
- agno/os/routers/memory/memory.py +158 -53
- agno/os/routers/memory/schemas.py +20 -16
- agno/os/routers/metrics/metrics.py +20 -8
- agno/os/routers/metrics/schemas.py +16 -16
- agno/os/routers/session/session.py +499 -38
- agno/os/schema.py +308 -198
- agno/os/utils.py +401 -41
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +2 -2
- agno/reasoning/deepseek.py +2 -2
- agno/reasoning/default.py +3 -1
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +2 -2
- agno/reasoning/ollama.py +2 -2
- agno/reasoning/openai.py +7 -2
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +248 -94
- agno/run/base.py +44 -5
- agno/run/team.py +238 -97
- agno/run/workflow.py +144 -33
- agno/session/agent.py +105 -89
- agno/session/summary.py +65 -25
- agno/session/team.py +176 -96
- agno/session/workflow.py +406 -40
- agno/team/team.py +3854 -1610
- agno/tools/dalle.py +2 -4
- agno/tools/decorator.py +4 -2
- agno/tools/duckduckgo.py +15 -11
- agno/tools/e2b.py +14 -7
- agno/tools/eleven_labs.py +23 -25
- agno/tools/exa.py +21 -16
- agno/tools/file.py +153 -23
- agno/tools/file_generation.py +350 -0
- agno/tools/firecrawl.py +4 -4
- agno/tools/function.py +250 -30
- agno/tools/gmail.py +238 -14
- agno/tools/google_drive.py +270 -0
- agno/tools/googlecalendar.py +36 -8
- agno/tools/googlesheets.py +20 -5
- agno/tools/jira.py +20 -0
- agno/tools/knowledge.py +3 -3
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +331 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/mcp_toolbox.py +284 -0
- agno/tools/mem0.py +11 -17
- agno/tools/memori.py +1 -53
- agno/tools/memory.py +419 -0
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/notion.py +204 -0
- agno/tools/parallel.py +314 -0
- agno/tools/scrapegraph.py +58 -31
- agno/tools/searxng.py +2 -2
- agno/tools/serper.py +2 -2
- agno/tools/slack.py +18 -3
- agno/tools/spider.py +2 -2
- agno/tools/tavily.py +146 -0
- agno/tools/whatsapp.py +1 -1
- agno/tools/workflow.py +278 -0
- agno/tools/yfinance.py +12 -11
- agno/utils/agent.py +820 -0
- agno/utils/audio.py +27 -0
- agno/utils/common.py +90 -1
- agno/utils/events.py +217 -2
- agno/utils/gemini.py +180 -22
- agno/utils/hooks.py +57 -0
- agno/utils/http.py +111 -0
- agno/utils/knowledge.py +12 -5
- agno/utils/log.py +1 -0
- agno/utils/mcp.py +92 -2
- agno/utils/media.py +188 -10
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +60 -0
- agno/utils/models/claude.py +40 -11
- agno/utils/print_response/agent.py +105 -21
- agno/utils/print_response/team.py +103 -38
- agno/utils/print_response/workflow.py +251 -34
- agno/utils/reasoning.py +22 -1
- agno/utils/serialize.py +32 -0
- agno/utils/streamlit.py +16 -10
- agno/utils/string.py +41 -0
- agno/utils/team.py +98 -9
- agno/utils/tools.py +1 -1
- agno/vectordb/base.py +23 -4
- agno/vectordb/cassandra/cassandra.py +65 -9
- agno/vectordb/chroma/chromadb.py +182 -38
- agno/vectordb/clickhouse/clickhousedb.py +64 -11
- agno/vectordb/couchbase/couchbase.py +105 -10
- agno/vectordb/lancedb/lance_db.py +124 -133
- agno/vectordb/langchaindb/langchaindb.py +25 -7
- agno/vectordb/lightrag/lightrag.py +17 -3
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +46 -7
- agno/vectordb/milvus/milvus.py +126 -9
- agno/vectordb/mongodb/__init__.py +7 -1
- agno/vectordb/mongodb/mongodb.py +112 -7
- agno/vectordb/pgvector/pgvector.py +142 -21
- agno/vectordb/pineconedb/pineconedb.py +80 -8
- agno/vectordb/qdrant/qdrant.py +125 -39
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +694 -0
- agno/vectordb/singlestore/singlestore.py +111 -25
- agno/vectordb/surrealdb/surrealdb.py +31 -5
- agno/vectordb/upstashdb/upstashdb.py +76 -8
- agno/vectordb/weaviate/weaviate.py +86 -15
- agno/workflow/__init__.py +2 -0
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +112 -18
- agno/workflow/loop.py +69 -10
- agno/workflow/parallel.py +266 -118
- agno/workflow/router.py +110 -17
- agno/workflow/step.py +638 -129
- agno/workflow/steps.py +65 -6
- agno/workflow/types.py +61 -23
- agno/workflow/workflow.py +2085 -272
- {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/METADATA +182 -58
- agno-2.3.0.dist-info/RECORD +577 -0
- agno/knowledge/reader/url_reader.py +0 -128
- agno/tools/googlesearch.py +0 -98
- agno/tools/mcp.py +0 -610
- agno/utils/models/aws_claude.py +0 -170
- agno-2.0.1.dist-info/RECORD +0 -515
- {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
- {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/licenses/LICENSE +0 -0
- {agno-2.0.1.dist-info → agno-2.3.0.dist-info}/top_level.txt +0 -0
agno/models/aimlapi/aimlapi.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
2
|
from os import getenv
|
|
3
3
|
from typing import Any, Dict, Optional
|
|
4
4
|
|
|
@@ -24,7 +24,7 @@ class AIMLAPI(OpenAILike):
|
|
|
24
24
|
name: str = "AIMLAPI"
|
|
25
25
|
provider: str = "AIMLAPI"
|
|
26
26
|
|
|
27
|
-
api_key: Optional[str] = getenv("AIMLAPI_API_KEY")
|
|
27
|
+
api_key: Optional[str] = field(default_factory=lambda: getenv("AIMLAPI_API_KEY"))
|
|
28
28
|
base_url: str = "https://api.aimlapi.com/v1"
|
|
29
29
|
max_tokens: int = 4096
|
|
30
30
|
|
agno/models/anthropic/claude.py
CHANGED
|
@@ -4,6 +4,7 @@ from dataclasses import asdict, dataclass
|
|
|
4
4
|
from os import getenv
|
|
5
5
|
from typing import Any, Dict, List, Optional, Type, Union
|
|
6
6
|
|
|
7
|
+
import httpx
|
|
7
8
|
from pydantic import BaseModel
|
|
8
9
|
|
|
9
10
|
from agno.exceptions import ModelProviderError, ModelRateLimitError
|
|
@@ -12,6 +13,7 @@ from agno.models.message import Citations, DocumentCitation, Message, UrlCitatio
|
|
|
12
13
|
from agno.models.metrics import Metrics
|
|
13
14
|
from agno.models.response import ModelResponse
|
|
14
15
|
from agno.run.agent import RunOutput
|
|
16
|
+
from agno.utils.http import get_default_async_client, get_default_sync_client
|
|
15
17
|
from agno.utils.log import log_debug, log_error, log_warning
|
|
16
18
|
from agno.utils.models.claude import MCPServerConfiguration, format_messages, format_tools_for_model
|
|
17
19
|
|
|
@@ -25,6 +27,11 @@ try:
|
|
|
25
27
|
from anthropic import (
|
|
26
28
|
AsyncAnthropic as AsyncAnthropicClient,
|
|
27
29
|
)
|
|
30
|
+
from anthropic.lib.streaming._beta_types import (
|
|
31
|
+
BetaRawContentBlockStartEvent,
|
|
32
|
+
ParsedBetaContentBlockStopEvent,
|
|
33
|
+
ParsedBetaMessageStopEvent,
|
|
34
|
+
)
|
|
28
35
|
from anthropic.types import (
|
|
29
36
|
CitationPageLocation,
|
|
30
37
|
CitationsWebSearchResultLocation,
|
|
@@ -39,12 +46,15 @@ try:
|
|
|
39
46
|
from anthropic.types import (
|
|
40
47
|
Message as AnthropicMessage,
|
|
41
48
|
)
|
|
49
|
+
|
|
42
50
|
except ImportError as e:
|
|
43
51
|
raise ImportError("`anthropic` not installed. Please install it with `pip install anthropic`") from e
|
|
44
52
|
|
|
45
53
|
# Import Beta types
|
|
46
54
|
try:
|
|
47
55
|
from anthropic.types.beta import BetaRawContentBlockDeltaEvent, BetaTextDelta
|
|
56
|
+
from anthropic.types.beta.beta_message import BetaMessage
|
|
57
|
+
from anthropic.types.beta.beta_usage import BetaUsage
|
|
48
58
|
except ImportError as e:
|
|
49
59
|
raise ImportError(
|
|
50
60
|
"`anthropic` not installed or missing beta components. Please install with `pip install anthropic`"
|
|
@@ -59,12 +69,23 @@ class Claude(Model):
|
|
|
59
69
|
For more information, see: https://docs.anthropic.com/en/api/messages
|
|
60
70
|
"""
|
|
61
71
|
|
|
62
|
-
|
|
72
|
+
# Models that DO NOT support extended thinking
|
|
73
|
+
# All future models are assumed to support thinking
|
|
74
|
+
# Based on official Anthropic documentation: https://docs.claude.com/en/docs/about-claude/models/overview
|
|
75
|
+
NON_THINKING_MODELS = {
|
|
76
|
+
# Claude Haiku 3 family (does not support thinking)
|
|
77
|
+
"claude-3-haiku-20240307",
|
|
78
|
+
# Claude Haiku 3.5 family (does not support thinking)
|
|
79
|
+
"claude-3-5-haiku-20241022",
|
|
80
|
+
"claude-3-5-haiku-latest",
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
id: str = "claude-sonnet-4-5-20250929"
|
|
63
84
|
name: str = "Claude"
|
|
64
85
|
provider: str = "Anthropic"
|
|
65
86
|
|
|
66
87
|
# Request parameters
|
|
67
|
-
max_tokens: Optional[int] =
|
|
88
|
+
max_tokens: Optional[int] = 8192
|
|
68
89
|
thinking: Optional[Dict[str, Any]] = None
|
|
69
90
|
temperature: Optional[float] = None
|
|
70
91
|
stop_sequences: Optional[List[str]] = None
|
|
@@ -73,17 +94,34 @@ class Claude(Model):
|
|
|
73
94
|
cache_system_prompt: Optional[bool] = False
|
|
74
95
|
extended_cache_time: Optional[bool] = False
|
|
75
96
|
request_params: Optional[Dict[str, Any]] = None
|
|
97
|
+
|
|
98
|
+
# Anthropic beta and experimental features
|
|
99
|
+
betas: Optional[List[str]] = None # Enables specific experimental or newly released features.
|
|
100
|
+
context_management: Optional[Dict[str, Any]] = None
|
|
76
101
|
mcp_servers: Optional[List[MCPServerConfiguration]] = None
|
|
102
|
+
skills: Optional[List[Dict[str, str]]] = (
|
|
103
|
+
None # e.g., [{"type": "anthropic", "skill_id": "pptx", "version": "latest"}]
|
|
104
|
+
)
|
|
77
105
|
|
|
78
106
|
# Client parameters
|
|
79
107
|
api_key: Optional[str] = None
|
|
80
108
|
default_headers: Optional[Dict[str, Any]] = None
|
|
109
|
+
timeout: Optional[float] = None
|
|
110
|
+
http_client: Optional[Union[httpx.Client, httpx.AsyncClient]] = None
|
|
81
111
|
client_params: Optional[Dict[str, Any]] = None
|
|
82
112
|
|
|
83
|
-
# Anthropic clients
|
|
84
113
|
client: Optional[AnthropicClient] = None
|
|
85
114
|
async_client: Optional[AsyncAnthropicClient] = None
|
|
86
115
|
|
|
116
|
+
def __post_init__(self):
|
|
117
|
+
"""Validate model configuration after initialization"""
|
|
118
|
+
# Validate thinking support immediately at model creation
|
|
119
|
+
if self.thinking:
|
|
120
|
+
self._validate_thinking_support()
|
|
121
|
+
# Set up skills configuration if skills are enabled
|
|
122
|
+
if self.skills:
|
|
123
|
+
self._setup_skills_configuration()
|
|
124
|
+
|
|
87
125
|
def _get_client_params(self) -> Dict[str, Any]:
|
|
88
126
|
client_params: Dict[str, Any] = {}
|
|
89
127
|
|
|
@@ -93,6 +131,8 @@ class Claude(Model):
|
|
|
93
131
|
|
|
94
132
|
# Add API key to client parameters
|
|
95
133
|
client_params["api_key"] = self.api_key
|
|
134
|
+
if self.timeout is not None:
|
|
135
|
+
client_params["timeout"] = self.timeout
|
|
96
136
|
|
|
97
137
|
# Add additional client parameters
|
|
98
138
|
if self.client_params is not None:
|
|
@@ -101,6 +141,15 @@ class Claude(Model):
|
|
|
101
141
|
client_params["default_headers"] = self.default_headers
|
|
102
142
|
return client_params
|
|
103
143
|
|
|
144
|
+
def _has_beta_features(self) -> bool:
|
|
145
|
+
"""Check if the model has any Anthropic beta features enabled."""
|
|
146
|
+
return (
|
|
147
|
+
self.mcp_servers is not None
|
|
148
|
+
or self.context_management is not None
|
|
149
|
+
or self.skills is not None
|
|
150
|
+
or self.betas is not None
|
|
151
|
+
)
|
|
152
|
+
|
|
104
153
|
def get_client(self) -> AnthropicClient:
|
|
105
154
|
"""
|
|
106
155
|
Returns an instance of the Anthropic client.
|
|
@@ -109,6 +158,16 @@ class Claude(Model):
|
|
|
109
158
|
return self.client
|
|
110
159
|
|
|
111
160
|
_client_params = self._get_client_params()
|
|
161
|
+
if self.http_client:
|
|
162
|
+
if isinstance(self.http_client, httpx.Client):
|
|
163
|
+
_client_params["http_client"] = self.http_client
|
|
164
|
+
else:
|
|
165
|
+
log_warning("http_client is not an instance of httpx.Client. Using default global httpx.Client.")
|
|
166
|
+
# Use global sync client when user http_client is invalid
|
|
167
|
+
_client_params["http_client"] = get_default_sync_client()
|
|
168
|
+
else:
|
|
169
|
+
# Use global sync client when no custom http_client is provided
|
|
170
|
+
_client_params["http_client"] = get_default_sync_client()
|
|
112
171
|
self.client = AnthropicClient(**_client_params)
|
|
113
172
|
return self.client
|
|
114
173
|
|
|
@@ -116,17 +175,69 @@ class Claude(Model):
|
|
|
116
175
|
"""
|
|
117
176
|
Returns an instance of the async Anthropic client.
|
|
118
177
|
"""
|
|
119
|
-
if self.async_client:
|
|
178
|
+
if self.async_client and not self.async_client.is_closed():
|
|
120
179
|
return self.async_client
|
|
121
180
|
|
|
122
181
|
_client_params = self._get_client_params()
|
|
182
|
+
if self.http_client:
|
|
183
|
+
if isinstance(self.http_client, httpx.AsyncClient):
|
|
184
|
+
_client_params["http_client"] = self.http_client
|
|
185
|
+
else:
|
|
186
|
+
log_warning(
|
|
187
|
+
"http_client is not an instance of httpx.AsyncClient. Using default global httpx.AsyncClient."
|
|
188
|
+
)
|
|
189
|
+
# Use global async client when user http_client is invalid
|
|
190
|
+
_client_params["http_client"] = get_default_async_client()
|
|
191
|
+
else:
|
|
192
|
+
# Use global async client when no custom http_client is provided
|
|
193
|
+
_client_params["http_client"] = get_default_async_client()
|
|
123
194
|
self.async_client = AsyncAnthropicClient(**_client_params)
|
|
124
195
|
return self.async_client
|
|
125
196
|
|
|
197
|
+
def _validate_thinking_support(self) -> None:
|
|
198
|
+
"""
|
|
199
|
+
Validate that the current model supports extended thinking.
|
|
200
|
+
|
|
201
|
+
Raises:
|
|
202
|
+
ValueError: If thinking is enabled but the model doesn't support it
|
|
203
|
+
"""
|
|
204
|
+
if self.thinking and self.id in self.NON_THINKING_MODELS:
|
|
205
|
+
non_thinking_models = "\n - ".join(sorted(self.NON_THINKING_MODELS))
|
|
206
|
+
raise ValueError(
|
|
207
|
+
f"Model '{self.id}' does not support extended thinking.\n\n"
|
|
208
|
+
f"The following models do NOT support thinking:\n - {non_thinking_models}\n\n"
|
|
209
|
+
f"All other Claude models support extended thinking by default.\n"
|
|
210
|
+
f"For more information, see: https://docs.anthropic.com/en/docs/about-claude/models/overview"
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
def _setup_skills_configuration(self) -> None:
|
|
214
|
+
"""
|
|
215
|
+
Set up configuration for Claude Agent Skills.
|
|
216
|
+
Automatically configures betas array with required values.
|
|
217
|
+
|
|
218
|
+
Skills enable document creation capabilities (PowerPoint, Excel, Word, PDF).
|
|
219
|
+
For more information, see: https://docs.claude.com/en/docs/agents-and-tools/agent-skills/quickstart
|
|
220
|
+
"""
|
|
221
|
+
# Required betas for skills
|
|
222
|
+
required_betas = ["code-execution-2025-08-25", "skills-2025-10-02"]
|
|
223
|
+
|
|
224
|
+
# Initialize or merge betas
|
|
225
|
+
if self.betas is None:
|
|
226
|
+
self.betas = required_betas
|
|
227
|
+
else:
|
|
228
|
+
# Add required betas if not present
|
|
229
|
+
for beta in required_betas:
|
|
230
|
+
if beta not in self.betas:
|
|
231
|
+
self.betas.append(beta)
|
|
232
|
+
|
|
126
233
|
def get_request_params(self) -> Dict[str, Any]:
|
|
127
234
|
"""
|
|
128
235
|
Generate keyword arguments for API requests.
|
|
129
236
|
"""
|
|
237
|
+
# Validate thinking support if thinking is enabled
|
|
238
|
+
if self.thinking:
|
|
239
|
+
self._validate_thinking_support()
|
|
240
|
+
|
|
130
241
|
_request_params: Dict[str, Any] = {}
|
|
131
242
|
if self.max_tokens:
|
|
132
243
|
_request_params["max_tokens"] = self.max_tokens
|
|
@@ -140,10 +251,17 @@ class Claude(Model):
|
|
|
140
251
|
_request_params["top_p"] = self.top_p
|
|
141
252
|
if self.top_k:
|
|
142
253
|
_request_params["top_k"] = self.top_k
|
|
254
|
+
if self.betas:
|
|
255
|
+
_request_params["betas"] = self.betas
|
|
256
|
+
if self.context_management:
|
|
257
|
+
_request_params["context_management"] = self.context_management
|
|
143
258
|
if self.mcp_servers:
|
|
144
259
|
_request_params["mcp_servers"] = [
|
|
145
260
|
{k: v for k, v in asdict(server).items() if v is not None} for server in self.mcp_servers
|
|
146
261
|
]
|
|
262
|
+
if self.skills:
|
|
263
|
+
_request_params["betas"] = self.betas
|
|
264
|
+
_request_params["container"] = {"skills": self.skills}
|
|
147
265
|
if self.request_params:
|
|
148
266
|
_request_params.update(self.request_params)
|
|
149
267
|
|
|
@@ -173,6 +291,15 @@ class Claude(Model):
|
|
|
173
291
|
else:
|
|
174
292
|
request_kwargs["system"] = [{"text": system_message, "type": "text"}]
|
|
175
293
|
|
|
294
|
+
# Add code execution tool if skills are enabled
|
|
295
|
+
if self.skills:
|
|
296
|
+
code_execution_tool = {"type": "code_execution_20250825", "name": "code_execution"}
|
|
297
|
+
if tools:
|
|
298
|
+
# Add code_execution to existing tools, code execution is needed for generating and processing files
|
|
299
|
+
tools = tools + [code_execution_tool]
|
|
300
|
+
else:
|
|
301
|
+
tools = [code_execution_tool]
|
|
302
|
+
|
|
176
303
|
if tools:
|
|
177
304
|
request_kwargs["tools"] = format_tools_for_model(tools)
|
|
178
305
|
|
|
@@ -199,12 +326,12 @@ class Claude(Model):
|
|
|
199
326
|
chat_messages, system_message = format_messages(messages)
|
|
200
327
|
request_kwargs = self._prepare_request_kwargs(system_message, tools)
|
|
201
328
|
|
|
202
|
-
if self.
|
|
329
|
+
if self._has_beta_features():
|
|
203
330
|
assistant_message.metrics.start_timer()
|
|
204
331
|
provider_response = self.get_client().beta.messages.create(
|
|
205
332
|
model=self.id,
|
|
206
333
|
messages=chat_messages, # type: ignore
|
|
207
|
-
**
|
|
334
|
+
**request_kwargs,
|
|
208
335
|
)
|
|
209
336
|
else:
|
|
210
337
|
assistant_message.metrics.start_timer()
|
|
@@ -266,7 +393,8 @@ class Claude(Model):
|
|
|
266
393
|
if run_response and run_response.metrics:
|
|
267
394
|
run_response.metrics.set_time_to_first_token()
|
|
268
395
|
|
|
269
|
-
|
|
396
|
+
# Beta features
|
|
397
|
+
if self._has_beta_features():
|
|
270
398
|
assistant_message.metrics.start_timer()
|
|
271
399
|
with self.get_client().beta.messages.stream(
|
|
272
400
|
model=self.id,
|
|
@@ -321,12 +449,13 @@ class Claude(Model):
|
|
|
321
449
|
chat_messages, system_message = format_messages(messages)
|
|
322
450
|
request_kwargs = self._prepare_request_kwargs(system_message, tools)
|
|
323
451
|
|
|
324
|
-
|
|
452
|
+
# Beta features
|
|
453
|
+
if self._has_beta_features():
|
|
325
454
|
assistant_message.metrics.start_timer()
|
|
326
455
|
provider_response = await self.get_async_client().beta.messages.create(
|
|
327
456
|
model=self.id,
|
|
328
457
|
messages=chat_messages, # type: ignore
|
|
329
|
-
**
|
|
458
|
+
**request_kwargs,
|
|
330
459
|
)
|
|
331
460
|
else:
|
|
332
461
|
assistant_message.metrics.start_timer()
|
|
@@ -385,7 +514,7 @@ class Claude(Model):
|
|
|
385
514
|
chat_messages, system_message = format_messages(messages)
|
|
386
515
|
request_kwargs = self._prepare_request_kwargs(system_message, tools)
|
|
387
516
|
|
|
388
|
-
if self.
|
|
517
|
+
if self._has_beta_features():
|
|
389
518
|
assistant_message.metrics.start_timer()
|
|
390
519
|
async with self.get_async_client().beta.messages.stream(
|
|
391
520
|
model=self.id,
|
|
@@ -421,33 +550,13 @@ class Claude(Model):
|
|
|
421
550
|
log_error(f"Unexpected error calling Claude API: {str(e)}")
|
|
422
551
|
raise ModelProviderError(message=str(e), model_name=self.name, model_id=self.id) from e
|
|
423
552
|
|
|
424
|
-
def format_function_call_results(self, messages: List[Message], function_call_results: List[Message]) -> None:
|
|
425
|
-
"""
|
|
426
|
-
Handle the results of function calls.
|
|
427
|
-
|
|
428
|
-
Args:
|
|
429
|
-
messages (List[Message]): The list of conversation messages.
|
|
430
|
-
function_call_results (List[Message]): The results of the function calls.
|
|
431
|
-
"""
|
|
432
|
-
if len(function_call_results) > 0:
|
|
433
|
-
fc_responses: List = []
|
|
434
|
-
for _fc_message in function_call_results:
|
|
435
|
-
fc_responses.append(
|
|
436
|
-
{
|
|
437
|
-
"type": "tool_result",
|
|
438
|
-
"tool_use_id": _fc_message.tool_call_id,
|
|
439
|
-
"content": str(_fc_message.content),
|
|
440
|
-
}
|
|
441
|
-
)
|
|
442
|
-
messages.append(Message(role="user", content=fc_responses))
|
|
443
|
-
|
|
444
553
|
def get_system_message_for_model(self, tools: Optional[List[Any]] = None) -> Optional[str]:
|
|
445
554
|
if tools is not None and len(tools) > 0:
|
|
446
555
|
tool_call_prompt = "Do not reflect on the quality of the returned search results in your response\n\n"
|
|
447
556
|
return tool_call_prompt
|
|
448
557
|
return None
|
|
449
558
|
|
|
450
|
-
def _parse_provider_response(self, response: AnthropicMessage, **kwargs) -> ModelResponse:
|
|
559
|
+
def _parse_provider_response(self, response: Union[AnthropicMessage, BetaMessage], **kwargs) -> ModelResponse:
|
|
451
560
|
"""
|
|
452
561
|
Parse the Claude response into a ModelResponse.
|
|
453
562
|
|
|
@@ -522,6 +631,30 @@ class Claude(Model):
|
|
|
522
631
|
if response.usage is not None:
|
|
523
632
|
model_response.response_usage = self._get_metrics(response.usage)
|
|
524
633
|
|
|
634
|
+
# Capture context management information if present
|
|
635
|
+
if self.context_management is not None and hasattr(response, "context_management"):
|
|
636
|
+
if response.context_management is not None: # type: ignore
|
|
637
|
+
model_response.provider_data = model_response.provider_data or {}
|
|
638
|
+
if hasattr(response.context_management, "model_dump"):
|
|
639
|
+
model_response.provider_data["context_management"] = response.context_management.model_dump() # type: ignore
|
|
640
|
+
else:
|
|
641
|
+
model_response.provider_data["context_management"] = response.context_management # type: ignore
|
|
642
|
+
# Extract file IDs if skills are enabled
|
|
643
|
+
if self.skills and response.content:
|
|
644
|
+
file_ids: List[str] = []
|
|
645
|
+
for block in response.content:
|
|
646
|
+
if block.type == "bash_code_execution_tool_result":
|
|
647
|
+
if hasattr(block, "content") and hasattr(block.content, "content"):
|
|
648
|
+
if isinstance(block.content.content, list):
|
|
649
|
+
for output_block in block.content.content:
|
|
650
|
+
if hasattr(output_block, "file_id"):
|
|
651
|
+
file_ids.append(output_block.file_id)
|
|
652
|
+
|
|
653
|
+
if file_ids:
|
|
654
|
+
if model_response.provider_data is None:
|
|
655
|
+
model_response.provider_data = {}
|
|
656
|
+
model_response.provider_data["file_ids"] = file_ids
|
|
657
|
+
|
|
525
658
|
return model_response
|
|
526
659
|
|
|
527
660
|
def _parse_provider_response_delta(
|
|
@@ -532,6 +665,9 @@ class Claude(Model):
|
|
|
532
665
|
ContentBlockStopEvent,
|
|
533
666
|
MessageStopEvent,
|
|
534
667
|
BetaRawContentBlockDeltaEvent,
|
|
668
|
+
BetaRawContentBlockStartEvent,
|
|
669
|
+
ParsedBetaContentBlockStopEvent,
|
|
670
|
+
ParsedBetaMessageStopEvent,
|
|
535
671
|
],
|
|
536
672
|
) -> ModelResponse:
|
|
537
673
|
"""
|
|
@@ -545,11 +681,11 @@ class Claude(Model):
|
|
|
545
681
|
"""
|
|
546
682
|
model_response = ModelResponse()
|
|
547
683
|
|
|
548
|
-
if isinstance(response, ContentBlockStartEvent):
|
|
684
|
+
if isinstance(response, (ContentBlockStartEvent, BetaRawContentBlockStartEvent)):
|
|
549
685
|
if response.content_block.type == "redacted_reasoning_content":
|
|
550
686
|
model_response.redacted_reasoning_content = response.content_block.data
|
|
551
687
|
|
|
552
|
-
if isinstance(response, ContentBlockDeltaEvent):
|
|
688
|
+
if isinstance(response, (ContentBlockDeltaEvent, BetaRawContentBlockDeltaEvent)):
|
|
553
689
|
# Handle text content
|
|
554
690
|
if response.delta.type == "text_delta":
|
|
555
691
|
model_response.content = response.delta.text
|
|
@@ -561,7 +697,7 @@ class Claude(Model):
|
|
|
561
697
|
"signature": response.delta.signature,
|
|
562
698
|
}
|
|
563
699
|
|
|
564
|
-
elif isinstance(response, ContentBlockStopEvent):
|
|
700
|
+
elif isinstance(response, (ContentBlockStopEvent, ParsedBetaContentBlockStopEvent)):
|
|
565
701
|
if response.content_block.type == "tool_use": # type: ignore
|
|
566
702
|
tool_use = response.content_block # type: ignore
|
|
567
703
|
tool_name = tool_use.name
|
|
@@ -582,7 +718,7 @@ class Claude(Model):
|
|
|
582
718
|
]
|
|
583
719
|
|
|
584
720
|
# Capture citations from the final response
|
|
585
|
-
elif isinstance(response, MessageStopEvent):
|
|
721
|
+
elif isinstance(response, (MessageStopEvent, ParsedBetaMessageStopEvent)):
|
|
586
722
|
model_response.content = ""
|
|
587
723
|
model_response.citations = Citations(raw=[], urls=[], documents=[])
|
|
588
724
|
for block in response.message.content: # type: ignore
|
|
@@ -600,6 +736,16 @@ class Claude(Model):
|
|
|
600
736
|
DocumentCitation(document_title=citation.document_title, cited_text=citation.cited_text)
|
|
601
737
|
)
|
|
602
738
|
|
|
739
|
+
# Capture context management information if present
|
|
740
|
+
if self.context_management is not None and hasattr(response.message, "context_management"): # type: ignore
|
|
741
|
+
context_mgmt = response.message.context_management # type: ignore
|
|
742
|
+
if context_mgmt is not None:
|
|
743
|
+
model_response.provider_data = model_response.provider_data or {}
|
|
744
|
+
if hasattr(context_mgmt, "model_dump"):
|
|
745
|
+
model_response.provider_data["context_management"] = context_mgmt.model_dump()
|
|
746
|
+
else:
|
|
747
|
+
model_response.provider_data["context_management"] = context_mgmt
|
|
748
|
+
|
|
603
749
|
if hasattr(response, "message") and hasattr(response.message, "usage") and response.message.usage is not None: # type: ignore
|
|
604
750
|
model_response.response_usage = self._get_metrics(response.message.usage) # type: ignore
|
|
605
751
|
|
|
@@ -616,7 +762,7 @@ class Claude(Model):
|
|
|
616
762
|
|
|
617
763
|
return model_response
|
|
618
764
|
|
|
619
|
-
def _get_metrics(self, response_usage: Union[Usage, MessageDeltaUsage]) -> Metrics:
|
|
765
|
+
def _get_metrics(self, response_usage: Union[Usage, MessageDeltaUsage, BetaUsage]) -> Metrics:
|
|
620
766
|
"""
|
|
621
767
|
Parse the given Anthropic-specific usage into an Agno Metrics object.
|
|
622
768
|
|
|
@@ -636,7 +782,7 @@ class Claude(Model):
|
|
|
636
782
|
|
|
637
783
|
# Anthropic-specific additional fields
|
|
638
784
|
if response_usage.server_tool_use:
|
|
639
|
-
metrics.provider_metrics = {"server_tool_use": response_usage.server_tool_use}
|
|
785
|
+
metrics.provider_metrics = {"server_tool_use": response_usage.server_tool_use.model_dump()}
|
|
640
786
|
if isinstance(response_usage, Usage):
|
|
641
787
|
if response_usage.service_tier:
|
|
642
788
|
metrics.provider_metrics = metrics.provider_metrics or {}
|